Linux设备驱动(6)模块之间关系详解

本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。

1. What is sysfs?
  个人理解:sysfs向用户空间展示了驱动设备的层次结构,即目录sys下的文件结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。

  我们来看看sysfs的文件结构:

[root@yj423 /sys]#ls
block     class     devices   fs        module
bus       dev       firmware  kernel    power

block:块设备

bus:系统中的总线

class: 设备类型,比如输入设备

dev:系统中已注册的设备节点的视图,有两个子目录char和block。

devices:系统中所有设备拓扑结构视图

fireware:固件

fs:文件系统

kernel:内核配置选项和状态信息

module:模块

power:系统的电源管理数据

2. kobject ,kset和ktype
  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个来完成的。

2.1 kobject
  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。

  kobject用struct kobject来描述。

 1 struct kobject {
 2     const char        *name;            /*在sysfs建立目录的名字*/
 3     struct list_head    entry;        /*用于连接到所属kset的链表中*/
 4     struct kobject        *parent;    /*父对象*/
 5     struct kset        *kset;            /*属于哪个kset*/
 6     struct kobj_type    *ktype;        /*类型*/
 7     struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
 8     struct kref        kref;            /*对象的应用计数*/
 9     unsigned int state_initialized:1;
10     unsigned int state_in_sysfs:1;
11     unsigned int state_add_uevent_sent:1;
12     unsigned int state_remove_uevent_sent:1;
13     unsigned int uevent_suppress:1;
14 };

2.2 kset
 kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。

  kset使用struct kset来描述。

 1 /**
 2  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
 3  *
 4  * A kset defines a group of kobjects.  They can be individually
 5  * different "types" but overall these kobjects all want to be grouped
 6  * together and operated on in the same manner.  ksets are used to
 7  * define the attribute callbacks and other common events that happen to
 8  * a kobject.
 9  *
10  * @list: the list of all kobjects for this kset
11  * @list_lock: a lock for iterating over the kobjects
12  * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
13  * @uevent_ops: the set of uevent operations for this kset.  These are
14  * called whenever a kobject has something happen to it so that the kset
15  * can add new environment variables, or filter out the uevents if so
16  * desired.
17  */
18 struct kset {
19     struct list_head list;
20     spinlock_t list_lock;
21     struct kobject kobj;
22     const struct kset_uevent_ops *uevent_ops;
23 };

2.3 ktype
每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。

 1 struct kobj_type {
 2     void (*release)(struct kobject *kobj);
 3     const struct sysfs_ops *sysfs_ops;
 4     struct attribute **default_attrs;
 5     const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
 6     const void *(*namespace)(struct kobject *kobj);
 7 };
 8 
 9 /*以下两个结构体定义位于include\linux\sysfs.h*/
10 struct sysfs_ops {
11     ssize_t    (*show)(struct kobject *, struct attribute *,char *);
12     ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);
13     const void *(*namespace)(struct kobject *, const struct attribute *);
14 };
15 
16 struct attribute {
17     const char        *name;
18     umode_t            mode;
19 #ifdef CONFIG_DEBUG_LOCK_ALLOC
20     bool            ignore_lockdep:1;
21     struct lock_class_key    *key;
22     struct lock_class_key    skey;
23 #endif

当kobject的引用计数为0时,通过release方法来释放相关的资源。
attribute为属性,每个属性在sysfs中都有对应的属性文件。

sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。

2.4 kobject与kset的关系
  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。

   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。


3.举例
在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录,以bus的创建过程分析kobject和kset。

下面代码位于drivers/base/bus.c。

3.1从函数buses_init()开始分析,直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数为空表示没有父对象,因为bus在sys目录下,没有父对象。

bus是一个kset,其下面有很多kobject。

 1 int __init buses_init(void)
 2 {/*这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。*/
 3     bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
 4     if (!bus_kset)
 5         return -ENOMEM;
 6  /*这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL*/
 7     system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);//也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。
 8     if (!system_kset)
 9         return -ENOMEM;
10 
11     return 0;
12 }
13 
14 static const struct kset_uevent_ops bus_uevent_ops = {
15     .filter = bus_uevent_filter,
16 };
17 
18 static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
19 {
20     struct kobj_type *ktype = get_ktype(kobj);
21 
22     if (ktype == &bus_ktype)
23         return 1;
24     return 0;
25 }
 1 /**
 2  * kset_create_and_add - create a struct kset dynamically and add it to sysfs
 3  *
 4  * @name: the name for the kset
 5  * @uevent_ops: a struct kset_uevent_ops for the kset
 6  * @parent_kobj: the parent kobject of this kset, if any.
 7  *
 8  * This function creates a kset structure dynamically and registers it
 9  * with sysfs.  When you are finished with this structure, call
10  * kset_unregister() and the structure will be dynamically freed when it
11  * is no longer being used.
12  *
13  * If the kset was not able to be created, NULL will be returned.
14  */
15 struct kset *kset_create_and_add(const char *name,
16                  struct kset_uevent_ops *uevent_ops,
17                  struct kobject *parent_kobj)
18 {
19     struct kset *kset;
20     int error;
21  
22     kset = kset_create(name, uevent_ops, parent_kobj);    /*建立kset,设置某些字段*/
23     if (!kset)
24         return NULL;
25     error = kset_register(kset);    /*添加kset到sysfs*/
26     if (error) {
27         kfree(kset);
28         return NULL;
29     }
30     return kset;
31 }
接着函数kset_create中,动态分配了kset结构,初始化kset结构体成员部分变量。
 1 /**
 2  * kset_create - create a struct kset dynamically
 3  *
 4  * @name: the name for the kset
 5  * @uevent_ops: a struct kset_uevent_ops for the kset
 6  * @parent_kobj: the parent kobject of this kset, if any.
 7  *
 8  * This function creates a kset structure dynamically.  This structure can
 9  * then be registered with the system and show up in sysfs with a call to
10  * kset_register().  When you are finished with this structure, if
11  * kset_register() has been called, call kset_unregister() and the
12  * structure will be dynamically freed when it is no longer being used.
13  *
14  * If the kset was not able to be created, NULL will be returned.
15  */
16 static struct kset *kset_create(const char *name,
17                 struct kset_uevent_ops *uevent_ops,
18                 struct kobject *parent_kobj)
19 {
20     struct kset *kset;
21  
22     kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/
23     if (!kset)
24         return NULL;
25     kobject_set_name(&kset->kobj, name);/*设置kobj->name*/
26     kset->uevent_ops = uevent_ops;
27     kset->kobj.parent = parent_kobj;    /*设置父对象*/
28  
29     /*
30      * The kobject of this kset will have a type of kset_ktype and belong to
31      * no kset itself.  That way we can properly free it when it is
32      * finished being used.
33      */
34     kset->kobj.ktype = &kset_ktype;
35     kset->kobj.kset = NULL;            /*本keset不属于任何kset*/
36  
37     return kset;
38 }

接着调用kobject_set_name 采用标准化格式设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录sys创建的,自然没有父对象。

/**
 * kobject_set_name - Set the name of a kobject
 * @kobj: struct kobject to set the name of
 * @fmt: format string used to build the name
 *
 * This sets the name of the kobject.  If you have already added the
 * kobject to the system, you must call kobject_rename() in order to
 * change the name of the kobject.
 */
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
    va_list vargs;
    int retval;
 
    va_start(vargs, fmt);
    retval = kobject_set_name_vargs(kobj, fmt, vargs);
    va_end(vargs);
 
    return retval;
}
 
/**
 * kobject_set_name_vargs - Set the name of an kobject
 * @kobj: struct kobject to set the name of
 * @fmt: format string used to build the name
 * @vargs: vargs to format the string.
 */
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                  va_list vargs)
{
    const char *old_name = kobj->name;
    char *s;
 
    if (kobj->name && !fmt)
        return 0;
 
    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
    if (!kobj->name)
        return -ENOMEM;
 
    /* ewww... some of these buggers have '/' in the name ... */
    while ((s = strchr(kobj->name, '/')))
        s[0] = '!';
 
    kfree(old_name);
    return 0;
}
 
