打印
[ZLG-ARM]

Linux-2.6.20的cs8900驱动分析经验总结

[复制链接]
1928|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
armpc|  楼主 | 2009-6-2 13:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
   几经波折,在开发板上终于可以使用网络了。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)();
……

相关帖子

沙发
xamic| | 2009-6-3 13:17 | 只看该作者

辛苦了,谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

55

帖子

0

粉丝