1 /**
2   ******************************************************************************
3   * @file    usbd_dfu.c
4   * @author  MCD Application Team
5   * @version V2.4.2
6   * @date    11-December-2015
7   * @brief   This file provides the DFU core functions.
8   *
9   * @verbatim
10   *
11   *          ===================================================================
12   *                                DFU Class Driver Description
13   *          ===================================================================
14   *           This driver manages the DFU class V1.1 following the "Device Class Specification for
15   *           Device Firmware Upgrade Version 1.1 Aug 5, 2004".
16   *           This driver implements the following aspects of the specification:
17   *             - Device descriptor management
18   *             - Configuration descriptor management
19   *             - Enumeration as DFU device (in DFU mode only)
20   *             - Requests management (supporting ST DFU sub-protocol)
21   *             - Memory operations management (Download/Upload/Erase/Detach/GetState/GetStatus)
22   *             - DFU state machine implementation.
23   *
24   *           @note
25   *            ST DFU sub-protocol is compliant with DFU protocol and use sub-requests to manage
26   *            memory addressing, commands processing, specific memories operations (ie. Erase) ...
27   *            As required by the DFU specification, only endpoint 0 is used in this application.
28   *            Other endpoints and functions may be added to the application (ie. DFU ...)
29   *
30   *           These aspects may be enriched or modified for a specific user application.
31   *
32   *           This driver doesn't implement the following aspects of the specification
33   *           (but it is possible to manage these features with some modifications on this driver):
34   *             - Manifestation Tolerant mode
35   *
36   *  @endverbatim
37   *
38   ******************************************************************************
39   * @attention
40   *
41   * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
42   *
43   * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
44   * You may not use this file except in compliance with the License.
45   * You may obtain a copy of the License at:
46   *
47   *        http://www.st.com/software_license_agreement_liberty_v2
48   *
49   * Unless required by applicable law or agreed to in writing, software
50   * distributed under the License is distributed on an "AS IS" BASIS,
51   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
52   * See the License for the specific language governing permissions and
53   * limitations under the License.
54   *
55   ******************************************************************************
56   */
57 
58 /* Includes ------------------------------------------------------------------*/
59 #include "usbd_dfu.h"
60 #include "usbd_desc.h"
61 #include "usbd_ctlreq.h"
62 
63 
64 /** @addtogroup STM32_USB_DEVICE_LIBRARY
65   * @{
66   */
67 
68 
69 /** @defgroup USBD_DFU
70   * @brief usbd core module
71   * @{
72   */
73 
74 /** @defgroup USBD_DFU_Private_TypesDefinitions
75   * @{
76   */
77 /**
78   * @}
79   */
80 
81 
82 /** @defgroup USBD_DFU_Private_Defines
83   * @{
84   */
85 
86 /**
87   * @}
88   */
89 
90 
91 /** @defgroup USBD_DFU_Private_Macros
92   * @{
93   */
94 #define DFU_SAMPLE_FREQ(frq)      (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
95 
96 #define DFU_PACKET_SZE(frq)          (uint8_t)(((frq * 2 * 2)/1000) & 0xFF), \
97                                        (uint8_t)((((frq * 2 * 2)/1000) >> 8) & 0xFF)
98 
99 /**
100   * @}
101   */
102 
103 
104 
105 
106 /** @defgroup USBD_DFU_Private_FunctionPrototypes
107   * @{
108   */
109 
110 
111 static uint8_t  USBD_DFU_Init (USBD_HandleTypeDef *pdev,
112                                uint8_t cfgidx);
113 
114 static uint8_t  USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
115                                  uint8_t cfgidx);
116 
117 static uint8_t  USBD_DFU_Setup (USBD_HandleTypeDef *pdev,
118                                 USBD_SetupReqTypedef *req);
119 
120 static uint8_t  *USBD_DFU_GetCfgDesc (uint16_t *length);
121 
122 static uint8_t  *USBD_DFU_GetDeviceQualifierDesc (uint16_t *length);
123 
124 static uint8_t  USBD_DFU_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
125 
126 static uint8_t  USBD_DFU_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
127 
128 static uint8_t  USBD_DFU_EP0_RxReady (USBD_HandleTypeDef *pdev);
129 
130 static uint8_t  USBD_DFU_EP0_TxReady (USBD_HandleTypeDef *pdev);
131 
132 static uint8_t  USBD_DFU_SOF (USBD_HandleTypeDef *pdev);
133 
134 static uint8_t  USBD_DFU_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum);
135 
136 static uint8_t  USBD_DFU_IsoOutIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum);
137 
138 #if (USBD_SUPPORT_USER_STRING == 1)
139 static uint8_t* USBD_DFU_GetUsrStringDesc ( USBD_HandleTypeDef *pdev, uint8_t index , uint16_t *length);
140 #endif
141 
142 static void DFU_Detach    (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
143 
144 static void DFU_Download  (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
145 
146 static void DFU_Upload    (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
147 
148 static void DFU_GetStatus (USBD_HandleTypeDef *pdev);
149 
150 static void DFU_ClearStatus (USBD_HandleTypeDef *pdev);
151 
152 static void DFU_GetState  (USBD_HandleTypeDef *pdev);
153 
154 static void DFU_Abort     (USBD_HandleTypeDef *pdev);
155 
156 static void DFU_Leave  (USBD_HandleTypeDef *pdev);
157 
158 
159 /**
160   * @}
161   */
162 
163 /** @defgroup USBD_DFU_Private_Variables
164   * @{
165   */
166 
167 USBD_ClassTypeDef  USBD_DFU =
168 {
169   USBD_DFU_Init,
170   USBD_DFU_DeInit,
171   USBD_DFU_Setup,
172   USBD_DFU_EP0_TxReady,
173   USBD_DFU_EP0_RxReady,
174   USBD_DFU_DataIn,
175   USBD_DFU_DataOut,
176   USBD_DFU_SOF,
177   USBD_DFU_IsoINIncomplete,
178   USBD_DFU_IsoOutIncomplete,
179   USBD_DFU_GetCfgDesc,
180   USBD_DFU_GetCfgDesc,
181   USBD_DFU_GetCfgDesc,
182   USBD_DFU_GetDeviceQualifierDesc,
183 #if (USBD_SUPPORT_USER_STRING == 1)
184   USBD_DFU_GetUsrStringDesc
185 #endif
186 };
187 
188 /* USB DFU device Configuration Descriptor */
189 __ALIGN_BEGIN static uint8_t USBD_DFU_CfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END =
190 {
191   0x09, /* bLength: Configuation Descriptor size */
192   USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
193   USB_DFU_CONFIG_DESC_SIZ,
194   /* wTotalLength: Bytes returned */
195   0x00,
196   0x01,         /*bNumInterfaces: 1 interface*/
197   0x01,         /*bConfigurationValue: Configuration value*/
198   0x02,         /*iConfiguration: Index of string descriptor describing the configuration*/
199   0xC0,         /*bmAttributes: bus powered and Supprts Remote Wakeup */
200   0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
201   /* 09 */
202 
203   /**********  Descriptor of DFU interface 0 Alternate setting 0 **************/
204   USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
205 
206 #if (USBD_DFU_MAX_ITF_NUM > 1)
207   /**********  Descriptor of DFU interface 0 Alternate setting 1 **************/
208   USBD_DFU_IF_DESC(1),
209 #endif /* (USBD_DFU_MAX_ITF_NUM > 1) */
210 
211 #if (USBD_DFU_MAX_ITF_NUM > 2)
212   /**********  Descriptor of DFU interface 0 Alternate setting 2 **************/
213   USBD_DFU_IF_DESC(2),
214 #endif /* (USBD_DFU_MAX_ITF_NUM > 2) */
215 
216 #if (USBD_DFU_MAX_ITF_NUM > 3)
217   /**********  Descriptor of DFU interface 0 Alternate setting 3 **************/
218   USBD_DFU_IF_DESC(3),
219 #endif /* (USBD_DFU_MAX_ITF_NUM > 3) */
220 
221 #if (USBD_DFU_MAX_ITF_NUM > 4)
222   /**********  Descriptor of DFU interface 0 Alternate setting 4 **************/
223   USBD_DFU_IF_DESC(4),
224 #endif /* (USBD_DFU_MAX_ITF_NUM > 4) */
225 
226 #if (USBD_DFU_MAX_ITF_NUM > 5)
227   /**********  Descriptor of DFU interface 0 Alternate setting 5 **************/
228   USBD_DFU_IF_DESC(5),
229 #endif /* (USBD_DFU_MAX_ITF_NUM > 5) */
230 
231 #if (USBD_DFU_MAX_ITF_NUM > 6)
232 #error "ERROR: usbd_dfu_core.c: Modify the file to support more descriptors!"
233 #endif /* (USBD_DFU_MAX_ITF_NUM > 6) */
234 
235   /******************** DFU Functional Descriptor********************/
236   0x09,   /*blength = 9 Bytes*/
237   DFU_DESCRIPTOR_TYPE,   /* DFU Functional Descriptor*/
238   0x0B,   /*bmAttribute
239                 bitCanDnload             = 1      (bit 0)
240                 bitCanUpload             = 1      (bit 1)
241                 bitManifestationTolerant = 0      (bit 2)
242                 bitWillDetach            = 1      (bit 3)
243                 Reserved                          (bit4-6)
244                 bitAcceleratedST         = 0      (bit 7)*/
245   0xFF,   /*DetachTimeOut= 255 ms*/
246   0x00,
247   /*WARNING: In DMA mode the multiple MPS packets feature is still not supported
248    ==> In this case, when using DMA USBD_DFU_XFER_SIZE should be set to 64 in usbd_conf.h */
249   TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE),       /* TransferSize = 1024 Byte*/
250   0x1A,                                /* bcdDFUVersion*/
251   0x01
252   /***********************************************************/
253   /* 9*/
254 };
255 
256 /* USB Standard Device Descriptor */
257 __ALIGN_BEGIN static uint8_t USBD_DFU_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
258 {
259   USB_LEN_DEV_QUALIFIER_DESC,
260   USB_DESC_TYPE_DEVICE_QUALIFIER,
261   0x00,
262   0x02,
263   0x00,
264   0x00,
265   0x00,
266   0x40,
267   0x01,
268   0x00,
269 };
270 
271 /**
272   * @}
273   */
274 
275 /** @defgroup USBD_DFU_Private_Functions
276   * @{
277   */
278 
279 /**
280   * @brief  USBD_DFU_Init
281   *         Initialize the DFU interface
282   * @param  pdev: device instance
283   * @param  cfgidx: Configuration index
284   * @retval status
285   */
USBD_DFU_Init(USBD_HandleTypeDef * pdev,uint8_t cfgidx)286 static uint8_t  USBD_DFU_Init (USBD_HandleTypeDef *pdev,
287                                uint8_t cfgidx)
288 {
289   USBD_DFU_HandleTypeDef   *hdfu;
290 
291  /* Allocate Audio structure */
292   pdev->pClassData = USBD_malloc(sizeof (USBD_DFU_HandleTypeDef));
293 
294   if(pdev->pClassData == NULL)
295   {
296     return USBD_FAIL;
297   }
298   else
299   {
300     hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
301 
302     hdfu->alt_setting = 0;
303     hdfu->data_ptr = USBD_DFU_APP_DEFAULT_ADD;
304     hdfu->wblock_num = 0;
305     hdfu->wlength = 0;
306 
307     hdfu->manif_state = DFU_MANIFEST_COMPLETE;
308     hdfu->dev_state = DFU_STATE_IDLE;
309 
310     hdfu->dev_status[0] = DFU_ERROR_NONE;
311     hdfu->dev_status[1] = 0;
312     hdfu->dev_status[2] = 0;
313     hdfu->dev_status[3] = 0;
314     hdfu->dev_status[4] = DFU_STATE_IDLE;
315     hdfu->dev_status[5] = 0;
316 
317     /* Initialize Hardware layer */
318     if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Init() != USBD_OK)
319     {
320       return USBD_FAIL;
321     }
322   }
323   return USBD_OK;
324 }
325 
326 /**
327   * @brief  USBD_DFU_Init
328   *         De-Initialize the DFU layer
329   * @param  pdev: device instance
330   * @param  cfgidx: Configuration index
331   * @retval status
332   */
USBD_DFU_DeInit(USBD_HandleTypeDef * pdev,uint8_t cfgidx)333 static uint8_t  USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
334                                  uint8_t cfgidx)
335 {
336   USBD_DFU_HandleTypeDef   *hdfu;
337   hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
338 
339   hdfu->wblock_num = 0;
340   hdfu->wlength = 0;
341 
342   hdfu->dev_state = DFU_STATE_IDLE;
343   hdfu->dev_status[0] = DFU_ERROR_NONE;
344   hdfu->dev_status[4] = DFU_STATE_IDLE;
345 
346   /* DeInit  physical Interface components */
347   if(pdev->pClassData != NULL)
348   {
349     /* De-Initialize Hardware layer */
350     ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->DeInit();
351     USBD_free(pdev->pClassData);
352     pdev->pClassData = NULL;
353   }
354 
355   return USBD_OK;
356 }
357 
358 /**
359   * @brief  USBD_DFU_Setup
360   *         Handle the DFU specific requests
361   * @param  pdev: instance
362   * @param  req: usb requests
363   * @retval status
364   */
USBD_DFU_Setup(USBD_HandleTypeDef * pdev,USBD_SetupReqTypedef * req)365 static uint8_t  USBD_DFU_Setup (USBD_HandleTypeDef *pdev,
366                                 USBD_SetupReqTypedef *req)
367 {
368   uint8_t *pbuf = 0;
369   uint16_t len = 0;
370   uint8_t ret = USBD_OK;
371   USBD_DFU_HandleTypeDef   *hdfu;
372 
373   hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
374 
375   switch (req->bmRequest & USB_REQ_TYPE_MASK)
376   {
377   case USB_REQ_TYPE_CLASS :
378     switch (req->bRequest)
379     {
380     case DFU_DNLOAD:
381       DFU_Download(pdev, req);
382       break;
383 
384     case DFU_UPLOAD:
385       DFU_Upload(pdev, req);
386       break;
387 
388     case DFU_GETSTATUS:
389       DFU_GetStatus(pdev);
390       break;
391 
392     case DFU_CLRSTATUS:
393       DFU_ClearStatus(pdev);
394       break;
395 
396     case DFU_GETSTATE:
397       DFU_GetState(pdev);
398       break;
399 
400     case DFU_ABORT:
401       DFU_Abort(pdev);
402       break;
403 
404     case DFU_DETACH:
405       DFU_Detach(pdev, req);
406       break;
407 
408 
409     default:
410       USBD_CtlError (pdev, req);
411       ret = USBD_FAIL;
412     }
413     break;
414 
415   case USB_REQ_TYPE_STANDARD:
416     switch (req->bRequest)
417     {
418     case USB_REQ_GET_DESCRIPTOR:
419       if( (req->wValue >> 8) == DFU_DESCRIPTOR_TYPE)
420       {
421         pbuf = USBD_DFU_CfgDesc + (9 * (USBD_DFU_MAX_ITF_NUM + 1));
422         len = MIN(USB_DFU_DESC_SIZ , req->wLength);
423       }
424 
425       USBD_CtlSendData (pdev,
426                         pbuf,
427                         len);
428       break;
429 
430     case USB_REQ_GET_INTERFACE :
431       USBD_CtlSendData (pdev,
432                         (uint8_t *)&hdfu->alt_setting,
433                         1);
434       break;
435 
436     case USB_REQ_SET_INTERFACE :
437       if ((uint8_t)(req->wValue) < USBD_DFU_MAX_ITF_NUM)
438       {
439         hdfu->alt_setting = (uint8_t)(req->wValue);
440       }
441       else
442       {
443         /* Call the error management function (command will be nacked */
444         USBD_CtlError (pdev, req);
445         ret = USBD_FAIL;
446       }
447       break;
448 
449     default:
450       USBD_CtlError (pdev, req);
451       ret = USBD_FAIL;
452     }
453   }
454   return ret;
455 }
456 
457 
458 /**
459   * @brief  USBD_DFU_GetCfgDesc
460   *         return configuration descriptor
461   * @param  speed : current device speed
462   * @param  length : pointer data length
463   * @retval pointer to descriptor buffer
464   */
USBD_DFU_GetCfgDesc(uint16_t * length)465 static uint8_t  *USBD_DFU_GetCfgDesc (uint16_t *length)
466 {
467   *length = sizeof (USBD_DFU_CfgDesc);
468   return USBD_DFU_CfgDesc;
469 }
470 
471 /**
472   * @brief  USBD_DFU_DataIn
473   *         handle data IN Stage
474   * @param  pdev: device instance
475   * @param  epnum: endpoint index
476   * @retval status
477   */
USBD_DFU_DataIn(USBD_HandleTypeDef * pdev,uint8_t epnum)478 static uint8_t  USBD_DFU_DataIn (USBD_HandleTypeDef *pdev,
479                               uint8_t epnum)
480 {
481 
482   return USBD_OK;
483 }
484 
485 /**
486   * @brief  USBD_DFU_EP0_RxReady
487   *         handle EP0 Rx Ready event
488   * @param  pdev: device instance
489   * @retval status
490   */
USBD_DFU_EP0_RxReady(USBD_HandleTypeDef * pdev)491 static uint8_t  USBD_DFU_EP0_RxReady (USBD_HandleTypeDef *pdev)
492 {
493 
494   return USBD_OK;
495 }
496 /**
497   * @brief  USBD_DFU_EP0_TxReady
498   *         handle EP0 TRx Ready event
499   * @param  pdev: device instance
500   * @retval status
501   */
USBD_DFU_EP0_TxReady(USBD_HandleTypeDef * pdev)502 static uint8_t  USBD_DFU_EP0_TxReady (USBD_HandleTypeDef *pdev)
503 {
504  uint32_t addr;
505  USBD_SetupReqTypedef     req;
506  USBD_DFU_HandleTypeDef   *hdfu;
507 
508  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
509 
510   if (hdfu->dev_state == DFU_STATE_DNLOAD_BUSY)
511   {
512     /* Decode the Special Command*/
513     if (hdfu->wblock_num == 0)
514     {
515       if ((hdfu->buffer.d8[0] ==  DFU_CMD_GETCOMMANDS) && (hdfu->wlength == 1))
516       {
517 
518       }
519       else if  (( hdfu->buffer.d8[0] ==  DFU_CMD_SETADDRESSPOINTER ) && (hdfu->wlength == 5))
520       {
521         hdfu->data_ptr  = hdfu->buffer.d8[1];
522         hdfu->data_ptr += hdfu->buffer.d8[2] << 8;
523         hdfu->data_ptr += hdfu->buffer.d8[3] << 16;
524         hdfu->data_ptr += hdfu->buffer.d8[4] << 24;
525       }
526       else if (( hdfu->buffer.d8[0] ==  DFU_CMD_ERASE ) && (hdfu->wlength == 5))
527       {
528         hdfu->data_ptr  = hdfu->buffer.d8[1];
529         hdfu->data_ptr += hdfu->buffer.d8[2] << 8;
530         hdfu->data_ptr += hdfu->buffer.d8[3] << 16;
531         hdfu->data_ptr += hdfu->buffer.d8[4] << 24;
532 
533         if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Erase(hdfu->data_ptr) != USBD_OK)
534         {
535           return USBD_FAIL;
536         }
537       }
538       else
539       {
540         /* Reset the global length and block number */
541         hdfu->wlength = 0;
542         hdfu->wblock_num = 0;
543         /* Call the error management function (command will be nacked) */
544         req.bmRequest = 0;
545         req.wLength = 1;
546         USBD_CtlError (pdev, &req);
547       }
548     }
549     /* Regular Download Command */
550     else if (hdfu->wblock_num > 1)
551     {
552       /* Decode the required address */
553       addr = ((hdfu->wblock_num - 2) * USBD_DFU_XFER_SIZE) + hdfu->data_ptr;
554 
555       /* Preform the write operation */
556       if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Write(hdfu->buffer.d8, (uint8_t *)addr, hdfu->wlength) != USBD_OK)
557       {
558         return USBD_FAIL;
559       }
560     }
561     /* Reset the global length and block number */
562     hdfu->wlength = 0;
563     hdfu->wblock_num = 0;
564 
565     /* Update the state machine */
566     hdfu->dev_state =  DFU_STATE_DNLOAD_SYNC;
567 
568     hdfu->dev_status[1] = 0;
569     hdfu->dev_status[2] = 0;
570     hdfu->dev_status[3] = 0;
571     hdfu->dev_status[4] = hdfu->dev_state;
572     return USBD_OK;
573   }
574   else if (hdfu->dev_state == DFU_STATE_MANIFEST)/* Manifestation in progress*/
575   {
576     /* Start leaving DFU mode */
577     DFU_Leave(pdev);
578   }
579 
580   return USBD_OK;
581 }
582 /**
583   * @brief  USBD_DFU_SOF
584   *         handle SOF event
585   * @param  pdev: device instance
586   * @retval status
587   */
USBD_DFU_SOF(USBD_HandleTypeDef * pdev)588 static uint8_t  USBD_DFU_SOF (USBD_HandleTypeDef *pdev)
589 {
590 
591   return USBD_OK;
592 }
593 /**
594   * @brief  USBD_DFU_IsoINIncomplete
595   *         handle data ISO IN Incomplete event
596   * @param  pdev: device instance
597   * @param  epnum: endpoint index
598   * @retval status
599   */
USBD_DFU_IsoINIncomplete(USBD_HandleTypeDef * pdev,uint8_t epnum)600 static uint8_t  USBD_DFU_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
601 {
602 
603   return USBD_OK;
604 }
605 /**
606   * @brief  USBD_DFU_IsoOutIncomplete
607   *         handle data ISO OUT Incomplete event
608   * @param  pdev: device instance
609   * @param  epnum: endpoint index
610   * @retval status
611   */
USBD_DFU_IsoOutIncomplete(USBD_HandleTypeDef * pdev,uint8_t epnum)612 static uint8_t  USBD_DFU_IsoOutIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
613 {
614 
615   return USBD_OK;
616 }
617 /**
618   * @brief  USBD_DFU_DataOut
619   *         handle data OUT Stage
620   * @param  pdev: device instance
621   * @param  epnum: endpoint index
622   * @retval status
623   */
USBD_DFU_DataOut(USBD_HandleTypeDef * pdev,uint8_t epnum)624 static uint8_t  USBD_DFU_DataOut (USBD_HandleTypeDef *pdev,
625                               uint8_t epnum)
626 {
627 
628   return USBD_OK;
629 }
630 
631 /**
632 * @brief  DeviceQualifierDescriptor
633 *         return Device Qualifier descriptor
634 * @param  length : pointer data length
635 * @retval pointer to descriptor buffer
636 */
USBD_DFU_GetDeviceQualifierDesc(uint16_t * length)637 static uint8_t  *USBD_DFU_GetDeviceQualifierDesc (uint16_t *length)
638 {
639   *length = sizeof (USBD_DFU_DeviceQualifierDesc);
640   return USBD_DFU_DeviceQualifierDesc;
641 }
642 
643 /**
644   * @brief  USBD_DFU_GetUsrStringDesc
645   *         Manages the transfer of memory interfaces string descriptors.
646   * @param  speed : current device speed
647   * @param  index: desciptor index
648   * @param  length : pointer data length
649   * @retval pointer to the descriptor table or NULL if the descriptor is not supported.
650   */
651 #if (USBD_SUPPORT_USER_STRING == 1)
USBD_DFU_GetUsrStringDesc(USBD_HandleTypeDef * pdev,uint8_t index,uint16_t * length)652 static uint8_t* USBD_DFU_GetUsrStringDesc (USBD_HandleTypeDef *pdev, uint8_t index , uint16_t *length)
653 {
654   static uint8_t USBD_StrDesc[255];
655   /* Check if the requested string interface is supported */
656   if (index <= (USBD_IDX_INTERFACE_STR + USBD_DFU_MAX_ITF_NUM))
657   {
658     USBD_GetString ((uint8_t *)((USBD_DFU_MediaTypeDef *)pdev->pUserData)->pStrDesc, USBD_StrDesc, length);
659     return USBD_StrDesc;
660   }
661   /* Not supported Interface Descriptor index */
662   else
663   {
664     return NULL;
665   }
666 }
667 #endif
668 
669 /**
670 * @brief  USBD_MSC_RegisterStorage
671 * @param  fops: storage callback
672 * @retval status
673 */
USBD_DFU_RegisterMedia(USBD_HandleTypeDef * pdev,USBD_DFU_MediaTypeDef * fops)674 uint8_t  USBD_DFU_RegisterMedia    (USBD_HandleTypeDef   *pdev,
675                                     USBD_DFU_MediaTypeDef *fops)
676 {
677   if(fops != NULL)
678   {
679     pdev->pUserData= fops;
680   }
681   return 0;
682 }
683 
684 /******************************************************************************
685      DFU Class requests management
686 ******************************************************************************/
687 /**
688   * @brief  DFU_Detach
689   *         Handles the DFU DETACH request.
690   * @param  pdev: device instance
691   * @param  req: pointer to the request structure.
692   * @retval None.
693   */
DFU_Detach(USBD_HandleTypeDef * pdev,USBD_SetupReqTypedef * req)694 static void DFU_Detach(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
695 {
696  USBD_DFU_HandleTypeDef   *hdfu;
697 
698  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
699 
700   if (hdfu->dev_state == DFU_STATE_IDLE || hdfu->dev_state == DFU_STATE_DNLOAD_SYNC
701       || hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_MANIFEST_SYNC
702         || hdfu->dev_state == DFU_STATE_UPLOAD_IDLE )
703   {
704     /* Update the state machine */
705     hdfu->dev_state = DFU_STATE_IDLE;
706     hdfu->dev_status[0] = DFU_ERROR_NONE;
707     hdfu->dev_status[1] = 0;
708     hdfu->dev_status[2] = 0;
709     hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
710     hdfu->dev_status[4] = hdfu->dev_state;
711     hdfu->dev_status[5] = 0; /*iString*/
712     hdfu->wblock_num = 0;
713     hdfu->wlength = 0;
714   }
715 
716   /* Check the detach capability in the DFU functional descriptor */
717   if ((USBD_DFU_CfgDesc[12 + (9 * USBD_DFU_MAX_ITF_NUM)]) & DFU_DETACH_MASK)
718   {
719     /* Perform an Attach-Detach operation on USB bus */
720     USBD_Stop (pdev);
721     USBD_Start (pdev);
722   }
723   else
724   {
725     /* Wait for the period of time specified in Detach request */
726     USBD_Delay (req->wValue);
727   }
728 }
729 
730 /**
731   * @brief  DFU_Download
732   *         Handles the DFU DNLOAD request.
733   * @param  pdev: device instance
734   * @param  req: pointer to the request structure
735   * @retval None
736   */
DFU_Download(USBD_HandleTypeDef * pdev,USBD_SetupReqTypedef * req)737 static void DFU_Download(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
738 {
739  USBD_DFU_HandleTypeDef   *hdfu;
740 
741  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
742 
743   /* Data setup request */
744   if (req->wLength > 0)
745   {
746     if ((hdfu->dev_state == DFU_STATE_IDLE) || (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE))
747     {
748       /* Update the global length and block number */
749       hdfu->wblock_num = req->wValue;
750       hdfu->wlength = req->wLength;
751 
752       /* Update the state machine */
753       hdfu->dev_state = DFU_STATE_DNLOAD_SYNC;
754       hdfu->dev_status[4] = hdfu->dev_state;
755 
756       /* Prepare the reception of the buffer over EP0 */
757       USBD_CtlPrepareRx (pdev,
758                          (uint8_t*)hdfu->buffer.d8,
759                          hdfu->wlength);
760     }
761     /* Unsupported state */
762     else
763     {
764       /* Call the error management function (command will be nacked */
765       USBD_CtlError (pdev, req);
766     }
767   }
768   /* 0 Data DNLOAD request */
769   else
770   {
771     /* End of DNLOAD operation*/
772     if (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_IDLE )
773     {
774       hdfu->manif_state = DFU_MANIFEST_IN_PROGRESS;
775       hdfu->dev_state = DFU_STATE_MANIFEST_SYNC;
776       hdfu->dev_status[1] = 0;
777       hdfu->dev_status[2] = 0;
778       hdfu->dev_status[3] = 0;
779       hdfu->dev_status[4] = hdfu->dev_state;
780     }
781     else
782     {
783       /* Call the error management function (command will be nacked */
784       USBD_CtlError (pdev, req);
785     }
786   }
787 }
788 
789 /**
790   * @brief  DFU_Upload
791   *         Handles the DFU UPLOAD request.
792   * @param  pdev: instance
793   * @param  req: pointer to the request structure
794   * @retval status
795   */
DFU_Upload(USBD_HandleTypeDef * pdev,USBD_SetupReqTypedef * req)796 static void DFU_Upload(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
797 {
798  USBD_DFU_HandleTypeDef   *hdfu;
799 
800  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
801 
802   uint8_t *phaddr = NULL;
803   uint32_t addr = 0;
804 
805   /* Data setup request */
806   if (req->wLength > 0)
807   {
808     if ((hdfu->dev_state == DFU_STATE_IDLE) || (hdfu->dev_state == DFU_STATE_UPLOAD_IDLE))
809     {
810       /* Update the global length and block number */
811       hdfu->wblock_num = req->wValue;
812       hdfu->wlength = req->wLength;
813 
814       /* DFU Get Command */
815       if (hdfu->wblock_num == 0)
816       {
817         /* Update the state machine */
818         hdfu->dev_state = (hdfu->wlength > 3)? DFU_STATE_IDLE:DFU_STATE_UPLOAD_IDLE;
819 
820         hdfu->dev_status[1] = 0;
821         hdfu->dev_status[2] = 0;
822         hdfu->dev_status[3] = 0;
823         hdfu->dev_status[4] = hdfu->dev_state;
824 
825         /* Store the values of all supported commands */
826         hdfu->buffer.d8[0] = DFU_CMD_GETCOMMANDS;
827         hdfu->buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
828         hdfu->buffer.d8[2] = DFU_CMD_ERASE;
829 
830         /* Send the status data over EP0 */
831         USBD_CtlSendData (pdev,
832                           (uint8_t *)(&(hdfu->buffer.d8[0])),
833                           3);
834       }
835       else if (hdfu->wblock_num > 1)
836       {
837         hdfu->dev_state = DFU_STATE_UPLOAD_IDLE ;
838 
839         hdfu->dev_status[1] = 0;
840         hdfu->dev_status[2] = 0;
841         hdfu->dev_status[3] = 0;
842         hdfu->dev_status[4] = hdfu->dev_state;
843 
844         addr = ((hdfu->wblock_num - 2) * USBD_DFU_XFER_SIZE) + hdfu->data_ptr;  /* Change is Accelerated*/
845 
846         /* Return the physical address where data are stored */
847         phaddr =  ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Read((uint8_t *)addr, hdfu->buffer.d8, hdfu->wlength);
848 
849         /* Send the status data over EP0 */
850         USBD_CtlSendData (pdev,
851                           phaddr,
852                           hdfu->wlength);
853       }
854       else  /* unsupported hdfu->wblock_num */
855       {
856         hdfu->dev_state = DFU_ERROR_STALLEDPKT;
857 
858         hdfu->dev_status[1] = 0;
859         hdfu->dev_status[2] = 0;
860         hdfu->dev_status[3] = 0;
861         hdfu->dev_status[4] = hdfu->dev_state;
862 
863         /* Call the error management function (command will be nacked */
864         USBD_CtlError (pdev, req);
865       }
866     }
867     /* Unsupported state */
868     else
869     {
870       hdfu->wlength = 0;
871       hdfu->wblock_num = 0;
872       /* Call the error management function (command will be nacked */
873       USBD_CtlError (pdev, req);
874     }
875   }
876   /* No Data setup request */
877   else
878   {
879     hdfu->dev_state = DFU_STATE_IDLE;
880 
881     hdfu->dev_status[1] = 0;
882     hdfu->dev_status[2] = 0;
883     hdfu->dev_status[3] = 0;
884     hdfu->dev_status[4] = hdfu->dev_state;
885   }
886 }
887 
888 /**
889   * @brief  DFU_GetStatus
890   *         Handles the DFU GETSTATUS request.
891   * @param  pdev: instance
892   * @retval status
893   */
DFU_GetStatus(USBD_HandleTypeDef * pdev)894 static void DFU_GetStatus(USBD_HandleTypeDef *pdev)
895 {
896  USBD_DFU_HandleTypeDef   *hdfu;
897 
898  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
899 
900   switch (hdfu->dev_state)
901   {
902   case   DFU_STATE_DNLOAD_SYNC:
903     if (hdfu->wlength != 0)
904     {
905       hdfu->dev_state = DFU_STATE_DNLOAD_BUSY;
906 
907       hdfu->dev_status[1] = 0;
908       hdfu->dev_status[2] = 0;
909       hdfu->dev_status[3] = 0;
910       hdfu->dev_status[4] = hdfu->dev_state;
911 
912       if ((hdfu->wblock_num == 0) && (hdfu->buffer.d8[0] == DFU_CMD_ERASE))
913       {
914         ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->GetStatus(hdfu->data_ptr, DFU_MEDIA_ERASE, hdfu->dev_status);
915       }
916       else
917       {
918         ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->GetStatus(hdfu->data_ptr, DFU_MEDIA_PROGRAM, hdfu->dev_status);
919       }
920     }
921     else  /* (hdfu->wlength==0)*/
922     {
923       hdfu->dev_state = DFU_STATE_DNLOAD_IDLE;
924 
925       hdfu->dev_status[1] = 0;
926       hdfu->dev_status[2] = 0;
927       hdfu->dev_status[3] = 0;
928       hdfu->dev_status[4] = hdfu->dev_state;
929     }
930     break;
931 
932   case   DFU_STATE_MANIFEST_SYNC :
933     if (hdfu->manif_state == DFU_MANIFEST_IN_PROGRESS)
934     {
935       hdfu->dev_state = DFU_STATE_MANIFEST;
936 
937       hdfu->dev_status[1] = 1;             /*bwPollTimeout = 1ms*/
938       hdfu->dev_status[2] = 0;
939       hdfu->dev_status[3] = 0;
940       hdfu->dev_status[4] = hdfu->dev_state;
941     }
942     else if ((hdfu->manif_state == DFU_MANIFEST_COMPLETE) && \
943       ((USBD_DFU_CfgDesc[(11 + (9 * USBD_DFU_MAX_ITF_NUM))]) & 0x04))
944     {
945       hdfu->dev_state = DFU_STATE_IDLE;
946 
947       hdfu->dev_status[1] = 0;
948       hdfu->dev_status[2] = 0;
949       hdfu->dev_status[3] = 0;
950       hdfu->dev_status[4] = hdfu->dev_state;
951     }
952     break;
953 
954   default :
955     break;
956   }
957 
958   /* Send the status data over EP0 */
959   USBD_CtlSendData (pdev,
960                     (uint8_t *)(&(hdfu->dev_status[0])),
961                     6);
962 }
963 
964 /**
965   * @brief  DFU_ClearStatus
966   *         Handles the DFU CLRSTATUS request.
967   * @param  pdev: device instance
968   * @retval status
969   */
DFU_ClearStatus(USBD_HandleTypeDef * pdev)970 static void DFU_ClearStatus(USBD_HandleTypeDef *pdev)
971 {
972  USBD_DFU_HandleTypeDef   *hdfu;
973 
974  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
975 
976   if (hdfu->dev_state == DFU_STATE_ERROR)
977   {
978     hdfu->dev_state = DFU_STATE_IDLE;
979     hdfu->dev_status[0] = DFU_ERROR_NONE;/*bStatus*/
980     hdfu->dev_status[1] = 0;
981     hdfu->dev_status[2] = 0;
982     hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
983     hdfu->dev_status[4] = hdfu->dev_state;/*bState*/
984     hdfu->dev_status[5] = 0;/*iString*/
985   }
986   else
987   {   /*State Error*/
988     hdfu->dev_state = DFU_STATE_ERROR;
989     hdfu->dev_status[0] = DFU_ERROR_UNKNOWN;/*bStatus*/
990     hdfu->dev_status[1] = 0;
991     hdfu->dev_status[2] = 0;
992     hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
993     hdfu->dev_status[4] = hdfu->dev_state;/*bState*/
994     hdfu->dev_status[5] = 0;/*iString*/
995   }
996 }
997 
998 /**
999   * @brief  DFU_GetState
1000   *         Handles the DFU GETSTATE request.
1001   * @param  pdev: device instance
1002   * @retval None
1003   */
DFU_GetState(USBD_HandleTypeDef * pdev)1004 static void DFU_GetState(USBD_HandleTypeDef *pdev)
1005 {
1006  USBD_DFU_HandleTypeDef   *hdfu;
1007 
1008  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
1009 
1010   /* Return the current state of the DFU interface */
1011   USBD_CtlSendData (pdev,
1012                     &hdfu->dev_state,
1013                     1);
1014 }
1015 
1016 /**
1017   * @brief  DFU_Abort
1018   *         Handles the DFU ABORT request.
1019   * @param  pdev: device instance
1020   * @retval None
1021   */
DFU_Abort(USBD_HandleTypeDef * pdev)1022 static void DFU_Abort(USBD_HandleTypeDef *pdev)
1023 {
1024  USBD_DFU_HandleTypeDef   *hdfu;
1025 
1026  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
1027 
1028   if (hdfu->dev_state == DFU_STATE_IDLE || hdfu->dev_state == DFU_STATE_DNLOAD_SYNC
1029       || hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_MANIFEST_SYNC
1030         || hdfu->dev_state == DFU_STATE_UPLOAD_IDLE )
1031   {
1032     hdfu->dev_state = DFU_STATE_IDLE;
1033     hdfu->dev_status[0] = DFU_ERROR_NONE;
1034     hdfu->dev_status[1] = 0;
1035     hdfu->dev_status[2] = 0;
1036     hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
1037     hdfu->dev_status[4] = hdfu->dev_state;
1038     hdfu->dev_status[5] = 0; /*iString*/
1039     hdfu->wblock_num = 0;
1040     hdfu->wlength = 0;
1041   }
1042 }
1043 
1044 /**
1045   * @brief  DFU_Leave
1046   *         Handles the sub-protocol DFU leave DFU mode request (leaves DFU mode
1047   *         and resets device to jump to user loaded code).
1048   * @param  pdev: device instance
1049   * @retval None
1050   */
DFU_Leave(USBD_HandleTypeDef * pdev)1051 void DFU_Leave(USBD_HandleTypeDef *pdev)
1052 {
1053  USBD_DFU_HandleTypeDef   *hdfu;
1054 
1055  hdfu = (USBD_DFU_HandleTypeDef*) pdev->pClassData;
1056 
1057  hdfu->manif_state = DFU_MANIFEST_COMPLETE;
1058 
1059   if ((USBD_DFU_CfgDesc[(11 + (9 * USBD_DFU_MAX_ITF_NUM))]) & 0x04)
1060   {
1061     hdfu->dev_state = DFU_STATE_MANIFEST_SYNC;
1062 
1063     hdfu->dev_status[1] = 0;
1064     hdfu->dev_status[2] = 0;
1065     hdfu->dev_status[3] = 0;
1066     hdfu->dev_status[4] = hdfu->dev_state;
1067     return;
1068   }
1069   else
1070   {
1071 
1072     hdfu->dev_state = DFU_STATE_MANIFEST_WAIT_RESET;
1073 
1074     hdfu->dev_status[1] = 0;
1075     hdfu->dev_status[2] = 0;
1076     hdfu->dev_status[3] = 0;
1077     hdfu->dev_status[4] = hdfu->dev_state;
1078 
1079     /* Disconnect the USB device */
1080     USBD_Stop (pdev);
1081 
1082     /* DeInitilialize the MAL(Media Access Layer) */
1083     ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->DeInit();
1084 
1085     /* Generate system reset to allow jumping to the user code */
1086     NVIC_SystemReset();
1087 
1088     /* This instruction will not be reached (system reset) */
1089     for(;;);
1090   }
1091 }
1092 
1093 /**
1094   * @}
1095   */
1096 
1097 
1098 /**
1099   * @}
1100   */
1101 
1102 
1103 /**
1104   * @}
1105   */
1106 
1107 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1108