~kris/9p

9hist

bfa326941d3f41b9af744416c13e759ba2307b78 — David du Colombier 26 years ago afe96c8
Plan 9 from Bell Labs 2000-08-17
6 files changed, 391 insertions(+), 252 deletions(-)

M mpc/devrtc.c
M mpc/main.c
M mpc/spi.c
M pc/devether.c
M pc/etherif.h
M port/dev.c
M mpc/devrtc.c => mpc/devrtc.c +110 -18
@@ 10,6 10,7 @@
enum{
	Qrtc = 1,
	Qnvram,
    Qeeprom,
	Qnvram2,
	Qled,



@@ 21,23 22,31 @@ enum{
	RTE=	1<<0,
	R38K=	1<<4,

	Nvoff=		4*1024,	/* where usable nvram lives */
	Nvsize=		4*1024,
	Nvoff=		0,	/* where usable EEPROM lives */
	Nvsize=		256,/*128x16=256x8*/
	Nvoff2=		8*1024,	/* where second usable nvram lives */
	Nvsize2=	4*1024,
};

static	QLock	rtclock;		/* mutex on clock operations */
static Lock nvrtlock;
static Lock eepromlock;

static Dirtab rtcdir[]={
	"rtc",		{Qrtc, 0},	12,	0666,
	"nvram",	{Qnvram, 0},	Nvsize,	0664,
	"eeprom",	{Qeeprom, 0},	Nvsize,	0664,
	"nvram2",	{Qnvram2, 0},	Nvsize,	0664,
	"led",	{Qled, 0},	0,	0664,
};
#define	NRTC	(sizeof(rtcdir)/sizeof(rtcdir[0]))

extern void spiread(ulong addr, uchar *buf);
extern void spiwrite(ulong addr, uchar *buf);
extern void spiresult(void);
extern void spienwrite(void);
extern void spidiswrite(void);
extern void spiwriteall(uchar *buf);

static void
rtcreset(void)
{


@@ 82,7 91,8 @@ rtcopen(Chan *c, int omode)
		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
			error(Eperm);
		break;
	case Qnvram:
	case Qeeprom:
    //case Qnvram:
	case Qnvram2:
		if(strcmp(up->user, eve)!=0)
			error(Eperm);


@@ 99,8 109,10 @@ rtcclose(Chan*)
static long	 
rtcread(Chan *c, void *buf, long n, vlong offset)
{
	ulong t;

	ulong t,readaddr;
    uchar spibuf[2];
    int  index;
    
	if(c->qid.path & CHDIR)
		return devdirread(c, buf, n, rtcdir, NRTC, devgen);



@@ 109,18 121,47 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
		t = m->iomem->rtc;
		n = readnum(offset, buf, n, t, 12);
		return n;
	case Qnvram:
		return 0;
	case Qeeprom:
    //case Qnvram:
		if(offset >= Nvsize)
			return 0;
		t = offset;
		if(t + n > Nvsize)
			n = Nvsize - t;
		ilock(&nvrtlock);
		memmove(buf, (uchar*)(NVRAMMEM + Nvoff + t), n);
		iunlock(&nvrtlock);
		ilock(&eepromlock);
        
        /* read from eeprom through spi, two bytes a time*/

        index=0;
        if(t%2!=0){
          print("not starting from an even address\n");
          readaddr=(t-1)/2;
          spiread(readaddr,spibuf);
          memmove((uchar*)buf+index,(uchar *)spibuf+1,1);
          index++;
          readaddr++;
        }
        else
          readaddr=t/2;
        
        while(index<n){
            spiread(readaddr,spibuf);
            memmove((uchar*)buf+index,spibuf,1);
            if(index+1<n)
               memmove((uchar*)buf+index+1,(uchar*)spibuf+1,1);
            readaddr++;
            index+=2;
        }
        
/*        print("result of reading is \n");
        for(index=0;index<n;index++)
          print(" %ux ",((uchar*)buf)[index]);
        print("\n");
*/
		iunlock(&eepromlock);
		return n;
	case Qnvram2:
        print("ram 2\n");
		return 0;
		if(offset >= Nvsize2)
			return 0;


@@ 132,7 173,13 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
		iunlock(&nvrtlock);
		return n;
	case Qled:
		return 0;
		if(offset >= 5)
			return 0;
		t = offset;
		if(t + n > 5)
			n = 5 - t;
		memmove(buf, "kitty" + t, n);
		return n;
	}
	error(Egreg);
	return 0;		/* not reached */


@@ 144,7 191,9 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
	ulong secs;
	char *cp, *ep;
	IMM *io;
	ulong t;
	ulong t,readaddr,writeaddr;
    int index;
    uchar spibuf[2];

	switch(c->qid.path){
	case Qrtc:


@@ 170,18 219,61 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
		io->rtck = ~KEEP_ALIVE_KEY;
		iopunlock();
		return n;
	case Qnvram:
		return 0;
	case Qeeprom:
    //case Qnvram:
		print("write %d to eeprom\n",n);
		if(offset >= Nvsize)
			return 0;
		t = offset;
		if(t + n > Nvsize)
			n = Nvsize - t;
		ilock(&nvrtlock);
		memmove((uchar*)(NVRAMMEM + Nvoff + offset), buf, n);
		iunlock(&nvrtlock);

		ilock(&eepromlock);
        index=0;
        spienwrite();
        /*if the writing addr starts at an odd address, we need to read in
          the higher byte first, combined it with the lower byte,
          and then write them out
        */
        if(t%2!=0){
          print("not starting from an even address\n");
          readaddr=(t-1)/2;
          spiread(readaddr,spibuf);
          memmove((uchar*)spibuf+1,(uchar*)buf+index,1);
          //spienwrite();
          spiwrite(readaddr,spibuf);
          //spidiswrite();
          index++;
          writeaddr=readaddr+1;
        }
        else
          writeaddr=t/2;

        while(index<n){
           if(index+1==n){
             //spienwrite();
             spiread(writeaddr,spibuf);
             //spidiswrite();
           }
           else
             memmove((uchar*)spibuf+1,(uchar*)buf+index+1,1);
           
           memmove((uchar*)spibuf,(uchar*)buf+index,1);
          // spienwrite();
           spiwrite(writeaddr,spibuf);
          // spidiswrite();
           writeaddr++;
           index+=2;
        }
          
        spidiswrite();
		//memmove((uchar*)(NVRAMMEM + Nvoff + offset), buf, n);
		iunlock(&eepromlock);
		return n;

	case Qnvram2:
        memmove((uchar*)spibuf,(uchar*)buf,2);
        spiwriteall(spibuf);
		return 0;
		if(offset >= Nvsize2)
			return 0;

M mpc/main.c => mpc/main.c +1 -0
@@ 39,6 39,7 @@ main(void)
	cpminit();
	uartinstall();
print("hello world from kernel %ux %ux %ux\n", m->iomem->pddat, m->iomem->pddir, m->iomem->pdpar);
	spiinit();
	mmuinit();
	pageinit();
	procinit0();

M mpc/spi.c => mpc/spi.c +250 -224
@@ 154,7 154,7 @@ spireset(void)

	/* step 13: enable in master mode, 8 bit chacters, slow clock */
	spi->spmode = MMaster|MRev|MDiv16|MEnable|(0x7<<4)|0xf;
print("spi->spmode = %ux\n", spi->spmode);

}

static void


@@ 168,7 168,7 @@ interrupt(Ureg*, void *arg)
	spi = ctlr->spi;
	events = spi->spie;
	spi->spie = events;
	print("SPI#%x\n", events);
//	print("SPI#%x\n", events);
}

void


@@ 199,6 199,7 @@ spitest(void)
	int len;
	Ctlr *ctlr;
	ulong status;
	uchar buf[2];

