123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include "usb.h"
- #include "usbproto.h"
- #include "dat.h"
- #include "fns.h"
- #include "audioclass.h"
- #define STACKSIZE 16*1024
- extern char *srvpost;
- char * mntpt;
- int debug;
- int debugdebug;
- int verbose;
- Channel *controlchan;
- char audstr[] = "Enabled 0x000101\n"; /* audio.control.0 */
- Nexus *nexushd;
- Nexus *nexustl;
- void
- makenexus(Audiofunc *af, Funcalt *alt, Unit *output)
- {
- int i, ch;
- Nexus *nx;
- Unit *u, *feat;
- static int idgen;
- Audiocontrol *c;
- Stream *ins, *outs;
- nx = emallocz(sizeof(Nexus), 1);
- nx->af = af;
- nx->alt = alt;
- nx->output = output;
- nx->id = idgen++;
- for(u = output; u != nil; u = u->source[0]) {
- switch(u->type) {
- case INPUT_TERMINAL:
- nx->input = u;
- break;
- case MIXER_UNIT:
- nx->mixer = u;
- break;
- case FEATURE_UNIT:
- nx->feat = u;
- break;
- }
- if(u->nsource == 0)
- break;
- }
- if(nx->input == nil) {
- free(nx);
- return;
- }
- ins = nx->output->stream;
- outs = nx->input->stream;
- if(ins == nil && outs == nil || ins != nil && outs != nil) {
- free(nx);
- return;
- }
- if(ins != nil) {
- nx->s = ins;
- nx->dir = Nin;
- }
- else {
- nx->s = outs;
- nx->dir = Nout;
- }
- memset(nx->control, 0, sizeof(nx->control));
- for(i = 0; i < Ncontrol; i++) {
- c = &nx->control[i];
- c->step = Undef;
- }
- calcbounds(nx);
- feat = nx->feat;
- if(feat != nil) {
- for(i = Mute_control; i < Mixer_control; i++) {
- c = &nx->control[i];
- for(ch = 0; ch <= feat->nchan; ch++) {
- if((feat->hascontrol[ch] & (1<<(i-1))) == 0)
- continue;
- c->readable = 1;
- c->settable = 1;
- if(ch > 0)
- c->chans |= (1<<ch);
- }
- }
- }
- feat = nx->mixer;
- if(feat != nil) {
- c = &nx->control[Mixer_control];
- for(ch = 1; ch <= feat->nchan; ch++) {
- if((feat->hascontrol[((ch-1)*feat->nsource)>>5] & (1 << (((ch-1)*feat->nsource) & 31))) == 0)
- continue;
- c->readable = 1;
- c->settable = 1;
- c->chans |= (1<<ch);
- }
- }
- if(nexushd == nil)
- nexushd = nx;
- else
- nexustl->next = nx;
- nexustl = nx;
- }
- int
- adddevice(Device *d)
- {
- int i;
- Unit *u;
- Dconf *c;
- Dinf *intf;
- ulong csp;
- Audiofunc *af;
- if(d->nconf < 1)
- sysfatal("no configurations???");
- /* we only handle first config for now -- most devices only have 1 anyway */
- c = &d->config[0];
- for(i = 0; i < c->nif; i++) {
- intf = &c->iface[i];
- if(intf == nil)
- continue;
- csp = intf->csp;
- if(Class(csp) == CL_AUDIO && Subclass(csp) == AUDIOCONTROL) {
- if((af = getaudiofunc(intf)) == nil)
- return -1;
- if(debug)
- dumpaudiofunc(af);
- for(u = af->falt->unit; u != nil; u = u->next)
- if(u->type == OUTPUT_TERMINAL)
- makenexus(af, af->falt, u);
- }
- if(Class(csp) == CL_HID && Subclass(csp) == 0) {
- if (verbose)
- fprint(2, "Buttons on endpoint %d\n", i);
- if(intf->alt->npt == 1)
- buttonendpt = intf->alt->ep[0].addr;
- }
- }
- return 0;
- }
- void
- controlproc(void *)
- {
- /* Proc that looks after /dev/usb/%d/ctl */
- int nf;
- Nexus *nx;
- long value[8];
- Audiocontrol *c;
- char *req, *args[8];
- Channel *replchan;
- while(req = recvp(controlchan)) {
- nf = tokenize(req, args, nelem(args));
- if (nf < 3)
- sysfatal("controlproc: not enough arguments");
- replchan = (Channel*)strtol(args[0], nil, 0);
- nx = findnexus(args[2]);
- if(nx == nil) {
- /* illegal request */
- if (debug) fprint(2, "%s must be record or playback", args[2]);
- if (replchan) chanprint(replchan, "%s must be record or playback", args[2]);
- free(req);
- continue;
- }
- c = findcontrol(nx, args[1]);
- if (c == nil){
- if (debug) fprint(2, "Illegal control name: %s", args[1]);
- if (replchan) chanprint(replchan, "Illegal control name: %s", args[1]);
- }else if (!c->settable){
- if (debug & Dbginfo) fprint(2, "%s %s is not settable", args[1], args[2]);
- if (replchan)
- chanprint(replchan, "%s %s is not settable", args[1], args[2]);
- }else if (nf < 4){
- if (debug & Dbginfo) fprint(2, "insufficient arguments for %s %s",
- args[1], args[2]);
- if (replchan)
- chanprint(replchan, "insufficient arguments for %s %s",
- args[1], args[2]);
- }else if (ctlparse(args[3], c, value) < 0) {
- if (replchan)
- chanprint(replchan, "parse error in %s %s", args[1], args[2]);
- } else {
- if (debug & Dbginfo)
- fprint(2, "controlproc: setcontrol %s %s %s\n", nx->name, args[1], args[3]);
- if (setcontrol(nx, args[1], value) < 0){
- if (replchan)
- chanprint(replchan, "setting %s %s failed", args[1], args[2]);
- }else{
- if (replchan) chanprint(replchan, "ok");
- }
- ctlevent();
- }
- free(req);
- }
- }
- void
- buttonproc(void *x)
- {
- int i, fd, b;
- Device *d;
- uchar buf[1];
- Audiocontrol *c;
- char fname[64], err[32];
- d = x;
- sprint(fname, "/dev/usb%d/%d/ep%ddata", d->ctlrno, d->id, buttonendpt);
- if (debug & Dbginfo) fprint(2, "buttonproc opening %s\n", fname);
- if ((fd = open(fname, OREAD)) < 0)
- sysfatal("Can't open %s: %r", fname);
- c = &nexus[Play]->control[Volume_control];
- for (;;) {
- if ((b = read(fd, buf, 1)) < 0){
- rerrstr(err, sizeof err);
- if (strcmp(err, "interrupted") == 0){
- if (debug & Dbginfo) fprint(2, "read interrupted\n");
- continue;
- }
- sysfatal("read %s: %r", fname);
- }
- if (b == 0 || buf[0] == 0){
- continue;
- }else if (buf[0] == 1){
- if (c->chans == 0)
- c->value[0] += c->step;
- else
- for (i = 1; i < 8; i++)
- if (c->chans & 1 << i)
- c->value[i] += c->step;
- chanprint(controlchan, "0 volume playback %A", c);
- }else if (buf[0] == 2){
- if (c->chans == 0)
- c->value[0] -= c->step;
- else
- for (i = 1; i < 8; i++)
- if (c->chans & 1 << i)
- c->value[i] -= c->step;
- chanprint(controlchan, "0 volume playback %A", c);
- }else if (debug & Dbginfo){
- fprint(2, "button");
- for (i = 0; i < b; i++)
- fprint(2, " %#2.2x", buf[i]);
- fprint(2, "\n");
- }
- }
- }
- void
- findendpoints(void)
- {
- Nexus *nx;
- for(nx = nexushd; nx != nil; nx = nx->next) {
- switch(nx->dir) {
- case Nin:
- nx->name = "record";
- nexus[Record] = nx;
- break;
- case Nout:
- nx->name = "play";
- nexus[Play] = nx;
- break;
- }
- }
- }
- void
- usage(void)
- {
- fprint(2, "usage: usbaudio [-d] [-v volume[%%]] [-s srvname] [-m mountpoint] [ctrlno id]\n");
- threadexitsall("usage");
- }
- void
- threadmain(int argc, char **argv)
- {
- Device *d;
- Nexus *nx;
- long value[8];
- long volume[8];
- Audiocontrol *c;
- int ctlrno, id, i, sfd;
- char buf[32], *p, line[256];
- ctlrno = -1;
- id = -1;
- volume[0] = Undef;
- for (i = 0; i<8; i++)
- value[i] = 0;
- fmtinstall('A', Aconv);
- quotefmtinstall();
- usbfmtinit();
- ARGBEGIN{
- case 'd':
- debug = strtol(ARGF(), nil, 0);
- if (debug == -1) debugdebug++;
- verbose++;
- break;
- case 'v':
- volume[0] = strtol(ARGF(), &p, 0);
- for(i = 1; i < 8; i++)
- volume[i] = volume[0];
- break;
- case 'm':
- mntpt = ARGF();
- break;
- case 's':
- srvpost = ARGF();
- break;
- default:
- usage();
- }ARGEND
- switch (argc) {
- case 0:
- for (ctlrno = 0; ctlrno < 16; ctlrno++) {
- for (i = 1; i < 128; i++) {
- sprint(buf, "/dev/usb%d/%d/status", ctlrno, i);
- sfd = open(buf, OREAD);
- if (sfd < 0)
- break;
- if (read(sfd, line, strlen(audstr)) == strlen(audstr)
- && strncmp(audstr, line, strlen(audstr)) == 0) {
- id = i;
- goto found;
- }
- close(sfd);
- }
- }
- if (verbose) fprint(2, "No usb audio\n");
- threadexitsall("usbaudio not found");
- found:
- break;
- case 2:
- ctlrno = atoi(argv[0]);
- id = atoi(argv[1]);
- break;
- default:
- usage();
- }
- d = opendev(ctlrno, id);
- if(describedevice(d) < 0)
- sysfatal("usbaudio: %r");
- if(adddevice(d) < 0)
- sysfatal("usbaudio: adddevice: %r");
- controlchan = chancreate(sizeof(char*), 8);
- findendpoints();
- nx = nexus[Play];
- if(nx != nil) {
- value[0] = 2;
- if(setcontrol(nx, "channels", value) == Undef)
- sysfatal("Can't set play channels");
- value[0] = 16;
- if(setcontrol(nx, "resolution", value) == Undef)
- sysfatal("Can't set play resolution");
- getcontrols(nx); /* Get the initial value of all controls */
- value[0] = 44100;
- if(setcontrol(nx, "speed", value) < 0){
- fprint(2, "warning: Can't set play speed to %d\n", value[0]);
- value[0] = 48000;
- if(setcontrol(nx, "speed", value) < 0)
- fprint(2, "warning: Can't set play speed to %d\n", value[0]);
- else
- fprint(2, "warning: Play speed set to %d\n", value[0]);
- }
- value[0] = 0;
- setcontrol(nx, "mute", value);
- if(volume[0] != Undef) {
- c = &nx->control[Volume_control];
- if(*p == '%' && c->min != Undef)
- for (i = 0; i < 8; i++)
- volume[i] = (volume[i]*c->max + (100-volume[i])*c->min)/100;
- if(c->settable)
- setcontrol(nx, "volume", volume);
- }
- }
- nx = nexus[Record];
- if(nx != nil) {
- value[0] = 2;
- if(setcontrol(nx, "channels", value) == Undef)
- sysfatal("Can't set record channels");
- value[0] = 16;
- if(setcontrol(nx, "resolution", value) == Undef)
- sysfatal("Can't set record resolution");
- getcontrols(nx); /* Get the initial value of all controls */
- value[0] = 44100;
- if(setcontrol(nx, "speed", value) < 0)
- fprint(2, "Can't set record speed\n");
- if(volume[0] != Undef) {
- c = &nx->control[Volume_control];
- if(c->settable)
- setcontrol(nx, "volume", volume);
- }
- }
- nx = nexus[Play];
- if(buttonendpt > 0 && nx != nil) {
- sprint(buf, "ep %d bulk r 1 1", buttonendpt);
- if(debug) fprint(2, "sending `%s' to /dev/usb/%d/ctl\n", buf, id);
- if(write(d->ctl, buf, strlen(buf)) > 0)
- proccreate(buttonproc, nx->s->intf->d, STACKSIZE);
- else
- fprint(2, "Could not configure button endpoint: %r\n");
- }
- proccreate(controlproc, nil, STACKSIZE);
- proccreate(serve, nil, STACKSIZE);
- threadexits(nil);
- }
|