1997 lines
85 KiB
C
1997 lines
85 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.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* NOTICE
|
|
*
|
|
* Semidrive modified this file to adapt it for ssdk platform.
|
|
* The modifications are only intended for use with Semidrive chips.
|
|
* Copyright of all the modifications belongs to Semidrive Semiconductor.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* USB COMMUNICATIONS DEVICE CLASS (CDC)
|
|
*
|
|
* Filename : usbd_cdc.c
|
|
* Version : V4.06.01
|
|
*********************************************************************************************************
|
|
* Note(s) : (1) This implementation is compliant with the CDC specification revision 1.2
|
|
* errata 1. November 3, 2010.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define MICRIUM_SOURCE
|
|
#include "usbd_cdc.h"
|
|
#include <lib_math.h>
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* MODULE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* MAXIMUM NUMBER OF COMMUNICATION/DATA IF EP STRUCTURES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* Max nbr of comm struct. */
|
|
#define USBD_CDC_COMM_NBR_MAX (USBD_CDC_CFG_MAX_NBR_DEV * \
|
|
USBD_CDC_CFG_MAX_NBR_CFG)
|
|
|
|
/* Max nbr of data IF EP struct. */
|
|
#define USBD_CDC_DATA_IF_EP_NBR_MAX (USBD_CDC_CFG_MAX_NBR_DEV * \
|
|
USBD_CDC_CFG_MAX_NBR_DATA_IF * \
|
|
USBD_CDC_CFG_MAX_NBR_CFG)
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC FUNCTIONAL DESCRIPTOR SIZE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_CDC_DESC_SIZE_HEADER 5u /* Header functional desc size. */
|
|
#define USBD_CDC_DESC_SIZE_UNION_MIN 4u /* Min size of union functional desc. */
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC TOTAL NUMBER DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_CDC_NBR_TOTAL (DEF_INT_08U_MAX_VAL - 1u)
|
|
#define USBD_CDC_DATA_IF_NBR_TOTAL (DEF_INT_08U_MAX_VAL - 1u)
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC STATE DATA TYPE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef enum usbd_cdc_state { /* CDC device state. */
|
|
USBD_CDC_STATE_NONE = 0,
|
|
USBD_CDC_STATE_INIT,
|
|
USBD_CDC_STATE_CFG
|
|
} USBD_CDC_STATE;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* FORWARD DECLARATIONS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_ctrl USBD_CDC_CTRL;
|
|
typedef struct usbd_cdc_data_if USBD_CDC_DATA_IF;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC DATA IF CLASS DATA TYPE
|
|
*
|
|
* Note(s) : (1) USB CDC specification specifies that the type of endpoints belonging to a Data IF are
|
|
* restricted to being either isochronous or bulk, and are expected to exist in pairs of
|
|
* the same type (one IN and one OUT).
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbd_cdc_data_if_ep {
|
|
CPU_INT08U DataIn;
|
|
CPU_INT08U DataOut;
|
|
} USBD_CDC_DATA_IF_EP;
|
|
|
|
|
|
struct usbd_cdc_data_if {
|
|
CPU_INT08U IF_Nbr; /* Data IF nbr. */
|
|
CPU_INT08U Protocol; /* Data IF protocol. */
|
|
CPU_BOOLEAN IsocEn; /* EP isochronous enable. */
|
|
USBD_CDC_DATA_IF *NextPtr; /* Next data IF. */
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC COMMUNICATION IF DATA TYPE
|
|
*
|
|
* Note(s) : (1) A CDC device consists in one communication IF, and multiple data IFs (optional).
|
|
*
|
|
* +-----IFs----+-------EPs-------+
|
|
* | COMM_IF | CTRL | <-------- Mgmt Requests.
|
|
* | | INTR (Optional)| ---------> Events Notifications.
|
|
* +------------+-----------------+
|
|
* | DATA_IF | BULK/ISOC IN | ---------> Data Tx (0)
|
|
* | | BULK/ISOC OUT | <--------- Data Rx (0)
|
|
* +------------+-----------------+
|
|
* | DATA_IF | BULK/ISOC IN | ---------> Data Tx (1)
|
|
* | | BULK/ISOC OUT | <--------- Data Rx (1)
|
|
* +------------+-----------------+
|
|
* | DATA_IF | BULK/ISOC IN | ---------> Data Tx (2)
|
|
* | | BULK/ISOC OUT | <--------- Data Rx (2)
|
|
* +------------+-----------------+
|
|
* .
|
|
* .
|
|
* .
|
|
* +------------+-----------------+
|
|
* | DATA_IF | BULK/ISOC IN | ---------> Data Tx (n - 1)
|
|
* | | BULK/ISOC OUT | <--------- Data Rx (n - 1)
|
|
* +------------+-----------------+
|
|
*
|
|
* (a) The communication IF may have an optional notification element. Notifications are
|
|
* sent using a interrupt endpoint.
|
|
*
|
|
* (b) The communication IF structure contains a link list of Data IFs.
|
|
*********************************************************************************************************
|
|
*/
|
|
/* ------ CDC DATA CLASS INTERFACE COMMUNICATION ------ */
|
|
typedef struct usbd_cdc_comm {
|
|
CPU_INT08U DevNbr; /* Dev nbr. */
|
|
CPU_INT08U CCI_IF_Nbr; /* Comm Class IF nbr. */
|
|
USBD_CDC_CTRL *CtrlPtr; /* Ptr to ctrl info. */
|
|
CPU_INT08U NotifyIn; /* Notification EP (see note #1a). */
|
|
CPU_INT16U DataIF_EP_Ix; /* Start ix of data IFs EP information. */
|
|
CPU_BOOLEAN NotifyInActiveXfer;
|
|
} USBD_CDC_COMM;
|
|
|
|
|
|
struct usbd_cdc_ctrl { /* ----------- CDC CLASS CONTROL INFORMATION ---------- */
|
|
USBD_CDC_STATE State; /* CDC state. */
|
|
CPU_BOOLEAN NotifyEn; /* CDC mgmt element notifications enable. */
|
|
CPU_INT16U NotifyInterval; /* CDC mgmt element notifications interval. */
|
|
CPU_INT08U DataIF_Nbr; /* Number of data IFs. */
|
|
USBD_CDC_DATA_IF *DataIF_HeadPtr; /* Data IFs list head ptr. (see note #1b) */
|
|
USBD_CDC_DATA_IF *DataIF_TailPtr; /* Data IFs list tail ptr. */
|
|
CPU_INT08U SubClassCode; /* CDC subclass code. */
|
|
CPU_INT08U SubClassProtocol; /* CDC subclass protocol. */
|
|
USBD_CDC_SUBCLASS_DRV *SubClassDrvPtr; /* CDC subclass drv. */
|
|
void *SubClassArg; /* CDC subclass drv argument. */
|
|
USBD_CDC_COMM *CommPtr; /* CDC comm information ptr. */
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL TABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBD_CDC_CTRL USBD_CDC_CtrlTbl[USBD_CDC_CFG_MAX_NBR_DEV];
|
|
static CPU_INT08U USBD_CDC_CtrlNbrNext;
|
|
|
|
static USBD_CDC_COMM USBD_CDC_CommTbl[USBD_CDC_COMM_NBR_MAX];
|
|
static CPU_INT16U USBD_CDC_CommNbrNext;
|
|
|
|
static USBD_CDC_DATA_IF USBD_CDC_DataIF_Tbl[USBD_CDC_CFG_MAX_NBR_DATA_IF];
|
|
static CPU_INT08U USBD_CDC_DataIF_NbrNext;
|
|
|
|
static USBD_CDC_DATA_IF_EP USBD_CDC_DataIF_EP_Tbl[USBD_CDC_DATA_IF_EP_NBR_MAX];
|
|
static CPU_INT16U USBD_CDC_DataIF_EP_NbrNext;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_Conn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_CDC_Disconn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_CDC_CommIF_Desc ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_INT16U USBD_CDC_CommIF_DescSizeGet( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_BOOLEAN USBD_CDC_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg);
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
static CPU_INT08U USBD_CDC_MS_GetCompatID ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U *p_sub_compat_id_ix,
|
|
void *p_if_class_arg);
|
|
|
|
static CPU_INT08U USBD_CDC_MS_GetExtPropertyTbl( CPU_INT08U dev_nbr,
|
|
USBD_MS_OS_EXT_PROPERTY **pp_ext_property_tbl,
|
|
void *p_if_class_arg);
|
|
#endif
|
|
|
|
static void USBD_CDC_DataIF_AltSetUpdate( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static void USBD_CDC_NotifyCmpl ( 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);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CDC CLASS DRIVERS
|
|
*********************************************************************************************************
|
|
*/
|
|
/* Comm IF class drv. */
|
|
static USBD_CLASS_DRV USBD_CDC_CommDrv = {
|
|
USBD_CDC_Conn,
|
|
USBD_CDC_Disconn,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
USBD_CDC_CommIF_Desc,
|
|
USBD_CDC_CommIF_DescSizeGet,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
USBD_CDC_ClassReq,
|
|
DEF_NULL,
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
USBD_CDC_MS_GetCompatID,
|
|
USBD_CDC_MS_GetExtPropertyTbl
|
|
#endif
|
|
};
|
|
|
|
/* Data IF class drv. */
|
|
static USBD_CLASS_DRV USBD_CDC_DataDrv = {
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
USBD_CDC_DataIF_AltSetUpdate,
|
|
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
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_CFG_MAX_NBR_IF_GRP < 1u)
|
|
#error "USBD_CFG_MAX_NBR_IF_GRP illegally #define'd in 'usbd_cfg.h' [MUST be >= 1 for CDC]"
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INTERFACE DRIVER
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* APPLICATION FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_Init()
|
|
*
|
|
* Description : Initialize CDC class.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE CDC class initialized successfully.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_Init (USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U ix;
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
#endif
|
|
|
|
for (ix = 0u; ix < USBD_CDC_CFG_MAX_NBR_DEV; ix++) { /* Init CDC ctrl tbl. */
|
|
p_ctrl = &USBD_CDC_CtrlTbl[ix];
|
|
p_ctrl->State = USBD_CDC_STATE_NONE;
|
|
p_ctrl->NotifyEn = DEF_DISABLED;
|
|
p_ctrl->NotifyInterval = 0u;
|
|
p_ctrl->DataIF_Nbr = 0u;
|
|
p_ctrl->DataIF_HeadPtr = (USBD_CDC_DATA_IF *)0;
|
|
p_ctrl->DataIF_TailPtr = (USBD_CDC_DATA_IF *)0;
|
|
p_ctrl->SubClassCode = USBD_CDC_SUBCLASS_RSVD;
|
|
p_ctrl->SubClassProtocol = USBD_CDC_COMM_PROTOCOL_NONE;
|
|
p_ctrl->SubClassDrvPtr = (USBD_CDC_SUBCLASS_DRV *)0;
|
|
p_ctrl->SubClassArg = (void *)0;
|
|
p_ctrl->CommPtr = (USBD_CDC_COMM *)0;
|
|
}
|
|
|
|
for (ix = 0u; ix < USBD_CDC_COMM_NBR_MAX; ix++) { /* Init CDC comm tbl. */
|
|
p_comm = &USBD_CDC_CommTbl[ix];
|
|
p_comm->CtrlPtr = (USBD_CDC_CTRL *)0;
|
|
p_comm->NotifyIn = USBD_EP_ADDR_NONE;
|
|
p_comm->DataIF_EP_Ix = 0u;
|
|
p_comm->CCI_IF_Nbr = USBD_IF_NBR_NONE;
|
|
p_comm->NotifyInActiveXfer = DEF_NO;
|
|
}
|
|
|
|
|
|
for (ix = 0u; ix < USBD_CDC_CFG_MAX_NBR_DATA_IF; ix++) { /* Init CDC data IF tbl. */
|
|
p_data_if = &USBD_CDC_DataIF_Tbl[ix];
|
|
p_data_if->Protocol = USBD_CDC_DATA_PROTOCOL_NONE;
|
|
p_data_if->IsocEn = DEF_DISABLED;
|
|
p_data_if->NextPtr = (USBD_CDC_DATA_IF *)0;
|
|
p_data_if->IF_Nbr = USBD_IF_NBR_NONE;
|
|
}
|
|
|
|
for (ix = 0u; ix < USBD_CDC_DATA_IF_EP_NBR_MAX; ix++) { /* Init CDC data IF EP tbl. */
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[ix];
|
|
p_data_ep->DataIn = USBD_EP_ADDR_NONE;
|
|
p_data_ep->DataOut = USBD_EP_ADDR_NONE;
|
|
}
|
|
|
|
USBD_CDC_CtrlNbrNext = 0u;
|
|
USBD_CDC_CommNbrNext = 0u;
|
|
USBD_CDC_DataIF_NbrNext = 0u;
|
|
USBD_CDC_DataIF_EP_NbrNext = 0u;
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_Add()
|
|
*
|
|
* Description : Add a new instance of the CDC class.
|
|
*
|
|
* Argument(s) : subclass Communication class subclass subcode (see Note #1).
|
|
*
|
|
* p_subclass_drv Pointer to CDC subclass driver.
|
|
*
|
|
* p_subclass_arg Pointer to CDC subclass driver argument.
|
|
*
|
|
* protocol Communication class protocol code.
|
|
*
|
|
* notify_en Notification enabled :
|
|
*
|
|
* DEF_ENABLED Enable CDC class notifications.
|
|
* DEF_DISABLED Disable CDC class notifications.
|
|
*
|
|
* notify_interval Notification interval in milliseconds. It must be a power of 2.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE CDC class instance successfully added.
|
|
* USBD_ERR_ALLOC CDC class instances NOT available.
|
|
*
|
|
* Return(s) : CDC class instance number, if NO error(s).
|
|
*
|
|
* USBD_CDC_NBR_NONE, otherwise.
|
|
*
|
|
* Note(s) : (1) Communication class subclass codes are defined in 'usbd_cdc.h'
|
|
* 'USBD_CDC_SUBCLASS_XXXX'.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_CDC_Add (CPU_INT08U subclass,
|
|
USBD_CDC_SUBCLASS_DRV *p_subclass_drv,
|
|
void *p_subclass_arg,
|
|
CPU_INT08U protocol,
|
|
CPU_BOOLEAN notify_en,
|
|
CPU_INT16U notify_interval,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U cdc_nbr;
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
|
|
if ((notify_en == DEF_ENABLED) &&
|
|
(MATH_IS_PWR2(notify_interval) == DEF_NO)) { /* Interval must be a power of 2. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (USBD_CDC_NBR_NONE);
|
|
}
|
|
#endif
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
cdc_nbr = USBD_CDC_CtrlNbrNext; /* Alloc new CDC class. */
|
|
|
|
if (cdc_nbr >= USBD_CDC_CFG_MAX_NBR_DEV) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CDC_INSTANCE_ALLOC;
|
|
return (USBD_CDC_NBR_NONE);
|
|
}
|
|
|
|
USBD_CDC_CtrlNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[cdc_nbr]; /* Get & init CDC struct. */
|
|
|
|
p_ctrl->SubClassCode = subclass;
|
|
p_ctrl->SubClassProtocol = protocol;
|
|
p_ctrl->NotifyEn = notify_en;
|
|
p_ctrl->NotifyInterval = notify_interval;
|
|
p_ctrl->SubClassDrvPtr = p_subclass_drv;
|
|
p_ctrl->SubClassArg = p_subclass_arg;
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return (cdc_nbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_AddCfg()
|
|
*
|
|
* Description : Add CDC instance into USB device configuration.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add new CDC class interface to.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE CDC class configuration successfully added.
|
|
* USBD_ERR_ALLOC CDC class communication instance NOT available.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
|
|
*
|
|
* --------- RETURNED BY USBD_IF_Add() : ----------
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_desc'/
|
|
* 'class_desc_size'.
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_DEV_INVALID_STATE Invalid device state.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_ALLOC Interfaces NOT available.
|
|
* USBD_ERR_IF_ALT_ALLOC Interface alternate settings NOT available.
|
|
*
|
|
* --------- RETURNED BY USBD_BulkAdd() : ---------
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'max_pkt_len'.
|
|
*
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
|
|
* USBD_ERR_EP_NONE_AVAIL Physical endpoint NOT available.
|
|
* USBD_ERR_EP_ALLOC Endpoints NOT available.
|
|
*
|
|
* --------- RETURNED BY USBD_IntrAdd() : ---------
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'interval'/
|
|
* 'max_pkt_len'.
|
|
*
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
|
|
* USBD_ERR_EP_NONE_AVAIL Physical endpoint NOT available.
|
|
* USBD_ERR_EP_ALLOC Endpoints NOT available.
|
|
*
|
|
* --------- RETURNED BY USBD_IF_Grp() : ----------
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
|
|
* USBD_ERR_IF_GRP_NBR_IN_USE Interface is part of another group.
|
|
* USBD_ERR_IF_GRP_ALLOC Interface groups NOT available.
|
|
*
|
|
* Return(s) : DEF_YES, if CDC class instance added to USB device configuration successfully.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_CDC_CfgAdd (CPU_INT08U class_nbr,
|
|
CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
const CPU_CHAR *comm_name,
|
|
const CPU_CHAR *data_name,
|
|
const CPU_CHAR *grp_name,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
CPU_INT08U if_nbr;
|
|
CPU_INT08U if_alt_nbr;
|
|
CPU_INT08U ep_addr;
|
|
CPU_INT16U comm_nbr;
|
|
CPU_INT16U data_if_nbr_cur = 0u;
|
|
CPU_INT16U data_if_nbr_end = 0u;
|
|
CPU_INT16U data_if_ix;
|
|
CPU_INT16U notify_interval;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
comm_nbr = USBD_CDC_CommNbrNext; /* Alloc CDC class comm info. */
|
|
if (comm_nbr >= USBD_CDC_COMM_NBR_MAX) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CDC_INSTANCE_ALLOC;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
USBD_CDC_CommNbrNext++;
|
|
p_comm = &USBD_CDC_CommTbl[comm_nbr];
|
|
|
|
if (p_ctrl->DataIF_Nbr > 0u) {
|
|
data_if_nbr_cur = USBD_CDC_DataIF_EP_NbrNext; /* Alloc data IFs EP struct. */
|
|
data_if_nbr_end = data_if_nbr_cur + p_ctrl->DataIF_Nbr;
|
|
if (data_if_nbr_end > USBD_CDC_DATA_IF_EP_NBR_MAX) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CDC_INSTANCE_ALLOC;
|
|
return (DEF_NO);
|
|
}
|
|
|
|
USBD_CDC_DataIF_EP_NbrNext = data_if_nbr_end;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if_nbr = USBD_IF_Add( dev_nbr, /* Add CDC comm IF to cfg. */
|
|
cfg_nbr,
|
|
&USBD_CDC_CommDrv,
|
|
(void *)p_comm,
|
|
(void *)0,
|
|
USBD_CLASS_CODE_CDC_CONTROL,
|
|
p_ctrl->SubClassCode,
|
|
p_ctrl->SubClassProtocol,
|
|
comm_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_comm->CCI_IF_Nbr = if_nbr;
|
|
|
|
if (p_ctrl->NotifyEn == DEF_TRUE) {
|
|
|
|
if (DEF_BIT_IS_CLR(cfg_nbr, USBD_CFG_NBR_SPD_BIT) == DEF_YES) {
|
|
notify_interval = p_ctrl->NotifyInterval; /* In FS, bInterval in frames. */
|
|
} else {
|
|
notify_interval = p_ctrl->NotifyInterval * 8u; /* In HS, bInterval in microframes. */
|
|
}
|
|
|
|
ep_addr = USBD_IntrAdd(dev_nbr, /* Add interrupt (IN) EP for notifications. */
|
|
cfg_nbr,
|
|
if_nbr,
|
|
0u,
|
|
DEF_YES,
|
|
0u,
|
|
notify_interval,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_comm->NotifyIn = ep_addr;
|
|
}
|
|
|
|
|
|
if (p_ctrl->DataIF_Nbr > 0u) { /* Add CDC data IFs to cfg. */
|
|
p_comm->DataIF_EP_Ix = data_if_nbr_cur;
|
|
p_data_if = p_ctrl->DataIF_HeadPtr;
|
|
|
|
for (data_if_ix = data_if_nbr_cur; data_if_ix < data_if_nbr_end; data_if_ix++) {
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[data_if_ix];
|
|
|
|
/* Add CDC data IF to cfg. */
|
|
if_nbr = USBD_IF_Add( dev_nbr,
|
|
cfg_nbr,
|
|
&USBD_CDC_DataDrv,
|
|
(void *)p_comm,
|
|
(void *)0u,
|
|
USBD_CLASS_CODE_CDC_DATA,
|
|
USBD_SUBCLASS_CODE_USE_IF_DESC,
|
|
p_data_if->Protocol,
|
|
data_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_data_if->IF_Nbr = if_nbr;
|
|
if_alt_nbr = 0;
|
|
|
|
if (p_ctrl->SubClassCode == USBD_CDC_SUBCLASS_NCM) {
|
|
if_alt_nbr = USBD_IF_AltAdd( dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
(void *)NULL,
|
|
data_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
if (p_data_if->IsocEn == DEF_DISABLED) {
|
|
/* Add Bulk IN EP. */
|
|
ep_addr = USBD_BulkAdd(dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
DEF_YES,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_data_ep->DataIn = ep_addr;
|
|
/* Add Bulk OUT EP. */
|
|
ep_addr = USBD_BulkAdd(dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
DEF_NO,
|
|
0u,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_data_ep->DataOut = ep_addr;
|
|
p_data_if = p_data_if->NextPtr;
|
|
/* Group comm IF with data IFs. */
|
|
(void)USBD_IF_Grp( dev_nbr,
|
|
cfg_nbr,
|
|
USBD_CLASS_CODE_CDC_CONTROL,
|
|
p_ctrl->SubClassCode,
|
|
p_ctrl->SubClassProtocol,
|
|
p_comm->CCI_IF_Nbr,
|
|
p_ctrl->DataIF_Nbr + 1u,
|
|
grp_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
p_comm->DevNbr = dev_nbr;
|
|
p_comm->CtrlPtr = p_ctrl;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->State = USBD_CDC_STATE_INIT;
|
|
p_ctrl->CommPtr = (USBD_CDC_COMM *)0;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
|
|
return (DEF_YES);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_IsConn()
|
|
*
|
|
* Description : Get the CDC class connection state.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* Return(s) : DEF_YES, if CDC class is connected.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_CDC_IsConn (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_DEV_STATE state;
|
|
USBD_ERR err;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
return (DEF_NO);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->CommPtr == (USBD_CDC_COMM *)0) {
|
|
return (DEF_NO);
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
state = USBD_DevStateGet(p_comm->DevNbr, &err); /* Get dev state. */
|
|
|
|
if ((err == USBD_ERR_NONE ) &&
|
|
(state == USBD_DEV_STATE_CONFIGURED) &&
|
|
(p_ctrl->State == USBD_CDC_STATE_CFG )) {
|
|
return (DEF_YES);
|
|
}
|
|
|
|
return (DEF_NO);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataIF_Add()
|
|
*
|
|
* Description : Add data interface class to CDC communication interface class.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* isoc_en Data interface isochronous enable (see Note #1) :
|
|
*
|
|
* DEF_ENABLED Data interface uses isochronous EPs.
|
|
* DEF_DISABLED Data interface uses bulk EPs.
|
|
*
|
|
* protocol Data interface protocol code.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data interface successfully added.
|
|
* USBD_ERR_ALLOC Data interface instance NOT available.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr/
|
|
* 'isoc_en'.
|
|
*
|
|
* Return(s) : Data interface number.
|
|
*
|
|
* Note(s) : (1) $$$$ The value of 'isoc_en' must be DEF_DISABLED. Isochronous EPs are not supported.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_CDC_DataIF_Add (CPU_INT08U class_nbr,
|
|
CPU_BOOLEAN isoc_en,
|
|
CPU_INT08U protocol,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
CPU_INT16U data_if_ix;
|
|
CPU_INT08U data_if_nbr;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
|
|
/* Check 'isoc_en' argument (see Note #1) . */
|
|
if (isoc_en == DEF_ENABLED) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (USBD_CDC_DATA_IF_NBR_NONE);
|
|
}
|
|
#endif
|
|
/* Check CDC class instance nbr. */
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) {
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (USBD_CDC_DATA_IF_NBR_NONE);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
data_if_ix = USBD_CDC_DataIF_NbrNext; /* Alloc data interface. */
|
|
|
|
if (data_if_ix >= USBD_CDC_CFG_MAX_NBR_DATA_IF) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CDC_DATA_IF_ALLOC;
|
|
return (USBD_CDC_DATA_IF_NBR_NONE);
|
|
}
|
|
|
|
USBD_CDC_DataIF_NbrNext++;
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
p_data_if = &USBD_CDC_DataIF_Tbl[data_if_ix];
|
|
data_if_nbr = p_ctrl->DataIF_Nbr;
|
|
|
|
if (data_if_nbr == USBD_CDC_DATA_IF_NBR_TOTAL) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CDC_DATA_IF_ALLOC;
|
|
return (USBD_CDC_DATA_IF_NBR_NONE);
|
|
}
|
|
|
|
if (p_ctrl->DataIF_HeadPtr == (USBD_CDC_DATA_IF *)0) { /* Add data IF in the list. */
|
|
p_ctrl->DataIF_HeadPtr = p_data_if;
|
|
} else {
|
|
p_ctrl->DataIF_TailPtr->NextPtr = p_data_if;
|
|
}
|
|
p_ctrl->DataIF_TailPtr = p_data_if;
|
|
p_ctrl->DataIF_Nbr++;
|
|
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_data_if->Protocol = protocol;
|
|
p_data_if->IsocEn = isoc_en;
|
|
p_data_if->NextPtr = (USBD_CDC_DATA_IF *)0;
|
|
|
|
return (data_if_nbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataRx()
|
|
*
|
|
* Description : Receive data on CDC data interface.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* data_if_nbr CDC data interface number.
|
|
*
|
|
* p_buf Pointer to destination buffer to receive data.
|
|
*
|
|
* buf_len Number of octets to receive.
|
|
*
|
|
* timeout_ms Timeout in milliseconds.
|
|
*
|
|
* p_err Pointer to variable that will receive return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data successfully received.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
|
|
* 'data_if_nbr'.
|
|
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
|
|
*
|
|
* --------- RETURNED BY USBD_BulkRx() : ---------
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
|
|
* configured state.
|
|
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
|
|
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
|
|
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
|
|
*
|
|
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
|
|
* specified by 'timeout_ms'.
|
|
* USBD_ERR_OS_ABORT OS signal aborted.
|
|
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
|
|
*
|
|
* See specific device driver(s) 'EP_RxStart()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_Rx()' for
|
|
* additional return error codes.
|
|
|
|
* Return(s) : Number of octets received, if NO error(s).
|
|
*
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT32U USBD_CDC_DataRx (CPU_INT08U class_nbr,
|
|
CPU_INT08U data_if_nbr,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
CPU_INT32U xfer_len;
|
|
CPU_INT16U data_if_ix;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->State != USBD_CDC_STATE_CFG) { /* Transfers are only valid in cfg state. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return (0u);
|
|
}
|
|
|
|
if (data_if_nbr >= p_ctrl->DataIF_Nbr) { /* Check 'data_if_nbr' is valid. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return(0u);
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
p_data_if = p_ctrl->DataIF_HeadPtr;
|
|
/* Find data IF struct. */
|
|
for (data_if_ix = 0u; data_if_ix < data_if_nbr; data_if_ix++) {
|
|
p_data_if = p_data_if->NextPtr;
|
|
}
|
|
|
|
data_if_ix = p_comm->DataIF_EP_Ix + data_if_nbr;
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[data_if_ix];
|
|
xfer_len = 0u;
|
|
|
|
if (p_data_if->IsocEn == DEF_DISABLED) {
|
|
xfer_len = USBD_BulkRx(p_comm->DevNbr,
|
|
p_data_ep->DataOut,
|
|
p_buf,
|
|
buf_len,
|
|
timeout,
|
|
p_err);
|
|
} else {
|
|
*p_err = USBD_ERR_DEV_UNAVAIL_FEAT; /* $$$$ Isoc transfer not supported. */
|
|
return (0u);
|
|
}
|
|
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataRxAsync()
|
|
*
|
|
* Description : Receive data on CDC data interface.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* data_if_nbr CDC data interface number.
|
|
*
|
|
* p_buf Pointer to destination buffer to receive data.
|
|
*
|
|
* buf_len Number of octets to receive.
|
|
*
|
|
* async_fnct Function that will be invoked upon completion of receive operation.
|
|
*
|
|
* p_async_arg Pointer to argument that will be passed as parameter of 'async_fnct'.
|
|
*
|
|
* p_err Pointer to variable that will receive return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data successfully received.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
|
|
* 'data_if_nbr'.
|
|
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
|
|
*
|
|
* --------- RETURNED BY USBD_BulkRx() : ---------
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
|
|
* configured state.
|
|
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
|
|
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
|
|
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
|
|
*
|
|
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
|
|
* specified by 'timeout_ms'.
|
|
* USBD_ERR_OS_ABORT OS signal aborted.
|
|
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
|
|
*
|
|
* See specific device driver(s) 'EP_RxStart()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_Rx()' for
|
|
* additional return error codes.
|
|
|
|
* Return(s) : Number of octets received, if NO error(s).
|
|
*
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_DataRxAsync (CPU_INT08U class_nbr,
|
|
CPU_INT08U data_if_nbr,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
USBD_ASYNC_FNCT async_fnct,
|
|
void *p_async_arg,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
CPU_INT16U data_if_ix;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return ;
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->State != USBD_CDC_STATE_CFG) { /* Transfers are only valid in cfg state. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return ;
|
|
}
|
|
|
|
if (data_if_nbr >= p_ctrl->DataIF_Nbr) { /* Check 'data_if_nbr' is valid. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
p_data_if = p_ctrl->DataIF_HeadPtr;
|
|
/* Find data IF struct. */
|
|
for (data_if_ix = 0u; data_if_ix < data_if_nbr; data_if_ix++) {
|
|
p_data_if = p_data_if->NextPtr;
|
|
}
|
|
|
|
data_if_ix = p_comm->DataIF_EP_Ix + data_if_nbr;
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[data_if_ix];
|
|
|
|
if (p_data_if->IsocEn == DEF_DISABLED) {
|
|
USBD_BulkRxAsync(p_comm->DevNbr,
|
|
p_data_ep->DataOut,
|
|
p_buf,
|
|
buf_len,
|
|
async_fnct,
|
|
p_async_arg,
|
|
p_err);
|
|
} else {
|
|
*p_err = USBD_ERR_DEV_UNAVAIL_FEAT; /* $$$$ Isoc transfer not supported. */
|
|
return ;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataTx()
|
|
*
|
|
* Description : Send data on CDC data interface.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* data_if_nbr CDC data interface number.
|
|
*
|
|
* p_buf Pointer to buffer of data that will be transmitted.
|
|
*
|
|
* buf_len Number of octets to transmit.
|
|
*
|
|
* timeout_ms Timeout in milliseconds.
|
|
*
|
|
* p_err Pointer to variable that will receive return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data successfully received.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
|
|
* 'data_if_nbr'.
|
|
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
|
|
*
|
|
* --------- RETURNED BY USBD_BulkTx() : ---------
|
|
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
|
|
* configured state.
|
|
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
|
|
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
|
|
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
|
|
*
|
|
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
|
|
* specified by 'timeout_ms'.
|
|
* USBD_ERR_OS_ABORT OS signal aborted.
|
|
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
|
|
*
|
|
* See specific device driver(s) 'EP_Tx()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxStart()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxZLP()' for
|
|
* additional return error codes.
|
|
*
|
|
* Return(s) : Number of octets transmitted, if NO error(s).
|
|
*
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT32U USBD_CDC_DataTx (CPU_INT08U class_nbr,
|
|
CPU_INT08U data_if_nbr,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
CPU_INT32U xfer_len;
|
|
CPU_INT16U data_if_ix;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->State != USBD_CDC_STATE_CFG) { /* Transfers are only valid in cfg state. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return (0u);
|
|
}
|
|
|
|
if (data_if_nbr >= p_ctrl->DataIF_Nbr) { /* Check 'data_if_nbr' is valid. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return(0u);
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
p_data_if = p_ctrl->DataIF_HeadPtr;
|
|
/* Find data IF struct. */
|
|
for (data_if_ix = 0u; data_if_ix < data_if_nbr; data_if_ix++) {
|
|
p_data_if = p_data_if->NextPtr;
|
|
}
|
|
|
|
data_if_ix = p_comm->DataIF_EP_Ix + data_if_nbr;
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[data_if_ix];
|
|
xfer_len = 0u;
|
|
|
|
if (p_data_if->IsocEn == DEF_DISABLED) {
|
|
xfer_len = USBD_BulkTx(p_comm->DevNbr,
|
|
p_data_ep->DataIn,
|
|
p_buf,
|
|
buf_len,
|
|
timeout,
|
|
DEF_YES,
|
|
p_err);
|
|
} else {
|
|
*p_err = USBD_ERR_DEV_UNAVAIL_FEAT; /* $$$$ Isoc transfer not supported. */
|
|
return (0u);
|
|
}
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataTxAsync()
|
|
*
|
|
* Description : Send data on CDC data interface.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* data_if_nbr CDC data interface number.
|
|
*
|
|
* p_buf Pointer to buffer of data that will be transmitted.
|
|
*
|
|
* buf_len Number of octets to transmit.
|
|
*
|
|
* async_fnct Function that will be invoked upon completion of transmit operation.
|
|
*
|
|
* p_async_arg Pointer to argument that will be passed as parameter of 'async_fnct'.
|
|
*
|
|
* p_err Pointer to variable that will receive return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data successfully received.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
|
|
* 'data_if_nbr'.
|
|
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
|
|
*
|
|
* --------- RETURNED BY USBD_BulkTx() : ---------
|
|
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
|
|
* configured state.
|
|
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
|
|
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
|
|
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
|
|
*
|
|
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
|
|
* specified by 'timeout_ms'.
|
|
* USBD_ERR_OS_ABORT OS signal aborted.
|
|
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
|
|
*
|
|
* See specific device driver(s) 'EP_Tx()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxStart()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxZLP()' for
|
|
* additional return error codes.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_CDC_DataTxAsync (CPU_INT08U class_nbr,
|
|
CPU_INT08U data_if_nbr,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
USBD_ASYNC_FNCT async_fnct,
|
|
void *p_async_arg,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
USBD_CDC_DATA_IF_EP *p_data_ep;
|
|
CPU_INT16U data_if_ix;
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return ;
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->State != USBD_CDC_STATE_CFG) { /* Transfers are only valid in cfg state. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return ;
|
|
}
|
|
|
|
if (data_if_nbr >= p_ctrl->DataIF_Nbr) { /* Check 'data_if_nbr' is valid. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
p_comm = p_ctrl->CommPtr;
|
|
p_data_if = p_ctrl->DataIF_HeadPtr;
|
|
/* Find data IF struct. */
|
|
for (data_if_ix = 0u; data_if_ix < data_if_nbr; data_if_ix++) {
|
|
p_data_if = p_data_if->NextPtr;
|
|
}
|
|
|
|
data_if_ix = p_comm->DataIF_EP_Ix + data_if_nbr;
|
|
p_data_ep = &USBD_CDC_DataIF_EP_Tbl[data_if_ix];
|
|
|
|
if (p_data_if->IsocEn == DEF_DISABLED) {
|
|
USBD_BulkTxAsync(p_comm->DevNbr,
|
|
p_data_ep->DataIn,
|
|
p_buf,
|
|
buf_len,
|
|
async_fnct,
|
|
p_async_arg,
|
|
DEF_YES,
|
|
p_err);
|
|
} else {
|
|
*p_err = USBD_ERR_DEV_UNAVAIL_FEAT; /* $$$$ Isoc transfer not supported. */
|
|
return ;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_Notify()
|
|
*
|
|
* Description : Send communication interface class notification to the host.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* notification Notification code.
|
|
*
|
|
* value Notification value.
|
|
*
|
|
* p_buf Pointer to notification buffer (see Note #1).
|
|
*
|
|
* data_len Length of the data portion of the notification.
|
|
*
|
|
* p_err Pointer to variable that will receive return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Data successfully received.
|
|
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'
|
|
* USBD_ERR_INVALID_CLASS_STATE Invalid class state.
|
|
*
|
|
* ------- RETURNED BY USBD_IntrTxAsync() : -------
|
|
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
|
|
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
|
|
* configured state.
|
|
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
|
|
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
|
|
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
|
|
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
|
|
* specified by 'timeout_ms'.
|
|
* USBD_ERR_OS_ABORT OS signal aborted.
|
|
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
|
|
*
|
|
* See specific device driver(s) 'EP_Tx()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxStart()' for
|
|
* additional return error codes.
|
|
*
|
|
* See specific device driver(s) 'EP_TxZLP()' for
|
|
* additional return error codes.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : (1) The notification buffer MUST contain space for the notification header
|
|
* 'USBD_CDC_NOTIFICATION_HEADER' plus the variable-length data portion.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_CDC_Notify (CPU_INT08U class_nbr,
|
|
CPU_INT08U notification,
|
|
CPU_INT16U value,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT16U data_len,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
|
|
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(DEF_FAIL);
|
|
}
|
|
#endif
|
|
|
|
if (class_nbr >= USBD_CDC_CtrlNbrNext) { /* Check CDC class instance nbr. */
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (DEF_FAIL);
|
|
}
|
|
|
|
p_ctrl = &USBD_CDC_CtrlTbl[class_nbr];
|
|
|
|
if (p_ctrl->State != USBD_CDC_STATE_CFG) { /* Transfers are only valid in cfg state. */
|
|
*p_err = USBD_ERR_INVALID_CLASS_STATE;
|
|
return (DEF_FAIL);
|
|
}
|
|
p_comm = p_ctrl->CommPtr;
|
|
|
|
p_buf[0] = (1u ) /* Recipient : Interface. */
|
|
| (1u << 5u) /* Type : Class. */
|
|
| DEF_BIT_07; /* Direction : Device to host. */
|
|
p_buf[1] = notification;
|
|
p_buf[4] = p_comm->CCI_IF_Nbr;
|
|
p_buf[5] = 0u;
|
|
MEM_VAL_SET_INT16U_LITTLE(&p_buf[2], value);
|
|
MEM_VAL_SET_INT16U_LITTLE(&p_buf[6], data_len);
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_comm->NotifyInActiveXfer == DEF_NO) { /* Check if another xfer is already in progress. */
|
|
p_comm->NotifyInActiveXfer = DEF_YES; /* Indicate that a xfer is in progres. */
|
|
CPU_CRITICAL_EXIT();
|
|
USBD_IntrTxAsync( p_comm->DevNbr,
|
|
p_comm->NotifyIn,
|
|
p_buf,
|
|
(CPU_INT32U)data_len + USBD_CDC_NOTIFICATION_HEADER,
|
|
USBD_CDC_NotifyCmpl,
|
|
(void *)p_comm,
|
|
DEF_YES,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
CPU_CRITICAL_ENTER();
|
|
p_comm->NotifyInActiveXfer = DEF_NO;
|
|
CPU_CRITICAL_EXIT();
|
|
return (DEF_FAIL);
|
|
}
|
|
} else {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_XFER_IN_PROGRESS;
|
|
return (DEF_FAIL);
|
|
}
|
|
|
|
return (DEF_OK);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_Conn()
|
|
*
|
|
* Description : Notify class that configuration is active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration ix to add the interface.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_COMM *p_comm;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)cfg_nbr;
|
|
(void)dev_nbr;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
CPU_CRITICAL_ENTER();
|
|
p_comm->CtrlPtr->CommPtr = p_comm;
|
|
p_comm->CtrlPtr->State = USBD_CDC_STATE_CFG;
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_Disconn()
|
|
*
|
|
* Description : Notify class that configuration is not active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration ix to add the interface.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_Disconn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_COMM *p_comm;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)cfg_nbr;
|
|
(void)dev_nbr;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
CPU_CRITICAL_ENTER();
|
|
p_comm->CtrlPtr->CommPtr = (USBD_CDC_COMM *)0;
|
|
p_comm->CtrlPtr->State = USBD_CDC_STATE_INIT;
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_ClassReq()
|
|
*
|
|
* Description : Class request handler.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* p_setup_req Pointer to setup request structure.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : DEF_OK, if NO error(s) occurred and request is supported.
|
|
*
|
|
* DEF_FAIL, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_BOOLEAN USBD_CDC_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
CPU_BOOLEAN valid;
|
|
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
valid = DEF_OK;
|
|
|
|
if (p_drv->MngmtReq != (void *)0) {
|
|
/* Call subclass-specific management request handler. */
|
|
valid = p_drv->MngmtReq(dev_nbr,
|
|
p_setup_req,
|
|
p_ctrl->SubClassArg);
|
|
}
|
|
|
|
return (valid);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_NotifyCmpl()
|
|
*
|
|
* Description : CDC notification complete callback.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* ep_addr Endpoint address.
|
|
*
|
|
* p_buf Pointer to the transmit buffer.
|
|
*
|
|
* buf_len Transmit 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_NotifyCmpl (CPU_INT08U dev_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
void *p_arg,
|
|
USBD_ERR err)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
|
|
|
|
(void)ep_addr;
|
|
(void)p_buf;
|
|
(void)buf_len;
|
|
(void)xfer_len;
|
|
(void)err;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
|
|
p_comm->NotifyInActiveXfer = DEF_NO; /* Xfer finished, no more active xfer. */
|
|
if (p_drv->NotifyCmpl != (void *)0) {
|
|
p_drv->NotifyCmpl(dev_nbr, p_ctrl->SubClassArg);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_CommIF_Desc()
|
|
*
|
|
* Description : Class interface descriptor callback.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_CommIF_Desc (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
USBD_CDC_DATA_IF *p_data_if;
|
|
CPU_INT08U desc_size;
|
|
CPU_INT08U data_if_nbr;
|
|
|
|
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)if_alt_nbr;
|
|
(void)p_if_alt_class_arg;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
/* ------------- BUILD HEADER DESCRIPTOR -------------- */
|
|
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_SIZE_HEADER);
|
|
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_SUBTYPE_HEADER);
|
|
USBD_DescWr16(dev_nbr, 0x0120u); /* CDC release number (1.20) in BCD fmt. */
|
|
|
|
/* ------------- BUILD UNION IF DESCRIPTOR ------------ */
|
|
if (p_ctrl->DataIF_Nbr > 0u) {
|
|
desc_size = USBD_CDC_DESC_SIZE_UNION_MIN + p_ctrl->DataIF_Nbr;
|
|
|
|
USBD_DescWr08(dev_nbr, desc_size);
|
|
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_SUBTYPE_UNION);
|
|
USBD_DescWr08(dev_nbr, p_comm->CCI_IF_Nbr);
|
|
|
|
p_data_if = p_ctrl->DataIF_HeadPtr; /* Add all subordinate data IFs. */
|
|
|
|
for (data_if_nbr = 0u; data_if_nbr < p_ctrl->DataIF_Nbr; data_if_nbr++) {
|
|
USBD_DescWr08(dev_nbr, p_data_if->IF_Nbr);
|
|
p_data_if = p_data_if->NextPtr;
|
|
}
|
|
}
|
|
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
|
|
if (p_drv->FnctDesc != (void *)0) {
|
|
/* Call subclass-specific functional descriptor. */;
|
|
p_drv->FnctDesc(dev_nbr,
|
|
p_ctrl->SubClassArg,
|
|
p_ctrl->DataIF_HeadPtr->IF_Nbr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_CommIF_DescSizeGet()
|
|
*
|
|
* Description : Retrieve the size of the class interface descriptor.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : Size of the class interface descriptor.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT16U USBD_CDC_CommIF_DescSizeGet (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
CPU_INT16U desc_size;
|
|
|
|
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)if_alt_nbr;
|
|
(void)p_if_alt_class_arg;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
|
|
desc_size = USBD_CDC_DESC_SIZE_HEADER;
|
|
|
|
if (p_ctrl->DataIF_Nbr > 0u) {
|
|
desc_size += USBD_CDC_DESC_SIZE_UNION_MIN;
|
|
desc_size += p_ctrl->DataIF_Nbr;
|
|
}
|
|
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
|
|
if (p_drv->FnctDescSizeGet != (void *)0) {
|
|
desc_size += p_drv->FnctDescSizeGet(dev_nbr, p_ctrl->SubClassArg);
|
|
}
|
|
|
|
return (desc_size);
|
|
}
|
|
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_MS_GetCompatID()
|
|
*
|
|
* Description : Returns Microsoft descriptor compatible ID.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* p_sub_compat_id_ix Pointer to variable that will receive subcompatible ID.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : Compatible ID.
|
|
*
|
|
* DEF_FAIL, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT08U USBD_CDC_MS_GetCompatID (CPU_INT08U dev_nbr,
|
|
CPU_INT08U *p_sub_compat_id_ix,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
|
|
(void)dev_nbr;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
|
|
*p_sub_compat_id_ix = USBD_MS_OS_SUBCOMPAT_ID_NULL;
|
|
|
|
if (p_ctrl->SubClassCode == USBD_CDC_SUBCLASS_NCM) {
|
|
return (USBD_MS_OS_COMPAT_ID_WINNCM);
|
|
} else {
|
|
return (USBD_MS_OS_COMPAT_ID_NONE);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_MS_GetExtPropertyTbl()
|
|
*
|
|
* Description : Returns Microsoft descriptor extended properties table.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* pp_ext_property_tbl Pointer to variable that will receive the Microsoft extended
|
|
* properties table.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : Number of Microsoft extended properties in table.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT08U USBD_CDC_MS_GetExtPropertyTbl (CPU_INT08U dev_nbr,
|
|
USBD_MS_OS_EXT_PROPERTY **pp_ext_property_tbl,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
|
|
(void)dev_nbr;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
|
|
if (p_drv->FnctMSExtPropertyTbl != (void *)NULL) {
|
|
/* Call subclass-specific MS property table request handler.*/
|
|
return p_drv->FnctMSExtPropertyTbl( dev_nbr,
|
|
p_ctrl->SubClassArg,
|
|
pp_ext_property_tbl);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_CDC_DataIF_AltSetUpdate()
|
|
*
|
|
* Description : Class interface alternate setting update callback.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_CDC_DataIF_AltSetUpdate (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_CDC_CTRL *p_ctrl;
|
|
USBD_CDC_COMM *p_comm;
|
|
USBD_CDC_SUBCLASS_DRV *p_drv;
|
|
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)p_if_alt_class_arg;
|
|
|
|
p_comm = (USBD_CDC_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
p_drv = p_ctrl->SubClassDrvPtr;
|
|
|
|
if (p_drv->DataAltSet != (void *)NULL) {
|
|
/* Call subclass-specific alternate setting update request handler. */
|
|
p_drv->DataAltSet(dev_nbr,
|
|
p_ctrl->SubClassArg,
|
|
if_alt_nbr);
|
|
}
|
|
}
|