linux usb 驱动程序开发,linux-usb驱动开发一

本文解析Linux USB驱动架构,介绍bus-device-driver模型及USB设备的枚举、匹配、探测流程。深入探讨Linux USB驱动注册机制,并分析关键数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用源码为: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;//该驱动的名称,推荐与模块同命

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完成时,传输状态。可用在完成回调者函数中进行判读

....

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值