Linux网卡驱动程序详解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
当网络上一台计算机准备发送数据时,他的网卡开始工作了,首先网卡的芯片侦听在网络上是否有数据在流动,如果没有,他就把数据发送到网络上,在侦听和发送之间有一段极小的时间延迟,在这段时间内,也有可能在网络上有其他的计算机也准备发送数据,也侦听到网络上没有数据在流动,这就可能两台甚至多台的数据一起发送到网络上,产生数据的碰撞,发送数据的计算机的网卡芯片当然要在发送完成后再校验返回的数据,如果发现和发送的数据不一致,那就是说产生了碰撞,所以在一个以太网络中的计算机数量不宜过多,他不但会增加广播包在网络中的数量,也请也会增加数据包的碰撞次数.
我们的计算机的网卡芯片在接收到一完整的数据包后,芯片的一引脚通知8259中断控制器,中断控制器再发出中断给CPU,由此,CPU随即调用该网卡的中断例程,如:
DOS是这样的
屏蔽所有中断(cli)
push any register
因为中断向量在段0
所以xor ax,ax
mov ds,ax
mul ax,中断号
那么在数据段的[ax]偏移处是该中断例程的指针了call [ax]就到该中断例程了...(DOS是比较遥远的事情了,我所描述的是他的原理,当然不会这么简单,如果那位网友有兴趣详细描述一下上面的原理,纠正或替换掉我所写的就感激不尽了)
总之,在本例程中,CPU将调用elintr中断例程,并带有参数unit即该种网卡的第几块(因为在计算机中,你有可能装了相同的网卡有几块),elintr的作用是把数据从网卡的数据存储器中读到我们在该网卡初始化时预先分配好的数据缓冲区中,他调用的函数就只有elread,同样elread也只调用了elget一个函数.elread函数比较简单,就是调用elget,elget则相对比较复杂一点,涉及到核心内存分配mbuf,mbuf是比较恐怖的东西,正如STEVEN所写的,为了节约当时"巨大"的4M内存,牺牲了性能搞出了这个mbuf东东,mbuf是必须要弄懂的,虽然在设备驱动程序中调用他的宏和函数不多,但在后面的IP协议,TCP协议中有不少涉及的地方.
关于数据发送方面和接收差不多,在上层协议放置好数据到mbuf链后,调用el_start函数,该函数把mbuf链中的数据放置到本块网卡的发送队列缓冲el_pktbuf中,然后再调用el_xmit 函数,此函数把发送队列缓冲el_pktbuf中的数据有传递到网卡的数据存储器中.我认为,这中间的内存拷贝是多于的,应该在el_start函数中直接把mbuf中的数据传递到网卡的数据存储器中,这样会使性能有较大幅度的提升,因为在驱动程序设计时,最好减少大量的内存拷贝,他占用的时间太多了.
*/
/* FreeBSD的3COM以太网设备驱动程序*/
/*本段头文件是在编译核心时产生的*/
#include "el.h" /*此三文件为编译时产生的头文件,内容是定制核心的一些常量*/
#include "opt_inet.h"
#include "opt_ipx.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /*此头文件是3COM卡的寄存器常量*/
/* 为了调试方便*/
#ifdef EL_DEBUG
#define dprintf(x) printf x /*如果定义了DEBUG调试,则打印到屏幕*/
#else
#define dprintf(x)
#endif
/* softc结构,每种网卡的该结构是不同的,主要是该第一个成员必须是一以太网的共用结构arpcom*/
static struct el_softc {
struct arpcom arpcom; /* 以太网公共部分*/
u_short el_base; /* 基本输入输出地址*/
char el_pktbuf[EL_BUFSIZ]; /* 帧缓冲大小2048 */
} el_softc[NEL]; /*NEL在el.h中定义,即编译时产生的头文件,意思为支持的网卡数*/
/*
看看arpcom结构吧
* 该结构是以太网设备驱动程序和ARP程序所共享.
struct arpcom {
/*
* ifnet 结构必须在此结构的第一个位置.
/
struct ifnet ac_if;
u_char ac_enaddr[6]; /* 以太网硬件地址/
int ac_multicnt; /* 多播地址列表数/
void *ac_netgraph; /* netgraph 节点信息,即我们所说的PPPoE,也就是ADSL宽带所用到的/ };
*/
/* 一些函数申明*/
static int el_attach(struct isa_device *);/*第二步:填充相关的数据结构*/
static void el_init(void *); /*不用说,是初始化,在probe,attach之后被调用*/
static int el_ioctl(struct ifnet *,u_long,caddr_t);/*控制网卡的函树指针*/
static int el_probe(struct isa_device *);/*第一步:探测程序.查看是否卡存在和是否在正确的位置.*/
static void el_start(struct ifnet *);/*把数据包从硬件接口输出去*/
static void el_reset(void *);/* 该例程重设接口. 在el_watchdog()中调用*/
static void el_watchdog(struct ifnet *);/*一般该函数用于包在一定时间内没发送出去,就调用他,在
本驱动程序中并不支持该函数,在我的rtl8139说明中有*/
static void el_stop(void *);/*停止接口,在el_ioctl()和el_reset()中调用*/
static int el_xmit(struct el_softc *,int);/*把数据包放到芯片内,发送到以太网上*/
static ointhand2_t elintr;/*中断例程*/
static __inline void elread(struct el_softc *,caddr_t,int);/* 传递包到更高一级协议处理,即ether_input()例程.由elintr()调用*/
static struct mbuf *elget(caddr_t,int,struct ifnet *); /* 从网卡上下载数据包,len是数据的长度,本地以太网头部被分开*/
static __inline void el_hardreset(void *);/* 这是一个子程序,目的是重设硬件.*/
/* isa_driver结构为autoconf准备*/
/* isa_driver结构说明:
该结构来之于文件isa_device.h头文件
结构成员:
/*
* 通用的设备驱动程序结构.
*
* 没一设备驱动程序定义一组例程入口,由设置程序在启动时使用.
struct isa_driver {
int (*probe) __P((struct isa_device *idp));
/* 测试设备是否存在
int (*attach) __P((struct isa_device *idp));
/* 为设备设置驱动程序
char *name; /* 设备名称
int sensitive_hw; /* 探测发生有冲突时为真,ISA设备的老毛病
};
*/
struct isa_driver eldriver = {
el_probe, el_attach, "el"
};
/* 探测程序.查看是否卡存在和是否在正确的位置. */
static int
el_probe(struct isa_device *idev)
{
/*