Linux设备模型——设备驱动模型和sysfs文件系统解读

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

内核版本:2.6.30

1. What is sysfs?

  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过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; /*属于该kset的kobject链表*/
  20. spinlock_t list_lock;
  21. struct kobject kobj; /*该kset内嵌的kobj*/
  22. struct kset_uevent_ops *uevent_ops;
  23. };

2.3 ktype

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


   
   
   
   
  1. struct kobj_type {
  2.      void (*release)(struct kobject *kobj);
  3.      struct sysfs_ops *sysfs_ops;
  4.      struct attribute **default_attrs;
  5. };
  6. struct sysfs_ops {
  7.      ssize_t    (*show)(struct kobject *, struct attribute *, char *);
  8.      ssize_t    (*store)(struct kobject *,struct attribute *, const char *, size_t);
  9. };
  10. /* FIXME
  11.  * The *owner field is no longer used.
  12.  * x86 tree has been cleaned up. The owner
  13.  * attribute is still left for other arches.
  14.  */
  15. struct attribute {
  16.      const char        *name;
  17.      struct module        *owner;
  18.      mode_t            mode;
  19. };
当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目录。

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


   
   
   
   
  1. int __ init buses_init(void)
  2. {
  3. bus_kset = kset_create_and_add( "bus", &bus_uevent_ops, NULL);
  4. if (!bus_kset)
  5. return -ENOMEM;
  6. return 0;
  7. }
  8. static struct kset_uevent_ops bus_uevent_ops = {
  9.     .filter = bus_uevent_filter,
  10. };
  11. static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
  12. {
  13.      struct kobj_type *ktype = get_ktype(kobj);
  14.      if (ktype == &bus_ktype)
  15.          return 1;
  16.      return 0;
  17. }
这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。

下面代码位于drivers/base/kobject.c


   
   
   
   
  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. kset = kset_create(name, uevent_ops, parent_kobj); /*建立kset,设置某些字段*/
  22. if (!kset)
  23. return NULL;
  24. error = kset_register(kset); /*添加kset到sysfs*/
  25. if (error) {
  26. kfree(kset);
  27. return NULL;
  28. }
  29. return kset;
  30. }

这里主要调用了两个函数,接下分别来看下。

3.1 kset_create函数

下面代码位于drivers/base/kobject.c


   
   
   
   
  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. kset = kzalloc( sizeof(*kset), GFP_KERNEL); /*分配kset*/
  22. if (!kset)
  23. return NULL;
  24. kobject_set_name(&kset->kobj, name); /*设置kobj->name*/
  25. kset->uevent_ops = uevent_ops;
  26. kset->kobj.parent = parent_kobj; /*设置父对象*/
  27. /*
  28. * The kobject of this kset will have a type of kset_ktype and belong to
  29. * no kset itself. That way we can properly free it when it is
  30. * finished being used.
  31. */
  32. kset->kobj.ktype = &kset_ktype;
  33. kset->kobj.kset = NULL; /*本keset不属于任何kset*/
  34. return kset;
  35. }

这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL

也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。