/* Simplified asprintf. */
char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
{
    unsigned int len;
    char *p;
    va_list aq;
 
    va_copy(aq, ap);
    len = vsnprintf(NULL, 0, fmt, aq);
    va_end(aq);
 
    p = kmalloc(len+1, gfp);
    if (!p)
        return NULL;
 
    vsnprintf(p, len+1, fmt, ap);
 
    return p;
}

 

3.2kset_create_and_add函数中调用函数kset_create的流程分析完,然后紧接着调用函数kset_register

 1 /**
 2  * kset_register - initialize and add a kset.
 3  * @k: kset.
 4  */
 5 int kset_register(struct kset *k)
 6 {
 7     int err;
 8  
 9     if (!k)
10         return -EINVAL;
11  
12     kset_init(k);           /*初始化kset*/
13     err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/
14     if (err)
15         return err;
16     kobject_uevent(&k->kobj, KOBJ_ADD);
17     return 0;
18 }

 

函数kset_init接着初始化kset中的其他成员变量

 1 /**
 2  * kset_init - initialize a kset for use
 3  * @k: kset
 4  */
 5 void kset_init(struct kset *k)
 6 {
 7     kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
 8     INIT_LIST_HEAD(&k->list);    /*初始化链表头*/
 9     spin_lock_init(&k->list_lock);    /*初始化自旋锁*/
10 }
11  
12 static void kobject_init_internal(struct kobject *kobj)
13 {
14     if (!kobj)
15         return;
16     kref_init(&kobj->kref);           /*初始化引用基计数*/
17     INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
18     kobj->state_in_sysfs = 0;
19     kobj->state_add_uevent_sent = 0;
20     kobj->state_remove_uevent_sent = 0;
21     kobj->state_initialized = 1;
22 }

 

 函数kobject_add_internal,将kobj加入内核,在sysfs中将建立目录。

 1 static int kobject_add_internal(struct kobject *kobj)
 2 {
 3     int error = 0;
 4     struct kobject *parent;
 5  
 6     if (!kobj)
 7         return -ENOENT;
 8     /*检查name字段是否存在*/
 9     if (!kobj->name || !kobj->name[0]) {
10         WARN(1, "kobject: (%p): attempted to be registered with empty "
11              "name!\n", kobj);
12         return -EINVAL;
13     }
14  
15     parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
16  
17     /* join kset if set, use it as parent if we do not already have one */
18     if (kobj->kset) {    
19         if (!parent)
20             /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
21             parent = kobject_get(&kobj->kset->kobj);
22         kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
23         kobj->parent = parent;
24     }
25  
26     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
27          kobject_name(kobj), kobj, __func__,
28          parent ? kobject_name(parent) : "<NULL>",
29          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
30  
31     error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
32     if (error) {
33         kobj_kset_leave(kobj);    /*删除链表项*/
34         kobject_put(parent);    /*减少引用计数*/
35         kobj->parent = NULL;
36  
37         /* be noisy on error issues */
38         if (error == -EEXIST)
39             printk(KERN_ERR "%s failed for %s with "
40                    "-EEXIST, don't try to register things with "
41                    "the same name in the same directory.\n",
42                    __func__, kobject_name(kobj));
43         else
44             printk(KERN_ERR "%s failed for %s (%d)\n",
45                    __func__, kobject_name(kobj), error);
46         dump_stack();
47     } else
48         kobj->state_in_sysfs = 1;
49  
50     return error;
51 }

在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。

在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。

至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。

4. 驱动模型回顾
前2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。Linux设备模型使用了bus/device/device_driver三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。这个属于分离的思想,将设备和驱动分开管理。同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。

下面分析bus/device/device_driver三者之间的关系,三个结构体不再重复。

4.1 bus
总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。结构体定义代码位于include/linux/device.h和driver/base/base.h。

 1 /**
 2  * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
 3  *
 4  * @subsys - the struct kset that defines this subsystem
 5  * @devices_kset - the subsystem's 'devices' directory
 6  * @interfaces - list of subsystem interfaces associated
 7  * @mutex - protect the devices, and interfaces lists.
 8  *
 9  * @drivers_kset - the list of drivers associated
10  * @klist_devices - the klist to iterate over the @devices_kset
11  * @klist_drivers - the klist to iterate over the @drivers_kset
12  * @bus_notifier - the bus notifier list for anything that cares about things
13  *                 on this bus.
14  * @bus - pointer back to the struct bus_type that this structure is associated
15  *        with.
16  *
17  * @glue_dirs - "glue" directory to put in-between the parent device to
18  *              avoid namespace conflicts
19  * @class - pointer back to the struct class that this structure is associated
20  *          with.
21  *
22  * This structure is the one that is the actual kobject allowing struct
23  * bus_type/class to be statically allocated safely.  Nothing outside of the
24  * driver core should ever touch these fields.
25  */
26 struct subsys_private {
27     struct kset subsys;
28     struct kset *devices_kset;//负责连接它下面的所有device的目录
29     struct list_head interfaces;
30     struct mutex mutex;
31 
32     struct kset *drivers_kset;//负责连接它下面的所有driver的目录
33     struct klist klist_devices;//负责连接它下面的所有device的链表,device->p->knode_bus的表头
34     struct klist klist_drivers;//负责连接它下面的所有driver的链表,driver->p->knode_bus的表头
35     struct blocking_notifier_head bus_notifier;
36     unsigned int drivers_autoprobe:1;
37     struct bus_type *bus;
38 
39     struct kset glue_dirs;
40     struct class *class;
41 };

 

每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。
drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。

总线有个私有数据subsys_private *p,只有该总线可以访问它,其他不可访问。同时总线上的设备和驱动将分别保存在两个链表中:bus_type->p->klist_devices和bus_type->p->klist_drivers。

4.2 device
设备对象在driver-model中使用struct device来表示。代码位于include/linux/device.h。不再重复。

device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。

device包含私有指针变量,用于连接bus和device_driver,只有device能访问,其他不可访问。

 1 /**
 2  * struct device_private - structure to hold the private to the driver core portions of the device structure.
 3  *
 4  * @klist_children - klist containing all children of this device
 5  * @knode_parent - node in sibling list
 6  * @knode_driver - node in driver list
 7  * @knode_bus - node in bus list
 8  * @deferred_probe - entry in deferred_probe_list which is used to retry the
 9  *    binding of drivers which were unable to get all the resources needed by
10  *    the device; typically because it depends on another driver getting
11  *    probed first.
12  * @driver_data - private pointer for driver specific info.  Will turn into a
13  * list soon.
14  * @device - pointer back to the struct class that this structure is
15  * associated with.
16  *
17  * Nothing outside of the driver core should ever touch these fields.
18  */
19 struct device_private {
20     struct klist klist_children;
21     struct klist_node knode_parent;
22     struct klist_node knode_driver;//一个driver可以支持多个device,该device就是靠这个节点加入到匹配到的driver的链表的
23     struct klist_node knode_bus;//所属的bus,bus下所有device组成一个链表,表头是bus的klist_devices
24     struct list_head deferred_probe;
25     void *driver_data;
26     struct device *device;
27 };

 

该device所挂载的bus由device->p->knode_bus指定。

该device所对应的设备驱动由device->p->knode_driver指定。

4.3 device_driver
设备设备对象在driver-model中使用struct device_driver来表示。结构体定义位于include/linux/device.h。device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方也有着一个对应的目录。

1 struct driver_private {
2     struct kobject kobj;
3     struct klist klist_devices;//一个driver可以支持多个device,用链表连接它所支持的device
4     struct klist_node knode_bus;//所属的bus,bus下所有driver组成一个链表,表头是bus的klist_drivers
5     struct module_kobject *mkobj;
6     struct device_driver *driver;
7 };

 

device_driver也有私有指针数据driver_private,同样只有该driver可以访问,其他不可访问。

该设备驱动所支持的设备由driver->p->klist_devices指定,该设备驱动所挂载的总线由driver->p->knode_bus制定。

小总:这样的话,bus、device和device_driver都有自己的私有指针数据,它们的功能就是负责连接对方。通过klist_node 强化版的链表,互相连接起来的。

5. platform bus实例
 接下来来分析/sys/bus/platform是如何建立的。定义位于drivers\base\platform.c

platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:

start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。

