1 /****************************************************************************
2 * drivers/usbdev/dfu.c
3 *
4 * Copyright (C) 2011-2018 Gregory Nutt. All rights reserved.
5 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
6 *
7 * Authors: Petteri Aimonen <jpa@git.mail.kapsi.fi>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 * 3. Neither the name NuttX nor the names of its contributors may be
20 * used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 ****************************************************************************/
37 /****************************************************************************
38 * Notice of Export Control Law
39 * ===============================================
40 * Huawei LiteOS may be subject to applicable export control laws and regulations,
41 * which might include those applicable to Huawei LiteOS of U.S. and the country in
42 * which you are located.
43 * Import, export and usage of Huawei LiteOS in any manner by you shall be in
44 * compliance with such applicable export control laws and regulations.
45 ****************************************************************************/
46
47 /* This is a driver for the USB Device Firmware Upgrade protocol v1.1.
48 * Currently it supports the app-side ("Run-Time") part of the protocol:
49 * a sequence of DFU_DETACH and USB reset commands, which will reboot into
50 * a separate USB DFU bootloader.
51 *
52 * The bootloader is provided by board-specific logic, or STM32's
53 * built-in ROM bootloader can be used.
54 *
55 * https://www.usb.org/sites/default/files/DFU_1.1.pdf
56 */
57
58 /****************************************************************************
59 * Included Files
60 ****************************************************************************/
61
62 #include <errno.h>
63 #include <string.h>
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include "gadget/composite.h"
67 #include "gadget/f_dfu.h"
68
69 /****************************************************************************
70 * Pre-processor definitions
71 ****************************************************************************/
72
73 #define DFU_MAX_TIMEOUT 255
74 #define DFU_MAX_TRANSFER 4096
75 #define DFU_VERSION 0x0110
76
77 /* All 16-bit values must be little-endian */
78
79 #define MSBYTE(u16) ((u16) >> 8) /* Get MS byte from uint16_t */
80 #define LSBYTE(u16) ((u16) & 0xff) /* Get LS byte from uint16_t */
81
82 /****************************************************************************
83 * Private Types
84 ****************************************************************************/
85
86 /* DFU functional descriptor */
87
88 struct dfu_funcdesc_s
89 {
90 uint8_t len; /* Descriptor length */
91 uint8_t type; /* 0x21 = DFU FUNCTIONAL */
92 uint8_t attributes; /* Bit mask of supported features */
93 uint8_t detach_timeout[2]; /* Maximum time in milliseconds between DFU_DETACH and USB reset */
94 uint8_t transfer_size[2]; /* Maximum number of bytes in control writes */
95 uint8_t dfu_version[2]; /* Version of DFU specification supported */
96 };
97
98 /* USB configuration descriptor */
99
100 struct dfu_cfgdesc_s
101 {
102 struct usb_interface_descriptor ifdesc; /* DFU interface descriptor */
103 struct dfu_funcdesc_s funcdesc; /* DFU functional descriptor */
104 };
105
106 struct dfu_driver_s
107 {
108 struct usbdevclass_driver_s drvr;
109 FAR struct usbdev_req_s *ctrlreq; /* Pointer to preallocated control request */
110 };
111
112 /****************************************************************************
113 * Private Function Prototypes
114 ****************************************************************************/
115
116 /* usbclass callbacks */
117
118 static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
119 FAR struct usbdev_s *dev,
120 FAR const struct usb_device_request *ctrl,
121 FAR uint8_t *dataout, size_t outlen);
122 static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
123 FAR struct usbdev_s *dev);
124 static int usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
125 FAR struct usbdev_s *dev);
126 static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
127 FAR struct usbdev_s *dev);
128
129 /****************************************************************************
130 * Private Data
131 ****************************************************************************/
132
133 /* USB driver operations */
134
135 const static struct usbdevclass_driverops_s g_dfu_driverops =
136 {
137 &usbclass_bind,
138 &usbclass_unbind,
139 &usbclass_setup,
140 &usbclass_disconnect,
141 NULL,
142 NULL
143 };
144
145 static struct dfu_cfgdesc_s g_dfu_cfgdesc =
146 {
147 {
148 .bLength = sizeof(struct usb_interface_descriptor),
149 .bDescriptorType = UDESC_INTERFACE,
150 .bInterfaceNumber = 0,
151 .bAlternateSetting = 0,
152 .bNumEndpoints = 0,
153 .bInterfaceClass = 0xFE,
154 .bInterfaceSubClass = 0x01,
155 .bInterfaceProtocol = 0x01, /* DFU runtime protocol */
156 .iInterface = 0x01
157 },
158 {
159 .len = sizeof(struct dfu_funcdesc_s),
160 .type = 0x21,
161 .attributes = 0x0F,
162 .detach_timeout = { LSBYTE(DFU_MAX_TIMEOUT), MSBYTE(DFU_MAX_TIMEOUT) },
163 .transfer_size = { LSBYTE(DFU_MAX_TRANSFER), MSBYTE(DFU_MAX_TRANSFER) },
164 .dfu_version = { LSBYTE(DFU_VERSION), MSBYTE(DFU_VERSION) }
165 }
166 };
167
to_runtime_mode(void)168 void to_runtime_mode(void)
169 {
170 g_dfu_cfgdesc.ifdesc.bInterfaceProtocol = 0x01; /* The runtime mode */
171 }
172
to_dfu_mode(void)173 void to_dfu_mode(void)
174 {
175 g_dfu_cfgdesc.ifdesc.bInterfaceProtocol = 0x02; /* The DFU mode */
176 }
177
178 /****************************************************************************
179 * Private Functions
180 ****************************************************************************/
181
usbclass_ep0incomplete(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * req)182 static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
183 FAR struct usbdev_req_s *req)
184 {
185 (void)ep;
186 (void)req;
187 }
188
usbclass_mkdevdesc(uint8_t * buf)189 static void usbclass_mkdevdesc(uint8_t *buf)
190 {
191 usbdev_dfu_mkdevdesc(buf);
192 }
193
usbclass_mkcfgdesc(FAR uint8_t * buf,FAR struct usbdev_devinfo_s * devinfo)194 static int16_t usbclass_mkcfgdesc(FAR uint8_t *buf,
195 FAR struct usbdev_devinfo_s *devinfo)
196 {
197 int16_t total_len = 0;
198 int16_t len = USB_CONFIG_DESC_SIZE;
199 int ret;
200
201 /* Modify according to the actual length. */
202
203 USETW(g_dfu_config_desc.wTotalLength, (USB_CONFIG_DESC_SIZE + sizeof(g_dfu_cfgdesc)));
204
205 /* Copy DFU device configure descriptor. */
206
207 ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, &g_dfu_config_desc, (uint16_t)len);
208 if (ret != EOK)
209 {
210 usb_err("memcpy_s fail, ret:%d\n", ret);
211 return -1;
212 }
213 total_len += len;
214
215 /* Copy DFU device function descriptor. */
216
217 buf += USB_CONFIG_DESC_SIZE;
218 len = sizeof(g_dfu_cfgdesc);
219 ret = memcpy_s(buf, (size_t)(USB_COMP_EP0_BUFSIZ - total_len), &g_dfu_cfgdesc, (uint16_t)len);
220 if (ret != EOK)
221 {
222 usb_err("memcpy_s fail, ret:%d\n", ret);
223 return -1;
224 }
225 total_len += len;
226
227 return total_len;
228 }
229
usbclass_mkstrdesc(uint8_t id,uint8_t * buf)230 static int usbclass_mkstrdesc(uint8_t id, uint8_t *buf)
231 {
232 return usbdev_dfu_mkstrdesc(id, buf);
233 }
234
usbclass_setup(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev,FAR const struct usb_device_request * ctrl,FAR uint8_t * dataout,size_t outlen)235 static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
236 FAR struct usbdev_s *dev,
237 FAR const struct usb_device_request *ctrl,
238 FAR uint8_t *dataout, size_t outlen)
239 {
240 FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
241 FAR struct usbdev_req_s *ctrlreq = priv->ctrlreq;
242 uint16_t value;
243 uint16_t len;
244 int ret = -EOPNOTSUPP;
245
246 (void)dataout;
247 (void)outlen;
248
249 value = UGETW(ctrl->wValue);
250 len = UGETW(ctrl->wLength);
251
252 if ((ctrl->bmRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
253 {
254 if (ctrl->bRequest == USB_REQ_SET_CONFIGURATION)
255 {
256 usbdev_dfu_set_config();
257 return 0; /* Composite driver will send the reply */
258 }
259 else if (ctrl->bRequest == USB_REQ_SET_INTERFACE)
260 {
261 /* Only one alternate setting (0) is supported */
262
263 if (value == 0)
264 {
265 ret = 0;
266 }
267 }
268 else if (ctrl->bRequest == USB_REQ_GET_INTERFACE)
269 {
270 *(FAR uint8_t *)ctrlreq->buf = 0;
271 ret = 1;
272 }
273 }
274 else if ((ctrl->bmRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
275 {
276 ret = usbdev_dfu_class_requests(dev, ctrl, ctrlreq);
277 }
278
279 /* Respond to the setup command if data was returned. On an error return
280 * value (ret < 0), the USB driver will stall.
281 */
282
283 if (ret >= 0)
284 {
285 ctrlreq->len = (len < ret) ? len : (uint32_t)ret;
286 ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT;
287 ret = EP_SUBMIT(dev->ep0, ctrlreq);
288 if (ret < 0)
289 {
290 usb_err("req submit failed!\r\n");
291 ctrlreq->result = OK;
292 }
293 }
294
295 return ret;
296 }
297
usbclass_bind(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)298 static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
299 FAR struct usbdev_s *dev)
300 {
301 FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
302 struct composite_dev_s *cdev = dev->ep0->priv;
303
304 priv->ctrlreq = cdev->ctrlreq;
305 if (priv->ctrlreq == NULL)
306 {
307 usb_err("Ctrlreq is NULL!\r\n");
308 return -ENOMEM;
309 }
310
311 priv->ctrlreq->callback = usbclass_ep0incomplete;
312
313 return OK;
314 }
315
usbclass_unbind(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)316 static int usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
317 FAR struct usbdev_s *dev)
318 {
319 FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
320
321 (void)dev;
322
323 if (usb_dfu_running())
324 {
325 PRINT_ERR("%s fail, dfu busy\n", __FUNCTION__);
326 return -1;
327 }
328
329 if (priv->ctrlreq != NULL)
330 {
331 priv->ctrlreq = NULL;
332 }
333 usbdev_dfu_init();
334
335 return 0;
336 }
337
usbclass_disconnect(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)338 static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
339 FAR struct usbdev_s *dev)
340 {
341 (void)driver;
342 (void)dev;
343
344 usbdev_dfu_transaction_cleanup();
345 dprintf("reset config\n");
346 }
347
348 /****************************************************************************
349 * Name: usbclass_classobject
350 *
351 * Description:
352 * Allocate memory for the RNDIS driver class object
353 *
354 * Returned Value:
355 * 0 on success, negative error code on failure.
356 *
357 ****************************************************************************/
358
usbclass_classobject(int minor,FAR struct usbdev_devinfo_s * devinfo,FAR struct usbdevclass_driver_s ** classdev)359 static int usbclass_classobject(int minor,
360 FAR struct usbdev_devinfo_s *devinfo,
361 FAR struct usbdevclass_driver_s **classdev)
362 {
363 FAR struct dfu_driver_s *alloc;
364
365 (void)minor;
366 (void)devinfo;
367
368 alloc = malloc(sizeof(struct dfu_driver_s));
369 if (alloc == NULL)
370 {
371 return -ENOMEM;
372 }
373
374 *classdev = &alloc->drvr;
375
376 alloc->drvr.speed = USB_SPEED_FULL;
377 alloc->drvr.ops = &g_dfu_driverops;
378
379 usbdev_dfu_dev_init();
380
381 return OK;
382 }
383
384 /****************************************************************************
385 * Name: usbclass_uninitialize
386 *
387 * Description:
388 * Free allocated memory
389 *
390 * Returned Value:
391 * 0 on success, negative error code on failure.
392 *
393 ****************************************************************************/
394
usbclass_uninitialize(FAR struct usbdevclass_driver_s * classdev)395 static void usbclass_uninitialize(FAR struct usbdevclass_driver_s *classdev)
396 {
397 usbdev_dfu_dev_deinit();
398 free(classdev);
399 }
400
401 /****************************************************************************
402 * Public Functions
403 ****************************************************************************/
404
usbdev_dfu_get_composite_devdesc(struct composite_devdesc_s * dev)405 void usbdev_dfu_get_composite_devdesc(struct composite_devdesc_s *dev)
406 {
407 (void)memset_s(dev, sizeof(struct composite_devdesc_s), 0, sizeof(struct composite_devdesc_s));
408
409 dev->mkdevdesc = usbclass_mkdevdesc;
410 dev->mkconfdesc = usbclass_mkcfgdesc;
411 dev->mkstrdesc = usbclass_mkstrdesc;
412 dev->classobject = usbclass_classobject;
413 dev->uninitialize = usbclass_uninitialize;
414 dev->nconfigs = 1;
415 dev->configid = 0;
416 dev->cfgdescsize = (int)sizeof(g_dfu_cfgdesc);
417 dev->devinfo.ninterfaces = 1;
418 dev->devinfo.nstrings = 1;
419 dev->devinfo.nendpoints = 0;
420 }
421