/* 检查输出后的状态,如果你要对watchdog支持,可以在这加上代码,即在5毫秒没发送出去,就调用el_watchdog() */ i = inb(base+EL_TXS); dprintf(("tx status=0x%xn",i)); if(!(i & EL_TXS_READY)) { /* 如果传输状态寄存器不是准备接受新帧就绪 */ dprintf(("el: err txs=%xn",i)); /*那就是出错了*/ sc->arpcom.ac_if.if_oerrors++; if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {/*网络数据包碰撞*/ if((!(i & EL_TXC_DCOLL16)) && retries < 15) {/*做循环的目的是为了有错误时可重传15次*/ retries++; outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST为系统总线可访问缓冲 */ } } else done = 1; } else { sc->arpcom.ac_if.if_opackets++;/*统计用的,说明该卡成功发送一包*/ done = 1; } } if(done == -1) /* 包没有传输(失败) */ continue; /* 现在给板卡一个机会接收.注意:在linux中曾经ALEN先生批评此卡好恐怖(他说要进博物馆,哈哈),并说在传输时会丢失进来的数据包,我查看了LINUX的驱动程序,确实是这样,但在FreeBSD中,给了一个机会,由此可证明他的关于"丢失包的说法不一定成立",但关于一个缓冲和一次只能发送一数据包的说法确实是真的,还有多播方面也不支持,我也希望大家最好不要去买这东西,和NE2000,PCI中的RTL8139芯片的网卡一样,性能太差了.*/ (void)inb(base+EL_AS);/*读辅助状态寄存器*/ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/ splx(s); /* 这有可能接收到中断(包到达) */ s = splimp(); } } /* 这是真正的传输包,由el_start()调用 */ static int el_xmit(struct el_softc *sc,int len) { int gpl; int i; gpl = EL_BUFSIZ - len; dprintf(("el: xmit...")); outb((sc->el_base)+EL_GPBL,(gpl & 0xff)); outb((sc->el_base)+EL_GPBH,((gpl>>&0xff)); outb((sc->el_base)+EL_AC,EL_AC_TXFRX);/*真正的传送指令*/ i = 20000; while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))/*如果传送还在忙,循环20000次等待*/ i--; if(i == 0) {/*这里有一个bug,大家发现没有,i到了0时也有可能传送成功,解决办法是把(i>0)这条件放到前面*/ /*我稍微讲一下C,在编译C程序时,象while ( (a>b) && (i>0) )时,是这个样子 top:if a>b then if i>0 then 执行体 endif endif goto top
也就是说,当i=0时候,inb((sc->el_base)+EL_AS)这指令还会执行,也有可能这时候传送完成了,而下面有给打出一个什么"tx not ready"的东东,而且返回失败,有得重新传送一次.
*/ dprintf(("tx not readyn")); sc->arpcom.ac_if.if_oerrors++; return(-1); } dprintf(("%d cycles.n",(20000-i))); return(0);/*成功*/ } /* 传递包到更高一级协议处理,即ether_input()例程.由elintr()调用 */ static __inline void elread(struct el_softc *sc,caddr_t buf,int len) { register struct ether_header *eh; struct mbuf *m; eh = (struct ether_header *)buf;/*从buf中分出以太网头部*/ /* * elget函数是把包放入一mbuf缓冲链中 */ m = elget(buf,len,&sc->arpcom.ac_if); if(m == 0)/*出错了*/ return; |