Chinaunix首页 | 论坛 | 博客
  • 博客访问: 35231
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 45
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-26 02:10
个人简介

滴水穿石。

文章分类

全部博文(8)

文章存档

2015年(8)

我的朋友

分类: 嵌入式

2015-02-03 23:26:51


>> kobject


点击(此处)折叠或打开

  1. struct kobject {
  2.     const char *name; // 对象名称
  3.     struct list_head entry; // kobject的链表入口,该kobject将添加到其所属的kset的list链表中
  4.     struct kobject *parent; // 父对象
  5.     struct kset *kset; // 所属的kset
  6.     struct kobj_type *ktype; // 所属的ktype
  7.     struct sysfs_dirent *sd; // 在sysfs中的目录结构,在哪里被设置的?
  8.     struct kref kref; // 引用计数,kobject的引用计数在什么时候会增减?
  9.     
  10.     // 位域形式定义状态变量
  11.     unsigned int state_initialized:1; // 标记kobject是否被初始化
  12.     unsigned int state_in_sysfs:1; // 标记是否已存在于sysfs文件系统中
  13.     unsigned int state_add_uevent_sent:1; // 标记ADD事件是否被sent过
  14.     unsigned int state_remove_uevent_sent:1; // 标记REMOVE事件是否被sent过
  15.     unsigned int uevent_suppress:1; // 这一位为1时,这个kobject不产生任何 uevent
  16. };

  17. struct kobj_type {
  18.     void (*release)(struct kobject *kobj); // kobject的析构函数
  19.     const struct sysfs_ops *sysfs_ops; // kobject的属性读写函数
  20.                             /*struct sysfs_ops {
  21.                                 ssize_t (*show)(struct kobject *, struct attribute *,char *);
  22.                                 ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
  23.                             };*/

  24.     struct attribute **default_attrs; // 属性数组(二级指针)
  25.                             /*struct attribute {
  26.                                 const char *name;
  27.                                 mode_t mode;
  28.                             };*/
  29.     const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); // 新特性,还未研究过
  30.     const void *(*namespace)(struct kobject *kobj); // 新特性,还未研究过
  31. }


kobject_init_and_add 函数用于"初始化"(不是"创建")并添加一个 kobject , 参数fmt一般就是kobject的name,  注意这个函数不会修改kobject的 kset,
应在这个函数调用之前设置好 kobj->kset 。

点击(此处)折叠或打开

  1. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
  2.              struct kobject *parent, const char *fmt, ...)
  3. {
  4.     va_list args;
  5.     int retval;

  6.     kobject_init(kobj, ktype); // 初始化 entry、 ktype和引用计数,并将state_initialized设置为1

  7.     va_start(args, fmt);
  8.     retval = kobject_add_varg(kobj, parent, fmt, args);
  9.         // kobject_add_varg内部会先调用kobject_set_name_vargs为kobjcet设置名称,
  10.         // 再调用kobject_add_internal(kobj)在sysfs中建立kobject的相关信息

  11.     va_end(args);

  12.     return retval;
  13. }

kobject_add_internal(kobj)中,几个关键的步骤:
1. 设置kobj的父对象,并将kobj加入到其所属的kset的链表中(通过调用kobj_kset_join(kobj));
    关于父对象,如果设置了kobj->kset,但未设置kobj->parent时,就将kobj->kset->kobj作为kobj的父对象。
2. 调用create_dir(kobj)为kobj在sysfs中创建目录,这个函数内部会调用sysfs_create_dir(kobj)
   和populate_dir(kobj),前者用于创建目录并设置kobj->sd,后者则用于创建属性文件。
    根据kobj的父对象可确定其在sysfs中的上级目录,如果kobj的parent是NULL,则将sysfs的顶级目录作为该
    kobj的上级目录。
3. 为kobj创建了目录后,将 kobj->state_in_sysfs 设为 1 。

kobject_del 函数用于释放一个kobject。

点击(此处)折叠或打开

  1. void kobject_del(struct kobject *kobj)
  2. {
  3.      if (!kobj)
  4.          return;
  5.  
  6.      sysfs_remove_dir(kobj); // 移除目录
  7.      kobj->state_in_sysfs = 0; // 取消state_in_sysfs标记
  8.      kobj_kset_leave(kobj); // 将kobj从其所属的kset的list列表中移除
  9.      kobject_put(kobj->parent); // 减少引用计数
  10.      kobj->parent = NULL; // 父对象设为 NULL
  11. }

kobject_del中重要的两步: 1. 移除kobj在sysfs中的目录; 2.取消kobj与其所属的kset的联系。注意这个函数中并不会调用析构函数(ktype->release())





>> kset


点击(此处)折叠或打开

  1. struct kset {
  2.     struct list_head list; // the list of all kobjects for this kset
  3.     spinlock_t list_lock; // 操作 list 的锁
  4.     struct kobject kobj; // kset本身的kobject对象
  5.     const struct kset_uevent_ops *uevent_ops; // 用户事件操作
  6. };



kset_create_and_add函数用于"创建"并添加一个 kset。这个函数会设置 kset 的parent,但不设置这个kset所属的上一层 kset

点击(此处)折叠或打开

  1. struct kset *kset_create_and_add(const char *name,
  2.                     struct kset_uevent_ops *uevent_ops,
  3.                     struct kobject *parent_kobj)
  4. {
  5.     struct kset *kset;
  6.     int error;

  7.     kset = kset_create(name, uevent_ops, parent_kobj);
  8.         // 创建一个 kset, 并设置其 kobj.name, kobj.ktype=&kset_ktype,(kset专有的ktype,内核提供)
  9.         // kobj.kset=NULL ,以及 kobj.parent 。
  10.     if (!kset)
  11.         return NULL;
  12.     error = kset_register(kset); // 注册kset。
  13.                     // 内部先调用kset_init(kset)初始化kset
  14.                     // 再调用kobject_add_internal(&kset->kobj)在sysfs中建立kset->kobj的相关信息
  15.                     // 再调用kobject_uevent(&k->kobj, KOBJ_ADD)向用户空间产生热插拔事件(事件类型为ADD)
  16.     if (error) {
  17.         kfree(kset);
  18.         return NULL;
  19.     }
  20.     return kset;
  21. }

  22. int kset_register(struct kset *k)
  23. {
  24.      int err;
  25.  
  26.      if (!k)
  27.          return -EINVAL;
  28.  
  29.      kset_init(k);
  30.      err = kobject_add_internal(&k->kobj);
  31.      if (err)
  32.          return err;
  33.      kobject_uevent(&k->kobj, KOBJ_ADD);
  34.      return 0;
  35. }

