Chinaunix首页 | 论坛 | 博客
  • 博客访问: 943034
  • 博文数量: 116
  • 博客积分: 3923
  • 博客等级: 中校
  • 技术积分: 1337
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-23 01:22
文章分类

全部博文(116)

文章存档

2013年(1)

2012年(17)

2011年(69)

2009年(29)

分类: LINUX

2011-12-11 14:45:16

【转】:http://blog.chinaunix.net/u1/57901/
【转】:http://blog.chinaunix.net/space.php?uid=13321460&do=blog&id=2902417

【作者: 】

在LINUX中最让人不解的大概就是/sys下面的内容了

1. 下面首先让我们来创建一个简单的platform设备,并从这个设备的视角进行深入,在此篇文章的深入过程中,我们只看kobeject的模型。我所使用的内核版本号为2.6.26,操作系统的内核版本号为2.6.27-7,暂未发现2.6.27-7与2.6.26的重大不同。

1.1 首先写一个简单的模块。
  1. #include <linux/platform_device.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>

  4. static int __init test_probe(struct platform_device *pdev)
  5. {
  6.     int err = 0;
  7.     return err;
  8. }

  9. static int test_remove(struct platform_device *pdev)
  10. {
  11.     return 0;
  12. }
  13. static struct platform_device test_device = {
  14.     .name = "test_ts",
  15.         .id = -1,
  16. };

  17. static struct platform_driver test_driver = {
  18.     .probe = test_probe,
  19.     .remove = test_remove,
  20.     .driver = {
  21.     .name = "test_ts",
  22.     .owner = THIS_MODULE,
  23.     },
  24. };

  25. static int __devinit test_init(void)
  26. {
  27.     platform_device_register(&test_device);
  28.     return platform_driver_register(&test_driver);
  29. }

  30. static void __exit test_exit(void)
  31. {
  32.     platform_device_unregister(&test_device);
  33.     platform_driver_unregister(&test_driver);
  34. }

  35. module_init(test_init);
  36. module_exit(test_exit);

  37. MODULE_AUTHOR("zwolf");
  38. MODULE_DESCRIPTION("Module test");
  39. MODULE_LICENSE("GPL");
  40. MODULE_ALIAS("test");
1.2 接下来是makefile。
  1. #Makefile

  2. obj-m:=test.o
  3. KDIR:=/lib/modules/2.6.27-7-generic/build
  4. PWD:=$(shell pwd)

  5. default:
  6.     $(MAKE) -C $(KDIR) M=$(PWD) modules

1.3 KDIR中的目录请改为各位实际运行中的内核目录,make之后进行模块的加载 sudo insmod ./test.ko;现在到sys目录中查看我们的设备是否已经加载上了,首先是/sys/bus/platform/devices/,在devices下每一个连接文件都代表了一个设备,ls可看见test_ts,进入test_ts,ls可发现driver这个链接文件,ls -l查看,发现这个文件是连到/sys/bus/platform/drivers/test_ts的这里需要说明的是连接的含义,并不是driver驱动存在于test_ts这个设备中,而是test_ts使用的驱动为/sys/bus/platform/drivers/test_ts,现在换到/sys/bus/platform/drivers这个目录下,ls查看会发现这里的文件都为目录,而非连接文件,说明这是驱动真正放置的位置。

现在进入test_ts目录,然后ls,发现有一个test_ts的连接文件,ls –l查看可发现该文件连接到/sys/devices/platform/test_ts下,回到/sys/bus/platform/devices/下ls –l也会发现test_ts连接到/sys/devices/platform/test_ts,为什么test_ts这个设备放置于/sys/devices/platform下,而不是/sys/bus/platform/devices下呢?

我认为和直观性有关,在sys下有这么几个目录:
block  bus  class  dev  devices  firmware  kernel  module  fs power
devices很直观的说明了设备在这个目录下,便于大家查找,而/sys/bus/platform/devices下的连接是为了分类查找,画了张目录图, 如下,绿色框的为连接文件,绿色线条为连接的对象:
--jpg1--

1.4 题外话:我自身对于这样的分类不是很喜欢,臃肿,重复,而且信息也不好规划,希望在以后的版本能对sys进行大的改造,现在来看另两个图,也就是构成sys的核心kobject,首先第一个是我去掉了连接部分的内容,也就是绿色线条的目录图:
--jpg2--

2. 第二个是组成这个目录图的核心,kobject图,我也叫他层次图:
--jpg3--

2.1 不看大号绿色箭头右边的内容的话是不是发现两个架构相同? 对的,kobject的层次决定了目录的结构
kobeject图很大,但也不要担心,里面的内容其实不多,基础框架涉及3个主要结构kset kobject和ktype
在说明test_ts的注册之前,先让我们看一下sys下的两个基础目录bus,devices。

首先是bus,bus的注册在/drivers/base/bus.c里
  1. int __init buses_init(void)
  2. {
  3.     bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
  4.     if (!bus_kset)
  5.         return -ENOMEM;
  6.     return 0;
  7. }

先看bus_uevent_ops,这是一个uevent的操作集(我也还没清楚uevent的用途,所以uevent的内容先放着)
然后到kset_create_and_add:
  1. struct kset *kset_create_and_add(const char *name,
  2.                                  struct kset_uevent_ops *uevent_ops,
  3.                                  struct kobject *parent_kobj)
  4. //传递进来的参数为("bus", &bus_uevent_ops, NULL)
  5. {
  6.     struct kset *kset;
  7.     int error;
  8.     
  9.     //创建一个kset容器
  10.     kset = kset_create(name, uevent_ops, parent_kobj);
  11.     if (!kset)
  12.         return NULL;
  13.     
  14.     //注册创建的kset容器
  15.     error = kset_register(kset);
  16.     if (error) {
  17.         kfree(kset);
  18.         return NULL;
  19.     }
  20.     return kset;
  21. }
首先需要创建一个kset容器:
  1. static struct kset *kset_create(const char *name,
  2.                                 struct kset_uevent_ops *uevent_ops,
  3.                                 struct kobject *parent_kobj)
  4. //传递进来的参数为("bus", &bus_uevent_ops, NULL)
  5. {
  6.     struct kset *kset;
  7.     
  8.     //为kset分配内存
  9.     kset = kzalloc(sizeof(*kset), GFP_KERNEL);
  10.     if (!kset)
  11.         return NULL;
  12.     
  13.     //设置kset中kobject的名字,这里为bus
  14.     kobject_set_name(&kset->kobj, name);
  15.     
  16.     //设置uevent操作集,这里为bus_uevent_ops
  17.     kset->uevent_ops = uevent_ops;
  18.     
  19.     //设置父对象,这里为NULL
  20.     kset->kobj.parent = parent_kobj;
  21.     
  22.     //设置容器操作集
  23.     kset->kobj.ktype = &kset_ktype;
  24.     
  25.     //设置父容器
  26.     kset->kobj.kset = NULL;
  27.     
  28.     return kset;
  29. }
