xref: /OK3568_Linux_fs/u-boot/drivers/usb/gadget/g_dnl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * g_dnl.c -- USB Downloader Gadget
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2012 Samsung Electronics
5*4882a593Smuzhiyun  * Lukasz Majewski  <l.majewski@samsung.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <mmc.h>
14*4882a593Smuzhiyun #include <part.h>
15*4882a593Smuzhiyun #include <usb.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <g_dnl.h>
18*4882a593Smuzhiyun #include <usb_mass_storage.h>
19*4882a593Smuzhiyun #include <dfu.h>
20*4882a593Smuzhiyun #include <thor.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <env_callback.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "gadget_chips.h"
25*4882a593Smuzhiyun #include "composite.c"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * One needs to define the following:
29*4882a593Smuzhiyun  * CONFIG_USB_GADGET_VENDOR_NUM
30*4882a593Smuzhiyun  * CONFIG_USB_GADGET_PRODUCT_NUM
31*4882a593Smuzhiyun  * CONFIG_USB_GADGET_MANUFACTURER
32*4882a593Smuzhiyun  * at e.g. ./configs/<board>_defconfig
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define STRING_MANUFACTURER 25
36*4882a593Smuzhiyun #define STRING_PRODUCT 2
37*4882a593Smuzhiyun /* Index of String Descriptor describing this configuration */
38*4882a593Smuzhiyun #define STRING_USBDOWN 2
39*4882a593Smuzhiyun /* Index of String serial */
40*4882a593Smuzhiyun #define STRING_SERIAL  3
41*4882a593Smuzhiyun #define MAX_STRING_SERIAL	256
42*4882a593Smuzhiyun /* Number of supported configurations */
43*4882a593Smuzhiyun #define CONFIGURATION_NUMBER 1
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define DRIVER_VERSION		"usb_dnl 2.0"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static const char product[] = "USB download gadget";
48*4882a593Smuzhiyun static char g_dnl_serial[MAX_STRING_SERIAL];
49*4882a593Smuzhiyun static const char manufacturer[] = CONFIG_USB_GADGET_MANUFACTURER;
50*4882a593Smuzhiyun 
g_dnl_set_serialnumber(char * s)51*4882a593Smuzhiyun void g_dnl_set_serialnumber(char *s)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
54*4882a593Smuzhiyun 	if (s)
55*4882a593Smuzhiyun 		strncpy(g_dnl_serial, s, MAX_STRING_SERIAL - 1);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun static struct usb_device_descriptor device_desc = {
59*4882a593Smuzhiyun 	.bLength = sizeof device_desc,
60*4882a593Smuzhiyun 	.bDescriptorType = USB_DT_DEVICE,
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	.bcdUSB = __constant_cpu_to_le16(0x0200),
63*4882a593Smuzhiyun 	.bDeviceClass = USB_CLASS_PER_INTERFACE,
64*4882a593Smuzhiyun 	.bDeviceSubClass = 0, /*0x02:CDC-modem , 0x00:CDC-serial*/
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	.idVendor = __constant_cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM),
67*4882a593Smuzhiyun 	.idProduct = __constant_cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM),
68*4882a593Smuzhiyun 	/* .iProduct = DYNAMIC */
69*4882a593Smuzhiyun 	/* .iSerialNumber = DYNAMIC */
70*4882a593Smuzhiyun 	.bNumConfigurations = 1,
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun  * static strings, in UTF-8
75*4882a593Smuzhiyun  * IDs for those strings are assigned dynamically at g_dnl_bind()
76*4882a593Smuzhiyun  */
77*4882a593Smuzhiyun static struct usb_string g_dnl_string_defs[] = {
78*4882a593Smuzhiyun 	{.s = manufacturer},
79*4882a593Smuzhiyun 	{.s = product},
80*4882a593Smuzhiyun 	{.s = g_dnl_serial},
81*4882a593Smuzhiyun 	{ }		/* end of list */
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static struct usb_gadget_strings g_dnl_string_tab = {
85*4882a593Smuzhiyun 	.language = 0x0409, /* en-us */
86*4882a593Smuzhiyun 	.strings = g_dnl_string_defs,
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static struct usb_gadget_strings *g_dnl_composite_strings[] = {
90*4882a593Smuzhiyun 	&g_dnl_string_tab,
91*4882a593Smuzhiyun 	NULL,
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun 
g_dnl_unbind(struct usb_composite_dev * cdev)94*4882a593Smuzhiyun static int g_dnl_unbind(struct usb_composite_dev *cdev)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct usb_gadget *gadget = cdev->gadget;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	debug("%s: calling usb_gadget_disconnect for "
99*4882a593Smuzhiyun 			"controller '%s'\n", __func__, gadget->name);
100*4882a593Smuzhiyun 	usb_gadget_disconnect(gadget);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return 0;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
g_dnl_bind_callback_first(void)105*4882a593Smuzhiyun static inline struct g_dnl_bind_callback *g_dnl_bind_callback_first(void)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	return ll_entry_start(struct g_dnl_bind_callback,
108*4882a593Smuzhiyun 				g_dnl_bind_callbacks);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
g_dnl_bind_callback_end(void)111*4882a593Smuzhiyun static inline struct g_dnl_bind_callback *g_dnl_bind_callback_end(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	return ll_entry_end(struct g_dnl_bind_callback,
114*4882a593Smuzhiyun 				g_dnl_bind_callbacks);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
g_dnl_do_config(struct usb_configuration * c)117*4882a593Smuzhiyun static int g_dnl_do_config(struct usb_configuration *c)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	const char *s = c->cdev->driver->name;
120*4882a593Smuzhiyun 	struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	debug("%s: configuration: 0x%p composite dev: 0x%p\n",
123*4882a593Smuzhiyun 	      __func__, c, c->cdev);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	for (; callback != g_dnl_bind_callback_end(); callback++)
126*4882a593Smuzhiyun 		if (!strcmp(s, callback->usb_function_name))
127*4882a593Smuzhiyun 			return callback->fptr(c);
128*4882a593Smuzhiyun 	return -ENODEV;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
g_dnl_config_register(struct usb_composite_dev * cdev)131*4882a593Smuzhiyun static int g_dnl_config_register(struct usb_composite_dev *cdev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct usb_configuration *config;
134*4882a593Smuzhiyun 	const char *name = "usb_dnload";
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
137*4882a593Smuzhiyun 	if (!config)
138*4882a593Smuzhiyun 		return -ENOMEM;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	memset(config, 0, sizeof(*config));
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	config->label = name;
143*4882a593Smuzhiyun 	config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
144*4882a593Smuzhiyun 	config->bConfigurationValue = CONFIGURATION_NUMBER;
145*4882a593Smuzhiyun 	config->iConfiguration = STRING_USBDOWN;
146*4882a593Smuzhiyun 	config->bind = g_dnl_do_config;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return usb_add_config(cdev, config);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun __weak
board_usb_init(int index,enum usb_init_type init)152*4882a593Smuzhiyun int board_usb_init(int index, enum usb_init_type init)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	return 0;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun __weak
board_usb_cleanup(int index,enum usb_init_type init)158*4882a593Smuzhiyun int board_usb_cleanup(int index, enum usb_init_type init)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun __weak
g_dnl_bind_fixup(struct usb_device_descriptor * dev,const char * name)164*4882a593Smuzhiyun int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
g_dnl_get_board_bcd_device_number(int gcnum)169*4882a593Smuzhiyun __weak int g_dnl_get_board_bcd_device_number(int gcnum)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	return gcnum;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
g_dnl_board_usb_cable_connected(void)174*4882a593Smuzhiyun __weak int g_dnl_board_usb_cable_connected(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	return -EOPNOTSUPP;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun static bool g_dnl_detach_request;
180*4882a593Smuzhiyun 
g_dnl_detach(void)181*4882a593Smuzhiyun bool g_dnl_detach(void)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	return g_dnl_detach_request;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
g_dnl_trigger_detach(void)186*4882a593Smuzhiyun void g_dnl_trigger_detach(void)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	g_dnl_detach_request = true;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
g_dnl_clear_detach(void)191*4882a593Smuzhiyun void g_dnl_clear_detach(void)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	g_dnl_detach_request = false;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
g_dnl_get_bcd_device_number(struct usb_composite_dev * cdev)196*4882a593Smuzhiyun static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	struct usb_gadget *gadget = cdev->gadget;
199*4882a593Smuzhiyun 	int gcnum;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	gcnum = usb_gadget_controller_number(gadget);
202*4882a593Smuzhiyun 	if (gcnum > 0)
203*4882a593Smuzhiyun 		gcnum += 0x200;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return g_dnl_get_board_bcd_device_number(gcnum);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun /**
209*4882a593Smuzhiyun  * Update internal serial number variable when the "serial#" env var changes.
210*4882a593Smuzhiyun  *
211*4882a593Smuzhiyun  * Handle all cases, even when flags == H_PROGRAMMATIC or op == env_op_delete.
212*4882a593Smuzhiyun  */
on_serialno(const char * name,const char * value,enum env_op op,int flags)213*4882a593Smuzhiyun static int on_serialno(const char *name, const char *value, enum env_op op,
214*4882a593Smuzhiyun 		int flags)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	g_dnl_set_serialnumber((char *)value);
217*4882a593Smuzhiyun 	return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun U_BOOT_ENV_CALLBACK(serialno, on_serialno);
220*4882a593Smuzhiyun 
g_dnl_bind(struct usb_composite_dev * cdev)221*4882a593Smuzhiyun static int g_dnl_bind(struct usb_composite_dev *cdev)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct usb_gadget *gadget = cdev->gadget;
224*4882a593Smuzhiyun 	int id, ret;
225*4882a593Smuzhiyun 	int gcnum;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	id = usb_string_id(cdev);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (id < 0)
232*4882a593Smuzhiyun 		return id;
233*4882a593Smuzhiyun 	g_dnl_string_defs[0].id = id;
234*4882a593Smuzhiyun 	device_desc.iManufacturer = id;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	id = usb_string_id(cdev);
237*4882a593Smuzhiyun 	if (id < 0)
238*4882a593Smuzhiyun 		return id;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	g_dnl_string_defs[1].id = id;
241*4882a593Smuzhiyun 	device_desc.iProduct = id;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	g_dnl_bind_fixup(&device_desc, cdev->driver->name);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (strlen(g_dnl_serial)) {
246*4882a593Smuzhiyun 		id = usb_string_id(cdev);
247*4882a593Smuzhiyun 		if (id < 0)
248*4882a593Smuzhiyun 			return id;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		g_dnl_string_defs[2].id = id;
251*4882a593Smuzhiyun 		device_desc.iSerialNumber = id;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	ret = g_dnl_config_register(cdev);
255*4882a593Smuzhiyun 	if (ret)
256*4882a593Smuzhiyun 		goto error;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	gcnum = g_dnl_get_bcd_device_number(cdev);
259*4882a593Smuzhiyun 	if (gcnum >= 0)
260*4882a593Smuzhiyun 		device_desc.bcdDevice = cpu_to_le16(gcnum);
261*4882a593Smuzhiyun 	else {
262*4882a593Smuzhiyun 		debug("%s: controller '%s' not recognized\n",
263*4882a593Smuzhiyun 			__func__, gadget->name);
264*4882a593Smuzhiyun 		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	debug("%s: calling usb_gadget_connect for "
268*4882a593Smuzhiyun 			"controller '%s'\n", __func__, gadget->name);
269*4882a593Smuzhiyun 	usb_gadget_connect(gadget);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	return 0;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun  error:
274*4882a593Smuzhiyun 	g_dnl_unbind(cdev);
275*4882a593Smuzhiyun 	return -ENOMEM;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun static struct usb_composite_driver g_dnl_driver = {
279*4882a593Smuzhiyun 	.name = NULL,
280*4882a593Smuzhiyun 	.dev = &device_desc,
281*4882a593Smuzhiyun 	.strings = g_dnl_composite_strings,
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	.bind = g_dnl_bind,
284*4882a593Smuzhiyun 	.unbind = g_dnl_unbind,
285*4882a593Smuzhiyun };
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun /*
288*4882a593Smuzhiyun  * NOTICE:
289*4882a593Smuzhiyun  * Registering via USB function name won't be necessary after rewriting
290*4882a593Smuzhiyun  * g_dnl to support multiple USB functions.
291*4882a593Smuzhiyun  */
g_dnl_register(const char * name)292*4882a593Smuzhiyun int g_dnl_register(const char *name)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	int ret;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	debug("%s: g_dnl_driver.name = %s\n", __func__, name);
297*4882a593Smuzhiyun 	g_dnl_driver.name = name;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	ret = usb_composite_register(&g_dnl_driver);
300*4882a593Smuzhiyun 	if (ret) {
301*4882a593Smuzhiyun 		printf("%s: failed!, error: %d\n", __func__, ret);
302*4882a593Smuzhiyun 		return ret;
303*4882a593Smuzhiyun 	}
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
g_dnl_unregister(void)307*4882a593Smuzhiyun void g_dnl_unregister(void)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	usb_composite_unregister(&g_dnl_driver);
310*4882a593Smuzhiyun }
311