	ctlr = spictlr;



@@ 223,7 224,6 @@ print("len = %d\n", len);
print("addr = %lux\n", PADDR(b->rp));
	dre->length = len;
	dre->status = (dre->status & BDWrap) | BDReady|BDInt|BDLast;
	eieio();
spdump(ctlr->sp);
m->iomem->pbdat |= IBIT(31);
microdelay(1);


@@ 248,6 248,14 @@ print("%d status = %lux len=%d\n", ctlr->rdrx, status, len);
	memmove(b->wp, KADDR(dre->addr), len);
	b->wp += len;
print("%ux %ux %ux %ux\n", b->rp[0], b->rp[1], b->rp[2], b->rp[3]);

/* get the data out of the receiving block
   the data begins at the 13th bit, and ends at the (13+16)th bit
*/
	buf[0]=b->rp[1]<<4 | b->rp[2]>>4;
	buf[1]=b->rp[2]<<4 | b->rp[3]>>4;

print("the value of address 0 in EEPROM is %ux %ux\n",buf[0],buf[1]);
	dcflush(KADDR(dre->addr), len);
	dre->status = (status & BDWrap) | BDEmpty | BDInt;
	ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);


@@ 260,262 268,280 @@ void
spiinit(void)
{
	spireset();
	spitest();
//	spitest();
}

