总线是处理器与设备之间的通道,在设备模型中,所有的设备都是通过总线相连的。在设备模型中,总线由bus_type表示
- struct bus_type {
- const char *name; //总线类型名称
- struct bus_attribute *bus_attrs; //总线属性
- struct device_attribute *dev_attrs; //设备属性
- struct driver_attribute *drv_attrs; //驱动属性
- int (*match)(struct device *dev, struct device_driver *drv); //匹配总线中的dev和driver
- int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //用于总线对uevent环境变量添加
- int (*probe)(struct device *dev); //总线匹配成功是会调用,bus和drv的probe中只有一个奇效//,如果bus存在就调用bus->probe
- int (*remove)(struct device *dev); //总线上设备或者驱动删去时调用
- void (*shutdown)(struct device *dev);//函数在所有设备都关闭时候调用
- int (*suspend)(struct device *dev, pm_message_t state);//总线上设备休眠
- int (*resume)(struct device *dev); //处理热插拔、电源管理
- const struct dev_pm_ops *pm;
- struct iommu_ops *iommu_ops;
- struct subsys_private *p;
- };
其中最后一个指向subsys_private的指针,定义了将bus同其他类型联系起来的关系,将bus同device、driver、sysfs联系起来。
- struct subsys_private {
- struct kset subsys;
- struct kset *devices_kset;
- struct kset *drivers_kset;
- struct klist klist_devices;
- struct klist klist_drivers;
- struct blocking_notifier_head bus_notifier;
- unsigned int drivers_autoprobe:1;
- struct bus_type *bus;
- struct list_head class_interfaces;
- struct kset glue_dirs;
- struct mutex class_mutex;
- struct class *class;
- };
subsys是kset类型,代表bus在sysfs中的类型
devices_kset代表bus目录下的device的子目录
driver_kset代表bus目录下的driver的子目录
klist_devices是bus的设备链表,klist_drivers是bus的驱动链表
linux设备中的每层都有自己特有的属性的表示方法bus_attribute
- struct bus_attribute {
- struct attribute attr;
- ssize_t (*show)(struct bus_type *bus, char *buf);
- ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
- };
- #define BUS_ATTR(_name, _mode, _show, _store) \
- struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
下面看看linux对于这个例子
- static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
- {
- struct bus_attribute *bus_attr = to_bus_attr(attr);
- struct subsys_private *subsys_priv = to_subsys_private(kobj);
- ssize_t ret = 0;
- if (bus_attr->store)
- ret = bus_attr->store(subsys_priv->bus, buf, count);
- return ret;
- }
- static const struct sysfs_ops bus_sysfs_ops = {
- .show = bus_attr_show,
- .store = bus_attr_store,
- };
- static struct kobj_type bus_ktype = {
- .sysfs_ops = &bus_sysfs_ops,
- };
上面是我们属性的kobj_type的表示方法,在kernel_init->do_basic_setup->driver_init会有很多相关文件系统的初始化
- void __init driver_init(void)
- {
- /* These are the core pieces */
- devtmpfs_init();//创建文件系统
- devices_init(); //创建devices/dev/block/char目录
- buses_init(); //总线初始化
- classes_init();//创建class目录
- firmware_init();
- hypervisor_init();
- /* These are also core pieces, but must come after the
- * core core pieces.
- */
- platform_bus_init();
- system_bus_init();
- cpu_dev_init();
- memory_dev_init();
- }
上面主要是创建文件系统中的一些目录,其中我们主要关心buses_init
- int __init buses_init(void)
- {
- bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
- if (!bus_kset)
- return -ENOMEM;
- return 0;
- }
上面只是创建/bus/bus目录,这是一个kset类型,使用了bus_uevent_ops的uevent操作类型。
下面来看看总线的注册函数
- int bus_register(struct bus_type *bus)
- {
- int retval;
- struct subsys_private *priv;
- priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);//分配一个结构体
- if (!priv)
- return -ENOMEM;
- priv->bus = bus; //指向该bus
- bus->p = priv;
- BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
- retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//bus的名字为bus->name
- if (retval)
- goto out;
- priv->subsys.kobj.kset = bus_kset; //所属的kset使用bus_kset
- priv->subsys.kobj.ktype = &bus_ktype; //类型使用bus_ktype
- priv->drivers_autoprobe = 1;
- retval = kset_register(&priv->subsys);//将bus加入到sysfs中
- if (retval)
- goto out;
- retval = bus_create_file(bus, &bus_attr_uevent);//创建bus下的属性文件
- if (retval)
- goto bus_uevent_fail;
- priv->devices_kset = kset_create_and_add("devices", NULL,
- &priv->subsys.kobj); //创建devices目录
- if (!priv->devices_kset) {
- retval = -ENOMEM;
- goto bus_devices_fail;
- }
- priv->drivers_kset = kset_create_and_add("drivers", NULL,
- &priv->subsys.kobj);//创建drivers目录
- if (!priv->drivers_kset) {
- retval = -ENOMEM;
- goto bus_drivers_fail;
- }
- klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
- klist_init(&priv->klist_drivers, NULL, NULL);
- retval = add_probe_files(bus);
- if (retval)
- goto bus_probe_files_fail;
- retval = bus_add_attrs(bus);
- if (retval)
- goto bus_attrs_fail;
- pr_debug("bus: '%s': registered\n", bus->name);
- return 0;
- bus_attrs_fail:
- remove_probe_files(bus);
- bus_probe_files_fail:
- kset_unregister(bus->p->drivers_kset);
- bus_drivers_fail:
- kset_unregister(bus->p->devices_kset);
- bus_devices_fail:
- bus_remove_file(bus, &bus_attr_uevent);
- bus_uevent_fail:
- kset_unregister(&bus->p->subsys);
- out:
- kfree(bus->p);
- bus->p = NULL;
- return retval;
- }
调用kset_register(),在上一编中分析过,这个函数主要是在/sys/bus目录,并向用户空间上报。klist_devices_get()用于bus设备链表上添加节点时增加对相应设备的引用。
- int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
- {
- int error;
- if (bus_get(bus)) {
- error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
- bus_put(bus);
- } else
- error = -EINVAL;
- return error;
- }
这个主要是在bus目录下创建属性文件。klist_devices_put()用于bus设备链表上删去节点时减少对相应设备的引用。
- static void klist_devices_get(struct klist_node *n)
- {
- struct device_private *dev_prv = to_device_private_bus(n);
- struct device *dev = dev_prv->device;
- get_device(dev);
- }
- static void klist_devices_put(struct klist_node *n)
- {
- struct device_private *dev_prv = to_device_private_bus(n);
- struct device *dev = dev_prv->device;
- put_device(dev);
- }
- static int add_probe_files(struct bus_type *bus)
- {
- int retval;
- retval = bus_create_file(bus, &bus_attr_drivers_probe);
- if (retval)
- goto out;
- retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
- if (retval)
- bus_remove_file(bus, &bus_attr_drivers_probe);
- out:
- return retval;
- }
add_probe_files()在bus目录下添加drivers_probe和drivers_autoprobe文件,bus_add_attrs()添加结构体中的属性。有上面可以看出,bus_register完成一些初始化,添加到sysfs中,添加相关的子目录和属性文件。
- static char *Version = "$Revision: 1.0 $";
- static int my_match(struct device *dev, struct device_driver *driver)
- {
- return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
- }
- struct bus_type my_bus_type = {
- .name = "my_bus",
- .match = my_match,
- };
- static ssize_t show_bus_version(struct bus_type *bus, char *buf)
- {
- return snprintf(buf, PAGE_SIZE, "%s\n", Version);
- }
- static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
- static int __init my_bus_init(void)
- {
- int ret;
-
- /*注册总线*/
- ret = bus_register(&my_bus_type);
- if (ret)
- return ret;
-
- /*创建属性文件*/
- if (bus_create_file(&my_bus_type, &bus_attr_version))
- printk(KERN_NOTICE "Fail to create version attribute!\n");
-
- return ret;
- }
- static void my_bus_exit(void)
- {
- bus_unregister(&my_bus_type);
- }
- module_init(my_bus_init);
- module_exit(my_bus_exit);
阅读(716) | 评论(0) | 转发(0) |