因为添加了kset会产生一个事件,这个事件是通过用户空间的hotplug程序处理的,这就是kset明显不
同于kobject的地方:注册一个kobject不会产生事件,只有注册kset才会。
之后会详细研究一下kobject_uevent函数.这对于我们研究hotplug的深层机理是很有帮助的.

kset的注销函数,只是减一下引用计数

点击(此处)折叠或打开

  1. void kset_unregister(struct kset *k)
  2. {
  3.     if (!k)
  4.         return;
  5.     kobject_put(&k->kobj);
  6. }


>> ktype (kobject的属性操作)
kype 决定了一个 kobject的所有属性及属性的操作方法。以 kset_ktype 为例,看看这个结构体该怎么用,以及kobject的属性应如何操作。
前面讲解kset时提到的kset_create函数中会将 kset->kobj.ktype 设置为 &kset_ktype ,相关的定义有:

点击(此处)折叠或打开

  1. static struct kobj_type kset_ktype = {
  2.     .sysfs_ops = &kobj_sysfs_ops,
  3.     .release = kset_release, // 析构函数
  4. };
  5. static void kset_release(struct kobject *kobj)
  6. {
  7.     struct kset *kset = container_of(kobj, struct kset, kobj);
  8.     pr_debug("kobject: '%s' (%p): %s\n",
  9.          kobject_name(kobj), kobj, __func__);
  10.     kfree(kset); //释放kset的内存
  11. }
  12. const struct sysfs_ops kobj_sysfs_ops = { // kobject默认的属性操作函数
  13.     .show = kobj_attr_show,
  14.     .store = kobj_attr_store,
  15. };
  16. /* default kobject attribute operations */ // kobject默认的属性读函数
  17. static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
  18.                   char *buf)
  19. {
  20.     struct kobj_attribute *kattr;
  21.     ssize_t ret = -EIO;

  22.     kattr = container_of(attr, struct kobj_attribute, attr); // 出现了kobj_attribute结构体
  23.     if (kattr->show) // 回调kobj_attribute结构体的show函数
  24.         ret = kattr->show(kobj, kattr, buf);
  25.     return ret;
  26. }

这里看到了另一个结构体,kobj_attribute,利用这个结构体可以为 kobject 的每个属性定制一个独特的读写方法,
它的定义如下:

点击(此处)折叠或打开

  1. struct kobj_attribute {
  2.     struct attribute attr; // 属性实体
  3.     ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
  4.             char *buf); // 属性独特的读函数
  5.     ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
  6.              const char *buf, size_t count); //属性独特的写函数
  7. };

取出kobj_attribute结构体中attr成员的地址,放到ktype结构体的default_attrs数组中,再将ktype结构体的sysfs_ops->show
函数设置为kobj_attr_show,属性的读操作就会自动回调到为该属性定制的独特读函数上。属性的store函数类似。
内核中 __ATTR 宏可以帮助快速地建立一个kobj_attribute结构体的实例:

点击(此处)折叠或打开

  1. #define __ATTR(_name,_mode,_show,_store) { \
  2.     .attr = {.name = __stringify(_name), .mode = _mode }, \
  3.     .show = _show, \
  4.     .store = _store, \
  5. }


>> struct kset_uevent_ops 和 kobject_uevent 函数
kset结构中有一个uevent_ops成员,kset_register(...)函数的最后也调用了kobject_uevent 函数,下面就看下与 uevent相关的
结构体和函数。


点击(此处)折叠或打开

  1. struct kset_uevent_ops {
  2.     int (* const filter)(struct kset *kset, struct kobject *kobj); // 事件过滤,返回0时说明事件被过滤,不再处理该事件
  3.     const char *(* const name)(struct kset *kset, struct kobject *kobj); // 返回kset和kobj所对应的子系统的名称
  4.     int (* const uevent)(struct kset *kset, struct kobject *kobj, // 为 用户空间事件 设置kset和kobj特有的额外的环境变量(基础环境变量之外的变量)
  5.               struct kobj_uevent_env *env);
  6. };
  7. enum kobject_action { // 事件类型
  8.     KOBJ_ADD,
  9.     KOBJ_REMOVE,
  10.     KOBJ_CHANGE,
  11.     KOBJ_MOVE,
  12.     KOBJ_ONLINE,
  13.     KOBJ_OFFLINE,
  14.     KOBJ_MAX
  15. };


kobject_uevent 函数的作用是在 kobj 这个对象上产生一个 action 事件,其内部主要是对kobject_uevent_env的调用。

