Chinaunix首页 | 论坛 | 博客
  • 博客访问: 646595
  • 博文数量: 329
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 693
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-05 23:37
个人简介

Do not panic!

文章存档

2021年(1)

2018年(3)

2017年(7)

2016年(98)

2015年(220)

我的朋友

分类: LINUX

2016-08-11 11:39:11

原文地址:设备驱动模型(1) 作者:gc5084

设备模型中有三个重要组件,总线(bus_type),设备(device),驱动(driver)。这是一个抽象模型,其他所有的具体总线类型都是建立在这个基础之上的,如I2C,platform等。
一,总线
1.总线基本数据类型,简单列举和总线相关的一些数据类型
总线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 (*resume)(struct device *dev);    //恢复函数

  13.     const struct dev_pm_ops *pm;        //电源管理的函数集

  14.     struct bus_type_private *p;        //总线私有数据
  15. };
总线属性类型

点击(此处)折叠或打开

  1. struct bus_attribute {
  2.     struct attribute    attr;                //和kobject中属性是一个定义,在include/linux/sysfs.h
  3.     ssize_t (*show)(struct bus_type *bus, char *buf);        //属性读取函数
  4.     ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);    //属性写入函数
  5. };
生成一个总线属性对象。一般可以使用宏,

点击(此处)折叠或打开

  1. #define BUS_ATTR(_name, _mode, _show, _store)    \
  2. struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

  3. #define __ATTR(_name,_mode,_show,_store) { \
  4.     .attr = {.name = __stringify(_name), .mode = _mode },    \
  5.     .show    = _show,                    \
  6.     .store    = _store,                    \
  7. }
总线bus_type上的match函数,如果定义了一个总线,那就必须实现match函数,此函数给出其总线上设备和驱动匹配的方法。
总线bus_type上的uevent函数,热插拔事件中传递环境变量参数的函数

总线私有数据类型,bus_type_private,这个数据结构中主要是一些kset类型的容器。

点击(此处)折叠或打开

  1. /**
  2.  * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
  3.  *
  4.  * @subsys - the struct kset that defines this bus. This is the main kobject
  5.  * @drivers_kset - the list of drivers associated with this bus
  6.  * @devices_kset - the list of devices associated with this bus
  7.  * @klist_devices - the klist to iterate over the @devices_kset
  8.  * @klist_drivers - the klist to iterate over the @drivers_kset
  9.  * @bus_notifier - the bus notifier list for anything that cares about things
  10.  * on this bus.
  11.  * @bus - pointer back to the struct bus_type that this structure is associated
  12.  * with.
  13.  *
  14.  * This structure is the one that is the actual kobject allowing struct
  15.  * bus_type to be statically allocated safely. Nothing outside of the driver
  16.  * core should ever touch these fields.
  17.  */
  18. struct bus_type_private {
  19.     struct kset subsys;                //总线bus子系统的kset
  20.     struct kset *drivers_kset;    //总线上所有驱动的kset
  21.     struct kset *devices_kset;    //总线上所有设备的kset
  22.     struct klist klist_devices;        //总线上所有的设备的list,和devices_kset里的list相同
  23.     struct klist klist_drivers;        //总线上所有的驱动的list,和drivers_kset里的list相同
  24.     struct blocking_notifier_head bus_notifier;        //
  25.     unsigned int drivers_autoprobe:1;            //是否在驱动加载时自动,自动探测(probe)设备
  26.     struct bus_type *bus;                        //反指回该总线类型
  27. };
2.总线注册
总线相关的基本数据类型看完之后,我们看如何注册一个总线(bus_type)。使用函数bus_register().在driver/base/bus.c中,注册一个bus总线将在sysfs中生成总线的目录,和其devices,drivers等目录以及它们的属性文件。

点击(此处)折叠或打开

  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);    //分配一个总线私有数据(bus_type_private)对象
  14.     if (!priv)
  15.         return -ENOMEM;

  16.     priv->bus = bus;    //私有数据中的bus反指回总线
  17.     bus->p = priv;        //总线的私有数据指向这个生成的总线私有数据

  18.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);    //初始化通知链表

  19.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);    //设置总结(私有数据)的kobject的名称
  20.     if (retval)
  21.         goto out;

  22.     priv->subsys.kobj.kset = bus_kset;        
  23.     //设置总线私有数据中的kset的kobject(kset中的kobject是此kset中包含kokject的父kobject)的kset。
  24.     //bus_kset将在bus_init函数中生成对象实体(1)
  25.     priv->subsys.kobj.ktype = &bus_ktype;    //设置属性,包含属性的默认方法
  26.     priv->drivers_autoprobe = 1;        //开启自动侦测

  27.     retval = kset_register(&priv->subsys);    //将总线私有数据的bus子系统kset注册
  28.     if (retval)
  29.         goto out;

  30.     retval = bus_create_file(bus, &bus_attr_uevent);    //创建uevent的属性(bus_attr_uevent)文件
  31.     if (retval)
  32.         goto bus_uevent_fail;

  33.     priv->devices_kset = kset_create_and_add("devices", NULL,
  34.                          &priv->subsys.kobj);                        
  35.     //创建并注册一个kset到sysfs中,名称为devices,父节点为总线kobject。
  36.     //即会在相应总线目录下创建一个devices目录。
  37.     if (!priv->devices_kset) {
  38.         retval = -ENOMEM;
  39.         goto bus_devices_fail;
  40.     }

  41.     priv->drivers_kset = kset_create_and_add("drivers", NULL,    //同上,将创建drivers目录
  42.                          &priv->subsys.kobj);
  43.     if (!priv->drivers_kset) {
  44.         retval = -ENOMEM;
  45.         goto bus_drivers_fail;
  46.     }

  47.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化总线私有数据上的设备链表,
  48.     klist_init(&priv->klist_drivers, NULL, NULL);        //初始化总线私有数据上的驱动链表

  49.     retval = add_probe_files(bus);    //配置了热插拔,则此函数会添加bus总线相关
  50.     if (retval)
  51.         goto bus_probe_files_fail;

  52.     retval = bus_add_attrs(bus);    //为bus总线添加默认的属性(2)
  53.     if (retval)
  54.         goto bus_attrs_fail;

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

  57. bus_attrs_fail:
  58.     remove_probe_files(bus);
  59. bus_probe_files_fail:
  60.     kset_unregister(bus->p->drivers_kset);
  61. bus_drivers_fail:
  62.     kset_unregister(bus->p->devices_kset);
  63. bus_devices_fail:
  64.     bus_remove_file(bus, &bus_attr_uevent);
  65. bus_uevent_fail:
  66.     kset_unregister(&bus->p->subsys);
  67.     kfree(bus->p);
  68. out:
  69.     bus->p = NULL;
  70.     return retval;
  71. }
(1)bus_init() 被__init修饰,将在内核初始化时执行。它生成了bus_kset对象,函数定义如下,

点击(此处)折叠或打开

  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. }
(2)为bus总线添加默认的属性,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) {            //如果此bus总线上配置了属性数组,则生成它们的文件
  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. }

点击(此处)折叠或打开

  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);    //将在bus总线目录下创建属性文件
  6.         bus_put(bus);
  7.     } else
  8.         error = -EINVAL;
  9.     return error;
  10. }

二,设备
设备驱动模型中的每一个设备是由device结构体来描述的。

点击(此处)折叠或打开

  1. struct device {
  2.     struct device        *parent;    //父设备的指针

  3.     struct device_private    *p;    //设备的私有数据

  4.     struct kobject kobj;    //设备的kobject
  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        *platform_data;    /* Platform specific data, device
  14.                      core doesn't touch it */
  15.     struct dev_pm_info    power;    //电源管理相关

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

  25.     struct device_dma_parameters *dma_parms;

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

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

  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. };
注册一个device结构(drvier/base/core.c)

点击(此处)折叠或打开

  1. int device_register(struct device *dev)
  2. {
  3.     device_initialize(dev);    //初始化device
  4.     return device_add(dev); //添加device
  5. }

