上一篇(见 ),用一个简单的虚拟网卡驱动,大致地介绍了一下网卡驱动的基本架构
这里,再针对DM9000网卡驱动具体地分析一下网卡驱动的架构
首先,Linux网络设备驱动从上到下分为四层:
1、网络协议接口层:向网络协议(ARP&IP)提供统一的数据包发送接口,通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接收数据。这一层的存在使得上层协议独立于具体的设备
2、网络设备接口层:向网络协议接口层提供统一的用于描述具体网络设备属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器,从宏观上规划了具体操作硬件的设备驱动功能层的结构
3、设备驱动功能层:各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,通过dev_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作(open() --> dev_interrupt --> dev_rx())
4、网络设备与媒介层:是完成数据包发送和接收的物理实体,包括网络适配器和具体的传输媒介,网络适配器被驱动功能层中的函数物理上驱动。对于Linux系统而言,网络设备和媒介都可以是虚拟的。
在设计具体的网络设备驱动程序是,我们需要完成的主要工作是编写设备驱动功能层的相关函数以填充net_device数据结构体的内容,并将net_device注册入内核。
DM9000网卡驱动位于内核源码的driver/net/dm9000.c,它是基于平台驱动架构的
ps:此处按代码的书写顺序分析架构
typedef struct board_info {
u32 io_addr; //寄存器I/O基地址
u32 io_data; //数据I/O基地址
... ...
}board_info_t;
static struct net_device *dm9000_dev = NULL;
static int irq = DM9KS_IRQ;
static int iobase = DM9KS_MIN_IO;
static unsigned char dev_addr[MAX_ADDR_LEN]; // hw address
//12、如下实现各net_device(dm9000_xxx)各成员函数
//13、网卡打开函数
static int dm9000_open(struct net_device *dev)
{
ret = request_irq(dev->irq, &dm9000_interrupt, 0, dev->name, dev); //申请端口、IRQ等(注册中断)
... ...
netif_start_queue(dev); //激活设备发送队列
}
//17、当我们在打开网卡的时候即有申请IRQ中断,因为网卡是通过中断来实现数据的接收的
static void dm9000_interrupt(int irq, void *dev_id)
{
...
switch(status & IRQ_EVENT_MASK){ //当有中断来到时,判断中断的类型
case IRQ_RECEIVER_EVENT: //当中断类型为有数据来到时
dm9000_rx(dev); //调用网卡的数据接收函数
break;
//其他类型的中断
... ...
}
}
//18、网卡数据包接收函数
static void dm9000_tx(struct dm9000_device *dev)
{
... ...
length = get_rev_len(...); //从硬件读取到接收数据包有效数据的长度
skb = dev_alloc_skb(length + 2); //分配新的套接字缓冲区