2 * g_dnl.c -- USB Downloader Gadget
4 * Copyright (C) 2012 Samsung Electronics
5 * Lukasz Majewski <l.majewski@samsung.com>
7 * SPDX-License-Identifier: GPL-2.0+
18 #include <usb_mass_storage.h>
22 #include "gadget_chips.h"
23 #include "composite.c"
26 * One needs to define the following:
27 * CONFIG_G_DNL_VENDOR_NUM
28 * CONFIG_G_DNL_PRODUCT_NUM
29 * CONFIG_G_DNL_MANUFACTURER
30 * at e.g. ./configs/<board>_defconfig
33 #define STRING_MANUFACTURER 25
34 #define STRING_PRODUCT 2
35 /* Index of String Descriptor describing this configuration */
36 #define STRING_USBDOWN 2
37 /* Index of String serial */
38 #define STRING_SERIAL 3
39 #define MAX_STRING_SERIAL 32
40 /* Number of supported configurations */
41 #define CONFIGURATION_NUMBER 1
43 #define DRIVER_VERSION "usb_dnl 2.0"
45 static const char product
[] = "USB download gadget";
46 static char g_dnl_serial
[MAX_STRING_SERIAL
];
47 static const char manufacturer
[] = CONFIG_G_DNL_MANUFACTURER
;
49 void g_dnl_set_serialnumber(char *s
)
51 memset(g_dnl_serial
, 0, MAX_STRING_SERIAL
);
52 strncpy(g_dnl_serial
, s
, MAX_STRING_SERIAL
- 1);
55 static struct usb_device_descriptor device_desc
= {
56 .bLength
= sizeof device_desc
,
57 .bDescriptorType
= USB_DT_DEVICE
,
59 .bcdUSB
= __constant_cpu_to_le16(0x0200),
60 .bDeviceClass
= USB_CLASS_PER_INTERFACE
,
61 .bDeviceSubClass
= 0, /*0x02:CDC-modem , 0x00:CDC-serial*/
63 .idVendor
= __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM
),
64 .idProduct
= __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM
),
65 .iProduct
= STRING_PRODUCT
,
66 .iSerialNumber
= STRING_SERIAL
,
67 .bNumConfigurations
= 1,
71 * static strings, in UTF-8
72 * IDs for those strings are assigned dynamically at g_dnl_bind()
74 static struct usb_string g_dnl_string_defs
[] = {
81 static struct usb_gadget_strings g_dnl_string_tab
= {
82 .language
= 0x0409, /* en-us */
83 .strings
= g_dnl_string_defs
,
86 static struct usb_gadget_strings
*g_dnl_composite_strings
[] = {
91 static int g_dnl_unbind(struct usb_composite_dev
*cdev
)
93 struct usb_gadget
*gadget
= cdev
->gadget
;
95 debug("%s: calling usb_gadget_disconnect for "
96 "controller '%s'\n", __func__
, gadget
->name
);
97 usb_gadget_disconnect(gadget
);
102 static inline struct g_dnl_bind_callback
*g_dnl_bind_callback_first(void)
104 return ll_entry_start(struct g_dnl_bind_callback
,
105 g_dnl_bind_callbacks
);
108 static inline struct g_dnl_bind_callback
*g_dnl_bind_callback_end(void)
110 return ll_entry_end(struct g_dnl_bind_callback
,
111 g_dnl_bind_callbacks
);
114 static int g_dnl_do_config(struct usb_configuration
*c
)
116 const char *s
= c
->cdev
->driver
->name
;
117 struct g_dnl_bind_callback
*callback
= g_dnl_bind_callback_first();
119 debug("%s: configuration: 0x%p composite dev: 0x%p\n",
120 __func__
, c
, c
->cdev
);
122 for (; callback
!= g_dnl_bind_callback_end(); callback
++)
123 if (!strcmp(s
, callback
->usb_function_name
))
124 return callback
->fptr(c
);
128 static int g_dnl_config_register(struct usb_composite_dev
*cdev
)
130 struct usb_configuration
*config
;
131 const char *name
= "usb_dnload";
133 config
= memalign(CONFIG_SYS_CACHELINE_SIZE
, sizeof(*config
));
137 memset(config
, 0, sizeof(*config
));
139 config
->label
= name
;
140 config
->bmAttributes
= USB_CONFIG_ATT_ONE
| USB_CONFIG_ATT_SELFPOWER
;
141 config
->bConfigurationValue
= CONFIGURATION_NUMBER
;
142 config
->iConfiguration
= STRING_USBDOWN
;
143 config
->bind
= g_dnl_do_config
;
145 return usb_add_config(cdev
, config
);
149 int board_usb_init(int index
, enum usb_init_type init
)
155 int board_usb_cleanup(int index
, enum usb_init_type init
)
161 int g_dnl_bind_fixup(struct usb_device_descriptor
*dev
, const char *name
)
166 __weak
int g_dnl_get_board_bcd_device_number(int gcnum
)
171 __weak
int g_dnl_board_usb_cable_connected(void)
176 static bool g_dnl_detach_request
;
178 bool g_dnl_detach(void)
180 return g_dnl_detach_request
;
183 void g_dnl_trigger_detach(void)
185 g_dnl_detach_request
= true;
188 void g_dnl_clear_detach(void)
190 g_dnl_detach_request
= false;
193 static int g_dnl_get_bcd_device_number(struct usb_composite_dev
*cdev
)
195 struct usb_gadget
*gadget
= cdev
->gadget
;
198 gcnum
= usb_gadget_controller_number(gadget
);
202 return g_dnl_get_board_bcd_device_number(gcnum
);
205 static int g_dnl_bind(struct usb_composite_dev
*cdev
)
207 struct usb_gadget
*gadget
= cdev
->gadget
;
211 debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__
, gadget
, cdev
);
213 id
= usb_string_id(cdev
);
217 g_dnl_string_defs
[0].id
= id
;
218 device_desc
.iManufacturer
= id
;
220 id
= usb_string_id(cdev
);
224 g_dnl_string_defs
[1].id
= id
;
225 device_desc
.iProduct
= id
;
227 id
= usb_string_id(cdev
);
231 g_dnl_string_defs
[2].id
= id
;
232 device_desc
.iSerialNumber
= id
;
234 g_dnl_bind_fixup(&device_desc
, cdev
->driver
->name
);
235 ret
= g_dnl_config_register(cdev
);
239 gcnum
= g_dnl_get_bcd_device_number(cdev
);
241 device_desc
.bcdDevice
= cpu_to_le16(gcnum
);
243 debug("%s: controller '%s' not recognized\n",
244 __func__
, gadget
->name
);
245 device_desc
.bcdDevice
= __constant_cpu_to_le16(0x9999);
248 debug("%s: calling usb_gadget_connect for "
249 "controller '%s'\n", __func__
, gadget
->name
);
250 usb_gadget_connect(gadget
);
259 static struct usb_composite_driver g_dnl_driver
= {
262 .strings
= g_dnl_composite_strings
,
265 .unbind
= g_dnl_unbind
,
270 * Registering via USB function name won't be necessary after rewriting
271 * g_dnl to support multiple USB functions.
273 int g_dnl_register(const char *name
)
277 debug("%s: g_dnl_driver.name = %s\n", __func__
, name
);
278 g_dnl_driver
.name
= name
;
280 ret
= usb_composite_register(&g_dnl_driver
);
282 printf("%s: failed!, error: %d\n", __func__
, ret
);
288 void g_dnl_unregister(void)
290 usb_composite_unregister(&g_dnl_driver
);