注:kernel_init()是在rest_init函数中创建内核线程来执行的。

 1 int __init platform_bus_init(void)
 2 {
 3     int error;
 4 
 5     early_platform_cleanup();
 6 
 7     error = device_register(&platform_bus);
 8     if (error)
 9         return error;
10     error =  bus_register(&platform_bus_type);
11     if (error)
12         device_unregister(&platform_bus);
13     return error;
14 }
15 
16 struct device platform_bus = {
17     .init_name    = "platform",
18 };
19 
20 struct bus_type platform_bus_type = {
21     .name        = "platform",
22     .dev_attrs    = platform_dev_attrs,
23     .match        = platform_match,
24     .uevent        = platform_uevent,
25     .pm        = &platform_dev_pm_ops,
26 };

从bus_type,我们看到该总线的名字为platform。
调用了device_register和bus_register两个函数,我们只关注bus_register函数。

 1 int bus_register(struct bus_type *bus)
 2 {
 3     int retval;
 4     struct subsys_private *priv;
 5     struct lock_class_key *key = &bus->lock_key;
 6 
 7     priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
 8     if (!priv)
 9         return -ENOMEM;
10 
11     priv->bus = bus;
12     bus->p = priv;
13 
14     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
15 
16     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
17     if (retval)
18         goto out;
19 
20     priv->subsys.kobj.kset = bus_kset;
21     priv->subsys.kobj.ktype = &bus_ktype;
22     priv->drivers_autoprobe = 1;
23 
24     retval = kset_register(&priv->subsys);
25     if (retval)
26         goto out;
27 
28     retval = bus_create_file(bus, &bus_attr_uevent);
29     if (retval)
30         goto bus_uevent_fail;
31 
32     priv->devices_kset = kset_create_and_add("devices", NULL,
33                          &priv->subsys.kobj);
34     if (!priv->devices_kset) {
35         retval = -ENOMEM;
36         goto bus_devices_fail;
37     }
38 
39     priv->drivers_kset = kset_create_and_add("drivers", NULL,
40                          &priv->subsys.kobj);
41     if (!priv->drivers_kset) {
42         retval = -ENOMEM;
43         goto bus_drivers_fail;
44     }
45 
46     INIT_LIST_HEAD(&priv->interfaces);
47     __mutex_init(&priv->mutex, "subsys mutex", key);
48     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
49     klist_init(&priv->klist_drivers, NULL, NULL);
50 
51     retval = add_probe_files(bus);
52     if (retval)
53         goto bus_probe_files_fail;
54 
55     retval = bus_add_attrs(bus);
56     if (retval)
57         goto bus_attrs_fail;
58 
59     pr_debug("bus: '%s': registered\n", bus->name);
60     return 0;
61 
62 bus_attrs_fail:
63     remove_probe_files(bus);
64 bus_probe_files_fail:
65     kset_unregister(bus->p->drivers_kset);
66 bus_drivers_fail:
67     kset_unregister(bus->p->devices_kset);
68 bus_devices_fail:
69     bus_remove_file(bus, &bus_attr_uevent);
70 bus_uevent_fail:
71     kset_unregister(&bus->p->subsys);
72 out:
73     kfree(bus->p);
74     bus->p = NULL;
75     return retval;
76 }

 

函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。
在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。

接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。

紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。

 1 /**
 2  * kset_register - initialize and add a kset.
 3  * @k: kset.
 4  */
 5 int kset_register(struct kset *k)
 6 {
 7     int err;
 8 
 9     if (!k)
10         return -EINVAL;
11 
12     kset_init(k);
13     err = kobject_add_internal(&k->kobj);
14     if (err)
15         return err;
16     kobject_uevent(&k->kobj, KOBJ_ADD);
17     return 0;
18 }

 

kset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。

然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。

 1 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
 2 {
 3     int error;
 4     if (bus_get(bus)) {
 5         error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
 6         bus_put(bus);
 7     } else
 8         error = -EINVAL;
 9     return error;
10 }

有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。

这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。

也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。

我们来看下关系图:


随后,bus_register接着调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。

 1 static int add_probe_files(struct bus_type *bus)
 2 {
 3     int retval;
 4 
 5     retval = bus_create_file(bus, &bus_attr_drivers_probe);
 6     if (retval)
 7         goto out;
 8 
 9     retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
10     if (retval)
11         bus_remove_file(bus, &bus_attr_drivers_probe);
12 out:
13     return retval;
14 }

该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。
最后调用bus_add_attrs创建总线相关的属性文件。

 1 /**
 2  * bus_add_attrs - Add default attributes for this bus.
 3  * @bus: Bus that has just been registered.
 4  */
 5 
 6 static int bus_add_attrs(struct bus_type *bus)
 7 {
 8     int error = 0;
 9     int i;
10 
11     if (bus->bus_attrs) {
12         for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
13             error = bus_create_file(bus, &bus->bus_attrs[i]);
14             if (error)
15                 goto err;
16         }
17     }
18 done:
19     return error;
20 err:
21     while (--i >= 0)
22         bus_remove_file(bus, &bus->bus_attrs[i]);
23     goto done;
24 }

我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。
好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。

[root1423 platform]#pwd
/sys/bus/platform
[root123 platform]#ls
devices drivers drivers_autoprobe drivers_probe uevent

最后,我们对整个bus_register的过程进行一个小结。

 

6. device举例
本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。

之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。

6.1虚拟的platform设备

在第5节,platform_bus_init函数中还调用了device_register,

详解:linux设备驱动(2)device详解

 1 int device_register(struct device *dev)
 2 {
 3     device_initialize(dev);    /*初始化dev的某些字段*/
 4     return device_add(dev); /*将设备添加到系统中*/
 5 }
 6 
 7 void device_initialize(struct device *dev)
 8 {
 9     dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/
10     kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/
11     INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
12     init_MUTEX(&dev->sem);                /*初始化互斥体*/
13     spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
14     INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
15     device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/
16     device_pm_init(dev);                /*设置该device的电源状态*/
17     set_dev_node(dev, -1);              /*如果使用NUMA,则设置NUMA节点*/
18 }

 

6.1.1

首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。

该对象的建立是在devices_init函数中完成的。

 1 int __init devices_init(void)
 2 {
 3     devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
 4     if (!devices_kset)
 5         return -ENOMEM;
 6     dev_kobj = kobject_create_and_add("dev", NULL);
 7     if (!dev_kobj)
 8         goto dev_kobj_err;
 9     sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
10     if (!sysfs_dev_block_kobj)
11         goto block_kobj_err;
12     sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
13     if (!sysfs_dev_char_kobj)
14         goto char_kobj_err;
15  
16     return 0;
17  
18  char_kobj_err:
19     kobject_put(sysfs_dev_block_kobj);
20  block_kobj_err:
21     kobject_put(dev_kobj);
22  dev_kobj_err:
23     kset_unregister(devices_kset);
24     return -ENOMEM;
25 }

由此可见,devices_kset对象表示的目录为/sys下的devices目录。

6.1.2kobject_init

 1 void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
 2 {
 3     char *err_str;
 4  
 5     if (!kobj) {
 6         err_str = "invalid kobject pointer!";
 7         goto error;
 8     }
 9     if (!ktype) {
10         err_str = "must have a ktype to be initialized properly!\n";
11         goto error;
12     }
13     if (kobj->state_initialized) {
14         /* do not error out as sometimes we can recover */
15         printk(KERN_ERR "kobject (%p): tried to init an initialized "
16                "object, something is seriously wrong.\n", kobj);
17         dump_stack();
18     }
19  
20     kobject_init_internal(kobj);
21     kobj->ktype = ktype;
22     return;
23  
24 error:
25     printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
26     dump_stack();
27 }
28 EXPORT_SYMBOL(kobject_init);
29  
30 static void kobject_init_internal(struct kobject *kobj)
31 {
32     if (!kobj)
33         return;
34     kref_init(&kobj->kref);            /*初始化引用基计数*/
35     INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
36     kobj->state_in_sysfs = 0;
37     kobj->state_add_uevent_sent = 0;
38     kobj->state_remove_uevent_sent = 0;
39     kobj->state_initialized = 1;
40 }

 

该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。

6.1.3device_init_wakeup

参数val为0,设置该device不能够唤醒。

 1 #ifdef CONFIG_PM
 2  
 3 /* changes to device_may_wakeup take effect on the next pm state change.
 4  * by default, devices should wakeup if they can.
 5  */
 6 static inline void device_init_wakeup(struct device *dev, int val)
 7 {
 8     dev->power.can_wakeup = dev->power.should_wakeup = !!val;
 9 }
