USB固件开发(HID设备)

USB 专栏收录该内容
2 篇文章 0 订阅

转: http://blog.csdn.net/kevinyujm/archive/2010/03/26/5420541.aspx

 

USB 固件开发( HID 设备)

 

1. HID 设备的识别

HID 设备类除了有文档第一部分所述的一些标准描述符(包括设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符)外,还有自己的类专有描述符:

HID 描述符

报告描述符

物理描述符

正确实现 HID 设备类专用描述符是主机成功识别 HID 设备的关键。 HID 描述符和报告描述符是必须要使用的,物理描述符一般不被使用。

 

1.1 HID 描述符

HID 描述符跟接口描述符、端点描述符类似,也是随配置信息一起返回给主机的,主机并不会单独发出请求来读取它。 HID 描述符在配置信息中的位置是紧接接口描述符。例如:

 

_Config_Descriptor:

    .dw   _Config_Descriptor_End-_Config_Descriptor    //bLength: 0x09 byte

    .dw    0x02             //bDescriptorType: CONFIGURATION

    .dw    _Config_Descriptor_Total-_Config_Descriptor  //wTotalLength:

    .dw     0x00

    .dw    0x01               //bNumInterfaces: 1 interfaces

    .dw    0x01               //bConfigurationValue: configuration 1

    .dw    0x00               //iConfiguration: index of string

    .dw    0xC0            //bmAttributes: self powered, Not Support Remote-Wakeup

    .dw    0x32              //MaxPower: 100 mA

_Config_Descriptor_End:

 

_HID_Interface_Descriptor:

        //Interface 1 (0x09 byte)

     .dw   0x09                   //bLength: 0x09 byte

     .dw   0x04                   //bDescriptorType: INTERFACE

     .dw   0x01                   //bInterfaceNumber: interface 0

     .dw   0x00                   //bAlternateSetting: alternate setting 0

     .dw   0x01                   //bNumEndpoints: 1 endpoints(EP1)

     .dw   0x03                   //bInterfaceClass: 人机接口设备( HID )类

     .dw   0xff                            //bInterfaceSubClass: 供应商定义

     .dw   0xff                    //bInterfaceProtocol 使用的协议:供应商定义

     .dw   0x00                   //iInterface: index of string

_HID_Interface_Descriptor_End:

 

_HID_Descriptor:

     .dw   0x09                   //bLength: 0x09 byte

     .dw   0x21                   //bDescriptorType: HID 描述符类型编号

     .dw   0x01, 0x10               //HID 类协议版本号,为 1.1

     .dw   0x21                   // 固件的国家地区代号, 0x21 为美国

     .dw   0x01                   // 下级描述符的数量

     .dw   0x22                   // 下级描述符为报告描述符

     .dw   _ReportDescriptor_End-_ReportDescriptor, 0x00  // 下级描述符的长度

_HID_Descriptor_End:

 

_Endpoint3:

     .dw   0x07                   //bLength: 0x07 byte

     .dw   0x05                   //bDescriptorType: ENDPOINT

     .dw   0x83                    //bEndpointAddress: IN endpoint 3

     .dw   0x03                   //bmAttributes: Interrupt

     .dw   0x02, 0x00               //wMaxPacketSize: 2 byte

     .dw   0x0A                   //bInterval: polling interval is 10 ms

_Config_Descriptor_Total:

 

HID 描述符其实是为了提供下级描述符(如报告描述符)的信息。

 

下图更清楚地表述了各描述符之间的层次关系。

 

1.2 报告描述符

要解释报告描述符,首先得清楚什么是“报告”。“报告”是主机和 HID 设 备之间进行数据交换的最小单位。也就是说,在主机完成对设备的识别之后,在具体应用上的数据交换就得以“报告”的方式进行。“报告”的类型有三种:输入报 告、输出报告和特征报告。输入报告就是设备发给主机的报告,而输出报告就是主机发给设备的报告,特征报告是主机发给设备的报告,特征报告常在自定义 HID 设备中被用作主机向设备发送自定义数据。


报告描述符,顾名思义就是描述“报告”格式的,这个格式使主机和设备能遵循着同一个规则来解释一个报告中所含有的数据。与 HID 描述符不同,主机会发出单独的请求来读取报告描述符。关于报告描述符的组成, HID 设备类定义文档中明确指出,一个报告描述符必须包含但不仅限于以下数据项:

输入(输出或特征)

用法(也可用“用法最小值与最大值”来定义一连串用法)

用法页

逻辑最小值

逻辑最大值

报告大小

报告计数

 

报告描述符看起来比较复杂,无论是 HID 设 备类定义文档,还是其他参考书籍,都会花较大的篇幅来阐述它。要把它完全理解是需要一点时间的,而且就算是理解了也不一定能写出“像样”的报告描述符来。 学习总有一个过程,入门才是最重要的,只要入了门,后面的事情就会慢慢变得简单,无需在一开始的时候就面面俱到。所以这里只对上面提到的必需的数据项进行 解释及举例说明。

 

