ref: 3a076c7a9556717bd5feed02bd9cd99bcef8b496
parent: 6f3039351a35eb4310cfa1fc5dec802e74ad73f8
author: cinap_lenrek <cinap_lenrek@localhost>
date: Mon Aug 1 01:34:04 EDT 2011
nusb: export a volume file and allow setting speed
--- a/sys/src/cmd/nusb/audio/audio.c
+++ b/sys/src/cmd/nusb/audio/audio.c
@@ -1,17 +1,32 @@
#include <u.h>
#include <libc.h>
+#include <fcall.h>
#include <thread.h>
+#include <9p.h>
#include "usb.h"
+typedef struct Audio Audio;
+struct Audio
+{
+ Audio *next;
+
+ int minfreq;
+ int maxfreq;
+};
+
int audiofreq = 44100;
int audiochan = 2;
int audiores = 16;
-char validaltc[] = "";
+char user[] = "audio";
+Dev *audiodev = nil;
+Ep *audioep = nil;
+
void
parsedescr(Desc *dd)
{
+ Audio *a, **ap;
uchar *b;
int i;
@@ -24,27 +39,110 @@
return;
if(b[6] != audiores)
return;
- if(b[7] == 0){
- int minfreq, maxfreq;
- minfreq = b[8] | b[9]<<8 | b[10]<<16;
- maxfreq = b[11] | b[12]<<8 | b[13]<<16;
- if(minfreq > audiofreq || maxfreq < audiofreq)
- return;
+ ap = (Audio**)&dd->altc->aux;
+ if(b[7] == 0){
+ a = mallocz(sizeof(*a), 1);
+ a->minfreq = b[8] | b[9]<<8 | b[10]<<16;
+ a->maxfreq = b[11] | b[12]<<8 | b[13]<<16;
+ a->next = *ap;
+ *ap = a;
} else {
- int freq;
-
for(i=0; i<b[7]; i++){
- freq = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
- if(freq == audiofreq)
- break;
+ a = mallocz(sizeof(*a), 1);
+ a->minfreq = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
+ a->maxfreq = a->minfreq;
+ a->next = *ap;
+ *ap = a;
}
- if(i == b[7])
+ }
+}
+
+Dev*
+setupep(Dev *d, Ep *e, int speed)
+{
+ uchar b[4];
+ Audio *x;
+ Altc *a;
+ int i;
+
+ for(i = 0; i < nelem(e->iface->altc); i++)
+ if(a = e->iface->altc[i])
+ for(x = a->aux; x; x = x->next)
+ if(speed >= x->minfreq && speed <= x->maxfreq)
+ goto Foundaltc;
+
+ werrstr("no altc found");
+ return nil;
+
+Foundaltc:
+ if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, i, e->iface->id, nil, 0) < 0){
+ werrstr("set altc: %r");
+ return nil;
+ }
+
+ b[0] = speed;
+ 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");
+
+ if((d = openep(d, e->id)) == nil){
+ werrstr("openep: %r");
+ return nil;
+ }
+ devctl(d, "pollival %d", 1);
+ devctl(d, "samplesz %d", audiochan*audiores/8);
+ devctl(d, "hz %d", speed);
+ return d;
+}
+
+void
+fsread(Req *r)
+{
+ char *msg;
+
+ msg = smprint("master 100 100\nspeed %d\n", audiofreq);
+ readstr(r, msg);
+ respond(r, nil);
+ free(msg);
+}
+
+void
+fswrite(Req *r)
+{
+ char msg[256], *f[4];
+ int nf;
+
+ snprint(msg, sizeof(msg), "%.*s", r->ifcall.count, r->ifcall.data);
+ nf = tokenize(msg, f, nelem(f));
+ if(nf < 2){
+ respond(r, "invalid ctl message");
+ return;
+ }
+ if(strcmp(f[0], "speed") == 0){
+ Dev *d;
+ int speed;
+
+ speed = atoi(f[1]);
+ if((d = setupep(audiodev, audioep, speed)) == nil){
+ responderror(r);
return;
+ }
+ devctl(d, "name audio");
+ closedev(d);
+
+ audiofreq = speed;
}
- dd->altc->aux = validaltc;
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
}
+Srv fs = {
+ .read = fsread,
+ .write = fswrite,
+};
+
void
usage(void)
{
@@ -55,10 +153,8 @@
void
main(int argc, char *argv[])
{
- Dev *d, *ed;
- Usbdev *ud;
- uchar b[4];
- Altc *a;
+ char buf[32];
+ Dev *d;
Ep *e;
int i;
@@ -72,15 +168,13 @@
sysfatal("getdev: %r");
if(configdev(d) < 0)
sysfatal("configdev: %r");
+ audiodev = d;
- ud = d->usb;
-
/* parse descriptors, mark valid altc */
- for(i = 0; i < nelem(ud->ddesc); i++)
- parsedescr(ud->ddesc[i]);
-
- for(i = 0; i < nelem(ud->ep); i++){
- e = ud->ep[i];
+ for(i = 0; i < nelem(d->usb->ddesc); i++)
+ parsedescr(d->usb->ddesc[i]);
+ for(i = 0; i < nelem(d->usb->ep); i++){
+ e = d->usb->ep[i];
if(e && e->iface && e->iface->csp == CSP(Claudio, 2, 0) && e->dir == Eout)
goto Foundendp;
}
@@ -88,31 +182,17 @@
return;
Foundendp:
- for(i = 0; i < nelem(e->iface->altc); i++){
- a = e->iface->altc[i];
- if(a && a->aux == validaltc)
- goto Foundaltc;
- }
- sysfatal("no altc found");
+ audioep = e;
+ if((d = setupep(audiodev, audioep, audiofreq)) == nil)
+ sysfatal("setupep: %r");
+ devctl(d, "name audio");
+ closedev(d);
-Foundaltc:
- if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, i, e->iface->id, nil, 0) < 0)
- sysfatal("usbcmd: set altc: %r");
+ fs.tree = alloctree(user, "usb", DMDIR|0555, nil);
+ createfile(fs.tree->root, "volume", user, 0666, nil);
- b[0] = audiofreq;
- b[1] = audiofreq >> 8;
- b[2] = audiofreq >> 16;
- if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0)
- fprint(2, "warning: set freq: %r");
-
- if((ed = openep(d, e->id)) == nil)
- sysfatal("openep: %r");
- devctl(ed, "pollival %d", 1);
- devctl(ed, "samplesz %d", audiochan*audiores/8);
- devctl(ed, "hz %d", audiofreq);
-
- /* rename endpoint to #u/audio */
- devctl(ed, "name audio");
+ snprint(buf, sizeof buf, "%d.audio", audiodev->id);
+ postsharesrv(&fs, nil, "usb", buf);
exits(0);
}