USB 鼠标驱动源码分析

时间:2024-05-31 08:38:10

kernel:kernel-3.4.39

UHCI: intel, 低速(1.5Mbps)/全速(12Mbps)
OHCI: microsoft 低速/全速
EHCI: 高速(480Mbps)

 

 USB总线驱动程序的作用:

1、分配地址给USB设备,同时将分配的地址发给USB设备(最开始通信地址是端口0)

2、发出命令获取描述符

3、查找和安装对应的设备驱动程序

4、提供USB读写函数

 

一个usb硬件有一个“设备描述符”;一个设备描述符下会有一个或多个“配置”;一个配置里可能有多个“接口——逻辑设备”;一个“接口”里面有多个“端点描述符”

“端点描述符”里面描述了一次性最多可以传输多少的数据;端口编号、方向、传输类型等信息。

 

USB主要有4种描述符:设备描述符、配置描述符、接口描述符、端点描述符(这是必须存在的描述符)

 

struct usb_device_descriptor {

         __u8  bLength;

         __u8  bDescriptorType;

 

         __le16 bcdUSB;

         __u8  bDeviceClass;

         __u8  bDeviceSubClass;

         __u8  bDeviceProtocol;

         __u8  bMaxPacketSize0;

         __le16 idVendor;

         __le16 idProduct;

         __le16 bcdDevice;

         __u8  iManufacturer;

         __u8  iProduct;

         __u8  iSerialNumber;

         __u8  bNumConfigurations;

} __attribute__ ((packed));

 

bLength:描述符长度

bDescriptorType:设备描述符 USB_DT_DEVICE 0x01

bcdUSB:USB: 描述符版本号,一个设备如果可以进行高速传输,那么设备描述符就是0200H

bDeviceClass:

bDeviceSubClass:

bDeviceProtocol:

bMaxPacketSize0:端点0一次可以处理最大字节,可选8、16、32、64低速8,高速64

idVendor:厂商ID

idProduct: 产品ID

bcdDevice:设备版本号

iManufacturer:厂商对应的字符串描述的索引值

iProduct:产品对应的字符串描述的索引值

iSerialNumber:***对应的字符串描述的索引值

bNumConfigurations:设备当前速度模式下支持的配置数量

 

配置描述符:

struct usb_config_descriptor {

         __u8  bLength;

         __u8  bDescriptorType;

 

         __le16 wTotalLength;

         __u8  bNumInterfaces;

         __u8  bConfigurationValue;

         __u8  iConfiguration;

         __u8  bmAttributes;

         __u8  bMaxPower;

} __attribute__ ((packed));

 

bLength:描述符长度

bDescriptorType:描述符类型

wTotalLength:使用GET_DESCRIPORT请求从设备获取的配置描述符信息返回的数据长度

bNumInterfaces:配置包含的接口数目

bConfigurationValue:要**的配置

iConfiguration:描述配置信息的字符串描述符的索引值

bmAttributes:

bMaxPower:从总线获取的最大电流值,2mA为单位

 

接口描述符:

struct usb_host_interface {

         struct usb_interface_descriptor     desc;

 

         /* array of desc.bNumEndpoint endpoints associated with this

          * interface setting.  these will be in no particular order.

          */

         struct usb_host_endpoint *endpoint;

 

         char *string;             /* iInterface string, if present */

         unsigned char *extra;   /* Extra descriptors */

         int extralen;

};

 

struct usb_interface_descriptor {

         __u8  bLength;

         __u8  bDescriptorType;

 

         __u8  bInterfaceNumber;

         __u8  bAlternateSetting;

         __u8  bNumEndpoints;

         __u8  bInterfaceClass;

         __u8  bInterfaceSubClass;

         __u8  bInterfaceProtocol;

         __u8  iInterface;

} __attribute__ ((packed));

 

__attribute__ ((packed)),意思就是告诉编译器,这个结构的元素都是 1 字节对齐的,不要再添加填充位了。如果不给编译器这么个暗示,编译器就会依据你平台的类型在结构的每个元素之间添加一定的填充位

 

bLength:描述符的字节长度。协议里规定,每个描述符必须以一个字节打头来表明描述符的长度。那可以扳着指头数一下,接口描述符的 bLength 应该是 9

 

bDescriptorType:描述符的类型,接口描述符在ch9.h的头文件中有定义USB_DT_INTERFACE

 

