现在的位置: 首页 > 技术文章 > 正文

Linux那些事儿之我是Sysfs(4)举例一lddbus

2014年06月19日 技术文章 ⁄ 共 4730字 ⁄ 字号 Linux那些事儿之我是Sysfs(4)举例一lddbus已关闭评论 ⁄ 阅读 1,726 次

接下来我们从例子着手

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中去。最后形成如下的层次结构

lddbus kobject层次结构

lddbus kobject层次结构

同理,我们可以看看device_register()的代码,它也是向devices_subsys这个subsystem注册,最后形成这样的结构与上图类似。

目前为止,我们知道了所谓的xx_register函数,就是通过其内嵌的kobject链入对应的subsystem,或是kset的层次结构中去。这样就可以通过一些全局的变量找到它们了。

转自:http://blog.csdn.net/fudan_abc/article/details/1768384

×