Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
}