随后简要看下由kobject_set_name函数调用引发的一系列调用。


   
   
   
   
  1. /**
  2. * kobject_set_name - Set the name of a kobject
  3. * @kobj: struct kobject to set the name of
  4. * @fmt: format string used to build the name
  5. *
  6. * This sets the name of the kobject. If you have already added the
  7. * kobject to the system, you must call kobject_rename() in order to
  8. * change the name of the kobject.
  9. */
  10. int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
  11. {
  12. va_list vargs;
  13. int retval;
  14. va_start(vargs, fmt);
  15. retval = kobject_set_name_vargs(kobj, fmt, vargs);
  16. va_end(vargs);
  17. return retval;
  18. }
  19. /**
  20.  * kobject_set_name_vargs - Set the name of an kobject
  21.  * @kobj: struct kobject to set the name of
  22.  * @fmt: format string used to build the name
  23.  * @vargs: vargs to format the string.
  24.  */
  25. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
  26.                   va_list vargs)
  27. {
  28.      const char *old_name = kobj->name;
  29.      char *s;
  30.      if (kobj->name && !fmt)
  31.          return 0;
  32.     kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
  33.      if (!kobj->name)
  34.          return -ENOMEM;
  35.      /* ewww... some of these buggers have '/' in the name ... */
  36.      while ((s = strchr(kobj->name, '/')))
  37.         s[ 0] = '!';
  38.     kfree(old_name);
  39.      return 0;
  40. }
  41. /* Simplified asprintf. */
  42. char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
  43. {
  44.      unsigned int len;
  45.      char *p;
  46.     va_list aq;
  47.     va_copy(aq, ap);
  48.     len = vsnprintf( NULL, 0, fmt, aq);
  49.     va_end(aq);
  50.     p = kmalloc(len+ 1, gfp);
  51.      if (!p)
  52.          return NULL;
  53.     vsnprintf(p, len+ 1, fmt, ap);
  54.      return p;
  55. }

3.2 kset_register

下面代码位于drivers/base/kobject.c


   
   
   
   
  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. if (!k)
  9. return -EINVAL;
  10. kset_init(k); /*初始化kset*/
  11. err = kobject_add_internal(&k->kobj); /*在sysfs中建立目录*/
  12. if (err)
  13. return err;
  14. kobject_uevent(&k->kobj, KOBJ_ADD);
  15. return 0;
  16. }

这里面调用了3个函数。这里先介绍前两个函数。

3.2.1 kset_init

  该函数用于初始化kset。

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


   
   
   
   
  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. static void kobject_init_internal(struct kobject *kobj)
  12. {
  13.      if (!kobj)
  14.          return;
  15.     kref_init(&kobj->kref);           /*初始化引用基计数*/
  16.     INIT_LIST_HEAD(&kobj->entry);     /*初始化链表头*/
  17.     kobj->state_in_sysfs = 0;
  18.     kobj->state_add_uevent_sent = 0;
  19.     kobj->state_remove_uevent_sent = 0;
  20.     kobj->state_initialized = 1;
  21. }

3.2.2 kobject_add_internal

  该函数将在sysfs中建立目录。

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


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

在上面的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. driver model

第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。

Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。

这个属于分离的思想,将设备和驱动分开管理。

同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。

4.1 bus

总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。

下列代码位于include/linux/device.h。


   
   
   
   
  1. struct bus_type {
  2.     const char        *name;
  3.     struct bus_attribute    *bus_attrs;
  4.     struct device_attribute    *dev_attrs;
  5.     struct driver_attribute    *drv_attrs;
  6.     int (*match)(struct device *dev, struct device_driver *drv);
  7.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  8.     int (*probe)(struct device *dev);
  9.     int (*remove)(struct device *dev);
  10.     void (*shutdown)(struct device *dev);
  11.     int (*suspend)(struct device *dev, pm_message_t state);
  12.     int (*suspend_late)(struct device *dev, pm_message_t state);
  13.     int (*resume_early)(struct device *dev);
  14.     int (*resume)(struct device *dev);
  15.     struct dev_pm_ops *pm;
  16.     struct bus_type_private *p;
  17. };
  18. /**
  19.  * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
  20.  *
  21.  * @subsys - the struct kset that defines this bus.  This is the main kobject
  22.  * @drivers_kset - the list of drivers associated with this bus
  23.  * @devices_kset - the list of devices associated with this bus
  24.  * @klist_devices - the klist to iterate over the @devices_kset
  25.  * @klist_drivers - the klist to iterate over the @drivers_kset
  26.  * @bus_notifier - the bus notifier list for anything that cares about things
  27.  * on this bus.
  28.  * @bus - pointer back to the struct bus_type that this structure is associated
  29.  * with.
  30.  *
  31.  * This structure is the one that is the actual kobject allowing struct
  32.  * bus_type to be statically allocated safely.  Nothing outside of the driver
  33.  * core should ever touch these fields.
  34.  */
  35. struct bus_type_private {
  36.     struct kset subsys;
  37.     struct kset *drivers_kset;
  38.     struct kset *devices_kset;
  39.     struct klist klist_devices;
  40.     struct klist klist_drivers;
  41.     struct blocking_notifier_head bus_notifier;
  42.     unsigned int drivers_autoprobe:1;
  43.     struct bus_type *bus;
  44. };
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。

drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。

同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。

4.2 device

设备对象在driver-model中使用struct device来表示。

下列代码位于include/linux/device.h。

   
   
   
   
  1. struct device {
  2. struct device *parent;
  3. struct device_private *p;
  4. struct kobject kobj;
  5. const char *init_name; /* initial name of the device */
  6. struct device_type *type;
  7. struct semaphore sem; /* semaphore to synchronize calls to
  8. * its driver.
  9. */
  10. struct bus_type *bus; /* type of bus device is on */
  11. struct device_driver *driver; /* which driver has allocated this
  12. device */
  13. void *driver_data; /* data private to the driver */
  14. void *platform_data; /* Platform specific data, device
  15. core doesn't touch it */
  16. struct dev_pm_info power;
  17. #ifdef CONFIG_NUMA
  18. int numa_node; /* NUMA node this device is close to */
  19. #endif
  20. u64 *dma_mask; /* dma mask (if dma'able device) */
  21. u64 coherent_dma_mask; /* Like dma_mask, but for
  22. alloc_coherent mappings as
  23. not all hardware supports
  24. 64 bit addresses for consistent
  25. allocations such descriptors. */
  26. struct device_dma_parameters *dma_parms;
  27. struct list_head dma_pools; /* dma pools (if dma'ble) */
  28. struct dma_coherent_mem *dma_mem; /* internal for coherent mem
  29. override */
  30. /* arch specific additions */
  31. struct dev_archdata archdata;
  32. dev_t devt; /* dev_t, creates the sysfs "dev" */
  33. spinlock_t devres_lock;
  34. struct list_head devres_head;
  35. struct klist_node knode_class;
  36. struct class *class;
  37. struct attribute_group **groups; /* optional groups */
  38. void (*release)(struct device *dev);
  39. };
  40. /**
  41.  * struct device_private - structure to hold the private to the driver core portions of the device structure.
  42.  *
  43.  * @klist_children - klist containing all children of this device
  44.  * @knode_parent - node in sibling list
  45.  * @knode_driver - node in driver list
  46.  * @knode_bus - node in bus list
  47.  * @device - pointer back to the struct class that this structure is
  48.  * associated with.
  49.  *
  50.  * Nothing outside of the driver core should ever touch these fields.
  51.  */
  52. struct device_private {
  53.      struct klist klist_children;
  54.      struct klist_node knode_parent;
  55.      struct klist_node knode_driver;
  56.      struct klist_node knode_bus;
  57.      struct device *device;
  58. };

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

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

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

4.3 driver

设备设备对象在driver-model中使用struct device_driver来表示。

下列代码位于include/linux/device.h。


   
   
   
   
  1. struct device_driver {
  2. const char *name;
  3. struct bus_type *bus;
  4. struct module *owner;
  5. const char *mod_name; /* used for built-in modules */
  6. int (*probe) (struct device *dev);
  7. int (*remove) (struct device *dev);
  8. void (*shutdown) (struct device *dev);
  9. int (*suspend) (struct device *dev, pm_message_t state);
  10. int (*resume) (struct device *dev);
  11. struct attribute_group **groups;
  12. struct dev_pm_ops *pm;
  13. struct driver_private *p;
  14. };
  15. struct driver_private {
  16.      struct kobject kobj;
  17.      struct klist klist_devices;
  18.      struct klist_node knode_bus;
  19.      struct module_kobject *mkobj;
  20.      struct device_driver *driver;
  21. }; 
