1
2
3
4
5
6
7
8
9
10#include <common.h>
11#include <malloc.h>
12
13#include <mmc.h>
14#include <part.h>
15#include <usb.h>
16
17#include <g_dnl.h>
18#include <usb_mass_storage.h>
19#include <dfu.h>
20#include <thor.h>
21
22#include "gadget_chips.h"
23#include "composite.c"
24
25
26
27
28
29
30
31
32
33#define STRING_MANUFACTURER 25
34#define STRING_PRODUCT 2
35
36#define STRING_USBDOWN 2
37
38#define STRING_SERIAL 3
39#define MAX_STRING_SERIAL 32
40
41#define CONFIGURATION_NUMBER 1
42
43#define DRIVER_VERSION "usb_dnl 2.0"
44
45static const char product[] = "USB download gadget";
46static char g_dnl_serial[MAX_STRING_SERIAL];
47static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
48
49void g_dnl_set_serialnumber(char *s)
50{
51 memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
52 if (strlen(s) < MAX_STRING_SERIAL)
53 strncpy(g_dnl_serial, s, strlen(s));
54}
55
56static struct usb_device_descriptor device_desc = {
57 .bLength = sizeof device_desc,
58 .bDescriptorType = USB_DT_DEVICE,
59
60 .bcdUSB = __constant_cpu_to_le16(0x0200),
61 .bDeviceClass = USB_CLASS_PER_INTERFACE,
62 .bDeviceSubClass = 0,
63
64 .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
65 .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
66 .iProduct = STRING_PRODUCT,
67 .iSerialNumber = STRING_SERIAL,
68 .bNumConfigurations = 1,
69};
70
71
72
73
74
75static struct usb_string g_dnl_string_defs[] = {
76 {.s = manufacturer},
77 {.s = product},
78 {.s = g_dnl_serial},
79 { }
80};
81
82static struct usb_gadget_strings g_dnl_string_tab = {
83 .language = 0x0409,
84 .strings = g_dnl_string_defs,
85};
86
87static struct usb_gadget_strings *g_dnl_composite_strings[] = {
88 &g_dnl_string_tab,
89 NULL,
90};
91
92static int g_dnl_unbind(struct usb_composite_dev *cdev)
93{
94 struct usb_gadget *gadget = cdev->gadget;
95
96 debug("%s: calling usb_gadget_disconnect for "
97 "controller '%s'\n", __func__, gadget->name);
98 usb_gadget_disconnect(gadget);
99
100 return 0;
101}
102
103static inline struct g_dnl_bind_callback *g_dnl_bind_callback_first(void)
104{
105 return ll_entry_start(struct g_dnl_bind_callback,
106 g_dnl_bind_callbacks);
107}
108
109static inline struct g_dnl_bind_callback *g_dnl_bind_callback_end(void)
110{
111 return ll_entry_end(struct g_dnl_bind_callback,
112 g_dnl_bind_callbacks);
113}
114
115static int g_dnl_do_config(struct usb_configuration *c)
116{
117 const char *s = c->cdev->driver->name;
118 struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();
119
120 debug("%s: configuration: 0x%p composite dev: 0x%p\n",
121 __func__, c, c->cdev);
122
123 for (; callback != g_dnl_bind_callback_end(); callback++)
124 if (!strcmp(s, callback->usb_function_name))
125 return callback->fptr(c);
126 return -ENODEV;
127}
128
129static int g_dnl_config_register(struct usb_composite_dev *cdev)
130{
131 struct usb_configuration *config;
132 const char *name = "usb_dnload";
133
134 config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
135 if (!config)
136 return -ENOMEM;
137
138 memset(config, 0, sizeof(*config));
139
140 config->label = name;
141 config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
142 config->bConfigurationValue = CONFIGURATION_NUMBER;
143 config->iConfiguration = STRING_USBDOWN;
144 config->bind = g_dnl_do_config;
145
146 return usb_add_config(cdev, config);
147}
148
149__weak
150int board_usb_init(int index, enum usb_init_type init)
151{
152 return 0;
153}
154
155__weak
156int board_usb_cleanup(int index, enum usb_init_type init)
157{
158 return 0;
159}
160
161__weak
162int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
163{
164 return 0;
165}
166
167__weak int g_dnl_get_board_bcd_device_number(int gcnum)
168{
169 return gcnum;
170}
171
172__weak int g_dnl_board_usb_cable_connected(void)
173{
174 return -EOPNOTSUPP;
175}
176
177static bool g_dnl_detach_request;
178
179bool g_dnl_detach(void)
180{
181 return g_dnl_detach_request;
182}
183
184void g_dnl_trigger_detach(void)
185{
186 g_dnl_detach_request = true;
187}
188
189void g_dnl_clear_detach(void)
190{
191 g_dnl_detach_request = false;
192}
193
194static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
195{
196 struct usb_gadget *gadget = cdev->gadget;
197 int gcnum;
198
199 gcnum = usb_gadget_controller_number(gadget);
200 if (gcnum > 0)
201 gcnum += 0x200;
202
203 return g_dnl_get_board_bcd_device_number(gcnum);
204}
205
206static int g_dnl_bind(struct usb_composite_dev *cdev)
207{
208 struct usb_gadget *gadget = cdev->gadget;
209 int id, ret;
210 int gcnum;
211
212 debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
213
214 id = usb_string_id(cdev);
215
216 if (id < 0)
217 return id;
218 g_dnl_string_defs[0].id = id;
219 device_desc.iManufacturer = id;
220
221 id = usb_string_id(cdev);
222 if (id < 0)
223 return id;
224
225 g_dnl_string_defs[1].id = id;
226 device_desc.iProduct = id;
227
228 id = usb_string_id(cdev);
229 if (id < 0)
230 return id;
231
232 g_dnl_string_defs[2].id = id;
233 device_desc.iSerialNumber = id;
234
235 g_dnl_bind_fixup(&device_desc, cdev->driver->name);
236 ret = g_dnl_config_register(cdev);
237 if (ret)
238 goto error;
239
240 gcnum = g_dnl_get_bcd_device_number(cdev);
241 if (gcnum >= 0)
242 device_desc.bcdDevice = cpu_to_le16(gcnum);
243 else {
244 debug("%s: controller '%s' not recognized\n",
245 __func__, gadget->name);
246 device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
247 }
248
249 debug("%s: calling usb_gadget_connect for "
250 "controller '%s'\n", __func__, gadget->name);
251 usb_gadget_connect(gadget);
252
253 return 0;
254
255 error:
256 g_dnl_unbind(cdev);
257 return -ENOMEM;
258}
259
260static struct usb_composite_driver g_dnl_driver = {
261 .name = NULL,
262 .dev = &device_desc,
263 .strings = g_dnl_composite_strings,
264
265 .bind = g_dnl_bind,
266 .unbind = g_dnl_unbind,
267};
268
269
270
271
272
273
274int g_dnl_register(const char *name)
275{
276 int ret;
277
278 debug("%s: g_dnl_driver.name = %s\n", __func__, name);
279 g_dnl_driver.name = name;
280
281 ret = usb_composite_register(&g_dnl_driver);
282 if (ret) {
283 printf("%s: failed!, error: %d\n", __func__, ret);
284 return ret;
285 }
286 return 0;
287}
288
289void g_dnl_unregister(void)
290{
291 usb_composite_unregister(&g_dnl_driver);
292}
293