usb hub驱动

1. hub驱动流程图


2. hub驱动初始化

	retval = usb_hub_init(); 
int usb_hub_init(void)
{
	if (usb_register(&hub_driver) < 0) { //注册hub驱动到usb子系统总线上
		printk(KERN_ERR "%s: can't register hub driver\n",
			usbcore_name);
		return -1;
	}

	khubd_task = kthread_run(hub_thread, NULL, "khubd"); //创建hub内核线程
	if (!IS_ERR(khubd_task))
		return 0;

	/* Fall through if kernel_thread failed */
	usb_deregister(&hub_driver);
	printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);

	return -1;
}

usb_hub_init()函数主要包括两个方面,1. hub驱动注册, 2. hub线程创建,接下来将主要围绕他俩进行分析。

3. hub驱动注册

if (usb_register(&hub_driver) < 0) { //注册hub驱动到usb子系统总线上

在分析usb_register()函数前先看下hub_driver结构体:

static struct usb_driver hub_driver = {
	.name =		"hub",
	.probe =	hub_probe, //hub探测接口,重要,待分析!
	.disconnect =	hub_disconnect,
	.suspend =	hub_suspend, //hub挂起,涉及到PM电源管理驱动控制
	.resume =	hub_resume, //hub恢复,
	.reset_resume =	hub_reset_resume, //通过对hub复位来引发复位
	.pre_reset =	hub_pre_reset, //与PM电源管理系统相关
	.post_reset =	hub_post_reset, //与PM电源管理系统相关
	.unlocked_ioctl = hub_ioctl,
	.id_table =	hub_id_table, //hub id表,重要,待分析!!
	.supports_autosuspend =	1,
};

hub_id_table 对应结构体 struct usb_device_id:

struct usb_device_id {
	/*表示下面哪些字段(产品、设备类别、接口类)可以进行匹配*/
	/* which fields to match against? */
	__u16		match_flags; 

	/*用于产品的匹配*/
	/* Used for product specific matches; range is inclusive */
	__u16		idVendor;
	__u16		idProduct;
	__u16		bcdDevice_lo;
	__u16		bcdDevice_hi;

	/*用于设备类别的匹配*/
	/* Used for device class matches */
	__u8		bDeviceClass;
	__u8		bDeviceSubClass;
	__u8		bDeviceProtocol;

	/*用于接口类别的匹配*/
	/* Used for interface class matches */
	__u8		bInterfaceClass;
	__u8		bInterfaceSubClass;
	__u8		bInterfaceProtocol;

	/* Used for vendor-specific interface matches */
	__u8		bInterfaceNumber;

	/* not matched against */
	kernel_ulong_t	driver_info
		__attribute__((aligned(sizeof(kernel_ulong_t))));
}

而hub_id_table 分别初始化了三个usb_device_id结构体:

static const struct usb_device_id hub_id_table[] = {
    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR  //
	           | USB_DEVICE_ID_MATCH_INT_CLASS,
      .idVendor = USB_VENDOR_GENESYS_LOGIC,
      .bInterfaceClass = USB_CLASS_HUB,
      .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
      .bDeviceClass = USB_CLASS_HUB},
    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
      .bInterfaceClass = USB_CLASS_HUB},
    { }						/* Terminating entry */
};

第1个结构体成员

.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS, //表示需匹配的字段 

 .idVendor = USB_VENDOR_GENESYS_LOGIC, //匹配的字段
 .bInterfaceClass = USB_CLASS_HUB //匹配的字段


第2个结构体成员

.match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, //表示需匹配的字段

.bDeviceClass = USB_CLASS_HUB //匹配的字段

第3个结构体成员

.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,  //表示需匹配的字段
.bInterfaceClass = USB_CLASS_HUB //匹配的字段

综上所述,match_flags 表示哪些字段匹配,而对应匹配的字段就是idVendor 、bInterfaceClass ,bDeviceClass ,bInterfaceClass ,这里在下面会分析如何使用。

hub_probe()函数内容太多,我将它放到第4.节分析函数内部细节。

现在我们继续回到hub驱动注册:

