本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/gdt_a20
===============================
内核的开发者将总线,设备,驱动这三者用软件思想抽象了出来,巧妙的建立了其间的关系,使之更形象化。结合前面所学的知识,总的来说其三者间的关系为bus有两条链表,分别用于挂接设备和驱动,指定了其自身bus的device或者driver最后都会分别连接到对应bus的这两条链表上,而总线又有其始端,为bus_kset,一个driver可以对应于几个设备,因此driver同样有其设备链表,用于挂接可以操作的设备,其自身也有bus挂接点,用于将自身挂接到对应bus(每个driver只属于一条总线),而对于device,一个设备只属于一条总线,只能有一个driver与其对应,因此对于device,都是单一的,一个driver挂接点,一个bus挂接点,device与bus相同的是都有始端,device为devices_kset,因此device的注册同时会出现在对应的bus目录和device总目录下。好了,下面就以源码为例分别分析一下bus,device,driver的注册过程。
一、bus的注册
bus的注册比较简单,首先来看一下bus的结构:
-
struct bus_type {
-
const char *name;
-
struct bus_attribute *bus_attrs;
-
struct device_attribute *dev_attrs;
-
struct driver_attribute *drv_attrs;
-
int (*match)(struct device *dev, struct device_driver *drv);
-
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
-
int (*probe)(struct device *dev);
-
int (*remove)(struct device *dev);
-
void (*shutdown)(struct device *dev);
-
int (*suspend)(struct device *dev, pm_message_t state);
-
int (*resume)(struct device *dev);
-
const struct dev_pm_ops *pm;
-
struct bus_type_private *p;
-
};
-
-
struct bus_type_private {
-
struct kset subsys;
-
struct kset *drivers_kset;
-
struct kset *devices_kset;
-
struct klist klist_devices;
-
struct klist klist_drivers;
-
struct blocking_notifier_head bus_notifier;
-
unsigned int drivers_autoprobe:1;
-
struct bus_type *bus;
-
};
无论是bus,driver,还是device其本身特征都放在私有成员里,其注册时,都会申请并填充这个结构体,下面具体分析一下bus的注册流程,从bus_register开始:
-
int bus_register(struct bus_type *bus)
-
{
-
int retval;
-
struct bus_type_private *priv;
-
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
-
if (!priv)
-
return -ENOMEM;
-
priv->bus = bus;
-
bus->p = priv;
-
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
-
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
-
if (retval)
-
goto out;
-
-
-
priv->subsys.kobj.kset = bus_kset;
-
priv->subsys.kobj.ktype = &bus_ktype;
-
priv->drivers_autoprobe = 1;
-
-
-
retval = kset_register(&priv->subsys);
-
if (retval)
-
goto out;
-
retval = bus_create_file(bus, &bus_attr_uevent);
-
if (retval)
-
goto bus_uevent_fail;
-
priv->devices_kset = kset_create_and_add("devices", NULL,
-
&priv->subsys.kobj);
-
if (!priv->devices_kset) {
-
retval = -ENOMEM;
-
goto bus_devices_fail;
-
}
-
priv->drivers_kset = kset_create_and_add("drivers", NULL,
-
&priv->subsys.kobj);
-
if (!priv->drivers_kset) {
-
retval = -ENOMEM;
-
goto bus_drivers_fail;
-
}
-
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
-
klist_init(&priv->klist_drivers, NULL, NULL);
-
retval = add_probe_files(bus);
-
if (retval)
-
goto bus_probe_files_fail;
-
retval = bus_add_attrs(bus);
-
if (retval)
-
goto bus_attrs_fail;
-
pr_debug("bus: '%s': registered/n", bus->name);
-
return 0;
-
bus_attrs_fail:
-
remove_probe_files(bus);
-
bus_probe_files_fail:
-
kset_unregister(bus->p->drivers_kset);
-
bus_drivers_fail:
-
kset_unregister(bus->p->devices_kset);
-
bus_devices_fail:
-
bus_remove_file(bus, &bus_attr_uevent);
-
bus_uevent_fail:
-
kset_unregister(&bus->p->subsys);
-
out:
-
kfree(bus->p);
-
bus->p = NULL;
-
return retval;
-
}
由此可见,bus又是kset的封装,bus_register主要完成了其私有成员bus_type_private的初始化,并初始化了其下的两个目录devices和drivers,及其属性文件,bus有个自己的根目录也就是bus有个起始端点,是bus_kset,经过此番的注册,bus目录下将会出现我们注册的bus,并且其下会有device和driver两个子目录,代表它下面的driver和device链表。
二、driver的注册
下面看一下driver是怎么和bus关联起来的,首先看下driver的结构:
-
struct device_driver {
-
const char *name;
-
struct bus_type *bus;
-
struct module *owner;
-
const char *mod_name;
-
bool suppress_bind_attrs;
-
#if defined(CONFIG_OF)
-
const struct of_device_id *of_match_table;
-
#endif
-
int (*probe) (struct device *dev);
-
int (*remove) (struct device *dev);
-
void (*shutdown) (struct device *dev);
-
int (*suspend) (struct device *dev, pm_message_t state);
-
int (*resume) (struct device *dev);
-
const struct attribute_group **groups;
-
const struct dev_pm_ops *pm;
-
struct driver_private *p;
-
};
-
-
struct driver_private {
-
struct kobject kobj;
-
struct klist klist_devices;
-
struct klist_node knode_bus;
-
struct module_kobject *mkobj;
-
struct device_driver *driver;
-
};
如同bus一样,重点的仍是可以代表其自身的私有属性,下面具体看一下driver的注册过程,从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);
-
if (other) {
-
put_driver(other);
-
printk(KERN_ERR "Error: Driver '%s' is already registered, "
-
"aborting.../n", drv->name);
-
return -EBUSY;
-
}
-
ret = bus_add_driver(drv);
-
if (ret)
-
return ret;
-
ret = driver_add_groups(drv, drv->groups);
-
if (ret)
-
bus_remove_driver(drv);
-
return ret;
-
}
-
-
-
-
struct device_driver *driver_find(const char *name, struct bus_type *bus)
-
{
-
struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
-
struct driver_private *priv;
-
-
if (k) {
-
priv = to_driver(k);
-
return priv->driver;
-
}
-
return NULL;
-
}
-
-
struct kobject *kset_find_obj(struct kset *kset, const char *name)
-
{
-
struct kobject *k;
-
struct kobject *ret = NULL;
-
spin_lock(&kset->list_lock);
-
list_for_each_entry(k, &kset->list, entry) {
-
if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
-
ret = kobject_get(k);
-
break;
-
}
-
}
-
spin_unlock(&kset->list_lock);
-
return ret;
-
}
-
-
-
-
-
int bus_add_driver(struct device_driver *drv)
-
{
-
struct bus_type *bus;
-
struct driver_private *priv;
-
int error = 0;
-
bus = bus_get(drv->bus);
-
if (!bus)
-
return -EINVAL;
-
pr_debug("bus: '%s': add driver %s/n", bus->name, drv->name);
-
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-
if (!priv) {
-
error = -ENOMEM;
-
goto out_put_bus;
-
}
-
klist_init(&priv->klist_devices, NULL, NULL);
-
priv->driver = drv;
-
drv->p = priv;
-
priv->kobj.kset = bus->p->drivers_kset;
-
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
-
"%s", drv->name);
-
if (error)
-
goto out_unregister;
-
if (drv->bus->p->drivers_autoprobe) {
-
error = driver_attach(drv);
-
if (error)
-
goto out_unregister;
-
}
-
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
-
module_add_driver(drv->owner, drv);
-
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) {
-
-
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) {
-
-
printk(KERN_ERR "%s: add_bind_files(%s) failed/n",
-
__func__, drv->name);
-
}
-
}
-
kobject_uevent(&priv->kobj, KOBJ_ADD);
-
return 0;
-
out_unregister:
-
kobject_put(&priv->kobj);
-
kfree(drv->p);
-
drv->p = NULL;
-
out_put_bus:
-
bus_put(bus);
-
return error;
-
}
-
-
-
-
int driver_attach(struct device_driver *drv)
-
{
-
return bus_for_each_dev(drv->bus, NULL, drv, __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)
-
return -EINVAL;
-
klist_iter_init_node(&bus->p->klist_devices, &i,
-
(start ? &start->p->knode_bus : NULL));
-
while ((dev = next_device(&i)) && !error)
-
error = fn(dev, data);
-
klist_iter_exit(&i);
-
return error;
-
}
-
-
-
-
static int __driver_attach(struct device *dev, void *data)
-
{
-
struct device_driver *drv = data;
-
if (!driver_match_device(drv, dev))
-
return 0;
-
if (dev->parent)
-
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;
-
}
-
-
-
-
static inline int driver_match_device(struct device_driver *drv,
-
struct device *dev)
-
{
-
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
-
}
-
-
-
-
int driver_probe_device(struct device_driver *drv, struct device *dev)
-
{
-
int ret = 0;
-
if (!device_is_registered(dev))
-
return -ENODEV;
-
pr_debug("bus: '%s': %s: matched device %s with driver %s/n",
-
drv->bus->name, __func__, dev_name(dev), drv->name);
-
pm_runtime_get_noresume(dev);
-
pm_runtime_barrier(dev);
-
ret = really_probe(dev, drv);
-
pm_runtime_put_sync(dev);
-
return ret;
-
}
-
-
-
-
static inline int device_is_registered(struct device *dev)
-
{
-
return dev->kobj.state_in_sysfs;
-
}
-
-
-
-
static int really_probe(struct device *dev, struct device_driver *drv)
-
{
-
int ret = 0;
-
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 (driver_sysfs_add(dev)) {
-
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
-
__func__, dev_name(dev));
-
goto probe_failed;
-
}
-
-
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;
-
}
-
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;
-
probe_failed:
-
devres_release_all(dev);
-
driver_sysfs_remove(dev);
-
dev->driver = NULL;
-
if (ret != -ENODEV && ret != -ENXIO) {
-
-
printk(KERN_WARNING
-
"%s: probe of %s failed with error %d/n",
-
drv->name, dev_name(dev), ret);
-
}
-
-
-
-
-
ret = 0;
-
done:
-
atomic_dec(&probe_count);
-
wake_up(&probe_waitqueue);
-
return ret;
-
}
-
-
-
-
static void driver_bound(struct device *dev)
-
{
-
if (klist_node_attached(&dev->p->knode_driver)) {
-
printk(KERN_WARNING "%s: device %s already bound/n",
-
__func__, kobject_name(&dev->kobj));
-
return;
-
}
-
pr_debug("driver: '%s': %s: bound to device '%s'/n", dev_name(dev),
-
__func__, dev->driver->name);
-
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
-
-
if (dev->bus)
-
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
-
BUS_NOTIFY_BOUND_DRIVER, dev);
-
}
-
总结一下,driver的注册,主要涉及将自身挂接到bus的driver链表,并将匹配到的设备加入自己的device链表,并且将匹配到的device的driver成员初始化为该driver,私有属性的driver节点也挂到driver的设备链表下,其中匹配函数是利用利用bus的match函数,该函数通常判断如果driver有id表,就查表匹配,如果没有就用driver和device名字匹配。当匹配成功后如果自动初始化标志允许则调用初始化函数probe,bus的probe优先级始终高于driver的。另外注意一点driver是没有总的起始端点的,driver不是可具体描述的事物。
由于篇幅比较长,device的分析放到下一篇《linux设备模型之bus,device,driver分析<二>》 ^_^!