输入项(输出或特征)指明了报告的类型,其中隐含了报告的传输方向以及报告数据所具有的数学特性。


用 法和用法页一起指明了数据项的用法,每个数据项都必须指明用法,否则主机端不能成功解析报告描述符。用法页是全局的,修饰列于其后的所有数据项,直到出现 新的用法页为止;用法则是局部数据项,局部数据项只修饰列于其后的第一个主数据项内的数据项,一旦出现新的主数据项,那么用法必须重新指定。这其中隐含的 意思是,每个主数据项前面都必须有修饰它的用法与用法页组合。(“用法”表示的是一个单独的用法,而“用法最小值”和“用法最大值”可以替代“用法”,代 表某个范围的用法。)


逻辑最小值和逻辑最大值指明了报告所使用的数据值的范围,这个数据值是以逻辑单位为基础的,与报告大小有着对应关系。


报告大小指明数据项的位数。报告计数指明有多少个这样的数据项。


例如,定义以下数据项:

逻辑最小值( 0

逻辑最大值( 0x7f

报告大小( 8

那么它的意思就是,此报告中数据字段的大小是 8 位,本身可以表示 0~255 之间的任何数,但是逻辑值的范围被定义在 0~127 之间,所以实际上数据字段的数据不能超过 127 ,否则视为无效报告。


再举一个例子:

逻辑最小值( 0

逻辑最大值( 3

报告大小( 2

这个例子的意思是,此报告中数据字段的大小是 2 位,逻辑值范围是 0~3 ,那么数据字段的值与逻辑值是一一对应且相等的,即 0 00b ), 1 01b ), 2 10b ), 3 11b )。


第三个例子:

再举一个例子:

逻辑最小值( -1

逻辑最大值( 1

报告大小( 2

这个例子的意思是,此报告中数据字段的大小是 3 位,逻辑值范围是 -1~1 ,那么数据字段的值与逻辑值是按左对齐的方式部分对应的,即数据字段值 0 00b )对应逻辑值 -1 ,数据字段值 1 01b )对应逻辑值 0 ,数据字段值 2 10b )对应逻辑值 1 ,数据字段值 3 11b )无效。

 

这里举一个 HID 自定义设备的报告描述符的例子,这个例子比鼠标和键盘更简单。更具体的内容,譬如常用的鼠标和键盘,可以参看官方文档 Device Class Definition for Human Interface Devices(HID).pdf HID Usage Tables.pdf

 

_ReportDescriptor:               // 报告描述符

       .dw 0x06,  0x00, 0xff  // 用法页,供应商自定义,修饰其下所有的主项

    .dw 0x09,  0x01     // 用法 ( 供应商用法 1) ,局部项,只修饰下面的“集合”主项。

    .dw 0xa1,  0x01       // 集合开始,主项

    .dw 0x85,  0x1          // 报告 ID(1) ,全局项,可以修饰其下所有的主项,但是在这个报告描述中由于后面出现了新的报告 ID ,所以它只是修饰下面的“输入”主项。

    .dw  0x9,  0x1       // 用法 ( 供应商用法 1)  

    .dw 0x15,  0x0       // 逻辑最小值 (0) ,全局项,修饰下面所有的主项

     .dw 0x26,  0xff, 0x0   // 逻辑最大值 (255) ,全局项,修饰下面所有的主项

     .dw 0x75,  0x8       // 报告大小 (8) ,全局项,修饰下面所有的主项

    .dw 0x95,  0x7         // 报告计数 (7) ,全局项,修饰下面所有的主项

    .dw  0x81,  0x6       // 输入(数据,变量,相对值),主项,说明此报告的属性

   

       // 下面开始一个新的主项目,前面提到的全局项仍对这个主项目有效,譬如报告大小等

    .dw 0x09,  0x01     // 用法 ( 供应商用法 1) ,局部项,修饰下面的“特征”   主项

    .dw 0x85,  0x03          // 报告 ID 3 ),全局项,之前的报告 ID 项失效

    .dw 0xb1, 0x6                     // 特征(数据,变量,相对值)

 

       // 下面开始一个新的主项目,前面提到的全局项仍对这个主项目有效,譬如报告大小等

       .dw 0x09,  0x01     // 用法 ( 供应商用法 1) ,局部项,修饰下面的“特征”   主项

    .dw 0x85,  0x02          // 报告 ID 2 ),全局项,之前的报告 ID 项失效

    .dw 0xb1,  0x06          // 特征(数据,变量,相对值)

   

       // 下面开始一个新的主项目,前面提到的全局项仍对这个主项目有效,譬如报告大小等

    .dw 0x09,  0x01     // 用法 ( 供应商用法 1) ,局部项,修饰下面的“输出”   主项

    .dw 0x85,  0x04          // 报告 ID 4 ),全局项,之前的报告 ID 项失效

    .dw 0x91, 0x6                     // 输出(数据,变量,相对值)

    .dw  0xc0            // 结合结束

_ReportDescriptor_End:

 

以上描述符定义了 4 个不同的报告,用报告 ID 区分。 HID 设备定义文档上有讲,在一个报告 ID 之后而在下一个报告 ID 之前范围内的所有数据项都属于一个报告,发送报告时会把报告 ID 附在这个报告的前面义区分报告。

 

4. Windows HID 编程接口

一般使用 WriteFile HidD_SetFeature 来向设备发送数据(报告),使用 ReadFile 来读取设备发过来的数据(报告)。详情可以参考本blog的另一文章Windows主机端与自定义USB HID设备通信详解

  • 1
    点赞
  • 0
    评论
  • 2
    收藏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
HID 设备类读写 #include //! Defines the maximum length of a serial number #define SERNUM_LEN 40 //! Defines the maximum number of physical devices #define MAX_PHYS_DEVICES 6 //! \name HID Device return codes //! @{ // //! HID action/transfer was successful #define HID_DEVICE_SUCCESS 0x00 //! HID device was not found #define HID_DEVICE_NOT_FOUND 0x01 //! HID device is not opened #define HID_DEVICE_NOT_OPENED 0x02 //! HID device is allready opened #define HID_DEVICE_ALREADY_OPENED 0x03 //! Timeout occurs during transfer #define HID_DEVICE_TRANSFER_TIMEOUT 0x04 //! HID transfer failed #define HID_DEVICE_TRANSFER_FAILED 0x05 //! Invalid handle #define HID_DEVICE_HANDLE_ERROR 0x06 //! Unknown error #define HID_DEVICE_UNKNOWN_ERROR 0xFF //! @} // Enabled only when debugging HID connection issues //#define DEBUG_MODE //****************************************************************************** // //! \brief Device information structure. // //****************************************************************************** struct strHidDevice{ //! Handle for hid device HANDLE hndHidDevice; //! Indicator if device is opened BOOL bDeviceOpen; //! Timeout for GetReport requests UINT uGetReportTimeout; //! Timeout for SetReport requests UINT uSetReportTimeout; //! Asynchronous I/O structure OVERLAPPED oRead; //! Asynchronous I/O structure OVERLAPPED oWrite; //! Maximum length of InReport's WORD wInReportBufferLength; //! Maximum length of OutReport's WORD wOutReportBufferLength; //! InBuffer contains data, if InReport provides more data then the application actual need BYTE inBuffer[8192]; //! Number of current used bytes in inBuffer WORD inBufferUsed; }; //****************************************************************************** // //! A structure that tracks the number of serial numbers // //****************************************************************************** struct strTrackSerialNumbers { //! Index number DWORD deviceNum; //! Serial number of physical device char serialNum[SERNUM_LEN]; }; //****************************************************************************** // //! \addtogroup hiddevice_api //! @{ // //****************************************************************************** //****************************************************************************** // //! \brief Close a HID Device. //! //! This function will close a HID device based on the HID structure //! //! \param pstrHidDevice Structure which contains important data of an HID //! device //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_NOT_OPENED //! \n \b HID_DEVICE_HANDLE_ERROR // //****************************************************************************** BYTE HID_Close(struct strHidDevice* pstrHidDevice); //****************************************************************************** // //! \brief Flush USB buffer for the given device //! //! \param pstrHidDevice Structure which contains important data of an HID //! device. //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_HANDLE_ERROR //! \n \b HID_DEVICE_UNKNOWN_ERROR // //****************************************************************************** BYTE HID_FlushBuffer(struct strHidDevice* pstrHidDevice); //****************************************************************************** // //! \brief Gets the number of HID devices //! //! This function will return the number of interfaces connected with a //! specified VID, PID and serial number, if no devices are connected, //! it will return a 0 //! //! \param vid Vendor-Id of the device //! \param pid Product-Id of the device //! \param numSerNums Total number of connected physical devices //! //! \return Return the number of connected devices with the specific VID, PID, //! and serial number. // //****************************************************************************** DWORD HID_GetNumOfInterfaces(WORD vid, WORD pid, DWORD numSerNums); //****************************************************************************** // //! \brief Gets the number of serial number and serial number list //! //! Scans the HID Devices on the system for any whose VID/PID match the //! ones specified. For every one it finds, it returns that device's //! serial number in serialNumList. Every physical USB device within a //! given VID/PID space has a unique serial number; therefore, each //! item in the list corresponds with a separate physical USB device //! attached to this host; that is, different physical instances of the //! same product or design. The function returns the total number of //! serial numbers found; if none are found, it returns 0. //! //! \param vid Vendor-ID of the device //! \param pid Product-ID of the device //! \param serialNumList List of serial numbers corresponding to the passed //! VID and PID //! //! \return Returns the number of connected physical devices with the specific //! VID and PID // //****************************************************************************** DWORD HID_GetSerNums(WORD vid, WORD pid, struct strTrackSerialNumbers * serialNumList); //****************************************************************************** // //! \brief Returns the version number of a device. //! //! \param pstrHidDevice Structure which contains important data of an HID //! device. //! \param VersionNumber Pointer to USHORT variable. //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_HANDLE_ERROR // //****************************************************************************** BYTE HID_GetVersionNumber(struct strHidDevice* pstrHidDevice, USHORT * VersionNumber); //****************************************************************************** // //! \brief Init structure with default values. //! //! It is important to call HID_Init() before calling HID_Open() to //! avoid unpredictable behavoir. //! //! \param pstrHidDevice Structure which contains important data of a HID //! device //! //! \return None // //****************************************************************************** void HID_Init(struct strHidDevice* pstrHidDevice); //****************************************************************************** // //! \brief This has to be called inside WM_ON_DEVICECHANGE notification window //! //! This function checks if the particular HID device structure is //! still connected or disconnected. //! //! \param pstrHidDevice Structure which contains important data of an HID //! device. //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_HANDLE_ERROR // //****************************************************************************** BOOL HID_IsDeviceAffected(struct strHidDevice* pstrHidDevice); //****************************************************************************** // //! \brief Open a HID Device. //! //! This function opens the HID device associated with the HID interface //! 'deviceIndex' (0-7), on the physical device described by the VID, //! PID, and serial number. //! \param pstrHidDevice Structure which contains important data of an HID //! device //! \param vid Vendor-ID of the device //! \param pid Product-ID of the device //! \param deviceIndex Index of the device.If only one HID is connected, //! deviceIndex is 0. //! - Starts with zero //! - Maximum value is (HID_GetNumOfInterfaces() - 1) //! \param serialNumber Serial number of device to be opened. //! \param totalDevNum Total number of interfaces associated with the //! serial number //! \param totalSerNum Total number of physical devices associated with //! the VID/PID //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_NOT_FOUND //! \n \b HID_DEVICE_ALREADY_OPENED // //****************************************************************************** BYTE HID_Open(struct strHidDevice* pstrHidDevice, WORD vid, WORD pid, DWORD deviceIndex, char serialNumber[SERNUM_LEN], DWORD totalDevNum, DWORD totalSerNum); //****************************************************************************** // //! \brief Reads a data stream from the given HID device. //! //! Prefixed report ID will be skipped. //! //! \param pstrHidDevice Structure which contains important data of an HID //! device //! \param buffer Pointer to buffer in which will be written //! \param bufferSize Number of bytes to read //! \param bytesReturned Number of actual read bytes //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_NOT_OPENED //! \n \b HID_DEVICE_TRANSFER_TIMEOUT //! \n \b HID_DEVICE_TRANSFER_FAILED // //****************************************************************************** BYTE HID_ReadFile(struct strHidDevice* pstrHidDevice, BYTE* buffer, DWORD bufferSize, DWORD* bytesReturned); //****************************************************************************** // //! \brief Registers a device for program Windows notification. //! //! Registers the window pointed to by handle hWnd to receive //! notification when devices are added or removed from the system. //! //! \param hWnd Windows handle //! \param diNotifyHandle Device notification handle pointer address //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_HANDLE_ERROR // //****************************************************************************** BYTE HID_RegisterForDeviceNotification(HWND hWnd, HDEVNOTIFY* diNotifyHandle); //****************************************************************************** // //! \brief Un-Registers a device from Windows notification. //! //! Un-registers the window pointed to by handle hWnd to receive //! notification when devices are added or removed from the system. //! //! \param diNotifyHandle: Device notification handle pointer address. //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_HANDLE_ERROR // //****************************************************************************** BYTE HID_UnRegisterForDeviceNotification(HDEVNOTIFY* diNotifyHandle); //****************************************************************************** // //! \brief Writes a data stream to the given HID device. //! //! Needed report IDs will be generated automatically. //! //! \param pstrHidDevice Structure which contains important data of an HID //! device //! \param buffer Buffer which will be send //! \param bufferSize Number of bytes to send //! //! \return Returns the error status, as one of //! \n \b HID_DEVICE_SUCCESS //! \n \b HID_DEVICE_NOT_OPENED //! \n \b HID_DEVICE_TRANSFER_TIMEOUT //! \n \b HID_DEVICE_TRANSFER_FAILED // //****************************************************************************** BYTE HID_WriteFile(struct strHidDevice* pstrHidDevice, BYTE* buffer, DWORD bufferSize);
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值