这里的ktype,也就是kset_ktype是一个操作集,用于为sys下文件的实时反馈做服务,例如我们cat name的时候就要通过ktype提供的show函数,具体什么怎么运用,将在后面讲解,现在回到kset_create_and_add中的kset_register,将建立好的kset添加进sys里:
  1. int kset_register(struct kset *k)
  2. {
  3.     int err;
  4.     
  5.     if (!k)
  6.         return -EINVAL;
  7.     
  8.     //初始化
  9.     kset_init(k);
  10.     
  11.     //添加该容器
  12.     err = kobject_add_internal(&k->kobj);
  13.     if (err)
  14.         return err;
  15.     kobject_uevent(&k->kobj, KOBJ_ADD);
  16.     return 0;
  17. }

kset_init进行一些固定的初始化操作,里面没有我们需要关心的内容,kobject_add_internal为重要的一个函数,他对kset里kobj的从属关系进行解析,搭建正确的架构。

  1. static int kobject_add_internal(struct kobject *kobj)
  2. {
  3.     int error = 0;
  4.     struct kobject *parent;
  5.     
  6.     //检测kobj是否为空
  7.     if (!kobj)
  8.         return -ENOENT;
  9.     
  10.     //检测kobj名字是否为空
  11.     if (!kobj->name || !kobj->name[0]) {
  12.         pr_debug("kobject: (%p): attempted to be registered with empty "
  13.             "name!\n", kobj);
  14.         WARN_ON(1);
  15.         return -EINVAL;
  16.     }
  17.     
  18.     //提取父对象
  19.     parent = kobject_get(kobj->parent);
  20.     
  21.     /* join kset if set, use it as parent if we do not already have one */
  22.     //父容器存在则设置父对象
  23.     if (kobj->kset) {//在bus的kset中为空,所以不会进入到下面的代码
  24.         
  25.         //检测是否已经设置父对象
  26.         if (!parent)
  27.             //无则使用父容器为父对象
  28.             parent = kobject_get(&kobj->kset->kobj);
  29.         
  30.         //添加该kobj到父容器的链表中
  31.         kobj_kset_join(kobj);
  32.         
  33.         //设置父对象
  34.         kobj->parent = parent;
  35.     }
  36.     
  37.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
  38.         kobject_name(kobj), kobj, __func__,
  39.         parent ? kobject_name(parent) : "",
  40.         kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
  41.     
  42.     //建立相应的目录
  43.     error = create_dir(kobj);
  44.     
  45.     if (error) {
  46.         kobj_kset_leave(kobj);
  47.         kobject_put(parent);
  48.         kobj->parent = NULL;
  49.         
  50.         if (error == -EEXIST)
  51.             printk(KERN_ERR "%s failed for %s with "
  52.             "-EEXIST, don't try to register things with "
  53.             "the same name in the same directory.\n",
  54.             __func__, kobject_name(kobj));
  55.         else
  56.             printk(KERN_ERR "%s failed for %s (%d)\n",
  57.             __func__, kobject_name(kobj), error);
  58.         dump_stack();
  59.     } else
  60.         kobj->state_in_sysfs = 1;
  61.     
  62.     return error;
  63. }
至此bus的目录就建立起来了,模型如下:
--jpg4--

接下来是devices,在/drivers/base/core.c里

  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.     return 0;
  7. }
过程和bus的注册一致,我就不复述了, 模型如下:
--jpg5--

然后是platform的注册,在platform的注册中,分为两个部分,一部分是注册到devices中,另一部分是注册到bus中,代码在/drivers/base/platform.c中:

  1. int __init platform_bus_init(void)
  2. {
  3.     int error;
  4.     
  5.     //注册到devices目录中
  6.     error = device_register(&platform_bus);
  7.     if (error)
  8.         return error;
  9.     
  10.     //注册到bus目录中
  11.     error = bus_register(&platform_bus_type);
  12.     
  13.     if (error)
  14.         device_unregister(&platform_bus);
  15.     return error;
  16. }
首先是device_register,注册的参数为platform_bus,如下所示
  1. struct device platform_bus = {
  2.     .bus_id = "platform",
  3. };
很简单,只有一个参数,表明了目录名:
  1. int device_register(struct device *dev)
  2. {
  3.     //初始化dev结构
  4.     device_initialize(dev);
  5.     //添加dev至目录
  6.     return device_add(dev);
  7. }

  8. void device_initialize(struct device *dev)
  9. {
  10.     //重要的一步,指明了父容器为devices_kset,而devices_kset的注册在前面已经介绍过了
  11.     dev->kobj.kset = devices_kset;
  12.     //初始化kobj的ktype为device_ktype
  13.     kobject_init(&dev->kobj, &device_ktype);
  14.     klist_init(&dev->klist_children, klist_children_get, klist_children_put);
  15.     INIT_LIST_HEAD(&dev->dma_pools);
  16.     INIT_LIST_HEAD(&dev->node);
  17.     init_MUTEX(&dev->sem);
  18.     spin_lock_init(&dev->devres_lock);
  19.     INIT_LIST_HEAD(&dev->devres_head);
  20.     device_init_wakeup(dev, 0);
  21.     set_dev_node(dev, -1);
  22. }

  23. int device_add(struct device *dev)
  24. {
  25.     struct device *parent = NULL;
  26.     struct class_interface *class_intf;
  27.     int error;
  28.     
  29.     dev = get_device(dev);
  30.     if (!dev || !strlen(dev->bus_id)) {
  31.         error = -EINVAL;
  32.         goto Done;
  33.     }
  34.     
  35.     pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
  36.     
  37.     parent = get_device(dev->parent);
  38.     setup_parent(dev, parent);
  39.     
  40.     if (parent)
  41.         set_dev_node(dev, dev_to_node(parent));
  42.     
  43.     //设置dev->kobj的名字和父对象,并建立相应的目录
  44.     error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
  45.     if (error)
  46.         goto Error;
  47.     
  48.     if (platform_notify)
  49.         platform_notify(dev);
  50.     
  51.     if (dev->bus)
  52.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  53.         BUS_NOTIFY_ADD_DEVICE, dev);
  54.     
  55.     //建立uevent文件
  56.     error = device_create_file(dev, &uevent_attr);
  57.     if (error)
  58.         goto attrError;
  59.     
  60.     if (MAJOR(dev->devt)) {
  61.         error = device_create_file(dev, &devt_attr);
  62.         if (error)
  63.             goto ueventattrError;
  64.     }
  65.     //建立subsystem连接文件连接到所属class,这里没有设置class对象所以不会建立
  66.     error = device_add_class_symlinks(dev);
  67.     if (error)
  68.         goto SymlinkError;
  69.     //建立dev的描述文件,这里没有设置描述文件所以不会建立
  70.     error = device_add_attrs(dev);
  71.     if (error)
  72.         goto AttrsError;
  73.     //建立链接文件至所属bus,这里没有设置所属bus所以不会建立
  74.     error = bus_add_device(dev);
  75.     if (error)
  76.         goto BusError;
  77.     //添加power文件,因为platform不属于设备,所以不会建立power文件
  78.     error = device_pm_add(dev);
  79.     if (error)
  80.         goto PMError;
  81.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  82.     
  83.     //检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配
  84.     bus_attach_device(dev);
  85.     if (parent)
  86.         klist_add_tail(&dev->knode_parent, &parent->klist_children);
  87.     
  88.     if (dev->class) {
  89.         down(&dev->class->sem);
  90.         list_add_tail(&dev->node, &dev->class->devices);
  91.         
  92.         list_for_each_entry(class_intf, &dev->class->interfaces, node)
  93.             if (class_intf->add_dev)
  94.                 class_intf->add_dev(dev, class_intf);
  95.             up(&dev->class->sem);
  96.     }
  97. Done:
  98.     put_device(dev);
  99.     return error;
  100. PMError:
  101.     bus_remove_device(dev);
  102. BusError:
  103.     if (dev->bus)
  104.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  105.         BUS_NOTIFY_DEL_DEVICE, dev);
  106.     device_remove_attrs(dev);
  107. AttrsError:
  108.     device_remove_class_symlinks(dev);
  109. SymlinkError:
  110.     if (MAJOR(dev->devt))
  111.         device_remove_file(dev, &devt_attr);
  112. ueventattrError:
  113.     device_remove_file(dev, &uevent_attr);
  114. attrError:
  115.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  116.     kobject_del(&dev->kobj);
  117. Error:
  118.     cleanup_device_parent(dev);
  119.     if (parent)
  120.         put_device(parent);
  121.     goto Done;
  122. }
