原创 USB的报告描述符学习

2010-4-25 21:03 9527 16 16 分类: MCU/ 嵌入式

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

 


现在在我手上,有三本书:《USB2.0硬件设计》、《圈圈教你玩USB》和《基于MKDSTM32处理器应用开发》。我都翻到了与 报告描述符相关的部分,边看、边理解、边记录。


一、HID类与报告描述符


 


1、设备类和接口类的含义


为了使USB设备的开发标准化,USB定义了许多标准设备类、设备子类,好处是如果你遵循这些设备类的控制要求,有时候可以不用开发上位机上的驱动程序,因为windows已经自带了驱动。即使没有相应的驱动,也会使驱动开发更为简单。


特别是有些标准系统设备,连应用程序都可以不用开发,真正的“即插即用”,比如USB鼠标、USB键盘和U盘。


 


通过“JoyStickMouse”例程的学习,我发现在描述符中有两处讲到了设备类。


一是设备描述符第456字节,分别表示设备类、子类和协议。


二是接口描述符第567字节,分别表示接口类、子列和协议。


它们之间有什么关联呢?书上都没有详细的说明,求助于网络。搜到了下面一片文章,讲得比较详细。我就留下链接,把表复制过来。有兴趣的可以去源地址查看全文。


 


USB设备类及设备子类及接口采用的设备协议


 




Base Class


Descriptor Usage


Description


00h


Device


Use class information in the Interface Descriptors


01h


Interface


Audio  


02h


Both


Communications and CDC Control


03h


Interface


HID (Human Interface Device)


05h


Interface


Physical


06h


Interface


Image


07h


Interface


Printer


08h


Interface


Mass Storage


09h


Device


Hub


0Ah


Interface


CDC-Data


0Bh


Interface


Smart Card


0Dh


Interface


Content Security


0Eh


Interface


Video


0Fh


Interface


Personal Healthcare


DCh


Both


Diagnostic Device


E0h


Interface


Wireless Controller


EFh


Both


Miscellaneous


FEh


Interface


Application Specific


FFh


Both


Vendor Specific


 


上面这个表指明了只有类“02”、“DC”、“EF”和“FF”可以将类代码写在设备描述符中,“09HUB类必须将设备类代码写在设备描述负重。其它的设备类、协议都必须放在接口描述符中。


 


HID设备设备类代码03,子类表示是否支持启动,协议与是否支持启动有关。对于普通应用没有意义,都写成0也可以


那么对于HID设备,到底加载什么类型的驱动呢?实际上这取决于“报告描述符”中对“用途页、用途”的指定


 


如果要使用自定义设备,则需要自己开发驱动,设备类代码设定为“FF”。


 


2、鼠标的报告描述符分析


《圈圈教你玩USB》的“4.8 再谈USB HID的报告描述符”对其结构、特性做了详细的分析,我从中学到了不少。


(1)   报告描述符主要是为了描述报告的结构、用途。


(2)   指定位域作用时,同时指明用途页、用途。


(3)   指明用途可以一个个指定、可以指明最大值和最小值。


(4)   Sel Ary:这个在实例中阐明。


(5)   基本用途类型:集合、控制、数据。


(6)   鼠标、游戏杆、键盘都属于集合类用途。


(7)   音量控制、键盘LED开关控制、鼠标按键控制属于控制类用途。


(8)   选择器、动态标志、动态值属于数据类用途。


后面这几个,还理解得不是很好。


 


 


const u8 Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =


  {


    0x05,  0x01,        /*Usage Page(Generic Desktop)*/


    0x09,  0x02,        /*Usage(Mouse)*/  用途鼠标属于集合类,可以开集合,以下所以数据都在这四个字节的控制范围内。主机读到以上信息后,就会将该设备视为标准系统设备“鼠标”。


  


    0xA1,  0x01,        /*Collection(Logical)*/ //这个应用集合一直作用到报告最后。


   


    0x09,  0x01,        /*Usage(Pointer)*/  //这里又开了一个子集合,用途为指针,集合为物理集合。0x05,  0x01的作用域到了这儿,所以这个集合仍然属于Generic Desktop


    0xA1,  0x00,        /*Collection(Linked)*/


   


    0x05,  0x09,        /*Usage Page(Buttons)*/


    0x19,  0x01,        /*Usage Minimum(1)*/


    0x29,  0x03,        /*Usage Maximum(3)*/


以上六个字节说明了这是按键用途页,下面的0103说明是控制类用途,可以确定,这个主条目有三个数据域。


    0x15, 0x00,         /*Logical Minimum(0)*/  每个数据域是1位。


    0x25, 0x01,         /*Logical Maximum(1)*/


   


    0x95, 0x03,        /*Report Count(3)*/ 3个数据域


    0x75, 0x01,         /*Report Size(1)*/ 每个大小为1位。


    0x81, 0x02,         /*Input(Variable)*/


//一个数据集合到此结束。81是一个输入主条目,02表示数据的性质为“数据、变量、绝对值。但是这个数据域只占了一个字节的3位,所以下面需要一个数据集合填满高5位。


 


    0x95,  0x01,        /*Report Count(1)*/


    0x75,  0x05,        /*Report Size(5)*/


    0x81,  0x03,        / 主条目结束,填充5位常数,构成一个字节。


//   0x01, 原来数据为0x01,这里改为03后,每位表示独立的常量


                     


    0x05, 0x01,         /*Usage Page(Generic Desktop)*/


    0x09, 0x30,         /*Usage(X axis)*/


    0x09, 0x31,         /*Usage(Y axis)*/


    0x09, 0x38,         /*Usage(Wheel)*/这里单独指明了三个用途。与前面的Usage Minimum——Usage Maximum有异曲同工之妙也是指明三个数据域。


    0x15, 0x81,         /*Logical Minimum(-127)*/


    0x25, 0x<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />7F,         /*Logical Maximum(127)*/这里指明了数据的范围-127127每个数据域至少8位。


   


    0x75, 0x08,         /*Report Size(8)*/


    0x95, 0x03,         /*Report Count(3)*/


    0x81, 0x06,         /*Input(Variable, Relative)*/


//这里数据的性质是相对值,针对鼠标XY方向和滚轮。


   


0xC0,          /*End Collection*/  //关掉了指针物理集合鼠标应用集合还没有关


   


0x09,   0x3c,        //这是一个局部条目,表示运动唤醒。全局条目性质仍然是:0x05,  0x01 (Generic Desktop)


   


    0x05,   0xff,          //这是一个全局条目用途页,由用户自己定义


    0x09,   0x01,        //局部条目用途,由用户自己定义,这里的意思没有弄明白,在程序中好像也没有用到。


    


    0x15,   0x00,        //全局条目,逻辑最小值


    0x25,   0x01,            //全局条目,逻辑最大值 说明数据域为1位。


   


    0x75,   0x01,            //全局条目 ,数据长度1


    0x95,   0x02,        //全局条目,数据的数量2个。


0xb1,   0x22,            //主条目,Feature,变量,数组,非优选状态


   


    0x75,   0x06,            //全局条目       ,数据长度6


    0x95,   0x01,            //全局条目 ,数量为1个。填充6个凑满一个字节。


    0xb1,   0x01,            //主条目,Feature,常数


   


    0xc0              //关鼠标应用集合。


  }


 


