diff --git a/sys/src/cmd/nusb/usbd/dat.h b/sys/src/cmd/nusb/usbd/dat.h index dc66eb1f0..28205f931 100644 --- a/sys/src/cmd/nusb/usbd/dat.h +++ b/sys/src/cmd/nusb/usbd/dat.h @@ -1,13 +1,17 @@ typedef struct Hub Hub; typedef struct DHub DHub; +typedef struct DSSHub DSSHub; typedef struct Port Port; enum { Stack = 32*1024, - Dhub = 0x29, /* hub descriptor type */ - Dhublen = 9, /* hub descriptor length */ + Dhub = 0x29, /* hub descriptor type */ + Dhublen = 9, /* hub descriptor length */ + + Dsshub = 0x2A, /* superspeed hub descriptor type */ + Dsshublen = 12, /* superspeed hub descriptor length */ /* hub class feature selectors */ Fhublocalpower = 0, @@ -106,3 +110,17 @@ struct DHub uchar bHubContrCurrent; uchar DeviceRemovable[1]; /* variable length */ }; + +/* Superspeed HUB descriptor */ +struct DSSHub +{ + uchar bLength; + uchar bDescriptorType; + uchar bNbrPorts; + uchar wHubCharacteristics[2]; + uchar bPwrOn2PwrGood; + uchar bHubContrCurrent; + uchar bHubHdrDecLat; + uchar wHubDelay[2]; + uchar DeviceRemovable[1]; /* variable length */ +}; diff --git a/sys/src/cmd/nusb/usbd/hub.c b/sys/src/cmd/nusb/usbd/hub.c index 9675890ce..3802e48d1 100644 --- a/sys/src/cmd/nusb/usbd/hub.c +++ b/sys/src/cmd/nusb/usbd/hub.c @@ -26,37 +26,12 @@ hubfeature(Hub *h, int port, int f, int on) } static int -confighub(Hub *h) +configusb2hub(Hub *h, DHub *dd, int nr) { - int type; - uchar buf[128]; /* room for extra descriptors */ - int i; - Usbdev *d; - DHub *dd; - Port *pp; - int nr; - int nmap; uchar *PortPwrCtrlMask; - int offset; - int mask; + int i, offset, mask, nmap; + Port *pp; - 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){ @@ -79,13 +54,79 @@ Config: pp->removable = (dd->DeviceRemovable[offset] & mask) != 0; pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0; } - if(h->dev->isusb3){ - type = Rh2d|Rclass|Rdev; - usbcmd(h->dev, type, Rsethubdepth, h->depth, 0, nil, 0); + return 0; +} + +static int +configusb3hub(Hub *h, DSSHub *dd, int nr) +{ + int i, offset, mask, nmap; + Port *pp; + + h->nport = dd->bNbrPorts; + nmap = 1 + h->nport/8; + if(nr < 10 + 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; + 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; + } + if(usbcmd(h->dev, Rh2d|Rclass|Rdev, Rsethubdepth, h->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; + else if(d->ddesc[i]->data.bDescriptorType == dt){ + dd = &d->ddesc[i]->data; + nr = dl; + goto Config; + } + nr = usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetdesc, dt<<8|0, 0, buf, sizeof buf); + if(nr < dl){ + fprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir); + return -1; + } + dd = buf; +Config: + if(h->dev->isusb3) + return configusb3hub(h, dd, nr); + else + return configusb2hub(h, dd, nr); +} + static void configroothub(Hub *h) {