在kobject_add-> kobject_add_varg-> kobject_add_internal中,
  1. //提取父对象,因为没有设置,所以为空
  2. parent = kobject_get(kobj->parent);

  3. //父容器存在则设置父对象,在前面的dev->kobj.kset = devices_kset中设为了devices_kset
  4. if (kobj->kset) {
  5. //检测是否已经设置父对象
  6.         if (!parent)
  7.                 //无则使用父容器为父对象
  8.                 parent = kobject_get(&kobj->kset->kobj);
  9. //添加该kobj到父容器的链表中
  10.         kobj_kset_join(kobj);

  11.         //设置父对象
  12.         kobj->parent = parent;
  13. }
现在devices下的platform目录建立好了,模型如下,其中红线描绘了目录关系:
--jpg6--

现在到bus_register了,注册的参数platform_bus_type,如下所示:
  1. struct bus_type platform_bus_type = {
  2.      .name = "platform",
  3.         .dev_attrs = platform_dev_attrs,
  4.         .match = platform_match,
  5.         .uevent = platform_uevent,
  6.         .suspend = platform_suspend,
  7.         .suspend_late = platform_suspend_late,
  8.         .resume_early = platform_resume_early,
  9.         .resume = platform_resume,
  10. };

  11. int bus_register(struct bus_type *bus)
  12. {
  13.     int retval;
  14.     
  15.     //声明一个总线私有数据并分配空间
  16.     struct bus_type_private *priv;
  17.     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
  18.     if (!priv)
  19.         return -ENOMEM;
  20.     
  21.     //互相关联
  22.     priv->bus = bus;
  23.     bus->p = priv;
  24.     
  25.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
  26.     
  27.     //设置私有数据中kobj对象的名字
  28.     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
  29.     if (retval)
  30.         goto out;
  31.     
  32.     //设置父容器为bus_kset,操作集为bus_ktype
  33.     priv->subsys.kobj.kset = bus_kset;
  34.     priv->subsys.kobj.ktype = &bus_ktype;
  35.     priv->drivers_autoprobe = 1;
  36.     
  37.     //注册bus容器
  38.     retval = kset_register(&priv->subsys);
  39.     if (retval)
  40.         goto out;
  41.     
  42.     //建立uevent属性文件
  43.     retval = bus_create_file(bus, &bus_attr_uevent);
  44.     if (retval)
  45.         goto bus_uevent_fail;
  46.     
  47.     //建立devices目录
  48.     priv->devices_kset = kset_create_and_add("devices", NULL,
  49.         &priv->subsys.kobj);
  50.     if (!priv->devices_kset) {
  51.         retval = -ENOMEM;
  52.         goto bus_devices_fail;
  53.     }
  54.     
  55.     //建立drivers目录
  56.     priv->drivers_kset = kset_create_and_add("drivers", NULL,
  57.         &priv->subsys.kobj);
  58.     if (!priv->drivers_kset) {
  59.         retval = -ENOMEM;
  60.         goto bus_drivers_fail;
  61.     }
  62.     
  63.     //初始化klist_devices和klist_drivers链表
  64.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  65.     klist_init(&priv->klist_drivers, NULL, NULL);
  66.     
  67.     //增加probe属性文件
  68.     retval = add_probe_files(bus);
  69.     if (retval)
  70.         goto bus_probe_files_fail;
  71.     
  72.     //增加总线的属性文件
  73.     retval = bus_add_attrs(bus);
  74.     if (retval)
  75.         goto bus_attrs_fail;
  76.     
  77.     pr_debug("bus: '%s': registered\n", bus->name);
  78.     return 0;
  79.     
  80. bus_attrs_fail:
  81.     remove_probe_files(bus);
  82. bus_probe_files_fail:
  83.     kset_unregister(bus->p->drivers_kset);
  84. bus_drivers_fail:
  85.     kset_unregister(bus->p->devices_kset);
  86. bus_devices_fail:
  87.     bus_remove_file(bus, &bus_attr_uevent);
  88. bus_uevent_fail:
  89.     kset_unregister(&bus->p->subsys);
  90.     kfree(bus->p);
  91. out:
  92.     return retval;
  93. }

  1. 在kset_register-> kobject_add_internal中

  2. //提取父对象,因为没有设置父对象,所以为空
  3. parent = kobject_get(kobj->parent);

  4. //父容器存在则设置父对象,在上文中设置了父容器priv->subsys.kobj.kset = bus_kset
  5. if (kobj->kset) {
  6.     
  7.     //检测是否已经设置父对象
  8.     if (!parent)
  9.         //无则使用父容器为父对象
  10.         parent = kobject_get(&kobj->kset->kobj);
  11.     
  12.     //添加该kobj到父容器的链表中
  13.     kobj_kset_join(kobj);
  14.     
  15.     //设置父对象
  16.     kobj->parent = parent;
  17. }
在retval = kset_register(&priv->subsys)完成之后platform在bus下的模型, 如下图:
--jpg7--

有印象的话大家还记得在platform下面有两个目录devices和drivers吧,现在就到这两个目录的注册了:
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);

注意这两条语句的头部
priv->devices_kset = kset_create_and_add
priv->drivers_kset = kset_create_and_add

可以清楚的看到bus_type_private下的devices_kset, drivers_kset分别连接到了devices,drivers的kset上
,现在来看kset_create_and_add("devices", NULL,&priv->subsys.kobj):

  1. struct kset *kset_create_and_add(const char *name,
  2.                                  struct kset_uevent_ops *uevent_ops,
  3.                                  struct kobject *parent_kobj)
  4. //参数为"devices", NULL,&priv->subsys.kobj
  5. {
  6.     struct kset *kset;
  7.     int error;
  8.     
  9.     //创建一个kset容器
  10.     kset = kset_create(name, uevent_ops, parent_kobj);
  11.     if (!kset)
  12.         return NULL;
  13.     
  14.     //注册创建的kset容器
  15.     error = kset_register(kset);
  16.     if (error) {
  17.         kfree(kset);
  18.         return NULL;
  19.     }
  20.     return kset;
  21. }
