接下来我们从例子着手
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的代码
688 int bus_register(struct bus_type * bus) 689 { 690 int retval; 691 692 retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); 693 if (retval) 694 goto out; 695 696 subsys_set_kset(bus, bus_subsys); 697 retval = subsystem_register(&bus->subsys); 698 if (retval) 699 goto out; 700 701 kobject_set_name(&bus->devices.kobj, "devices"); 702 bus->devices.subsys = &bus->subsys; 703 retval = kset_register(&bus->devices); 704 if (retval) 705 goto bus_devices_fail; 706 707 kobject_set_name(&bus->drivers.kobj, "drivers"); 708 bus->drivers.subsys = &bus->subsys; 709 bus->drivers.ktype = &ktype_driver; 710 retval = kset_register(&bus->drivers); 711 if (retval) 712 goto bus_drivers_fail; 713 bus_add_attrs(bus); 714 715 pr_debug("bus type '%s' registered/n", bus->name); 716 return 0; 717 718 bus_drivers_fail: 719 kset_unregister(&bus->devices); 720 bus_devices_fail: 721 subsystem_unregister(&bus->subsys); 722 out: 723 return retval; 724 }
692-700是对bus->subsys的操作。701-705是操作bus->devices。706-710是操作bus->drivers。
692 kobject_set_name()设置bus->subsys.kset.kobj的名字。此函数很简单,就是调用vsnprintf()。此不列出。
696 subsys_set_kset(bus, bus subsys)
#define subsys_set_kset(obj,_subsys) (obj)->subsys.kset.kobj.kset = &(_subsys).kset
我们先看看bus_subsys的定义,它是一个subsystem类型的全局变量。在driver/base/bus.c中,decl subsys(bus, &ktype bus, NULL); 在/include/linux/kobject.h中有,decl subsys的原型,
#define decl_subsys(_name,_type,_hotplug_ops) / struct subsystem _name##_subsys = { / .kset = { / .kobj = { .name = __stringify(_name) }, / .ktype = _type, / .hotplug_ops =_hotplug_ops, / } / } 就相当于 struct subsystem bus_subsys = { / .kset = { / .kobj = { .name = “bus” }, / .ktype = ktype_bus, / .hotplug_ops =NULL, / } / }
其中ktype bus定义如下,
static struct kobj_type ktype_bus = { .sysfs_ops = &bus_sysfs_ops, };
697 subsystem_register(&bus->subsys)作用是向全局的bus_subsys”登记”, 把自己加入到bus_subsys的链表中去。
subsystem_register() -> kset_add() -> kobject_add()
155 int kobject_add(struct kobject * kobj) 156 { 157 int error = 0; 158 struct kobject * parent; 159 160 if (!(kobj = kobject_get(kobj))) 161 return -ENOENT; 162 if (!kobj->k_name) 163 kobj->k_name = kobj->name; 164 parent = kobject_get(kobj->parent); 165 166 pr_debug("kobject %s: registering. parent: %s, set: %s/n", 167 kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", 168 kobj->kset ? kobj->kset->kobj.name : "<NULL>" ); 169 170 if (kobj->kset) { 171 down_write(&kobj->kset->subsys->rwsem); 172 173 if (!parent) 174 parent = kobject_get(&kobj->kset->kobj); 175 176 list_add_tail(&kobj->entry,&kobj->kset->list); 177 up_write(&kobj->kset->subsys->rwsem); 178 } 179 kobj->parent = parent; 180 181 error = create_dir(kobj); 182 if (error) { 183 /* unlink does the kobject_put() for us */ 184 unlink(kobj); 185 if (parent) 186 kobject_put(parent); 187 } else { 188 kobject_hotplug(kobj, KOBJ_ADD); 189 } 190 191 return error; 192 }
代码的170-178就是把自己连入到父辈上级kset中。我们注意到在kobject_add()函数中181行调用了create_dir(kobj),这个函数作用是在sysfs下创建一个文件夹。可见kobject和sysfs是同时更新的。
kset_register(&bus->devices) 和kset_register(&bus->drivers)作用类似,把bus->devices这个kset加入到bus->subsys这个subsystem中去。最后形成如下的层次结构
同理,我们可以看看device_register()的代码,它也是向devices_subsys这个subsystem注册,最后形成这样的结构与上图类似。
目前为止,我们知道了所谓的xx_register函数,就是通过其内嵌的kobject链入对应的subsystem,或是kset的层次结构中去。这样就可以通过一些全局的变量找到它们了。
转自:http://blog.csdn.net/fudan_abc/article/details/1768384