首页>计算机>Linux认证>学习教程>正文
Linux网卡驱动程序详解

www.zige365.com 2008-8-19 15:40:09 点击:发送给好友 和学友门交流一下 收藏到我的会员中心
ether_input(&sc->arpcom.ac_if,eh,m);/*传输给上一层的包括ifnet结构,以太网头部,一mbuf*/
}
/* 中断例程 */
static void
elintr(int unit)
{
register struct el_softc *sc;
register int base;
int stat, rxstat, len, done;
/* 寻址softc和I/O基地址 */
sc = &el_softc[unit];
base = sc->el_base;
dprintf(("elintr: "));
/* 检查板卡状态 */
stat = inb(base+EL_AS);
if(stat & EL_AS_RXBUSY) {/*接收忙*/
(void)inb(base+EL_RXC);/*读接收命令寄存器*/
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/
return;
}
done = 0;
while(!done) {
rxstat = inb(base+EL_RXS);
if(rxstat & EL_RXS_STALE) {/*EL_RXS_STALE代表接受状态没有改变*/
(void)inb(base+EL_RXC);/*读接收命令寄存器*/
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/
return;
}
/* 如果这有一个溢出发生,重新初始化板卡. */
if(!(rxstat & EL_RXS_NOFLOW)) {
dprintf(("overflow.n"));
el_hardreset(sc);
/* 使板卡回到接收模式 */
if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
else
outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
(void)inb(base+EL_AS);/*读辅助状态寄存器*/
outb(base+EL_RBC,0);/*清除接收缓冲*/
(void)inb(base+EL_RXC);/*读接收命令寄存器*/
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/
return;
}
/* 到这应该是进来了一数据包 */
len = inb(base+EL_RBL);
len |= inb(base+EL_RBH) << 8;/*包长度的高低位组合为该包的长度*/
dprintf(("receive len=%d rxstat=%x ",len,rxstat));
outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST为系统总线可访问缓冲 */
/* 如果包太短或太长,回到接收模式并返回
*/
if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) {/*如果包小于以太网头部的长度或大于最大长度*/
if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)/*为重置硬件准备if_flags*/
outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
else
outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
(void)inb(base+EL_AS);/*读辅助状态寄存器*/
outb(base+EL_RBC,0);/*清除接收缓冲*/
(void)inb(base+EL_RXC);/*读接收命令寄存器*/
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/
return;
}
sc->arpcom.ac_if.if_ipackets++;/*统计使用,说明接收包总数*/
/* 拷贝数据到我们的缓冲 */
outb(base+EL_GPBL,0);
outb(base+EL_GPBH,0);
insb(base+EL_BUF,sc->el_pktbuf,len);/*从端口读一串数据到指定地址()*/
outb(base+EL_RBC,0);
outb(base+EL_AC,EL_AC_RX);
dprintf(("m-->",sc->el_pktbuf+6,":"));/*也放置到el_pktbuf中,发送也放在他中,在发送时有一个开中断接数据包的过程不过那时候el_pktbuf中没有数据,不会相互影响.*/
dprintf(("mn",sc->el_pktbuf,":"));
/* 把数据传递到上一层 */
len -= sizeof(struct ether_header);
elread(sc,(caddr_t)(sc->el_pktbuf),len);
/* 对状态? */
stat = inb(base+EL_AS);
/* 如果忙不为真则继续 */
if(!(stat & EL_AS_RXBUSY))
dprintf((" "));
else
done = 1; /*退出循环*/
}
(void)inb(base+EL_RXC);
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
return;
}

本新闻共9页,当前在第7页  1  2  3  4  5  6  7  8  9  

我要投稿 新闻来源: 编辑: 作者:
相关新闻
红旗linux认证工程师考题系统部份(3)
Wine让Windows上的软件集体移民
Linux启动过程全接触
LinuxDNS的负载均衡及子域委派
用chkconfig轻松管理启动程序
如何设置Ubuntu做网关