#ifdef XXX
void
spicmdsend(Block *b, BD *dre, Ctlr *ctlr, int CSdown)
{   
	int len;

	if(dre->status & BDReady)
		panic("spicmdsend: txstart");
	
	len = BLEN(b);
	dcflush(b->rp, len);

	ctlr->txb[ctlr->tdrh] = b;
	dre->addr = PADDR(b->rp);
	dre->length = len;
	dre->status = (dre->status & BDWrap) | BDReady|BDInt|BDLast;
	m->iomem->pbdat |= IBIT(31);

	ctlr->spi->spcom = 1<<7;	/* transmit now */

	//eieio();
	ctlr->ntq++;
	ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);

	delay(1);

	while(dre->status&BDReady) microdelay(10);

	if(CSdown) m->iomem->pbdat &= ~(IBIT(31));

static void
epprod(Ctlr *ctlr, int epn)
{
	ctlr->spi->uscom = FifoFill | (epn&3);
	eieio();
}

static void
txstart(Endpt *r)

void
spiread(ulong addr,uchar * buf)
{
	int len, flags;

  	BD *dre;
	Block *b;
	BD *dre, *rdy;
	int len;
	Ctlr *ctlr;
	ushort status;
  
	ctlr = spictlr;

	if(r->ctlr->init)
		return;
	rdy = nil;
	while(r->ntq < Ntdre-1){
		b = qget(r->oq);
		if(b == 0)
			break;

		dre = &r->tdr[r->tdrh];
		if(dre->status & BDReady)
			panic("txstart");
dumpspi(b, "TX");
	dre = &ctlr->tdr[ctlr->tdrh];

	b = allocb(4);
	b->wp[0] = 0xc0 | addr>>3;
	b->wp[1] = addr<<5;
	b->wp[2] = 0x00;
	b->wp[3] = 0x00;
	b->wp += 4;

	spicmdsend(b, dre, ctlr, 0);

	//delay(10);
	
		/*
		 * Give ownership of the descriptor to the chip, increment the
		 * software ring descriptor pointer and tell the chip to poll.
		 */
		flags = 0;
		switch(b->rp[0]){
		case TokDATA1:
			flags = BDData1|BDData0;
		case TokDATA0:
			flags |= BDtxcrc|BDcnf|BDReady;
			flags |= BDData0;
			b->rp++;	/* skip DATAn */
		}
		len = BLEN(b);
		dcflush(b->rp, len);
		if(r->txb[r->tdrh] != nil)
			panic("spi: txstart");
		r->txb[r->tdrh] = b;
		dre->addr = PADDR(b->rp);
		dre->length = len;
		eieio();
		dre->status = (dre->status & BDWrap) | BDInt|BDLast | flags;
		if(rdy){
			rdy->status |= BDReady;
			rdy = nil;
		}
		if((flags & BDReady) == 0)
			rdy = dre;
		eieio();
		r->ntq++;
		r->tdrh = NEXT(r->tdrh, Ntdre);
	}
	if(rdy)
		rdy->status |= BDReady;
	eieio();
	dre = &ctlr->rdr[ctlr->rdrx];
	status = dre->status;
	len = dre->length;
	
	while(dre->status&BDEmpty) microdelay(10);

	b = iallocb(len);
	memmove(b->wp, KADDR(dre->addr), len);
	b->wp += len;


/* get the data out of the receiving block
   the data begins at the 13th bit, and ends at the (13+16)th bit
*/
	buf[0]=b->rp[1]<<4 | b->rp[2]>>4;
	buf[1]=b->rp[2]<<4 | b->rp[3]>>4;

//    print("read out %ux %ux\n", buf[0],buf[1]);
	dcflush(KADDR(dre->addr), len);
	dre->status = (status & BDWrap) | BDEmpty | BDInt;
	ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
	freeb(b);
	m->iomem->pbdat &= ~(IBIT(31));
	microdelay(5);

	return;
}

