===============================
本文系本站原创,欢迎转载!
转载请注明出处: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的流程给出一个框图
以便更明确其间的流程:
阅读(924) | 评论(0) | 转发(0) |