点击(此处)折叠或打开

  1. int kobject_uevent(struct kobject *kobj, enum kobject_action action)
  2. {
  3.      return kobject_uevent_env(kobj, action, NULL);
  4. }
  5. int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
  6.                char *envp_ext[]) // 参数envp_ext是uevent所需的额外的环境变量
  7. {
  8.     ...
  9.     ...

  10.     top_kobj = kobj;
  11.     while (!top_kobj->kset && top_kobj->parent)
  12.         top_kobj = top_kobj->parent;
  13.     if (!top_kobj->kset) {
  14.         pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  15.              "without kset!\n", kobject_name(kobj), kobj,
  16.              __func__);
  17.         return -EINVAL;
  18.     }
  19.     kset = top_kobj->kset;
  20.     uevent_ops = kset->uevent_ops; // 获得 uevent_ops

  21.     1 . 因为对事件的处理函数包含在kobject->kset-> uevent_ops中.要处理事件,就必须要找到上层的
  22.     一个不为空的kset.上面的代码就是顺着kobject->parent找不到一个不为空的kset.如果不存在
  23.     这样的kset.就退出;

  24.     /* skip the event, if uevent_suppress is set*/
  25.     if (kobj->uevent_suppress) {
  26.         pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  27.                  "caused the event to drop!\n",
  28.                  kobject_name(kobj), kobj, __func__);
  29.         return 0;
  30.     }
  31.     /* skip the event, if the filter returns zero. */
  32.     if (uevent_ops && uevent_ops->filter)
  33.         if (!uevent_ops->filter(kset, kobj)) {
  34.             pr_debug("kobject: '%s' (%p): %s: filter function "
  35.                  "caused the event to drop!\n",
  36.                  kobject_name(kobj), kobj, __func__);
  37.             return 0;
  38.         }
  39.     
  40.     2. 对事件进行过滤。如果 kobj 不接受 uevent (由kobj->uevent_suppress决定),或者
  41.     该类型的uevent被 filter() 过滤掉了,就不再处理该事件。


  42.     /* originating subsystem */
  43.     if (uevent_ops && uevent_ops->name)
  44.         subsystem = uevent_ops->name(kset, kobj);
  45.     else
  46.         subsystem = kobject_name(&kset->kobj); // 如果uevent_ops的name函数未设置,则用top_kobj所属的kset的名称作为子系统名
  47.     if (!subsystem) {
  48.         pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  49.              "event to drop!\n", kobject_name(kobj), kobj,
  50.              __func__);
  51.         return 0;
  52.     }
  53.     3. 获得子系统(subsystem)的名称(之后需要将它设置到环境变量中)。

  54.     /* environment buffer */
  55.     env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  56.     if (!env)
  57.         return -ENOMEM;

  58.     4. 申请环境变量所需的内存,主要是申请一个kobj_uevent_env结构体,这个结构体能容纳最多 32 个变量和最多2048字节的缓存空间。


  59.     /* complete object path */
  60.     devpath = kobject_get_path(kobj, GFP_KERNEL); // 获得 kobj 在sysfs中的目录
  61.     if (!devpath) {
  62.         retval = -ENOENT;
  63.         goto exit;
  64.     }
  65.     /* default keys */ 设置3个基本环境变量,分别是 动作ACTION、设备路径devpath、子系统subsystem.
  66.     retval = add_uevent_var(env, "ACTION=%s", action_string);
  67.     if (retval)
  68.         goto exit;
  69.     retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  70.     if (retval)
  71.         goto exit;
  72.     retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  73.     if (retval)
  74.         goto exit;
  75.     /* keys passed in from the caller */ 设置调用本函数时传递进来的额外的环境变量
  76.     if (envp_ext) {
  77.         for (i = 0; envp_ext[i]; i++) {
  78.             retval = add_uevent_var(env, "%s", envp_ext[i]);
  79.             if (retval)
  80.                 goto exit;
  81.         }
  82.     }
  83.     /* let the kset specific function add its stuff */// 让kset指定的uevent_ops结构添加特有的环境变量
  84.     if (uevent_ops && uevent_ops->uevent) {
  85.         retval = uevent_ops->uevent(kset, kobj, env);
  86.         if (retval) {
  87.             pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  88.                  "%d\n", kobject_name(kobj), kobj,
  89.                  __func__, retval);
  90.             goto exit;
  91.         }
  92.     }
  93.     if (action == KOBJ_ADD)
  94.         kobj->state_add_uevent_sent = 1; // 根据事件类型设置 kobj 的state_add_uevent_sent和state_remove_uevent_sent状态
  95.     else if (action == KOBJ_REMOVE)
  96.         kobj->state_remove_uevent_sent = 1;
  97.     /* we will send an event, so request a new sequence number */
  98.     spin_lock(&sequence_lock);
  99.     seq = ++uevent_seqnum; // 每发送一个uevent, 全局变量uevent_seqnum就加1,并将它的值添加到环境变量中
  100.     spin_unlock(&sequence_lock);
  101.     retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
  102.     if (retval)
  103.         goto exit;
  104.     5. 添加各种所需的环境变量到kobj_uevent_env结构体中。

  105. #if defined(CONFIG_NET)
  106.     ...
  107.     ...
  108. #endif
  109.     /* call uevent_helper, usually only enabled during early boot */
  110.     if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
  111.         char *argv [3];

  112.         argv [0] = uevent_helper;
  113.         argv [1] = (char *)subsystem; // 子系统作为参数
  114.         argv [2] = NULL;
  115.             // 添加最后两个环境变量 , HOME 和 PATH
  116.         retval = add_uevent_var(env, "HOME=/");
  117.         if (retval)
  118.             goto exit;
  119.         retval = add_uevent_var(env,
  120.                     "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  121.         if (retval)
  122.             goto exit;

  123.         retval = call_usermodehelper(argv[0], argv, // 调用用户空间的程序
  124.                          env->envp, UMH_WAIT_EXEC);
  125.                         /*enum umh_wait {
  126.                             UMH_NO_WAIT = -1, // don't wait at all
  127.                             UMH_WAIT_EXEC = 0, // wait for the exec, but not the process
  128.                             UMH_WAIT_PROC = 1, // wait for the process to complete
  129.                         };*/

  130.     }
  131.     6. 调用用户空间的uevent_helper(hotplug?),以子系统名称为参数,hotplug处理程序中的参数和环境变量就是这么来的


  132. exit:
  133.     kfree(devpath);
  134.     kfree(env);
  135.     return retval;
  136. }





>> bus_type


点击(此处)折叠或打开

  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 (*resume)(struct device *dev);

  13.     const struct dev_pm_ops *pm;

  14.     struct subsys_private *p;
  15. };
  16. struct subsys_private {
  17.     struct kset subsys;
  18.     struct kset *devices_kset;

  19.     struct kset *drivers_kset;
  20.     struct klist klist_devices;
  21.     struct klist klist_drivers;
  22.     struct blocking_notifier_head bus_notifier;
  23.     unsigned int drivers_autoprobe:1;
  24.     struct bus_type *bus;

  25.     struct list_head class_interfaces;
  26.     struct kset glue_dirs;
  27.     struct mutex class_mutex;
  28.     struct class *class;
  29. };
  30. #define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj)


bus_register用于注册总线