device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。

该设备驱动所支持的设备由klist_devices指定。

该设备驱动所挂载的总线由knode_bus制定。

5. Bus举例

本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。

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.     early_platform_cleanup();
  5.     error = device_register(&platform_bus);
  6.      if (error)
  7.          return error;
  8.     error =  bus_register(&platform_bus_type);
  9.      if (error)
  10.         device_unregister(&platform_bus);
  11.      return error;
  12. }
  13. struct bus_type platform_bus_type = {
  14. .name = "platform",
  15. .dev_attrs = platform_dev_attrs,
  16. .match = platform_match,
  17. .uevent = platform_uevent,
  18. .pm = PLATFORM_PM_OPS_PTR,
  19. };
  20. EXPORT_SYMBOL_GPL(platform_bus_type);
从bus_type,我们看到该总线的名字为platform。

调用了两个函数,我们只关注bus_register函数。


   
   
   
   
  1. /**
  2. * bus_register - register a bus with the system.
  3. * @bus: bus.
  4. *
  5. * Once we have that, we registered the bus with the kobject
  6. * infrastructure, then register the children subsystems it has:
  7. * the devices and drivers that belong to the bus.
  8. */
  9. int bus_register(struct bus_type *bus)
  10. {
  11. int retval;
  12. struct bus_type_private *priv;
  13. priv = kzalloc( sizeof(struct bus_type_private), GFP_KERNEL);
  14. if (!priv)
  15. return -ENOMEM;
  16. /*互相保存*/
  17. priv->bus = bus;
  18. bus->p = priv;
  19. BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
  20. /*设定kobject->name*/
  21. retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
  22. if (retval)
  23. goto out;
  24. priv->subsys.kobj.kset = bus_kset;
  25. priv->subsys.kobj.ktype = &bus_ktype;
  26. priv->drivers_autoprobe = 1;
  27. /*注册kset,在bus/建立目录XXX,XXX为bus->name*/
  28. retval = kset_register(&priv->subsys);
  29. if (retval)
  30. goto out;
  31. /*创建属性,在bus/XXX/建立文件uevent*/
  32. retval = bus_create_file(bus, &bus_attr_uevent);
  33. if (retval)
  34. goto bus_uevent_fail;
  35. /*创建kset,在bus/XXX/建立目录devices*/
  36. priv->devices_kset = kset_create_and_add( "devices", NULL,
  37. &priv->subsys.kobj);
  38. if (!priv->devices_kset) {
  39. retval = -ENOMEM;
  40. goto bus_devices_fail;
  41. }
  42. /*创建kset,在bus/XXX/建立目录drivers*/
  43. priv->drivers_kset = kset_create_and_add( "drivers", NULL,
  44. &priv->subsys.kobj);
  45. if (!priv->drivers_kset) {
  46. retval = -ENOMEM;
  47. goto bus_drivers_fail;
  48. }
  49. /*初始化2个内核链表,*/
  50. klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  51. klist_init(&priv->klist_drivers, NULL, NULL);
  52. /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/
  53. retval = add_probe_files(bus);
  54. if (retval)
  55. goto bus_probe_files_fail;
  56. /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
  57. retval = bus_add_attrs(bus);
  58. if (retval)
  59. goto bus_attrs_fail;
  60. pr_debug( "bus: '%s': registered\n", bus->name);
  61. return 0;
  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. kfree(bus->p);
  73. out:
  74. bus->p = NULL;
  75. return retval;
  76. }
  77. EXPORT_SYMBOL_GPL(bus_register);

