mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
devusb: destruct usb tree from the leaves, split epclose() into epstop()/epclose()
For xhci, we want to keep the hubs around until all its attached devices have been released, so have the Udev take a reference to its parent hubs ep0. This also means that we can now use just a pointer to the tthub instead of duplicating the properties needed for xhci and ythe code becomes trivial. Do a non-recursive implementation of putep() to conserve stack space. For device detaches, we want to immediately cancel all I/O so that the driver can release the device as soon as possible. For this, we add epstop callback in the Hci struct.
This commit is contained in:
parent
acf707cbbc
commit
ebf3e9067d
7 changed files with 219 additions and 108 deletions
|
@ -180,8 +180,8 @@ chansetup(Hostchan *hc, Ep *ep)
|
|||
hcc |= Lspddev;
|
||||
/* fall through */
|
||||
case Fullspeed:
|
||||
if(ep->dev->tthub != 0 && ep->dev->ttport != 0){
|
||||
hc->hcsplt = Spltena | POS_ALL | ep->dev->tthub<<OHubaddr | ep->dev->ttport;
|
||||
if(ep->dev->tthub != nil){
|
||||
hc->hcsplt = Spltena | POS_ALL | ep->dev->tthub->addr<<OHubaddr | ep->dev->ttport;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
|
@ -582,10 +582,8 @@ ctltrans(Ep *ep, uchar *req, long n)
|
|||
datalen = GET2(req+Rcount);
|
||||
if(datalen <= 0 || datalen > Maxctllen)
|
||||
error(Ebadlen);
|
||||
/* XXX cache madness */
|
||||
epio->cb = b = allocb(ROUND(datalen, ep->maxpkt));
|
||||
assert(((uintptr)b->wp & (BLOCKALIGN-1)) == 0);
|
||||
memset(b->wp, 0x55, b->lim - b->wp);
|
||||
cachedwbinvse(b->wp, b->lim - b->wp);
|
||||
data = b->wp;
|
||||
}else{
|
||||
|
@ -604,7 +602,7 @@ ctltrans(Ep *ep, uchar *req, long n)
|
|||
chansetup(hc, ep);
|
||||
chanio(ep, hc, Epout, SETUP, req, Rsetuplen);
|
||||
if(req[Rtype] & Rd2h){
|
||||
if(ep->dev->hub <= 1){
|
||||
if(ep->dev->depth == 0){
|
||||
ep->toggle[Read] = DATA1;
|
||||
b->wp += multitrans(ep, hc, Read, data, datalen);
|
||||
}else
|
||||
|
|
|
@ -2147,21 +2147,19 @@ cancelio(Ep *ep, Qio *io)
|
|||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
epstop(Ep *ep)
|
||||
{
|
||||
Ctlio *cio;
|
||||
Isoio *iso;
|
||||
Qio *io;
|
||||
|
||||
deprint("ohci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
deprint("ohci: epstop ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
if(ep->aux == nil)
|
||||
panic("ohci: epclose called with closed ep");
|
||||
panic("ohci: epstop called with closed ep");
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
cancelio(ep, cio);
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tbulk:
|
||||
case Tintr:
|
||||
|
@ -2181,6 +2179,29 @@ epclose(Ep *ep)
|
|||
iso = ep->aux;
|
||||
cancelio(ep, iso);
|
||||
break;
|
||||
default:
|
||||
panic("epstop: bad ttype %d", ep->ttype);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
{
|
||||
Ctlio *cio;
|
||||
|
||||
deprint("ohci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
if(ep->aux == nil)
|
||||
panic("ohci: epclose called with closed ep");
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tbulk:
|
||||
case Tintr:
|
||||
case Tiso:
|
||||
break;
|
||||
default:
|
||||
panic("epclose: bad ttype %d", ep->ttype);
|
||||
}
|
||||
|
@ -2598,6 +2619,7 @@ reset(Hci *hp)
|
|||
hp->init = init;
|
||||
hp->interrupt = interrupt;
|
||||
hp->epopen = epopen;
|
||||
hp->epstop = epstop;
|
||||
hp->epclose = epclose;
|
||||
hp->epread = epread;
|
||||
hp->epwrite = epwrite;
|
||||
|
|
|
@ -1909,7 +1909,7 @@ cancelisoio(Ctlr *ctlr, Isoio *iso, int pollival, ulong load)
|
|||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
epstop(Ep *ep)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
Ctlio *cio;
|
||||
|
@ -1917,16 +1917,15 @@ epclose(Ep *ep)
|
|||
Qio *io;
|
||||
|
||||
ctlr = ep->hp->aux;
|
||||
deprint("uhci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
deprint("uhci: epstop ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
|
||||
if(ep->aux == nil)
|
||||
panic("uhci: epclose called with closed ep");
|
||||
panic("uhci: epstop called with closed ep");
|
||||
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
cancelio(ctlr, cio);
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tbulk:
|
||||
case Tintr:
|
||||
|
@ -1947,13 +1946,36 @@ epclose(Ep *ep)
|
|||
iso = ep->aux;
|
||||
cancelisoio(ctlr, iso, ep->pollival, ep->load);
|
||||
break;
|
||||
default:
|
||||
panic("epstop: bad ttype %d", ep->ttype);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
{
|
||||
Ctlio *cio;
|
||||
|
||||
deprint("uhci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
|
||||
if(ep->aux == nil)
|
||||
panic("uhci: epclose called with closed ep");
|
||||
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tbulk:
|
||||
case Tintr:
|
||||
case Tiso:
|
||||
break;
|
||||
default:
|
||||
panic("epclose: bad ttype %d", ep->ttype);
|
||||
}
|
||||
|
||||
free(ep->aux);
|
||||
ep->aux = nil;
|
||||
|
||||
}
|
||||
|
||||
static char*
|
||||
|
@ -2327,6 +2349,7 @@ reset(Hci *hp)
|
|||
hp->init = init;
|
||||
hp->interrupt = interrupt;
|
||||
hp->epopen = epopen;
|
||||
hp->epstop = epstop;
|
||||
hp->epclose = epclose;
|
||||
hp->epread = epread;
|
||||
hp->epwrite = epwrite;
|
||||
|
|
|
@ -326,7 +326,7 @@ seprintep(char *s, char *se, Ep *ep, int all)
|
|||
s = seprint(s, se, " samplesz %ld", ep->samplesz);
|
||||
s = seprint(s, se, " hz %ld", ep->hz);
|
||||
s = seprint(s, se, " uframes %d", ep->uframes);
|
||||
s = seprint(s, se, " hub %d", ep->dev->hubnb);
|
||||
s = seprint(s, se, " hub %d", ep->dev->hub? ep->dev->hub->nb: 0);
|
||||
s = seprint(s, se, " port %d", ep->dev->port);
|
||||
s = seprint(s, se, " rootport %d", ep->dev->rootport);
|
||||
s = seprint(s, se, " addr %d", ep->dev->addr);
|
||||
|
@ -409,33 +409,38 @@ static void
|
|||
putep(Ep *ep)
|
||||
{
|
||||
Udev *d;
|
||||
Ep *next;
|
||||
|
||||
if(ep == nil || decref(ep) > 0)
|
||||
return;
|
||||
d = ep->dev;
|
||||
deprint("usb: ep%d.%d %#p released\n", d->nb, ep->nb, ep);
|
||||
qlock(ep->ep0);
|
||||
qlock(&epslck);
|
||||
assert(d->eps[ep->nb] == ep);
|
||||
d->eps[ep->nb] = nil;
|
||||
assert(eps[ep->idx] == ep);
|
||||
eps[ep->idx] = nil;
|
||||
if(ep->idx == epmax-1){
|
||||
while(epmax > 0 && eps[epmax-1] == nil)
|
||||
epmax--;
|
||||
for(; ep != nil; ep = next){
|
||||
if(decref(ep) > 0)
|
||||
return;
|
||||
assert(ep->inuse == 0);
|
||||
d = ep->dev;
|
||||
deprint("usb: ep%d.%d %#p released\n", d->nb, ep->nb, ep);
|
||||
qlock(ep->ep0);
|
||||
qlock(&epslck);
|
||||
assert(d->eps[ep->nb] == ep);
|
||||
d->eps[ep->nb] = nil;
|
||||
assert(eps[ep->idx] == ep);
|
||||
eps[ep->idx] = nil;
|
||||
if(ep->idx == epmax-1){
|
||||
while(epmax > 0 && eps[epmax-1] == nil)
|
||||
epmax--;
|
||||
}
|
||||
qunlock(&epslck);
|
||||
qunlock(ep->ep0);
|
||||
if(ep->ep0 != ep)
|
||||
next = ep->ep0;
|
||||
else {
|
||||
next = d->hub != nil? d->hub->eps[0]: nil;
|
||||
if(ep->hp->devclose != nil)
|
||||
(*ep->hp->devclose)(d);
|
||||
free(d);
|
||||
}
|
||||
free(ep->info);
|
||||
free(ep->name);
|
||||
free(ep);
|
||||
}
|
||||
qunlock(&epslck);
|
||||
qunlock(ep->ep0);
|
||||
if(ep->ep0 != ep)
|
||||
putep(ep->ep0);
|
||||
else {
|
||||
if(d->free != nil)
|
||||
(*d->free)(d->aux);
|
||||
free(d);
|
||||
}
|
||||
free(ep->info);
|
||||
free(ep->name);
|
||||
free(ep);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -497,22 +502,22 @@ newdev(Hci *hp, Ep *hub, int port, int speed)
|
|||
|
||||
d->nports = 0;
|
||||
d->rootport = d->routestr = 0;
|
||||
d->tthub = d->ttport = d->ttt = d->mtt = 0;
|
||||
d->ttport = d->ttt = d->mtt = 0;
|
||||
d->tthub = nil;
|
||||
|
||||
if(hub != nil){
|
||||
d->hub = hub->dev->addr;
|
||||
d->hubnb = hub->dev->nb;
|
||||
d->depth = hub->dev->depth+1;
|
||||
d->hub = hub->dev;
|
||||
d->depth = d->hub->depth+1;
|
||||
if(d->depth > 0){
|
||||
assert(d->depth <= 5);
|
||||
d->routestr = hub->dev->routestr | (d->port<15? d->port: 15) << 4*(d->depth-1);
|
||||
d->routestr = d->hub->routestr | (d->port<15? d->port: 15) << 4*(d->depth-1);
|
||||
if(speed < Highspeed){
|
||||
if(hub->dev->speed == Highspeed){
|
||||
d->tthub = hub->dev->addr;
|
||||
if(d->hub->speed == Highspeed){
|
||||
d->tthub = d->hub;
|
||||
d->ttport = port;
|
||||
}else {
|
||||
d->tthub = hub->dev->tthub;
|
||||
d->ttport = hub->dev->ttport;
|
||||
d->tthub = d->hub->tthub;
|
||||
d->ttport = d->hub->ttport;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -520,8 +525,7 @@ newdev(Hci *hp, Ep *hub, int port, int speed)
|
|||
if(d->rootport == 0)
|
||||
error(Ebadport);
|
||||
} else {
|
||||
d->hub = 0;
|
||||
d->hubnb = 0;
|
||||
d->hub = nil;
|
||||
d->depth = -1;
|
||||
}
|
||||
|
||||
|
@ -548,8 +552,9 @@ newdev(Hci *hp, Ep *hub, int port, int speed)
|
|||
ep->ep0 = ep; /* no ref counted here */
|
||||
ep->dev = d;
|
||||
d->eps[0] = ep;
|
||||
if(hub != nil)
|
||||
incref(hub);
|
||||
incref(ep);
|
||||
|
||||
qunlock(&epslck);
|
||||
poperror();
|
||||
poperror();
|
||||
|
@ -1049,18 +1054,21 @@ usbclose(Chan *c)
|
|||
return;
|
||||
|
||||
deprint("usbclose q %#x fid %d ref %ld\n", q, c->fid, ep->ref);
|
||||
|
||||
qlock(ep);
|
||||
if(!ep->inuse)
|
||||
qunlock(ep);
|
||||
else {
|
||||
if(!waserror()){
|
||||
(*ep->hp->epclose)(ep);
|
||||
if(ep->hp->epstop != nil)
|
||||
(*ep->hp->epstop)(ep);
|
||||
if(ep->hp->epclose != nil)
|
||||
(*ep->hp->epclose)(ep);
|
||||
poperror();
|
||||
}
|
||||
ep->inuse = 0;
|
||||
ep->aux = nil;
|
||||
qunlock(ep);
|
||||
putep(ep); /* release ref kept since usbopen */
|
||||
putep(ep); /* release ref from usbopen() */
|
||||
}
|
||||
putep(ep); /* release ref of getep() above */
|
||||
}
|
||||
|
@ -1219,7 +1227,7 @@ usbread(Chan *c, void *a, long n, vlong offset)
|
|||
ddeprint("\nusbread q %#x fid %d cnt %ld off %lld\n",q,c->fid,n,offset);
|
||||
Again:
|
||||
nr = (*ep->hp->epread)(ep, a, n);
|
||||
if(nr == 0 && ep->ttype == Tiso){
|
||||
if(nr == 0 && ep->ttype == Tiso && ep->dev->state != Ddetach){
|
||||
tsleep(&up->sleep, return0, nil, 2*ep->pollival);
|
||||
goto Again;
|
||||
}
|
||||
|
@ -1315,9 +1323,18 @@ epctl(Ep *ep, Chan *c, void *a, long n)
|
|||
d->state = Ddetach;
|
||||
qunlock(ep);
|
||||
poperror();
|
||||
/* Release file system ref. for its endpoints */
|
||||
for(i = 0; i < nelem(d->eps); i++)
|
||||
putep(d->eps[i]);
|
||||
for(i = 0; i < nelem(d->eps); i++){
|
||||
ep = d->eps[i];
|
||||
if(ep != nil){
|
||||
qlock(ep);
|
||||
if(ep->inuse && ep->hp->epstop != nil && !waserror()){
|
||||
(*ep->hp->epstop)(ep);
|
||||
poperror();
|
||||
}
|
||||
qunlock(ep);
|
||||
putep(ep);
|
||||
}
|
||||
}
|
||||
goto Unlocked;
|
||||
case CMpreset:
|
||||
if(d->state != Denabled)
|
||||
|
|
|
@ -90,7 +90,8 @@ enum
|
|||
* Services provided by the driver.
|
||||
* epopen allocates hardware structures to prepare the endpoint
|
||||
* for I/O. This happens when the user opens the data file.
|
||||
* epclose releases them. This happens when the data file is closed.
|
||||
* epstop canceles in-flight I/O and epclose releases them.
|
||||
* This happens when the data file is closed.
|
||||
* epwrite tries to write the given bytes, waiting until all of them
|
||||
* have been written (or failed) before returning; but not for Iso.
|
||||
* epread does the same for reading.
|
||||
|
@ -102,7 +103,7 @@ enum
|
|||
* hubs. Port status must return bits as a hub request would do.
|
||||
* Toggle handling and other details are left for the controller driver
|
||||
* to avoid mixing too much the controller and the comon device.
|
||||
* While an endpoint is closed, its toggles are saved in the Ep struct.
|
||||
* While an endpoint is stopped, its toggles are saved in the Ep struct.
|
||||
*/
|
||||
struct Hciimpl
|
||||
{
|
||||
|
@ -110,10 +111,12 @@ struct Hciimpl
|
|||
void (*init)(Hci*); /* init. controller */
|
||||
void (*interrupt)(Ureg*, void*); /* service interrupt */
|
||||
void (*epopen)(Ep*); /* prepare ep. for I/O */
|
||||
void (*epclose)(Ep*); /* terminate I/O on ep. */
|
||||
void (*epstop)(Ep*); /* cancel I/O on ep. */
|
||||
void (*epclose)(Ep*); /* release I/O on ep. (after epstop) */
|
||||
long (*epread)(Ep*,void*,long); /* transmit data for ep */
|
||||
long (*epwrite)(Ep*,void*,long); /* receive data for ep */
|
||||
char* (*seprintep)(char*,char*,Ep*); /* debug */
|
||||
void (*devclose)(Udev*); /* release the device */
|
||||
int (*portenable)(Hci*, int, int); /* enable/disable port */
|
||||
int (*portreset)(Hci*, int, int); /* set/clear port reset */
|
||||
int (*portstatus)(Hci*, int); /* get port status */
|
||||
|
@ -185,23 +188,22 @@ struct Udev
|
|||
int state; /* state for the device */
|
||||
int nports; /* number of downstream ports for hub */
|
||||
int speed; /* Full/Low/High/Super -speed */
|
||||
int hubnb; /* USB device number for the parent hub */
|
||||
int hub; /* device address of parent hub */
|
||||
int port; /* port number on parent hub */
|
||||
int addr; /* device address */
|
||||
int depth; /* hub depth from root port -1 */
|
||||
int rootport; /* port number on root hub */
|
||||
int routestr; /* route string */
|
||||
|
||||
int tthub; /* device address of TT HS hub */
|
||||
Udev *hub; /* parent hub; keeping ref to hub->eps[0] */
|
||||
|
||||
Udev *tthub; /* the TT HS hub */
|
||||
int ttport; /* port number on TT HS hub */
|
||||
int ttt; /* TT Think-Time for HS hub */
|
||||
int mtt; /* Multi TT enabled for HS hub */
|
||||
|
||||
void *aux;
|
||||
void (*free)(void*);
|
||||
|
||||
Ep* eps[Ndeveps]; /* end points for this device (cached) */
|
||||
Ep *eps[Ndeveps]; /* end points for this device (cached) */
|
||||
};
|
||||
|
||||
void addhcitype(char *type, int (*reset)(Hci*));
|
||||
|
|
|
@ -682,8 +682,10 @@ qhalloc(Ctlr *ctlr, Ep *ep, Qio *io, char* tag)
|
|||
coherence();
|
||||
qhsetaddr(qh, io->usbid);
|
||||
qh->eps1 = (ep->ntds & Qhmultmask) << Qhmultshift;
|
||||
qh->eps1 |= ep->dev->ttport << Qhportshift;
|
||||
qh->eps1 |= ep->dev->tthub << Qhhubshift;
|
||||
if(ep->dev->tthub != nil){
|
||||
qh->eps1 |= ep->dev->tthub->addr << Qhhubshift;
|
||||
qh->eps1 |= ep->dev->ttport << Qhportshift;
|
||||
}
|
||||
qh->eps1 |= 034 << Qhscmshift;
|
||||
if(ep->ttype == Tintr)
|
||||
qh->eps1 |= 1 << Qhismshift; /* intr. start µf. */
|
||||
|
@ -2725,10 +2727,11 @@ isofsinit(Ep *ep, Isoio *iso)
|
|||
for(i = 0; i < iso->nframes; i++){
|
||||
td = sitdalloc(ctlr);
|
||||
td->data = iso->data + i * ep->maxpkt;
|
||||
td->epc = ep->dev->ttport << Stdportshift;
|
||||
td->epc |= ep->dev->tthub << Stdhubshift;
|
||||
td->epc |= (ep->nb&Epmax) << Stdepshift;
|
||||
td->epc |= ep->dev->addr << Stddevshift;
|
||||
td->epc = (ep->nb&Epmax) << Stdepshift | ep->dev->addr << Stddevshift;
|
||||
if(ep->dev->tthub != nil){
|
||||
td->epc |= ep->dev->tthub->addr << Stdhubshift;
|
||||
td->epc |= ep->dev->ttport << Stdportshift;
|
||||
}
|
||||
td->mfs = 034 << Stdscmshift | 1 << Stdssmshift;
|
||||
if(ep->mode == OREAD){
|
||||
td->epc |= Stdin;
|
||||
|
@ -3095,7 +3098,7 @@ cancelisoio(Ctlr *ctlr, Isoio *iso, ulong load)
|
|||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
epstop(Ep *ep)
|
||||
{
|
||||
Qio *io;
|
||||
Ctlio *cio;
|
||||
|
@ -3103,16 +3106,15 @@ epclose(Ep *ep)
|
|||
Ctlr *ctlr;
|
||||
|
||||
ctlr = ep->hp->aux;
|
||||
deprint("ehci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
deprint("ehci: epstop ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
|
||||
if(ep->aux == nil)
|
||||
panic("ehci: epclose called with closed ep");
|
||||
panic("ehci: epstop called with closed ep");
|
||||
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
cancelio(ctlr, cio);
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tintr:
|
||||
case Tbulk:
|
||||
|
@ -3128,12 +3130,36 @@ epclose(Ep *ep)
|
|||
if(io[OWRITE].toggle == Tddata1)
|
||||
ep->toggle[OWRITE] = 1;
|
||||
}
|
||||
coherence();
|
||||
break;
|
||||
case Tiso:
|
||||
iso = ep->aux;
|
||||
cancelisoio(ctlr, iso, ep->load);
|
||||
break;
|
||||
default:
|
||||
panic("epstop: bad ttype");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
{
|
||||
Ctlio *cio;
|
||||
|
||||
deprint("ehci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
|
||||
|
||||
if(ep->aux == nil)
|
||||
panic("ehci: epclose called with closed ep");
|
||||
|
||||
switch(ep->ttype){
|
||||
case Tctl:
|
||||
cio = ep->aux;
|
||||
free(cio->data);
|
||||
cio->data = nil;
|
||||
break;
|
||||
case Tintr:
|
||||
case Tbulk:
|
||||
case Tiso:
|
||||
break;
|
||||
default:
|
||||
panic("epclose: bad ttype");
|
||||
}
|
||||
|
@ -3292,6 +3318,7 @@ ehcilinkage(Hci *hp)
|
|||
hp->init = init;
|
||||
hp->interrupt = interrupt;
|
||||
hp->epopen = epopen;
|
||||
hp->epstop = epstop;
|
||||
hp->epclose = epclose;
|
||||
hp->epread = epread;
|
||||
hp->epwrite = epwrite;
|
||||
|
|
|
@ -928,13 +928,10 @@ interrupt(Ureg*, void *arg)
|
|||
}
|
||||
|
||||
static void
|
||||
freeslot(void *arg)
|
||||
freeslot(Slot *slot)
|
||||
{
|
||||
Slot *slot;
|
||||
|
||||
if(arg == nil)
|
||||
if(slot == nil)
|
||||
return;
|
||||
slot = arg;
|
||||
if(slot->id > 0){
|
||||
Ctlr *ctlr = slot->ctlr;
|
||||
qlock(&ctlr->slotlock);
|
||||
|
@ -1026,7 +1023,6 @@ initdevctx(Ctlr *ctlr, Slot *slot)
|
|||
{
|
||||
Udev *dev = slot->dev;
|
||||
u32int *w;
|
||||
int i;
|
||||
|
||||
/* (input) control context */
|
||||
w = slot->ibase;
|
||||
|
@ -1044,31 +1040,45 @@ initdevctx(Ctlr *ctlr, Slot *slot)
|
|||
w[2] |= dev->ttt<<16;
|
||||
}
|
||||
|
||||
if(dev->speed < Highspeed && dev->tthub != 0 && dev->ttport != 0){
|
||||
qlock(&ctlr->slotlock);
|
||||
for(i=1; i<=ctlr->nslots; i++){
|
||||
Slot *hub = ctlr->slot[i];
|
||||
|
||||
if(hub == nil || hub->dev == nil || hub->dev->aux != hub)
|
||||
continue;
|
||||
if(hub == slot || hub->dev == dev)
|
||||
continue;
|
||||
|
||||
if(hub->dev->addr != dev->tthub)
|
||||
continue;
|
||||
if(hub->dev->rootport != dev->rootport)
|
||||
continue;
|
||||
|
||||
if(dev->tthub != nil){
|
||||
Slot *hub = dev->tthub->aux;
|
||||
if(hub != nil && hub->dev == dev->tthub){
|
||||
w[0] |= hub->dev->mtt<<25;
|
||||
w[2] |= hub->id | dev->ttport<<8;
|
||||
break;
|
||||
}
|
||||
qunlock(&ctlr->slotlock);
|
||||
}
|
||||
|
||||
return slot->ibase;
|
||||
}
|
||||
|
||||
static void
|
||||
epstop(Ep *ep)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
Slot *slot;
|
||||
Ring *ring;
|
||||
Epio *io;
|
||||
|
||||
if(ep->nb == 0 || ep->dev->depth < 0)
|
||||
return;
|
||||
|
||||
io = ep->aux;
|
||||
if(io == nil)
|
||||
return;
|
||||
|
||||
ctlr = ep->hp->aux;
|
||||
slot = ep->dev->aux;
|
||||
|
||||
if((ring = io[OREAD].ring) != nil && ring->stopped == 0){
|
||||
ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
|
||||
ring->stopped = 1;
|
||||
}
|
||||
if((ring = io[OWRITE].ring) != nil && ring->stopped == 0){
|
||||
ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
|
||||
ring->stopped = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
epclose(Ep *ep)
|
||||
{
|
||||
|
@ -1097,13 +1107,11 @@ epclose(Ep *ep)
|
|||
w[0] |= 1 << ring->id;
|
||||
if(ring->id == slot->nep)
|
||||
slot->nep--;
|
||||
ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
|
||||
}
|
||||
if((ring = io[OWRITE].ring) != nil){
|
||||
w[0] |= 1 << ring->id;
|
||||
if(ring->id == slot->nep)
|
||||
slot->nep--;
|
||||
ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
|
||||
}
|
||||
|
||||
/* find largest index still in use */
|
||||
|
@ -1271,6 +1279,12 @@ initep(Ep *ep)
|
|||
poperror();
|
||||
}
|
||||
|
||||
static void
|
||||
devclose(Udev *dev)
|
||||
{
|
||||
freeslot(dev->aux);
|
||||
}
|
||||
|
||||
static void
|
||||
epopen(Ep *ep)
|
||||
{
|
||||
|
@ -1338,10 +1352,16 @@ epopen(Ep *ep)
|
|||
/* (output) slot context */
|
||||
w = slot->obase;
|
||||
|
||||
if(((w[3] >> 27) & 0x1F) < 2)
|
||||
error("xhci did not set device address");
|
||||
|
||||
dev->addr = w[3] & 0xFF;
|
||||
if(dev->addr == 0 || dev->addr > Devmax){
|
||||
dev->addr = 0;
|
||||
error("xhci returned invalid device address");
|
||||
}
|
||||
|
||||
dev->aux = slot;
|
||||
dev->free = freeslot;
|
||||
|
||||
poperror();
|
||||
poperror();
|
||||
|
@ -1823,10 +1843,12 @@ xhcilinkage(Hci *hp, Xhci *ctlr)
|
|||
|
||||
hp->interrupt = interrupt;
|
||||
hp->epopen = epopen;
|
||||
hp->epstop = epstop;
|
||||
hp->epclose = epclose;
|
||||
hp->epread = epread;
|
||||
hp->epwrite = epwrite;
|
||||
hp->seprintep = seprintep;
|
||||
hp->devclose = devclose;
|
||||
hp->portenable = portenable;
|
||||
hp->portreset = portreset;
|
||||
hp->portstatus = portstatus;
|
||||
|
|
Loading…
Reference in a new issue