Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1371607
  • 博文数量: 284
  • 博客积分: 3251
  • 博客等级: 中校
  • 技术积分: 3046
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-26 17:23
文章分类

全部博文(284)

文章存档

2019年(2)

2018年(5)

2015年(19)

2014年(13)

2013年(10)

2012年(235)

分类:

2012-11-27 15:42:25

原文地址:linux设备:device 作者:zengxg14


简述struct device相关的东西。
类似于bus_type,kobject是嵌入在struct device中的。
而且device也有device_attribute。

用struct device声明一个设备,然后用device_register函数来注册,完后用device_unregister注销设备。
用struct device_attribute定义设备属性,或用DEVICE_ATTR宏来定义,对属性文件的处理使用
device_create_file函数和device_remove_file函数。

这里以platform_bus_init()函数来为例来介绍设备注册的过程。
platform_bus_init是在设备初始化过程中调用的函数,对应于目录/sys/devices/platform。



1:struct 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.     struct device_type    *type;
  7.     struct semaphore    sem;    /* semaphore to synchronize calls to its driver*/
  8.     struct bus_type    *bus;        /* type of bus device is on */
  9.     struct device_driver *driver;    /* which driver has allocated this device */
  10.     void        *platform_data;    /* Platform specific data, device core doesn't touch it */
  11.     struct dev_pm_info    power;
  12. #ifdef CONFIG_NUMA
  13.     int        numa_node;    /* NUMA node this device is close to */
  14. #endif
  15.     u64        *dma_mask;    /* dma mask (if dma'able device) */
  16.     u64        coherent_dma_mask;/* Like dma_mask, but for
  17.                      alloc_coherent mappings as
  18.                      not all hardware supports
  19.                      64 bit addresses for consistent
  20.                      allocations such descriptors. */

  21.     struct device_dma_parameters *dma_parms;

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

  23.     struct dma_coherent_mem    *dma_mem; /* internal for coherent mem override */
  24.     /* arch specific additions */
  25.     struct dev_archdata    archdata;

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

  27.     spinlock_t        devres_lock;
  28.     struct list_head    devres_head;

  29.     struct klist_node    knode_class;
  30.     struct class        *class;
  31.     const struct attribute_group **groups;    /* optional groups */

  32.     void    (*release)(struct device *dev);
  33. };

  34. struct driver_private {
  35.     struct kobject kobj;
  36.     struct klist klist_devices;
  37.     struct klist_node knode_bus;
  38.     struct module_kobject *mkobj;
  39.     struct device_driver *driver;
  40. };
platform_bus的定义如下:

  1. struct device platform_bus = {
  2.     .init_name = "platform",
  3. };

在platform_bus_init(void)中调用了“error = device_register(&platform_bus);”下面主要分析device_register函数

2:device_register(struct device *)

  1. int device_register(struct device *dev)
  2. {
  3.     device_initialize(dev);
  4.     return device_add(dev);
  5. }
意外的只有两句,先初始化设备,然后add设备。

3:device_initialize(struct device *)

  1. void device_initialize(struct device *dev)
  2. {
  3.     /* 先初始化dev->kobj */
  4.     dev->kobj.kset = devices_kset;
  5.     kobject_init(&dev->kobj, &device_ktype);
  6.     
  7.     /* 初始化其他部分 */
  8.     INIT_LIST_HEAD(&dev->dma_pools);
  9.     init_MUTEX(&dev->sem);
  10.     spin_lock_init(&dev->devres_lock);
  11.     INIT_LIST_HEAD(&dev->devres_head);
  12.     device_init_wakeup(dev, 0);
  13.     device_pm_init(dev);
  14.     set_dev_node(dev, -1);
  15. }
那么前两句将dev->kobj的kset初始化为devices_kset, ktype初始化为device_ktype。
devices_kset是在函数devices_init中初始化的,
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);

device_ktype的定义如下:

  1. static struct kobj_type device_ktype = {
  2.     .release    = device_release,
  3.     .sysfs_ops    = &dev_sysfs_ops,
  4. };
  5.  
  6. /* 先尝试dev->release,在尝试dev->type->release,最后尝试dev->class->dev_release */
  1. static void device_release(struct kobject *kobj)

  2. static struct sysfs_ops dev_sysfs_ops = {
  3.     .show    = dev_attr_show,
  4.     .store    = dev_attr_store,
  5. };

  6. static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
  7.              char *buf)
  8. {
  9.     struct device_attribute *dev_attr = to_dev_attr(attr);
  10.     struct device *dev = to_dev(kobj);
  11.     ssize_t ret = -EIO;

  12.     if (dev_attr->show)
  13.         ret = dev_attr->show(dev, dev_attr, buf);
  14.     ...
  15. }

  16. static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
  17.              const char *buf, size_t count)
  18. {
  19.     struct device_attribute *dev_attr = to_dev_attr(attr);
  20.     struct device *dev = to_dev(kobj);
  21.     ssize_t ret = -EIO;

  22.     if (dev_attr->store)
  23.         ret = dev_attr->store(dev, dev_attr, buf, count);
  24.     return ret;
  25. }
