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

linux设备模型之bus,device,driver分析二

2011-05-17 16:40 676 查看
===============================

本文系本站原创,欢迎转载!

转载请注明出处:http://blog.csdn.net/gdt_a20

===============================

上篇分析了bus,driver的注册过程,这篇主要分析device的注册,并总结给出个流程图。

三、device的注册

还是照例先看一下device的结构:

struct device {
	struct device		*parent;
	struct device_private	*p;                                              //私有属性结构,重点
	struct kobject kobj;
	const char		*init_name; /* initial name of the device */
	struct device_type	*type;
	struct mutex		mutex;	/* mutex to synchronize calls to
					 * its driver.
					 */
	struct bus_type	*bus;		/* type of bus device is on */            //所在bus
	struct device_driver *driver;	/* which driver has allocated this    //匹配的driver
					   device */
	void		*platform_data;	/* Platform specific data, device
					   core doesn't touch it */
	struct dev_pm_info	power;
#ifdef CONFIG_NUMA
	int		numa_node;	/* NUMA node this device is close to */
#endif
	u64		*dma_mask;	/* dma mask (if dma'able device) */
	u64		coherent_dma_mask;/* Like dma_mask, but for
					     alloc_coherent mappings as
					     not all hardware supports
					     64 bit addresses for consistent
					     allocations such descriptors. */
	struct device_dma_parameters *dma_parms;
	struct list_head	dma_pools;	/* dma pools (if dma'ble) */
	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
					     override */
	/* arch specific additions */
	struct dev_archdata	archdata;
#ifdef CONFIG_OF
	struct device_node	*of_node;
#endif
	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
	spinlock_t		devres_lock;
	struct list_head	devres_head;
	struct klist_node	knode_class;
	struct class		*class;
	const struct attribute_group **groups;	/* optional groups */
	void	(*release)(struct device *dev);
};
//重点看一下私有属性结构
struct device_private {
	struct klist klist_children;             //子集结构
	struct klist_node knode_parent;          //父级挂接点
	struct klist_node knode_driver;          //driver挂接点
	struct klist_node knode_bus;             //bus挂接点
	void *driver_data;
	struct device *device;                   //回指
};


接下来详细看一下device的注册device_register:

int device_register(struct device *dev)
{
	device_initialize(dev);                //初始化dev
	return device_add(dev);                //添加dev
}
/******************************
* 先看一下device_initialize(dev)
******************************/
void device_initialize(struct device *dev)
{
	dev->kobj.kset = devices_kset;                  //可见device和bus都有其起始的kset,而driver没有
	kobject_init(&dev->kobj, &device_ktype);        //初始化这个kobj并建立层次关系以及属性文件,此时
	INIT_LIST_HEAD(&dev->dma_pools);                //是放到了总的device文件目录下面
	mutex_init(&dev->mutex);
	lockdep_set_novalidate_class(&dev->mutex);
	spin_lock_init(&dev->devres_lock);
	INIT_LIST_HEAD(&dev->devres_head);
	device_pm_init(dev);
	set_dev_node(dev, -1);
}
/******************************
* 再来看一下device_add(dev)
******************************/
int device_add(struct device *dev)
{
	struct device *parent = NULL;
	struct class_interface *class_intf;
	int error = -EINVAL;
	dev = get_device(dev);
	if (!dev)
		goto done;
	if (!dev->p) {
		error = device_private_init(dev);                        //初始化dev的私有成员,及其链表操作函数
		if (error)
			goto done;
	}
	/*
	 * for statically allocated devices, which should all be converted
	 * some day, we need to initialize the name. We prevent reading back
	 * the name, and force the use of dev_name()
	 */
	if (dev->init_name) {
		dev_set_name(dev, "%s", dev->init_name);                 //设置名字,给kobj
		dev->init_name = NULL;
	}
	if (!dev_name(dev)) {                                         //名字为空出错退出
		error = -EINVAL;
		goto name_error;
	}
	pr_debug("device: '%s': %s/n", dev_name(dev), __func__);
	parent = get_device(dev->parent);                          //返回父节点,如果有返回,没有返回NULL
	setup_parent(dev, parent);                   
	/* use parent numa_node */
	if (parent)
		set_dev_node(dev, dev_to_node(parent));
	/* first, register with generic layer. */
	/* we require the name to be set before, and pass NULL */
	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);   //初始化kobj与其父节点的连接
	if (error)
		goto Error;
	/* notify platform of device entry */
	if (platform_notify)
		platform_notify(dev);
	error = device_create_file(dev, &uevent_attr);             //产生属性文件
	if (error)
		goto attrError;
	if (MAJOR(dev->devt)) {
		error = device_create_file(dev, &devt_attr);             //在sys下产生dev属性文件
		if (error)
			goto ueventattrError;
		error = device_create_sys_dev_entry(dev);
		if (error)
			goto devtattrError;
		devtmpfs_create_node(dev);                               
	}
	error = device_add_class_symlinks(dev);                    
	if (error)
		goto SymlinkError;
	error = device_add_attrs(dev);                             //增加属性文件
	if (error)
		goto AttrsError;
	error = bus_add_device(dev);                               //把device的bus节点挂到bus的设备节点上
	if (error)
		goto BusError;
	error = dpm_sysfs_add(dev);
	if (error)
		goto DPMError;
	device_pm_add(dev);
	/* Notify clients of device addition.  This call must come
	 * after dpm_sysf_add() and before kobject_uevent().
	 */
	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_ADD_DEVICE, dev);
	kobject_uevent(&dev->kobj, KOBJ_ADD);
	bus_probe_device(dev);                                    //匹配driver
	if (parent)
		klist_add_tail(&dev->p->knode_parent,                 //把该设备的节点挂到其父节点的链表
			       &parent->p->klist_children);
	if (dev->class) {
		mutex_lock(&dev->class->p->class_mutex);
		/* tie the class to the device */
		klist_add_tail(&dev->knode_class,
			       &dev->class->p->class_devices);
		/* notify any interfaces that the device is here */
		list_for_each_entry(class_intf,
				    &dev->class->p->class_interfaces, node)
			if (class_intf->add_dev)
				class_intf->add_dev(dev, class_intf);
		mutex_unlock(&dev->class->p->class_mutex);
	}
