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