📄 ether8390.c
字号:
/* * If it's a good packet read it in to the software buffer. * If the packet wraps round the hardware ring, read it in * two pieces. */ if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){ p = bp->rp; bp->wp = p+len; data += sizeof(Hdr); if((data+len) >= ctlr->pstop*Dp8390BufSz){ count = ctlr->pstop*Dp8390BufSz - data; if(ctlr->ram) memmove(p, (void*)(ether->mem+data), count); else _dp8390read(ctlr, p, data, count); p += count; data = ctlr->pstart*Dp8390BufSz; len -= count; } if(len){ if(ctlr->ram) memmove(p, (void*)(ether->mem+data), len); else _dp8390read(ctlr, p, data, len); } /* * Copy the packet to whoever wants it. */ etheriq(ether, bp, 1); } /* * Finished with this packet, update the * hardware and software ring pointers. */ ctlr->nxtpkt = hdr.next; hdr.next--; if(hdr.next < ctlr->pstart) hdr.next = ctlr->pstop-1; regw(ctlr, Bnry, hdr.next); }}static voidtxstart(Ether* ether){ int len; Dp8390 *ctlr; Block *bp; uchar minpkt[ETHERMINTU], *rp; ctlr = ether->ctlr; /* * This routine is called both from the top level and from interrupt * level and expects to be called with ctlr already locked. */ if(ctlr->txbusy) return; bp = qget(ether->oq); if(bp == nil) return; /* * Make sure the packet is of minimum length; * copy it to the card's memory by the appropriate means; * start the transmission. */ len = BLEN(bp); rp = bp->rp; if(len < ETHERMINTU){ rp = minpkt; memmove(rp, bp->rp, len); memset(rp+len, 0, ETHERMINTU-len); len = ETHERMINTU; } if(ctlr->ram) memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len); else dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len); freeb(bp); regw(ctlr, Tbcr0, len & 0xFF); regw(ctlr, Tbcr1, (len>>8) & 0xFF); regw(ctlr, Cr, Page0|RdABORT|Txp|Sta); ether->outpackets++; ctlr->txbusy = 1;}static voidtransmit(Ether* ether){ Dp8390 *ctlr; ctlr = ether->ctlr; ilock(ctlr); txstart(ether); iunlock(ctlr);}static voidoverflow(Ether *ether){ Dp8390 *ctlr; uchar txp; int resend; ctlr = ether->ctlr; /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ txp = regr(ctlr, Cr) & Txp; regw(ctlr, Cr, Page0|RdABORT|Stp); delay(2); regw(ctlr, Rbcr0, 0); regw(ctlr, Rbcr1, 0); resend = 0; if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0) resend = 1; regw(ctlr, Tcr, LpbkNIC); regw(ctlr, Cr, Page0|RdABORT|Sta); receive(ether); regw(ctlr, Isr, Ovw); regw(ctlr, Tcr, LpbkNORMAL); if(resend) regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);}static voidinterrupt(Ureg*, void* arg){ Ether *ether; Dp8390 *ctlr; uchar isr, r; ether = arg; ctlr = ether->ctlr; /* * While there is something of interest, * clear all the interrupts and process. */ ilock(ctlr); regw(ctlr, Imr, 0x00); while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){ if(isr & Ovw){ overflow(ether); regw(ctlr, Isr, Ovw); ether->overflows++; } /* * Packets have been received. * Take a spin round the ring. */ if(isr & (Rxe|Prx)){ receive(ether); regw(ctlr, Isr, Rxe|Prx); } /* * A packet completed transmission, successfully or * not. Start transmission on the next buffered packet, * and wake the output routine. */ if(isr & (Txe|Ptx)){ r = regr(ctlr, Tsr); if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){ print("dp8390: Tsr#%2.2ux|", r); ether->oerrs++; } regw(ctlr, Isr, Txe|Ptx); if(isr & Ptx) ether->outpackets++; ctlr->txbusy = 0; txstart(ether); } if(isr & Cnt){ ether->frames += regr(ctlr, Cntr0); ether->crcs += regr(ctlr, Cntr1); ether->buffs += regr(ctlr, Cntr2); regw(ctlr, Isr, Cnt); } } regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); iunlock(ctlr);}static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };static voidsetfilter(Ether *ether, Dp8390 *ctlr){ uchar r, cr; int i; uchar *mar; r = Ab; mar = 0; if(ether->prom){ r |= Pro|Am; mar = allmar; } else if(ether->nmaddr){ r |= Am; mar = ctlr->mar; } if(mar){ cr = regr(ctlr, Cr) & ~Txp; regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); for(i = 0; i < 8; i++) regw(ctlr, Mar0+i, *(mar++)); regw(ctlr, Cr, cr); } regw(ctlr, Rcr, r);}static voidpromiscuous(void *arg, int ){ Ether *ether; Dp8390 *ctlr; ether = arg; ctlr = ether->ctlr; ilock(ctlr); setfilter(ether, ctlr); iunlock(ctlr);}static voidsetbit(Dp8390 *ctlr, int bit, int on){ int i, h; i = bit/8; h = bit%8; if(on){ if(++(ctlr->mref[bit]) == 1) ctlr->mar[i] |= 1<<h; } else { if(--(ctlr->mref[bit]) <= 0){ ctlr->mref[bit] = 0; ctlr->mar[i] &= ~(1<<h); } }}static uchar reverse[64];static voidmulticast(void* arg, uchar *addr, int on){ Ether *ether; Dp8390 *ctlr; int i; ulong h; ether = arg; ctlr = ether->ctlr; if(reverse[1] == 0){ for(i = 0; i < 64; i++) reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1) | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5); } /* * change filter bits */ h = ethercrc(addr, 6); ilock(ctlr); setbit(ctlr, reverse[h&0x3f], on); setfilter(ether, ctlr); iunlock(ctlr);}static voidattach(Ether* ether){ Dp8390 *ctlr; uchar r; ctlr = ether->ctlr; /* * Enable the chip for transmit/receive. * The init routine leaves the chip in monitor * mode. Clear the missed-packet counter, it * increments while in monitor mode. * Sometimes there's an interrupt pending at this * point but there's nothing in the Isr, so * any pending interrupts are cleared and the * mask of acceptable interrupts is enabled here. */ r = Ab; if(ether->prom) r |= Pro; if(ether->nmaddr) r |= Am; ilock(ctlr); regw(ctlr, Isr, 0xFF); regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); regw(ctlr, Rcr, r); r = regr(ctlr, Cntr2); regw(ctlr, Tcr, LpbkNORMAL); iunlock(ctlr); USED(r);}static voiddisable(Dp8390* ctlr){ int timo; /* * Stop the chip. Set the Stp bit and wait for the chip * to finish whatever was on its tiny mind before it sets * the Rst bit. * The timeout is needed because there may not be a real * chip there if this is called when probing for a device * at boot. */ regw(ctlr, Cr, Page0|RdABORT|Stp); regw(ctlr, Rbcr0, 0); regw(ctlr, Rbcr1, 0); for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--) ;}intdp8390reset(Ether* ether){ Dp8390 *ctlr; ctlr = ether->ctlr; /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references * to the 3C503 technical reference manual. */ disable(ctlr); if(ctlr->width != 1) regw(ctlr, Dcr, Ft4WORD|Ls|Wts); else regw(ctlr, Dcr, Ft4WORD|Ls); regw(ctlr, Rbcr0, 0); regw(ctlr, Rbcr1, 0); regw(ctlr, Tcr, LpbkNIC); regw(ctlr, Rcr, Mon); /* * Init the ring hardware and software ring pointers. * Can't initialise ethernet address as it may not be * known yet. */ ringinit(ctlr); regw(ctlr, Tpsr, ctlr->tstart); /* * Clear any pending interrupts and mask then all off. */ regw(ctlr, Isr, 0xFF); regw(ctlr, Imr, 0); /* * Leave the chip initialised, * but in monitor mode. */ regw(ctlr, Cr, Page0|RdABORT|Sta); /* * Set up the software configuration. */ ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = 0; ether->promiscuous = promiscuous; ether->multicast = multicast; ether->arg = ether; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -