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

2487 lines
99 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 HID CLASS
*
* Filename : usbd_hid.c
* Version : V4.06.01
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#define USBD_HID_MODULE
#include "usbd_hid.h"
#include "usbd_hid_os.h"
#include <lib_math.h>
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
/* Max nbr of comm struct. */
#define USBD_HID_MAX_NBR_COMM USBD_HID_CFG_MAX_NBR_CFG
#define USBD_HID_CTRL_REQ_TIMEOUT_mS 5000u
/*
*********************************************************************************************************
* CLASS-SPECIFIC LOCAL DEFINES
*
* Note(s) : (1) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 7.1 for more details about class-descriptor types.
*
* (a) The 'wValue' field of Get_Descriptor Request specifies the Descriptor Type in the
* high byte.
*
* (2) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 7.2 for more details about class-specific requests.
*
* (a) The 'bRequest' field of SETUP packet may contain one of these values.
*********************************************************************************************************
*/
#define USBD_HID_DESC_LEN 6u
/* --------- CLASS-SPECIFIC DESC (see Note #1) -------- */
#define USBD_HID_DESC_TYPE_HID 0x21
#define USBD_HID_DESC_TYPE_REPORT 0x22
#define USBD_HID_DESC_TYPE_PHYSICAL 0x23
/* --------- CLASS-SPECIFIC REQ (see Note #2) --------- */
#define USBD_HID_REQ_GET_REPORT 0x01
#define USBD_HID_REQ_GET_IDLE 0x02
#define USBD_HID_REQ_GET_PROTOCOL 0x03
#define USBD_HID_REQ_SET_REPORT 0x09
#define USBD_HID_REQ_SET_IDLE 0x0A
#define USBD_HID_REQ_SET_PROTOCOL 0x0B
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL DATA TYPES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* FORWARD DECLARATIONS
*********************************************************************************************************
*/
typedef struct usbd_hid_ctrl USBD_HID_CTRL;
/*
*********************************************************************************************************
* HID CLASS STATES
*********************************************************************************************************
*/
typedef enum usbd_hid_state { /* HID class states. */
USBD_HID_STATE_NONE = 0,
USBD_HID_STATE_INIT,
USBD_HID_STATE_CFG
} USBD_HID_STATE;
/*
*********************************************************************************************************
* HID CLASS EP REQUIREMENTS DATA TYPE
*********************************************************************************************************
*/
/* ---------------- HID CLASS COMM INFO --------------- */
typedef struct usbd_hid_comm {
USBD_HID_CTRL *CtrlPtr; /* Pointer to control information. */
/* Avail EP for comm: Intr */
CPU_INT08U DataIntrInEpAddr;
CPU_INT08U DataIntrOutEpAddr;
CPU_BOOLEAN DataIntrOutActiveXfer;
} USBD_HID_COMM;
struct usbd_hid_ctrl { /* ----------------- HID CLASS CTRL INFO -------------- */
CPU_INT08U DevNbr; /* Dev nbr. */
CPU_INT08U ClassNbr; /* Class nbr. */
USBD_HID_STATE State; /* HID class state. */
USBD_HID_COMM *CommPtr; /* HID class comm info ptr. */
USBD_HID_ASYNC_FNCT IntrRdAsyncFnct; /* Ptr to async comm callback and arg. */
void *IntrRdAsyncArgPtr;
USBD_HID_ASYNC_FNCT IntrWrAsyncFnct;
void *IntrWrAsyncArgPtr;
CPU_INT32U DataIntrInXferLen;
CPU_INT08U SubClassCode;
CPU_INT08U ProtocolCode;
USBD_HID_COUNTRY_CODE CountryCode;
USBD_HID_REPORT Report;
CPU_INT08U *ReportDescPtr;
CPU_INT16U ReportDescLen;
CPU_INT08U *PhyDescPtr;
CPU_INT16U PhyDescLen;
CPU_INT16U IntervalIn;
CPU_INT16U IntervalOut;
CPU_BOOLEAN CtrlRdEn; /* En rd operations thru ctrl xfer. */
USBD_HID_CALLBACK *CallbackPtr; /* Ptr to class-specific desc and req callbacks. */
CPU_INT08U *RxBufPtr;
CPU_INT32U RxBufLen;
CPU_BOOLEAN IsRx;
CPU_INT08U *CtrlStatusBufPtr; /* Buf used for ctrl status xfers. */
};
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*
* Note(s) : (1) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 6.2 for more details about HID descriptor fields.
*********************************************************************************************************
*/
static USBD_HID_CTRL USBD_HID_CtrlTbl[USBD_HID_CFG_MAX_NBR_DEV];
static CPU_INT08U USBD_HID_CtrlNbrNext;
/* HID class comm array. */
static USBD_HID_COMM USBD_HID_CommTbl[USBD_HID_MAX_NBR_COMM];
static CPU_INT08U USBD_HID_CommNbrNext;
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static void USBD_HID_Conn ( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg);
static void USBD_HID_Disconn ( CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg);
static void USBD_HID_AltSettingUpdate( 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_HID_EP_StateUpdate ( 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 void USBD_HID_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 void USBD_HID_IF_DescHandler ( CPU_INT08U dev_nbr,
void *p_if_class_arg);
static CPU_INT16U USBD_HID_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 CPU_BOOLEAN USBD_HID_IF_Req ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg);
static CPU_BOOLEAN USBD_HID_ClassReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg);
static void USBD_HID_WrAsyncCmpl ( CPU_INT08U dev_nbr,
CPU_INT08U ep_addr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBD_ERR err);
static void USBD_HID_WrSyncCmpl ( CPU_INT08U dev_nbr,
CPU_INT08U ep_addr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBD_ERR err);
static void USBD_HID_RdAsyncCmpl ( CPU_INT08U dev_nbr,
CPU_INT08U ep_addr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBD_ERR err);
static void USBD_HID_OutputDataCmpl ( CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBD_ERR err);
/*
*********************************************************************************************************
* HID CLASS DRIVER
*********************************************************************************************************
*/
static USBD_CLASS_DRV USBD_HID_Drv = {
USBD_HID_Conn,
USBD_HID_Disconn,
USBD_HID_AltSettingUpdate,
USBD_HID_EP_StateUpdate,
USBD_HID_IF_Desc,
USBD_HID_IF_DescSizeGet,
DEF_NULL,
DEF_NULL,
USBD_HID_IF_Req,
USBD_HID_ClassReq,
DEF_NULL,
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
DEF_NULL,
DEF_NULL
#endif
};
/*
*********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*********************************************************************************************************
* GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_HID_Init()
*
* Description : Initialize HID class.
*
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE HID class initialized successfully.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_HID_Init (USBD_ERR *p_err)
{
CPU_INT08U ix;
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
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
USBD_HID_OS_Init(p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
USBD_HID_Report_Init(p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
for (ix = 0u; ix < USBD_HID_CFG_MAX_NBR_DEV; ix++) { /* Init HID class struct. */
p_ctrl = &USBD_HID_CtrlTbl[ix];
p_ctrl->DevNbr = USBD_DEV_NBR_NONE;
p_ctrl->ClassNbr = USBD_CLASS_NBR_NONE;
p_ctrl->State = USBD_HID_STATE_NONE;
p_ctrl->CommPtr = (USBD_HID_COMM *)0;
p_ctrl->SubClassCode = USBD_HID_SUBCLASS_NONE;
p_ctrl->ProtocolCode = USBD_HID_PROTOCOL_NONE;
p_ctrl->CountryCode = USBD_HID_COUNTRY_CODE_NOT_SUPPORTED;
p_ctrl->ReportDescPtr = (CPU_INT08U *)0;
p_ctrl->ReportDescLen = 0u;
p_ctrl->PhyDescPtr = (CPU_INT08U *)0;
p_ctrl->PhyDescLen = 0u;
p_ctrl->IntervalIn = 0u;
p_ctrl->IntervalOut = 0u;
p_ctrl->CtrlRdEn = DEF_TRUE;
p_ctrl->CallbackPtr = (USBD_HID_CALLBACK *)0;
p_ctrl->IntrWrAsyncFnct = (USBD_HID_ASYNC_FNCT)0;
p_ctrl->IntrWrAsyncArgPtr = (void *)0;
p_ctrl->IntrRdAsyncFnct = (USBD_HID_ASYNC_FNCT)0;
p_ctrl->IntrRdAsyncArgPtr = (void *)0;
p_ctrl->CtrlStatusBufPtr = (CPU_INT08U *)Mem_HeapAlloc( sizeof(CPU_ADDR),
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;
}
}
for (ix = 0u; ix < USBD_HID_MAX_NBR_COMM; ix++) { /* Init HID EP tbl. */
p_comm = &USBD_HID_CommTbl[ix];
p_comm->CtrlPtr = (USBD_HID_CTRL *)0;
p_comm->DataIntrInEpAddr = USBD_EP_ADDR_NONE;
p_comm->DataIntrOutEpAddr = USBD_EP_ADDR_NONE;
p_comm->DataIntrOutActiveXfer = DEF_NO;
}
USBD_HID_CtrlNbrNext = 0u;
USBD_HID_CommNbrNext = 0u;
}
/*
*********************************************************************************************************
* USBD_HID_Add()
*
* Description : Add a new instance of the HID class.
*
* Argument(s) : subclass Subclass code.
*
* protocol Protocol code.
*
* country_code Country code ID.
*
* p_report_desc Pointer to report descriptor structure
*
* report_desc_len Report descriptor length.
*
* p_phy_desc Pointer to physical descriptor structure.
*
* phy_desc_len Physical descriptor length.
*
* interval_in Polling interval for input transfers, in milliseconds.
* It must be a power of 2.
*
* interval_out Polling interval for output transfers, in milliseconds.
* It must be a power of 2. Used only when read operations are not
* through control transfers.
*
* ctrl_rd_en Enable read operations through control transfers.
*
* p_hid_callback Pointer to HID descriptor and request callback structure.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE HID class instance successfully added.
* USBD_ERR_ALLOC HID class instances NOT available.
* USBD_ERR_NULL_PTR Argument 'p_hid_callbacks' passed a NULL pointer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'p_hid_callbacks'/
* 'intr_out_en'/'p_report_desc'/'report_desc_len'/
* 'p_phy_desc'/'phy_desc_len'/'ctrl_rd_en'.
*
* ------ RETURNED BY USBD_HID_Report_Parse() : -------
* USBD_ERR_NULL_PTR Argument 'p_report_data'/'p_report' passed a NULL
* pointer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'p_report_data'/
* 'report_data_len'.
* USBD_ERR_FAIL Invalid HID descriptor data, mismatch on end of
* collection, or mismatch on pop items.
* USBD_ERR_ALLOC No more Report ID or global item structure available,
* or memory allocation failed for report buffers.
*
* Return(s) : Class instance number, if NO error(s).
*
* USBD_CLASS_NBR_NONE, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT08U USBD_HID_Add (CPU_INT08U subclass,
CPU_INT08U protocol,
USBD_HID_COUNTRY_CODE country_code,
CPU_INT08U *p_report_desc,
CPU_INT16U report_desc_len,
CPU_INT08U *p_phy_desc,
CPU_INT16U phy_desc_len,
CPU_INT16U interval_in,
CPU_INT16U interval_out,
CPU_BOOLEAN ctrl_rd_en,
USBD_HID_CALLBACK *p_hid_callback,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
CPU_INT08U class_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);
}
if (MATH_IS_PWR2(interval_in) == DEF_NO) { /* Interval for intr IN must be a power of 2. */
*p_err = USBD_ERR_INVALID_ARG;
return (USBD_CLASS_NBR_NONE);
}
if ((ctrl_rd_en == DEF_NO) &&
(MATH_IS_PWR2(interval_out) == DEF_NO)) { /* Interval for intr OUT must be a power of 2. */
*p_err = USBD_ERR_INVALID_ARG;
return (USBD_CLASS_NBR_NONE);
}
#endif
if (((p_report_desc == (CPU_INT08U *)0) &&
( report_desc_len > 0u)) ||
((p_report_desc != (CPU_INT08U *)0) &&
( report_desc_len == 0u))) {
*p_err = USBD_ERR_INVALID_ARG;
return (USBD_CLASS_NBR_NONE);
}
if (((p_phy_desc == (CPU_INT08U *)0) &&
( phy_desc_len > 0u)) ||
((p_phy_desc != (CPU_INT08U *)0) &&
( phy_desc_len < 3u))) {
*p_err = USBD_ERR_INVALID_ARG;
return (USBD_CLASS_NBR_NONE);
}
CPU_CRITICAL_ENTER();
class_nbr = USBD_HID_CtrlNbrNext; /* Alloc new HID class instance. */
if (class_nbr >= USBD_HID_CFG_MAX_NBR_DEV) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_HID_INSTANCE_ALLOC;
return (USBD_CLASS_NBR_NONE);
}
USBD_HID_CtrlNbrNext++;
CPU_CRITICAL_EXIT();
p_ctrl = &USBD_HID_CtrlTbl[class_nbr];
p_ctrl->SubClassCode = subclass;
p_ctrl->ProtocolCode = protocol;
p_ctrl->CountryCode = country_code;
p_ctrl->ReportDescPtr = p_report_desc;
p_ctrl->ReportDescLen = report_desc_len;
p_ctrl->PhyDescPtr = p_phy_desc;
p_ctrl->PhyDescLen = phy_desc_len;
p_ctrl->IntervalIn = interval_in;
p_ctrl->IntervalOut = interval_out;
p_ctrl->CtrlRdEn = ctrl_rd_en;
p_ctrl->CallbackPtr = p_hid_callback;
USBD_HID_Report_Parse(class_nbr,
p_ctrl->ReportDescPtr,
p_ctrl->ReportDescLen,
&p_ctrl->Report,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (USBD_CLASS_NBR_NONE);
} else {
return (class_nbr);
}
}
/*
*********************************************************************************************************
* USBD_HID_CfgAdd()
*
* Description : Add HID class instance into USB device configuration (see Note #1).
*
* Argument(s) : class_nbr Class instance number.
*
* dev_nbr Device number.
*
* cfg_nbr Configuration index to add HID class instance to.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE HID class configuration successfully added.
* USBD_ERR_ALLOC HID class communication instances 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_NULL_PTR Argument 'p_class_drv'/'p_class_drv->Conn'/
* 'p_class_drv->Disconn' passed a NULL pointer.
* 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.
*
* Return(s) : DEF_YES, if HID class instance added to USB device configuration successfully.
*
* DEF_NO, otherwise.
*
* Note(s) : (1) Called several times, it allows to create multiple instances and multiple configurations.
* For instance, the following architecture could be created :
*
* HS
* |-- Configuration 0 (HID class 0)
* (HID class 1)
* (HID class 2)
* |-- Interface 0
* |-- Configuration 1 (HID class 0)
* |-- Interface 0
*
* (2) Configuration Descriptor corresponding to a HID device has the following format :
*
* Configuration Descriptor
* |-- Interface Descriptor (HID class)
* |-- Endpoint Descriptor (Interrupt IN)
* |-- Endpoint Descriptor (Interrupt OUT) - optional
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_HID_CfgAdd (CPU_INT08U class_nbr,
CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT08U if_nbr;
CPU_INT08U ep_addr;
CPU_INT16U comm_nbr;
CPU_INT16U interval_in;
CPU_INT16U interval_out;
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_HID_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (DEF_NO);
}
p_ctrl = &USBD_HID_CtrlTbl[class_nbr]; /* Get HID class instance. */
CPU_CRITICAL_ENTER();
if ((p_ctrl->DevNbr != USBD_DEV_NBR_NONE) && /* Chk if class is associated with a different dev. */
(p_ctrl->DevNbr != dev_nbr)) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_INVALID_ARG;
return (DEF_NO);
}
p_ctrl->DevNbr = dev_nbr;
comm_nbr = USBD_HID_CommNbrNext; /* Alloc new HID class comm info. */
if (comm_nbr >= USBD_HID_MAX_NBR_COMM) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_HID_INSTANCE_ALLOC;
return (DEF_NO);
}
USBD_HID_CommNbrNext++;
CPU_CRITICAL_EXIT();
p_comm = &USBD_HID_CommTbl[comm_nbr];
/* -------------- CFG DESC CONSTRUCTION --------------- */
/* See Note #2. */
/* Add HID IF desc to cfg desc. */
if_nbr = USBD_IF_Add( dev_nbr,
cfg_nbr,
&USBD_HID_Drv,
(void *)p_comm, /* Comm struct associated to HID IF. */
(void *)0,
USBD_CLASS_CODE_HID,
p_ctrl->SubClassCode,
p_ctrl->ProtocolCode,
"HID Class",
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
if (DEF_BIT_IS_CLR(cfg_nbr, USBD_CFG_NBR_SPD_BIT) == DEF_YES) {
/* In FS, bInterval in frames. */
interval_in = p_ctrl->IntervalIn;
interval_out = p_ctrl->IntervalOut;
} else { /* In HS, bInterval in microframes. */
interval_in = p_ctrl->IntervalIn * 8u;
interval_out = p_ctrl->IntervalOut * 8u;
}
ep_addr = USBD_IntrAdd(dev_nbr, /* Add intr IN EP desc. */
cfg_nbr,
if_nbr,
0u,
DEF_YES,
0u,
interval_in,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
p_comm->DataIntrInEpAddr = ep_addr; /* Store intr IN EP addr. */
if (p_ctrl->CtrlRdEn == DEF_FALSE) {
ep_addr = USBD_IntrAdd(dev_nbr, /* Add intr OUT EP desc. */
cfg_nbr,
if_nbr,
0u,
DEF_NO,
0u,
interval_out,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
} else {
ep_addr = USBD_EP_ADDR_NONE;
}
p_comm->DataIntrOutEpAddr = ep_addr; /* Store intr OUT EP addr. */
/* Store HID class instance info. */
CPU_CRITICAL_ENTER();
p_ctrl->ClassNbr = class_nbr;
p_ctrl->State = USBD_HID_STATE_INIT;
CPU_CRITICAL_EXIT();
p_comm->CtrlPtr = p_ctrl;
*p_err = USBD_ERR_NONE;
return (DEF_YES);
}
/*
*********************************************************************************************************
* USBD_HID_IsConn()
*
* Description : Get the HID class connection state.
*
* Argument(s) : class_nbr Class instance number.
*
* Return(s) : DEF_YES, if HID class is connected.
*
* DEF_NO, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_HID_IsConn (CPU_INT08U class_nbr)
{
USBD_HID_CTRL *p_ctrl;
USBD_DEV_STATE state;
USBD_ERR err;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
if (class_nbr >= USBD_HID_CtrlNbrNext) {
return (DEF_NO);
}
#endif
p_ctrl = &USBD_HID_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_HID_STATE_CFG )) {
return (DEF_YES);
} else {
return (DEF_NO);
}
}
/*
*********************************************************************************************************
* USBD_HID_Rd()
*
* Description : Receive data from host through Interrupt OUT endpoint. This function is blocking.
*
* Argument(s) : class_nbr Class instance number.
*
* p_buf Pointer to receive buffer.
*
* buf_len Receive buffer length, in octets.
*
* timeout Timeout, in milliseconds.
*
* 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_NULL_PTR Argument 'p_buf' passed a NULL pointer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid class state.
*
* ------ 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.
*
* Return(s) : Number of octets received, if NO error(s).
*
* 0, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT32U USBD_HID_Rd (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT32U xfer_len;
CPU_BOOLEAN conn;
USBD_ERR err;
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 ((p_buf == (void *)0) &&
(buf_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return (0u);
}
#endif
if (class_nbr >= USBD_HID_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_HID_CtrlTbl[class_nbr];
CPU_CRITICAL_ENTER();
p_comm = p_ctrl->CommPtr;
conn = USBD_HID_IsConn(class_nbr);
CPU_CRITICAL_EXIT();
if (conn != DEF_YES) { /* Chk class state. */
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
if (p_ctrl->CtrlRdEn == DEF_TRUE) { /* Use SET_REPORT to rx data instead. */
USBD_HID_OS_OutputLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
if (p_ctrl->IsRx == DEF_TRUE) {
USBD_HID_OS_OutputUnlock(class_nbr);
*p_err = USBD_ERR_FAIL;
return (0u);
}
p_ctrl->IsRx = DEF_TRUE;
p_ctrl->RxBufLen = buf_len;
p_ctrl->RxBufPtr = (CPU_INT08U *)p_buf;
/* Save app rx callback. */
p_ctrl->IntrRdAsyncFnct = USBD_HID_OutputDataCmpl;
p_ctrl->IntrRdAsyncArgPtr = &xfer_len;
USBD_HID_OS_OutputUnlock(class_nbr);
USBD_HID_OS_OutputDataPend(class_nbr, timeout, &err);
USBD_HID_OS_OutputLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
*p_err = err;
if (*p_err == USBD_ERR_OS_TIMEOUT) {
p_ctrl->RxBufLen = 0u;
p_ctrl->RxBufPtr = (CPU_INT08U *)0;
p_ctrl->IntrRdAsyncFnct = 0;
p_ctrl->IntrRdAsyncArgPtr = 0;
p_ctrl->IsRx = DEF_FALSE;
USBD_HID_OS_OutputUnlock(class_nbr);
return (0u);
}
USBD_HID_OS_OutputUnlock(class_nbr);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
return (xfer_len);
}
/* ------------------ INTR OUT COMM ------------------- */
xfer_len = USBD_IntrRx(p_ctrl->DevNbr,
p_comm->DataIntrOutEpAddr,
p_buf,
buf_len,
timeout,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
return (xfer_len);
}
/*
*********************************************************************************************************
* USBD_HID_RdAsync()
*
* Description : Receive data from host through Interrupt OUT endpoint. This function is non-blocking and
* returns immediately after transfer preparation. Upon transfer completion, the callback
* provided is called to notify the application.
*
* Argument(s) : class_nbr Class instance number.
*
* p_buf Pointer to receive buffer.
*
* buf_len Receive buffer length, in octets.
*
* async_fnct Receive callback.
*
* p_async_arg Additional argument provided by application for receive callback.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Transfer successfully prepared.
* USBD_ERR_NULL_PTR Argument 'p_buf' passed a NULL pointer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid class state.
* USBD_ERR_FAIL Read operation already in progress.
*
* --- RETURNED BY USBD_BulkRxAsync() : ---
* 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.
* USBD_ERR_EP_INVALID_STATE Endpoint not opened.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_HID_RdAsync (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
USBD_HID_ASYNC_FNCT async_fnct,
void *p_async_arg,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_BOOLEAN conn;
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) &&
(buf_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
#endif
if (class_nbr >= USBD_HID_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_HID_CtrlTbl[class_nbr];
CPU_CRITICAL_ENTER();
p_comm = p_ctrl->CommPtr;
conn = USBD_HID_IsConn(class_nbr);
CPU_CRITICAL_EXIT();
if (conn != DEF_YES) { /* Chk class state. */
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
if (p_ctrl->CtrlRdEn == DEF_TRUE) { /* Use SET_REPORT to rx data instead. */
USBD_HID_OS_OutputLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
if (p_ctrl->IsRx == DEF_TRUE) {
USBD_HID_OS_OutputUnlock(class_nbr);
*p_err = USBD_ERR_FAIL;
return;
}
p_ctrl->IsRx = DEF_TRUE;
p_ctrl->RxBufLen = buf_len;
p_ctrl->RxBufPtr = (CPU_INT08U *)p_buf;
/* Save app rx callback. */
p_ctrl->IntrRdAsyncFnct = async_fnct;
p_ctrl->IntrRdAsyncArgPtr = p_async_arg;
USBD_HID_OS_OutputUnlock(class_nbr);
} else {
/* Save app rx callback. */
CPU_CRITICAL_ENTER();
p_ctrl->IntrRdAsyncFnct = async_fnct;
p_ctrl->IntrRdAsyncArgPtr = p_async_arg;
/* ------------------ INTR OUT COMM ------------------- */
if (p_comm->DataIntrOutActiveXfer == DEF_NO) { /* Check if another xfer is already in progress. */
p_comm->DataIntrOutActiveXfer = DEF_YES; /* Indicate that a xfer is in progres. */
CPU_CRITICAL_EXIT();
USBD_IntrRxAsync( p_ctrl->DevNbr,
p_comm->DataIntrOutEpAddr,
p_buf,
buf_len,
USBD_HID_RdAsyncCmpl,
(void *)p_comm,
p_err);
if (*p_err != USBD_ERR_NONE) {
CPU_CRITICAL_ENTER();
p_comm->DataIntrOutActiveXfer = DEF_NO;
CPU_CRITICAL_EXIT();
}
} else {
CPU_CRITICAL_ENTER();
*p_err = USBD_ERR_CLASS_XFER_IN_PROGRESS;
return;
}
}
}
/*
*********************************************************************************************************
* USBD_HID_Wr()
*
* Description : Send data to host through Interrupt IN endpoint. This function is blocking.
*
* Argument(s) : class_nbr Class instance number.
*
* p_buf Pointer to transmit buffer. If more than one input report exists, the first
* byte must represent the Report ID.
*
* buf_len Transmit buffer length, in octets.
*
* timeout Timeout in milliseconds.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Data successfully sent to host.
* USBD_ERR_NULL_PTR Argument 'p_buf' passed a NULL pointer.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid class state.
*
* ------ RETURNED BY USBD_BulkTx() : ------
* 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.
*
* Return(s) : Number of octets sent, if NO error(s).
*
* 0, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT32U USBD_HID_Wr (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT32U xfer_len;
CPU_INT08U report_id;
CPU_INT08U *p_buf_data;
CPU_INT08U *p_buf_report;
CPU_INT16U report_len;
CPU_BOOLEAN is_largest;
CPU_BOOLEAN conn;
CPU_BOOLEAN eot;
USBD_ERR err;
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 ((p_buf == (void *)0) &&
(buf_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return (0u);
}
#endif
if (class_nbr >= USBD_HID_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_HID_CtrlTbl[class_nbr];
CPU_CRITICAL_ENTER();
p_comm = p_ctrl->CommPtr;
conn = USBD_HID_IsConn(class_nbr);
CPU_CRITICAL_EXIT();
if (conn != DEF_YES) { /* Chk class state. */
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
/* ----------------- STORE REPORT DATA ---------------- */
if (buf_len > 0) {
p_buf_data = (CPU_INT08U *)p_buf;
if (p_ctrl->Report.HasReports == DEF_YES) {
report_id = p_buf_data[0];
} else {
report_id = 0;
}
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_INPUT,
report_id,
&p_buf_report,
&is_largest,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
if (report_len > buf_len) {
*p_err = USBD_ERR_INVALID_ARG;
return (0u);
}
eot = (is_largest == DEF_YES) ? DEF_NO : DEF_YES;
} else {
p_buf_data = (CPU_INT08U *)0;
p_buf_report = (CPU_INT08U *)0;
report_len = 0;
eot = DEF_YES;
}
USBD_HID_OS_TxLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
return (0u);
}
/* ------------------- INTR IN COMM ------------------- */
USBD_IntrTxAsync( p_ctrl->DevNbr,
p_comm->DataIntrInEpAddr,
p_buf,
buf_len,
USBD_HID_WrSyncCmpl,
(void *)p_comm,
eot,
p_err);
if (*p_err != USBD_ERR_NONE) {
USBD_HID_OS_TxUnlock(class_nbr);
return (0u);
}
if (buf_len > 0) { /* Defer copy while transmitting. */
USBD_HID_OS_InputLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
USBD_HID_OS_TxUnlock(class_nbr);
return (0u);
}
Mem_Copy(&p_buf_report[0], &p_buf_data[0], report_len);
USBD_HID_OS_InputUnlock(class_nbr);
}
USBD_HID_OS_InputDataPend(class_nbr, timeout, p_err);
if (*p_err != USBD_ERR_NONE) {
if (*p_err == USBD_ERR_OS_TIMEOUT) {
USBD_EP_Abort(p_ctrl->DevNbr,
p_comm->DataIntrInEpAddr,
&err);
}
USBD_HID_OS_TxUnlock(class_nbr);
return (0u);
}
xfer_len = p_ctrl->DataIntrInXferLen;
USBD_HID_OS_TxUnlock(class_nbr);
return (xfer_len);
}
/*
*********************************************************************************************************
* USBD_HID_WrAsync()
*
* Description : Send data to host through Interrupt IN endpoint. This function is non-blocking, and returns
* immediately after transfer preparation. Upon transfer completion, the callback provided
* is called to notify the application.
*
* Argument(s) : class_nbr Class instance number.
*
* p_buf Pointer to transmit buffer. If more than one input report exists, the first
* byte must represent the Report ID.
*
* buf_len Transmit buffer length, in octets.
*
* async_fnct Transmit callback.
*
* p_async_arg Additional argument provided by application for transmit callback.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Transfer successfully prepared.
* USBD_ERR_NULL_PTR Argument 'p_buf' passed a NULL pointer.
* 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_EP_INVALID_NBR Invalid endpoint number.
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if device is in
* configured state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
* USBD_ERR_EP_INVALID_STATE Endpoint not opened.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_HID_WrAsync (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
USBD_HID_ASYNC_FNCT async_fnct,
void *p_async_arg,
USBD_ERR *p_err)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT08U report_id;
CPU_INT08U *p_buf_data;
CPU_INT08U *p_buf_report;
CPU_INT16U report_len;
CPU_BOOLEAN is_largest;
CPU_BOOLEAN conn;
CPU_BOOLEAN eot;
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) &&
(buf_len != 0)) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
#endif
if (class_nbr >= USBD_HID_CtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_HID_CtrlTbl[class_nbr];
CPU_CRITICAL_ENTER();
p_comm = p_ctrl->CommPtr;
conn = USBD_HID_IsConn(class_nbr);
CPU_CRITICAL_EXIT();
if (conn != DEF_YES) { /* Chk class state. */
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
/* ----------------- STORE REPORT DATA ---------------- */
if (buf_len > 0) {
p_buf_data = (CPU_INT08U *)p_buf;
if (p_ctrl->Report.HasReports == DEF_YES) {
report_id = p_buf_data[0];
} else {
report_id = 0;
}
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_INPUT,
report_id,
&p_buf_report,
&is_largest,
p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
if (report_len > buf_len) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
eot = (is_largest == DEF_YES) ? DEF_NO : DEF_YES;
} else {
p_buf_data = (CPU_INT08U *)0;
p_buf_report = (CPU_INT08U *)0;
report_len = 0;
eot = DEF_YES;
}
USBD_HID_OS_TxLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
/* Save app rx callback. */
p_ctrl->IntrWrAsyncFnct = async_fnct;
p_ctrl->IntrWrAsyncArgPtr = p_async_arg;
/* ------------------- INTR IN COMM ------------------- */
USBD_IntrTxAsync( p_ctrl->DevNbr,
p_comm->DataIntrInEpAddr,
p_buf,
buf_len,
USBD_HID_WrAsyncCmpl,
(void *)p_comm,
eot,
p_err);
if (*p_err != USBD_ERR_NONE) {
USBD_HID_OS_TxUnlock(class_nbr);
return;
}
if (buf_len > 0) { /* Defer copy while transmitting. */
USBD_HID_OS_InputLock(class_nbr, p_err);
if (*p_err != USBD_ERR_NONE) {
USBD_HID_OS_TxUnlock(class_nbr);
return;
}
Mem_Copy(&p_buf_report[0], &p_buf_data[0], report_len);
USBD_HID_OS_InputUnlock(class_nbr);
}
}
/*
*********************************************************************************************************
*********************************************************************************************************
* LOCAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_HID_Conn()
*
* Description : Notify class that configuration is active.
*
* Argument(s) : dev_nbr Device number.
*
* cfg_nbr Configuration number.
*
* p_if_class_arg Pointer to class argument specific to interface.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_HID_Conn (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg)
{
USBD_HID_COMM *p_comm;
CPU_SR_ALLOC();
(void)dev_nbr;
(void)cfg_nbr;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
CPU_CRITICAL_ENTER();
p_comm->CtrlPtr->CommPtr = p_comm;
p_comm->CtrlPtr->State = USBD_HID_STATE_CFG;
CPU_CRITICAL_EXIT();
}
/*
*********************************************************************************************************
* USBD_HID_Disconn()
*
* Description : Notify class that configuration is not active.
*
* Argument(s) : dev_nbr Device number.
*
* cfg_nbr Configuration number.
*
* p_if_class_arg Pointer to class argument specific to interface.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_HID_Disconn (CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
void *p_if_class_arg)
{
USBD_HID_COMM *p_comm;
USBD_HID_CTRL *p_ctrl;
CPU_SR_ALLOC();
(void)dev_nbr;
(void)cfg_nbr;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
USBD_HID_Report_RemoveAllIdle(&p_ctrl->Report);
CPU_CRITICAL_ENTER();
p_ctrl->CommPtr = (USBD_HID_COMM *)0;
p_ctrl->State = USBD_HID_STATE_INIT;
if (p_ctrl->IsRx == DEF_TRUE) {
CPU_CRITICAL_EXIT();
p_ctrl->IntrRdAsyncFnct( p_ctrl->ClassNbr,
p_ctrl->RxBufPtr,
p_ctrl->RxBufLen,
0,
(void *)p_ctrl->IntrRdAsyncArgPtr,
USBD_ERR_OS_ABORT);
CPU_CRITICAL_ENTER();
p_ctrl->IsRx = DEF_FALSE;
p_ctrl->RxBufLen = 0;
p_ctrl->RxBufPtr = (CPU_INT08U *)0;
p_ctrl->IntrRdAsyncFnct = 0;
p_ctrl->IntrRdAsyncArgPtr = 0;
CPU_CRITICAL_EXIT();
} else {
CPU_CRITICAL_EXIT();
}
}
/*
*********************************************************************************************************
* USBD_HID_AltSettingUpdate()
*
* Description : Notify class that interface alternate setting has been updated.
*
* 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_HID_AltSettingUpdate (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_HID_COMM *p_comm;
CPU_SR_ALLOC();
(void)dev_nbr;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
CPU_CRITICAL_ENTER();
p_comm->CtrlPtr->CommPtr = p_comm;
CPU_CRITICAL_EXIT();
}
/*
*********************************************************************************************************
* USBD_HID_EP_StateUpdate()
*
* Description : Notify class that endpoint state has been updated.
*
* 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) : (1) EP state may have changed, it can be checked through USBD_EP_IsStalled().
*********************************************************************************************************
*/
static void USBD_HID_EP_StateUpdate (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)
{
(void)dev_nbr;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)ep_addr;
(void)p_if_class_arg;
(void)p_if_alt_class_arg;
}
/*
*********************************************************************************************************
* USBD_HID_IF_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_HID_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)
{
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
USBD_HID_IF_DescHandler(dev_nbr, p_if_class_arg);
}
/*
*********************************************************************************************************
* USBD_HID_IF_DescHandler()
*
* Description : Class interface descriptor callback handler.
*
* Argument(s) : dev_nbr Device number.
*
* p_if_class_arg Pointer to class argument.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_HID_IF_DescHandler (CPU_INT08U dev_nbr,
void *p_if_class_arg)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT08U nbr_desc;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
nbr_desc = 0u;
if (p_ctrl->ReportDescLen > 0u) {
nbr_desc++;
}
if (p_ctrl->PhyDescLen > 0u) {
nbr_desc++;
}
USBD_DescWr08(dev_nbr, USBD_HID_DESC_LEN + nbr_desc * 3u);
USBD_DescWr08(dev_nbr, USBD_HID_DESC_TYPE_HID);
USBD_DescWr16(dev_nbr, 0x0111);
USBD_DescWr08(dev_nbr, (CPU_INT08U)p_ctrl->CountryCode);
USBD_DescWr08(dev_nbr, nbr_desc);
if (p_ctrl->ReportDescLen > 0u) {
USBD_DescWr08(dev_nbr, USBD_HID_DESC_TYPE_REPORT);
USBD_DescWr16(dev_nbr, p_ctrl->ReportDescLen);
}
if (p_ctrl->PhyDescLen > 0u) {
USBD_DescWr08(dev_nbr, USBD_HID_DESC_TYPE_PHYSICAL);
USBD_DescWr16(dev_nbr, p_ctrl->PhyDescLen);
}
}
/*
*********************************************************************************************************
* USBD_HID_IF_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_HID_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)
{
USBD_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT08U nbr_desc;
(void)dev_nbr;
(void)cfg_nbr;
(void)if_nbr;
(void)if_alt_nbr;
(void)p_if_alt_class_arg;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
nbr_desc = 0u;
if (p_ctrl->ReportDescLen > 0u) {
nbr_desc++;
}
if (p_ctrl->PhyDescLen > 0u) {
nbr_desc++;
}
return (USBD_HID_DESC_LEN + nbr_desc * 3u);
}
/*
*********************************************************************************************************
* USBD_HID_IF_Req()
*
* Description : Process interface requests.
*
* 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) : (1) HID class supports 3 class-specific descriptors:
*
* (a) HID descriptor (mandatory)
*
* (a) Report descriptor (mandatory)
*
* (a) Physical descriptor (optional)
*
* HID descriptor is sent to Host as part of the Configuration descriptor. Report and
* Physical descriptors are retrieved by the host using a GET_DESCRIPTOR standard request
* with the recipient being the interface. The way to get Report and Physical descriptors
* is specific to the HID class. The HID class specification indicates in the section
* '7.1 Standard Requests':
*
* "The HID class uses the standard request Get_Descriptor as described in the USB Specification.
* When a Get_Descriptor(Configuration) request is issued, it returns the Configuration descriptor,
* all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
* It shall not return the String descriptor, HID Report descriptor or any of the
* optional HID class descriptors."
*
* (2) The HID descriptor identifies the length and type of subordinate descriptors for a
* device.
* See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 6.2.1 for more details about HID descriptor.
*
* (3) The Report descriptor is made up of items that provide information about the device.
* The first part of an item contains three fields: item type, item tag, and item size.
* Together these fields identify the kind of information the item provides.
* See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 6.2.2 for more details about Report descriptor.
*
* (4) A Physical Descriptor is a data structure that provides information about the
* specific part or parts of the human body that are activating a control or controls.
* See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 6.2.3 for more details about Physical descriptor.
*
* (a) Descriptor set 0 is a special descriptor set that specifies the number of additional
* descriptor sets, and also the number of Physical Descriptors in each set.
*********************************************************************************************************
*/
static CPU_BOOLEAN USBD_HID_IF_Req ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg)
{
USBD_HID_COMM *p_comm;
CPU_BOOLEAN valid;
CPU_BOOLEAN dev_to_host;
CPU_INT08U desc_type;
CPU_INT08U w_value;
CPU_INT16U desc_len;
CPU_INT32U desc_offset;
(void)dev_nbr;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
valid = DEF_FAIL;
dev_to_host = DEF_BIT_IS_SET(p_setup_req->bmRequestType, USBD_REQ_DIR_BIT);
if (p_setup_req->bRequest == USBD_REQ_GET_DESCRIPTOR) { /* ---------- GET DESCRIPTOR (see Note #1) ------------ */
if (dev_to_host != DEF_YES) {
return (valid);
}
/* Get desc type. */
desc_type = (CPU_INT08U)((p_setup_req->wValue >> 8u) & DEF_INT_08_MASK);
w_value = (CPU_INT08U) (p_setup_req->wValue & DEF_INT_08_MASK);
switch (desc_type) {
case USBD_HID_DESC_TYPE_HID: /* ------------- HID DESC (see Note #2) --------------- */
if (w_value != 0) {
break;
}
USBD_HID_IF_DescHandler(dev_nbr, p_if_class_arg);
valid = DEF_OK;
break;
case USBD_HID_DESC_TYPE_REPORT: /* ------------ REPORT DESC (see Note #3) ------------- */
if (w_value != 0) {
break;
}
if (p_comm->CtrlPtr->ReportDescLen > 0) {
USBD_DescWr(dev_nbr,
p_comm->CtrlPtr->ReportDescPtr,
p_comm->CtrlPtr->ReportDescLen);
valid = DEF_OK;
}
break;
case USBD_HID_DESC_TYPE_PHYSICAL: /* ------------ PHYSICAL DESC (see Note #4) ----------- */
if (p_comm->CtrlPtr->PhyDescLen < 3) {
break;
}
if (w_value > 0) {
desc_len = MEM_VAL_GET_INT16U_LITTLE(p_comm->CtrlPtr->PhyDescPtr + 1);
desc_offset = desc_len * (w_value - 1) + 3;
if (p_comm->CtrlPtr->PhyDescLen < (desc_offset + desc_len)) {
break;
}
USBD_DescWr(dev_nbr,
&p_comm->CtrlPtr->PhyDescPtr[desc_offset],
desc_len);
} else {
USBD_DescWr(dev_nbr, /* See Note #4a. */
p_comm->CtrlPtr->PhyDescPtr,
3);
}
valid = DEF_OK;
break;
default: /* Other desc type not supported. */
break;
}
}
return (valid);
}
/*
*********************************************************************************************************
* USBD_HID_ClassReq()
*
* Description : Process class-specific requests.
*
* 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) : (1) HID defines the following class-specific requests :
*
* (a) GET_REPORT allows the host to receive a report.
*
* (b) SET_REPORT allows the host to send a report to the device, possibly setting
* the state of input, output, or feature controls.
*
* (c) GET_IDLE reads the current idle rate for a particular Input report.
*
* (d) SET_IDLE silences a particular report on the Interrupt In pipe until a
* new event occurs or the specified amount of time passes.
*
* (e) GET_PROTOCOL reads which protocol is currently active (either the boot
* protocol or the report protocol).
*
* (1) Protocol is either BOOT or REPORT.
*
* (f) SET_PROTOCOL switches between the boot protocol and the report protocol (or
* vice versa).
*
* See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
* section 7.2 for more details about Class-Specific Requests.
*********************************************************************************************************
*/
static CPU_BOOLEAN USBD_HID_ClassReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_if_class_arg)
{
USBD_HID_COMM *p_comm;
USBD_HID_CTRL *p_ctrl;
CPU_BOOLEAN valid;
CPU_BOOLEAN dev_to_host;
USBD_ERR err;
CPU_INT08U idle_rate;
CPU_INT08U report_id;
CPU_INT08U report_type;
CPU_INT16U report_len;
CPU_INT08U protocol;
CPU_INT08U *p_buf;
CPU_INT32U buf_len;
CPU_INT16U req_len;
CPU_INT08U w_value;
CPU_BOOLEAN is_largest;
USBD_HID_CALLBACK *p_callback;
(void)dev_nbr;
p_comm = (USBD_HID_COMM *)p_if_class_arg;
p_ctrl = p_comm->CtrlPtr;
valid = DEF_FAIL;
p_callback = p_ctrl->CallbackPtr;
dev_to_host = DEF_BIT_IS_SET(p_setup_req->bmRequestType, USBD_REQ_DIR_BIT);
switch (p_setup_req->bRequest) { /* See Note #1. */
case USBD_HID_REQ_GET_REPORT: /* ------------- GET_REPORT (see Note #1a) ------------ */
if (dev_to_host != DEF_YES) {
break;
}
report_type = (CPU_INT08U)((p_setup_req->wValue >> 8u) & DEF_INT_08_MASK);
report_id = (CPU_INT08U)( p_setup_req->wValue & DEF_INT_08_MASK);
switch (report_type) {
case 1: /* Input report. */
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_INPUT,
report_id,
&p_buf,
&is_largest,
&err);
if (err != USBD_ERR_NONE) {
break;
}
/* Get min between req len & report size. */
buf_len = DEF_MIN(p_setup_req->wLength, report_len);
USBD_HID_OS_InputLock(p_ctrl->ClassNbr, &err);
if (err != USBD_ERR_NONE) {
break;
}
/* Send Report to host. */
USBD_CtrlTx( p_ctrl->DevNbr,
(void *)p_buf,
buf_len,
USBD_HID_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
USBD_HID_OS_InputUnlock(p_ctrl->ClassNbr);
break;
case 3: /* Feature report. */
if ((p_callback == (USBD_HID_CALLBACK *)0) ||
(p_callback->FeatureReportGet == (void *)0)) {
break; /* Stall request. */
}
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_FEATURE,
report_id,
&p_buf,
&is_largest,
&err);
if (err != USBD_ERR_NONE) {
break;
}
/* Get min between req len & report size. */
req_len = DEF_MIN(p_setup_req->wLength, report_len);
valid = p_callback->FeatureReportGet(p_ctrl->ClassNbr,
report_id,
p_buf,
req_len);
if (valid != DEF_OK) {
break;
}
/* Send Report to host. */
USBD_CtrlTx( p_ctrl->DevNbr,
(void *)p_buf,
req_len,
USBD_HID_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
break;
case 0:
default:
break;
}
break;
case USBD_HID_REQ_SET_REPORT: /* ------------- SET_REPORT (see Note #1b) ------------ */
if (dev_to_host != DEF_NO) {
break;
}
report_type = (CPU_INT08U)((p_setup_req->wValue >> 8u) & DEF_INT_08_MASK);
report_id = (CPU_INT08U)( p_setup_req->wValue & DEF_INT_08_MASK);
switch (report_type) {
case 2: /* Output report. */
if ((p_callback == (USBD_HID_CALLBACK *)0) ||
(p_callback->ReportSet == (void *)0)) {
break; /* Stall request. */
}
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_OUTPUT,
report_id,
&p_buf,
&is_largest,
&err);
if (err != USBD_ERR_NONE) {
break;
}
USBD_HID_OS_OutputLock(p_ctrl->ClassNbr, &err);
if (err != USBD_ERR_NONE) {
break;
}
if (p_setup_req->wLength > report_len) {
USBD_HID_OS_OutputUnlock(p_ctrl->ClassNbr);
break;
}
/* Receive report from host. */
USBD_CtrlRx( p_ctrl->DevNbr,
(void *)p_buf,
report_len,
USBD_HID_CTRL_REQ_TIMEOUT_mS,
&err);
if (err != USBD_ERR_NONE) {
USBD_HID_OS_OutputUnlock(p_ctrl->ClassNbr);
break;
}
USBD_HID_OS_OutputUnlock(p_ctrl->ClassNbr);
p_callback->ReportSet(p_ctrl->ClassNbr,
report_id,
p_buf,
report_len);
valid = DEF_OK;
break;
case 3: /* Feature report. */
if ((p_callback == (USBD_HID_CALLBACK *)0) ||
(p_callback->FeatureReportSet == (void *)0)) {
break; /* Stall request. */
}
report_len = USBD_HID_ReportID_InfoGet(&p_ctrl->Report,
USBD_HID_REPORT_TYPE_FEATURE,
report_id,
&p_buf,
&is_largest,
&err);
if (err != USBD_ERR_NONE) {
break;
}
if (p_setup_req->wLength != report_len) {
break;
}
/* Receive report from host. */
USBD_CtrlRx( p_ctrl->DevNbr,
(void *)p_buf,
report_len,
0,
&err);
if (err != USBD_ERR_NONE) {
break;
}
valid = p_callback->FeatureReportSet(p_ctrl->ClassNbr,
report_id,
p_buf,
report_len);
break;
case 0:
default:
break;
}
break;
case USBD_HID_REQ_GET_IDLE: /* -------------- GET_IDLE (see Note #1c) ------------- */
if (dev_to_host != DEF_YES) {
break;
}
w_value = (CPU_INT08U)((p_setup_req->wValue >> 8u) & DEF_INT_08_MASK);
if ((p_setup_req->wLength == 1) && /* Chk if setup req is valid. */
(w_value == 0)) {
report_id = (CPU_INT08U)(p_setup_req->wValue & DEF_INT_08_MASK);
/* Get idle rate (duration). */
p_ctrl->CtrlStatusBufPtr[0] = USBD_HID_ReportID_IdleGet(&p_ctrl->Report,
report_id,
&err);
if (err != USBD_ERR_NONE) {
break;
}
USBD_CtrlTx( p_ctrl->DevNbr,
(void *)&p_ctrl->CtrlStatusBufPtr[0],
1u,
USBD_HID_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
}
break;
case USBD_HID_REQ_SET_IDLE: /* -------------- SET_IDLE (see Note #1d) ------------- */
if (dev_to_host != DEF_NO) {
break;
}
if (p_setup_req->wLength > 0) { /* Chk if setup req is valid. */
break;
}
idle_rate = (CPU_INT08U)((p_setup_req->wValue >> 8u) & DEF_INT_08_MASK);
report_id = (CPU_INT08U)( p_setup_req->wValue & DEF_INT_08_MASK);
USBD_HID_ReportID_IdleSet(&p_ctrl->Report,
report_id,
idle_rate,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
break;
case USBD_HID_REQ_GET_PROTOCOL: /* ------------ GET_PROTOCOL (see Note #1e) ----------- */
if ((p_callback == (USBD_HID_CALLBACK *)0) ||
(p_callback->ProtocolGet == (void *)0)) {
break; /* Stall request. */
}
if (dev_to_host != DEF_YES) {
break;
}
if ((p_setup_req->wLength != 1) || /* Chk if setup req is valid. */
(p_setup_req->wValue != 0)) {
break;
}
/* Get currently active protocol from app. */
p_ctrl->CtrlStatusBufPtr[0] = p_callback->ProtocolGet(p_ctrl->ClassNbr,
&err);
if (err != USBD_ERR_NONE) {
break;
}
/* Send active protocol to host (see Note #1e1). */
USBD_CtrlTx( p_ctrl->DevNbr,
(void *)&p_ctrl->CtrlStatusBufPtr[0],
1u,
USBD_HID_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
break;
case USBD_HID_REQ_SET_PROTOCOL: /* ------------ SET_PROTOCOL (see Note #1f) ----------- */
if ((p_callback == (USBD_HID_CALLBACK *)0) ||
(p_callback->ProtocolSet == (void *)0)) {
break; /* Stall request. */
}
if (dev_to_host != DEF_NO) {
break;
}
if ((p_setup_req->wLength != 0) || /* Chk if setup req is valid. */
((p_setup_req->wValue != 0) &&
(p_setup_req->wValue != 1))) {
break;
}
protocol = (CPU_INT08U)p_setup_req->wValue;
/* Set new protocol. */
p_callback->ProtocolSet(p_ctrl->ClassNbr,
protocol,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
break;
default:
break;
}
return (valid);
}
/*
*********************************************************************************************************
* USBD_HID_OutputDataCmpl()
*
* Description : Inform the class about the set report transfer completion on control endpoint.
*
* Argument(s) : class_nbr Class instance number.
*
* p_buf Pointer to the receive buffer.
*
* buf_len Receive buffer length.
*
* xfer_len Number of octets received.
*
* p_arg Additional argument provided by application.
*
* err Transfer status.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_HID_OutputDataCmpl (CPU_INT08U class_nbr,
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_arg,
USBD_ERR err)
{
CPU_INT32U *p_xfer_len;
(void)class_nbr;
(void)p_buf;
(void)buf_len;
p_xfer_len = (CPU_INT32U *)p_arg;
if (err == USBD_ERR_NONE) {
*p_xfer_len = xfer_len;
USBD_HID_OS_OutputDataPost(class_nbr);
} else {
*p_xfer_len = 0;
USBD_HID_OS_OutputDataPendAbort(class_nbr);
}
}
/*
*********************************************************************************************************
* USBD_HID_RdAsyncCmpl()
*
* Description : Inform the application about the Bulk OUT transfer completion.
*
* Argument(s) : dev_nbr Device number.
*
* ep_addr Endpoint address.
*
* p_buf Pointer to the receive buffer.
*
* buf_len Receive buffer length.
*
* xfer_len Number of octets received.
*
* p_arg Additional argument provided by application.
*
* err Transfer status: success or error.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_HID_RdAsyncCmpl (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_HID_COMM *p_comm;
USBD_HID_CTRL *p_ctrl;
USBD_HID_ASYNC_FNCT fnct;
void *p_fnct_arg;
(void)dev_nbr;
(void)ep_addr;
p_comm = (USBD_HID_COMM *)p_arg;
p_ctrl = p_comm->CtrlPtr;
fnct = p_ctrl->IntrRdAsyncFnct;
p_fnct_arg = p_ctrl->IntrRdAsyncArgPtr;
p_comm->DataIntrOutActiveXfer = DEF_NO; /* Xfer finished, no more active xfer. */
fnct(p_ctrl->ClassNbr, /* Notify app about xfer completion. */
p_buf,
buf_len,
xfer_len,
p_fnct_arg,
err);
}
/*
*********************************************************************************************************
* USBD_HID_WrAsyncCmpl()
*
* Description : Inform the application about the Bulk IN transfer completion.
*
* Argument(s) : dev_nbr Device number.
*
* ep_addr Endpoint address.
*
* p_buf Pointer to the 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_HID_WrAsyncCmpl (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_HID_COMM *p_comm;
USBD_HID_CTRL *p_ctrl;
(void)dev_nbr;
(void)ep_addr;
p_comm = (USBD_HID_COMM *)p_arg;
p_ctrl = (USBD_HID_CTRL *)p_comm->CtrlPtr;
USBD_HID_OS_TxUnlock(p_ctrl->ClassNbr);
p_ctrl->IntrWrAsyncFnct(p_ctrl->ClassNbr, /* Notify app about xfer completion. */
p_buf,
buf_len,
xfer_len,
p_ctrl->IntrWrAsyncArgPtr,
err);
}
/*
*********************************************************************************************************
* USBD_HID_WrSyncCmpl()
*
* Description : Inform the class about the Bulk IN transfer completion.
*
* 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_HID_WrSyncCmpl (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_HID_CTRL *p_ctrl;
USBD_HID_COMM *p_comm;
CPU_INT08U class_nbr;
(void)dev_nbr;
(void)ep_addr;
(void)p_buf;
(void)buf_len;
p_comm = (USBD_HID_COMM *)p_arg;
p_ctrl = p_comm->CtrlPtr;
class_nbr = p_ctrl->ClassNbr;
if (err == USBD_ERR_NONE) {
p_ctrl->DataIntrInXferLen = xfer_len;
USBD_HID_OS_InputDataPost(class_nbr);
} else {
p_ctrl->DataIntrInXferLen = 0;
USBD_HID_OS_InputDataPendAbort(class_nbr);
}
}