1 /*
2 * USB audio driver for Plan 9
3 * This needs a full rewrite.
4 * As it is, it does not check for all errors,
5 * mixes the audio data structures with the usb configuration,
6 * may cross nil pointers, and is hard to debug and fix.
7 * Also, it does not issue a dettach request to the endpoint
8 * after the device is unplugged. This means that the old
9 * endpoint would still be around until manually reclaimed.
10 */
11
12 #include <u.h>
13 #include <libc.h>
14 #include <thread.h>
15 #include "usb.h"
16 #include "audio.h"
17 #include "audioctl.h"
18
19 #define STACKSIZE 16*1024
20
21 extern char* srvpost;
22 char * mntpt;
23
24 Channel *controlchan;
25
26 int verbose;
27 int setrec = 0;
28 int defaultspeed[2] = {44100, 44100};
29 Dev *buttondev;
30 Dev *epdev[2];
31
32 static void
audio_endpoint(Dev *,Desc * dd)33 audio_endpoint(Dev *, Desc *dd)
34 {
35 byte *b = (uchar*)&dd->data;
36 int n = dd->data.bLength;
37 char *hd;
38
39 switch(b[2]){
40 case 0x01:
41 if(usbdebug){
42 fprint(2, "CS_ENDPOINT for attributes 0x%x, lockdelayunits %d, lockdelay %#ux, ",
43 b[3], b[4], b[5] | (b[6]<<8));
44 if(b[3] & has_setspeed)
45 fprint(2, "has sampling-frequency control");
46 else
47 fprint(2, "does not have sampling-frequency control");
48 if(b[3] & 0x1<<1)
49 fprint(2, ", has pitch control");
50 else
51 fprint(2, ", does not have pitch control");
52 if(b[3] & 0x1<<7)
53 fprint(2, ", max packets only");
54 fprint(2, "\n");
55 }
56 if(dd->conf == nil)
57 sysfatal("conf == nil");
58 if(dd->iface == nil)
59 sysfatal("iface == nil");
60 if(dd->altc == nil)
61 sysfatal("alt == nil");
62 if(dd->altc->aux == nil)
63 dd->altc->aux= mallocz(sizeof(Audioalt),1);
64 ((Audioalt*)dd->altc->aux)->caps |= b[3];
65 break;
66 case 0x02:
67 if(usbdebug){
68 fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ",
69 b[3], b[4], b[5], b[6], b[7]);
70 fprint(2, "freq0 %d, freq1 %d\n",
71 b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16));
72 }
73 break;
74 default:
75 if(usbdebug){
76 hd = hexstr(b, n);
77 fprint(2, "CS_INTERFACE: %s\n", hd);
78 free(hd);
79 }
80 }
81 }
82
83 enum {
84 None,
85 Volumeset,
86 Volumeget,
87 Altset,
88 Altget,
89 Speedget,
90 };
91
92 void
controlproc(void *)93 controlproc(void *)
94 {
95 /* Proc that looks after /dev/usb/%d/ctl */
96 int i, nf;
97 char *req, *args[8];
98 Audiocontrol *c;
99 long value[8];
100 Channel *replchan;
101
102 while(req = recvp(controlchan)){
103 int rec;
104
105 nf = tokenize(req, args, nelem(args));
106 if(nf < 3)
107 sysfatal("controlproc: not enough arguments");
108 replchan = (Channel*)strtol(args[0], nil, 0);
109 if(strcmp(args[2], "playback") == 0)
110 rec = Play;
111 else if(strcmp(args[2], "record") == 0)
112 rec = Record;
113 else{
114 /* illegal request */
115 dprint(2, "%s must be record or playback", args[2]);
116 if(replchan) chanprint(replchan, "%s must be record or playback", args[2]);
117 free(req);
118 continue;
119 }
120 c = nil;
121 for(i = 0; i < Ncontrol; i++){
122 c = &controls[rec][i];
123 if(strcmp(args[1], c->name) == 0)
124 break;
125 }
126 if(i == Ncontrol){
127 dprint(2, "Illegal control name: %s", args[1]);
128 if(replchan) chanprint(replchan, "Illegal control name: %s", args[1]);
129 }else if(!c->settable){
130 dprint(2, "%s %s is not settable", args[1], args[2]);
131 if(replchan)
132 chanprint(replchan, "%s %s is not settable", args[1], args[2]);
133 }else if(nf < 4){
134 dprint(2, "insufficient arguments for %s %s", args[1], args[2]);
135 if(replchan)
136 chanprint(replchan, "insufficient arguments for %s %s",
137 args[1], args[2]);
138 }else if(ctlparse(args[3], c, value) < 0){
139 if(replchan)
140 chanprint(replchan, "parse error in %s %s", args[1], args[2]);
141 }else{
142 dprint(2, "controlproc: setcontrol %s %s %s\n",
143 rec?"in":"out", args[1], args[3]);
144 if(setcontrol(rec, args[1], value) < 0){
145 if(replchan)
146 chanprint(replchan, "setting %s %s failed", args[1], args[2]);
147 }else{
148 if(replchan) chanprint(replchan, "ok");
149 }
150 ctlevent();
151 }
152 free(req);
153 }
154 }
155
156 void
buttonproc(void *)157 buttonproc(void *)
158 {
159 int i, fd, b;
160 char err[32];
161 byte buf[1];
162 Audiocontrol *c;
163
164 fd = buttondev->dfd;
165
166 c = &controls[Play][Volume_control];
167 for(;;){
168 if((b = read(fd, buf, 1)) < 0){
169 rerrstr(err, sizeof err);
170 if(strcmp(err, "interrupted") == 0){
171 dprint(2, "read interrupted\n");
172 continue;
173 }
174 sysfatal("read %s/data: %r", buttondev->dir);
175 }
176 if(b == 0 || buf[0] == 0){
177 continue;
178 }else if(buf[0] == 1){
179 if(c->chans == 0)
180 c->value[0] += c->step;
181 else
182 for(i = 1; i < 8; i++)
183 if(c->chans & 1 << i)
184 c->value[i] += c->step;
185 chanprint(controlchan, "0 volume playback %A", c);
186 }else if(buf[0] == 2){
187 if(c->chans == 0)
188 c->value[0] -= c->step;
189 else
190 for(i = 1; i < 8; i++)
191 if(c->chans & 1 << i)
192 c->value[i] -= c->step;
193 chanprint(controlchan, "0 volume playback %A", c);
194 }else if(usbdebug){
195 fprint(2, "button");
196 for(i = 0; i < b; i++)
197 fprint(2, " %#2.2x", buf[i]);
198 fprint(2, "\n");
199 }
200 }
201 }
202
203
204 void
usage(void)205 usage(void)
206 {
207 fprint(2, "usage: usbaudio [-dpV] [-N nb] [-m mountpoint] [-s srvname] "
208 "[-v volume] [dev]\n");
209 threadexitsall("usage");
210 }
211
212 void
threadmain(int argc,char ** argv)213 threadmain(int argc, char **argv)
214 {
215 char *devdir;
216 int i;
217 long value[8], volume[8];
218 Audiocontrol *c;
219 char *p;
220 extern int attachok;
221 Ep *ep;
222 int csps[] = { Audiocsp, 0};
223
224 devdir = nil;
225 volume[0] = Undef;
226 for(i = 0; i<8; i++)
227 value[i] = 0;
228 fmtinstall('A', Aconv);
229 fmtinstall('U', Ufmt);
230 quotefmtinstall();
231
232 ARGBEGIN{
233 case 'N':
234 p = EARGF(usage()); /* ignore dev nb */
235 break;
236 case 'd':
237 usbdebug++;
238 verbose++;
239 break;
240 case 'm':
241 mntpt = EARGF(usage());
242 break;
243 case 'p':
244 attachok++;
245 break;
246 case 's':
247 srvpost = EARGF(usage());
248 break;
249 case 'v':
250 volume[0] = strtol(EARGF(usage()), &p, 0);
251 for(i = 1; i < 8; i++)
252 volume[i] = volume[0];
253 break;
254 case 'V':
255 verbose++;
256 break;
257 default:
258 usage();
259 }ARGEND
260 switch(argc){
261 case 0:
262 break;
263 case 1:
264 devdir = argv[0];
265 break;
266 default:
267 usage();
268 }
269 if(devdir == nil)
270 if(finddevs(matchdevcsp, csps, &devdir, 1) < 1){
271 fprint(2, "No usb audio\n");
272 threadexitsall("usbaudio not found");
273 }
274 ad = opendev(devdir);
275 if(ad == nil)
276 sysfatal("opendev: %r");
277 if(configdev(ad) < 0)
278 sysfatal("configdev: %r");
279
280 for(i = 0; i < nelem(ad->usb->ddesc); i++)
281 if(ad->usb->ddesc[i] != nil)
282 switch(ad->usb->ddesc[i]->data.bDescriptorType){
283 case AUDIO_INTERFACE:
284 audio_interface(ad, ad->usb->ddesc[i]);
285 break;
286 case AUDIO_ENDPOINT:
287 audio_endpoint(ad, ad->usb->ddesc[i]);
288 break;
289 }
290
291 controlchan = chancreate(sizeof(char*), 8);
292
293 for(i = 0; i < nelem(ad->usb->ep); i++)
294 if((ep = ad->usb->ep[i]) != nil){
295 if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Eout)
296 endpt[0] = ep->id;
297 if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Ein)
298 endpt[1] = ep->id;
299 if(buttonendpt<0 && Class(ep->iface->csp) == Clhid)
300 buttonendpt = ep->id;
301 }
302 if(endpt[0] != -1){
303 if(verbose)
304 fprint(2, "usb/audio: playback on ep %d\n", endpt[0]);
305 interface[0] = ad->usb->ep[endpt[0]]->iface->id;
306 }
307 if(endpt[1] != -1){
308 if(verbose)
309 fprint(2, "usb/audio: record on ep %d\n", endpt[0]);
310 interface[1] = ad->usb->ep[endpt[1]]->iface->id;
311 }
312 if(verbose && buttonendpt >= 0)
313 fprint(2, "usb/audio: buttons on ep %d\n", buttonendpt);
314
315 if(endpt[Play] >= 0){
316 if(verbose)
317 fprint(2, "Setting default play parameters: %d Hz, %d channels at %d bits\n",
318 defaultspeed[Play], 2, 16);
319 if(findalt(Play, 2, 16, defaultspeed[Play]) < 0){
320 if(findalt(Play, 2, 16, 48000) < 0)
321 sysfatal("Can't configure playout for %d or %d Hz", defaultspeed[Play], 48000);
322 fprint(2, "Warning, can't configure playout for %d Hz, configuring for %d Hz instead\n",
323 defaultspeed[Play], 48000);
324 defaultspeed[Play] = 48000;
325 }
326 value[0] = 2;
327 if(setcontrol(Play, "channels", value) == Undef)
328 sysfatal("Can't set play channels");
329 value[0] = 16;
330 if(setcontrol(Play, "resolution", value) == Undef)
331 sysfatal("Can't set play resolution");
332 }
333
334 if(endpt[Record] >= 0){
335 setrec = 1;
336 if(verbose)
337 fprint(2, "Setting default record parameters: "
338 "%d Hz, %d channels at %d bits\n",
339 defaultspeed[Record], 2, 16);
340 i = 2;
341 while(findalt(Record, i, 16, defaultspeed[Record]) < 0)
342 if(i == 2 && controls[Record][Channel_control].max == 1){
343 fprint(2, "Warning, can't configure stereo "
344 "recording, configuring mono instead\n");
345 i = 1;
346 }else
347 break;
348 if(findalt(Record, i, 16, 48000) < 0){
349 endpt[Record] = -1; /* disable recording */
350 setrec = 0;
351 fprint(2, "Warning, can't configure record for %d Hz or %d Hz\n",
352 defaultspeed[Record], 48000);
353 }else
354 fprint(2, "Warning, can't configure record for %d Hz, "
355 "configuring for %d Hz instead\n",
356 defaultspeed[Record], 48000);
357 defaultspeed[Record] = 48000;
358 if(setrec){
359 value[0] = i;
360 if(setcontrol(Record, "channels", value) == Undef)
361 sysfatal("Can't set record channels");
362 value[0] = 16;
363 if(setcontrol(Record, "resolution", value) == Undef)
364 sysfatal("Can't set record resolution");
365 }
366 }
367
368 getcontrols(); /* Get the initial value of all controls */
369 value[0] = defaultspeed[Play];
370 if(endpt[Play] >= 0 && setcontrol(Play, "speed", value) < 0)
371 sysfatal("can't set play speed");
372 value[0] = defaultspeed[Record];
373 if(endpt[Record] >= 0 && setcontrol(Record, "speed", value) < 0)
374 fprint(2, "%s: can't set record speed\n", argv0);
375 value[0] = 0;
376 setcontrol(Play, "mute", value);
377
378 if(volume[0] != Undef){
379 c = &controls[Play][Volume_control];
380 if(*p == '%' && c->min != Undef)
381 for(i = 0; i < 8; i++)
382 volume[i] = (volume[i]*c->max + (100-volume[i])*c->min)/100;
383 if(c->settable)
384 setcontrol(Play, "volume", volume);
385 c = &controls[Record][Volume_control];
386 if(c->settable && setrec)
387 setcontrol(Record, "volume", volume);
388 }
389
390 if(buttonendpt > 0){
391 buttondev = openep(ad, buttonendpt);
392 if(buttondev == nil)
393 sysfatal("openep: buttons: %r");
394 if(opendevdata(buttondev, OREAD) < 0)
395 sysfatal("open buttons fd: %r");
396 proccreate(buttonproc, nil, STACKSIZE);
397 }
398 proccreate(controlproc, nil, STACKSIZE);
399 proccreate(serve, nil, STACKSIZE);
400
401 threadexits(nil);
402 }
403