点击(此处)折叠或打开

  1. int bus_register(struct bus_type *bus)
  2. {
  3.     int retval;
  4.     struct bus_type_private *priv;

  5.     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
  6.     if (!priv)
  7.         return -ENOMEM;

  8.     priv->bus = bus;
  9.     bus->p = priv;

  10.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

  11.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
  12.     if (retval)
  13.         goto out;

  14.     priv->subsys.kobj.kset = bus_kset;
  15.     priv->subsys.kobj.ktype = &bus_ktype;
  16.     priv->drivers_autoprobe = 1;

  17.     retval = kset_register(&priv->subsys);
  18.     if (retval)
  19.         goto out;

  20.     首先,先为struct bus_type的私有区分配空间,然后将其和struct bus_type关联起来.
  21.     由于struct bus_type也要在sysfs文件中表示一个节点,因此,它也内嵌也一个kset的结构,这就是priv->subsys.
  22.     首先,它为这个kset的名称赋值为bus的名称,然后将priv->subsys.kobj.kset指向bus_kset.priv->subsys.kobj.ktype指向bus_ktype;
  23.     然后调用kset_reqister()将priv->subsys注册.这里涉及到的接口都在之前分析过.注册过后,
  24.     应该会在bus_kset所表示的目录下创建一个总线名称的目录.并且用户空间的hotplug应该会检测到一个add事件.
  25.     我们来看一下bus_kset到底指向的是什么: bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
  26.     从此可以看出.这个bus_kset在sysfs中的结点就是/sys/bus.在这里注册的struct bus_types就会在/sys/bus/下面出现.
  27.  
  28.     retval = bus_create_file(bus, &bus_attr_uevent); // 添加bus_attr_uevent属性,他对应的属性文件名为 uevent 。
  29.     if (retval)
  30.         goto bus_uevent_fail;

  31.     bus_create_file()就是在priv->subsys.kobj的这个kobject上建立一个普通属性的文件.
  32.     这个文件的属性对应在bus_attr_uevent.读写操作对应在priv->subsys.ktype中.
  33.     我们到后面才统一分析bus注册时候的文件创建
  34.  
  35.     // drivers和devices两个kset的 uevent_ops 都是NULL,他们的kset也是NULL,
  36.     // 但parent是subsys.kobj(即总线 bus_type 对应的kobjct)。而subsys.kobj的
  37.     // kset是bus_kset。 因此drivers和devices这两个kset的 top_kobj(参见kobject_uevent_env函数)
  38.     // 也是bus_kset,他们产生的 uevent 也都由bus_kset的uevent_ops,即bus_uevent_ops处理。
  39.     ///sys/bus/<bus>/drivers目录下面有所有挂在该总线上的驱动,而/sys/bus/<bus>/devices目录下
  40.     // 只是指向/sys/devices/..的链接
  41.     priv->devices_kset = kset_create_and_add("devices", NULL,
  42.                      &priv->subsys.kobj);
  43.     if (!priv->devices_kset) {
  44.      retval = -ENOMEM;
  45.      goto bus_devices_fail;
  46.     }

  47.     priv->drivers_kset = kset_create_and_add("drivers", NULL,
  48.                      &priv->subsys.kobj);
  49.     if (!priv->drivers_kset) {
  50.      retval = -ENOMEM;
  51.      goto bus_drivers_fail;
  52.     }

  53.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  54.     klist_init(&priv->klist_drivers, NULL, NULL);

  55.     这段代码会在bus所在的目录下建立两个目录,分别为devices和drivers.并初始化挂载设备和驱动的链表

  56.     retval = add_probe_files(bus); // 这个函数内部只创建 bus_attr_drivers_probe和
  57.                     // bus_attr_drivers_autoprobe两个属性文件,它们对应的文件名
  58.                     // 分别是drivers_probe和drivers_autoprobe。
  59.     if (retval)
  60.         goto bus_probe_files_fail;

  61.     retval = bus_add_attrs(bus); // 这个函数内部创建 bus->bus_attrs 属性数组中的所有属性文件,这个数组最后一个属性的名称是NULL。
  62.     if (retval)
  63.         goto bus_attrs_fail;

  64.     pr_debug("bus: '%s': registered\n", bus->name);
  65.     return 0;


  66. bus_attrs_fail:
  67.     remove_probe_files(bus);
  68. bus_probe_files_fail:
  69.     kset_unregister(bus->p->drivers_kset);

  70.     ...
  71.     ...

  72. }

上面的函数为bus_type创建的三个重要属性是 uevent, drivers_probe 和 drivers_probe 。
uevent 没有读操作,只有写操作,用于在用户空间手动产生事件,如echo add > event就会产生一个add的事件;
drivers_probe 没有读操作,只有写操作,将用户输入该文件的设备名称对应的设备与驱动匹配一次。
drivers_autoprobe 既有读操作又有写操作。文件中的值是1时,表示使能自动匹配;为0时禁止自动匹配。



>> device


点击(此处)折叠或打开

  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.     ...
  7.     ...

  8.     struct bus_type *bus; /* type of bus device is on */
  9.     struct device_driver *driver; /* which driver has allocated this
  10.                        device */
  11.     ...
  12.     ...

  13.     dev_t devt; /* dev_t, creates the sysfs "dev" */
  14.     ...
  15.     ...
  16.     struct klist_node knode_class;
  17.     struct class *class;
  18.     ...
  19.     ...
  20.     void (*release)(struct device *dev);
  21. };

  22. struct device_private {
  23.     struct klist klist_children;
  24.     struct klist_node knode_parent;
  25.     struct klist_node knode_driver;
  26.     struct klist_node knode_bus;
  27.     void *driver_data;
  28.     struct device *device;
  29. };



  30. int device_register(struct device *dev)
  31. {
  32.     device_initialize(dev);
  33.     return device_add(dev);
  34. }


  35. void device_initialize(struct device *dev)
  36. {
  37.     dev->kobj.kset = devices_kset; // 重要的两步:设置kset和ktype
  38.     kobject_init(&dev->kobj, &device_ktype);
  39.     ...
  40.     ...
  41.     spin_lock_init(&dev->devres_lock);
  42.     INIT_LIST_HEAD(&dev->devres_head);
  43.     ...
  44.     ...
  45. }




  46. int device_add(struct device *dev)
  47. {
  48.     ...
  49.     ...
  50.     if (dev->init_name) {
  51.         dev_set_name(dev, "%s", dev->init_name); // 最终设置的是 dev->kobj的name
  52.         dev->init_name = NULL;
  53.     }
  54.     ...
  55.     ...
  56.     parent = get_device(dev->parent);
  57.     setup_parent(dev, parent);
  58.     ...
  59.     ...
  60.     /* we require the name to be set before, and pass NULL */
  61.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
  62.     1. 建立dev->kobj的目录
  63.     ...
  64.     ...
  65.     error = device_create_file(dev, &uevent_attr); // 创建 uevent 属性文件 。device的 uevent属性文件的show函数(读操作)
  66.                             // 会显示出由设备对应的kset即devices_kset所产生的环境变量,这些环境
  67.                             // 变量就是 devices_kset->uevent_ops->uevent()的返回值;它的store函数
  68.                             // (写操作)则用于手动产生事件
  69.     if (error)
  70.         goto attrError;
  71.     if (MAJOR(dev->devt)) {
  72.         error = device_create_file(dev, &devt_attr); // 如果device存在设备号,则创建设备号属性文件
  73.         if (error)
  74.             goto ueventattrError;
  75.         error = device_create_sys_dev_entry(dev); ///sys/dev 目录下创建符号链接;如果一个设备有所属的class,
  76.                                 // 则根据class中指定的dev_kobj决定是在/sys/dev/char还是/sys/dev/block
  77.                                 // 下创建链接。链接的名称是设备号
  78.         if (error)
  79.             goto devtattrError;
  80.         devtmpfs_create_node(dev); // 目测是创建 /dev 目录下的设备节点文件?
  81.     }
  82.     error = device_add_class_symlinks(dev); // 创建 /sys/class 目录下到device的链接
  83.     if (error)
  84.         goto SymlinkError;
  85.     error = device_add_attrs(dev); //涉及到了group的部分,暂不讨论
  86.     if (error)
  87.         goto AttrsError;
  88.     error = bus_add_device(dev); /* 作用三点:
  89.                      * - Add device's bus attributes.
  90.                      * - Create links to device's bus. 创建 /sys/bus 目录下到device的链接
  91.                      * - Add the device to its bus's list of devices.
  92.                      */
  93.     if (error)
  94.         goto BusError;
  95.     2. 建立属性文件以及链接,还有设备节点文件


  96.     ...
  97.     ...
  98.     kobject_uevent(&dev->kobj, KOBJ_ADD); // 产生ADD事件
  99.     bus_probe_device(dev); // 将设备自动与挂在总线上面的驱动进行匹配,后面会详细讲这个函数
  100.     if (parent)
  101.         klist_add_tail(&dev->p->knode_parent,
  102.                    &parent->p->klist_children); // 在父设备的子设备链表中添加klist节点
  103.     if (dev->class) {
  104.         ...
  105.         ...
  106.     }
  107.     3. 产生ADD事件,并尝试将device与driver进行匹配

  108. done:
  109.     put_device(dev);
  110.     return error;
  111. DPMError:
  112.     bus_remove_device(dev);
  113. BusError:
  114.     ...
  115.     ...
  116.     goto done;
  117. }