在kset_create 中比较重要的操作为:
kset->kobj.ktype = &kset_ktype   //设置了ktype,为kset_ktype
kset->kobj.parent = parent_kobj; //设置了父对象,为priv->subsys.kobj,也就是platform_bus_type->p->subsys.kobj
kset->kobj.kset = NULL;          //设置父容器为空

在kset_register中:
  1. //提取父对象
  2. parent = kobject_get(kobj->parent); //在之前设置为了

  3. //父容器存在则设置父对象,由于父容器为空,不执行以下代码
  4. if (kobj->kset) {
  5.     
  6.     //检测是否已经设置父对象
  7.     if (!parent)
  8.         //无则使用父容器为父对象
  9.         parent = kobject_get(&kobj->kset->kobj);
  10.     
  11.     //添加该kobj到父容器的链表中
  12.     kobj_kset_join(kobj);
  13.     
  14.     //设置父对象
  15.     kobj->parent = parent;
  16. }
至此, devices的模型就建立好了,drivers模型的建立和devices是一致的,只是名字不同而已,我就不复述了,建立好的模型如下:
--jpg8--

好了,到了这里,bus,devices和platform的基础模型就就建立好了,就等设备来注册了,在platform模型设备的建立中,需要2个部分的注册,驱动的注册和设备的注册:
platform_device_register(&test_device);       
platform_driver_register(&test_driver);

首先看platform_device_register, 注册参数为test_device,结构如下

  1. static struct platform_device test_device = {
  2.     .name = "test_ts",
  3.     .id = -1,
  4.     //. resource
  5.     //.dev
  6. };
这个结构主要描述了设备的名字,ID和资源和私有数据,其中资源和私有数据我们在这里不使用,将在别的文章中进行讲解:
  1. int platform_device_register(struct platform_device *pdev)
  2. {
  3.     //设备属性的初始化
  4.     device_initialize(&pdev->dev);
  5.     //将设备添加进platform里
  6.     return platform_device_add(pdev);
  7. }

  8. void device_initialize(struct device *dev)
  9. {
  10.     dev->kobj.kset = devices_kset; //设置kset为devices_kset,则将设备挂接上了devices目录
  11.     kobject_init(&dev->kobj, &device_ktype); //初始化kobeject,置ktype为device_ktype
  12.     klist_init(&dev->klist_children, klist_children_get,
  13.         klist_children_put);
  14.     INIT_LIST_HEAD(&dev->dma_pools);
  15.     INIT_LIST_HEAD(&dev->node);
  16.     init_MUTEX(&dev->sem);
  17.     spin_lock_init(&dev->devres_lock);
  18.     INIT_LIST_HEAD(&dev->devres_head);
  19.     device_init_wakeup(dev, 0);
  20.     set_dev_node(dev, -1);
  21. }

  22. int platform_device_add(struct platform_device *pdev)
  23. {
  24.     int i, ret = 0;
  25.     
  26.     if (!pdev)
  27.         return -EINVAL;
  28.     
  29.     //检测是否设置了dev中的parent,无则赋为platform_bus
  30.     if (!pdev->dev.parent)
  31.         pdev->dev.parent = &platform_bus;
  32.     
  33.     //设置dev中的bus为platform_bus_type
  34.     pdev->dev.bus = &platform_bus_type;
  35.     
  36.     //检测id,id为-1表明该设备只有一个,用设备名为bus_id
  37.     //不为1则表明该设备有数个,需要用序号标明bus_id
  38.     if (pdev->id != -1)
  39.         snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
  40.         pdev->id);
  41.     else
  42.         strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
  43.     
  44.     //增加资源到资源树中
  45.     for (i = 0; i < pdev->num_resources; i++) {
  46.         struct resource *p, *r = &pdev->resource;
  47.         
  48.         if (r->name == NULL)
  49.             r->name = pdev->dev.bus_id;
  50.         
  51.         p = r->parent;
  52.         if (!p) {
  53.             if (r->flags & IORESOURCE_MEM)
  54.                 p = &iomem_resource;
  55.             else if (r->flags & IORESOURCE_IO)
  56.                 p = &ioport_resource;
  57.         }
  58.         
  59.         if (p && insert_resource(p, r)) {
  60.             printk(KERN_ERR "%s: failed to claim resource %d\n",pdev->dev.bus_id, i);
  61.             ret = -EBUSY;
  62.             goto failed;
  63.         }
  64.     }
  65.     
  66.     pr_debug("Registering platform device '%s'. Parent at %s\n",pdev->dev.bus_id, pdev->dev.parent->bus_id);
  67.     
  68.     //添加设备到设备层次中
  69.     ret = device_add(&pdev->dev);
  70.     if (ret == 0)
  71.         return ret;
  72.     
  73. failed:
  74.     while (--i >= 0)
  75.         if (pdev->resource.flags & (IORESOURCE_MEM|IORESOURCE_IO))
  76.             release_resource(&pdev->resource);
  77.         return ret;
  78. }



  79. int device_add(struct device *dev)
  80. {
  81.     struct device *parent = NULL;
  82.     struct class_interface *class_intf;
  83.     int error;
  84.     
  85.     dev = get_device(dev);
  86.     if (!dev || !strlen(dev->bus_id)) {
  87.         error = -EINVAL;
  88.         goto Done;
  89.     }
  90.     
  91.     pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
  92.     
  93.     //取得上层device,而dev->parent的赋值是在platform_device_add中的pdev->dev.parent = &platform_bus完成的
  94.     parent = get_device(dev->parent);
  95.     
  96.     //以上层devices为准重设dev->kobj.parent
  97.     setup_parent(dev, parent);
  98.     
  99.     if (parent)
  100.         set_dev_node(dev, dev_to_node(parent));
  101.     
  102.     //设置dev->kobj的名字和父对象,并建立相应目录
  103.     error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
  104.     if (error)
  105.         goto Error;
  106.     
  107.     if (platform_notify)
  108.         platform_notify(dev);
  109.     
  110.     //一种新型的通知机制,但是platform中没有设置相应的结构,所以在这里跳过
  111.     /* notify clients of device entry (new way) */
  112.     if (dev->bus)
  113.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
  114.     
  115.     //建立uevent文件
  116.     error = device_create_file(dev, &uevent_attr);
  117.     if (error)
  118.         goto attrError;
  119.     
  120.     //设备有设备号则建立dev文件
  121.     if (MAJOR(dev->devt)) {
  122.         error = device_create_file(dev, &devt_attr);
  123.         if (error)
  124.             goto ueventattrError;
  125.     }
  126.     //建立subsystem连接文件连接到所属class
  127.     error = device_add_class_symlinks(dev);
  128.     if (error)
  129.         goto SymlinkError;
  130.     //添加dev的描述文件
  131.     error = device_add_attrs(dev);
  132.     if (error)
  133.         goto AttrsError;
  134.     //添加链接文件至所属bus
  135.     error = bus_add_device(dev);
  136.     if (error)
  137.         goto BusError;
  138.     //添加power文件
  139.     error = device_pm_add(dev);
  140.     if (error)
  141.         goto PMError;
  142.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  143.     
  144.     //检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配
  145.     bus_attach_device(dev);
  146.     if (parent)
  147.         klist_add_tail(&dev->knode_parent, &parent->klist_children);
  148.     
  149.     if (dev->class) {
  150.         down(&dev->class->sem);
  151.         list_add_tail(&dev->node, &dev->class->devices);
  152.         
  153.         list_for_each_entry(class_intf, &dev->class->interfaces, node)
  154.             if (class_intf->add_dev)
  155.                 class_intf->add_dev(dev, class_intf);
  156.             up(&dev->class->sem);
  157.     }
  158. Done:
  159.     put_device(dev);
  160.     return error;
  161. PMError:
  162.     bus_remove_device(dev);
  163. BusError:
  164.     if (dev->bus)
  165.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);
  166.     device_remove_attrs(dev);
  167. AttrsError:
  168.     device_remove_class_symlinks(dev);
  169. SymlinkError:
  170.     if (MAJOR(dev->devt))
  171.         device_remove_file(dev, &devt_attr);
  172. ueventattrError:
  173.     device_remove_file(dev, &uevent_attr);
  174. attrError:
  175.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  176.     kobject_del(&dev->kobj);
  177. Error:
  178.     cleanup_device_parent(dev);
  179.     if (parent)
  180.         put_device(parent);
  181.     goto Done;
  182. }

  183. static void setup_parent(struct device *dev, struct device *parent)
  184. {
  185.     struct kobject *kobj;
  186.     //取得上层device的kobj
  187.     kobj = get_device_parent(dev, parent);
  188.     //kobj不为空则重设dev->kobj.parent
  189.     if (kobj)
  190.         dev->kobj.parent = kobj;
  191. }


  192. static struct kobject *get_device_parent(struct device *dev,
  193.                                          struct device *parent)
  194. {
  195.     int retval;
  196.     
  197.     //因为dev->class为空,所以跳过这段代码
  198.     if (dev->class) {
  199.         struct kobject *kobj = NULL;
  200.         struct kobject *parent_kobj;
  201.         struct kobject *k;
  202.         
  203.         if (parent == NULL)
  204.             parent_kobj = virtual_device_parent(dev);
  205.         else if (parent->class)
  206.             return &parent->kobj;
  207.         else
  208.             parent_kobj = &parent->kobj;
  209.         
  210.         spin_lock(&dev->class->class_dirs.list_lock);
  211.         list_for_each_entry(k, &dev->class->class_dirs.list, entry)
  212.             if (k->parent == parent_kobj) {
  213.                 kobj = kobject_get(k);
  214.                 break;
  215.             }
  216.             spin_unlock(&dev->class->class_dirs.list_lock);
  217.             if (kobj)
  218.                 return kobj;
  219.             
  220.             k = kobject_create();
  221.             if (!k)
  222.                 return NULL;
  223.             k->kset = &dev->class->class_dirs;
  224.             retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
  225.             if (retval < 0) {
  226.                 kobject_put(k);
  227.                 return NULL;
  228.             }
  229.             return k;
  230.     }
  231.     
  232.     if (parent)
  233.         //返回上层device的kobj
  234.         return &parent->kobj;
  235.     return NULL;
  236. }