点击(此处)折叠或打开

  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;    //默认的device的kset    (1)
  19.     //device_kset 在系统初始化时创建(driver/base/core.c,devices_init())。将生成/sys/device目录
  20.     kobject_init(&dev->kobj, &device_ktype); //初始化dev的kobject (2)
  21.     INIT_LIST_HEAD(&dev->dma_pools);    //初始化dev链表
  22.     init_MUTEX(&dev->sem);    //初始化互斥量
  23.     spin_lock_init(&dev->devres_lock);//
  24.     INIT_LIST_HEAD(&dev->devres_head);
  25.     device_init_wakeup(dev, 0); //电源管理相关
  26.     device_pm_init(dev);    //电源管理相关
  27.     set_dev_node(dev, -1); //NUMA有关 不用管
  28. }
  29. (1)
  30. int __init devices_init(void)
  31. {
  32.     devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
  33.     //创建的kset的名称为devices。uevent操作集device_uevent_ops,kset的父kobject为NULL
  34.     //这将在sys根目录下创建device目录
  35.     if (!devices_kset)
  36.         return -ENOMEM;
  37.     dev_kobj = kobject_create_and_add("dev", NULL);//
  38.     if (!dev_kobj)
  39.         goto dev_kobj_err;
  40.     sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
  41.     if (!sysfs_dev_block_kobj)
  42.         goto block_kobj_err;
  43.     sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
  44.     if (!sysfs_dev_char_kobj)
  45.         goto char_kobj_err;

  46.     return 0;

  47.  char_kobj_err:
  48.     kobject_put(sysfs_dev_block_kobj);
  49.  block_kobj_err:
  50.     kobject_put(dev_kobj);
  51.  dev_kobj_err:
  52.     kset_unregister(devices_kset);
  53.     return -ENOMEM;
  54. }
  55. (2)这个给设备(device)的kobject中的kobj_type的默认成员device_ktype将在这段有后分析。

