usb驱动开发10之usb_device_match
在第五节我们说过会专门分析函数usb_device_match,以体现模型的重要性。同时,我们还是要守信用的。
再贴一遍代码,看代码就要不厌其烦。


static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { /* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;usb_device_driver /* TODO: Add real matching code */
return 1;
usb_device } else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id; /* device drivers never match interfaces */
if (is_usb_device_driver(drv))
return 0; intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv); id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1; id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
} return 0;
}
前面说过,总线上挂着两条链表,一条是设备链表,一条是驱动链表,经过漫长的岁月里的煎熬,终于通过usb_device_match这位大媒人的牵引下一个个的匹配成功了,当然也会有失败哦,缘分天注定嘛。
USB的世界里,设备和驱动对于我们来说是不可言传的玄机,对于它们来说只是usb_device_match函数的两端。usb_device_match函数为它们指明哪个才是它们命中注定的缘。第一次遇到这个函数的时候,就说了这里有两条路,一条给USB设备走,一条给USB接口走。
is_usb_device函数相当于是一个把门的,在进入关卡前需要安检一样。
static inline int is_usb_device(const struct device *dev)
{
return dev->type == &usb_device_type;
}
is_usb_device函数里的usb_device_type定义如下:
struct device_type usb_device_type = {
.name = "usb_device",
.release = usb_release_dev,
};
假设现在过来一个设备,经过判断,它要走的是设备这条路,可问题是,这个设备的type字段啥时候被初始化成usb_device_type了,暂且不表,带着疑问上路吧?
is_usb_device_driver函数脸上写着我是用来判断是不是usb device driver的,那咱们就要讨论什么是usb device driver?前面一直都说一个usb接口对应一个usb驱动。对吗?你是不是曾经怀疑过?我可以负责任的告诉你,你记得没错,一个接口就是要对应一个usb驱动,可是我们不能只钻到接口的那个口里边儿,我们应该眼光放的更加开阔些,要知道接口在usb的世界里并不是老大,它上边儿还有配置,还有设备,都比它大。每个接口对应了一个独立的功能,是需要专门的驱动来和它交流,但是接口毕竟整体是作为一个usb设备而存在的,设备还可以有不同的配置,我们还可以为设备指定特定的配置,那谁来做这个事情?接口驱动么?它还不够级别,它的级别只够和接口会谈会谈。这个和整个usb设备进行对等交流的光荣任务就交给了struct usb_device _driver,即usb设备驱动,它和usb的接口驱动struct usb_driver都定义在include/linux/usb.h文件里。现在明白/* interface drivers never match devices */注释的含义了吗????含蓄的我都不想再解释了。


