2013年(7)
分类: LINUX
2013-08-17 14:20:12
原文地址:linux 内核设备驱动初始化的实现(转) 作者:renbok
<./init/main.c>-------------------------
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
···········································································
printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);
//打印内核命令行
parse_early_param();
parse_args("Booting kernel", command_line, __start___param, __stop___param - __start___param,
&unknown_bootoption);
//解析由BOOT传递的启动参数
···········································································
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
start_kernel()中的函数rest_init()将创建第一个核心线程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),调用init()函数:
static int init(void * unused)-------------------
{
·······················
do_basic_setup();
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) { //判断在启动时是否指定了init参数
//如果指定则执行用户init进程,成功将不会返回
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command);
}
/* 如果没有指定init启动参数,则查找下面的目录init进程,成功将不会返回,否则打印出错信息 */
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
继而调用函数do_basic_setup()(此时与体系结构相关的部分已经初始化完了,现在开始初始化设备了):
/*
* Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and * running, and memory and process management works.
*
* Now we can finally start doing some real work..
*/
static void __init do_basic_setup(void)-----------------
{
/* drivers will send hotplug events */
init_workqueues();
usermodehelper_init();
driver_init(); //建立设备模型子系统
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
/* Networking initialization needs a process context */
sock_init();
do_initcalls(); //系统初始化(包括设备,文件系统,内核模块等)
}
下面分析driver_init():
<./drivers/base/init.c>-------------------------
/**
* 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 */
devices_init();
<./drivers/base/core.c>-------------
int __init devices_init(void)
{
return subsystem_register(&devices_subsys);
}
subsystem_register():
buses_init();
classes_init();
firmware_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();
attribute_container_init();
}
---------------------------
extern initcall_t __initcall_start[], __initcall_end[];
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
··················
(*call)(); //调用一系列初始化函数
···················
}
__initcall_start和__initcall_end界定了存放初始化函数指针区域的起始地址,即从__initcall_start开始到__initcall_end结束的区域中存放了指向各个初始化函数的函数指针。 由 (*call)()完成各个部分的初始化工作,且便于扩充。具体实现如下:<./arch//kernel/vmlinux.lds.S>-----------------__initcall_start = .;
*(.initcall1.init) *(.initcall2.init) *(.initcall3.init) *(.initcall4.init) *(.initcall5.init) *(.initcall6.init) *(.initcall7.init) __initcall_end = .;
<./include/linux/init.h>---------------------
#ifndef MODULE /*如果驱动模块静态编译进内核*/
···············································
/* initcalls are now grouped by functionality into separate
* subsections. Ordering inside the subsections is determined * by link order. * For backwards compatibility, initcall() puts the call in * the device init subsection.
*/
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn
#define core_initcall(fn) __define_initcall("1",fn) #define postcore_initcall(fn) __define_initcall("2",fn) #define arch_initcall(fn) __define_initcall("3",fn)
//此处初始化了设备
/*----eg:arch_initcall(at91sam9261_device_init)---
static int __init at91sam9261_device_init(void)
{
at91_add_device_udc();
at91_add_device_dm9000();
ebs3_add_input_buttons();
return platform_add_devices(at91sam9261_devices, ARRAY_SIZE(at91sam9261_devices));
}
------------------------*/
#define subsys_initcall(fn) __define_initcall("4",fn) #define fs_initcall(fn) __define_initcall("5",fn) #define device_initcall(fn) __define_initcall("6",fn)
//此处初始化了静态编译的驱动模块
#define late_initcall(fn) __define_initcall("7",fn)
#define __initcall(fn) device_initcall(fn)
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will either be called during do_initcalls (if
* builtin) or at module insertion time (if a module). There can only * be one per module.
*/
#define module_init(x) __initcall(x);
//静态编译的驱动模块作为device_initcall在内核启动就被do_initcalls
/**
* module_exit() - driver exit entry point
* @x: function to be run when driver is removed
*
* module_exit() will wrap the driver clean-up code
* with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically * compiled into the kernel, module_exit() has no effect. * There can only be one per module.
*/
#define module_exit(x) __exitcall(x);
#else /* MODULE如果驱动模块动态加载入内核*/
···············································
/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
//insmod 是通过系统调用sys_init_module(const char *name_user, struct module *mod_user)
//将动态驱动模块载入到内核空间
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
-----------------------------
<注:新的内核已将init改为kernel_init>