1968 lines
75 KiB
C
1968 lines
75 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/USB-Device
|
|
* The Embedded USB Device 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.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* USB COMMUNICATIONS DEVICE CLASS (CDC)
|
|
* ETHERNET EMULATION MODEL (EEM)
|
|
*
|
|
* Filename : usbd_cdc_eem.c
|
|
* Version : V4.06.01
|
|
*********************************************************************************************************
|
|
* Note(s) : (1) This implementation is compliant with the CDC-EEM specification "Universal Serial
|
|
* Bus Communications Class Subclass Specification for Ethernet Emulation Model
|
|
* Devices" revision 1.0. February 2, 2005.
|
|
*
|
|
* (2) This class implementation does NOT use the CDC base class implementation as
|
|
* CDC-EEM specification does not follow the CDC specification revision 1.2
|
|
* December 6, 2012.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define MICRIUM_SOURCE
|
|
#define USBD_CDC_EEM_MODULE
|
|
#include <lib_mem.h>
|
|
#include <usbd_cfg.h>
|
|
#include <KAL/kal.h>
|
|
#include "usbd_cdc_eem.h"
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* Dflt Rx buffer qty is 1. */
|
|
#ifndef USBD_CDC_EEM_CFG_RX_BUF_QTY_PER_DEV
|
|
#define USBD_CDC_EEM_CFG_RX_BUF_QTY_PER_DEV 1u
|
|
#endif
|
|
|
|
/* Max nbr of comm struct. */
|
|
#define USBD_CDC_EEM_COMM_NBR_MAX (USBD_CDC_EEM_CFG_MAX_NBR_DEV * \
|
|
USBD_CDC_EEM_CFG_MAX_NBR_CFG)
|
|
|
|
|
|
#define USBD_CDC_EEM_MAX_RETRY_CNT 3u /* Max nbr of retry when Rx buf submission fails.*/
|
|
|
|
|
|
#define USBD_CDC_EEM_SUBCLASS_CODE 0x0C
|
|
#define USBD_CDC_EEM_PROTOCOL_CODE 0x07
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* ZERO LENGTH EEM (ZLE) SPECIAL PACKET
|
|
*
|
|
* Note(s) : (1) ZLE packet is defined in "Universal Serial Bus Communications Class Subclass
|
|
* Specification for Ethernet Emulation Model Devices" revision 1.0. February 2, 2005,
|
|
* section 5.1.2.3.1.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_CDC_EEM_HDR_ZLE 0x0000
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* PACKET TYPES
|
|
*
|
|
* Note(s) : (1) Packet types are defined in "Universal Serial Bus Communications Class Subclass
|
|
* Specification for Ethernet Emulation Model Devices" revision 1.0. February 2, 2005,
|
|
* section 5.1.2.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_CDC_EEM_PKT_TYPE_MASK DEF_BIT_15
|
|
#define USBD_CDC_EEM_PKT_TYPE_PAYLOAD 0u
|
|
#define USBD_CDC_EEM_PKT_TYPE_CMD 1u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* EEM PAYLOAD PACKET HEADER DEFINITIONS
|
|
*
|
|
* Note(s) : (1) Payload header format is defined in "Universal Serial Bus Communications Class Subclass
|
|
* Specification for Ethernet Emulation Model Devices" revision 1.0. February 2, 2005,
|
|
* section 5.1.2.1.
|
|
*
|
|
* (a) Payload packets header have the following format:
|
|
*
|
|
* +---------+----------------------------------+
|
|
* | Bit | 15 | 14 | 13..0 |
|
|
* +---------+----------------------------------+
|
|
* | Content | bmType | bmCRC | Length of |
|
|
* | | (0) | | Ethernet frame |
|
|
* +---------+----------------------------------+
|
|
*
|
|
* (1) bmCRC indicates whether the Ethernet frame contains a valid CRC or a CRC set
|
|
* to 0xDEADBEEF.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* ----------------- PAYLOAD PKT CRC ------------------ */
|
|
#define USBD_CDC_EEM_PAYLOAD_CRC_MASK DEF_BIT_14
|
|
#define USBD_CDC_EEM_PAYLOAD_CRC_NOT_CALC 0u
|
|
#define USBD_CDC_EEM_PAYLOAD_CRC_CALC 1u
|
|
|
|
/* ----------------- PAYLOAD PKT LEN ------------------ */
|
|
#define USBD_CDC_EEM_PAYLOAD_LEN_MASK DEF_BIT_FIELD(14u, 0u)
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* EEM COMMAND PACKET HEADER DEFINITIONS
|
|
*
|
|
* Note(s) : (1) Command header format is defined in "Universal Serial Bus Communications Class Subclass
|
|
* Specification for Ethernet Emulation Model Devices" revision 1.0. February 2, 2005,
|
|
* section 5.1.2.2.
|
|
*
|
|
* (a) Command packets header have the following format:
|
|
*
|
|
* +---------+------------------------------------------------+
|
|
* | Bit | 15 | 14 | 13..11 | 10..0 |
|
|
* +---------+------------------------------------------------+
|
|
* | Content | bmType | bmReserved | bmEEMCmd | bmEEMCmdParam |
|
|
* | | (1) | (0) | | |
|
|
* +---------+------------------------------------------------+
|
|
*
|
|
* (1) bmEEMCmd gives the code of the command to execute.
|
|
*
|
|
* (2) bmEEMCmdParam gives extra information for the command execution. Format depends
|
|
* on the command code.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* ------------------- CMD RSVD BIT ------------------- */
|
|
#define USBD_CDC_EEM_CMD_RSVD_MASK DEF_BIT_14
|
|
#define USBD_CDC_EEM_CMD_RSVD_OK 0u
|
|
|
|
/* ------------------- CMD PKT CODE ------------------- */
|
|
#define USBD_CDC_EEM_CMD_CODE_MASK DEF_BIT_FIELD(3u, 11u)
|
|
#define USBD_CDC_EEM_CMD_CODE_ECHO 0u
|
|
#define USBD_CDC_EEM_CMD_CODE_ECHO_RESP 1u
|
|
#define USBD_CDC_EEM_CMD_CODE_SUSP_HINT 2u
|
|
#define USBD_CDC_EEM_CMD_CODE_RESP_HINT 3u
|
|
#define USBD_CDC_EEM_CMD_CODE_RESP_CMPL_HINT 4u
|
|
#define USBD_CDC_EEM_CMD_CODE_TICKLE 5u
|
|
|
|
/* ------------------- CMD PKT PARAM ------------------- */
|
|
#define USBD_CDC_EEM_CMD_PARAM_MASK DEF_BIT_FIELD(11u, 0u)
|
|
|
|
/* ------------------- ECHO CMD LEN ------------------- */
|
|
#define USBD_CDC_EEM_CMD_PARAM_ECHO_LEN_MASK DEF_BIT_FIELD(10u, 0u)
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* Dflt CRC value. */
|
|
static const CPU_INT08U USBD_CDC_EEM_PayloadCRC[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* FORWARD DECLARATIONS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_eem_ctrl USBD_CDC_EEM_CTRL; /* Forward declaration. */
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS STATES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef enum usbd_cdc_eem_state {
|
|
USBD_CDC_EEM_STATE_NONE = 0,
|
|
USBD_CDC_EEM_STATE_INIT,
|
|
USBD_CDC_EEM_STATE_CFG
|
|
} USBD_CDC_EEM_STATE;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS BUFFER QUEUE ENTRY
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_eem_buf_entry {
|
|
CPU_INT08U *BufPtr; /* Pointer to buffer. */
|
|
CPU_INT16U BufLen; /* Buffer length in bytes. */
|
|
CPU_BOOLEAN CrcComputed; /* Flag indicates if CRC computed for this buf. */
|
|
} USBD_CDC_EEM_BUF_ENTRY;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS COMM INFO
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_eem_comm {
|
|
USBD_CDC_EEM_CTRL *CtrlPtr; /* Ptr to ctrl info. */
|
|
/* Avail EP for comm: Bulk (and Intr) */
|
|
CPU_INT08U DataInEpAddr; /* Address of Bulk IN EP. */
|
|
CPU_INT08U DataOutEpAddr; /* Address of Bulk OUT EP. */
|
|
} USBD_CDC_EEM_COMM;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS BUFFER QUEUE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_eem_buf_q {
|
|
USBD_CDC_EEM_BUF_ENTRY *Tbl; /* Ptr to table of buffer entry. */
|
|
CPU_INT08U InIdx; /* In Q index. */
|
|
CPU_INT08U OutIdx; /* Out Q index. */
|
|
CPU_INT08U Cnt; /* Nbr of elements in Q. */
|
|
CPU_INT08U Size; /* Size of Q. */
|
|
} USBD_CDC_EEM_BUF_Q;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS CTRL INFO
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
struct usbd_cdc_eem_ctrl {
|
|
CPU_INT08U DevNbr; /* Dev nbr to which this class instance is associated. */
|
|
CPU_INT08U ClassNbr; /* Class instacne number. */
|
|
USBD_CDC_EEM_COMM *CommPtr; /* Ptr to comm. */
|
|
|
|
USBD_CDC_EEM_STATE State; /* Class instance current state. */
|
|
CPU_INT08U StartCnt; /* Start cnt. */
|
|
KAL_LOCK_HANDLE StateLockHandle; /* Handle on lock for class instance state. */
|
|
|
|
CPU_INT08U RxErrCnt; /* Cnt of Rx error. */
|
|
|
|
/* Ptr to Rx buffer table. */
|
|
CPU_INT08U *RxBufPtrTbl[USBD_CDC_EEM_CFG_RX_BUF_QTY_PER_DEV];
|
|
|
|
CPU_INT08U *BufEchoPtr; /* Ptr to buffer that contains echo data. */
|
|
|
|
USBD_CDC_EEM_DRV *DrvPtr; /* Ptr to network driver. */
|
|
void *DrvArgPtr; /* Arg of network driver. */
|
|
|
|
/* ----------------- RX STATE MACHINE ----------------- */
|
|
CPU_INT16U CurHdr; /* Hdr of current buffer. */
|
|
CPU_INT32U CurBufLenRem; /* Remaining length of current buffer. */
|
|
CPU_INT08U *CurBufPtr; /* Pointer to current network buffer. */
|
|
CPU_INT16U CurBufIx; /* Index of network buffer to write. */
|
|
CPU_BOOLEAN CurBufCrcComputed; /* Flag indicates if CRC is computed on current buf. */
|
|
|
|
/* ---------------- NETWORK BUFFER QS ----------------- */
|
|
USBD_CDC_EEM_BUF_Q RxBufQ; /* Rx buffer Q. */
|
|
USBD_CDC_EEM_BUF_Q TxBufQ; /* Tx buffer Q. */
|
|
CPU_BOOLEAN TxInProgress; /* Flag that indicates if a Tx is in progress. */
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL TABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
/* CDC EEM class instances array. */
|
|
static USBD_CDC_EEM_CTRL USBD_CDC_EEM_CtrlTbl[USBD_CDC_EEM_CFG_MAX_NBR_DEV];
|
|
static CPU_INT08U USBD_CDC_EEM_CtrlNbrNext;
|
|
/* CDC EEM class comm array. */
|
|
static USBD_CDC_EEM_COMM USBD_CDC_EEM_CommTbl[USBD_CDC_EEM_COMM_NBR_MAX];
|
|
static CPU_INT08U USBD_CDC_EEM_CommNbrNext;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_CDC_EEM_Disconn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_CDC_EEM_CommStart (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err);
|
|
|
|
static void USBD_CDC_EEM_RxCmpl (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);
|
|
|
|
static void USBD_CDC_EEM_TxCmpl (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);
|
|
|
|
static void USBD_CDC_EEM_TxBufSubmit(USBD_CDC_EEM_CTRL *p_ctrl,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT16U buf_len,
|
|
USBD_ERR *p_err);
|
|
|
|
static void USBD_CDC_EEM_BufQ_Add (USBD_CDC_EEM_BUF_Q *p_buf_q,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT16U buf_len,
|
|
CPU_BOOLEAN crc_computed);
|
|
|
|
static CPU_INT08U *USBD_CDC_EEM_BufQ_Get (USBD_CDC_EEM_BUF_Q *p_buf_q,
|
|
CPU_INT16U *p_buf_len,
|
|
CPU_BOOLEAN *p_crc_computed);
|
|
|
|
static void USBD_CDC_EEM_StateLock (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err);
|
|
|
|
static void USBD_CDC_EEM_StateUnlock(USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC-EEM CLASS DRIVER
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBD_CLASS_DRV USBD_CDC_EEM_Drv = {
|
|
USBD_CDC_EEM_Conn,
|
|
USBD_CDC_EEM_Disconn,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
#endif
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONFIGURATION ERRORS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* GLOBAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_Init()
|
|
*
|
|
* Description : Initializes internal structures and variables used by the CDC EEM class.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_OS_SIGNAL_CREATE Unable to create state lock.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_Init (USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U ix;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
USBD_CDC_EEM_COMM *p_comm;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
#endif
|
|
|
|
for (ix = 0u; ix < USBD_CDC_EEM_CFG_MAX_NBR_DEV; ix++) { /* Init ctrl struct. */
|
|
KAL_ERR err_kal;
|
|
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[ix];
|
|
p_ctrl->DevNbr = USBD_DEV_NBR_NONE;
|
|
p_ctrl->State = USBD_CDC_EEM_STATE_NONE;
|
|
p_ctrl->ClassNbr = USBD_CLASS_NBR_NONE;
|
|
p_ctrl->CommPtr = DEF_NULL;
|
|
p_ctrl->DrvPtr = DEF_NULL;
|
|
p_ctrl->DrvArgPtr = DEF_NULL;
|
|
p_ctrl->StartCnt = 0u;
|
|
|
|
p_ctrl->StateLockHandle = KAL_LockCreate("USBD - CDC EEM State lock",
|
|
DEF_NULL,
|
|
&err_kal);
|
|
if (err_kal != KAL_ERR_NONE) {
|
|
*p_err = USBD_ERR_OS_SIGNAL_CREATE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (ix = 0u; ix < USBD_CDC_EEM_COMM_NBR_MAX; ix++) { /* Init comm struct. */
|
|
p_comm = &USBD_CDC_EEM_CommTbl[ix];
|
|
p_comm->CtrlPtr = DEF_NULL;
|
|
p_comm->DataInEpAddr = USBD_EP_ADDR_NONE;
|
|
p_comm->DataOutEpAddr = USBD_EP_ADDR_NONE;
|
|
}
|
|
|
|
USBD_CDC_EEM_CtrlNbrNext = 0u;
|
|
USBD_CDC_EEM_CommNbrNext = 0u;
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_Add()
|
|
*
|
|
* Description : Adds a new instance of the CDC EEM class.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* 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_CDC_EEM_Add (USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U class_nbr;
|
|
CPU_INT08U buf_cnt;
|
|
LIB_ERR err_lib;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(USBD_CLASS_NBR_NONE);
|
|
}
|
|
#endif
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
class_nbr = USBD_CDC_EEM_CtrlNbrNext;
|
|
if (class_nbr >= USBD_CDC_EEM_CFG_MAX_NBR_DEV) {
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
USBD_CDC_EEM_CtrlNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
/* Alloc buffer used by echo response command. */
|
|
p_ctrl->BufEchoPtr = (CPU_INT08U *)Mem_HeapAlloc(USBD_CDC_EEM_CFG_ECHO_BUF_LEN,
|
|
USBD_CFG_BUF_ALIGN_OCTETS,
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
|
|
/* Allocate Rx buffers. */
|
|
for (buf_cnt = 0u; buf_cnt < USBD_CDC_EEM_CFG_RX_BUF_QTY_PER_DEV; buf_cnt++) {
|
|
p_ctrl->RxBufPtrTbl[buf_cnt] = (CPU_INT08U *)Mem_HeapAlloc(USBD_CDC_EEM_CFG_RX_BUF_LEN,
|
|
USBD_CFG_BUF_ALIGN_OCTETS,
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return (class_nbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_CfgAdd()
|
|
*
|
|
* Description : Add CDC-EEM class instance into the specified configuration.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add CDC-EEM class instance to.
|
|
*
|
|
* p_if_name Pointer to string that contains name of the CDC-EEM interface.
|
|
* Can be DEF_NULL.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
* USBD_ERR_ALLOC No more class communication structure available.
|
|
*
|
|
* -RETURNED BY USBD_IF_Add()-
|
|
* See USBD_IF_Add() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_BulkAdd()-
|
|
* See USBD_BulkAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_CfgAdd ( CPU_INT08U class_nbr,
|
|
CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
const CPU_CHAR *p_if_name,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
USBD_CDC_EEM_COMM *p_comm;
|
|
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 == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
CPU_CRITICAL_ENTER();
|
|
if ((p_ctrl->DevNbr != USBD_DEV_NBR_NONE) && /* Chk if class is associated with a different dev. */
|
|
(p_ctrl->DevNbr != dev_nbr)) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
p_ctrl->DevNbr = dev_nbr;
|
|
|
|
comm_nbr = USBD_CDC_EEM_CommNbrNext;
|
|
if (comm_nbr >= USBD_CDC_EEM_COMM_NBR_MAX) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return;
|
|
}
|
|
USBD_CDC_EEM_CommNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_comm = &USBD_CDC_EEM_CommTbl[comm_nbr];
|
|
|
|
/* ------------------ BUILD USB FNCT ------------------ */
|
|
if_nbr = USBD_IF_Add( dev_nbr,
|
|
cfg_nbr,
|
|
&USBD_CDC_EEM_Drv,
|
|
(void *)p_comm,
|
|
DEF_NULL,
|
|
USBD_CLASS_CODE_CDC_CONTROL,
|
|
USBD_CDC_EEM_SUBCLASS_CODE,
|
|
USBD_CDC_EEM_PROTOCOL_CODE,
|
|
p_if_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
ep_addr = USBD_BulkAdd(dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
0u,
|
|
DEF_YES,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
p_comm->DataInEpAddr = ep_addr;
|
|
|
|
|
|
ep_addr = USBD_BulkAdd(dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
0u,
|
|
DEF_NO,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
p_comm->DataOutEpAddr = ep_addr;
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->State = USBD_CDC_EEM_STATE_INIT;
|
|
p_ctrl->ClassNbr = class_nbr;
|
|
p_ctrl->CommPtr = DEF_NULL;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_comm->CtrlPtr = p_ctrl;
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_IsConn()
|
|
*
|
|
* Description : Gets the CDC-EEM class instance connection state.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* Return(s) : DEF_YES, if class instance is connected.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_CDC_EEM_IsConn (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_DEV_STATE dev_state;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
USBD_CDC_EEM_STATE class_state;
|
|
USBD_ERR err;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
return (DEF_NO);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
dev_state = USBD_DevStateGet(p_ctrl->DevNbr, &err);
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
USBD_CDC_EEM_StateLock(p_ctrl, &err);
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
class_state = p_ctrl->State;
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err);
|
|
|
|
if ((err == USBD_ERR_NONE ) &&
|
|
(dev_state == USBD_DEV_STATE_CONFIGURED) &&
|
|
(class_state == USBD_CDC_EEM_STATE_CFG )) {
|
|
return (DEF_YES);
|
|
} else {
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_InstanceInit()
|
|
*
|
|
* Description : Initializes CDC-EEM class instance according to network driver needs.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_cfg Pointer to CDC-EEM configuration structure.
|
|
*
|
|
* p_cdc_eem_drv Pointer to CDC-EEM driver structure.
|
|
*
|
|
* p_arg Pointer to CDC-EEM driver argument.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'
|
|
* /'p_cfg'/'p_cdc_eem_drv'.
|
|
* USBD_ERR_NULL_PTR Invalid null pointer passed to 'p_cfg'.
|
|
* USBD_ERR_ALLOC Unable to allocate Rx and or Tx queue(s).
|
|
* USBD_ERR_INVALID_CLASS_STATE Class instance laready configured.
|
|
*
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_InstanceInit (CPU_INT08U class_nbr,
|
|
USBD_CDC_EEM_CFG *p_cfg,
|
|
USBD_CDC_EEM_DRV *p_cdc_eem_drv,
|
|
void *p_arg,
|
|
USBD_ERR *p_err)
|
|
{
|
|
LIB_ERR err_lib;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_cfg == DEF_NULL) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
|
|
if ((p_cfg->RxBufQSize < 1u) ||
|
|
(p_cfg->TxBufQSize < 2u)) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
if (p_cdc_eem_drv == DEF_NULL) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_ctrl->DrvPtr != DEF_NULL) { /* Ensure class instance is not already configured. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
p_ctrl->DrvPtr = p_cdc_eem_drv;
|
|
p_ctrl->DrvArgPtr = p_arg;
|
|
|
|
/* ---------------- ALLOC TX AND RX QS ---------------- */
|
|
p_ctrl->TxBufQ.Size = p_cfg->TxBufQSize + 1u; /* Add 1 entry for echo buf. */
|
|
p_ctrl->TxBufQ.Tbl = (USBD_CDC_EEM_BUF_ENTRY *)Mem_HeapAlloc(sizeof(USBD_CDC_EEM_BUF_ENTRY) * p_ctrl->TxBufQ.Size,
|
|
sizeof(CPU_ALIGN),
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return;
|
|
}
|
|
|
|
p_ctrl->RxBufQ.Size = p_cfg->RxBufQSize;
|
|
p_ctrl->RxBufQ.Tbl = (USBD_CDC_EEM_BUF_ENTRY *)Mem_HeapAlloc(sizeof(USBD_CDC_EEM_BUF_ENTRY) * p_ctrl->RxBufQ.Size,
|
|
sizeof(CPU_ALIGN),
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return;
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_Start()
|
|
*
|
|
* Description : Starts communication on given CDC-EEM class instance.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_StateLock()-
|
|
* See USBD_CDC_EEM_StateLock() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_CommStart()-
|
|
* See USBD_CDC_EEM_CommStart() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) This function will start communication only if class instance is connected.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_Start (CPU_INT08U class_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
USBD_ERR err_unlock;
|
|
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
USBD_CDC_EEM_StateLock(p_ctrl, p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
p_ctrl->StartCnt++;
|
|
|
|
if ((p_ctrl->StartCnt == 1u) && /* If net drv started and class connected, start comm. */
|
|
(p_ctrl->State == USBD_CDC_EEM_STATE_CFG)) {
|
|
|
|
USBD_CDC_EEM_CommStart(p_ctrl, p_err);
|
|
} else {
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_unlock);
|
|
(void)err_unlock;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_Stop()
|
|
*
|
|
* Description : Stops communication on given CDC-EEM class instance.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_StateLock()-
|
|
* See USBD_CDC_EEM_StateLock() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_StateUnlock()-
|
|
* See USBD_CDC_EEM_StateUnlock() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) This function will stop communication only if class instance is connected.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_Stop (CPU_INT08U class_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
USBD_CDC_EEM_StateLock(p_ctrl, p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
if (p_ctrl->StartCnt > 0u) {
|
|
p_ctrl->StartCnt--;
|
|
}
|
|
|
|
if ((p_ctrl->StartCnt == 0u) && /* If class conn still connected, stop comm. */
|
|
(p_ctrl->State == USBD_CDC_EEM_STATE_CFG)) {
|
|
USBD_ERR err_abort;
|
|
|
|
|
|
USBD_EP_Abort(p_ctrl->DevNbr,
|
|
p_ctrl->CommPtr->DataInEpAddr,
|
|
&err_abort);
|
|
|
|
USBD_EP_Abort(p_ctrl->DevNbr,
|
|
p_ctrl->CommPtr->DataOutEpAddr,
|
|
&err_abort);
|
|
|
|
(void)err_abort;
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, p_err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_DevNbrGet()
|
|
*
|
|
* Description : Gets device number associated to this CDC-EEM class instance.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
*
|
|
* Return(s) : Device number.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_CDC_EEM_DevNbrGet (CPU_INT08U class_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
|
|
return (USBD_DEV_NBR_NONE);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return (p_ctrl->DevNbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_RxDataPktGet()
|
|
*
|
|
* Description : Gets first received data packet from received queue.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_rx_len Pointer to variable that will receive the length of the received
|
|
* buffer in bytes.
|
|
*
|
|
* p_crc_computed Pointer to variable that will receive the status of the ethernet CRC
|
|
* in buffer. Can be DEF_NULL.
|
|
*
|
|
* DEF_YES CRC is computed.
|
|
* DEF_NO CRC is not computed. Last 4 bytes of buffer are set to
|
|
* 0xDEADBEEF.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
* USBD_ERR_NULL_PTR Invalid null pointer passed to 'p_rx_len'.
|
|
* USBD_ERR_RX No rx buffer available.
|
|
*
|
|
* Return(s) : Pointer to received buffer, if successful.
|
|
*
|
|
* DEF_NULL, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U *USBD_CDC_EEM_RxDataPktGet (CPU_INT08U class_nbr,
|
|
CPU_INT16U *p_rx_len,
|
|
CPU_BOOLEAN *p_crc_computed,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U *p_buf;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_DEV_INVALID_NBR;
|
|
|
|
return (DEF_NULL);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_rx_len == DEF_NULL) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (DEF_NULL);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
CPU_CRITICAL_ENTER(); /* Get next buffer if any. */
|
|
p_buf = USBD_CDC_EEM_BufQ_Get(&p_ctrl->RxBufQ,
|
|
p_rx_len,
|
|
p_crc_computed);
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = (p_buf != DEF_NULL) ? USBD_ERR_NONE : USBD_ERR_RX;
|
|
|
|
return (p_buf);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_TxDataPktSubmit()
|
|
*
|
|
* Description : Submits a Tx buffer.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_buf Pointer to buffer to submit.
|
|
*
|
|
* buf_len Buffer length in bytes.
|
|
*
|
|
* crc_computed Flag that indicates if submitted buffer contains a computed ethernet CRC.
|
|
*
|
|
* DEF_YES Buffer contains a valid ethernet CRC in its last 4 bytes.
|
|
* DEF_NO Buffer does not contain a valid ethernet CRC.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
* USBD_ERR_NULL_PTR Invalid null pointer passed to 'p_buf'.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_TxBufSubmit()-
|
|
* See USBD_CDC_EEM_TxBufSubmit() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) Buffers submitted using this function MUST have a padding of 2 bytes at the
|
|
* beginning.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_EEM_TxDataPktSubmit (CPU_INT08U class_nbr,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_BOOLEAN crc_computed,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT16U hdr;
|
|
USBD_CDC_EEM_CTRL *p_ctrl;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) {
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_CDC_EEM_CtrlNbrNext) {
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if ((p_buf == DEF_NULL) &&
|
|
(buf_len != 0u)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_EEM_CtrlTbl[class_nbr];
|
|
|
|
/* Prepare header. */
|
|
hdr = DEF_BIT_FIELD_ENC(USBD_CDC_EEM_PKT_TYPE_PAYLOAD, USBD_CDC_EEM_PKT_TYPE_MASK);
|
|
|
|
if (crc_computed == DEF_NO) {
|
|
/* Set CRC to 0xDEADBEEF as per CDC-EEM specification. */
|
|
Mem_Copy((void *)&p_buf[buf_len + USBD_CDC_EEM_HDR_LEN],
|
|
(void *) USBD_CDC_EEM_PayloadCRC,
|
|
4u);
|
|
|
|
hdr |= DEF_BIT_FIELD_ENC(USBD_CDC_EEM_PAYLOAD_CRC_NOT_CALC, USBD_CDC_EEM_PAYLOAD_CRC_MASK) |
|
|
DEF_BIT_FIELD_ENC(buf_len + 4u, USBD_CDC_EEM_PAYLOAD_LEN_MASK);
|
|
} else {
|
|
hdr |= DEF_BIT_FIELD_ENC(USBD_CDC_EEM_PAYLOAD_CRC_CALC, USBD_CDC_EEM_PAYLOAD_CRC_MASK) |
|
|
DEF_BIT_FIELD_ENC(buf_len, USBD_CDC_EEM_PAYLOAD_LEN_MASK);
|
|
}
|
|
|
|
((CPU_INT16U *)p_buf)[0u] = MEM_VAL_GET_INT16U_LITTLE(&hdr); /* Copy hdr to buffer. */
|
|
|
|
USBD_CDC_EEM_TxBufSubmit(p_ctrl, /* Send buffer to host. */
|
|
p_buf,
|
|
buf_len + USBD_CDC_EEM_HDR_LEN + 4u,
|
|
p_err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_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_CDC_EEM_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_EEM_COMM *p_comm = (USBD_CDC_EEM_COMM *)p_if_class_arg;
|
|
USBD_ERR err;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
|
|
USBD_CDC_EEM_StateLock(p_comm->CtrlPtr, &err);
|
|
|
|
p_comm->CtrlPtr->State = USBD_CDC_EEM_STATE_CFG;
|
|
p_comm->CtrlPtr->CommPtr = p_comm;
|
|
|
|
if (p_comm->CtrlPtr->StartCnt > 0u) { /* If class instance is started by net drv, start comm. */
|
|
USBD_CDC_EEM_CommStart(p_comm->CtrlPtr, &err);
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_comm->CtrlPtr, &err);
|
|
|
|
(void)err;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_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_CDC_EEM_Disconn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_EEM_COMM *p_comm = (USBD_CDC_EEM_COMM *)p_if_class_arg;
|
|
USBD_ERR err_lock;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
|
|
USBD_CDC_EEM_StateLock(p_comm->CtrlPtr, &err_lock);
|
|
p_comm->CtrlPtr->State = USBD_CDC_EEM_STATE_INIT;
|
|
p_comm->CtrlPtr->CommPtr = DEF_NULL;
|
|
USBD_CDC_EEM_StateUnlock(p_comm->CtrlPtr, &err_lock);
|
|
|
|
(void)err_lock;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_CommStart()
|
|
*
|
|
* Description : Starts communication on given class instance.
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to class instance control structure.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
*
|
|
* -RETURNED BY USBD_BulkRxAsync()-
|
|
* See USBD_BulkRxAsync() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) State of CDC-EEM must be locked by caller function.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_CommStart (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U buf_cnt;
|
|
USBD_CDC_EEM_COMM *p_comm;
|
|
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
/* Init Rx state machine. */
|
|
p_ctrl->CurBufLenRem = 0u;
|
|
p_ctrl->CurBufPtr = DEF_NULL;
|
|
p_ctrl->CurBufIx = 0u;
|
|
p_ctrl->CurBufCrcComputed = DEF_NO;
|
|
p_ctrl->RxErrCnt = 0u;
|
|
|
|
/* Init Tx and Rx Qs. */
|
|
p_ctrl->TxBufQ.InIdx = 0u;
|
|
p_ctrl->TxBufQ.OutIdx = 0u;
|
|
p_ctrl->TxBufQ.Cnt = 0u;
|
|
p_ctrl->TxInProgress = DEF_NO;
|
|
|
|
p_ctrl->RxBufQ.InIdx = 0u;
|
|
p_ctrl->RxBufQ.OutIdx = 0u;
|
|
p_ctrl->RxBufQ.Cnt = 0u;
|
|
|
|
/* Submit all avail Rx buffers. */
|
|
for (buf_cnt = 0u; buf_cnt < USBD_CDC_EEM_CFG_RX_BUF_QTY_PER_DEV; buf_cnt++) {
|
|
USBD_BulkRxAsync( p_ctrl->DevNbr,
|
|
p_comm->DataOutEpAddr,
|
|
p_ctrl->RxBufPtrTbl[buf_cnt],
|
|
USBD_CDC_EEM_CFG_RX_BUF_LEN,
|
|
USBD_CDC_EEM_RxCmpl,
|
|
(void *)p_ctrl,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_RxCmpl()
|
|
*
|
|
* Description : Inform the application about the Bulk OUT transfer completion.
|
|
*
|
|
* Argument(s) : dev_nbr Device number
|
|
*
|
|
* ep_addr Endpoint address.
|
|
*
|
|
* p_buf Pointer to the receive buffer.
|
|
*
|
|
* buf_len Receive buffer length.
|
|
*
|
|
* xfer_len Number of octets received.
|
|
*
|
|
* p_arg Additional argument provided by application.
|
|
*
|
|
* err Transfer status: success or error.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_RxCmpl (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)
|
|
{
|
|
CPU_INT16U buf_ix_cur = 0u;
|
|
USBD_CDC_EEM_CTRL *p_ctrl = (USBD_CDC_EEM_CTRL *)p_arg;
|
|
USBD_ERR err_usbd;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)ep_addr;
|
|
(void)buf_len;
|
|
|
|
switch (err) { /* Chk errors. */
|
|
case USBD_ERR_NONE:
|
|
p_ctrl->RxErrCnt = 0u;
|
|
break;
|
|
|
|
|
|
case USBD_ERR_EP_ABORT:
|
|
return;
|
|
|
|
|
|
default:
|
|
p_ctrl->RxErrCnt++; /* Retry a few times. */
|
|
if (p_ctrl->RxErrCnt > USBD_CDC_EEM_MAX_RETRY_CNT) {
|
|
return;
|
|
}
|
|
|
|
goto resubmit;
|
|
}
|
|
|
|
if (p_ctrl->CurBufLenRem > 0u) { /* If previous received buffer was incomplete. */
|
|
CPU_INT16U len_to_copy = DEF_MIN(xfer_len, p_ctrl->CurBufLenRem);
|
|
|
|
|
|
if (p_ctrl->CurBufPtr != DEF_NULL) {
|
|
Mem_Copy((void *)&p_ctrl->CurBufPtr[p_ctrl->CurBufIx],
|
|
p_buf,
|
|
len_to_copy);
|
|
}
|
|
|
|
p_ctrl->CurBufIx += len_to_copy;
|
|
p_ctrl->CurBufLenRem -= len_to_copy;
|
|
buf_ix_cur += len_to_copy;
|
|
|
|
if (p_ctrl->CurBufLenRem != 0u) {
|
|
goto resubmit;
|
|
}
|
|
}
|
|
|
|
do {
|
|
CPU_INT08U cmd;
|
|
CPU_INT16U cmd_param;
|
|
|
|
|
|
if (p_ctrl->CurBufIx == 0u) { /* Get hdr only if not in data copy phase. */
|
|
p_ctrl->CurHdr = MEM_VAL_GET_INT16U_LITTLE(&((CPU_INT08U *)p_buf)[buf_ix_cur]);
|
|
}
|
|
|
|
/* Ensure not a Zero-Length EEM (ZLE) pkt. */
|
|
if (p_ctrl->CurHdr == USBD_CDC_EEM_HDR_ZLE) {
|
|
buf_ix_cur += USBD_CDC_EEM_HDR_LEN;
|
|
continue;
|
|
}
|
|
|
|
switch (DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_PKT_TYPE_MASK)) {
|
|
case USBD_CDC_EEM_PKT_TYPE_CMD: /* --------------------- EEM CMD ---------------------- */
|
|
/* Ensure rsvd bit is 0. */
|
|
if (DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_CMD_RSVD_MASK) != USBD_CDC_EEM_CMD_RSVD_OK) {
|
|
buf_ix_cur += USBD_CDC_EEM_HDR_LEN;
|
|
continue;
|
|
}
|
|
|
|
cmd = DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_CMD_CODE_MASK);
|
|
cmd_param = DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_CMD_PARAM_MASK);
|
|
|
|
switch (cmd) {
|
|
case USBD_CDC_EEM_CMD_CODE_ECHO: /* --------------------- ECHO CMD --------------------- */
|
|
if (p_ctrl->CurBufIx == 0u) {
|
|
CPU_INT16U len_to_copy;
|
|
|
|
|
|
buf_ix_cur += USBD_CDC_EEM_HDR_LEN;
|
|
p_ctrl->CurBufIx += USBD_CDC_EEM_HDR_LEN;
|
|
|
|
/* Copy echo buffer. */
|
|
p_ctrl->CurBufPtr = p_ctrl->BufEchoPtr;
|
|
p_ctrl->CurBufLenRem = DEF_MIN(DEF_BIT_FIELD_RD(cmd_param, USBD_CDC_EEM_CMD_PARAM_ECHO_LEN_MASK),
|
|
USBD_CDC_EEM_CFG_ECHO_BUF_LEN - USBD_CDC_EEM_HDR_LEN);
|
|
|
|
len_to_copy = DEF_MIN(p_ctrl->CurBufLenRem, (xfer_len - buf_ix_cur));
|
|
Mem_Copy((void *)&p_ctrl->CurBufPtr[p_ctrl->CurBufIx],
|
|
&((CPU_INT08U *)p_buf)[buf_ix_cur],
|
|
len_to_copy);
|
|
p_ctrl->CurBufIx += len_to_copy;
|
|
p_ctrl->CurBufLenRem -= len_to_copy;
|
|
|
|
buf_ix_cur += len_to_copy;
|
|
}
|
|
|
|
if (p_ctrl->CurBufLenRem == 0u) { /* If buf copy done, prepare echo resp reply. */
|
|
CPU_INT16U *p_hdr = &((CPU_INT16U *)p_ctrl->CurBufPtr)[0u];
|
|
|
|
|
|
/* Prepare hdr. */
|
|
*p_hdr = DEF_BIT_FIELD_ENC(USBD_CDC_EEM_PKT_TYPE_CMD, USBD_CDC_EEM_PKT_TYPE_MASK) |
|
|
DEF_BIT_FIELD_ENC(USBD_CDC_EEM_CMD_CODE_ECHO_RESP, USBD_CDC_EEM_CMD_CODE_MASK) |
|
|
DEF_BIT_FIELD_ENC(p_ctrl->CurBufIx - USBD_CDC_EEM_HDR_LEN, USBD_CDC_EEM_CMD_PARAM_ECHO_LEN_MASK);
|
|
|
|
USBD_CDC_EEM_TxBufSubmit(p_ctrl,
|
|
p_ctrl->CurBufPtr,
|
|
p_ctrl->CurBufIx,
|
|
&err_usbd);
|
|
|
|
p_ctrl->CurBufIx = 0u;
|
|
}
|
|
break;
|
|
|
|
|
|
case USBD_CDC_EEM_CMD_CODE_ECHO_RESP: /* ----------------- UNSUPPORTED CMDS ----------------- */
|
|
case USBD_CDC_EEM_CMD_CODE_TICKLE:
|
|
case USBD_CDC_EEM_CMD_CODE_SUSP_HINT:
|
|
case USBD_CDC_EEM_CMD_CODE_RESP_HINT:
|
|
case USBD_CDC_EEM_CMD_CODE_RESP_CMPL_HINT:
|
|
default:
|
|
buf_ix_cur+= USBD_CDC_EEM_HDR_LEN;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case USBD_CDC_EEM_PKT_TYPE_PAYLOAD: /* ------------------- EEM PAYLOADS ------------------- */
|
|
if (p_ctrl->CurBufIx == 0u) {
|
|
CPU_INT16U net_buf_len;
|
|
CPU_INT16U len_to_copy;
|
|
|
|
|
|
buf_ix_cur += USBD_CDC_EEM_HDR_LEN;
|
|
p_ctrl->CurBufPtr = p_ctrl->DrvPtr->RxBufGet(p_ctrl->ClassNbr,
|
|
p_ctrl->DrvArgPtr,
|
|
&net_buf_len);
|
|
|
|
p_ctrl->CurBufLenRem = DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_PAYLOAD_LEN_MASK);
|
|
|
|
if (DEF_BIT_FIELD_RD(p_ctrl->CurHdr, USBD_CDC_EEM_PAYLOAD_CRC_MASK) == USBD_CDC_EEM_PAYLOAD_CRC_CALC) {
|
|
p_ctrl->CurBufCrcComputed = DEF_YES;
|
|
} else {
|
|
p_ctrl->CurBufCrcComputed = DEF_NO;
|
|
}
|
|
|
|
/* Copy payload content to network drv's buf. */
|
|
len_to_copy = DEF_MIN(p_ctrl->CurBufLenRem, (xfer_len - buf_ix_cur));
|
|
if (p_ctrl->CurBufPtr != DEF_NULL) {
|
|
Mem_Copy((void *)&p_ctrl->CurBufPtr[p_ctrl->CurBufIx],
|
|
&((CPU_INT08U *)p_buf)[buf_ix_cur],
|
|
len_to_copy);
|
|
}
|
|
p_ctrl->CurBufIx += len_to_copy;
|
|
p_ctrl->CurBufLenRem -= len_to_copy;
|
|
|
|
buf_ix_cur += len_to_copy;
|
|
}
|
|
|
|
if (p_ctrl->CurBufLenRem == 0u) { /* If reception complete, submit buf to network drv. */
|
|
if (p_ctrl->CurBufPtr != DEF_NULL) {
|
|
CPU_CRITICAL_ENTER();
|
|
USBD_CDC_EEM_BufQ_Add(&p_ctrl->RxBufQ,
|
|
p_ctrl->CurBufPtr,
|
|
p_ctrl->CurBufIx,
|
|
p_ctrl->CurBufCrcComputed);
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_ctrl->DrvPtr->RxBufRdy(p_ctrl->ClassNbr,
|
|
p_ctrl->DrvArgPtr);
|
|
}
|
|
|
|
p_ctrl->CurBufIx = 0u;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} while (buf_ix_cur <= (xfer_len - USBD_CDC_EEM_HDR_LEN));
|
|
|
|
|
|
resubmit:
|
|
USBD_CDC_EEM_StateLock(p_ctrl, &err_usbd);
|
|
|
|
if ((p_ctrl->StartCnt > 0u) && /* Re-submit buf if still connected. */
|
|
(p_ctrl->State == USBD_CDC_EEM_STATE_CFG)) {
|
|
USBD_BulkRxAsync( p_ctrl->DevNbr,
|
|
p_ctrl->CommPtr->DataOutEpAddr,
|
|
p_buf,
|
|
USBD_CDC_EEM_CFG_RX_BUF_LEN,
|
|
USBD_CDC_EEM_RxCmpl,
|
|
(void *)p_ctrl,
|
|
&err_usbd);
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_usbd);
|
|
|
|
(void)err_usbd;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_TxCmpl()
|
|
*
|
|
* Description : Inform the application about the Bulk IN transfer completion.
|
|
*
|
|
* Argument(s) : dev_nbr Device number
|
|
*
|
|
* ep_addr Endpoint address.
|
|
*
|
|
* p_buf Pointer to the receive buffer.
|
|
*
|
|
* buf_len Receive buffer length.
|
|
*
|
|
* xfer_len Number of octets sent.
|
|
*
|
|
* p_arg Additional argument provided by application.
|
|
*
|
|
* err Transfer status: success or error.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_TxCmpl (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)
|
|
{
|
|
CPU_INT08U *p_next_buf;
|
|
CPU_INT16U next_buf_len;
|
|
USBD_CDC_EEM_CTRL *p_ctrl = (USBD_CDC_EEM_CTRL *)p_arg;
|
|
USBD_ERR err_lock;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)ep_addr;
|
|
(void)xfer_len;
|
|
(void)err;
|
|
|
|
if ((p_buf != p_ctrl->BufEchoPtr) &&
|
|
(p_buf != DEF_NULL)) { /* Free Tx buf to network drv. */
|
|
p_ctrl->DrvPtr->TxBufFree( p_ctrl->ClassNbr,
|
|
p_ctrl->DrvArgPtr,
|
|
(CPU_INT08U *)p_buf,
|
|
buf_len);
|
|
}
|
|
|
|
USBD_CDC_EEM_StateLock(p_ctrl, &err_lock);
|
|
|
|
if ((p_ctrl->State != USBD_CDC_EEM_STATE_CFG) ||
|
|
(p_ctrl->StartCnt == 0u)) {
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_lock);
|
|
return;
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER(); /* Submit next buffer if any. */
|
|
p_next_buf = USBD_CDC_EEM_BufQ_Get(&p_ctrl->TxBufQ,
|
|
&next_buf_len,
|
|
DEF_NULL);
|
|
if (p_next_buf == DEF_NULL) {
|
|
p_ctrl->TxInProgress = DEF_NO;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_next_buf != DEF_NULL) {
|
|
USBD_ERR err_submit;
|
|
|
|
|
|
USBD_BulkTxAsync( p_ctrl->DevNbr,
|
|
p_ctrl->CommPtr->DataInEpAddr,
|
|
(void *)p_next_buf,
|
|
next_buf_len,
|
|
USBD_CDC_EEM_TxCmpl,
|
|
(void *)p_ctrl,
|
|
DEF_YES,
|
|
&err_submit);
|
|
|
|
(void)err_submit;
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_lock);
|
|
(void)err_lock;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_TxBufSubmit()
|
|
*
|
|
* Description : Submits a transmit buffer.
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to class instance control structure.
|
|
*
|
|
* p_buf Pointer to buffer that contains data to send.
|
|
*
|
|
* buf_len Length of buffer in bytes.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
*
|
|
* -RETURNED BY USBD_CDC_EEM_StateLock()-
|
|
* See USBD_CDC_EEM_StateLock() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_BulkTxAsync()-
|
|
* See USBD_BulkTxAsync() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_TxBufSubmit (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT16U buf_len,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN tx_in_progress;
|
|
USBD_ERR err_unlock;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
USBD_CDC_EEM_StateLock(p_ctrl, p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
if ((p_ctrl->State != USBD_CDC_EEM_STATE_CFG) ||
|
|
(p_ctrl->StartCnt == 0u)) {
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_unlock);
|
|
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return;
|
|
}
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
tx_in_progress = p_ctrl->TxInProgress;
|
|
if (tx_in_progress == DEF_NO) {
|
|
p_ctrl->TxInProgress = DEF_YES; /* Submit buffer if no buffer in Q. */
|
|
} else {
|
|
USBD_CDC_EEM_BufQ_Add(&p_ctrl->TxBufQ, /* Add buffer to Q. */
|
|
p_buf,
|
|
buf_len,
|
|
DEF_NO);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (tx_in_progress == DEF_NO) {
|
|
USBD_BulkTxAsync( p_ctrl->DevNbr,
|
|
p_ctrl->CommPtr->DataInEpAddr,
|
|
(void *)p_buf,
|
|
buf_len,
|
|
USBD_CDC_EEM_TxCmpl,
|
|
(void *)p_ctrl,
|
|
DEF_YES,
|
|
p_err);
|
|
}
|
|
|
|
USBD_CDC_EEM_StateUnlock(p_ctrl, &err_unlock);
|
|
(void)err_unlock;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_BufQ_Add()
|
|
*
|
|
* Description : Adds a buffer to the tail of the Q.
|
|
*
|
|
* Argument(s) : p_buf_q Pointer to buffer Q.
|
|
*
|
|
* p_buf Pointer to buffer to add to Q.
|
|
*
|
|
* buf_len Length of buffer in bytes.
|
|
*
|
|
* crc_computed Flag that indicates if ethernet CRC is computed in submitted buffer.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) This function must be called from within a critical section.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_BufQ_Add (USBD_CDC_EEM_BUF_Q *p_buf_q,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT16U buf_len,
|
|
CPU_BOOLEAN crc_computed)
|
|
{
|
|
if (p_buf_q->Cnt >= p_buf_q->Size) {
|
|
return;
|
|
}
|
|
|
|
p_buf_q->Tbl[p_buf_q->InIdx].BufPtr = p_buf;
|
|
p_buf_q->Tbl[p_buf_q->InIdx].BufLen = buf_len;
|
|
p_buf_q->Tbl[p_buf_q->InIdx].CrcComputed = crc_computed;
|
|
|
|
p_buf_q->InIdx++;
|
|
if (p_buf_q->InIdx >= p_buf_q->Size) {
|
|
p_buf_q->InIdx = 0u;
|
|
}
|
|
|
|
p_buf_q->Cnt++;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_BufQ_Get()
|
|
*
|
|
* Description : Gets a buffer from the head of the Q.
|
|
*
|
|
* Argument(s) : p_buf_q Pointer to buffer Q.
|
|
*
|
|
* p_buf_len Pointer to variable that will receive length of buffer in bytes.
|
|
*
|
|
* p_crc_computed Pointer to variable that will receive the CRC computes state of the
|
|
* buffer. Can be DEF_NULL if ignored.
|
|
*
|
|
* DEF_YES Buffer contains a valid/computed ethernet CRC.
|
|
* DEF_NO Buffer does not contains a valid/computed ethernet CRC.
|
|
*
|
|
* Return(s) : Pointer to buffer.
|
|
*
|
|
* Note(s) : (1) This function must be called from within a critical section.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT08U *USBD_CDC_EEM_BufQ_Get (USBD_CDC_EEM_BUF_Q *p_buf_q,
|
|
CPU_INT16U *p_buf_len,
|
|
CPU_BOOLEAN *p_crc_computed)
|
|
{
|
|
CPU_INT08U *p_buf;
|
|
|
|
|
|
if (p_buf_q->Cnt == 0u) {
|
|
return (DEF_NULL);
|
|
}
|
|
|
|
p_buf = p_buf_q->Tbl[p_buf_q->OutIdx].BufPtr;
|
|
*p_buf_len = p_buf_q->Tbl[p_buf_q->OutIdx].BufLen;
|
|
|
|
if (p_crc_computed != DEF_NULL) {
|
|
*p_crc_computed = p_buf_q->Tbl[p_buf_q->OutIdx].CrcComputed;
|
|
}
|
|
|
|
p_buf_q->OutIdx++;
|
|
if (p_buf_q->OutIdx >= p_buf_q->Size) {
|
|
p_buf_q->OutIdx = 0u;
|
|
}
|
|
|
|
p_buf_q->Cnt--;
|
|
|
|
return (p_buf);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_StateLock()
|
|
*
|
|
* Description : Locks CDC-EEM class instance state.
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to class instance control structure.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_OS_FAIL Lock failed.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_StateLock (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err)
|
|
{
|
|
KAL_ERR err_kal;
|
|
|
|
|
|
KAL_LockAcquire(p_ctrl->StateLockHandle,
|
|
KAL_OPT_PEND_NONE,
|
|
0u,
|
|
&err_kal);
|
|
*p_err = (err_kal == KAL_ERR_NONE) ? USBD_ERR_NONE : USBD_ERR_OS_FAIL;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_EEM_StateUnlock()
|
|
*
|
|
* Description : Unlocks CDC-EEM class instance state.
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to class instance control structure.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Operation was successful.
|
|
* USBD_ERR_OS_FAIL Unlock failed.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_EEM_StateUnlock (USBD_CDC_EEM_CTRL *p_ctrl,
|
|
USBD_ERR *p_err)
|
|
{
|
|
KAL_ERR err_kal;
|
|
|
|
|
|
KAL_LockRelease(p_ctrl->StateLockHandle,
|
|
&err_kal);
|
|
*p_err = (err_kal == KAL_ERR_NONE) ? USBD_ERR_NONE : USBD_ERR_OS_FAIL;
|
|
}
|