为了阐明表示总线、设备和设备驱动程序的各个数据结构之间彼此的关联,它们的注册过程是很有必要的。顺序一定是如下:(1)注册总线---bus_register;(2)注册设备device_register;(3)注册设备驱动程序----bus_add_driver。
下文摘自:点击打开链接
我该怎么样来形容这个图呢? 它把依赖关系说的已经足够清楚了!!我这里唯一要解释的仅仅是在驱动文件夹被正确后所谓的文件属性有在那里。同样我们顺着目录 /sys/bus/sdio/driver/wlan_sdio/ 下我们发现了 bind 、unbind 和 new_id 三个文件。
好了,别忘了我们在前面提过的问题,kset 是如何扮演容器的角色的呢?图中很清楚吧,看看粉红色的箭头,kset children list用来将将同类型的kobject连接起来以达到容器的效果。
但是我们的驱动还没有结束,关于这个图的建立,我们势必要用代码才能说得明白。
我们还是花费一点时间来看一下内核中的代码,关于 sdio 总线注册的代码部分,其它的部分,大家类举就可以了。懂了这段自然就懂了全部:
int bus_register( struct bus_type * bus)
{
int retval;
BLOCKING_INIT_NOTIFIER_HEAD (&bus->bus_notifier);
retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); // 总线的名字 ”sdio”, 我们说过了一个 kobject对应一个目录,这时会为这个目录赋值名字。
if (retval)
goto out;
bus->subsys.kobj.kset = &bus_subsys; // 将其 kset 指向 bus_subsys., 如何理解? 看看ldd_bus_type 指向 bus_subsys 的那条蓝线
retval = subsystem_register(&bus->subsys); //bus->subsys 的注册,实际上是用 kset 指针将其链接在一起。好吧 我得承认实际上这里取消了 subsysem 结构的概念,用 kset 代替了。这里会创建一个目录。它是一个 kset 也是一个 kobject,因为 kset 包含了 kobject 。
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent); // 创建属性文件
if (retval)
goto bus_uevent_fail;
kobject_set_name(&bus->devices.kobj, "devices"); // 设置 devices kset 的名字为 devices
bus->devices.kobj.parent = &bus->subsys.kobj; // 参见 ldd_bus_type->devices 指向 ldd_bus_type->sub_sys的红色箭头(注意这里也不是 subsystem, 而是 kset )
retval = kset_register(&bus->devices); // 创建 devices 命名的目录
if (retval)
goto bus_devices_fail;
kobject_set_name(&bus->drivers.kobj, "drivers"); // 设置 devices kset 的名字为 drivers
bus->drivers.kobj.parent = &bus->subsys.kobj; // 同样参见 ldd_bus_type->drivers 指向 ldd_bus_type->sub_sys的红色箭头(注意这里也不是 subsystem, 而是 kset )。
bus->drivers.ktype = &driver_ktype; // 对 kobject 默认属性的赋值
retval = kset_register(&bus->drivers); // 创建 drivers 命名的目录
if (retval)
goto bus_drivers_fail;
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); //klist 结构的初始化,关于 klist 链接的作用我们已经说得很清楚了
klist_init(&bus->klist_drivers, NULL, NULL);
bus->drivers_autoprobe = 1;
retval = add_probe_files(bus); // 添加探测属性
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus); // 添加其他属性
if (retval)
goto bus_attrs_fail;
pr_debug("bus type '%s' registered/n", bus->name);
return 0;
bus_attrs_fail :
remove_probe_files(bus);
bus_probe_files_fail :
kset_unregister(&bus->drivers);
bus_drivers_fail :
kset_unregister(&bus->devices);
bus_devices_fail :
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail :
subsystem_unregister(&bus->subsys);
out :
return retval;
}
至此 我们终于理顺了整个过程。