>> device 与 driver 的匹配过程
device_add(dev)函数的最后会调用bus_probe_device(dev)将dev与驱动匹配,下面就来分析一下这个过程。
bus_probe_device(dev)是一个很重要的函数。它将设备自动与挂在总线上面的驱动进行匹配。代码如下:

点击(此处)折叠或打开

  1. void bus_probe_device(struct device *dev)
  2. {
  3.     struct bus_type *bus = dev->bus;
  4.     int ret;

  5.     if (bus && bus->p->drivers_autoprobe) { // 可见只有当 bus_type 的 autoprobe属性为1时才自动匹配驱动和设备
  6.         ret = device_attach(dev);
  7.         WARN_ON(ret < 0);
  8.     }
  9. }
  10. int device_attach(struct device *dev) //bus目录下的drivers_probe 文件被写入正确的设备名时就会调用这个函数
  11. {
  12.     int ret = 0;

  13.     device_lock(dev);
  14.     if (dev->driver) {
  15.         if (klist_node_attached(&dev->p->knode_driver)) {
  16.             ret = 1;
  17.             goto out_unlock;
  18.         }
  19.         ret = device_bind_driver(dev); // 对于设备自己已经指定驱动的情况,只需要将其直接和驱动绑定即可
  20.                         /* int device_bind_driver(struct device *dev)
  21.                         {
  22.                             int ret;

  23.                             ret = driver_sysfs_add(dev);
  24.                             if (!ret)
  25.                                 driver_bound(dev);
  26.                             return ret;
  27.                         }*/ // driver_sysfs_add和driver_bound这两个函数在后面讲really_probe()时会提到
  28.         if (ret == 0)
  29.             ret = 1;
  30.         else {
  31.             dev->driver = NULL;
  32.             ret = 0;
  33.         }
  34.     } else {
  35.         pm_runtime_get_noresume(dev);
  36.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
  37.                 //如果没有指定驱动,就遍历匹配总线之上的驱动。将总线上的每个驱动
  38.                 // 与device尝试匹配一次(通过__device_attach函数进行尝试匹配)
  39.         pm_runtime_put_sync(dev);
  40.     }
  41. out_unlock:
  42.     device_unlock(dev);
  43.     return ret;
  44. }

  45. static int __device_attach(struct device_driver *drv, void *data)
  46. {
  47.     struct device *dev = data;

  48.     if (!driver_match_device(drv, dev)) // 如果不匹配match,直接返回0
  49.         return 0; /* static inline int driver_match_device(struct device_driver *drv,
  50.                                   struct device *dev)
  51.                         {
  52.                             return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  53.                         } */

  54.     return driver_probe_device(drv, dev); // 匹配的情况下(match成功),再尝试 probe
  55. }

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

  59.     if (!device_is_registered(dev)) //如果设备没有注册到sysfs之中, 就直接返回。
  60.         return -ENODEV; /* static inline int device_is_registered(struct device *dev)
  61.                         {
  62.                             return dev->kobj.state_in_sysfs;
  63.                         } */


  64.     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
  65.          drv->bus->name, __func__, dev_name(dev), drv->name);

  66.     pm_runtime_get_noresume(dev);
  67.     pm_runtime_barrier(dev);
  68.     ret = really_probe(dev, drv); // 进一步检查是否匹配
  69.     pm_runtime_put_sync(dev);

  70.     return ret;
  71. }


  72. static int really_probe(struct device *dev, struct device_driver *drv)
  73. {
  74.     int ret = 0;

  75.     dev->driver = drv;
  76.     if (driver_sysfs_add(dev)) {
  77.             // driver_sysfs_add()建立几个符号链接,它返回0时代表创建链接成功。这几个链接分别为:
  78.             // 1:在驱动目录下建立一个到设备的同名链接
  79.             // 2:在设备目录下建立一个名为driver的到驱动的链接
  80.         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
  81.             __func__, dev_name(dev));
  82.         goto probe_failed;
  83.     }

  84.     然后,再调用总线的probe函数。如果总线的此函数不存在。就会调用驱动的probe函数。
  85.     如果匹配成功,返回0.如果不成功,就会跳转到probe_failed
  86.     这一步可以看出,系统会优先使用总线的 probe 函数。
  87.     if (dev->bus->probe) {
  88.         ret = dev->bus->probe(dev);
  89.         if (ret)
  90.             goto probe_failed;
  91.     } else if (drv->probe) {
  92.         ret = drv->probe(dev);
  93.         if (ret)
  94.             goto probe_failed;
  95.     }

  96.     driver_bound(dev); // 到这里。设备和驱动已经匹配成功,调用driver_bound()将其关联起来。
  97.                 // 在这个函数里会将设备加至驱动的设备链表。相关的代码如下:
  98.                 // klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

  99.     ret = 1; //至此,这个匹配过程已经圆满结束了。返回1
  100.     pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
  101.          drv->bus->name, __func__, dev_name(dev), drv->name);
  102.     goto done;

  103. probe_failed:
  104.     ...
  105.     ...
  106. }



>> device_driver