二、改造成键盘报告描述符


1、改造的目的


我的开发板上可以实现7个键,除了PB3按钮用于退出,还有六个键可以用于键盘。分配如下:


OK键用于“左GUI键”,就是那个一按就显示开始菜单的按键;


PB2用于“左Ctrl”。


上右下左分别表示“abcd”。


 


通过这样分析,报告描述符输入部分需要2个字节(除了ctrlshift外,不支持多键同时按下)。


输出部分用一个字节,其中用1位表示大小写是否打开并且用于控制开发板上“唯一的可控Led”。


这个报告描述符将用于实现USB键盘。


 


2、键盘报告描述符


   以下报告描述符结合上面的鼠标报告描述符,并且借鉴了圈圈书中的报告描述符代码。


const u8 Keyboard_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =


  {


    0x05,  0x01,        /*Usage Page(Generic Desktop)*/


   0x09,  0x02,        /*Usage(Mouse)*/  用途鼠标属于集合类,可以开集合,以下所以数据都在这四个字节的控制范围内。主机读到以上信息后,就会将该设备视为标准系统设备“鼠标”。)


    0x09,  0x06  //06表示键盘用途。


 


 


    0xA1,  0x01,        /*Collection(Logical)*/ //这个应用集合一直作用到报告最后。


   


    0x09,  0x01,        /*Usage(Pointer)*/  //这里又开了一个子集合,用途为指针,集合为物理集合。0x05,  0x01的作用域到了这儿,所以这个集合仍然属于Generic Desktop


    0xA1,  0x00,        /*Collection(Linked)*/


    现在不需要物理集合了,应用集合将包含所有的数据。


 


    0x05,  0x09,        /*Usage Page(Buttons)*/


    0x05,  0x07,   //把用途页改变为按键


    0x19,  0xe0,        /*Usage Minimum(1)*/


    0x29,  0xe7,        /*Usage Maximum(3)*/


 


    0x15, 0x00,         /*Logical Minimum(0)*/  每个数据域是1位。


    0x25, 0x01,         /*Logical Maximum(1)*/


   


    0x95, 0x08,        /*Report Count(3)*/ 3个数据域


    0x75, 0x01,         /*Report Size(1)*/ 每个大小为1位。


    0x81, 0x02,         /*Input(Variable)*/


//一个数据集合到此结束。81是一个输入主条目,02表示数据的性质为“数据、变量、绝对值。但是这个数据域只占了一个字节的3位,所以下面需要一个数据集合填满高5位。


                     


    0x05, 0x07,         /*键盘控制用途页*/


    0x19, 0x00,         /*Usage 最小值0*/


    0x29, 0x65,         /*Usage  最大值101*/


   


0x15, 0x00,         /*Logical Minimum(0)*/


    0x25, 0xFF,         /*Logical Maximum(255)*/这里指明了数据的范围0255每个数据域至少8位。


   


    0x75, 0x08,         /*Report Size(8)*/


    0x95, 0x01,         /*Report Count(1)*/


    0x81, 0x00,         /*Input(Variable, Array)*/


//这里数据的性质是数据、数组、绝对值。


//又一个数据集合结束。一个字节。输入共两个字节。


 


    0x05,  0x07,         /*LED用途页*/


    0x19,  0x00,         /*Usage 最小值0*/


    0x29,  0x03,         /*Usage  最大值3*/  表示有3个数据域


   


    0x15,  0x00,         /*Logical Minimum(0)*/


    0x25,  0x01,         /*Logical Maximum(1)*/这里指明了数据的范围01每个数据域为1位。


   


    0x75, 0x01,         /*Report Size(1)*/


    0x95, 0x03,         /*Report Count(3)*/


    0x91, 0x02,         /*Output(Variable, Abs)*/


//输出3个位。


   


    0x75, 0x01,         /*Report Size(1)*/


    0x95, 0x05,         /*Report Count(5)*/


    0x91, 0x03,         /*Output(Constant, Abs)*/


//输出5个位。常数。


//加上上面的3构成输出一个字节。


    0xc0              //关键盘应用集合。


  }


 


 


 


 


 

文章评论0条评论)

登录后参与讨论
我要评论
0
16
关闭 站长推荐上一条 /2 下一条