Merge pull request #93 from zyp/master
[fw/stlink] / example / stm32f4 / STM32_USB_Device_Library / Class / dfu / src / usbd_dfu_core.c
1 /**
2   ******************************************************************************
3   * @file    usbd_dfu_core.c
4   * @author  MCD Application Team
5   * @version V1.0.0
6   * @date    22-July-2011
7   * @brief   This file provides the high layer firmware functions to manage the 
8   *          following functionalities of the USB DFU Class:
9   *           - Initialization and Configuration of high and low layer
10   *           - Enumeration as DFU Device (and enumeration for each implemented memory interface)
11   *           - Transfers to/from memory interfaces
12   *           - Easy-to-customize "plug-in-like" modules for adding/removing memory interfaces.
13   *           - Error management
14   *           
15   *  @verbatim
16   *      
17   *          ===================================================================      
18   *                                DFU Class Driver Description
19   *          =================================================================== 
20   *           This driver manages the DFU class V1.1 following the "Device Class Specification for 
21   *           Device Firmware Upgrade Version 1.1 Aug 5, 2004".
22   *           This driver implements the following aspects of the specification:
23   *             - Device descriptor management
24   *             - Configuration descriptor management
25   *             - Enumeration as DFU device (in DFU mode only)
26   *             - Requests management (supporting ST DFU sub-protocol)
27   *             - Memory operations management (Download/Upload/Erase/Detach/GetState/GetStatus)
28   *             - DFU state machine implementation.
29   *          
30   *           @note
31   *            ST DFU sub-protocol is compliant with DFU protocol and use sub-requests to manage
32   *            memory addressing, commands processing, specific memories operations (ie. Erase) ...
33   *            As required by the DFU specification, only endpoint 0 is used in this application.
34   *            Other endpoints and functions may be added to the application (ie. DFU ...)
35   * 
36   *           These aspects may be enriched or modified for a specific user application.
37   *          
38   *           This driver doesn't implement the following aspects of the specification 
39   *           (but it is possible to manage these features with some modifications on this driver):
40   *             - Manifestation Tolerant mode
41   *      
42   *  @endverbatim
43   *                                  
44   ******************************************************************************               
45   * @attention
46   *
47   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
48   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
49   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
50   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
51   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
52   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
53   *
54   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
55   ******************************************************************************
56   */ 
57
58 /* Includes ------------------------------------------------------------------*/
59 #include "usbd_dfu_core.h"
60 #include "usbd_desc.h"
61 #include "usbd_req.h"
62 #include "usb_bsp.h"
63
64
65 /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
66   * @{
67   */
68
69
70 /** @defgroup usbd_dfu 
71   * @brief usbd core module
72   * @{
73   */ 
74
75 /** @defgroup usbd_dfu_Private_TypesDefinitions
76   * @{
77   */ 
78 /**
79   * @}
80   */ 
81
82
83 /** @defgroup usbd_dfu_Private_Defines
84   * @{
85   */ 
86 /**
87   * @}
88   */ 
89
90
91 /** @defgroup usbd_dfu_Private_Macros
92   * @{
93   */ 
94 /**
95   * @}
96   */ 
97
98
99 /** @defgroup usbd_dfu_Private_FunctionPrototypes
100   * @{
101   */
102
103 /*********************************************
104    DFU Device library callbacks
105  *********************************************/
106 static uint8_t  usbd_dfu_Init     (void  *pdev, 
107                                   uint8_t cfgidx);
108
109 static uint8_t  usbd_dfu_DeInit   (void  *pdev, 
110                                   uint8_t cfgidx);
111
112 static uint8_t  usbd_dfu_Setup    (void  *pdev, 
113                                   USB_SETUP_REQ *req);
114
115 static uint8_t  EP0_TxSent        (void  *pdev);
116
117 static uint8_t  EP0_RxReady       (void  *pdev);
118
119
120 static uint8_t  *USBD_DFU_GetCfgDesc (uint8_t speed, 
121                                       uint16_t *length);
122
123
124 #ifdef USB_OTG_HS_CORE
125 static uint8_t  *USBD_DFU_GetOtherCfgDesc (uint8_t speed, 
126                                       uint16_t *length);
127 #endif
128
129 static uint8_t* USBD_DFU_GetUsrStringDesc (uint8_t speed, 
130                                            uint8_t index ,
131                                            uint16_t *length);
132
133 /*********************************************
134    DFU Requests management functions
135  *********************************************/
136 static void DFU_Req_DETACH    (void *pdev, 
137                                USB_SETUP_REQ *req);
138
139 static void DFU_Req_DNLOAD    (void *pdev,
140                                USB_SETUP_REQ *req);
141
142 static void DFU_Req_UPLOAD    (void *pdev,
143                                USB_SETUP_REQ *req);
144
145 static void DFU_Req_GETSTATUS (void *pdev);
146
147 static void DFU_Req_CLRSTATUS (void *pdev);
148
149 static void DFU_Req_GETSTATE  (void *pdev);
150
151 static void DFU_Req_ABORT     (void *pdev);
152
153 static void DFU_LeaveDFUMode  (void *pdev); 
154
155 /**
156   * @}
157   */ 
158
159 /** @defgroup usbd_dfu_Private_Variables
160   * @{
161   */ 
162 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
163   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
164     #pragma data_alignment=4   
165   #endif
166 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
167 __ALIGN_BEGIN uint8_t usbd_dfu_CfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END ;
168
169
170 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
171   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
172     #pragma data_alignment=4   
173   #endif
174 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
175 __ALIGN_BEGIN uint8_t usbd_dfu_OtherCfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END ;
176
177 /* The list of Interface String descriptor pointers is defined in usbd_dfu_mal.c 
178   file. This list can be updated whenever a memory has to be added or removed */
179 extern const uint8_t* usbd_dfu_StringDesc[];
180
181 /* State Machine variables */
182 uint8_t DeviceState;
183 uint8_t DeviceStatus[6];
184 uint32_t Manifest_State = Manifest_complete;
185 /* Data Management variables */
186 static uint32_t wBlockNum = 0, wlength = 0;
187 static uint32_t Pointer = APP_DEFAULT_ADD;  /* Base Address to Erase, Program or Read */
188 static __IO uint32_t  usbd_dfu_AltSet = 0;
189
190 extern uint8_t MAL_Buffer[];
191
192 /* DFU interface class callbacks structure */
193 USBD_Class_cb_TypeDef  DFU_cb = 
194 {
195   usbd_dfu_Init,
196   usbd_dfu_DeInit,
197   usbd_dfu_Setup,
198   EP0_TxSent,
199   EP0_RxReady,
200   NULL, /* DataIn, */
201   NULL, /* DataOut, */
202   NULL, /*SOF */
203   NULL,
204   NULL,     
205   USBD_DFU_GetCfgDesc,
206 #ifdef USB_OTG_HS_CORE  
207   USBD_DFU_GetOtherCfgDesc, /* use same cobfig as per FS */
208 #endif  
209   USBD_DFU_GetUsrStringDesc,
210 };
211
212 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
213   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
214     #pragma data_alignment=4   
215   #endif
216 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
217 /* USB DFU device Configuration Descriptor */
218 __ALIGN_BEGIN uint8_t usbd_dfu_CfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END =
219 {
220   0x09, /* bLength: Configuation Descriptor size */
221   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
222   USB_DFU_CONFIG_DESC_SIZ,
223   /* wTotalLength: Bytes returned */
224   0x00,
225   0x01,         /*bNumInterfaces: 1 interface*/
226   0x01,         /*bConfigurationValue: Configuration value*/
227   0x02,         /*iConfiguration: Index of string descriptor describing the configuration*/
228   0xC0,         /*bmAttributes: bus powered and Supprts Remote Wakeup */
229   0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
230   /* 09 */
231   
232   /**********  Descriptor of DFU interface 0 Alternate setting 0 **************/  
233   USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
234   
235 #if (USBD_ITF_MAX_NUM > 1)
236   /**********  Descriptor of DFU interface 0 Alternate setting 1 **************/ 
237   USBD_DFU_IF_DESC(1),
238 #endif /* (USBD_ITF_MAX_NUM > 1) */
239
240 #if (USBD_ITF_MAX_NUM > 2)
241   /**********  Descriptor of DFU interface 0 Alternate setting 2 **************/ 
242   USBD_DFU_IF_DESC(2),
243 #endif /* (USBD_ITF_MAX_NUM > 2) */
244
245 #if (USBD_ITF_MAX_NUM > 3)
246   /**********  Descriptor of DFU interface 0 Alternate setting 3 **************/ 
247   USBD_DFU_IF_DESC(3),
248 #endif /* (USBD_ITF_MAX_NUM > 3) */
249
250 #if (USBD_ITF_MAX_NUM > 4)
251   /**********  Descriptor of DFU interface 0 Alternate setting 4 **************/ 
252   USBD_DFU_IF_DESC(4),
253 #endif /* (USBD_ITF_MAX_NUM > 4) */
254
255 #if (USBD_ITF_MAX_NUM > 5)
256   /**********  Descriptor of DFU interface 0 Alternate setting 5 **************/ 
257   USBD_DFU_IF_DESC(5),
258 #endif /* (USBD_ITF_MAX_NUM > 5) */
259
260 #if (USBD_ITF_MAX_NUM > 6)
261 #error "ERROR: usbd_dfu_core.c: Modify the file to support more descriptors!"
262 #endif /* (USBD_ITF_MAX_NUM > 6) */
263
264   /******************** DFU Functional Descriptor********************/
265   0x09,   /*blength = 9 Bytes*/
266   DFU_DESCRIPTOR_TYPE,   /* DFU Functional Descriptor*/
267   0x0B,   /*bmAttribute
268                 bitCanDnload             = 1      (bit 0)
269                 bitCanUpload             = 1      (bit 1)
270                 bitManifestationTolerant = 0      (bit 2)
271                 bitWillDetach            = 1      (bit 3)
272                 Reserved                          (bit4-6)
273                 bitAcceleratedST         = 0      (bit 7)*/
274   0xFF,   /*DetachTimeOut= 255 ms*/
275   0x00,
276   /*WARNING: In DMA mode the multiple MPS packets feature is still not supported
277    ==> In this case, when using DMA XFERSIZE should be set to 64 in usbd_conf.h */
278   TRANSFER_SIZE_BYTES(XFERSIZE),       /* TransferSize = 1024 Byte*/         
279   0x1A,                                /* bcdDFUVersion*/
280   0x01
281   /***********************************************************/
282   /* 9*/
283 } ;
284
285 #ifdef USE_USB_OTG_HS
286 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
287   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
288     #pragma data_alignment=4   
289   #endif
290 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
291
292 __ALIGN_BEGIN uint8_t usbd_dfu_OtherCfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END =
293 {
294   0x09, /* bLength: Configuation Descriptor size */
295   USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION, /* bDescriptorType: Configuration */
296   USB_DFU_CONFIG_DESC_SIZ,
297   /* wTotalLength: Bytes returned */
298   0x00,
299   0x01,         /*bNumInterfaces: 1 interface*/
300   0x01,         /*bConfigurationValue: Configuration value*/
301   0x02,         /*iConfiguration: Index of string descriptor describing the configuration*/
302   0xC0,         /*bmAttributes: bus powered and Supprts Remote Wakeup */
303   0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
304   /* 09 */
305   
306   /**********  Descriptor of DFU interface 0 Alternate setting 0 **************/  
307   USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
308   
309 #if (USBD_ITF_MAX_NUM > 1)
310   /**********  Descriptor of DFU interface 0 Alternate setting 1 **************/ 
311   USBD_DFU_IF_DESC(1),
312 #endif /* (USBD_ITF_MAX_NUM > 1) */
313
314 #if (USBD_ITF_MAX_NUM > 2)
315   /**********  Descriptor of DFU interface 0 Alternate setting 2 **************/ 
316   USBD_DFU_IF_DESC(2),
317 #endif /* (USBD_ITF_MAX_NUM > 2) */
318
319 #if (USBD_ITF_MAX_NUM > 3)
320   /**********  Descriptor of DFU interface 0 Alternate setting 3 **************/ 
321   USBD_DFU_IF_DESC(3),
322 #endif /* (USBD_ITF_MAX_NUM > 3) */
323
324 #if (USBD_ITF_MAX_NUM > 4)
325   /**********  Descriptor of DFU interface 0 Alternate setting 4 **************/ 
326   USBD_DFU_IF_DESC(4),
327 #endif /* (USBD_ITF_MAX_NUM > 4) */
328
329 #if (USBD_ITF_MAX_NUM > 5)
330   /**********  Descriptor of DFU interface 0 Alternate setting 5 **************/ 
331   USBD_DFU_IF_DESC(5),
332 #endif /* (USBD_ITF_MAX_NUM > 5) */
333
334 #if (USBD_ITF_MAX_NUM > 6)
335 #error "ERROR: usbd_dfu_core.c: Modify the file to support more descriptors!"
336 #endif /* (USBD_ITF_MAX_NUM > 6) */
337
338   /******************** DFU Functional Descriptor********************/
339   0x09,   /*blength = 9 Bytes*/
340   DFU_DESCRIPTOR_TYPE,   /* DFU Functional Descriptor*/
341   0x0B,   /*bmAttribute
342                 bitCanDnload             = 1      (bit 0)
343                 bitCanUpload             = 1      (bit 1)
344                 bitManifestationTolerant = 0      (bit 2)
345                 bitWillDetach            = 1      (bit 3)
346                 Reserved                          (bit4-6)
347                 bitAcceleratedST         = 0      (bit 7)*/
348   0xFF,   /*DetachTimeOut= 255 ms*/
349   0x00,
350   /*WARNING: In DMA mode the multiple MPS packets feature is still not supported
351    ==> In this case, when using DMA XFERSIZE should be set to 64 in usbd_conf.h */
352   TRANSFER_SIZE_BYTES(XFERSIZE),       /* TransferSize = 1024 Byte*/         
353   0x1A,                                /* bcdDFUVersion*/
354   0x01
355   /***********************************************************/
356   /* 9*/
357 };
358 #endif /* USE_USB_OTG_HS */
359
360 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
361   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
362     #pragma data_alignment=4   
363   #endif
364
365 __ALIGN_BEGIN static uint8_t usbd_dfu_Desc[USB_DFU_DESC_SIZ] __ALIGN_END =
366 {
367   0x09,   /*blength = 9 Bytes*/
368   DFU_DESCRIPTOR_TYPE,   /* DFU Functional Descriptor*/
369   0x0B,   /*bmAttribute
370                 bitCanDnload             = 1      (bit 0)
371                 bitCanUpload             = 1      (bit 1)
372                 bitManifestationTolerant = 0      (bit 2)
373                 bitWillDetach            = 1      (bit 3)
374                 Reserved                          (bit4-6)
375                 bitAcceleratedST         = 0      (bit 7)*/
376   0xFF,   /*DetachTimeOut= 255 ms*/
377   0x00,
378   /*WARNING: In DMA mode the multiple MPS packets feature is still not supported
379    ==> In this case, when using DMA XFERSIZE should be set to 64 in usbd_conf.h */
380   TRANSFER_SIZE_BYTES(XFERSIZE),  /* TransferSize = 1024 Byte*/
381   0x1A,                     /* bcdDFUVersion*/
382   0x01
383 };
384 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
385
386 /**
387   * @}
388   */ 
389
390 /** @defgroup usbd_dfu_Private_Functions
391   * @{
392   */ 
393
394 /**
395   * @brief  usbd_dfu_Init
396   *         Initializes the DFU interface.
397   * @param  pdev: device instance
398   * @param  cfgidx: Configuration index
399   * @retval status
400   */
401 static uint8_t  usbd_dfu_Init (void  *pdev, 
402                                uint8_t cfgidx)
403 {
404   /* Initilialize the MAL(Media Access Layer) */
405   MAL_Init();
406   
407   /* Initialize the state of the DFU interface */
408   DeviceState = STATE_dfuIDLE;
409   DeviceStatus[0] = STATUS_OK;
410   DeviceStatus[4] = DeviceState;
411   
412   return USBD_OK;
413 }
414
415 /**
416   * @brief  usbd_dfu_Init
417   *         De-initializes the DFU layer.
418   * @param  pdev: device instance
419   * @param  cfgidx: Configuration index
420   * @retval status
421   */
422 static uint8_t  usbd_dfu_DeInit (void  *pdev, 
423                                  uint8_t cfgidx)
424 {
425   /* Restore default state */
426   DeviceState = STATE_dfuIDLE;
427   DeviceStatus[0] = STATUS_OK;
428   DeviceStatus[4] = DeviceState;
429   wBlockNum = 0;
430   wlength = 0;
431
432   /* DeInitilialize the MAL(Media Access Layer) */
433   MAL_DeInit();
434   
435   return USBD_OK;
436 }
437
438 /**
439   * @brief  usbd_dfu_Setup
440   *         Handles the DFU request parsing.
441   * @param  pdev: instance
442   * @param  req: usb requests
443   * @retval status
444   */
445 static uint8_t  usbd_dfu_Setup (void  *pdev, 
446                                 USB_SETUP_REQ *req)
447 {
448   uint16_t len = 0;
449   uint8_t  *pbuf = NULL;
450   
451   switch (req->bmRequest & USB_REQ_TYPE_MASK)
452   {
453     /* DFU Class Requests -------------------------------*/
454   case USB_REQ_TYPE_CLASS :  
455     switch (req->bRequest)
456     {
457     case DFU_DNLOAD:
458       DFU_Req_DNLOAD(pdev, req);
459       break;
460       
461     case DFU_UPLOAD:
462       DFU_Req_UPLOAD(pdev, req);   
463       break;
464       
465     case DFU_GETSTATUS:
466       DFU_Req_GETSTATUS(pdev);
467       break;
468       
469     case DFU_CLRSTATUS:
470       DFU_Req_CLRSTATUS(pdev);
471       break;      
472
473     case DFU_GETSTATE:
474       DFU_Req_GETSTATE(pdev);
475       break;  
476
477     case DFU_ABORT:
478       DFU_Req_ABORT(pdev);
479       break;
480
481     case DFU_DETACH:
482       DFU_Req_DETACH(pdev, req);
483       break;
484
485     default:
486       USBD_CtlError (pdev, req);
487       return USBD_FAIL;
488     }
489     break;
490     
491     /* Standard Requests -------------------------------*/
492   case USB_REQ_TYPE_STANDARD:
493     switch (req->bRequest)
494     {
495     case USB_REQ_GET_DESCRIPTOR: 
496       if( (req->wValue >> 8) == DFU_DESCRIPTOR_TYPE)
497       {
498 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
499         pbuf = usbd_dfu_Desc;   
500 #else
501         pbuf = usbd_dfu_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM);
502 #endif 
503         len = MIN(USB_DFU_DESC_SIZ , req->wLength);
504       }
505       
506       USBD_CtlSendData (pdev, 
507                         pbuf,
508                         len);
509       break;
510       
511     case USB_REQ_GET_INTERFACE :
512       USBD_CtlSendData (pdev,
513                         (uint8_t *)&usbd_dfu_AltSet,
514                         1);
515       break;
516       
517     case USB_REQ_SET_INTERFACE :
518       if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM)
519       {
520         usbd_dfu_AltSet = (uint8_t)(req->wValue);
521       }
522       else
523       {
524         /* Call the error management function (command will be nacked */
525         USBD_CtlError (pdev, req);
526       }
527       break;
528     }
529   }
530   return USBD_OK;
531 }
532
533 /**
534   * @brief  EP0_TxSent
535   *         Handles the DFU control endpoint data IN stage.
536   * @param  pdev: device instance
537   * @retval status
538   */
539 static uint8_t  EP0_TxSent (void  *pdev)
540 {
541   uint32_t Addr;
542   USB_SETUP_REQ req;  
543   
544   if (DeviceState == STATE_dfuDNBUSY)
545   {
546     /* Decode the Special Command*/
547     if (wBlockNum == 0)   
548     {
549       if ((MAL_Buffer[0] ==  CMD_GETCOMMANDS) && (wlength == 1))
550       {}
551       else if  (( MAL_Buffer[0] ==  CMD_SETADDRESSPOINTER ) && (wlength == 5))
552       {
553         Pointer  = MAL_Buffer[1];
554         Pointer += MAL_Buffer[2] << 8;
555         Pointer += MAL_Buffer[3] << 16;
556         Pointer += MAL_Buffer[4] << 24;
557       }
558       else if (( MAL_Buffer[0] ==  CMD_ERASE ) && (wlength == 5))
559       {
560         Pointer  = MAL_Buffer[1];
561         Pointer += MAL_Buffer[2] << 8;
562         Pointer += MAL_Buffer[3] << 16;
563         Pointer += MAL_Buffer[4] << 24;
564         MAL_Erase(Pointer);
565       }
566       else
567       {
568         /* Reset the global length and block number */
569         wlength = 0;
570         wBlockNum = 0;     
571         /* Call the error management function (command will be nacked) */
572         req.bmRequest = 0;
573         req.wLength = 1;
574         USBD_CtlError (pdev, &req);
575       }
576     }
577     /* Regular Download Command */
578     else if (wBlockNum > 1)  
579     {
580       /* Decode the required address */
581       Addr = ((wBlockNum - 2) * XFERSIZE) + Pointer;
582       
583       /* Preform the write operation */
584       MAL_Write(Addr, wlength);
585     }
586     /* Reset the global lenght and block number */
587     wlength = 0;
588     wBlockNum = 0;
589     
590     /* Update the state machine */
591     DeviceState =  STATE_dfuDNLOAD_SYNC;
592     DeviceStatus[4] = DeviceState;
593     DeviceStatus[1] = 0;
594     DeviceStatus[2] = 0;
595     DeviceStatus[3] = 0;
596     return USBD_OK;
597   }
598   else if (DeviceState == STATE_dfuMANIFEST)/* Manifestation in progress*/
599   {
600     /* Start leaving DFU mode */
601     DFU_LeaveDFUMode(pdev);
602   }
603   
604   return USBD_OK;
605 }
606
607 /**
608   * @brief  EP0_RxReady
609   *         Handles the DFU control endpoint data OUT stage.
610   * @param  pdev: device instance
611   * @retval status
612   */
613 static uint8_t  EP0_RxReady (void  *pdev)
614
615   return USBD_OK;
616 }
617
618
619 /******************************************************************************
620      DFU Class requests management
621 ******************************************************************************/
622 /**
623   * @brief  DFU_Req_DETACH
624   *         Handles the DFU DETACH request.
625   * @param  pdev: device instance
626   * @param  req: pointer to the request structure.
627   * @retval None.
628   */
629 static void DFU_Req_DETACH(void *pdev, USB_SETUP_REQ *req)
630 {
631   if (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuDNLOAD_SYNC
632       || DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuMANIFEST_SYNC
633         || DeviceState == STATE_dfuUPLOAD_IDLE )
634   {
635     /* Update the state machine */
636     DeviceState = STATE_dfuIDLE;
637     DeviceStatus[0] = STATUS_OK;
638     DeviceStatus[1] = 0;
639     DeviceStatus[2] = 0;
640     DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/
641     DeviceStatus[4] = DeviceState;
642     DeviceStatus[5] = 0; /*iString*/
643     wBlockNum = 0;
644     wlength = 0;
645   } 
646   
647   /* Check the detach capability in the DFU functional descriptor */
648   if ((usbd_dfu_CfgDesc[12 + (9 * USBD_ITF_MAX_NUM)]) & DFU_DETACH_MASK)
649   {
650     /* Perform an Attach-Detach operation on USB bus */
651     DCD_DevDisconnect (pdev);
652     DCD_DevConnect (pdev);  
653   }
654   else
655   {
656     /* Wait for the period of time specified in Detach request */
657     USB_OTG_BSP_mDelay (req->wValue);  
658   }
659 }
660
661 /**
662   * @brief  DFU_Req_DNLOAD
663   *         Handles the DFU DNLOAD request.
664   * @param  pdev: device instance
665   * @param  req: pointer to the request structure
666   * @retval None
667   */
668 static void DFU_Req_DNLOAD(void *pdev, USB_SETUP_REQ *req)
669 {
670   /* Data setup request */
671   if (req->wLength > 0)
672   {
673     if ((DeviceState == STATE_dfuIDLE) || (DeviceState == STATE_dfuDNLOAD_IDLE))
674     {
675       /* Update the global length and block number */
676       wBlockNum = req->wValue;
677       wlength = req->wLength;
678       
679       /* Update the state machine */
680       DeviceState = STATE_dfuDNLOAD_SYNC;
681       DeviceStatus[4] = DeviceState;
682       
683       /* Prepare the reception of the buffer over EP0 */
684       USBD_CtlPrepareRx (pdev,
685                          (uint8_t*)MAL_Buffer,                                  
686                          wlength);
687     }
688     /* Unsupported state */
689     else
690     {
691       /* Call the error management function (command will be nacked */
692       USBD_CtlError (pdev, req);
693     }
694   }
695   /* 0 Data DNLOAD request */
696   else
697   {
698     /* End of DNLOAD operation*/
699     if (DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuIDLE )
700     {
701       Manifest_State = Manifest_In_Progress;
702       DeviceState = STATE_dfuMANIFEST_SYNC;
703       DeviceStatus[1] = 0;
704       DeviceStatus[2] = 0;
705       DeviceStatus[3] = 0;
706       DeviceStatus[4] = DeviceState;
707     }
708     else
709     {
710       /* Call the error management function (command will be nacked */
711       USBD_CtlError (pdev, req);
712     }
713   }  
714 }
715
716 /**
717   * @brief  DFU_Req_UPLOAD
718   *         Handles the DFU UPLOAD request.
719   * @param  pdev: instance
720   * @param  req: pointer to the request structure
721   * @retval status
722   */
723 static void DFU_Req_UPLOAD(void *pdev, USB_SETUP_REQ *req)
724 {
725   uint8_t *Phy_Addr = NULL;
726   uint32_t Addr = 0;
727   
728   /* Data setup request */
729   if (req->wLength > 0)
730   {
731     if ((DeviceState == STATE_dfuIDLE) || (DeviceState == STATE_dfuUPLOAD_IDLE))
732     {
733       /* Update the global langth and block number */
734       wBlockNum = req->wValue;
735       wlength = req->wLength;
736       
737       /* DFU Get Command */
738       if (wBlockNum == 0)  
739       {
740         /* Update the state machine */
741         DeviceState = (wlength > 3)? STATE_dfuIDLE:STATE_dfuUPLOAD_IDLE;        
742         DeviceStatus[4] = DeviceState;
743         DeviceStatus[1] = 0;
744         DeviceStatus[2] = 0;
745         DeviceStatus[3] = 0;
746         
747         /* Store the values of all supported commands */
748         MAL_Buffer[0] = CMD_GETCOMMANDS;
749         MAL_Buffer[1] = CMD_SETADDRESSPOINTER;
750         MAL_Buffer[2] = CMD_ERASE;
751         
752         /* Send the status data over EP0 */
753         USBD_CtlSendData (pdev,
754                           (uint8_t *)(&(MAL_Buffer[0])),
755                           3);
756       }
757       else if (wBlockNum > 1)
758       {
759         DeviceState = STATE_dfuUPLOAD_IDLE ;
760         DeviceStatus[4] = DeviceState;
761         DeviceStatus[1] = 0;
762         DeviceStatus[2] = 0;
763         DeviceStatus[3] = 0;
764         Addr = ((wBlockNum - 2) * XFERSIZE) + Pointer;  /* Change is Accelerated*/
765         
766         /* Return the physical address where data are stored */
767         Phy_Addr = MAL_Read(Addr, wlength);
768         
769         /* Send the status data over EP0 */
770         USBD_CtlSendData (pdev,
771                           Phy_Addr,
772                           wlength);
773       }
774       else  /* unsupported wBlockNum */
775       {
776         DeviceState = STATUS_ERRSTALLEDPKT;
777         DeviceStatus[4] = DeviceState;
778         DeviceStatus[1] = 0;
779         DeviceStatus[2] = 0;
780         DeviceStatus[3] = 0;
781         
782         /* Call the error management function (command will be nacked */
783         USBD_CtlError (pdev, req); 
784       }
785     }
786     /* Unsupported state */
787     else
788     {
789       wlength = 0;
790       wBlockNum = 0;   
791       /* Call the error management function (command will be nacked */
792       USBD_CtlError (pdev, req);
793     }
794   }
795   /* No Data setup request */
796   else
797   {
798     DeviceState = STATE_dfuIDLE;
799     DeviceStatus[1] = 0;
800     DeviceStatus[2] = 0;
801     DeviceStatus[3] = 0;
802     DeviceStatus[4] = DeviceState;
803   }
804 }
805
806 /**
807   * @brief  DFU_Req_GETSTATUS
808   *         Handles the DFU GETSTATUS request.
809   * @param  pdev: instance
810   * @retval status
811   */
812 static void DFU_Req_GETSTATUS(void *pdev)
813 {
814   switch (DeviceState)
815   {
816   case   STATE_dfuDNLOAD_SYNC:
817     if (wlength != 0)
818     {
819       DeviceState = STATE_dfuDNBUSY;
820       DeviceStatus[4] = DeviceState;
821       if ((wBlockNum == 0) && (MAL_Buffer[0] == CMD_ERASE))
822       {
823         MAL_GetStatus(Pointer, 0, DeviceStatus);
824       }
825       else
826       {
827         MAL_GetStatus(Pointer, 1, DeviceStatus);
828       }
829     }
830     else  /* (wlength==0)*/
831     {
832       DeviceState = STATE_dfuDNLOAD_IDLE;
833       DeviceStatus[4] = DeviceState;
834       DeviceStatus[1] = 0;
835       DeviceStatus[2] = 0;
836       DeviceStatus[3] = 0;
837     }
838     break;
839     
840   case   STATE_dfuMANIFEST_SYNC :
841     if (Manifest_State == Manifest_In_Progress)
842     {
843       DeviceState = STATE_dfuMANIFEST;
844       DeviceStatus[4] = DeviceState;
845       DeviceStatus[1] = 1;             /*bwPollTimeout = 1ms*/
846       DeviceStatus[2] = 0;
847       DeviceStatus[3] = 0;
848       //break;
849     }
850     else if ((Manifest_State == Manifest_complete) && \
851       ((usbd_dfu_CfgDesc[(11 + (9 * USBD_ITF_MAX_NUM))]) & 0x04))
852     {
853       DeviceState = STATE_dfuIDLE;
854       DeviceStatus[4] = DeviceState;
855       DeviceStatus[1] = 0;
856       DeviceStatus[2] = 0;
857       DeviceStatus[3] = 0;
858       //break;
859     }
860     break;
861     
862   default :
863     break;
864   }
865   
866   /* Send the status data over EP0 */
867   USBD_CtlSendData (pdev,
868                     (uint8_t *)(&(DeviceStatus[0])),
869                     6);
870 }
871
872 /**
873   * @brief  DFU_Req_CLRSTATUS 
874   *         Handles the DFU CLRSTATUS request.
875   * @param  pdev: device instance
876   * @retval status
877   */
878 static void DFU_Req_CLRSTATUS(void *pdev)
879 {
880   if (DeviceState == STATE_dfuERROR)
881   {
882     DeviceState = STATE_dfuIDLE;
883     DeviceStatus[0] = STATUS_OK;/*bStatus*/
884     DeviceStatus[1] = 0;
885     DeviceStatus[2] = 0;
886     DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/
887     DeviceStatus[4] = DeviceState;/*bState*/
888     DeviceStatus[5] = 0;/*iString*/
889   }
890   else
891   {   /*State Error*/
892     DeviceState = STATE_dfuERROR;
893     DeviceStatus[0] = STATUS_ERRUNKNOWN;/*bStatus*/
894     DeviceStatus[1] = 0;
895     DeviceStatus[2] = 0;
896     DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/
897     DeviceStatus[4] = DeviceState;/*bState*/
898     DeviceStatus[5] = 0;/*iString*/
899   }
900 }
901
902 /**
903   * @brief  DFU_Req_GETSTATE
904   *         Handles the DFU GETSTATE request.
905   * @param  pdev: device instance
906   * @retval None
907   */
908 static void DFU_Req_GETSTATE(void *pdev)
909 {
910   /* Return the current state of the DFU interface */
911   USBD_CtlSendData (pdev, 
912                     &DeviceState,
913                     1);  
914 }
915
916 /**
917   * @brief  DFU_Req_ABORT
918   *         Handles the DFU ABORT request.
919   * @param  pdev: device instance
920   * @retval None
921   */
922 static void DFU_Req_ABORT(void *pdev)
923 {
924   if (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuDNLOAD_SYNC
925       || DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuMANIFEST_SYNC
926         || DeviceState == STATE_dfuUPLOAD_IDLE )
927   {
928     DeviceState = STATE_dfuIDLE;
929     DeviceStatus[0] = STATUS_OK;
930     DeviceStatus[1] = 0;
931     DeviceStatus[2] = 0;
932     DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/
933     DeviceStatus[4] = DeviceState;
934     DeviceStatus[5] = 0; /*iString*/
935     wBlockNum = 0;
936     wlength = 0;
937   }  
938 }
939
940 /**
941   * @brief  DFU_LeaveDFUMode
942   *         Handles the sub-protocol DFU leave DFU mode request (leaves DFU mode
943   *         and resets device to jump to user loaded code).
944   * @param  pdev: device instance
945   * @retval None
946   */
947 void DFU_LeaveDFUMode(void *pdev)
948 {
949  Manifest_State = Manifest_complete;
950
951   if ((usbd_dfu_CfgDesc[(11 + (9 * USBD_ITF_MAX_NUM))]) & 0x04)
952   {
953     DeviceState = STATE_dfuMANIFEST_SYNC;
954     DeviceStatus[4] = DeviceState;
955     DeviceStatus[1] = 0;
956     DeviceStatus[2] = 0;
957     DeviceStatus[3] = 0;
958     return;
959   }
960   else
961   {
962     DeviceState = STATE_dfuMANIFEST_WAIT_RESET;
963     DeviceStatus[4] = DeviceState;
964     DeviceStatus[1] = 0;
965     DeviceStatus[2] = 0;
966     DeviceStatus[3] = 0;
967
968     /* Disconnect the USB device */
969     DCD_DevDisconnect (pdev);
970
971     /* DeInitilialize the MAL(Media Access Layer) */
972     MAL_DeInit();
973     
974     /* Generate system reset to allow jumping to the user code */
975     NVIC_SystemReset();
976    
977     /* This instruction will not be reached (system reset) */
978     return;
979   }  
980 }
981
982 /**
983   * @brief  USBD_DFU_GetCfgDesc 
984   *         Returns configuration descriptor
985   * @param  speed : current device speed
986   * @param  length : pointer data length
987   * @retval pointer to descriptor buffer
988   */
989 static uint8_t  *USBD_DFU_GetCfgDesc (uint8_t speed, uint16_t *length)
990 {
991   *length = sizeof (usbd_dfu_CfgDesc);
992   return usbd_dfu_CfgDesc;
993 }
994
995 #ifdef USB_OTG_HS_CORE
996 /**
997   * @brief  USBD_DFU_GetOtherCfgDesc 
998   *         Returns other speed configuration descriptor.
999   * @param  speed : current device speed
1000   * @param  length : pointer data length
1001   * @retval pointer to descriptor buffer
1002   */
1003 static uint8_t  *USBD_DFU_GetOtherCfgDesc (uint8_t speed, uint16_t *length)
1004 {
1005   *length = sizeof (usbd_dfu_OtherCfgDesc);
1006   return usbd_dfu_OtherCfgDesc;
1007 }
1008 #endif
1009
1010 /**
1011   * @brief  USBD_DFU_GetUsrStringDesc
1012   *         Manages the transfer of memory interfaces string descriptors.
1013   * @param  speed : current device speed
1014   * @param  index: desciptor index
1015   * @param  length : pointer data length
1016   * @retval pointer to the descriptor table or NULL if the descriptor is not supported.
1017   */
1018 static uint8_t* USBD_DFU_GetUsrStringDesc (uint8_t speed, uint8_t index , uint16_t *length)
1019 {
1020   /* Check if the requested string interface is supported */
1021   if (index <= (USBD_IDX_INTERFACE_STR + USBD_ITF_MAX_NUM))
1022   {
1023     
1024     
1025     USBD_GetString ((uint8_t *)usbd_dfu_StringDesc[index - USBD_IDX_INTERFACE_STR - 1], USBD_StrDesc, length);
1026     return USBD_StrDesc;  
1027   }
1028   /* Not supported Interface Descriptor index */
1029   else
1030   {
1031     return NULL;
1032   }
1033 }
1034 /**
1035   * @}
1036   */ 
1037
1038 /**
1039   * @}
1040   */ 
1041
1042 /**
1043   * @}
1044   */ 
1045
1046 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/