/**
* struct usb_driver - identifies USB interface driver to usbcore
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular
* interface on a device. If it is, probe returns zero and uses
* usb_set_intfdata() to associate driver-specific data with the
* interface. It may also use usb_set_interface() to specify the
* appropriate altsetting. If unwilling to manage the interface,
* return -ENODEV, if genuine IO errors occured, an appropriate
* negative errno value.
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.
* @ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
* @reset_resume: Called when the suspended device has been reset instead
* of being resumed.
* @pre_reset: Called by usb_reset_device() when the device
* is about to be reset.
* @post_reset: Called by usb_reset_device() after the device
* has been reset
* @id_table: USB drivers use ID table to support hotplugging.
* Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
* or your driver's probe function will never get called.
* @dynids: used internally to hold the list of dynamically added device
* ids for this driver.
* @drvwrap: Driver-model core structure wrapper.
* @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
* added to this driver by preventing the sysfs file from being created.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
* for interfaces bound to this driver.
* @soft_unbind: if set to 1, the USB core will not kill URBs and disable
* endpoints before calling the driver's disconnect method.
*
* USB interface drivers must provide a name, probe() and disconnect()
* methods, and an id_table. Other driver fields are optional.
*
* The id_table is used in hotplugging. It holds a set of descriptors,
* and specialized data may be associated with each entry. That table
* is used by both user and kernel mode hotplugging support.
*
* The probe() and disconnect() methods are called in a context where
* they can sleep, but they should avoid abusing the privilege. Most
* work to connect to a device should be done when the device is opened,
* and undone at the last close. The disconnect code needs to address
* concurrency issues with respect to open() and close() methods, as
* well as forcing all pending I/O requests to complete (by unlinking
* them as necessary, and blocking until the unlinks complete).
*/
struct usb_driver {
const char *name; int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id); void (*disconnect) (struct usb_interface *intf); int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf); int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf); int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf); const struct usb_device_id *id_table; struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
这么长,为什么要贴出来,重要啊!还有什么比这注释看的更让人有劲有味的?
每个写usb驱动的人心中都有一个usb_driver。一般来说,我们平时所谓的编写usb驱动指的也就是写usb接口的驱动,需要以一个struct usb_driver结构的对象为中心,以设备的接口提供的功能为基础,开展usb驱动的建设。
name,驱动程序的名字。
probe,用来看看这个usb驱动是否愿意接受某个(或多个)接口的函数。每个驱动自诞生起,它的另一半就已经确定了,这个函数就是来判断哪个才是她苦苦等待的那个他。当然,这个他应该是他们,因为一个驱动往往可以支持多个接口。
disconnect,当接口失去联系,或使用rmmod卸载驱动将它和接口强行分开时这个函数就会被调用。
ioctl,当你的驱动通过usbfs和用户空间交流的需要的话,就使用它吧。
suspend,resume,分别在设备被挂起和唤醒时使用。
pre_reset,post_reset,分别在设备将要复位(reset)和已经复位后使用。
id_table,驱动支持的所有设备的花名册,驱动就靠这张表儿来识别是不是支持哪个设备接口的。
dynids,支持动态id的。什么是动态id?本来前面刚说每个驱动诞生时她的另一半在id_table里就已经确定了,加入了动态id的机制。即使驱动已经加载了,也可以添加新的id给她,只要新id代表的设备存在。怎么添加新的id?到驱动所在的地方瞅瞅,也就是/sys/bus/usb/drivers目录下边儿,那里列出的每个目录就代表了一个usb驱动,随便选一个进去,能够看到一个new_id文件吧,使用echo将厂商和产品id写进去就可以了。看看Greg举的一个例子
echo 0557 2008 > /sys/bus/usb/drivers/foo_driver/new_id
就可以将16进制值0557和2008写到foo_driver驱动的设备id表里取。
drvwrap,这个字段有点意思,struct usbdrv_wrap结构的,也在include/linux/usb.h里定义。
struct usbdrv_wrap {
struct device_driver driver;
int for_devices;
};
这个结构里面只有一个struct device_driver结构的对象和一个for_devices的整型字段。回想一下linux的设备模型,我们的心头就会产生这样的疑问,这里的struct device_driver对象不是应该嵌入到struct usb_driver结构里么,为什么又要包装一层?主要是驱动在usb的世界里不得已分成了设备驱动和接口驱动两种,为了区分这两种驱动,就中间加了这么一层,添了个for_devices标志来判断是哪种(虽然用int整型)。大家发现没,之前见识过的结构里,很多不是1就是0的标志使用的是位字段,特别是几个这样的标志放一块儿的时候,而这里的for_devices虽然也只能有两个值,但却没有使用位字段,为什么?简单的说就是这里没那个必要,那些使用位字段的是几个在一块儿,可以节省点儿存储空间,而这里只有这么一个,就是使用位字段也节省不了,就不用多此一举了,这个大家都知道哈。其实就这么说为了加个判断标志就硬生生的塞这么一层,还是会有点模糊的,不过,其它字段不敢说,这个drvwrap咱们以后肯定还会遇到它,这里先有个概念,混个面熟,等到再次相遇的那一刻,你可能就会明白它的用心。
no_dynamic_id,可以用来禁止动态id的。
supports_autosuspend,对autosuspend的支持,如果设置为0的话,就不再允许绑定到这个驱动的接口autosuspend。
struct usb_driver结构就暂时了解到这里,咱们再来看看所谓的usb设备驱动与接口驱动到底都有多大的不同。


