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

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

    总线是处理器与设备之间的通道,在设备模型中,所有的设备都是通过总线相连的。在设备模型中,总线由bus_type表示

点击(此处)折叠或打开

  1. struct bus_type {
  2.     const char        *name;                   //总线类型名称
  3.     struct bus_attribute    *bus_attrs;        //总线属性
  4.     struct device_attribute    *dev_attrs;     //设备属性
  5.     struct driver_attribute    *drv_attrs;     //驱动属性

  6.     int (*match)(struct device *dev, struct device_driver *drv);  //匹配总线中的dev和driver
  7.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //用于总线对uevent环境变量添加
  8.     int (*probe)(struct device *dev);         //总线匹配成功是会调用,bus和drv的probe中只有一个奇效//,如果bus存在就调用bus->probe
  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 iommu_ops *iommu_ops;

  15.     struct subsys_private *p;
  16. };
其中最后一个指向subsys_private的指针,定义了将bus同其他类型联系起来的关系,将bus同device、driver、sysfs联系起来。

点击(此处)折叠或打开

  1. struct subsys_private {
  2.     struct kset subsys;
  3.     struct kset *devices_kset;

  4.     struct kset *drivers_kset;
  5.     struct klist klist_devices;
  6.     struct klist klist_drivers;
  7.     struct blocking_notifier_head bus_notifier;
  8.     unsigned int drivers_autoprobe:1;
  9.     struct bus_type *bus;

  10.     struct list_head class_interfaces;
  11.     struct kset glue_dirs;
  12.     struct mutex class_mutex;
  13.     struct class *class;
  14. };
subsys是kset类型,代表bus在sysfs中的类型
devices_kset代表bus目录下的device的子目录
driver_kset代表bus目录下的driver的子目录
klist_devices是bus的设备链表,klist_drivers是bus的驱动链表
     linux设备中的每层都有自己特有的属性的表示方法bus_attribute

点击(此处)折叠或打开

  1. struct bus_attribute {
  2.     struct attribute    attr;
  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. };

  6. #define BUS_ATTR(_name, _mode, _show, _store)    \
  7. struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
下面看看linux对于这个例子

点击(此处)折叠或打开

  1. static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
  2.              const char *buf, size_t count)
  3. {
  4.     struct bus_attribute *bus_attr = to_bus_attr(attr);
  5.     struct subsys_private *subsys_priv = to_subsys_private(kobj);
  6.     ssize_t ret = 0;

  7.     if (bus_attr->store)
  8.         ret = bus_attr->store(subsys_priv->bus, buf, count);
  9.     return ret;
  10. }

  11. static const struct sysfs_ops bus_sysfs_ops = {
  12.     .show    = bus_attr_show,
  13.     .store    = bus_attr_store,
  14. };

  15. static struct kobj_type bus_ktype = {
  16.     .sysfs_ops    = &bus_sysfs_ops,
  17. };
上面是我们属性的kobj_type的表示方法,在kernel_init->do_basic_setup->driver_init会有很多相关文件系统的初始化

点击(此处)折叠或打开

  1. void __init driver_init(void)
  2. {
  3.     /* These are the core pieces */
  4.     devtmpfs_init();//创建文件系统
  5.     devices_init(); //创建devices/dev/block/char目录
  6.     buses_init();  //总线初始化
  7.     classes_init();//创建class目录
  8.     firmware_init();
  9.     hypervisor_init();

  10.     /* These are also core pieces, but must come after the
  11.      * core core pieces.
  12.      */
  13.     platform_bus_init();
  14.     system_bus_init();
  15.     cpu_dev_init();
  16.     memory_dev_init();
  17. }
 上面主要是创建文件系统中的一些目录,其中我们主要关心buses_init

点击(此处)折叠或打开

  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/bus目录,这是一个kset类型,使用了bus_uevent_ops的uevent操作类型。
下面来看看总线的注册函数

