X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2Fcmd%2Fnusb%2Fusbd%2Fhub.c;h=8fb19d2148b27a0cf3322df2b3ad66c8356b8490;hb=07674f6e8d241ffbec969fab7fc1d71cef8e0e69;hp=6d64c001dcee62c9cddee6222fa4975f2e4cdff0;hpb=7f27b397caa5b6b585a186c2351831d2788fa5f9;p=plan9front.git diff --git a/sys/src/cmd/nusb/usbd/hub.c b/sys/src/cmd/nusb/usbd/hub.c index 6d64c001d..8fb19d214 100644 --- a/sys/src/cmd/nusb/usbd/hub.c +++ b/sys/src/cmd/nusb/usbd/hub.c @@ -10,35 +10,9 @@ QLock hublock; static int nhubs; static int mustdump; static int pollms = Pollms; -static Lock masklck; static char *dsname[] = { "disabled", "attached", "configed" }; -int -getdevnb(uvlong *maskp) -{ - int i; - - lock(&masklck); - for(i = 0; i < 8 * sizeof *maskp; i++) - if((*maskp & (1ULL<= 0) - *maskp &= ~(1ULL<dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0); } -/* - * This may be used to detect overcurrent on the hub - */ -static void -checkhubstatus(Hub *h) +static int +configusb2hub(Hub *h, DHub *dd, int nr) { - uchar buf[4]; - int sts; + uchar *PortPwrCtrlMask; + int i, offset, mask, nmap; + Port *pp; - if(h->isroot) /* not for root hubs */ - return; - if(usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetstatus, 0, 0, buf, 4) < 0){ - dprint(2, "%s: get hub status: %r\n", h->dev->dir); - return; + h->nport = dd->bNbrPorts; + nmap = 1 + h->nport/8; + if(nr < 7 + 2*nmap){ + fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir); + return -1; + } + h->port = emallocz((h->nport+1)*sizeof(Port), 1); + h->pwrms = dd->bPwrOn2PwrGood*2; + if(h->pwrms < Powerdelay) + h->pwrms = Powerdelay; + h->maxcurrent = dd->bHubContrCurrent; + h->pwrmode = dd->wHubCharacteristics[0] & 3; + h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0; + h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0; + PortPwrCtrlMask = dd->DeviceRemovable + nmap; + for(i = 1; i <= h->nport; i++){ + pp = &h->port[i]; + offset = i/8; + mask = 1<<(i%8); + pp->removable = (dd->DeviceRemovable[offset] & mask) != 0; + pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0; } - sts = GET2(buf); - dprint(2, "hub %s: status %#ux\n", h->dev->dir, sts); + return 0; } static int -confighub(Hub *h) +configusb3hub(Hub *h, DSSHub *dd, int nr) { - int type; - uchar buf[128]; /* room for extra descriptors */ - int i; - Usbdev *d; - DHub *dd; + int i, offset, mask, nmap; Port *pp; - int nr; - int nmap; - uchar *PortPwrCtrlMask; - int offset; - int mask; - d = h->dev->usb; - for(i = 0; i < nelem(d->ddesc); i++) - if(d->ddesc[i] == nil) - break; - else if(d->ddesc[i]->data.bDescriptorType == Dhub){ - dd = (DHub*)&d->ddesc[i]->data; - nr = Dhublen; - goto Config; - } - type = Rd2h|Rclass|Rdev; - nr = usbcmd(h->dev, type, Rgetdesc, Dhub<<8|0, 0, buf, sizeof buf); - if(nr < Dhublen){ - dprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir); - return -1; - } - dd = (DHub*)buf; -Config: h->nport = dd->bNbrPorts; nmap = 1 + h->nport/8; - if(nr < 7 + 2*nmap){ + if(nr < 10 + nmap){ fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir); return -1; } @@ -116,24 +77,68 @@ Config: h->pwrmode = dd->wHubCharacteristics[0] & 3; h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0; h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0; - PortPwrCtrlMask = dd->DeviceRemovable + nmap; for(i = 1; i <= h->nport; i++){ pp = &h->port[i]; offset = i/8; mask = 1<<(i%8); pp->removable = (dd->DeviceRemovable[offset] & mask) != 0; - pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0; + } + if(usbcmd(h->dev, Rh2d|Rclass|Rdev, Rsethubdepth, h->dev->depth, 0, nil, 0) < 0){ + fprint(2, "%s: %s: sethubdepth: %r\n", argv0, h->dev->dir); + return -1; } return 0; } +static int +confighub(Hub *h) +{ + uchar buf[128]; /* room for extra descriptors */ + int i, dt, dl, nr; + Usbdev *d; + void *dd; + + d = h->dev->usb; + if(h->dev->isusb3){ + dt = Dsshub; + dl = Dsshublen; + } else { + dt = Dhub; + dl = Dhublen; + } + for(i = 0; i < nelem(d->ddesc); i++){ + if(d->ddesc[i] == nil) + break; + if(d->ddesc[i]->data.bDescriptorType == dt){ + dd = &d->ddesc[i]->data; + nr = d->ddesc[i]->data.bLength; + goto Config; + } + } + nr = usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetdesc, dt<<8|0, 0, buf, sizeof buf); + if(nr < 0){ + fprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir); + return -1; + } + dd = buf; +Config: + if(nr < dl){ + fprint(2, "%s: %s: hub descriptor too small (%d < %d)\n", argv0, h->dev->dir, nr, dl); + return -1; + } + if(h->dev->isusb3) + return configusb3hub(h, dd, nr); + else + return configusb2hub(h, dd, nr); +} + static void configroothub(Hub *h) { - Dev *d; - char buf[128]; + char buf[1024]; char *p; int nr; + Dev *d; d = h->dev; h->nport = 2; @@ -143,7 +148,7 @@ configroothub(Hub *h) if(nr < 0) goto Done; buf[nr] = 0; - + d->isusb3 = strstr(buf, "speed super") != nil; p = strstr(buf, "ports "); if(p == nil) fprint(2, "%s: %s: no port information\n", argv0, d->dir); @@ -174,11 +179,13 @@ newhub(char *fn, Dev *d) fprint(2, "%s: opendev: %s: %r", argv0, fn); goto Fail; } + h->dev->depth = -1; + configroothub(h); /* never fails */ if(opendevdata(h->dev, ORDWR) < 0){ fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn); + closedev(h->dev); goto Fail; } - configroothub(h); /* never fails */ }else{ h->dev = d; if(confighub(h) < 0){ @@ -186,10 +193,6 @@ newhub(char *fn, Dev *d) goto Fail; } } - if(h->dev == nil){ - fprint(2, "%s: opendev: %s: %r\n", argv0, fn); - goto Fail; - } devctl(h->dev, "hub"); ud = h->dev->usb; if(h->isroot) @@ -265,13 +268,13 @@ closehub(Hub *h) free(h); } -static int +static u32int portstatus(Hub *h, int p) { Dev *d; uchar buf[4]; + u32int sts; int t; - int sts; int dbg; dbg = usbdebug; @@ -282,34 +285,38 @@ portstatus(Hub *h, int p) if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0) sts = -1; else - sts = GET2(buf); + sts = GET4(buf); usbdebug = dbg; return sts; } static char* -stsstr(int sts) +stsstr(int sts, int isusb3) { static char s[80]; char *e; e = s; - if(sts&PSsuspend) - *e++ = 'z'; - if(sts&PSreset) - *e++ = 'r'; - if(sts&PSslow) - *e++ = 'l'; - if(sts&PShigh) - *e++ = 'h'; - if(sts&PSchange) - *e++ = 'c'; - if(sts&PSenable) - *e++ = 'e'; - if(sts&PSstatuschg) - *e++ = 's'; if(sts&PSpresent) *e++ = 'p'; + if(sts&PSenable) + *e++ = 'e'; + if(sts&PSovercurrent) + *e++ = 'o'; + if(sts&PSreset) + *e++ = 'r'; + if(!isusb3){ + if(sts&PSslow) + *e++ = 'l'; + if(sts&PShigh) + *e++ = 'h'; + if(sts&PSchange) + *e++ = 'c'; + if(sts&PSstatuschg) + *e++ = 's'; + if(sts&PSsuspend) + *e++ = 'z'; + } if(e == s) *e++ = '-'; *e = 0; @@ -322,6 +329,8 @@ getmaxpkt(Dev *d, int islow) uchar buf[64]; /* More room to try to get device-specific descriptors */ DDev *dd; + if(d->isusb3) + return 512; dd = (DDev*)buf; if(islow) dd->bMaxPacketSize0 = 8; @@ -336,7 +345,7 @@ getmaxpkt(Dev *d, int islow) * BUG: does not consider max. power avail. */ static Dev* -portattach(Hub *h, int p, int sts) +portattach(Hub *h, int p, u32int sts) { Dev *d; Port *pp; @@ -352,31 +361,43 @@ portattach(Hub *h, int p, int sts) nd = nil; pp->state = Pattached; dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts); - sleep(Connectdelay); - if(hubfeature(h, p, Fportenable, 1) < 0) - dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); - sleep(Enabledelay); - if(hubfeature(h, p, Fportreset, 1) < 0){ - dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); - goto Fail; - } - sleep(Resetdelay); - sts = portstatus(h, p); - if(sts < 0) - goto Fail; - if((sts & PSenable) == 0){ - dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); - hubfeature(h, p, Fportenable, 1); + if(h->dev->isusb3){ + sleep(Connectdelay); sts = portstatus(h, p); - if((sts & PSenable) == 0) + if(sts == -1) + goto Fail; + if((sts & PSenable) == 0){ + dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); + goto Fail; + } + sp = "super"; + } else { + sleep(Connectdelay); + if(hubfeature(h, p, Fportenable, 1) < 0) + dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); + sleep(Enabledelay); + if(hubfeature(h, p, Fportreset, 1) < 0){ + dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); goto Fail; + } + sleep(Resetdelay); + sts = portstatus(h, p); + if(sts == -1) + goto Fail; + if((sts & PSenable) == 0){ + dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); + hubfeature(h, p, Fportenable, 1); + sts = portstatus(h, p); + if((sts & PSenable) == 0) + goto Fail; + } + sp = "full"; + if(sts & PSslow) + sp = "low"; + if(sts & PShigh) + sp = "high"; } - sp = "full"; - if(sts & PSslow) - sp = "low"; - if(sts & PShigh) - sp = "high"; - dprint(2, "%s: %s: port %d: attached status %#ux\n", argv0, d->dir, p, sts); + dprint(2, "%s: %s: port %d: attached status %#ux, speed %s\n", argv0, d->dir, p, sts, sp); if(devctl(d, "newdev %s %d", sp, p) < 0){ fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p); @@ -399,6 +420,8 @@ portattach(Hub *h, int p, int sts) fprint(2, "%s: %s: port %d: opendev: %r\n", argv0, d->dir, p); goto Fail; } + nd->depth = h->dev->depth+1; + nd->isusb3 = h->dev->isusb3; if(usbdebug > 2) devctl(nd, "debug 1"); if(opendevdata(nd, ORDWR) < 0){ @@ -413,7 +436,6 @@ portattach(Hub *h, int p, int sts) dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p); goto Fail; } - mp=getmaxpkt(nd, strcmp(sp, "low") == 0); if(mp < 0){ dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p); @@ -422,9 +444,6 @@ portattach(Hub *h, int p, int sts) dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp); devctl(nd, "maxpkt %d", mp); } - if((sts & PSslow) != 0 && strcmp(sp, "full") == 0) - dprint(2, "%s: %s: port %d: %s is full speed when port is low\n", - argv0, d->dir, p, nd->dir); if(configdev(nd) < 0){ dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p); goto Fail; @@ -438,17 +457,16 @@ portattach(Hub *h, int p, int sts) if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0) goto Fail; } - dprint(2, "%s: %U", argv0, nd); pp->state = Pconfiged; - dprint(2, "%s: %s: port %d: configed: %s\n", - argv0, d->dir, p, nd->dir); + dprint(2, "%s: %s: port %d: configured: %s\n", argv0, d->dir, p, nd->dir); return pp->dev = nd; Fail: pp->state = Pdisabled; pp->sts = 0; if(pp->hub != nil) pp->hub = nil; /* hub closed by enumhub */ - hubfeature(h, p, Fportenable, 0); + if(!h->dev->isusb3) + hubfeature(h, p, Fportenable, 0); if(nd != nil) devctl(nd, "detach"); closedev(nd); @@ -477,10 +495,9 @@ portdetach(Hub *h, int p) closehub(pp->hub); pp->hub = nil; } - if(pp->devmaskp != nil) - putdevnb(pp->devmaskp, pp->devnb); - pp->devmaskp = nil; if(pp->dev != nil){ + detachdev(pp); + devctl(pp->dev, "detach"); closedev(pp->dev); pp->dev = nil; @@ -523,7 +540,7 @@ portresetwanted(Hub *h, int p) static void portreset(Hub *h, int p) { - int sts; + u32int sts; Dev *d, *nd; Port *pp; @@ -537,10 +554,12 @@ portreset(Hub *h, int p) } sleep(Resetdelay); sts = portstatus(h, p); - if(sts < 0) + if(sts == -1) goto Fail; if((sts & PSenable) == 0){ dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); + if(h->dev->isusb3) + goto Fail; hubfeature(h, p, Fportenable, 1); sts = portstatus(h, p); if((sts & PSenable) == 0) @@ -562,24 +581,27 @@ portreset(Hub *h, int p) if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0) goto Fail; } - if(nd->dfd >= 0) + if(nd->dfd >= 0){ close(nd->dfd); + nd->dfd = -1; + } return; Fail: pp->state = Pdisabled; pp->sts = 0; if(pp->hub != nil) pp->hub = nil; /* hub closed by enumhub */ - hubfeature(h, p, Fportenable, 0); + if(!h->dev->isusb3) + hubfeature(h, p, Fportenable, 0); if(nd != nil) devctl(nd, "detach"); closedev(nd); } static int -portgone(Port *pp, int sts) +portgone(Port *pp, u32int sts) { - if(sts < 0) + if(sts == -1) return 1; /* * If it was enabled and it's not now then it may be reconnect. @@ -593,7 +615,7 @@ portgone(Port *pp, int sts) static int enumhub(Hub *h, int p) { - int sts; + u32int sts; Dev *d; Port *pp; int onhubs; @@ -605,31 +627,33 @@ enumhub(Hub *h, int p) fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p); sts = portstatus(h, p); - if(sts < 0){ + if(sts == -1){ hubfail(h); /* avoid delays on detachment */ return -1; } pp = &h->port[p]; onhubs = nhubs; - if((sts & PSsuspend) != 0){ - if(hubfeature(h, p, Fportenable, 1) < 0) - dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); - sleep(Enabledelay); - sts = portstatus(h, p); - fprint(2, "%s: %s: port %d: resumed (sts %#ux)\n", argv0, d->dir, p, sts); + if(!h->dev->isusb3){ + if((sts & PSsuspend) != 0){ + if(hubfeature(h, p, Fportenable, 1) < 0) + dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); + sleep(Enabledelay); + sts = portstatus(h, p); + fprint(2, "%s: %s: port %d: resumed (sts %#ux)\n", argv0, d->dir, p, sts); + } } if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){ if(portattach(h, p, sts) != nil) - if(startdev(pp) < 0) + if(attachdev(pp) < 0) portdetach(h, p); - }else if(portgone(pp, sts)) + }else if(portgone(pp, sts)){ portdetach(h, p); - else if(portresetwanted(h, p)) + }else if(portresetwanted(h, p)) portreset(h, p); else if(pp->sts != sts){ - dprint(2, "%s: %s port %d: sts %s %#x ->", - argv0, d->dir, p, stsstr(pp->sts), pp->sts); - dprint(2, " %s %#x\n",stsstr(sts), sts); + dprint(2, "%s: %s port %d: sts %s %#ux ->", + argv0, d->dir, p, stsstr(pp->sts, h->dev->isusb3), pp->sts); + dprint(2, " %s %#ux\n",stsstr(sts, h->dev->isusb3), sts); } pp->sts = sts; if(onhubs != nhubs) @@ -646,7 +670,7 @@ dump(void) mustdump = 0; for(h = hubs; h != nil; h = h->next) for(i = 1; i <= h->nport; i++) - fprint(2, "%s: hub %#p %s port %d: %U", + fprint(2, "%s: hub %#p %s port %d: %U\n", argv0, h, h->dev->dir, i, h->port[i].dev); } @@ -666,6 +690,10 @@ work(void) fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn); free(fn); } + + if(hubs == nil) + return; + /* * Enumerate (and acknowledge after first enumeration). * Do NOT perform enumeration concurrently for the same @@ -686,6 +714,7 @@ Again: goto Again; } qunlock(&hublock); + checkidle(); sleep(pollms); if(mustdump) dump();