总线设备驱动模型--设备篇

740阅读 0评论2013-07-23 枫海8深蓝
分类:LINUX

    上篇主要对总线进行了一些梳理,现在来看看内核对于设备的处理过程。

点击(此处)折叠或打开

  1. struct device {
  2.     struct device        *parent;     /*指向父节点的指针*/

  3.     struct device_private    *p;

  4.     struct kobject kobj;/*用它联系到sysfs中*/
  5.     const char        *init_name; /*初始化设备的名字 */
  6.     const struct device_type *type;/*device属性文件*/

  7.     struct mutex        mutex;    /* mutex to synchronize calls to
  8.                      * its driver.
  9.                      */

  10.     struct bus_type    *bus;        /* 属于那条总线 */
  11.     struct device_driver *driver;    /*那个驱动能匹配该设备*/
  12.     void        *platform_data;    
  13.     struct dev_pm_info    power;
  14.     struct dev_pm_domain    *pm_domain;

  15. #ifdef CONFIG_NUMA
  16.     int        numa_node;    /* NUMA node this device is close to */
  17. #endif
  18.     u64        *dma_mask;    /* dma mask (if dma'able device) */
  19.     u64        coherent_dma_mask;/* Like dma_mask, but for
  20.                      alloc_coherent mappings as
  21.                      not all hardware supports
  22.                      64 bit addresses for consistent
  23.                      allocations such descriptors. */

  24.     struct device_dma_parameters *dma_parms;

  25.     struct list_head    dma_pools;    /* dma pools (if dma'ble) */

  26.     struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
  27.                      override */
  28.     /* arch specific additions */
  29.     struct dev_archdata    archdata;

  30.     struct device_node    *of_node; /* associated device tree node */

  31.     dev_t            devt;    /* dev_t, creates the sysfs "dev" */

  32.     spinlock_t        devres_lock;
  33.     struct list_head    devres_head;

  34.     struct klist_node    knode_class;
  35.     struct class        *class;
  36.     const struct attribute_group **groups;    /* optional groups */

  37.     void    (*release)(struct device *dev);
  38. };
来看看strcut device的结构变量,首先是指向父节点的指针parent,kobj是内嵌在device中的kbojcet,匹配的驱动,属于哪条总线,其中比较重要的是release函数,当这个设备被删去时,内核调用该方法,所有的注册到内核的设备结构必须有一个release方法。和总线一样,device也有一个联系bus、device、driver的数据结构。

点击(此处)折叠或打开

  1. struct device_private {
  2.     struct klist klist_children;//子设备的链表
  3.     struct klist_node knode_parent;//连接到父设备的klist_childern时所用的节点
  4.     struct klist_node knode_driver;//连接到驱动的设备时用到得节点
  5.     struct klist_node knode_bus;//连接到总线时所用的节点
  6.     void *driver_data;          //用于在设备结构中存放相关的驱动信息
  7.     struct device *device;     //指向属于有的device
  8. };
  9. #define to_device_private_parent(obj)    \
  10.     container_of(obj, struct device_private, knode_parent)//从父设备的klist_children上节点,获取相应的private
  11. #define to_device_private_driver(obj)    \
  12.     container_of(obj, struct device_private, knode_driver)//从驱动链表上获得private
  13. #define to_device_private_bus(obj)    \
  14.     container_of(obj, struct device_private, knode_bus) //从总线上获得private
从数据结构上看出,device也有和bus总线一样的。

点击(此处)折叠或打开

  1. /* interface for exporting device attributes */
  2. struct device_attribute {
  3.     struct attribute    attr;
  4.     ssize_t (*show)(struct device *dev, struct device_attribute *attr,
  5.             char *buf);
  6.     ssize_t (*store)(struct device *dev, struct device_attribute *attr,
  7.              const char *buf, size_t count);
  8. };

  9. #define DEVICE_ATTR(_name, _mode, _show, _store) \
  10. struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