10 #else /* !CONFIG_PM */
11  
12 /* For some reason the next two routines work even without CONFIG_PM */
13 static inline void device_init_wakeup(struct device *dev, int val)
14 {
15     dev->power.can_wakeup = !!val;
16 }
17 #endif

 

6.2device_add

接下来是注册的第二步:调用device_add。

  1 int device_add(struct device *dev)
  2 {
  3     struct device *parent = NULL;
  4     struct class_interface *class_intf;
  5     int error = -EINVAL;
  6  
  7     dev = get_device(dev);    /*增加引用计数*/
  8     if (!dev)
  9         goto done;
 10  
 11     dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);    /*分配device_private结构*/
 12     if (!dev->p) {
 13         error = -ENOMEM;
 14         goto done;
 15     }
 16     dev->p->device = dev;    /*保存dev*/
 17     klist_init(&dev->p->klist_children, klist_children_get,    /*初始化内核链表*/
 18            klist_children_put);
 19  
 20     /*
 21      * for statically allocated devices, which should all be converted
 22      * some day, we need to initialize the name. We prevent reading back
 23      * the name, and force the use of dev_name()
 24      */
 25     if (dev->init_name) {
 26         dev_set_name(dev, dev->init_name);     /*dev->kobject->name = dev->init_name*/
 27         dev->init_name = NULL;
 28     }
 29  
 30     if (!dev_name(dev))    /*检查dev->kobject->name*/
 31         goto name_error;
 32  
 33     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 34  
 35     parent = get_device(dev->parent);    /*增加父设备引用计数*/
 36     setup_parent(dev, parent);            /*设置dev->kobject->parent*/
 37  
 38     /* use parent numa_node */
 39     if (parent)
 40         set_dev_node(dev, dev_to_node(parent));
 41  
 42     /* first, register with generic layer. */
 43     /* we require the name to be set before, and pass NULL */
 44     /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
 45     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);    
 46     if (error)
 47         goto Error;
 48  
 49     /* notify platform of device entry */
 50     if (platform_notify)
 51         platform_notify(dev);
 52  
 53     /*在XXX下建立文件uevent*/
 54     error = device_create_file(dev, &uevent_attr);
 55     if (error)
 56         goto attrError;
 57  
 58     if (MAJOR(dev->devt)) {/*主设备号不为0*/
 59         error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/
 60         if (error)
 61             goto ueventattrError;
 62  
 63         /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */
 64         error = device_create_sys_dev_entry(dev); 
 65         if (error)
 66             goto devtattrError;
 67     }
 68  
 69     error = device_add_class_symlinks(dev);
 70     if (error)
 71         goto SymlinkError;
 72     error = device_add_attrs(dev);    /*添加类设备属型文件和属性组*/
 73     if (error)
 74         goto AttrsError;
 75     error = bus_add_device(dev);    /*添加3个symlink*/
 76     if (error)
 77         goto BusError;
 78     error = dpm_sysfs_add(dev);        /*创建power子目录,并在其下添加电源管理的属性组文件*/
 79     if (error)
 80         goto DPMError;
 81     device_pm_add(dev);                /*将该device添加到电源管理链表中*/
 82  
 83     /* Notify clients of device addition.  This call must come
 84      * after dpm_sysf_add() and before kobject_uevent().
 85      */
 86     if (dev->bus)
 87         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 88                          BUS_NOTIFY_ADD_DEVICE, dev);
 89  
 90     kobject_uevent(&dev->kobj, KOBJ_ADD);    /*通知用户层*/
 91     bus_attach_device(dev);                    /*将设备添加到总线的设备链表中,并尝试获取驱动*/
 92     if (parent)
 93         klist_add_tail(&dev->p->knode_parent,    /*有父设备,则将该设备添加到父设备的儿子链表中*/
 94                    &parent->p->klist_children);
 95  
 96     if (dev->class) {                        /*该设备属于某个设备类*/
 97         mutex_lock(&dev->class->p->class_mutex);
 98         /* tie the class to the device */
 99         klist_add_tail(&dev->knode_class,    /*将device添加到class的类设备链表中*/
100                    &dev->class->p->class_devices);
101  
102         /* notify any interfaces that the device is here */
103         list_for_each_entry(class_intf,
104                     &dev->class->p->class_interfaces, node)
105             if (class_intf->add_dev)
106                 class_intf->add_dev(dev, class_intf);
107         mutex_unlock(&dev->class->p->class_mutex);
108     }
109 done:
110     put_device(dev);
111     return error;
112  DPMError:
113     bus_remove_device(dev);
114  BusError:
115     device_remove_attrs(dev);
116  AttrsError:
117     device_remove_class_symlinks(dev);
118  SymlinkError:
119     if (MAJOR(dev->devt))
120         device_remove_sys_dev_entry(dev);
121  devtattrError:
122     if (MAJOR(dev->devt))
123         device_remove_file(dev, &devt_attr);
124  ueventattrError:
125     device_remove_file(dev, &uevent_attr);
126  attrError:
127     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
128     kobject_del(&dev->kobj);
129  Error:
130     cleanup_device_parent(dev);
131     if (parent)
132         put_device(parent);
133 name_error:
134     kfree(dev->p);
135     dev->p = NULL;
136     goto done;
137 }

 

 

该函数是device的重要API,接下来以此设备为例,逐步分析

6.2.1setup_parent

下列代码位于drivers/base/core.c。

 1 static void setup_parent(struct device *dev, struct device *parent)
 2 {
 3     struct kobject *kobj;
 4     kobj = get_device_parent(dev, parent);
 5     if (kobj)
 6         dev->kobj.parent = kobj;
 7 }
 8  
 9 static struct kobject *get_device_parent(struct device *dev,
10                      struct device *parent)
11 {
12     /* class devices without a parent live in /sys/class/<classname>/ */
13     if (dev->class && (!parent || parent->class != dev->class))
14         return &dev->class->p->class_subsys.kobj;
15     /* all other devices keep their parent */
16     else if (parent)
17         return &parent->kobj;
18  
19     return NULL;
20 }

该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。

6.2.2 kobject_add

 1 int kobject_add(struct kobject *kobj, struct kobject *parent,
 2         const char *fmt, ...)
 3 {
 4     va_list args;
 5     int retval;
 6  
 7     if (!kobj)
 8         return -EINVAL;
 9  
10     if (!kobj->state_initialized) {
11         printk(KERN_ERR "kobject '%s' (%p): tried to add an "
12                "uninitialized object, something is seriously wrong.\n",
13                kobject_name(kobj), kobj);
14         dump_stack();
15         return -EINVAL;
16     }
17     va_start(args, fmt);
18     retval = kobject_add_varg(kobj, parent, fmt, args);
19     va_end(args);
20  
21     return retval;
22 }
23 EXPORT_SYMBOL(kobject_add);
24  
25 static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
26                 const char *fmt, va_list vargs)
27 {
28     int retval;
29  
30     retval = kobject_set_name_vargs(kobj, fmt, vargs);
31     if (retval) {
32         printk(KERN_ERR "kobject: can not set name properly!\n");
33         return retval;
34     }
35     kobj->parent = parent;
36     return kobject_add_internal(kobj);
37 }
38  
39 static int kobject_add_internal(struct kobject *kobj)
40 {
41     int error = 0;
42     struct kobject *parent;
43  
44     if (!kobj)
45         return -ENOENT;
46     /*检查name字段是否存在*/
47     if (!kobj->name || !kobj->name[0]) {
48         WARN(1, "kobject: (%p): attempted to be registered with empty "
49              "name!\n", kobj);
50         return -EINVAL;
51     }
52  
53     parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
54  
55     /* join kset if set, use it as parent if we do not already have one */
56     if (kobj->kset) {    
57         if (!parent)
58             /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
59             parent = kobject_get(&kobj->kset->kobj);
60         kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
61         kobj->parent = parent;
62     }
63  
64     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
65          kobject_name(kobj), kobj, __func__,
66          parent ? kobject_name(parent) : "<NULL>",
67          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
68  
69     error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
70     if (error) {
71         kobj_kset_leave(kobj);    /*删除链表项*/
72         kobject_put(parent);    /*减少引用计数*/
73         kobj->parent = NULL;
74  
75         /* be noisy on error issues */
76         if (error == -EEXIST)
77             printk(KERN_ERR "%s failed for %s with "
78                    "-EEXIST, don't try to register things with "
79                    "the same name in the same directory.\n",
80                    __func__, kobject_name(kobj));
81         else
82             printk(KERN_ERR "%s failed for %s (%d)\n",
83                    __func__, kobject_name(kobj), error);
84         dump_stack();
85     } else
86         kobj->state_in_sysfs = 1;
87  
88     return error;
89 }

