12 static int pollms = Pollms;
15 static char *dsname[] = { "disabled", "attached", "configed" };
18 getdevnb(uvlong *maskp)
23 for(i = 0; i < 8 * sizeof *maskp; i++)
24 if((*maskp & (1ULL<<i)) == 0){
34 putdevnb(uvlong *maskp, int id)
38 *maskp &= ~(1ULL<<id);
43 hubfeature(Hub *h, int port, int f, int on)
51 return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0);
55 * This may be used to detect overcurrent on the hub
58 checkhubstatus(Hub *h)
63 if(h->isroot) /* not for root hubs */
65 if(usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetstatus, 0, 0, buf, 4) < 0){
66 dprint(2, "%s: get hub status: %r\n", h->dev->dir);
70 dprint(2, "hub %s: status %#ux\n", h->dev->dir, sts);
77 uchar buf[128]; /* room for extra descriptors */
84 uchar *PortPwrCtrlMask;
89 for(i = 0; i < nelem(d->ddesc); i++)
90 if(d->ddesc[i] == nil)
92 else if(d->ddesc[i]->data.bDescriptorType == Dhub){
93 dd = (DHub*)&d->ddesc[i]->data;
97 type = Rd2h|Rclass|Rdev;
98 nr = usbcmd(h->dev, type, Rgetdesc, Dhub<<8|0, 0, buf, sizeof buf);
100 dprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir);
105 h->nport = dd->bNbrPorts;
106 nmap = 1 + h->nport/8;
108 fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir);
111 h->port = emallocz((h->nport+1)*sizeof(Port), 1);
112 h->pwrms = dd->bPwrOn2PwrGood*2;
113 if(h->pwrms < Powerdelay)
114 h->pwrms = Powerdelay;
115 h->maxcurrent = dd->bHubContrCurrent;
116 h->pwrmode = dd->wHubCharacteristics[0] & 3;
117 h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0;
118 h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0;
119 PortPwrCtrlMask = dd->DeviceRemovable + nmap;
120 for(i = 1; i <= h->nport; i++){
124 pp->removable = (dd->DeviceRemovable[offset] & mask) != 0;
125 pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0;
131 configroothub(Hub *h)
142 nr = read(d->cfd, buf, sizeof(buf)-1);
147 p = strstr(buf, "ports ");
149 fprint(2, "%s: %s: no port information\n", argv0, d->dir);
151 h->nport = atoi(p+6);
152 p = strstr(buf, "maxpkt ");
154 fprint(2, "%s: %s: no maxpkt information\n", argv0, d->dir);
156 h->maxpkt = atoi(p+7);
158 h->port = emallocz((h->nport+1)*sizeof(Port), 1);
159 dprint(2, "%s: %s: ports %d maxpkt %d\n", argv0, d->dir, h->nport, h->maxpkt);
163 newhub(char *fn, Dev *d)
169 h = emallocz(sizeof(Hub), 1);
170 h->isroot = (d == nil);
172 h->dev = opendev(fn);
174 fprint(2, "%s: opendev: %s: %r", argv0, fn);
177 if(opendevdata(h->dev, ORDWR) < 0){
178 fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn);
181 configroothub(h); /* never fails */
184 if(confighub(h) < 0){
185 fprint(2, "%s: %s: config: %r\n", argv0, fn);
190 fprint(2, "%s: opendev: %s: %r\n", argv0, fn);
193 devctl(h->dev, "hub");
196 devctl(h->dev, "info roothub csp %#08ux ports %d",
199 devctl(h->dev, "info hub csp %#08ulx ports %d %q %q",
200 ud->csp, h->nport, ud->vendor, ud->product);
201 for(i = 1; i <= h->nport; i++)
202 if(hubfeature(h, i, Fportpower, 1) < 0)
203 fprint(2, "%s: %s: power: %r\n", argv0, fn);
205 for(i = 1; i <= h->nport; i++)
207 hubfeature(h, i, Fportindicator, 1);
212 dprint(2, "%s: hub %#p allocated:", argv0, h);
213 dprint(2, " ports %d pwrms %d max curr %d pwrm %d cmp %d leds %d\n",
214 h->nport, h->pwrms, h->maxcurrent,
215 h->pwrmode, h->compound, h->leds);
223 dprint(2, "%s: hub %#p failed to start:", argv0, h);
227 static void portdetach(Hub *h, int p);
230 * If during enumeration we get an I/O error the hub is gone or
231 * in pretty bad shape. Because of retries of failed usb commands
232 * (and the sleeps they include) it can take a while to detach all
233 * ports for the hub. This detaches all ports and makes the hub void.
234 * The parent hub will detect a detach (probably right now) and
242 for(i = 1; i <= h->nport; i++)
252 dprint(2, "%s: closing hub %#p\n", argv0, h);
253 for(hl = &hubs; *hl != nil; hl = &(*hl)->next)
257 sysfatal("closehub: no hub");
260 hubfail(h); /* detach all ports */
262 assert(h->dev != nil);
263 devctl(h->dev, "detach");
269 portstatus(Hub *h, int p)
278 if(dbg != 0 && dbg < 4)
279 usbdebug = 1; /* do not be too chatty */
281 t = Rd2h|Rclass|Rother;
282 if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0)
320 getmaxpkt(Dev *d, int islow)
322 uchar buf[64]; /* More room to try to get device-specific descriptors */
327 dd->bMaxPacketSize0 = 8;
329 dd->bMaxPacketSize0 = 64;
330 if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) < 0)
332 return dd->bMaxPacketSize0;
336 * BUG: does not consider max. power avail.
339 portattach(Hub *h, int p, int sts)
353 pp->state = Pattached;
354 dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts);
356 if(hubfeature(h, p, Fportenable, 1) < 0)
357 dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
359 if(hubfeature(h, p, Fportreset, 1) < 0){
360 dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
364 sts = portstatus(h, p);
367 if((sts & PSenable) == 0){
368 dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
369 hubfeature(h, p, Fportenable, 1);
370 sts = portstatus(h, p);
371 if((sts & PSenable) == 0)
379 dprint(2, "%s: %s: port %d: attached status %#ux\n", argv0, d->dir, p, sts);
381 if(devctl(d, "newdev %s %d", sp, p) < 0){
382 fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
386 nr = read(d->cfd, buf, sizeof(buf)-1);
388 fprint(2, "%s: %s: port %d: newdev: eof\n", argv0, d->dir, p);
392 fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
396 snprint(fname, sizeof(fname), "/dev/usb/%s", buf);
399 fprint(2, "%s: %s: port %d: opendev: %r\n", argv0, d->dir, p);
403 devctl(nd, "debug 1");
404 if(opendevdata(nd, ORDWR) < 0){
405 fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir);
408 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
409 dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
412 if(devctl(nd, "address") < 0){
413 dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
417 mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
419 dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
422 dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp);
423 devctl(nd, "maxpkt %d", mp);
425 if((sts & PSslow) != 0 && strcmp(sp, "full") == 0)
426 dprint(2, "%s: %s: port %d: %s is full speed when port is low\n",
427 argv0, d->dir, p, nd->dir);
428 if(configdev(nd) < 0){
429 dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p);
433 * We always set conf #1. BUG.
435 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
436 dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
437 unstall(nd, nd, Eout);
438 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
441 dprint(2, "%s: %U", argv0, nd);
442 pp->state = Pconfiged;
443 dprint(2, "%s: %s: port %d: configed: %s\n",
444 argv0, d->dir, p, nd->dir);
447 pp->state = Pdisabled;
450 pp->hub = nil; /* hub closed by enumhub */
451 hubfeature(h, p, Fportenable, 0);
453 devctl(nd, "detach");
459 portdetach(Hub *h, int p)
467 * Clear present, so that we detect an attach on reconnects.
469 pp->sts &= ~(PSpresent|PSenable);
471 if(pp->state == Pdisabled)
473 pp->state = Pdisabled;
474 dprint(2, "%s: %s: port %d: detached\n", argv0, d->dir, p);
480 if(pp->devmaskp != nil)
481 putdevnb(pp->devmaskp, pp->devnb);
484 devctl(pp->dev, "detach");
491 * The next two functions are included to
492 * perform a port reset asked for by someone (usually a driver).
493 * This must be done while no other device is in using the
494 * configuration address and with care to keep the old address.
495 * To keep drivers decoupled from usbd they write the reset request
496 * to the #u/usb/epN.0/ctl file and then exit.
497 * This is unfortunate because usbd must now poll twice as much.
499 * An alternative to this reset process would be for the driver to detach
500 * the device. The next function could see that, issue a port reset, and
501 * then restart the driver once to see if it's a temporary error.
503 * The real fix would be to use interrupt endpoints for non-root hubs
504 * (would probably make some hubs fail) and add an events file to
505 * the kernel to report events to usbd. This is a severe change not
509 portresetwanted(Hub *h, int p)
517 if(nd != nil && nd->cfd >= 0 && pread(nd->cfd, buf, 5, 0LL) == 5)
518 return strncmp(buf, "reset", 5) == 0;
524 portreset(Hub *h, int p)
533 dprint(2, "%s: %s: port %d: resetting\n", argv0, d->dir, p);
534 if(hubfeature(h, p, Fportreset, 1) < 0){
535 dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
539 sts = portstatus(h, p);
542 if((sts & PSenable) == 0){
543 dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
544 hubfeature(h, p, Fportenable, 1);
545 sts = portstatus(h, p);
546 if((sts & PSenable) == 0)
550 opendevdata(nd, ORDWR);
551 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
552 dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
555 if(devctl(nd, "address") < 0){
556 dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
559 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
560 dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
561 unstall(nd, nd, Eout);
562 if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
569 pp->state = Pdisabled;
572 pp->hub = nil; /* hub closed by enumhub */
573 hubfeature(h, p, Fportenable, 0);
575 devctl(nd, "detach");
580 portgone(Port *pp, int sts)
585 * If it was enabled and it's not now then it may be reconnect.
586 * We pretend it's gone and later we'll see it as attached.
588 if((pp->sts & PSenable) != 0 && (sts & PSenable) == 0)
590 return (pp->sts & PSpresent) != 0 && (sts & PSpresent) == 0;
594 enumhub(Hub *h, int p)
605 fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p);
607 sts = portstatus(h, p);
609 hubfail(h); /* avoid delays on detachment */
614 if((sts & PSsuspend) != 0){
615 if(hubfeature(h, p, Fportenable, 1) < 0)
616 dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
618 sts = portstatus(h, p);
619 fprint(2, "%s: %s: port %d: resumed (sts %#ux)\n", argv0, d->dir, p, sts);
621 if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){
622 if(portattach(h, p, sts) != nil)
625 }else if(portgone(pp, sts)){
628 }else if(portresetwanted(h, p))
630 else if(pp->sts != sts){
631 dprint(2, "%s: %s port %d: sts %s %#x ->",
632 argv0, d->dir, p, stsstr(pp->sts), pp->sts);
633 dprint(2, " %s %#x\n",stsstr(sts), sts);
648 for(h = hubs; h != nil; h = h->next)
649 for(i = 1; i <= h->nport; i++)
650 fprint(2, "%s: hub %#p %s port %d: %U",
651 argv0, h, h->dev->dir, i, h->port[i].dev);
663 while((fn = rendezvous(work, nil)) != nil){
664 dprint(2, "%s: %s starting\n", argv0, fn);
667 fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn);
671 * Enumerate (and acknowledge after first enumeration).
672 * Do NOT perform enumeration concurrently for the same
673 * controller. new devices attached respond to a default
674 * address (0) after reset, thus enumeration has to work
675 * one device at a time at least before addresses have been
677 * Do not use hub interrupt endpoint because we
678 * have to poll the root hub(s) in any case.
683 for(h = hubs; h != nil; h = h->next)
684 for(i = 1; i <= h->nport; i++)
685 if(enumhub(h, i) < 0){
686 /* changes in hub list; repeat */