在bus_attach_device中虽然没有成功进行匹配,但是有很重要的一步为之后正确的匹配打下基础:
  1. void bus_attach_device(struct device *dev)
  2. {
  3.     struct bus_type *bus = dev->bus;
  4.     int ret = 0;
  5.     
  6.     if (bus) {
  7.         if (bus->p->drivers_autoprobe)
  8.             ret = device_attach(dev);
  9.         WARN_ON(ret < 0);
  10.         if (ret >= 0)
  11.             klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
  12.     }
  13. }
klist_add_tail(&dev->knode_bus, &bus->p->klist_devices)就是这一行,在这一行代码中将设备挂载到了bus下的devices链表下,这样,当驱动请求匹配的时候,platform总线就会历遍devices链表为驱动寻找合适的设备。

现在来看一下test_device的模型
:
--jpg9--


然后platform_driver_unregister,他的参数 test_driver的结构如下:
  1. static struct platform_driver test_driver = {
  2.      .probe = test_probe,
  3.         .remove = test_remove,
  4.         .driver = {
  5.         .name            = "test_ts",
  6.         .owner            = THIS_MODULE,
  7.     },
  8. };

  9. int platform_driver_register(struct platform_driver *drv)
  10. {
  11.     drv->driver.bus = &platform_bus_type;
  12.     if (drv->probe)
  13.         drv->driver.probe = platform_drv_probe;
  14.     if (drv->remove)
  15.         drv->driver.remove = platform_drv_remove;
  16.     if (drv->shutdown)
  17.         drv->driver.shutdown = platform_drv_shutdown;
  18.     if (drv->suspend)
  19.         drv->driver.suspend = platform_drv_suspend;
  20.     if (drv->resume)
  21.         drv->driver.resume = platform_drv_resume;
  22.     return driver_register(&drv->driver);
  23. }
