123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * USB audio driver for Plan 9
- * This needs a full rewrite.
- * As it is, it does not check for all errors,
- * mixes the audio data structures with the usb configuration,
- * may cross nil pointers, and is hard to debug and fix.
- * Also, it does not issue a dettach request to the endpoint
- * after the device is unplugged. This means that the old
- * endpoint would still be around until manually reclaimed.
- */
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include <usb/usb.h>
- #include <usb/audio.h>
- #include <usb/audioctl.h>
- #define STACKSIZE 16*1024
- extern char* srvpost;
- char * mntpt;
- Channel *controlchan;
- int verbose;
- int setrec = 0;
- int defaultspeed[2] = {44100, 44100};
- Dev *buttondev;
- Dev *epdev[2];
- static void
- audio_endpoint(Dev *_, Desc *dd)
- {
- byte *b = (uint8_t*)&dd->data;
- int n = dd->data.bLength;
- char *hd;
- switch(b[2]){
- case 0x01:
- if(usbdebug){
- fprint(2, "CS_ENDPOINT for attributes 0x%x, lockdelayunits %d, lockdelay %#x, ",
- b[3], b[4], b[5] | (b[6]<<8));
- if(b[3] & has_setspeed)
- fprint(2, "has sampling-frequency control");
- else
- fprint(2, "does not have sampling-frequency control");
- if(b[3] & 0x1<<1)
- fprint(2, ", has pitch control");
- else
- fprint(2, ", does not have pitch control");
- if(b[3] & 0x1<<7)
- fprint(2, ", max packets only");
- fprint(2, "\n");
- }
- if(dd->conf == nil)
- sysfatal("conf == nil");
- if(dd->iface == nil)
- sysfatal("iface == nil");
- if(dd->altc == nil)
- sysfatal("alt == nil");
- if(dd->altc->aux == nil)
- dd->altc->aux= mallocz(sizeof(Audioalt),1);
- ((Audioalt*)dd->altc->aux)->caps |= b[3];
- break;
- case 0x02:
- if(usbdebug){
- fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ",
- b[3], b[4], b[5], b[6], b[7]);
- fprint(2, "freq0 %d, freq1 %d\n",
- b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16));
- }
- break;
- default:
- if(usbdebug){
- hd = hexstr(b, n);
- fprint(2, "CS_INTERFACE: %s\n", hd);
- free(hd);
- }
- }
- }
- enum {
- None,
- Volumeset,
- Volumeget,
- Altset,
- Altget,
- Speedget,
- };
- void
- controlproc(void *_)
- {
- /* Proc that looks after /dev/usb/%d/ctl */
- int i, nf;
- char *req, *args[8];
- Audiocontrol *c;
- int32_t value[8];
- Channel *replchan;
- while((req = recvp(controlchan)) != nil){
- int rec;
- nf = tokenize(req, args, nelem(args));
- if(nf < 3)
- sysfatal("controlproc: not enough arguments");
- replchan = (Channel*)strtoll(args[0], nil, 0);
- if(strcmp(args[2], "playback") == 0)
- rec = Play;
- else if(strcmp(args[2], "record") == 0)
- rec = Record;
- else{
- /* illegal request */
- dprint(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 = nil;
- for(i = 0; i < Ncontrol; i++){
- c = &controls[rec][i];
- if(strcmp(args[1], c->name) == 0)
- break;
- }
- if(i == Ncontrol){
- dprint(2, "Illegal control name: %s", args[1]);
- if(replchan) chanprint(replchan, "Illegal control name: %s", args[1]);
- }else if(!c->settable){
- dprint(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){
- dprint(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{
- dprint(2, "controlproc: setcontrol %s %s %s\n",
- rec?"in":"out", args[1], args[3]);
- if(setcontrol(rec, 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 *_)
- {
- int i, fd, b;
- char err[32];
- byte buf[1];
- Audiocontrol *c;
- fd = buttondev->dfd;
- c = &controls[Play][Volume_control];
- for(;;){
- if((b = read(fd, buf, 1)) < 0){
- rerrstr(err, sizeof err);
- if(strcmp(err, "interrupted") == 0){
- dprint(2, "read interrupted\n");
- continue;
- }
- sysfatal("read %s/data: %r", buttondev->dir);
- }
- 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(usbdebug){
- fprint(2, "button");
- for(i = 0; i < b; i++)
- fprint(2, " %#2.2x", buf[i]);
- fprint(2, "\n");
- }
- }
- }
- void
- usage(void)
- {
- fprint(2, "usage: usbaudio [-dpV] [-N nb] [-m mountpoint] [-s srvname] "
- "[-v volume] [dev]\n");
- threadexitsall("usage");
- }
- void
- threadmain(int argc, char **argv)
- {
- char *devdir;
- int i;
- int32_t value[8], volume[8];
- Audiocontrol *c;
- char *p;
- extern int attachok;
- Ep *ep;
- int csps[] = { Audiocsp, 0};
- devdir = nil;
- volume[0] = Undef;
- for(i = 0; i<8; i++)
- value[i] = 0;
- fmtinstall('A', Aconv);
- fmtinstall('U', Ufmt);
- quotefmtinstall();
- ARGBEGIN{
- case 'N':
- p = EARGF(usage()); /* ignore dev nb */
- break;
- case 'd':
- usbdebug++;
- verbose++;
- break;
- case 'm':
- mntpt = EARGF(usage());
- break;
- case 'p':
- attachok++;
- break;
- case 's':
- srvpost = EARGF(usage());
- break;
- case 'v':
- volume[0] = strtol(EARGF(usage()), &p, 0);
- for(i = 1; i < 8; i++)
- volume[i] = volume[0];
- break;
- case 'V':
- verbose++;
- break;
- default:
- usage();
- }ARGEND
- switch(argc){
- case 0:
- break;
- case 1:
- devdir = argv[0];
- break;
- default:
- usage();
- }
- if(devdir == nil)
- if(finddevs(matchdevcsp, csps, &devdir, 1) < 1){
- fprint(2, "No usb audio\n");
- threadexitsall("usbaudio not found");
- }
- ad = opendev(devdir);
- if(ad == nil)
- sysfatal("opendev: %r");
- if(configdev(ad) < 0)
- sysfatal("configdev: %r");
- for(i = 0; i < nelem(ad->usb->ddesc); i++)
- if(ad->usb->ddesc[i] != nil)
- switch(ad->usb->ddesc[i]->data.bDescriptorType){
- case AUDIO_INTERFACE:
- audio_interface(ad, ad->usb->ddesc[i]);
- break;
- case AUDIO_ENDPOINT:
- audio_endpoint(ad, ad->usb->ddesc[i]);
- break;
- }
- controlchan = chancreate(sizeof(char*), 8);
- for(i = 0; i < nelem(ad->usb->ep); i++)
- if((ep = ad->usb->ep[i]) != nil){
- if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Eout)
- endpt[0] = ep->id;
- if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Ein)
- endpt[1] = ep->id;
- if(buttonendpt<0 && Class(ep->iface->csp) == Clhid)
- buttonendpt = ep->id;
- }
- if(endpt[0] != -1){
- if(verbose)
- fprint(2, "usb/audio: playback on ep %d\n", endpt[0]);
- interface[0] = ad->usb->ep[endpt[0]]->iface->id;
- }
- if(endpt[1] != -1){
- if(verbose)
- fprint(2, "usb/audio: record on ep %d\n", endpt[0]);
- interface[1] = ad->usb->ep[endpt[1]]->iface->id;
- }
- if(verbose && buttonendpt >= 0)
- fprint(2, "usb/audio: buttons on ep %d\n", buttonendpt);
- if(endpt[Play] >= 0){
- if(verbose)
- fprint(2, "Setting default play parameters: %d Hz, %d channels at %d bits\n",
- defaultspeed[Play], 2, 16);
- if(findalt(Play, 2, 16, defaultspeed[Play]) < 0){
- if(findalt(Play, 2, 16, 48000) < 0)
- sysfatal("Can't configure playout for %d or %d Hz", defaultspeed[Play], 48000);
- fprint(2, "Warning, can't configure playout for %d Hz, configuring for %d Hz instead\n",
- defaultspeed[Play], 48000);
- defaultspeed[Play] = 48000;
- }
- value[0] = 2;
- if(setcontrol(Play, "channels", value) == Undef)
- sysfatal("Can't set play channels");
- value[0] = 16;
- if(setcontrol(Play, "resolution", value) == Undef)
- sysfatal("Can't set play resolution");
- }
- if(endpt[Record] >= 0){
- setrec = 1;
- if(verbose)
- fprint(2, "Setting default record parameters: "
- "%d Hz, %d channels at %d bits\n",
- defaultspeed[Record], 2, 16);
- i = 2;
- while(findalt(Record, i, 16, defaultspeed[Record]) < 0)
- if(i == 2 && controls[Record][Channel_control].max == 1){
- fprint(2, "Warning, can't configure stereo "
- "recording, configuring mono instead\n");
- i = 1;
- }else
- break;
- if(findalt(Record, i, 16, 48000) < 0){
- endpt[Record] = -1; /* disable recording */
- setrec = 0;
- fprint(2, "Warning, can't configure record for %d Hz or %d Hz\n",
- defaultspeed[Record], 48000);
- }else
- fprint(2, "Warning, can't configure record for %d Hz, "
- "configuring for %d Hz instead\n",
- defaultspeed[Record], 48000);
- defaultspeed[Record] = 48000;
- if(setrec){
- value[0] = i;
- if(setcontrol(Record, "channels", value) == Undef)
- sysfatal("Can't set record channels");
- value[0] = 16;
- if(setcontrol(Record, "resolution", value) == Undef)
- sysfatal("Can't set record resolution");
- }
- }
- getcontrols(); /* Get the initial value of all controls */
- value[0] = defaultspeed[Play];
- if(endpt[Play] >= 0 && setcontrol(Play, "speed", value) < 0)
- sysfatal("can't set play speed");
- value[0] = defaultspeed[Record];
- if(endpt[Record] >= 0 && setcontrol(Record, "speed", value) < 0)
- fprint(2, "%s: can't set record speed\n", argv0);
- value[0] = 0;
- setcontrol(Play, "mute", value);
- if(volume[0] != Undef){
- c = &controls[Play][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(Play, "volume", volume);
- c = &controls[Record][Volume_control];
- if(c->settable && setrec)
- setcontrol(Record, "volume", volume);
- }
- if(buttonendpt > 0){
- buttondev = openep(ad, buttonendpt);
- if(buttondev == nil)
- sysfatal("openep: buttons: %r");
- if(opendevdata(buttondev, OREAD) < 0)
- sysfatal("open buttons fd: %r");
- proccreate(buttonproc, nil, STACKSIZE);
- }
- proccreate(controlproc, nil, STACKSIZE);
- proccreate(serve, nil, STACKSIZE);
- threadexits(nil);
- }
|