linux内核总线驱动模型-设备篇

上篇主要对总线进行了一些梳理,现在来看看内核对于设备的处理过程。

struct device {
    
    
	struct device		*parent; /*指向父上游的指针*/

	struct device_private	*p;

	struct kobject kobj;	   /*用它联系到sysfs中*/
	const char		*init_name; /* initial name of the device */
	const struct device_type *type; /*设备属性文件*/

	struct mutex		mutex;	/* mutex to synchronize calls to
					 * its driver.
					 */

	struct bus_type	*bus;	/*属于那条总线*/
	struct device_driver *driver;	/*那个驱动能匹配该设备*/
	void		*platform_data;	/* Platform specific data, device
	.
	.
	.
	void	(*release)(struct device *dev);

};

其中比较重要的是释放函数,当这个设备被删除时,内核调用该方法,所有的注册到内核的设备结构必须有也给释放方法。和总线一样,device也有一个联系总线,设备,驱动程序的数据结构。

/* interface for exporting device attributes */
struct device_attribute {
    
    
	struct attribute	attr;
	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
			char *buf);
	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count);
};
//定义DEVICE_ATTR ( _name , _mode , _show , _store ) \
struct device_attribute dev_attr _ ## _ name = __ATTR ( _name , _mode , _show , _store )

该接口用于向外暴露设备属性。

同总线过程一样,device的初始化也是在driver_init完成初始化的:

int __init devices_init(void)
{
    
    	
	/*创建/sys目录下的devices目录*/
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	/*创建/sys目录下的dev目录*/
	dev_kobj = kobject_create_and_add("dev", NULL);
	if (!dev_kobj)
		goto dev_kobj_err;

	/*创建dev目录下的block目录*/
	sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
	if (!sysfs_dev_block_kobj)
		goto block_kobj_err;
	/*创建dev目录的char目录*/
	sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
	if (!sysfs_dev_char_kobj)
		goto char_kobj_err;

	return 0;

 char_kobj_err:
	kobject_put(sysfs_dev_block_kobj);
 block_kobj_err:
	kobject_put(dev_kobj);
 dev_kobj_err:
	kset_unregister(devices_kset);
	return -ENOMEM;
}

这个函数干的事情很明显,就是创建在sysfs中的设备目录和dev目录,还在dev目录下创建了block和char两个子目录。

下面分析下设备的注册过程:

int device_register(struct device *dev)
{
    
    
	/*设备初始化*/
	device_initialize(dev);
	/*将设备添加到系统中*/
	return device_add(dev);
}
void device_initialize(struct device *dev)
{
    
    
	dev->kobj.kset = devices_kset;
	kobject_init(&dev->kobj, &device_ktype);
	INIT_LIST_HEAD(&dev->dma_pools);
	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_initialize主要是完成设备结构的初始化,把设备中能初始化的部分全部初始化。

int device_add(struct device *dev)
{
    
    
	struct device *parent = NULL;
	struct kobject *kobj;
	struct class_interface *class_intf;
	int error = -EINVAL;
	/*增加设备的应用计数*/
	dev = get_device(dev);
	if (!dev)
		goto done;

	/*分配device_private 空间并初始化*/
	if (!dev->p) {
    
    
		error = device_private_init(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);/*设置dev的名字*/
		dev->init_name = NULL;
	}

	/* subsystems can specify simple device enumeration */
	if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
		dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

	if (!dev_name(dev)) {
    
    
		error = -EINVAL;
		goto name_error;
	}

	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

	parent = get_device(dev->parent);
	kobj = get_device_parent(dev, parent);
	if (kobj)
		dev->kobj.parent = kobj;

	/* 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);/*将设备加入到sys/中*/
	if (error)
		goto Error;

	/* notify platform of device entry */
	if (platform_notify)
		platform_notify(dev);
	/*创建uevent文件*/
	error = device_create_file(dev, &dev_attr_uevent);
	if (error)
		goto attrError;
	/*dev与class创建软链接*/
	error = device_add_class_symlinks(dev);
	if (error)
		goto SymlinkError;
	error = device_add_attrs(dev);
	if (error)
		goto AttrsError;
	/*将设备加入到bus的设备链表中*/
	error = bus_add_device(dev);
	if (error)
		goto BusError;
	error = dpm_sysfs_add(dev);
	if (error)
		goto DPMError;
	device_pm_add(dev);
	/*没有设置主设备号,就创建dev*/
	if (MAJOR(dev->devt)) {
    
    
		error = device_create_file(dev, &dev_attr_dev);
		if (error)
			goto DevAttrError;
		/*创建软链接*/
		error = device_create_sys_dev_entry(dev);
		if (error)
			goto SysEntryError;

		devtmpfs_create_node(dev);
	}

	/* Notify clients of device addition.  This call must come
	 * after dpm_sysfs_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);
	if (parent)
		klist_add_tail(&dev->p->knode_parent,
			       &parent->p->klist_children);

	if (dev->class) {
    
    
		mutex_lock(&dev->class->p->mutex);
		/* tie the class to the device */
		klist_add_tail(&dev->knode_class,
			       &dev->class->p->klist_devices);

		/* notify any interfaces that the device is here */
		list_for_each_entry(class_intf,
				    &dev->class->p->interfaces, node)
			if (class_intf->add_dev)
				class_intf->add_dev(dev, class_intf);
		mutex_unlock(&dev->class->p->mutex);
	}
done:
	put_device(dev);
	return error;

}