sysf中的设备入口的属性结构

点击(此处)折叠或打开

  1. struct device_type {
  2.     const char *name;
  3.     const struct attribute_group **groups;
  4.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  5.     char *(*devnode)(struct device *dev, mode_t *mode);
  6.     void (*release)(struct device *dev);

  7.     const struct dev_pm_ops *pm;
  8. };
同bus过程一样,device的初始化也是在driver_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. }
这个函数干的事情很明显,就是创建在sysfs中的devices目录和dev目录,还在dev目录下创建了block和char两个子目录。

点击(此处)折叠或打开

  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. };
这部分用于向用户控件传递event事件。
下面来分析下设备的注册过程

点击(此处)折叠或打开

  1. int device_register(struct device *dev)
  2. {
  3.     device_initialize(dev);
  4.     return device_add(dev);
  5. }
device_register是提供给外界注册设备的接口,主要调用device_initialize完成dev结构的初始化,然后调用device_add将其加入到系统中。

点击(此处)折叠或打开

  1. void device_initialize(struct device *dev)
  2. {
  3.     dev->kobj.kset = devices_kset;
  4.     kobject_init(&dev->kobj, &device_ktype);
  5.     INIT_LIST_HEAD(&dev->dma_pools);
  6.     mutex_init(&dev->mutex);
  7.     lockdep_set_novalidate_class(&dev->mutex);
  8.     spin_lock_init(&dev->devres_lock);
  9.     INIT_LIST_HEAD(&dev->devres_head);
  10.     device_pm_init(dev);
  11.     set_dev_node(dev, -1);
  12. }
主要是完成device结构的初始化,把device中能初始化的部分全部初始化。主要是将device_ktype加入到kobject中。

