nusb/usbd: create endpoint files for conf #1, usb3 preparation
This commit is contained in:
parent
d46099e3af
commit
215b67ff3d
6 changed files with 128 additions and 133 deletions
|
@ -27,7 +27,12 @@ parsedev(Dev *xd, uchar *b, int n)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol);
|
d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol);
|
||||||
d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0;
|
d->ver = GET2(dd->bcdUSB);
|
||||||
|
xd->isusb3 = (d->ver >= 0x0300);
|
||||||
|
if(xd->isusb3)
|
||||||
|
d->ep[0]->maxpkt = xd->maxpkt = 1<<dd->bMaxPacketSize0;
|
||||||
|
else
|
||||||
|
d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0;
|
||||||
d->class = dd->bDevClass;
|
d->class = dd->bDevClass;
|
||||||
d->nconf = dd->bNumConfigurations;
|
d->nconf = dd->bNumConfigurations;
|
||||||
if(d->nconf == 0)
|
if(d->nconf == 0)
|
||||||
|
|
|
@ -36,7 +36,7 @@ enum {
|
||||||
Rep = 2, /* endpoint */
|
Rep = 2, /* endpoint */
|
||||||
Rother = 3,
|
Rother = 3,
|
||||||
|
|
||||||
/* standard requests */
|
/* standard requests (USB2.0) */
|
||||||
Rgetstatus = 0,
|
Rgetstatus = 0,
|
||||||
Rclearfeature = 1,
|
Rclearfeature = 1,
|
||||||
Rsetfeature = 3,
|
Rsetfeature = 3,
|
||||||
|
@ -49,6 +49,10 @@ enum {
|
||||||
Rsetiface = 11,
|
Rsetiface = 11,
|
||||||
Rsynchframe = 12,
|
Rsynchframe = 12,
|
||||||
|
|
||||||
|
/* standard requests (USB3.0) */
|
||||||
|
Rsethubdepth = 12,
|
||||||
|
Rgetporterrcnt = 13,
|
||||||
|
|
||||||
Rgetcur = 0x81,
|
Rgetcur = 0x81,
|
||||||
Rgetmin = 0x82,
|
Rgetmin = 0x82,
|
||||||
Rgetmax = 0x83,
|
Rgetmax = 0x83,
|
||||||
|
@ -169,6 +173,7 @@ struct Dev
|
||||||
int id; /* usb id for device or ep. number */
|
int id; /* usb id for device or ep. number */
|
||||||
int dfd; /* descriptor for the data file */
|
int dfd; /* descriptor for the data file */
|
||||||
int cfd; /* descriptor for the control file */
|
int cfd; /* descriptor for the control file */
|
||||||
|
int isusb3; /* this is a usb3 device */
|
||||||
int maxpkt; /* cached from usb description */
|
int maxpkt; /* cached from usb description */
|
||||||
Ref nerrs; /* number of errors in requests */
|
Ref nerrs; /* number of errors in requests */
|
||||||
Usbdev* usb; /* USB description */
|
Usbdev* usb; /* USB description */
|
||||||
|
@ -182,6 +187,7 @@ struct Dev
|
||||||
*/
|
*/
|
||||||
struct Usbdev
|
struct Usbdev
|
||||||
{
|
{
|
||||||
|
int ver; /* usb version */
|
||||||
ulong csp; /* USB class/subclass/proto */
|
ulong csp; /* USB class/subclass/proto */
|
||||||
int vid; /* vendor id */
|
int vid; /* vendor id */
|
||||||
int did; /* product (device) id */
|
int did; /* product (device) id */
|
||||||
|
|
|
@ -50,9 +50,7 @@ enum
|
||||||
Pconfiged,
|
Pconfiged,
|
||||||
|
|
||||||
/* Delays, timeouts (ms) */
|
/* Delays, timeouts (ms) */
|
||||||
// Spawndelay = 1000, /* how often may we re-spawn a driver */
|
|
||||||
Spawndelay = 250, /* how often may we re-spawn a driver */
|
Spawndelay = 250, /* how often may we re-spawn a driver */
|
||||||
// Connectdelay = 1000, /* how much to wait after a connect */
|
|
||||||
Connectdelay = 500, /* how much to wait after a connect */
|
Connectdelay = 500, /* how much to wait after a connect */
|
||||||
Resetdelay = 20, /* how much to wait after a reset */
|
Resetdelay = 20, /* how much to wait after a reset */
|
||||||
Enabledelay = 20, /* how much to wait after an enable */
|
Enabledelay = 20, /* how much to wait after an enable */
|
||||||
|
@ -82,6 +80,7 @@ struct Hub
|
||||||
Port *port;
|
Port *port;
|
||||||
int failed; /* I/O error while enumerating */
|
int failed; /* I/O error while enumerating */
|
||||||
int isroot; /* set if root hub */
|
int isroot; /* set if root hub */
|
||||||
|
int depth; /* hub depth */
|
||||||
Dev *dev; /* for this hub */
|
Dev *dev; /* for this hub */
|
||||||
Hub *next; /* in list of hubs */
|
Hub *next; /* in list of hubs */
|
||||||
};
|
};
|
||||||
|
@ -89,13 +88,11 @@ struct Hub
|
||||||
struct Port
|
struct Port
|
||||||
{
|
{
|
||||||
int state; /* state of the device */
|
int state; /* state of the device */
|
||||||
int sts; /* old port status */
|
u32int sts; /* old port status */
|
||||||
uchar removable;
|
uchar removable;
|
||||||
uchar pwrctl;
|
uchar pwrctl;
|
||||||
Dev *dev; /* attached device (if non-nil) */
|
Dev *dev; /* attached device (if non-nil) */
|
||||||
Hub *hub; /* non-nil if hub attached */
|
Hub *hub; /* non-nil if hub attached */
|
||||||
int devnb; /* device number */
|
|
||||||
uvlong *devmaskp; /* ptr to dev mask */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* USB HUB descriptor */
|
/* USB HUB descriptor */
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
int attachdev(Port*);
|
int attachdev(Hub*, Port*);
|
||||||
void detachdev(Port*);
|
void detachdev(Hub*, Port*);
|
||||||
void work(void);
|
void work(void);
|
||||||
Hub* newhub(char *, Dev *);
|
Hub* newhub(char *, Dev*, Hub*);
|
||||||
void hname(char *);
|
void hname(char *);
|
||||||
void checkidle(void);
|
void checkidle(void);
|
||||||
|
|
|
@ -10,35 +10,9 @@ QLock hublock;
|
||||||
static int nhubs;
|
static int nhubs;
|
||||||
static int mustdump;
|
static int mustdump;
|
||||||
static int pollms = Pollms;
|
static int pollms = Pollms;
|
||||||
static Lock masklck;
|
|
||||||
|
|
||||||
static char *dsname[] = { "disabled", "attached", "configed" };
|
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<<i)) == 0){
|
|
||||||
*maskp |= 1ULL<<i;
|
|
||||||
unlock(&masklck);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
unlock(&masklck);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
putdevnb(uvlong *maskp, int id)
|
|
||||||
{
|
|
||||||
lock(&masklck);
|
|
||||||
if(id >= 0)
|
|
||||||
*maskp &= ~(1ULL<<id);
|
|
||||||
unlock(&masklck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hubfeature(Hub *h, int port, int f, int on)
|
hubfeature(Hub *h, int port, int f, int on)
|
||||||
{
|
{
|
||||||
|
@ -51,25 +25,6 @@ hubfeature(Hub *h, int port, int f, int on)
|
||||||
return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0);
|
return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This may be used to detect overcurrent on the hub
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
checkhubstatus(Hub *h)
|
|
||||||
{
|
|
||||||
uchar buf[4];
|
|
||||||
int sts;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
sts = GET2(buf);
|
|
||||||
dprint(2, "hub %s: status %#ux\n", h->dev->dir, sts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
confighub(Hub *h)
|
confighub(Hub *h)
|
||||||
{
|
{
|
||||||
|
@ -124,6 +79,10 @@ Config:
|
||||||
pp->removable = (dd->DeviceRemovable[offset] & mask) != 0;
|
pp->removable = (dd->DeviceRemovable[offset] & mask) != 0;
|
||||||
pp->pwrctl = (PortPwrCtrlMask[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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +102,7 @@ configroothub(Hub *h)
|
||||||
if(nr < 0)
|
if(nr < 0)
|
||||||
goto Done;
|
goto Done;
|
||||||
buf[nr] = 0;
|
buf[nr] = 0;
|
||||||
|
d->isusb3 = strstr(buf, "speed super") != nil;
|
||||||
p = strstr(buf, "ports ");
|
p = strstr(buf, "ports ");
|
||||||
if(p == nil)
|
if(p == nil)
|
||||||
fprint(2, "%s: %s: no port information\n", argv0, d->dir);
|
fprint(2, "%s: %s: no port information\n", argv0, d->dir);
|
||||||
|
@ -160,7 +119,7 @@ Done:
|
||||||
}
|
}
|
||||||
|
|
||||||
Hub*
|
Hub*
|
||||||
newhub(char *fn, Dev *d)
|
newhub(char *fn, Dev *d, Hub *ph)
|
||||||
{
|
{
|
||||||
Hub *h;
|
Hub *h;
|
||||||
int i;
|
int i;
|
||||||
|
@ -169,27 +128,26 @@ newhub(char *fn, Dev *d)
|
||||||
h = emallocz(sizeof(Hub), 1);
|
h = emallocz(sizeof(Hub), 1);
|
||||||
h->isroot = (d == nil);
|
h->isroot = (d == nil);
|
||||||
if(h->isroot){
|
if(h->isroot){
|
||||||
|
h->depth = -1;
|
||||||
h->dev = opendev(fn);
|
h->dev = opendev(fn);
|
||||||
if(h->dev == nil){
|
if(h->dev == nil){
|
||||||
fprint(2, "%s: opendev: %s: %r", argv0, fn);
|
fprint(2, "%s: opendev: %s: %r", argv0, fn);
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
|
configroothub(h); /* never fails */
|
||||||
if(opendevdata(h->dev, ORDWR) < 0){
|
if(opendevdata(h->dev, ORDWR) < 0){
|
||||||
fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn);
|
fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn);
|
||||||
|
closedev(h->dev);
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
configroothub(h); /* never fails */
|
|
||||||
}else{
|
}else{
|
||||||
|
h->depth = ph->depth+1;
|
||||||
h->dev = d;
|
h->dev = d;
|
||||||
if(confighub(h) < 0){
|
if(confighub(h) < 0){
|
||||||
fprint(2, "%s: %s: config: %r\n", argv0, fn);
|
fprint(2, "%s: %s: config: %r\n", argv0, fn);
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(h->dev == nil){
|
|
||||||
fprint(2, "%s: opendev: %s: %r\n", argv0, fn);
|
|
||||||
goto Fail;
|
|
||||||
}
|
|
||||||
devctl(h->dev, "hub");
|
devctl(h->dev, "hub");
|
||||||
ud = h->dev->usb;
|
ud = h->dev->usb;
|
||||||
if(h->isroot)
|
if(h->isroot)
|
||||||
|
@ -265,13 +223,13 @@ closehub(Hub *h)
|
||||||
free(h);
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static u32int
|
||||||
portstatus(Hub *h, int p)
|
portstatus(Hub *h, int p)
|
||||||
{
|
{
|
||||||
Dev *d;
|
Dev *d;
|
||||||
uchar buf[4];
|
uchar buf[4];
|
||||||
|
u32int sts;
|
||||||
int t;
|
int t;
|
||||||
int sts;
|
|
||||||
int dbg;
|
int dbg;
|
||||||
|
|
||||||
dbg = usbdebug;
|
dbg = usbdebug;
|
||||||
|
@ -282,34 +240,38 @@ portstatus(Hub *h, int p)
|
||||||
if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0)
|
if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0)
|
||||||
sts = -1;
|
sts = -1;
|
||||||
else
|
else
|
||||||
sts = GET2(buf);
|
sts = GET4(buf);
|
||||||
usbdebug = dbg;
|
usbdebug = dbg;
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
stsstr(int sts)
|
stsstr(int sts, int isusb3)
|
||||||
{
|
{
|
||||||
static char s[80];
|
static char s[80];
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
e = s;
|
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)
|
if(sts&PSpresent)
|
||||||
*e++ = 'p';
|
*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)
|
if(e == s)
|
||||||
*e++ = '-';
|
*e++ = '-';
|
||||||
*e = 0;
|
*e = 0;
|
||||||
|
@ -322,6 +284,8 @@ getmaxpkt(Dev *d, int islow)
|
||||||
uchar buf[64]; /* More room to try to get device-specific descriptors */
|
uchar buf[64]; /* More room to try to get device-specific descriptors */
|
||||||
DDev *dd;
|
DDev *dd;
|
||||||
|
|
||||||
|
if(d->isusb3)
|
||||||
|
return 512;
|
||||||
dd = (DDev*)buf;
|
dd = (DDev*)buf;
|
||||||
if(islow)
|
if(islow)
|
||||||
dd->bMaxPacketSize0 = 8;
|
dd->bMaxPacketSize0 = 8;
|
||||||
|
@ -336,7 +300,7 @@ getmaxpkt(Dev *d, int islow)
|
||||||
* BUG: does not consider max. power avail.
|
* BUG: does not consider max. power avail.
|
||||||
*/
|
*/
|
||||||
static Dev*
|
static Dev*
|
||||||
portattach(Hub *h, int p, int sts)
|
portattach(Hub *h, int p, u32int sts)
|
||||||
{
|
{
|
||||||
Dev *d;
|
Dev *d;
|
||||||
Port *pp;
|
Port *pp;
|
||||||
|
@ -352,31 +316,43 @@ portattach(Hub *h, int p, int sts)
|
||||||
nd = nil;
|
nd = nil;
|
||||||
pp->state = Pattached;
|
pp->state = Pattached;
|
||||||
dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts);
|
dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts);
|
||||||
sleep(Connectdelay);
|
if(h->dev->isusb3){
|
||||||
if(hubfeature(h, p, Fportenable, 1) < 0)
|
sleep(Connectdelay);
|
||||||
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);
|
|
||||||
sts = portstatus(h, p);
|
sts = portstatus(h, p);
|
||||||
if((sts & PSenable) == 0)
|
if(sts == -1)
|
||||||
goto Fail;
|
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";
|
dprint(2, "%s: %s: port %d: attached status %#ux, speed %s\n", argv0, d->dir, p, sts, sp);
|
||||||
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);
|
|
||||||
|
|
||||||
if(devctl(d, "newdev %s %d", sp, p) < 0){
|
if(devctl(d, "newdev %s %d", sp, p) < 0){
|
||||||
fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
|
fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
|
||||||
|
@ -413,7 +389,7 @@ portattach(Hub *h, int p, int sts)
|
||||||
dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
|
dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
|
nd->isusb3 = h->dev->isusb3;
|
||||||
mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
|
mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
|
||||||
if(mp < 0){
|
if(mp < 0){
|
||||||
dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
|
dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
|
||||||
|
@ -422,9 +398,6 @@ portattach(Hub *h, int p, int sts)
|
||||||
dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp);
|
dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp);
|
||||||
devctl(nd, "maxpkt %d", 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){
|
if(configdev(nd) < 0){
|
||||||
dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p);
|
dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p);
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
@ -446,7 +419,8 @@ Fail:
|
||||||
pp->sts = 0;
|
pp->sts = 0;
|
||||||
if(pp->hub != nil)
|
if(pp->hub != nil)
|
||||||
pp->hub = nil; /* hub closed by enumhub */
|
pp->hub = nil; /* hub closed by enumhub */
|
||||||
hubfeature(h, p, Fportenable, 0);
|
if(!h->dev->isusb3)
|
||||||
|
hubfeature(h, p, Fportenable, 0);
|
||||||
if(nd != nil)
|
if(nd != nil)
|
||||||
devctl(nd, "detach");
|
devctl(nd, "detach");
|
||||||
closedev(nd);
|
closedev(nd);
|
||||||
|
@ -475,11 +449,8 @@ portdetach(Hub *h, int p)
|
||||||
closehub(pp->hub);
|
closehub(pp->hub);
|
||||||
pp->hub = nil;
|
pp->hub = nil;
|
||||||
}
|
}
|
||||||
if(pp->devmaskp != nil)
|
|
||||||
putdevnb(pp->devmaskp, pp->devnb);
|
|
||||||
pp->devmaskp = nil;
|
|
||||||
if(pp->dev != nil){
|
if(pp->dev != nil){
|
||||||
detachdev(pp);
|
detachdev(h, pp);
|
||||||
|
|
||||||
devctl(pp->dev, "detach");
|
devctl(pp->dev, "detach");
|
||||||
closedev(pp->dev);
|
closedev(pp->dev);
|
||||||
|
@ -523,7 +494,7 @@ portresetwanted(Hub *h, int p)
|
||||||
static void
|
static void
|
||||||
portreset(Hub *h, int p)
|
portreset(Hub *h, int p)
|
||||||
{
|
{
|
||||||
int sts;
|
u32int sts;
|
||||||
Dev *d, *nd;
|
Dev *d, *nd;
|
||||||
Port *pp;
|
Port *pp;
|
||||||
|
|
||||||
|
@ -537,10 +508,12 @@ portreset(Hub *h, int p)
|
||||||
}
|
}
|
||||||
sleep(Resetdelay);
|
sleep(Resetdelay);
|
||||||
sts = portstatus(h, p);
|
sts = portstatus(h, p);
|
||||||
if(sts < 0)
|
if(sts == -1)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
if((sts & PSenable) == 0){
|
if((sts & PSenable) == 0){
|
||||||
dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
|
dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
|
||||||
|
if(h->dev->isusb3)
|
||||||
|
goto Fail;
|
||||||
hubfeature(h, p, Fportenable, 1);
|
hubfeature(h, p, Fportenable, 1);
|
||||||
sts = portstatus(h, p);
|
sts = portstatus(h, p);
|
||||||
if((sts & PSenable) == 0)
|
if((sts & PSenable) == 0)
|
||||||
|
@ -572,16 +545,17 @@ Fail:
|
||||||
pp->sts = 0;
|
pp->sts = 0;
|
||||||
if(pp->hub != nil)
|
if(pp->hub != nil)
|
||||||
pp->hub = nil; /* hub closed by enumhub */
|
pp->hub = nil; /* hub closed by enumhub */
|
||||||
hubfeature(h, p, Fportenable, 0);
|
if(!h->dev->isusb3)
|
||||||
|
hubfeature(h, p, Fportenable, 0);
|
||||||
if(nd != nil)
|
if(nd != nil)
|
||||||
devctl(nd, "detach");
|
devctl(nd, "detach");
|
||||||
closedev(nd);
|
closedev(nd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
portgone(Port *pp, int sts)
|
portgone(Port *pp, u32int sts)
|
||||||
{
|
{
|
||||||
if(sts < 0)
|
if(sts == -1)
|
||||||
return 1;
|
return 1;
|
||||||
/*
|
/*
|
||||||
* If it was enabled and it's not now then it may be reconnect.
|
* If it was enabled and it's not now then it may be reconnect.
|
||||||
|
@ -595,7 +569,7 @@ portgone(Port *pp, int sts)
|
||||||
static int
|
static int
|
||||||
enumhub(Hub *h, int p)
|
enumhub(Hub *h, int p)
|
||||||
{
|
{
|
||||||
int sts;
|
u32int sts;
|
||||||
Dev *d;
|
Dev *d;
|
||||||
Port *pp;
|
Port *pp;
|
||||||
int onhubs;
|
int onhubs;
|
||||||
|
@ -607,31 +581,33 @@ enumhub(Hub *h, int p)
|
||||||
fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p);
|
fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p);
|
||||||
|
|
||||||
sts = portstatus(h, p);
|
sts = portstatus(h, p);
|
||||||
if(sts < 0){
|
if(sts == -1){
|
||||||
hubfail(h); /* avoid delays on detachment */
|
hubfail(h); /* avoid delays on detachment */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pp = &h->port[p];
|
pp = &h->port[p];
|
||||||
onhubs = nhubs;
|
onhubs = nhubs;
|
||||||
if((sts & PSsuspend) != 0){
|
if(!h->dev->isusb3){
|
||||||
if(hubfeature(h, p, Fportenable, 1) < 0)
|
if((sts & PSsuspend) != 0){
|
||||||
dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
|
if(hubfeature(h, p, Fportenable, 1) < 0)
|
||||||
sleep(Enabledelay);
|
dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
|
||||||
sts = portstatus(h, p);
|
sleep(Enabledelay);
|
||||||
fprint(2, "%s: %s: port %d: resumed (sts %#ux)\n", argv0, d->dir, p, sts);
|
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((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){
|
||||||
if(portattach(h, p, sts) != nil)
|
if(portattach(h, p, sts) != nil)
|
||||||
if(attachdev(pp) < 0)
|
if(attachdev(h, pp) < 0)
|
||||||
portdetach(h, p);
|
portdetach(h, p);
|
||||||
}else if(portgone(pp, sts)){
|
}else if(portgone(pp, sts)){
|
||||||
portdetach(h, p);
|
portdetach(h, p);
|
||||||
}else if(portresetwanted(h, p))
|
}else if(portresetwanted(h, p))
|
||||||
portreset(h, p);
|
portreset(h, p);
|
||||||
else if(pp->sts != sts){
|
else if(pp->sts != sts){
|
||||||
dprint(2, "%s: %s port %d: sts %s %#x ->",
|
dprint(2, "%s: %s port %d: sts %s %#ux ->",
|
||||||
argv0, d->dir, p, stsstr(pp->sts), pp->sts);
|
argv0, d->dir, p, stsstr(pp->sts, h->dev->isusb3), pp->sts);
|
||||||
dprint(2, " %s %#x\n",stsstr(sts), sts);
|
dprint(2, " %s %#ux\n",stsstr(sts, h->dev->isusb3), sts);
|
||||||
}
|
}
|
||||||
pp->sts = sts;
|
pp->sts = sts;
|
||||||
if(onhubs != nhubs)
|
if(onhubs != nhubs)
|
||||||
|
@ -663,7 +639,7 @@ work(void)
|
||||||
hubs = nil;
|
hubs = nil;
|
||||||
while((fn = rendezvous(work, nil)) != nil){
|
while((fn = rendezvous(work, nil)) != nil){
|
||||||
dprint(2, "%s: %s starting\n", argv0, fn);
|
dprint(2, "%s: %s starting\n", argv0, fn);
|
||||||
h = newhub(fn, nil);
|
h = newhub(fn, nil, nil);
|
||||||
if(h == nil)
|
if(h == nil)
|
||||||
fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn);
|
fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn);
|
||||||
free(fn);
|
free(fn);
|
||||||
|
|
|
@ -373,9 +373,10 @@ assignhname(Dev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
attachdev(Port *p)
|
attachdev(Hub *h, Port *p)
|
||||||
{
|
{
|
||||||
Dev *d = p->dev;
|
Dev *d = p->dev;
|
||||||
|
int id;
|
||||||
|
|
||||||
if(d->usb->class == Clhub){
|
if(d->usb->class == Clhub){
|
||||||
/*
|
/*
|
||||||
|
@ -384,11 +385,21 @@ attachdev(Port *p)
|
||||||
* has the config address in use.
|
* has the config address in use.
|
||||||
* We cancel kernel debug for these eps. too chatty.
|
* We cancel kernel debug for these eps. too chatty.
|
||||||
*/
|
*/
|
||||||
if((p->hub = newhub(d->dir, d)) == nil)
|
if((p->hub = newhub(d->dir, d, h)) == nil)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create all endpoint files for default conf #1 */
|
||||||
|
for(id=1; id<nelem(d->usb->ep); id++){
|
||||||
|
Ep *ep = d->usb->ep[id];
|
||||||
|
if(ep != nil && ep->conf != nil && ep->conf->cval == 1){
|
||||||
|
Dev *epd = openep(d, id);
|
||||||
|
if(epd != nil)
|
||||||
|
closedev(epd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* close control endpoint so driver can open it */
|
/* close control endpoint so driver can open it */
|
||||||
close(d->dfd);
|
close(d->dfd);
|
||||||
d->dfd = -1;
|
d->dfd = -1;
|
||||||
|
@ -406,7 +417,7 @@ attachdev(Port *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
detachdev(Port *p)
|
detachdev(Hub *, Port *p)
|
||||||
{
|
{
|
||||||
Dev *d = p->dev;
|
Dev *d = p->dev;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue