kobject结构和sys文件系统联系紧密,在sysfs创建文件时,传递的输入参数就是一个kobject。实际上可以认为kobject代表sysfs文件系统的一个目录。
4.1.1 kobject和kset的关系
struct kobject {
____const char______* k_name;
____char____________name[KOBJ_NAME_LEN];
____struct kref_____kref;
____struct list_head____entry;
____struct kobject______* parent;
____struct kset_____* kset;
____struct kobj_type____* ktype;
____struct dentry_______* dentry;
____wait_queue_head_t___poll;
};
struct kset {
____struct subsystem____* subsys;
____struct kobj_type____* ktype;
____struct list_head____list;
____spinlock_t______list_lock;
____struct kobject______kobj;
____struct kset_uevent_ops__* uevent_ops;
};
kset结构里封装了一个kobject(kobj),同时包括一个链表头(list),属于这个kset的所有kobject都要链接到kset的链表头。
4.4.2 kobject实例:总线的注册
总线的注册使用bus_register实现。
以下是platform总线的注册。
int __init platform_bus_init(void)
{
____device_register(&platform_bus);
____return bus_register(&platform_bus_type);
}
device_register:设备注册函数。
bus_register:总线注册函数,作用是把总线注册到内核。
bus对象内含两个kset,一个是devices,另一个是drivers,而bus本身是一个subsystem,这个结构只比kset多了一个信号量。
struct bus_type {
____const char______* name;
____struct subsystem____subsys;
____struct kset_____drivers;
____struct kset_____devices;
____struct klist________klist_devices;
____struct klist________klist_drivers;
____struct bus_attribute____* bus_attrs;
____struct device_attribute_* dev_attrs;
____struct driver_attribute_* drv_attrs;
____int_____(*match)(struct device * dev, struct device_driver * drv);
____int_____(*uevent)(struct device *dev, char **envp,
________________ int num_envp, char *buffer, int buffer_size);
____int_____(*probe)(struct device * dev);
____int_____(*remove)(struct device * dev);
____void________(*shutdown)(struct device * dev);
____int_____(*suspend)(struct device * dev, pm_message_t state);
____int_____(*resume)(struct device * dev);
};
struct subsystem {
____struct kset_____kset;
____struct rw_semaphore_rwsem;
};
以下是bus的注册函数:
int bus_register(struct bus_type * bus)
{
____int retval;
____retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
____if (retval)
________goto out;
____subsys_set_kset(bus, bus_subsys);
____retval = subsystem_register(&bus->subsys);
____if (retval)
________goto out;
____kobject_set_name(&bus->devices.kobj, "devices");
____bus->devices.subsys = &bus->subsys;
____retval = kset_register(&bus->devices);
____if (retval)
________goto bus_devices_fail;
____kobject_set_name(&bus->drivers.kobj, "drivers");
____bus->drivers.subsys = &bus->subsys;
____bus->drivers.ktype = &ktype_driver;
____retval = kset_register(&bus->drivers);
____if (retval)
________goto bus_drivers_fail;
____klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
____klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);
____bus_add_attrs(bus);
____pr_debug("bus type '%s' registered\n", bus->name);
____return 0;
bus_drivers_fail:
____kset_unregister(&bus->devices);
bus_devices_fail:
____subsystem_unregister(&bus->subsys);
out:
____return retval;
}
从bus_register()中,可以看到,大体流程是:
1)kobject_set_name设置bus的名字,subsystem_register注册总线子系统。
2)kobject_set_name设置devices的名字,kset_register注册设备,生成devices目录。
3)kobject_set_name设置drivers的名字,kset_register注册设备,生成drivers目录。
subsystem_register
->subsystem_init
->init_rwsem(&s->rwsem);
->kset_init(&s->kset);
->kset_add->kobject_add->create_dir(kobj)->sysfs_create_dir(kobj) /* 创建一个目录文件 */
->populate_dir(kobj) /* 根据kobj下的default_attrs,创建文件 */
kset_register
->kset_init
->kset_add
kset_register和subsystem_register的区别在于,subsystem在初始化过程中,多一个rwsem的初始化。
总结:通过以上的分析,bus_register实际上创建devices和drivers目录及目录下的attribute文件。这些目录和文件共同展示了一条总线和总线下的设备及驱动的属性信息。