M ip/tcp.c => ip/tcp.c +1 -1
@@ 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 */
M mpc/dat.h => mpc/dat.h +1 -0
@@ 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;
M mpc/devpcmcia.c => mpc/devpcmcia.c +18 -28
@@ 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<<Rconfig)){
+print("devpcmcia: reset caddr = %x!\n", pp->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
M mpc/devuart.c => mpc/devuart.c +6 -3
@@ 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);
M mpc/etherscc.c => mpc/etherscc.c +2 -1
@@ 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)
A mpc/etherwavelan.c => mpc/etherwavelan.c +885 -0
@@ 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; p<sizeof(ether->ea); 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);
+}
A mpc/etherwavelan.h => mpc/etherwavelan.h +494 -0
@@ 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 */
M mpc/fns.h => mpc/fns.h +2 -0
@@ 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)
M mpc/io.h => mpc/io.h +14 -0
@@ 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;
+};
M mpc/main.c => mpc/main.c +1 -1
@@ 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
M pc/etherwavelan.c => pc/etherwavelan.c +857 -8
@@ 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; p<sizeof(ether->ea); 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
A pc/wavelan.c => pc/wavelan.c +168 -0
@@ 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 <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#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;
M port/devtinyfs.c => port/devtinyfs.c +1 -1
@@ 475,7 475,7 @@ tinyfsinit(void)
* specifier is an open file descriptor
*/
static Chan*
-tinyfsattach(void *spec)
+tinyfsattach(char *spec)
{
Tfs *fs;
Chan *c;