linux文件系统的系统分析--(十一)sysfs和设备模型--Bus
时间:2016-02-22 13:08 来源:linux.it.net.cn 作者:IT
在分析设备模型的bus之前,我们看一下初始化的过程,很有意思:
start_kernel-->rest_init-->kernel_init-->do_basic_setup
在do_basic_setup中有个usermodehelper_init有意思,凭感觉,这个函数与kobject_uevent有联系,kobject_uevent做什么的,就是内核空间来通知用户空间的,比如udev就是利用这个来在/dev创建设备文件的,再比如在嵌入式中,插拔个硬盘或者USB,gui总会提示插入或者拨出之类的提示,这个一般是内核中驱动模型根据kobject的uevent来告诉用户态的,如果通信的,是通过netlink这种特殊的socket来像用户空间广播的,这样gui中可以用socket来接受信息,并解析,然后显示出来。先提到这里,usermodehelper_init是不是这么回事,还需要更多的时间去研究。
好,继续看do_basic_setup中的其它函数:driver_init
-
/**
-
* driver_init - initialize driver model.
-
*
-
* Call the driver model init functions to initialize their
-
* subsystems. Called early from init/main.c.
-
*/
-
void __init driver_init(void)
-
{
-
/* These are the core pieces */
-
devtmpfs_init();
-
devices_init();
-
buses_init();
-
classes_init();
-
firmware_init();
-
hypervisor_init();
-
-
/* These are also core pieces, but must come after the
-
* core core pieces.
-
*/
-
platform_bus_init();
-
system_bus_init();
-
cpu_dev_init();
-
memory_dev_init();
-
}
看下这个函数的注释,就清楚它就是接下来要分析的设备模型 的初始化。
devtmpfs_init是什么?是在/dev下面挂载的一个内存文件系统,具体可以看《linux设备模型之字符设备》一文,与驱动是有一定联系,应该是2.6.32之后加入的。
今天我们只分析core core pieces中的buses_init:
-
int __init buses_init(void)
-
{
-
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
-
if (!bus_kset)
-
return -ENOMEM;
-
return 0;
-
}
很简单,新增一个kset,在/sys下有了bus目录。
我们的重心在后面,如何在bus目录下添加总线类型:
描述总线的结构体:bus_type
-
struct bus_type {
-
const char *name; //总线的名称
-
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, struct kobj_uevent_env *env); //添加或移除设备时,该函数向用户空间产生环境变量
-
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); //总线的电源管理操作
-
-
const struct dev_pm_ops *pm;
-
-
struct bus_type_private *p; //总线的私有变量指针
-
};
与bus_type紧密相关的结构体:struct bus_type_private
-
struct bus_type_private {
-
struct kset subsys; //具体总线的kset
-
struct kset *drivers_kset; //总线上所有驱动的集合
-
struct kset *devices_kset; //总线上所有设备的集合
-
struct klist klist_devices; //链表,上面是总线上的设备
-
struct klist klist_drivers; //链表,上面是总线上的驱动
-
struct blocking_notifier_head bus_notifier;
-
unsigned int drivers_autoprobe:1;
-
struct bus_type *bus; //指向总线类型结构体
-
};
总线的注册:bus_register
-
/**
-
* bus_register - register a bus with the system.
-
* @bus: bus.
-
*
-
* Once we have that, we registered the bus with the kobject
-
* infrastructure, then register the children subsystems it has:
-
* the devices and drivers that belong to the bus.
-
*/
-
int bus_register(struct bus_type *bus)
-
{
-
int retval;
-
struct bus_type_private *priv;
-
-
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
-
if (!priv)
-
return -ENOMEM;
-
-
priv->bus = bus;
-
bus->p = priv; //bus_type和bus_type_private紧密联系起来
-
-
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
-
-
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置具体总线kset内嵌kobject的名称
-
if (retval)
-
goto out;
-
-
priv->subsys.kobj.kset = bus_kset; //总线kset内嵌kobject的kset指向bus_kset,也就是说上级目录是/sys/bus
-
priv->subsys.kobj.ktype = &bus_ktype;
-
priv->drivers_autoprobe = 1;
-
-
retval = kset_register(&priv->subsys); //注册总线的kset,生成/sys/bus/xxbus 目录
-
if (retval)
-
goto out;
-
-
retval = bus_create_file(bus, &bus_attr_uevent); //创建uevent目录,只写的文件,写文件会调用kobject_uevent函数
-
if (retval)
-
goto bus_uevent_fail;
-
-
priv->devices_kset = kset_create_and_add("devices", NULL, //在xxbus目录下建立devices目录
-
&priv->subsys.kobj);
-
if (!priv->devices_kset) {
-
retval = -ENOMEM;
-
goto bus_devices_fail;
-
}
-
-
priv->drivers_kset = kset_create_and_add("drivers", NULL, //在xxbus目录下建立drivers目录
-
&priv->subsys.kobj);
-
if (!priv->drivers_kset) {
-
retval = -ENOMEM;
-
goto bus_drivers_fail;
-
}
-
-
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化klist_devices链表
-
klist_init(&priv->klist_drivers, NULL, NULL); //初始化klist_drivers链表
-
-
retval = add_probe_files(bus); //在xxbus目录下建立drivers_probe和drivers_autoprobe文件
-
if (retval)
-
goto bus_probe_files_fail;
-
-
retval = bus_add_attrs(bus); //建立bus的总线属性文件
-
if (retval)
-
goto bus_attrs_fail;
-
-
pr_debug("bus: '%s': registered\n", bus->name);
-
return 0;
-
-
bus_attrs_fail:
-
remove_probe_files(bus);
-
bus_probe_files_fail:
-
kset_unregister(bus->p->drivers_kset);
-
bus_drivers_fail:
-
kset_unregister(bus->p->devices_kset);
-
bus_devices_fail:
-
bus_remove_file(bus, &bus_attr_uevent);
-
bus_uevent_fail:
-
kset_unregister(&bus->p->subsys);
-
kfree(bus->p);
-
out:
-
bus->p = NULL;
-
return retval;
-
}
总线的注册方法就是上面这么多,比如platform总线的注册,就是在/sys/bus目录下多了个platform目录,而在platform目录下:
devices drivers drivers_autoprobe drivers_probe uevent
总线远没有目前看到的这么简单,因为它的方法我们还没用到。在分析完设备和驱动后,我们再分析一个完整的过程。
(责任编辑:IT)
在分析设备模型的bus之前,我们看一下初始化的过程,很有意思: start_kernel-->rest_init-->kernel_init-->do_basic_setup 在do_basic_setup中有个usermodehelper_init有意思,凭感觉,这个函数与kobject_uevent有联系,kobject_uevent做什么的,就是内核空间来通知用户空间的,比如udev就是利用这个来在/dev创建设备文件的,再比如在嵌入式中,插拔个硬盘或者USB,gui总会提示插入或者拨出之类的提示,这个一般是内核中驱动模型根据kobject的uevent来告诉用户态的,如果通信的,是通过netlink这种特殊的socket来像用户空间广播的,这样gui中可以用socket来接受信息,并解析,然后显示出来。先提到这里,usermodehelper_init是不是这么回事,还需要更多的时间去研究。 好,继续看do_basic_setup中的其它函数:driver_init
devtmpfs_init是什么?是在/dev下面挂载的一个内存文件系统,具体可以看《linux设备模型之字符设备》一文,与驱动是有一定联系,应该是2.6.32之后加入的。 今天我们只分析core core pieces中的buses_init:
我们的重心在后面,如何在bus目录下添加总线类型: 描述总线的结构体:bus_type
devices drivers drivers_autoprobe drivers_probe uevent 总线远没有目前看到的这么简单,因为它的方法我们还没用到。在分析完设备和驱动后,我们再分析一个完整的过程。 (责任编辑:IT) |