在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。
而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。

但是这里比较奇怪的是,为什么platform目录没有对应的kset对象?

6.2.3device_create_sys_dev_entry

在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。

但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。

 1 static int device_create_sys_dev_entry(struct device *dev)
 2 {
 3     struct kobject *kobj = device_to_dev_kobj(dev);
 4     int error = 0;
 5     char devt_str[15];
 6  
 7     if (kobj) {
 8         format_dev_t(devt_str, dev->devt);
 9         error = sysfs_create_link(kobj, &dev->kobj, devt_str);
10     }
11  
12     return error;
13 }
14 /**
15  * device_to_dev_kobj - select a /sys/dev/ directory for the device
16  * @dev: device
17  *
18  * By default we select char/ for new entries.  Setting class->dev_obj
19  * to NULL prevents an entry from being created.  class->dev_kobj must
20  * be set (or cleared) before any devices are registered to the class
21  * otherwise device_create_sys_dev_entry() and
22  * device_remove_sys_dev_entry() will disagree about the the presence
23  * of the link.
24  */
25 static struct kobject *device_to_dev_kobj(struct device *dev)
26 {
27     struct kobject *kobj;
28  
29     if (dev->class)
30         kobj = dev->class->dev_kobj;
31     else
32         kobj = sysfs_dev_char_kobj;
33  
34     return kobj;
35 }

 6.2.4device_add_class_symlinks

由于dev->class为NULL,本函数其实没做任何工作。

下列代码位于drivers/base/core.c。

 1 static int device_add_class_symlinks(struct device *dev)
 2 {
 3     int error;
 4  
 5     if (!dev->class)
 6         return 0;
 7  
 8     error = sysfs_create_link(&dev->kobj,
 9                   &dev->class->p->class_subsys.kobj,
10                   "subsystem");
11     if (error)
12         goto out;
13  
14 #ifdef CONFIG_SYSFS_DEPRECATED
15     /* stacked class devices need a symlink in the class directory */
16     if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
17         device_is_not_partition(dev)) {
18         error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
19                       &dev->kobj, dev_name(dev));
20         if (error)
21             goto out_subsys;
22     }
23  
24     if (dev->parent && device_is_not_partition(dev)) {
25         struct device *parent = dev->parent;
26         char *class_name;
27  
28         /*
29          * stacked class devices have the 'device' link
30          * pointing to the bus device instead of the parent
31          */
32         while (parent->class && !parent->bus && parent->parent)
33             parent = parent->parent;
34  
35         error = sysfs_create_link(&dev->kobj,
36                       &parent->kobj,
37                       "device");
38         if (error)
39             goto out_busid;
40  
41         class_name = make_class_name(dev->class->name,
42                         &dev->kobj);
43         if (class_name)
44             error = sysfs_create_link(&dev->parent->kobj,
45                         &dev->kobj, class_name);
46         kfree(class_name);
47         if (error)
48             goto out_device;
49     }
50     return 0;
51  
52 out_device:
53     if (dev->parent && device_is_not_partition(dev))
54         sysfs_remove_link(&dev->kobj, "device");
55 out_busid:
56     if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
57         device_is_not_partition(dev))
58         sysfs_remove_link(&dev->class->p->class_subsys.kobj,
59                   dev_name(dev));
60 #else
61     /* link in the class directory pointing to the device */
62     error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
63                   &dev->kobj, dev_name(dev));
64     if (error)
65         goto out_subsys;
66  
67     if (dev->parent && device_is_not_partition(dev)) {
68         error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
69                       "device");
70         if (error)
71             goto out_busid;
72     }
73     return 0;
74  
75 out_busid:
76     sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
77 #endif
78  
79 out_subsys:
80     sysfs_remove_link(&dev->kobj, "subsystem");
81 out:
82     return error;
83 }

 

 6.2.5

同样dev->class为空,什么都没干。

下列代码位于drivers/base/core.c。

 

 1 static int device_add_attrs(struct device *dev)
 2 {
 3     struct class *class = dev->class;
 4     struct device_type *type = dev->type;
 5     int error;
 6  
 7     if (class) {
 8         error = device_add_attributes(dev, class->dev_attrs);
 9         if (error)
10             return error;
11     }
12  
13     if (type) {
14         error = device_add_groups(dev, type->groups);
15         if (error)
16             goto err_remove_class_attrs;
17     }
18  
19     error = device_add_groups(dev, dev->groups);
20     if (error)
21         goto err_remove_type_groups;
22  
23     return 0;
24  
25  err_remove_type_groups:
26     if (type)
27         device_remove_groups(dev, type->groups);
28  err_remove_class_attrs:
29     if (class)
30         device_remove_attributes(dev, class->dev_attrs);
31  
32     return error;
33 }

 

6.2.6bus_add_device 

由于dev->bus未指定,因此这个函数什么都没干。

该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。

下列代码位于drivers/base/bus.c。

 

 1 int bus_add_device(struct device *dev)
 2 {
 3     struct bus_type *bus = bus_get(dev->bus);
 4     int error = 0;
 5  
 6     if (bus) {
 7         pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
 8         error = device_add_attrs(bus, dev);
 9         if (error)
10             goto out_put;
11         
12         /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/
13         error = sysfs_create_link(&bus->p->devices_kset->kobj,
14                         &dev->kobj, dev_name(dev));
15         if (error)
16             goto out_id;
17         
18         /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
19         error = sysfs_create_link(&dev->kobj,
20                 &dev->bus->p->subsys.kobj, "subsystem");
21         if (error)
22             goto out_subsys;
23         
24         /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/
25         error = make_deprecated_bus_links(dev);
26         if (error)
27             goto out_deprecated;
28     }
29     return 0;
30  
31 out_deprecated:
32     sysfs_remove_link(&dev->kobj, "subsystem");
33 out_subsys:
34     sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
35 out_id:
36     device_remove_attrs(bus, dev);
37 out_put:
38     bus_put(dev->bus);
39     return error;
40 }

 

 6.2.7

下列代码位于drivers/base/power/sysfs.c。

 1 int dpm_sysfs_add(struct device * dev)
 2 {
 3     return sysfs_create_group(&dev->kobj, &pm_attr_group);
 4 }
 5  
 6 static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
 7  
 8  
 9 static struct attribute * power_attrs[] = {
10     &dev_attr_wakeup.attr,
11     NULL,
12 };
13 static struct attribute_group pm_attr_group = {
14     .name    = "power",
15     .attrs    = power_attrs,
16 };

该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。

在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。

6.2.8

下列代码位于drivers/base/power/main.c。该函数只是将设备添加到电源管理链表中。

 1 /**
 2  *    device_pm_add - add a device to the list of active devices
 3  *    @dev:    Device to be added to the list
 4  */
 5 void device_pm_add(struct device *dev)
 6 {
 7     pr_debug("PM: Adding info for %s:%s\n",
 8          dev->bus ? dev->bus->name : "No Bus",
 9          kobject_name(&dev->kobj));
10     mutex_lock(&dpm_list_mtx);
11     if (dev->parent) {
12         if (dev->parent->power.status >= DPM_SUSPENDING)
13             dev_warn(dev, "parent %s should not be sleeping\n",
14                  dev_name(dev->parent));
15     } else if (transition_started) {
16         /*
17          * We refuse to register parentless devices while a PM
18          * transition is in progress in order to avoid leaving them
19          * unhandled down the road
20          */
21         dev_WARN(dev, "Parentless device registered during a PM transaction\n");
22     }
23  
24     list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/
25     mutex_unlock(&dpm_list_mtx);
26 }