点击(此处)折叠或打开

  1. int device_add(struct device *dev)
  2. {
  3.     struct device *parent = NULL;
  4.     struct class_interface *class_intf;
  5.     int error = -EINVAL;

  6.     dev = get_device(dev); //增加dev的引用计数
  7.     if (!dev)
  8.         goto done;

  9.     if (!dev->p) {
  10.         error = device_private_init(dev);//分配和初始化dev->p
  11.         if (error)
  12.             goto done;
  13.     }

  14.     /*
  15.      * for statically allocated devices, which should all be converted
  16.      * some day, we need to initialize the name. We prevent reading back
  17.      * the name, and force the use of dev_name()
  18.      */
  19.     if (dev->init_name) {
  20.         dev_set_name(dev, "%s", dev->init_name);//设置dev名字
  21.         dev->init_name = NULL;
  22.     }

  23.     if (!dev_name(dev)) {
  24.         error = -EINVAL;
  25.         goto name_error;
  26.     }

  27.     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

  28.     parent = get_device(dev->parent);
  29.     setup_parent(dev, parent);

  30.     /* use parent numa_node */
  31.     if (parent)
  32.         set_dev_node(dev, dev_to_node(parent));

  33.     /* first, register with generic layer. */
  34.     /* we require the name to be set before, and pass NULL */
  35.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); //将dev加入sysfs
  36.     if (error)
  37.         goto Error;

  38.     /* notify platform of device entry */
  39.     if (platform_notify)
  40.         platform_notify(dev);

  41.     error = device_create_file(dev, &uevent_attr);//创建uevent属性文件
  42.     if (error)
  43.         goto attrError;

  44.     if (MAJOR(dev->devt)) {
  45.         error = device_create_file(dev, &devt_attr);//如果没有设备号,就创建dev属性
  46.         if (error)
  47.             goto ueventattrError;

  48.         error = device_create_sys_dev_entry(dev); //创建软链接
  49.         if (error)
  50.             goto devtattrError;

  51.         devtmpfs_create_node(dev);//在dev下创建设备文件
  52.     }

  53.     error = device_add_class_symlinks(dev);//dev与class创建软链接
  54.     if (error)
  55.         goto SymlinkError;
  56.     error = device_add_attrs(dev); //添加device/type/class定义的属性集合
  57.     if (error)
  58.         goto AttrsError;
  59.     error = bus_add_device(dev);
  60.     if (error)
  61.         goto BusError;
  62.     error = dpm_sysfs_add(dev);
  63.     if (error)
  64.         goto DPMError;
  65.     device_pm_add(dev);

  66.     /* Notify clients of device addition. This call must come
  67.      * after dpm_sysf_add() and before kobject_uevent().
  68.      */
  69.     if (dev->bus)
  70.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  71.                      BUS_NOTIFY_ADD_DEVICE, dev);

  72.     kobject_uevent(&dev->kobj, KOBJ_ADD);//
  73.     bus_probe_device(dev);
  74.     if (parent)
  75.         klist_add_tail(&dev->p->knode_parent,
  76.              &parent->p->klist_children);

  77.     if (dev->class) {
  78.         mutex_lock(&dev->class->p->class_mutex);
  79.         /* tie the class to the device */
  80.         klist_add_tail(&dev->knode_class,
  81.              &dev->class->p->klist_devices);

  82.         /* notify any interfaces that the device is here */
  83.         list_for_each_entry(class_intf,
  84.                  &dev->class->p->class_interfaces, node)
  85.             if (class_intf->add_dev)
  86.                 class_intf->add_dev(dev, class_intf);
  87.         mutex_unlock(&dev->class->p->class_mutex);
  88.     }
  89. done:
  90.     put_device(dev);
  91.     return error;
  92.  DPMError:
  93.     bus_remove_device(dev);
  94.  BusError:
  95.     device_remove_attrs(dev);
  96.  AttrsError:
  97.     device_remove_class_symlinks(dev);
  98.  SymlinkError:
  99.     if (MAJOR(dev->devt))
  100.         devtmpfs_delete_node(dev);
  101.     if (MAJOR(dev->devt))
  102.         device_remove_sys_dev_entry(dev);
  103.  devtattrError:
  104.     if (MAJOR(dev->devt))
  105.         device_remove_file(dev, &devt_attr);
  106.  ueventattrError:
  107.     device_remove_file(dev, &uevent_attr);
  108.  attrError:
  109.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  110.     kobject_del(&dev->kobj);
  111.  Error:
  112.     cleanup_device_parent(dev);
  113.     if (parent)
  114.         put_device(parent);
  115. name_error:
  116.     kfree(dev->p);
  117.     dev->p = NULL;
  118.     goto done;
  119. }
创建属性文件

点击(此处)折叠或打开

  1. int device_create_file(struct device *dev,
  2.          const struct device_attribute *attr)
  3. {
  4.     int error = 0;
  5.     if (dev)
  6.         error = sysfs_create_file(&dev->kobj, &attr->attr);
  7.     return error;
  8. }
从上面可以看出 error = device_create_file(dev, &uevent_attr)创建了uevent的属性。调用error = device_create_file(dev, &devt_attr);如果dev没有被分配设备号,添加dev属性,之后会调用device_create_sys_dev_entry在/sys/dev下添加相应的软链接,最后在调用devtmpfs_create_node在/dev下创建相应的设备文件。

点击(此处)折叠或打开

  1. static int device_add_class_symlinks(struct device *dev)
  2. {
  3.     int error;

  4.     if (!dev->class)
  5.         return 0;

  6.     error = sysfs_create_link(&dev->kobj,
  7.                  &dev->class->p->subsys.kobj,
  8.                  "subsystem");
  9.     if (error)
  10.         goto out;

  11.     if (dev->parent && device_is_not_partition(dev)) {
  12.         error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
  13.                      "device");
  14.         if (error)
  15.             goto out_subsys;
  16.     }

  17. #ifdef CONFIG_BLOCK
  18.     /* /sys/block has directories and does not need symlinks */
  19.     if (sysfs_deprecated && dev->class == &block_class)
  20.         return 0;
  21. #endif

  22.     /* link in the class directory pointing to the device */
  23.     error = sysfs_create_link(&dev->class->p->subsys.kobj,
  24.                  &dev->kobj, dev_name(dev));
  25.     if (error)
  26.         goto out_device;

  27.     return 0;

  28. out_device:
  29.     sysfs_remove_link(&dev->kobj, "device");

  30. out_subsys:
  31.     sysfs_remove_link(&dev->kobj, "subsystem");
  32. out:
  33.     return error;
  34. }
