Files
test/middleware/usb/uC-USBH/Class/CDC/usbh_cdc.c
2025-11-07 20:19:23 +08:00

1426 lines
52 KiB
C

/*
*********************************************************************************************************
* uC/USB-Host
* The Embedded USB Host Stack
*
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* COMMUNICATIONS DEVICE CLASS (CDC)
*
* Filename : usbh_cdc.c
* Version : V3.42.01
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define USBH_CDC_MODULE
#define MICRIUM_SOURCE
#include "usbh_cdc.h"
#include "../../Source/usbh_core.h"
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL DATA TYPES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* UNION DESCRIPTOR DATA TYPE
*
* Note(s) : (1) See 'USB Class Definitions for Communication Devices Revision 1.1', Section 5.2.3.8, Table 33.
*********************************************************************************************************
*/
typedef struct usbh_cdc_union_desc {
CPU_INT08U bFunctionLength; /* Size of desc in bytes. */
CPU_INT08U bDescriptorType; /* IF desc type. */
CPU_INT08U bDescriptorSubtype; /* Union functional desc subtype. */
CPU_INT08U bMasterInterface; /* Nbr of comm or Data Class IF, designated as master. */
CPU_INT08U bSlaveInterface0; /* IF nbr of first slave or associated IF in union. */
} USBH_CDC_UNION_DESC;
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
static USBH_CDC_DEV USBH_CDC_DevArr[USBH_CDC_CFG_MAX_DEV];
static MEM_POOL USBH_CDC_DevPool;
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static void USBH_CDC_GlobalInit (USBH_ERR *p_err);
static void *USBH_CDC_ProbeDev (USBH_DEV *p_dev,
USBH_ERR *p_err);
static USBH_ERR USBH_CDC_EP_Open (USBH_CDC_DEV *p_cdc_dev);
static USBH_ERR USBH_CDC_UnionDescParse (USBH_CDC_UNION_DESC *p_union_desc,
USBH_IF *p_if);
static void USBH_CDC_Suspend (void *p_class_dev);
static void USBH_CDC_Resume (void *p_class_dev);
static void USBH_CDC_Disconn (void *p_class_dev);
static void USBH_CDC_DIC_DataTxCmpl (USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err);
static void USBH_CDC_DIC_DataRxCmpl (USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err);
static USBH_ERR USBH_CDC_EventRxAsync (USBH_CDC_DEV *p_cdc_dev);
static void USBH_CDC_CIC_EventRxCmpl(USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err);
/*
*********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* CDC CLASS DRIVER
*********************************************************************************************************
*/
USBH_CLASS_DRV USBH_CDC_ClassDrv = {
(CPU_INT08U *)"CDC",
USBH_CDC_GlobalInit,
USBH_CDC_ProbeDev,
0,
USBH_CDC_Suspend,
USBH_CDC_Resume,
USBH_CDC_Disconn
};
/*
*********************************************************************************************************
*********************************************************************************************************
* GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBH_CDC_RefAdd()
*
* Description : Increment application reference count to CDC device.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* Return(s) : USBH_ERR_NONE, if reference added successfully.
* USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_cdc_dev'.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_RefAdd (USBH_CDC_DEV *p_cdc_dev)
{
if (p_cdc_dev == (USBH_CDC_DEV *)0) {
return (USBH_ERR_INVALID_ARG);
}
(void)USBH_OS_MutexLock(p_cdc_dev->HMutex);
p_cdc_dev->RefCnt++; /* Increment app ref cnt to CDC dev. */
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_CDC_RefRel()
*
* Description : Decrement application reference count to CDC device. Free device if there is no more
* reference to it.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* Return(s) : USBH_ERR_NONE, if reference released successfully.
* USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_cdc_dev'.
* USBH_ERR_FREE, if device not successfully freed.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_RefRel (USBH_CDC_DEV *p_cdc_dev)
{
LIB_ERR err_lib;
if (p_cdc_dev == (USBH_CDC_DEV *)0) {
return (USBH_ERR_INVALID_ARG);
}
(void)USBH_OS_MutexLock(p_cdc_dev->HMutex);
if (p_cdc_dev->RefCnt > 0) {
p_cdc_dev->RefCnt--;
if ((p_cdc_dev->RefCnt == 0u) &&
(p_cdc_dev->State == USBH_CLASS_DEV_STATE_DISCONN)) {
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
Mem_PoolBlkFree( &USBH_CDC_DevPool,
(void *)p_cdc_dev,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
return (USBH_ERR_FREE);
} else {
return (USBH_ERR_NONE);
}
}
}
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
return (USBH_ERR_NONE);
}
/*
*********************************************************************************************************
* USBH_CDC_EvtNotifyReg()
*
* Description : Register application / subclass event callback functions.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_evt_notify Pointer to application's / sublasse's notify function.
*
* Return(s) : USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_cdc_dev' / 'p_evt_notify'.
*
* ---- RETURNED BY USBH_CDC_EventRxAsync ----
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE If endpoint type is not interrupt or direction is not IN.
* USBH_ERR_EP_INVALID_STATE If endpoint is not opened.
* USBH_ERR_ALLOC If URB cannot be allocated.
* USBH_ERR_UNKNOWN If unknown error occured.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_EventNotifyReg (USBH_CDC_DEV *p_cdc_dev,
SUBCLASS_NOTIFY p_evt_notify,
void *p_arg)
{
USBH_ERR err;
if ((p_cdc_dev == (USBH_CDC_DEV *)0) ||
(p_evt_notify == (SUBCLASS_NOTIFY)0)) {
return (USBH_ERR_INVALID_ARG);
}
p_cdc_dev->EvtNotifyPtr = p_evt_notify; /* Reg callback fnct provided by subclass. */
p_cdc_dev->EvtNotifyArgPtr = p_arg;
err = USBH_CDC_EventRxAsync(p_cdc_dev);
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_CmdTx()
*
* Description : Send CDC control command.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* b_req One-byte value that specifies request.
*
* bm_req_type One-byte value that specifies direction, type and the recipient of
* request.
*
* w_val Two-byte value used to pass information to device.
*
* p_buf Pointer to data buffer to transmit.
*
* buf_len Two-byte value containing buffer length in octets.
*
* Return(s) : USBH_ERR_NONE, if control command successfully sent.
* USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_cdc_dev'.
* USBH_ERR_DEV_NOT_READY, if device is not connected.
*
* ----- RETURNED BY USBH_CtrlTx() : -----
* USBH_ERR_UNKNOWN Unknown error occurred.
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
* USBH_ERR_HC_IO, Root hub input/output error.
* USBH_ERR_EP_STALL, Root hub does not support request.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_CmdTx (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U b_req,
CPU_INT08U bm_req_type,
CPU_INT16U w_val,
void *p_buf,
CPU_INT32U buf_len)
{
USBH_ERR err;
if (p_cdc_dev == (USBH_CDC_DEV *)0) {
return (USBH_ERR_INVALID_ARG);
}
if (p_cdc_dev->State != USBH_CLASS_DEV_STATE_CONN) {
return (USBH_ERR_DEV_NOT_READY);
}
USBH_CtrlTx(p_cdc_dev->DevPtr, /* Issue req to dev. */
b_req,
bm_req_type,
w_val,
p_cdc_dev->CIC_IF_Nbr,
p_buf,
buf_len,
USBH_CFG_STD_REQ_TIMEOUT,
&err);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Reset( p_cdc_dev->DevPtr,
(USBH_EP *)0);
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_RespRx()
*
* Description : Send CDC control rx request.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* b_req One-byte value that specifies request.
*
* bm_req_type One-byte value that specifies direction, type and the recipient of
* request.
*
* w_val Two-byte value used to pass information to device.
*
* p_buf Pointer to data buffer to hold received data.
*
* buf_len Two-byte value containing buffer length in octets.
*
* Return(s) : USBH_ERR_NONE, if control command successfully received.
* USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_cdc_dev'.
* USBH_ERR_DEV_NOT_READY, if device is not connected.
*
* ----- RETURNED BY USBH_CtrlRx() : -----
* USBH_ERR_UNKNOWN, Unknown error occurred.
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
* USBH_ERR_HC_IO, Root hub input/output error.
* USBH_ERR_EP_STALL, Root hub does not support request.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_RespRx (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U b_req,
CPU_INT08U bm_req_type,
CPU_INT16U w_val,
void *p_buf,
CPU_INT32U buf_len)
{
USBH_ERR err;
if (p_cdc_dev == (USBH_CDC_DEV *)0) {
return (USBH_ERR_INVALID_ARG);
}
if (p_cdc_dev->State != USBH_CLASS_DEV_STATE_CONN) {
return (USBH_ERR_DEV_NOT_READY);
}
USBH_CtrlRx(p_cdc_dev->DevPtr,
b_req,
bm_req_type,
w_val,
p_cdc_dev->CIC_IF_Nbr,
p_buf,
buf_len,
USBH_CFG_STD_REQ_TIMEOUT,
&err);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Reset( p_cdc_dev->DevPtr,
(USBH_EP *)0);
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_DataTx()
*
* Description : Transfer raw buffer to device.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_buf Pointer to buffer of data that will be sent.
*
* buf_len Buffer length in octets.
*
* p_err Variable that will receive the return error code from this function.
*
* ----- RETURNED BY USBH_BulkTx() : -----
* USBH_ERR_NONE Bulk transfer successfully transmitted.
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT.
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
* USBH_ERR_NONE, URB is successfully submitted to host controller.
* Host controller drivers error code, Otherwise.
*
* Return(s) : Number of octets transferred.
*
* Note(s) : None.
*********************************************************************************************************
*/
CPU_INT32U USBH_CDC_DataTx (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
USBH_ERR *p_err)
{
CPU_INT32U xfer_len;
xfer_len = USBH_BulkTx( &p_cdc_dev->DIC_BulkOut,
(void *)p_buf,
buf_len,
0u,
p_err);
if (*p_err != USBH_ERR_NONE) {
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
&p_cdc_dev->DIC_BulkOut);
if (*p_err == USBH_ERR_EP_STALL) {
USBH_EP_StallClr(&p_cdc_dev->DIC_BulkOut);
}
return (0u);
}
return (xfer_len);
}
/*
*********************************************************************************************************
* USBH_CDC_DataTxAsync()
*
* Description : Transfer raw buffer to device asynchronously.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_buf Pointer to buffer of data that will be sent.
*
* buf_len Buffer length in octets.
*
* tx_cmpl_notify Function that will be invoked upon completion of transmit operation.
*
* p_arg Pointer to argument that will be passed as parameter of 'tx_cmpl_notify'.
*
* Return(s) : USBH_ERR_NONE, if data successfully transmitted.
*
* ----- RETURNED BY USBH_BulkTxAsync() : -----
* USBH_ERR_NONE If request is successfully submitted.
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE If endpoint type is not bulk or direction is not OUT.
* USBH_ERR_EP_INVALID_STATE If endpoint is not opened.
* USBH_ERR_ALLOC If URB cannot be allocated.
* USBH_ERR_UNKNOWN If unknown error occured.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_DataTxAsync (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
SUBCLASS_NOTIFY tx_cmpl_notify,
void *p_arg)
{
USBH_ERR err;
p_cdc_dev->DataTxNotifyPtr = tx_cmpl_notify;
p_cdc_dev->DataTxNotifyArgPtr = p_arg;
err = USBH_BulkTxAsync( &p_cdc_dev->DIC_BulkOut,
(void *)p_buf,
buf_len,
USBH_CDC_DIC_DataTxCmpl,
(void *)p_cdc_dev);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
&p_cdc_dev->DIC_BulkOut);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(&p_cdc_dev->DIC_BulkOut);
}
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_DataRx()
*
* Description : Receive raw data from device.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_buf Pointer to data buffer to hold received data.
*
* buf_len Buffer length in octets.
*
* p_err Variable that will receive the return error code from this function.
*
* ----- RETURNED BY USBH_BulkRx() : -----
* USBH_ERR_NONE Bulk transfer successfully received.
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN.
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
* USBH_ERR_NONE, URB is successfully submitted to host controller.
* Host controller drivers error code, Otherwise.
*
* Return(s) : Number of octets received.
*
* Note(s) : None.
*********************************************************************************************************
*/
CPU_INT32U USBH_CDC_DataRx (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
USBH_ERR *p_err)
{
CPU_INT32U xfer_len;
xfer_len = USBH_BulkRx( &p_cdc_dev->DIC_BulkIn,
(void *)p_buf,
buf_len,
0u,
p_err);
if (*p_err != USBH_ERR_NONE) {
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
&p_cdc_dev->DIC_BulkIn);
if (*p_err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(&p_cdc_dev->DIC_BulkIn);
}
return (0u);
}
return (xfer_len);
}
/*
*********************************************************************************************************
* USBH_CDC_DataRxAsync()
*
* Description : Receive raw data from device asynchronously.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_buf Pointer to data buffer to hold received data.
*
* buf_len Buffer length in octets.
*
* rx_cmpl_notify Function that will be invoked upon completion of receive operation.
*
* p_arg Pointer to argument that will be passed as parameter of 'tx_cmpl_notify'.
*
* Return(s) : USBH_ERR_NONE, if data successfully received.
*
* ----- RETURNED BY USBH_BulkRxAsync() : -----
* USBH_ERR_NONE If request is successfully submitted.
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE If endpoint type is not Bulk or direction is not IN.
* USBH_ERR_EP_INVALID_STATE If endpoint is not opened.
* USBH_ERR_ALLOC If URB cannot be allocated.
* USBH_ERR_UNKNOWN If unknown error occured.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_DataRxAsync (USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
SUBCLASS_NOTIFY rx_cmpl_notify,
void *p_arg)
{
USBH_ERR err;
p_cdc_dev->DataRxNotifyPtr = rx_cmpl_notify;
p_cdc_dev->DataRxNotifyArgPtr = p_arg;
err = USBH_BulkRxAsync( &p_cdc_dev->DIC_BulkIn,
(void *)p_buf,
buf_len,
USBH_CDC_DIC_DataRxCmpl,
(void *)p_cdc_dev);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
&p_cdc_dev->DIC_BulkIn);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(&p_cdc_dev->DIC_BulkIn);
}
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_EventRxAsync()
*
* Description : Receive serial state of device.
*
* Argument(s) : p_cdc_dev Pointer to the CDC device.
*
* Return(s) : USBH_ERR_NONE, if data successfully received.
*
* ----- RETURNED BY USBH_IntrRxAsync() : -----
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_TYPE If endpoint type is not interrupt or direction is not IN.
* USBH_ERR_EP_INVALID_STATE If endpoint is not opened.
* USBH_ERR_ALLOC If URB cannot be allocated.
* USBH_ERR_UNKNOWN If unknown error occured.
* Host controller drivers error code, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_CDC_EventRxAsync (USBH_CDC_DEV *p_cdc_dev)
{
USBH_ERR err;
err = USBH_IntrRxAsync( &p_cdc_dev->CIC_IntrIn,
(void *)p_cdc_dev->EventNotifyBuf,
USBH_CDC_LEN_EVENT_BUF,
USBH_CDC_CIC_EventRxCmpl,
(void *)p_cdc_dev);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
&p_cdc_dev->CIC_IntrIn);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(&p_cdc_dev->CIC_IntrIn);
}
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_CommIF_Get()
*
* Description : Get pointer to communication interface.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* Return(s) : Pointer to communication interface.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_IF *USBH_CDC_CommIF_Get (USBH_CDC_DEV *p_cdc_dev)
{
return (p_cdc_dev->CIC_IF_Ptr);
}
/*
*********************************************************************************************************
* USBH_CDC_SubclassGet()
*
* Description : Get subclass code.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_subclass Pointer to variable that will receive subclass code.
*
* Return(s) : USBH_ERR_NONE, if subclass code successfully fetched.
*
* ----- RETURNED BY USBH_IF_DescGet() : -----
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'alt_ix'.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_SubclassGet(USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_subclass)
{
USBH_IF_DESC if_desc;
USBH_ERR err;
err = USBH_IF_DescGet(p_cdc_dev->CIC_IF_Ptr,
0u,
&if_desc);
if (err != USBH_ERR_NONE) {
*p_subclass = 0u;
return (err);
}
*p_subclass = if_desc.bInterfaceSubClass;
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_ProtocolGet()
*
* Description : Get protocol code.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* p_protocol Pointer to variable that will receive protocol code.
*
* Return(s) : USBH_ERR_NONE, if protocol code successfully fetched.
*
* ----- RETURNED BY USBH_IF_DescGet() : -----
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'alt_ix'.
*
* Note(s) : None.
*********************************************************************************************************
*/
USBH_ERR USBH_CDC_ProtocolGet(USBH_CDC_DEV *p_cdc_dev,
CPU_INT08U *p_protocol)
{
USBH_IF_DESC if_desc;
USBH_ERR err;
err = USBH_IF_DescGet(p_cdc_dev->CIC_IF_Ptr,
0u,
&if_desc);
if (err != USBH_ERR_NONE) {
*p_protocol = 0u;
return (err);
}
*p_protocol = if_desc.bInterfaceProtocol;
return (err);
}
/*
*********************************************************************************************************
*********************************************************************************************************
* LOCAL FUNCTION
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBH_CDC_GlobalInit()
*
* Description : Initialize the internal variables and structure required by CDC.
*
* Argument(s) : p_err Variable that will receive the return error code from this function.
* USBH_ERR_NONE, Initialization was succesfull.
* USBH_ERR_ALLOC, Memory pool creation failed.
*
* ----- RETURNED BY USBH_OS_MutexCreate() : -----
* USBH_ERR_OS_SIGNAL_CREATE, if mutex creation failed.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_GlobalInit (USBH_ERR *p_err)
{
CPU_INT08U ix;
CPU_SIZE_T octets_reqd;
CPU_SIZE_T cdc_len;
LIB_ERR err_lib;
cdc_len = sizeof(USBH_CDC_DEV) * USBH_CDC_CFG_MAX_DEV;
Mem_Clr((void *)USBH_CDC_DevArr,
cdc_len);
for (ix = 0u; ix < USBH_CDC_CFG_MAX_DEV; ix++) { /* --------------- INIT CDC DEV STRUCT ---------------- */
*p_err = USBH_OS_MutexCreate(&USBH_CDC_DevArr[ix].HMutex);
if (*p_err != USBH_ERR_NONE) {
return;
}
USBH_CDC_DevArr[ix].State = USBH_CLASS_DEV_STATE_NONE;
Mem_Clr((void *)USBH_CDC_DevArr[ix].EventNotifyBuf,
USBH_CDC_LEN_RESPONSE_AVAIL);
}
Mem_PoolCreate ( &USBH_CDC_DevPool,
(void *)USBH_CDC_DevArr,
cdc_len,
USBH_CDC_CFG_MAX_DEV,
sizeof(USBH_CDC_DEV),
sizeof(CPU_ALIGN),
&octets_reqd,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBH_ERR_ALLOC;
} else {
*p_err = USBH_ERR_NONE;
}
}
/*
*********************************************************************************************************
* USBH_CDC_ProbeDev()
*
* Description : Determine if device implements CDC.
*
* Argument(s) : p_dev Pointer to device.
*
* p_err Variable that will receive the return error code from this function.
*
* USBH_ERR_NONE Device is CDC.
* USBH_ERR_CLASS_PROBE_FAIL Device is not CDC.
* USBH_ERR_ALLOC Cannot allocate CDC structure.
* USBH_ERR_DESC_INVALID Invalid union descriptor.
*
* ----- RETURNED BY USBH_CfgSet() : -----
* USBH_ERR_UNKNOWN Unknown error occurred.
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
* USBH_ERR_HC_IO, Root hub input/output error.
* USBH_ERR_EP_STALL, Root hub does not support request.
* Host controller drivers error code, Otherwise.
*
* ---- RETURNED BY USBH_CDC_EP_Open ----
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
* Host controller drivers error, Otherwise.
*
* ---- RETURNED BY USBH_CDC_UnionDescParse ----
* USBH_ERR_DESC_INVALID, if union descriptor is invalid.
*
* Return(s) : pcdc_acm_dev, if device implements CDC.
* 0, otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void *USBH_CDC_ProbeDev (USBH_DEV *p_dev,
USBH_ERR *p_err)
{
CPU_INT08U if_ix;
CPU_INT08U cic_if_nbr = 0u;
CPU_INT08U dic_if_nbr = 0u;
CPU_INT08U nbr_ifs;
USBH_CFG *p_cfg;
USBH_DEV_DESC dev_desc;
USBH_IF_DESC if_desc;
USBH_IF *p_if;
USBH_IF *p_cic_if;
USBH_IF *p_dic_if;
USBH_CDC_DEV *p_cdc_dev;
USBH_CDC_UNION_DESC union_desc;
LIB_ERR err_lib;
p_cic_if = (USBH_IF *)0;
p_dic_if = (USBH_IF *)0;
USBH_DevDescGet(p_dev, &dev_desc);
if (dev_desc.bDeviceClass != USBH_CLASS_CODE_CDC_CTRL) {
*p_err = USBH_ERR_CLASS_PROBE_FAIL;
return ((void *)0);
}
p_cfg = USBH_CfgGet(p_dev, 0u);
if (p_cfg == (USBH_CFG *) 0) {
*p_err = USBH_ERR_CLASS_PROBE_FAIL;
return ((void *)0);
}
nbr_ifs = USBH_CfgIF_NbrGet(p_cfg);
for (if_ix = 0u; if_ix < nbr_ifs; if_ix++) {
p_if = USBH_IF_Get(p_cfg, if_ix);
USBH_IF_DescGet(p_if, /* Get IF desc from IF. */
0u,
&if_desc);
switch (if_desc.bInterfaceClass) {
case USBH_CLASS_CODE_CDC_CTRL:
p_cic_if = p_if;
cic_if_nbr = if_desc.bInterfaceNumber;
*p_err = USBH_CDC_UnionDescParse(&union_desc, p_if);
if (*p_err != USBH_ERR_NONE) {
return ((void *)0);
}
if (union_desc.bMasterInterface != cic_if_nbr) {
*p_err = USBH_ERR_DESC_INVALID;
return ((void *)0);
}
dic_if_nbr = union_desc.bSlaveInterface0;
break;
case USBH_CLASS_CODE_CDC_DATA:
if (p_cic_if != (USBH_IF *)0) {
if (if_desc.bInterfaceNumber == dic_if_nbr) {
p_dic_if = p_if;
}
}
break;
default:
break;
}
if ((p_cic_if != (USBH_IF *)0) &&
(p_dic_if != (USBH_IF *)0)) {
break;
}
}
if ((p_cic_if == (USBH_IF *)0) ||
(p_dic_if == (USBH_IF *)0)) {
*p_err = USBH_ERR_CLASS_PROBE_FAIL;
return ((void *)0);
}
*p_err = USBH_CfgSet(p_dev, 1u); /* Select 1st cfg. */
if (*p_err != USBH_ERR_NONE) {
return ((void *)0);
}
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
USBH_PRINT_LOG("CDC device connected\r\n");
#endif
/* Alloc a dev from CDC dev pool. */
p_cdc_dev = (USBH_CDC_DEV *)Mem_PoolBlkGet(&USBH_CDC_DevPool,
sizeof(USBH_CDC_DEV),
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBH_ERR_ALLOC;
return ((void *)0);
}
p_cdc_dev->DevPtr = p_dev;
p_cdc_dev->CIC_IF_Nbr = cic_if_nbr;
p_cdc_dev->CIC_IF_Ptr = p_cic_if;
p_cdc_dev->DIC_IF_Nbr = dic_if_nbr;
p_cdc_dev->DIC_IF_Ptr = p_dic_if;
*p_err = USBH_CDC_EP_Open(p_cdc_dev);
if (*p_err != USBH_ERR_NONE) {
Mem_PoolBlkFree( &USBH_CDC_DevPool,
(void *)p_cdc_dev,
&err_lib);
p_cdc_dev = (USBH_CDC_DEV *)0;
return ((void *)p_cdc_dev);
}
p_cdc_dev->State = USBH_CLASS_DEV_STATE_CONN;
return ((void *)p_cdc_dev);
}
/*
*********************************************************************************************************
* USBH_CDC_Disconn()
*
* Description : Handle disconnection of a CDC device.
*
* Argument(s) : p_class_dev Pointer to CDC device.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_Disconn (void *p_class_dev)
{
LIB_ERR err_lib;
USBH_CDC_DEV *p_cdc_dev;
p_cdc_dev = (USBH_CDC_DEV *)p_class_dev;
(void)USBH_OS_MutexLock(p_cdc_dev->HMutex);
p_cdc_dev->State = USBH_CLASS_DEV_STATE_DISCONN;
USBH_EP_Close(&p_cdc_dev->CIC_IntrIn); /* Close EPs. */
USBH_EP_Close(&p_cdc_dev->DIC_BulkIn);
USBH_EP_Close(&p_cdc_dev->DIC_BulkOut);
if (p_cdc_dev->RefCnt == 0) { /* Release CDC dev if app ref cnt is 0. */
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
Mem_PoolBlkFree( &USBH_CDC_DevPool,
(void *)p_cdc_dev,
&err_lib);
return;
}
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
}
/*
*********************************************************************************************************
* USBH_CDC_Suspend()
*
* Description : Put CDC device in suspended state.
*
* Argument(s) : p_class_dev Pointer to CDC device.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_Suspend (void *p_class_dev)
{
USBH_CDC_DEV *p_cdc_dev;
p_cdc_dev = (USBH_CDC_DEV *)p_class_dev;
(void)USBH_OS_MutexLock(p_cdc_dev->HMutex);
p_cdc_dev->State = USBH_CLASS_DEV_STATE_SUSPEND;
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
}
/*
*********************************************************************************************************
* USBH_CDC_Resume()
*
* Description : Put CDC device back to "connected" state.
*
* Argument(s) : p_class_dev Pointer to CDC device.
*
* Return(s) : None..
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_Resume (void *p_class_dev)
{
USBH_CDC_DEV *p_cdc_dev;
p_cdc_dev = (USBH_CDC_DEV *)p_class_dev;
(void)USBH_OS_MutexLock(p_cdc_dev->HMutex);
p_cdc_dev->State = USBH_CLASS_DEV_STATE_CONN;
(void)USBH_OS_MutexUnlock(p_cdc_dev->HMutex);
}
/*
*********************************************************************************************************
* USBH_CDC_EP_Open()
*
* Description : Open device endpoints.
*
* Argument(s) : p_cdc_dev Pointer to CDC device.
*
* Return(s) : USBH_ERR_NONE. If endpoints opened successfully.
*
* ----- RETURNED BY USBH_IntrInOpen() : -----
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
* Host controller drivers error, Otherwise.
*
* ----- RETURNED BY USBH_BulkInOpen() : -----
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
* Host controller drivers error, Otherwise.
*
* ----- RETURNED BY USBH_BulkOutOpen() : -----
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
* Host controller drivers error, Otherwise.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_CDC_EP_Open (USBH_CDC_DEV *p_cdc_dev)
{
USBH_ERR err;
err = USBH_IntrInOpen(p_cdc_dev->DevPtr,
p_cdc_dev->CIC_IF_Ptr,
&p_cdc_dev->CIC_IntrIn);
if (err != USBH_ERR_NONE) {
return (err);
}
err = USBH_BulkInOpen(p_cdc_dev->DevPtr,
p_cdc_dev->DIC_IF_Ptr,
&p_cdc_dev->DIC_BulkIn);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Close(&p_cdc_dev->CIC_IntrIn);
return (err);
}
err = USBH_BulkOutOpen(p_cdc_dev->DevPtr,
p_cdc_dev->DIC_IF_Ptr,
&p_cdc_dev->DIC_BulkOut);
if (err != USBH_ERR_NONE) {
(void)USBH_EP_Close(&p_cdc_dev->CIC_IntrIn);
(void)USBH_EP_Close(&p_cdc_dev->DIC_BulkIn);
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_UnionDescParse()
*
* Description : Parse union functional descriptor into USBH_CDC_UNION_DESC structure.
*
* Argument(s) : p_union_desc Variable that will receive union descriptor.
*
* p_if Pointer to interface.
*
* Return(s) : USBH_ERR_NONE. if parsing is successful.
* USBH_ERR_DESC_INVALID, if union descriptor is invalid.
*
* Note(s) : None.
*********************************************************************************************************
*/
static USBH_ERR USBH_CDC_UnionDescParse (USBH_CDC_UNION_DESC *p_union_desc,
USBH_IF *p_if)
{
USBH_ERR err;
CPU_INT08U *p_if_desc;
err = USBH_ERR_DESC_INVALID;
p_if_desc = (CPU_INT08U *)p_if->IF_DataPtr;
while (p_if_desc[1] != USBH_DESC_TYPE_EP) {
if (p_if_desc[2] == USBH_CDC_FNCTL_DESC_SUB_UFD) {
p_union_desc->bFunctionLength = p_if_desc[0];
p_union_desc->bDescriptorType = p_if_desc[1];
p_union_desc->bDescriptorSubtype = p_if_desc[2];
p_union_desc->bMasterInterface = p_if_desc[3];
p_union_desc->bSlaveInterface0 = p_if_desc[4];
err = USBH_ERR_NONE;
break;
} else {
p_if_desc += p_if_desc[0];
}
}
return (err);
}
/*
*********************************************************************************************************
* USBH_CDC_DIC_DataTxCmpl()
*
* Description : Asynchronous data transfer completion function.
*
* Argument(s) : p_ep Pointer to endpoint.
*
* p_buf Pointer to transmit buffer.
*
* buf_len Buffer length in octets.
*
* xfer_len Number of octets transferred.
*
* p_arg Asynchronous function argument.
*
* err Status of transaction.
*
* Return(s) : none
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBH_CDC_DIC_DataTxCmpl (USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err)
{
USBH_CDC_DEV *p_cdc_dev;
(void)buf_len;
p_cdc_dev = (USBH_CDC_DEV *)p_arg;
if (err != USBH_ERR_NONE) { /* Chk status of transaction. */
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
p_ep);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(p_ep);
}
}
p_cdc_dev->DataTxNotifyPtr( p_cdc_dev->DataTxNotifyArgPtr,
(CPU_INT08U *)p_buf,
xfer_len,
err);
}
/*
*********************************************************************************************************
* USBH_CDC_DIC_DataRxCmpl()
*
* Description : Asynchronous data receive completion function.
*
* Argument(s) : p_ep Pointer to endpoint.
*
* p_buf Pointer to receive buffer.
*
* buf_len Buffer length in octets.
*
* xfer_len Number of octets received.
*
* p_arg Asynchronous function argument.
*
* err Status of transaction.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_DIC_DataRxCmpl (USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err)
{
USBH_CDC_DEV *p_cdc_dev;
(void)buf_len;
p_cdc_dev = (USBH_CDC_DEV *)p_arg;
if (err != USBH_ERR_NONE) { /* Check status of transaction. */
(void)USBH_EP_Reset(p_cdc_dev->DevPtr,
p_ep);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(p_ep);
}
}
p_cdc_dev->DataRxNotifyPtr( p_cdc_dev->DataRxNotifyArgPtr,
(CPU_INT08U *)p_buf,
xfer_len,
err);
}
/*
*********************************************************************************************************
* USBH_CDC_CIC_EventRxCmpl()
*
* Description : Asynchronous serial state receive completion function.
*
* Argument(s) : p_ep Pointer to endpoint.
*
* p_buf Pointer to receive buffer.
*
* buf_len Buffer length in octets.
*
* xfer_len Number of octets received.
*
* p_arg Asynchronous function argument.
*
* err Status of transaction.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
static void USBH_CDC_CIC_EventRxCmpl (USBH_EP *p_ep,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBH_ERR err)
{
USBH_CDC_DEV *p_cdc_dev;
(void)buf_len;
p_cdc_dev = (USBH_CDC_DEV*)p_arg;
if (err != USBH_ERR_NONE) { /* Chk status of transaction. */
(void)USBH_EP_Reset(p_cdc_dev->DevPtr, p_ep);
if (err == USBH_ERR_EP_STALL) {
(void)USBH_EP_StallClr(p_ep);
}
}
if (p_cdc_dev->EvtNotifyPtr != (SUBCLASS_NOTIFY)0) {
p_cdc_dev->EvtNotifyPtr( p_cdc_dev->EvtNotifyArgPtr,
(CPU_INT08U *)p_buf,
xfer_len,
err);
}
(void)USBH_CDC_EventRxAsync(p_cdc_dev);
}
/*
*********************************************************************************************************
* END
*********************************************************************************************************
*/