点击(此处)折叠或打开

  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 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);        //增加dev的引用
  22.     if (!dev)
  23.         goto done;

  24.     if (!dev->p) {            
  25.         error = device_private_init(dev);    
  26.         if (error)
  27.             goto done;
  28.     }

  29.     /*
  30.      * for statically allocated devices, which should all be converted
  31.      * some day, we need to initialize the name. We prevent reading back
  32.      * the name, and force the use of dev_name()
  33.      */
  34.     if (dev->init_name) {
  35.         dev_set_name(dev, "%s", dev->init_name);    //将设置kobject的名字
  36.         dev->init_name = NULL;
  37.     }

  38.     if (!dev_name(dev))
  39.         goto name_error;

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

  41.     parent = get_device(dev->parent);    //增加对父设备的引用,注意这里是device中的父。不是kobject中的父(1)
  42.     setup_parent(dev, parent);//将设置dev中的kobject的父。在后面的添加kobject中,没有parent将设置为kset的kobject

  43.     /* use parent numa_node */
  44.     if (parent)
  45.         set_dev_node(dev, dev_to_node(parent));

  46.     /* first, register with generic layer. */
  47.     /* we require the name to be set before, and pass NULL */
  48.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//添加dev的kobject,其init在device_initialize中
  49.     if (error)
  50.         goto Error;

  51.     /* notify platform of device entry */
  52.     if (platform_notify)
  53.         platform_notify(dev);

  54.     error = device_create_file(dev, &uevent_attr);    //添加uevevt属性文件
  55.     if (error)
  56.         goto attrError;

  57.     if (MAJOR(dev->devt)) {        //如果有主设备号
  58.         error = device_create_file(dev, &devt_attr); //创建设备下的一个默认属性文件。(1)
  59.         if (error)
  60.             goto ueventattrError;

  61.         error = device_create_sys_dev_entry(dev); //生成相应目录的连接文件
  62.         if (error)
  63.             goto devtattrError;

  64.         devtmpfs_create_node(dev);    //
  65.     }

  66.     error = device_add_class_symlinks(dev);    //生成class的连接文件
  67.     if (error)
  68.         goto SymlinkError;
  69.     error = device_add_attrs(dev);        //生成类的属性文件和其他文件(?)
  70.     if (error)
  71.         goto AttrsError;
  72.     error = bus_add_device(dev);    //将设备添加到其bus总线上,将在设备目录下与总线目录下生成相互指向的文件
  73.     if (error)
  74.         goto BusError;
  75.     error = dpm_sysfs_add(dev);    //生成power节点在这个设备的目录下
  76.     if (error)
  77.         goto DPMError;
  78.     device_pm_add(dev);    //添加为活跃设备链表

  79.     /* Notify clients of device addition. This call must come
  80.      * after dpm_sysf_add() and before kobject_uevent().
  81.      */
  82.     if (dev->bus)    //将添加这个总线上所有的设备
  83.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  84.                      BUS_NOTIFY_ADD_DEVICE, dev);

  85.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  86.     bus_probe_device(dev); // 为这个新的设备寻找对于驱动,在注册device时候会match相应的driver并probe,
  87.                             //在后面我们将详细分析注册driver时也将match相应的device并probe,这两者的逻辑都差不多
  88.     if (parent)
  89.         klist_add_tail(&dev->p->knode_parent,
  90.              &parent->p->klist_children);

  91.     if (dev->class) {    //设备的类以后再详细分析
  92.         mutex_lock(&dev->class->p->class_mutex);
  93.         /* tie the class to the device */
  94.         klist_add_tail(&dev->knode_class,
  95.              &dev->class->p->class_devices);

  96.         /* notify any interfaces that the device is here */
  97.         list_for_each_entry(class_intf,
  98.                  &dev->class->p->class_interfaces, node)
  99.             if (class_intf->add_dev)
  100.                 class_intf->add_dev(dev, class_intf);
  101.         mutex_unlock(&dev->class->p->class_mutex);
  102.     }
  103. done:
  104.     put_device(dev);
  105.     return error;
  106.  DPMError:
  107.     bus_remove_device(dev);
  108.  BusError:
  109.     device_remove_attrs(dev);
  110.  AttrsError:
  111.     device_remove_class_symlinks(dev);
  112.  SymlinkError:
  113.     if (MAJOR(dev->devt))
  114.         device_remove_sys_dev_entry(dev);
  115.  devtattrError:
  116.     if (MAJOR(dev->devt))
  117.         device_remove_file(dev, &devt_attr);
  118.  ueventattrError:
  119.     device_remove_file(dev, &uevent_attr);
  120.  attrError:
  121.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  122.     kobject_del(&dev->kobj);
  123.  Error:
  124.     cleanup_device_parent(dev);
  125.     if (parent)
  126.         put_device(parent);
  127. name_error:
  128.     kfree(dev->p);
  129.     dev->p = NULL;
  130.     goto done;
  131. }
(1)device_create_file此函数将在dev设备目录下创建attr的属性文件。

点击(此处)折叠或打开

  1. int device_create_file(struct device *dev, struct device_attribute *attr)
  2. {
  3.     int error = 0;
  4.     if (dev)
  5.         error = sysfs_create_file(&dev->kobj, &attr->attr);    
  6.     return error;
  7. }
  8. static struct device_attribute devt_attr =
  9.     __ATTR(dev, S_IRUGO, show_dev, NULL);

  10. device_attribute
  11. struct device_attribute {
  12.     struct attribute    attr;
  13.     ssize_t (*show)(struct device *dev, struct device_attribute *attr,
  14.             char *buf);
  15.     ssize_t (*store)(struct device *dev, struct device_attribute *attr,
  16.              const char *buf, size_t count);
  17. };
  18. #define __ATTR(_name,_mode,_show,_store) { \
  19.     .attr = {.name = __stringify(_name), .mode = _mode },    \
  20.     .show    = _show,                    \
  21.     .store    = _store,                    \
  22. }
  23. static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
  24.             char *buf)
  25. {
  26.     return print_dev_t(buf, dev->devt);
  27. }
  28. #define print_dev_t(buffer, dev)                    \
  29.     sprintf((buffer), "%u:%u\n", MAJOR(dev), MINOR(dev))
