summaryrefslogtreecommitdiff
path: root/sys/src/9/port/usbehci.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-09-03 01:54:34 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-09-03 01:54:34 +0200
commitcfd25faa2857ee9de75910d81530be62d7ba4704 (patch)
tree1bebf05a269d6923290e5e362a5bdf46fda6e8f4 /sys/src/9/port/usbehci.c
parent1be10947ba37964feb10e0cf45576b029043866b (diff)
usb: fix isowrite putsamples race
Diffstat (limited to 'sys/src/9/port/usbehci.c')
-rw-r--r--sys/src/9/port/usbehci.c47
1 files changed, 28 insertions, 19 deletions
diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c
index ef1c1ca71..22af2e798 100644
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1996,33 +1996,44 @@ episoread(Ep *ep, Isoio *iso, void *a, long count)
* it is activated and tdu advanced.
*/
static long
-putsamples(Isoio *iso, uchar *b, long count)
+putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
{
- long tot, n;
+ long left, tot, n;
+ Sitd *stdu;
+ Itd *tdu;
for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
n = count-tot;
+ left = iso->nleft;
if(iso->hs != 0){
- if(n > iso->tdu->mdata - iso->nleft)
- n = iso->tdu->mdata - iso->nleft;
- memmove(iso->tdu->data + iso->nleft, b + tot, n);
- coherence();
+ tdu = iso->tdu;
+ if(n > tdu->mdata - left)
+ n = tdu->mdata - left;
+ iunlock(ctlr); /* We could page fault here */
+ memmove(tdu->data + left, b + tot, n);
+ ilock(ctlr);
+ if(iso->tdu != tdu)
+ continue;
iso->nleft += n;
- if(iso->nleft == iso->tdu->mdata){
- itdinit(iso, iso->tdu);
+ if(iso->nleft == tdu->mdata){
+ itdinit(iso, tdu);
+ iso->tdu = tdu->next;
iso->nleft = 0;
- iso->tdu = iso->tdu->next;
}
}else{
- if(n > iso->stdu->mdata - iso->nleft)
- n = iso->stdu->mdata - iso->nleft;
- memmove(iso->stdu->data + iso->nleft, b + tot, n);
- coherence();
+ stdu = iso->stdu;
+ if(n > stdu->mdata - left)
+ n = stdu->mdata - left;
+ iunlock(ctlr); /* We could page fault here */
+ memmove(stdu->data + left, b + tot, n);
+ ilock(ctlr);
+ if(iso->stdu != stdu)
+ continue;
iso->nleft += n;
- if(iso->nleft == iso->stdu->mdata){
- sitdinit(iso, iso->stdu);
+ if(iso->nleft == stdu->mdata){
+ sitdinit(iso, stdu);
+ iso->stdu = stdu->next;
iso->nleft = 0;
- iso->stdu = iso->stdu->next;
}
}
}
@@ -2081,9 +2092,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count)
}
if(iso->state != Qrun)
panic("episowrite: iso not running");
- iunlock(ctlr); /* We could page fault here */
- nw = putsamples(iso, b+tot, count-tot);
- ilock(ctlr);
+ nw = putsamples(ctlr, iso, b+tot, count-tot);
}
while(isodelay(iso) == 0){
iunlock(ctlr);