summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-08-01 19:02:50 +0200
committercinap_lenrek <cinap_lenrek@localhost>2011-08-01 19:02:50 +0200
commit676a876df607eda5488d7635592a99228066d0f9 (patch)
tree624a13da9b0f0fc5dc107fe2e69fda149f5220ae
parent89ab1f286e7c9c5f21109eaf351e5e3c195fb337 (diff)
usb: added buffer delay control
-rw-r--r--sys/src/9/pc/devusb.c7
-rw-r--r--sys/src/9/pc/usbohci.c18
-rw-r--r--sys/src/9/pc/usbuhci.c36
-rw-r--r--sys/src/9/port/usb.h1
-rw-r--r--sys/src/9/port/usbehci.c44
-rw-r--r--sys/src/cmd/nusb/audio/audio.c19
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);