From 657746c1ccb30c879e409a8ecba2aaf79fd6b80d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 23 Jun 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-06-23 --- ip/tcp.c | 2 +- mpc/dat.h | 1 + mpc/devpcmcia.c | 46 +-- mpc/devuart.c | 9 +- mpc/etherscc.c | 3 +- mpc/etherwavelan.c | 885 +++++++++++++++++++++++++++++++++++++++++++++ mpc/etherwavelan.h | 494 +++++++++++++++++++++++++ mpc/fns.h | 2 + mpc/io.h | 14 + mpc/main.c | 2 +- pc/etherwavelan.c | 865 +++++++++++++++++++++++++++++++++++++++++++- pc/wavelan.c | 168 +++++++++ port/devtinyfs.c | 2 +- 13 files changed, 2450 insertions(+), 43 deletions(-) create mode 100644 mpc/etherwavelan.c create mode 100644 mpc/etherwavelan.h create mode 100644 pc/wavelan.c diff --git a/ip/tcp.c b/ip/tcp.c index b558dbe588c430d8066a4bcbde18968ab8802a7a..04fcddfb6e8c9d60e18d6e500a6aad6d1a5d4b49 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -38,7 +38,7 @@ enum MSPTICK = 50, /* Milliseconds per timer tick */ DEF_MSS = 1460, /* Default mean segment */ DEF_RTT = 1000, /* Default round trip */ - DEF_KAT = 10000, /* Default time ms) between keep alives */ + DEF_KAT = 30000, /* Default time ms) between keep alives */ TCP_LISTEN = 0, /* Listen connection */ TCP_CONNECT = 1, /* Outgoing connection */ diff --git a/mpc/dat.h b/mpc/dat.h index ce845ecb59a35dd535b4a3723fad01d123cd04ab..55321fc5f28aca2b170578eed636a222dc837e6e 100644 --- a/mpc/dat.h +++ b/mpc/dat.h @@ -7,6 +7,7 @@ typedef struct Label Label; typedef struct Lock Lock; typedef struct Mach Mach; typedef struct Notsave Notsave; +typedef struct PCMmap PCMmap; typedef struct PMMU PMMU; typedef struct Map Map; typedef struct PCArch PCArch; diff --git a/mpc/devpcmcia.c b/mpc/devpcmcia.c index 0d5555ed701d434ac7065aabf51a9d537dd62fb5..24fc6156e8182579b7624cceb8dd5cc21c1e6091 100644 --- a/mpc/devpcmcia.c +++ b/mpc/devpcmcia.c @@ -11,7 +11,6 @@ * */ -typedef struct PCMmap PCMmap; typedef struct Slot Slot; typedef struct Conftab Conftab; @@ -93,18 +92,6 @@ struct Conftab ulong otherwait; }; -/* - * Map between ISA memory space and PCMCIA card memory space. - */ -struct PCMmap { - ulong ca; /* card address */ - ulong cea; /* card end address */ - ulong isa; /* ISA address */ - int len; /* length of the ISA area */ - int attr; /* attribute memory */ - int ref; -}; - /* a card slot */ struct Slot { @@ -160,8 +147,6 @@ enum static void pcmciaintr(Ureg *, void *); static void increfp(Slot *pp); static void decrefp(Slot *pp); -static PCMmap* pcmmap(Slot*, ulong, int, int); -static void pcmunmap(Slot*, PCMmap*); static Slot *slot; static nslot; @@ -243,7 +228,7 @@ pcmciareset(void) // 64K io io->pcmr[1].base = ISAMEM+0x300; io->pcmr[1].option = (0x6<<27) | (2<<16) | (4<<12) | (8<<7) - | Rport16 | Rio | Rvalid; + | Rport8 | Rio | Rvalid; // intrenable(VectorPIC+PCMCIAlevel, pcmciaintr, 0, BUSUNKNOWN); io->pscr = 0xFEF0FEF0; /* reset status */ @@ -318,13 +303,13 @@ pcmread(int slotno, int attr, void *a, long n, vlong offset) m = 0; if(waserror()){ if(m) - pcmunmap(pp, m); + pcmunmap(pp->slotno, m); nexterror(); } ac = a; for(len = n; len > 0; len -= i){ - m = pcmmap(pp, offset, 0, attr); + m = pcmmap(pp->slotno, offset, 0, attr); if(m == 0) error("can't map PCMCIA card"); if(offset + len > m->cea) @@ -333,7 +318,7 @@ pcmread(int slotno, int attr, void *a, long n, vlong offset) i = len; ka = KZERO|(m->isa + offset - m->ca); memmoveb(ac, (void*)ka, i); - pcmunmap(pp, m); + pcmunmap(pp->slotno, m); offset += i; ac += i; } @@ -502,12 +487,14 @@ pcmciaintr(Ureg *, void *) /* * get a map for pc card region, return corrected len */ -static PCMmap* -pcmmap(Slot *pp, ulong offset, int len, int attr) +PCMmap* +pcmmap(int slotno, ulong offset, int len, int attr) { PCMmap *m; ulong e; + Slot *pp; + pp = slot + slotno; if(attr == 0) panic("pcmmap"); @@ -530,9 +517,10 @@ pcmmap(Slot *pp, ulong offset, int len, int attr) return m; } -static void -pcmunmap(Slot *pp, PCMmap *m) +void +pcmunmap(int slotno, PCMmap *m) { + USED(slotno, m); } static int @@ -612,19 +600,21 @@ pcmio(int slotno, ISAConf *isa) return -1; if(pp->cpresent & (1<caddr); /* Reset adapter */ - m = pcmmap(pp, pp->caddr + Rconfig, 1, 1); + m = pcmmap(pp->slotno, pp->caddr + Rconfig, 1, 1); p = KADDR(m->isa + pp->caddr + Rconfig - m->ca); /* set configuration and interrupt type */ x = 1; - x |= ct->index<<1; +// x |= ct->index<<1; if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) { x |= Clevel; } +print("devpcmcia: x = %ux!\n", x); *p = x; delay(5); - pcmunmap(pp, m); + pcmunmap(pp->slotno, m); } return 0; } @@ -722,7 +712,7 @@ cisread(Slot *pp) pp->configed = 0; pp->nctab = 0; - m = pcmmap(pp, 0, 0, 1); + m = pcmmap(pp->slotno, 0, 0, 1); if(m == 0) return; pp->cisbase = KADDR(m->isa); @@ -743,7 +733,7 @@ cisread(Slot *pp) break; pp->cispos = this + (2+link); } - pcmunmap(pp, m); + pcmunmap(pp->slotno, m); } static ulong diff --git a/mpc/devuart.c b/mpc/devuart.c index e0bcd8a3fae2a481a272911c28d93d7dd63d6b64..c1450cbb4cc9738f41f7779bd7a21346f50dff62 100644 --- a/mpc/devuart.c +++ b/mpc/devuart.c @@ -828,8 +828,9 @@ txstart(Uart *p) * (re)start output */ static void -uartkick(Uart *p) +uartkick(void *arg) { + Uart *p = arg; ilock(&p->plock); if(p->outb == nil) txstart(p); @@ -843,8 +844,9 @@ uartkick(Uart *p) * restart input if its off */ static void -uartflow(Uart *p) +uartflow(void *arg) { + Uart *p = arg; if(p->modem) uartrts(p, 1); } @@ -1033,6 +1035,7 @@ uartintr(Uart *p, int events) iunlock(&p->plock); } } + USED(dokick); #ifdef XXX eieio(); /* TO DO: modem status isn't available on 82xFADS */ @@ -1290,7 +1293,7 @@ uartctl(Uart *p, char *cmd) /* let output drain for a while */ for(i = 0; i < 16 && qlen(p->oq); i++) - tsleep(&p->r, qlen, p->oq, 125); + tsleep(&p->r, (int (*)(void*))qlen, p->oq, 125); if(strncmp(cmd, "break", 5) == 0){ uartbreak(p, 0); diff --git a/mpc/etherscc.c b/mpc/etherscc.c index e4137bec6c37c06c5cfcf8d22494ef2cc5b7ef7b..83492b466311d32b360d09e8c124d8da0c71f95a 100644 --- a/mpc/etherscc.c +++ b/mpc/etherscc.c @@ -241,12 +241,13 @@ transmit(Ether* ether) } static void -interrupt(Ureg*, Ether *ether) +interrupt(Ureg*, void *arg) { int len, events, status; Ctlr *ctlr; BD *dre; Block *b; + Ether *ether = arg; ctlr = ether->ctlr; if(!ctlr->active) diff --git a/mpc/etherwavelan.c b/mpc/etherwavelan.c new file mode 100644 index 0000000000000000000000000000000000000000..e4adaa9c67e1e460d7a967fbe9bf5a8ed1450048 --- /dev/null +++ b/mpc/etherwavelan.c @@ -0,0 +1,885 @@ +/* + * Port for WaveLAN I PCMCIA cards running on 2.4 GHz + * important: only works for WaveLAN I and PCMCIA 2.4 GHz cards + * Based on Linux driver by Anthony D. Joseph MIT a.o. + * We have not added the frequency, encryption and NWID selection stuff, this + * can be done with the WaveLAN provided DOS programs: instconf.exe, setconf.exe, wfreqsel.exe, etc. + * Gerard Smit 07/22/98 + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/netif.h" +#include "etherif.h" +#include "etherwavelan.h" + + +static void wavelan_receive(Ether *ether); +static int txstart(Ether *ether); + +static void +hacr_write_slow(int base, uchar hacr) +{ + outb(HACR(base), hacr); + /* delay might only be needed sometimes */ + delay(1); +} /* hacr_write_slow */ + +static long +ifstat(Ether* ether, void* a, long n, ulong offset) +{ + Ctlr *ctlr; + int len; + char *p; + + ctlr = ether->ctlr; + p = malloc(READSTR); + len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts); + len += snprint(p+len, READSTR-len, "upinterrupts: %lud\n", ctlr->upinterrupts); + len += snprint(p+len, READSTR-len, "dninterrupts: %lud\n", ctlr->dninterrupts); + len += snprint(p+len, READSTR-len, "int_errors: %lud\n", ctlr->int_errors); + len += snprint(p+len, READSTR-len, "read_errors: %lud\n", ctlr->read_errors); + len += snprint(p+len, READSTR-len, "out_packets: %lud\n", ctlr->out_packets); + len += snprint(p+len, READSTR-len, "tx_too_long: %lud\n", ctlr->tx_too_long); + len += snprint(p+len, READSTR-len, "tx_DMA_underrun: %lud\n", ctlr->tx_DMA_underrun); + len += snprint(p+len, READSTR-len, "tx_carrier_error: %lud\n", ctlr->tx_carrier_error); + len += snprint(p+len, READSTR-len, "tx_congestion: %lud\n", ctlr->tx_congestion); + len += snprint(p+len, READSTR-len, "tx_heart_beat: %lud\n", ctlr->tx_heart_beat); + len += snprint(p+len, READSTR-len, "rx_overflow: %lud\n", ctlr->rx_overflow); + len += snprint(p+len, READSTR-len, "rx_overrun: %lud\n", ctlr->rx_overrun); + len += snprint(p+len, READSTR-len, "rx_crc_error: %lud\n", ctlr->rx_crc); + len += snprint(p+len, READSTR-len, "rx_no_sfd: %lud\n", ctlr->rx_no_sfd); + len += snprint(p+len, READSTR-len, "rx_dropped: %lud\n", ctlr->rx_dropped); + len += snprint(p+len, READSTR-len, "tx_packets: %lud\n", ctlr->tx_packets); + len += snprint(p+len, READSTR-len, "rx_packets: %lud\n", ctlr->rx_packets); + snprint(p+len, READSTR-len, "in_packets: %lud\n", ctlr->in_packets); + + n = readstr(offset, a, n, p); + free(p); + return n; +} + +static void +attach(Ether* ether) +{ + Ctlr *ctlr; + + ctlr = ether->ctlr; + ilock(&ctlr->wlock); + if(ctlr->attached){ + iunlock(&ctlr->wlock); + return; + } + ctlr->attached = 1; + iunlock(&ctlr->wlock); +} + +static void +interrupt_handler(Ether *ether, uchar status) +{ + Ctlr *ctlr; + int status0; + int tx_status; + int base; + ctlr = ether->ctlr; + base = ctlr->port; + + status0 = status; + + /* Return if no actual interrupt from i82593 */ + if(!(status0 & SR0_INTERRUPT)) { + print("Wavelan: Interrupt from dead card\n"); + return; + } + ctlr->status = status0; /* Save current status (for commands) */ + if (status0 & SR0_RECEPTION) { + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) { + print("wavelan: receive buffer overflow\n"); + ctlr->rx_overflow++; + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + wavelan_receive(ether); + if (status0 & SR0_EXECUTION) + print("wavelan_cs: interrupt is both rx and tx, status0 = %x\n", + status0); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + if (!(status0 & SR0_EXECUTION)) { + print("wavelan_cs: interrupt is neither rx or tx, status0 = %x\n", + status0); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + /* interrupt due to configure_done or IA_setup_done */ + if ((status0 & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE || + (status0 & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) { + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + /* so a transmit interrupt is remaining */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE) { + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); + if (!(tx_status & TX_OK)) { + if (tx_status & TX_FRTL) { + print("wavelan_cs: frame too long\n"); + ctlr->tx_too_long++; + } + if (tx_status & TX_UND_RUN) { + /* print("wavelan_csd: DMA underrun\n"); */ + ctlr->tx_DMA_underrun++; + } + if (tx_status & TX_LOST_CTS) { + /* print("wavelan: no CTS\n"); */ + ctlr->tx_carrier_error++; + } + if (tx_status & TX_LOST_CRS) { + /* print("wavelan: lost CRS\n"); */ + ctlr->tx_carrier_error++; + } + if (tx_status & TX_DEFER) { + /* print("wavelan: channel jammed\n"); */ + ctlr->tx_congestion++; + } + if (tx_status & TX_COLL) { + if (tx_status & TX_MAX_COL) { + /* print("wavelan_cs: channel congestion\n"); */ + ctlr->tx_congestion++; + } + } + if (tx_status & TX_HRT_BEAT) { + /* print("wavelan_cs: heart beat\n"); */ + ctlr->tx_heart_beat++; + } + } + + ctlr->tx_packets++; + ctlr->txbusy = 0; + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + txstart(ether); /* start new transfer if any */ + return; + } + print("wavelan: unknown interrupt\n"); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + +} + + +static Block* +rbpalloc(Block* (*f)(int)) +{ + Block *bp; + ulong addr; + + /* + * The receive buffers must be on a 32-byte + * boundary for EISA busmastering. + */ + if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){ + addr = (ulong)bp->base; + addr = ROUNDUP(addr, 32); + bp->rp = (uchar*)addr; + } + + return bp; +} + +static int +wavelan_cmd(Ether *ether, int base, char *str, int cmd, int result) +{ + int status; + unsigned long spin; + + /* Spin until the chip finishes executing its current command (if any) */ + do { + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + + outb(LCCR(base), cmd); /* Send the command */ + if(result == SR0_NO_RESULT) { /* Return immediately, if the command + doesn't return a result */ + return(TRUE); + } + + /* Busy wait while the LAN controller executes the command. + * Interrupts had better be enabled (or it will be a long wait). + * (We could enable just the WaveLAN's IRQ..., we do not bother this is only for setup commands) + */ + for(spin = 0; (spin < 10000000); spin++) + ; + outb(LCCR(base), CR0_STATUS_0 | OP0_NOP); + status = inb(LCSR(base)); + if(status & SR0_INTERRUPT){ + if (((status & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE) || + ((status & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) || + ((status & SR0_EVENT_MASK) == SR0_EXECUTION_ABORTED) || + ((status & SR0_EVENT_MASK) == SR0_DIAGNOSE_PASSED)) + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* acknowledge interrupt */ + else + interrupt_handler(ether, status); + } else { + print("wavelan_cmd: %s timeout, status0 = 0x%uX\n", str, status); + outb(OP0_ABORT, LCCR(base)); + spin = 0; + while(spin++ < 250) /* wait for the command to execute */ + delay(1); + return 0; + } + if((status & SR0_EVENT_MASK) != result){ + print("wavelan_cmd: %s failed, status0 = 0x%uX\n", str, status); + return 0; + } + return 1; +} /* wavelan_cmd */ + +static uchar +mmc_in(int base, uchar o) +{ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), o << 1); /* Set the read address */ + outb(MMD(base), 0); /* Required dummy write */ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + return((uchar) (inb(MMD(base)))); +} + +static int +read_ringbuf(Ether *ether, int addr, uchar *buf, int len) +{ Ctlr *ctlr; + int base; + int ring_ptr = addr; + int chunk_len; + uchar *buf_ptr = buf; + ctlr = ether->ctlr; + base = ctlr->port; + + /* If buf is NULL, just increment the ring buffer pointer */ + if (buf == 0) + return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE); + while (len > 0) { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(PIORL(base), ring_ptr & 0xff); + outb(PIORH(base), ((ring_ptr >> 8) & PIORH_MASK)); + /* First, determine how much we can read without wrapping around the + ring buffer */ + if ((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +static void +wavelan_hardware_send_packet(Ether *ether, void *buf, short length) +{ + Ctlr *ctlr; + int base; + register ushort xmtdata_base = TX_BASE; + ctlr = ether->ctlr; + base = ctlr->port; + + outb(PIORL(base), xmtdata_base & 0xff); + outb(PIORH(base), ((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), length & 0xff); /* lsb */ + outb(PIOP(base), length >> 8); /* msb */ + outsb(PIOP(base), buf, length); /* Send the data */ + outb(PIOP(base), OP0_NOP); /* Indicate end of transmit chain */ + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + /* Send the transmit command */ + wavelan_cmd(ether, base, "wavelan_hardware_send_packet(): transmit", OP0_TRANSMIT, + SR0_NO_RESULT); +} /* wavelan_hardware_send_packet */ + + + +static int +txstart(Ether *ether) +{ + Ctlr *ctlr; + Block *bp; + int base, length; + int status; + ctlr = ether->ctlr; + base = ctlr->port; + + for(;;) { + if(ctlr->txbp){ + bp = ctlr->txbp; + ctlr->txbp = 0; + } + else{ + bp = qget(ether->oq); + if(bp == nil) + break; + } + + length = BLEN(bp); + length = (ETH_ZLEN < length) ? length : ETH_ZLEN; + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + if ((status & SR3_EXEC_STATE_MASK) == SR3_EXEC_IDLE) { + wavelan_hardware_send_packet(ether, bp->rp, length); + freeb(bp); + ctlr->out_packets++; + } + else{ + ctlr->txbp = bp; + if(ctlr->txbusy == 0){ + ctlr->txbusy = 1; + } + break; + } + + } + return 0; +} /* wavelan txstart */ + + +static int +wavelan_start_of_frame(Ether *ether, int rfp, int wrap) +{ + Ctlr *ctlr; + int base; + int rp, len; + + ctlr = ether->ctlr; + base = ctlr->port; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(PIORL(base), rp & 0xff); + outb(PIORH(base), ((rp >> 8) & PIORH_MASK)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + if (len > 1600) { /* Sanity check on size */ + print("wavelan_cs: Received frame too large, rfp %d rp %d len 0x%x\n", + rfp, rp, len); + return -1; + } + + if(len < 7){ + print("wavelan_start_of_frame: Received null frame, rfp %d len 0x%x\n", rfp, len); + return(-1); + } + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) { /* magic formula ! */ + print("wavelan_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",wrap, rfp, len); + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +static void wavelan_read(Ether *ether, int fd_p, int sksize) +{ + Ctlr *ctlr; + Block *bp; + uchar stats[3]; + + ctlr = ether->ctlr; + + ctlr->rx_packets++; + + if ((bp = rbpalloc(allocb)) == 0){ + print("wavelan: could not rbpalloc(%d).\n", sksize); + ctlr->rx_dropped++; + return; + } else { + fd_p = read_ringbuf(ether, fd_p, ctlr->rbp->rp, sksize); + ctlr->rbp->wp = ctlr->rbp->rp + sksize; + /* read signal level, silence level and signal quality bytes */ + read_ringbuf(ether, (fd_p+4) % RX_SIZE+RX_BASE, stats, 3); + /* + * Hand the packet to the Network Module + */ + etheriq(ether, ctlr->rbp, 1); + ctlr->in_packets++; + ctlr->rbp = bp; + return; + } +} /* wavelan_read */ + +static void +wavelan_receive(Ether *ether) +{ + Ctlr *ctlr; + int base; + int newrfp, rp, len, f_start, status; + int i593_rfp, stat_ptr; + uchar c[4]; + + ctlr = ether->ctlr; + base = ctlr->port; + + /* Get the new receive frame pointer from the i82593 chip */ + outb(LCCR(base), CR0_STATUS_2 | OP0_NOP); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +// print("wavelan_cs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", +// i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + + if (newrfp == ctlr->rfp) + print("wavelan_cs: odd RFPs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", + i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + + while(newrfp != ctlr->rfp) { + rp = newrfp; + /* Find the first frame by skipping backwards over the frames */ + while (((f_start = wavelan_start_of_frame(ether,rp, newrfp)) != ctlr->rfp) && (f_start != -1)) + rp = f_start; + if(f_start == -1){ + print("wavelan_cs: cannot find start of frame "); + print(" i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", + i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + ctlr->rfp = rp; + continue; + } + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + read_ringbuf(ether, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + if(!(status & RX_RCV_OK)) { + if(status & RX_NO_SFD) ctlr->rx_no_sfd++; + if(status & RX_CRC_ERR) ctlr->rx_crc++; + if(status & RX_OVRRUN) ctlr->rx_overrun++; + + print("wavelan_cs: packet not received ok, status = 0x%x\n", status); + } else wavelan_read(ether, f_start, len - 2); + + ctlr->rfp = rp; /* one packet processed, skip it */ + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + ctlr->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); +} /* wavelan_receive */ + +static void +interrupt(Ureg*, void* arg) +{ + Ether *ether; + Ctlr *ctlr; + int base; + + ether = arg; + ctlr = ether->ctlr; + base = ctlr->port; + + ilock(&ctlr->wlock); + + ctlr->interrupts++; + + outb(LCCR(base), CR0_STATUS_0 | OP0_NOP); + interrupt_handler(ether, inb(LCSR(base))); + + iunlock(&ctlr->wlock); + +}; /* wavelan interrupt */ + + + +static void +promiscuous() +{ + ; +}; + +static void +multicast() +{ + ; +}; + +static void +mmc_read(int base, uchar o, uchar *b, int n) +{ + while (n-- > 0) { + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), o << 1); /* Set the read address */ + o++; + + outb(MMD(base), 0); /* Required dummy write */ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + *b++ = (uchar)(inb(MMD(base))); /* Now do the actual read */ + } +} /* mmc_read */ + + +static void +fee_wait(int base, int del, int numb) +{ int count = 0; + while ((count++ < numb) && (mmc_in(base, MMC_EECTRL) & MMR_FEE_STATUS_BUSY)) + delay(del); + if (count==numb) print("Wavelan: fee wait timed out\n"); +} + +static void +mmc_write_b(int base, uchar o, uchar b) +{ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), (uchar)((o << 1) | MMR_MMI_WR)); + outb(MMD(base), (uchar)(b)); +} /* mmc_write_b */ + +static void +mmc_write(int base, uchar o, uchar *b, int n) +{ + o += n; + b += n; + while (n-- > 0 ) + mmc_write_b(base, --o, *(--b)); +} /* mmc_write */ + + +static void wavelan_mmc_init(Ether *ether, int port) +{ + Ctlr *ctlr; + mmw_t m; + ctlr = ether->ctlr; + + memset(&m, 0x00, sizeof(m)); + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + m.mmw_encr_enable = 0; + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED; + m.mmw_thr_pre_set = 0x04; /* PCMCIA */ + m.mmw_quality_thr = 0x03; + m.mmw_netw_id_l = ctlr->nwid[1]; /* use nwid of PSA memory */ + m.mmw_netw_id_h = ctlr->nwid[0]; + + mmc_write(port, 0, (uchar *)&m, 37); /* size of mmw_t == 37 */ + + /* Start the modem's receive unit on version 2.00 */ + /* 2.4 Gz: half-card ver */ + /* 2.4 Gz */ + /* 2.4 Gz: position ch # */ + mmc_write_b(port, MMC_EEADDR, 0x0f); /* 2.4 Gz: named ch, wc=16 */ + mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Synths */ + MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */ + fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */ + /* 2.4 Gz */ + mmc_write_b(port, MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */ + mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Xmit Pwr */ + MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */ + fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */ + +} /* wavelan_mmc_init */ + + +int wavelan_diag(Ether *ether, int port) +{ + if (wavelan_cmd(ether, port, "wavelan_diag(): diagnose", OP0_DIAGNOSE, + SR0_DIAGNOSE_PASSED)){ + return 0; + } + print("wavelan_cs: i82593 Self Test failed!\n"); + return 1; +} /* wavelan_diag */ + + + +int wavelan_hw_config(int base, Ether *ether) +{ + struct i82593_conf_block cfblk; + + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 6; /* = 48 bytes rx and tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 0; + cfblk.throttle_enb = TRUE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 2; /* 7 byte preamble */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.exp_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.bof_met = 0; /* conform to 802.3 backoff algoritm */ + cfblk.ifrm_spc = 6; /* 96 bit times interframe spacing */ + cfblk.slottim_low = 0x10 & 0x7; /* 512 bit times slot time */ + cfblk.slottim_hi = 0x10 >> 3; + cfblk.max_retr = 15; + cfblk.prmisc = FALSE; /* Promiscuous mode ?? */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = 64 >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ + cfblk.mc_all = FALSE; /* No multicast all mode */ + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE;/* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = TRUE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + + outb(PIORL(base), (TX_BASE & 0xff)); + outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX)); + outb(PIOP(base), (sizeof(struct i82593_conf_block) & 0xff)); /* lsb */ + outb(PIOP(base), (sizeof(struct i82593_conf_block) >> 8)); /* msb */ + outsb(PIOP(base), ((char *) &cfblk), sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + if(!wavelan_cmd(ether, base, "wavelan_hw_config(): configure", OP0_CONFIGURE, + SR0_CONFIGURE_DONE)) + return(FALSE); + + /* Initialize adapter's ethernet MAC address */ + outb(PIORL(base), (TX_BASE & 0xff)); + outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX)); + outb(PIOP(base), WAVELAN_ADDR_SIZE); /* byte count lsb */ + outb(PIOP(base), 0); /* byte count msb */ + outsb(PIOP(base), ðer->ea[0], WAVELAN_ADDR_SIZE); + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + if(!wavelan_cmd(ether, base, "wavelan_hw_config(): ia-setup", OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + return(FALSE); + return(TRUE); +} /* wavelan_hw_config */ + +static void +wavelan_graceful_shutdown(Ether *ether, int base) +{ + int status; + + /* First, send the LAN controller a stop receive command */ + wavelan_cmd(ether, base, "wavelan_graceful_shutdown(): stop-rcv", OP0_STOP_RCV, + SR0_NO_RESULT); + /* Then, spin until the receive unit goes idle */ + do { + outb(LCCR(base), (OP0_NOP | CR0_STATUS_3)); + status = inb(LCSR(base)); + } while((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE); + + /* Now, spin until the chip finishes executing its current command */ + do { + outb(LCCR(base), (OP0_NOP | CR0_STATUS_3)); + status = inb(LCSR(base)); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); +} /* wavelan_graceful_shutdown */ + + +static void +wavelan_ru_start(Ether *ether, int base) +{ + Ctlr *ctlr; + ctlr = ether->ctlr; + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + + wavelan_graceful_shutdown(ether, base); + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + ctlr->rfp = 0; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(LCCR(base), OP1_RESET_RING_MNGMT); + ctlr->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_INT_ENABLE); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); + + /* Reset receive DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_RX_DMA_RESET); + delay(100); + outb(HACR(base), HACR_PWR_STAT); + delay(100); + + /* Receive DMA on channel 1 */ + wavelan_cmd(ether, base, "wavelan_ru_start(): rcv-enable", + (CR0_CHNL | OP0_RCV_ENABLE), SR0_NO_RESULT); + +} /* wavelan_ru_start */ + +static void +transmit(Ether* ether) +{ + Ctlr *ctlr; + ctlr = ether->ctlr; + + ilock(&ctlr->wlock); + txstart(ether); + iunlock(&ctlr->wlock); +} + + +static int +reset(Ether* ether) +{ + int slot, p; + int port; + char *pp; + Ctlr *ctlr; + PCMmap *m; + + ctlr = ether->ctlr = malloc(sizeof(Ctlr)); + ilock(&ctlr->wlock); + + if(ether->port == 0) + ether->port = 0x280; + port = ether->port; + + if((slot = pcmspecial(ether->type, ether)) < 0) { + print("could not find the PCMCIA WaveLAN card.\n"); + return -1; + } + + + print("#l%dWaveLAN: slot %d, port 0x%ulX irq %ld type %s\n", ether->ctlrno, slot, ether->port, ether->irq, ether->type); + + /* create a receive buffer */ + ctlr->rbp = rbpalloc(allocb); + +/* map a piece of memory (Attribute memory) first */ + m = pcmmap(slot, 0, 0x5000, 1); + if (m==0) { + return 1; + } +/* read ethernet address from the card and put in ether->ea */ + pp = (char*)(KZERO|m->isa) + 0x0E00 + 2*0x10; + for(p = 0; pea); p++) + ether->ea[p] = (uchar) (*(pp+2*p))&0xFF; + +// print("wavelan: dump of PSA memory\n"); +// pp = (char *) (KZERO|m->isa) + 0x0E00; +// for(p=0; p<64; p++) { +// print("%2uX ", (*(pp+2*p)&0xFF)); +// if (p%16==15) print("\n"); +// } + +/* read nwid from PSA into ctlr->nwid */ + pp = (char*)(KZERO|m->isa) + 0x0E00; + ctlr->nwid[0] = *(pp+2*0x23); + ctlr->nwid[1] = *(pp+2*0x24); + +/* access the configuration option register */ + pp = (char *)(KZERO|m->isa) + 0x4000; + *pp = *pp | COR_SW_RESET; + delay(5); + *pp = (COR_LEVEL_IRQ | COR_CONFIG); + delay(5); + + hacr_write_slow(port, HACR_RESET); + outb(HACR(port), HACR_DEFAULT); + + if(inb(HASR(port)) & HASR_NO_CLK) { + print("wavelan: modem not connected\n"); + return 1; + } + + wavelan_mmc_init(ether, port); /* initialize modem */ + + outb(LCCR(port), OP0_RESET); /* reset the LAN controller */ + delay(10); + + if (wavelan_hw_config(port, ether) == FALSE) + return 1; + + if (wavelan_diag(ether, port) == 1) + return 1; + wavelan_ru_start(ether, port); + + print("wavelan: init done; receiver started\n"); + + iunlock(&ctlr->wlock); + + ctlr->port = port; + ether->port = port; + ether->mbps = 2; /* 2 Mpbs */ + ether->attach = attach; + ether->transmit = transmit; + ether->interrupt = interrupt; + ether->ifstat = ifstat; + + ether->promiscuous = promiscuous; + ether->multicast = multicast; + ether->arg = ether; + + return 0; /* reset succeeded */ +} + +void +etherwavelanlink(void) +{ + addethercard("WaveLAN", reset); +} diff --git a/mpc/etherwavelan.h b/mpc/etherwavelan.h new file mode 100644 index 0000000000000000000000000000000000000000..b9ea4d696e13185a4b1aa729213467f4934e2c67 --- /dev/null +++ b/mpc/etherwavelan.h @@ -0,0 +1,494 @@ + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +enum { + OP0_NOP = 0, /* CHNL = 0 */ + OP0_SWIT_TO_PORT_1 = 0, /* CHNL = 1 */ + OP0_IA_SETUP = 1, + OP0_CONFIGURE = 2, + OP0_MC_SETUP = 3, + OP0_TRANSMIT = 4, + OP0_TDR = 5, + OP0_DUMP = 6, + OP0_DIAGNOSE = 7, + OP0_TRANSMIT_NO_CRC = 9, + OP0_RETRANSMIT = 12, + OP0_ABORT = 13, +/* Reception operations */ + OP0_RCV_ENABLE = 8, + OP0_RCV_DISABLE = 10, + OP0_STOP_RCV = 11, +/* Status pointer control operations */ + OP0_FIX_PTR = 15, /* CHNL = 1 */ + OP0_RLS_PTR = 15, /* CHNL = 0 */ + OP0_RESET = 14, +}; +enum { + CR0_CHNL = (1 << 4), /* 0=Channel 0, 1=Channel 1 */ + CR0_STATUS_0 = 0x00, + CR0_STATUS_1 = 0x20, + CR0_STATUS_2 = 0x40, + CR0_STATUS_3 = 0x60, + CR0_INT_ACK = (1 << 7), /* 0=No ack, 1=acknowledge */ +}; +/* Port 0 Status Register definitions */ +enum { + SR0_NO_RESULT = 0, /* dummy */ + SR0_EVENT_MASK = 0x0f, + SR0_IA_SETUP_DONE = 1, + SR0_CONFIGURE_DONE = 2, + SR0_MC_SETUP_DONE = 3, + SR0_TRANSMIT_DONE = 4, + SR0_TDR_DONE = 5, + SR0_DUMP_DONE = 6, + SR0_DIAGNOSE_PASSED = 7, + SR0_TRANSMIT_NO_CRC_DONE = 9, + SR0_RETRANSMIT_DONE = 12, + SR0_EXECUTION_ABORTED = 13, + SR0_END_OF_FRAME = 8, + SR0_RECEPTION_ABORTED = 10, + SR0_DIAGNOSE_FAILED = 15, + SR0_STOP_REG_HIT = 11, + + SR0_CHNL = (1 << 4), + SR0_EXECUTION = (1 << 5), + SR0_RECEPTION = (1 << 6), + SR0_INTERRUPT = (1 << 7), +}; +enum { + SR3_EXEC_STATE_MASK = 0x03, + SR3_EXEC_IDLE = 0, + SR3_TX_ABORT_IN_PROGRESS = 1, + SR3_EXEC_ACTIVE = 2, + SR3_ABORT_IN_PROGRESS = 3, + SR3_EXEC_CHNL = (1 << 2), + SR3_STP_ON_NO_RSRC = (1 << 3), + SR3_RCVING_NO_RSRC = (1 << 4), + SR3_RCV_STATE_MASK = 0x60, + SR3_RCV_IDLE = 0x00, + SR3_RCV_READY = 0x20, + SR3_RCV_ACTIVE = 0x40, + SR3_RCV_STOP_IN_PROG = 0x60, + SR3_RCV_CHNL = (1 << 7), +}; +/* Port 1 Command Register definitions */ +enum { + OP1_NOP = 0, + OP1_SWIT_TO_PORT_0 = 1, + OP1_INT_DISABLE = 2, + OP1_INT_ENABLE = 3, + OP1_SET_TS = 5, + OP1_RST_TS = 7, + OP1_POWER_DOWN = 8, + OP1_RESET_RING_MNGMT = 11, + OP1_RESET = 14, + OP1_SEL_RST = 15, +}; +enum { + CR1_STATUS_4 = 0x00, + CR1_STATUS_5 = 0x20, + CR1_STATUS_6 = 0x40, + CR1_STOP_REG_UPDATE = (1 << 7), +}; +/* Receive frame status bits */ +enum { + RX_RCLD = (1 << 0), + RX_IA_MATCH = (1 << 1), + RX_NO_AD_MATCH = (1 << 2), + RX_NO_SFD = (1 << 3), + RX_SRT_FRM = (1 << 7), + RX_OVRRUN = (1 << 8), + RX_ALG_ERR = (1 << 10), + RX_CRC_ERR = (1 << 11), + RX_LEN_ERR = (1 << 12), + RX_RCV_OK = (1 << 13), + RX_TYP_LEN = (1 << 15), +}; +/* Transmit status bits */ +enum { + TX_NCOL_MASK = 0x0f, + TX_FRTL = (1 << 4), + TX_MAX_COL = (1 << 5), + TX_HRT_BEAT = (1 << 6), + TX_DEFER = (1 << 7), + TX_UND_RUN = (1 << 8), + TX_LOST_CTS = (1 << 9), + TX_LOST_CRS = (1 << 10), + TX_LTCOL = (1 << 11), + TX_OK = (1 << 13), + TX_COLL = (1 << 15), +}; + +typedef struct { + Lock wlock; + int port; /* port number */ + int status; /* interrupt status */ + int stop; + int rfp; + int attached; + Block* rbp; /* receive buffer */ + Block* txbp; /* FIFO -based transmission */ + int txbusy; + uchar nwid[2]; /* Network ID */ + long interrupts; /* statistics */ + long upinterrupts; + long dninterrupts; + long out_packets; + long in_packets; + long tx_too_long; + long tx_DMA_underrun; + long tx_carrier_error; + long tx_congestion; + long tx_heart_beat; + long rx_overflow; + long rx_overrun; + long rx_crc; + long rx_no_sfd; + long rx_dropped; + long tx_packets; + long rx_packets; + long int_errors; + long read_errors; + int upenabled; + int dnenabled; + int waiting; +} Ctlr; + + +struct i82593_conf_block { + uchar fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + uchar throttle : 6, + cntrxint : 1, + contin : 1; + uchar addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + uchar lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + uchar : 4, + ifrm_spc : 4; + uchar : 5, + slottim_low : 3; + uchar slottim_hi : 3, + : 1, + max_retr : 4; + uchar prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + uchar cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + uchar : 2, + min_fr_len : 6; + uchar lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + uchar : 6, + fdx : 1, + : 1; + uchar dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + uchar dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + uchar fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + uchar rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* Host Adaptor Command Register bit definitions */ +enum { + HACR_LOF = (1 << 3), /* Lock Out Flag, toggle every 250ms */ + HACR_PWR_STAT = (1 << 4), /* Power State, 1=active, 0=sleep */ + HACR_TX_DMA_RESET = (1 << 5), /* Reset transmit DMA ptr on high */ + HACR_RX_DMA_RESET = (1 << 6), /* Reset receive DMA ptr on high */ + HACR_ROM_WEN = (1 << 7), /* EEPROM write enabled when true */ + + HACR_RESET = (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET), + HACR_DEFAULT = (HACR_PWR_STAT), +}; +/* Host Adapter Status Register bit definitions */ +enum { + HASR_MMI_BUSY = (1 << 2), /* MMI is busy when true */ + HASR_LOF = (1 << 3), /* Lock out flag status */ + HASR_NO_CLK = (1 << 4), /* active when modem not connected */ +}; +/* Miscellaneous bit definitions */ +enum { + PIORH_SEL_TX = (1 << 5), /* PIOR points to 0=rx/1=tx buffer */ + MMR_MMI_WR = (1 << 0), /* Next MMI cycle is 0=read, 1=write */ + PIORH_MASK = 0x1f, /* only low 5 bits are significant */ + RPLH_MASK = 0x1f, /* only low 5 bits are significant */ + MMI_ADDR_MASK = 0x7e, /* Bits 1-6 of MMR are significant */ +}; +/* Attribute Memory map */ +enum { + CIS_ADDR = 0x0000, /* Card Information Status Register */ + PSA_ADDR = 0x0e00, /* Parameter Storage Area address */ + EEPROM_ADDR = 0x1000, /* EEPROM address */ + COR_ADDR = 0x4000, /* Configuration Option Register */ +}; +/* Configuration Option Register bit definitions */ +enum { + COR_CONFIG = (1 << 0), /* Config Index, 0 when unconfigured */ + COR_SW_RESET = (1 << 7), /* Software Reset on true */ + COR_LEVEL_IRQ = (1 << 6), /* Level IRQ */ +}; +/* Local Memory map */ +enum { + RX_BASE = 0x0000, /* Receive memory, 8 kB */ + TX_BASE = 0x2000, /* Transmit memory, 2 kB */ + UNUSED_BASE = 0x2800, /* Unused, 22 kB */ + RX_SIZE = (TX_BASE-RX_BASE), /* Size of receive area */ + RX_SIZE_SHIFT = 6, /* Bits to shift in stop register */ +}; +#define MMI_WRITE(base,cmd,val) \ + while(inb(HASR(base)) & HASR_MMI_BUSY) ; \ + outb(MMR(base), ((cmd) << 1) | MMR_MMI_WR); \ + outb(MMD(base), va); + + +#define TRUE 1 +#define FALSE 0 +#define ETH_ZLEN 64 /* minimum length 64 bytes */ + +#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ + +#define SA_ADDR0 0x08 /* First octet of AT&T WaveLAN MAC addr */ +#define SA_ADDR1 0x00 /* Second octet of AT&T WaveLAN MAC addr */ +#define SA_ADDR2 0x0E /* Third octet of AT&T WaveLAN MAC addr */ + +#define WAVELAN_MTU 1500 /* Maximum size of Wavelan packet */ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + /* For the PCMCIA Adapter, locations 0x00-0x0F are fixed at 00 */ + uchar psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + uchar psa_io_base_addr_2; /* [0x01] Base address 2 */ + uchar psa_io_base_addr_3; /* [0x02] Base address 3 */ + uchar psa_io_base_addr_4; /* [0x03] Base address 4 */ + uchar psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + uchar psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + uchar psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + uchar psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + uchar psa_int_req_no; /* [0x08] Interrupt Request Line */ + uchar psa_unused0[7]; /* [0x09-0x0F] unused */ + uchar psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; + /* [0x10-0x15] Universal (factory) MAC Address */ + uchar psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + uchar psa_univ_local_sel; /* [0x1C] Universal Local Selection */ + uchar psa_comp_number; /* [0x1D] Compatability Number: */ + uchar psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + uchar psa_feature_select; /* [0x1F] Call code required (1=on) */ + uchar psa_subband; /* [0x20] Subband */ + uchar psa_quality_thr; /* [0x21] Modem Quality Threshold */ + uchar psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + uchar psa_nwid[2]; /* [0x23-0x24] Network ID */ + uchar psa_nwid_select; /* [0x25] Network ID Select */ + uchar psa_encryption_select; /* [0x26] Encryption On Off */ + uchar psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + uchar psa_databus_width; /* [0x2F] AT Dbus width select 8/16 */ + uchar psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + uchar psa_reserved[4]; /* [0x38-0x3B] Reserved - fixed (00) */ + uchar psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + uchar psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + uchar psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; +enum { + PSA_UNIVERSAL = 0, /* Universal (factory) */ + PSA_LOCAL = 1, /* Local */ +}; +enum { + PSA_COMP_PC_AT_915 = 0, /* PC-AT 915 MHz */ + PSA_COMP_PC_MC_915 = 1, /* PC-MC 915 MHz */ + PSA_COMP_PC_AT_2400 = 2, /* PC-AT 2.4 GHz */ + PSA_COMP_PC_MC_2400 = 3, /* PC-MC 2.4 GHz */ + PSA_COMP_PCMCIA_915 = 4, /* PCMCIA 915 MHz */ +}; +enum { + PSA_SUBBAND_915 = 0, /* 915 MHz */ + PSA_SUBBAND_2425 = 1, /* 2425 MHz */ + PSA_SUBBAND_2460 = 2, /* 2460 MHz */ + PSA_SUBBAND_2484 = 3, /* 2484 MHz */ + PSA_SUBBAND_2430_5 = 4, /* 2430.5 MHz */ +}; +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + uchar mmw_encr_key[8]; /* 0x00--07 encryption key */ + uchar mmw_encr_enable; /* 0x08 enable/disable encryption */ + uchar mmw_unused0; /* 0x09 unused */ + uchar mmw_des_io_invert; /* 0x0A ??? */ + uchar mmw_unused1[5]; /* 0x0B - 0F unused */ + uchar mmw_loopt_sel; /* 0x10 looptest selection */ + uchar mmw_jabber_enable; /* 0x11 jabber timer enable */ + uchar mmw_freeze; /* 0x12 freeze / unfreeeze signal level */ + uchar mmw_anten_sel; /* 0x13 antenna selection */ + uchar mmw_ifs; /* 0x14 inter frame spacing */ + uchar mmw_mod_delay; /* 0x15 modem delay */ + uchar mmw_jam_time; /* 0x16 jamming time */ + uchar mmw_unused2; /* 0x17 unused */ + uchar mmw_thr_pre_set; /* 0x18 level threshold preset */ + uchar mmw_decay_prm; /* 0x19 decay parameters */ + uchar mmw_decay_updat_prm; /* 0x1A decay update parameterz */ + uchar mmw_quality_thr; /* 0x1B quality (z-quotient) threshold */ + uchar mmw_netw_id_l; /* 0x1C NWID low order byte */ + uchar mmw_netw_id_h; /* 0x1D NWID high order byte */ + uchar mmw_mode_sel; /* 0x1E */ + uchar mmw_dummy; /* 0x1F */ + uchar mmw_eectrl; /* 0x20 2.4 Gz */ + uchar mmw_eeaddr; /* 0x21 2.4 Gz */ + uchar mmw_eedatal; /* 0x22 2.4 Gz */ + uchar mmw_eedatah; /* 0x23 2.4 Gz */ + uchar mmw_analctrl; /* 0x24 2.4 Gz */ + +}; + +enum { MMC_EECTRL = 0x20, + MMC_EEADDR = 0x21, + MMC_ANALCTRL = 0x24, +}; +enum { + MMW_LOOPT_SEL_UNDEFINED = 0x40, /* undefined */ + MMW_LOOPT_SEL_INT = 0x20, /* activate Attention Request */ + MMW_LOOPT_SEL_LS = 0x10, /* looptest w/o collision avoidance */ + MMW_LOOPT_SEL_LT3A = 0x08, /* looptest 3a */ + MMW_LOOPT_SEL_LT3B = 0x04, /* looptest 3b */ + MMW_LOOPT_SEL_LT3C = 0x02, /* looptest 3c */ + MMW_LOOPT_SEL_LT3D = 0x01, /* looptest 3d */ +}; +enum { + MMW_ANTEN_SEL_SEL = 0x01, /* direct antenna selection */ + MMW_ANTEN_SEL_ALG_EN = 0x02, /* antenna selection algo. enable */ +}; + +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + uchar mmr_unused0[8]; /* 0x00..07 unused */ + uchar mmr_des_status; /* 0x08 encryption status */ + uchar mmr_des_avail; /* 0x09 encryption available (0x55 read) */ + uchar mmr_des_io_invert; /* 0x0A des I/O invert register */ + uchar mmr_unused1[5]; /* 0x0B..0F unused */ + uchar mmr_dce_status; /* 0x10 DCE status */ + uchar mmr_mmr_dsp_id; /* 0x11 DSP id (AA = Deadalus rev A) + uchar mmr_unused2[2]; /* 0x12..13 unused */ + uchar mmr_correct_nwid_l; /* 0x14 no. of correct NWID's rxd (low) */ + uchar mmr_correct_nwid_h; /* 0x15 no. of correct NWID's rxd (high) */ + uchar mmr_wrong_nwid_l; /* 0x16 count of wrong NWID's received (low) */ + uchar mmr_wrong_nwid_h; /* 0x17 count of wrong NWID's received (high) */ + uchar mmr_thr_pre_set; /* 0x18 level threshold preset */ + uchar mmr_signal_lvl; /* 0x19 signal level */ + uchar mmr_silence_lvl; /* 0x1A silence level */ + uchar mmr_sgnl_qual; /* 0x1B signal quality */ + uchar mmr_netw_id_l; /* 0x1C NWID low order byte ??? */ + uchar mmr_unused3[3]; /* 0x1D..1F unused */ + uchar mmr_fee_status; /* 0x20 status of frequency eeprom */ + uchar mmr_unused4[1]; /* 0x21 */ + uchar mmr_fee_data_l; /* 0x22 read data from eeprom (low) */ + uchar mmr_fee_data_h; /* 0x23 read data from eeprom (high) */ +}; +enum { + MMR_DCE_STATUS_ENERG_DET = 0x01, /* energy detected */ + MMR_DCE_STATUS_LOOPT_IND = 0x02, /* loop test indicated */ + MMR_DCE_STATUS_XMTITR_IND = 0x04, /* transmitter on */ + MMR_DCE_STATUS_JBR_EXPIRED = 0x08, /* jabber timer expired */ +}; +enum { + MMR_FEE_STATUS_ID = 0xF0, /* modem revision id */ + MMR_FEE_STATUS_DWLD = 0x08, /* download in progress */ + MMR_FEE_STATUS_BUSY = 0x04, /* EEprom busy */ +}; +enum { + MMR_SGNL_QUAL_0 = 0x01, /* signal quality 0 */ + MMR_SGNL_QUAL_1 = 0x02, /* signal quality 1 */ + MMR_SGNL_QUAL_2 = 0x04, /* signal quality 2 */ + MMR_SGNL_QUAL_3 = 0x08, /* signal quality 3 */ + MMR_SGNL_QUAL_S_A = 0x80, /* currently selected antenna */ +}; +#define MMR_LEVEL_MASK 0x3F + +/* fields in MMC registers that relate to EEPROM in WaveMODEM daughtercard */ +enum{ + MMC_EECTRL_EEPRE = 0x10, /* 2.4 Gz EEPROM Protect Reg Enable */ + MMC_EECTRL_DWLD = 0x08, /* 2.4 Gz EEPROM Download Synths */ + MMC_EECTRL_EEOP = 0x07, /* 2.4 Gz EEPROM Opcode mask */ + MMC_EECTRL_EEOP_READ = 0x06, /* 2.4 Gz EEPROM Read Opcode */ + MMC_EEADDR_CHAN = 0xf0, /* 2.4 Gz EEPROM Channel # mask */ + MMC_EEADDR_WDCNT = 0x0f, /* 2.4 Gz EEPROM DNLD WordCount-1 */ + MMC_ANALCTRL_ANTPOL = 0x02, /* 2.4 Gz Antenna Polarity mask */ + MMC_ANALCTRL_EXTANT = 0x01, /* 2.4 Gz External Antenna mask */ +}; +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + +#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) + +struct wl_cntrs { + int pkt_arp; + int pkt_ein[32]; + int pkt_lin[128/8]; + int pkt_eout[32]; + int pkt_lout[128/8]; +}; +typedef struct wl_cntrs *wl_cntrs_t; + +#endif /* WAVELAN_H */ diff --git a/mpc/fns.h b/mpc/fns.h index 62989eff38400f963b1837095e400de4fb8bbab5..104a2b08c5ec2ac2be53c247d15d9bf31a9b208f 100644 --- a/mpc/fns.h +++ b/mpc/fns.h @@ -70,6 +70,8 @@ void outs(int, ushort); void outss(int, void*, int); void outl(int, ulong); void outsl(int, void*, int); +PCMmap* pcmmap(int, ulong, int, int); +void pcmunmap(int, PCMmap*); int pcmspecial(char*, ISAConf*); void pcmspecialclose(int); #define procrestore(p) diff --git a/mpc/io.h b/mpc/io.h index 5c8f961c4b96f68b28ce8ccd14cc9843310cafe1..3e76a8003fcfd5fe2777c0ac101a16c7ba496e40 100644 --- a/mpc/io.h +++ b/mpc/io.h @@ -576,3 +576,17 @@ enum { BusXPRESS, /* Express System Bus */ }; +/* + * PCMCIA support code. + */ +/* + * Map between ISA memory space and PCMCIA card memory space. + */ +struct PCMmap { + ulong ca; /* card address */ + ulong cea; /* card end address */ + ulong isa; /* ISA address */ + int len; /* length of the ISA area */ + int attr; /* attribute memory */ + int ref; +}; diff --git a/mpc/main.c b/mpc/main.c index 19e4e6fe5ccd6d78fd10343a4488f15efdba57a9..0c331862327deafd5ca715e3d6ca21a2fc3fe7de 100644 --- a/mpc/main.c +++ b/mpc/main.c @@ -309,7 +309,7 @@ getcfields(char* lp, char** fields, int n, char* sep) } static char BOOTARGS[] = - "ether0=type=SCC port=1 ea=08003e27df94\r\n" + "ether0=type=SCC port=1 ea=000086353a6b\r\n" "ether1=type=589E port=0x300\r\n"; static void diff --git a/pc/etherwavelan.c b/pc/etherwavelan.c index 249915fa1fbff69e9ff4ce9c3379b1109e1b820c..e4adaa9c67e1e460d7a967fbe9bf5a8ed1450048 100644 --- a/pc/etherwavelan.c +++ b/pc/etherwavelan.c @@ -1,5 +1,12 @@ /* + * Port for WaveLAN I PCMCIA cards running on 2.4 GHz + * important: only works for WaveLAN I and PCMCIA 2.4 GHz cards + * Based on Linux driver by Anthony D. Joseph MIT a.o. + * We have not added the frequency, encryption and NWID selection stuff, this + * can be done with the WaveLAN provided DOS programs: instconf.exe, setconf.exe, wfreqsel.exe, etc. + * Gerard Smit 07/22/98 */ + #include "u.h" #include "../port/lib.h" #include "mem.h" @@ -8,25 +15,867 @@ #include "io.h" #include "../port/error.h" #include "../port/netif.h" - #include "etherif.h" +#include "etherwavelan.h" + + +static void wavelan_receive(Ether *ether); +static int txstart(Ether *ether); + +static void +hacr_write_slow(int base, uchar hacr) +{ + outb(HACR(base), hacr); + /* delay might only be needed sometimes */ + delay(1); +} /* hacr_write_slow */ + +static long +ifstat(Ether* ether, void* a, long n, ulong offset) +{ + Ctlr *ctlr; + int len; + char *p; + + ctlr = ether->ctlr; + p = malloc(READSTR); + len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts); + len += snprint(p+len, READSTR-len, "upinterrupts: %lud\n", ctlr->upinterrupts); + len += snprint(p+len, READSTR-len, "dninterrupts: %lud\n", ctlr->dninterrupts); + len += snprint(p+len, READSTR-len, "int_errors: %lud\n", ctlr->int_errors); + len += snprint(p+len, READSTR-len, "read_errors: %lud\n", ctlr->read_errors); + len += snprint(p+len, READSTR-len, "out_packets: %lud\n", ctlr->out_packets); + len += snprint(p+len, READSTR-len, "tx_too_long: %lud\n", ctlr->tx_too_long); + len += snprint(p+len, READSTR-len, "tx_DMA_underrun: %lud\n", ctlr->tx_DMA_underrun); + len += snprint(p+len, READSTR-len, "tx_carrier_error: %lud\n", ctlr->tx_carrier_error); + len += snprint(p+len, READSTR-len, "tx_congestion: %lud\n", ctlr->tx_congestion); + len += snprint(p+len, READSTR-len, "tx_heart_beat: %lud\n", ctlr->tx_heart_beat); + len += snprint(p+len, READSTR-len, "rx_overflow: %lud\n", ctlr->rx_overflow); + len += snprint(p+len, READSTR-len, "rx_overrun: %lud\n", ctlr->rx_overrun); + len += snprint(p+len, READSTR-len, "rx_crc_error: %lud\n", ctlr->rx_crc); + len += snprint(p+len, READSTR-len, "rx_no_sfd: %lud\n", ctlr->rx_no_sfd); + len += snprint(p+len, READSTR-len, "rx_dropped: %lud\n", ctlr->rx_dropped); + len += snprint(p+len, READSTR-len, "tx_packets: %lud\n", ctlr->tx_packets); + len += snprint(p+len, READSTR-len, "rx_packets: %lud\n", ctlr->rx_packets); + snprint(p+len, READSTR-len, "in_packets: %lud\n", ctlr->in_packets); + + n = readstr(offset, a, n, p); + free(p); + return n; +} + +static void +attach(Ether* ether) +{ + Ctlr *ctlr; + + ctlr = ether->ctlr; + ilock(&ctlr->wlock); + if(ctlr->attached){ + iunlock(&ctlr->wlock); + return; + } + ctlr->attached = 1; + iunlock(&ctlr->wlock); +} + +static void +interrupt_handler(Ether *ether, uchar status) +{ + Ctlr *ctlr; + int status0; + int tx_status; + int base; + ctlr = ether->ctlr; + base = ctlr->port; + + status0 = status; + + /* Return if no actual interrupt from i82593 */ + if(!(status0 & SR0_INTERRUPT)) { + print("Wavelan: Interrupt from dead card\n"); + return; + } + ctlr->status = status0; /* Save current status (for commands) */ + if (status0 & SR0_RECEPTION) { + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) { + print("wavelan: receive buffer overflow\n"); + ctlr->rx_overflow++; + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + wavelan_receive(ether); + if (status0 & SR0_EXECUTION) + print("wavelan_cs: interrupt is both rx and tx, status0 = %x\n", + status0); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + if (!(status0 & SR0_EXECUTION)) { + print("wavelan_cs: interrupt is neither rx or tx, status0 = %x\n", + status0); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + /* interrupt due to configure_done or IA_setup_done */ + if ((status0 & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE || + (status0 & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) { + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + return; + } + /* so a transmit interrupt is remaining */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE) { + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); + if (!(tx_status & TX_OK)) { + if (tx_status & TX_FRTL) { + print("wavelan_cs: frame too long\n"); + ctlr->tx_too_long++; + } + if (tx_status & TX_UND_RUN) { + /* print("wavelan_csd: DMA underrun\n"); */ + ctlr->tx_DMA_underrun++; + } + if (tx_status & TX_LOST_CTS) { + /* print("wavelan: no CTS\n"); */ + ctlr->tx_carrier_error++; + } + if (tx_status & TX_LOST_CRS) { + /* print("wavelan: lost CRS\n"); */ + ctlr->tx_carrier_error++; + } + if (tx_status & TX_DEFER) { + /* print("wavelan: channel jammed\n"); */ + ctlr->tx_congestion++; + } + if (tx_status & TX_COLL) { + if (tx_status & TX_MAX_COL) { + /* print("wavelan_cs: channel congestion\n"); */ + ctlr->tx_congestion++; + } + } + if (tx_status & TX_HRT_BEAT) { + /* print("wavelan_cs: heart beat\n"); */ + ctlr->tx_heart_beat++; + } + } + + ctlr->tx_packets++; + ctlr->txbusy = 0; + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + txstart(ether); /* start new transfer if any */ + return; + } + print("wavelan: unknown interrupt\n"); + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */ + +} + + +static Block* +rbpalloc(Block* (*f)(int)) +{ + Block *bp; + ulong addr; + + /* + * The receive buffers must be on a 32-byte + * boundary for EISA busmastering. + */ + if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){ + addr = (ulong)bp->base; + addr = ROUNDUP(addr, 32); + bp->rp = (uchar*)addr; + } + + return bp; +} + +static int +wavelan_cmd(Ether *ether, int base, char *str, int cmd, int result) +{ + int status; + unsigned long spin; + + /* Spin until the chip finishes executing its current command (if any) */ + do { + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + + outb(LCCR(base), cmd); /* Send the command */ + if(result == SR0_NO_RESULT) { /* Return immediately, if the command + doesn't return a result */ + return(TRUE); + } + + /* Busy wait while the LAN controller executes the command. + * Interrupts had better be enabled (or it will be a long wait). + * (We could enable just the WaveLAN's IRQ..., we do not bother this is only for setup commands) + */ + for(spin = 0; (spin < 10000000); spin++) + ; + outb(LCCR(base), CR0_STATUS_0 | OP0_NOP); + status = inb(LCSR(base)); + if(status & SR0_INTERRUPT){ + if (((status & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE) || + ((status & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) || + ((status & SR0_EVENT_MASK) == SR0_EXECUTION_ABORTED) || + ((status & SR0_EVENT_MASK) == SR0_DIAGNOSE_PASSED)) + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* acknowledge interrupt */ + else + interrupt_handler(ether, status); + } else { + print("wavelan_cmd: %s timeout, status0 = 0x%uX\n", str, status); + outb(OP0_ABORT, LCCR(base)); + spin = 0; + while(spin++ < 250) /* wait for the command to execute */ + delay(1); + return 0; + } + if((status & SR0_EVENT_MASK) != result){ + print("wavelan_cmd: %s failed, status0 = 0x%uX\n", str, status); + return 0; + } + return 1; +} /* wavelan_cmd */ + +static uchar +mmc_in(int base, uchar o) +{ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), o << 1); /* Set the read address */ + outb(MMD(base), 0); /* Required dummy write */ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + return((uchar) (inb(MMD(base)))); +} + +static int +read_ringbuf(Ether *ether, int addr, uchar *buf, int len) +{ Ctlr *ctlr; + int base; + int ring_ptr = addr; + int chunk_len; + uchar *buf_ptr = buf; + ctlr = ether->ctlr; + base = ctlr->port; + + /* If buf is NULL, just increment the ring buffer pointer */ + if (buf == 0) + return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE); + while (len > 0) { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(PIORL(base), ring_ptr & 0xff); + outb(PIORH(base), ((ring_ptr >> 8) & PIORH_MASK)); + /* First, determine how much we can read without wrapping around the + ring buffer */ + if ((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +static void +wavelan_hardware_send_packet(Ether *ether, void *buf, short length) +{ + Ctlr *ctlr; + int base; + register ushort xmtdata_base = TX_BASE; + ctlr = ether->ctlr; + base = ctlr->port; + + outb(PIORL(base), xmtdata_base & 0xff); + outb(PIORH(base), ((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), length & 0xff); /* lsb */ + outb(PIOP(base), length >> 8); /* msb */ + outsb(PIOP(base), buf, length); /* Send the data */ + outb(PIOP(base), OP0_NOP); /* Indicate end of transmit chain */ + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + /* Send the transmit command */ + wavelan_cmd(ether, base, "wavelan_hardware_send_packet(): transmit", OP0_TRANSMIT, + SR0_NO_RESULT); +} /* wavelan_hardware_send_packet */ + + + +static int +txstart(Ether *ether) +{ + Ctlr *ctlr; + Block *bp; + int base, length; + int status; + ctlr = ether->ctlr; + base = ctlr->port; + + for(;;) { + if(ctlr->txbp){ + bp = ctlr->txbp; + ctlr->txbp = 0; + } + else{ + bp = qget(ether->oq); + if(bp == nil) + break; + } + + length = BLEN(bp); + length = (ETH_ZLEN < length) ? length : ETH_ZLEN; + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + if ((status & SR3_EXEC_STATE_MASK) == SR3_EXEC_IDLE) { + wavelan_hardware_send_packet(ether, bp->rp, length); + freeb(bp); + ctlr->out_packets++; + } + else{ + ctlr->txbp = bp; + if(ctlr->txbusy == 0){ + ctlr->txbusy = 1; + } + break; + } + + } + return 0; +} /* wavelan txstart */ + + +static int +wavelan_start_of_frame(Ether *ether, int rfp, int wrap) +{ + Ctlr *ctlr; + int base; + int rp, len; + + ctlr = ether->ctlr; + base = ctlr->port; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(PIORL(base), rp & 0xff); + outb(PIORH(base), ((rp >> 8) & PIORH_MASK)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + if (len > 1600) { /* Sanity check on size */ + print("wavelan_cs: Received frame too large, rfp %d rp %d len 0x%x\n", + rfp, rp, len); + return -1; + } + + if(len < 7){ + print("wavelan_start_of_frame: Received null frame, rfp %d len 0x%x\n", rfp, len); + return(-1); + } + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) { /* magic formula ! */ + print("wavelan_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",wrap, rfp, len); + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +static void wavelan_read(Ether *ether, int fd_p, int sksize) +{ + Ctlr *ctlr; + Block *bp; + uchar stats[3]; + + ctlr = ether->ctlr; + + ctlr->rx_packets++; + + if ((bp = rbpalloc(allocb)) == 0){ + print("wavelan: could not rbpalloc(%d).\n", sksize); + ctlr->rx_dropped++; + return; + } else { + fd_p = read_ringbuf(ether, fd_p, ctlr->rbp->rp, sksize); + ctlr->rbp->wp = ctlr->rbp->rp + sksize; + /* read signal level, silence level and signal quality bytes */ + read_ringbuf(ether, (fd_p+4) % RX_SIZE+RX_BASE, stats, 3); + /* + * Hand the packet to the Network Module + */ + etheriq(ether, ctlr->rbp, 1); + ctlr->in_packets++; + ctlr->rbp = bp; + return; + } +} /* wavelan_read */ + +static void +wavelan_receive(Ether *ether) +{ + Ctlr *ctlr; + int base; + int newrfp, rp, len, f_start, status; + int i593_rfp, stat_ptr; + uchar c[4]; + + ctlr = ether->ctlr; + base = ctlr->port; + + /* Get the new receive frame pointer from the i82593 chip */ + outb(LCCR(base), CR0_STATUS_2 | OP0_NOP); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +// print("wavelan_cs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", +// i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + + if (newrfp == ctlr->rfp) + print("wavelan_cs: odd RFPs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", + i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + + while(newrfp != ctlr->rfp) { + rp = newrfp; + /* Find the first frame by skipping backwards over the frames */ + while (((f_start = wavelan_start_of_frame(ether,rp, newrfp)) != ctlr->rfp) && (f_start != -1)) + rp = f_start; + if(f_start == -1){ + print("wavelan_cs: cannot find start of frame "); + print(" i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n", + i593_rfp, ctlr->stop, newrfp, ctlr->rfp); + ctlr->rfp = rp; + continue; + } + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + read_ringbuf(ether, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + if(!(status & RX_RCV_OK)) { + if(status & RX_NO_SFD) ctlr->rx_no_sfd++; + if(status & RX_CRC_ERR) ctlr->rx_crc++; + if(status & RX_OVRRUN) ctlr->rx_overrun++; + + print("wavelan_cs: packet not received ok, status = 0x%x\n", status); + } else wavelan_read(ether, f_start, len - 2); + + ctlr->rfp = rp; /* one packet processed, skip it */ + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + ctlr->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); +} /* wavelan_receive */ + +static void +interrupt(Ureg*, void* arg) +{ + Ether *ether; + Ctlr *ctlr; + int base; + + ether = arg; + ctlr = ether->ctlr; + base = ctlr->port; + + ilock(&ctlr->wlock); + + ctlr->interrupts++; + + outb(LCCR(base), CR0_STATUS_0 | OP0_NOP); + interrupt_handler(ether, inb(LCSR(base))); + + iunlock(&ctlr->wlock); + +}; /* wavelan interrupt */ + + + +static void +promiscuous() +{ + ; +}; + +static void +multicast() +{ + ; +}; + +static void +mmc_read(int base, uchar o, uchar *b, int n) +{ + while (n-- > 0) { + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), o << 1); /* Set the read address */ + o++; + + outb(MMD(base), 0); /* Required dummy write */ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + *b++ = (uchar)(inb(MMD(base))); /* Now do the actual read */ + } +} /* mmc_read */ + + +static void +fee_wait(int base, int del, int numb) +{ int count = 0; + while ((count++ < numb) && (mmc_in(base, MMC_EECTRL) & MMR_FEE_STATUS_BUSY)) + delay(del); + if (count==numb) print("Wavelan: fee wait timed out\n"); +} + +static void +mmc_write_b(int base, uchar o, uchar b) +{ + while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */ + outb(MMR(base), (uchar)((o << 1) | MMR_MMI_WR)); + outb(MMD(base), (uchar)(b)); +} /* mmc_write_b */ + +static void +mmc_write(int base, uchar o, uchar *b, int n) +{ + o += n; + b += n; + while (n-- > 0 ) + mmc_write_b(base, --o, *(--b)); +} /* mmc_write */ + + +static void wavelan_mmc_init(Ether *ether, int port) +{ + Ctlr *ctlr; + mmw_t m; + ctlr = ether->ctlr; + + memset(&m, 0x00, sizeof(m)); + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + m.mmw_encr_enable = 0; + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED; + m.mmw_thr_pre_set = 0x04; /* PCMCIA */ + m.mmw_quality_thr = 0x03; + m.mmw_netw_id_l = ctlr->nwid[1]; /* use nwid of PSA memory */ + m.mmw_netw_id_h = ctlr->nwid[0]; + + mmc_write(port, 0, (uchar *)&m, 37); /* size of mmw_t == 37 */ + + /* Start the modem's receive unit on version 2.00 */ + /* 2.4 Gz: half-card ver */ + /* 2.4 Gz */ + /* 2.4 Gz: position ch # */ + mmc_write_b(port, MMC_EEADDR, 0x0f); /* 2.4 Gz: named ch, wc=16 */ + mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Synths */ + MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */ + fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */ + /* 2.4 Gz */ + mmc_write_b(port, MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */ + mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Xmit Pwr */ + MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */ + fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */ + +} /* wavelan_mmc_init */ + + +int wavelan_diag(Ether *ether, int port) +{ + if (wavelan_cmd(ether, port, "wavelan_diag(): diagnose", OP0_DIAGNOSE, + SR0_DIAGNOSE_PASSED)){ + return 0; + } + print("wavelan_cs: i82593 Self Test failed!\n"); + return 1; +} /* wavelan_diag */ + + + +int wavelan_hw_config(int base, Ether *ether) +{ + struct i82593_conf_block cfblk; + + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 6; /* = 48 bytes rx and tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 0; + cfblk.throttle_enb = TRUE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 2; /* 7 byte preamble */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.exp_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.bof_met = 0; /* conform to 802.3 backoff algoritm */ + cfblk.ifrm_spc = 6; /* 96 bit times interframe spacing */ + cfblk.slottim_low = 0x10 & 0x7; /* 512 bit times slot time */ + cfblk.slottim_hi = 0x10 >> 3; + cfblk.max_retr = 15; + cfblk.prmisc = FALSE; /* Promiscuous mode ?? */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = 64 >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ + cfblk.mc_all = FALSE; /* No multicast all mode */ + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE;/* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = TRUE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + + outb(PIORL(base), (TX_BASE & 0xff)); + outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX)); + outb(PIOP(base), (sizeof(struct i82593_conf_block) & 0xff)); /* lsb */ + outb(PIOP(base), (sizeof(struct i82593_conf_block) >> 8)); /* msb */ + outsb(PIOP(base), ((char *) &cfblk), sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + if(!wavelan_cmd(ether, base, "wavelan_hw_config(): configure", OP0_CONFIGURE, + SR0_CONFIGURE_DONE)) + return(FALSE); + + /* Initialize adapter's ethernet MAC address */ + outb(PIORL(base), (TX_BASE & 0xff)); + outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX)); + outb(PIOP(base), WAVELAN_ADDR_SIZE); /* byte count lsb */ + outb(PIOP(base), 0); /* byte count msb */ + outsb(PIOP(base), ðer->ea[0], WAVELAN_ADDR_SIZE); + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + outb(HACR(base), HACR_DEFAULT); + if(!wavelan_cmd(ether, base, "wavelan_hw_config(): ia-setup", OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + return(FALSE); + return(TRUE); +} /* wavelan_hw_config */ + +static void +wavelan_graceful_shutdown(Ether *ether, int base) +{ + int status; + + /* First, send the LAN controller a stop receive command */ + wavelan_cmd(ether, base, "wavelan_graceful_shutdown(): stop-rcv", OP0_STOP_RCV, + SR0_NO_RESULT); + /* Then, spin until the receive unit goes idle */ + do { + outb(LCCR(base), (OP0_NOP | CR0_STATUS_3)); + status = inb(LCSR(base)); + } while((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE); + + /* Now, spin until the chip finishes executing its current command */ + do { + outb(LCCR(base), (OP0_NOP | CR0_STATUS_3)); + status = inb(LCSR(base)); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); +} /* wavelan_graceful_shutdown */ + + +static void +wavelan_ru_start(Ether *ether, int base) +{ + Ctlr *ctlr; + ctlr = ether->ctlr; + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + + wavelan_graceful_shutdown(ether, base); + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + ctlr->rfp = 0; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(LCCR(base), OP1_RESET_RING_MNGMT); + ctlr->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_INT_ENABLE); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); + + /* Reset receive DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_RX_DMA_RESET); + delay(100); + outb(HACR(base), HACR_PWR_STAT); + delay(100); + + /* Receive DMA on channel 1 */ + wavelan_cmd(ether, base, "wavelan_ru_start(): rcv-enable", + (CR0_CHNL | OP0_RCV_ENABLE), SR0_NO_RESULT); + +} /* wavelan_ru_start */ + +static void +transmit(Ether* ether) +{ + Ctlr *ctlr; + ctlr = ether->ctlr; + + ilock(&ctlr->wlock); + txstart(ether); + iunlock(&ctlr->wlock); +} + static int reset(Ether* ether) { - int slot; + int slot, p; + int port; + char *pp; + Ctlr *ctlr; + PCMmap *m; + + ctlr = ether->ctlr = malloc(sizeof(Ctlr)); + ilock(&ctlr->wlock); - if(ether->irq == 0) - ether->irq = 10; if(ether->port == 0) - ether->port = 0x240; + ether->port = 0x280; + port = ether->port; - if((slot = pcmspecial(ether->type, ether)) < 0) + if((slot = pcmspecial(ether->type, ether)) < 0) { + print("could not find the PCMCIA WaveLAN card.\n"); return -1; + } + + + print("#l%dWaveLAN: slot %d, port 0x%ulX irq %ld type %s\n", ether->ctlrno, slot, ether->port, ether->irq, ether->type); + + /* create a receive buffer */ + ctlr->rbp = rbpalloc(allocb); + +/* map a piece of memory (Attribute memory) first */ + m = pcmmap(slot, 0, 0x5000, 1); + if (m==0) { + return 1; + } +/* read ethernet address from the card and put in ether->ea */ + pp = (char*)(KZERO|m->isa) + 0x0E00 + 2*0x10; + for(p = 0; pea); p++) + ether->ea[p] = (uchar) (*(pp+2*p))&0xFF; + +// print("wavelan: dump of PSA memory\n"); +// pp = (char *) (KZERO|m->isa) + 0x0E00; +// for(p=0; p<64; p++) { +// print("%2uX ", (*(pp+2*p)&0xFF)); +// if (p%16==15) print("\n"); +// } + +/* read nwid from PSA into ctlr->nwid */ + pp = (char*)(KZERO|m->isa) + 0x0E00; + ctlr->nwid[0] = *(pp+2*0x23); + ctlr->nwid[1] = *(pp+2*0x24); + +/* access the configuration option register */ + pp = (char *)(KZERO|m->isa) + 0x4000; + *pp = *pp | COR_SW_RESET; + delay(5); + *pp = (COR_LEVEL_IRQ | COR_CONFIG); + delay(5); + + hacr_write_slow(port, HACR_RESET); + outb(HACR(port), HACR_DEFAULT); + + if(inb(HASR(port)) & HASR_NO_CLK) { + print("wavelan: modem not connected\n"); + return 1; + } + + wavelan_mmc_init(ether, port); /* initialize modem */ + + outb(LCCR(port), OP0_RESET); /* reset the LAN controller */ + delay(10); + + if (wavelan_hw_config(port, ether) == FALSE) + return 1; + + if (wavelan_diag(ether, port) == 1) + return 1; + wavelan_ru_start(ether, port); + + print("wavelan: init done; receiver started\n"); + + iunlock(&ctlr->wlock); + + ctlr->port = port; + ether->port = port; + ether->mbps = 2; /* 2 Mpbs */ + ether->attach = attach; + ether->transmit = transmit; + ether->interrupt = interrupt; + ether->ifstat = ifstat; - print("WaveLAN: slot %d, port 0x%uX irq %d\n", slot, ether->port, ether->irq); + ether->promiscuous = promiscuous; + ether->multicast = multicast; + ether->arg = ether; - return -1; + return 0; /* reset succeeded */ } void diff --git a/pc/wavelan.c b/pc/wavelan.c new file mode 100644 index 0000000000000000000000000000000000000000..293715c1a031651244316c03b934962be3c8bab9 --- /dev/null +++ b/pc/wavelan.c @@ -0,0 +1,168 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +extern Dev rootdevtab; +extern Dev consdevtab; +extern Dev envdevtab; +extern Dev pipedevtab; +extern Dev procdevtab; +extern Dev mntdevtab; +extern Dev srvdevtab; +extern Dev dupdevtab; +extern Dev rtcdevtab; +extern Dev ssldevtab; +extern Dev mntstatsdevtab; +extern Dev etherdevtab; +extern Dev ipdevtab; +extern Dev drawdevtab; +extern Dev mousedevtab; +extern Dev vgadevtab; +extern Dev scsidevtab; +extern Dev cddevtab; +extern Dev sddevtab; +extern Dev atadevtab; +extern Dev floppydevtab; +extern Dev audiodevtab; +extern Dev i82365devtab; +extern Dev lptdevtab; +extern Dev ns16552devtab; +extern Dev lmldevtab; +Dev* devtab[]={ + &rootdevtab, + &consdevtab, + &envdevtab, + &pipedevtab, + &procdevtab, + &mntdevtab, + &srvdevtab, + &dupdevtab, + &rtcdevtab, + &ssldevtab, + &mntstatsdevtab, + ðerdevtab, + &ipdevtab, + &drawdevtab, + &mousedevtab, + &vgadevtab, + &scsidevtab, + &cddevtab, + &sddevtab, + &atadevtab, + &floppydevtab, + &audiodevtab, + &i82365devtab, + &lptdevtab, + &ns16552devtab, + &lmldevtab, + nil, +}; + +extern void ether2000link(void); +extern void ether2114xlink(void); +extern void ether589link(void); +extern void ether79c970link(void); +extern void ether8003link(void); +extern void ether82557link(void); +extern void etherelnk3link(void); +extern void etherwavelanlink(void); +extern void ethermediumlink(void); +void links(void){ + ether2000link(); + ether2114xlink(); + ether589link(); + ether79c970link(); + ether8003link(); + ether82557link(); + etherelnk3link(); + etherwavelanlink(); + ethermediumlink(); +} + +extern PCArch archgeneric; +extern PCArch archmp; +PCArch* knownarch[] = { + &archgeneric, + &archmp, + nil, +}; + +extern SCSIdev scsibuslogicdev; +SCSIdev* scsidev[] = { + &scsibuslogicdev, + nil, +}; + +#define Image IMAGE +#include +#include +#include +#include "screen.h" +extern VGAdev vgaark2000pvdev; +extern VGAdev vgaclgd542xdev; +extern VGAdev vgact65545dev; +extern VGAdev vgamach64xxdev; +extern VGAdev vgamga2164wdev; +extern VGAdev vgas3dev; +VGAdev* vgadev[] = { + &vgaark2000pvdev, + &vgaclgd542xdev, + &vgact65545dev, + &vgamach64xxdev, + &vgamga2164wdev, + &vgas3dev, + nil, +}; + +extern VGAcur vgaark2000pvcur; +extern VGAcur vgabt485cur; +extern VGAcur vgaclgd542xcur; +extern VGAcur vgact65545cur; +extern VGAcur vgamach64xxcur; +extern VGAcur vgamga2164wcur; +extern VGAcur vgargb524cur; +extern VGAcur vgas3cur; +extern VGAcur vgatvp3020cur; +extern VGAcur vgatvp3026cur; +VGAcur* vgacur[] = { + &vgaark2000pvcur, + &vgabt485cur, + &vgaclgd542xcur, + &vgact65545cur, + &vgamach64xxcur, + &vgamga2164wcur, + &vgargb524cur, + &vgas3cur, + &vgatvp3020cur, + &vgatvp3026cur, + nil, +}; + +#include "../ip/ip.h" +extern void ilinit(Fs*); +extern void tcpinit(Fs*); +extern void udpinit(Fs*); +extern void rudpinit(Fs*); +extern void ipifcinit(Fs*); +extern void icmpinit(Fs*); +extern void greinit(Fs*); +extern void ipmuxinit(Fs*); +void (*ipprotoinit[])(Fs*) = { + ilinit, + tcpinit, + udpinit, + rudpinit, + ipifcinit, + icmpinit, + greinit, + ipmuxinit, + nil, +}; + + int cpuserver = 0; +char* conffile = "wavelan"; +ulong kerndate = KERNDATE; diff --git a/port/devtinyfs.c b/port/devtinyfs.c index 054cf8cec594bab6b5aab9ab38170e2492be2b76..a77fb7c10260ea975f92a47592acb94d181141b1 100644 --- a/port/devtinyfs.c +++ b/port/devtinyfs.c @@ -475,7 +475,7 @@ tinyfsinit(void) * specifier is an open file descriptor */ static Chan* -tinyfsattach(void *spec) +tinyfsattach(char *spec) { Tfs *fs; Chan *c;