circuitpython/stmhal/usbdev/class/DFU/Src/usbd_dfu.c
Damien George b30c02afa0 stmhal: Get USB enumerating a CDC device.
Enumerates CDC device over USB, but doesn't transmit/receive yet.
2014-03-14 00:30:37 +00:00

1096 lines
30 KiB
C

/**
******************************************************************************
* @file usbd_dfu.c
* @author MCD Application Team
* @version V2.0.0
* @date 18-February-2014
* @brief This file provides the HID core functions.
*
* @verbatim
*
* ===================================================================
* DFU Class Description
* ===================================================================
*
*
*
*
*
*
* @note In HS mode and when the DMA is used, all variables and data structures
* dealing with the DMA during the transaction process should be 32-bit aligned.
*
*
* @endverbatim
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_dfu.h"
#include "usbd_desc.h"
#include "usbd_ctlreq.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_DFU
* @brief usbd core module
* @{
*/
/** @defgroup USBD_DFU_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DFU_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DFU_Private_Macros
* @{
*/
#define DFU_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
#define DFU_PACKET_SZE(frq) (uint8_t)(((frq * 2 * 2)/1000) & 0xFF), \
(uint8_t)((((frq * 2 * 2)/1000) >> 8) & 0xFF)
/**
* @}
*/
/** @defgroup USBD_DFU_Private_FunctionPrototypes
* @{
*/
static uint8_t USBD_DFU_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_DFU_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t *USBD_DFU_GetCfgDesc (uint16_t *length);
static uint8_t *USBD_DFU_GetDeviceQualifierDesc (uint16_t *length);
static uint8_t USBD_DFU_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_DFU_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_DFU_EP0_RxReady (USBD_HandleTypeDef *pdev);
static uint8_t USBD_DFU_EP0_TxReady (USBD_HandleTypeDef *pdev);
static uint8_t USBD_DFU_SOF (USBD_HandleTypeDef *pdev);
static uint8_t USBD_DFU_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_DFU_IsoOutIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum);
#if (USBD_SUPPORT_USER_STRING == 1)
static uint8_t* USBD_DFU_GetUsrStringDesc ( USBD_HandleTypeDef *pdev, uint8_t index , uint16_t *length);
#endif
static void DFU_Detach (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static void DFU_Download (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static void DFU_Upload (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static void DFU_GetStatus (USBD_HandleTypeDef *pdev);
static void DFU_ClearStatus (USBD_HandleTypeDef *pdev);
static void DFU_GetState (USBD_HandleTypeDef *pdev);
static void DFU_Abort (USBD_HandleTypeDef *pdev);
static void DFU_Leave (USBD_HandleTypeDef *pdev);
/**
* @}
*/
/** @defgroup USBD_DFU_Private_Variables
* @{
*/
USBD_ClassTypeDef USBD_DFU =
{
USBD_DFU_Init,
USBD_DFU_DeInit,
USBD_DFU_Setup,
USBD_DFU_EP0_TxReady,
USBD_DFU_EP0_RxReady,
USBD_DFU_DataIn,
USBD_DFU_DataOut,
USBD_DFU_SOF,
USBD_DFU_IsoINIncomplete,
USBD_DFU_IsoOutIncomplete,
USBD_DFU_GetCfgDesc,
USBD_DFU_GetCfgDesc,
USBD_DFU_GetCfgDesc,
USBD_DFU_GetDeviceQualifierDesc,
#if (USBD_SUPPORT_USER_STRING == 1)
USBD_DFU_GetUsrStringDesc
#endif
};
/* USB DFU device Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_DFU_CfgDesc[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuation Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_DFU_CONFIG_DESC_SIZ,
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 1 interface*/
0x01, /*bConfigurationValue: Configuration value*/
0x02, /*iConfiguration: Index of string descriptor describing the configuration*/
0xC0, /*bmAttributes: bus powered and Supprts Remote Wakeup */
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
/* 09 */
/********** Descriptor of DFU interface 0 Alternate setting 0 **************/
USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
#if (USBD_DFU_MAX_ITF_NUM > 1)
/********** Descriptor of DFU interface 0 Alternate setting 1 **************/
USBD_DFU_IF_DESC(1),
#endif /* (USBD_DFU_MAX_ITF_NUM > 1) */
#if (USBD_DFU_MAX_ITF_NUM > 2)
/********** Descriptor of DFU interface 0 Alternate setting 2 **************/
USBD_DFU_IF_DESC(2),
#endif /* (USBD_DFU_MAX_ITF_NUM > 2) */
#if (USBD_DFU_MAX_ITF_NUM > 3)
/********** Descriptor of DFU interface 0 Alternate setting 3 **************/
USBD_DFU_IF_DESC(3),
#endif /* (USBD_DFU_MAX_ITF_NUM > 3) */
#if (USBD_DFU_MAX_ITF_NUM > 4)
/********** Descriptor of DFU interface 0 Alternate setting 4 **************/
USBD_DFU_IF_DESC(4),
#endif /* (USBD_DFU_MAX_ITF_NUM > 4) */
#if (USBD_DFU_MAX_ITF_NUM > 5)
/********** Descriptor of DFU interface 0 Alternate setting 5 **************/
USBD_DFU_IF_DESC(5),
#endif /* (USBD_DFU_MAX_ITF_NUM > 5) */
#if (USBD_DFU_MAX_ITF_NUM > 6)
#error "ERROR: usbd_dfu_core.c: Modify the file to support more descriptors!"
#endif /* (USBD_DFU_MAX_ITF_NUM > 6) */
/******************** DFU Functional Descriptor********************/
0x09, /*blength = 9 Bytes*/
DFU_DESCRIPTOR_TYPE, /* DFU Functional Descriptor*/
0x0B, /*bmAttribute
bitCanDnload = 1 (bit 0)
bitCanUpload = 1 (bit 1)
bitManifestationTolerant = 0 (bit 2)
bitWillDetach = 1 (bit 3)
Reserved (bit4-6)
bitAcceleratedST = 0 (bit 7)*/
0xFF, /*DetachTimeOut= 255 ms*/
0x00,
/*WARNING: In DMA mode the multiple MPS packets feature is still not supported
==> In this case, when using DMA USBD_DFU_XFER_SIZE should be set to 64 in usbd_conf.h */
TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE), /* TransferSize = 1024 Byte*/
0x1A, /* bcdDFUVersion*/
0x01
/***********************************************************/
/* 9*/
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_DFU_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x01,
0x00,
};
/**
* @}
*/
/** @defgroup USBD_DFU_Private_Functions
* @{
*/
/**
* @brief USBD_DFU_Init
* Initialize the DFU interface
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_DFU_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
USBD_DFU_HandleTypeDef *hdfu;
/* Allocate Audio structure */
pdev->pClassData = USBD_malloc(sizeof (USBD_DFU_HandleTypeDef));
if(pdev->pClassData == NULL)
{
return USBD_FAIL;
}
else
{
hdfu = pdev->pClassData;
hdfu->alt_setting = 0;
hdfu->data_ptr = USBD_DFU_APP_DEFAULT_ADD;
hdfu->wblock_num = 0;
hdfu->wlength = 0;
hdfu->manif_state = DFU_MANIFEST_COMPLETE;
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = DFU_STATE_IDLE;
hdfu->dev_status[5] = 0;
/* Initialize Hardware layer */
if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Init() != USBD_OK)
{
return USBD_FAIL;
}
}
return USBD_OK;
}
/**
* @brief USBD_DFU_Init
* DeInitialize the DFU layer
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
hdfu->wblock_num = 0;
hdfu->wlength = 0;
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;
hdfu->dev_status[4] = DFU_STATE_IDLE;
/* DeInit physical Interface components */
if(pdev->pClassData != NULL)
{
/* De-Initialize Hardware layer */
((USBD_DFU_MediaTypeDef *)pdev->pUserData)->DeInit();
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return USBD_OK;
}
/**
* @brief USBD_DFU_Setup
* Handle the DFU specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_DFU_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
uint8_t *pbuf = 0;
uint16_t len = 0;
uint8_t ret = USBD_OK;
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case DFU_DNLOAD:
DFU_Download(pdev, req);
break;
case DFU_UPLOAD:
DFU_Upload(pdev, req);
break;
case DFU_GETSTATUS:
DFU_GetStatus(pdev);
break;
case DFU_CLRSTATUS:
DFU_ClearStatus(pdev);
break;
case DFU_GETSTATE:
DFU_GetState(pdev);
break;
case DFU_ABORT:
DFU_Abort(pdev);
break;
case DFU_DETACH:
DFU_Detach(pdev, req);
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
if( (req->wValue >> 8) == DFU_DESCRIPTOR_TYPE)
{
pbuf = USBD_DFU_CfgDesc + (9 * (USBD_DFU_MAX_ITF_NUM + 1));
len = MIN(USB_DFU_DESC_SIZ , req->wLength);
}
USBD_CtlSendData (pdev,
pbuf,
len);
break;
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData (pdev,
(uint8_t *)&hdfu->alt_setting,
1);
break;
case USB_REQ_SET_INTERFACE :
if ((uint8_t)(req->wValue) < USBD_DFU_MAX_ITF_NUM)
{
hdfu->alt_setting = (uint8_t)(req->wValue);
}
else
{
/* Call the error management function (command will be nacked */
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
}
return ret;
}
/**
* @brief USBD_DFU_GetCfgDesc
* return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static uint8_t *USBD_DFU_GetCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_DFU_CfgDesc);
return USBD_DFU_CfgDesc;
}
/**
* @brief USBD_DFU_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_DFU_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief USBD_DFU_EP0_RxReady
* handle EP0 Rx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_DFU_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief USBD_DFU_EP0_TxReady
* handle EP0 TRx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_DFU_EP0_TxReady (USBD_HandleTypeDef *pdev)
{
uint32_t addr;
USBD_SetupReqTypedef req;
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
if (hdfu->dev_state == DFU_STATE_DNLOAD_BUSY)
{
/* Decode the Special Command*/
if (hdfu->wblock_num == 0)
{
if ((hdfu->buffer.d8[0] == DFU_CMD_GETCOMMANDS) && (hdfu->wlength == 1))
{
}
else if (( hdfu->buffer.d8[0] == DFU_CMD_SETADDRESSPOINTER ) && (hdfu->wlength == 5))
{
hdfu->data_ptr = hdfu->buffer.d8[1];
hdfu->data_ptr += hdfu->buffer.d8[2] << 8;
hdfu->data_ptr += hdfu->buffer.d8[3] << 16;
hdfu->data_ptr += hdfu->buffer.d8[4] << 24;
}
else if (( hdfu->buffer.d8[0] == DFU_CMD_ERASE ) && (hdfu->wlength == 5))
{
hdfu->data_ptr = hdfu->buffer.d8[1];
hdfu->data_ptr += hdfu->buffer.d8[2] << 8;
hdfu->data_ptr += hdfu->buffer.d8[3] << 16;
hdfu->data_ptr += hdfu->buffer.d8[4] << 24;
if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Erase(hdfu->data_ptr) != USBD_OK)
{
return USBD_FAIL;
}
}
else
{
/* Reset the global length and block number */
hdfu->wlength = 0;
hdfu->wblock_num = 0;
/* Call the error management function (command will be nacked) */
req.bmRequest = 0;
req.wLength = 1;
USBD_CtlError (pdev, &req);
}
}
/* Regular Download Command */
else if (hdfu->wblock_num > 1)
{
/* Decode the required address */
addr = ((hdfu->wblock_num - 2) * USBD_DFU_XFER_SIZE) + hdfu->data_ptr;
/* Preform the write operation */
if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Write(hdfu->buffer.d8, (uint8_t *)addr, hdfu->wlength) != USBD_OK)
{
return USBD_FAIL;
}
}
/* Reset the global lenght and block number */
hdfu->wlength = 0;
hdfu->wblock_num = 0;
/* Update the state machine */
hdfu->dev_state = DFU_STATE_DNLOAD_SYNC;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
return USBD_OK;
}
else if (hdfu->dev_state == DFU_STATE_MANIFEST)/* Manifestation in progress*/
{
/* Start leaving DFU mode */
DFU_Leave(pdev);
}
return USBD_OK;
}
/**
* @brief USBD_DFU_SOF
* handle SOF event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_DFU_SOF (USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}
/**
* @brief USBD_DFU_IsoINIncomplete
* handle data ISO IN Incomplete event
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_DFU_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief USBD_DFU_IsoOutIncomplete
* handle data ISO OUT Incomplete event
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_DFU_IsoOutIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief USBD_DFU_DataOut
* handle data OUT Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_DFU_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
return USBD_OK;
}
/**
* @brief DeviceQualifierDescriptor
* return Device Qualifier descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static uint8_t *USBD_DFU_GetDeviceQualifierDesc (uint16_t *length)
{
*length = sizeof (USBD_DFU_DeviceQualifierDesc);
return USBD_DFU_DeviceQualifierDesc;
}
/**
* @brief USBD_DFU_GetUsrStringDesc
* Manages the transfer of memory interfaces string descriptors.
* @param speed : current device speed
* @param index: desciptor index
* @param length : pointer data length
* @retval pointer to the descriptor table or NULL if the descriptor is not supported.
*/
#if (USBD_SUPPORT_USER_STRING == 1)
static uint8_t* USBD_DFU_GetUsrStringDesc (USBD_HandleTypeDef *pdev, uint8_t index , uint16_t *length)
{
static uint8_t USBD_StrDesc[255];
/* Check if the requested string interface is supported */
if (index <= (USBD_IDX_INTERFACE_STR + USBD_DFU_MAX_ITF_NUM))
{
USBD_GetString ((uint8_t *)((USBD_DFU_MediaTypeDef *)pdev->pUserData)->pStrDesc, USBD_StrDesc, length);
return USBD_StrDesc;
}
/* Not supported Interface Descriptor index */
else
{
return NULL;
}
}
#endif
/**
* @brief USBD_MSC_RegisterStorage
* @param fops: storage callback
* @retval status
*/
uint8_t USBD_DFU_RegisterMedia (USBD_HandleTypeDef *pdev,
USBD_DFU_MediaTypeDef *fops)
{
if(fops != NULL)
{
pdev->pUserData= fops;
}
return 0;
}
/******************************************************************************
DFU Class requests management
******************************************************************************/
/**
* @brief DFU_Detach
* Handles the DFU DETACH request.
* @param pdev: device instance
* @param req: pointer to the request structure.
* @retval None.
*/
static void DFU_Detach(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
if (hdfu->dev_state == DFU_STATE_IDLE || hdfu->dev_state == DFU_STATE_DNLOAD_SYNC
|| hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_MANIFEST_SYNC
|| hdfu->dev_state == DFU_STATE_UPLOAD_IDLE )
{
/* Update the state machine */
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
hdfu->dev_status[4] = hdfu->dev_state;
hdfu->dev_status[5] = 0; /*iString*/
hdfu->wblock_num = 0;
hdfu->wlength = 0;
}
/* Check the detach capability in the DFU functional descriptor */
if ((USBD_DFU_CfgDesc[12 + (9 * USBD_DFU_MAX_ITF_NUM)]) & DFU_DETACH_MASK)
{
/* Perform an Attach-Detach operation on USB bus */
USBD_Stop (pdev);
USBD_Start (pdev);
}
else
{
/* Wait for the period of time specified in Detach request */
USBD_Delay (req->wValue);
}
}
/**
* @brief DFU_Download
* Handles the DFU DNLOAD request.
* @param pdev: device instance
* @param req: pointer to the request structure
* @retval None
*/
static void DFU_Download(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
/* Data setup request */
if (req->wLength > 0)
{
if ((hdfu->dev_state == DFU_STATE_IDLE) || (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE))
{
/* Update the global length and block number */
hdfu->wblock_num = req->wValue;
hdfu->wlength = req->wLength;
/* Update the state machine */
hdfu->dev_state = DFU_STATE_DNLOAD_SYNC;
hdfu->dev_status[4] = hdfu->dev_state;
/* Prepare the reception of the buffer over EP0 */
USBD_CtlPrepareRx (pdev,
(uint8_t*)hdfu->buffer.d8,
hdfu->wlength);
}
/* Unsupported state */
else
{
/* Call the error management function (command will be nacked */
USBD_CtlError (pdev, req);
}
}
/* 0 Data DNLOAD request */
else
{
/* End of DNLOAD operation*/
if (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_IDLE )
{
hdfu->manif_state = DFU_MANIFEST_IN_PROGRESS;
hdfu->dev_state = DFU_STATE_MANIFEST_SYNC;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
}
else
{
/* Call the error management function (command will be nacked */
USBD_CtlError (pdev, req);
}
}
}
/**
* @brief DFU_Upload
* Handles the DFU UPLOAD request.
* @param pdev: instance
* @param req: pointer to the request structure
* @retval status
*/
static void DFU_Upload(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
uint8_t *phaddr = NULL;
uint32_t addr = 0;
/* Data setup request */
if (req->wLength > 0)
{
if ((hdfu->dev_state == DFU_STATE_IDLE) || (hdfu->dev_state == DFU_STATE_UPLOAD_IDLE))
{
/* Update the global langth and block number */
hdfu->wblock_num = req->wValue;
hdfu->wlength = req->wLength;
/* DFU Get Command */
if (hdfu->wblock_num == 0)
{
/* Update the state machine */
hdfu->dev_state = (hdfu->wlength > 3)? DFU_STATE_IDLE:DFU_STATE_UPLOAD_IDLE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
/* Store the values of all supported commands */
hdfu->buffer.d8[0] = DFU_CMD_GETCOMMANDS;
hdfu->buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
hdfu->buffer.d8[2] = DFU_CMD_ERASE;
/* Send the status data over EP0 */
USBD_CtlSendData (pdev,
(uint8_t *)(&(hdfu->buffer.d8[0])),
3);
}
else if (hdfu->wblock_num > 1)
{
hdfu->dev_state = DFU_STATE_UPLOAD_IDLE ;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
addr = ((hdfu->wblock_num - 2) * USBD_DFU_XFER_SIZE) + hdfu->data_ptr; /* Change is Accelerated*/
/* Return the physical address where data are stored */
phaddr = ((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Read((uint8_t *)addr, hdfu->buffer.d8, hdfu->wlength);
/* Send the status data over EP0 */
USBD_CtlSendData (pdev,
phaddr,
hdfu->wlength);
}
else /* unsupported hdfu->wblock_num */
{
hdfu->dev_state = DFU_ERROR_STALLEDPKT;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
/* Call the error management function (command will be nacked */
USBD_CtlError (pdev, req);
}
}
/* Unsupported state */
else
{
hdfu->wlength = 0;
hdfu->wblock_num = 0;
/* Call the error management function (command will be nacked */
USBD_CtlError (pdev, req);
}
}
/* No Data setup request */
else
{
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
}
}
/**
* @brief DFU_GetStatus
* Handles the DFU GETSTATUS request.
* @param pdev: instance
* @retval status
*/
static void DFU_GetStatus(USBD_HandleTypeDef *pdev)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
switch (hdfu->dev_state)
{
case DFU_STATE_DNLOAD_SYNC:
if (hdfu->wlength != 0)
{
hdfu->dev_state = DFU_STATE_DNLOAD_BUSY;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
if ((hdfu->wblock_num == 0) && (hdfu->buffer.d8[0] == DFU_CMD_ERASE))
{
((USBD_DFU_MediaTypeDef *)pdev->pUserData)->GetStatus(hdfu->data_ptr, DFU_MEDIA_ERASE, hdfu->dev_status);
}
else
{
((USBD_DFU_MediaTypeDef *)pdev->pUserData)->GetStatus(hdfu->data_ptr, DFU_MEDIA_PROGRAM, hdfu->dev_status);
}
}
else /* (hdfu->wlength==0)*/
{
hdfu->dev_state = DFU_STATE_DNLOAD_IDLE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
}
break;
case DFU_STATE_MANIFEST_SYNC :
if (hdfu->manif_state == DFU_MANIFEST_IN_PROGRESS)
{
hdfu->dev_state = DFU_STATE_MANIFEST;
hdfu->dev_status[1] = 1; /*bwPollTimeout = 1ms*/
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
}
else if ((hdfu->manif_state == DFU_MANIFEST_COMPLETE) && \
((USBD_DFU_CfgDesc[(11 + (9 * USBD_DFU_MAX_ITF_NUM))]) & 0x04))
{
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
}
break;
default :
break;
}
/* Send the status data over EP0 */
USBD_CtlSendData (pdev,
(uint8_t *)(&(hdfu->dev_status[0])),
6);
}
/**
* @brief DFU_ClearStatus
* Handles the DFU CLRSTATUS request.
* @param pdev: device instance
* @retval status
*/
static void DFU_ClearStatus(USBD_HandleTypeDef *pdev)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
if (hdfu->dev_state == DFU_STATE_ERROR)
{
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;/*bStatus*/
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
hdfu->dev_status[4] = hdfu->dev_state;/*bState*/
hdfu->dev_status[5] = 0;/*iString*/
}
else
{ /*State Error*/
hdfu->dev_state = DFU_STATE_ERROR;
hdfu->dev_status[0] = DFU_ERROR_UNKNOWN;/*bStatus*/
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
hdfu->dev_status[4] = hdfu->dev_state;/*bState*/
hdfu->dev_status[5] = 0;/*iString*/
}
}
/**
* @brief DFU_GetState
* Handles the DFU GETSTATE request.
* @param pdev: device instance
* @retval None
*/
static void DFU_GetState(USBD_HandleTypeDef *pdev)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
/* Return the current state of the DFU interface */
USBD_CtlSendData (pdev,
&hdfu->dev_state,
1);
}
/**
* @brief DFU_Abort
* Handles the DFU ABORT request.
* @param pdev: device instance
* @retval None
*/
static void DFU_Abort(USBD_HandleTypeDef *pdev)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
if (hdfu->dev_state == DFU_STATE_IDLE || hdfu->dev_state == DFU_STATE_DNLOAD_SYNC
|| hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || hdfu->dev_state == DFU_STATE_MANIFEST_SYNC
|| hdfu->dev_state == DFU_STATE_UPLOAD_IDLE )
{
hdfu->dev_state = DFU_STATE_IDLE;
hdfu->dev_status[0] = DFU_ERROR_NONE;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/
hdfu->dev_status[4] = hdfu->dev_state;
hdfu->dev_status[5] = 0; /*iString*/
hdfu->wblock_num = 0;
hdfu->wlength = 0;
}
}
/**
* @brief DFU_Leave
* Handles the sub-protocol DFU leave DFU mode request (leaves DFU mode
* and resets device to jump to user loaded code).
* @param pdev: device instance
* @retval None
*/
void DFU_Leave(USBD_HandleTypeDef *pdev)
{
USBD_DFU_HandleTypeDef *hdfu;
hdfu = pdev->pClassData;
hdfu->manif_state = DFU_MANIFEST_COMPLETE;
if ((USBD_DFU_CfgDesc[(11 + (9 * USBD_DFU_MAX_ITF_NUM))]) & 0x04)
{
hdfu->dev_state = DFU_STATE_MANIFEST_SYNC;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
return;
}
else
{
hdfu->dev_state = DFU_STATE_MANIFEST_WAIT_RESET;
hdfu->dev_status[1] = 0;
hdfu->dev_status[2] = 0;
hdfu->dev_status[3] = 0;
hdfu->dev_status[4] = hdfu->dev_state;
/* Disconnect the USB device */
USBD_Stop (pdev);
/* DeInitilialize the MAL(Media Access Layer) */
((USBD_DFU_MediaTypeDef *)pdev->pUserData)->DeInit();
/* Generate system reset to allow jumping to the user code */
NVIC_SystemReset();
/* This instruction will not be reached (system reset) */
for(;;);
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/