上 编写Linux网络设备驱动

本文介绍基于 8139芯片PCI接口的网卡驱动程序 。我选择了芯片有两个原因:首先,提供免费的芯片技术手册; 第二,芯片相当便宜 。
本文介绍的驱动程序是最基本的,它只有发送和接收数据包功能,和做一些简单的统计 。对于一个全面和专业级的驱动程序,请参阅Linux源码 。
本文代码是基于.4.18上测试的,建议编译一个内核,此内核没有任何形式驱动程序,以避免有莫名的BUG 。最后,你将网卡插入PCI插槽,我们可以开始了 。
目录
网络设备驱动程序的开发,分解成以下步骤:
上:
中:
下:
1.设备检测
第一步,我们需要检测的网卡设备 。Linux内核提供了丰富的API检测PCI总线上的设备,我们这只用其中最简单的一个API——?? 。
#define REALTEK_VENDER_ID0x10EC#define REALTEK_DEVICE_ID0x8139#include #include #include #include int init_module(void){struct pci_dev *pdev;pdev = pci_find_device(REALTEK_VENDER_ID, REALTEK_DEVICE_ID, NULL);if(!pdev)printk("<1>Device not found\n");elseprintk("<1>Device found\n");return 0;}
Table 1:the
PCI标准为每个供应商分配一个唯一的 ID,供应商会为每一个特定类型的设备分配一个唯一的 ID 。宏、表示这些ID 。你可以在规范的“PCI配置空间表”找到这些值 。
2.设备启用()
检测到设备后,我们使用设备之前,我必须先激活设备,这个步骤称为[启用设备] 。表2所示的代码片段是[设备检测]和[设备启用]合并的代码 。
∨Table 2:andthe
#define REALTEK_VENDER_ID0x10EC#define REALTEK_DEVICE_ID0X8139static struct pci_dev* probe_for_realtek8139(void){struct pci_dev *pdev = NULL;/* Ensure we are not working on a non-PCI system *if(!pci_present( )) {LOG_MSG("<1>pci not present\n");return pdev;}/* Look for RealTek 8139 NIC */pdev = pci_find_device(REALTEK_VENDER_ID, REALTEK_DEVICE_ID, NULL);if(pdev) {/* device found, enable it */if(pci_enable_device(pdev)) {LOG_MSG("Could not enable the device\n");return NULL;}elseLOG_MSG("Device enabled\n");}else {LOG_MSG("device not found\n");return pdev;}return pdev;}int init_module(void){struct pci_dev *pdev;pdev = probe_for_realtek8139();if(!pdev)return 0;return 0;}
在表2,函数9执行以下任务:
现在,为了更好地理解代码,我们先暂停一下驱动程序代码的研究,转而看一下Linux内核是怎样[处理]设备和设备驱动的 。我们将着眼于[网络设备的定义],内存映射I/O和独立端口I/O之间的差异,还有PCI配置空间的概念 。
3.理解何为网络设备
我们是检测到了PCI设备,并启用它,但它只是一支硬件设备(网卡设备),而Linux的网络协议栈只认得[网络设备] 。[网络设备]是一支逻辑设备,由结构表征 。也就是说,网络协议栈向[网络设备]发出命令,而[网络设备]的驱动将这些命令传递到PCI[网卡设备] 。表3列出了结构的一些重要数据域,这将在本文稍后使用 。
struct net_device{char *name;unsigned long base_addr;unsigned char addr_len;unsigned char dev_addr[MAX_ADDR_LEN];unsigned char broadcast[MAX_ADDR_LEN];unsigned short hard_header_len;unsigned char irq;int (*open) (struct net_device *dev);int (*stop) (struct net_device *dev);int (*hard_start_xmit) (struct sk_buff *skb,struct net_device *dev);struct net_device_stats* (*get_stats)(struct net_device *dev);void *priv;};
Table 3:
上表只列出C结构部分成员,不过,对于我们最小驱动程序,这些成员已经足够 。以下简介这些成员的用途:
请特别注意,没有接收数据包的成员函数,这是因为接收数据包是由设备的[中断处理程序]负责的,我们将在本文后面看到 。
4.总线无关的设备访问(Bus-)