点击(此处)折叠或打开

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

  5.     priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);//分配一个结构体
  6.     if (!priv)
  7.         return -ENOMEM;

  8.     priv->bus = bus;   //指向该bus
  9.     bus->p = priv;    

  10.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

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

  14.     priv->subsys.kobj.kset = bus_kset;    //所属的kset使用bus_kset
  15.     priv->subsys.kobj.ktype = &bus_ktype;   //类型使用bus_ktype
  16.     priv->drivers_autoprobe = 1;
  17.     retval = kset_register(&priv->subsys);//将bus加入到sysfs中
  18.     if (retval)
  19.         goto out;

  20.     retval = bus_create_file(bus, &bus_attr_uevent);//创建bus下的属性文件
  21.     if (retval)
  22.         goto bus_uevent_fail;

  23.     priv->devices_kset = kset_create_and_add("devices", NULL,
  24.                          &priv->subsys.kobj);    //创建devices目录
  25.     if (!priv->devices_kset) {
  26.         retval = -ENOMEM;
  27.         goto bus_devices_fail;
  28.     }

  29.     priv->drivers_kset = kset_create_and_add("drivers", NULL,
  30.                          &priv->subsys.kobj);//创建drivers目录
  31.     if (!priv->drivers_kset) {
  32.         retval = -ENOMEM;
  33.         goto bus_drivers_fail;
  34.     }

  35.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  36.     klist_init(&priv->klist_drivers, NULL, NULL);

  37.     retval = add_probe_files(bus);
  38.     if (retval)
  39.         goto bus_probe_files_fail;

  40.     retval = bus_add_attrs(bus);
  41.     if (retval)
  42.         goto bus_attrs_fail;

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

  45. bus_attrs_fail:
  46.     remove_probe_files(bus);
  47. bus_probe_files_fail:
  48.     kset_unregister(bus->p->drivers_kset);
  49. bus_drivers_fail:
  50.     kset_unregister(bus->p->devices_kset);
  51. bus_devices_fail:
  52.     bus_remove_file(bus, &bus_attr_uevent);
  53. bus_uevent_fail:
  54.     kset_unregister(&bus->p->subsys);
  55. out:
  56.     kfree(bus->p);
  57.     bus->p = NULL;
  58.     return retval;
  59. }
调用kset_register(),在上一编中分析过,这个函数主要是在/sys/bus目录,并向用户空间上报。klist_devices_get()用于bus设备链表上添加节点时增加对相应设备的引用。

点击(此处)折叠或打开

  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);
  6.         bus_put(bus);
  7.     } else
  8.         error = -EINVAL;
  9.     return error;
  10. }
这个主要是在bus目录下创建属性文件。klist_devices_put()用于bus设备链表上删去节点时减少对相应设备的引用。

点击(此处)折叠或打开

  1. static void klist_devices_get(struct klist_node *n)
  2. {
  3.     struct device_private *dev_prv = to_device_private_bus(n);
  4.     struct device *dev = dev_prv->device;

  5.     get_device(dev);
  6. }

  7. static void klist_devices_put(struct klist_node *n)
  8. {
  9.     struct device_private *dev_prv = to_device_private_bus(n);
  10.     struct device *dev = dev_prv->device;

  11.     put_device(dev);
  12. }

点击(此处)折叠或打开

  1. static int add_probe_files(struct bus_type *bus)
  2. {
  3.     int retval;

  4.     retval = bus_create_file(bus, &bus_attr_drivers_probe);
  5.     if (retval)
  6.         goto out;

  7.     retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
  8.     if (retval)
  9.         bus_remove_file(bus, &bus_attr_drivers_probe);
  10. out:
  11.     return retval;
  12. }
add_probe_files()在bus目录下添加drivers_probe和drivers_autoprobe文件,bus_add_attrs()添加结构体中的属性。有上面可以看出,bus_register完成一些初始化,添加到sysfs中,添加相关的子目录和属性文件。

点击(此处)折叠或打开

  1. static char *Version = "$Revision: 1.0 $";

  2. static int my_match(struct device *dev, struct device_driver *driver)
  3. {
  4.     return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
  5. }

  6. struct bus_type my_bus_type = {
  7.     .name = "my_bus",
  8.     .match = my_match,
  9. };

  10. static ssize_t show_bus_version(struct bus_type *bus, char *buf)
  11. {
  12.     return snprintf(buf, PAGE_SIZE, "%s\n", Version);
  13. }

  14. static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);


  15. static int __init my_bus_init(void)
  16. {
  17.     int ret;
  18.         
  19.         /*注册总线*/
  20.     ret = bus_register(&my_bus_type);
  21.     if (ret)
  22.         return ret;
  23.         
  24.     /*创建属性文件*/    
  25.     if (bus_create_file(&my_bus_type, &bus_attr_version))
  26.         printk(KERN_NOTICE "Fail to create version attribute!\n");
  27.         
  28.     return ret;
  29. }

  30. static void my_bus_exit(void)
  31. {
  32.     bus_unregister(&my_bus_type);
  33. }

  34. module_init(my_bus_init);
  35. module_exit(my_bus_exit);



上一篇:总线设备驱动模型--设备篇
下一篇:Linux设备驱动的分层设计思想