几经波折,在开发板上终于可以使用网络了。Linux内核可以通过网络挂接网络文件系统了。首先感谢Internet,Google等帮助过我的工具,还要感谢各位嵌友的无私奉献。在移植的过程中尤其感激weibing的博客**cs8900移植linux-2.6.19.2,根据他的**使cs8900 成功跑起来。此**可以在http://weibing.blogbus.com/logs/4467465.html找到。 在解释网络驱动前,先说说自己的硬件配置: 1. 处理器为s3c2410 2. 网络芯片cs8900a 3. cs8900a映射到s3c2410的bank3空间 4. cs8900a占用int9号中断 5. Linux内核版本为2.6.20 一、初始化阶段 网络初始化被调用的路径为: init->do_basic_setup->do_initcalls->net_olddevs_init->ethif_probe2->probe_list2->cs89x0_probe->cs89x0_probe1 真是不容易啊,终于进到cs89x0_probe1了,在这里开始探测和初始化cs8900了。下面就按照这个顺序来说明网络驱动第一阶段的工作。注意:这里的调用顺序是将cs8900驱动编入内核所产生的,如果将cs8900驱动选为模块,这个路径:init->do_basic_setup->do_initcalls->net_olddevs_init->ethif_probe2->probe_list2也会执行。 1.1 init函数 我们知道当start_kernel函数完成后就会启动init进程执行,在真正的应用程序init进程(如busybox的/sbin/init)之前,Linux还需要执行一些初始化操作。init的代码可以在initmain.c中找到,它的代码如下: static int init(void * unused) { lock_kernel(); …… //省略多cpu的初始化代码先 do_basic_setup(); //我们所关注的初始化函数 …… if (!ramdisk_execute_command) ramdisk_execute_command = '/init'; if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { ramdisk_execute_command = NULL; prepare_namespace(); //挂接根文件系统 } …… free_initmem(); //释放初始化代码的空间 unlock_kernel(); …… //这几段没看懂
if (sys_open((const char __user *) '/dev/console', O_RDWR, 0) < 0) //检查控制台 //console是否存在 printk(KERN_WARNING 'Warning: unable to open an initial console. '); ……//这几段没看懂 if (ramdisk_execute_command) { //运行ramdisk_execute_command指定的init用户进程 run_init_process(ramdisk_execute_command); printk(KERN_WARNING 'Failed to execute %s ', ramdisk_execute_command); } …… if (execute_command) { //判断在启动时是否指定了init参数,如果指定, //此值将赋给execute_command run_init_process(execute_command); //开始执行用户init进程,如果成功将不会 //返回。 printk(KERN_WARNING 'Failed to execute %s. Attempting ' 'defaults... ', execute_command); } //如果没有指定init启动参数,则查找下面的目录init进程,如果找到则不会返回 run_init_process('/sbin/init'); run_init_process('/etc/init'); run_init_process('/bin/init'); run_init_process('/bin/sh'); //如果上面的程序都出错,则打印下面的信息,如果内核找到init进程, //则程序不会指向到此处 panic('No init found. Try passing init= option to kernel.'); } 1.2 do_basic_setup函数 在这里我们最关心的是do_basic_setup函数,顾名思义该函数的功能就是“做基本设置”,它的实现代码也在initmain.c中。do_basic_setup()完成外设及其驱动程序的加载和初始化。该函数代码如下所示:
static void __init do_basic_setup(void) { /* drivers will send hotplug events */ init_workqueues(); //初始化工作队列 usermodehelper_init(); //初始化khelper内核线程,还没弄清楚
driver_init(); //初始化内核的设备管理架构需要的数据结构, //很复杂,以后在谈这部分。
#ifdef CONFIG_SYSCTL sysctl_init(); //没搞懂 #endif do_initcalls(); //重点函数,初始化的主要工作就靠它了 } 1.3 do_ initcalls函数 do_initcalls函数将会调用内核中所有的初始化函数,它的代码同样在initmain.c中。do_initcalls函数调用其他初始化函数相当简洁,它的关键代码如下所示: initcall_t *call; for (call = __initcall_start; call < __initcall_end; call++) { …… result = (*call)(); …… }
|