xref: /plan9/sys/src/cmd/usb/audio/audio.c (revision ed868a7c1f0ac853ba7f6fe1cfc03d41d6ae4523)
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