这个函数主要是添加dev与class间的软链接,下面来看看重点的,将dev挂入到bus的设备链表中。

点击(此处)折叠或打开

  1. int bus_add_device(struct device *dev)
  2. {
  3.     struct bus_type *bus = bus_get(dev->bus);
  4.     int error = 0;

  5.     if (bus) {
  6.         pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
  7.         error = device_add_attrs(bus, dev);
  8.         if (error)
  9.             goto out_put;
  10.         error = sysfs_create_link(&bus->p->devices_kset->kobj,
  11.                         &dev->kobj, dev_name(dev));
  12.         if (error)
  13.             goto out_id;
  14.         error = sysfs_create_link(&dev->kobj,
  15.                 &dev->bus->p->subsys.kobj, "subsystem");//创建bus与dev的软链接
  16.         if (error)
  17.             goto out_subsys;
  18.         klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); //挂入链表
  19.     }
  20.     return 0;

  21. out_subsys:
  22.     sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
  23. out_id:
  24.     device_remove_attrs(bus, dev);
  25. out_put:
  26.     bus_put(dev->bus);
  27.     return error;
  28. }
可以看出,其只做了一个添加dev与bus间的软链接,并将dev挂到bus的设备链表中。之后dpm_sysfs_add增加dev下的power属性, 在将dev加入到dpm_list的链表中。 

点击(此处)折叠或打开

  1. void device_pm_add(struct device *dev)
  2. {
  3.     pr_debug("PM: Adding info for %s:%s\n",
  4.          dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
  5.     mutex_lock(&dpm_list_mtx);
  6.     if (dev->parent && dev->parent->power.is_prepared)
  7.         dev_warn(dev, "parent %s should not be sleeping\n",
  8.             dev_name(dev->parent));
  9.     list_add_tail(&dev->power.entry, &dpm_list);
  10.     dev_pm_qos_constraints_init(dev);
  11.     mutex_unlock(&dpm_list_mtx);
  12. }
kobject_uevent(&dev->kobj, KOBJ_ADD)会做kobject_uevent发布KOBJ_ADD消息,最后会进入中要的函数bus_probe_device(dev),为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) {
  6.         ret = device_attach(dev);
  7.         WARN_ON(ret < 0);
  8.     }
  9. }

点击(此处)折叠或打开

  1. int device_attach(struct device *dev)
  2. {
  3.     int ret = 0;

  4.     device_lock(dev);
  5.     if (dev->driver) {
  6.         if (klist_node_attached(&dev->p->knode_driver)) {
  7.             ret = 1;
  8.             goto out_unlock;
  9.         }
  10.         ret = device_bind_driver(dev);
  11.         if (ret == 0)
  12.             ret = 1;
  13.         else {
  14.             dev->driver = NULL;
  15.             ret = 0;
  16.         }
  17.     } else {
  18.         pm_runtime_get_noresume(dev);
  19.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
  20.         pm_runtime_put_sync(dev);
  21.     }
  22. out_unlock:
  23.     device_unlock(dev);
  24.     return ret;
  25. }
上面主要的做的是,当device被注册时候,会匹配drv是否有匹配的项,其匹配过程主要是调用__device_attach。