/**
* struct usb_device_driver - identifies USB device driver to usbcore
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular
* device. If it is, probe returns zero and uses dev_set_drvdata()
* to associate driver-specific data with the device. If unwilling
* to manage the device, return a negative errno value.
* @disconnect: Called when the device is no longer accessible, usually
* because it has been (or is being) disconnected or the driver's
* module is being unloaded.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
* @drvwrap: Driver-model core structure wrapper.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
* for devices bound to this driver.
*
* USB drivers must provide all the fields listed above except drvwrap.
*/
struct usb_device_driver {
const char *name; int (*probe) (struct usb_device *udev);
void (*disconnect) (struct usb_device *udev); int (*suspend) (struct usb_device *udev, pm_message_t message);
int (*resume) (struct usb_device *udev, pm_message_t message);
struct usbdrv_wrap drvwrap;
unsigned int supports_autosuspend:1;
};
再一次连注释附上,表示这个结构体很重要。
这个usb设备驱动比前面的接口驱动要少了很多东西外,剩下的将参数里的struct usb_interface换成struct usb_device后就几乎一摸一样了。友情提醒一下,这里说的是几乎,而不是完全,这是因为probe,它的参数里与接口驱动里的probe相比少了那个设备的花名册,也就是说它不用再去根据花名册来判断是不是愿意接受一个usb设备。即它来者不拒,接受所有的usb设备。在内核里找来找去,也就只能找得着它在drivers/usb/core/generic.c文件里定义了usb_generic_driver这么一个对象
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
即使这么一个独苗儿,也早在usb_init函数就已经注册给usb子系统了。
不管怎么说,总算是把usb接口的驱动和设备的驱动给过了一下,还是回到这节开头儿的usb_device_match函数,目前为止,设备这条路已经比较清晰了。就是如果设备过来了,走到了设备这条路,然后要判断下驱动是不是设备驱动,是不是针对整个设备的,如果不是的话,对不起,虽然这条路走对了,可是沿这条路,设备找不到对应的驱动,匹配不成功,就直接返回了,那如果驱动也确实是设备驱动那?代码里是直接返回1,表示匹配成功了。
现在是不是可以理解usb_device_match这里多了一条给设备走的路。暂时告别usb_device_match函数,我们去分析usb设备在usb世界里的整个人生旅程。
usb驱动开发10之usb_device_match的更多相关文章
- HarmonyOS USB DDK助你轻松实现USB驱动开发
HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载.驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效地开发驱 ...
- usb驱动开发5之总线设备与接口
Linux设备模型中的总线落实在USB子系统里就是usb_bus_type,它在usb_init的函数bus_register(&usb_bus_type)里注册.usb_bus_type定义 ...
- usb驱动开发之大结局
从usb总线的那个match函数usb_device_match()开始到现在,遇到了设备,遇到了设备驱动,遇到了接口,也遇到了接口驱动,期间还多次遇到usb_device_match(),又多次与它 ...
- usb驱动开发24之接口驱动
从第一节我们已经知道,usb_generic_driver在自己的生命线里,以一己之力将设备的各个接口送给了linux的设备模型,让usb总线的match函数,也就是usb_device_match, ...
- usb驱动开发15之设备生命线
总算是进入了HCD的片儿区,既然来到一个片区,怎么都要去拜会一下山头几个大哥吧.,先回忆一些我们怎么到这里的?给你列举一个调用函数过程usb_control_msg->usb_internal_ ...
- usb驱动开发14之设备生命线
直接看代码吧. /*-------------------------------------------------------------------*/ /** * usb_submit_urb ...
- usb驱动开发12之设备生命线
函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...
- usb驱动开发1之学习准备
此系列是http://blog.csdn.net/fudan_abc/博文的整理,同时加入了自己的理解.很敬佩fudan_abc的文章,仔细学习和分析受益很多.注:fundan_abc所分析linux ...
- 庖丁解牛:USB 驱动开发技术彻底解密
我们知道如果开发工程师不懂RS232 肯定会让人笑话可以想象面向未来USB 接口无处不在因此掌握USB 的原理固件编程及其驱动开发技术势必成为当务之急USB 即插即用的优点和灵活性运用于各种电子产品现 ...
随机推荐
- GTD桌面2.0
在以前实践了一个GTD桌面,当时称为1.0版本,当时的效果是这样的: 2015年更换一点设备,把GTD桌面升级一下,就称为2.0吧.直接上图: 可以发现显示器由以前的1台又变回2台,原以为1台大显示器 ...
- JSP Model模式
用JSP开发的Web应用模型可以分为Model1和Model2 对于小型的Web应用,通常可以使用模型1来完成. 模型1可以分为两种方式: 一种是完全使用JSP页面来开发Web应用: 另一种是使用JS ...
- 高级iOS面试题
非标准答案 2 1: 类方法是可以直接通过类名直接调用,无需进行实例化对象.类方法是以+开头2. 实例方法,需要显示实例化对象,为对象分配堆栈空间,并通过对象实例调用实例方法3. RUNTIME 是在 ...
- 【原】macbook不睡眠的排查与解决
这几天突然发现手上的macbook pro笔记本不能睡眠了,就算合上盖子也是如此.有没有进入睡眠可以观察右下角的呼吸灯,如果呼吸灯常亮则说明有问题.所谓“工欲善其事,必先利其器”,攻城狮想敲更多更好的 ...
- 朝花夕拾-android 自定义application 管理activity的生命周期
为了安全退出多个已创建的activity? 可以自定义application:myapplication. 增加一个list成员保存,一些关键的已创建的activity实例: private List ...
- 深入理解CSS中的层叠上下文和层叠顺序
零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在C ...
- Android 实用代码片段
一些不常见确又很实用的代码块. 1.精确获取屏幕尺寸(例如:3.5.4.0.5.0寸屏幕) public static double getScreenPhysicalSize(Activity ct ...
- Effective Java 61 Throw exceptions appropriate to the abstraction
Exception translation: higher layers should catch lower-level exceptions and, in their place, throw ...
- MySQL数据库初识(二)
8. 向数据表中插入数据记录(INSERT): 向数据表中插入数据记录有两种方法: 基本语法1:INSERT INTO 数据表 (字段名1,字段名2,字段名3……字段名n) VALUES (数据值1, ...
- ubuntu创建、删除文件及文件夹方法
mkdir 目录名 => 创建一个目录 rmdir 空目录名 => 删除一个空目录 rm 文件名 文件名 => 删除一个文件或多个文件 rm –rf 非 ...