#define usb_register(driver) \
	usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
			const char *mod_name)
{
	int retval = 0;

	if (usb_disabled())
		return -ENODEV;

	//对drvwrap USB驱动包初始化
	new_driver->drvwrap.for_devices = 0;
	new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
	new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
	new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
	new_driver->drvwrap.driver.remove = usb_unbind_interface;
	new_driver->drvwrap.driver.owner = owner;
	new_driver->drvwrap.driver.mod_name = mod_name;
	spin_lock_init(&new_driver->dynids.lock);
	INIT_LIST_HEAD(&new_driver->dynids.list);

	retval = driver_register(&new_driver->drvwrap.driver); //驱动注册
	if (retval)
		goto out;

	retval = usb_create_newid_files(new_driver);
	if (retval)
		goto out_newid;

	pr_info("%s: registered new interface driver %s\n",
			usbcore_name, new_driver->name);

out:
	return retval;

out_newid:
	driver_unregister(&new_driver->drvwrap.driver);

	printk(KERN_ERR "%s: error %d registering interface "
			"	driver %s\n",
			usbcore_name, retval, new_driver->name);
	goto out;
}
EXPORT_SYMBOL_GPL(usb_register_driver);

usb_register_driver()函数内部主要涉及到两个函数,驱动注册driver_register()和newid文件创建usb_create_newid_files(),接下来将逐个分析:

driver_register():

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);

	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
		printk(KERN_WARNING "Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);

	other = driver_find(drv->name, drv->bus); //这里查找drv->name="hub"驱动是否已经在drv->bus总线上注册。
	if (other) {
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}

	ret = bus_add_driver(drv); //bus总线上注册驱动
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}
EXPORT_SYMBOL_GPL(driver_register);

bus_add_driver() usb总线上添加hub驱动:

int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus); //drv->bus=&usb_bus_type, bus为usb_bus_type
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL); //分配一个驱动私有数据driver_private
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL); //初始化设备链表
	//以下相互绑定
	priv->driver = drv; //私有驱动数据绑定drv
	drv->p = priv; //drv->p驱动绑定priv
	priv->kobj.kset = bus->p->drivers_kset; //将priv->kobj.kset当前内核集合指向bus->p->drivers_kset内核集合(该集合在usb总线注册bus_register()描述)
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;

	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将当前注册的priv->knode_bus节点加入到全局bus->p->klist_drivers链表中
	if (drv->bus->p->drivers_autoprobe) { //在usb总线注册时对该变量drivers_autoprobe初始化为1了
		error = driver_attach(drv); //见下面,按照内核启动的流程分析,这个时候usb总线上只有hub这个驱动,没有设备,所以driver_attach函数将返回失败
		if (error)
			goto out_unregister;
	}
	module_add_driver(drv->owner, drv); //见下面,从该函数这开始,本次hub驱动将不会执行下面的函数了,不过为了分析函数内部的功能,我们继续,因为在其他驱动模块注册时会用到

	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_attrs(bus, drv);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
			__func__, drv->name);
	}

	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
		if (error) {
			/* Ditto */
			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
				__func__, drv->name);
		}
	}

	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

3.1 hub内核对象初始化

这里重点分析下内核对象初始化的内部细节,

error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);

其中,driver_ktype为驱动的内核集合类型,主要用来对内核对象的操作

static struct kobj_type driver_ktype = {
	.sysfs_ops	= &driver_sysfs_ops,
	.release	= driver_release,
};
static const struct sysfs_ops driver_sysfs_ops = {
	.show	= drv_attr_show,
	.store	= drv_attr_store,
};
static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
			     char *buf)
{
	struct driver_attribute *drv_attr = to_drv_attr(attr); //获取驱动的属性结构体
	struct driver_private *drv_priv = to_driver(kobj); //获取驱动的私有数据
	ssize_t ret = -EIO;

	if (drv_attr->show) //驱动属性文件是否不为NULL
		ret = drv_attr->show(drv_priv->driver, buf); //显示驱动
	return ret;
}

static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
			      const char *buf, size_t count)
{
	struct driver_attribute *drv_attr = to_drv_attr(attr);
	struct driver_private *drv_priv = to_driver(kobj);
	ssize_t ret = -EIO;

	if (drv_attr->store)
		ret = drv_attr->store(drv_priv->driver, buf, count); //存储
	return ret;
}

分析完了驱动内核对象类型操作,再回到内核对象的初始化

int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
			 struct kobject *parent, const char *fmt, ...)
{
	va_list args;
	int retval;

	kobject_init(kobj, ktype); //初始化内核对象(绑定内核对象kobject的内核对象类型接口为ktype)

	va_start(args, fmt);
	retval = kobject_add_varg(kobj, parent, fmt, args); //内核对象增加,即创建hub目录
	va_end(args);