从上面代码可以看出,在platform_driver中设置了probe, remove, shutdown, suspend或resume函数的话,则drv->driver也会设置成platform对应的函数:
  1. int driver_register(struct device_driver *drv)
  2. {
  3.     int ret;
  4.     struct device_driver *other;
  5.     
  6.     //检测总线的操作函数和驱动的操作函数是否同时存在,同时存在则提示使用总线提供的操作函数
  7.     if ((drv->bus->probe && drv->probe) ||
  8.         (drv->bus->remove && drv->remove) ||
  9.         (drv->bus->shutdown && drv->shutdown))
  10.         printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);
  11.     
  12.     //检测是否已经注册过
  13.     other = driver_find(drv->name, drv->bus);
  14.     if (other) {
  15.         put_driver(other);
  16.         printk(KERN_ERR "Error: Driver '%s' is already registered, “"aborting...\n", drv->name);
  17.             return -EEXIST;
  18.     }
  19.     
  20.     //添加驱动到总线上
  21.     ret = bus_add_driver(drv);
  22.     if (ret)
  23.         return ret;
  24.     
  25.     ret = driver_add_groups(drv, drv->groups);
  26.     if (ret)
  27.         bus_remove_driver(drv);
  28.     return ret;
  29. }

  30. int bus_add_driver(struct device_driver *drv)
  31. {
  32.     struct bus_type *bus;
  33.     struct driver_private *priv;
  34.     int error = 0;
  35.     
  36.     //取bus结构
  37.     bus = bus_get(drv->bus);
  38.     if (!bus)
  39.         return -EINVAL;
  40.     
  41.     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
  42.     
  43.     //分配驱动私有数据
  44.     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  45.     if (!priv) {
  46.         error = -ENOMEM;
  47.         goto out_put_bus;
  48.     }
  49.     
  50.     //初始化klist_devices链表
  51.     klist_init(&priv->klist_devices, NULL, NULL);
  52.     
  53.     //互相关联
  54.     priv->driver = drv;
  55.     drv->p = priv;
  56.     
  57.     //设置私有数据的父容器,在这一步中,设置了kset为platform下的drivers_kset结构,也就是drivers呢个目录
  58.     priv->kobj.kset = bus->p->drivers_kset;
  59.     
  60.     //初始化kobj对象,设置容器操作集并建立相应的目录,这里由于没有提供parent,所以会使用父容器中的kobj为父对象
  61.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
  62.         "%s", drv->name);
  63.     if (error)
  64.         goto out_unregister;
  65.     
  66.     //检测所属总线的drivers_autoprobe属性是否为真
  67.     //为真则进行与设备的匹配,到这里,就会与我们之前注册的test_device连接上了,至于如何连接,进行了什么操作,将在别的文章中详细描述
  68.     if (drv->bus->p->drivers_autoprobe) {
  69.         error = driver_attach(drv);
  70.         if (error)
  71.             goto out_unregister;
  72.     }
  73.     
  74.     //挂载到所属总线驱动链表上
  75.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
  76.     module_add_driver(drv->owner, drv);
  77.     
  78.     //建立uevent属性文件
  79.     error = driver_create_file(drv, &driver_attr_uevent);
  80.     if (error) {
  81.         printk(KERN_ERR "%s: uevent attr (%s) failed\n",
  82.             __func__, drv->name);
  83.     }
  84.     
  85.     //建立设备属性文件
  86.     error = driver_add_attrs(bus, drv);
  87.     if (error) {
  88.         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
  89.     }
  90.     error = add_bind_files(drv);
  91.     if (error) {
  92.         printk(KERN_ERR "%s: add_bind_files(%s) failed\n

到这里test_driver的模型就建立好了,图就是最上面的层次图,我就不再贴了。到这里一个基本的框架就建立起来了,下面,我开始对kobject kset和ktype做分析,先说说关系,ktype与kobject和kset这两者之前的关系较少,让我画一个图,是这样的:

--jpg10--

ktype依赖于kobject,kset也依赖于kobject,而kobject有时需要kset(所以用了一个白箭头),不一定需要ktype(真可怜,连白箭头都没有)。首先先说一下这个可有可无的ktype,到/sys/bus/platform下面可以看见一个drivers_autoprobe的文件,cat drivers_autoprobe可以查看这个文件的值,echo 0 > drivers_autoprobe则可以改变这个文件的值,drivers_autoprobe这个文件表示的是是否自动进行初始化
在:

  1. void bus_attach_device(struct device *dev)
  2. {
  3.     struct bus_type *bus = dev->bus;
  4.     int ret = 0;
  5.     
  6.     if (bus) {
  7.         if (bus->p->drivers_autoprobe)
  8.             ret = device_attach(dev);
  9.         WARN_ON(ret < 0);
  10.         if (ret >= 0)
  11.             klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
  12.     }
  13. }
中可以看见这么一段代码:
if (bus->p->drivers_autoprobe)
        ret = device_attach(dev);

bus->p->drivers_autoprobe的值为真则进行匹配,而drivers_autoprobe这个文件则可以动态的修改这个值选择是否进行匹配,使用外部文件修改内核参数,ktype就是提供了这么一种方法,现在让我们看看ktype是怎么通过kobject进行运作的。

首先是ktype及通过ktype进行运作的drivers_autoprobe的注册,ktype的挂载十分简单,因为他是和kobject是一体的,只有这么下面一句:      
priv->subsys.kobj.ktype = &bus_ktype;
这样就将bus_ktype挂载到了platform_bus_type的kobject上,drivers_autoprobe的注册如下:
retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);

bus_attr_drivers_autoprobe这个结构由一系列的宏进行组装:
  1. static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
  2.                 show_drivers_autoprobe, store_drivers_autoprobe);

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

  5. #define __ATTR(_name,_mode,_show,_store) { \
  6.     .attr = {.name = __stringify(_name), .mode = _mode }, \
  7.     .show = _show, \
  8.     .store = _store, \
  9. }
最后bus_attr_drivers_autoprobe的模型如下:
  1. struct bus_attribute bus_attr_drivers_autoprobe
  2. {
  3.         .attr = {
  4.         .name = “drivers_autoprobe”,
  5.         .mode = S_IWUSR | S_IRUGO
  6. },
  7.         .show = show_drivers_autoprobe,
  8.         .store = store_drivers_autoprobe,
  9. }
进入到bus_create_file中:
  1. int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
  2. //参数为(bus, &bus_attr_drivers_autoprobe)
  3. {
  4.     int error;
  5.     if (bus_get(bus)) {
  6.         error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
  7.         bus_put(bus);
  8.     } else
  9.         error = -EINVAL;
  10.     return error;
  11. }

  12. int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
  13. //参数为(&bus->p->subsys.kobj, &attr->attr)
  14. {
  15.     BUG_ON(!kobj || !kobj->sd || !attr);
  16.     return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
  17. }

  18. int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,int type)
  19. //参数为(&bus->p->subsys.kobj ->sd, &attr->attr, SYSFS_KOBJ_ATTR)
  20. {
  21.     return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
  22. }


  23. int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
  24.                         const struct attribute *attr, int type, mode_t amode)
  25. //整理一下参数,现在应该为
  26. //(&platform_bus_type->p->subsys.kobj ->sd, &bus_attr_drivers_autoprobe->attr, SYSFS_KOBJ_ATTR, &bus_attr_drivers_autoprobe->attr->mode)
  27. {
  28.     umode_t mode = (amode & S_IALLUGO) | S_IFREG;
  29.     struct sysfs_addrm_cxt acxt;
  30.     struct sysfs_dirent *sd;
  31.     int rc;
  32.     
  33.     //在这一步中可以看出新建了一个节点
  34.     sd = sysfs_new_dirent(attr->name, mode, type);
  35.     if (!sd)
  36.         return -ENOMEM;
  37.     
  38.     //这一步挂载了&bus_attr_drivers_autoprobe->attr到节点中,为以后提取attr及上层结构做准备
  39.     sd->s_attr.attr = (void *)attr;
  40.     
  41.     // dir_sd也就是上层目录,在这里为platform_bus_type->p->subsys.kobj ->sd
  42.     //也就是/sys/bus/platform这个目录
  43.     sysfs_addrm_start(&acxt, dir_sd);
  44.     rc = sysfs_add_one(&acxt, sd);
  45.     sysfs_addrm_finish(&acxt);
  46.     
  47.     if (rc)
  48.         sysfs_put(sd);
  49.     
  50.     return rc;
  51. }


  52. struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
  53. {
  54.     char *dup_name = NULL;
  55.     struct sysfs_dirent *sd;
  56.     
  57.     if (type & SYSFS_COPY_NAME) {
  58.         name = dup_name = kstrdup(name, GFP_KERNEL);
  59.         if (!name)
  60.             return NULL;
  61.     }
  62.     
  63.     sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
  64.     if (!sd)
  65.         goto err_out1;
  66.     
  67.     if (sysfs_alloc_ino(&sd->s_ino))
  68.         goto err_out2;
  69.     
  70.     atomic_set(&sd->s_count, 1);
  71.     atomic_set(&sd->s_active, 0);
  72.     
  73.     sd->s_name = name; //节点的名字为&bus_attr_drivers_autoprobe->attr->name 也就是drivers_autoprobe
  74.     sd->s_mode = mode;
  75.     sd->s_flags = type; //节点的type为SYSFS_KOBJ_ATTR
  76.     return sd;
  77.     
  78. err_out2:
  79.     kmem_cache_free(sysfs_dir_cachep, sd);
  80. err_out1:
  81.     kfree(dup_name);
  82.     return NULL;
  83. }