函数中,首先调用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. /* add the kobject to its kset's list */
  2. static void kobj_kset_join(struct kobject *kobj)
  3. {
  4. if (!kobj->kset)
  5. return;
  6. kset_get(kobj->kset); /*增加kset引用计数*/
  7. spin_lock(&kobj->kset->list_lock);
  8. list_add_tail(&kobj->entry, &kobj->kset-> list); /*将kojbect添加到kset结构中的链表当中*/
  9. spin_unlock(&kobj->kset->list_lock);
  10. }
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. }
  11. EXPORT_SYMBOL_GPL(bus_create_file);
有关底层的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中。

我们来看下关系图:


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


   
   
   
   
  1. static int add_probe_files(struct bus_type *bus)
  2. {
  3. int retval;
  4. retval = bus_create_file(bus, &bus_attr_drivers_probe);
  5. if (retval)
  6. goto out;
  7. retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
  8. if (retval)
  9. bus_remove_file(bus, &bus_attr_drivers_probe);
  10. out:
  11. return retval;
  12. }
该函数只是简单的调用了两次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. static int bus_add_attrs(struct bus_type *bus)
  6. {
  7. int error = 0;
  8. int i;
  9. if (bus->bus_attrs) {
  10. for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
  11. error = bus_create_file(bus, &bus->bus_attrs[i]);
  12. if (error)
  13. goto err;
  14. }
  15. }
  16. done:
  17. return error;
  18. err:
  19. while (--i >= 0)
  20. bus_remove_file(bus, &bus->bus_attrs[i]);
  21. goto done;
  22. }
我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。

好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。

[root@yj423 platform]#pwd
/sys/bus/platform
[root@yj423 platform]#ls
devices            drivers            drivers_autoprobe  drivers_probe      uevent

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

6. device举例

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

6.1 虚拟的platform设备

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

在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。


   
   
   
   
  1. int __ init platform_bus_init(void)
  2. {
  3. int error;
  4. early_platform_cleanup();
  5. error = device_register(&platform_bus);
  6. if (error)
  7. return error;
  8. error = bus_register(&platform_bus_type);
  9. if (error)
  10. device_unregister(&platform_bus);
  11. return error;
  12. }
  13. struct device platform_bus = {
  14.     .init_name    = "platform",
  15. };
  16. EXPORT_SYMBOL_GPL(platform_bus)
下列函数位于drivers/base/core.c。

   
   
   
   
  1. /**
  2. * device_register - register a device with the system.
  3. * @dev: pointer to the device structure
  4. *
  5. * This happens in two clean steps - initialize the device
  6. * and add it to the system. The two steps can be called
  7. * separately, but this is the easiest and most common.
  8. * I.e. you should only call the two helpers separately if
  9. * have a clearly defined need to use and refcount the device
  10. * before it is added to the hierarchy.
  11. *
  12. * NOTE: _Never_ directly free @dev after calling this function, even
  13. * if it returned an error! Always use put_device() to give up the
  14. * reference initialized in this function instead.
  15. */
  16. int device_register(struct device *dev)
  17. {
  18. device_initialize(dev); /*初始化dev的某些字段*/
  19. return device_add(dev); /*将设备添加到系统中*/
  20. }

一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:

下列函数位于drivers/base/core.c。


   
   
   
   
  1. /**
  2. * device_initialize - init device structure.
  3. * @dev: device.
  4. *
  5. * This prepares the device for use by other layers by initializing
  6. * its fields.
  7. * It is the first half of device_register(), if called by
  8. * that function, though it can also be called separately, so one
  9. * may use @dev's fields. In particular, get_device()/put_device()
  10. * may be used for reference counting of @dev after calling this
  11. * function.
  12. *
  13. * NOTE: Use put_device() to give up your reference instead of freeing
  14. * @dev directly once you have called this function.
  15. */
  16. void device_initialize(struct device *dev)
  17. {
  18.     dev->kobj.kset = devices_kset;         /*设置kobj属于哪个kset,/sys/devices/*/
  19.     kobject_init(&dev->kobj, &device_ktype); /*初始化dev->kobj*/
  20.     INIT_LIST_HEAD(&dev->dma_pools);     /*初始化链表头*/
  21.     init_MUTEX(&dev->sem);                 /*初始化互斥体*/
  22.     spin_lock_init(&dev->devres_lock);     /*初始化自旋锁*/
  23.     INIT_LIST_HEAD(&dev->devres_head);     /*初始化链表头*/
  24.     device_init_wakeup(dev, 0);             /*设置该device不能唤醒*/
  25.     device_pm_init(dev);                 /*设置该device可操作*/
  26.     set_dev_node(dev, -1);                 /*设置NUMA节点*/
  27. }

