From 50425f67e5cf896910bb3479c1b34617a8fef5a8 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 28 Jul 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-07-28 --- alphapc/devarch.c | 2 +- alphapc/faultalpha.c | 3 +- alphapc/fns.h | 1 + alphapc/main.c | 19 +- alphapc/mmu.c | 99 ++++---- alphapc/sd53c8xx.c | 38 ++-- alphapc/trap.c | 93 ++++---- port/devpnp.c | 523 +++++++++++++++++++++++++++++++++++++++++++ port/qio.c | 2 + port/sysfile.c | 2 + 10 files changed, 653 insertions(+), 129 deletions(-) create mode 100644 port/devpnp.c diff --git a/alphapc/devarch.c b/alphapc/devarch.c index 5ee9a37f97ea6b78d2ade43444ae207179072675..384de1b42936d4a4181beba16a5e5e371f99b9e1 100644 --- a/alphapc/devarch.c +++ b/alphapc/devarch.c @@ -452,7 +452,7 @@ cputyperead(Chan*, void *a, long n, vlong offset) Hwcpu *cpu; mhz = (m->cpuhz+999999)/1000000; - cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff); + cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff); /* NB CPU 0 */ cputype = "unknown"; maj = (ulong)cpu->cputype; if (maj < nelem(cpunames)) diff --git a/alphapc/faultalpha.c b/alphapc/faultalpha.c index cc26c6b2e070b22aa34da209d7df6fca7af3c82f..c2d6469052c457f5723f2b600dd937f1c6837822 100644 --- a/alphapc/faultalpha.c +++ b/alphapc/faultalpha.c @@ -45,7 +45,8 @@ faultalpha(Ureg *ur) if(0) mmudump(); dumpregs(ur); - panic("fault"); + _dumpstack(ur); + exit(1); } /* diff --git a/alphapc/fns.h b/alphapc/fns.h index e1e5f45df6c91e9224cd9e8ba978ecde9c1f77a9..9cf4fc1f5afac3dee97c5447e572c9c715bb245f 100644 --- a/alphapc/fns.h +++ b/alphapc/fns.h @@ -17,6 +17,7 @@ int dmadone(int); void dmaend(int); int dmainit(int, int); long dmasetup(int, void*, long, int); +void _dumpstack(Ureg *); void evenaddr(ulong); void fataltrap(Ureg *, char *); void fault0(void); diff --git a/alphapc/main.c b/alphapc/main.c index ec4d73f27cfb3d9da8da421674bfb699e2107cc1..b1d4ffe9b1afc964e6fe88018c00f9bb3dc64f82 100644 --- a/alphapc/main.c +++ b/alphapc/main.c @@ -29,9 +29,9 @@ options(void) long i, n; char *cp, *line[MAXCONF], *p, *q; - cp = bootconf->bootargs; + cp = bootargs; + strncpy(cp, bootconf->bootargs, BOOTARGSLEN); cp[BOOTARGSLEN-1] = 0; - strcpy(bootargs, cp); /* * Strip out '\r', change '\t' -> ' '. @@ -88,16 +88,6 @@ main(void) if(arch->corehello) arch->corehello(); -#ifdef NEVER - percpu = hwrpb + (hwrpb[40]>>2); -// percpu[32] |= 2; /* restart capable */ - percpu[32] &= ~1; /* boot in progress - not */ -// percpu[32] |= (3<<16); /* warm boot requested */ -// percpu[32] |= (2<<16); /* cold boot requested */ -// percpu[32] |= (4<<16); /* stay halted */ - percpu[32] |= (0<<16); /* default action */ -#endif - procinit0(); initseg(); links(); @@ -118,6 +108,7 @@ void machinit(void) { int n; + Hwcpu *cpu; icflush(); n = m->machno; @@ -126,6 +117,10 @@ machinit(void) active.exiting = 0; active.machs = 1; + + cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen); + cpu->state &= ~1; /* boot in progress - not */ +/* cpu->state |= (4<<16); /* stay halted */ } void diff --git a/alphapc/mmu.c b/alphapc/mmu.c index 4293652d43a4e002e103d104982330af1c04d3f3..88ba1809f0e18789f5ccbd3c2254275559622b41 100644 --- a/alphapc/mmu.c +++ b/alphapc/mmu.c @@ -38,42 +38,38 @@ mmuinit(void) nextio = (uchar*) (KZERO|bootconf->maxphys); } -/* - * Called splhi, not in Running state - */ -void -mmuswitch(Proc *p) +static void +mmuptefree(Proc* proc) { - Page *pg; uvlong *lvl2; - - if(p->newtlb){ - /* - * newtlb set means that they are inconsistent - * with the segment.c data structures. - * - * bin the current 3rd level page tables and - * the pointers to them in the 2nd level page. - * pg->daddr is used by putmmu to save the offset into - * the 2nd level page. - */ - if(p->mmutop && p->mmuused){ - lvl2 = (uvlong*)p->mmulvl2->va; - for(pg = p->mmuused; pg->next; pg = pg->next) - lvl2[pg->daddr] = 0; - lvl2[pg->daddr] = 0; - pg->next = p->mmufree; - p->mmufree = p->mmuused; - p->mmuused = 0; + Page **last, *page; + + if(proc->mmutop && proc->mmuused){ + lvl2 = (uvlong*)proc->mmulvl2->va; + last = &proc->mmuused; + for(page = *last; page; page = page->next){ + lvl2[page->daddr] = 0; + last = &page->next; } - p->newtlb = 0; + *last = proc->mmufree; + proc->mmufree = proc->mmuused; + proc->mmuused = 0; + } +} + +void +mmuswitch(Proc *proc) +{ + if(proc->newtlb){ + mmuptefree(proc); + proc->newtlb = 0; } /* tell processor about new page table and flush cached entries */ - if(p->mmutop == 0) + if(proc->mmutop == 0) setptb(origlvl1); else - setptb(p->mmutop->pa); + setptb(proc->mmutop->pa); tlbflush(-1, 0); icflush(); } @@ -83,44 +79,35 @@ mmuswitch(Proc *p) * with palloc locked. */ void -mmurelease(Proc *p) +mmurelease(Proc *proc) { - Page *pg; - Page *next; - - if(canlock(&palloc)) - panic("mmurelease"); + Page *page, *next; /* point to protoype page map */ setptb(origlvl1); icflush(); - /* give away page table pages */ - for(pg = p->mmuused; pg; pg = next){ - next = pg->next; - pg->next = p->mmufree; - p->mmufree = pg; - } - p->mmuused = 0; - if(p->mmutop) { - p->mmutop->next = p->mmufree; - p->mmufree = p->mmutop; - p->mmutop = 0; + mmuptefree(proc); + proc->mmuused = 0; + if(proc->mmutop) { + proc->mmutop->next = proc->mmufree; + proc->mmufree = proc->mmutop; + proc->mmutop = 0; } - if(p->mmulvl2) { - p->mmulvl2->next = p->mmufree; - p->mmufree = p->mmulvl2; - p->mmulvl2 = 0; + if(proc->mmulvl2) { + proc->mmulvl2->next = proc->mmufree; + proc->mmufree = proc->mmulvl2; + proc->mmulvl2 = 0; } - for(pg = p->mmufree; pg; pg = next){ - next = pg->next; - if(--pg->ref) - panic("mmurelease: pg->ref %d\n", pg->ref); - pagechainhead(pg); + for(page = proc->mmufree; page; page = next){ + next = page->next; + if(--page->ref) + panic("mmurelease: page->ref %d\n", page->ref); + pagechainhead(page); } - if(p->mmufree && palloc.r.p) + if(proc->mmufree && palloc.r.p) wakeup(&palloc.r); - p->mmufree = 0; + proc->mmufree = 0; } void diff --git a/alphapc/sd53c8xx.c b/alphapc/sd53c8xx.c index c19cf3deab556df4350b203377932114fa027e00..d2eab8ae8e3403b7879b9bb15349e3fd2cc7ce47 100644 --- a/alphapc/sd53c8xx.c +++ b/alphapc/sd53c8xx.c @@ -200,20 +200,12 @@ typedef enum State { } State; typedef struct Dsa { - union { - uchar state[4]; - struct { - uchar stateb; - uchar result; - uchar dmablks; - uchar flag; /* setbyte(state,3,...) */ - }; - }; - - union { - ulong dmancr; /* For block transfer: NCR order (little-endian) */ - uchar dmaaddr[4]; - }; + uchar stateb; + uchar result; + uchar dmablks; + uchar flag; /* setbyte(state,3,...) */ + + uchar dmaaddr[4]; uchar target; /* Target */ uchar pad0[3]; @@ -397,7 +389,7 @@ dsaalloc(Controller *c, int target, int lun) if (DEBUG(1)) KPRINT(PRINTPREFIX "%d/%d: allocated new dsa %lux\n", target, lun, (ulong)d); lesetl(d->next, 0); - lesetl(d->state, A_STATE_ALLOCATED); + lesetl(&d->stateb, A_STATE_ALLOCATED); if (legetl(c->dsalist.head) == 0) lesetl(c->dsalist.head, DMASEG(d)); /* ATOMIC?!? */ else @@ -408,7 +400,7 @@ dsaalloc(Controller *c, int target, int lun) if (DEBUG(1)) KPRINT(PRINTPREFIX "%d/%d: reused dsa %lux\n", target, lun, (ulong)d); c->dsalist.freechain = d->freechain; - lesetl(d->state, A_STATE_ALLOCATED); + lesetl(&d->stateb, A_STATE_ALLOCATED); } iunlock(&c->dsalist); d->target = target; @@ -422,7 +414,7 @@ dsafree(Controller *c, Dsa *d) ilock(&c->dsalist); d->freechain = c->dsalist.freechain; c->dsalist.freechain = d; - lesetl(d->state, A_STATE_FREE); + lesetl(&d->stateb, A_STATE_FREE); iunlock(&c->dsalist); } @@ -1204,7 +1196,7 @@ interrupt(Ureg *ur, void *a) dsa->dmablks, legetl(dsa->dmaaddr), legetl(dsa->data_buf.pa), legetl(dsa->data_buf.dbc)); n->scratcha[2] = dsa->dmablks; - lesetl(n->scratchb, dsa->dmancr); + lesetl(n->scratchb, *(ulong*)dsa->dmaaddr); cont = E_data_block_mismatch_recover; } else if (sa == E_data_out_mismatch) { @@ -1231,7 +1223,7 @@ interrupt(Ureg *ur, void *a) dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc)); /* copy changes into scratch registers */ n->scratcha[2] = dsa->dmablks; - lesetl(n->scratchb, dsa->dmancr); + lesetl(n->scratchb, *(ulong*)dsa->dmaaddr); cont = E_data_block_mismatch_recover; } else if (sa == E_id_out_mismatch) { @@ -1442,6 +1434,12 @@ interrupt(Ureg *ur, void *a) dsa->target, dsa->lun); cont = -2; break; + case A_error_reselected: /* dsa isn't valid here */ + print(PRINTPREFIX "reselection error\n"); + dumpncrregs(c, 1); + for (dsa = KPTR(legetl(c->dsalist.head)); dsa; dsa = KPTR(legetl(dsa->next))) + IPRINT(PRINTPREFIX "dsa target %d lun %d state %d\n", dsa->target, dsa->lun, dsa->stateb); + break; default: IPRINT(PRINTPREFIX "%d/%d: script error %ld\n", dsa->target, dsa->lun, legetl(n->dsps)); @@ -1752,7 +1750,7 @@ docheck: * Clear out the microcode state * so the Dsa can be re-used. */ - lesetl(d->state, A_STATE_ALLOCATED); + lesetl(&d->stateb, A_STATE_ALLOCATED); goto docheck; } qunlock(&c->q[target]); diff --git a/alphapc/trap.c b/alphapc/trap.c index 32fe4919a6afdf9796cbd38fd374a994e80fa647..7ba94e7c0cc4a42401e62f62f7b7a9a85e4fc02a 100644 --- a/alphapc/trap.c +++ b/alphapc/trap.c @@ -245,7 +245,7 @@ intr(Ureg *ur) } else{ dumpregs(ur); - panic("unknown intr: %d\n", vno); /* */ + print("unknown intr: %d\n", vno); /* */ } } @@ -375,7 +375,50 @@ kernfault(Ureg *ur, int code) } void -dumpstack(void) +dumpregs(Ureg *ur) +{ + int i, col; + uvlong *l; + + if(up) + print("registers for %s %ld\n", up->text, up->pid); + else + print("registers for kernel\n"); + + l = &ur->type; + col = 0; + for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) { + print("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : " "); + if (col++ == 2) + col = 0; + } + print("\n"); +} + + +/* + * Fill in enough of Ureg to get a stack trace, and call a function. + * Used by debugging interface rdb. + */ +static void +getpcsp(ulong *pc, ulong *sp) +{ + *pc = getcallerpc(&pc); + *sp = (ulong)&pc-8; +} + +void +callwithureg(void (*fn)(Ureg*)) +{ + Ureg ureg; + + getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp); + ureg.r26 = getcallerpc(&fn); + fn(&ureg); +} + +void +_dumpstack(Ureg *ureg) { ulong l, sl, el, v, i, instr, op; extern ulong etext; @@ -392,15 +435,12 @@ dumpstack(void) el = sl + KSTACK; } if(l > el || l < sl){ - iprint("dumpstack: l %lux sl %lux el %lux m %lux up %lux\n", - l, sl, el, m, up); el = (ulong)m+BY2PG; sl = el-KSTACK; } - iprint("dumpstack: l %lux sl %lux el %lux m %lux\n", l, sl, el, m); - if(l > el || l < sl){ + if(l > el || l < sl) return; - } + print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", (ulong)ureg->pc, (ulong)ureg->sp, (ulong)ureg->r26); i = 0; for(; l>26); if(op == 26 || op == 52){ - iprint("%lux ", v); + print("%lux=%lux ", l, v); i++; } } - if(i == 8){ + if(i == 4){ i = 0; - iprint("\n"); + print("\n"); } } + if(i) + print("\n"); } void -callwithureg(void (*fn)(Ureg*)) -{ - Ureg ureg; - ureg.pc = getcallerpc(&fn); - ureg.sp = (ulong)&fn; - fn(&ureg); -} - -void -dumpregs(Ureg *ur) +dumpstack(void) { - int i, col; - uvlong *l; - - spllo(); - prflush(); - if(up) - iprint("registers for %s %d\n", up->text, up->pid); - else - iprint("registers for kernel\n"); - - l = &ur->type; - col = 0; - for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) { - iprint("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : " "); - if (col++ == 2) - col = 0; - } - iprint("\n"); -// prflush(); + callwithureg(_dumpstack); } int diff --git a/port/devpnp.c b/port/devpnp.c new file mode 100644 index 0000000000000000000000000000000000000000..743c020f66ad177ea49ede8734e12776e5b2581a --- /dev/null +++ b/port/devpnp.c @@ -0,0 +1,523 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +typedef struct Pnp Pnp; +typedef struct Card Card; + +struct Pnp +{ + Lock; + int rddata; + int debug; + Card *cards; +}; + +struct Card +{ + int csn; + ulong id1; + ulong id2; + int ncfg; + Card* next; +}; + +static Pnp pnp; + +#define DPRINT if(pnp.debug) print +#define XPRINT if(1) print + +enum { + Address = 0x279, + WriteData = 0xa79, + + Qtopdir = 0, + + Qpnpdir, + Qpnpctl, + Qcsnctl, + Qcsnraw, + + Qpcidir, + Qpcictl, + Qpciraw, +}; + +#define TYPE(q) ((ulong)(q).path & 0x0F) +#define CSN(q) (((ulong)(q).path>>4) & 0xFF) +#define QID(c, t) (((c)<<4)|(t)) + +static Dirtab topdir[] = { + ".", { Qtopdir, 0, QTDIR }, 0, 0555, + "pnp", { Qpnpdir, 0, QTDIR }, 0, 0555, + "pci", { Qpcidir, 0, QTDIR }, 0, 0555, +}; + +static Dirtab pnpdir[] = { + ".", { Qpnpdir, 0, QTDIR }, 0, 0555, + "ctl", { Qpnpctl, 0, 0 }, 0, 0666, +}; + +extern Dev pnpdevtab; + +static char key[32] = +{ + 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, + 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, + 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, + 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39, +}; + +static void +cmd(int reg, int val) +{ + outb(Address, reg); + outb(WriteData, val); +} + +/* Send initiation key, putting each card in Sleep state */ +static void +initiation(void) +{ + int i; + + /* ensure each card's LFSR is reset */ + outb(Address, 0x00); + outb(Address, 0x00); + + /* send initiation key */ + for (i = 0; i < 32; i++) + outb(Address, key[i]); +} + +/* isolation protocol... */ +static int +readbit(int rddata) +{ + int r1, r2; + + r1 = inb(rddata); + r2 = inb(rddata); + microdelay(250); + return (r1 == 0x55) && (r2 == 0xaa); +} + +static int +isolate(int rddata, ulong *id1, ulong *id2) +{ + int i, csum, bit; + uchar *p, id[9]; + + outb(Address, 0x01); /* point to serial isolation register */ + delay(1); + csum = 0x6a; + for (i = 0; i < 64; i++) { + bit = readbit(rddata); + csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7); + p = &id[i>>3]; + *p = (*p>>1) | (bit<<7); + } + for (; i < 72; i++) { + p = &id[i>>3]; + *p = (*p>>1) | (readbit(rddata)<<7); + } + *id1 = (id[3]<<24)|(id[2]<<16)|(id[1]<<8)|id[0]; + *id2 = (id[7]<<24)|(id[6]<<16)|(id[5]<<8)|id[4]; + if (*id1 == 0) + return 0; + if (id[8] != csum) + DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/ + return id[8] == csum; +} + +static int +getresbyte(int rddata) +{ + int tries = 0; + + outb(Address, 0x05); + while ((inb(rddata) & 1) == 0) + if (tries++ > 1000000) + error("pnp: timeout waiting for resource data\n"); + outb(Address, 0x04); + return inb(rddata); +} + +static char * +serial(ulong id1, ulong id2) +{ + int i1, i2, i3; + ulong x; + static char buf[20]; + + i1 = (id1>>2)&31; + i2 = ((id1<<3)&24)+((id1>>13)&7); + i3 = (id1>>8)&31; + x = (id1>>8)&0xff00|(id1>>24)&0x00ff; + if (i1 > 0 && i1 < 27 && i2 > 0 && i2 < 27 && i3 > 0 && i3 < 27 && (id1 & (1<<7)) == 0) + snprint(buf, sizeof(buf), "%c%c%c%.4lux.%lux", 'A'+i1-1, 'A'+i2-1, 'A'+i3-1, x, id2); + else + snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2); + return buf; +} + +/* called with pnp locked */ +static Card * +findcsn(int csn, int create) +{ + Card *c, *nc, **l; + + l = &pnp.cards; + for(c = *l; c != nil; c = *l) { + if(c->csn == csn) + return c; + if(c->csn > csn) + break; + l = &c->next; + } + if(!create) + return nil; + *l = nc = malloc(sizeof(Card)); + nc->next = c; + nc->csn = csn; + return nc; +} + +static int +newcsn(void) +{ + int csn; + Card *c; + + csn = 1; + for(c = pnp.cards; c != nil; c = c->next) { + if(c->csn > csn) + break; + csn = c->csn+1; + } + return csn; +} + +static int +pnpncfg(int rddata) +{ + int i, n, x, ncfg, n1, n2; + + ncfg = 0; + for (;;) { + x = getresbyte(rddata); + if((x & 0x80) == 0) { + n = (x&7)+1; + for(i = 1; i < n; i++) + getresbyte(rddata); + } + else { + n1 = getresbyte(rddata); + n2 = getresbyte(rddata); + n = (n2<<8)|n1 + 3; + for (i = 3; i < n; i++) + getresbyte(rddata); + } + ncfg += n; + if((x>>3) == 0x0f) + break; + } + return ncfg; +} + +/* look for cards, and assign them CSNs */ +static int +pnpscan(int rddata) +{ + Card *c; + int csn, ok; + ulong id1, id2; + + ilock(&pnp); + pnp.rddata = rddata; + initiation(); + cmd(0x02, 0x04+0x01); /* reset CSN on all cards and reset logical devices */ + delay(1); /* delay after resetting cards */ + + cmd(0x03, 0); /* Wake all cards with a CSN of 0 */ + cmd(0x00, rddata>>2); /* Set the READ_DATA port on all cards */ + while(isolate(rddata, &id1, &id2)) { + for(c = pnp.cards; c != nil; c = c->next) + if(c->id1 == id1 && c->id2 == id2) + break; + if(c == nil) { + csn = newcsn(); + c = findcsn(csn, 1); + c->id1 = id1; + c->id2 = id2; + } + cmd(0x06, c->csn); /* set the card's csn */ + print("pnp%d: %s\n", c->csn, serial(id1, id2)); + c->ncfg = pnpncfg(rddata); + cmd(0x03, 0); /* Wake all cards with a CSN of 0, putting this card to sleep */ + } + cmd(0x02, 0x02); /* return cards to Wait for Key state */ + ok = (pnp.cards != 0); + iunlock(&pnp); + return ok; +} + +static void +pnpreset(void) +{ + Card *c; + ulong id1, id2; + int csn, i1, i2, i3, x; + char *s, *p, buf[20]; + ISAConf isa; + + memset(&isa, 0, sizeof(ISAConf)); + pnp.rddata = -1; + if (isaconfig("pnp", 0, &isa) == 0) + return; + if(isa.port < 0x203 || isa.port > 0x3ff) + return; + for(csn = 1; csn < 256; csn++) { + sprint(buf, "pnp%d", csn); + s = getconf(buf); + if(s == 0) + continue; + if(strlen(s) < 8 || s[7] != '.' || s[0] < 'A' || s[0] > 'Z' || s[1] < 'A' || s[1] > 'Z' || s[2] < 'A' || s[2] > 'Z') { +bad: + print("pnp%d: bad conf string %s\n", csn, s); + continue; + } + i1 = s[0]-'A'+1; + i2 = s[1]-'A'+1; + i3 = s[2]-'A'+1; + x = strtoul(&s[3], 0, 16); + id1 = (i1<<2)|((i2>>3)&3)|((i2&7)<<13)|(i3<<8)|((x&0xff)<<24)|((x&0xff00)<<8); + id2 = strtoul(&s[8], &p, 16); + if(*p != ' ' && *p != '\0') + goto bad; + c = findcsn(csn, 1); + c->id1 = id1; + c->id2 = id2; + } + pnpscan(isa.port); +} + +static int +pnpgen1(Chan *c, int t, int csn, Card *cp, Dir *dp) +{ + Qid q; + char buf[20]; + + switch(t) { + case Qcsnctl: + q = (Qid){QID(csn, Qcsnctl), 0, 0}; + sprint(buf, "csn%dctl", csn); + devdir(c, q, buf, 0, eve, 0664, dp); + return 1; + case Qcsnraw: + q = (Qid){QID(csn, Qcsnraw), 0, 0}; + sprint(buf, "csn%draw", csn); + devdir(c, q, buf, cp->ncfg, eve, 0444, dp); + return 1; + } + return -1; +} + +static int +pnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) +{ + Qid q; + int csn; + Card *cp; + char name[KNAMELEN]; + +DPRINT("pnpgen s %d offset %uld qid %lux\n", s, (ulong)c->offset, (ulong)c->qid.path); + switch(TYPE(c->qid)){ + case Qtopdir: + if(s == DEVDOTDOT){ + q = (Qid){QID(0, Qtopdir), 0, QTDIR}; + snprint(name, KNAMELEN, "#%C", pnpdevtab.dc); + devdir(c, q, name, 0, eve, 0555, dp); + return 1; + } + return devgen(c, nil, topdir, nelem(topdir), s, dp); + case Qpnpdir: + if(s == DEVDOTDOT){ + q = (Qid){QID(0, Qtopdir), 0, QTDIR}; + snprint(name, KNAMELEN, "#%C", pnpdevtab.dc); + devdir(c, q, name, 0, eve, 0555, dp); + return 1; + } +DPRINT("Qpnpdir s %d\n", s); + if(s < nelem(pnpdir)) + return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp); + s -= nelem(pnpdir); +DPRINT("Qpnpdir s now %d\n", s); + ilock(&pnp); + cp = pnp.cards; + while(s >= 2 && cp != nil) { + s -= 2; + cp = cp->next; + } + iunlock(&pnp); +DPRINT("Qpnpdir s now %d, cp %p\n", s, cp); + if(cp == nil) + return -1; + return pnpgen1(c, s+Qcsnctl, cp->csn, cp, dp); + case Qpnpctl: + return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp); + case Qcsnctl: + case Qcsnraw: + csn = CSN(c->qid); + ilock(&pnp); + cp = findcsn(csn, 0); + iunlock(&pnp); + if(cp == nil) + return -1; + return pnpgen1(c, TYPE(c->qid), csn, cp, dp); + default: + break; + } + return -1; +} + +static Chan* +pnpattach(char *spec) +{ + return devattach(pnpdevtab.dc, spec); +} + +Walkqid* +pnpwalk(Chan* c, Chan *nc, char** name, int nname) +{ + return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen); +} + +static int +pnpstat(Chan* c, uchar* dp, int n) +{ + return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen); +} + +static Chan* +pnpopen(Chan *c, int omode) +{ + c = devopen(c, omode, (Dirtab*)0, 0, pnpgen); + switch(TYPE(c->qid)){ + default: + break; + } + return c; +} + +static void +pnpclose(Chan*) +{ +} + +static long +pnpread(Chan *c, void *va, long n, vlong offset) +{ + int csn, i; + Card *cp; + char *a = va, buf[20]; + + switch(TYPE(c->qid)){ + case Qtopdir: + case Qpnpdir: + case Qpcidir: + return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen); + case Qpnpctl: + if(pnp.rddata > 0) + sprint(buf, "enabled 0x%x\n", pnp.rddata); + else + sprint(buf, "disabled\n"); + return readstr(offset, a, n, buf); + case Qcsnraw: + csn = CSN(c->qid); + ilock(&pnp); + cp = findcsn(csn, 0); + iunlock(&pnp); + if(cp == nil) + error(Egreg); + if(offset+n > cp->ncfg) + n = cp->ncfg - offset; + ilock(&pnp); + initiation(); + cmd(0x03, csn); /* Wake up the card */ + for (i = 0; i < offset+9; i++) /* 9 == skip serial + csum */ + getresbyte(pnp.rddata); + for (i = 0; i < n; i++) + a[i] = getresbyte(pnp.rddata); + cmd(0x03, 0); /* Wake all cards with a CSN of 0, putting this card to sleep */ + cmd(0x02, 0x02); /* return cards to Wait for Key state */ + iunlock(&pnp); + break; + case Qcsnctl: + csn = CSN(c->qid); + ilock(&pnp); + cp = findcsn(csn, 0); + iunlock(&pnp); + if(cp == nil) + error(Egreg); + sprint(buf, "%s\n", serial(cp->id1, cp->id2)); + return readstr(offset, a, n, buf); + default: + error(Egreg); + } + return n; +} + +static long +pnpwrite(Chan *c, void *a, long n, vlong offset) +{ + ulong port; + char buf[256]; + + switch(TYPE(c->qid)){ + case Qpnpctl: + if(n >= sizeof(buf)) + n = sizeof(buf)-1; + strncpy(buf, a, n); + buf[n] = 0; + if(strncmp(buf, "rddata ", 7) == 0) { + port = strtoul(buf+7, 0, 0); + if(port < 0x203 || port > 0x3ff) + error("bad value for rddata port"); + if(!pnpscan(port)) + error("no cards found"); + } + else if(strncmp(buf, "debug ", 6) == 0) + pnp.debug = strtoul(buf+6, 0, 0); + else + error(Ebadctl); + break; + default: +USED(offset); + error(Egreg); + } + return n; +} + +Dev pnpdevtab = { + '$', + "pnp", + + pnpreset, + devinit, + pnpattach, + pnpwalk, + pnpstat, + pnpopen, + devcreate, + pnpclose, + pnpread, + devbread, + pnpwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/port/qio.c b/port/qio.c index 2fb7e78f4ba440fc59c73fdcf3115528b469f050..6542dda136883ed0ec50dda21a375000fe8a51c5 100644 --- a/port/qio.c +++ b/port/qio.c @@ -817,6 +817,8 @@ qwait(Queue *q) if(q->state & Qclosed){ if(++q->eof > 3) return -1; + if(*q->err && strcmp(q->err, Ehungup) != 0) + return -1; return 0; } diff --git a/port/sysfile.c b/port/sysfile.c index 5fb38bcf14cd0712bf98ccb0b6c09aaf4842cc88..847fbaf2764ae8fcc768e611d566d8a66de98c1a 100644 --- a/port/sysfile.c +++ b/port/sysfile.c @@ -417,6 +417,7 @@ syspread(ulong *arg) uvlong v; va_list list; + /* use varargs to guarantee alignment of vlong */ va_start(list, arg[2]); v = va_arg(list, uvlong); va_end(list); @@ -489,6 +490,7 @@ syspwrite(ulong *arg) uvlong v; va_list list; + /* use varargs to guarantee alignment of vlong */ va_start(list, arg[2]); v = va_arg(list, uvlong); va_end(list);