点击(此处)折叠或打开

  1. static int __device_attach(struct device_driver *drv, void *data)
  2. {
  3.     struct device *dev = data;

  4.     if (!driver_match_device(drv, dev))
  5.         return 0;

  6.     return driver_probe_device(drv, dev);
  7. }
如果匹配成功,就会调用probe函数。先来看看匹配的过程,主要是调用bus的match函数。

点击(此处)折叠或打开

  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. }
匹配成功后,调用probe函数,从下面可以看出如果bus的probe函数存在,调用bus的,如果不存在,则调用dev的probe函数。

点击(此处)折叠或打开

  1. static int really_probe(struct device *dev, struct device_driver *drv)
  2. {
  3.     int ret = 0;

  4.     atomic_inc(&probe_count);
  5.     pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
  6.          drv->bus->name, __func__, drv->name, dev_name(dev));
  7.     WARN_ON(!list_empty(&dev->devres_head));

  8.     dev->driver = drv;
  9.     if (driver_sysfs_add(dev)) {
  10.         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
  11.             __func__, dev_name(dev));
  12.         goto probe_failed;
  13.     }

  14.     if (dev->bus->probe) {
  15.         ret = dev->bus->probe(dev);
  16.         if (ret)
  17.             goto probe_failed;
  18.     } else if (drv->probe) {
  19.         ret = drv->probe(dev);
  20.         if (ret)
  21.             goto probe_failed;
  22.     }

  23.     driver_bound(dev);
  24.     ret = 1;
  25.     pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
  26.          drv->bus->name, __func__, dev_name(dev), drv->name);
  27.     goto done;

  28. probe_failed:
  29.     devres_release_all(dev);
  30.     driver_sysfs_remove(dev);
  31.     dev->driver = NULL;

  32.     if (ret != -ENODEV && ret != -ENXIO) {
  33.         /* driver matched but the probe failed */
  34.         printk(KERN_WARNING
  35.          "%s: probe of %s failed with error %d\n",
  36.          drv->name, dev_name(dev), ret);
  37.     } else {
  38.         pr_debug("%s: probe of %s rejects match %d\n",
  39.          drv->name, dev_name(dev), ret);
  40.     }
  41.     /*
  42.      * Ignore errors returned by ->probe so that the next driver can try
  43.      * its luck.
  44.      */
  45.     ret = 0;
  46. done:
  47.     atomic_dec(&probe_count);
  48.     wake_up(&probe_waitqueue);
  49.     return ret;
  50. }
寻找到合适的驱动后,下面做的主要是如果有parent节点,把knode_parent挂入klist_children链表。如果dev有属于的class,也挂入到链表中,上面对device的分析也就完了,下面来看一个例子。

点击(此处)折叠或打开

  1. extern struct device my_bus;
  2. extern struct bus_type my_bus_type;

  3. /* Why need this ?*/
  4. static void my_dev_release(struct device *dev)
  5. {
  6.     
  7. }

  8. struct device my_dev = {
  9.     .bus = &my_bus_type,
  10.     .parent = &my_bus,
  11.     .release = my_dev_release,
  12. };

  13. /*
  14.  * Export a simple attribute.
  15.  */
  16. static ssize_t mydev_show(struct device *dev, char *buf)
  17. {
  18.     return sprintf(buf, "%s\n", "This is my device!");
  19. }

  20. static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

  21. static int __init my_device_init(void)
  22. {
  23.     int ret = 0;
  24.         
  25.         /* 初始化设备 */
  26.     strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
  27.         
  28.         /*注册设备*/
  29.     device_register(&my_dev);
  30.         
  31.     /*创建属性文件*/
  32.     device_create_file(&my_dev, &dev_attr_dev);
  33.     
  34.     return ret;    

  35. }

  36. static void my_device_exit(void)
  37. {
  38.     device_unregister(&my_dev);
  39. }

  40. module_init(my_device_init);
  41. module_exit(my_device_exit);


上一篇:platform驱动小结
下一篇:总线设备驱动模型---总线篇