6.2.9

 1 void bus_attach_device(struct device *dev)
 2 {
 3     struct bus_type *bus = dev->bus;
 4     int ret = 0;
 5  
 6     if (bus) {
 7         if (bus->p->drivers_autoprobe)
 8             ret = device_attach(dev);    /*尝试获取驱动*/
 9         WARN_ON(ret < 0);
10         if (ret >= 0)        /*将设备挂在到总线中*/
11             klist_add_tail(&dev->p->knode_bus,
12                        &bus->p->klist_devices);
13     }
14 }
15  
16 /**
17  * device_attach - try to attach device to a driver.
18  * @dev: device.
19  *
20  * Walk the list of drivers that the bus has and call
21  * driver_probe_device() for each pair. If a compatible
22  * pair is found, break out and return.
23  *
24  * Returns 1 if the device was bound to a driver;
25  * 0 if no matching device was found;
26  * -ENODEV if the device is not registered.
27  *
28  * When called for a USB interface, @dev->parent->sem must be held.
29  */
30 int device_attach(struct device *dev)
31 {
32     int ret = 0;
33  
34     down(&dev->sem);
35     if (dev->driver) {    /*如果已指定驱动,即已绑定*/
36         ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
37         if (ret == 0)
38             ret = 1;
39         else {
40             dev->driver = NULL;
41             ret = 0;
42         }
43     } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/
44         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
45     }
46     up(&dev->sem);
47     return ret;
48 }

 

如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。

为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。

我们来看下bus_for_each_drv:

 1 int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
 2              void *data, int (*fn)(struct device_driver *, void *))
 3 {
 4     struct klist_iter i;
 5     struct device_driver *drv;
 6     int error = 0;
 7  
 8     if (!bus)
 9         return -EINVAL;
10  
11     klist_iter_init_node(&bus->p->klist_drivers, &i,
12                  start ? &start->p->knode_bus : NULL);
13     while ((drv = next_driver(&i)) && !error)
14         error = fn(drv, data);
15     klist_iter_exit(&i);
16     return error;
17 }

 

该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:

 1 static int __device_attach(struct device_driver *drv, void *data)
 2 {
 3     struct device *dev = data;
 4  
 5     if (!driver_match_device(drv, dev))   /*进行匹配工作*/
 6         return 0;
 7  
 8     return driver_probe_device(drv, dev);
 9 }
10  
11 static inline int driver_match_device(struct device_driver *drv,
12                       struct device *dev)
13 {
14     return drv->bus->match ? drv->bus->match(dev, drv) : 1;
15 } 
16  
17 /**
18  * driver_probe_device - attempt to bind device & driver together
19  * @drv: driver to bind a device to
20  * @dev: device to try to bind to the driver
21  *
22  * This function returns -ENODEV if the device is not registered,
23  * 1 if the device is bound sucessfully and 0 otherwise.
24  *
25  * This function must be called with @dev->sem held.  When called for a
26  * USB interface, @dev->parent->sem must be held as well.
27  */
28 int driver_probe_device(struct device_driver *drv, struct device *dev)
29 {
30     int ret = 0;
31  
32     if (!device_is_registered(dev))    /*该device是否已在sysfs中*/
33         return -ENODEV;
34  
35     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
36          drv->bus->name, __func__, dev_name(dev), drv->name);
37  
38     ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/    
39  
40     return ret;
41 }

 

该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。

我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。

随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。

really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。

6.3.10总结

在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。

整个调用流程如下:

 

6.3 spi主控制器的平台设备
本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。

在内核的启动阶段,platform设备将被注册进内核。我们来看下。

下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c

 1 static struct resource s3c_spi0_resource[] = {
 2     [0] = {
 3         .start = S3C24XX_PA_SPI,
 4         .end   = S3C24XX_PA_SPI + 0x1f,
 5         .flags = IORESOURCE_MEM,
 6     },
 7     [1] = {
 8         .start = IRQ_SPI0,
 9         .end   = IRQ_SPI0,
10         .flags = IORESOURCE_IRQ,
11     }
12  
13 };
14  
15 static u64 s3c_device_spi0_dmamask = 0xffffffffUL;
16  
17 struct platform_device s3c_device_spi0 = {
18     .name          = "s3c2410-spi",
19     .id          = 0,
20     .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
21     .resource      = s3c_spi0_resource,
22         .dev              = {
23                 .dma_mask = &s3c_device_spi0_dmamask,
24                 .coherent_dma_mask = 0xffffffffUL
25         }
26 };
27  
28 static struct platform_device *smdk2440_devices[] __initdata = {
29     &s3c_device_usb,
30     &s3c_device_lcd,
31     &s3c_device_wdt,
32     &s3c_device_i2c0,
33     &s3c_device_iis,
34     &s3c_device_spi0,
35 };
36  
37 static void __init smdk2440_machine_init(void)
38 {
39     s3c24xx_fb_set_platdata(&smdk2440_fb_info);
40     s3c_i2c0_set_platdata(NULL);
41  
42     platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
43     smdk_machine_init();
44 }

在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。
6.3.1 platform_add_devices

 1 /**
 2  * platform_add_devices - add a numbers of platform devices
 3  * @devs: array of platform devices to add
 4  * @num: number of platform devices in array
 5  */
 6 int platform_add_devices(struct platform_device **devs, int num)
 7 {
 8     int i, ret = 0;
 9  
10     for (i = 0; i < num; i++) {
11         ret = platform_device_register(devs[i]);
12         if (ret) {
13             while (--i >= 0)
14                 platform_device_unregister(devs[i]);
15             break;
16         }
17     }
18  
19     return ret;
20 }

 

该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。
6.3.2  platform_device_register

1 /**
2  * platform_device_register - add a platform-level device
3  * @pdev: platform device we're adding
4  */
5 int platform_device_register(struct platform_device *pdev)
6 {
7     device_initialize(&pdev->dev);
8     return platform_device_add(pdev);
9 }

调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。
6.3.2  platform_device_register

 1 /**
 2  * platform_device_add - add a platform device to device hierarchy
 3  * @pdev: platform device we're adding
 4  *
 5  * This is part 2 of platform_device_register(), though may be called
 6  * separately _iff_ pdev was allocated by platform_device_alloc().
 7  */
 8 int platform_device_add(struct platform_device *pdev)
 9 {
10     int i, ret = 0;
11  
12     if (!pdev)
13         return -EINVAL;
14  
15     if (!pdev->dev.parent)
16         pdev->dev.parent = &platform_bus;    /*该设备的父设备是platform设备,/sys/devices/platform*/
17  
18     pdev->dev.bus = &platform_bus_type;        /*设备挂载到platform总线上*/
19  
20     if (pdev->id != -1)
21         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
22     else
23         dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/
24  
25     /*遍历平台设备的资源,并将资源添加到资源树中*/
26     for (i = 0; i < pdev->num_resources; i++) {
27         struct resource *p, *r = &pdev->resource[i];
28  
29         if (r->name == NULL)
30             r->name = dev_name(&pdev->dev);    /*获取dev->kobject->name*/
31  
32         p = r->parent;
33         if (!p) {    /*p空*/
34             if (resource_type(r) == IORESOURCE_MEM)
35                 p = &iomem_resource;
36             else if (resource_type(r) == IORESOURCE_IO)
37                 p = &ioport_resource;
38         }
39  
40         if (p && insert_resource(p, r)) {    /*将资源添加到资源树中*/
41             printk(KERN_ERR
42                    "%s: failed to claim resource %d\n",
43                    dev_name(&pdev->dev), i);
44             ret = -EBUSY;
45             goto failed;
46         }
47     }
48  
49     pr_debug("Registering platform device '%s'. Parent at %s\n",
50          dev_name(&pdev->dev), dev_name(pdev->dev.parent));
51  
52     ret = device_add(&pdev->dev);    /*添加设备*/
53     if (ret == 0)
54         return ret;
55  
56  failed:
57     while (--i >= 0) {
58         struct resource *r = &pdev->resource[i];
59         unsigned long type = resource_type(r);
60  
61         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
62             release_resource(r);
63     }
64  
65     return ret;
66 }

在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。

那么这个"其他的工作"干了些什么呢?

首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。
然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。

最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。

在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。

由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。

6.3.3 不一样device_add调用结果
首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:

pdev->dev->kobj.kset = devices_kset

pdev->dev-.parent = &platform_bus

pdev->dev.bus = &platform_bus_type

set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。

kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。

device_create_file建立属性文件uevent。
bus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。

            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。

           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。

dpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。

执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。

[root@yj423 s3c2410-spi.0]#pwd
/sys/devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#ll
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent

[root@yj423 devices]#pwd
/sys/bus/platform/devices
[root@yj423 devices]#ll s3c2410-spi.0
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0

通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。

bus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。

接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。

7. driver举例
我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。

7.1 s3c24xx_spi_init
下列代码位于drivers/spi/spi_s3c24xx.c。

 1 MODULE_ALIAS("platform:s3c2410-spi");
 2 static struct platform_driver s3c24xx_spi_driver = {
 3     .remove        = __exit_p(s3c24xx_spi_remove),
 4     .suspend    = s3c24xx_spi_suspend,
 5     .resume        = s3c24xx_spi_resume,
 6     .driver        = {
 7         .name    = "s3c2410-spi",
 8         .owner    = THIS_MODULE,
 9     },
10 };
11  
12 static int __init s3c24xx_spi_init(void)
13 {
14         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
15

驱动注册通过调用platform_driver_probe来完成。
注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。
7.2  platform_driver_probe
下列代码位于drivers/base/platform.c。

 1 /**
 2  * platform_driver_probe - register driver for non-hotpluggable device
 3  * @drv: platform driver structure
 4  * @probe: the driver probe routine, probably from an __init section
 5  *
 6  * Use this instead of platform_driver_register() when you know the device
 7  * is not hotpluggable and has already been registered, and you want to
 8  * remove its run-once probe() infrastructure from memory after the driver
 9  * has bound to the device.
10  *
11  * One typical use for this would be with drivers for controllers integrated
12  * into system-on-chip processors, where the controller devices have been
13  * configured as part of board setup.
14  *
15  * Returns zero if the driver registered and bound to a device, else returns
16  * a negative error code and with the driver not registered.
17  */
18 int __init_or_module platform_driver_probe(struct platform_driver *drv,
19         int (*probe)(struct platform_device *))
20 {
21     int retval, code;
22  
23     /* temporary section violation during probe() */
24     drv->probe = probe;
25     retval = code = platform_driver_register(drv); /*注册platform驱动*/
26  
27     /* Fixup that section violation, being paranoid about code scanning
28      * the list of drivers in order to probe new devices.  Check to see
29      * if the probe was successful, and make sure any forced probes of
30      * new devices fail.
31      */
32     spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
33     drv->probe = NULL;
34     if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
35         retval = -ENODEV;
36     drv->driver.probe = platform_drv_probe_fail;
37     spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
38  
39     if (code != retval)
40         platform_driver_unregister(drv);
41     return retval;
42 }

这里的重点是platform_driver_register,由它来完成了platform驱动的注册。
7.3 platform_driver_register

 1 /**
 2  * platform_driver_register
 3  * @drv: platform driver structure
 4  */
 5 int platform_driver_register(struct platform_driver *drv)
 6 {
 7     drv->driver.bus = &platform_bus_type;//驱动挂载的总线
 8     if (drv->probe)
 9         drv->driver.probe = platform_drv_probe;
10     if (drv->remove)
11         drv->driver.remove = platform_drv_remove;
12     if (drv->shutdown)
13         drv->driver.shutdown = platform_drv_shutdown;
14     if (drv->suspend)
15         drv->driver.suspend = platform_drv_suspend;
16     if (drv->resume)
17         drv->driver.resume = platform_drv_resume;
18     return driver_register(&drv->driver); /*驱动注册*/
19 }

7.4driver_register

driver_register以及其他driver的api详解:linux设备驱动(3)devive_driver 详解

driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。

 1 /**
 2  * driver_register - register driver with bus
 3  * @drv: driver to register
 4  *
 5  * We pass off most of the work to the bus_add_driver() call,
 6  * since most of the things we have to do deal with the bus
 7  * structures.
 8  */
 9 int driver_register(struct device_driver *drv)
10 {
11     int ret;
12     struct device_driver *other;
13  
14     BUG_ON(!drv->bus->p);
15  
16     if ((drv->bus->probe && drv->probe) ||
17         (drv->bus->remove && drv->remove) ||
18         (drv->bus->shutdown && drv->shutdown))
19         printk(KERN_WARNING "Driver '%s' needs updating - please use "
20             "bus_type methods\n", drv->name);
21  
22     other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/
23     if (other) {    /*存在则报错*/
24         put_driver(other);
25         printk(KERN_ERR "Error: Driver '%s' is already registered, "
26             "aborting...\n", drv->name);
27         return -EEXIST;
28     }
29  
30     ret = bus_add_driver(drv);    /*将驱动添加到一个总线中*/
31     if (ret)
32         return ret;
33     ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/
34     if (ret)
35         bus_remove_driver(drv);
36     return ret;
37 }

这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。

接下来就分析这两个函数。

7.5driver_find

 1 /**
 2  * driver_find - locate driver on a bus by its name.
 3  * @name: name of the driver.
 4  * @bus: bus to scan for the driver.
 5  *
 6  * Call kset_find_obj() to iterate over list of drivers on
 7  * a bus to find driver by name. Return driver if found.
 8  *
 9  * Note that kset_find_obj increments driver's reference count.
10  */
11 struct device_driver *driver_find(const char *name, struct bus_type *bus)
12 {
13     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
14     struct driver_private *priv;
15  
16     if (k) {
17         priv = to_driver(k);
18         return priv->driver;
19     }
20     return NULL;
21 }
22 
23 
24 /**
25  * kset_find_obj - search for object in kset.
26  * @kset: kset we're looking in.
27  * @name: object's name.
28  *
29  * Lock kset via @kset->subsys, and iterate over @kset->list,
30  * looking for a matching kobject. If matching object is found
31  * take a reference and return the object.
32  */
33 struct kobject *kset_find_obj(struct kset *kset, const char *name)
34 {
35     struct kobject *k;
36     struct kobject *ret = NULL;
37  
38     spin_lock(&kset->list_lock);
39     list_for_each_entry(k, &kset->list, entry) {
40         if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
41             ret = kobject_get(k);
42             break;
43         }
44     }
45     spin_unlock(&kset->list_lock);
46     return ret;
47 }

这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。
7.6bus_add_driver

 1 /**
 2  * bus_add_driver - Add a driver to the bus.
 3  * @drv: driver.
 4  */
 5 int bus_add_driver(struct device_driver *drv)
 6 {
 7     struct bus_type *bus;
 8     struct driver_private *priv;
 9     int error = 0;
10  
11     bus = bus_get(drv->bus);    /*增加引用计数获取bus_type*/
12     if (!bus)
13         return -EINVAL;
14  
15     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
16  
17     priv = kzalloc(sizeof(*priv), GFP_KERNEL);    /*分配driver_private结构体*/
18     if (!priv) {
19         error = -ENOMEM;
20         goto out_put_bus;
21     }
22     /*初始化内核链表*/
23     klist_init(&priv->klist_devices, NULL, NULL);
24     /*相互保存*/
25     priv->driver = drv;
26     drv->p = priv;
27     /*设置该kobj属于那个kset*/
28     priv->kobj.kset = bus->p->drivers_kset;
29     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,    /*parent=NULL*/
30                      "%s", drv->name);    /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
31     if (error)
32         goto out_unregister;
33  
34     if (drv->bus->p->drivers_autoprobe) {
35         error = driver_attach(drv);    /*尝试绑定驱动和设备*/
36         if (error)
37             goto out_unregister;
38     }
39     /*添加该驱动到bus的内核链表中*/
40     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
41     module_add_driver(drv->owner, drv);/*?????????*/
42  
43     /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
44     error = driver_create_file(drv, &driver_attr_uevent);
45     if (error) {
46         printk(KERN_ERR "%s: uevent attr (%s) failed\n",
47             __func__, drv->name);
48     }
49     /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/
50     error = driver_add_attrs(bus, drv);
51     if (error) {
52         /* How the hell do we get out of this pickle? Give up */
53         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
54             __func__, drv->name);
55     }
56     /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/
57     error = add_bind_files(drv);
58     if (error) {
59         /* Ditto */
60         printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
61             __func__, drv->name);
62     }
63     /*通知用户空间???*/
64     kobject_uevent(&priv->kobj, KOBJ_ADD);
65     return 0;
66 out_unregister:
67     kfree(drv->p);
68     drv->p = NULL;
69     kobject_put(&priv->kobj);
70 out_put_bus:
71     bus_put(bus);
72     return error;
73 }