bInterfaceNumber:接口号。每个配置可以包含多个接口,这个值就是接口的索引值。

 

bAlternateSetting:接口使用的是哪个可选设置。协议里规定,接口默认使用的设置总为 0 号设置。

 

bNumEndpoints:接口拥有的端点数量。这里并不包括端点 0,端点 0 是所有的设备都必须提供的,所以这里就没必要再包括它了。

bInterfaceClass 、 bInterfaceSubClass、 bInterfaceProtocol:

bInterfaceClass接口类

bInterfaceSubClass接口子类

bInterfaceProtocol接口协议

每个Device或Interface属于一个Class,然后 Class 下面又分了 SubClass, 完了 SubClass 下面又按各种设备所遵循的不同的通信协议继续细分。 usb 协议里边为每一种 Class,每一种 SubClass,每一种 Protocol 定义一个数值

 

iInterface:接口对应的字符串描述符的索引值。一些设备专门准备了一些字符串描述符(string descriptor),就用来记这些长串的东西。字符串描述符主要就是提供一些设备接口相关的描述性信息, 比如厂商的名字, 产品***等等。 字符串描述符当然可以有多个,这里的索引值就是用来区分它们的。

 

端口描述符:

struct usb_host_endpoint {

         struct usb_endpoint_descriptor               desc;

         struct usb_ss_ep_comp_descriptor        ss_ep_comp;

         struct list_head                 urb_list;

         void                              *hcpriv;

         struct ep_device               *ep_dev; /* For sysfs info */

 

         unsigned char *extra;   /* Extra descriptors */

         int extralen;

         int enabled;

};

 

struct usb_endpoint_descriptor {

         __u8  bLength;

         __u8  bDescriptorType;

 

         __u8  bEndpointAddress;

         __u8  bmAttributes;

         __le16 wMaxPacketSize;

         __u8  bInterval;

 

         /* NOTE:  these two are _only_ in audio endpoints. */

         /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */

         __u8  bRefresh;

         __u8  bSynchAddress;

} __attribute__ ((packed));

 

与上面的接口描述符类似

bLength:描述符的字节长度,这里是9个字节

bDescriptorType:描述符类型

bEndpointAddress:这个字段包含了端点地址、输入端点还是输出端点;bits 0~3表示端点号,bit 8表示方向,输入还是输出

bmAttributes:属性。bits 0~1表示传输类型,00 控制、01等时、10批量、11中断

wMaxPacketSize:端点一次可以处理的最大字节数

bInterval:轮询时间

最后两个字节是针对音频的扩展


 

一个USB设备可能有多种功能,例:可以录音、录像;键盘带有扬声器等

一个接口表示usb设备的一个功能 接口下的端点表示的是数据通道,读、写端点是不同的

 

USB总线驱动设备模型程序,在插入USB设备时,会构造一个新的usb_dev注册到“usb_bus_type”usb总线设备驱动模型中。写驱动时我们需要声明一个usb_driver结构体,也注册到usb_bus_type中。在usb设备插入时,就要去匹配驱动usb_driver结构体中id_table,是否有驱动去支持这个设备,当设备在id_table中找到对应的设备驱动则调用usb_driver的.probe函数。

 

首先构造一个USB_driver结构体

USB 鼠标驱动源码分析

 

.probe :表示“USB 总线驱动程序”发现一个新设备后,就会与 driver 比较,若 id_table 表示能支持它,就调用.probe 函数。

.disconnect :拔掉 USB 设备时调用这个函数

.id_table :表示能支持的设备

 

首先确定我们的驱动要支持哪一类设备 id_table

USB 鼠标驱动源码分析

我们需要设置的支持项包括接口类,接口子类,接口协议三个匹配项。

.match_flags                      :表示要匹配“设备描述符”中的哪一项

.bInterfaceClass                : 接口描述符里的类cl

.bInterfaceSubClass                  : 接口描述符里的子类sc

USB 鼠标驱动源码分析.bInterfaceProtocol          : 接口协议pr

这个id_table中

类是USB_INTERFACE_CLASS_HID  HID

子类是USB_INTERFACE_SUBCLASS_BOOT  BOOT

协议是USB_INTERFACE_PROTOCOL_MOUSE  MOUSE

 

如果想支持某一个设备,则需要VID(厂家ID)、PID(设备ID)

这样就可以支持对应厂家对应的设备了。

 

 

假设插入设备与id_table匹配,就调用.probe

待续·······