From a1f31a8c9b85ef3496c303c8db96f507b389f2e5 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 26 Jun 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-06-26 --- bitsy/power.c | 3 - pc/devether.c | 1 - pc/devusb.c | 1116 ++++++++++++++++++++++++++++++++++++++++++++++- pc/ether82557.c | 13 +- pc/fns.h | 1 - pc/pci.c | 1 - pc/uarti8250.c | 8 - 7 files changed, 1105 insertions(+), 38 deletions(-) diff --git a/bitsy/power.c b/bitsy/power.c index 8dfbf39283609614de45c29d4b0a8629c15a1db5..95f5bae666e6de40837639b32a9fd4e377c75f4f 100644 --- a/bitsy/power.c +++ b/bitsy/power.c @@ -78,9 +78,6 @@ static void sa1100_power_off(void) { -iprint("calling resume\n"); -sa1100_power_resume(); - /* enable wakeup by µcontroller, on/off switch or real-time clock alarm */ powerregs->pwer = 1 << IRQrtc | 1 << IRQgpio0 | 1 << IRQgpio1; diff --git a/pc/devether.c b/pc/devether.c index abcf385034e955f3d3851e7d0ca919a3df5517b4..a522dc8d14ac2503a2f7a38c28bc5c937c2c2f86 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -354,7 +354,6 @@ etherreset(void) int i, n, ctlrno; char name[32], buf[128]; - print("Searching for ethernet devices\n"); for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ if(ether == 0) ether = malloc(sizeof(Ether)); diff --git a/pc/devusb.c b/pc/devusb.c index 3d56f242b1d34d975a13a581e89ec073a6d0af20..d55dd396824e8a54e5d1a02e1a828ba5aced9ef2 100644 --- a/pc/devusb.c +++ b/pc/devusb.c @@ -197,9 +197,9 @@ enum { static char *devstates[] = { [Disabled] "Disabled", - [Attached] "Attached", + [Attached] "Attached", [Enabled] "Enabled", - [Assigned] "Assigned", + [Assigned] "Assigned", [Configured] "Configured", }; @@ -213,14 +213,14 @@ struct Endpt { int id; /* hardware endpoint address */ int maxpkt; /* maximum packet size (from endpoint descriptor) */ int data01; /* 0=DATA0, 1=DATA1 */ - byte eof; + byte eof; ulong csp; - byte mode; /* OREAD, OWRITE, ORDWR */ - byte nbuf; /* number of buffers allowed */ - byte periodic; - byte iso; - byte debug; - byte active; /* listed for examination by interrupts */ + byte mode; /* OREAD, OWRITE, ORDWR */ + byte nbuf; /* number of buffers allowed */ + byte periodic; + byte iso; + byte debug; + byte active; /* listed for examination by interrupts */ int sched; /* schedule index; -1 if undefined or aperiodic */ int setin; ulong bw; /* bandwidth requirement */ @@ -369,7 +369,8 @@ dumptd(TD *t, int follow) XPRINT("td %8.8lux: ", t); XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); - XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); + XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", + buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); if(debug && t->bp && (t->flags & CancelTD) == 0) dumpdata(t->bp, n); if(!follow || t->link & Terminate || t->link & IsQH) @@ -479,7 +480,8 @@ cleantd(TD *t, int discard) Block *b; int n, err; - XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); + XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", + t->link, t->status, t->dev, t->buffer); if(t->ep != nil && t->ep->debug) dumptd(t, 0); if(t->status & Active) @@ -487,7 +489,8 @@ cleantd(TD *t, int discard) err = t->status & (AnyError&~NAKed); /* TO DO: on t->status&AnyError, q->entries will not have advanced */ if (err) - XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); + XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", + t->link, t->status, t->dev, t->buffer); switch(t->dev&0xFF){ case TokIN: if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){ @@ -550,7 +553,8 @@ cleanq(QH *q, int discard, int vf) ilock(ub); tp = nil; for(t = q->first; t != nil;){ - XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer, t->flags, t->next); + XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", + t->link, t->status, t->dev, t->buffer, t->flags, t->next); if(t->status & Active){ if(t->status & NAKed){ t->status = (t->status & ~NAKed) | IOC; /* ensure interrupt next frame */ @@ -565,9 +569,9 @@ cleanq(QH *q, int discard, int vf) t = t->next; continue; } -tp = t; -t = t->next; -continue; + tp = t; + t = t->next; + continue; break; } t->status &= ~IOC; @@ -879,4 +883,1082 @@ schedendpt(Endpt *e) QH *qh; int q; - if(!e->periodic || e->sched + if(!e->periodic || e->sched >= 0) + return 0; + ub = &ubus; + if(e->epq == nil){ + e->epq = allocqh(ub); + if(e->epq == nil) + return -1; + } + qlock(ub->tree); + q = pickschedq(ub->tree, e->pollms, e->bw, ~0); /* TO DO: bus bandwidth limit */ + if(q < 0) + return -1; + ub->tree->bw[q] += e->bw; + qh = &ub->tree->root[q]; + e->sched = q; + e->epq->head = qh->entries; + e->epq->entries = Terminate; + qh->entries = PADDR(e->epq) | IsQH; + qunlock(ub->tree); + return 0; +} + +static void +unschedendpt(Endpt *e) +{ + Ctlr *ub; + ulong p; + QH *qh; + int q; + + ub = &ubus; + if(!e->periodic || (q = e->sched) < 0) + return; + p = PADDR(e->epq) | IsQH; + qlock(ub->tree); + ub->tree->bw[q] -= e->bw; + qh = &ub->tree->root[q]; + for(; qh->entries != p; qh = QFOL(qh->entries)) + if(qh->entries & Terminate || (qh->entries & IsQH) == 0){ + qunlock(ub->tree); + panic("usb: unschedendpt"); + } + qh->entries = e->epq->head; + qunlock(ub->tree); + e->epq->head = Terminate; +} + +static Endpt * +devendpt(Udev *d, int id, int add) +{ + Endpt *e, **p; + Ctlr *ub; + + ub = &ubus; + p = &d->ep[id&0xF]; + lock(d); + if((e = *p) != nil){ + incref(e); + unlock(d); + return e; + } + unlock(d); + if(!add) + return nil; + e = mallocz(sizeof(*e), 1); + e->ref = 1; + e->x = id&0xF; + e->id = id; + e->periodic = 0; + e->sched = -1; + e->maxpkt = 8; + e->pollms = 0; + e->bw = 0; + e->nbuf = 1; + e->dev = d; + e->active = 0; + e->epq = allocqh(ub); + if(e->epq == nil) + panic("devendpt"); + + lock(d); + if(*p != nil){ + incref(*p); + unlock(d); + free(e); + return *p; + } + *p = e; + unlock(d); + e->rq = qopen(8*1024, 0, nil, e); + e->wq = qopen(8*1024, 0, nil, e); + return e; +} + +static void +freept(Endpt *e) +{ + if(e != nil && decref(e) == 0){ + XPRINT("freept(%d,%d)\n", e->dev->x, e->x); + unschedendpt(e); + e->dev->ep[e->x] = nil; + eptdeactivate(e); + if(e->epq != nil) + freeqh(&ubus, e->epq); + free(e); + } +} + +static void +usbdevreset(Udev *d) +{ + d->state = Disabled; + if(Class(d->csp) == Hubclass) + for(d = d->ports; d != nil; d = d->next) + usbdevreset(d); +} + +static void +freedev(Udev *d) +{ + int i; + + if(d != nil && decref(d) == 0){ + for(i=0; iep); i++) + freept(d->ep[i]); + if(d->x >= 0) + usbdev[d->x] = nil; + free(d); + } +} + +static void +hubportreset(Udev *h, int p) +{ + USED(h, p); + /* reset state of each attached device? */ +} + +static int ioports[] = {-1, Portsc0, Portsc1}; + +static void +portreset(int port) +{ + Ctlr *ub; + int i, p; + + /* should check that device not being configured on other port? */ + p = ioports[port]; + ub = &ubus; + qlock(&ub->resetl); + if(waserror()){ + qunlock(&ub->resetl); + nexterror(); + } + XPRINT("r: %x\n", IN(p)); + ilock(ub); + OUT(p, PortReset); + delay(12); /* BUG */ + XPRINT("r2: %x\n", IN(p)); + OUT(p, IN(p) & ~PortReset); + XPRINT("r3: %x\n", IN(p)); + OUT(p, IN(p) | PortEnable); + microdelay(64); + for(i=0; i<1000 && (IN(p) & PortEnable) == 0; i++) + ; + XPRINT("r': %x %d\n", IN(p), i); + OUT(p, (IN(p) & ~PortReset)|PortEnable); + iunlock(ub); + hubportreset(nil, port); + poperror(); + qunlock(&ub->resetl); +} + +static void +portenable(int port, int on) +{ + Ctlr *ub; + int w, p; + + /* should check that device not being configured on other port? */ + p = ioports[port]; + ub = &ubus; + qlock(&ub->resetl); + if(waserror()){ + qunlock(&ub->resetl); + nexterror(); + } + ilock(ub); + w = IN(p); + if(on) + w |= PortEnable; + else + w &= ~PortEnable; + OUT(p, w); + microdelay(64); + iunlock(ub); + XPRINT("e: %x\n", IN(p)); + if(!on) + hubportreset(nil, port); + poperror(); + qunlock(&ub->resetl); +} + +static int +portinfo(Ctlr *ub, int *p0, int *p1) +{ + int m, v; + + ilock(ub); + m = 0; + if((v = IN(Portsc0)) & PortChange){ + OUT(Portsc0, v); + m |= 1<<0; + } + *p0 = v; + if((v = IN(Portsc1)) & PortChange){ + OUT(Portsc1, v); + m |= 1<<1; + } + *p1 = v; + iunlock(ub); + return m; +} + +static void +interrupt(Ureg*, void *a) +{ + Ctlr *ub; + Endpt *e; + int s; + QH *q; + + ub = a; + s = IN(Status); + OUT(Status, s); + if ((s & 0x1f) == 0) + return; + XPRINT("usbint: #%x f%d\n", s, IN(Frnum)); + if (s & 0x1a) { + XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod)); + XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); + } + + XPRINT("cleanq(ub->ctlq, 0, 0)\n"); + cleanq(ub->ctlq, 0, 0); + XPRINT("cleanq(ub->bulkq, 0, Vf)\n"); + cleanq(ub->bulkq, 0, Vf); + XPRINT("clean recvq\n"); + for (q = ub->recvq->next; q; q = q->hlink) { + XPRINT("cleanq(q, 0, Vf)\n"); + cleanq(q, 0, Vf); + } + ilock(&activends); + for(e = activends.f; e != nil; e = e->activef) + if(e->epq != nil) { + XPRINT("cleanq(e->epq, 0, 0)\n"); + cleanq(e->epq, 0, 0); + } + iunlock(&activends); +} + +enum +{ + Qtopdir = 0, + Q2nd, + Qbusctl, + Qnew, + Qport, + Q3rd, + Qctl, + Qsetup, + Qdebug, + Qstatus, + Qep0, + /* other endpoint files */ +}; + +/* + * Qid path is: + * 8 bits of file type (qids above) + * 10 bits of slot number +1; 0 means not attached to device + */ +#define QSHIFT 8 /* location in qid of device # */ +#define QMASK ((1<>QSHIFT) + +static Dirtab usbdir2[] = { + "new", {Qnew}, 0, 0666, + "ctl", {Qbusctl}, 0, 0666, + "port", {Qport}, 0, 0444, +}; + +static Dirtab usbdir3[]={ + "ctl", {Qctl}, 0, 0666, + "setup", {Qsetup}, 0, 0666, + "status", {Qstatus}, 0, 0444, + "debug", {Qdebug}, 0, 0666, + /* epNdata names are generated on demand */ +}; + +static Udev * +usbdeviceofpath(ulong path) +{ + int s; + + s = DEVPATH(path); + if(s == 0) + return nil; + return usbdev[s-1]; +} + +static Udev * +usbdevice(Chan *c) +{ + Udev *d; + + d = usbdeviceofpath(c->qid.path); + if(d == nil || d->id != c->qid.vers || d->state == Disabled) + error(Ehungup); + return d; +} + +static Udev * +usbnewdevice(void) +{ + Udev *d; + Endpt *e; + int i; + + d = nil; + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + for(i=0; iref = 1; + d->x = i; + d->id = (ubus.idgen << 8) | i; + d->state = Enabled; + e = devendpt(d, 0, 1); /* always provide control endpoint 0 */ + e->mode = ORDWR; + e->periodic = 0; + e->sched = -1; + usbdev[i] = d; + break; + } + poperror(); + qunlock(&usbstate); + return d; +} + +static void +usbreset(void) +{ + Pcidev *cfg; + int i; + ulong port; + QTree *qt; + TD *t; + Ctlr *ub; + ISAConf isa; + + if(isaconfig("usb", 0, &isa) == 0) { + XPRINT("usb not in plan9.ini\n"); +// return; + } + ub = &ubus; + memset(&cfg, 0, sizeof(cfg)); + cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ + if(cfg == nil) { + cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ + if(cfg == nil) { + DPRINT("No USB device found\n"); + return; + } + } + port = cfg->mem[4].bar & ~0x0F; + if (port == 0) { + print("usb: failed to map registers\n"); + return; + } + + DPRINT("USB: %x/%x port 0x%lux size 0x%x irq %d\n", + cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); + + i = inb(port+SOFMod); + if(1){ + OUT(Cmd, 4); /* global reset */ + delay(15); + OUT(Cmd, 0); /* end reset */ + delay(4); + } + outb(port+SOFMod, i); + /* + * Interrupt handler. + * Bail out if no IRQ assigned by the BIOS. + */ + if(cfg->intl == 0xFF || cfg->intl == 0) + return; + intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); + + ub->io = port; + ub->tdpool = xspanalloc(128*sizeof(TD), 16, 0); + for(i=128; --i>=0;){ + ub->tdpool[i].next = ub->freetd; + ub->freetd = &ub->tdpool[i]; + } + ub->qhpool = xspanalloc(32*sizeof(QH), 16, 0); + for(i=32; --i>=0;){ + ub->qhpool[i].next = ub->freeqh; + ub->freeqh = &ub->qhpool[i]; + } + + /* + * the root of the periodic (interrupt & isochronous) scheduling tree + * points to the control queue and the bandwidth sop for bulk traffic. + * this is looped following the instructions in PIIX4 errata 29773804.pdf: + * a QH links to a looped but inactive TD as its sole entry, + * with its head entry leading on to the bulk traffic, the last QH of which + * links back to the empty QH. + */ + ub->ctlq = allocqh(ub); + ub->bwsop = allocqh(ub); + ub->bulkq = allocqh(ub); + ub->recvq = allocqh(ub); + t = alloctd(ub); /* inactive TD, looped */ + t->link = PADDR(t); + ub->bwsop->entries = PADDR(t); + ub->ctlq->head = PADDR(ub->bwsop) | IsQH; + ub->bwsop->head = PADDR(ub->bulkq) | IsQH; + ub->bulkq->head = PADDR(ub->recvq) | IsQH; + ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ + XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", + IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); + XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", + IN(Flbaseadd), inb(port+SOFMod), IN(Portsc0), IN(Portsc1)); + OUT(Cmd, 0); /* stop */ + ub->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); + qt = mkqhtree(ub->frames, NFRAME, 32); + if(qt == nil){ + print("usb: can't allocate scheduling tree\n"); + ub->io = 0; + return; + } + qt->root->head = PADDR(ub->ctlq) | IsQH; + ub->tree = qt; + XPRINT("usb tree: nel=%d depth=%d\n", qt->nel, qt->depth); + + outl(port+Flbaseadd, PADDR(ub->frames)); + OUT(Frnum, 0); + OUT(Usbintr, 0xF); /* enable all interrupts */ + XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(port+SOFMod)); + XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); +} + +void +usbinit(void) +{ + Udev *d; + + if(ubus.io != 0 && usbdev[0] == nil){ + d = usbnewdevice(); /* reserve device 0 for configuration */ + incref(d); + d->state = Attached; + } +} + +Chan * +usbattach(char *spec) +{ + Ctlr *ub; + + ub = &ubus; + if(ub->io == 0) { + XPRINT("usbattach failed\n"); + error(Enodev); + } + if((IN(Cmd)&1)==0 || *spec) + OUT(Cmd, 1); /* run */ +// pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0)); + return devattach('U', spec); +} + +static int +usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) +{ + int t; + Qid q; + ulong path; + Udev *d; + Dirtab *tab; + Endpt *e; + + /* + * Top level directory contains the name of the device. + */ + if(c->qid.path == Qtopdir){ + if(s == DEVDOTDOT){ + mkqid(&q, Qtopdir, 0, QTDIR); + devdir(c, q, "#U", 0, eve, 0555, dp); + return 1; + } + if(s == 0){ + mkqid(&q, Q2nd, 0, QTDIR); + devdir(c, q, "usb", 0, eve, 0555, dp); + return 1; + } + return -1; + } + + /* + * Second level contains "new" plus all the clients. + */ + t = QID(c->qid); + if(t < Q3rd){ + if(s == DEVDOTDOT){ + mkqid(&q, Qtopdir, 0, QTDIR); + devdir(c, q, "#U", 0, eve, 0555, dp); + return 1; + } + if(s < nelem(usbdir2)){ + tab = &usbdir2[s]; + devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); + return 1; + } + s -= nelem(usbdir2); + if(s >= 0 && s < nelem(usbdev)){ + d = usbdev[s]; + if(d == nil) + return -1; + sprint(up->genbuf, "%d", s); + mkqid(&q, ((s+1)<id, QTDIR); + devdir(c, q, up->genbuf, 0, eve, 0555, dp); + return 1; + } + return -1; + } + + /* + * Third level. + */ + path = c->qid.path & ~QMASK; /* slot component */ + if(s == DEVDOTDOT){ + mkqid(&q, Q2nd, c->qid.vers, QTDIR); + devdir(c, q, "usb", 0, eve, 0555, dp); + return 1; + } + if(s < nelem(usbdir3)){ + Dirtab *tab = &usbdir3[s]; + mkqid(&q, path | tab->qid.path, c->qid.vers, QTFILE); + devdir(c, q, tab->name, tab->length, eve, tab->perm, dp); + return 1; + } + + /* active endpoints */ + d = usbdeviceofpath(path); + if(d == nil) + return -1; + s -= nelem(usbdir3); + if(s < 0 || s >= nelem(d->ep)) + return -1; + if(s == 0 || (e = d->ep[s]) == nil) /* ep0data is called "setup" */ + return 0; + sprint(up->genbuf, "ep%ddata", s); + mkqid(&q, path | (Qep0+s), c->qid.vers, QTFILE); + devdir(c, q, up->genbuf, 0, eve, e->mode==OREAD? 0444: e->mode==OWRITE? 0222: 0666, dp); + return 1; +} + +static Walkqid* +usbwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, nil, 0, usbgen); +} + +static int +usbstat(Chan *c, uchar *db, int n) +{ + return devstat(c, db, n, nil, 0, usbgen); +} + +Chan * +usbopen(Chan *c, int omode) +{ + Udev *d; + int f, s; + + if(c->qid.type == QTDIR) + return devopen(c, omode, nil, 0, usbgen); + + f = 0; + if(QID(c->qid) == Qnew){ + d = usbnewdevice(); + if(d == nil) { + XPRINT("usbopen failed (usbnewdevice)\n"); + error(Enodev); + } + c->qid.path = Qctl|((d->x+1)<qid.vers = d->id; + f = 1; + } + + if(c->qid.path < Q3rd) + return devopen(c, omode, nil, 0, usbgen); + + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + + switch(QID(c->qid)){ + case Qctl: + d = usbdevice(c); + if(0&&d->busy) + error(Einuse); + d->busy = 1; + if(!f) + incref(d); + break; + + default: + d = usbdevice(c); + s = QID(c->qid) - Qep0; + if(s >= 0 && s < nelem(d->ep)){ + Endpt *e; + if((e = d->ep[s]) == nil) { + XPRINT("usbopen failed (endpoint)\n"); + error(Enodev); + } + if(schedendpt(e) < 0) + error("can't schedule USB endpoint"); + eptactivate(e); + } + incref(d); + break; + } + poperror(); + qunlock(&usbstate); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +usbcreate(Chan *c, char *name, int omode, ulong perm) +{ + USED(c, name, omode, perm); + error(Eperm); +} + +void +usbremove(Chan*) +{ + error(Eperm); +} + +void +usbwstat(Chan *c, char *dp) +{ + USED(c, dp); + error(Eperm); +} + +void +usbclose(Chan *c) +{ + Udev *d; + + if(c->qid.type == QTDIR || c->qid.path < Q3rd) + return; + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + d = usbdevice(c); + if(QID(c->qid) == Qctl) + d->busy = 0; + if(c->flag & COPEN) + freedev(d); + poperror(); + qunlock(&usbstate); +} + +static int +eptinput(void *arg) +{ + Endpt *e; + + e = arg; + return e->eof || e->err || qcanread(e->rq); +} + +static long +readusb(Endpt *e, void *a, long n) +{ + Block *b; + uchar *p; + long l, i; + + XPRINT("qlock(%p)\n", &e->rlock); + qlock(&e->rlock); + XPRINT("got qlock(%p)\n", &e->rlock); + if(waserror()){ + qunlock(&e->rlock); + eptcancel(e); + nexterror(); + } + p = a; + do { + if(e->eof) { + XPRINT("e->eof\n"); + break; + } + if(e->err) + error(e->err); + qrcv(e); + if(!e->iso) + e->data01 ^= 1; + sleep(&e->rr, eptinput, e); + if(e->err) + error(e->err); + b = qget(e->rq); /* TO DO */ + if(b == nil) { + XPRINT("b == nil\n"); + break; + } + if(waserror()){ + freeb(b); + nexterror(); + } + l = BLEN(b); + if((i = l) > n) + i = n; + if(i > 0){ + memmove(p, b->rp, i); + p += i; + } + poperror(); + freeb(b); + n -= i; + } while (l == e->maxpkt && n > 0); + poperror(); + qunlock(&e->rlock); + return p-(uchar*)a; +} + +long +usbread(Chan *c, void *a, long n, vlong offset) +{ + Endpt *e; + Udev *d; + char buf[48], *s; + int t, w0, w1, ps, l, i; + + if(c->qid.type == QTDIR) + return devdirread(c, a, n, nil, 0, usbgen); + + t = QID(c->qid); + switch(t){ + case Qbusctl: + snprint(buf, sizeof(buf), "%11d %11d ", 0, 0); + return readstr(offset, a, n, buf); + + case Qport: + ps = portinfo(&ubus, &w0, &w1); + snprint(buf, sizeof(buf), "0x%ux 0x%ux 0x%ux ", ps, w0, w1); + return readstr(offset, a, n, buf); + + case Qctl: + d = usbdevice(c); + sprint(buf, "%11d %11d ", d->x, d->id); + return readstr(offset, a, n, buf); + + case Qsetup: /* endpoint 0 */ + d = usbdevice(c); + if((e = d->ep[0]) == nil) + error(Eio); /* can't happen */ + e->data01 = 1; + n = readusb(e, a, n); + if(e->setin){ + e->setin = 0; + e->data01 = 1; + writeusb(e, "", 0, TokOUT); + } + break; + + case Qdebug: + n=0; + break; + + case Qstatus: + d = usbdevice(c); + s = smalloc(READSTR); + if(waserror()){ + free(s); + nexterror(); + } + l = snprint(s, READSTR, "%s %#6.6lux\n", devstates[d->state], d->csp); + for(i=0; iep); i++) + if((e = d->ep[i]) != nil) /* TO DO: freeze e */ + l += snprint(s+l, READSTR-l, "%2d %#6.6lux %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks); + n = readstr(offset, a, n, s); + poperror(); + free(s); + break; + + default: + d = usbdevice(c); + if((t -= Qep0) < 0 || t >= nelem(d->ep)) + error(Eio); + if((e = d->ep[t]) == nil || e->mode == OWRITE) + error(Eio); /* can't happen */ + n=readusb(e, a, n); + break; + } + return n; +} + +static int +qisempty(void *arg) +{ + return ((QH*)arg)->entries & Terminate; +} + +static long +writeusb(Endpt *e, void *a, long n, int tok) +{ + long i; + Block *b; + uchar *p; + QH *qh; + + p = a; + qlock(&e->wlock); + if(waserror()){ + qunlock(&e->wlock); + eptcancel(e); + nexterror(); + } + do { + int j; + + if(e->err) + error(e->err); + if((i = n) >= e->maxpkt) + i = e->maxpkt; + b = allocb(i); + if(waserror()){ + freeb(b); + nexterror(); + } + XPRINT("out [%ld]", i); + for (j = 0; j < i; j++) XPRINT(" %.2x", p[j]); + XPRINT("\n"); + memmove(b->wp, p, i); + b->wp += i; + p += i; + n -= i; + poperror(); + qh = qxmit(e, b, tok); + tok = TokOUT; + if(!e->iso) + e->data01 ^= 1; + if(e->ntd >= e->nbuf) { + XPRINT("writeusb: sleep %lux\n", &e->wr); + sleep(&e->wr, qisempty, qh); + XPRINT("writeusb: awake\n"); + } + } while(n > 0); + poperror(); + qunlock(&e->wlock); + return p-(uchar*)a; +} + +long +usbwrite(Chan *c, void *a, long n, vlong) +{ + Udev *d; + Endpt *e; + int id, nw, nf, t, i; + char cmd[50], *fields[10]; + + if(c->qid.type == QTDIR) + error(Egreg); + t = QID(c->qid); + if(t == Qbusctl){ + if(n >= sizeof(cmd)-1) + n = sizeof(cmd)-1; + memmove(cmd, a, n); + cmd[n] = 0; + nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); + if(nf==1 && strcmp(fields[0], "dump")==0){ + dumpframe(-1, -1); + return n; + } + if(nf < 2) + error(Ebadarg); + id = strtol(fields[1], nil, 0); + if(id != 1 && id != 2) + error(Ebadarg); /* there are two ports on the root hub */ + if(strcmp(fields[0], "reset") == 0) + portreset(id); + else if(strcmp(fields[0], "enable") == 0) + portenable(id, 1); + else if(strcmp(fields[0], "disable") == 0) + portenable(id, 0); + else + error(Ebadarg); + return n; + } + d = usbdevice(c); + t = QID(c->qid); + switch(t){ + case Qctl: + if(n >= sizeof(cmd)-1) + n = sizeof(cmd)-1; + memmove(cmd, a, n); + cmd[n] = 0; + nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); + if(nf > 1 && strcmp(fields[0], "speed") == 0){ + d->ls = strtoul(fields[1], nil, 0) == 0; + } else if(nf > 3 && strcmp(fields[0], "class") == 0){ + i = strtoul(fields[2], nil, 0); + d->npt = strtoul(fields[1], nil, 0); + /* class config# csp ( == class subclass proto) */ + if (i < 0 || i >= nelem(d->ep) + || d->npt > nelem(d->ep) || i >= d->npt) + error(Ebadarg); + if (i == 0) { + d->csp = strtoul(fields[3], nil, 0); + } + if(d->ep[i] == nil) + d->ep[i] = devendpt(d, i, 1); + d->ep[i]->csp = strtoul(fields[3], nil, 0); + }else if(nf > 2 && strcmp(fields[0], "data") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->data01 = strtoul(fields[2], nil, 0) != 0; + }else if(nf > 2 && strcmp(fields[0], "maxpkt") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->maxpkt = strtoul(fields[2], nil, 0); + if(e->maxpkt > 1500) + e->maxpkt = 1500; + }else if(nf > 2 && strcmp(fields[0], "debug") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + if (i == -1) + debug = 0; + else { + debug = 1; + e = d->ep[i]; + e->debug = strtoul(fields[2], nil, 0); + } + }else if(nf > 1 && strcmp(fields[0], "unstall") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->err = nil; + }else if(nf == 6 && strcmp(fields[0], "ep") == 0){ + /* ep n maxpkt mode poll nbuf */ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep)) { + XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep)); + error(Ebadarg); + } + if((e = d->ep[i]) == nil) + e = devendpt(d, i, 1); + if(waserror()){ + freept(e); + nexterror(); + } + i = strtoul(fields[2], nil, 0); + if(i < 8 || i > 1023) + i = 8; + e->maxpkt = i; + e->mode = strcmp(fields[3],"r") == 0? OREAD : + strcmp(fields[3],"w") == 0? OWRITE : ORDWR; + e->periodic = 0; + e->sched = -1; + if(strcmp(fields[4], "bulk") == 0){ + Ctlr *ub; + + ub = &ubus; + /* Each bulk device gets a queue head hanging off the + * bulk queue head + */ + if (e->epq == nil) { + e->epq = allocqh(ub); + if(e->epq == nil) + panic("usbwrite: allocqh"); + } + queueqh(e->epq); + } else { + e->periodic = 1; + i = strtoul(fields[4], nil, 0); + if(i > 0 && i <= 1000) + e->pollms = i; + else { + XPRINT("field 4: 0 <= %d <= 1000\n", i); + error(Ebadarg); + } + } + i = strtoul(fields[5], nil, 0); + if(i >= 1 && i <= 32) + e->nbuf = i; + poperror(); + }else { + XPRINT("command %s, fields %d\n", fields[0], nf); + error(Ebadarg); + } + return n; + + case Qsetup: /* SETUP endpoint 0 */ + /* should canqlock etc */ + if((e = d->ep[0]) == nil) + error(Eio); /* can't happen */ + if(n < 8 || n > 1023) + error(Eio); + nw = *(uchar*)a & RD2H; + e->data01 = 0; + n = writeusb(e, a, n, TokSETUP); + if(nw == 0){ /* host to device: use IN[DATA1] to ack */ + e->data01 = 1; + nw = readusb(e, cmd, 8); + if(nw != 0) + error(Eio); /* could provide more status */ + }else + e->setin = 1; /* two-phase */ + break; + + default: /* sends DATA[01] */ + if((t -= Qep0) < 0 || t >= nelem(d->ep)) { + print("t = %d\n", t); + error(Eio); + } + if((e = d->ep[t]) == nil || e->mode == OREAD) { + error(Eio); /* can't happen */ + } + n = writeusb(e, a, n, TokOUT); + break; + } + return n; +} + +Dev usbdevtab = { + 'U', + "usb", + + usbreset, + usbinit, + usbattach, + usbwalk, + usbstat, + usbopen, + devcreate, + usbclose, + usbread, + devbread, + usbwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/pc/ether82557.c b/pc/ether82557.c index fae45bc3ba2ea7f1600861b94f3bcfe262c81fbf..8b0fe44196d5fc5953a1bf7b96e4c4d4fefe0cf2 100644 --- a/pc/ether82557.c +++ b/pc/ether82557.c @@ -225,6 +225,7 @@ typedef struct Ctlr { } Ctlr; static Ctlr* ctlrhead; +static Ctlr* ctlrtail; static uchar configdata[24] = { 0x16, /* byte count */ @@ -913,13 +914,11 @@ i82557pci(void) ctlr->port = port; ctlr->pcidev = p; - /* - * this is backwards from what we really wanted to do - * but this keeps the numbering of ethernet cards - * consistent with 9load. - */ - ctlr->next = ctlrhead; - ctlrhead = ctlr; + if(ctlrhead != nil) + ctlrtail->next = ctlr; + else + ctlrhead = ctlr; + ctlrtail = ctlr; pcisetbme(p); } diff --git a/pc/fns.h b/pc/fns.h index 405826e96e891dd61a0a3b3d5cd4b1722f9add28..01409d6af862aea57b9f82e72971047744fbd663 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -6,7 +6,6 @@ Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,v //void addscsilink(char*, Scsiio (*)(int, ISAConf*)); void archinit(void); void bootargs(ulong); -void cbinit(void); vlong checkcycintr(Ureg*, void*); int cistrcmp(char*, char*); int cistrncmp(char*, char*, int); diff --git a/pc/pci.c b/pc/pci.c index 1a3058347b24476838d67c46e4cc3c58cc28aa06..6bcd245f277804787fc2f32d74114ec5e39a6fa4 100644 --- a/pc/pci.c +++ b/pc/pci.c @@ -589,7 +589,6 @@ pcicfginit(void) } out: qunlock(&pcicfginitlock); - cbinit(); } static int diff --git a/pc/uarti8250.c b/pc/uarti8250.c index fd252a7171a468862aac8e3d8e11dcf3e1f78934..22d0e33d5bdd008d360a5e965bd01e15804791f5 100644 --- a/pc/uarti8250.c +++ b/pc/uarti8250.c @@ -134,10 +134,6 @@ static Uart i8250uart[2] = { { .regs = &i8250ctlr[0], .name = "COM1", .freq = UartFREQ, - .bits = 8, - .stop = 1, - .parity = 'n', - .baud = 9600, .phys = &i8250physuart, .special=0, .next = &i8250uart[1], }, @@ -145,10 +141,6 @@ static Uart i8250uart[2] = { { .regs = &i8250ctlr[1], .name = "COM2", .freq = UartFREQ, - .bits = 8, - .stop = 1, - .parity = 'n', - .baud = 9600, .phys = &i8250physuart, .special=0, .next = nil, },