可见device_ktype与bus_ktype类似。对show和store函数的调用最终还是要调用device_attribute中指定的show与store函数。

4:device_add(struct *dev)
核心函数,该函数比较复杂。

  1. int device_add(struct device *dev)
  2. {
  3.     struct device *parent = NULL;
  4.     struct class_interface *class_intf;
  5.     int error = -EINVAL;
  6.      
  7.     /* 调用了kobject_get(&dev->kobj) */
  8.     dev = get_device(dev);
  9.     if (!dev)
  10.         goto done;

  11.     if (!dev->p) {
  12.         /* 分配了一个device_private对象,并初始化dev->p->klist_children */
  13.         error = device_private_init(dev);
  14.         if (error)
  15.             goto done;
  16.     }

  17.     /* 对platform_bus变量来说,这里将dev->kobj.name设成"platform" */
  18.     if (dev->init_name) {
  19.         dev_set_name(dev, "%s", dev->init_name);
  20.         dev->init_name = NULL;
  21.     }

  22.     if (!dev_name(dev))
  23.         goto name_error;

  24.     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
  25.     /* platform_bus->parent为NULL, setup_parent函数用于设定dev->kobj.parent的值*/
  1.     parent = get_device(dev->parent);
  2.     setup_parent(dev, parent);

  3.     /* use parent numa_node */
  4.     if (parent)
  5.         set_dev_node(dev, dev_to_node(parent));

  6.     /* first, register with generic layer. */
  7.     /* we require the name to be set before, and pass NULL */
  8.     /* 调用kobject_add将dev->kobj加入设备模型,这里parent为NULL,因此此处将
  9.        dev->kobj加入了devices_kset, 并将dev->kobj.parent = devices_kset->kobj */
  10.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
  11.     if (error)
  12.         goto Error;

  13.     /* notify platform of device entry */
  14.     if (platform_notify)
  15.         platform_notify(dev);
  16.     
  17.     /* 创建属性文件,即uevent文件 (在注册pci_bus_type时也有它)*/
  18.     error = device_create_file(dev, &uevent_attr);
  19.     if (error)
  20.         goto attrError;

  21.     if (MAJOR(dev->devt)) {
  22.         error = device_create_file(dev, &devt_attr);
  23.         if (error)
  24.             goto ueventattrError;

  25.         error = device_create_sys_dev_entry(dev);
  26.         if (error)
  27.             goto devtattrError;

  28.         devtmpfs_create_node(dev);
  29.     }
  30.     /* 对于platform_bus变量来说,下面的函数均无作用(是我选的device不好,有点特殊)*/
  31.     error = device_add_class_symlinks(dev);
  32.     if (error)
  33.         goto SymlinkError;
  34.     error = device_add_attrs(dev);
  35.     if (error)
  36.         goto AttrsError;
  37.     error = bus_add_device(dev);
  38.     if (error)
  39.         goto BusError;
  40.     error = dpm_sysfs_add(dev);
  41.     if (error)
  42.         goto DPMError;
  43.     device_pm_add(dev);

  44.     /* Notify clients of device addition. This call must come
  45.      * after dpm_sysf_add() and before kobject_uevent().
  46.      */
  47.     if (dev->bus)
  48.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  49.                      BUS_NOTIFY_ADD_DEVICE, dev);

  50.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  51.     bus_probe_device(dev);
  52.     if (parent)
  53.         klist_add_tail(&dev->p->knode_parent,
  54.              &parent->p->klist_children);

  55.     if (dev->class) {
  56.         mutex_lock(&dev->class->p->class_mutex);
  57.         /* tie the class to the device */
  58.         klist_add_tail(&dev->knode_class,
  59.              &dev->class->p->class_devices);

  60.         /* notify any interfaces that the device is here */
  61.         list_for_each_entry(class_intf,
  62.                  &dev->class->p->class_interfaces, node)
  63.             if (class_intf->add_dev)
  64.                 class_intf->add_dev(dev, class_intf);
  65.         mutex_unlock(&dev->class->p->class_mutex);
  66.     }
  67. done:
  68.     put_device(dev);
  69.     return error;
  70. /* 下面都是错误处理相关的代码,已省略 */
  71. .........
  72. }

好吧,这个platform_bus的例子不太好,该变量太特殊,并没有具体的设备,因此device_add函数里很多函数没有用到。

通常在device_register之前需要设置好device对象的parent, bus_id, bus和release成员,但platform_bus仅设定了init_name,
可见对platform_bus的注册主要就是调用kobject_add函数在/sys/devices目录下创建个platform目录。



!!!需补充例子...
待续...
















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