Make usbaudio work for a few more devices (e.g Griffin iMic, some soundblasters, devices with mono-only input). Also make 'speed' settings for /dev/volume in Hz instead of percentage of the range, to be compatible with audio(3). (I noticed that ‘ls -m’ said I was the last person to modify this directory; I'm not sure what exactly I did. —btdn) Reference: /n/sources/patch/applied/usbaudio-imic Date: Sat Feb 3 22:28:14 CET 2007 Signed-off-by: miller@hamnavoe.com --- /sys/src/cmd/usb/audio/audiosub.c Fri Dec 8 11:34:30 2006 +++ /sys/src/cmd/usb/audio/audiosub.c Fri Dec 8 11:34:27 2006 @@ -8,8 +8,10 @@ Namelist terminal_types[] = { { 0x100, "USB Terminal, undefined type"}, { 0x101, "USB Streaming"}, + { 0x201, "Microphone"}, { 0x301, "Speaker"}, { 0x603, "Line connector"}, + { 0x605, "S/PDIF"}, { 0, nil } }; @@ -153,6 +155,9 @@ if (selectorid[u] >= 0) fprint(2, "Second selector (%d, %d) on %s\n", selectorid[u], b[3], u?"record":"playback"); selectorid[u] = b[3]; + controls[u][Selector_control].readable = 1; + controls[u][Selector_control].settable = 1; + controls[u][Selector_control].chans = 0; } } break; --- /sys/src/cmd/usb/audio/usbaudioctl.c Fri Dec 8 11:34:46 2006 +++ /sys/src/cmd/usb/audio/usbaudioctl.c Fri Dec 8 11:34:42 2006 @@ -197,24 +197,32 @@ buf[0] = speed; buf[1] = speed >> 8; buf[2] = speed >> 16; - if(setupcmd(ad->ep[0], RH2D|Rclass|Rendpt, SET_CUR, sampling_freq_control<<8, endpt[rec], buf, 3) < 0){ + n = endpt[rec]; + if (rec) + n |= 0x80; + if(setupcmd(ad->ep[0], RH2D|Rclass|Rendpt, SET_CUR, sampling_freq_control<<8, n, buf, 3) < 0){ fprint(2, "Error in setupcmd\n"); return Undef; } - if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, GET_CUR, sampling_freq_control<<8, endpt[rec], 3) < 0){ + if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, GET_CUR, sampling_freq_control<<8, n, 3) < 0){ fprint(2, "Error in setupreq\n"); return Undef; } n = setupreply(ad->ep[0], buf, 3); if (n != 3) fprint(2, "Error in setupreply: %d\n", n); - else if (buf[2]){ - if (debug & Dbgcontrol) - fprint(2, "Speed out of bounds %d (0x%x)\n", - buf[0] | buf[1] << 8 | buf[2] << 16, - buf[0] | buf[1] << 8 | buf[2] << 16); - }else - speed = buf[0] | buf[1] << 8 | buf[2] << 16; + else{ + n = buf[0] | buf[1] << 8 | buf[2] << 16; + if (buf[2] || n == 0){ + if (debug & Dbgcontrol) + fprint(2, "Speed out of bounds %d (0x%x)\n", n, n); + }else if (n != speed && ad->vid == 0x077d && (ad->did == 0x0223 || ad->did == 0x07af)){ + /* Griffin iMic responds incorrectly to sample rate inquiry */ + if (debug & Dbgcontrol) + fprint(2, " reported as %d (iMic bug?);", n); + }else + speed = n; + } if (debug & Dbgcontrol) fprint(2, " speed now %d Hz;", speed); } @@ -256,7 +264,7 @@ if (endpt[rec] < 0) sysfatal("endpt[%s] not set\n", rec?"Record":"Playback"); if(debug & Dbgcontrol) - fprint(2, "getspeed: curalt[%d] == %d\n", rec, endpt[rec]); + fprint(2, "getspeed: endpt[%d] == %d\n", rec, endpt[rec]); ep = ad->ep[endpt[rec]]; if (ep->iface == nil) sysfatal("no interface"); @@ -274,7 +282,10 @@ if (a->caps & has_setspeed){ if(debug & Dbgcontrol) fprint(2, "getspeed: has_setspeed, ask\n"); - if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, which, sampling_freq_control<<8, endpt[rec], 3) < 0) + n = endpt[rec]; + if (rec) + n |= 0x80; + if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, which, sampling_freq_control<<8, n, 3) < 0) return Undef; n = setupreply(ad->ep[0], buf, 3); if(n == 3){ @@ -411,8 +422,8 @@ break; case Selector_control: type = RH2D|Rclass|Rinterface; - control = ctl<<8; - index = selectorid[rec]; + control = 0; + index = selectorid[rec]<<8; break; case Channel_control: control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]); @@ -463,10 +474,11 @@ { byte buf[3]; int m, n, i; - int type, control, index, count; + int type, control, index, count, signedbyte; short svalue; count = 1; + signedbyte = 0; switch(ctl){ default: return Undef; @@ -488,22 +500,29 @@ case Delay_control: count = 2; /* fall through */ - case Mute_control: case Bass_control: case Mid_control: case Treble_control: case Equalizer_control: - case Agc_control: - case Bassboost_control: - case Loudness_control: + signedbyte = 1; type = RD2H|Rclass|Rinterface; control = ctl<<8; index = featureid[rec]<<8; break; case Selector_control: type = RD2H|Rclass|Rinterface; + control = 0; + index = selectorid[rec]<<8; + break; + case Mute_control: + case Agc_control: + case Bassboost_control: + case Loudness_control: + if (req != GET_CUR) + return Undef; + type = RD2H|Rclass|Rinterface; control = ctl<<8; - index = selectorid[rec]; + index = featureid[rec]<<8; break; } if (controls[rec][ctl].chans){ @@ -528,12 +547,15 @@ value[0] = svalue; break; case 1: + svalue = buf[0]; + if (signedbyte && (svalue&0x80)) + svalue |= 0xFF00; if (req == GET_CUR){ - value[i] = buf[0]; - value[0] += buf[0]; + value[i] = svalue; + value[0] += svalue; m++; }else - value[0] = buf[0]; + value[0] = svalue; } } } @@ -552,7 +574,10 @@ value[0] = svalue; break; case 1: - value[0] = buf[0]; + svalue = buf[0]; + if (signedbyte && (svalue&0x80)) + svalue |= 0xFF00; + value[0] = svalue; } return 0; } --- /sys/src/cmd/usb/audio/audiofs.c Fri Dec 8 11:35:04 2006 +++ /sys/src/cmd/usb/audio/audiofs.c Fri Dec 8 11:35:00 2006 @@ -720,7 +720,7 @@ if (debug) fprint(2, "bad3\n"); return Ebadctl; } - if (f->dir == &dirs[Qvolume] && c->min != Undef && c->max != Undef){ + if (f->dir == &dirs[Qvolume] && ctl != Speed_control && c->min != Undef && c->max != Undef){ nnf = tokenize(fields[nf-1], subfields, nelem(subfields)); if (nnf <= 0 || nnf > 8){ if (debug) fprint(2, "bad4\n"); --- /sys/src/cmd/usb/audio/usbaudio.c Fri Dec 8 11:35:24 2006 +++ /sys/src/cmd/usb/audio/usbaudio.c Fri Dec 8 11:35:20 2006 @@ -354,15 +354,22 @@ if (endpt[Record] >= 0){ if(verbose) fprint(2, "Setting default record parameters: %d Hz, %d channels at %d bits\n", - defaultspeed[Play], 2, 16); - if(findalt(Record, 2, 16, defaultspeed[Record]) < 0){ - if(findalt(Record, 2, 16, 48000) < 0) + 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; + continue; + } + if(findalt(Record, i, 16, 48000) < 0) sysfatal("Can't configure record for %d or %d Hz", defaultspeed[Record], 48000); fprint(2, "Warning, can't configure record for %d Hz, configuring for %d Hz instead\n", defaultspeed[Record], 48000); defaultspeed[Record] = 48000; + break; } - value[0] = 2; + value[0] = i; if (setcontrol(Record, "channels", value) == Undef) sysfatal("Can't set record channels\n"); value[0] = 16; --- /sys/man/4/usb Fri Dec 8 11:35:44 2006 +++ /sys/man/4/usb Fri Dec 8 11:35:42 2006 @@ -108,7 +108,8 @@ .PP This file can be written using the same syntax. The keyword .I out -may be omitted. Settings are given as percentages of the range. +may be omitted. Settings are given as percentages of the range, +except for speed which is in Hz. .PP The file .B audioctl