现在一切准备就绪,来看看怎么读取吧。首先是open,大概流程可以看我的另一篇文章<从文件到设备>,一直看到ext3_lookup,这里和ext3_lookup不同的是,sys的文件系统是sysfs文件系统,所以应该使用的lookup函数为sysfs_lookup(/fs/sysfs/dir.c):
  1. static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
  2.                                     struct nameidata *nd)
  3. {
  4.     struct dentry *ret = NULL;
  5.     struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
  6.     struct sysfs_dirent *sd;
  7.     struct inode *inode;
  8.     
  9.     mutex_lock(&sysfs_mutex);
  10.     
  11.     sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
  12.     
  13.     if (!sd) {
  14.         ret = ERR_PTR(-ENOENT);
  15.         goto out_unlock;
  16.     }
  17.     
  18.     //节点的初始化在这里
  19.     inode = sysfs_get_inode(sd);
  20.     if (!inode) {
  21.         ret = ERR_PTR(-ENOMEM);
  22.         goto out_unlock;
  23.     }
  24.     
  25.     dentry->d_op = &sysfs_dentry_ops;
  26.     dentry->d_fsdata = sysfs_get(sd);
  27.     d_instantiate(dentry, inode);
  28.     d_rehash(dentry);
  29.     
  30. out_unlock:
  31.     mutex_unlock(&sysfs_mutex);
  32.     return ret;
  33. }


  34. struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
  35. {
  36.     struct inode *inode;
  37.     
  38.     inode = iget_locked(sysfs_sb, sd->s_ino);
  39.     if (inode && (inode->i_state & I_NEW))
  40.         //为节点赋值
  41.         sysfs_init_inode(sd, inode);
  42.     
  43.     return inode;
  44. }


  45. static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
  46. {
  47.     struct bin_attribute *bin_attr;
  48.     
  49.     inode->i_blocks = 0;
  50.     inode->i_mapping->a_ops = &sysfs_aops;
  51.     inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
  52.     inode->i_op = &sysfs_inode_operations;
  53.     inode->i_ino = sd->s_ino;
  54.     lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
  55.     
  56.     if (sd->s_iattr) {
  57.         set_inode_attr(inode, sd->s_iattr);
  58.     } else
  59.         set_default_inode_attr(inode, sd->s_mode);
  60.     
  61.     //判断类型
  62.     switch (sysfs_type(sd)) {
  63.     case SYSFS_DIR:
  64.         inode->i_op = &sysfs_dir_inode_operations;
  65.         inode->i_fop = &sysfs_dir_operations;
  66.         inode->i_nlink = sysfs_count_nlink(sd);
  67.         break;
  68.         //还记得在注册的时候有一个参数为SYSFS_KOBJ_ATTR赋到了sd->s_flags上面吧
  69.     case SYSFS_KOBJ_ATTR:
  70.         inode->i_size = PAGE_SIZE;
  71.         inode->i_fop = &sysfs_file_operations;
  72.         break;
  73.     case SYSFS_KOBJ_BIN_ATTR:
  74.         bin_attr = sd->s_bin_attr.bin_attr;
  75.         inode->i_size = bin_attr->size;
  76.         inode->i_fop = &bin_fops;
  77.         break;
  78.     case SYSFS_KOBJ_LINK:
  79.         inode->i_op = &sysfs_symlink_inode_operations;
  80.         break;
  81.     default:
  82.         BUG();
  83.     }
  84.     
  85.     unlock_new_inode(inode);
  86. }
sysfs_file_operations的结构如下,之后open和read,write都明了:
  1. const struct file_operations sysfs_file_operations = {
  2.      .read = sysfs_read_file,
  3.         .write = sysfs_write_file,
  4.         .llseek = generic_file_llseek,
  5.         .open = sysfs_open_file,
  6.         .release = sysfs_release,
  7.         .poll = sysfs_poll,
  8. };
有关在哪调用open还是请查阅我的另一篇文章<从文件到设备>中 nameidata_to_filp之后的操作。好的,现在进入到了sysfs_open_file中:
  1. static int sysfs_open_file(struct inode *inode, struct file *file)
  2. {
  3.     struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  4.     //要重的取值,在这里取得了drivers_autoprobe的目录platform的kproject
  5.     struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  6.     struct sysfs_buffer *buffer;
  7.     struct sysfs_ops *ops;
  8.     int error = -EACCES;
  9.     
  10.     if (!sysfs_get_active_two(attr_sd))
  11.         return -ENODEV;
  12.     
  13.     if (kobj->ktype && kobj->ktype->sysfs_ops)
  14.     //这里可谓是ktype实现中的核心,在这里ops设置成了platform_bus_type中kobject->ktype的sysfs_ops
  15.         ops = kobj->ktype->sysfs_ops;
  16.     else {
  17.         printk(KERN_ERR "missing sysfs attribute operations for ""kobject: %s\n", kobject_name(kobj));
  18.         WARN_ON(1);
  19.         goto err_out;
  20.     }
  21.     
  22.     if (file->f_mode & FMODE_WRITE) {
  23.         if (!(inode->i_mode & S_IWUGO) || !ops->store)
  24.             goto err_out;
  25.     }
  26.     
  27.     if (file->f_mode & FMODE_READ) {
  28.         if (!(inode->i_mode & S_IRUGO) || !ops->show)
  29.             goto err_out;
  30.     }
  31.     
  32.     error = -ENOMEM;
  33.     buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
  34.     if (!buffer)
  35.         goto err_out;
  36.     
  37.     mutex_init(&buffer->mutex);
  38.     buffer->needs_read_fill = 1;
  39.     //然后将设置好的ops挂载到buffer上
  40.     buffer->ops = ops;
  41.     //再将buffer挂载到file->private_data中
  42.     file->private_data = buffer;
  43.     
  44.     error = sysfs_get_open_dirent(attr_sd, buffer);
  45.     if (error)
  46.         goto err_free;
  47.     
  48.     sysfs_put_active_two(attr_sd);
  49.     return 0;
  50.     
  51. err_free:
  52.     kfree(buffer);
  53. err_out:
  54.     sysfs_put_active_two(attr_sd);
  55.     return error;
  56. }
现在已经为read和write操作准备好了,马上进入到read操作中:
--jpg11--