	return retval;
}
EXPORT_SYMBOL_GPL(kobject_init_and_add);
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
	char *err_str;

	if (!kobj) {
		err_str = "invalid kobject pointer!";
		goto error;
	}
	if (!ktype) {
		err_str = "must have a ktype to be initialized properly!\n";
		goto error;
	}
	if (kobj->state_initialized) {
		/* do not error out as sometimes we can recover */
		printk(KERN_ERR "kobject (%p): tried to init an initialized "
		       "object, something is seriously wrong.\n", kobj);
		dump_stack();
	}

	kobject_init_internal(kobj);
	kobj->ktype = ktype; //绑定内核对象的内核类型(内核对象的操作接口)
	return;

error:
	printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
	dump_stack();
}
EXPORT_SYMBOL(kobject_init);
static void kobject_init_internal(struct kobject *kobj)
{
	if (!kobj)
		return;
	kref_init(&kobj->kref);
	INIT_LIST_HEAD(&kobj->entry); //表示父内核对象下挂接的子内核对象
	kobj->state_in_sysfs = 0; //sysfs没有初始化(涉及到sysfs文件系统)
	kobj->state_add_uevent_sent = 0; //用户层事件是否发送
	kobj->state_remove_uevent_sent = 0; //用户层事件是否移除
	kobj->state_initialized = 1; //kobj对象初始化完成标识
}

kobject_init_and_add()->kobject_add_varg():

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
			    const char *fmt, va_list vargs)
{
	int retval;

	retval = kobject_set_name_vargs(kobj, fmt, vargs); //设置内核对象的名称为hub
	if (retval) {
		printk(KERN_ERR "kobject: can not set name properly!\n");
		return retval;
	}
	kobj->parent = parent;
	return kobject_add_internal(kobj); //内核对象增加,在sys文件系统下创建目录hub,绝对路径/sys/bus/usb/drivers/hub
}
static int kobject_add_internal(struct kobject *kobj)
{
	int error = 0;
	struct kobject *parent;

	if (!kobj)
		return -ENOENT;

	if (!kobj->name || !kobj->name[0]) {
		WARN(1, "kobject: (%p): attempted to be registered with empty "
			 "name!\n", kobj);
		return -EINVAL;
	}

	parent = kobject_get(kobj->parent);

	/* join kset if set, use it as parent if we do not already have one */
	if (kobj->kset) { //kset为usb集合(因为kset集合是被内核对象绑定,所以下面可以获取内核对象)
		if (!parent)
			parent = kobject_get(&kobj->kset->kobj); //即为usb内核对象
		kobj_kset_join(kobj);
		kobj->parent = parent;
	}

	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
		 kobject_name(kobj), kobj, __func__,
		 parent ? kobject_name(parent) : "<NULL>",
		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

	error = create_dir(kobj);
	if (error) {
		kobj_kset_leave(kobj);
		kobject_put(parent);
		kobj->parent = NULL;

		/* be noisy on error issues */
		if (error == -EEXIST)
			WARN(1, "%s failed for %s with "
			     "-EEXIST, don't try to register things with "
			     "the same name in the same directory.\n",
			     __func__, kobject_name(kobj));
		else
			WARN(1, "%s failed for %s (error: %d parent: %s)\n",
			     __func__, kobject_name(kobj), error,
			     parent ? kobject_name(parent) : "'none'");
	} else
		kobj->state_in_sysfs = 1; //表示kobject对象在sysfs中的状态

	return error;
}

小节,到这里完成了hub内核对象的初始化和添加,并将该节点添加到了usb总线的bus->p->klist_drivers驱动链表中,同时创建目录hub,绝对路径为/sys/bus/usb/hub;接下来将分析driver_attach()

3.2 驱动绑定driver_attach()

路径:bus_add_driver()-->driver_attach(drv)

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //__driver_attach见下分析
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,//设备通过bus_add_device(...)添加时,最终会将设备加入到bus->p->klist_devices设备链表中
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error) 
		error = fn(dev, data); //回调接口函数__driver_attach
	klist_iter_exit(&i);
	return error;
}

bus_for_each_dev()函数内部主要是遍历usb总线的设备链表(由于本次注册的是hub驱动),需找与本次注册的hub驱动相匹配;

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

	if (!driver_match_device(drv, dev)) //驱动和设备是否匹配,不匹配将退出,bus_for_each_dev函数继续下一个设备来匹配...
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver) 
		driver_probe_device(drv, dev); //探测函数
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

