diff 3d5dca521797b5a91ebc4281fbaf58211bb4f40f uncommitted --- a/sys/src/cmd/nusb/audio/audio.c +++ b/sys/src/cmd/nusb/audio/audio.c @@ -3,6 +3,8 @@ #include #include #include <9p.h> +#include +#pragma varargck type "!" Pcmdesc #include "usb.h" enum { @@ -13,12 +15,43 @@ /* audio 1 */ Rsetcur = 0x01, + Rgetcur = 0x81, + Rgetmin, + Rgetmax, + Rgetres, /* audio 2 */ Rcur = 0x01, Rrange = 0x02, + + /* feature unit control values */ + Cmute = 1, + Cvolume, + Cbass, + Cmid, + Ctreble, + Cagc = 7, + Cbassboost = 9, + Cloudness = 10, + Cnum, }; +#define Conlycur (1<ddesc); i++){ - dd = u->ddesc[i]; + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; if(dd == nil || dd->data.bDescriptorType != 11 || dd->data.bLength != 8) continue; b = dd->data.bbytes; - if(b[0] == id && b[0]+b[1] <= Niface && csp == CSP(b[2], b[3], b[4])) + if(b[0] == ac->id && b[0]+b[1] <= Niface && csp == CSP(b[2], b[3], b[4])) return dd; } return nil; @@ -92,14 +140,14 @@ } Desc* -findacheader(Usbdev *u, Iface *ac) +findacheader(void) { Desc *dd; uchar *b; int i; - for(i = 0; i < nelem(u->ddesc); i++){ - dd = u->ddesc[i]; + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; if(dd == nil || dd->iface != ac || dd->data.bDescriptorType != 0x24) continue; if(dd->data.bLength < 8 || dd->data.bbytes[0] != 1) @@ -120,14 +168,14 @@ } Desc* -findterminal(Usbdev *u, Iface *ac, int id) +findterminal(int id) { Desc *dd; uchar *b; int i; - for(i = 0; i < nelem(u->ddesc); i++){ - dd = u->ddesc[i]; + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; if(dd == nil || dd->iface != ac) continue; if(dd->data.bDescriptorType != 0x24 || dd->data.bLength < 4) @@ -148,14 +196,14 @@ } Desc* -findclocksource(Usbdev *u, Iface *ac, int id) +findclocksource(int id) { Desc *dd; uchar *b; int i; - for(i = 0; i < nelem(u->ddesc); i++){ - dd = u->ddesc[i]; + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; if(dd == nil || dd->iface != ac) continue; if(dd->data.bDescriptorType != 0x24 || dd->data.bLength != 8) @@ -167,6 +215,19 @@ return nil; } +Rune +tofmt(int v) +{ + switch(v){ + case 1: return L's'; + case 2: return L'u'; + case 3: return L'f'; + case 4: return L'a'; + case 5: return L'ยต'; + } + return 0; +} + void parseasdesc1(Desc *dd, Aconf *c) { @@ -185,7 +246,7 @@ if(dd->data.bLength != 7) return; c->terminal = b[1]; - c->format = GET2(&b[3]); + c->fmt = tofmt(GET2(&b[3])); break; case 0x2402: /* CS_INTERFACE, FORMAT_TYPE */ @@ -223,7 +284,7 @@ if(dd->data.bLength != 16 || b[3] != 1) return; c->terminal = b[1]; - c->format = GET4(&b[4]); + c->fmt = tofmt(GET4(&b[4])); c->channels = b[8]; break; @@ -237,7 +298,7 @@ } int -setclock(Dev *d, Iface *ac, Aconf *c, int speed) +setclock(Aconf *c, int speed) { uchar b[4]; int index; @@ -252,22 +313,22 @@ index = c->ep->id & Epmax; if(c->ep->dir == Ein) index |= 0x80; - return usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, Csamfreq<<8, index, b, 3); + return usbcmd(adev, Rh2d|Rclass|Rep, Rsetcur, Csamfreq<<8, index, b, 3); case Paudio2: PUT4(b, speed); index = c->clock<<8 | ac->id; - return usbcmd(d, Rh2d|Rclass|Riface, Rcur, Csamfreq<<8, index, b, 4); + return usbcmd(adev, Rh2d|Rclass|Riface, Rcur, Csamfreq<<8, index, b, 4); } return 0; } int -getclockrange(Dev *d, Iface *ac, Aconf *c) +getclockrange(Aconf *c) { uchar b[2 + 32*12]; int i, n, rc; - rc = usbcmd(d, Rd2h|Rclass|Riface, Rrange, Csamfreq<<8, c->clock<<8 | ac->id, b, sizeof(b)); + rc = usbcmd(adev, Rd2h|Rclass|Riface, Rrange, Csamfreq<<8, c->clock<<8 | ac->id, b, sizeof(b)); if(rc < 0) return -1; if(rc < 2 || rc < 2 + (n = GET2(b))*12){ @@ -281,11 +342,206 @@ return 0; } +int +setvalue(uchar id, uchar hi, uchar lo, short value, int sz) +{ + uchar b[2]; + + if(sz == 1) + b[0] = value; + else + PUT2(b, value); + + if(Proto(ac->csp) == Paudio1) + return usbcmd(adev, Rh2d|Rclass|Riface, Rsetcur, hi<<8 | lo, id<<8 | ac->id, b, sz); + + return usbcmd(adev, Rh2d|Rclass|Riface, Rcur, hi<<8 | lo, id<<8 | ac->id, b, sz); +} + +int +getvalue(int r, uchar id, uchar hi, uchar lo, short *value) +{ + uchar b[2 + 32*3*4]; + int rc, i, n; + + *value = 0; + i = 0; + if(Proto(ac->csp) == Paudio1) + rc = usbcmd(adev, Rd2h|Rclass|Riface, r, hi<<8 | lo, id<<8 | ac->id, b, sizeof(b)); + else{ + i = r - Rgetmin; + r = r == Rgetcur ? Rcur : Rrange; + rc = usbcmd(adev, Rd2h|Rclass|Riface, r, hi<<8 | lo, id<<8 | ac->id, b, sizeof(b)); + } + if(rc < 0) + return -1; + if(rc < 1) + goto Invalid; + if(r == Rrange){ + rc -= 2; + if(rc < 3 || (n = GET2(b)) < 1) + goto Invalid; + else if(rc == n*3*2) + *value = GET2(&b[2 + i*2]); + else if(rc == n*3*1) + *value = b[2 + i]; + else + goto Invalid; + }else + *value = rc > 1 ? GET2(b) : b[0]; + return 0; +Invalid: + werrstr("invalid response"); + return -1; +} + +int +getvalues(Ctrl *c) +{ + char *s; + int onlycur; + + onlycur = Conlycur & (1<cs); + if(((s = "cur") && getvalue(Rgetcur, c->id, c->cs, c->ch, &c->cur) < 0) || + (!onlycur && ( + ((s = "min") && getvalue(Rgetmin, c->id, c->cs, c->ch, &c->min) < 0) || + ((s = "max") && getvalue(Rgetmax, c->id, c->cs, c->ch, &c->max) < 0) || + ((s = "res") && getvalue(Rgetres, c->id, c->cs, c->ch, &c->res) < 0)))){ + fprint(2, "getvalue: %s: %s: %r\n", ctrlname[c->cs], s); + return -1; + } + if(onlycur){ + c->min = 0; + c->max = 1; + c->res = 1; + }else if(c->res < 1){ + fprint(2, "getvalue: %s: invalid res: %d\n", ctrlname[c->cs], c->res); + return -1; + } + return 0; +} + +int +cmpctrl(void *a_, void *b_) +{ + Ctrl *a, *b; + a = a_; + b = b_; + if(a->id != b->id) + return a->id - b->id; + if(a->cs != b->cs) + return a->cs - b->cs; + return a->ch - b->ch; +} + void -parsestream(Dev *d, Iface *ac, int id) +findcontrols1(void) { - Iface *as; Desc *dd; + uchar *b; + Ctrl *c; + int i, k, n, x; + uchar cs, ch; + + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; + if(dd == nil) + continue; + b = dd->data.bbytes; + switch(dd->data.bDescriptorType<<8 | b[0]){ + case 0x2406: /* CS_INTERFACE, FEATURE_UNIT */ + if(dd->data.bLength < 8 || nctrl >= nelem(ctrl) || (n = b[3]) < 1) + continue; + for(k = 0; k < nctrl; k++) + if(ctrl[k].id == b[1]) + break; + if(k < nctrl) + break; + for(k = 4, ch = 0; k <= dd->data.bLength-2-n-1; k += n, ch++){ + x = (n > 1 ? GET2(b+k) : b[k]) & (Call>>1); + if(x == 0) + continue; + for(cs = 1; cs < Cnum && nctrl < nelem(ctrl); cs++, x >>= 1){ + if((x & 1) != 1) + continue; + c = &ctrl[nctrl++]; + c->cs = cs; + c->ch = ch; + c->id = b[1]; + getvalues(c); + } + } + break; + } + } + qsort(ctrl, nctrl, sizeof(Ctrl), cmpctrl); +} + +void +findcontrols2(void) +{ + Desc *dd; + uchar *b; + Ctrl *c; + int i, k, n, x; + uchar cs, ch; + + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; + if(dd == nil) + continue; + b = dd->data.bbytes; + switch(dd->data.bDescriptorType<<8 | b[0]){ + case 0x2406: /* CS_INTERFACE, FEATURE_UNIT */ + if(dd->data.bLength < 9 || nctrl >= nelem(ctrl)) + continue; + for(k = 0; k < nctrl; k++) + if(ctrl[k].id == b[1]) + break; + if(k < nctrl) + break; + n = 4; + for(k = 3, ch = 0; k <= dd->data.bLength-2-n-1; k += n, ch++){ + x = GET4(b+k) & (Call2>>2); + if(x == 0) + continue; + for(cs = 1; cs < Cnum && nctrl < nelem(ctrl); cs++, x >>= 2){ + if((x & 3) != 3) + continue; + c = &ctrl[nctrl++]; + c->cs = cs; + c->ch = ch; + c->id = b[1]; + getvalues(c); + } + } + break; + } + } + qsort(ctrl, nctrl, sizeof(Ctrl), cmpctrl); +} + +void +parseterminal2(Desc *dd, Aconf *c) +{ + uchar *b; + + b = dd->data.bbytes; + switch(b[0]){ + case 0x02: /* INPUT_TERMINAL */ + c->clock = b[5]; + break; + case 0x03: /* OUTPUT_TERMINAL */ + c->clock = b[6]; + break; + } +} + +void +parsestream(int id) +{ + Iface *as, *zb; + Desc *dd; Ep *e; Aconf *c; uchar *b; @@ -292,8 +548,11 @@ int i; /* find AS interface */ - as = findiface(d->usb->conf[0], Claudio, 2, id); + as = findiface(adev->usb->conf[0], Claudio, 2, id); + /* find zero-bandwidth setting, if any */ + for(zb = as; zb != nil && zb->alt != 0; zb = zb->next); + /* enumerate through alt. settings */ for(; as != nil; as = as->next){ c = emallocz(sizeof(*c), 1); @@ -313,10 +572,11 @@ as->aux = nil; continue; } + c->zb = zb; /* parse AS descriptors */ - for(i = 0; i < nelem(d->usb->ddesc); i++){ - dd = d->usb->ddesc[i]; + for(i = 0; i < nelem(adev->usb->ddesc); i++){ + dd = adev->usb->ddesc[i]; if(dd == nil || dd->iface != as) continue; switch(Proto(ac->csp)){ @@ -332,20 +592,12 @@ if(Proto(ac->csp) == Paudio1) continue; - dd = findterminal(d->usb, ac, c->terminal); + dd = findterminal(c->terminal); if(dd == nil) goto Skip; - b = dd->data.bbytes; - switch(b[0]){ - case 0x02: /* INPUT_TERMINAL */ - c->clock = b[5]; - break; - case 0x03: /* OUTPUT_TERMINAL */ - c->clock = b[6]; - break; - } + parseterminal2(dd, c); - dd = findclocksource(d->usb, ac, c->clock); + dd = findclocksource(c->clock); if(dd == nil) goto Skip; b = dd->data.bbytes; @@ -352,123 +604,349 @@ /* check that clock has rw frequency control */ if((b[3] & 3) != 3) goto Skip; - if(getclockrange(d, ac, c) != 0){ - fprint(2, "getclockrange %d: %r", c->clock); + if(getclockrange(c) != 0){ + fprint(2, "getclockrange %d: %r\n", c->clock); goto Skip; } } } +int +fmtcmp(Pcmdesc *a, Pcmdesc *b) +{ + if(a->rate != b->rate) + return a->rate - b->rate; + if(a->channels != b->channels) + return a->channels - b->channels; + if(a->bits != b->bits) + return a->bits - b->bits; + if(a->fmt != b->fmt){ + if(a->fmt == L's' || a->fmt == L'f') + return 1; + if(b->fmt == L's' || b->fmt == L'f') + return -1; + } + return a->fmt - b->fmt; +} + Dev* -setupep(Dev *d, Iface *ac, Ep *e, int *speed, int force) +setupep(Ep *e, Pcmdesc *fmt, int exact) { - int dir = e->dir; Aconf *c, *bestc; + Ep *beste, *ep; + int n, r, dir; + Pcmdesc p; Range *f; - Ep *beste; - int closest, sp; + Dev *d; + dir = e->dir; + ep = e; bestc = nil; beste = nil; - closest = 1<<30; - sp = *speed; + r = -1; for(;e != nil; e = e->next){ c = e->iface->aux; - if(c == nil || e != c->ep || e->dir != dir) + if(c == nil || e != c->ep || e->dir != dir || c->bits != 8*c->bps) continue; - if(c->format != 1 || c->bits != audiores || 8*c->bps != audiores || c->channels != audiochan) - continue; for(f = c->freq; f != c->freq+c->nfreq; f++){ - if(sp >= f->min && sp <= f->max) - goto Foundaltc; - if(force) - continue; - if(f->min >= sp && closest-sp >= f->min-sp){ - closest = f->min; + p = *c; + if(f->min >= fmt->rate) + p.rate = f->min; + else if(f->max <= fmt->rate) + p.rate = f->max; + else + p.rate = fmt->rate; + if((n = fmtcmp(&p, fmt)) == 0 || bestc == nil){ +Better: + c->rate = p.rate; bestc = c; beste = e; - }else if(bestc == nil || (f->max < sp && closest < sp && sp-closest > sp-f->max)){ - closest = f->max; - bestc = c; - beste = e; + if((r = n) == 0) + goto Done; + continue; } + /* both better, but the new is closer */ + if(n > 0 && (r > 0 && fmtcmp(&p, bestc) < 0)) + goto Better; + /* both worse, but the new one is better so far */ + if(n < 0 && (r < 0 && fmtcmp(&p, bestc) > 0)) + goto Better; } } - if(bestc == nil){ + +Done: + if(bestc == nil || (exact && r != 0)){ werrstr("no altc found"); return nil; } e = beste; c = bestc; - sp = closest; -Foundaltc: - if(setalt(d, e->iface) < 0){ - fprint(2, "setalt: %r\n"); + if(setalt(adev, e->iface) < 0){ + werrstr("setalt: %r\n"); return nil; } - if(setclock(d, ac, c, sp) < 0){ + if(setclock(c, c->rate) < 0){ werrstr("setclock: %r"); return nil; } - if((d = openep(d, e)) == nil){ + if((d = openep(adev, e)) == nil){ werrstr("openep: %r"); return nil; } - devctl(d, "samplesz %d", audiochan*audiores/8); + devctl(d, "samplesz %d", c->channels*c->bits/8); devctl(d, "sampledelay %d", audiodelay); - devctl(d, "hz %d", sp); - devctl(d, "name audio%sU%s", e->dir==Ein ? "in" : "", audiodev->hname); - *speed = sp; + devctl(d, "hz %d", c->rate); + devctl(d, "name audio%sU%s", e->dir==Ein ? "in" : "", adev->hname); + ep->aux = c; return d; } +char * +ctrlvalue(Ctrl *c) +{ + static char v[64]; + int x, n; + + if((Conlycur & (1<cs)) == 0){ + if((ushort)c->cur == 0x8000) + x = 0; + else{ + n = (c->max - c->min); + x = (c->cur - c->min) * 100; + x /= n; + } + }else{ + x = !!c->cur; + } + snprint(v, sizeof(v), "%d", x); + return v; +} + +char * +seprintaconf(char *s, char *e, Ep *ep) +{ + Pcmdesc d; + Range *f; + Aconf *c; + int dir; + + dir = ep->dir; + for(; ep != nil; ep = ep->next){ + c = ep->iface->aux; + if(c == nil || ep != c->ep || ep->dir != dir || c->fmt == 0 || c->bits != 8*c->bps) + continue; + for(f = c->freq; f != c->freq+c->nfreq; f++){ + d = c->Pcmdesc; + d.rate = f->min; + s = seprint(s, e, " %!", d); + if(f->min < f->max){ + d.rate = f->max; + s = seprint(s, e, "-%!", d); + } + } + } + return seprint(s, e, "\n"); +} + void fsread(Req *r) { - char *msg; + static char msg[1024]; + Ctrl *cur, *prev; + char *s, *e; + Aconf *c; + int i; - msg = smprint("master 100 100\nspeed %d\ndelay %d\n", audiofreq, audiodelay); + s = msg; + e = msg+sizeof(msg); + *s = 0; + + if(r->fid->file == ctl){ + if(epout != nil) + s = seprint(s, e, "out %s\n", outoff ? "off" : "on"); + if(epin != nil) + seprint(s, e, "in %s\n", inoff ? "off" : "on"); + } else if(r->fid->file == status){ + s = seprint(s, e, "bufsize %6d buffered %6d\n", 0, 0); + if(epout != nil) + s = seprintaconf(seprint(s, e, "fmtout"), e, epout); + if(epin != nil) + seprintaconf(seprint(s, e, "fmtin"), e, epin); + } else if(r->fid->file == volume){ + if(epout != nil){ + c = epout->aux; + s = seprint(s, e, "delay %d\nfmtout %!\nspeed %d\n", + audiodelay, c->Pcmdesc, c->rate); + } + if(epin != nil){ + c = epin->aux; + s = seprint(s, e, "fmtin %!\n", c->Pcmdesc); + } + + prev = nil; + for(i = 0; i < nctrl; i++, prev = cur){ + cur = ctrl+i; + if(prev == nil || prev->id != cur->id || prev->cs != cur->cs) + s = seprint(s, e, "%s%s%d", i==0?"":"\n", ctrlname[cur->cs], cur->id); + s = seprint(s, e, " %s", ctrlvalue(cur)); + } + if(i > 0) + seprint(s, e, "\n"); + } else { + respond(r, "protocol botch"); + return; + } + readstr(r, msg); respond(r, nil); - free(msg); } +int +setctrl(char *f[8], int nf) +{ + int i, j, id, n, x, sz; + char *s, *e; + uchar cs; + Ctrl *c; + + id = -1; + s = nil; + for(e = f[0]; *e; e++){ + if(*e >= '0' && *e <= '9'){ + s = e; + id = strtol(e, &e, 10); + break; + } + } + if(id < 0 || *e != 0){ +Invalid: + werrstr("invalid name"); + goto Error; + } + *s = 0; + for(i = 0, c = ctrl; i < nctrl; i++, c++){ + if(ctrl[i].id == id && strcmp(ctrlname[c->cs], f[0]) == 0) + break; + } + if(i == nctrl) + goto Invalid; + + cs = c->cs; + for(j = 1; j < nf; j++){ + x = atoi(f[j]); + if((Conlycur & (1<cs)) == 0){ + sz = (Cszone & (1<cs)) ? 1 : 2; + if(x <= 0 && sz == 2) + x = 0x8000; + else{ + n = (c->max - c->min) / c->res; + x = (x * n * c->res)/100 + c->min; + if(x < c->min) + x = c->min; + else if(x > c->max) + x = c->max; + } + }else{ + x = !!x; + sz = 1; + } +Groupset: + if(setvalue(c->id, c->cs, c->ch, x, sz) < 0) + goto Error; + if(getvalue(Rgetcur, c->id, c->cs, c->ch, &c->cur) < 0) + goto Error; + + c++; + if(c >= ctrl+nctrl || c->id != id || c->cs != cs) + break; /* just ignore anything extra */ + if(nf == 2) + goto Groupset; + } + + return 0; +Error: + werrstr("%s: %r", f[0]); + return -1; +} + void fswrite(Req *r) { - char msg[256], *f[4]; - int nf, speed; + char msg[256], *f[8]; + int nf, off; + Pcmdesc pd; + Aconf *c; + Dev *d; + Ep *e; snprint(msg, sizeof(msg), "%.*s", utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data); nf = tokenize(msg, f, nelem(f)); if(nf < 2){ +Invalid: respond(r, "invalid ctl message"); return; } - if(strcmp(f[0], "speed") == 0){ - Dev *d; + c = epout->aux; - speed = atoi(f[1]); -Setup: - if((d = setupep(audiodev, audiocontrol, audioepout, &speed, 1)) == nil){ - responderror(r); + if(r->fid->file == ctl){ + if(strcmp(f[0], "out") == 0) + e = epout; + else if(strcmp(f[0], "in") == 0) + e = epin; + else + goto Invalid; + if(strcmp(f[1], "on") == 0) + off = 0; + else if(strcmp(f[1], "off") == 0) + off = 1; + else + goto Invalid; + c = e->aux; + if(c->zb == nil){ + respond(r, "no zero-bandwidth config"); return; } - audiofreq = speed; + if(setalt(adev, c->zb) < 0) + goto Error; + if(e == epout) + outoff = off; + else + inoff = off; + } else if(r->fid->file != volume){ + werrstr("protocol botch"); + goto Error; + } else if((strcmp(f[0], "speed") == 0 || strcmp(f[0], "fmtout") == 0) && epout != nil){ + if(f[0][0] == 's'){ + pd = c->Pcmdesc; + pd.rate = atoi(f[1]); + }else if(mkpcmdesc(f[1], &pd) != 0) + goto Error; +Setup: + if((d = setupep(epout, &pd, 1)) == nil) + goto Error; closedev(d); - if(audioepin != nil) - if(d = setupep(audiodev, audiocontrol, audioepin, &speed, 1)) - closedev(d); - } else if(strcmp(f[0], "delay") == 0){ + } else if(strcmp(f[0], "fmtin") == 0 && epin != nil){ + if(mkpcmdesc(f[1], &pd) != 0) + goto Error; + if((d = setupep(epin, &pd, 1)) == nil) + goto Error; + closedev(d); + } else if(strcmp(f[0], "delay") == 0 && epout != nil){ + pd = c->Pcmdesc; audiodelay = atoi(f[1]); - speed = audiofreq; goto Setup; + } else if(setctrl(f, nf) < 0){ + goto Error; } + r->ofcall.count = r->ifcall.count; respond(r, nil); + return; +Error: + responderror(r); } Srv fs = { @@ -487,10 +965,9 @@ main(int argc, char *argv[]) { char buf[32]; - Dev *d, *ed; + Dev *ed; Desc *dd; Conf *conf; - Iface *ac; Aconf *c; Ep *e; uchar *b; @@ -508,37 +985,36 @@ if(argc == 0) usage(); - if((d = getdev(*argv)) == nil) + fmtinstall('!', pcmdescfmt); + if((adev = getdev(*argv)) == nil) sysfatal("getdev: %r"); - audiodev = d; - conf = d->usb->conf[0]; + conf = adev->usb->conf[0]; ac = findiface(conf, Claudio, 1, -1); if(ac == nil) sysfatal("no audio control interface"); - audiocontrol = ac; switch(Proto(ac->csp)){ case Paudio1: - dd = findacheader(d->usb, ac); + dd = findacheader(); if(dd == nil) sysfatal("no audio control header"); b = dd->data.bbytes; for(i = 6; i < dd->data.bLength-2; i++) - parsestream(d, ac, b[i]); + parsestream(b[i]); break; case Paudio2: - dd = findiad(d->usb, ac->id, CSP(Claudio, 0, Paudio2)); + dd = findiad(CSP(Claudio, 0, Paudio2)); if(dd == nil) sysfatal("no audio function"); b = dd->data.bbytes; for(i = b[0]+1; i < b[0]+b[1]; i++) - parsestream(d, ac, i); + parsestream(i); break; } - for(i = 0; i < nelem(d->usb->ep); i++){ - for(e = d->usb->ep[i]; e != nil; e = e->next){ + for(i = 0; i < nelem(adev->usb->ep); i++){ + for(e = adev->usb->ep[i]; e != nil; e = e->next){ c = e->iface->aux; if(c != nil && c->ep == e) break; @@ -547,35 +1023,47 @@ continue; switch(e->dir){ case Ein: - if(audioepin != nil) + if(epin != nil) continue; - audioepin = e; + epin = e; break; case Eout: - if(audioepout != nil) + if(epout != nil) continue; - audioepout = e; + epout = e; break; } - if((ed = setupep(d, ac, e, &audiofreq, 0)) == nil){ - fprint(2, "setupep: %r\n"); - - if(e == audioepin) - audioepin = nil; - if(e == audioepout) - audioepout = nil; + if((ed = setupep(e, &pcmdescdef, 0)) == nil){ + fprint(2, "setupep: %s: %r\n", epout == e ? "out" : "in"); + if(e == epin) + epin = nil; + if(e == epout) + epout = nil; continue; } closedev(ed); } - if(audioepout == nil) - sysfatal("no output stream found"); + if(epout == nil && epin == nil) + sysfatal("no streams found"); + switch(Proto(ac->csp)){ + case Paudio1: + findcontrols1(); + break; + case Paudio2: + findcontrols2(); + break; + } + fs.tree = alloctree(user, "usb", DMDIR|0555, nil); - snprint(buf, sizeof buf, "volumeU%s", audiodev->hname); - createfile(fs.tree->root, buf, user, 0666, nil); + snprint(buf, sizeof buf, "audioctlU%s", adev->hname); + ctl = createfile(fs.tree->root, buf, user, 0666, nil); + snprint(buf, sizeof buf, "audiostatU%s", adev->hname); + status = createfile(fs.tree->root, buf, user, 0444, nil); + snprint(buf, sizeof buf, "volumeU%s", adev->hname); + volume = createfile(fs.tree->root, buf, user, 0666, nil); - snprint(buf, sizeof buf, "%d.audio", audiodev->id); + snprint(buf, sizeof buf, "%d.audio", adev->id); postsharesrv(&fs, nil, "usb", buf); exits(0);