done:
	put_device(dev);
	return error;
 DPMError:
	bus_remove_device(dev);
 BusError:
	device_remove_attrs(dev);
 AttrsError:
	device_remove_class_symlinks(dev);
 SymlinkError:
	if (MAJOR(dev->devt))
		devtmpfs_delete_node(dev);
	if (MAJOR(dev->devt))
		device_remove_sys_dev_entry(dev);
 devtattrError:
	if (MAJOR(dev->devt))
		device_remove_file(dev, &devt_attr);
 ueventattrError:
	device_remove_file(dev, &uevent_attr);
 attrError:
	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
	kobject_del(&dev->kobj);
 Error:
	cleanup_device_parent(dev);
	if (parent)
		put_device(parent);
name_error:
	kfree(dev->p);
	dev->p = NULL;
	goto done;
}
/***********************************************
* 重点看一下bus_probe_device匹配driver以及初始化过程
***********************************************/
void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	int ret;
	if (bus && bus->p->drivers_autoprobe) {         //设置了自动匹配初始化那么就开始匹配
		ret = device_attach(dev);
		WARN_ON(ret < 0);
	}
}
/******************
* 继续device_attach
******************/
int device_attach(struct device *dev)
{
	int ret = 0;
	device_lock(dev);
	if (dev->driver) {                            //默认指定了driver就直接绑定
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {                                      //没有指定就进行遍历匹配
		pm_runtime_get_noresume(dev);
		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
		pm_runtime_put_sync(dev);
	}
	device_unlock(dev);
	return ret;
}
/**************************
* 再来看device_bind_driver分支
**************************/
int device_bind_driver(struct device *dev)
{
	int ret;
	ret = driver_sysfs_add(dev);
	if (!ret)
		driver_bound(dev);              //主要是完成了将私有成员的driver节点挂到
	return ret;                         //了driver的设备链表
}
/**************************
* 先看bus_for_each_drv分支
**************************/
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
		     void *data, int (*fn)(struct device_driver *, void *))
{
	struct klist_iter i;
	struct device_driver *drv;
	int error = 0;
	if (!bus)
		return -EINVAL;
	klist_iter_init_node(&bus->p->klist_drivers, &i,           //和driver遍历device类似,从头开始遍历bus的driver链表
			     start ? &start->p->knode_bus : NULL);         //发现一个driver就调用fn即__device_attach进行匹配
	while ((drv = next_driver(&i)) && !error)
		error = fn(drv, data);
	klist_iter_exit(&i);
	return error;
}
/*********************************
* 最后来看一下__device_attach这个函数
*********************************/
static int __device_attach(struct device_driver *drv, void *data)
{
	struct device *dev = data;
	if (!driver_match_device(drv, dev))    
		return 0;
	return driver_probe_device(drv, dev);
}
/*
  对比driver的注册最后调用的__driver_attach可以发现其实质是一样的,都最后归宿到了
  这driver_match_device,driver_probe_device两个函数,本质参数的和谐做到了通用
  性在这里就不继续分析了,不是很清楚的可以看前一篇文章driver最后一部分的分析  ^_^
*/


以上便是device的注册,可以发现device和driver围绕着bus最后有种殊途同归的感觉,下面结合driver的流程给出一个框图

以便更明确其间的流程:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: