Files
base/middleware/usb/uC-USBD/Class/PHDC/usbd_phdc.c
2025-11-07 09:57:14 +08:00

2427 lines
100 KiB
C

/*
*********************************************************************************************************
* uC/USB-Device
* The Embedded USB Device Stack
*
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
**********************************************************************************************************
*
* USB DEVICE PHDC CLASS
*
* Filename : usbd_phdc.c
* Version : V4.06.01
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* INCLUDE FILES
**********************************************************************************************************
*/
#define MICRIUM_SOURCE
#define USBD_PHDC_MODULE
#include "usbd_phdc.h"
#include "usbd_phdc_os.h"
#include <lib_math.h>
/*
**********************************************************************************************************
* MODULE
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* LOCAL DEFINES
**********************************************************************************************************
*/
#define USBD_PHDC_COM_NBR_MAX (USBD_PHDC_CFG_MAX_NBR_DEV * \
USBD_PHDC_CFG_MAX_NBR_CFG)
#define USBD_PHDC_CLASS_FNCT_DESC_LEN 4
#define USBD_PHDC_FUNCT_EXTN_DESC_DFLT_LEN 4
#define USBD_PHDC_EXTRA_EP_DESC_MAX_LEN (USBD_PHDC_QOS_DESC_LEN + \
USBD_PHDC_CFG_DATA_OPAQUE_MAX_LEN + \
USBD_PHDC_METADATA_DESC_LEN)
#define USBD_PHDC_QOS_DESC_LEN 4u
#define USBD_PHDC_QOS_ENCOD_VER 0x01u
#define USBD_PHDC_QOS_VER_OFFSET 17u
#define USBD_PHDC_QOS_SIGNATURE "PhdcQoSSignature"
#define USBD_PHDC_QOS_SIGNATURE_LEN 16u
#define USBD_PHDC_METADATA_MSG_PREAMBLE_DFLT_LEN 20
#define USBD_PHDC_METADATA_MSG_PREAMBLE_MAX_LEN (USBD_PHDC_CFG_DATA_OPAQUE_MAX_LEN + \
USBD_PHDC_METADATA_MSG_PREAMBLE_DFLT_LEN)
#define USBD_PHDC_METADATA_DESC_LEN 2
#define USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_IN (USBD_PHDC_LATENCY_VERYHIGH_RELY_BEST | \
USBD_PHDC_LATENCY_HIGH_RELY_BEST | \
USBD_PHDC_LATENCY_MEDIUM_RELY_BEST | \
USBD_PHDC_LATENCY_MEDIUM_RELY_BETTER | \
USBD_PHDC_LATENCY_MEDIUM_RELY_GOOD)
#define USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_OUT (USBD_PHDC_LATENCY_VERYHIGH_RELY_BEST | \
USBD_PHDC_LATENCY_HIGH_RELY_BEST | \
USBD_PHDC_LATENCY_MEDIUM_RELY_BEST)
#define USBD_PHDC_RELY_LATENCY_FLAGS_EP_INTR_IN (USBD_PHDC_LATENCY_LOW_RELY_GOOD)
#define USBD_PHDC_XFER_PRIO_MAX 6
#define USBD_PHDC_XFER_PRIO_LOW_LATENCY 0u
#define USBD_PHDC_CTRL_REQ_TIMEOUT_mS 5000u
/*
*********************************************************************************************************
* PHDC NBR EP
*
* Note(s) : (1) PHDC require 2 bulk endpoints (IN and OUT) for very high, high and medium latency
* transfers. It optionally needs 1 interrupt IN endpoint for low latency transfer. See
* 'USB PHDC Class Specification Overview', Revision 1.0, Section 4.4.1.
*********************************************************************************************************
*/
#define USBD_PHDC_NBR_EP 3u
/*
*********************************************************************************************************
* DESCRIPTOR TYPES
*
* Note(s) : (1) See 'USB PHDC Class Specification Overview', Revision 1.0, Section 8 and Appendix A.
*********************************************************************************************************
*/
#define USBD_PHDC_DESC_TYPE_CLASS_FNCT 0x20u
#define USBD_PHDC_DESC_TYPE_FUNCT_EXTN_11073 0x30u
#define USBD_PHDC_DESC_TYPE_QOS 0x21u
#define USBD_PHDC_DESC_TYPE_METADATA 0x22u
/*
*********************************************************************************************************
* DATA FORMAT
*
* Note(s) : (1) See 'USB PHDC Class Specification Overview', Revision 1.0, Appendix A.
*********************************************************************************************************
*/
#define USBD_PHDC_DATA_FMT_VENDOR 0x01u
#define USBD_PHDC_DATA_FMT_11073_20601 0x02u
/*
*********************************************************************************************************
* PHDC CAPABILITY
*
* Note(s) : (1) See 'USB PHDC Class Specification Overview', Revision 1.0, Section 5.2.1.
*********************************************************************************************************
*/
#define USBD_PHDC_PREAMBLE_CAPABLE DEF_BIT_00
#define USBD_PHDC_PREAMBLE_NOT_CAPABLE DEF_BIT_NONE
/*
*********************************************************************************************************
* SUBCLASS CODES
*
* Note(s) : (1) See 'USB PHDC Class Specification Overview', Revision 1.0, Section 5.1.1.
* The PHDC does not assign a SUBCLASS CODE.
*********************************************************************************************************
*/
#define USBD_PHDC_SUBCLASS_CODE_NONE 0x00
/*
*********************************************************************************************************
* PROTOCOL CODES
*
* Note(s) : (1) See 'USB PHDC Class Specification Overview', Revision 1.0, Section 5.1.1.
* The PHDC does not assign a PROTOCOL CODE.
*********************************************************************************************************
*/
#define USBD_PHDC_PROTOCOL_CODE_NONE 0x00
/*
*********************************************************************************************************
* FEATURE SELECTORS
*
* Note(s) : (1) See 'Universal Serial Bus Specification Revision 2.0', Section 9.4, Table 9-6, and
* Section 9.4.1.
*
* (2) For a 'clear feature' setup request, the 'wValue' field may contain one of these values.
*********************************************************************************************************
*/
#define USBD_PHDC_CLASS_SPEC_FEATURE_PHDC_QOS 0x01u
/*
**********************************************************************************************************
* LOCAL CONSTANTS
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* LOCAL DATA TYPES
**********************************************************************************************************
*/
/*
*********************************************************************************************************
* ENDPOINT IDENTIFIERS
*********************************************************************************************************
*/
typedef enum usbd_phdc_ep_id {
USBD_PHDC_EP_BULK_IN = 0x00,
USBD_PHDC_EP_BULK_OUT,
USBD_PHDC_EP_INTR_IN
} USBD_PHDC_EP_ID;
/*
*********************************************************************************************************
* PHDC STATE
*********************************************************************************************************
*/
typedef enum usbd_phdc_state {
USBD_PHDC_STATE_NONE = 0,
USBD_PHDC_STATE_INIT,
USBD_PHDC_STATE_CFG
} USBD_PHDC_STATE;
/*
*********************************************************************************************************
* PHDC EP PARAMS
*********************************************************************************************************
*/
typedef struct usbd_phdc_ep_params {
const CPU_INT08U *DataOpaquePtr; /* Opaque data written in metadata desc. */
CPU_INT16U DataOpaqueLen;
} USBD_PHDC_EP_PARAMS;
/*
*********************************************************************************************************
* PHDC PARAMS
*********************************************************************************************************
*/
typedef struct usbd_phdc_params {
CPU_BOOLEAN DataFmt11073; /* DEF_TRUE if dev use 11073 data format. */
CPU_BOOLEAN PreambleCapable; /* DEF_TRUE if dev can send metadata preamble. */
CPU_INT16U *DevSpecialization; /* Array of dev specialization codes. */
CPU_INT16U NbrDevSpecialization;
} USBD_PHDC_PARAMS;
/*
*********************************************************************************************************
* FORWARD DECLARATIONS
*********************************************************************************************************
*/
typedef struct usbd_phdc_ctrl USBD_PHDC_CTRL;
/*
**********************************************************************************************************
* PRIORITY Q PREAMBLE
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* PHDC COMM INFO
**********************************************************************************************************
*/
typedef struct usbd_phdc_comm {
USBD_PHDC_CTRL *CtrlPtr;
CPU_INT08U DataBulkOut;
CPU_INT08U DataBulkIn;
CPU_INT08U DataIntrIn;
} USBD_PHDC_COMM;
/*
**********************************************************************************************************
* PHDC CTRL INFO
*
* Note(s) : (1) Rx and Tx DataXfersTotal holds the value of following tranfers to which QoS settings of a
* preamble applies. Rx and Tx DataXfersCur indicates what is the count of the current
* processed transfer.
**********************************************************************************************************
*/
struct usbd_phdc_ctrl {
CPU_INT08U Nbr; /* PHDC class instance number. */
CPU_INT08U DevNbr; /* Device number. */
USBD_PHDC_STATE State; /* PHDC state. */
USBD_PHDC_COMM *CommPtr; /* PHDC communication information ptr. */
USBD_PHDC_PARAMS IF_Params;
USBD_PHDC_EP_PARAMS EP_Params[USBD_PHDC_NBR_EP];
CPU_INT16U EP_DataStatus; /* See 'PHDC specifications Revision 1.0', Section 7.1.2*/
CPU_INT08U *CtrlStatusBufPtr; /* Buf used for ctrl status xfers. */
CPU_INT08U RxDataXfersTotal; /* See note 1. */
CPU_INT08U RxDataXfersCur;
LATENCY_RELY_FLAGS RxLatencyRelyBitmap;
CPU_INT08U TxDataXfersTotal[USBD_PHDC_XFER_PRIO_MAX - 1u];
CPU_INT08U TxDataXfersCur[USBD_PHDC_XFER_PRIO_MAX - 1u];
LATENCY_RELY_FLAGS TxLatencyRelyBitmap;
CPU_INT16U TxLowLatencyInterval; /* Intr EP interval in frames or micro-frames. */
CPU_INT08U *PreambleBufTxPtr;
CPU_INT08U *PreambleBufRxPtr;
CPU_BOOLEAN PreambleEn; /* Indicate if host enabled preamble or not. */
USBD_PHDC_PREAMBLE_EN_NOTIFY PreambleEnNotify;
};
/*
**********************************************************************************************************
* LOCAL TABLES
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* LOCAL GLOBAL VARIABLES
**********************************************************************************************************
*/
static USBD_PHDC_CTRL USBD_PHDC_CtrlTbl[USBD_PHDC_CFG_MAX_NBR_DEV];
static CPU_INT08U USBD_PHDC_CtrlNbrNext;
static USBD_PHDC_COMM USBD_PHDC_CommTbl[USBD_PHDC_COM_NBR_MAX];
static CPU_INT16U USBD_PHDC_CommNbrNext;
/*
**********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
**********************************************************************************************************
*/
static void USBD_PHDC_Conn ( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg);
static void USBD_PHDC_Disconn ( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg);
static void USBD_PHDC_SettingUpdate ( 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_PHDC_IF_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_PHDC_IF_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 void USBD_PHDC_EP_Desc ( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
CPU_INT08U if_nbr,
CPU_INT08U if_alt_nbr,
CPU_INT08U ep_addr,
void *p_if_class_arg,
void *p_if_alt_class_arg);
static CPU_INT16U USBD_PHDC_EP_DescSizeGet( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
CPU_INT08U if_nbr,
CPU_INT08U if_alt_nbr,
CPU_INT08U ep_addr,
void *p_if_class_arg,
void *p_if_alt_class_arg);
static CPU_BOOLEAN USBD_PHDC_ClassReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg);
/*
*********************************************************************************************************
* PHDC CLASS DRIVER
*********************************************************************************************************
*/
static USBD_CLASS_DRV USBD_PHDC_Drv = {
USBD_PHDC_Conn,
USBD_PHDC_Disconn,
USBD_PHDC_SettingUpdate,
DEF_NULL,
USBD_PHDC_IF_Desc,
USBD_PHDC_IF_DescSizeGet,
USBD_PHDC_EP_Desc,
USBD_PHDC_EP_DescSizeGet,
DEF_NULL,
USBD_PHDC_ClassReq,
DEF_NULL,
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
DEF_NULL,
DEF_NULL
#endif
};
/*
**********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
**********************************************************************************************************
*/
/*
*********************************************************************************************************
*********************************************************************************************************
* GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_PHDC_Init()
*
* Description : Initialize PHDC.
*
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE PHDC initialized successfully.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_PHDC_Init (USBD_ERR *p_err)
{
CPU_INT08U ix;
CPU_INT08U i;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
CPU_SIZE_T ctrl_buf_len;
LIB_ERR err_lib;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
for (ix = 0u; ix < USBD_PHDC_CFG_MAX_NBR_DEV; ix++) { /* Init PHDC ctrl struct. */
p_ctrl = &USBD_PHDC_CtrlTbl[ix];
p_ctrl->Nbr = ix;
p_ctrl->DevNbr = USBD_DEV_NBR_NONE;
p_ctrl->State = USBD_PHDC_STATE_NONE;
p_ctrl->CommPtr = (USBD_PHDC_COMM *)0;
p_ctrl->EP_Params[0].DataOpaquePtr = (const CPU_INT08U *)0;
p_ctrl->EP_Params[1].DataOpaquePtr = (const CPU_INT08U *)0;
p_ctrl->EP_Params[2].DataOpaquePtr = (const CPU_INT08U *)0;
p_ctrl->EP_Params[0].DataOpaqueLen = 0;
p_ctrl->EP_Params[1].DataOpaqueLen = 0;
p_ctrl->EP_Params[2].DataOpaqueLen = 0;
p_ctrl->EP_DataStatus = DEF_BIT_NONE;
p_ctrl->RxDataXfersTotal = 0u;
p_ctrl->RxDataXfersCur = 0u;
p_ctrl->RxLatencyRelyBitmap = DEF_BIT_NONE;
p_ctrl->TxLatencyRelyBitmap = DEF_BIT_NONE;
p_ctrl->TxLowLatencyInterval = 0u;
p_ctrl->PreambleEn = DEF_DISABLED;
for (i = 0; i < (USBD_PHDC_XFER_PRIO_MAX - 1u); i++) {
p_ctrl->TxDataXfersTotal[i] = 0u;
p_ctrl->TxDataXfersCur[i] = 0u;
}
p_ctrl->PreambleBufTxPtr = (CPU_INT08U *)Mem_HeapAlloc( USBD_PHDC_METADATA_MSG_PREAMBLE_MAX_LEN,
USBD_CFG_BUF_ALIGN_OCTETS,
(CPU_SIZE_T *)DEF_NULL,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBD_ERR_ALLOC;
return;
}
p_ctrl->PreambleBufRxPtr = (CPU_INT08U *)Mem_HeapAlloc( USBD_PHDC_METADATA_MSG_PREAMBLE_MAX_LEN,
USBD_CFG_BUF_ALIGN_OCTETS,
(CPU_SIZE_T *)DEF_NULL,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBD_ERR_ALLOC;
return;
}
Mem_Copy((void *)p_ctrl->PreambleBufTxPtr, /* Init preamble template. */
(void *)USBD_PHDC_QOS_SIGNATURE,
USBD_PHDC_QOS_SIGNATURE_LEN);
p_ctrl->PreambleBufTxPtr[17] = USBD_PHDC_QOS_ENCOD_VER;
ctrl_buf_len = sizeof(CPU_ADDR);
if (sizeof(CPU_ADDR) < 2u) {
ctrl_buf_len = 2u;
}
p_ctrl->CtrlStatusBufPtr = (CPU_INT08U *)Mem_HeapAlloc( ctrl_buf_len,
USBD_CFG_BUF_ALIGN_OCTETS,
(CPU_SIZE_T *)DEF_NULL,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBD_ERR_ALLOC;
return;
}
p_ctrl->IF_Params.NbrDevSpecialization = 0;
p_ctrl->IF_Params.DataFmt11073 = DEF_NO;
p_ctrl->IF_Params.PreambleCapable = DEF_NO;
}
for (ix = 0u; ix < USBD_PHDC_COM_NBR_MAX; ix++) { /* Init PHDC comm tbl. */
p_comm = &USBD_PHDC_CommTbl[ix];
p_comm->DataBulkIn = USBD_EP_ADDR_NONE;
p_comm->DataBulkOut = USBD_EP_ADDR_NONE;
p_comm->DataIntrIn = USBD_EP_ADDR_NONE;
p_comm->CtrlPtr = (USBD_PHDC_CTRL *)0;
}
USBD_PHDC_CtrlNbrNext = 0;
USBD_PHDC_CommNbrNext = 0;
USBD_PHDC_OS_Init(p_err);
}
/*
*********************************************************************************************************
* USBD_PHDC_Add()
*
* Description : Add a new instance of PHDC.
*
* Argument(s) : data_fmt_11073 Class instance use ieee 11073 protocol if set to DEF_YES.
* Otherwise, vendor defined protocol is used.
*
* preamble_capable Class instance support metadata message preamble if set
* to DEF_YES.
*
* preamble_en_notify Pointer to a callback function that notify application if
* metadata message preambles are enabled.
*
* low_latency_interval Interrupt endpoint interval in milliseconds. Can be 0
* if PHDC device will not send low latency data. When the value
* is different from 0, 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 PHDC instance successfully added.
* USBD_ERR_ALLOC No more class instance structure available.
*
* Return(s) : PHDC device number, if NO error(s).
*
* USBD_PHDC_NBR_NONE, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT08U USBD_PHDC_Add (CPU_BOOLEAN data_fmt_11073,
CPU_BOOLEAN preamble_capable,
USBD_PHDC_PREAMBLE_EN_NOTIFY preamble_en_notify,
CPU_INT16U low_latency_interval,
USBD_ERR *p_err)
{
CPU_INT08U phdc_nbr;
USBD_PHDC_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 ((low_latency_interval != 0u) &&
(MATH_IS_PWR2(low_latency_interval) == DEF_NO)) { /* Interval must be a power of 2. */
*p_err = USBD_ERR_INVALID_ARG;
return (USBD_CLASS_NBR_NONE);
}
#endif
CPU_CRITICAL_ENTER();
phdc_nbr = USBD_PHDC_CtrlNbrNext; /* Alloc new PHDC instance. */
if (phdc_nbr >= USBD_PHDC_CFG_MAX_NBR_DEV) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_PHDC_INSTANCE_ALLOC;
return (USBD_CLASS_NBR_NONE);
}
USBD_PHDC_CtrlNbrNext++;
CPU_CRITICAL_EXIT();
p_ctrl = &USBD_PHDC_CtrlTbl[phdc_nbr];
p_ctrl->IF_Params.DataFmt11073 = data_fmt_11073;
p_ctrl->IF_Params.PreambleCapable = preamble_capable;
p_ctrl->PreambleEnNotify = preamble_en_notify;
p_ctrl->TxLowLatencyInterval = low_latency_interval;
return (phdc_nbr);
}
/*
*********************************************************************************************************
* USBD_PHDC_CfgAdd()
*
* Description : Add PHDC instance into USB device configuration.
*
* Argument(s) : class_nbr PHDC instance number.
*
* dev_nbr Device number.
*
* cfg_nbr Configuration index to add new PHDC interface to.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE PHDC instance successfully added.
* USBD_ERR_INVALID_ARG, if invalid argument(s) passed to class_nbr.
* USBD_ERR_ALLOC No more class communication structure available.
*
* --------- RETURNED BY USBD_IF_Add() : ---------
* USBD_ERR_NULL_PTR Invalid NULL pointer was passed to 3rd argument.
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_IF_ALLOC NO available device interfaces.
*
* -------- RETURNED BY USBD_BulkAdd() : --------
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
* USBD_ERR_IF_ALTINVALID_NBR Invalid interface alternative setting number.
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
*
* --------- RETURNED BY USBD_IF_Add() : ---------
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
* USBD_ERR_IF_ALTINVALID_NBR Invalid interface alternative setting number.
* USBD_ERR_IF_INVALID_NBR Invalid interface number.
*
* Return(s) : DEF_YES, if PHDC instance added to USB device configuration successfully.
*
* DEF_NO, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_PHDC_CfgAdd (CPU_INT08U class_nbr,
CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
USBD_ERR *p_err)
{
CPU_BOOLEAN ep_intr_en;
CPU_INT08U if_nbr;
CPU_INT08U ep_addr;
CPU_INT16U comm_nbr;
CPU_INT16U tx_low_latency_interval;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
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_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (DEF_NO);
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if ((p_ctrl->RxLatencyRelyBitmap == (LATENCY_RELY_FLAGS)0) ||
(p_ctrl->TxLatencyRelyBitmap == (LATENCY_RELY_FLAGS)0)) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (DEF_NO);
}
CPU_CRITICAL_ENTER();
comm_nbr = USBD_PHDC_CommNbrNext; /* Alloc new PHDC comm info. */
if (comm_nbr >= USBD_PHDC_COM_NBR_MAX) {
USBD_PHDC_CtrlNbrNext--;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_PHDC_INSTANCE_ALLOC;
return (DEF_NO);
}
USBD_PHDC_CommNbrNext++;
CPU_CRITICAL_EXIT();
p_comm = &USBD_PHDC_CommTbl[comm_nbr];
if_nbr = USBD_IF_Add( dev_nbr, /* Add PHDC to cfg. */
cfg_nbr,
&USBD_PHDC_Drv,
(void *)p_comm,
(void *)0,
USBD_CLASS_CODE_PERSONAL_HEALTHCARE,
USBD_PHDC_SUBCLASS_CODE_NONE,
USBD_PHDC_PROTOCOL_CODE_NONE,
"Personal Healthcare Device Class",
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
/* --------- ADD ENPOINTS TO DEFAULT INTERFACE -------- */
ep_addr = USBD_BulkAdd(dev_nbr, /* Add bulk (IN) EP. */
cfg_nbr,
if_nbr,
0u,
DEF_YES,
0u,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
p_comm->DataBulkIn = ep_addr; /* Store bulk (IN) EP address. */
ep_addr = USBD_BulkAdd(dev_nbr, /* Add bulk (OUT) EP. */
cfg_nbr,
if_nbr,
0u,
DEF_NO,
0u,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
p_comm->DataBulkOut = ep_addr;
ep_intr_en = DEF_BIT_IS_SET(p_ctrl->TxLatencyRelyBitmap, USBD_PHDC_RELY_LATENCY_FLAGS_EP_INTR_IN);
if (ep_intr_en == DEF_TRUE) {
if (DEF_BIT_IS_CLR(cfg_nbr, USBD_CFG_NBR_SPD_BIT) == DEF_YES) {
/* In FS, bInterval in frames. */
tx_low_latency_interval = p_ctrl->TxLowLatencyInterval;
} else { /* In HS, bInterval in microframes. */
tx_low_latency_interval = p_ctrl->TxLowLatencyInterval * 8u;
}
ep_addr = USBD_IntrAdd(dev_nbr, /* Add intr (IN) EP. */
cfg_nbr,
if_nbr,
0u,
DEF_YES,
0u,
tx_low_latency_interval,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
p_comm->DataIntrIn = ep_addr; /* Store intr (IN) EP address. */
}
CPU_CRITICAL_ENTER();
p_comm->CtrlPtr = p_ctrl;
p_ctrl->State = USBD_PHDC_STATE_INIT;
p_ctrl->DevNbr = dev_nbr;
p_ctrl->CommPtr = (USBD_PHDC_COMM *)0;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
return (DEF_YES);
}
/*
*********************************************************************************************************
* USBD_PHDC_IsConn()
*
* Description : Get PHDC connection state.
*
* Argument(s) : class_nbr Class instance number.
*
* Return(s) : DEF_YES, if PHDC is connected.
*
* DEF_NO, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_PHDC_IsConn (CPU_INT08U class_nbr)
{
USBD_ERR err;
USBD_PHDC_CTRL *p_ctrl;
USBD_DEV_STATE state;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
return (DEF_NO);
}
#endif
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
state = USBD_DevStateGet(p_ctrl->DevNbr, &err); /* Get dev state. */
if ((err == USBD_ERR_NONE ) &&
(state == USBD_DEV_STATE_CONFIGURED) &&
(p_ctrl->State == USBD_PHDC_STATE_CFG )) {
return (DEF_YES);
}
return (DEF_NO);
}
/*
*********************************************************************************************************
* USBD_PHDC_RdCfg()
*
* Description : Configure read communication pipe parameters.
*
* Argument(s) : class_nbr PHDC instance number.
*
* latency_rely Latency / reliability flags. Can be one or more of these values:
*
* USBD_PHDC_LATENCY_VERYHIGH_RELY_BEST Very high latency, best reliability
* USBD_PHDC_LATENCY_HIGH_RELY_BEST, High latency, best reliability
* USBD_PHDC_LATENCY_MEDIUM_RELY_BEST, Medium latency, best reliability
*
* p_data_opaque Pointer to a buffer that contains opaque data.
*
* data_opaque_len Opaque data length. If 0, no metadata descriptor will be written.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE if communication pipe has been succesfully initialized.
* USBD_ERR_INVALID_ARG if invalid argument(s) passed to class_nbr or latency_rely.
* USBD_ERR_NULL_PTR if p_data_opaque is an invalid null pointer.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_PHDC_RdCfg ( CPU_INT08U class_nbr,
LATENCY_RELY_FLAGS latency_rely,
const CPU_INT08U *p_data_opaque,
CPU_INT08U data_opaque_len,
USBD_ERR *p_err)
{
LATENCY_RELY_FLAGS other_latency_rely;
LATENCY_RELY_FLAGS latency_rely_test;
USBD_PHDC_CTRL *p_ctrl;
CPU_INT08U latency_rely_bit;
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(;);
}
if ((p_data_opaque == (CPU_INT08U *)0 ) &&
(data_opaque_len != 0u)) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
if (latency_rely == DEF_BIT_NONE) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_NONE) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
}
if (p_ctrl->IF_Params.PreambleCapable == DEF_NO) { /* If device is not capable of preamble send/recv... */
latency_rely_test = latency_rely;
latency_rely_bit = CPU_CntTrailZeros08(latency_rely);
DEF_BIT_CLR(latency_rely_test, DEF_BIT(latency_rely_bit));
if (latency_rely_test != DEF_BIT_NONE) {
*p_err = USBD_ERR_INVALID_ARG; /* ... only one QoS bin shall be set. */
return;
}
}
/* Rx pipe can only have best rely. */
other_latency_rely = latency_rely;
DEF_BIT_CLR(other_latency_rely, USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_OUT);
if (other_latency_rely != DEF_BIT_NONE) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
CPU_CRITICAL_ENTER();
p_ctrl->EP_Params[USBD_PHDC_EP_BULK_OUT].DataOpaquePtr = p_data_opaque;
p_ctrl->EP_Params[USBD_PHDC_EP_BULK_OUT].DataOpaqueLen = data_opaque_len;
p_ctrl->RxLatencyRelyBitmap = latency_rely;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_PHDC_WrCfg()
*
* Description : Configure write communication pipe parameters.
*
* Argument(s) : class_nbr PHDC instance number.
*
* latency_rely Latency / reliability flags. Can be one or more of these values:
*
* USBD_PHDC_LATENCY_VERYHIGH_RELY_BEST Very high latency, best reliability
* USBD_PHDC_LATENCY_HIGH_RELY_BEST High latency, best reliability
* USBD_PHDC_LATENCY_MEDIUM_RELY_BEST Medium latency, best reliability
* USBD_PHDC_LATENCY_MEDIUM_RELY_BETTER Medium latency, better reliability
* USBD_PHDC_LATENCY_MEDIUM_RELY_GOOD Medium latency, good reliability
* USBD_PHDC_LATENCY_LOW_RELY_GOOD Low latency, good reliability
*
* p_data_opaque Pointer to a buffer that contains opaque data.
*
* data_opaque_len Opaque data length. If 0, no metadata descriptor will be written.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE if communication pipe has been succesfully initialized.
* USBD_ERR_INVALID_ARG if invalid argument(s) passed to class_nbr or latency_rely.
* USBD_ERR_NULL_PTR if p_data_opaque is an invalid null pointer.
*
* Return(s) : none.
*
* Note(s) : (1) If application needs to have different opaque data for low latency pipe, than
* this function should be called twice. Once for pipe carrying medium /
* high / very high latency transfers, and once for pipe carrying low latency transfers.
*********************************************************************************************************
*/
void USBD_PHDC_WrCfg ( CPU_INT08U class_nbr,
LATENCY_RELY_FLAGS latency_rely,
const CPU_INT08U *p_data_opaque,
CPU_INT08U data_opaque_len,
USBD_ERR *p_err)
{
CPU_BOOLEAN ep_bulk;
CPU_BOOLEAN ep_intr;
CPU_INT08U latency_rely_bit;
LATENCY_RELY_FLAGS latency_rely_test;
USBD_PHDC_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(;);
}
if ((p_data_opaque == (CPU_INT08U *)0) &&
(data_opaque_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
if (latency_rely == 0) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_NONE) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
if (p_ctrl->IF_Params.PreambleCapable == DEF_NO) {
latency_rely_test = latency_rely;
latency_rely_bit = CPU_CntTrailZeros08(latency_rely);
DEF_BIT_CLR(latency_rely_test, DEF_BIT(latency_rely_bit));
if (latency_rely_test != DEF_BIT_NONE) {
*p_err = USBD_ERR_INVALID_ARG; /* ... not preamble capable. */
return;
}
}
ep_bulk = DEF_BIT_IS_SET_ANY(latency_rely, USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_IN);
ep_intr = DEF_BIT_IS_SET_ANY(latency_rely, USBD_PHDC_RELY_LATENCY_FLAGS_EP_INTR_IN);
CPU_CRITICAL_ENTER();
p_ctrl->TxLatencyRelyBitmap |= latency_rely;
/* Check if dev need intr EP */
if (ep_intr == DEF_TRUE) {
p_ctrl->EP_Params[USBD_PHDC_EP_INTR_IN].DataOpaquePtr = p_data_opaque;
p_ctrl->EP_Params[USBD_PHDC_EP_INTR_IN].DataOpaqueLen = data_opaque_len;
}
if (ep_bulk == DEF_TRUE) {
p_ctrl->EP_Params[USBD_PHDC_EP_BULK_IN].DataOpaquePtr = p_data_opaque;
p_ctrl->EP_Params[USBD_PHDC_EP_BULK_IN].DataOpaqueLen = data_opaque_len;
}
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_PHDC_11073_ExtCfg()
*
* Description : Configure function extension for given class instance.
*
* Argument(s) : class_nbr PHDC instance number.
*
* p_dev_specialization Pointer to an array that contains a list of device
* specializations. (See 'Personal Healthcare Device Class
* specifications Revision 1.0', Appendix A.)
*
* nbr_dev_specialization Number of device specialzations specified in p_fnct_ext array.
*
* p_err Pointer to variable that will receive the return error
* code from this function :
*
* USBD_ERR_NONE if function extensions successfully configured.
* USBD_ERR_INVALID_ARG if invalid argument(s) passed to class_nbr.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_PHDC_11073_ExtCfg (CPU_INT08U class_nbr,
CPU_INT16U *p_dev_specialization,
CPU_INT08U nbr_dev_specialization,
USBD_ERR *p_err)
{
USBD_PHDC_CTRL *p_ctrl;
#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
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
p_ctrl->IF_Params.DevSpecialization = p_dev_specialization;
p_ctrl->IF_Params.NbrDevSpecialization = nbr_dev_specialization;
}
/*
**********************************************************************************************************
* USBD_PHDC_PreambleRd()
*
* Description : Read metadata preamble. This function is blocking.
*
* Argument(s) : class_nbr PHDC class instance number.
*
* p_buf Pointer to buffer that will contain opaque data from metadata
* message preamble.
*
* buf_len Opaque data buffer length in octets.
*
* p_nbr_xfer Pointer to a variable that will contain number of transfer the preamble apply to.
* After this call, USBD_PHDC_Rd shall be called nbr_xfer times by the application.
*
* timeout Timeout (ms).
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Data successfully received from host.
* USBD_ERR_INVALID_CLASS_STATE Invalid PHDC state.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to class_nbr.
* USBD_ERR_NULL_PTR Invalid NULL receive buffer.
* USBD_ERR_RX No metadata preamble expected from host or
* invalid metadata preamble received.
*
* ------ RETURNED BY USBD_BulkRx() : ------
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_EP_INVALID_NBR Invalid endpoint number.
* USBD_ERR_DEV_INVALID_STATE Bulk transfer can ONLY be used after the
* device is in configured state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* --- RETURNED BY USBD_PHDC_OS_RdLock() ---
* USBD_ERR_NONE OS signal successfully acquired.
* USBD_OS_ERR_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_OS_ERR_ABORT OS signal aborted.
* USBD_OS_ERR_FAIL OS signal not acquired because another error.
*
* Return(s) : Opaque data length in octets, if no error(s).
*
* 0, otherwise.
*
* Note(s) : (1) Metadata message preamble contains the following fields (see 'USB PHDC Class Specification
* Overview', Revision 1.0, Section 6.1.):
*
* +--------+-----------------------+----------------------+-----------------------------------+
* | Offset | Field | Size | Description |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 0 | aSignature | 16 | Cst used to verify preamble. |
* | | | | Set to PhdcQoSSignature string. |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 16 | bNumTransfers | 1 | Cnt of following xfers to which |
* | | | | QoS setting applies. |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 17 | bQoSEncodingVersion | 1 | QoS info encoding version. Set to |
* | | | | 0x01 for the moment. |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 18 | bmLatencyReliability | 1 | Bitmap that refers to latency/rely|
* | | | | bin for data. Shall be set to one |
* | | | | of the value specified in section |
* | | | | LATENCY / RELIABILITY BITMAPS of |
* | | | | usbd_phdc.h. |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 19 | bOpaqueDataSize | 1 | Length, in bytes, of opaque data. |
* +--------+-----------------------+----------------------+-----------------------------------+
* | 20 | bOpaqueData | [0 .. | Opaque data. |
* | | | MaxPacketSize - 21] | |
* +--------+-----------------------+----------------------+-----------------------------------+
*
* (2) If host disable preamble while the application is pending on this function, the call will
* immediately return with error USBD_OS_ERR_ABORT.
*
**********************************************************************************************************
*/
CPU_INT08U USBD_PHDC_PreambleRd (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT08U buf_len,
CPU_INT08U *p_nbr_xfer,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
CPU_INT08U data_opaque_len;
CPU_INT16U xfer_len;
CPU_BOOLEAN preamble_valid;
CPU_BOOLEAN latency_rely_valid;
#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 ((p_buf == (void *)0) &&
(buf_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return (0u);
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_CFG) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
if (p_ctrl->PreambleEn == DEF_DISABLED) { /* Chk that preamble is expected from host. */
*p_err = USBD_ERR_RX;
return (0u);
}
if (p_ctrl->RxDataXfersTotal != 0) {
*p_err = USBD_ERR_RX;
return (0u);
}
USBD_PHDC_OS_RdLock(class_nbr, timeout, p_err); /* Lock rd xfer. */
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
if (p_ctrl->PreambleEn == DEF_DISABLED) { /* Make sure preamble not been disabled while pending. */
*p_err = USBD_ERR_RX;
USBD_PHDC_OS_RdUnlock(class_nbr);
return (0u);
}
p_comm = p_ctrl->CommPtr;
xfer_len = USBD_BulkRx(p_ctrl->DevNbr,
p_comm->DataBulkOut,
p_ctrl->PreambleBufRxPtr,
USBD_PHDC_METADATA_MSG_PREAMBLE_MAX_LEN,
timeout,
p_err);
if (*p_err != USBD_ERR_NONE) {
if (*p_err == USBD_ERR_OS_ABORT) { /* Xfer is aborted when preamble status change. */
*p_err = USBD_ERR_RX;
}
USBD_PHDC_OS_RdUnlock(class_nbr);
return (0u);
}
preamble_valid = DEF_NO;
if (xfer_len >= USBD_PHDC_METADATA_MSG_PREAMBLE_DFLT_LEN) { /* Validate metadata msg preamble. */
preamble_valid = Mem_Cmp(p_ctrl->PreambleBufRxPtr, /* Chk if preamble contain signature. */
USBD_PHDC_QOS_SIGNATURE,
USBD_PHDC_QOS_SIGNATURE_LEN);
/* Chk QoS, QoS encoding version and nbr xfers is valid.*/
latency_rely_valid = DEF_BIT_IS_SET(p_ctrl->RxLatencyRelyBitmap, p_ctrl->PreambleBufRxPtr[18]);
preamble_valid = (p_ctrl->PreambleBufRxPtr[16] > 0u ) ? preamble_valid : DEF_NO;
preamble_valid = (p_ctrl->PreambleBufRxPtr[17] == USBD_PHDC_QOS_ENCOD_VER) ? preamble_valid : DEF_NO;
preamble_valid = (latency_rely_valid == DEF_YES ) ? preamble_valid : DEF_NO;
}
if (preamble_valid == DEF_NO) {
USBD_PHDC_OS_RdUnlock(class_nbr);
USBD_EP_Stall(p_ctrl->DevNbr,
p_comm->DataBulkOut,
DEF_SET,
p_err);
*p_err = USBD_ERR_RX;
return (0u);
}
p_ctrl->RxDataXfersTotal = p_ctrl->PreambleBufRxPtr[16]; /* Update xfers ctr. */
p_ctrl->RxDataXfersCur = 0u;
*p_nbr_xfer = p_ctrl->PreambleBufRxPtr[16]; /* Return nbr xfers and opaque data to app. */
data_opaque_len = DEF_MIN(p_ctrl->PreambleBufRxPtr[19], buf_len);
if (data_opaque_len > 0) {
Mem_Copy(p_buf, (void *)&p_ctrl->PreambleBufRxPtr[20], data_opaque_len);
}
USBD_PHDC_OS_RdUnlock(class_nbr); /* Unlock rd xfer. */
*p_err = USBD_ERR_NONE;
return (data_opaque_len);
}
/*
**********************************************************************************************************
* USBD_PHDC_Rd()
*
* Description : Read PHDC data. This function is blocking.
*
* Argument(s) : class_nbr PHDC class instance number.
*
* p_buf Pointer to buffer that will contain data.
*
* buf_len Receive buffer length in octets.
*
* timeout Timeout (ms).
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Data successfully received from host.
* USBD_ERR_INVALID_CLASS_STATE Invalid PHDC state.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to class_nbr.
* USBD_ERR_NULL_PTR Invalid NULL receive buffer.
* USBD_ERR_RX A preamble is expected. USBD_PHDC_PreambleRd
* shall be called instead.
*
* ------ RETURNED BY USBD_BulkRx() : ------
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_EP_INVALID_NBR Invalid endpoint number.
* USBD_ERR_DEV_INVALID_STATE Bulk transfer can ONLY be used after the
* device is in configured state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* --- RETURNED BY USBD_PHDC_OS_RdLock() ---
* USBD_ERR_NONE OS signal successfully acquired.
* USBD_OS_ERR_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_OS_ERR_ABORT OS signal aborted.
* USBD_OS_ERR_FAIL OS signal not acquired because another error.
*
* Return(s) : Number of octets received, if no error(s).
*
* 0, otherwise.
*
* Note(s) : (1) If host enable preamble while the application is pending on this function, the call will
* immediately return with error USBD_OS_ERR_ABORT.
**********************************************************************************************************
*/
CPU_INT16U USBD_PHDC_Rd (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT16U buf_len,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
CPU_INT16U xfer_len;
#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 (p_buf == (void *)0) {
*p_err = USBD_ERR_NULL_PTR;
return (0u);
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_CFG) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
if ((p_ctrl->PreambleEn == DEF_ENABLED) &&
(p_ctrl->RxDataXfersTotal == 0u )) {
*p_err = USBD_ERR_RX;
return (0u);
}
USBD_PHDC_OS_RdLock(class_nbr, timeout, p_err); /* Lock rd pipe. */
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
if ((p_ctrl->PreambleEn == DEF_ENABLED) && /* Make sure preamble status not changed while pending. */
(p_ctrl->RxDataXfersTotal == 0u )) {
*p_err = USBD_ERR_RX;
USBD_PHDC_OS_RdUnlock(class_nbr);
return (0u);
}
p_comm = p_ctrl->CommPtr;
xfer_len = USBD_BulkRx( p_ctrl->DevNbr,
p_comm->DataBulkOut,
(CPU_INT08U *)p_buf,
buf_len,
timeout,
p_err);
if (*p_err != USBD_ERR_NONE) {
if (*p_err == USBD_ERR_OS_ABORT) { /* Xfer is aborted when preamble status change. */
*p_err = USBD_ERR_RX;
}
USBD_PHDC_OS_RdUnlock(class_nbr);
return (0u);
}
if (p_ctrl->PreambleEn == DEF_ENABLED) {
p_ctrl->RxDataXfersCur++; /* Update internal ctr. */
if (p_ctrl->RxDataXfersCur == p_ctrl->RxDataXfersTotal) {
p_ctrl->RxDataXfersTotal = 0u;
}
}
USBD_PHDC_OS_RdUnlock(class_nbr); /* Unlock rd pipe. */
return (xfer_len);
}
/*
**********************************************************************************************************
* USBD_PHDC_PreambleWr()
*
* Description : Add PHDC metadata preamble to transmit priority queue.
*
* Argument(s) : class_nbr PHDC instance number.
*
* p_data_opaque Pointer to buffer that will supply opaque data.
*
* data_opaque_len Length of opaque data in octets.
*
* latency_rely Latency / reliability to be specified in preamble.
*
* nbr_xfers Number of transfer this preamble will apply to.
*
* timeout Timeout (ms).
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Data successfully added to priority queue.
* USBD_ERR_NULL_PTR Invalid NULL transmit buffer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to class_nbr,
* data_opaque_len, nbr_xfers or latency_rely.
* USBD_ERR_TX Host doesn't expect a preamble.
*
* ------ RETURNED BY USBD_BulkTx() : ------
* USBD_ERR_NONE Data successfully transmitted.
* 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.
*
* - RETURNED BY USBD_PHDC_OS_WrBulkLock() -
* USBD_ERR_NONE OS signal successfully acquired.
* USBD_OS_ERR_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_OS_ERR_ABORT OS signal aborted.
* USBD_OS_ERR_FAIL OS signal not acquired because another error.
*
* Return(s) : none.
*
* Note(s) : none.
**********************************************************************************************************
*/
void USBD_PHDC_PreambleWr (CPU_INT08U class_nbr,
void *p_data_opaque,
CPU_INT08U data_opaque_len,
LATENCY_RELY_FLAGS latency_rely,
CPU_INT08U nbr_xfers,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
CPU_INT16U preamble_len;
CPU_INT16U data_opaque_max_len;
LATENCY_RELY_FLAGS latency_rely_flag;
CPU_BOOLEAN bulk_ep_xfer;
CPU_INT08U prio;
CPU_INT08U ep_log_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(;);
}
if (nbr_xfers == 0u) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
if ((p_data_opaque == (void *)0) &&
(data_opaque_len > 0u )) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) { /* -------------------- CHK ARG ----------------------- */
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_CFG) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
p_comm = p_ctrl->CommPtr;
data_opaque_max_len = USBD_EP_MaxPktSizeGet(p_ctrl->DevNbr,
p_comm->DataBulkIn,
p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
data_opaque_max_len -= (USBD_PHDC_METADATA_MSG_PREAMBLE_DFLT_LEN + 1u);
data_opaque_max_len = DEF_MIN(data_opaque_max_len, 255u); /* Opaque data len field makes 8 bits in preamble. */
if (data_opaque_len > data_opaque_max_len) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
latency_rely_flag = latency_rely; /* Validate EP support QoS and metadata preamble. */
latency_rely_flag &= p_ctrl->TxLatencyRelyBitmap;
bulk_ep_xfer = DEF_BIT_IS_SET_ANY(latency_rely_flag, USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_IN);
if (bulk_ep_xfer == DEF_NO) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
prio = CPU_CntTrailZeros08(latency_rely) - 1;
ep_log_nbr = USBD_EP_ADDR_TO_LOG(p_ctrl->CommPtr->DataBulkIn);
if (p_ctrl->PreambleEn == DEF_DISABLED) {
*p_err = USBD_ERR_TX; /* Host did not enable preamble. Call USBD_PHDC_Wr. */
return;
}
if (p_ctrl->TxDataXfersTotal[prio] != 0u) {
*p_err = USBD_ERR_TX; /* Preamble not expected by host, call USBD_PHDC_Wr. */
return;
}
USBD_PHDC_OS_WrBulkLock(class_nbr, prio, timeout, p_err); /* Lock bulk wr pipe. */
if (*p_err != USBD_ERR_NONE) {
return;
}
CPU_CRITICAL_ENTER();
DEF_BIT_SET(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
p_ctrl->TxDataXfersTotal[prio] = nbr_xfers;
p_ctrl->TxDataXfersCur[prio] = 0u;
CPU_CRITICAL_EXIT();
p_ctrl->PreambleBufTxPtr[16] = nbr_xfers; /* Prepare metadata message preamble. See note 1 of... */
p_ctrl->PreambleBufTxPtr[18] = latency_rely; /* ...USBD_PHDC_PreambleRd(). */
p_ctrl->PreambleBufTxPtr[19] = data_opaque_len;
if (data_opaque_len > 0) {
Mem_Copy(&p_ctrl->PreambleBufTxPtr[20],
p_data_opaque,
data_opaque_len);
}
preamble_len = USBD_PHDC_METADATA_MSG_PREAMBLE_DFLT_LEN + data_opaque_len;
USBD_BulkTx( p_ctrl->DevNbr,
p_comm->DataBulkIn,
(void *)p_ctrl->PreambleBufTxPtr,
preamble_len,
timeout,
DEF_YES,
p_err);
if (*p_err != USBD_ERR_NONE) {
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
p_ctrl->TxDataXfersTotal[prio] = 0u;
p_ctrl->TxDataXfersCur[prio] = 0u;
USBD_PHDC_OS_WrBulkUnlock(class_nbr);
}
}
/*
**********************************************************************************************************
* USBD_PHDC_Wr()
*
* Description : Write PHDC data.
*
* Argument(s) : class_nbr PHDC instance number.
*
* p_buf Pointer to buffer that will supply data.
*
* buf_len Data length in octets.
*
* latency_rely Latency / reliability of this transfer.
*
* timeout Timeout (ms).
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Data successfully added to priority queue.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to class_nbr or latency_rely.
* USBD_ERR_NULL_PTR Invalid null buffer.
* USBD_ERR_TX USBD_PHDC_PreambleWr shall be called first.
* USBD_ERR_INVALID_CLASS_STATE Invalid PHDC state.
* USBD_ERR_ALLOC Data queue is full.
*
* ------ RETURNED BY USBD_BulkTx() : ------
* USBD_ERR_NONE Data successfully transmitted.
* 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.
*
* ------ RETURNED BY USBD_IntrTx() : ------
* USBD_ERR_NONE Data successfully transmitted.
* 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.
*
* - RETURNED BY USBD_PHDC_OS_WrBulkLock() -
* USBD_ERR_NONE OS signal successfully acquired.
* USBD_OS_ERR_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_OS_ERR_ABORT OS signal aborted.
* USBD_OS_ERR_FAIL OS signal not acquired because another error.
*
* - RETURNED BY USBD_PHDC_OS_WrIntrLock() -
* USBD_ERR_NONE OS signal successfully acquired.
* USBD_OS_ERR_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_OS_ERR_ABORT OS signal aborted.
* USBD_OS_ERR_FAIL OS signal not acquired because another error.
*
* Return(s) : none.
*
* Note(s) : none.
**********************************************************************************************************
*/
void USBD_PHDC_Wr (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT16U buf_len,
LATENCY_RELY_FLAGS latency_rely,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
CPU_INT08U latency_rely_test;
CPU_BOOLEAN qos_supported;
CPU_INT08U prio;
CPU_INT08U ep_log_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(;);
}
if (p_buf == (void *)0) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
if (latency_rely == 0u) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
#endif
if (class_nbr >= USBD_PHDC_CtrlNbrNext) { /* -------------------- CHK ARG ----------------------- */
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
if (p_ctrl->State != USBD_PHDC_STATE_CFG) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
prio = CPU_CntTrailZeros08(latency_rely);
if (prio >= USBD_PHDC_XFER_PRIO_MAX) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
latency_rely_test = latency_rely;
DEF_BIT_CLR(latency_rely_test, DEF_BIT(prio));
if (latency_rely_test != DEF_BIT_NONE) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
qos_supported = DEF_BIT_IS_SET(p_ctrl->TxLatencyRelyBitmap, latency_rely);
if (qos_supported != DEF_YES) { /* Validate EP support QoS. */
*p_err = USBD_ERR_INVALID_ARG;
return;
}
p_comm = p_ctrl->CommPtr;
if (latency_rely == USBD_PHDC_LATENCY_LOW_RELY_GOOD) { /* Low latency xfer use intr EP. */
ep_log_nbr = USBD_EP_ADDR_TO_LOG(p_comm->DataIntrIn);
CPU_CRITICAL_ENTER();
DEF_BIT_SET(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
USBD_PHDC_OS_WrIntrLock(class_nbr, timeout, p_err); /* Lock intr EP. */
if (*p_err != USBD_ERR_NONE) {
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
return;
}
USBD_IntrTx(p_ctrl->DevNbr,
p_comm->DataIntrIn,
p_buf,
buf_len,
timeout,
DEF_YES,
p_err);
USBD_PHDC_OS_WrIntrUnlock(class_nbr); /* Unlock intr EP. */
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
} else { /* Very high, high and medium latency xfer use bulk EP. */
ep_log_nbr = USBD_EP_ADDR_TO_LOG(p_comm->DataBulkIn);
prio--; /* There are 5 QoS level on bulk IN EP. */
CPU_CRITICAL_ENTER();
if ((p_ctrl->PreambleEn == DEF_ENABLED) &&
(p_ctrl->TxDataXfersTotal[prio] == 0u )) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_TX; /* App need to call USBD_PHDC_PreambleWr first. */
return;
}
DEF_BIT_SET(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
if (p_ctrl->PreambleEn == DEF_DISABLED) {
USBD_PHDC_OS_WrBulkLock(class_nbr, prio, timeout, p_err);
if (*p_err != USBD_ERR_NONE) {
if (*p_err != USBD_ERR_OS_TIMEOUT) {
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
}
return;
}
}
USBD_BulkTx(p_ctrl->DevNbr,
p_comm->DataBulkIn,
p_buf,
buf_len,
timeout,
DEF_YES,
p_err);
if (p_ctrl->PreambleEn == DEF_ENABLED) {
if (*p_err == USBD_ERR_NONE) {
p_ctrl->TxDataXfersCur[prio]++;
/* Update xfers ctr. */
if (p_ctrl->TxDataXfersCur[prio] == p_ctrl->TxDataXfersTotal[prio]) {
p_ctrl->TxDataXfersCur[prio] = 0u;
p_ctrl->TxDataXfersTotal[prio] = 0u;
USBD_PHDC_OS_WrBulkUnlock(class_nbr); /* Unlock bulk EP if all xfer cmpleted under preamble. */
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
}
}
} else {
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->EP_DataStatus, DEF_BIT(ep_log_nbr));
CPU_CRITICAL_EXIT();
USBD_PHDC_OS_WrBulkUnlock(class_nbr);
}
}
}
/*
**********************************************************************************************************
* USBD_PHDC_Reset()
*
* Description : Reset PHDC instance.
*
* Argument(s) : class_nbr PHDC instance number.
*
* Return(s) : none.
*
* Note(s) : none.
**********************************************************************************************************
*/
void USBD_PHDC_Reset (CPU_INT08U class_nbr)
{
CPU_INT16U cnt;
USBD_PHDC_CTRL *p_ctrl;
USBD_ERR err;
CPU_SR_ALLOC();
if (class_nbr >= USBD_PHDC_CtrlNbrNext) {
return;
}
p_ctrl = &USBD_PHDC_CtrlTbl[class_nbr];
USBD_EP_Abort(p_ctrl->DevNbr,
p_ctrl->CommPtr->DataBulkIn,
&err);
USBD_EP_Abort(p_ctrl->DevNbr,
p_ctrl->CommPtr->DataIntrIn,
&err);
USBD_EP_Abort(p_ctrl->DevNbr,
p_ctrl->CommPtr->DataBulkOut,
&err);
CPU_CRITICAL_ENTER();
if (p_ctrl->PreambleEn != DEF_DISABLED) {
p_ctrl->PreambleEn = DEF_DISABLED;
if (p_ctrl->PreambleEnNotify != (USBD_PHDC_PREAMBLE_EN_NOTIFY)0) {
p_ctrl->PreambleEnNotify(class_nbr, DEF_DISABLED);
}
}
for (cnt = 0; cnt < (USBD_PHDC_XFER_PRIO_MAX - 1u); cnt++) {
p_ctrl->TxDataXfersTotal[cnt] = 0u;
p_ctrl->TxDataXfersCur[cnt] = 0u;
}
p_ctrl->EP_DataStatus = DEF_BIT_NONE;
p_ctrl->RxDataXfersTotal = 0u;
p_ctrl->RxDataXfersCur = 0u;
CPU_CRITICAL_EXIT();
USBD_PHDC_OS_Reset(class_nbr);
}
/*
**********************************************************************************************************
**********************************************************************************************************
* LOCAL FUNCTIONS
**********************************************************************************************************
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* INTERFACE DRIVER FUNCTIONS
**********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_PHDC_Conn()
*
* Description : Notify class that configuration is active.
*
* Argument(s) : 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_PHDC_Conn (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg)
{
USBD_PHDC_COMM *p_comm;
CPU_SR_ALLOC();
(void)cfg_nbr;
(void)dev_nbr;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
CPU_CRITICAL_ENTER();
p_comm->CtrlPtr->CommPtr = p_comm;
p_comm->CtrlPtr->State = USBD_PHDC_STATE_CFG;
CPU_CRITICAL_EXIT();
}
/*
*********************************************************************************************************
* USBD_PHDC_Disconn()
*
* Description : Notify class that configuration is not active.
*
* Argument(s) : 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_PHDC_Disconn (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg)
{
USBD_PHDC_COMM *p_comm;
CPU_SR_ALLOC();
(void)cfg_nbr;
(void)dev_nbr;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
USBD_PHDC_Reset(p_comm->CtrlPtr->Nbr);
CPU_CRITICAL_ENTER();
p_comm->CtrlPtr->CommPtr = (USBD_PHDC_COMM *)0;
p_comm->CtrlPtr->State = USBD_PHDC_STATE_INIT;
CPU_CRITICAL_EXIT();
}
/*
*********************************************************************************************************
* USBD_PHDC_SettingUpdate()
*
* Description : Notify class that interface alternative setting has been updated.
*
* Argument(s) : cfg_nbr Configuration ix to add the interface.
*
* 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_PHDC_SettingUpdate (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_PHDC_COMM *p_comm;
USBD_PHDC_CTRL *p_ctrl;
CPU_SR_ALLOC();
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)dev_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
CPU_CRITICAL_ENTER();
p_ctrl->CommPtr = p_comm;
CPU_CRITICAL_EXIT();
}
/*
**********************************************************************************************************
* USBD_PHDC_IF_Desc()
*
* Description : Write extra 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) : none.
*
* Note(s) : none.
**********************************************************************************************************
*/
static void USBD_PHDC_IF_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)
{
CPU_INT08U cnt;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
/* Class fnct desc */
USBD_DescWr08(dev_nbr, USBD_PHDC_CLASS_FNCT_DESC_LEN);
USBD_DescWr08(dev_nbr, USBD_PHDC_DESC_TYPE_CLASS_FNCT);
if (p_ctrl->IF_Params.DataFmt11073 == DEF_YES) {
USBD_DescWr08(dev_nbr, USBD_PHDC_DATA_FMT_11073_20601);
} else {
USBD_DescWr08(dev_nbr, USBD_PHDC_DATA_FMT_VENDOR);
}
if (p_ctrl->IF_Params.PreambleCapable == DEF_YES) {
USBD_DescWr08(dev_nbr, USBD_PHDC_PREAMBLE_CAPABLE);
} else {
USBD_DescWr08(dev_nbr, USBD_PHDC_PREAMBLE_NOT_CAPABLE);
}
/* Fnct ext desc */
USBD_DescWr08(dev_nbr,
USBD_PHDC_FUNCT_EXTN_DESC_DFLT_LEN + (p_ctrl->IF_Params.NbrDevSpecialization * 2));
USBD_DescWr08(dev_nbr, USBD_PHDC_DESC_TYPE_FUNCT_EXTN_11073);
USBD_DescWr08(dev_nbr, 0x00); /* Reserved */
USBD_DescWr08(dev_nbr, p_ctrl->IF_Params.NbrDevSpecialization);
for (cnt = 0; cnt < p_ctrl->IF_Params.NbrDevSpecialization; cnt++) {
USBD_DescWr16(dev_nbr, p_ctrl->IF_Params.DevSpecialization[cnt]);
}
}
/*
**********************************************************************************************************
* USBD_PHDC_IF_DescSizeGet()
*
* Description : Return size of extra 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 extra interface descriptor in octets.
*
* Note(s) : none.
**********************************************************************************************************
*/
static CPU_INT16U USBD_PHDC_IF_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)
{
CPU_INT16U desc_len;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
(void)dev_nbr;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
desc_len = USBD_PHDC_CLASS_FNCT_DESC_LEN +
USBD_PHDC_FUNCT_EXTN_DESC_DFLT_LEN +
(p_ctrl->IF_Params.NbrDevSpecialization * 2);
return (desc_len);
}
/*
**********************************************************************************************************
* USBD_PHDC_EP_Desc()
*
* Description : Write extra endpoint descriptor.
*
* Argument(s) : dev_nbr Device number.
*
* cfg_nbr Configuration number.
*
* if_nbr Interface number.
*
* if_alt_nbr Interface alternate setting number.
*
* ep_addr Endpoint address.
*
* 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_PHDC_EP_Desc (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
CPU_INT08U if_nbr,
CPU_INT08U if_alt_nbr,
CPU_INT08U ep_addr,
void *p_if_class_arg,
void *p_if_alt_class_arg)
{
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
USBD_PHDC_EP_PARAMS *ep_params;
LATENCY_RELY_FLAGS latency_rely_bitmap;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
if (ep_addr == p_comm->DataBulkIn) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_BULK_IN];
latency_rely_bitmap = p_ctrl->TxLatencyRelyBitmap;
DEF_BIT_CLR(latency_rely_bitmap, USBD_PHDC_RELY_LATENCY_FLAGS_EP_INTR_IN);
} else if (ep_addr == p_comm->DataBulkOut) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_BULK_OUT];
latency_rely_bitmap = p_ctrl->RxLatencyRelyBitmap;
} else if (ep_addr == p_comm->DataIntrIn) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_INTR_IN];
latency_rely_bitmap = p_ctrl->TxLatencyRelyBitmap;
DEF_BIT_CLR(latency_rely_bitmap, USBD_PHDC_RELY_LATENCY_FLAGS_EP_BULK_IN);
} else {
return;
}
USBD_DescWr08(dev_nbr, USBD_PHDC_QOS_DESC_LEN); /* QoS desc */
USBD_DescWr08(dev_nbr, USBD_PHDC_DESC_TYPE_QOS);
USBD_DescWr08(dev_nbr, USBD_PHDC_QOS_ENCOD_VER);
USBD_DescWr08(dev_nbr, latency_rely_bitmap);
if (ep_params->DataOpaqueLen > 0) {
USBD_DescWr08(dev_nbr, /* Metadata descriptor */
USBD_PHDC_METADATA_DESC_LEN + ep_params->DataOpaqueLen);
USBD_DescWr08(dev_nbr, USBD_PHDC_DESC_TYPE_METADATA);
USBD_DescWr(dev_nbr,
ep_params->DataOpaquePtr,
ep_params->DataOpaqueLen);
}
}
/*
**********************************************************************************************************
* USBD_PHDC_EP_DescSizeGet()
*
* Description : Return size of extra endpoint descriptor.
*
* Argument(s) : dev_nbr Device number.
*
* cfg_nbr Configuration number.
*
* if_nbr Interface number.
*
* if_alt_nbr Interface alternate setting number.
*
* ep_addr Endpoint address.
*
* 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 extra endpoint descriptor in octets.
*
* Note(s) : none.
**********************************************************************************************************
*/
static CPU_INT16U USBD_PHDC_EP_DescSizeGet (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
CPU_INT08U if_nbr,
CPU_INT08U if_alt_nbr,
CPU_INT08U ep_addr,
void *p_if_class_arg,
void *p_if_alt_class_arg)
{
CPU_INT16U desc_len;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
USBD_PHDC_EP_PARAMS *ep_params;
(void)dev_nbr;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
if (ep_addr == p_comm->DataBulkIn) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_BULK_IN];
} else if (ep_addr == p_comm->DataBulkOut) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_BULK_OUT];
} else if (ep_addr == p_comm->DataIntrIn) {
ep_params = &p_ctrl->EP_Params[USBD_PHDC_EP_INTR_IN];
} else {
return (0);
}
desc_len = USBD_PHDC_QOS_DESC_LEN;
if (ep_params->DataOpaqueLen > 0) {
desc_len += USBD_PHDC_METADATA_DESC_LEN +
ep_params->DataOpaqueLen;
}
return (desc_len);
}
/*
*********************************************************************************************************
* USBD_PHDC_ClassReq()
*
* Description : Class request handler.
*
* Argument(s) : 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 should be sent.
*
* DEF_FAIL, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
static CPU_BOOLEAN USBD_PHDC_ClassReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg)
{
CPU_BOOLEAN rtn_val;
USBD_ERR err;
USBD_PHDC_CTRL *p_ctrl;
USBD_PHDC_COMM *p_comm;
p_comm = (USBD_PHDC_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
rtn_val = DEF_FAIL;
switch (p_setup_req->bRequest) {
case USBD_REQ_GET_STATUS: /* -------------------- GET STATUS ------------------- */
switch (p_ctrl->State) {
case USBD_PHDC_STATE_CFG:
if (p_setup_req->wValue != 0) {
break;
}
p_ctrl->CtrlStatusBufPtr[0] = (CPU_INT08U)( p_ctrl->EP_DataStatus & DEF_INT_08_MASK);
p_ctrl->CtrlStatusBufPtr[1] = (CPU_INT08U)((p_ctrl->EP_DataStatus >> 8u) & DEF_INT_08_MASK);
USBD_CtrlTx( dev_nbr,
(void *)&p_ctrl->CtrlStatusBufPtr[0],
2u,
USBD_PHDC_CTRL_REQ_TIMEOUT_mS,
DEF_FALSE,
&err);
if (err == USBD_ERR_NONE) {
rtn_val = DEF_OK;
}
break;
case USBD_PHDC_STATE_NONE:
case USBD_PHDC_STATE_INIT:
default :
break;
}
break;
case USBD_REQ_CLEAR_FEATURE: /* ------------------ CLEAR FEATURE ------------------- */
switch (p_ctrl->State) {
case USBD_PHDC_STATE_CFG:
if (((CPU_INT08U) p_setup_req->wValue == USBD_PHDC_CLASS_SPEC_FEATURE_PHDC_QOS) &&
((CPU_INT08U)((p_setup_req->wValue & 0xFF00) >> 8) == 0x00)) {
/* Make sure metadata msg preambles are supported */
if (p_ctrl->IF_Params.PreambleCapable == DEF_YES) {
if (p_ctrl->PreambleEn != DEF_DISABLED) {
p_ctrl->PreambleEn = DEF_DISABLED;
if (p_ctrl->PreambleEnNotify != (USBD_PHDC_PREAMBLE_EN_NOTIFY)0) {
p_ctrl->PreambleEnNotify(p_ctrl->Nbr, DEF_DISABLED);
}
USBD_EP_Abort(dev_nbr,
p_ctrl->CommPtr->DataBulkOut,
&err);
}
rtn_val = DEF_OK;
}
}
break;
case USBD_PHDC_STATE_NONE:
case USBD_PHDC_STATE_INIT:
default :
break;
}
break;
case USBD_REQ_SET_FEATURE: /* ------------------- SET FEATURE -------------------- */
switch (p_ctrl->State) {
case USBD_PHDC_STATE_CFG:
if (((CPU_INT08U) p_setup_req->wValue == USBD_PHDC_CLASS_SPEC_FEATURE_PHDC_QOS) &&
((CPU_INT08U)((p_setup_req->wValue & 0xFF00) >> 8) == USBD_PHDC_QOS_ENCOD_VER)) {
/* Make sure metadata msg preambles are supported */
if (p_ctrl->IF_Params.PreambleCapable == DEF_YES) {
if (p_ctrl->PreambleEn != DEF_ENABLED) {
p_ctrl->PreambleEn = DEF_ENABLED;
if (p_ctrl->PreambleEnNotify != (USBD_PHDC_PREAMBLE_EN_NOTIFY)0) {
p_ctrl->PreambleEnNotify(p_ctrl->Nbr, DEF_ENABLED);
}
USBD_EP_Abort(dev_nbr,
p_ctrl->CommPtr->DataBulkOut,
&err);
}
rtn_val = DEF_OK;
}
}
break;
case USBD_PHDC_STATE_NONE:
case USBD_PHDC_STATE_INIT:
default :
break;
}
break;
default: /* Request not supported */
break;
}
return (rtn_val);
}
/*
**********************************************************************************************************
* MODULE END
**********************************************************************************************************
*/