~kris/9p

9hist

657746c1ccb30c879e409a8ecba2aaf79fd6b80d — David du Colombier 27 years ago 835fd8d
Plan 9 from Bell Labs 1999-06-23
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), &ether->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), &ether->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,
	&etherdevtab,
	&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;