歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

Linux那些事兒之我是Sysfs(4)舉例一lddbus

對了,你得把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中, 定義了一個總線和硬件類型

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中去。最後形成圖1的層次結構。

圖1:lddbus kobject層次結構

同理,我們可以看看device_register()的代碼,它也是向devices_subsys這個subsystem注冊,最後形成這樣的結構與圖1類似。

目前為止,我們知道了所謂的xx_register函數,就是通過其內嵌的kobject鏈入對應的subsystem,或是kset的層次結構中去。這樣就可以通過一些全局的變量找到它們了。

Copyright © Linux教程網 All Rights Reserved