• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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