总线是处理器与设备之间的通道,在设备模型中,所有的设备都是通过总线相连的。在设备模型中,总线由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);