前面即便文章讲述了基本的数据结构和操作函数,这篇文章将从系统启动开始简述整个驱动子系统的构建过程。
从系统加电开始,首先是一系列初始化过程,这些过程一般由汇编语言代码完成,在成功初始化一些必要的设备之后,程序会执行第一个C函数start_kernel。为了找个驱动子系统的构建过程,需要沿着start_kernel的函数调用顺序差下去,start_kernel()-->rest_init(),在rest_init中启动了一个内核线程,该线程执行函数kernel_init。从kernel_init一路差下去,我们又要经过do_basic_setup,终于发现了driver_init()这个目标。
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();
}
|
这就是整个驱动子系统构建的初始过程,当然在这个过程之中只是构建一个大的框架,并没有什么真正的设备可以运行。接下来我们挨个看看这些函数。
1、devtmpfs_init()
这一部主要是构建一个临时的/dev文件系统,主要是VFS的内容,此处不述。
2、devices_init()
int
__init devices_init(
void
)
{
devices_kset = kset_create_and_add(
"devices"
, &device_uevent_ops, NULL);
if
(!devices_kset)
return
-ENOMEM;
dev_kobj = kobject_create_and_add(
"dev"
, NULL);
if
(!dev_kobj)
goto
dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add(
"block"
, dev_kobj);
if
(!sysfs_dev_block_kobj)
goto
block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add(
"char"
, dev_kobj);
if
(!sysfs_dev_char_kobj)
goto
char_kobj_err;
return
0;
char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return
-ENOMEM;
}
|
这里创建了三个kobject和一个kset,其中devices_kset和dev_kobj是两个顶级节点,在sysfs文件系统中(一般是目录/sys)尤其对应的两个目录:/sys/devices和/sys/dev,而sysfs_dev_block_kobj和sysfs_dev_char_kobj则是dev_kobj的两个子节点,对应于目录/sys/dev/char和/sys/dev/char。
3、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--bus_kset,这也是一个顶级节点,对应于目录/sys/bus。
4、classes_init
int
__init classes_init(
void
)
{
class_kset = kset_create_and_add(
"class"
, NULL, NULL);
if
(!class_kset)
return
-ENOMEM;
return
0;
}
|
这里创建了一个kset--class_kset,这也是一个顶级节点,对应于目录/sys/class。
5、firmware_init
int
__init firmware_init(
void
)
{
firmware_kobj = kobject_create_and_add(
"firmware"
, NULL);
if
(!firmware_kobj)
return
-ENOMEM;
return
0;
}
|
这里创建了一个kobject--firmware_kobj,这也是一个顶级节点,对应于目录/sys/firmware。
6、hypervisor_init
int
__init hypervisor_init(
void
)<br>{<br> hypervisor_kobj = kobject_create_and_add(
"hypervisor"
, NULL);<br>
if
(!hypervisor_kobj)<br>
return
-ENOMEM;<br>
return
0;<br>}
|
这里创建了一个kobject--hypervisor_kobj,这也是一个顶级节点,对应于目录/sys/firmware。
以此为界限,下面的几个函数不再是简单创建几个顶级节点这么简单。
7、platform_bus_init
int
__init platform_bus_init(
void
)<br>{<br>
int
error;<br><br> early_platform_cleanup();<br><br> error = device_register(&platform_bus);<br>
if
(error)<br>
return
error;<br> error = bus_register(&platform_bus_type);<br>
if
(error)<br> device_unregister(&platform_bus);<br>
return
error;<br>}
|
在2.6版本的内核中引入了一种虚拟的总线类型--platform bus。它并不对应真实的总线。在该函数中,首先调用一个函数early_platform_cleanup(),我猜是对启动过程中的数据进行清理,然后会注册一个名为“platform”的设备,这个设备会作为所有platform设备的父节点。在struct device中有一个parent成员就是会了完成这种父子关系的构建。
除了注册一个名为“platform”的设备之外,还会注册一个同样名称的总线,所有的platform设备都被当作挂载到这个总线上。
8、system_bus_init
int
__init system_bus_init(
void
)<br>{<br> system_kset = kset_create_and_add(
"system"
, NULL, &devices_kset->kobj);<br>
if
(!system_kset)<br>
return
-ENOMEM;<br>
return
0;<br>}
|
这里创建了一个名为system的kset,其父节点为在devices_init中创建的devices_kset。在此kset中是一些和CPU、中断控制器、时钟之类的设备。
9、cpu_dev_init
int
__init cpu_dev_init(
void
)<br>{<br>
int
err;<br><br> err = sysdev_class_register(&cpu_sysdev_class);<br>#
if
defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)<br>
if
(!err)<br> err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);<br>#endif<br><br>
return
err;<br>}
|
这里注册了一个名为"CPU"的类,其父节点在system_bus_init中注册的system_kset。其对应的目录为/sys/devices/system/cpu,其中包含CPU相关的属性。
10、memory_dev_init
int
__init memory_dev_init(
void
)
{
unsigned
int
i;
int
ret;
int
err;
unsigned
long
block_sz;
memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
ret = sysdev_class_register(&memory_sysdev_class);
if
(ret)
goto
out;
block_sz = get_memory_block_size();
sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
/*
* Create entries for memory sections that were found
* during boot and have been initialized
*/
for
(i = 0; i < NR_MEM_SECTIONS; i++) {
if
(!present_section_nr(i))
continue
;
err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE,
BOOT);
if
(!ret)
ret = err;
}
err = memory_probe_init();
if
(!ret)
ret = err;
err = memory_fail_init();
if
(!ret)
ret = err;
err = block_size_init();
if
(!ret)
ret = err;
out:
if
(ret)
printk(KERN_ERR
"%s() failed: %d\n"
, __func__, ret);
return
ret;
}
|
这里注册了一个名为"memory"的类,其父节点在system_bus_init中注册的system_kset。其对应的目录为/sys/devices/system/memory,其中包含内存相关的属性,如块大小等。