点击(此处)折叠或打开

  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.     bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ // 是否使能手动绑定/解绑驱动和设备

  7.     const struct of_device_id *of_match_table;

  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 (*resume) (struct device *dev);
  13.     const struct attribute_group **groups;

  14.     const struct dev_pm_ops *pm;

  15.     struct driver_private *p;
  16. };

  17. struct driver_private {
  18.     struct kobject kobj;
  19.     struct klist klist_devices;
  20.     struct klist_node knode_bus;
  21.     struct module_kobject *mkobj;
  22.     struct device_driver *driver;
  23. };


  24. int driver_register(struct device_driver *drv)
  25. {
  26.     int ret;
  27.     struct device_driver *other;

  28.     BUG_ON(!drv->bus->p);

  29.     if ((drv->bus->probe && drv->probe) ||
  30.         (drv->bus->remove && drv->remove) ||
  31.         (drv->bus->shutdown && drv->shutdown))
  32.         printk(KERN_WARNING "Driver '%s' needs updating - please use "
  33.             "bus_type methods\n", drv->name);
  34.     // ↑如果设备与总线定义了相同的成员的函数。内核是优先使用bus中定义的.这一点
  35.     // 我们在分析device注册的时候已经分析过。所以。这里打印出警告信息,用来提醒代码编写者。

  36.     other = driver_find(drv->name, drv->bus);
  37.     if (other) {
  38.         put_driver(other);
  39.         printk(KERN_ERR "Error: Driver '%s' is already registered, "
  40.             "aborting...\n", drv->name);
  41.         return -EBUSY;
  42.     }

  43.     ret = bus_add_driver(drv); // 我们主要分析这个函数
  44.     if (ret)
  45.         return ret;
  46.     ret = driver_add_groups(drv, drv->groups); //在这里,忽略有关group的东西。
  47.     if (ret)
  48.         bus_remove_driver(drv);
  49.     return ret;
  50. }


  51. int bus_add_driver(struct device_driver *drv)
  52. {
  53.     struct bus_type *bus;
  54.     struct driver_private *priv;
  55.     int error = 0;

  56.     bus = bus_get(drv->bus);
  57.     if (!bus)
  58.         return -EINVAL;

  59.     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

  60.     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  61.     if (!priv) {
  62.         error = -ENOMEM;
  63.         goto out_put_bus;
  64.     }
  65.     klist_init(&priv->klist_devices, NULL, NULL);
  66.     priv->driver = drv;
  67.     drv->p = priv;
  68.     priv->kobj.kset = bus->p->drivers_kset;
  69.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
  70.                      "%s", drv->name);
  71.     // ↑初始化驱动的driver_private域。使其内嵌的kobject的kset指bus中的drivers_kset.
  72.     // 这样,这个内嵌的kobject所生成的目录就会存在于bus对应目录的driver目录之下。
  73.     // 这里还要注意的是,为内嵌kobject指定的ktype是driver_ktype.属性文件的读写操
  74.     // 作都回回溯到struct driver_attribute中。

  75.     1. ↑初始化kobj,主要是其ktype和kset.

  76.     if (error)
  77.         goto out_unregister;

  78.     if (drv->bus->p->drivers_autoprobe) {
  79.         //如果总线允许自动进行匹配。就会调用driver_attach()进行这个自己匹配过程。
  80.         // driver_attach()与前面讲的device_attach()的机制类似,最后也是通过调用
  81.         // driver_probe_device(drv,dev)来匹配设备和驱动
  82.         error = driver_attach(drv);
  83.         if (error)
  84.             goto out_unregister;
  85.     }
  86.     2.↑匹配驱动和设备

  87.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将驱动挂到bus对应的驱动链表
  88.     module_add_driver(drv->owner, drv);
  89.     3. 将驱动挂到bus对应的驱动链表

  90.     error = driver_create_file(drv, &driver_attr_uevent); // 创建uevent属性文件,只能写不能读
  91.     if (error) {
  92.         printk(KERN_ERR "%s: uevent attr (%s) failed\n",
  93.             __func__, drv->name);
  94.     }
  95.     error = driver_add_attrs(bus, drv); // 为bus中指定的与driver相关的属性生成属性文件,
  96.                                 // 所有挂在这个bus上的驱动都应有这些属性。
  97.     if (error) {
  98.         /* How the hell do we get out of this pickle? Give up */
  99.         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
  100.             __func__, drv->name);
  101.     }

  102.     if (!drv->suppress_bind_attrs) {
  103.         error = add_bind_files(drv); // 生成属性为driver_attr_unbind和driver_attr_bind的属性文件,
  104.                         // 两个属性都是只能写不能读的,向该属性文件中写入一个device名,
  105.                         // 就会将该device与driver进行解绑或绑定(通过调用driver_probe_device)
  106.         if (error) {
  107.             /* Ditto */
  108.             printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
  109.                 __func__, drv->name);
  110.         }
  111.     }
  112.     4. 添加属性文件

  113.     kobject_uevent(&priv->kobj, KOBJ_ADD); // 产生ADD事件
  114.     5. 产生ADD事件

  115.     return 0;

  116.     // 错误处理
  117.     ...
  118.     ...
  119. }

>>  bus\device\driver 的 事件uevent处理

前面提到过,所有的kobject产生的uevent都由其所属的kset的uevent_ops 处理。
bus 的kset是全局的bus_kset: 在buses_init()函数中,全局的bus_kset的uevent_ops被设为了bus_uevent_ops,

点击(此处)折叠或打开

  1. static const struct kset_uevent_ops bus_uevent_ops = {
  2.         .filter = bus_uevent_filter, // bus_uevent_ops 只指定了filter函数
  3.     };
  4.     static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
  5.     {
  6.         struct kobj_type *ktype = get_ktype(kobj);
  7.         if (ktype == &bus_ktype)
  8.             return 1; // 过滤掉非总线类型的kobject产生的事件
  9.         return 0;
  10.     }

device的kset是全局的devices_kset: 在devices_init()函数中,全局的devices_kset的uevent_ops被设为了device_uevent_ops;

