<br /> 在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,<br />配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。<br />USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较<br />复杂的一个描述符。<br /> USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。<br />输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等<br />信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送<br />给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是<br />一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点<br />输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出<br />端点0发送,当有中断输出端点时,通过中断输出端点发出。<br /> 而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。<br />通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入<br />端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求<br />是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的<br />报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中<br />没有规定报告ID时,报告中就没有ID字段,开始就是数据。更详细的说明请参看<br />USB HID协议,该协议可从Http://www.usb.org下载。<br /> USB报告描述符可以通过使用HID Descriptor tool来生成,这个工具可以<br />到Http://www.usb.org下载,为了方便大家,我顺便上传了一份。<br /><a href="http://www.**/Upload/Blog/2007/4/2/af7c3443-ad61-4465-adc7-a74d28bbc322.zip" target=_blank>http://www.**/Upload/Blog/2007/4/2/af7c3443-ad61-4465-adc7-a74d28bbc322.zip</a>uploadfile-/2007-4/42672233.zip 下面通过由HID Descriptor tool生成的USB鼠标和USB键盘来说明一下报告<br />描述符和报告。<br />code char KeyBoardReportDescriptor[63] = {<br /> //表示用途页为通用桌面设备<br /> 0x05, 0x01, // USAGE_PAGE (Generic Desktop)<br /> //表示用途为键盘<br /> 0x09, 0x06, // USAGE (Keyboard)<br /> <br /> //表示应用集合,必须要以END_COLLECTION来结束它,见最后的END_COLLECTION<br /> 0xa1, 0x01, // COLLECTION (Application)<br /> <br /> //表示用途页为按键<br /> 0x05, 0x07, // USAGE_PAGE (Keyboard)<br /> //用途最小值,这里为左ctrl键<br /> 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)<br /> //用途最大值,这里为右GUI键,即window键<br /> 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)<br /> //逻辑最小值为0<br /> 0x15, 0x00, // LOGICAL_MINIMUM (0)<br /> //逻辑最大值为1<br /> 0x25, 0x01, // LOGICAL_MAXIMUM (1)<br /> //报告大小(即这个字段的宽度)为1bit,所以前面的逻辑最小值为0,逻辑最大值为1<br /> 0x75, 0x01, // REPORT_SIZE (1)<br /> //报告的个数为8,即总共有8个bits<br /> 0x95, 0x08, // REPORT_COUNT (8)<br /> //输入用,变量,值,绝对值。像键盘这类一般报告绝对值,<br /> //而鼠标移动这样的则报告相对值,表示鼠标移动多少<br /> 0x81, 0x02, // INPUT (Data,Var,Abs)<br /> //上面这这几项描述了一个输入用的字段,总共为8个bits,每个bit表示一个按键<br /> //分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。<br /> //它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下,<br /> //否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位,<br /> //需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示<br /> //特殊键,例如ctrl,shift,del键等<br /> <br /> //这样的数据段个数为1<br /> 0x95, 0x01, // REPORT_COUNT (1)<br /> //每个段长度为8bits<br /> 0x75, 0x08, // REPORT_SIZE (8)<br /> //输入用,常量,值,绝对值<br /> 0x81, 0x03, // INPUT (Cnst,Var,Abs)<br /> <br /> //上面这8个bit是常量,设备必须返回0<br /><br /> //这样的数据段个数为5<br /> 0x95, 0x05, // REPORT_COUNT (5)<br /> //每个段大小为1bit<br /> 0x75, 0x01, // REPORT_SIZE (1)<br /> //用途是LED,即用来控制键盘上的LED用的,因此下面会说明它是输出用<br /> 0x05, 0x08, // USAGE_PAGE (LEDs)<br /> //用途最小值是Num Lock,即数字键锁定灯<br /> 0x19, 0x01, // USAGE_MINIMUM (Num Lock)<br /> //用途最大值是Kana,这个是什么灯我也不清楚^_^<br /> 0x29, 0x05, // USAGE_MAXIMUM (Kana)<br /> //如前面所说,这个字段是输出用的,用来控制LED。变量,值,绝对值。<br /> //1表示灯亮,0表示灯灭<br /> 0x91, 0x02, // OUTPUT (Data,Var,Abs)<br /> //这样的数据段个数为1<br /> 0x95, 0x01, // REPORT_COUNT (1)<br /> //每个段大小为3bits<br /> 0x75, 0x03, // REPORT_SIZE (3)<br /> //输出用,常量,值,绝对<br /> 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) <br /> //由于要按字节对齐,而前面控制LED的只用了5个bit,<br /> //所以后面需要附加3个不用bit,设置为常量。<br /> <br /> //报告个数为6<br /> 0x95, 0x06, // REPORT_COUNT (6)<br /> //每个段大小为8bits<br /> 0x75, 0x08, // REPORT_SIZE (8)<br /> //逻辑最小值0<br /> 0x15, 0x00, // LOGICAL_MINIMUM (0)<br /> //逻辑最大值255<br /> 0x25, 0xFF, // LOGICAL_MAXIMUM (255)<br /> //用途页为按键<br /> 0x05, 0x07, // USAGE_PAGE (Keyboard)<br /> //使用最小值为0<br /> 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))<br /> //使用最小值为0x65<br /> 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)<br /> //输入用,变量,数组,绝对值<br /> 0x81, 0x00, // INPUT (Data,Ary,Abs)<br /> //以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个按键,所以可以同时<br /> //有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统<br /> //无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一<br /> //个字节为相应的键值(具体的值参看HID Usage Tables),如果两个键按下,则第1、2两个<br /> //字节分别为相应的键值,以次类推。<br /><br /> //关集合,跟上面的对应<br /> 0xc0 // END_COLLECTION<br />};<br /> <br /> 通过上面的分析,我们知道这个报告中只有一个报告,所以没有报告ID,<br />因此返回的都是实际使用的数据。总共有8字节输入,1字节输出。其中输入的<br />第一字节用来表示特殊按键,第二字节保留,后面的六字节为普通按键。如果<br />只有左ctrl键按下,则返回01 00 00 00 00 00 00 00(十六进制),如果<br />只有数字键1 按下,则返回00 00 59 00 00 00 00 00,如果数字<br />键1 和2 同时按下,则返回00 00 59 5A 00 00 00 00,如果<br />再按下左shift 键,则返回02 00 59 5A 00 00 00 00,<br />然后再释放1 键,则返回02 00 5A 00 00 00 00 00,<br />然后全部按键释放,则返回00 00 00 00 00 00 00 00。<br />这些数据(即报告)都是通过中断端点返回的。当按下Num Lock键时,PC会发送<br />输出报告,从报告描述符中我们知道,Num Lock的LED对应着输出报告的最低位,<br />当数字小键盘打开时,输出xxxxxxx1(二进制,打x的由其它的LED状态决定);<br />当数字小键盘关闭时,输出xxxxxxx0(同前)。取出最低位就可以控制数字键锁定LED了。<br /> <br /><br />下面这个报告描述符是USB鼠标报告描述符,比起键盘的来说要简单些。<br />它描述了4个字节,第一个字节表示按键,第二个字节表示x轴(即鼠标左右移动,<br />0表示不动,正值表示往右移,负值表示往左移),第三个字节表示y轴(即鼠标<br />上下移动,0表示不动,正值表示往下移动,负值表示往上移动),第四个字节<br />表示鼠标滚轮(正值为往上滚动,负值为往下滚动)。<br />code char MouseReportDescriptor[52] = {<br /> //通用桌面设备<br /> 0x05, 0x01, // USAGE_PAGE (Generic Desktop)<br /> //鼠标<br /> 0x09, 0x02, // USAGE (Mouse)<br /> //集合<br /> 0xa1, 0x01, // COLLECTION (Application)<br /> //指针设备<br /> 0x09, 0x01, // USAGE (Pointer)<br /> //集合<br /> 0xa1, 0x00, // COLLECTION (Physical)<br /> //按键<br /> 0x05, 0x09, // USAGE_PAGE (Button)<br /> //使用最小值1<br /> 0x19, 0x01, // USAGE_MINIMUM (Button 1)<br /> //使用最小值3。1表示左键,2表示右键,3表示中键<br /> 0x29, 0x03, // USAGE_MAXIMUM (Button 3)<br /> //逻辑最小值0<br /> 0x15, 0x00, // LOGICAL_MINIMUM (0)<br /> //逻辑最大值1<br /> 0x25, 0x01, // LOGICAL_MAXIMUM (1)<br /> //数量为3<br /> 0x95, 0x03, // REPORT_COUNT (3)<br /> //大小为1bit<br /> 0x75, 0x01, // REPORT_SIZE (1)<br /> //输入,变量,数值,绝对值<br /> //以上3个bit分别表示鼠标的三个按键情况,最低位(bit-0)为左键<br /> //bit-1为右键,bit-2为中键,按下时对应的位值为1,释放时对应的值为0<br /> 0x81, 0x02, // INPUT (Data,Var,Abs)<br /> //填充5个bit,补足一个字节<br /> 0x95, 0x01, // REPORT_COUNT (1)<br /> 0x75, 0x05, // REPORT_SIZE (5)<br /> 0x81, 0x03, // INPUT (Cnst,Var,Abs)<br /> //用途页为通用桌面<br /> 0x05, 0x01, // USAGE_PAGE (Generic Desktop)<br /> //用途为X<br /> 0x09, 0x30, // USAGE (X)<br /> //用途为Y<br /> 0x09, 0x31, // USAGE (Y)<br /> //用途为滚轮<br /> 0x09, 0x38, // USAGE (Wheel)<br /> //逻辑最小值为-127<br /> 0x15, 0x81, // LOGICAL_MINIMUM (-127)<br /> //逻辑最大值为+127<br /> 0x25, 0x7f, // LOGICAL_MAXIMUM (127)<br /> //大小为8个bits<br /> 0x75, 0x08, // REPORT_SIZE (8)<br /> //数量为3个,即分别代表x,y,滚轮<br /> 0x95, 0x03, // REPORT_COUNT (3)<br /> //输入,变量,值,相对值<br /> 0x81, 0x06, // INPUT (Data,Var,Rel)<br /> //关集合<br /> 0xc0, // END_COLLECTION<br /> 0xc0 // END_COLLECTION<br />};<br /> <br /> <br />通过对上面的报告分析,我们知道报告返回4个字节,没有报告ID。如果鼠标左键按下,<br />则返回01 00 00 00(十六进制值),如果右键按下,则返回02 00 00 00,如果中键按下,<br />则返回04 00 00 00,如果三个键同时按下,则返回07 00 00 00。如果鼠标往右移动则<br />第二字节返回正值,值越大移动速度越快。其它的类推。<br /> <br />这里只对报告描述符做一个简单的介绍,更详细的资料请参看USB HID协议以及HID Usage Tables,<br />可以从Http://www.usb.org下载。<br /><br />根据这个实际设计的USB键盘和USB鼠标:<br />USB键盘:<br />user1/2198/archives/2007/36484.html<br /><a href="http://www.**/blog/computer00/20134/message.aspx" target=_blank>http://www.**/blog/computer00/20134/message.aspx</a><br />USB鼠标:<br />user1/2198/archives/2007/36520.html<br /><a href="http://www.**/blog/computer00/20135/message.aspx" target=_blank>http://www.**/blog/computer00/20135/message.aspx</a><br /> |
|