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>© 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