文章目录
1.简介
今天来介绍下usb鼠标,属于USB五类设备的人机交互设备(hid:Human Interface Devices),在4种基本传输方式中使用中断传输,这里的中断传输并不是指从机可以随意发送给主机,因为usb只能有主机发起数据传输,实际上是由主机来不断查询从机的方式。
2.鼠标
2.1描述符
用软件看看鼠标的描述符组成如下所示,HID类设备描述符除了标准的之外还有类特殊描述符(包括报告描述符和物理描述符)。
2.1.1标准描述符
来看看usb文档是怎么描述Class、SubClass、Protocol Codes(主要这三个重要):
The bInterfaceClass member of an Interface descriptor is always 3 for HID class devices,Consequently, the HID class does not use subclasses to define most protocols,The bInterfaceProtocol member of an Interface descriptor only has meaning if the bInterfaceS-ubClass member declares that the device supports a boot interface, otherwise it is 0,所以我们只需要设置Class = HID.
2.1.2类特殊描述符
类特殊描述符有报告描述符和物理描述符,这个HID Descriptor类设备描述符跟在接口描述符后面,用来描述类描述符(报告描述符和物理描述),报告描述符用来描述主机和从机之间进行通信的协议,物理描述符描述有关激活设备上的的控件的信息(可选,一般不用)。
2.2.1 HID Descriptor
描述符含义如下所示:
2.2.2 Report Descriptor
报告描述符的组成比较复杂,我先介绍报告描述符组成,然后用HID文档上的一个鼠标例子来说明。
2.2.2.1 Report Descriptor
报告描述符是由几块数据组成的,每块数据叫条目(item),条目第一字节有三个区域组成item type、item tag、item size,当条目是短条目的时候item size可以是0、1、2、3(一般都是用短条目,所以这里只讨论短条目)用来定义后面数据大小,有三种类型的item type:Main,Global,Local,主条目有5种类型的item tag(Input、Output、Feature、Collection、End Collection),主条目(Input、Output、Feature)指示数据控制方式、数据是相对还是绝对的,全局和本地用来描述数据范围和其他等等,一般全局和本地条目用来在主条目前面用来修饰,全局定义后对后面的数据属性都有效除非重新定义全局属性。
hid驱动的解析器会遍历报告描述符,然后把它们存在项目状态表中(item state table),当遇到主条目的时候就会创建一个项目状态表,然后用Global和Local加入状态表(主条目用来新建一个项目状态表,而Global和Local可以改变它,其中Collectiong用来关联主项目),他们之间的关系就像如下所示:
2.2.2.2 MAIN
2.2.2.3 Global
2.2.2.4 Local
2.2.2.5 鼠标例子
定义一个3字节的鼠标报告:
2.2.2.6 伪代码
hid类的请求有标准的和类特殊的,类的请求都是到接口的,接上两节枚举程序控制传输流程添加代码:
//控制传输流程
void usb_control_transmit()
{
usb_ctl_req req;
static int state;
if(state == 建立过程){
//读8个字节长度请求
usb_read_ep0(&req, 8);
switch(req.bmRequestType & 0x1f){
//******************************到设备的请求**************************************//
case DEVICE:
SET_ADDRESS:
结束流程,没有数据过程;
break;
GET_DESCRIPTOR:
设备、配置、接口描述符;
state = 数据过程;
break;
//*********************************到接口的请求*********************************//
case INTERFACE:
//要根据接口号来判断请求是不是到hid接口的if(req->index == HID_INTERFACE)
switch(req.bmRequestType & 0x60){
//获取描述符,wValue为描述符类型,wIndex为接口号
case Standard:
switch(req->wValue){
case Report://获取报告描述符
break;
case HID://获取接口描述符
break;
default:
break;
}
break;
case Class:
//................................
break;
default:
break;
}
break;
//*******************************到端点的请求***************************************************//
case ENDPOINT:
break;
default:
break;
//************************************************************************************************
}
}else if(数据过程){
发送数据/接收数据;
数据发送完成/接收完成结束;
}
}
2.2 发送报告
hid主机每间隔一段时间(在端点描述符中)就会查询从机是否有数据发送,从机只要将相应报告数据回复主机
3.参考文档
USB官网:https://www.usb.org/
HID1_11.pdf
hut1_12v2.pdf