19.向左走,向右走

19.向左走,向右走

我们回到前面提到的函数usb_device_match:

540 static int usb_device_match(struct device *dev, struct device_driver *drv)
541 {
542     /* devices and interfaces are handled separately */
543     if (is_usb_device(dev)) {
544
545     /* interface drivers never match devices */
546     if (!is_usb_device_driver(drv))
547            return 0;
548
549         /* TODO: Add real matching code */
550         return 1;
551
552      } else {
553         struct usb_interface *intf;
554         struct usb_driver *usb_drv;
555         const struct usb_device_id *id;
556
557          /* device drivers never match interfaces */
558         if (is_usb_device_driver(drv))
559            return 0;
560
561          intf = to_usb_interface(dev);
562          usb_drv = to_usb_driver(drv);
563
564          id = usb_match_id(intf, usb_drv->id_table);
565          if (id)
566          return 1;
567
568          id = usb_match_dynamic_id(intf, usb_drv);
569          if (id)
570          return 1;
571    }
572
573    return 0;
574 }

在USB的世界里,对于设备和驱动来说只是usb_device_match函数的两端。usb_device_ match函数为它们指明向左走还是向右走。

543行,第一次遇到这个函数时,我说了这里有两条路:一条给USB设备走,一条给USB接口走。先来查看设备走的这条路,上面只有两个函数。

85 static inline int is_usb_device(const struct device *dev)
86 {
87      return dev->type == &usb_device_type;
88 }

drivers/usb/core/usb.h中定义的这个函数就是要告诉你,只有usb_device才能从这里走。但关键问题不是它让不让你进去,而是它怎么知道你是不是usb_device。

关键就在于这个dev->type,设备的类型,看它是不是等于定义的usb_device_type,也就是说USB设备类型,相等的话,那可以通过;不相等,那就此路不是为你开的,你找别的路吧。usb_device_type在drivers/usb/core/usb.c中定义:

195 struct device_type usb_device_type = {
196     .name =   "usb_device",
197     .release =  usb_release_dev,
198 };

它和前面看到的usb_bus_type差不多,一个表示总线的类型,一个表示设备的类型,总线有总线的类型,设备有设备的类型。

假设现在过来一个设备,经过判断,它要走的是设备这条路,可问题是,这个设备的type字段什么时候被初始化成usb_device_type了。这倒是一个问题,不过先不说明,继续向前走,带着疑问上路。

546行,又见到一个if,它就在is_usb_device函数后面在drivers/usb/core/usb.h文件中定义:

92 static inline int is_usb_device_driver(struct device_driver *drv)
93 {
94     return container_of(drv, struct usbdrv_wrap, driver)->
95                   for_devices;
96 }

这个函数用于判断是不是usb device driver,那什么是usb device driver?前面不是一直都是说一个USB接口对应一个USB驱动吗?可是我们不能只钻到接口的那个接口里边儿,应该把眼界放得更加开阔一些,要知道接口在USB的世界里并不是老大,它上边儿还有配置,还有设备,都比它大。

每个接口对应了一个独立的功能,是需要专门的驱动来和它交流,但是接口毕竟整体是作为一个USB设备而存在的,设备还可以有不同的配置,我们还可以为设备指定特定的配置,那谁来做这个事情?struct usb_device _driver,即USB设备驱动,它和USB的接口驱动struct usb_driver都定义在include/linux/usb.h文件中。

833 struct usb_driver {
834     const char *name;
835
836     int (*probe) (struct usb_interface *intf,
837                 const struct usb_device_id *id);
838
839     void (*disconnect) (struct usb_interface *intf);
840
841     int (*ioctl) (struct usb_interface *intf, unsigned int code,
842                  void *buf);
843
844     int (*suspend) (struct usb_interface *intf, pm_message_t message);
845     int (*resume) (struct usb_interface *intf);
846
847     void (*pre_reset) (struct usb_interface *intf);
848     void (*post_reset) (struct usb_interface *intf);
849
850     const struct usb_device_id *id_table;
851
852     struct usb_dynids dynids;
853     struct usbdrv_wrap drvwrap;
854     unsigned int no_dynamic_id:1;
855     unsigned int supports_autosuspend:1;
856 };

一般来说,我们平时所谓的编写USB驱动指的也就是写USB接口的驱动,需要以一个struct usb_driver结构的对象为中心,以设备的接口提供的功能为基础,开展USB驱动的建设。

834行,name,驱动程序的名字,对应了在/sys/bus/usb/drivers/下面的子目录名称。和我们每个人一样,它只是区别彼此的一个代号,不同的是我们可以有很多人同名,但这里的名字在所有的USB驱动中必须是唯一的。

836行,probe,用来看一看这个USB驱动是否愿意接受某个接口的函数。一个驱动往往可以支持多个接口。

839行,disconnect,当接口失去联系,或使用rmmod卸载驱动将它和接口强行分开时这个函数就会被调用。

