usb驱动开发10之usb_device_match

时间:2021-12-17 20:38:04

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

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

usb驱动开发10之usb_device_matchusb驱动开发10之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 */注释的含义了吗????含蓄的我都不想再解释了。

usb驱动开发10之usb_device_matchusb驱动开发10之usb_device_match
/**
* 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设备驱动与接口驱动到底都有多大的不同。

usb驱动开发10之usb_device_matchusb驱动开发10之usb_device_match
/**
* 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世界里的整个人生旅程。