static void
transmit(Endpt *r)
void
spienwrite(void)
{
	ilock(r->ctlr);
	txstart(r);
	iunlock(r->ctlr);
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	int len;

	ctlr = spictlr;

	b = allocb(4);
	b->wp[0] = 0x98;
	b->wp[1] = 0x00;
	b->wp[2] = 0x00;
	b->wp[3] = 0x00;
	b->wp += 4;

	dre = &ctlr->tdr[ctlr->tdrh];
	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	freeb(b);
	microdelay(5);
	return;
}

static void
endptintr(Endpt *r, int events)
void
spidiswrite(void)
{
	int len, status;
	BD *dre;
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	int len;

	if(events & Frxb || 1){
		dre = &r->rdr[r->rdrx];
		while(((status = dre->status) & BDEmpty) == 0){
			if(status & BDrxerr || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
				print("spi rx: %4.4ux %d ", status, dre->length);
				{uchar *p;int i; p=KADDR(dre->addr); for(i=0;i<14&&i<dre->length; i++)print(" %.2ux", p[i]);print("\n");}
			}
			else{
				/*
				 * We have a packet. Read it into the next
				 * free ring buffer, if any.
				 */
				len = dre->length-2;	/* discard CRC */
				if(len >= 0 && (b = iallocb(len)) != 0){
					memmove(b->wp, KADDR(dre->addr), len);
					dcflush(KADDR(dre->addr), len);
					b->wp += len;
					// spiiq(ctlr, b);
					dumpspi(b, "RX");
					freeb(b);
				}
			}

			/*
			 * Finished with this descriptor, reinitialise it,
			 * give it back to the chip, then on to the next...
			 */
			dre->length = 0;
			dre->status = (dre->status & BDWrap) | BDEmpty | BDInt;
			eieio();

			r->rdrx = NEXT(r->rdrx, Nrdre);
			dre = &r->rdr[r->rdrx];
			r->rxintr = 1;
			wakeup(&r->ir);
		}
	}
	ctlr = spictlr;

	/*
	 * Transmitter interrupt: handle anything queued for a free descriptor.
	 */
	if(events & (Ftxb|Ftxe0|Ftxe1)){
		lock(r->ctlr);
		while(r->ntq){
			dre = &r->tdr[r->tdri];
			if(dre->status & BDReady)
				break;
			print("spitx=#%.4x %8.8lux\n", dre->status, dre->addr);
			/* TO DO: error counting */
			b = r->txb[r->tdri];
			if(b == nil)
				panic("spi/interrupt: bufp");
			r->txb[r->tdri] = nil;
			freeb(b);
			r->ntq--;
			r->tdri = NEXT(r->tdri, Ntdre);
		}
		txstart(r);
		unlock(r->ctlr);
		if(r->ntq)
			epprod(r->ctlr, r->x);
	}
}
	dre = &ctlr->tdr[ctlr->tdrh];

	b = allocb(4);
	b->wp[0] = 0x80;
	b->wp[1] = 0x00;
	b->wp[2] = 0x00;
	b->wp[3] = 0x00;
	b->wp += 4;

