LINUX网卡驱动分析

来源:互联网 发布:js 切换隐藏 编辑:程序博客网 时间:2024/04/29 00:02


一、网络设备驱动结构

1网络协议接口层

2网络设备接口层

3设备驱动功能层

4网络设备与媒介层

二、网络协议接口层

1功能:给上层协议提供透明的数据包发送和接收接口

2定义在/include/linux/netdevice.h中

3函数原型:

int     dev_queue_xmit(struct sk_buff *skb);

int            netif_rx(struct sk_buff *skb);

4        Sk_buff含义为套接字缓冲区

三、套接字

1  Sk_buff结构体定义在/linux/skbuff.h中

2 套接字在所有网络操作系统和网络应用程序中都是必不可少的,它是网络通信中应用进程和网络协议的接口

3 在Linux中,套接字属于文件系统的一部分,网络 通信可以被看作是对文件的读取

四、Linux网络层次模型

 

五、网络设备接口层

1  定义了net_device结构体

2 它包含网络设备的属性描述和操作接口,写驱动时只需填充net_device的具体成员并注册即可实现硬件操作函数与内核的挂接

设备驱动功能层 & 网络设备与媒介层

3        Net_device结构体成员(属性和函数指针)需要被设备驱动功能层的具体数值和函数赋予,并且在这一层定义中断处理函数,负责读取硬件上接收的数据包并传给上层协议。

网络设备与媒介层直接对应于实际的硬件设备

分析驱动程序

4        驱动程序包括设备的注册与注消,设备的初始化,设备的打开与释放,数据发送与接收,统计网络联接状态数据等

5        这里以我们常用的Cirrus公司的CS8900网卡为例对程序加以分析.文件为/drivers/net/cs89x0.c

cs8900 datasheet的下载地址:http://cst.mi.fu-berlin.de/proje ... eets/old/CS8900.pdf

六、设备的注册与注消

1  在/include/linux/netdevice.h中定义了许多API接口

2        设备的注册与注销定义如下:

Int  register_netdev(struct net_device *dev)

Void unregister_netdev(struct net_device *dev)

3        net_device数据结构的地位很重要

七、设备的初始化

1 程序的初始化由net_device结构体中的init()函数完成,这个函数将在net_device被注册时自动被调用.init()函数在程序中对应于cs89x0_probe()函数:
struct net_device * __init cs89x0_probe(int unit)

4  for (port = netcard_portlist; *port; port++) { /*netcard_portlist为unsigned int型数组,在cs89x0.c文件中定义,里面列出了cs8900可能占用空间的起始地址,这些地址在cs89x0_probe1函数中用于向内核申请*/
      if (cs89x0_probe1(dev, *port, 0) == 0)  /*若探测成功返回, 验证了网卡的存在,并获取cs8900所使用的硬件资源*/

2        下来才是真正的探测工作
static int __init
cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) 

(1)初始化设备结构

(2)读取芯片类型并判断型号

(3)完成net_device设备结构体的初始化,赋值其属性和函数指针

七、网络设备的打开与释放

1定义在/include/linux/netdevice.h中

2打开函数void netif_start_queue(struct net_device *dev)

3 打开函数完成使能设备使用的硬件资源,申请I/O区域,中断和DMA通道,激活设备发送队列

4关闭函数为void netif_stop_queue(struct net_device *dev)

八、发送数据

1向控制寄存器TX_CMD寄存器写入发送命令

2将发送数据长度写入TX_LENG寄存器

3读取PacketPage空间内的PP_BusST寄存器,确定其第8位被设置为READY_FOR_TX_NOW ,即设备处于准备发送状态

4将要发送的数据循环写入寄存器.

CAUTION!!这里有个自旋锁spin_lock_irq(&lp->lock)的应用

九、接收数据

1   cs8900的数据包接收流程由中断引发,在中断服务程序中会判断中断的类型,如果是接收到数据包中断,则完成套接字缓冲区的创建和填充,并调用netif_rx()函数将套接字缓冲区传递给上层协议.中断函数为irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)

2     /*读取中断事件类型*/

 while ((status = readword(dev, ISQ_PORT))) {
      if (net_debug > 4)printk(“%s: event=%04x\n”, dev->name, status);
          handled = 1;
          switch(status & ISQ_EVENT_MASK) {
        case ISQ_RECEIVER_EVENT:  /*获得数据包*/
        net_rx(dev);  /*当网卡中断为接收中断时,调用 net_rx()函数完成数据包的获取与上层协议传递*/
         break; 

3   Void net_rx(struct net_device *dev)

(1).          接收数据包长度

(2).          分配新的套接字缓冲区和数据缓冲区

(3).          读数据包放入缓冲区

(4).          解析协议类型

(5).          这两行统计接收数据包数和接收字节数 
        lp->stats.rx_packets++;
        lp->stats.rx_bytes += length;

十、总结

1   网络设备驱动体系结构的层次化设计实现了对上层协议接口的统一和硬件驱动的对下层多样化 硬件设备的可适应,这也正是驱动程序所要起到的主要作用.

2  对源码的分析可以发现net_device结构体的定义非常重要,它内部的属性和函数指针在驱动 程序中负担了大部分工作.

3  同时需要留意的是套接字缓冲区sk_buff,它承载了所有数据流的传输.