整个流程如上图所示,如何进入到sysfs_read_file在上面open的操作中已经说明了,我们就从sysfs_read_file开始分析(该文件在/fs/sysfs/file.c中):
  1. sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  2. {
  3.     struct sysfs_buffer * buffer = file->private_data;
  4.     ssize_t retval = 0;
  5.     
  6.     mutex_lock(&buffer->mutex);
  7.     if (buffer->needs_read_fill || *ppos == 0) {
  8.         //主要操作在fill_read_buffer中
  9.         retval = fill_read_buffer(file->f_path.dentry,buffer);
  10.         if (retval)
  11.             goto out;
  12.     }
  13.     pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",__func__, count, *ppos, buffer->page);
  14.     retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
  15.         buffer->count);
  16. out:
  17.     mutex_unlock(&buffer->mutex);
  18.     return retval;
  19. }

  20. static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
  21. {
  22.     struct sysfs_dirent *attr_sd = dentry->d_fsdata;
  23.     //取得父目录的kobject,也就是platform的kobject
  24.     struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  25.     //还记得这个buffer->ops在什么时候进行赋值的么?
  26.     struct sysfs_ops * ops = buffer->ops;
  27.     int ret = 0;
  28.     ssize_t count;
  29.     
  30.     if (!buffer->page)
  31.         buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
  32.     if (!buffer->page)
  33.         return -ENOMEM;
  34.     
  35.     if (!sysfs_get_active_two(attr_sd))
  36.         return -ENODEV;
  37.     
  38.     buffer->event = atomic_read(&attr_sd->s_attr.open->event);
  39.     
  40.     //调用ops->show 也就是bus_sysfs_ops->show 具体就是bus_attr_show了
  41.     //参数为父目录的kobject, bus_attr_drivers_autoprobe->attr,和一段char信息
  42.     count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
  43.     
  44.     sysfs_put_active_two(attr_sd);
  45.     
  46.     if (count >= (ssize_t)PAGE_SIZE) {
  47.         print_symbol("fill_read_buffer: %s returned bad count\n",
  48.             (unsigned long)ops->show);
  49.         /* Try to struggle along */
  50.         count = PAGE_SIZE - 1;
  51.     }
  52.     if (count >= 0) {
  53.         buffer->needs_read_fill = 0;
  54.         buffer->count = count;
  55.     } else {
  56.         ret = count;
  57.     }
  58.     return ret;
  59. }

现在进入bus_attr_show中:
  1. static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
  2. {
  3.     //提取attr的上层结构,也就是bus_attr_drivers_autoprobe
  4.     struct bus_attribute *bus_attr = to_bus_attr(attr);
  5.     //提取kobj的上上层结构,也就是bus_type_private
  6.     struct bus_type_private *bus_priv = to_bus(kobj);
  7.     ssize_t ret = 0;
  8.     
  9.     if (bus_attr->show)
  10.         //终于到了这里,最后的调用,调用bus_attr_drivers_autoprobe.show ,也就是show_drivers_autoprobe
  11.         //参数为bus_priv->bus,也就是platform_bus_type , 及一段char信息
  12.         ret = bus_attr->show(bus_priv->bus, buf);
  13.     return ret;
  14. }

  15. static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
  16. {
  17.     return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
  18. }
没什么好介绍了就是打印 buf + bus->p->drivers_autoprobe, 从结果来看, buf是空的,到这里,终于把内核的信息给打印出来了,千辛万苦,层层调用,就是为了取得上层kobject结构,逆运算再取得kobject的上层结构,大家是否对kobject有所了解了呢? 在对kobject进行介绍之前还是先把write操作讲完吧 哈哈~

write操作和read操作重要的步骤基本是一致的,只不过在最后的调用中:
  1. static ssize_t store_drivers_autoprobe(struct bus_type *bus,
  2.                                        const char *buf, size_t count)
  3. {
  4.     if (buf[0] == '0')
  5.         bus->p->drivers_autoprobe = 0;
  6.     else
  7.         bus->p->drivers_autoprobe = 1;
  8.     return count;
  9. }
不进行打印而对内核的参数进行了修改而已, 好, 现在让我们来看看kobject吧.
kobject的结构如下:
  1. struct kobject {
  2.     const char *name; //kobject的名字
  3.     struct kref kref; //kobject的原子操作
  4.     struct list_head entry;
  5.     struct kobject *parent; //父对象
  6.     struct kset *kset; //父容器
  7.     struct kobj_type *ktype; //ktype
  8.     struct sysfs_dirent *sd; //文件节点
  9.     unsigned int state_initialized:1;
  10.     unsigned int state_in_sysfs:1;
  11.     unsigned int state_add_uevent_sent:1;
  12.     unsigned int state_remove_uevent_sent:1;
  13. };
kobject描述的是较具体的对象,一个设备,一个驱动,一个总线,一类设备,在层次图上可以看出,每个存在于层次图中的设备,驱动,总线,类别都有自己的kobject。

kobject与kobject之间的层次由kobject中的parent指针决定,而kset指针则表明了kobject的容器,像platform_bus 和test_device的kset都是devices_kset。

那么parent和kset有什么不同呢?
我认为是人工和默认的区别,看下面这张图 ,蓝框为kset,红框为kobject:
--jpg12--

容器提供了一种默认的层次,但也可以人工设置层次, 对于kobject现在我只理解了这么多,欢迎大家指出有疑问的地方.
最后是kset,kset比较简单,看下面的结构:
  1. struct kset {
  2.         struct list_head list;
  3.         spinlock_t list_lock;
  4.         struct kobject kobj;
  5.         struct kset_uevent_ops *uevent_ops;
  6. };
对于kset的描述,文档里也有介绍:
  1. /**
  2. * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  3. *
  4. * A kset defines a group of kobjects. They can be individually
  5. * different "types" but overall these kobjects all want to be grouped
  6. * together and operated on in the same manner. ksets are used to
  7. * define the attribute callbacks and other common events that happen to
  8. * a kobject.
  9. */

翻译过来大概就是
结构kset,一个指定类型的kobject的集合,属于某一个指定的子系统
kset定义了一组kobject,它们可以是不同类型组成但却希望捆在一起有一个统一的操作
kset通常被定义为回调属性和其他通用的事件发生在kobject上

可能翻译的不是很好,望大家见谅
从结构中能看出kset比kobject多了3个属性
list_head                      //列表
spinlock_t                     //共享锁
kset_uevent_ops                //uevent操作集

list_head        连接了所有kobject中kset属性指向自己的kobject
而kset_uevent_ops则用于通知机制,由于uevent的作用我也没接触过,所以暂不解析uevent的机制了


写到这里,不知道大家对内核驱动架构中的注册和对kobject的了解有无加深呢?
 
欢迎转载 = 3= 转载请标上转自BLOG : zwolf.cublog.cn

【转】:http://blog.chinaunix.net/space.php?uid=13321460&do=blog&id=2902417
阅读(4964) | 评论(1) | 转发(7) |
给主人留下些什么吧!~~

重返人生2011-12-15 02:08:33

层次图( ^_^ )不错