static void
dumpspi(Block *b, char *msg)
{
	int i;
	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	print("%s: %8.8lux [%d]: ", msg, (ulong)b->rp, BLEN(b));
	for(i=0; i<BLEN(b) && i < 16; i++)
		print(" %.2x", b->rp[i]);
	print("\n");
	freeb(b);
	microdelay(5);
	return;
}

static void
setaddr(Endpt *e, int dev, int endpt)
void
spiwrite(ulong addr, uchar *buf)
{
	ushort v;

	e->dev = dev;
	e->endpt = endpt;
	v = (e->endpt<<7) | e->dev;
	v |= crc5(v) << 11;
	e->addr[0] = v;
	e->addr[1] = v>>8;
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	int len;
  
	ctlr = spictlr;

	dre = &ctlr->tdr[ctlr->tdrh];

	b = allocb(4);
	b->wp[0] = 0x05 ;
	b->wp[1] = 0x7f & addr;
	b->wp+=2;
	memmove((uchar*)b->wp,buf,2);
	b->wp += 2;

	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	freeb(b);
	delay(15);
	//sleep(15); //sleep for 15ms 
	return;
}

static int
spiinput(void *a)
void
spiwriteall(uchar *buf)
{
	return ((Ctlr*)a)->rxintr;
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	int len;

	ctlr = spictlr;

	dre = &ctlr->tdr[ctlr->tdrh];
	
	b = allocb(4);
	b->wp[0] = 0x04;
	b->wp[1] = 0x40;
	b->wp+=2;
	memmove((uchar*)b->wp,buf,2);
	//b->wp[2]=0xf0;
	//b->wp[3]=0xf0;
	b->wp += 2;

	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	freeb(b);
	delay(15);
	//sleep(15000); //sleep for 15ms 
	print("leave spiwriteall\n");
	return;
}

static void
spitest(void)
void
spierase(ulong addr)
{
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	Endpt *e, *e1;
	uchar msg[8];
	int epn, testing, i;
	int len;

	ctlr = spictlr;
	epn = 0;
	testing = ctlr->spi->usmod & TEST;
	if(testing)
		epn = 1;
	e = &ctlr->pts[0];
	e1 = &ctlr->pts[1];
	memset(msg, 0, 8);
	msg[0] = 0;
	msg[1] = 8;	/* set configuration */
	msg[2] = 1;
	setaddr(e, 0, epn);
	sendtoken(e, TokSETUP);
	senddata(e, msg, 8);
	if(!testing){
		for(i=0; i<8; i++)
			msg[i] = 0x40+i;
		senddata(e1, msg, 8);
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, spiinput, e, 1000);
		if(!spiinput(e))
			print("RX: none\n");
	}
	sendtoken(e, TokSETUP);
	msg[0] = 0x23;
	msg[1] = 3;	/* set feature */
	msg[2] = 8;	/* port power */
	msg[3] = 0;
	msg[4] = 1;	/* port 1 */
	senddata(e, msg, 8);
	if(!testing){
		for(i=0; i<8; i++)
			msg[i] = 0x60+i;
		senddata(e1, msg, 8);
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, spiinput, e, 1000);
		if(!spiinput(e))
			print("RX: none\n");
	}

	b = allocb(2);
	b->wp[0] = 0x07;
	b->wp[1] = addr&0x7f;
	b->wp+=2;

	dre = &ctlr->tdr[ctlr->tdrh];
	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	freeb(b);
	delay(15);
	return;
}

