ref: 6ba62a039631802779a6d44a1eb1e79af5e98bd3
parent: 8569aecf35a6780be42eeda0cfbd4bf1d7bc8ee6
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jul 31 09:12:17 EDT 2022
usb: fix ehci isochronous "in" split transactions For "in" transactions, the "Total Bytes to Transfer" field in the siTD is decremented by the controller by the actual transfer size, so what remains in the field is the residue number of bytes. Also, handle restart when we get a zero byte read on a isochronous "in" endpoint in devusb itself (removing the restart code for xhci drivers). This fixes audio recording with a usb1.1 audio device connected to ehci controller.
--- a/sys/src/9/imx8/usbxhciimx.c
+++ b/sys/src/9/imx8/usbxhciimx.c
@@ -1326,7 +1326,6 @@
}
µ = io->period;
ctlr = ep->hp->aux;
-Again:
if(needrecover(ctlr))
error(Erecover);
@@ -1374,10 +1373,6 @@
io->frame = i;
*io->ring->doorbell = io->ring->id;
- if(p == s){
- tsleep(&up->sleep, return0, nil, 5);
- goto Again;
- }
qunlock(io);
poperror();
--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -1199,19 +1199,22 @@
error(Enotconf);
case Tctl:
nr = rhubread(ep, a, n);
- if(nr >= 0){
- n = nr;
+ if(nr >= 0)
break;
- }
/* else fall */
default:
ddeprint("\nusbread q %#x fid %d cnt %ld off %lld\n",q,c->fid,n,offset);
- n = ep->hp->epread(ep, a, n);
+ Again:
+ nr = ep->hp->epread(ep, a, n);
+ if(nr == 0 && ep->ttype == Tiso){
+ tsleep(&up->sleep, return0, nil, 2*ep->pollival);
+ goto Again;
+ }
break;
}
poperror();
putep(ep);
- return n;
+ return nr;
}
/*
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1365,7 +1365,7 @@
ctlr->nisointr++;
ddiprint("isohsintr: iso %#p: tdi %#p tdu %#p\n", iso, tdi, iso->tdu);
if(iso->state != Qrun && iso->state != Qdone)
- panic("isofsintr: iso state");
+ panic("isohsintr: iso state");
if(ehcidebug > 1 || iso->debug > 1)
isodump(iso, 0);
@@ -1394,6 +1394,8 @@
tdi->ndata = 0;
if(tdi->next == iso->tdu || tdi->next->next == iso->tdu){
+ diprint("overrun iso %#p tdi %#p tdu %#p\n", iso, tdi, iso->tdu);
+
memset(iso->tdu->data, 0, iso->tdu->mdata);
itdinit(ctlr, iso, iso->tdu);
iso->tdu = iso->tdu->next;
@@ -1402,13 +1404,13 @@
tdi = tdi->next;
coherence();
}
- ddiprint("isohsintr: %d frames processed\n", nframes);
+ ddiprint("isohsintr: %d frames processed\n", i);
if(i == nframes){
tdi->csw[0] |= Itdioc;
coherence();
}
- iso->tdi = tdi;
coherence();
+ iso->tdi = tdi;
if(isocanwrite(iso) || isocanread(iso)){
diprint("wakeup iso %#p tdi %#p tdu %#p\n", iso,
iso->tdi, iso->tdu);
@@ -1444,20 +1446,24 @@
err = stdi->csw & Stderrors;
if(err == 0){
iso->nerrs = 0;
- if(iso->tok == Tdtokin)
- stdi->ndata = (stdi->csw>>Stdlenshift)&Stdlenmask;
- }else if(iso->nerrs++ > iso->nframes/2){
- if(iso->err == nil){
- iso->err = serrmsg(err);
- diprint("isofsintr: tdi %#p error %#ux %s\n",
- stdi, err, iso->err);
- diprint("ctlr load %uld\n", ctlr->load);
+ if(iso->tok == Tdtokin){
+ ulong residue = (stdi->csw>>Stdlenshift)&Stdlenmask;
+ stdi->ndata = residue < stdi->ndata ? stdi->ndata - residue : 0;
+ diprint("isofsintr: tdi %#p ndata %lud, mdata %lud\n", stdi, stdi->ndata, stdi->mdata);
}
+ }else {
+ diprint("isofsintr: tdi %#p error %#ux %s\n", stdi, err, serrmsg(err));
+ if(iso->nerrs++ > iso->nframes/2){
+ if(iso->err == nil){
+ iso->err = serrmsg(err);
+ diprint("ctlr load %uld\n", ctlr->load);
+ }
+ }
stdi->ndata = 0;
- }else
- stdi->ndata = 0;
-
+ }
if(stdi->next == iso->stdu || stdi->next->next == iso->stdu){
+ diprint("overrun iso %#p tdi %#p tdu %#p\n", iso, stdi, iso->stdu);
+
memset(iso->stdu->data, 0, iso->stdu->mdata);
sitdinit(ctlr, iso, iso->stdu);
iso->stdu = iso->stdu->next;
@@ -1466,13 +1472,13 @@
coherence();
stdi = stdi->next;
}
- ddiprint("isofsintr: %d frames processed\n", nframes);
+ ddiprint("isofsintr: %d frames processed\n", i);
if(i == nframes){
stdi->csw |= Stdioc;
coherence();
}
- iso->stdi = stdi;
coherence();
+ iso->stdi = stdi;
if(isocanwrite(iso) || isocanread(iso)){
diprint("wakeup iso %#p tdi %#p tdu %#p\n", iso,
iso->stdi, iso->stdu);
--- a/sys/src/9/port/usbxhci.c
+++ b/sys/src/9/port/usbxhci.c
@@ -1338,7 +1338,6 @@
}
µ = io->period;
ctlr = ep->hp->aux;
-Again:
if(needrecover(ctlr))
error(Erecover);
@@ -1386,10 +1385,6 @@
io->frame = i;
*io->ring->doorbell = io->ring->id;
- if(p == s){
- tsleep(&up->sleep, return0, nil, 5);
- goto Again;
- }
qunlock(io);
poperror();
--
⑨