科创园

科创园地,分享技术知识,为科技助力发展,贡献一己之力。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

usb驱动开发10之usb_device_match

Posted on 2014-03-30 22:41  科创园  阅读(6800)  评论(0编辑  收藏  举报

在第五节我们说过会专门分析函数usb_device_match,以体现模型的重要性。同时,我们还是要守信用的。

再贴一遍代码,看代码就要不厌其烦。

 


前面说过,总线上挂着两条链表,一条是设备链表,一条是驱动链表,经过漫长的岁月里的煎熬,终于通过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 */注释的含义了吗????含蓄的我都不想再解释了。

 

这么长,为什么要贴出来,重要啊!还有什么比这注释看的更让人有劲有味的?

每个写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设备驱动与接口驱动到底都有多大的不同。

 


再一次连注释附上,表示这个结构体很重要。

这个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世界里的整个人生旅程。