6.1.1 有关devices_kset

首先其中用到了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. return 0;
  16. char_kobj_err:
  17. kobject_put(sysfs_dev_block_kobj);
  18. block_kobj_err:
  19. kobject_put(dev_kobj);
  20. dev_kobj_err:
  21. kset_unregister(devices_kset);
  22. return -ENOMEM;
  23. }
由此可见,devices_kset对象表示的目录为/sys下的devices目录。

6.1.2 kobject_init

下列函数位于lib/kojbect.c。


   
   
   
   
  1. /**
  2. * kobject_init - initialize a kobject structure
  3. * @kobj: pointer to the kobject to initialize
  4. * @ktype: pointer to the ktype for this kobject.
  5. *
  6. * This function will properly initialize a kobject such that it can then
  7. * be passed to the kobject_add() call.
  8. *
  9. * After this function is called, the kobject MUST be cleaned up by a call
  10. * to kobject_put(), not by a call to kfree directly to ensure that all of
  11. * the memory is cleaned up properly.
  12. */
  13. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  14. {
  15. char *err_str;
  16. if (!kobj) {
  17. err_str = "invalid kobject pointer!";
  18. goto error;
  19. }
  20. if (!ktype) {
  21. err_str = "must have a ktype to be initialized properly!\n";
  22. goto error;
  23. }
  24. if (kobj->state_initialized) {
  25. /* do not error out as sometimes we can recover */
  26. printk(KERN_ERR "kobject (%p): tried to init an initialized "
  27. "object, something is seriously wrong.\n", kobj);
  28. dump_stack();
  29. }
  30. kobject_init_internal(kobj);
  31. kobj->ktype = ktype;
  32. return;
  33. error:
  34. printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
  35. dump_stack();
  36. }
  37. EXPORT_SYMBOL(kobject_init);
  38. static void kobject_init_internal(struct kobject *kobj)
  39. {
  40.      if (!kobj)
  41.          return;
  42.     kref_init(&kobj->kref);             /*初始化引用基计数*/
  43.     INIT_LIST_HEAD(&kobj->entry);     /*初始化链表头*/
  44.     kobj->state_in_sysfs = 0;
  45.     kobj->state_add_uevent_sent = 0;
  46.     kobj->state_remove_uevent_sent = 0;
  47.     kobj->state_initialized = 1;
  48. }
该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。

6.1.3 device_init_wakeup

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


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

6.1.4 device_pm_init

设置电源的状态。


   
   
   
   
  1. static inline void device_pm_init(struct device *dev)
  2. {
  3. dev->power.status = DPM_ON;     /*该device被认为可操作*/
  4. }

6.1.5 set_dev_node

如果使用NUMA,则设置NUMA节点。


   
   
   
   
  1. #ifdef CONFIG_NUMA
  2. 。。。。。。
  3. static inline void set_dev_node(struct device *dev, int node)
  4. {
  5. dev->numa_node = node;
  6. }
  7. #else
  8. 。。。。。。
  9. static inline void set_dev_node(struct device *dev, int node)
  10. {
  11. }
  12. #endif

6.2 device_add

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


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

该函数调用了非常多的其他函数,接下来对主要的函数做出分析。

6.2.1 setup_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. static struct kobject *get_device_parent(struct device *dev,

你可能感兴趣的:(driver,linux,driver,sys)