diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-08-01 19:02:50 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-08-01 19:02:50 +0200 |
commit | 676a876df607eda5488d7635592a99228066d0f9 (patch) | |
tree | 624a13da9b0f0fc5dc107fe2e69fda149f5220ae | |
parent | 89ab1f286e7c9c5f21109eaf351e5e3c195fb337 (diff) |
usb: added buffer delay control
-rw-r--r-- | sys/src/9/pc/devusb.c | 7 | ||||
-rw-r--r-- | sys/src/9/pc/usbohci.c | 18 | ||||
-rw-r--r-- | sys/src/9/pc/usbuhci.c | 36 | ||||
-rw-r--r-- | sys/src/9/port/usb.h | 1 | ||||
-rw-r--r-- | sys/src/9/port/usbehci.c | 44 | ||||
-rw-r--r-- | sys/src/cmd/nusb/audio/audio.c | 19 |
6 files changed, 114 insertions, 11 deletions
diff --git a/sys/src/9/pc/devusb.c b/sys/src/9/pc/devusb.c index fc87bbcca..6153edc5d 100644 --- a/sys/src/9/pc/devusb.c +++ b/sys/src/9/pc/devusb.c @@ -88,6 +88,7 @@ enum CMdebugep, /* debug n (set/clear debug for this ep) */ CMname, /* name str (show up as #u/name as well) */ CMtmout, /* timeout n (activate timeouts for ep) */ + CMsampledelay, /* maximum delay introduced by buffering (iso) */ CMpreset, /* reset the port */ /* Hub feature selectors */ @@ -132,6 +133,7 @@ static Cmdtab epctls[] = {CMclrhalt, "clrhalt", 1}, {CMname, "name", 2}, {CMtmout, "timeout", 2}, + {CMsampledelay, "sampledelay", 2}, {CMpreset, "reset", 1}, }; @@ -1309,6 +1311,11 @@ epctl(Ep *ep, Chan *c, void *a, long n) if(ep->tmout != 0 && ep->tmout < Xfertmout) ep->tmout = Xfertmout; break; + case CMsampledelay: + if(ep->ttype != Tiso) + error("ctl ignored for this endpoint type"); + ep->sampledelay = strtoul(cb->f[1], nil, 0); + break; case CMpreset: deprint("usb epctl %s\n", cb->f[0]); if(ep->ttype != Tctl) diff --git a/sys/src/9/pc/usbohci.c b/sys/src/9/pc/usbohci.c index c0a790ff9..003a5e7ee 100644 --- a/sys/src/9/pc/usbohci.c +++ b/sys/src/9/pc/usbohci.c @@ -220,6 +220,7 @@ struct Isoio ulong frno; /* next frame number avail for I/O */ ulong left; /* remainder after rounding Hz to samples/ms */ int nerrs; /* consecutive errors on iso I/O */ + int delay; /* maximum number of frames to buffer */ }; /* @@ -1101,6 +1102,17 @@ isocanwrite(void *a) iso->navail > iso->nframes / 2; } +static int +isodelay(void *a) +{ + Isoio *iso; + + iso = a; + if(iso->state == Qclose || iso->err != nil || iso->delay == 0) + return 1; + return (iso->nframes - iso->navail) <= iso->delay; +} + /* * Service a completed/failed Td from the done queue. * It may be of any transfer type. @@ -1780,6 +1792,7 @@ episowrite(Ep *ep, void *a, long count) ctlr = ep->hp->aux; iso = ep->aux; + iso->delay = (ep->sampledelay*ep->samplesz + ep->maxpkt-1) / ep->maxpkt; iso->debug = ep->debug; qlock(iso); @@ -1821,6 +1834,11 @@ episowrite(Ep *ep, void *a, long count) nw = putsamples(ctlr, ep, iso, b+tot, count-tot); ilock(ctlr); } + while(isodelay(iso) == 0){ + iunlock(ctlr); + sleep(iso, isodelay, iso); + ilock(ctlr); + } if(iso->state != Qclose) iso->state = Qdone; iunlock(ctlr); diff --git a/sys/src/9/pc/usbuhci.c b/sys/src/9/pc/usbuhci.c index 6a1dab01d..d5a107a68 100644 --- a/sys/src/9/pc/usbuhci.c +++ b/sys/src/9/pc/usbuhci.c @@ -195,6 +195,7 @@ struct Isoio int debug; /* debug flag from the endpoint */ Isoio* next; /* in list of active Isoios */ Td* tdps[Nframes]; /* pointer to Td used for i-th frame or nil */ + int delay; /* maximum number of bytes to buffer */ }; struct Tdpool @@ -775,6 +776,29 @@ isocanwrite(void *a) iso->tok == Tdtokout && iso->tdu->next != iso->tdi); } +static int +isodelay(void *a) +{ + Isoio *iso; + int delay; + Td *tdi; + + iso = a; + if(iso->state == Qclose || iso->err || iso->delay == 0) + return 1; + + delay = 0; + for(tdi = iso->tdi; tdi->next != iso->tdu; tdi = tdi->next){ + if((tdi->csw & Tdactive) == 0) + continue; + delay += maxtdlen(tdi); + if(delay > iso->delay) + break; + } + + return delay <= iso->delay; +} + static void tdisoinit(Isoio *iso, Td *td, long count) { @@ -812,7 +836,6 @@ isointerrupt(Ctlr *ctlr, Isoio* iso) nframes = iso->nframes / 2; /* limit how many we look */ if(nframes > 64) nframes = 64; - for(i = 0; i < nframes && (tdi->csw & Tdactive) == 0; i++){ tdi->csw &= ~Tdioc; err = tdi->csw & Tderrors; @@ -839,7 +862,7 @@ isointerrupt(Ctlr *ctlr, Isoio* iso) } tdi = tdi->next; } - ddiprint("isointr: %d frames processed\n", nframes); + ddiprint("isointr: %d frames processed\n", i); if(i == nframes) tdi->csw |= Tdioc; iso->tdi = tdi; @@ -848,7 +871,6 @@ isointerrupt(Ctlr *ctlr, Isoio* iso) iso->tdi, iso->tdu); wakeup(iso); } - } /* @@ -1005,6 +1027,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count) char *err; iso->debug = ep->debug; + iso->delay = ep->sampledelay * ep->samplesz; diprint("uhci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb); ctlr = ep->hp->aux; @@ -1046,6 +1069,11 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count) nw = putsamples(iso, b+tot, count-tot); ilock(ctlr); } + while(isodelay(iso) == 0){ + iunlock(ctlr); + sleep(iso, isodelay, iso); + ilock(ctlr); + } if(iso->state != Qclose) iso->state = Qdone; iunlock(ctlr); @@ -1678,7 +1706,7 @@ isoopen(Ep *ep) } ltd->next = iso->tdps[iso->td0frno]; iso->tdi = iso->tdps[iso->td0frno]; - iso->tdu = iso->tdi; /* read: right now; write: 1s ahead */ + iso->tdu = iso->tdi; ilock(ctlr); frno = iso->td0frno; for(i = 0; i < iso->nframes; i++){ diff --git a/sys/src/9/port/usb.h b/sys/src/9/port/usb.h index 11b00212f..5758bdd20 100644 --- a/sys/src/9/port/usb.h +++ b/sys/src/9/port/usb.h @@ -170,6 +170,7 @@ struct Ep long samplesz; /* sample size (iso) */ int ntds; /* nb. of Tds per µframe */ int tmout; /* 0 or timeout for transfers (ms) */ + int sampledelay; /* maximum delay introduced by buffering (iso) */ }; /* diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c index e6ff879e3..56aae9371 100644 --- a/sys/src/9/port/usbehci.c +++ b/sys/src/9/port/usbehci.c @@ -215,6 +215,7 @@ struct Isoio ulong maxsize; /* ntds * ep->maxpkt */ long nleft; /* number of bytes left from last write */ int debug; /* debug flag from the endpoint */ + int delay; /* max number of bytes to buffer */ int hs; /* is high speed? */ Isoio* next; /* in list of active Isoios */ ulong td0frno; /* first frame used in ctlr */ @@ -1291,6 +1292,43 @@ itdactive(Itd *td) } static int +isodelay(void *a) +{ + Isoio *iso; + int delay; + + iso = a; + if(iso->state == Qclose || iso->err || iso->delay == 0) + return 1; + + delay = 0; + if(iso->hs){ + Itd *i; + + for(i = iso->tdi; i->next != iso->tdu; i = i->next){ + if(!itdactive(i)) + continue; + delay += i->mdata; + if(delay > iso->delay) + break; + } + } else { + Sitd *i; + + for(i = iso->stdi; i->next != iso->stdu; i = i->next){ + if((i->csw & Stdactive) == 0) + continue; + delay += i->mdata; + if(delay > iso->delay) + break; + } + } + + return delay <= iso->delay; +} + + +static int isohsinterrupt(Ctlr *ctlr, Isoio *iso) { int err, i, nframes, t; @@ -1996,6 +2034,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count) int tot, nw; char *err; + iso->delay = ep->sampledelay * ep->samplesz; iso->debug = ep->debug; diprint("ehci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb); @@ -2039,6 +2078,11 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count) nw = putsamples(iso, b+tot, count-tot); ilock(ctlr); } + while(isodelay(iso) == 0){ + iunlock(ctlr); + sleep(iso, isodelay, iso); + ilock(ctlr); + } if(iso->state != Qclose) iso->state = Qdone; iunlock(ctlr); diff --git a/sys/src/cmd/nusb/audio/audio.c b/sys/src/cmd/nusb/audio/audio.c index 8ba3d99d5..dbbab7ca8 100644 --- a/sys/src/cmd/nusb/audio/audio.c +++ b/sys/src/cmd/nusb/audio/audio.c @@ -14,6 +14,7 @@ struct Audio int maxfreq; }; +int audiodelay = 882; int audiofreq = 44100; int audiochan = 2; int audiores = 16; @@ -85,15 +86,17 @@ Foundaltc: b[1] = speed >> 8; b[2] = speed >> 16; if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0) - fprint(2, "warning: set freq: %r"); + fprint(2, "warning: set freq: %r\n"); if((d = openep(d, e->id)) == nil){ werrstr("openep: %r"); return nil; } - devctl(d, "pollival %d", 1); + devctl(d, "pollival %d", a->interval); devctl(d, "samplesz %d", audiochan*audiores/8); + devctl(d, "sampledelay %d", audiodelay); devctl(d, "hz %d", speed); + devctl(d, "name audio"); return d; } @@ -102,7 +105,7 @@ fsread(Req *r) { char *msg; - msg = smprint("master 100 100\nspeed %d\n", audiofreq); + msg = smprint("master 100 100\nspeed %d\ndelay %d\n", audiofreq, audiodelay); readstr(r, msg); respond(r, nil); free(msg); @@ -112,7 +115,7 @@ void fswrite(Req *r) { char msg[256], *f[4]; - int nf; + int nf, speed; snprint(msg, sizeof(msg), "%.*s", r->ifcall.count, r->ifcall.data); nf = tokenize(msg, f, nelem(f)); @@ -122,17 +125,20 @@ fswrite(Req *r) } if(strcmp(f[0], "speed") == 0){ Dev *d; - int speed; speed = atoi(f[1]); +Setup: if((d = setupep(audiodev, audioep, speed)) == nil){ responderror(r); return; } - devctl(d, "name audio"); closedev(d); audiofreq = speed; + } else if(strcmp(f[0], "delay") == 0){ + audiodelay = atoi(f[1]); + speed = audiofreq; + goto Setup; } r->ofcall.count = r->ifcall.count; respond(r, nil); @@ -185,7 +191,6 @@ Foundendp: audioep = e; if((d = setupep(audiodev, audioep, audiofreq)) == nil) sysfatal("setupep: %r"); - devctl(d, "name audio"); closedev(d); fs.tree = alloctree(user, "usb", DMDIR|0555, nil); |