841行,ioctl,当你的驱动需要通过usbfs和用户空间交流的话,就可以使用ioctl。

844行,suspend;845行,resume,分别在设备被挂起和唤醒时使用。

847行,pre_reset;848行,post_reset,分别在设备将要复位(reset)和已经复位后使用。

850行,id_table,驱动支持的所有设备的列表,驱动就靠这张列表来识别是不是支持哪个设备接口的,如果不属于这张列表,那就不支持。

852行,dynids,支持动态id。什么是动态id?每个驱动诞生时它的id在id_table里就已经确定了,可是Greg显然在一年多前加入了动态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

可以将十六进制值0557和2008写到foo_driver驱动的设备id表里。

853行,drvwrap,这个字段是struct usbdrv_wrap结构,也在include/linux/usb.h中定义。

779 struct usbdrv_wrap {
780     struct device_driver driver;
781     int for_devices;
782 };

近距离观察这个结构,它里面内容比较贫乏,只有一个struct device_driver结构的对象和一个for_devices的整型字段。回想Linux的设备模型,我们就会产生这样的疑问,这里的struct device_driver对象不是应该嵌入到struct usb_driver结构中吗,怎么这里又包装了一层?

再包装这么一层当然不是为了美观,这主要还是因为本来驱动在USB的世界里不得已被分成了设备驱动和接口驱动两种,为了区分这两种驱动,就在中间加了这么一层,添了一个for_devices标志来判断是哪种驱动。

不知你有没有发现,之前见识过的结构中,很多不是1就是0的标志使用的是位字段,特别是几个这样的标志放一起时,而这里的for_devices虽然只能有两个值,但却没有使用位字段,为什么?因为没必要,那些使用位字段的是几个在一块儿,可以节省点儿存储空间,而这里只有这么一个,就是使用位字段也节省不了,就不用多此一举了。

其实就这么说为了加一个判断标志就硬生生地加这么一层,不过,这个drvwrap以后肯定还会遇到它,这里先简单介绍。

854行,no_dynamic_id,可以用来禁止动态id。

855行,supports_autosuspend,对autosuspend的支持,如果设置为0的话,就不再允许绑定到这个驱动的接口autosuspend。

struct usb_driver结构就暂时了解到这里,再来看一看所谓的USB设备驱动与接口驱动的区别。

878 struct usb_device_driver {
879     const char *name;
880
881     int (*probe) (struct usb_device *udev);
882     void (*disconnect) (struct usb_device *udev);
883
884     int (*suspend) (struct usb_device *udev, pm_message_t message);
885     int (*resume) (struct usb_device *udev);
886     struct usbdrv_wrap drvwrap;
887     unsigned int supports_autosuspend:1;
888 };

这个USB设备驱动比前面的接口驱动要简洁多了,除了少很多参数外,剩下的将参数中的struct usb_interface换成struct usb_device后就几乎一模一样了。

提醒的是,这里说的是几乎,而不是完全,这是因为probe,它的参数中与接口驱动里的probe相比少了设备的列表,也就是说它不用再去根据列表来判断是不是愿意接受一个USB设备。那么这意味着什么?是它来者不拒,接受所有的USB设备?还是拒绝所有的USB设备?当然只会是前者,不然这个USB设备驱动就完全毫无疑义了,而且我们在内核中找来找去,也就只能找到它在drivers/usb/core/generic.c文件中定义了usb_generic_driver这个对象:

210 struct usb_device_driver usb_generic_driver = {
211    .name = "usb",
212    .probe = generic_probe,
213    .disconnect = generic_disconnect,
214 #ifdef CONFIG_PM
215    .suspend = generic_suspend,
216    .resume = generic_resume,
217 #endif
218    .supports_autosuspend = 1,
219 };

这个对象在usb_init的895行就已经注册给USB子系统了。

不管怎么说,总算是把USB接口的驱动和设备的驱动介绍完了,还是回到这节开头的usb_device_match函数,目前为止,设备走的这条路已经比较清晰了,就是如果设备过来了,走到了设备这条路,然后要判断驱动是不是设备驱动,是不是针对整个设备的,如果不是的话,对不起,虽然这条路走对了,可是沿这条路,设备找不到对应的驱动,匹配不成功,就直接返回了。那如果驱动也确实是设备驱动呢?代码直接返回1,表示匹配成功了。

本来这么说应该是可以了,可是我还是忍不住想告诉你,在之前的内核版本里,是没有很明确的struct usb_device_driver这样一个表示USB设备驱动的结构的,而是直接定义了struct device_driver结构类型的一个对象usb_generic_driver来处理与整个设备相关的事情,相对应的,usb_device_match这个匹配函数也只有简单的一条路,在接口和对应的驱动之间做匹配。但是在2006年,内核中多了struct usb_device_driver结构,usb_device_match这里也多了一条给设备走的路。

是时候也有必要对USB设备在USB世界里的整个人生旅程做一个介绍了。