static void
setupep(int n, EPparam *ep)
void
spieraseall(void)
{
	Endpt *e;

	e = &usbctlr->pts[n];
	e->x = n;
	e->ctlr = usbctlr;
	e->xtog = TokDATA0;
	if(e->oq == nil)
		e->oq = qopen(8*1024, 1, 0, 0);
	if(e->iq == nil)
		e->iq = qopen(8*1024, 1, 0, 0);
	e->ep = ep;
	if(ioringinit(e, Nrdre, Ntdre, Bufsize) < 0)
		panic("usbreset");
	ep->rbase = PADDR(e->rdr);
	ep->rbptr = ep->rbase;
	ep->tbase = PADDR(e->tdr);
	ep->tbptr = ep->tbase;
	eieio();
}
  	BD *dre;
	Block *b;
	Ctlr *ctlr;
	int len;

	ctlr = spictlr;

	b = allocb(2);
	b->wp[0] = 0x07;
	b->wp[1] = 0x80;
	b->wp+=2;

#endif
	dre = &ctlr->tdr[ctlr->tdrh];
	spicmdsend(b,dre,ctlr,1);

	dre=&ctlr->rdr[ctlr->rdrx];
	len=dre->length;
	dcflush(KADDR(dre->addr),len);
	dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
	ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);

	freeb(b);
	delay(15);
	return;
}

M pc/devether.c => pc/devether.c +23 -10
@@ 244,10 244,19 @@ etherwrite(Chan* chan, void* buf, long n, vlong)
{
	Ether *ether;
	Block *bp;
	int nn;

	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid)
		return netifwrite(ether, chan, buf, n);
	if(NETTYPE(chan->qid.path) != Ndataqid) {
		nn = netifwrite(ether, chan, buf, n);
		if(nn >= 0)
			return nn;

		if(ether->ctl!=nil)
			return ether->ctl(ether,buf,n);
			
		error(Ebadctl);
	}

	if(n > ETHERMAXTU)
		error(Etoobig);


@@ 255,13 264,8 @@ etherwrite(Chan* chan, void* buf, long n, vlong)
		error(Etoosmall);

	bp = allocb(n);
	if(waserror()){
		freeb(bp);
		nexterror();
	}
	memmove(bp->rp, buf, n);
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
	poperror();
	bp->wp += n;

	return etheroq(ether, bp);


@@ 274,12 278,16 @@ etherbwrite(Chan* chan, Block* bp, ulong)
	long n;

	n = BLEN(bp);
	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid){
		n = netifwrite(ether, chan, bp->rp, n);
		if(waserror()) {
			freeb(bp);
			nexterror();
		}
		n = etherwrite(chan, bp->rp, n, 0);
		freeb(bp);
		return n;
	}
	ether = etherxx[chan->dev];

	if(n > ETHERMAXTU){
		freeb(bp);


@@ 369,7 377,12 @@ etherreset(void)
			if(ether->irq == 2)
				ether->irq = 9;
			snprint(name, sizeof(name), "ether%d", ctlrno);
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);

			/* If ether->irq is less than 0, it is a hack to indicate no interrupt
			 * used for the seocnd logical ethernet for the wavelan card
			 */
			if(ether->irq >= 0)
				intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);

			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);

M pc/etherif.h => pc/etherif.h +2 -0
@@ 11,11 11,13 @@ struct Ether {
	int	tbdf;			/* type+busno+devno+funcno */
	int	mbps;			/* Mbps */
	uchar	ea[Eaddrlen];
	int	encry;

	void	(*attach)(Ether*);	/* filled in by reset routine */
	void	(*transmit)(Ether*);
	void	(*interrupt)(Ureg*, void*);
	long	(*ifstat)(Ether*, void*, long, ulong);
	long 	(*ctl)(Ether*, void*, long); /* custom ctl messages */
	void	*ctlr;

	Queue*	oq;

M port/dev.c => port/dev.c +5 -0
@@ 288,7 288,12 @@ devbwrite(Chan *c, Block *bp, ulong offset)
{
	long n;

	if(waserror()) {
		freeb(bp);
		nexterror();
	}
	n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
	poperror();
	freeb(bp);

	return n;