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