您的位置:首页 > 运维架构 > Linux

Linux那些事儿 之 戏说USB(17)向左走,向右走

2015-03-25 11:38 351 查看
drivers/usb/core/driver.c

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;

		/* TODO: Add real matching code */
		return 1;

	} 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设备走,一条给USB接口走。

drivers/usb/core/usb.h

static inline int is_usb_device(const struct device *dev)
{
	return dev->type == &usb_device_type;
}
drivers/usb/core/usb.h里定义的这个函数看长相就是个把门儿的角色,这个函数就是要告诉你,是usb_device才能打这儿过,否则一边儿该干吗干吗去。但关键问题是它怎么知道你是不是usb_device,关键就在于这个dev->type,设备的类型,看它是不是等于咱们定义的usb_device_type,也就是说usb设备类型,相等的话,那好说,不相等,那就此路不是为你开的。usb_device_type在drivers/usb/core/usb.c里定义

struct device_type usb_device_type = {
	.name =		"usb_device",
	.release =	usb_release_dev,
	.uevent =	usb_dev_uevent,
	.devnode = 	usb_devnode,
#ifdef CONFIG_PM
	.pm =		&usb_device_pm_ops,
#endif
};
它和咱们前面看到的那个usb_bus_type差不多,一个表示总线的类型,一个表示设备的类型,总线有总线的类型,设备有设备的类型

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

546行,又见到一个if,一个把门儿的。它就跟在上面的is_usb_device函数后面在drivers/usb/core/usb.h文件里定义

/* Do the same for device drivers and interface drivers. */

static inline int is_usb_device_driver(struct device_driver *drv)
{
	return container_of(drv, struct usbdrv_wrap, driver)->
			for_devices;
}
这个函数的脸上就写着我是用来判断是不是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文件里

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 (*unlocked_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 disable_hub_initiated_lpm:1;
	unsigned int soft_unbind:1;
};
一般来说,我们平时所谓的编写usb驱动指的也就是写usb接口的驱动,需要以一个struct usb_driver结构的对象为中心,以设备的接口提供的功能为基础,开展usb驱动的建设。

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

probe,用来看看这个usb驱动是否愿意接受某个接口的函数。每个驱动自诞生起,它的另一半就已经确定了,这个函数就是来判断哪个才是她苦苦等待的那个他。当然,这个他应该是他们,因为一个驱动往往可以支持多个接口。

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

ioctl,当你的驱动有通过usbfs和用户空间交流的需要的话,就使用它吧。

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

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

id_table,驱动支持的所有设备的花名册,所有的三宫六院要想受到宠幸都要在这里登记。驱动就靠这张表儿来识别是不是支持哪个设备接口的,如果不属于这张表,那就躲一边儿去吧。

dynids,支持动态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

就可以将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标志来判断是哪种。其实就这么说为了加个判断标志就硬生生的塞这么一层,还是会有点模糊的,不过,其它字段不敢说,这个drvwrap咱们以后肯定还会遇到它,这里先有个概念,混个面熟。

no_dynamic_id,可以用来禁止动态id的,设置了之后,驱动就从一而终吧,别七想八想了。

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

struct usb_driver结构就暂时了解到这里,咱们再来看看所谓的usb设备驱动与接口驱动到底都有多大的不同。

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设备?还是独锁深闺垂影自恋决绝所有人?当然只会是前者,不然这个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设备驱动完全就是一个博爱的主儿,我们的core用它来与所有的usb设备进行交流,它们都交流些什么?这是后话,我会告诉你的。

不管怎么说,总算是把usb接口的驱动和设备的驱动给过了一下,还是回到这节开头儿的usb_device_match函数,目前为止,设备这条路已经比较清晰了。就是如果设备过来了,走到了设备这条路,然后要判断下驱动是不是设备驱动,是不是针对整个设备的,如果不是的话,对不起,虽然这条路走对了,可是沿这条路,设备找不到对应的驱动,匹配不成功,就直接返回了,那如果驱动也确实是设备驱动那?代码里是直接返回1,表示匹配成功了,没有再花费哪怕多一点儿的精力。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: