Linux那些事儿之我是Sysfs(4)举例一lddbus
2015-03-19 16:45
211 查看
对了,你得把ldd3的examples代码下下来。不然没法继续了。
接下来我们从例子着手,
localhost:/home/XX/examples/lddbus#insmod lddbus.ko
此时再看/sys/bus/ 这时就多了一个文件夹ldd。里面的文件构成是这样的
/sys/bus/ldd/
|--device
|--driver
`--version
localhost:/sys/bus/ldd#cat version
$Revision: 1.9$
这表示系统中多了一种名叫ldd的总线类型。同时再看/sys/device/,也多出来一个ldd0的文件夹。这表示系统中多了一个名叫ldd0的硬件。
在lddbus.c中, 定义了一个总线和硬件类型
lddbus模块初始化时调用这个函数
其实就是调用了两个注册函数,bus_register(), device_register()。bus_create_file()是在sysfs下创建一个文件夹。
bus_register(),向系统注册ldd_bus_type这个总线类型。bus_create_file()这个就是向sysfs中创建一个文件。device_register()系统注册ldd_bus这个硬件类型。
注册好了之后,我们就可以在sysfs下看到相应的信息。
我们深入下去,仔细看看bus_register的代码。
drivers/base/bus.c
kobject_set_name()设置kobj的名字。此函数很简单,就是调用vsnprintf()。此不列出。
kset_register(&priv->subsys)作用是向全局的bus_subsys”登记”, 把自己加入到bus_subsys的链表中去。
kset_register()——>kobject_add_internal()
lib/kobject.c
代码的18-23行就是把自己连入到父辈上级kset中。我们注意到在kobject_add()函数中30行调用了create_dir(kobj),这个函数作用是在sysfs下创建一个文件夹。可见kobject和sysfs是同时更新的。
接下来我们从例子着手,
localhost:/home/XX/examples/lddbus#insmod lddbus.ko
此时再看/sys/bus/ 这时就多了一个文件夹ldd。里面的文件构成是这样的
/sys/bus/ldd/
|--device
|--driver
`--version
localhost:/sys/bus/ldd#cat version
$Revision: 1.9$
这表示系统中多了一种名叫ldd的总线类型。同时再看/sys/device/,也多出来一个ldd0的文件夹。这表示系统中多了一个名叫ldd0的硬件。
在lddbus.c中, 定义了一个总线和硬件类型
struct bus_type ldd_bus_type = { .name = "ldd", .match = ldd_match, .hotplug = ldd_hotplug, }; struct device ldd_bus = { .bus_id = "ldd0", .release = ldd_bus_release };
lddbus模块初始化时调用这个函数
static int __init ldd_bus_init(void) { int ret; ret = bus_register(&ldd_bus_type); if (ret) return ret; if (bus_create_file(&ldd_bus_type, &bus_attr_version)) printk(KERN_NOTICE "Unable to create version attribute/n"); ret = device_register(&ldd_bus); if (ret) printk(KERN_NOTICE "Unable to register ldd0/n"); return ret; }
其实就是调用了两个注册函数,bus_register(), device_register()。bus_create_file()是在sysfs下创建一个文件夹。
bus_register(),向系统注册ldd_bus_type这个总线类型。bus_create_file()这个就是向sysfs中创建一个文件。device_register()系统注册ldd_bus这个硬件类型。
注册好了之后,我们就可以在sysfs下看到相应的信息。
我们深入下去,仔细看看bus_register的代码。
drivers/base/bus.c
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; 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); 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; }
kobject_set_name()设置kobj的名字。此函数很简单,就是调用vsnprintf()。此不列出。
kset_register(&priv->subsys)作用是向全局的bus_subsys”登记”, 把自己加入到bus_subsys的链表中去。
kset_register()——>kobject_add_internal()
lib/kobject.c
static int kobject_add_internal(struct kobject *kobj) { int error = 0; struct kobject *parent; if (!kobj) return -ENOENT; if (!kobj->name || !kobj->name[0]) { WARN(1, "kobject: (%p): attempted to be registered with empty " "name!\n", kobj); return -EINVAL; } parent = kobject_get(kobj->parent); /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { if (!parent) parent = kobject_get(&kobj->kset->kobj); kobj_kset_join(kobj); kobj->parent = parent; } pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", kobject_name(kobj), kobj, __func__, parent ? kobject_name(parent) : "<NULL>", kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>"); error = create_dir(kobj); if (error) { kobj_kset_leave(kobj); kobject_put(parent); kobj->parent = NULL; /* be noisy on error issues */ if (error == -EEXIST) WARN(1, "%s failed for %s with " "-EEXIST, don't try to register things with " "the same name in the same directory.\n", __func__, kobject_name(kobj)); else WARN(1, "%s failed for %s (error: %d parent: %s)\n", __func__, kobject_name(kobj), error, parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1; return error; }
代码的18-23行就是把自己连入到父辈上级kset中。我们注意到在kobject_add()函数中30行调用了create_dir(kobj),这个函数作用是在sysfs下创建一个文件夹。可见kobject和sysfs是同时更新的。
相关文章推荐
- 【转】Linux那些事儿之我是Sysfs(4)举例一lddbus
- Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容
- Linux那些事儿之我是Sysfs(4)举例一lddbus
- Linux那些事儿之我是Sysfs(5)举例二sculld
- 【转】Linux那些事儿之我是Sysfs(13)举例四:sysfs读入普通文件内容
- Linux那些事儿之我是Sysfs(5)举例二sculld
- 【转】Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容
- Linux那些事儿之我是Sysfs(13)举例四:sysfs读入普通文件内容
- Linux那些事儿之我是Sysfs(4)举例一lddbus
- 【转】Linux那些事儿之我是Sysfs(5)举例二sculld
- Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容
- Linux那些事儿之我是Sysfs(13)举例四:sysfs读入普通文件内容
- Linux那些事儿之我是Sysfs--12-(opendir,readdir系统调用流程)
- Linux那些事儿之我是Sysfs(8)一起散散步-pathwalk
- Linux那些事儿之我是Sysfs(7)dentry与inode
- 【转】Linux那些事儿之我是Sysfs(6)文件系统
- Linux那些事儿之我是Sysfs(7)dentry与inode
- 【转】Linux那些事儿之我是Sysfs(7)dentry与inode
- Linux那些事儿之我是Sysfs(11)sysfs 创建普通文件
- 【转】Linux那些事儿之我是Sysfs(8)一起散散步-pathwalk