2198 lines
88 KiB
C
2198 lines
88 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/USB-Host
|
|
* The Embedded USB Host Stack
|
|
*
|
|
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
|
|
*
|
|
* SPDX-License-Identifier: APACHE-2.0
|
|
*
|
|
* This software is subject to an open source license and is distributed by
|
|
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
|
|
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* NOTICE
|
|
*
|
|
* Semidrive modified this file to adapt it for ssdk platform.
|
|
* The modifications are only intended for use with Semidrive chips.
|
|
* Copyright of all the modifications belongs to Semidrive Semiconductor.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* HUMAN INTERFACE DEVICE CLASS
|
|
*
|
|
* Filename : usbh_hid.c
|
|
* Version : V3.42.01
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_MODULE
|
|
#define MICRIUM_SOURCE
|
|
#include "usbh_hid.h"
|
|
#include "usbh_hidparser.h"
|
|
#include "../../Source/usbh_core.h"
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_MAX_DUR 1020u
|
|
#define USBH_HID_DUR_RESOLUTION 4u
|
|
#define USBH_HID_LEN_HID_DESC 9u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SUBCLASS CODES
|
|
*
|
|
* Note(s) : (1) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
|
|
* section 4.2 for more details about subclass codes.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_SUBCLASS_CODE_NONE 0x00u
|
|
#define USBH_HID_SUBCLASS_CODE_BOOT_IF 0x01u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CLASS-SPECIFIC DESCRIPTORS
|
|
*
|
|
* 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-specific descriptors.
|
|
*
|
|
* (2) For a 'get descriptor' setup request, the low byte of the 'wValue' field may contain
|
|
* one of these values.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_DESC_TYPE_HID 0x21u
|
|
#define USBH_HID_DESC_TYPE_REPORT 0x22u
|
|
#define USBH_HID_DESC_TYPE_PHYSICAL 0x23u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CLASS-SPECIFIC REQUESTS
|
|
*
|
|
* Note(s) : (1) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
|
|
* section 7.2 for more details about class-s[ecific requests.
|
|
*
|
|
* (2) The 'bRequest' field of a class-specific setup request may contain one of these values.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_REQ_GET_REPORT 0x01u
|
|
#define USBH_HID_REQ_GET_IDLE 0x02u
|
|
#define USBH_HID_REQ_GET_PROTOCOL 0x03u
|
|
#define USBH_HID_REQ_SET_REPORT 0x09u
|
|
#define USBH_HID_REQ_SET_IDLE 0x0Au
|
|
#define USBH_HID_REQ_SET_PROTOCOL 0x0Bu
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* GET REPORT REQUEST TYPES
|
|
*
|
|
* Note(s) : (1) See 'Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11',
|
|
* section 7.2.1 for more details about get report request types.
|
|
*
|
|
* (2) The upper byte of the 'wValue' field of a get report setup request may contain one of
|
|
* these values.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_HID_REPORT_TYPE_IN 0x01u
|
|
#define USBH_HID_REPORT_TYPE_OUT 0x02u
|
|
#define USBH_HID_REPORT_TYPE_FEATURE 0x03u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL TABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_HID_DEV USBH_HID_DevArr[USBH_HID_CFG_MAX_DEV];
|
|
static MEM_POOL USBH_HID_DevPool;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_GlobalInit (USBH_ERR *p_err);
|
|
|
|
static void *USBH_HID_ProbeIF (USBH_DEV *p_dev,
|
|
USBH_IF *p_if,
|
|
USBH_ERR *p_err);
|
|
|
|
static void USBH_HID_Suspend (void *p_class_dev);
|
|
|
|
static void USBH_HID_Resume (void *p_class_dev);
|
|
|
|
static void USBH_HID_Disconn (void *p_class_dev);
|
|
|
|
static void USBH_HID_DevClr (USBH_HID_DEV *p_hid_dev);
|
|
|
|
static USBH_ERR USBH_HID_DevLock (USBH_HID_DEV *p_hid_dev);
|
|
|
|
static void USBH_HID_DevUnlock (USBH_HID_DEV *p_hid_dev);
|
|
|
|
static CPU_INT32U USBH_HID_TxData (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err);
|
|
|
|
static CPU_INT32U USBH_HID_RxData (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err);
|
|
|
|
static USBH_ERR USBH_HID_MemReadHIDDesc (USBH_HID_DEV *p_hid_dev);
|
|
|
|
static void USBH_HID_IntrRxCB (USBH_EP *p_ep,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
void *p_arg,
|
|
USBH_ERR err);
|
|
|
|
static void USBH_HID_DispatchReport (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
USBH_ERR err);
|
|
|
|
static USBH_ERR USBH_HID_ProcessReportDesc(USBH_HID_DEV *p_hid_dev);
|
|
|
|
static USBH_ERR USBH_HID_RxReportAsync (USBH_HID_DEV *p_hid_dev);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONFIGURATION ERRORS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HID CLASS DRIVER
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_CLASS_DRV USBH_HID_ClassDrv = {
|
|
(CPU_INT08U *)"HID",
|
|
USBH_HID_GlobalInit,
|
|
0,
|
|
USBH_HID_ProbeIF,
|
|
USBH_HID_Suspend,
|
|
USBH_HID_Resume,
|
|
USBH_HID_Disconn
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* GLOBAL FUNCTION
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_Init()
|
|
*
|
|
* Description : Initialize the HID device, read & parse report descriptor and create report ID list.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If device successfully initialized.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_ProcessReportDesc() : -----
|
|
* USBH_ERR_DESC_ALLOC, Failed to allocate memory for descriptor.
|
|
* USBH_ERR_HID_RD_PARSER_FAIL, Cannot parse report descriptor.
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* USBH_ERR_DESC_EXTRA_NOT_FOUND, HID descriptor not found.
|
|
* USBH_ERR_DESC_INVALID, HID descriptor contains invalid value(s).
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_CreateReportID -----
|
|
* USBH_ERR_ALLOC, if report ID cannot be allocated.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_Init (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_HID_ProcessReportDesc(p_hid_dev); /* Read and parse report desc. */
|
|
if (err == USBH_ERR_NONE) {
|
|
err = USBH_HID_CreateReportID(p_hid_dev); /* Create report ID list. */
|
|
|
|
if (err == USBH_ERR_NONE) {
|
|
p_hid_dev->MaxReportPtr = USBH_HID_MaxReport(p_hid_dev, USBH_HID_MAIN_ITEM_TAG_IN);
|
|
p_hid_dev->IsInit = DEF_TRUE;
|
|
}
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RefAdd()
|
|
*
|
|
* Description : Increment the application reference count to HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If access to device is successful.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexUnlock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_RefAdd (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
p_hid_dev->AppRefCnt++;
|
|
|
|
err = USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RefRel()
|
|
*
|
|
* Description : Decrement reference count of a HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If reference release is successful.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_RefRel (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_ERR err;
|
|
LIB_ERR err_lib;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->AppRefCnt > 0) {
|
|
p_hid_dev->AppRefCnt--;
|
|
|
|
if ((p_hid_dev->AppRefCnt == 0 ) &&
|
|
(p_hid_dev->State == USBH_CLASS_DEV_STATE_DISCONN)) {
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
Mem_PoolBlkFree( &USBH_HID_DevPool, /* If no more ref on dev, release it. */
|
|
(void *)p_hid_dev,
|
|
&err_lib);
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_GetReportIDArray()
|
|
*
|
|
* Description : Returns report id structure array and number of report id structures.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* p_report_id Pointer to variable that will receive the report ID structure
|
|
* array base.
|
|
*
|
|
* p_nbr_report_id Pointer to variable that will receive the number of report ID
|
|
* structures.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If report ID array successfully retrieved.
|
|
* USBH_ERR_DEV_NOT_READY If device is not ready.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_GetReportIDArray (USBH_HID_DEV *p_hid_dev,
|
|
USBH_HID_REPORT_ID **p_report_id,
|
|
CPU_INT08U *p_nbr_report_id)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
*p_report_id = p_hid_dev->ReportID; /* Rtn report ID struct array base addr. */
|
|
*p_nbr_report_id = p_hid_dev->NbrReportID; /* Rtn nbr of report ID struct. */
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_GetAppCollArray()
|
|
*
|
|
* Description : Returns application collection structure array and number of application collection
|
|
* structures.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* p_app_coll Pointer to the application collection structure array base.
|
|
*
|
|
* p_nbr_app_coll Pointer to number of application collection structures.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If application collection array successfully retrieved.
|
|
* USBH_ERR_DEV_NOT_READY If device is not ready.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'/'p_app_coll'/
|
|
* 'p_nbr_app_coll'.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_GetAppCollArray (USBH_HID_DEV *p_hid_dev,
|
|
USBH_HID_APP_COLL **p_app_coll,
|
|
CPU_INT08U *p_nbr_app_coll)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if ((p_hid_dev == (USBH_HID_DEV *)0) ||
|
|
(p_app_coll == (USBH_HID_APP_COLL **)0) ||
|
|
(p_nbr_app_coll == (CPU_INT08U *)0)) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
*p_app_coll = p_hid_dev->AppColl; /* Return App collection structure array base address */
|
|
*p_nbr_app_coll = p_hid_dev->NbrAppColl; /* Return the number of App collection structure */
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_IsBootDev()
|
|
*
|
|
* Description : Test whether HID interface belongs to boot subclass.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function.
|
|
*
|
|
* USBH_ERR_NONE, If information retrieved successfully.
|
|
* USBH_ERR_DEV_NOT_READY If device is not ready.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Return(s) : DEF_TRUE Device belongs to boot subclass.
|
|
* DEF_FALSE Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBH_HID_IsBootDev (USBH_HID_DEV *p_hid_dev,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN is_boot;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (DEF_FALSE);
|
|
}
|
|
|
|
*p_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (DEF_FALSE);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
is_boot = (p_hid_dev->SubClass == USBH_HID_SUBCLASS_CODE_BOOT_IF) ? DEF_TRUE : DEF_FALSE;
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (is_boot);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RxReport()
|
|
*
|
|
* Description : Receive input report from device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* p_buf Pointer to buffer that will receive the report.
|
|
*
|
|
* buf_len Buffer length, in octets.
|
|
*
|
|
* timeout_ms Timeout, in milliseconds.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
* USBH_ERR_NONE, Report successfully received.
|
|
* USBH_ERR_DEV_NOT_READY, Device not ready.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_RxData() : -----
|
|
* USBH_ERR_NULL_PTR Invalid null pointer passed to 'p_buf'.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Return(s) : Number of octets received.
|
|
*
|
|
* Note(s) : 1) p_buf contains only the report data without the report id.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBH_HID_RxReport (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT08U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U xfer_len;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
return (0u);
|
|
}
|
|
|
|
xfer_len = (CPU_INT08U)USBH_HID_RxData(p_hid_dev, /* Receive input report. */
|
|
report_id,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_TxReport()
|
|
*
|
|
* Description : Send the report to the device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* p_buf Pointer to the buffer that contains the report.
|
|
*
|
|
* buf_len Buffer length, in octets.
|
|
*
|
|
* timeout_ms Timeout, in milliseconds.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
*
|
|
* USBH_ERR_NONE Report successfully transmitted.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_hid_dev'.
|
|
* USBH_ERR_DEV_NOT_READY Device is not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_TxData() : -----
|
|
* USBH_ERR_NONE Report successfully transmitted.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'buf_len'.
|
|
* USBH_ERR_NULL_PTR Invalid null pointer passed to 'p_buf'.
|
|
* USBH_ERR_CLASS_DRV_NOT_FOUND Interface is not of HID type.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_UNKNOWN Unknown error occurred.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Return(s) : Number of octets sent.
|
|
*
|
|
* Note(s) : 1) Do not add the report id to p_buf, it will be added automatically.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBH_HID_TxReport (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT08U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U xfer_len;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
return (0u);
|
|
}
|
|
|
|
xfer_len = (CPU_INT08U)USBH_HID_TxData(p_hid_dev, /* Send the output report. */
|
|
report_id,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RegRxCB()
|
|
*
|
|
* Description : Register a callback function to receive reports from device asynchronously.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* async_fnct Callback function.
|
|
*
|
|
* p_async_arg Pointer to context that will be passed to callback function.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If callback successfully registered.
|
|
* USBH_ERR_INVALID_ARG, If invalid arguemnt passed to 'async_fnct'/'p_hid_dev'.
|
|
* USBH_ERR_DEV_NOT_READY, If device is not ready.
|
|
* USBH_ERR_HID_NOT_IN_REPORT, If incorrect report descriptor provided by device.
|
|
* USBH_ERR_ALLOC, If rx callback cannot be allocated.
|
|
* USBH_ERR_HID_REPORT_ID, If callback with same report ID is already registered.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_RegRxCB (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
USBH_HID_RXCB_FNCT async_fnct,
|
|
void *p_async_arg)
|
|
{
|
|
CPU_INT08U ix;
|
|
CPU_INT32U report_len_bytes;
|
|
USBH_HID_RXCB *p_rx_cb;
|
|
USBH_ERR err;
|
|
|
|
|
|
if ((p_hid_dev == (USBH_HID_DEV *)0) ||
|
|
(async_fnct == (USBH_HID_RXCB_FNCT)0)) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
if (p_hid_dev->MaxReportPtr == (USBH_HID_REPORT_ID *)0) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_HID_NOT_IN_REPORT);
|
|
}
|
|
/* Check max buf size to recv data. */
|
|
report_len_bytes = (p_hid_dev->MaxReportPtr->Size / 8u);
|
|
if ((p_hid_dev->MaxReportPtr->Size % 8u) != 0u) {
|
|
report_len_bytes++;
|
|
}
|
|
|
|
if (report_len_bytes > USBH_HID_CFG_MAX_RX_BUF_SIZE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_ALLOC);
|
|
}
|
|
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) { /* Check already reg callback with same report id. */
|
|
|
|
if ((p_hid_dev->RxCB[ix].InUse == DEF_TRUE) &&
|
|
(p_hid_dev->RxCB[ix].ReportID == report_id)) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_HID_REPORT_ID);
|
|
}
|
|
}
|
|
|
|
p_rx_cb = (USBH_HID_RXCB *)0; /* Search for empty callback structure. */
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) {
|
|
|
|
if (p_hid_dev->RxCB[ix].InUse == DEF_FALSE) {
|
|
p_rx_cb = &p_hid_dev->RxCB[ix];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p_rx_cb == (USBH_HID_RXCB *)0) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_ALLOC);
|
|
}
|
|
/* Fill callback structure. */
|
|
p_rx_cb->ReportID = report_id;
|
|
p_rx_cb->AsyncFnct = async_fnct;
|
|
p_rx_cb->AsyncArgPtr = p_async_arg;
|
|
p_rx_cb->InUse = DEF_TRUE;
|
|
|
|
if (p_hid_dev->RxInProg == DEF_FALSE) { /* Receive Async if not started */
|
|
err = USBH_HID_RxReportAsync(p_hid_dev);
|
|
} else {
|
|
err = USBH_ERR_NONE;
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_UnregRxCB()
|
|
*
|
|
* Description : Unregisters the callback function for the given report ID.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If success
|
|
* USBH_ERR_DEV_NOT_READY If the device is not ready
|
|
* USBH_ERR_HID_REPORTID_NOT_REGISTERED If report ID is not registered
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_UnregRxCB (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id)
|
|
{
|
|
CPU_INT08U ix;
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) { /* Search and close callback structure */
|
|
|
|
if ((p_hid_dev->RxCB[ix].InUse == DEF_TRUE ) &&
|
|
(p_hid_dev->RxCB[ix].ReportID == report_id)) {
|
|
|
|
p_hid_dev->RxCB[ix].InUse = DEF_FALSE;
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (USBH_ERR_HID_REPORT_ID);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_ProtocolSet()
|
|
*
|
|
* Description : Set protocol (boot/report descriptor) of HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* protocol Protocol to set.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If protocol is successfully set.
|
|
* USBH_ERR_DEV_NOT_READY, If device is not ready.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlTx() : -----
|
|
* USBH_ERR_UNKNOWN Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : For more information on the 'Set_Protocol' request, see 'Device Class Definition for
|
|
* Human Interface Devices (HID), 6/27/01, Version 1.11, section 7.2.6'.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_ProtocolSet (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT16U protocol)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
(void)USBH_CtrlTx( p_hid_dev->DevPtr, /* Send Set protocol request. */
|
|
USBH_HID_REQ_SET_PROTOCOL,
|
|
(USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
protocol,
|
|
p_hid_dev->IfNbr,
|
|
(void *)0,
|
|
0u,
|
|
USBH_CFG_STD_REQ_TIMEOUT,
|
|
&err);
|
|
if (err == USBH_ERR_NONE) {
|
|
p_hid_dev->Boot = DEF_TRUE;
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_ProtocolGet()
|
|
*
|
|
* Description : Get protocol (boot/report) of the HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* p_protocol Variable that will receive protocol of the device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If protocol was successfully retrieved.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'.
|
|
* USBH_ERR_DEV_NOT_READY, If device is not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlRx() : -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : For more information on the 'Get_Protocol' request, see 'Device Class Definition for
|
|
* Human Interface Devices (HID), 6/27/01, Version 1.11, section 7.2.5'.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_ProtocolGet (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT16U *p_protocol)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
(void)USBH_CtrlRx( p_hid_dev->DevPtr, /* Send Get protocol request. */
|
|
USBH_HID_REQ_GET_PROTOCOL,
|
|
(USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
0u,
|
|
p_hid_dev->IfNbr,
|
|
(void *)p_protocol,
|
|
1u,
|
|
USBH_CFG_STD_REQ_TIMEOUT,
|
|
&err);
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_IdleSet()
|
|
*
|
|
* Description : Set idle state duration for a given report ID.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* dur Duration of the idle state in milliseconds.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If duration is successfully set.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_hid_dev'/'dur'.
|
|
* USBH_ERR_DEV_NOT_READY. If device is not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlTx() : -----
|
|
* USBH_ERR_UNKNOWN Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : For more information on the 'Set_Idle' request, see 'Device Class Definition for
|
|
* Human Interface Devices (HID), 6/27/01, Version 1.11, section 7.2.4'.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_HID_IdleSet (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
CPU_INT32U dur)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
if (dur > USBH_HID_MAX_DUR) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_HID_DevLock(p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
dur = dur / USBH_HID_DUR_RESOLUTION; /* Convert into resolution units. */
|
|
/* Send class-specific request. */
|
|
(void)USBH_CtrlTx( p_hid_dev->DevPtr,
|
|
USBH_HID_REQ_SET_IDLE,
|
|
(USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
(((dur << 8u) & 0xFF00u) | report_id),
|
|
p_hid_dev->IfNbr,
|
|
(void *)0,
|
|
0u,
|
|
USBH_CFG_STD_REQ_TIMEOUT,
|
|
&err);
|
|
if (err == USBH_ERR_EP_STALL) {
|
|
(void)USBH_EP_Reset( p_hid_dev->DevPtr,
|
|
(USBH_EP *)0);
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_IdleGet()
|
|
*
|
|
* Description : Get idle duration for given report ID.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
*
|
|
* USBH_ERR_NONE Idle duration successfully retrieved.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_hid_dev'.
|
|
* USBH_ERR_DEV_NOT_READY Device is not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlRx() : -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_DevLock -----
|
|
* USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Return(s) : Idle duration in milliseconds.
|
|
*
|
|
* Note(s) : For more information on the 'Get_Idle' request, see 'Device Class Definition for
|
|
* Human Interface Devices (HID), 6/27/01, Version 1.11, section 7.2.3'.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT32U USBH_HID_IdleGet (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
USBH_ERR *p_err)
|
|
{
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, dur, 1);
|
|
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
if (p_hid_dev->IsInit == DEF_FALSE) {
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
return (0u);
|
|
}
|
|
|
|
(void)USBH_CtrlRx( p_hid_dev->DevPtr, /* Send the class-specific request. */
|
|
USBH_HID_REQ_GET_IDLE,
|
|
(USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
report_id,
|
|
p_hid_dev->IfNbr,
|
|
(void *) dur,
|
|
1u,
|
|
USBH_CFG_STD_REQ_TIMEOUT,
|
|
p_err);
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
/* Convert to ms. */
|
|
return (dur[0] * USBH_HID_DUR_RESOLUTION);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_GlobalInit()
|
|
*
|
|
* Description : This function is used to initialize the global variables
|
|
*
|
|
* Argument(s) : p_err Variable that will receive the return error code from this function.
|
|
* USBH_ERR_NONE, Idle duration successfully retrieved.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_hid_dev'.
|
|
* USBH_ERR_DEV_NOT_READY, Device is not ready.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_ParserGlobalInit -----
|
|
* USBH_ERR_ALLOC, if global item or collection list allocation failed.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_GlobalInit (USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U ix;
|
|
LIB_ERR err_lib;
|
|
CPU_SIZE_T octets_reqd;
|
|
|
|
/* --------------- INIT HID DEV STRUCT ---------------- */
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_DEV; ix++) {
|
|
(void)USBH_OS_MutexCreate(&USBH_HID_DevArr[ix].HMutex); /* Mutex for protection from multiple app access. */
|
|
}
|
|
|
|
Mem_PoolCreate ( &USBH_HID_DevPool, /* POOL for managing HID dev struct. */
|
|
(void *)USBH_HID_DevArr,
|
|
sizeof(USBH_HID_DEV) * USBH_HID_CFG_MAX_DEV,
|
|
USBH_HID_CFG_MAX_DEV,
|
|
sizeof(USBH_HID_DEV),
|
|
sizeof(CPU_ALIGN),
|
|
&octets_reqd,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBH_ERR_ALLOC;
|
|
return;
|
|
}
|
|
|
|
*p_err = USBH_HID_ParserGlobalInit(); /* Init HID parser struct. */
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_ProbeIF()
|
|
*
|
|
* Description : Determine if the interface is HID class interface.
|
|
*
|
|
* Argument(s) : p_dev Pointer to USB device.
|
|
*
|
|
* p_if Pointer to interface.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
* USBH_ERR_NONE Interface is of HID type.
|
|
* USBH_ERR_DEV_ALLOC Cannot allocate HID device.
|
|
* USBH_ERR_CLASS_DRV_NOT_FOUND Interface is not of HID type.
|
|
*
|
|
* ----- RETURNED BY USBH_IF_DescGet() : -----
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'alt_ix'.
|
|
*
|
|
* ----- RETURNED BY USBH_IntrInOpen() : -----
|
|
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
|
|
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
|
|
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
|
|
* Host controller drivers error, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_IntrOutOpen() : -----
|
|
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
|
|
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
|
|
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
|
|
* Host controller drivers error, Otherwise.
|
|
*
|
|
* Return(s) : p_hid_dev, If device has a HID class interface.
|
|
* 0, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void *USBH_HID_ProbeIF (USBH_DEV *p_dev,
|
|
USBH_IF *p_if,
|
|
USBH_ERR *p_err)
|
|
{
|
|
USBH_IF_DESC p_if_desc;
|
|
USBH_HID_DEV *p_hid_dev;
|
|
LIB_ERR err_lib;
|
|
|
|
|
|
*p_err = USBH_IF_DescGet(p_if, 0u, &p_if_desc); /* Get IF desc from IF. */
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return ((void *)0);
|
|
}
|
|
/* Check for HID class code. */
|
|
if (p_if_desc.bInterfaceClass == USBH_CLASS_CODE_HID){
|
|
/* Alloc a dev from HID dev pool. */
|
|
p_hid_dev = (USBH_HID_DEV *)Mem_PoolBlkGet( &USBH_HID_DevPool,
|
|
(CPU_SIZE_T)sizeof(USBH_HID_DEV),
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBH_ERR_DEV_ALLOC;
|
|
return ((void *)0);
|
|
}
|
|
|
|
USBH_HID_DevClr(p_hid_dev);
|
|
p_hid_dev->State = USBH_CLASS_DEV_STATE_CONN;
|
|
p_hid_dev->RxInProg = DEF_FALSE;
|
|
p_hid_dev->IsInit = DEF_FALSE;
|
|
p_hid_dev->DevPtr = p_dev;
|
|
p_hid_dev->IfPtr = p_if;
|
|
p_hid_dev->IfNbr = p_if_desc.bInterfaceNumber;
|
|
p_hid_dev->SubClass = p_if_desc.bInterfaceSubClass;
|
|
p_hid_dev->Protocol = p_if_desc.bInterfaceProtocol;
|
|
|
|
*p_err = USBH_IntrInOpen(p_hid_dev->DevPtr, /* Open intr IN EP. */
|
|
p_hid_dev->IfPtr,
|
|
&p_hid_dev->IntrInEP);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
Mem_PoolBlkFree( &USBH_HID_DevPool,
|
|
(void *)p_hid_dev,
|
|
&err_lib);
|
|
return ((void *)0);
|
|
}
|
|
|
|
*p_err = USBH_IntrOutOpen(p_hid_dev->DevPtr, /* Try to open optional intr OUT EP. */
|
|
p_hid_dev->IfPtr,
|
|
&p_hid_dev->IntrOutEP);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
p_hid_dev->IsOutEP_Present = DEF_FALSE;
|
|
*p_err = USBH_ERR_NONE;
|
|
} else {
|
|
p_hid_dev->IsOutEP_Present = DEF_TRUE;
|
|
}
|
|
} else {
|
|
p_hid_dev = (USBH_HID_DEV *)0;
|
|
*p_err = USBH_ERR_CLASS_DRV_NOT_FOUND;
|
|
}
|
|
|
|
return ((void *)p_hid_dev);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_Disconn()
|
|
*
|
|
* Description : Handle disconnection of HID device.
|
|
*
|
|
* Argument(s) : p_class_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_Disconn (void *p_class_dev)
|
|
{
|
|
LIB_ERR err_lib;
|
|
USBH_HID_DEV *p_hid_dev;
|
|
|
|
|
|
p_hid_dev = (USBH_HID_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
|
|
p_hid_dev->State = USBH_CLASS_DEV_STATE_DISCONN;
|
|
|
|
/* -------------------- CLOSE EPS --------------------- */
|
|
USBH_EP_Close(&p_hid_dev->IntrInEP);
|
|
|
|
if (p_hid_dev->IsOutEP_Present == DEF_TRUE) {
|
|
USBH_EP_Close(&p_hid_dev->IntrOutEP);
|
|
}
|
|
|
|
if (p_hid_dev->AppRefCnt == 0u) { /* Release HID dev if app reference count is zero. */
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
Mem_PoolBlkFree( &USBH_HID_DevPool, /* App refcnt is 0 and Dev is removed, release HID dev. */
|
|
(void *)p_hid_dev,
|
|
&err_lib);
|
|
return;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_Suspend()
|
|
*
|
|
* Description : Suspend HID device, waits for completion of any pending I/O.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_Suspend (void *p_class_dev)
|
|
{
|
|
USBH_HID_DEV *p_hid_dev;
|
|
|
|
|
|
p_hid_dev = (USBH_HID_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
|
|
p_hid_dev->State = USBH_CLASS_DEV_STATE_SUSPEND;
|
|
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_Resume()
|
|
*
|
|
* Description : Resume HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_Resume (void *p_class_dev)
|
|
{
|
|
USBH_HID_DEV *p_hid_dev;
|
|
|
|
|
|
p_hid_dev = (USBH_HID_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
|
|
p_hid_dev->State = USBH_CLASS_DEV_STATE_CONN;
|
|
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_DevClr()
|
|
*
|
|
* Description : Clear HID device structure.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_DevClr (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_HMUTEX h_mutex;
|
|
|
|
|
|
h_mutex = p_hid_dev->HMutex; /* Save mutex var. */
|
|
|
|
Mem_Clr((void *)p_hid_dev, sizeof(USBH_HID_DEV));
|
|
|
|
p_hid_dev->State = USBH_CLASS_DEV_STATE_NONE;
|
|
p_hid_dev->HMutex = h_mutex; /* Restore mutex var. */
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_DevLock()
|
|
*
|
|
* Description : Lock HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If HID device successfully locked.
|
|
* USBH_ERR_DEV_NOT_READY, If HID device not ready.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_HID_DevLock (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
CPU_INT08U state;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
state = p_hid_dev->State;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (state != USBH_CLASS_DEV_STATE_CONN) {
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
(void)USBH_OS_MutexLock(p_hid_dev->HMutex);
|
|
if (p_hid_dev->State != USBH_CLASS_DEV_STATE_CONN) {
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
return (USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
|
|
return (USBH_ERR_NONE);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_DevUnlock()
|
|
*
|
|
* Description : Unlock HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_DevUnlock (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
(void)USBH_OS_MutexUnlock(p_hid_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_TxData()
|
|
*
|
|
* Description : Send data (report) to HID device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report Id.
|
|
*
|
|
* p_buf Pointer to buffer that contains the report.
|
|
*
|
|
* buf_len Buffer length, in octets.
|
|
*
|
|
* timeout_ms Timeout, in milliseconds.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
*
|
|
* USBH_ERR_NONE Report successfully transmitted.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'buf_len'.
|
|
* USBH_ERR_NULL_PTR Invalid null pointer passed to 'p_buf'.
|
|
* USBH_ERR_CLASS_DRV_NOT_FOUND Interface is not of HID type.
|
|
*
|
|
* ----- RETURNED BY USBH_IntrTx() : -----
|
|
* USBH_ERR_NONE Interrupt transfer successfully transmitted.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_NONE, URB is successfully submitted to host controller.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlTx() : -----
|
|
* USBH_ERR_UNKNOWN Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets sent.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_HID_TxData (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
if ((p_buf == (void *)0 ) ||
|
|
(buf_len == 0u)) {
|
|
*p_err = USBH_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
/* Use optional intr OUT EP if available. */
|
|
if (p_hid_dev->IsOutEP_Present == DEF_TRUE) {
|
|
|
|
if (report_id != 0u) { /* Copy report id and buf if report is non zero. */
|
|
|
|
if (buf_len > USBH_HID_CFG_MAX_TX_BUF_SIZE) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
p_hid_dev->TxBuf[0] = report_id; /* First byte should be report id. */
|
|
Mem_Copy((void *)&p_hid_dev->TxBuf[1],
|
|
p_buf,
|
|
buf_len);
|
|
|
|
xfer_len = USBH_IntrTx(&p_hid_dev->IntrOutEP,
|
|
p_hid_dev->TxBuf,
|
|
buf_len + 1u,
|
|
timeout_ms,
|
|
p_err);
|
|
if ((*p_err == USBH_ERR_NONE) &&
|
|
( xfer_len != 0u )) {
|
|
xfer_len--;
|
|
}
|
|
} else {
|
|
xfer_len = USBH_IntrTx(&p_hid_dev->IntrOutEP,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
}
|
|
} else {
|
|
/* Send report via ctrl EP if intr OUT not available. */
|
|
xfer_len = USBH_CtrlTx(p_hid_dev->DevPtr,
|
|
USBH_HID_REQ_SET_REPORT,
|
|
(USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
(((USBH_HID_REPORT_TYPE_OUT << 8u) & 0xFF00u) | report_id),
|
|
p_hid_dev->IfNbr,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
}
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RxData()
|
|
*
|
|
* Description : Receive data (report) from device.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* report_id Report id.
|
|
*
|
|
* p_buf Pointer to buffer that will receive the report.
|
|
*
|
|
* buf_len Buffer length, in octets.
|
|
*
|
|
* timeout_ms Timeout, in milliseconds.
|
|
*
|
|
* p_err Variable that will receive the return error code from this function.
|
|
*
|
|
* USBH_ERR_NONE Report successfully received.
|
|
* USBH_ERR_NULL_PTR Invalid null pointer passed to 'p_buf'.
|
|
*
|
|
* ----- RETURNED BY USBH_IntrRx() : -----
|
|
* USBH_ERR_NONE Interrupt transfer successfully received.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_NONE, URB is successfully submitted to host controller.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlRx() : -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets received.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_HID_RxData (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U report_id,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT16U timeout_ms,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
if ((p_buf == (void *)0 ) ||
|
|
(buf_len == 0u)) {
|
|
*p_err = USBH_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
|
|
if ((report_id != 0u) || /* If report ID 0 specified or intr IN EP busy, use ... */
|
|
(p_hid_dev->RxInProg == DEF_TRUE)) { /* ... ctrl EP. */
|
|
xfer_len = USBH_CtrlRx(p_hid_dev->DevPtr,
|
|
USBH_HID_REQ_GET_REPORT,
|
|
(USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
(((USBH_HID_REPORT_TYPE_IN << 8u) & 0xFF00u) | report_id),
|
|
p_hid_dev->IfNbr,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
} else { /* Rcv report on intr IN EP. */
|
|
xfer_len = USBH_IntrRx(&p_hid_dev->IntrInEP,
|
|
p_buf,
|
|
buf_len,
|
|
timeout_ms,
|
|
p_err);
|
|
}
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_MemReadHIDDesc()
|
|
*
|
|
* Description : Retrieve and parse HID descriptor.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, HID descriptor successfully retrieved and parsed.
|
|
* USBH_ERR_DESC_EXTRA_NOT_FOUND, HID descriptor not found.
|
|
* USBH_ERR_DESC_INVALID, HID descriptor contains invalid value(s).
|
|
*
|
|
* Note(s) : (1) The HID descriptor must have at least report descriptor type/length pair.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_HID_MemReadHIDDesc (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_HID_DESC *p_hid_desc;
|
|
CPU_INT08U *p_mem;
|
|
CPU_INT08U len;
|
|
CPU_INT08U b_type;
|
|
CPU_INT16U tot_len;
|
|
CPU_INT16U w_len;
|
|
|
|
|
|
/* Get HID desc from extra desc. */
|
|
p_mem = (CPU_INT08U *)USBH_IF_ExtraDescGet(p_hid_dev->IfPtr,
|
|
0u,
|
|
&tot_len);
|
|
if (p_mem == (CPU_INT08U *)0) {
|
|
return (USBH_ERR_DESC_EXTRA_NOT_FOUND);
|
|
}
|
|
|
|
p_hid_desc = &p_hid_dev->Desc;
|
|
|
|
p_hid_desc->bLength = MEM_VAL_GET_INT08U_LITTLE((void *)p_mem);/* Get desc len. */
|
|
len = p_hid_desc->bLength;
|
|
if (len < USBH_HID_LEN_HID_DESC) { /* Chk len. */
|
|
return (USBH_ERR_DESC_INVALID);
|
|
}
|
|
p_mem += sizeof(CPU_INT08U);
|
|
len -= sizeof(CPU_INT08U);
|
|
/* Get desc type. */
|
|
p_hid_desc->bDescriptorType = MEM_VAL_GET_INT08U_LITTLE((void *)p_mem);
|
|
if (p_hid_desc->bDescriptorType != USBH_HID_DESC_TYPE_HID) {/* Type should be USBH_HID_DESC_TYPE_HID. */
|
|
return (USBH_ERR_DESC_INVALID);
|
|
}
|
|
p_mem += sizeof(CPU_INT08U);
|
|
len -= sizeof(CPU_INT08U);
|
|
/* -------------------- GET bcdHID -------------------- */
|
|
p_hid_desc->bcdHID = MEM_VAL_GET_INT16U_LITTLE((void *)p_mem);
|
|
p_mem += sizeof(CPU_INT16U);
|
|
len -= sizeof(CPU_INT16U);
|
|
/* ----------------- GET COUNTRY CODE ----------------- */
|
|
p_hid_desc->bCountryCode = MEM_VAL_GET_INT08U_LITTLE((void *)p_mem);
|
|
p_mem += sizeof(CPU_INT08U);
|
|
len -= sizeof(CPU_INT08U);
|
|
/* -------------- GET NBR OF CLASS DESC --------------- */
|
|
p_hid_desc->bNbrDescriptors = MEM_VAL_GET_INT08U_LITTLE((void *)p_mem);
|
|
p_mem += sizeof(CPU_INT08U);
|
|
len -= sizeof(CPU_INT08U);
|
|
|
|
if (p_hid_desc->bNbrDescriptors < 1u) { /* Nbr of desc should be at least one. */
|
|
return (USBH_ERR_DESC_INVALID);
|
|
}
|
|
/* ----------------- GET REPORT DESC ------------------ */
|
|
while (len > 0) {
|
|
b_type = MEM_VAL_GET_INT08U_LITTLE((void *)p_mem);
|
|
p_mem += sizeof(CPU_INT08U);
|
|
len -= sizeof(CPU_INT08U);
|
|
|
|
w_len = MEM_VAL_GET_INT16U_LITTLE((void *)p_mem);
|
|
p_mem += sizeof(CPU_INT16U);
|
|
len -= sizeof(CPU_INT16U);
|
|
/* If this is a report desc ... */
|
|
if ((b_type == USBH_HID_DESC_TYPE_REPORT) &&
|
|
(w_len > 0u )) {
|
|
p_hid_desc->bDescriptorType = b_type;
|
|
p_hid_desc->wClassDescriptorLength = w_len;
|
|
return (USBH_ERR_NONE); /* ... assign len & rtn. */
|
|
}
|
|
}
|
|
|
|
return (USBH_ERR_DESC_EXTRA_NOT_FOUND);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_IntrRxCB()
|
|
*
|
|
* Description : Interrupt callback funtion :
|
|
* (1) Check transfer status.
|
|
* (2) Dispatch report.
|
|
*
|
|
* Argument(s) : p_ep Pointer to endpoint.
|
|
*
|
|
* p_buf Pointer to receive buffer.
|
|
*
|
|
* buf_len Length of received buffer in octets.
|
|
*
|
|
* xfer_len Number of octets received.
|
|
*
|
|
* p_arg Context variable.
|
|
*
|
|
* err Receive status.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) The bInterval period associated to periodic transfer can be managed by hardware
|
|
* (i.e. host controller) or by sofware (i.e. host stack).
|
|
*
|
|
* (a) Hardware: host controller will emit the periodic IN request every bInterval
|
|
* written into a register. Essentially, a list-based host controller will use this
|
|
* method (e.g. OHCI host controller).
|
|
*
|
|
* (b) Software: host controller doesn't provide a hardware management of the bInterval
|
|
* period. In this case, the stack will wait bInterval frame before re-submiting an
|
|
* IN request.
|
|
*
|
|
* (2) If endpoint has no interrupt data to transmit when accessed by the host, it
|
|
* responds with NAK. Next polling from the Host will take place at the next period
|
|
* (i.e. bInterval of the endpoint).
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_IntrRxCB (USBH_EP *p_ep,
|
|
void *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
void *p_arg,
|
|
USBH_ERR err)
|
|
{
|
|
USBH_ERR temp_err;
|
|
USBH_HID_DEV *p_hid_dev;
|
|
USBH_ERR lock_err;
|
|
CPU_INT08U state;
|
|
CPU_INT08U ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)p_ep;
|
|
|
|
p_hid_dev = (USBH_HID_DEV *)p_arg; /* Get HID dev. */
|
|
|
|
if (p_hid_dev == (USBH_HID_DEV *)0) {
|
|
return;
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
state = p_hid_dev->State;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (state != USBH_CLASS_DEV_STATE_CONN) {
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) { /* Notify all callback about state. */
|
|
|
|
if (p_hid_dev->RxCB[ix].InUse == DEF_TRUE) {
|
|
p_hid_dev->RxCB[ix].AsyncFnct((void *)p_hid_dev->RxCB[ix].AsyncArgPtr,
|
|
(void *)0,
|
|
0u,
|
|
USBH_ERR_DEV_NOT_READY);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
switch (err) {
|
|
case USBH_ERR_EP_NACK: /* NAK is not an error. Device has just no valid data */
|
|
err = USBH_ERR_NONE;
|
|
temp_err = USBH_ERR_EP_NACK;
|
|
case USBH_ERR_NONE:
|
|
p_hid_dev->ErrCnt = 0u;
|
|
break;
|
|
|
|
case USBH_ERR_EP_INVALID_STATE:
|
|
case USBH_ERR_HC_IO:
|
|
case USBH_ERR_EP_STALL:
|
|
USBH_EP_Reset(p_ep->DevPtr, p_ep);
|
|
p_hid_dev->ErrCnt++;
|
|
break;
|
|
|
|
case USBH_ERR_URB_ABORT:
|
|
default:
|
|
p_hid_dev->ErrCnt = USBH_HID_CFG_MAX_ERR_CNT;
|
|
break;
|
|
}
|
|
/* Dispatch data and err to app. */
|
|
USBH_HID_DispatchReport(p_hid_dev,
|
|
p_buf,
|
|
buf_len,
|
|
xfer_len,
|
|
err);
|
|
|
|
lock_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (lock_err != USBH_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
if (p_hid_dev->ErrCnt < USBH_HID_CFG_MAX_ERR_CNT) { /* If err cnt > MAX, do not resubmit. */
|
|
|
|
if(((p_hid_dev->DevPtr->DevSpd == USBH_DEV_SPD_LOW ) ||
|
|
(p_hid_dev->DevPtr->DevSpd == USBH_DEV_SPD_FULL))
|
|
&& (temp_err == USBH_ERR_EP_NACK)) { /* See Note #1. */
|
|
|
|
USBH_OS_DlyMS(p_hid_dev->IntrInEP.Desc.bInterval); /* Wait bInterval period associated to IN endpoint */
|
|
/* before resubmitting xfer. See Note #2. */
|
|
}
|
|
|
|
USBH_HID_RxReportAsync(p_hid_dev); /* Resubmit xfer if dev is in operational state. */
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_DispatchReport()
|
|
*
|
|
* Description : Dispatch reports received asynchronously from device:
|
|
* (1) Identify report ID.
|
|
* (2) Find callback for report ID.
|
|
* (3) Invoke callback.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* p_buf Pointer to buffer containing.
|
|
*
|
|
* buf_len Length of report buffer in octets.
|
|
*
|
|
* xfer_len Number of octets received.
|
|
*
|
|
* p_arg Context variable.
|
|
*
|
|
* err Receive status.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_HID_DispatchReport (USBH_HID_DEV *p_hid_dev,
|
|
CPU_INT08U *p_buf,
|
|
CPU_INT32U buf_len,
|
|
CPU_INT32U xfer_len,
|
|
USBH_ERR err)
|
|
{
|
|
CPU_INT08U report_id;
|
|
CPU_INT08U ix;
|
|
void *p_arg;
|
|
USBH_ERR lock_err;
|
|
USBH_HID_RXCB_FNCT fnct;
|
|
|
|
|
|
(void)buf_len;
|
|
|
|
lock_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (lock_err != USBH_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
if (err != USBH_ERR_NONE) {
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) { /* Notify all reg's callback of err. */
|
|
|
|
if (p_hid_dev->RxCB[ix].InUse == DEF_TRUE) {
|
|
p_arg = p_hid_dev->RxCB[ix].AsyncArgPtr;
|
|
fnct = p_hid_dev->RxCB[ix].AsyncFnct;
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev); /* Unlock dev before invoking callback. */
|
|
|
|
fnct( p_arg,
|
|
(void *)0,
|
|
0u,
|
|
err);
|
|
|
|
lock_err = USBH_HID_DevLock(p_hid_dev);
|
|
if (lock_err != USBH_ERR_NONE) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return;
|
|
}
|
|
|
|
if (xfer_len == 0u) { /* Nothing to dispatch. */
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
return;
|
|
}
|
|
|
|
if (p_hid_dev->Boot == DEF_TRUE) { /* If boot dev, report ID is 0. */
|
|
report_id = 0u;
|
|
} else {
|
|
if (p_hid_dev->ReportID[0].ReportID == 0u) { /* If first report ID is 0, there is no report ID. */
|
|
report_id = 0u;
|
|
} else { /* Otherwise, report ID is first byte of buf. */
|
|
report_id = p_buf[0];
|
|
}
|
|
}
|
|
/* Find callback with same report ID. */
|
|
for (ix = 0u; ix < USBH_HID_CFG_MAX_NBR_RXCB; ix++) {
|
|
if ((p_hid_dev->RxCB[ix].InUse == DEF_TRUE ) &&
|
|
(p_hid_dev->RxCB[ix].ReportID == report_id)) {
|
|
|
|
p_arg = p_hid_dev->RxCB[ix].AsyncArgPtr;
|
|
fnct = p_hid_dev->RxCB[ix].AsyncFnct;
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev); /* Unlock dev before invoking callback. */
|
|
|
|
if (report_id != 0u) {
|
|
fnct( p_arg,
|
|
(void *)&p_buf[1],
|
|
xfer_len - 1u,
|
|
err);
|
|
} else {
|
|
fnct( p_arg,
|
|
(void *)&p_buf[0],
|
|
xfer_len,
|
|
err);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
USBH_HID_DevUnlock(p_hid_dev);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_ProcessReportDesc()
|
|
*
|
|
* Description : Read and parse report descriptor.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, Report descriptor successfully processed.
|
|
* USBH_ERR_DESC_ALLOC, Failed to allocate memory for descriptor.
|
|
* USBH_ERR_HID_RD_PARSER_FAIL, Cannot parse report descriptor.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlRx() : -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_HID_MemReadHIDDesc() : -----
|
|
* USBH_ERR_DESC_EXTRA_NOT_FOUND, HID descriptor not found.
|
|
* USBH_ERR_DESC_INVALID, HID descriptor contains invalid value(s).
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_HID_ProcessReportDesc (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
CPU_INT32U len;
|
|
USBH_ERR err;
|
|
|
|
|
|
err = USBH_HID_MemReadHIDDesc(p_hid_dev); /* Read HID desc. */
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_hid_dev->Desc.wClassDescriptorLength > USBH_HID_CFG_MAX_REPORT_DESC_LEN) {
|
|
return (USBH_ERR_DESC_ALLOC);
|
|
}
|
|
|
|
len = USBH_CtrlRx( p_hid_dev->DevPtr, /* Read report desc. */
|
|
USBH_REQ_GET_DESC,
|
|
(USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_STD | USBH_REQ_RECIPIENT_IF),
|
|
((USBH_HID_DESC_TYPE_REPORT << 8u) & 0xFF00u),
|
|
p_hid_dev->IfNbr,
|
|
(void *)&p_hid_dev->ReportDesc,
|
|
p_hid_dev->Desc.wClassDescriptorLength,
|
|
USBH_CFG_STD_REQ_TIMEOUT,
|
|
&err);
|
|
|
|
if ((err == USBH_ERR_NONE ) &&
|
|
(len == p_hid_dev->Desc.wClassDescriptorLength)) {
|
|
|
|
err = USBH_HID_ItemParser(p_hid_dev, /* Parse report desc. */
|
|
p_hid_dev->ReportDesc,
|
|
len);
|
|
if (err != USBH_ERR_NONE) {
|
|
err = USBH_ERR_HID_RD_PARSER_FAIL;
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_HID_RxReportAsync()
|
|
*
|
|
* Description : Read report on interrupt in endpoint.
|
|
*
|
|
* Argument(s) : p_hid_dev Pointer to HID device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if read request successfully transmitted.
|
|
*
|
|
* ----- RETURNED BY USBH_IntrRxAsync() : -----
|
|
* USBH_ERR_NONE If request is successfully submitted.
|
|
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE If endpoint type is not interrupt or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE If endpoint is not opened.
|
|
* USBH_ERR_ALLOC If URB cannot be allocated.
|
|
* USBH_ERR_UNKNOWN If unknown error occured.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_HID_RxReportAsync (USBH_HID_DEV *p_hid_dev)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_INT08U len;
|
|
|
|
|
|
len = p_hid_dev->MaxReportPtr->Size / 8u;
|
|
if (p_hid_dev->MaxReportPtr->ReportID != 0u) {
|
|
len++;
|
|
}
|
|
/* Start receiving in data. */
|
|
err = USBH_IntrRxAsync( &p_hid_dev->IntrInEP,
|
|
(void *)p_hid_dev->RxBuf,
|
|
len,
|
|
USBH_HID_IntrRxCB,
|
|
(void *)p_hid_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
p_hid_dev->RxInProg = DEF_FALSE;
|
|
USBH_PRINT_ERR(err);
|
|
} else {
|
|
p_hid_dev->RxInProg = DEF_TRUE;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* END
|
|
*********************************************************************************************************
|
|
*/
|