7.6.1

下列代码位于lib/kobject.c。

 1 /**
 2  * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
 3  * @kobj: pointer to the kobject to initialize
 4  * @ktype: pointer to the ktype for this kobject.
 5  * @parent: pointer to the parent of this kobject.
 6  * @fmt: the name of the kobject.
 7  *
 8  * This function combines the call to kobject_init() and
 9  * kobject_add().  The same type of error handling after a call to
10  * kobject_add() and kobject lifetime rules are the same here.
11  */
12 int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
13              struct kobject *parent, const char *fmt, ...)
14 {
15     va_list args;
16     int retval;
17  
18     kobject_init(kobj, ktype);
19  
20     va_start(args, fmt);
21     retval = kobject_add_varg(kobj, parent, fmt, args);
22     va_end(args);
23  
24     return retval;
25 }

该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。
调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。

我们来验证下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi

接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。

7.6.2

下列代码位于drivers/base/dd.c。

 1 /**
 2  * driver_attach - try to bind driver to devices.
 3  * @drv: driver.
 4  *
 5  * Walk the list of devices that the bus has on it and try to
 6  * match the driver with each one.  If driver_probe_device()
 7  * returns 0 and the @dev->driver is set, we've found a
 8  * compatible pair.
 9  */
10 int driver_attach(struct device_driver *drv)
11 {
12     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
13 }

该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。

这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。

 1 int bus_for_each_dev(struct bus_type *bus, struct device *start,
 2              void *data, int (*fn)(struct device *, void *))
 3 {
 4     struct klist_iter i;
 5     struct device *dev;
 6     int error = 0;
 7  
 8     if (!bus)
 9         return -EINVAL;
10  
11     klist_iter_init_node(&bus->p->klist_devices, &i,
12                  (start ? &start->p->knode_bus : NULL));
13     while ((dev = next_device(&i)) && !error)
14         error = fn(dev, data);
15     klist_iter_exit(&i);
16     return error;
17 }

通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。

 1 static int __driver_attach(struct device *dev, void *data)
 2 {
 3     struct device_driver *drv = data;
 4  
 5     /*
 6      * Lock device and try to bind to it. We drop the error
 7      * here and always return 0, because we need to keep trying
 8      * to bind to devices and some drivers will return an error
 9      * simply if it didn't support the device.
10      *
11      * driver_probe_device() will spit a warning if there
12      * is an error.
13      */
14  
15     if (!driver_match_device(drv, dev))
16         return 0;
17  
18     if (dev->parent)    /* Needed for USB */
19         down(&dev->parent->sem);
20     down(&dev->sem);
21     if (!dev->driver)
22         driver_probe_device(drv, dev);
23     up(&dev->sem);
24     if (dev->parent)
25         up(&dev->parent->sem);
26  
27     return 0;
28 }

首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:

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

这里直接调用了platform总线的match方法,我们来看下这个方法。

 

 1 /**
 2  * platform_match - bind platform device to platform driver.
 3  * @dev: device.
 4  * @drv: driver.
 5  *
 6  * Platform device IDs are assumed to be encoded like this:
 7  * "<name><instance>", where <name> is a short description of the type of
 8  * device, like "pci" or "floppy", and <instance> is the enumerated
 9  * instance of the device, like '0' or '42'.  Driver IDs are simply
10  * "<name>".  So, extract the <name> from the platform_device structure,
11  * and compare it against the name of the driver. Return whether they match
12  * or not.
13  */
14 static int platform_match(struct device *dev, struct device_driver *drv)
15 {
16     struct platform_device *pdev = to_platform_device(dev);
17     struct platform_driver *pdrv = to_platform_driver(drv);
18  
19     /* match against the id table first */
20     if (pdrv->id_table)
21         return platform_match_id(pdrv->id_table, pdev) != NULL;
22  
23     /* fall-back to driver name match */
24     return (strcmp(pdev->name, drv->name) == 0);
25 }

该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。

 在本例中两者同为s3c2410-spi。因此匹配完成,返回1。

返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:

 1 int driver_probe_device(struct device_driver *drv, struct device *dev)
 2 {
 3     int ret = 0;
 4  
 5     if (!device_is_registered(dev))
 6         return -ENODEV;
 7  
 8     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
 9          drv->bus->name, __func__, dev_name(dev), drv->name);
10  
11     ret = really_probe(dev, drv);
12  
13     return ret;
14 }
15 static inline int device_is_registered(struct device *dev)
16 {
17     return dev->kobj.state_in_sysfs;
18 }

该函数将调用really_probe来绑定设备和它的驱动。

 1 static int really_probe(struct device *dev, struct device_driver *drv)
 2 {
 3     int ret = 0;
 4  
 5     atomic_inc(&probe_count);
 6     pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
 7          drv->bus->name, __func__, drv->name, dev_name(dev));
 8     WARN_ON(!list_empty(&dev->devres_head));
 9  
10     dev->driver = drv;
11     if (driver_sysfs_add(dev)) {    /*创建两个symlink,更新sysfs*/
12         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
13             __func__, dev_name(dev));
14         goto probe_failed;
15     }
16  
17     if (dev->bus->probe) {
18         ret = dev->bus->probe(dev);/*调用总线的probe方法*/
19         if (ret)
20             goto probe_failed;
21     } else if (drv->probe) {
22         ret = drv->probe(dev);    /*调用驱动的probe方法*/
23         if (ret)
24             goto probe_failed;
25     }
26  
27     driver_bound(dev);              /*绑定设备和驱动*/
28     ret = 1;
29     pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
30          drv->bus->name, __func__, dev_name(dev), drv->name);
31     goto done;
32  
33 probe_failed:
34     devres_release_all(dev);
35     driver_sysfs_remove(dev);
36     dev->driver = NULL;
37  
38     if (ret != -ENODEV && ret != -ENXIO) {
39         /* driver matched but the probe failed */
40         printk(KERN_WARNING
41                "%s: probe of %s failed with error %d\n",
42                drv->name, dev_name(dev), ret);
43     }
44     /*
45      * Ignore errors returned by ->probe so that the next driver can try
46      * its luck.
47      */
48     ret = 0;
49 done:
50     atomic_dec(&probe_count);
51     wake_up(&probe_waitqueue);
52     return ret;
53 }

在这个函数中调用4个函数。

第一个函数driver_sysfs_add将更新sysfs。

 1 static int driver_sysfs_add(struct device *dev)
 2 {
 3     int ret;
 4     /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
 5        链接指向/sys/devices/platform/XXX */
 6     ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
 7               kobject_name(&dev->kobj));
 8     if (ret == 0) {
 9         /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,
10           指向/sys/bus/xxx/drivers目录下的某个目录*/
11         ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
12                     "driver");
13         if (ret)
14             sysfs_remove_link(&dev->driver->p->kobj,
15                     kobject_name(&dev->kobj));
16     }
17     return ret;
18 }

执行完以后,建立了两个链接。
在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0
在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。
这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#pwd
/sys/devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#ll driver
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi

第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。

第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。

第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。

 1 static void driver_bound(struct device *dev)
 2 {
 3     if (klist_node_attached(&dev->p->knode_driver)) {
 4         printk(KERN_WARNING "%s: device %s already bound\n",
 5             __func__, kobject_name(&dev->kobj));
 6         return;
 7     }
 8  
 9     pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
10          __func__, dev->driver->name);
11  
12     if (dev->bus)
13         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
14                          BUS_NOTIFY_BOUND_DRIVER, dev);
15  
16     klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
17 }

其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。
至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。

在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。

首先,将驱动添加到总线的驱动列表中。
接着,如果定义了驱动属性文件,则创建。
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。

我们来验证下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ls
bind           s3c2410-spi.0  uevent         unbind

 

7.7小结

在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。

同时,还更新了链表的指向,在内核中体现了同样的关系。

最后以platform driver的注册过程总结如下:

 

参考博文:https://blog.csdn.net/yj4231/java/article/details/7799245

posted @ 2020-05-17 16:59  Action_er  阅读(1954)  评论(1编辑  收藏  举报