driver_match_device():

static inline int driver_match_device(struct device_driver *drv, struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

通过上面的usb_register_driver()函数分析,得知这里的drv为new_driver->drvwrap.driver,再次贴上该代码

	new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
	new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
	new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
	new_driver->drvwrap.driver.remove = usb_unbind_interface;
	new_driver->drvwrap.driver.owner = owner;
	new_driver->drvwrap.driver.mod_name = mod_name;

所以driver_match_device()函数内部drv->bus=&usb_bus_type,即会调用 drv->bus->match(dev, drv)

struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match, //见下
	.uevent =	usb_uevent,
};
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* devices and interfaces are handled separately */
	if (is_usb_device(dev)) { //是否是usb设备

		/* 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)) { //是否是usb接口
		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_register()函数注册时并未绑定类型,所以这里直接返回0,也就不会执行相应的probe探测函数了。那么这里就有疑问,usb设备和接口是什么时候被调用呢?在接下来的章节中将详细分析, intf->dev.type = &usb_if_device_type 将在usb_set_configuration()内部初始化,dev->dev.type = &usb_device_type将在usb_alloc_dev()内部初始化,这里先留个悬疑.....

3.3 module_add_driver()驱动模块增加

      Hub驱动注册到usb总线上,并且这个时候usb总线上只有hub一个驱动,所以上面调用usb_device_match函数时将无法在对应的usb总线上匹配到设备,即该函数module_add_driver将不会被执行!不过为了后续再调用到该函数时不解,这里继续分析

module_add_driver(drv->owner, drv);
void module_add_driver(struct module *mod, struct device_driver *drv)
{
	char *driver_name;
	int no_warn;
	struct module_kobject *mk = NULL;

	if (!drv)
		return;

	if (mod) //mod为真
		mk = &mod->mkobj;
	else if (drv->mod_name) { //驱动名称,假设是usb主机控制器"ehci_hcd"
		struct kobject *mkobj;

		/* Lookup built-in module entry in /sys/modules */
		mkobj = kset_find_obj(module_kset, drv->mod_name); //根据mod_name,在module_kset内核集合上查找是否有相同的驱动
		if (mkobj) {
			mk = container_of(mkobj, struct module_kobject, kobj); //通过结构体成员mkobj,获取对应的module_kobject结构体指针
			/* remember our module structure */
			drv->p->mkobj = mk;
			/* kset_find_obj took a reference */
			kobject_put(mkobj);
		}
	}

	if (!mk)
		return;

	/* Don't check return codes; these calls are idempotent */
	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //创建module符号链接,即/sys/bus/usb/drivers/hub/module
	driver_name = make_driver_name(drv); //driver_name ="usb:hub"
	if (driver_name) {
		module_create_drivers_dir(mk); //创建目录/sys/bus/usb/drivers/hub/module/usb:hub
		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
					    driver_name);
		kfree(driver_name);
	}
}

3.5 驱动属性文件绑定

路径:linux-3.10.x\include\linux\device.h

#define DRIVER_ATTR(_name, _mode, _show, _store)	\
struct driver_attribute driver_attr_##_name =		\
	__ATTR(_name, _mode, _show, _store)
static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
static ssize_t driver_uevent_store(struct device_driver *drv,
				   const char *buf, size_t count)
{
	enum kobject_action action;

	if (kobject_action_type(buf, count, &action) == 0)
		kobject_uevent(&drv->p->kobj, action);
	return count;
}
所以上面创建了驱动属性文件结构体driver_attr_uevent
error = driver_create_file(drv, &driver_attr_uevent); //创建驱动的属性文件操作
error = driver_add_attrs(bus, drv); //总线上增加属性文件操作
error = add_bind_files(drv);

4. hub_probe()

hub_probe()是被主机控制器ehci注册hub root时调用,详见:点击打开链接

5. hub_thread()

当usb主机控制器检测到设备接入时,通过等待队列唤醒hub_thread线程,执行usb设备的枚举,最终调用hub_probe(),关于hub_thread()分析,详见:点击打开链接

6. 总结:

usb hub初始化换号usb_hub_init()主要完成两个工作,

1. 注册hub驱动到usb总线上,其中最重要的就是hub_probe()函数;

2. 创建hub_thread()内核线程,用来处理usb主机控制器插入设备时的枚举操作。




  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值