#include #include #include #include "usb.h" #include "usbaudio.h" #include "usbaudioctl.h" int endpt[2] = {-1, -1}; int interface[2] = {-1, -1}; int featureid[2] = {-1, -1}; int selectorid[2] = {-1, -1}; int mixerid[2] = {-1, -1}; int curalt[2] = {-1, -1}; int buttonendpt = -1; int id; Device *ad; Audiocontrol controls[2][Ncontrol] = { { [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, [Mid_control] = { "mid", 0, {0}, 0, 0, Undef}, [Treble_control] = { "treble", 0, {0}, 0, 0, Undef}, [Equalizer_control] = { "equalizer", 0, {0}, 0, 0, Undef}, [Agc_control] = { "agc", 0, {0}, 0, 0, Undef}, [Delay_control] = { "delay", 0, {0}, 0, 0, Undef}, [Bassboost_control] = { "bassboost", 0, {0}, 0, 0, Undef}, [Loudness_control] = { "loudness", 0, {0}, 0, 0, Undef}, [Channel_control] = { "channels", 0, {0}, 0, 2, Undef}, [Resolution_control] = { "resolution", 0, {0}, 0, 16, Undef}, // [Selector_control] = { "selector", 0, {0}, 0, 0, Undef}, }, { [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, [Mid_control] = { "mid", 0, {0}, 0, 0, Undef}, [Treble_control] = { "treble", 0, {0}, 0, 0, Undef}, [Equalizer_control] = { "equalizer", 0, {0}, 0, 0, Undef}, [Agc_control] = { "agc", 0, {0}, 0, 0, Undef}, [Delay_control] = { "delay", 0, {0}, 0, 0, Undef}, [Bassboost_control] = { "bassboost", 0, {0}, 0, 0, Undef}, [Loudness_control] = { "loudness", 0, {0}, 0, 0, Undef}, [Channel_control] = { "channels", 0, {0}, 0, 2, Undef}, [Resolution_control] = { "resolution", 0, {0}, 0, 16, Undef}, // [Selector_control] = { "selector", 0, {0}, 0, 0, Undef}, } }; int setaudioalt(int rec, Audiocontrol *c, int control) { if (debug & Dbgcontrol) fprint(2, "setcontrol %s: Set alt %d\n", c->name, control); curalt[rec] = control; if (setupcmd(ad->ep[0], RH2D|Rstandard|Rinterface, SET_INTERFACE, control, interface[rec], nil, 0) < 0){ if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n", c->name); return -1; } return control; } int findalt(int rec, int nchan, int res, int speed) { Endpt *ep; Audioalt *a; Dalt *da; int i, j, k, retval; retval = -1; controls[rec][Channel_control].min = 1000000; controls[rec][Channel_control].max = 0; controls[rec][Channel_control].step = Undef; controls[rec][Resolution_control].min = 1000000; controls[rec][Resolution_control].max = 0; controls[rec][Resolution_control].step = Undef; for (i = 0; i < Nendpt; i++) { if ((ep = ad->ep[i]) == nil) continue; if(ep->csp != CSP(CL_AUDIO, 2, 0)) continue; if (ep->iface == nil) { fprint(2, "\tno interface\n"); return 0; } if ((rec == Play && (ep->addr & 0x80)) || (rec == Record && (ep->addr & 0x80) == 0)) continue; for (j = 0; j < 16; j++) { if ((da = ep->iface->dalt[j]) == nil || (a = da->devspec) == nil) continue; if (a->nchan < controls[rec][Channel_control].min) controls[rec][Channel_control].min = a->nchan; if (a->nchan > controls[rec][Channel_control].max) controls[rec][Channel_control].max = a->nchan; if (a->res < controls[rec][Resolution_control].min) controls[rec][Resolution_control].min = a->res; if (a->res > controls[rec][Resolution_control].max) controls[rec][Resolution_control].max = a->res; controls[rec][Channel_control].settable = 1; controls[rec][Channel_control].readable = 1; controls[rec][Resolution_control].settable = 1; controls[rec][Resolution_control].readable = 1; controls[rec][Speed_control].settable = 1; controls[rec][Speed_control].readable = 1; if (a->nchan == nchan && a->res == res){ if(speed == Undef) retval = j; else if(a->caps & (has_discfreq|onefreq)){ for(k = 0; k < nelem(a->freqs); k++){ if(a->freqs[k] == speed){ retval = j; break; } } } else { if(speed >= a->minfreq && speed <= a->maxfreq) retval = j; } } } } if ((debug & Dbgcontrol) && retval < 0){ fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed); } return retval; } int setspeed(int rec, int speed) { int ps, n, no, dist, i; Audioalt *a; Dalt *da; Endpt *ep; char cmdbuf[32]; uchar buf[3]; if (curalt[rec] < 0){ fprint(2, "Must set channels and resolution before speed\n"); return Undef; } if (endpt[rec] < 0) sysfatal("endpt[%s] not set\n", rec?"Record":"Playback"); ep = ad->ep[endpt[rec]]; if (ep->iface == nil) sysfatal("no interface"); if (curalt[rec] < 0) sysfatal("curalt[%s] not set\n", rec?"Record":"Playback"); da = ep->iface->dalt[curalt[rec]]; a = da->devspec; if (a->caps & onefreq){ if (debug & Dbgcontrol) fprint(2, "setspeed %d: onefreq\n", speed); speed = a->freqs[0]; /* speed not settable, but packet size must still be set */ }else if (a->caps & has_contfreq){ if (debug & Dbgcontrol) fprint(2, "setspeed %d: contfreq\n", speed); if (speed < a->minfreq) speed = a->minfreq; else if (speed > a->maxfreq) speed = a->maxfreq; if (debug & Dbgcontrol) fprint(2, "Setting continuously variable %s speed to %d\n", rec?"record":"playback", speed); }else if (a->caps & has_discfreq){ if (debug & Dbgcontrol) fprint(2, "setspeed %d: discfreq\n", speed); dist = 1000000; no = -1; for (i = 0; a->freqs[i] > 0; i++) if (abs(a->freqs[i] - speed) < dist){ dist = abs(a->freqs[i] - speed); no = i; } if (no == -1){ if (debug & Dbgcontrol) fprint(2, "no = -1\n"); return Undef; } speed = a->freqs[no]; if (debug & Dbgcontrol) fprint(2, "Setting discreetly variable %s speed to %d\n", rec?"record":"playback", speed); }else{ if (debug & Dbgcontrol) fprint(2, "can't happen\n?"); return Undef; } if (a->caps & has_setspeed){ if (debug & Dbgcontrol) fprint(2, "Setting %s speed to %d Hz;", rec?"record":"playback", speed); 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){ 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){ 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; if (debug & Dbgcontrol) fprint(2, " speed now %d Hz;", speed); } ps = ((speed * da->interval + 999) / 1000) * controls[rec][Channel_control].value[0] * controls[rec][Resolution_control].value[0]/8; if(ps > ep->maxpkt){ fprint(2, "packet size %d > maximum packet size %d\n", ps, ep->maxpkt); return Undef; } if (debug & Dbgcontrol) fprint(2, "Configuring %s endpoint for %d Hz\n", rec?"record":"playback", speed); sprint(cmdbuf, "ep %d %d %c %ld %d", endpt[rec], da->interval, rec?'r':'w', controls[rec][Channel_control].value[0]*controls[rec][Resolution_control].value[0]/8, speed); if (write(ad->ctl, cmdbuf, strlen(cmdbuf)) != strlen(cmdbuf)){ fprint(2, "writing %s to #U/usb/%d/ctl: %r\n", cmdbuf, id); return Undef; } if (debug & Dbgcontrol) fprint(2, "sent `%s' to /dev/usb/%d/ctl\n", cmdbuf, id); return speed; } long getspeed(int rec, int which) { int i, n; Audioalt *a; Dalt *da; Endpt *ep; uchar buf[3]; if (curalt[rec] < 0){ fprint(2, "Must set channels and resolution before getspeed\n"); return Undef; } 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]); ep = ad->ep[endpt[rec]]; if (ep->iface == nil) sysfatal("no interface"); if (curalt[rec] < 0) sysfatal("curalt[%s] not set\n", rec?"Record":"Playback"); da = ep->iface->dalt[curalt[rec]]; a = da->devspec; if (a->caps & onefreq){ if(debug & Dbgcontrol) fprint(2, "getspeed: onefreq\n"); if (which == GET_RES) return Undef; return a->freqs[0]; /* speed not settable */ } 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) return Undef; n = setupreply(ad->ep[0], buf, 3); if(n == 3){ if(buf[2]){ if (debug & Dbgcontrol) fprint(2, "Speed out of bounds\n"); if ((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8) return a->freqs[buf[0] | buf[1] << 8]; } return buf[0] | buf[1] << 8 | buf[2] << 16; } if(debug & Dbgcontrol) fprint(2, "getspeed: n = %d\n", n); } if (a->caps & has_contfreq){ if(debug & Dbgcontrol) fprint(2, "getspeed: has_contfreq\n"); if (which == GET_CUR) return controls[rec][Speed_control].value[0]; if (which == GET_MIN) return a->minfreq; if (which == GET_MAX) return a->maxfreq; if (which == GET_RES) return 1; } if (a->caps & has_discfreq){ if(debug & Dbgcontrol) fprint(2, "getspeed: has_discfreq\n"); if (which == GET_CUR) return controls[rec][Speed_control].value[0]; if (which == GET_MIN) return a->freqs[0]; for (i = 0; i < 8 && a->freqs[i] > 0; i++) ; if (which == GET_MAX) return a->freqs[i-1]; if (which == GET_RES) return Undef; } if (debug & Dbgcontrol) fprint(2, "can't happen\n?"); return Undef; } int setcontrol(int rec, char *name, long *value) { int i, ctl, m; byte buf[3]; int type, req, control, index, count; Audiocontrol *c; c = nil; for (ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; if (strcmp(name, c->name) == 0) break; } if (ctl == Ncontrol){ if (debug & Dbgcontrol) fprint(2, "setcontrol: control not found\n"); return -1; } if (c->settable == 0) { if (debug & Dbgcontrol) fprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl); if (c->chans){ for (i = 0; i < 8; i++) if ((c->chans & 1 << i) && c->value[i] != value[i]) return -1; return 0; } if (c->value[0] != value[0]) return -1; return 0; } if (c->chans){ value[0] = 0; // set to average m = 0; for (i = 1; i < 8; i++) if (c->chans & 1 << i){ if (c->min != Undef && value[i] < c->min) value[i] = c->min; if (c->max != Undef && value[i] > c->max) value[i] = c->max; value[0] += value[i]; m++; } else value[i] = Undef; if (m) value[0] /= m; }else{ if (c->min != Undef && value[0] < c->min) value[0] = c->min; if (c->max != Undef && value[0] > c->max) value[0] = c->max; } req = SET_CUR; count = 1; switch(ctl){ default: if (debug & Dbgcontrol) fprint(2, "setcontrol: can't happen\n"); return -1; case Speed_control: if ((value[0] = setspeed(rec, value[0])) < 0) return -1; c->value[0] = value[0]; return 0; case Equalizer_control: /* not implemented */ return -1; case Resolution_control: control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]); if(control < 0 || setaudioalt(rec, c, control) < 0){ if (debug & Dbgcontrol) fprint(2, "setcontrol: can't find setting for %s\n", c->name); return -1; } c->value[0] = value[0]; controls[rec][Speed_control].value[0] = defaultspeed[rec]; return 0; case Volume_control: case Delay_control: count = 2; /* fall through */ case Mute_control: case Bass_control: case Mid_control: case Treble_control: case Agc_control: case Bassboost_control: case Loudness_control: type = RH2D|Rclass|Rinterface; control = ctl<<8; index = featureid[rec]<<8; break; case Selector_control: type = RH2D|Rclass|Rinterface; control = ctl<<8; index = selectorid[rec]; break; case Channel_control: control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]); if(control < 0 || setaudioalt(rec, c, control) < 0){ if (debug & Dbgcontrol) fprint(2, "setcontrol: can't find setting for %s\n", c->name); return -1; } c->value[0] = value[0]; controls[rec][Speed_control].value[0] = defaultspeed[rec]; return 0; } if(c->chans){ for (i = 1; i < 8; i++) if (c->chans & 1 << i){ switch(count){ case 2: buf[1] = value[i] >> 8; case 1: buf[0] = value[i]; } if (setupcmd(ad->ep[0], type, req, control | i, index, buf, count) < 0){ if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n", controls[rec][ctl].name); return -1; } c->value[i] = value[i]; } }else{ switch(count){ case 2: buf[1] = value[0] >> 8; case 1: buf[0] = value[0]; } if (setupcmd(ad->ep[0], type, req, control, index, buf, count) < 0){ if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n", c->name); return -1; } } c->value[0] = value[0]; return 0; } int getspecialcontrol(int rec, int ctl, int req, long *value) { byte buf[3]; int m, n, i; int type, control, index, count; short svalue; count = 1; switch(ctl){ default: return Undef; case Speed_control: value[0] = getspeed(rec, req); return 0; case Channel_control: case Resolution_control: if (req == GET_MIN) value[0] = controls[rec][ctl].min; if (req == GET_MAX) value[0] = controls[rec][ctl].max; if (req == GET_RES) value[0] = controls[rec][ctl].step; if (req == GET_CUR) value[0] = controls[rec][ctl].value[0]; return 0; case Volume_control: 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: type = RD2H|Rclass|Rinterface; control = ctl<<8; index = featureid[rec]<<8; break; case Selector_control: type = RD2H|Rclass|Rinterface; control = ctl<<8; index = selectorid[rec]; break; } if (controls[rec][ctl].chans){ m = 0; value[0] = 0; // set to average for (i = 1; i < 8; i++){ value[i] = Undef; if (controls[rec][ctl].chans & 1 << i){ if (setupreq(ad->ep[0], type, req, control | i, index, count) < 0) return Undef; n = setupreply(ad->ep[0], buf, count); if (n != count) return -1; switch (count) { case 2: svalue = buf[1] << 8 | buf[0]; if (req == GET_CUR){ value[i] = svalue; value[0] += svalue; m++; }else value[0] = svalue; break; case 1: if (req == GET_CUR){ value[i] = buf[0]; value[0] += buf[0]; m++; }else value[0] = buf[0]; } } } if (m) value[0] /= m; return 0; } value[0] = Undef; if (setupreq(ad->ep[0], type, req, control, index, count) < 0) return -1; n = setupreply(ad->ep[0], buf, count); if (n != count) return -1; switch (count) { case 2: svalue = buf[1] << 8 | buf[0]; value[0] = svalue; break; case 1: value[0] = buf[0]; } return 0; } int getcontrol(int rec, char *name, long *value) { int i; for (i = 0; i < Ncontrol; i++){ if (strcmp(name, controls[rec][i].name) == 0) break; } if (i == Ncontrol) return -1; if (controls[rec][i].readable == 0) return -1; if(getspecialcontrol(rec, i, GET_CUR, value) < 0) return -1; memmove(controls[rec][i].value, value, sizeof controls[rec][i].value); return 0; } void getcontrols(void) { int rec, ctl, i; Audiocontrol *c; long v[8]; for (rec = 0; rec < 2; rec++) for (ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; if (c->readable){ if (verbose) fprint(2, "%s %s control", rec?"Record":"Playback", controls[rec][ctl].name); c->min = (getspecialcontrol(rec, ctl, GET_MIN, v) < 0) ? Undef : v[0]; if (verbose && c->min != Undef) fprint(2, ", min %ld", c->min); c->max = (getspecialcontrol(rec, ctl, GET_MAX, v) < 0) ? Undef : v[0]; if (verbose && c->max != Undef) fprint(2, ", max %ld", c->max); c->step = (getspecialcontrol(rec, ctl, GET_RES, v) < 0) ? Undef : v[0]; if (verbose && c->step != Undef) fprint(2, ", step %ld", c->step); if (getspecialcontrol(rec, ctl, GET_CUR, c->value) == 0){ if (verbose) { if (c->chans){ fprint(2, ", values"); for (i = 1; i < 8; i++) if (c->chans & 1 << i) fprint(2, "[%d] %ld ", i, c->value[i]); }else fprint(2, ", value %ld", c->value[0]); } } if (verbose) fprint(2, "\n"); } else { c->min = Undef; c->max = Undef; c->step = Undef; c->value[0] = Undef; if (debug & Dbgcontrol) fprint(2, "%s %s control not settable\n", rec?"Playback":"Record", controls[rec][ctl].name); } } } int ctlparse(char *s, Audiocontrol *c, long *v) { int i, j, nf, m; char *vals[9]; char *p; long val; nf = tokenize(s, vals, nelem(vals)); if (nf <= 0) return -1; if (c->chans){ j = 0; m = 0; SET(val); v[0] = 0; // will compute average of v[i] for (i = 1; i < 8; i++) if (c->chans & 1 << i) { if (j < nf){ val = strtol(vals[j], &p, 0); if (val == 0 && *p != '\0' && *p != '%') return -1; if (*p == '%' && c->min != Undef) val = (val*c->max + (100-val)*c->min)/100; j++; } v[i] = val; v[0] += val; m++; } else v[i] = Undef; if (m) v[0] /= m; } else { val = strtol(vals[0], &p, 0); if (*p == '%' && c->min != Undef) val = (val*c->max + (100-val)*c->min)/100; v[0] = val; } return 0; } int Aconv(Fmt *fp) { char str[256]; Audiocontrol *c; int fst, i; char *p; c = va_arg(fp->args, Audiocontrol*); p = str; if (c->chans) { fst = 1; for (i = 1; i < 8; i++) if (c->chans & 1 << i){ p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]); fst = 0; } seprint(p, str+sizeof str, "'"); } else seprint(p, str+sizeof str, "%ld", c->value[0]); return fmtstrcpy(fp, str); }