总线是处理器与设备之间的通道,在设备模型中,所有的设备都是通过总线相连的。在设备模型中,总线由bus_type表示
struct bus_type { const char *name; const char *dev_name; struct device *dev_root; struct device_attribute *dev_attrs; /* use dev_groups instead */ const struct attribute_group **bus_groups; const struct attribute_group **dev_groups; const struct attribute_group **drv_groups; int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*online)(struct device *dev); int (*offline)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; const struct iommu_ops *iommu_ops; struct subsys_private *p; struct lock_class_key lock_key; }; name:总线的名称device_attrs:设备的属性match:匹配函数,用于在driver和device做适配,为设备找驱动,为驱动找设备uevent:用于总线对uevent环境变量的添加probe:探针函数,当device和driver配对成功以后,总线的probe或者driver的probe有一个会被调用remove:总线上有驱动或者设备移除时调用shutdown:在总线上所有设备都关闭时调用resume:处理热插拔,电源管理在最后有指向subsys_private的指针,定义了将于总线同其他类型联系起来的关系,将总线同设备,驱动程序,sysfs联系起来,这里不再展开描述。
在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(); cpu_dev_init(); memory_dev_init(); container_dev_init(); of_core_init(); }我们主要关心buses_init()
int __init buses_init(void) { /*创建sys 下bus目录*/ bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); if (!bus_kset) return -ENOMEM; system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); if (!system_kset) return -ENOMEM; return 0; }用于在/sys目录下创建bus目录以及在/sys/devices/下创建system目录。接着看下总线注册函数:
int bus_register(struct bus_type *bus) { int retval; struct subsys_private *priv; struct lock_class_key *key = &bus->lock_key; /*分配资源*/ priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); if (!priv) return -ENOMEM; priv->bus = bus; bus->p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); /*赋值总线的名字*/ retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); if (retval) goto out; priv->subsys.kobj.kset = bus_kset; priv->subsys.kobj.ktype = &bus_ktype; priv->drivers_autoprobe = 1; /*总线注册到/sys/bus下*/ retval = kset_register(&priv->subsys); if (retval) goto out; retval = bus_create_file(bus, &bus_attr_uevent); if (retval) goto bus_uevent_fail; /*创建总线下的设备目录*/ priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj); if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } /*创建总线下的驱动目录*/ priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj); if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; } INIT_LIST_HEAD(&priv->interfaces); __mutex_init(&priv->mutex, "subsys mutex", key); klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL); /*创建bus目录下对应总线下的drivers_autoprobe,drivers_probe文件*/ retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; retval = bus_add_groups(bus, bus->bus_groups); if (retval) goto bus_groups_fail; pr_debug("bus: '%s': registered\n", bus->name); return 0; bus_groups_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; }第7-12行:分配subsys_private空间,并进行bus->p的初始化
第16-24行:初始化总线的名称,并在/sys/bus下创建总线的目录。
第28行:在对应总线下,创建uevent目录
第32-39行:在对应总线下,创建devices和driver目录
第52行:在对应总线目录下,创建drivers_probe,drivers_autoprobe 目录。
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; }下面看一个例子:
static char * Version = “ $ Revision:1.0 $” ; staic int my_match (struct device* dev ,struct device_driver *driver) { return !strncpm (dev-> bus_id ,driver->name, strlen(driver->name)); } struct bus_type my_bus_type = { .name = “ my_bus” , .macth = 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 “无法创建版本属性!\ n” ); return ret ; } static void my_bus_exit(void) { bus_unregister(&my_bus_type); } module_init( my_bus_init); module_exit(my_bus_exit);