| plan 9 kernel history: overview | file list | diff list |
1995/0409/pc/ether8390.c (diff list | history)
| pc/ether8390.c on 1992/1222 | ||
| 1992/1222 | /* * National Semiconductor DP8390 * and SMC 83C90 * Network Interface Controller. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" | |
| 1993/1116 | #include "../port/error.h" #include "../port/netif.h" | |
| 1992/1222 | ||
| 1993/1116 | #include "etherif.h" | |
| 1992/1222 | ||
| 1995/0409 | extern int slowinb(ulong); extern void slowoutb(ulong, uchar); | |
| 1992/1222 | enum { Cr = 0x00, /* command register, all pages */ Stp = 0x01, /* stop */ Sta = 0x02, /* start */ Txp = 0x04, /* transmit packet */ RDMAread = (1<<3), /* remote DMA read */ RDMAwrite = (2<<3), /* remote DMA write */ RDMAsend = (3<<3), /* remote DMA send packet */ RDMAabort = (4<<3), /* abort/complete remote DMA */ | |
| 1993/0212 | Ps0 = 0x40, /* page select */ Ps1 = 0x80, /* page select */ Page0 = 0x00, Page1 = Ps0, Page2 = Ps1, | |
| 1992/1222 | }; enum { /* Page 0, read */ Clda0 = 0x01, /* current local DMA address 0 */ Clda1 = 0x02, /* current local DMA address 1 */ Bnry = 0x03, /* boundary pointer (R/W) */ Tsr = 0x04, /* transmit status register */ Ncr = 0x05, /* number of collisions register */ Fifo = 0x06, /* FIFO */ Isr = 0x07, /* interrupt status register (R/W) */ Crda0 = 0x08, /* current remote DMA address 0 */ | |
| 1993/0212 | Crda1 = 0x09, /* current remote DMA address 1 */ | |
| 1992/1222 | Rsr = 0x0C, /* receive status register */ Cntr0 = 0x0D, /* frame alignment errors */ Cntr1 = 0x0E, /* CRC errors */ Cntr2 = 0x0F, /* missed packet errors */ }; enum { /* Page 0, write */ Pstart = 0x01, /* page start register */ Pstop = 0x02, /* page stop register */ Tpsr = 0x04, /* transmit page start address */ Tbcr0 = 0x05, /* transmit byte count register 0 */ Tbcr1 = 0x06, /* transmit byte count register 1 */ Rsar0 = 0x08, /* remote start address register 0 */ Rsar1 = 0x09, /* remote start address register 1 */ Rbcr0 = 0x0A, /* remote byte count register 0 */ Rbcr1 = 0x0B, /* remote byte count register 1 */ Rcr = 0x0C, /* receive configuration register */ Tcr = 0x0D, /* transmit configuration register */ Dcr = 0x0E, /* data configuration register */ Imr = 0x0F, /* interrupt mask */ }; enum { /* Page 1, read/write */ Par0 = 0x01, /* physical address register 0 */ Curr = 0x07, /* current page register */ Mar0 = 0x08, /* multicast address register 0 */ }; enum { /* Interrupt Status Register */ Prx = 0x01, /* packet received */ Ptx = 0x02, /* packet transmitted */ Rxe = 0x04, /* receive error */ Txe = 0x08, /* transmit error */ Ovw = 0x10, /* overwrite warning */ Cnt = 0x20, /* counter overflow */ Rdc = 0x40, /* remote DMA complete */ Rst = 0x80, /* reset status */ }; enum { /* Interrupt Mask Register */ Prxe = 0x01, /* packet received interrupt enable */ Ptxe = 0x02, /* packet transmitted interrupt enable */ Rxee = 0x04, /* receive error interrupt enable */ Txee = 0x08, /* transmit error interrupt enable */ Ovwe = 0x10, /* overwrite warning interrupt enable */ Cnte = 0x20, /* counter overflow interrupt enable */ Rdce = 0x40, /* DMA complete interrupt enable */ }; enum { /* Data Configuration register */ Wts = 0x01, /* word transfer select */ Bos = 0x02, /* byte order select */ Las = 0x04, /* long address select */ Ls = 0x08, /* loopback select */ Arm = 0x10, /* auto-initialise remote */ Ft1 = (0x00<<5), /* FIFO threshhold select 1 byte/word */ Ft2 = (0x01<<5), /* FIFO threshhold select 2 bytes/words */ Ft4 = (0x02<<5), /* FIFO threshhold select 4 bytes/words */ Ft6 = (0x03<<5), /* FIFO threshhold select 6 bytes/words */ }; enum { /* Transmit Configuration Register */ Crc = 0x01, /* inhibit CRC */ Lb = 0x02, /* internal loopback */ Atd = 0x08, /* auto transmit disable */ Ofst = 0x10, /* collision offset enable */ }; enum { /* Transmit Status Register */ Ptxok = 0x01, /* packet transmitted */ Col = 0x04, /* transmit collided */ Abt = 0x08, /* tranmit aborted */ Crs = 0x10, /* carrier sense lost */ Fu = 0x20, /* FIFO underrun */ Cdh = 0x40, /* CD heartbeat */ Owc = 0x80, /* out of window collision */ }; enum { /* Receive Configuration Register */ Sep = 0x01, /* save errored packets */ Ar = 0x02, /* accept runt packets */ Ab = 0x04, /* accept broadcast */ Am = 0x08, /* accept multicast */ Pro = 0x10, /* promiscuous physical */ Mon = 0x20, /* monitor mode */ }; enum { /* Receive Status Register */ Prxok = 0x01, /* packet received intact */ Crce = 0x02, /* CRC error */ Fae = 0x04, /* frame alignment error */ Fo = 0x08, /* FIFO overrun */ Mpa = 0x10, /* missed packet */ Phy = 0x20, /* physical/multicast address */ Dis = 0x40, /* receiver disabled */ Dfr = 0x80, /* deferring */ }; typedef struct { uchar status; uchar next; uchar len0; uchar len1; } Hdr; static void | |
| 1993/1117 | dp8390disable(Dp8390 *dp8390) | |
| 1992/1222 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1992/1222 | 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. * We need the timeout because there may not be a real * chip there if this is called when probing for a device * at boot. */ | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAabort|Stp); slowoutb(port+Rbcr0, 0); slowoutb(port+Rbcr1, 0); for(timo = 10000; (slowinb(port+Isr) & Rst) == 0 && timo; timo--) | |
| 1992/1222 | ; } | |
| 1993/0212 | static void | |
| 1993/1117 | dp8390ring(Dp8390 *dp8390) | |
| 1993/0212 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1993/0212 | ||
| 1995/0409 | slowoutb(port+Pstart, dp8390->pstart); slowoutb(port+Pstop, dp8390->pstop); slowoutb(port+Bnry, dp8390->pstop-1); | |
| 1993/0212 | ||
| 1995/0409 | slowoutb(port+Cr, Page1|RDMAabort|Stp); slowoutb(port+Curr, dp8390->pstart); slowoutb(port+Cr, Page0|RDMAabort|Stp); | |
| 1993/0915 | ||
| 1993/1117 | dp8390->nxtpkt = dp8390->pstart; | |
| 1993/0212 | } | |
| 1992/1222 | void | |
| 1993/1116 | dp8390setea(Ether *ether) | |
| 1992/1222 | { | |
| 1993/1118 | ulong port = ((Dp8390*)ether->private)->dp8390; | |
| 1992/1222 | uchar cr; int i; /* * Set the ethernet address into the chip. * Take care to restore the command register * afterwards. We don't care about multicast * addresses as we never set the multicast * enable. */ | |
| 1995/0409 | cr = slowinb(port+Cr) & ~Txp; slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); | |
| 1993/1116 | for(i = 0; i < sizeof(ether->ea); i++) | |
| 1995/0409 | slowoutb(port+Par0+i, ether->ea[i]); slowoutb(port+Cr, cr); | |
| 1992/1222 | } | |
| 1993/0915 | void | |
| 1993/1116 | dp8390getea(Ether *ether) | |
| 1993/0915 | { | |
| 1993/1118 | ulong port = ((Dp8390*)ether->private)->dp8390; | |
| 1993/0915 | uchar cr; int i; /* | |
| 1993/1116 | * Get the ethernet address from the chip. | |
| 1993/0915 | * Take care to restore the command register * afterwards. We don't care about multicast * addresses as we never set the multicast * enable. */ | |
| 1995/0409 | cr = slowinb(port+Cr) & ~Txp; slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); | |
| 1993/1116 | for(i = 0; i < sizeof(ether->ea); i++) | |
| 1995/0409 | ether->ea[i] = slowinb(port+Par0+i); slowoutb(port+Cr, cr); | |
| 1993/0915 | } | |
| 1994/0128 | void* | |
| 1993/1117 | dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len) | |
| 1992/1222 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1992/1222 | uchar cr; int timo; /* | |
| 1993/0212 | * Read some data at offset 'from' in the card's memory | |
| 1992/1222 | * using the DP8390 remote DMA facility, and place it at * 'to' in main memory, via the I/O data port. */ | |
| 1995/0409 | cr = slowinb(port+Cr) & ~Txp; slowoutb(port+Cr, Page0|RDMAabort|Sta); slowoutb(port+Isr, Rdc); | |
| 1992/1222 | /* * Set up the remote DMA address and count. */ | |
| 1993/1117 | if(dp8390->bit16) | |
| 1992/1222 | len = ROUNDUP(len, 2); | |
| 1995/0409 | slowoutb(port+Rbcr0, len & 0xFF); slowoutb(port+Rbcr1, (len>>8) & 0xFF); slowoutb(port+Rsar0, from & 0xFF); slowoutb(port+Rsar1, (from>>8) & 0xFF); | |
| 1992/1222 | /* * Start the remote DMA read and suck the data * out of the I/O port. */ | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAread|Sta); | |
| 1993/1117 | if(dp8390->bit16) inss(dp8390->data, to, len/2); | |
| 1992/1222 | else | |
| 1993/1117 | insb(dp8390->data, to, len); | |
| 1992/1222 | /* * Wait for the remote DMA to complete. The timeout * is necessary because we may call this routine on * a non-existent chip during initialisation and, due * to the miracles of the bus, we could get this far * and still be talking to a slot full of nothing. */ | |
| 1995/0409 | for(timo = 10000; (slowinb(port+Isr) & Rdc) == 0 && timo; timo--) | |
| 1992/1222 | ; | |
| 1995/0409 | slowoutb(port+Isr, Rdc); slowoutb(port+Cr, cr); | |
| 1992/1222 | return to; } | |
| 1994/0128 | void* | |
| 1993/1118 | dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len) | |
| 1992/1222 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; ulong crda; | |
| 1992/1222 | uchar cr; | |
| 1994/0201 | int s, tries; | |
| 1992/1222 | ||
| 1994/0202 | /* * Keep out interrupts since reading and writing * use the same DMA engine. */ | |
| 1994/0201 | s = splhi(); | |
| 1994/0202 | ||
| 1992/1222 | /* | |
| 1993/0212 | * Write some data to offset 'to' in the card's memory | |
| 1992/1222 | * using the DP8390 remote DMA facility, reading it at * 'from' in main memory, via the I/O data port. */ | |
| 1995/0409 | cr = slowinb(port+Cr) & ~Txp; slowoutb(port+Cr, Page0|RDMAabort|Sta); slowoutb(port+Isr, Rdc); | |
| 1992/1222 | ||
| 1993/1118 | if(dp8390->bit16) | |
| 1993/0212 | len = ROUNDUP(len, 2); | |
| 1992/1222 | /* * Set up the remote DMA address and count. | |
| 1993/0212 | * This is straight from the DP8390[12D] datasheet, hence * the initial set up for read. | |
| 1992/1222 | */ | |
| 1993/1118 | crda = to-1-dp8390->bit16; | |
| 1995/0409 | slowoutb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF); slowoutb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF); slowoutb(port+Rsar0, crda & 0xFF); slowoutb(port+Rsar1, (crda>>8) & 0xFF); slowoutb(port+Cr, Page0|RDMAread|Sta); | |
| 1992/1222 | ||
| 1993/0212 | for(;;){ | |
| 1995/0409 | crda = slowinb(port+Crda0); crda |= slowinb(port+Crda1)<<8; | |
| 1993/0212 | if(crda == to){ /* * Start the remote DMA write and make sure * the registers are correct. */ | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAwrite|Sta); | |
| 1992/1222 | ||
| 1995/0409 | crda = slowinb(port+Crda0); crda |= slowinb(port+Crda1)<<8; | |
| 1993/0212 | if(crda != to) panic("crda write %d to %d\n", crda, to); break; } } | |
| 1992/1222 | /* | |
| 1993/0212 | * Pump the data into the I/O port. | |
| 1992/1222 | */ | |
| 1993/1118 | if(dp8390->bit16) outss(dp8390->data, from, len/2); | |
| 1992/1222 | else | |
| 1993/1118 | outsb(dp8390->data, from, len); | |
| 1992/1222 | /* | |
| 1994/0202 | * Wait for the remote DMA to finish. It should * be almost immediate. | |
| 1992/1222 | */ | |
| 1994/0201 | tries = 0; | |
| 1995/0409 | while((slowinb(port+Isr) & Rdc) == 0){ | |
| 1994/0202 | if(tries++ >= 100000){ print("dp8390write dma timed out\n"); | |
| 1994/0201 | break; } | |
| 1994/0202 | } | |
| 1992/1222 | ||
| 1995/0409 | slowoutb(port+Isr, Rdc); slowoutb(port+Cr, cr); | |
| 1994/0202 | splx(s); | |
| 1992/1222 | return (void*)to; } | |
| 1993/0212 | static uchar | |
| 1993/1118 | getcurr(Dp8390 *dp8390) | |
| 1993/0212 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1993/0212 | uchar cr, curr; | |
| 1995/0409 | cr = slowinb(port+Cr) & ~Txp; slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); curr = slowinb(port+Curr); slowoutb(port+Cr, cr); | |
| 1993/0212 | return curr; } | |
| 1993/0213 | static void | |
| 1993/1116 | receive(Ether *ether) | |
| 1993/0213 | { | |
| 1993/1118 | Dp8390 *dp8390; uchar curr, *pkt; | |
| 1992/1222 | Hdr hdr; | |
| 1993/1118 | ulong port, data, len, len1; | |
| 1992/1222 | ||
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){ | |
| 1993/1116 | ether->inpackets++; | |
| 1992/1222 | ||
| 1993/1118 | data = dp8390->nxtpkt*Dp8390BufSz; if(dp8390->ram) memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr)); else dp8390read(dp8390, &hdr, data, sizeof(Hdr)); | |
| 1992/1222 | /* | |
| 1993/0212 | * Don't believe the upper byte count, work it * out from the software next-page pointer and * the current next-page pointer. | |
| 1992/1222 | */ | |
| 1993/1118 | if(hdr.next > dp8390->nxtpkt) len1 = hdr.next - dp8390->nxtpkt - 1; | |
| 1993/0212 | else | |
| 1993/1118 | len1 = (dp8390->pstop-dp8390->nxtpkt) + (hdr.next-dp8390->pstart) - 1; | |
| 1993/0212 | if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) len1--; len = ((len1<<8)|hdr.len0)-4; /* * Chip is badly scrogged, reinitialise the ring. */ | |
| 1993/1118 | if(hdr.next < dp8390->pstart || hdr.next >= dp8390->pstop | |
| 1993/0212 | || len < 60 || len > sizeof(Etherpkt)){ | |
| 1993/1118 | print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n", | |
| 1993/0212 | hdr.status, hdr.next, hdr.len0, hdr.len1, len); | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAabort|Stp); | |
| 1993/1118 | dp8390ring(dp8390); | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAabort|Sta); | |
| 1992/1222 | return; } | |
| 1993/0212 | /* | |
| 1993/1116 | * 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. | |
| 1994/0202 | * * We could conceivably remove the copy into rpkt here by wrapping * this up with the etherrloop code. | |
| 1993/0212 | */ | |
| 1993/1116 | if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){ | |
| 1993/1118 | pkt = (uchar*)ðer->rpkt; | |
| 1992/1222 | data += sizeof(Hdr); | |
| 1993/1118 | len1 = len; | |
| 1993/0212 | ||
| 1993/1118 | if((data+len1) >= dp8390->pstop*Dp8390BufSz){ ulong count = dp8390->pstop*Dp8390BufSz - data; | |
| 1993/0212 | ||
| 1993/1118 | if(dp8390->ram) memmove(pkt, (void*)(ether->mem+data), count); else dp8390read(dp8390, pkt, data, count); | |
| 1993/0212 | pkt += count; | |
| 1993/1118 | data = dp8390->pstart*Dp8390BufSz; len1 -= count; | |
| 1992/1222 | } | |
| 1993/1118 | if(len1){ if(dp8390->ram) memmove(pkt, (void*)(ether->mem+data), len1); else dp8390read(dp8390, pkt, data, len1); } | |
| 1993/0212 | ||
| 1993/1116 | /* * Copy the packet to whoever wants it. */ | |
| 1994/0715 | etherrloop(ether, ðer->rpkt, len, 1); | |
| 1992/1222 | } | |
| 1993/0212 | /* | |
| 1993/1118 | * Finished with this packet, update the | |
| 1993/0212 | * hardware and software ring pointers. */ | |
| 1993/1118 | dp8390->nxtpkt = hdr.next; | |
| 1993/0212 | hdr.next--; | |
| 1993/1118 | if(hdr.next < dp8390->pstart) hdr.next = dp8390->pstop-1; | |
| 1995/0409 | slowoutb(port+Bnry, hdr.next); | |
| 1992/1222 | } } | |
| 1993/1118 | static int | |
| 1993/1119 | istxavail(void *arg) | |
| 1992/1222 | { | |
| 1993/1119 | return ((Ether*)arg)->tlen == 0; | |
| 1993/1118 | } | |
| 1993/0212 | ||
| 1993/1118 | static long | |
| 1993/1120 | write(Ether *ether, void *buf, long len) | |
| 1993/1118 | { Dp8390 *dp8390; ulong port; | |
| 1993/1120 | Etherpkt *pkt; | |
| 1993/0213 | ||
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/0213 | ||
| 1993/1119 | tsleep(ðer->tr, istxavail, ether, 10000); if(ether->tlen){ print("dp8390: transmitter jammed\n"); return 0; | |
| 1993/0212 | } | |
| 1993/1120 | ether->tlen = len; | |
| 1993/1118 | ||
| 1993/1120 | /* * If it's a shared-memory interface, copy the packet * directly to the shared-memory area. Otherwise, copy * it to a staging buffer so the I/O-port write can be * done in one. */ | |
| 1993/1118 | if(dp8390->ram) | |
| 1993/1120 | pkt = (Etherpkt*)(ether->mem+dp8390->tstart*Dp8390BufSz); | |
| 1993/1118 | else | |
| 1993/1120 | pkt = ðer->tpkt; memmove(pkt, buf, len); | |
| 1993/1118 | ||
| 1993/1120 | /* * Give the packet a source address and make sure it * is of minimum length. */ memmove(pkt->s, ether->ea, sizeof(ether->ea)); if(len < ETHERMINTU){ memset(pkt->d+len, 0, ETHERMINTU-len); len = ETHERMINTU; } if(dp8390->ram == 0) dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, pkt, len); | |
| 1995/0409 | slowoutb(port+Tbcr0, len & 0xFF); slowoutb(port+Tbcr1, (len>>8) & 0xFF); slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta); | |
| 1993/1118 | ||
| 1993/1120 | return len; | |
| 1993/0212 | } | |
| 1993/1116 | static void overflow(Ether *ether) | |
| 1993/0212 | { | |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/0212 | uchar txp; int resend; | |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/0212 | /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ | |
| 1995/0409 | txp = slowinb(port+Cr) & Txp; slowoutb(port+Cr, Page0|RDMAabort|Stp); | |
| 1993/0212 | delay(2); | |
| 1995/0409 | slowoutb(port+Rbcr0, 0); slowoutb(port+Rbcr1, 0); | |
| 1993/0212 | resend = 0; | |
| 1995/0409 | if(txp && (slowinb(port+Isr) & (Txe|Ptx)) == 0) | |
| 1993/0212 | resend = 1; | |
| 1995/0409 | slowoutb(port+Tcr, Lb); slowoutb(port+Cr, Page0|RDMAabort|Sta); | |
| 1993/1118 | receive(ether); | |
| 1995/0409 | slowoutb(port+Isr, Ovw); slowoutb(port+Tcr, 0); | |
| 1993/0212 | if(resend) | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta); | |
| 1993/0212 | } | |
| 1993/1116 | static void | |
| 1993/1124 | interrupt(Ureg *ur, void *arg) | |
| 1993/0212 | { | |
| 1993/1124 | Ether *ether; | |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/0212 | uchar isr, r; | |
| 1992/1222 | ||
| 1993/1124 | USED(ur); ether = arg; | |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1992/1222 | /* * While there is something of interest, * clear all the interrupts and process. */ | |
| 1995/0409 | slowoutb(port+Imr, 0x00); while(isr = slowinb(port+Isr)){ | |
| 1992/1222 | if(isr & Ovw){ | |
| 1993/1116 | overflow(ether); | |
| 1995/0409 | slowoutb(port+Isr, Ovw); | |
| 1993/1116 | ether->overflows++; | |
| 1992/1222 | } /* * We have received packets. | |
| 1993/1116 | * Take a spin round the ring. and | |
| 1992/1222 | */ if(isr & (Rxe|Prx)){ | |
| 1993/1116 | receive(ether); | |
| 1995/0409 | slowoutb(port+Isr, Rxe|Prx); | |
| 1992/1222 | } /* * A packet completed transmission, successfully or * not. Start transmission on the next buffered packet, * and wake the output routine. */ if(isr & (Txe|Ptx)){ | |
| 1995/0409 | r = slowinb(port+Tsr); | |
| 1993/0212 | if(isr & Txe){ | |
| 1993/1118 | if((r & (Cdh|Fu|Crs|Abt))) print("dp8390: Tsr#%2.2ux\n", r); | |
| 1993/1116 | ether->oerrs++; | |
| 1993/0212 | } | |
| 1995/0409 | slowoutb(port+Isr, Txe|Ptx); | |
| 1993/0212 | if(isr & Ptx) | |
| 1993/1116 | ether->outpackets++; | |
| 1993/1119 | ether->tlen = 0; | |
| 1993/1116 | wakeup(ðer->tr); | |
| 1992/1222 | } | |
| 1993/0212 | if(isr & Cnt){ | |
| 1995/0409 | ether->frames += slowinb(port+Cntr0); ether->crcs += slowinb(port+Cntr1); ether->buffs += slowinb(port+Cntr2); slowoutb(port+Isr, Cnt); | |
| 1993/0212 | } | |
| 1992/1222 | } | |
| 1995/0409 | slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1993/1116 | } static void | |
| 1993/1118 | promiscuous(void *arg, int on) | |
| 1993/1116 | { | |
| 1993/1118 | Dp8390 *dp8390 = ((Ether*)arg)->private; | |
| 1993/1117 | ||
| 1993/1116 | /* * Set/reset promiscuous mode. */ if(on) | |
| 1995/0409 | slowoutb(dp8390->dp8390+Rcr, Pro|Ab); | |
| 1993/1116 | else | |
| 1995/0409 | slowoutb(dp8390->dp8390+Rcr, Ab); | |
| 1993/1116 | } | |
| 1993/1118 | static void attach(Ether *ether) | |
| 1993/1116 | { | |
| 1993/1118 | Dp8390 *dp8390 = ether->private; | |
| 1993/1117 | ||
| 1993/1116 | /* * 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. */ | |
| 1995/0409 | slowoutb(dp8390->dp8390+Rcr, Ab); slowinb(dp8390->dp8390+Cntr2); | |
| 1993/1116 | } | |
| 1993/1118 | int | |
| 1993/1116 | dp8390reset(Ether *ether) { | |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/1116 | ||
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/1116 | /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references * to the 3Com503 technical reference manual. */ | |
| 1993/1118 | dp8390disable(dp8390); if(dp8390->bit16) | |
| 1995/0409 | slowoutb(port+Dcr, Ft4|Ls|Wts); | |
| 1993/1116 | else | |
| 1995/0409 | slowoutb(port+Dcr, Ft4|Ls); | |
| 1993/1116 | ||
| 1995/0409 | slowoutb(port+Rbcr0, 0); slowoutb(port+Rbcr1, 0); | |
| 1993/1116 | ||
| 1995/0409 | slowoutb(port+Tcr, 0); slowoutb(port+Rcr, Mon); | |
| 1993/1116 | /* * Init the ring hardware and software ring pointers. * Can't initialise ethernet address as we may not know * it yet. */ | |
| 1993/1118 | dp8390ring(dp8390); | |
| 1995/0409 | slowoutb(port+Tpsr, dp8390->tstart); | |
| 1993/1116 | ||
| 1995/0409 | slowoutb(port+Isr, 0xFF); slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1993/1116 | /* * Leave the chip initialised, * but in monitor mode. */ | |
| 1995/0409 | slowoutb(port+Cr, Page0|RDMAabort|Sta); | |
| 1993/1116 | /* * Set up the software configuration. */ ether->attach = attach; ether->write = write; ether->interrupt = interrupt; ether->promiscuous = promiscuous; ether->arg = ether; return 0; | |
| 1992/1222 | } | |