点击(此处)折叠或打开

  1. static const struct kset_uevent_ops device_uevent_ops = {
  2.         .filter = dev_uevent_filter,
  3.         .name = dev_uevent_name,
  4.         .uevent = dev_uevent,
  5.     };
  6.     static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
  7.     {
  8.         // 过滤掉类型是非device的kobject的事件;如果产生事件的device没有所属的总线或类,其产生的事件也将被过滤
  9.         struct kobj_type *ktype = get_ktype(kobj);

  10.         if (ktype == &device_ktype) {
  11.             struct device *dev = to_dev(kobj);
  12.             if (dev->bus)
  13.                 return 1;
  14.             if (dev->class)
  15.                 return 1;
  16.         }
  17.         return 0;
  18.     }
  19.     static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
  20.     {
  21.         struct device *dev = to_dev(kobj);

  22.         if (dev->bus)
  23.             return dev->bus->name; // 如果设备有自己的总线,则以总线名称作为子系统名称返回
  24.         if (dev->class)
  25.             return dev->class->name; // 如果设备没有自己的总线但有所属的类,则将类名作为子系统名称返回
  26.         return NULL; // 类和总线都可以作为子系统
  27.     }
  28.     static int dev_uevent(struct kset *kset, struct kobject *kobj,
  29.                   struct kobj_uevent_env *env)
  30.     {
  31.         struct device *dev = to_dev(kobj);
  32.         int retval = 0;

  33.         // 如果设备有设备号,则导出与设备节点文件相关的环境变量,如主次设备号、设备节点文件名等
  34.         /* add device node properties if present */
  35.         if (MAJOR(dev->devt)) {
  36.             const char *tmp;
  37.             const char *name;
  38.             mode_t mode = 0;

  39.             add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
  40.             add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
  41.             name = device_get_devnode(dev, &mode, &tmp);
  42.             if (name) {
  43.                 add_uevent_var(env, "DEVNAME=%s", name);
  44.                 kfree(tmp);
  45.                 if (mode)
  46.                     add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
  47.             }
  48.         }
  49.         //添加设备type和driver相关的环境变量
  50.         if (dev->type && dev->type->name)
  51.             add_uevent_var(env, "DEVTYPE=%s", dev->type->name);

  52.         if (dev->driver)
  53.             add_uevent_var(env, "DRIVER=%s", dev->driver->name);
  54.         // 导出设备所属的bus特有的环境变量
  55.         /* have the bus specific function add its stuff */
  56.         if (dev->bus && dev->bus->uevent) {
  57.             retval = dev->bus->uevent(dev, env);
  58.             if (retval)
  59.                 pr_debug("device: '%s': %s: bus uevent() returned %d\n",
  60.                      dev_name(dev), __func__, retval);
  61.         }
  62.         // 导出设备所属的class特有的环境变量
  63.         /* have the class specific function add its stuff */
  64.         if (dev->class && dev->class->dev_uevent) {
  65.             retval = dev->class->dev_uevent(dev, env);
  66.             if (retval)
  67.                 pr_debug("device: '%s': %s: class uevent() "
  68.                      "returned %d\n", dev_name(dev),
  69.                      __func__, retval);
  70.         }
  71.         // 导出设备所属的type特有的环境变量
  72.         /* have the device type specific function add its stuff */
  73.         if (dev->type && dev->type->uevent) {
  74.             retval = dev->type->uevent(dev, env);
  75.             if (retval)
  76.                 pr_debug("device: '%s': %s: dev_type uevent() "
  77.                      "returned %d\n", dev_name(dev),
  78.                      __func__, retval);
  79.         }

  80.         return retval;
  81.     }


driver的kset是其所属的bus的drivers_kset成员(非全局,不同总线上的驱动有不同的kset): 在bus_register()函数中,bus的drivers_kset成员的uevent_ops被设为了NULL;




>> class


点击(此处)折叠或打开

  1. struct class {
  2.     const char *name;
  3.     struct module *owner;

  4.     struct class_attribute *class_attrs;
  5.     struct device_attribute *dev_attrs;
  6.     struct bin_attribute *dev_bin_attrs;
  7.     struct kobject *dev_kobj;

  8.     int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
  9.     char *(*devnode)(struct device *dev, mode_t *mode);

  10.     void (*class_release)(struct class *class);
  11.     void (*dev_release)(struct device *dev);

  12.     int (*suspend)(struct device *dev, pm_message_t state);
  13.     int (*resume)(struct device *dev);

  14.     const struct kobj_ns_type_operations *ns_type;
  15.     const void *(*namespace)(struct device *dev);

  16.     const struct dev_pm_ops *pm;

  17.     struct subsys_private *p;
  18. };


对比一下,class和bus_type结构体有很多相似之处,而且他们都包含一个subsys_private类型的私有数据,
总线和类都是子系统级别。一个class就是一个子系统

类的注册

点击(此处)折叠或打开

  1. int __class_register(struct class *cls, struct lock_class_key *key)
  2. {
  3.     struct subsys_private *cp;
  4.     int error;

  5.     pr_debug("device class '%s': registering\n", cls->name);

  6.     cp = kzalloc(sizeof(*cp), GFP_KERNEL);
  7.     if (!cp)
  8.         return -ENOMEM;
  9.     klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
  10.     INIT_LIST_HEAD(&cp->class_interfaces);
  11.     kset_init(&cp->glue_dirs);
  12.     __mutex_init(&cp->class_mutex, "struct class mutex", key);
  13.     error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
  14.     if (error) {
  15.         kfree(cp);
  16.         return error;
  17.     }
  18.     1. 对子系统cp做必要的初始化,将子系统名称设置为类名


  19.     /* set the default /sys/dev directory for devices of this class */
  20.     if (!cls->dev_kobj)
  21.         cls->dev_kobj = sysfs_dev_char_kobj;
  22.     2. 如果cls->dev_kobj没有指定,则设置本类中的设备在/sys/dev下的默认目录为char。
  23.     /sys/dev目录下通常只有两个子目录,分别是char和block,他们分别对应sysfs_dev_char_kobj和
  24.     sysfs_dev_block_kobj这两个kobject对象,在devices_init函数中,有如下几句:
  25.     * dev_kobj = kobject_create_and_add("dev", NULL); // 创建了/sys/dev目录
  26.     * sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
  27.     * // 创建了/sys/dev/block目录
  28.     * sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
  29.     * // 创建了/sys/dev/char目录


  30. #if defined(CONFIG_BLOCK)
  31.     /* let the block class directory show up in the root of sysfs */
  32.     if (!sysfs_deprecated || cls != &block_class)
  33.         cp->subsys.kobj.kset = class_kset;
  34. #else
  35.     cp->subsys.kobj.kset = class_kset;
  36. #endif
  37.     3. 设置子系统的kset为class_kset。在classes_init函数中,class_kset被设置:
  38.      * class_kset = kset_create_and_add("class", NULL, NULL); // 创建了/sys/class目录


  39.     cp->subsys.kobj.ktype = &class_ktype;
  40.     4. 设置子系统的ktype为class_ktype,class_ktype中的release函数就是回调类class的class_release函数,
  41.     属性读写函数就是回调class_attribute结构的属性读写函数;

  42.     cp->class = cls;
  43.     cls->p = cp;
  44.     5.绑定子系统与类

  45.     error = kset_register(&cp->subsys);
  46.     if (error) {
  47.         kfree(cp);
  48.         return error;
  49.     }
  50.     6. 注册子系统

  51.     error = add_class_attrs(class_get(cls));
  52.     class_put(cls);
  53.     7. 创建属于这个类的属性文件

  54.     return error;
  55. }



创建一个class只需要提供该class的名称和所属模块

点击(此处)折叠或打开

  1. struct class *__class_create(struct module *owner, const char *name,
  2.                  struct lock_class_key *key)
  3. {
  4.     struct class *cls;
  5.     int retval;

  6.     cls = kzalloc(sizeof(*cls), GFP_KERNEL);
  7.     if (!cls) {
  8.         retval = -ENOMEM;
  9.         goto error;
  10.     }

  11.     // 设置类的名称和模块,以及析构函数。
  12.     cls->name = name;
  13.     cls->owner = owner;
  14.     cls->class_release = class_create_release;
  15.             /*static void class_create_release(struct class *cls)
  16.             {
  17.                 pr_debug("%s called for %s\n", __func__, cls->name);
  18.                 kfree(cls);
  19.             }*/

  20.     // 注册类
  21.     retval = __class_register(cls, key);
  22.     if (retval)
  23.         goto error;

  24.     return cls;

  25. error:
  26.     kfree(cls);
  27.     return ERR_PTR(retval);
  28. }





内核中有一个函数 device_create()可以快速创建一个device,这个函数需要制定device所属的类。
为了更清楚device与class的关系,我们来看一下这个函数。用这个函数创建一个device时,需要
提供device所属的类、它的父设备(可有可无)、设备号、设备名等



点击(此处)折叠或打开

  1. /**
  2.  * device_create - creates a device and registers it with sysfs
  3.  * @class: pointer to the struct class that this device should be registered to
  4.  * @parent: pointer to the parent struct device of this new device, if any
  5.  * @devt: the dev_t for the char device to be added
  6.  * @drvdata: the data to be added to the device for callbacks 要添加到device中供回调用的数据,设备的驱动所需的特有数据
  7.  * @fmt: string for the device's name 指定设备名称的字符串
  8.  *
  9.  * This function can be used by char device classes. A struct device
  10.  * will be created in sysfs, registered to the specified class.这个函数被字符类的设备使用
  11.  *
  12.  * A "dev" file will be created, showing the dev_t for the device, if
  13.  * the dev_t is not 0,0.
  14.  * If a pointer to a parent struct device is passed in, the newly created
  15.  * struct device will be a child of that device in sysfs.
  16.  * The pointer to the struct device will be returned from the call.
  17.  * Any further sysfs files that might be required can be created using this
  18.  * pointer.
  19.  *
  20.  * Returns &struct device pointer on success, or ERR_PTR() on error.
  21.  *
  22.  * Note: the struct class passed to this function must have previously
  23.  * been created with a call to class_create().传递到这个函数中的class参数必须是用class_create()函数创建的
  24.  */
  25. struct device *device_create(struct class *class, struct device *parent,
  26.                  dev_t devt, void *drvdata, const char *fmt, ...)
  27. {
  28.     va_list vargs;
  29.     struct device *dev;

  30.     va_start(vargs, fmt);
  31.     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
  32.     va_end(vargs);
  33.     return dev;
  34. }

  35. struct device *device_create_vargs(struct class *class, struct device *parent,
  36.                    dev_t devt, void *drvdata, const char *fmt,
  37.                    va_list args)
  38. {
  39.     struct device *dev = NULL;
  40.     int retval = -ENODEV;

  41.     if (class == NULL || IS_ERR(class))
  42.         goto error;

  43.     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  44.     if (!dev) {
  45.         retval = -ENOMEM;
  46.         goto error;
  47.     }

  48.     // 根据穿进来的参数设置device的设备号,设备名,类等信息
  49.     dev->devt = devt;
  50.     dev->class = class;
  51.     dev->parent = parent;
  52.     dev->release = device_create_release;
  53.             /*static void device_create_release(struct device *dev)
  54.             {
  55.                 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
  56.                 kfree(dev);
  57.             }*/
  58.     dev_set_drvdata(dev, drvdata);
  59.     retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
  60.     if (retval)
  61.         goto error;

  62.     // 注册设备
  63.     retval = device_register(dev);
  64.     if (retval)
  65.         goto error;

  66.     return dev;

  67. error:
  68.     put_device(dev);
  69.     return ERR_PTR(retval);
  70. }






>> tips:
1. kobject 中虽然记录了 父对象 的指针,但并未记录 子对象 列表,所以通过一个 kobject 可以
   获得其父对象,却无法知道它的子对象有哪些;
2. 设置了 kobj->kset 后,再调用kobj_kset_join(kobj)就可以将 kobj 加入到其所属的kset的list链
   表中了,二者的关系即建立;kobj_kset_leave(kobj)将kobj从其所属的kset的list列表中移除
3. bus\device\driver 的 uevent 属性的读写权限和作用比较:
    bus\driver 的uevent属性都是只写的,用于手动产生事件
    device 的uevent属性是可写可读的,写入操作用于手动产生事件,读取操作用于
    显示产生事件的设备特有的环境变量(devices_kset->uevent_ops->uevent()所产生的环境变量)
4. bus\device\driver 中出现的klist,以及klist链表与kobject层次的联系
    klist结构代表一个链表,klist_node代表链表中的一个节点。
    klist链表与kobject组成的层次结构是一致的,kobject系统主要用于建立sysfs目录结构,klist系统
    则更详细地记录了设备、驱动和总线之间的层次关系,方便三者之间的交叉访问。
    bus_type 有两个链表 :
        klist_devices     挂在该总线上的设备组成的链表
        klist_drivers     挂在该总线上的驱动组成的链表
    device_driver有一个链表和一个节点:
        klist_devices    与该驱动绑定的设备组成的链表
        knode_bus     该驱动在其所属总线的驱动链表中的节点(在bus_add_driver()函数中设置此节点)
    device 有一个链表和4个节点:
        klist_children    该设备的子设备组成的链表
        knode_parent    该设备在其父设备的子设备链表中的节点(在device_add()中设置此节点)
        knode_driver    该设备在其绑定的驱动的设备链表中的节点(在device_bind_driver()或really_probe()中通过调用driver_bound()设置此节点)
        knode_bus    该设备再起所属总线的设备链表中的节点(在device_add()中通过调用bus_add_device()设置此节点)
        knode_class    该设备在其所属类中的节点(暂不研究这个)
5. 关于之前提到的 group(属性组attribute_group),就是同时创建一组属性,这一组属性会放在其所属的kobject的目录下的一个子目录中。每一个属性组对应一个子目录

    

阅读(1368) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~