1 /*!
2     \file    dfu_core.c
3     \brief   USB DFU device class core functions
4 
5     \version 2020-08-04, V1.1.0, firmware for GD32VF103
6     \version 2020-12-11, V1.1.1, firmware for GD32VF103
7 */
8 
9 /*
10     Copyright (c) 2020, GigaDevice Semiconductor Inc.
11 
12     Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14 
15     1. Redistributions of source code must retain the above copyright notice, this
16        list of conditions and the following disclaimer.
17     2. Redistributions in binary form must reproduce the above copyright notice,
18        this list of conditions and the following disclaimer in the documentation
19        and/or other materials provided with the distribution.
20     3. Neither the name of the copyright holder nor the names of its contributors
21        may be used to endorse or promote products derived from this software without
22        specific prior written permission.
23 
24     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGE.
34 */
35 
36 #include "dfu_core.h"
37 #include "drv_usb_hw.h"
38 #include "dfu_mal.h"
39 #include "flash_if.h"
40 #include <string.h>
41 
42 #define USBD_VID                     0x28E9U
43 #define USBD_PID                     0x0189U
44 
45 /* local function prototypes ('static') */
46 static uint8_t dfu_init(usb_dev *udev, uint8_t config_index);
47 static uint8_t dfu_deinit(usb_dev *udev, uint8_t config_index);
48 static uint8_t dfu_req_handler(usb_dev *udev, usb_req *req);
49 static uint8_t dfu_ctlx_in(usb_dev *udev);
50 static void dfu_detach(usb_dev *udev, usb_req *req);
51 static void dfu_dnload(usb_dev *udev, usb_req *req);
52 static void dfu_upload(usb_dev *udev, usb_req *req);
53 static void dfu_getstatus(usb_dev *udev, usb_req *req);
54 static void dfu_clrstatus(usb_dev *udev, usb_req *req);
55 static void dfu_getstate(usb_dev *udev, usb_req *req);
56 static void dfu_abort(usb_dev *udev, usb_req *req);
57 static void dfu_mode_leave(usb_dev *udev);
58 static uint8_t dfu_getstatus_complete (usb_dev *udev);
59 
60 static void (*dfu_request_process[])(usb_dev *udev, usb_req *req) =
61 {
62     [DFU_DETACH]    = dfu_detach,
63     [DFU_DNLOAD]    = dfu_dnload,
64     [DFU_UPLOAD]    = dfu_upload,
65     [DFU_GETSTATUS] = dfu_getstatus,
66     [DFU_CLRSTATUS] = dfu_clrstatus,
67     [DFU_GETSTATE]  = dfu_getstate,
68     [DFU_ABORT]     = dfu_abort
69 };
70 
71 /* note:it should use the c99 standard when compiling the below codes */
72 /* USB standard device descriptor */
73 const usb_desc_dev dfu_dev_desc =
74 {
75     .header =
76      {
77          .bLength          = USB_DEV_DESC_LEN,
78          .bDescriptorType  = USB_DESCTYPE_DEV
79      },
80     .bcdUSB                = 0x0200U,
81     .bDeviceClass          = 0x00U,
82     .bDeviceSubClass       = 0x00U,
83     .bDeviceProtocol       = 0x00U,
84     .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
85     .idVendor              = USBD_VID,
86     .idProduct             = USBD_PID,
87     .bcdDevice             = 0x0100U,
88     .iManufacturer         = STR_IDX_MFC,
89     .iProduct              = STR_IDX_PRODUCT,
90     .iSerialNumber         = STR_IDX_SERIAL,
91     .bNumberConfigurations = USBD_CFG_MAX_NUM
92 };
93 
94 /* USB device configuration descriptor */
95 const usb_dfu_desc_config_set dfu_config_desc =
96 {
97     .config =
98     {
99         .header =
100          {
101              .bLength         = sizeof(usb_desc_config),
102              .bDescriptorType = USB_DESCTYPE_CONFIG
103          },
104         .wTotalLength         = USB_DFU_CONFIG_DESC_SIZE,
105         .bNumInterfaces       = 0x01U,
106         .bConfigurationValue  = 0x01U,
107         .iConfiguration       = 0x04U,
108         .bmAttributes         = 0x80U,
109         .bMaxPower            = 0x32U
110     },
111 
112     .dfu_itf =
113     {
114         .header =
115          {
116              .bLength         = sizeof(usb_desc_itf),
117              .bDescriptorType = USB_DESCTYPE_ITF
118          },
119         .bInterfaceNumber     = 0x00U,
120         .bAlternateSetting    = 0x00U,
121         .bNumEndpoints        = 0x00U,
122         .bInterfaceClass      = USB_DFU_CLASS,
123         .bInterfaceSubClass   = USB_DFU_SUBCLASS_UPGRADE,
124         .bInterfaceProtocol   = USB_DFU_PROTOCL_DFU,
125         .iInterface           = 0x05U
126     },
127 
128     .dfu_func =
129     {
130         .header =
131          {
132             .bLength          = sizeof(usb_desc_dfu_func),
133             .bDescriptorType  = DFU_DESC_TYPE
134          },
135         .bmAttributes         = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_WILL_DETACH,
136         .wDetachTimeOut       = 0x00FFU,
137         .wTransferSize        = TRANSFER_SIZE,
138         .bcdDFUVersion        = 0x011AU,
139     },
140 };
141 
142 /* USB language ID Descriptor */
143 static const usb_desc_LANGID usbd_language_id_desc =
144 {
145     .header = {
146          .bLength         = sizeof(usb_desc_LANGID),
147          .bDescriptorType = USB_DESCTYPE_STR
148      },
149     .wLANGID              = ENG_LANGID
150 };
151 
152 /* USB manufacture string */
153 static const usb_desc_str manufacturer_string =
154 {
155     .header =
156      {
157          .bLength         = USB_STRING_LEN(10U),
158          .bDescriptorType = USB_DESCTYPE_STR,
159      },
160     .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
161 };
162 
163 /* USB product string */
164 static const usb_desc_str product_string =
165 {
166     .header =
167      {
168          .bLength         = USB_STRING_LEN(12U),
169          .bDescriptorType = USB_DESCTYPE_STR,
170      },
171     .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'D', 'F', 'U'}
172 };
173 
174 /* USBD serial string */
175 static usb_desc_str serial_string =
176 {
177     .header =
178      {
179          .bLength         = USB_STRING_LEN(2U),
180          .bDescriptorType = USB_DESCTYPE_STR,
181      }
182 };
183 
184 /* USB configure string */
185 static const usb_desc_str config_string =
186 {
187     .header =
188      {
189          .bLength         = USB_STRING_LEN(15U),
190          .bDescriptorType = USB_DESCTYPE_STR,
191      },
192     .unicode_string = {'G', 'D', '3', '2', ' ', 'U', 'S', 'B', ' ', 'C', 'O', 'N', 'F', 'I', 'G'}
193 };
194 
195 static const usb_desc_str interface_string =
196 {
197     .header =
198      {
199          .bLength         = USB_STRING_LEN(44U),
200          .bDescriptorType = USB_DESCTYPE_STR,
201      },
202     .unicode_string = {'@', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'F', 'l', 'a', 's', 'h', ' ', '/', '0', 'x', '0', '8', '0', '0',
203                        '0', '0', '0', '0', '/', '1', '6', '*', '0', '0', '1', 'K', 'a', ',', '4', '8', '*', '0', '0', '1', 'K', 'g'}
204 };
205 
206 void *const usbd_dfu_strings[] =
207 {
208     [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
209     [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
210     [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
211     [STR_IDX_SERIAL]  = (uint8_t *)&serial_string,
212     [STR_IDX_CONFIG]  = (uint8_t *)&config_string,
213     [STR_IDX_ITF]     = (uint8_t *)&interface_string
214 };
215 
216 usb_desc dfu_desc = {
217     .dev_desc    = (uint8_t *)&dfu_dev_desc,
218     .config_desc = (uint8_t *)&dfu_config_desc,
219     .strings     = usbd_dfu_strings
220 };
221 
222 usb_class_core dfu_class = {
223     .init            = dfu_init,
224     .deinit          = dfu_deinit,
225     .req_proc        = dfu_req_handler,
226     .ctlx_in         = dfu_ctlx_in
227 };
228 
229 /*!
230     \brief      initialize the DFU device
231     \param[in]  udev: pointer to USB device instance
232     \param[in]  config_index: configuration index
233     \param[out] none
234     \retval     USB device operation status
235 */
dfu_init(usb_dev * udev,uint8_t config_index)236 static uint8_t dfu_init (usb_dev *udev, uint8_t config_index)
237 {
238     static usbd_dfu_handler dfu_handler;
239 
240     /* unlock the internal flash */
241     dfu_mal_init();
242 
243     memset((void *)&dfu_handler, 0, sizeof(usbd_dfu_handler));
244 
245     dfu_handler.base_addr = APP_LOADED_ADDR;
246     dfu_handler.manifest_state = MANIFEST_COMPLETE;
247     dfu_handler.bState = STATE_DFU_IDLE;
248     dfu_handler.bStatus = STATUS_OK;
249 
250     udev->dev.class_data[USBD_DFU_INTERFACE] = (void *)&dfu_handler;
251 
252     return USBD_OK;
253 }
254 
255 /*!
256     \brief      de-initialize the DFU device
257     \param[in]  udev: pointer to USB device instance
258     \param[in]  config_index: configuration index
259     \param[out] none
260     \retval     USB device operation status
261 */
dfu_deinit(usb_dev * udev,uint8_t config_index)262 static uint8_t dfu_deinit (usb_dev *udev, uint8_t config_index)
263 {
264     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
265 
266     /* restore device default state */
267     memset(udev->dev.class_data[USBD_DFU_INTERFACE], 0, sizeof(usbd_dfu_handler));
268 
269     dfu->bState = STATE_DFU_IDLE;
270     dfu->bStatus = STATUS_OK;
271 
272     /* lock the internal flash */
273     dfu_mal_deinit();
274 
275     return USBD_OK;
276 }
277 
278 /*!
279     \brief      handle the DFU class-specific requests
280     \param[in]  udev: pointer to USB device instance
281     \param[in]  req: device class-specific request
282     \param[out] none
283     \retval     USB device operation status
284 */
dfu_req_handler(usb_dev * udev,usb_req * req)285 static uint8_t dfu_req_handler (usb_dev *udev, usb_req *req)
286 {
287     if (req->bRequest < DFU_REQ_MAX) {
288         dfu_request_process[req->bRequest](udev, req);
289     } else {
290         return USBD_FAIL;
291     }
292 
293     return USBD_OK;
294 }
295 
296 /*!
297     \brief      handle data Stage
298     \param[in]  udev: pointer to USB device instance
299     \param[in]  ep_num: the endpoint number
300     \param[out] none
301     \retval     USB device operation status
302 */
dfu_ctlx_in(usb_dev * udev)303 static uint8_t dfu_ctlx_in (usb_dev *udev)
304 {
305     dfu_getstatus_complete(udev);
306 
307     return USBD_OK;
308 }
309 
310 /*!
311     \brief      leave DFU mode and reset device to jump to user loaded code
312     \param[in]  udev: pointer to USB device instance
313     \param[out] none
314     \retval     none
315 */
dfu_mode_leave(usb_dev * udev)316 static void dfu_mode_leave (usb_dev *udev)
317 {
318     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
319 
320     dfu->manifest_state = MANIFEST_COMPLETE;
321 
322     if (dfu_config_desc.dfu_func.bmAttributes & 0x04U) {
323         dfu->bState = STATE_DFU_MANIFEST_SYNC;
324     } else {
325         dfu->bState = STATE_DFU_MANIFEST_WAIT_RESET;
326 
327         /* lock the internal flash */
328         dfu_mal_deinit();
329 
330         /* generate system reset to allow jumping to the user code */
331         eclic_system_reset();
332     }
333 }
334 
335 /*!
336     \brief      handle data IN stage in control endpoint 0
337     \param[in]  udev: pointer to usb device instance
338     \param[out] none
339     \retval     usb device operation status
340   */
dfu_getstatus_complete(usb_dev * udev)341 static uint8_t  dfu_getstatus_complete (usb_dev *udev)
342 {
343     uint32_t addr;
344 
345     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
346 
347     if (STATE_DFU_DNBUSY == dfu->bState) {
348         /* decode the special command */
349         if (0U == dfu->block_num) {
350             if (1U == dfu->data_len){
351                 if (GET_COMMANDS == dfu->buf[0]) {
352                     /* no operation */
353                 }
354             } else if (5U == dfu->data_len) {
355                 if (SET_ADDRESS_POINTER == dfu->buf[0]) {
356                     /* set flash operation address */
357                     dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
358                 } else if (ERASE == dfu->buf[0]) {
359                     dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
360 
361                     dfu_mal_erase(dfu->base_addr);
362                 } else {
363                     /* no operation */
364                 }
365             } else {
366                 /* no operation */
367             }
368         } else if (dfu->block_num > 1U) {  /* regular download command */
369             /* decode the required address */
370             addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
371 
372             dfu_mal_write (dfu->buf, addr, dfu->data_len);
373 
374             dfu->block_num = 0U;
375         } else {
376             /* no operation */
377         }
378 
379         dfu->data_len = 0U;
380 
381         /* update the device state and poll timeout */
382         dfu->bState = STATE_DFU_DNLOAD_SYNC;
383 
384         return USBD_OK;
385     } else if (dfu->bState == STATE_DFU_MANIFEST) { /* manifestation in progress */
386         /* start leaving DFU mode */
387         dfu_mode_leave(udev);
388     } else {
389         /* no operation */
390     }
391 
392     return USBD_OK;
393 }
394 
395 /*!
396     \brief      handle the DFU_DETACH request
397     \param[in]  udev: pointer to usb device instance
398     \param[in]  req: DFU class request
399     \param[out] none
400     \retval     none.
401 */
dfu_detach(usb_dev * udev,usb_req * req)402 static void dfu_detach(usb_dev *udev, usb_req *req)
403 {
404     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
405 
406     switch (dfu->bState) {
407     case STATE_DFU_IDLE:
408     case STATE_DFU_DNLOAD_SYNC:
409     case STATE_DFU_DNLOAD_IDLE:
410     case STATE_DFU_MANIFEST_SYNC:
411     case STATE_DFU_UPLOAD_IDLE:
412         dfu->bStatus = STATUS_OK;
413         dfu->bState = STATE_DFU_IDLE;
414         dfu->iString = 0U; /* iString */
415 
416         dfu->block_num = 0U;
417         dfu->data_len = 0U;
418         break;
419 
420     default:
421         break;
422     }
423 
424     /* check the detach capability in the DFU functional descriptor */
425     if (dfu_config_desc.dfu_func.wDetachTimeOut & DFU_DETACH_MASK) {
426         usbd_disconnect (udev);
427 
428         usbd_connect (udev);
429     } else {
430         /* wait for the period of time specified in detach request */
431         usb_mdelay (4U);
432     }
433 }
434 
435 /*!
436     \brief      handle the DFU_DNLOAD request
437     \param[in]  udev: pointer to usb device instance
438     \param[in]  req: DFU class request
439     \param[out] none
440     \retval     none
441 */
dfu_dnload(usb_dev * udev,usb_req * req)442 static void dfu_dnload(usb_dev *udev, usb_req *req)
443 {
444     usb_transc *transc = &udev->dev.transc_out[0];
445     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
446 
447     switch (dfu->bState) {
448     case STATE_DFU_IDLE:
449     case STATE_DFU_DNLOAD_IDLE:
450         if (req->wLength > 0U) {
451             /* update the global length and block number */
452             dfu->block_num = req->wValue;
453             dfu->data_len = req->wLength;
454 
455             dfu->bState = STATE_DFU_DNLOAD_SYNC;
456 
457             transc->remain_len = dfu->data_len;
458             transc->xfer_buf = dfu->buf;
459         } else {
460             dfu->manifest_state = MANIFEST_IN_PROGRESS;
461             dfu->bState = STATE_DFU_MANIFEST_SYNC;
462         }
463         break;
464 
465     default:
466         break;
467     }
468 }
469 
470 /*!
471     \brief      handles the DFU UPLOAD request.
472     \param[in]  udev: pointer to usb device instance
473     \param[in]  req: DFU class request
474     \param[out] none
475     \retval     none
476 */
dfu_upload(usb_dev * udev,usb_req * req)477 static void  dfu_upload (usb_dev *udev, usb_req *req)
478 {
479     uint8_t *phy_addr = NULL;
480     uint32_t addr = 0U;
481     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
482 
483     usb_transc *transc = &udev->dev.transc_in[0];
484 
485     if(req->wLength <= 0U) {
486         dfu->bState = STATE_DFU_IDLE;
487         return;
488     }
489 
490     switch (dfu->bState) {
491     case STATE_DFU_IDLE:
492     case STATE_DFU_UPLOAD_IDLE:
493         /* update the global length and block number */
494         dfu->block_num = req->wValue;
495         dfu->data_len = req->wLength;
496 
497         /* DFU get command */
498         if (0U == dfu->block_num) {
499             /* update the state machine */
500             dfu->bState = (dfu->data_len > 3U) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
501 
502             /* store the values of all supported commands */
503             dfu->buf[0] = GET_COMMANDS;
504             dfu->buf[1] = SET_ADDRESS_POINTER;
505             dfu->buf[2] = ERASE;
506 
507             /* send the status data over EP0 */
508             transc->xfer_buf = &(dfu->buf[0]);
509             transc->remain_len = 3U;
510         } else if (dfu->block_num > 1U) {
511             dfu->bState = STATE_DFU_UPLOAD_IDLE;
512 
513             /* change is accelerated */
514             addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
515 
516             /* return the physical address where data are stored */
517             phy_addr = dfu_mal_read (dfu->buf, addr, dfu->data_len);
518 
519             /* send the status data over EP0 */
520             transc->xfer_buf = phy_addr;
521             transc->remain_len = dfu->data_len;
522         } else {
523             dfu->bState = STATUS_ERR_STALLEDPKT;
524         }
525         break;
526 
527     default:
528         dfu->data_len = 0U;
529         dfu->block_num = 0U;
530         break;
531     }
532 }
533 
534 /*!
535     \brief      handle the DFU_GETSTATUS request
536     \param[in]  udev: pointer to usb device instance
537     \param[in]  req: DFU class request
538     \param[out] none
539     \retval     none
540 */
dfu_getstatus(usb_dev * udev,usb_req * req)541 static void  dfu_getstatus (usb_dev *udev, usb_req *req)
542 {
543     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
544 
545     usb_transc *transc = &udev->dev.transc_in[0];
546 
547     switch (dfu->bState) {
548     case STATE_DFU_DNLOAD_SYNC:
549         if (0U != dfu->data_len) {
550             dfu->bState = STATE_DFU_DNBUSY;
551 
552             if (0U == dfu->block_num) {
553                 if (ERASE == dfu->buf[0]) {
554                     dfu_mal_getstatus (dfu->base_addr, CMD_ERASE, (uint8_t *)&dfu->bwPollTimeout0);
555                 } else {
556                     dfu_mal_getstatus (dfu->base_addr, CMD_WRITE, (uint8_t *)&dfu->bwPollTimeout0);
557                 }
558             }
559         } else {
560             dfu->bState = STATE_DFU_DNLOAD_IDLE;
561         }
562         break;
563 
564     case STATE_DFU_MANIFEST_SYNC:
565         if (MANIFEST_IN_PROGRESS == dfu->manifest_state) {
566             dfu->bState = STATE_DFU_MANIFEST;
567             dfu->bwPollTimeout0 = 1U;
568         } else if ((MANIFEST_COMPLETE == dfu->manifest_state) && \
569             (dfu_config_desc.dfu_func.bmAttributes & 0x04U)){
570             dfu->bState = STATE_DFU_IDLE;
571             dfu->bwPollTimeout0 = 0U;
572         } else {
573             /* no operation */
574         }
575         break;
576 
577     default:
578         break;
579     }
580 
581     /* send the status data of DFU interface to host over EP0 */
582     transc->xfer_buf = (uint8_t *)&(dfu->bStatus);
583     transc->remain_len = 6U;
584 }
585 
586 /*!
587     \brief      handle the DFU_CLRSTATUS request
588     \param      udev: pointer to usb device instance
589     \param[out] none
590     \retval     none
591 */
dfu_clrstatus(usb_dev * udev,usb_req * req)592 static void  dfu_clrstatus (usb_dev *udev, usb_req *req)
593 {
594     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
595 
596     if (STATE_DFU_ERROR == dfu->bState) {
597         dfu->bStatus = STATUS_OK;
598         dfu->bState = STATE_DFU_IDLE;
599     } else {
600         /* state error */
601         dfu->bStatus = STATUS_ERR_UNKNOWN;
602         dfu->bState = STATE_DFU_ERROR;
603     }
604 
605     dfu->iString = 0U; /* iString: index = 0 */
606 }
607 
608 /*!
609     \brief      handle the DFU_GETSTATE request
610     \param[in]  udev: pointer to usb device instance
611     \param[out] none
612     \retval     none
613 */
dfu_getstate(usb_dev * udev,usb_req * req)614 static void  dfu_getstate (usb_dev *udev, usb_req *req)
615 {
616     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
617 
618     usb_transc *transc = &udev->dev.transc_in[0];
619 
620     /* send the current state of the DFU interface to host */
621     transc->xfer_buf = &(dfu->bState);
622     transc->remain_len = 1U;
623 }
624 
625 /*!
626     \brief      handle the DFU_ABORT request
627     \param[in]  udev: pointer to usb device instance
628     \param[out] none
629     \retval     none
630 */
dfu_abort(usb_dev * udev,usb_req * req)631 static void dfu_abort (usb_dev *udev, usb_req *req)
632 {
633     usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
634 
635     switch (dfu->bState){
636     case STATE_DFU_IDLE:
637     case STATE_DFU_DNLOAD_SYNC:
638     case STATE_DFU_DNLOAD_IDLE:
639     case STATE_DFU_MANIFEST_SYNC:
640     case STATE_DFU_UPLOAD_IDLE:
641         dfu->bStatus = STATUS_OK;
642         dfu->bState = STATE_DFU_IDLE;
643         dfu->iString = 0U; /* iString: index = 0 */
644 
645         dfu->block_num = 0U;
646         dfu->data_len = 0U;
647         break;
648 
649     default:
650         break;
651     }
652 }
653