From bfa326941d3f41b9af744416c13e759ba2307b78 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 17 Aug 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-08-17 --- mpc/devrtc.c | 128 ++++++++++++-- mpc/main.c | 1 + mpc/spi.c | 474 ++++++++++++++++++++++++++------------------------ pc/devether.c | 33 ++-- pc/etherif.h | 2 + port/dev.c | 5 + 6 files changed, 391 insertions(+), 252 deletions(-) diff --git a/mpc/devrtc.c b/mpc/devrtc.c index d83a4fc2680471a3ab62361d65c27ac98d281d90..4e28c2c7d2184c6181ac76b900c8e1fba9ec8244 100644 --- a/mpc/devrtc.c +++ b/mpc/devrtc.c @@ -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= 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= Nvsize2) return 0; diff --git a/mpc/main.c b/mpc/main.c index 5ea0c6c849a8ad40579085ded639aee5f10d535c..590f954197ceb8b2800b17a1b2ad947f018fc09f 100644 --- a/mpc/main.c +++ b/mpc/main.c @@ -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(); diff --git a/mpc/spi.c b/mpc/spi.c index 0fa8d32ba30d21d84038824d8a44171297d012b0..c1f43a18047a03fffb0bc8e0d8c60884174e998e 100644 --- a/mpc/spi.c +++ b/mpc/spi.c @@ -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&&ilength; 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; irp[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; +} diff --git a/pc/devether.c b/pc/devether.c index f6406ee891d8938670e525229881ed5c2273ce21..f042e2b248a3dcb327f41aede1518d97e7cff53f 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -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); diff --git a/pc/etherif.h b/pc/etherif.h index 271b506b0fca23a14f1e271cad6d0310a7ddc16b..85b85925ecbb22f4d73f1b5ccdd67943be7180d9 100644 --- a/pc/etherif.h +++ b/pc/etherif.h @@ -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; diff --git a/port/dev.c b/port/dev.c index 8978bff3f1eb3c8cff04fb83beb7fe6f259b35e2..a8984e1f218f6a0ee666f8bccc8cf2a3d6287a7d 100644 --- a/port/dev.c +++ b/port/dev.c @@ -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;