Chinaunix首页 | 论坛 | 博客
  • 博客访问: 766156
  • 博文数量: 370
  • 博客积分: 2334
  • 博客等级: 大尉
  • 技术积分: 3222
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-06 16:56
文章分类

全部博文(370)

文章存档

2013年(2)

2012年(368)

分类:

2012-06-26 23:11:50

1.4 net_olddevs_init函数

       我们知道net_olddevs_init函数在do_initcalls函数中被调用并执行,那么它到底要做什么呢?看看实现代码就知道了,它的实现代码可以在\drivers\net\Space.c中找到。对于网络驱动部分的主要实现代码如下:

static int __init net_olddevs_init(void){  

……

       int num;

       for (num = 0; num < 8; num)

              ethif_probe2(num);

       ……

}

这段代码就不用讲解了吧,嘿嘿!就是调用了8ethif_probe2,赶快去看看ethif_probe2长什么样子。

1.5 ethif_probe2函数

       先看看该函数的实现代码,该代码也在\drivers\net\Space.c文件中。

static void __init ethif_probe2(int unit)

{

       unsigned long base_addr = netdev_boot_base("eth", unit);   // 由于ethif_probe2net_olddevs_init调用了8次,

                                          // 所以unit的值为07,也即在这里可以注册eth0eth7八个网络设备

       if (base_addr == 1)

              return;


       (void)(    probe_list2(unit, m68k_probes, base_addr == 0) &&

              probe_list2(unit, eisa_probes, base_addr == 0) &&

              probe_list2(unit, mca_probes, base_addr == 0) &&

              probe_list2(unit, isa_probes, base_addr == 0) &&

              probe_list2(unit, parport_probes, base_addr == 0));

}

       该函数首先调用netdev_boot_base所给的设备是否已经向内核注册,如果已注册netdev_boot_base返回1,随后推出ethif_probe2。如果设备没注册,则又调用函数probe_list2四次,每次传递的传输不同,注意到每次传递的第二个参数不同,这个参数也是相当重要的,这里拿isa_probes参数为例说明,因为这个参数与cs89x0_probe有关,isa_probes的定义也在\drivers\net\Space.c中,它的样子形如:

static struct devprobe2 isa_probes[] __initdata = {

……

#ifdef CONFIG_SEEQ8005

       {seeq8005_probe, 0},

#endif

#ifdef CONFIG_CS89x0

     {cs89x0_probe, 0},

#endif

#ifdef CONFIG_AT1700

       {at1700_probe, 0},

#endif

       {NULL, 0},

……

};

如果把cs8900的驱动选为非编译进内核,那么它的探测函数cs89x0_probe就不会存在于isa_probes数组中,所以在初始阶段就不能被调用。从上面的代码可以知道devprobe2类型至少包括两个域,至少一个域为函数指针,看看它的原型如下:

struct devprobe2 {

       struct net_device *(*probe)(int unit);                         //函数指针,指向探测函数

       int status;       /* non-zero if autoprobe has failed */

};

下面看看probe_list2函数是怎么表演的。

1.6 ethif_probe2函数

       对于ethif_probe2函数也没有什么需要说明的,它的主要任务是依次调用devprobe2类型的probe域指向的函数。他的实现代码同样在\drivers\net\Space.c中,它的关键代码如下:

static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)

{

       struct net_device *dev;

       for (; p->probe; p ) {

           ……

              dev = p->probe(unit);

              ……

       }

……

}

1.7 cs89x0_probe函数

       从该函数起,真正开始执行与cs8900驱动初始化程序,该函数在\drivers\net\cs89x0.c文件实现。下面依次解释该函数。

struct net_device * __init cs89x0_probe(int unit)

{

       struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); //该函数申请一个net_device

//sizeof(struct net_local)的空间,net_localcs8900驱动的私有数据空间。

       unsigned *port;

       int err = 0;

       int irq;

       int io;

      

       if (!dev)

              return ERR_PTR(-ENODEV);

       sprintf(dev->name, "eth%d", unit);                 //初始化dev->name

       netdev_boot_setup_check(dev);                  //检查是否给定了启动参数,如果给定了启动参数,此函数将初始

//devirqbase_addrmem_startmem_end域。

       io = dev->base_addr;                                 //io实际实质cs8900所占地址空间的起始地址,此地址为虚拟地址

       irq = dev->irq;

       if (net_debug)

              printk("cs89x0:cs89x0_probe(0x%x)\n", io);

//下面根据io的值调用cs89x0_probe1函数

       if (io > 0x1ff) {/* Check a single specified location. *///此段没搞懂,由于没给启动参数,这里也不会执行

       err = cs89x0_probe1(dev, io, 0);

       } else if (io != 0) { /* Don''''''''''''''''''''''''''''''''t probe at all. */

              err = -ENXIO;

       } else {

              for (port = netcard_portlist; *port; port ) {// netcard_portlistunsigned int型数组,在cs89x0.c文件中定

//义,里面列出了cs8900可能占用空间的起始地址,这些地址

//将在cs89x0_probe1函数中用于向内核申请。

                     if (cs89x0_probe1(dev, *port, 0) == 0) // cs89x0_probe1探测成功就返回0

                            break;

                     dev->irq = irq;

              }

              if (!*port)

                     err = -ENODEV;

       }

       if (err)

              goto out;

       return dev;

out:

       free_netdev(dev);   //表示探测失败,这里就释放dev的空间,随后打印些消息

       printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n");

       return ERR_PTR(err);

}

       从上面的程序清单可以看到该函数还没有真正的开始探测cs8900,实质的探测工作是让cs89x0_probe1完成的。在解释cs89x0_probe1之前先提一下网络驱动程序中非常重要的一些函数。内核需要一个数据结构来管理或者描述每个网络驱动程序,这个数据类型就是struct net_device,该数据类型包括很多域,详细的解释可以参见《Linux 设备驱动程序》一书中的描述,也可以参见源代码(在\include\linux\netdevice.h中,源码中也有详细的注解)。内核为了编程方便特地实现了函数alloc_netdev来完成对net_device的空间分配。那么alloc_etherdev函数主要针对以太网在alloc_netdev基础上封装的一个函数,它除了申请net_device空间外,还会初始化net_device的相关域。
阅读(1066) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~