1、在USB中USB HOST是通过各种描述符来识别设备的USB HID报告及报告描述符简介在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符。 USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯
2、等。报告是一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出端点0发送,当有中断输出端点时,通过中断输出端点发出。 而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数
3、据。更详细的说明请参看USB HID协议,该协议可从Http:/www.usb.org下载。 USB报告描述符可以通过使用HID Descriptor tool来生成,这个工具可以到Http:/www.usb.org下载,为了方便大家,我顺便上传了一份。 下面通过由HID Descriptor tool生成的USB鼠标和USB键盘来说明一下报告描述符和报告。code char KeyBoardReportDescriptor63 = /表示用途页为通用桌面设备 0x05, 0x01, / USAGE_PAGE (Generic Desktop)/表示用途为键盘 0x09, 0x06, / US
4、AGE (Keyboard) /表示应用集合,必须要以END_COLLECTION来结束它,见最后的 /END_COLLECTION 0xa1, 0x01, / COLLECTION (Application) /表示用途页为按键 0x05, 0x07, / USAGE_PAGE (Keyboard) /用途最小值,这里为左ctrl键 0x19, 0xe0, / USAGE_MINIMUM (Keyboard LeftControl) /用途最大值,这里为右GUI键,即window键 0x29, 0xe7, / USAGE_MAXIMUM (Keyboard Right GUI) /逻辑最小值
5、为0 0x15, 0x00, / LOGICAL_MINIMUM (0) /逻辑最大值为1 0x25, 0x01, / LOGICAL_MAXIMUM (1) /报告大小(即这个字段的宽度)为1bit,所以前面的逻辑最小值为0,逻辑最大值为1 0x75, 0x01, / REPORT_SIZE (1) /报告的个数为8,即总共有8个bits 0x95, 0x08, / REPORT_COUNT (8) /输入用,变量,值,绝对值。像键盘这类一般报告绝对值, /而鼠标移动这样的则报告相对值,表示鼠标移动多少 0x81, 0x02, / INPUT (Data,Var,Abs) /上面这这几项描述
6、了一个输入用的字段,总共为8个bits,每个bit表示一个按键 /分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。 /它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下, /否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位, /需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示 /特殊键,例如ctrl,shift,del键等 /这样的数据段个数为1 0x95, 0x01, / REPORT_COUNT (1) /每个段长度为8bit
7、s 0x75, 0x08, / REPORT_SIZE (8) /输入用,常量,值,绝对值 0x81, 0x03, / INPUT (Cnst,Var,Abs) /上面这8个bit是常量,设备必须返回0 /这样的数据段个数为5 0x95, 0x05, / REPORT_COUNT (5) /每个段大小为1bit 0x75, 0x01, / REPORT_SIZE (1) /用途是LED,即用来控制键盘上的LED用的,因此下面会说明它是输出用 0x05, 0x08, / USAGE_PAGE (LEDs) /用途最小值是Num Lock,即数字键锁定灯 0x19, 0x01, / USAGE_M
8、INIMUM (Num Lock) /用途最大值是Kana,这个是什么灯我也不清楚_ 0x29, 0x05, / USAGE_MAXIMUM (Kana) /如前面所说,这个字段是输出用的,用来控制LED。变量,值,绝对值。 /1表示灯亮,0表示灯灭 0x91, 0x02, / OUTPUT (Data,Var,Abs) /这样的数据段个数为1 0x95, 0x01, / REPORT_COUNT (1) /每个段大小为3bits 0x75, 0x03, / REPORT_SIZE (3) /输出用,常量,值,绝对 0x91, 0x03, / OUTPUT (Cnst,Var,Abs) /由于
9、要按字节对齐,而前面控制LED的只用了5个bit, /所以后面需要附加3个不用bit,设置为常量。 /报告个数为6 0x95, 0x06, / REPORT_COUNT (6) /每个段大小为8bits 0x75, 0x08, / REPORT_SIZE (8) /逻辑最小值0 0x15, 0x00, / LOGICAL_MINIMUM (0) /逻辑最大值255 0x25, 0xFF, / LOGICAL_MAXIMUM (255) /用途页为按键 0x05, 0x07, / USAGE_PAGE (Keyboard) /使用最小值为0 0x19, 0x00, / USAGE_MINIMUM
10、 (Reserved (no event indicated) /使用最大值为0x65 0x29, 0x65, / USAGE_MAXIMUM (Keyboard Application) /输入用,变量,数组,绝对值 0x81, 0x00, / INPUT (Data,Ary,Abs) /以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个按键,所以可以同时 /有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统 /无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一 /个字节为相应的键值(具体的值参看HID
11、Usage Tables),如果两个键按下,则第1、2两个 /字节分别为相应的键值,以次类推。 /关集合,跟上面的对应 0xc0 / END_COLLECTION; 通过上面的分析,我们知道这个报告中只有一个报告,所以没有报告ID,因此返回的都是实际使用的数据。总共有8字节输入,1字节输出。其中输入的第一字节用来表示特殊按键,第二字节保留,后面的六字节为普通按键。如果只有左ctrl键按下,则返回01 00 00 00 00 00 00 00(十六进制),如果只有数字键1 按下,则返回00 00 59 00 00 00 00 00,如果数字键1 和2 同时按下,则返回00 00 59 5A 00
12、 00 00 00,如果再按下左shift 键,则返回02 00 59 5A 00 00 00 00,然后再释放1 键,则返回02 00 5A 00 00 00 00 00,然后全部按键释放,则返回00 00 00 00 00 00 00 00。这些数据(即报告)都是通过中断端点返回的。当按下Num Lock键时,PC会发送输出报告,从报告描述符中我们知道,Num Lock的LED对应着输出报告的最低位,当数字小键盘打开时,输出xxxxxxx1(二进制,打x的由其它的LED状态决定);当数字小键盘关闭时,输出xxxxxxx0(同前)。取出最低位就可以控制数字键锁定LED了。下面这个报告描述符是
13、USB鼠标报告描述符,比起键盘的来说要简单些。它描述了4个字节,第一个字节表示按键,第二个字节表示x轴(即鼠标左右移动,0表示不动,正值表示往右移,负值表示往左移),第三个字节表示y轴(即鼠标上下移动,0表示不动,正值表示往下移动,负值表示往上移动),第四个字节表示鼠标滚轮(正值为往上滚动,负值为往下滚动)。code char MouseReportDescriptor52 = /通用桌面设备 0x05, 0x01, / USAGE_PAGE (Generic Desktop) /鼠标 0x09, 0x02, / USAGE (Mouse) /集合 0xa1, 0x01, / COLLECTI
14、ON (Application) /指针设备 0x09, 0x01, / USAGE (Pointer) /集合 0xa1, 0x00, / COLLECTION (Physical) /按键 0x05, 0x09, / USAGE_PAGE (Button) /使用最小值1 0x19, 0x01, / USAGE_MINIMUM (Button 1) /使用最大值3。1表示左键,2表示右键,3表示中键 0x29, 0x03, / USAGE_MAXIMUM (Button 3) /逻辑最小值0 0x15, 0x00, / LOGICAL_MINIMUM (0) /逻辑最大值1 0x25, 0
15、x01, / LOGICAL_MAXIMUM (1) /数量为3 0x95, 0x03, / REPORT_COUNT (3) /大小为1bit 0x75, 0x01, / REPORT_SIZE (1) /输入,变量,数值,绝对值 /以上3个bit分别表示鼠标的三个按键情况,最低位(bit-0)为左键 /bit-1为右键,bit-2为中键,按下时对应的位值为1,释放时对应的值为0 0x81, 0x02, / INPUT (Data,Var,Abs) /填充5个bit,补足一个字节 0x95, 0x01, / REPORT_COUNT (1) 0x75, 0x05, / REPORT_SIZE
16、 (5) 0x81, 0x03, / INPUT (Cnst,Var,Abs) /用途页为通用桌面 0x05, 0x01, / USAGE_PAGE (Generic Desktop) /用途为X 0x09, 0x30, / USAGE (X) /用途为Y 0x09, 0x31, / USAGE (Y) /用途为滚轮 0x09, 0x38, / USAGE (Wheel) /逻辑最小值为-127 0x15, 0x81, / LOGICAL_MINIMUM (-127) /逻辑最大值为+127 0x25, 0x7f, / LOGICAL_MAXIMUM (127) /大小为8个bits 0x75
17、, 0x08, / REPORT_SIZE (8) /数量为3个,即分别代表x,y,滚轮 0x95, 0x03, / REPORT_COUNT (3) /输入,变量,值,相对值 0x81, 0x06, / INPUT (Data,Var,Rel) /关集合 0xc0, / END_COLLECTION 0xc0 / END_COLLECTION;通过对上面的报告分析,我们知道报告返回4个字节,没有报告ID。如果鼠标左键按下,则返回01 00 00 00(十六进制值),如果右键按下,则返回02 00 00 00,如果中键按下,则返回04 00 00 00,如果三个键同时按下,则返回07 00 0
18、0 00。如果鼠标往右移动则第二字节返回正值,值越大移动速度越快。其它的类推。这里只对报告描述符做一个简单的介绍,更详细的资料请参看USB HID协议以及HID Usage Tables,可以从Http:/www.usb.org下载。根据这个实际设计的USB键盘和USB鼠标:USB键盘:http:/computer00.21ic.org/user1/2198/archives/2007/36484.htmlUSB鼠标:http:/computer00.21ic.org/user1/2198/archives/2007/36520.html USB入门系列之五 USB设备的插入检测机制 USB主
19、机是如何检测到设备的插入的呢?首先,在USB集线器的每个下游端口的D+和D-上,分别接了一个15K欧姆的下拉电阻到地。这样,在集线器的端口悬空时,就被这两个下拉电阻拉到了低电平。而在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻。对于全速和高速设备,上拉电阻是接在D+上;而低速设备则是上拉电阻接在D-上。这样,当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的一条拉高了。集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。USB高速设备先是被识别为全速设备,然后通过HOST和D
20、EVICE两者之间的确认,再切换到高速模式的。在高速模式下,是电流传输模式,这时将D+上的上拉电阻断开。 一个简单的实验:只用一个上拉电阻接在USB的+5V和D+或者D-上,WINDOWS也会提示发现新硬件,但是无法找到驱动程序。这时去设备管理器里面看,有显示未知USB设备,并且其VID和PID为0。根据这个,我们可以简单的判断设备是否枚举成功。如下图所示,分别是枚举不成功和枚举成功的图。USB入门系列之六 USB设备的枚举过程 USB主机在检测到USB设备插入后,就要对设备进行枚举了。为什么要枚举呢?枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息
21、来加载合适的驱动程序。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,那么就已经成功大半了。 在说枚举之前,先大概说说USB的一种传输模式控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:建立阶段。数据阶段。确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确
22、认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。 好了,下面我们来看看枚举的详细过程。 首先,USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不
23、足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。 然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一
24、个唯一的设备地址,以后主机就通过它来进行访问该设备。 然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。 接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。 如果有字符串描述符的话,还要获取字符串描述符。另外HID设备还有HID描述符等。使用BUS HOUND以及通过串口返回信息,很容易看到具体的过程。总之是主机请求什么,你的程序就响应什么。下面这些数据是使用BUS HOUND抓的,这个是在WIN2000下抓到的,如果在WINXP下,就看不到设置地址之前的数据。写了注释下面的部分就是主机和设备之间的数据通信,而其它的则是主机跟根集线器之间的通信数据。Device Phase Data Description Cmd.Phase.Ofs(rep) Delta- - - - -
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1