以上代码看出,devt_attr类型是device_attribute。通过宏__ATTR创建了一个名为dev的属性。属性的操作方法show。功能是显示主次设备号。

我们再简单看一下bus_add_device,这个函数将device添加到其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,    //在bus目录下创建这个设备的连接文件
  11.                         &dev->kobj, dev_name(dev));
  12.         if (error)
  13.             goto out_id;
  14.         error = sysfs_create_link(&dev->kobj,    //在设备目录下创建指向总线的连接,连接文件名为subsystem
  15.                 &dev->bus->p->subsys.kobj, "subsystem");
  16.         if (error)
  17.             goto out_subsys;
  18.         error = make_deprecated_bus_links(dev);
  19.         if (error)
  20.             goto out_deprecated;
  21.         klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
  22.     }
  23.     return 0;

  24. out_deprecated:
  25.     sysfs_remove_link(&dev->kobj, "subsystem");
  26. out_subsys:
  27.     sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
  28. out_id:
  29.     device_remove_attrs(bus, dev);
  30. out_put:
  31.     bus_put(dev->bus);
  32.     return error;
  33. }

设备的kobj_type
设备kobject的默认kobj_type,定义如下

点击(此处)折叠或打开

  1. static struct kobj_type device_ktype = {
  2.     .release    = device_release,            //设备kobject的默认release函数(1)
  3.     .sysfs_ops    = &dev_sysfs_ops,        //设备kobject的属性默认操作函数集(2)
  4. };
(1)

点击(此处)折叠或打开

  1. static void device_release(struct kobject *kobj)
  2. {
  3.     struct device *dev = to_dev(kobj);    //取的包含具体设备kobject的device结构
  4.     struct device_private *p = dev->p;

  5.     if (dev->release)        //如果有设备(device)结构的release指向的函数则调用
  6.         dev->release(dev);
  7.     else if (dev->type && dev->type->release) //否则,有设备(device)结构的device_type,并且它有release函数,则调用
  8.         dev->type->release(dev);
  9.     else if (dev->class && dev->class->dev_release)//否则,有设备(device)结构的class,并且它有release函数,则调用
  10.         dev->class->dev_release(dev);
  11.     else    //如果都没有则警告
  12.         WARN(1, KERN_ERR "Device '%s' does not have a release() "
  13.             "function, it is broken and must be fixed.\n",
  14.             dev_name(dev));
  15.     kfree(p); //是否设备中的device_private数据
  16. }
上面函数可以看出,device层中的kobject的release函数,只是一个中介,在设备的kobject被销毁时,函数将依次寻找并调用,dev->release;dev->type->release;dev->class->dev_release.中的函数。而这些函数则必须在具体的设备相关中实现。

(2)kobj_type中的sysfs_ops,是相应kobject的属性的操作函数集。

点击(此处)折叠或打开

  1. static struct sysfs_ops dev_sysfs_ops = {
  2.     .show    = dev_attr_show,        //对属性的读操作
  3.     .store    = dev_attr_store,    //对属性的写操作
  4. };

点击(此处)折叠或打开

  1. static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
  2. {
  3.     struct device_attribute *dev_attr = to_dev_attr(attr);    //取出包含attr的device_attribute类型变量
  4.     struct device *dev = to_dev(kobj);    //取出包含kobj的device
  5.     ssize_t ret = -EIO;

  6.     if (dev_attr->show)        //调用dev_attr中的show函数
  7.         ret = dev_attr->show(dev, dev_attr, buf);
  8.     if (ret >= (ssize_t)PAGE_SIZE) {
  9.         print_symbol("dev_attr_show: %s returned bad count\n",
  10.                 (unsigned long)dev_attr->show);
  11.     }
  12.     return ret;
  13. }
和上面一样,在device层中。这些属性函数都是一些中介作用。他是要调用device_attribute(设备属性结构)中的show,store函数。而device_attribute变量的实例是要在具体设备中实现的。

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