您的位置:首页 > 运维架构 > Linux

linux-usb驱动开发一

2014-12-14 11:01 176 查看
使用源码为:Linux-2.6.29

一、linux-usb的bus-device-driver模型

Linux在内核中为bus-device-driver模型定义了三个数据结构体:struct bus_type、struct device、struct device_driver。而在usb模块,这三个数据结构体以此对应:struct usb_bus_type、struct usb_driver、struct usb_device。
bus的一端为device链表、另一端为driver链表。
对于ubs-device-driver的认识,目前仅限于此!

二、linux-usb的探测与去链接分析

2.1 枚举过程

该部分分析目前尚未推测阶段;如有错误,敬请指正!
在usb-host正式与usb-device开始真正通信之前,首先要对usb-deivce进行枚举。枚举过程就是获得usb-deivce的各种信息,例如PID、VID等等,也就是获得各种描述符。在Linux-USB模块中,该部分由USB-core执行,无需用户干预。
当USB-device插入时,会引发一个cpu中断。此时,CPU知道有新的设备插入,就通知USB-core对其进行枚举,以获得各种描述符信息。

2.2 匹配

当USB-core枚举过程完成后,USB-core将该USB-device的信息与驱动链表中的各个struct usb_device_id结构体进行匹配。若符合,则加载该驱动,匹配完成;否则,继续匹配。
struct usb_device_id{
__u16    mach_flag;
__u16    idVendor;
.....
}
该结构体第一个域,__u16_flag,指明了匹配项。也就是说,USB-core将会使用枚举出来的USB-device的哪些项与表中的进行匹配。
内核提供了几个相关的接口用来创建struct usb_device_id结构体。现一并收录如下:
USB_DEVICE(vendor,product)
创建struct usb_deivce_id结构体,仅和指定的pid、vid匹配。常用于需要特定驱动的USB-device
USB_DEVICE_VER(vendor,product,lo,hi)
创建struct usb_deivce_id结构体,仅和制定的pid、vid,且版本号符合的特定usb-device匹配
USB_DEVICE_INFO(class,subclass,protocol)
创建struct usb_deivce_id结构体,仅和制定的设备类和子类相匹配
USB_INTERFACE_INFO(class,subclass,protocol)
创建struct usb_deivce_id结构体,仅和指定的接口的类和子类相匹配

2.3 探测

当上述匹配成功后,USB-core自动调用该驱动注册的probe回调函数。
既然枚举过程已经获得了设备的各种信息,那probe回调函数还有什么用呢?
假设存在这样的设备:带有媒体功能的usb键盘。该键盘同时还可以播放音乐。
在USB中,功能是与接口相对应的。一种功能对应一个接口。因此,该设备要正常工作需要加载两个驱动模块:键盘、媒体。这两个驱动模块的struct usb_device_id都是与pid、vid进行匹配判断。
那么应该同时两个判断都成功。但是,这样的话,就会发生混乱。当键盘有键按下,或者媒体有音乐播放时,如何判断对应那个驱动呢?

probe回调函数完成的任务就是:检查传递给它的有关设备的信息,确定是否真的支持。例如,判断端点类型、方向等。

首先加载驱动,再插入设备
insmod命令加载驱动模块,USB-core探测到USB的驱动链表端有变化。然后,基于该新增加的驱动模块的struct usb_device_id结构体,USB-core在设备端的链表中搜索是否有与其匹配的项。如果有,则进行绑定;否则,不绑定。

推测:因为一个设备只能绑定一个驱动,因此,该处的搜索对象不应该包括已经与之前驱动进行过绑定的设备。与之前的驱动完成绑定关系的设备,肯定不是这个驱动的菜;因为,一个设备无法绑定两个驱动。因此,该处的搜索算法应该是遍历设备链表中所有未进行绑定关系的设备

首先插入设备,再加载驱动     
当有设备插入时,USB总线的设备链表发生变化。基于该新插入的设备,USB-core遍历驱动链表。但是,只要找到一个匹配项,则该搜索算法就结束。

三、Linux-USB驱动的注册

在bus-device-driver模型中,我们知道,bus的两端一端为设备链表,一端为驱动链表。Linux提供了一个将驱动增加到bus的一端的驱动链表的函数,即usb_register函数。该函数有个参数struct usb_driver类型。
struct usb_driver{
const char *name;<span style="white-space:pre">				</span>//该驱动的名称,推荐与模块同命
int (*probe)(struct usb_interface *intf);       //探测函数指针
int (*disconnect)(struct usb_interface *intf)   //去链接函数指针
....
....
const struct usb_device_id *id_table;           //匹配设备列表
....
}
与usb_register对应的,usb_deregister函数,将该驱动从驱动链表中去除。

四、部分数据结构体

4.1 struct usb_interface

虽然在bus-device-driver模型中存在struct device结构体,但是对于USB驱动而言,真正操作的对象是struct usb_interface。推测原因如下:
在USB中,一种功能对应一个接口,而一个驱动模块就是描述了设备的一种功能。
struct usb_interface{
struct usb_host_interface *altsetting;        //可选设置
struct usb_host_interface *cur_altsetting;    //当前设置
unsigned num_alsetting;                       //设置数,有几种可选设置
....
int minor;                                    //次设备好,因为USB设备主设备号是固定的,180
....
}

4.2 struct urb

urb结构体就是个信封,作用是用来封装正真的传输数据。整个驱动都是围绕着该结构体进行。其典型生命周期包括:

创建
填充
提交
释放
struct urb{
struct usb_device *dev;                     //urb所发送的目标指针
unsigned int pipe;
void *transfer_buff;                        //对于out-endpoint,为发送buffer;对于in-endpoint,为接收buffer
int transfer_buff_length;                   //该数据buffer的长度
usb_complete_t complete;                    //urb完成回调者函数
int actual_length;                          //当urb完成时,实际传送的数据长度
int state;                                  //当urb完成时,传输状态。可用在完成回调者函数中进行判读
....
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux驱动开发 usb