summaryrefslogtreecommitdiff
path: root/sys/src/9/port
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2022-07-31 13:12:17 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2022-07-31 13:12:17 +0000
commit9672be80e84cb3253dc999fbaa5dbc7913a17e0e (patch)
tree69fa2962395657faccf1b17413ff4ce58240f53b /sys/src/9/port
parent30dcf55ee221b986aee6d428b4da431f6174c66b (diff)
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.
Diffstat (limited to 'sys/src/9/port')
-rw-r--r--sys/src/9/port/devusb.c13
-rw-r--r--sys/src/9/port/usbehci.c38
-rw-r--r--sys/src/9/port/usbxhci.c5
3 files changed, 30 insertions, 26 deletions
diff --git a/sys/src/9/port/devusb.c b/sys/src/9/port/devusb.c
index e395df265..beb55055c 100644
--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -1199,19 +1199,22 @@ usbread(Chan *c, void *a, long n, vlong offset)
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;
}
/*
diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c
index 1d2dd6d49..f89804415 100644
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1365,7 +1365,7 @@ isohsinterrupt(Ctlr *ctlr, Isoio *iso)
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 @@ isohsinterrupt(Ctlr *ctlr, Isoio *iso)
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 @@ isohsinterrupt(Ctlr *ctlr, Isoio *iso)
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 @@ isofsinterrupt(Ctlr *ctlr, Isoio *iso)
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 @@ isofsinterrupt(Ctlr *ctlr, Isoio *iso)
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);
diff --git a/sys/src/9/port/usbxhci.c b/sys/src/9/port/usbxhci.c
index 4c2b60a3b..bdaf968ed 100644
--- a/sys/src/9/port/usbxhci.c
+++ b/sys/src/9/port/usbxhci.c
@@ -1338,7 +1338,6 @@ isoread(Ep *ep, uchar *p, long n)
}
ยต = io->period;
ctlr = ep->hp->aux;
-Again:
if(needrecover(ctlr))
error(Erecover);
@@ -1386,10 +1385,6 @@ Again:
io->frame = i;
*io->ring->doorbell = io->ring->id;
- if(p == s){
- tsleep(&up->sleep, return0, nil, 5);
- goto Again;
- }
qunlock(io);
poperror();