第8行:增加设备的引用计数

第12-17行:分配device_private空间并初始化

第24-36行:设置驱动的名字

第51行:将设备加入到sys文件系统中

第59行:创建设备属性uevent文件

第63行:创建dev和class的软链接

第70行:将设备加入到bus的设备链表中

第99行:为设备寻找合适的驱动,我们重点看下这个函数

void bus_probe_device(struct device *dev)
{
    
    
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;
	int ret;

	if (!bus)
		return;
	/*允许设备自动探测驱动*/
	if (bus->p->drivers_autoprobe) {
    
    
		ret = device_attach(dev);
		WARN_ON(ret < 0);
	}

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->add_dev)
			sif->add_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);
}

第10行:drivers_autoprobe在总线注册时被设置为1,所以这里执行device_attach进行设备和驱动的匹配

int device_attach(struct device *dev)
{
    
    
	int ret = 0;

	device_lock(dev);
	if (dev->driver) {
    
    
		if (klist_node_attached(&dev->p->knode_driver)) {
    
    
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
    
    
			dev->driver = NULL;
			ret = 0;
		}
	} else {
    
    /*进行驱动和设备的匹配*/
		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
		pm_request_idle(dev);
	}
out_unlock:
	device_unlock(dev);
	return ret;
}

device_attach函数中走到19行,进行设备和驱动的匹配:

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,
			     start ? &start->p->knode_bus : NULL);
	while ((drv = next_driver(&i)) && !error)
		error = fn(drv, data);
	klist_iter_exit(&i);
	return error;
}

第13-14行:遍历bus上所有的驱动,调用__device_attach进行匹配,为设备找驱动。

static int __device_attach(struct device_driver *drv, void *data)
{
    
    
	struct device *dev = data;
	/*调用bus-match函数进行匹配*/
	if (!driver_match_device(drv, dev))
		return 0;
	/*
		匹配成功以后执行probe
		如果bus有probe函数,优先执行,
		否则执行drvier的probe函数

	*/
	return driver_probe_device(drv, dev);
}

__device_attach调用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;
}

匹配函数是在总线注册时,实现的match函数。在匹配成功后,调用probe函数:

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    
    
	int ret = 0;
	.
	ret = really_probe(dev, drv);
	.

	return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
    
    
	int ret = 0;
	int local_trigger_count = atomic_read(&deferred_trigger_count);

	atomic_inc(&probe_count);
	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
		 drv->bus->name, __func__, drv->name, dev_name(dev));
	WARN_ON(!list_empty(&dev->devres_head));

	dev->driver = drv;

	.
     .

	if (dev->bus->probe) {
    
    
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
    
    
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	if (dev->pm_domain && dev->pm_domain->sync)
		dev->pm_domain->sync(dev);

	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);
	goto done;

	.
	.
}

really_probe函数中重点看17-25行,如果bus->probe不为空,则执行总线的probe函数,如果不存在,则查看drv->probe,不为空的话,执行驱动的probe函数。

下面来看下例子:

extern bus_type my_bus_type;
extern struct device my_bus;
   
static void my_dev_release(struct device *dev)
{
    
    
    
}
struct device my_dev = {
    
    
     
     .bus = &my_bus_type,
     .parent = &my_bus,
     .release = my_dev_release,
};
static ssize_t mydev_show(struct device *dev, char * buf)
{
    
    
     return sprintf(buf, "%s \n", "这是我的设备");
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
static  int __init my_device_init(void)
{
    
    
	int ret = 0 ;
        
    / *初始化设备* /
    strncpy(my_dev.bus_id , “my_dev” , BUS_ID_SIZE );
        
    / *注册设备* /
    device_register(&my_dev);
        
    device_create_file (&my_dev, &dev_attr_dev);
    
    return ret; 
}

猜你喜欢

转载自blog.csdn.net/wll1228/article/details/108392248