linux 内核设备驱动初始化的实现(转)


网址:http://blog.chinaunix.net/uid-20806919-id-132281.html
 
Uboot完成系统的引导并将Linux内核拷贝到内存之后,bootm -> do_bootm_linux()跳转到kernel的起始位置;压缩过的kernel入口在arch/arm/boot/compressed/head.S,它将调用函数decompress_kernel()<./arch/arm/boot/compressed/misc.c>解压,打印“Uncompressing Linux...”,调用gunzip(),打印"done, booting the kernel."然后call_kernel,执行解压后的kernel,经linux/arch/arm/kernel/head.S调用start_kernel转入体系结构无关的通用C代码,在start_kernel()中完成了一系列系统初始化,设备及驱动的注册即在此时完成:

    <./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/arm/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();

    armebs3_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>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a746742897

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值