/* ********************************************************************************************************* * 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 /* ********************************************************************************************************* * 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); } }