mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +00:00
feat(plat/st): add a USB DFU stack
Add a stack to support the Universal Serial Bus Device Class Specification for Device Firmware Upgrade (USB DFU v1.1). This stack is based on the USB device stack (USBD). Change-Id: I8a56411d184882b6a9e3617c6dfb859086b8f353 Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
This commit is contained in:
parent
859bfd8d42
commit
efbd65fa7b
2 changed files with 618 additions and 0 deletions
80
plat/st/common/include/usb_dfu.h
Normal file
80
plat/st/common/include/usb_dfu.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef USB_DFU_H
|
||||
#define USB_DFU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <drivers/usb_device.h>
|
||||
|
||||
#define DFU_DESCRIPTOR_TYPE 0x21U
|
||||
|
||||
/* Max DFU Packet Size = 1024 bytes */
|
||||
#define USBD_DFU_XFER_SIZE 1024U
|
||||
|
||||
#define TRANSFER_SIZE_BYTES(size) \
|
||||
((uint8_t)((size) & 0xFF)), /* XFERSIZEB0 */\
|
||||
((uint8_t)((size) >> 8)) /* XFERSIZEB1 */
|
||||
|
||||
/*
|
||||
* helper for descriptor of DFU interface 0 Alternate setting n
|
||||
* with iInterface = index of string descriptor, assumed Nth user string
|
||||
*/
|
||||
#define USBD_DFU_IF_DESC(n) 0x09U, /* Interface Descriptor size */\
|
||||
USB_DESC_TYPE_INTERFACE, /* descriptor type */\
|
||||
0x00U, /* Number of Interface */\
|
||||
(n), /* Alternate setting */\
|
||||
0x00U, /* bNumEndpoints*/\
|
||||
0xFEU, /* Application Specific Class Code */\
|
||||
0x01U, /* Device Firmware Upgrade Code */\
|
||||
0x02U, /* DFU mode protocol */ \
|
||||
USBD_IDX_USER0_STR + (n) /* iInterface */
|
||||
|
||||
/* DFU1.1 Standard */
|
||||
#define USB_DFU_VERSION 0x0110U
|
||||
#define USB_DFU_ITF_SIZ 9U
|
||||
#define USB_DFU_DESC_SIZ(itf) (USB_DFU_ITF_SIZ * ((itf) + 2U))
|
||||
|
||||
/*
|
||||
* bmAttribute value for DFU:
|
||||
* bitCanDnload = 1(bit 0)
|
||||
* bitCanUpload = 1(bit 1)
|
||||
* bitManifestationTolerant = 1 (bit 2)
|
||||
* bitWillDetach = 1(bit 3)
|
||||
* Reserved (bit4-6)
|
||||
* bitAcceleratedST = 0(bit 7)
|
||||
*/
|
||||
#define DFU_BM_ATTRIBUTE 0x0FU
|
||||
|
||||
#define DFU_STATUS_SIZE 6U
|
||||
|
||||
/* Callback for media access */
|
||||
struct usb_dfu_media {
|
||||
int (*upload)(uint8_t alt, uintptr_t *buffer, uint32_t *len,
|
||||
void *user_data);
|
||||
int (*download)(uint8_t alt, uintptr_t *buffer, uint32_t *len,
|
||||
void *user_data);
|
||||
int (*manifestation)(uint8_t alt, void *user_data);
|
||||
};
|
||||
|
||||
/* Internal DFU handle */
|
||||
struct usb_dfu_handle {
|
||||
uint8_t status[DFU_STATUS_SIZE];
|
||||
uint8_t dev_state;
|
||||
uint8_t dev_status;
|
||||
uint8_t alt_setting;
|
||||
const struct usb_dfu_media *callback;
|
||||
};
|
||||
|
||||
void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle);
|
||||
|
||||
int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia);
|
||||
|
||||
/* Function provided by plat */
|
||||
struct usb_handle *usb_dfu_plat_init(void);
|
||||
|
||||
#endif /* USB_DFU_H */
|
538
plat/st/common/usb_dfu.c
Normal file
538
plat/st/common/usb_dfu.c
Normal file
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <usb_dfu.h>
|
||||
|
||||
/* Device states as defined in DFU spec */
|
||||
#define STATE_APP_IDLE 0
|
||||
#define STATE_APP_DETACH 1
|
||||
#define STATE_DFU_IDLE 2
|
||||
#define STATE_DFU_DNLOAD_SYNC 3
|
||||
#define STATE_DFU_DNLOAD_BUSY 4
|
||||
#define STATE_DFU_DNLOAD_IDLE 5
|
||||
#define STATE_DFU_MANIFEST_SYNC 6
|
||||
#define STATE_DFU_MANIFEST 7
|
||||
#define STATE_DFU_MANIFEST_WAIT_RESET 8
|
||||
#define STATE_DFU_UPLOAD_IDLE 9
|
||||
#define STATE_DFU_ERROR 10
|
||||
|
||||
/* DFU errors */
|
||||
#define DFU_ERROR_NONE 0x00
|
||||
#define DFU_ERROR_TARGET 0x01
|
||||
#define DFU_ERROR_FILE 0x02
|
||||
#define DFU_ERROR_WRITE 0x03
|
||||
#define DFU_ERROR_ERASE 0x04
|
||||
#define DFU_ERROR_CHECK_ERASED 0x05
|
||||
#define DFU_ERROR_PROG 0x06
|
||||
#define DFU_ERROR_VERIFY 0x07
|
||||
#define DFU_ERROR_ADDRESS 0x08
|
||||
#define DFU_ERROR_NOTDONE 0x09
|
||||
#define DFU_ERROR_FIRMWARE 0x0A
|
||||
#define DFU_ERROR_VENDOR 0x0B
|
||||
#define DFU_ERROR_USB 0x0C
|
||||
#define DFU_ERROR_POR 0x0D
|
||||
#define DFU_ERROR_UNKNOWN 0x0E
|
||||
#define DFU_ERROR_STALLEDPKT 0x0F
|
||||
|
||||
/* DFU request */
|
||||
#define DFU_DETACH 0
|
||||
#define DFU_DNLOAD 1
|
||||
#define DFU_UPLOAD 2
|
||||
#define DFU_GETSTATUS 3
|
||||
#define DFU_CLRSTATUS 4
|
||||
#define DFU_GETSTATE 5
|
||||
#define DFU_ABORT 6
|
||||
|
||||
static bool usb_dfu_detach_req;
|
||||
|
||||
/*
|
||||
* usb_dfu_init
|
||||
* Initialize the DFU interface
|
||||
* pdev: device instance
|
||||
* cfgidx: Configuration index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)cfgidx;
|
||||
|
||||
/* Nothing to do in this stage */
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_de_init
|
||||
* De-Initialize the DFU layer
|
||||
* pdev: device instance
|
||||
* cfgidx: Configuration index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)cfgidx;
|
||||
|
||||
/* Nothing to do in this stage */
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_data_in
|
||||
* handle data IN Stage
|
||||
* pdev: device instance
|
||||
* epnum: endpoint index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)epnum;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_ep0_rx_ready
|
||||
* handle EP0 Rx Ready event
|
||||
* pdev: device
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev)
|
||||
{
|
||||
(void)pdev;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_ep0_tx_ready
|
||||
* handle EP0 TRx Ready event
|
||||
* pdev: device instance
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev)
|
||||
{
|
||||
(void)pdev;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_sof
|
||||
* handle SOF event
|
||||
* pdev: device instance
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_sof(struct usb_handle *pdev)
|
||||
{
|
||||
(void)pdev;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_iso_in_incomplete
|
||||
* handle data ISO IN Incomplete event
|
||||
* pdev: device instance
|
||||
* epnum: endpoint index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)epnum;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_iso_out_incomplete
|
||||
* handle data ISO OUT Incomplete event
|
||||
* pdev: device instance
|
||||
* epnum: endpoint index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev,
|
||||
uint8_t epnum)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)epnum;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_data_out
|
||||
* handle data OUT Stage
|
||||
* pdev: device instance
|
||||
* epnum: endpoint index
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)epnum;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_detach
|
||||
* Handles the DFU DETACH request.
|
||||
* pdev: device instance
|
||||
* req: pointer to the request structure.
|
||||
*/
|
||||
static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
INFO("Receive DFU Detach\n");
|
||||
|
||||
if ((hdfu->dev_state == STATE_DFU_IDLE) ||
|
||||
(hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
|
||||
(hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
|
||||
(hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
|
||||
(hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
|
||||
/* Update the state machine */
|
||||
hdfu->dev_state = STATE_DFU_IDLE;
|
||||
hdfu->dev_status = DFU_ERROR_NONE;
|
||||
}
|
||||
|
||||
usb_dfu_detach_req = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_download
|
||||
* Handles the DFU DNLOAD request.
|
||||
* pdev: device instance
|
||||
* req: pointer to the request structure
|
||||
*/
|
||||
static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
uintptr_t data_ptr;
|
||||
uint32_t length;
|
||||
int ret;
|
||||
|
||||
/* Data setup request */
|
||||
if (req->length > 0) {
|
||||
/* Unsupported state */
|
||||
if ((hdfu->dev_state != STATE_DFU_IDLE) &&
|
||||
(hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) {
|
||||
/* Call the error management function (command will be nacked) */
|
||||
usb_core_ctl_error(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the data address */
|
||||
length = req->length;
|
||||
ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr,
|
||||
&length, pdev->user_data);
|
||||
if (ret == 0U) {
|
||||
/* Update the state machine */
|
||||
hdfu->dev_state = STATE_DFU_DNLOAD_SYNC;
|
||||
/* Start the transfer */
|
||||
usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length);
|
||||
} else {
|
||||
usb_core_ctl_error(pdev);
|
||||
}
|
||||
} else {
|
||||
/* End of DNLOAD operation*/
|
||||
if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) {
|
||||
/* Call the error management function (command will be nacked) */
|
||||
usb_core_ctl_error(pdev);
|
||||
return;
|
||||
}
|
||||
/* End of DNLOAD operation*/
|
||||
hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
|
||||
ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data);
|
||||
if (ret == 0U) {
|
||||
hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
usb_core_ctl_error(pdev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_upload
|
||||
* Handles the DFU UPLOAD request.
|
||||
* pdev: instance
|
||||
* req: pointer to the request structure
|
||||
*/
|
||||
static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
uintptr_t data_ptr;
|
||||
uint32_t length;
|
||||
int ret;
|
||||
|
||||
/* Data setup request */
|
||||
if (req->length == 0) {
|
||||
/* No Data setup request */
|
||||
hdfu->dev_state = STATE_DFU_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unsupported state */
|
||||
if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) {
|
||||
ERROR("UPLOAD : Unsupported State\n");
|
||||
/* Call the error management function (command will be nacked) */
|
||||
usb_core_ctl_error(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the data address */
|
||||
length = req->length;
|
||||
ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data);
|
||||
if (ret == 0U) {
|
||||
/* Short frame */
|
||||
hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
/* Start the transfer */
|
||||
usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length);
|
||||
} else {
|
||||
ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index);
|
||||
hdfu->dev_state = STATE_DFU_ERROR;
|
||||
hdfu->dev_status = DFU_ERROR_STALLEDPKT;
|
||||
|
||||
/* Call the error management function (command will be nacked) */
|
||||
usb_core_ctl_error(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_get_status
|
||||
* Handles the DFU GETSTATUS request.
|
||||
* pdev: instance
|
||||
*/
|
||||
static void usb_dfu_get_status(struct usb_handle *pdev)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
hdfu->status[0] = hdfu->dev_status; /* bStatus */
|
||||
hdfu->status[1] = 0; /* bwPollTimeout[3] */
|
||||
hdfu->status[2] = 0;
|
||||
hdfu->status[3] = 0;
|
||||
hdfu->status[4] = hdfu->dev_state; /* bState */
|
||||
hdfu->status[5] = 0; /* iString */
|
||||
|
||||
/* next step */
|
||||
switch (hdfu->dev_state) {
|
||||
case STATE_DFU_DNLOAD_SYNC:
|
||||
hdfu->dev_state = STATE_DFU_DNLOAD_IDLE;
|
||||
break;
|
||||
case STATE_DFU_MANIFEST_SYNC:
|
||||
/* the device is 'ManifestationTolerant' */
|
||||
hdfu->status[4] = STATE_DFU_MANIFEST;
|
||||
hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */
|
||||
hdfu->dev_state = STATE_DFU_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start the transfer */
|
||||
usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status));
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_clear_status
|
||||
* Handles the DFU CLRSTATUS request.
|
||||
* pdev: device instance
|
||||
*/
|
||||
static void usb_dfu_clear_status(struct usb_handle *pdev)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
if (hdfu->dev_state == STATE_DFU_ERROR) {
|
||||
hdfu->dev_state = STATE_DFU_IDLE;
|
||||
hdfu->dev_status = DFU_ERROR_NONE;
|
||||
} else {
|
||||
/* State Error */
|
||||
hdfu->dev_state = STATE_DFU_ERROR;
|
||||
hdfu->dev_status = DFU_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_get_state
|
||||
* Handles the DFU GETSTATE request.
|
||||
* pdev: device instance
|
||||
*/
|
||||
static void usb_dfu_get_state(struct usb_handle *pdev)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
/* Return the current state of the DFU interface */
|
||||
usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_abort
|
||||
* Handles the DFU ABORT request.
|
||||
* pdev: device instance
|
||||
*/
|
||||
static void usb_dfu_abort(struct usb_handle *pdev)
|
||||
{
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
if ((hdfu->dev_state == STATE_DFU_IDLE) ||
|
||||
(hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
|
||||
(hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
|
||||
(hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
|
||||
(hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
|
||||
hdfu->dev_state = STATE_DFU_IDLE;
|
||||
hdfu->dev_status = DFU_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_dfu_setup
|
||||
* Handle the DFU specific requests
|
||||
* pdev: instance
|
||||
* req: usb requests
|
||||
* return: status
|
||||
*/
|
||||
static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req)
|
||||
{
|
||||
uint8_t *pbuf = NULL;
|
||||
uint16_t len = 0U;
|
||||
uint8_t ret = USBD_OK;
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
switch (req->bm_request & USB_REQ_TYPE_MASK) {
|
||||
case USB_REQ_TYPE_CLASS:
|
||||
switch (req->b_request) {
|
||||
case DFU_DNLOAD:
|
||||
usb_dfu_download(pdev, req);
|
||||
break;
|
||||
|
||||
case DFU_UPLOAD:
|
||||
usb_dfu_upload(pdev, req);
|
||||
break;
|
||||
|
||||
case DFU_GETSTATUS:
|
||||
usb_dfu_get_status(pdev);
|
||||
break;
|
||||
|
||||
case DFU_CLRSTATUS:
|
||||
usb_dfu_clear_status(pdev);
|
||||
break;
|
||||
|
||||
case DFU_GETSTATE:
|
||||
usb_dfu_get_state(pdev);
|
||||
break;
|
||||
|
||||
case DFU_ABORT:
|
||||
usb_dfu_abort(pdev);
|
||||
break;
|
||||
|
||||
case DFU_DETACH:
|
||||
usb_dfu_detach(pdev, req);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR("unknown request %x on alternate %i\n",
|
||||
req->b_request, hdfu->alt_setting);
|
||||
usb_core_ctl_error(pdev);
|
||||
ret = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_REQ_TYPE_STANDARD:
|
||||
switch (req->b_request) {
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) {
|
||||
pbuf = pdev->desc->get_config_desc(&len);
|
||||
/* DFU descriptor at the end of the USB */
|
||||
pbuf += len - 9U;
|
||||
len = 9U;
|
||||
len = MIN(len, req->length);
|
||||
}
|
||||
|
||||
/* Start the transfer */
|
||||
usb_core_transmit_ep0(pdev, pbuf, len);
|
||||
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
/* Start the transfer */
|
||||
usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U);
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
hdfu->alt_setting = LOBYTE(req->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
usb_core_ctl_error(pdev);
|
||||
ret = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct usb_class usb_dfu = {
|
||||
.init = usb_dfu_init,
|
||||
.de_init = usb_dfu_de_init,
|
||||
.setup = usb_dfu_setup,
|
||||
.ep0_tx_sent = usb_dfu_ep0_tx_ready,
|
||||
.ep0_rx_ready = usb_dfu_ep0_rx_ready,
|
||||
.data_in = usb_dfu_data_in,
|
||||
.data_out = usb_dfu_data_out,
|
||||
.sof = usb_dfu_sof,
|
||||
.iso_in_incomplete = usb_dfu_iso_in_incomplete,
|
||||
.iso_out_incomplete = usb_dfu_iso_out_incomplete,
|
||||
};
|
||||
|
||||
void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle)
|
||||
{
|
||||
pdev->class = (struct usb_class *)&usb_dfu;
|
||||
pdev->class_data = phandle;
|
||||
|
||||
phandle->dev_state = STATE_DFU_IDLE;
|
||||
phandle->dev_status = DFU_ERROR_NONE;
|
||||
}
|
||||
|
||||
int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia)
|
||||
{
|
||||
uint32_t it_count;
|
||||
enum usb_status ret;
|
||||
struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
|
||||
|
||||
hdfu->callback = pmedia;
|
||||
usb_dfu_detach_req = false;
|
||||
/* Continue to handle USB core IT to assure complete data transmission */
|
||||
it_count = 100U;
|
||||
|
||||
/* DFU infinite loop until DETACH_REQ */
|
||||
while (it_count != 0U) {
|
||||
ret = usb_core_handle_it(pdev);
|
||||
if (ret != USBD_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Detach request received */
|
||||
if (usb_dfu_detach_req) {
|
||||
it_count--;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue