1315 lines
43 KiB
C
1315 lines
43 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/USB-Device
|
|
* The Embedded USB Device Stack
|
|
*
|
|
* Copyright (c) 2021 Semidrive Semiconductor
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* USB DEVICE FASTBOOT CLASS
|
|
*
|
|
* Filename : usbd_fb.c
|
|
* Version : V1.00.00
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <armv7-r/cache.h>
|
|
#include "usbd_fb.h"
|
|
#include "usbd_fb_os.h"
|
|
#include <debug.h>
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* EXTERNAL C LANGUAGE LINKAGE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_FB_MSG_BUF_LEN 512u
|
|
#define USBD_FB_VAR_INFO_LEN 128u
|
|
|
|
/* Since Win10 sends fastboot data 1MB by 1MB, let usb controller receive it correspondingly. */
|
|
#define USBD_FB_RX_LIMIT (1024 * 1024u)
|
|
|
|
#if CONFIG_OS
|
|
#define USBD_FB_TRX_TIMEOUT (0)
|
|
#else
|
|
#define USBD_FB_TRX_TIMEOUT (1500)
|
|
#endif
|
|
|
|
#define USBD_FB_COM_NBR_MAX (USBD_FB_CFG_MAX_NBR_DEV * \
|
|
USBD_FB_CFG_MAX_NBR_CFG)
|
|
|
|
|
|
#define USBD_FB_SUBCLASS_CODE 0x42u
|
|
#define USBD_FB_PROTOCOL_CODE 3u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* FORWARD DECLARATIONS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_fb_ctrl USBD_FB_CTRL;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* FASTBOOT STATES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef enum usbd_fb_state {
|
|
USBD_FB_STATE_NONE = 0,
|
|
USBD_FB_STATE_INIT,
|
|
USBD_FB_STATE_CFG
|
|
} USBD_FB_STATE;
|
|
|
|
typedef enum usbd_fb_comm_state {
|
|
USBD_FB_COMM_STATE_NONE = 0,
|
|
USBD_FB_COMM_STATE_RX_WAIT,
|
|
USBD_FB_COMM_STATE_RX_HANDLE,
|
|
USBD_FB_COMM_STATE_COMMAND,
|
|
USBD_FB_COMM_STATE_COMPLETE,
|
|
USBD_FB_COMM_STATE_ERROR,
|
|
} USBD_FB_COMM_STATE;
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* FASTBOOT EP REQUIREMENTS DATA TYPE
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_fb_comm { /* ---------- FB COMMUNICATION INFORMATION ----------- */
|
|
USBD_FB_CTRL *CtrlPtr; /* Ptr to ctrl information. */
|
|
CPU_INT08U DataBulkInEpAddr;
|
|
CPU_INT08U DataBulkOutEpAddr;
|
|
USBD_FB_COMM_STATE CommState; /* comm state of the FB device. */
|
|
CPU_INT32U RxLen;
|
|
} USBD_FB_COMM;
|
|
|
|
|
|
struct usbd_fb_ctrl { /* ------------- FB CONTROL INFORMATION -------------- */
|
|
CPU_INT08U DevNbr; /* FB dev nbr. */
|
|
USBD_FB_STATE State; /* FB dev state. */
|
|
USBD_FB_COMM *CommPtr; /* FB comm info ptr. */
|
|
|
|
CPU_INT16U CmdLen;
|
|
CPU_INT16U VarLen;
|
|
const USBD_FB_CMD *CmdArray;
|
|
const USBD_FB_VAR *VarArray;
|
|
|
|
void *DLAddr;
|
|
CPU_INT32U DLMax;
|
|
CPU_INT32U DLSize;
|
|
|
|
char *MSG_BufPtr;
|
|
};
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* LOCAL TABLES
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
**********************************************************************************************************
|
|
*/
|
|
/* FB instance array. */
|
|
static USBD_FB_CTRL USBD_FBCtrlTbl[USBD_FB_CFG_MAX_NBR_DEV];
|
|
static CPU_INT08U USBD_FBCtrlNbrNext;
|
|
/* FB comm array. */
|
|
static USBD_FB_COMM USBD_FBCommTbl[USBD_FB_COM_NBR_MAX];
|
|
static CPU_INT16U USBD_FBCommNbrNext;
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
static const CPU_INT08U USBD_FB_MsExtPropName[] = {
|
|
'L', 0, 'a', 0, 'b', 0, 'e', 0, 'l', 0, 0, 0
|
|
};
|
|
|
|
static const CPU_INT08U USBD_FB_MsExtPropStr[] = {
|
|
'F', 0, 'a', 0, 's', 0, 't', 0, 'B', 0, 'o', 0, 'o', 0, 't', 0,
|
|
' ', 0, 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 0 , 0
|
|
};
|
|
|
|
static USBD_MS_OS_EXT_PROPERTY USBD_FB_MsExtProp[] = {
|
|
{
|
|
USBD_MS_OS_PROPERTY_TYPE_REG_SZ,
|
|
USBD_FB_MsExtPropName, sizeof(USBD_FB_MsExtPropName),
|
|
USBD_FB_MsExtPropStr, sizeof(USBD_FB_MsExtPropStr)
|
|
}
|
|
};
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL MACRO'S
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define fbd_err(x, ...) ssdk_printf(SSDK_CRIT, "[FB]" x "\r\n", ##__VA_ARGS__)
|
|
#define fbd_log(x, ...) ssdk_printf(SSDK_INFO, "[FB]" x "\r\n", ##__VA_ARGS__)
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_FB_Conn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_FB_Disconn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
static CPU_INT08U USBD_FB_MS_GetCompatID ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U *p_sub_compat_id_ix,
|
|
void *p_if_class_arg);
|
|
|
|
static CPU_INT08U USBD_FB_MS_GetExtPropertyTbl( CPU_INT08U dev_nbr,
|
|
USBD_MS_OS_EXT_PROPERTY **pp_ext_property_tbl,
|
|
void *p_if_class_arg);
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* FastBoot CLASS DRIVER
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBD_CLASS_DRV USBD_FB_Drv = {
|
|
USBD_FB_Conn,
|
|
USBD_FB_Disconn,
|
|
DEF_NULL,
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
.MS_GetCompatID = USBD_FB_MS_GetCompatID,
|
|
.MS_GetExtPropertyTbl = USBD_FB_MS_GetExtPropertyTbl,
|
|
#endif
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONFIGURATION ERRORS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* GLOBAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* USBD_FB_Init()
|
|
*
|
|
* Description : Initialize internal structures and variables used by the Fast Boot Class
|
|
* Bulk Only Transport.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE FB class successfully initialized.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_FB_Init (USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U ix;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
LIB_ERR err_lib;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
#endif
|
|
|
|
for (ix = 0u; ix < USBD_FB_CFG_MAX_NBR_DEV; ix++) { /* Init FB class struct. */
|
|
p_ctrl = &USBD_FBCtrlTbl[ix];
|
|
p_ctrl->State = USBD_FB_STATE_NONE;
|
|
p_ctrl->CommPtr = (USBD_FB_COMM *)0;
|
|
|
|
p_ctrl->CmdLen = 0;
|
|
p_ctrl->VarLen = 0;
|
|
|
|
p_ctrl->DLAddr = NULL;
|
|
p_ctrl->DLMax = 0;
|
|
p_ctrl->DLSize = 0;
|
|
|
|
p_ctrl->MSG_BufPtr = (char *)Mem_HeapAlloc( USBD_FB_MSG_BUF_LEN,
|
|
CONFIG_ARCH_CACHE_LINE,
|
|
NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (ix = 0u; ix < USBD_FB_COM_NBR_MAX; ix++) { /* Init FB class EP tbl. */
|
|
p_comm = &USBD_FBCommTbl[ix];
|
|
p_comm->DataBulkInEpAddr = USBD_EP_ADDR_NONE;
|
|
p_comm->DataBulkOutEpAddr = USBD_EP_ADDR_NONE;
|
|
p_comm->CommState = USBD_FB_COMM_STATE_NONE;
|
|
p_comm->CtrlPtr = (USBD_FB_CTRL *)0;
|
|
}
|
|
|
|
USBD_FBCtrlNbrNext = 0u;
|
|
USBD_FBCommNbrNext = 0u;
|
|
|
|
#if CONFIG_OS
|
|
USBD_FB_OS_Init(p_err); /* Init FB OS layer. */
|
|
#else
|
|
*p_err = USBD_ERR_NONE;
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_Add()
|
|
*
|
|
* Description : Add a new instance of the Fast Boot Class.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE FB class instance successfully added.
|
|
*
|
|
* USBD_ERR_ALLOC No more class instance structure available.
|
|
*
|
|
* Return(s) : Class instance number, if NO error(s).
|
|
*
|
|
* USBD_CLASS_NBR_NONE, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_FB_Add (USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U fb_nbr;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
#endif
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
fb_nbr = USBD_FBCtrlNbrNext; /* Alloc new FB class. */
|
|
|
|
if (fb_nbr >= USBD_FB_CFG_MAX_NBR_DEV) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_FB_INSTANCE_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
|
|
USBD_FBCtrlNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (fb_nbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_CfgAdd()
|
|
*
|
|
* Description : Add an existing FB instance to the specified configuration and device.
|
|
*
|
|
* Argument(s) : class_nbr FB instance number.
|
|
*
|
|
* dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add existing FB interface to.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function:
|
|
|
|
* USBD_ERR_NONE FB class instance successfully added.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
|
|
* 'dev_nbr'/'intr_en'/'interval'.
|
|
* USBD_ERR_ALLOC No more class communication structure available.
|
|
|
|
* ---------- RETURNED BY USBD_IF_Add() : ----------
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_desc'/
|
|
* 'class_desc_size'.
|
|
* USBD_ERR_NULL_PTR Argument 'p_class_drv'/'p_class_drv->Conn'/
|
|
* 'p_class_drv->Disconn' passed a NULL
|
|
* pointer.
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_DEV_INVALID_STATE Invalid device state.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_ALLOC Interfaces NOT available.
|
|
* USBD_ERR_IF_ALT_ALLOC Interface alternate settings NOT available.
|
|
*
|
|
* ---------- RETURNED BY USBD_BulkAdd() : ----------
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'max_pkt_len'.
|
|
*
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
|
|
* USBD_ERR_EP_NONE_AVAIL Physical endpoint NOT available.
|
|
* USBD_ERR_EP_ALLOC Endpoints NOT available.
|
|
*
|
|
* Return(s) : DEF_YES, if FB instance added to USB device configuration successfully.
|
|
*
|
|
* DEF_NO, otherwise
|
|
*
|
|
* Note(s) : (1) USBD_FB_CfgAdd() basically adds an Interface descriptor and its associated Endpoint
|
|
* descriptor(s) to the Configuration descriptor. One call to USBD_FB_CfgAdd() builds
|
|
* the Configuration descriptor corresponding to a FB device with the following format:
|
|
*
|
|
* Configuration Descriptor
|
|
* |-- Interface Descriptor (FB)
|
|
* |-- Endpoint Descriptor (Bulk OUT)
|
|
* |-- Endpoint Descriptor (Bulk IN)
|
|
*
|
|
* If USBD_FB_CfgAdd() is called several times from the application, it allows to create
|
|
* multiple instances and multiple configurations.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_FB_CfgAdd(CPU_INT08U class_nbr,
|
|
CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
USBD_DEV_CFG *p_dev_cfg;
|
|
CPU_INT08U if_nbr;
|
|
CPU_INT08U ep_addr;
|
|
CPU_INT16U comm_nbr;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_FBCtrlNbrNext) {
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_dev_cfg = USBD_DevCfgGet(dev_nbr, p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
if (p_dev_cfg->SerialNbrStrPtr == (CPU_CHAR *)0) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->DevNbr = dev_nbr;
|
|
|
|
comm_nbr = USBD_FBCommNbrNext;
|
|
if (comm_nbr >= USBD_FB_COM_NBR_MAX) {
|
|
USBD_FBCtrlNbrNext--;
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_FB_INSTANCE_ALLOC;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
USBD_FBCommNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_comm = &USBD_FBCommTbl[comm_nbr];
|
|
|
|
if_nbr = USBD_IF_Add ( dev_nbr, /* Add FB IF desc to cfg desc. */
|
|
cfg_nbr,
|
|
&USBD_FB_Drv,
|
|
(void *)p_comm,
|
|
(void *)0,
|
|
USBD_CLASS_CODE_VENDOR_SPECIFIC,
|
|
USBD_FB_SUBCLASS_CODE,
|
|
USBD_FB_PROTOCOL_CODE,
|
|
"USB Fast Boot Interface",
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
ep_addr = USBD_BulkAdd ( dev_nbr, /* Add bulk-IN EP desc. */
|
|
cfg_nbr,
|
|
if_nbr,
|
|
0u,
|
|
DEF_YES,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_comm->DataBulkInEpAddr = ep_addr; /* Store bulk-IN EP address. */
|
|
|
|
ep_addr = USBD_BulkAdd ( dev_nbr, /* Add bulk-OUT EP desc. */
|
|
cfg_nbr,
|
|
if_nbr,
|
|
0u,
|
|
DEF_NO,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_comm->DataBulkOutEpAddr = ep_addr; /* Store bulk-OUT EP address. */
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->State = USBD_FB_STATE_INIT; /* Set class instance to init state. */
|
|
p_ctrl->DevNbr = dev_nbr;
|
|
p_ctrl->CommPtr = (USBD_FB_COMM *)0;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_comm->CtrlPtr = p_ctrl;
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return (DEF_YES);
|
|
}
|
|
|
|
CPU_BOOLEAN USBD_FB_SetDL( CPU_INT08U class_nbr,
|
|
void *download_addr,
|
|
CPU_INT32U download_max,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (!p_err) {
|
|
CPU_SW_EXCEPTION(DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
if (!download_addr || !download_max) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
if (class_nbr >= USBD_FBCtrlNbrNext) {
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
p_ctrl->DLAddr = download_addr;
|
|
p_ctrl->DLMax = download_max;
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (DEF_YES);
|
|
}
|
|
|
|
CPU_BOOLEAN USBD_FB_SetCmdTbl( CPU_INT08U class_nbr,
|
|
const USBD_FB_CMD *cmd_tbl,
|
|
CPU_INT16U cmd_len,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT16U ix;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (!p_err) {
|
|
CPU_SW_EXCEPTION(DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
if (!cmd_tbl || !cmd_len) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
for (ix = 0; ix < cmd_len; ix++) {
|
|
if (!cmd_tbl[ix].cmd || !*cmd_tbl[ix].cmd || !cmd_tbl[ix].handler) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
if (class_nbr >= USBD_FBCtrlNbrNext) {
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->CmdLen = cmd_len;
|
|
p_ctrl->CmdArray = cmd_tbl;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (DEF_YES);
|
|
}
|
|
|
|
CPU_BOOLEAN USBD_FB_SetVarTbl( CPU_INT08U class_nbr,
|
|
const USBD_FB_VAR *var_tbl,
|
|
CPU_INT16U var_len,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT16U ix;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (!p_err) {
|
|
CPU_SW_EXCEPTION(DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
if (!var_tbl || !var_len) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
for (ix = 0; ix < var_len; ix++) {
|
|
if (!var_tbl[ix].name ||
|
|
!*var_tbl[ix].name ||
|
|
!var_tbl[ix].value ||
|
|
!*var_tbl[ix].value) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
|
|
if (class_nbr >= USBD_FBCtrlNbrNext) {
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->VarLen = var_len;
|
|
p_ctrl->VarArray = var_tbl;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (DEF_YES);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_IsConn()
|
|
*
|
|
* Description : Get the FB connection state of the device.
|
|
*
|
|
* Argument(s) : class_nbr FB instance number.
|
|
*
|
|
* Return(s) : DEF_YES, if FB class is connected.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_FB_IsConn (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_DEV_STATE state;
|
|
USBD_ERR err;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (class_nbr >= USBD_FBCtrlNbrNext) {
|
|
return (DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->CommPtr == (USBD_FB_COMM *)0) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
state = USBD_DevStateGet(p_ctrl->DevNbr, &err); /* Get dev state. */
|
|
|
|
if ((err == USBD_ERR_NONE ) && /* Return true if dev state is cfg & FB state is cfg. */
|
|
(state == USBD_DEV_STATE_CONFIGURED) &&
|
|
(p_ctrl->State == USBD_FB_STATE_CFG )) {
|
|
return (DEF_YES);
|
|
} else {
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
|
|
#if CONFIG_OS
|
|
/*
|
|
**********************************************************************************************************
|
|
* USBD_FB_TaskHandler()
|
|
*
|
|
* Description : This function is used to handle FB transfers.
|
|
*
|
|
* Argument(s) : class_nbr FB instance number.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_FB_TaskHandler (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_ERR err;
|
|
USBD_ERR os_err;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
CPU_BOOLEAN conn;
|
|
CPU_INT32U xfer_len;
|
|
CPU_DATA ix;
|
|
unsigned char fb_cls_nbr;
|
|
USBD_FB_CMD_HDL cmd_hdl;
|
|
|
|
fb_cls_nbr = class_nbr;
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
while (DEF_TRUE) {
|
|
|
|
conn = USBD_FB_IsConn(class_nbr);
|
|
if (conn != DEF_YES) {
|
|
fbd_log("fastboot: offline!");
|
|
|
|
/* Wait till FB state and dev state is connected. */
|
|
USBD_FB_OS_EnumSignalPend((CPU_INT16U)0, &os_err);
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
if (p_comm != (USBD_FB_COMM *)0) {
|
|
xfer_len = USBD_BulkRx (p_ctrl->DevNbr,
|
|
p_comm->DataBulkOutEpAddr,
|
|
p_ctrl->MSG_BufPtr,
|
|
USBD_FB_MSG_BUF_LEN,
|
|
0,
|
|
&err);
|
|
if ((err != USBD_ERR_NONE) || (xfer_len == 0)) {
|
|
fbd_err("get fastboot command err=%d", err);
|
|
continue;
|
|
}
|
|
|
|
if (xfer_len == USBD_FB_MSG_BUF_LEN)
|
|
p_ctrl->MSG_BufPtr[xfer_len - 1] = 0;
|
|
else
|
|
p_ctrl->MSG_BufPtr[xfer_len] = 0;
|
|
|
|
fbd_log("fastboot cmd: %s", p_ctrl->MSG_BufPtr);
|
|
|
|
p_comm->CommState = USBD_FB_COMM_STATE_COMMAND;
|
|
cmd_hdl = NULL;
|
|
for (ix = 0; ix < p_ctrl->CmdLen; ix++) {
|
|
if (!memcmp(p_ctrl->MSG_BufPtr,
|
|
p_ctrl->CmdArray[ix].cmd,
|
|
strlen(p_ctrl->CmdArray[ix].cmd))) {
|
|
cmd_hdl = p_ctrl->CmdArray[ix].handler;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cmd_hdl) {
|
|
cmd_hdl(&fb_cls_nbr,
|
|
p_ctrl->MSG_BufPtr + strlen(p_ctrl->CmdArray[ix].cmd),
|
|
p_ctrl->DLAddr,
|
|
p_ctrl->DLSize);
|
|
|
|
if (p_comm->CommState == USBD_FB_COMM_STATE_COMMAND) {
|
|
USBD_FB_Fail(&fb_cls_nbr, "unknown reason");
|
|
}
|
|
} else {
|
|
USBD_FB_Fail(&fb_cls_nbr, "unknown command");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
|
|
static void USBD_FB_RxDone (CPU_INT08U dev_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
void *p_arg,
|
|
USBD_ERR err)
|
|
{
|
|
USBD_FB_COMM *p_comm;
|
|
|
|
p_comm = p_arg;
|
|
if ((err != USBD_ERR_NONE) || (xfer_len == 0)) {
|
|
fbd_err("get fastboot command err=%d", err);
|
|
p_comm->CommState = USBD_FB_COMM_STATE_NONE;
|
|
return;
|
|
}
|
|
|
|
p_comm->RxLen = xfer_len;
|
|
p_comm->CommState = USBD_FB_COMM_STATE_RX_HANDLE;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* USBD_FB_TaskLoop()
|
|
*
|
|
* Description : This function is used to handle FB transfers.
|
|
*
|
|
* Argument(s) : class_nbr FB instance number.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_FB_TaskLoop (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_ERR err;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
CPU_BOOLEAN conn;
|
|
CPU_INT32U xfer_len;
|
|
CPU_DATA ix;
|
|
unsigned char fb_cls_nbr;
|
|
USBD_FB_CMD_HDL cmd_hdl;
|
|
|
|
fb_cls_nbr = class_nbr;
|
|
p_ctrl = &USBD_FBCtrlTbl[class_nbr];
|
|
|
|
conn = USBD_FB_IsConn(class_nbr);
|
|
if (conn != DEF_YES) {
|
|
return;
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
switch (p_comm->CommState) {
|
|
case USBD_FB_COMM_STATE_NONE:
|
|
USBD_BulkRxAsync (p_ctrl->DevNbr,
|
|
p_comm->DataBulkOutEpAddr,
|
|
p_ctrl->MSG_BufPtr,
|
|
USBD_FB_MSG_BUF_LEN,
|
|
USBD_FB_RxDone,
|
|
p_comm,
|
|
&err);
|
|
if (err != USBD_ERR_NONE) {
|
|
fbd_err("get fastboot command err=%d", err);
|
|
break;
|
|
}
|
|
p_comm->CommState = USBD_FB_COMM_STATE_RX_WAIT;
|
|
break;
|
|
|
|
case USBD_FB_COMM_STATE_RX_HANDLE:
|
|
xfer_len = p_comm->RxLen;
|
|
if (xfer_len == USBD_FB_MSG_BUF_LEN)
|
|
p_ctrl->MSG_BufPtr[xfer_len - 1] = 0;
|
|
else
|
|
p_ctrl->MSG_BufPtr[xfer_len] = 0;
|
|
|
|
fbd_log("fastboot cmd: %s", p_ctrl->MSG_BufPtr);
|
|
|
|
p_comm->CommState = USBD_FB_COMM_STATE_COMMAND;
|
|
cmd_hdl = NULL;
|
|
for (ix = 0; ix < p_ctrl->CmdLen; ix++) {
|
|
if (!memcmp(p_ctrl->MSG_BufPtr,
|
|
p_ctrl->CmdArray[ix].cmd,
|
|
strlen(p_ctrl->CmdArray[ix].cmd))) {
|
|
cmd_hdl = p_ctrl->CmdArray[ix].handler;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cmd_hdl) {
|
|
cmd_hdl(&fb_cls_nbr,
|
|
p_ctrl->MSG_BufPtr + strlen(p_ctrl->CmdArray[ix].cmd),
|
|
p_ctrl->DLAddr,
|
|
p_ctrl->DLSize);
|
|
|
|
if (p_comm->CommState == USBD_FB_COMM_STATE_COMMAND) {
|
|
USBD_FB_Fail(&fb_cls_nbr, "unknown reason");
|
|
}
|
|
} else {
|
|
USBD_FB_Fail(&fb_cls_nbr, "unknown command");
|
|
}
|
|
p_comm->CommState = USBD_FB_COMM_STATE_NONE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
**********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
**********************************************************************************************************
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_Conn()
|
|
*
|
|
* Description : Notify class that configuration is active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add the interface to.
|
|
*
|
|
* p_if_class_arg Pointer to class argument.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_FB_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_FB_COMM *p_comm;
|
|
#if CONFIG_OS
|
|
USBD_ERR os_err;
|
|
#endif
|
|
CPU_SR_ALLOC();
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
p_comm = (USBD_FB_COMM *)p_if_class_arg;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_comm->CtrlPtr->CommPtr = p_comm;
|
|
p_comm->CtrlPtr->State = USBD_FB_STATE_CFG; /* Set initial FB state to cfg. */
|
|
p_comm->CommState = USBD_FB_COMM_STATE_NONE; /* Set FB comm state to none. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
#if CONFIG_OS
|
|
USBD_FB_OS_EnumSignalPost(&os_err);
|
|
#endif
|
|
fbd_log("Conn");
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_Disconn()
|
|
*
|
|
* Description : Notify class that configuration is not active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add the interface.
|
|
*
|
|
* p_if_class_arg Pointer to class argument.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_FB_Disconn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_FB_COMM *p_comm;
|
|
CPU_SR_ALLOC();
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
p_comm = (USBD_FB_COMM *)p_if_class_arg;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_comm->CtrlPtr->CommPtr = (USBD_FB_COMM *)0;
|
|
p_comm->CtrlPtr->State = USBD_FB_STATE_INIT; /* Set FB state to init. */
|
|
p_comm->CommState = USBD_FB_COMM_STATE_NONE; /* Set FB comm state to none. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
fbd_log("Disconn");
|
|
}
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_MS_GetCompatID()
|
|
*
|
|
* Description : Returns Microsoft descriptor compatible ID.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* p_sub_compat_id_ix Pointer to variable that will receive subcompatible ID.
|
|
*
|
|
* Return(s) : Compatible ID.
|
|
*
|
|
* DEF_FAIL, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
static CPU_INT08U USBD_FB_MS_GetCompatID (CPU_INT08U dev_nbr,
|
|
CPU_INT08U *p_sub_compat_id_ix,
|
|
void *p_if_class_arg)
|
|
{
|
|
(void)dev_nbr;
|
|
(void)p_if_class_arg;
|
|
|
|
*p_sub_compat_id_ix = USBD_MS_OS_SUBCOMPAT_ID_NULL;
|
|
|
|
return (USBD_MS_OS_COMPAT_ID_WINUSB);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_FB_MS_GetExtPropertyTbl()
|
|
*
|
|
* Description : Returns Microsoft descriptor extended properties table.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* pp_ext_property_tbl Pointer to variable that will receive the Microsoft extended
|
|
* properties table.
|
|
*
|
|
* Return(s) : Number of Microsoft extended properties in table.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
static CPU_INT08U USBD_FB_MS_GetExtPropertyTbl(CPU_INT08U dev_nbr,
|
|
USBD_MS_OS_EXT_PROPERTY **pp_ext_property_tbl,
|
|
void *p_if_class_arg)
|
|
{
|
|
(void)dev_nbr;
|
|
(void)p_if_class_arg;
|
|
|
|
*pp_ext_property_tbl = USBD_FB_MsExtProp;
|
|
|
|
return sizeof(USBD_FB_MsExtProp) / sizeof(USBD_FB_MsExtProp[0]);
|
|
}
|
|
#endif
|
|
|
|
|
|
void USBD_FB_Ack( unsigned char *fb_cls,
|
|
const char *code,
|
|
const char *reason)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
int str_len;
|
|
USBD_ERR err;
|
|
|
|
if (!fb_cls || (*fb_cls >= USBD_FBCtrlNbrNext)) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[*fb_cls];
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
if (!p_comm || (p_comm->CommState != USBD_FB_COMM_STATE_COMMAND)) {
|
|
return;
|
|
}
|
|
|
|
if (reason == 0) {
|
|
reason = "";
|
|
}
|
|
|
|
str_len = snprintf((char *)p_ctrl->MSG_BufPtr, MAX_RSP_SIZE, "%s%s", code, reason);
|
|
if (str_len >= MAX_RSP_SIZE)
|
|
str_len = MAX_RSP_SIZE - 1;
|
|
p_comm->CommState = USBD_FB_COMM_STATE_COMPLETE;
|
|
|
|
(void)USBD_BulkTx(p_ctrl->DevNbr,
|
|
p_comm->DataBulkInEpAddr,
|
|
p_ctrl->MSG_BufPtr,
|
|
str_len,
|
|
USBD_FB_TRX_TIMEOUT,
|
|
DEF_NO,
|
|
&err);
|
|
if (err != USBD_ERR_NONE)
|
|
p_comm->CommState = USBD_FB_COMM_STATE_ERROR;
|
|
}
|
|
|
|
void USBD_FB_Info(unsigned char *fb_cls, const char *reason)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
int str_len;
|
|
USBD_ERR err;
|
|
|
|
if (!fb_cls || (*fb_cls >= USBD_FBCtrlNbrNext)) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[*fb_cls];
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
if (!reason || !p_comm || (p_comm->CommState != USBD_FB_COMM_STATE_COMMAND)) {
|
|
return;
|
|
}
|
|
|
|
str_len = snprintf((char *)p_ctrl->MSG_BufPtr, MAX_RSP_SIZE, "INFO%s", reason);
|
|
if (str_len >= MAX_RSP_SIZE)
|
|
str_len = MAX_RSP_SIZE - 1;
|
|
|
|
(void)USBD_BulkTx(p_ctrl->DevNbr,
|
|
p_comm->DataBulkInEpAddr,
|
|
p_ctrl->MSG_BufPtr,
|
|
str_len,
|
|
USBD_FB_TRX_TIMEOUT,
|
|
DEF_NO,
|
|
&err);
|
|
if (err != USBD_ERR_NONE)
|
|
p_comm->CommState = USBD_FB_COMM_STATE_ERROR;
|
|
}
|
|
|
|
void USBD_FB_Fail(unsigned char *fb_cls, const char *reason)
|
|
{
|
|
USBD_FB_Ack(fb_cls, "FAIL", reason);
|
|
}
|
|
|
|
void USBD_FB_Okay(unsigned char *fb_cls, const char *info)
|
|
{
|
|
USBD_FB_Ack(fb_cls, "OKAY", info);
|
|
}
|
|
|
|
static void USBD_FB_GetAllVar(unsigned char *fb_cls, USBD_FB_CTRL *p_ctrl)
|
|
{
|
|
CPU_DATA ix;
|
|
char getvar_all[USBD_FB_VAR_INFO_LEN];
|
|
|
|
for (ix = 0; ix < p_ctrl->VarLen; ix++) {
|
|
snprintf( getvar_all,
|
|
USBD_FB_VAR_INFO_LEN,
|
|
"%s:%s",
|
|
p_ctrl->VarArray[ix].name,
|
|
p_ctrl->VarArray[ix].value);
|
|
USBD_FB_Info(fb_cls, getvar_all);
|
|
}
|
|
|
|
USBD_FB_Okay(fb_cls, "");
|
|
}
|
|
|
|
void USBD_FB_CmdGetVar( unsigned char *fb_cls,
|
|
const char *arg,
|
|
void *data,
|
|
unsigned sz)
|
|
{
|
|
USBD_FB_CTRL *p_ctrl;
|
|
CPU_DATA ix;
|
|
|
|
if (!fb_cls || (*fb_cls >= USBD_FBCtrlNbrNext)) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[*fb_cls];
|
|
|
|
if (!strcmp("all", arg)) {
|
|
USBD_FB_GetAllVar(fb_cls, p_ctrl);
|
|
return;
|
|
}
|
|
|
|
for (ix = 0; ix < p_ctrl->VarLen; ix++) {
|
|
if (!strcmp(p_ctrl->VarArray[ix].name, arg)) {
|
|
USBD_FB_Okay(fb_cls, p_ctrl->VarArray[ix].value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
USBD_FB_Okay(fb_cls, "");
|
|
}
|
|
|
|
void USBD_FB_CmdFlash( unsigned char *fb_cls,
|
|
const char *arg,
|
|
void *data,
|
|
unsigned sz)
|
|
{
|
|
fbd_log("Flash %s", arg);
|
|
USBD_FB_Okay(fb_cls, "");
|
|
}
|
|
|
|
static CPU_INT32U USBD_FB_ReadLarge(CPU_INT08U dev_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT32U usbd_rd_limit;
|
|
CPU_INT32U rd_len;
|
|
CPU_INT32U ret_len;
|
|
CPU_INT32U already_rd;
|
|
|
|
usbd_rd_limit = USBD_FB_RX_LIMIT;
|
|
|
|
already_rd = 0;
|
|
while (buf_len > 0) {
|
|
rd_len = (buf_len > usbd_rd_limit) ? usbd_rd_limit : buf_len;
|
|
ret_len = USBD_BulkRx ( dev_nbr,
|
|
ep_addr,
|
|
p_buf,
|
|
rd_len,
|
|
USBD_FB_TRX_TIMEOUT,
|
|
p_err);
|
|
if ((*p_err != USBD_ERR_NONE) || (ret_len != rd_len)) {
|
|
fbd_err("read large data err=%d", *p_err);
|
|
return already_rd;
|
|
}
|
|
|
|
p_buf = (uint8_t *)p_buf + rd_len;
|
|
buf_len -= rd_len;
|
|
already_rd += rd_len;
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return already_rd;
|
|
}
|
|
|
|
void USBD_FB_CmdDownload( unsigned char *fb_cls,
|
|
const char *arg,
|
|
void *data,
|
|
unsigned sz)
|
|
{
|
|
char *tmp;
|
|
unsigned long len;
|
|
int str_len;
|
|
CPU_INT32U rd_len;
|
|
USBD_FB_CTRL *p_ctrl;
|
|
USBD_FB_COMM *p_comm;
|
|
USBD_ERR err;
|
|
|
|
if (!fb_cls || (*fb_cls >= USBD_FBCtrlNbrNext)) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl = &USBD_FBCtrlTbl[*fb_cls];
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
if (!p_comm || (p_comm->CommState != USBD_FB_COMM_STATE_COMMAND)) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl->DLSize = 0;
|
|
|
|
errno = 0;
|
|
len = strtoul(arg, &tmp, 16);
|
|
if (*tmp || ((len == ULONG_MAX) && errno) || !len) {
|
|
USBD_FB_Fail(fb_cls, "data len incorrect");
|
|
return;
|
|
}
|
|
|
|
if (len > p_ctrl->DLMax) {
|
|
USBD_FB_Fail(fb_cls, "data too large");
|
|
return;
|
|
}
|
|
|
|
str_len = snprintf((char *)p_ctrl->MSG_BufPtr, MAX_RSP_SIZE, "DATA%08x", (CPU_INT32U)len);
|
|
|
|
(void)USBD_BulkTx(p_ctrl->DevNbr,
|
|
p_comm->DataBulkInEpAddr,
|
|
p_ctrl->MSG_BufPtr,
|
|
str_len,
|
|
USBD_FB_TRX_TIMEOUT,
|
|
DEF_NO,
|
|
&err);
|
|
if (err != USBD_ERR_NONE){
|
|
p_comm->CommState = USBD_FB_COMM_STATE_ERROR;
|
|
fbd_err("download tx data err=%d", err);
|
|
return;
|
|
}
|
|
|
|
rd_len = USBD_FB_ReadLarge( p_ctrl->DevNbr,
|
|
p_comm->DataBulkOutEpAddr,
|
|
p_ctrl->DLAddr,
|
|
len,
|
|
&err);
|
|
if ((err != USBD_ERR_NONE) || (rd_len != len)) {
|
|
fbd_err("read download data err=%d", err);
|
|
p_comm->CommState = USBD_FB_COMM_STATE_ERROR;
|
|
return;
|
|
}
|
|
|
|
p_ctrl->DLSize = len;
|
|
USBD_FB_Okay(fb_cls, "");
|
|
}
|
|
|
|
|