xref: /plan9/sys/src/cmd/usb/audio/audioctl.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5 #include "audio.h"
6 #include "audioctl.h"
7 
8 int endpt[2] =		{-1, -1};
9 int interface[2] =	{-1, -1};
10 int featureid[2] =	{-1, -1};
11 int selectorid[2] =	{-1, -1};
12 int mixerid[2] =	{-1, -1};
13 int curalt[2] =		{-1, -1};
14 int buttonendpt =	-1;
15 
16 int id;
17 Dev *ad;
18 
19 Audiocontrol controls[2][Ncontrol] = {
20 	{
21 	[Speed_control] = {		"speed",	0, {0}, 0,	44100,	Undef},
22 	[Mute_control] = {		"mute",		0, {0}, 0,	0,	Undef},
23 	[Volume_control] = {		"volume",	0, {0}, 0,	0,	Undef},
24 	[Bass_control] = {		"bass",		0, {0}, 0,	0,	Undef},
25 	[Mid_control] = {		"mid",		0, {0}, 0,	0,	Undef},
26 	[Treble_control] = {		"treble",	0, {0}, 0,	0,	Undef},
27 	[Equalizer_control] = {		"equalizer",	0, {0}, 0,	0,	Undef},
28 	[Agc_control] = {		"agc",		0, {0}, 0,	0,	Undef},
29 	[Delay_control] = {		"delay",	0, {0}, 0,	0,	Undef},
30 	[Bassboost_control] = {		"bassboost",	0, {0}, 0,	0,	Undef},
31 	[Loudness_control] = {		"loudness",	0, {0}, 0,	0,	Undef},
32 	[Channel_control] = {		"channels",	0, {0}, 0,	2,	Undef},
33 	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,	Undef},
34 //	[Selector_control] = {		"selector",	0, {0}, 0,	0,	Undef},
35 	}, {
36 	[Speed_control] = {		"speed",	0, {0}, 0,	44100,	Undef},
37 	[Mute_control] = {		"mute",		0, {0}, 0,	0,	Undef},
38 	[Volume_control] = {		"volume",	0, {0}, 0,	0,	Undef},
39 	[Bass_control] = {		"bass",		0, {0}, 0,	0,	Undef},
40 	[Mid_control] = {		"mid",		0, {0}, 0,	0,	Undef},
41 	[Treble_control] = {		"treble",	0, {0}, 0,	0,	Undef},
42 	[Equalizer_control] = {		"equalizer",	0, {0}, 0,	0,	Undef},
43 	[Agc_control] = {		"agc",		0, {0}, 0,	0,	Undef},
44 	[Delay_control] = {		"delay",	0, {0}, 0,	0,	Undef},
45 	[Bassboost_control] = {		"bassboost",	0, {0}, 0,	0,	Undef},
46 	[Loudness_control] = {		"loudness",	0, {0}, 0,	0,	Undef},
47 	[Channel_control] = {		"channels",	0, {0}, 0,	2,	Undef},
48 	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,	Undef},
49 //	[Selector_control] = {		"selector",	0, {0}, 0,	0,	Undef},
50 	}
51 };
52 
53 int
setaudioalt(int rec,Audiocontrol * c,int control)54 setaudioalt(int rec, Audiocontrol *c, int control)
55 {
56 	dprint(2, "setcontrol %s: Set alt %d\n", c->name, control);
57 	curalt[rec] = control;
58 	if(usbcmd(ad, Rh2d|Rstd|Riface, Rsetiface, control, interface[rec], nil, 0) < 0){
59 		dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
60 		return -1;
61 	}
62 	return control;
63 }
64 
65 int
findalt(int rec,int nchan,int res,int speed)66 findalt(int rec, int nchan, int res, int speed)
67 {
68 	Ep *ep;
69 	Audioalt *a;
70 	Altc *da;
71 	int i, j, k, retval;
72 
73 	retval = -1;
74 	controls[rec][Channel_control].min = 1000000;
75 	controls[rec][Channel_control].max = 0;
76 	controls[rec][Channel_control].step = Undef;
77 	controls[rec][Resolution_control].min = 1000000;
78 	controls[rec][Resolution_control].max = 0;
79 	controls[rec][Resolution_control].step = Undef;
80 	for(i = 0; i < nelem(ad->usb->ep); i++){
81 		if((ep = ad->usb->ep[i]) == nil)
82 			continue;
83 		if(ep->iface == nil){
84 			fprint(2, "\tno interface\n");
85 			return 0;
86 		}
87 		if(ep->iface->csp != CSP(Claudio, 2, 0))
88 			continue;
89 		if((rec == Play && (ep->addr &  0x80))
90 		|| (rec == Record && (ep->addr &  0x80) == 0))
91 			continue;
92 		for(j = 0; j < 16; j++){
93 			if((da = ep->iface->altc[j]) == nil || (a = da->aux) == nil)
94 				continue;
95 			if(a->nchan < controls[rec][Channel_control].min)
96 				controls[rec][Channel_control].min = a->nchan;
97 			if(a->nchan > controls[rec][Channel_control].max)
98 				controls[rec][Channel_control].max = a->nchan;
99 			if(a->res < controls[rec][Resolution_control].min)
100 				controls[rec][Resolution_control].min = a->res;
101 			if(a->res > controls[rec][Resolution_control].max)
102 				controls[rec][Resolution_control].max = a->res;
103 			controls[rec][Channel_control].settable = 1;
104 			controls[rec][Channel_control].readable = 1;
105 			controls[rec][Resolution_control].settable = 1;
106 			controls[rec][Resolution_control].readable = 1;
107 			controls[rec][Speed_control].settable = 1;
108 			controls[rec][Speed_control].readable = 1;
109 			if(a->nchan == nchan && a->res == res){
110 				if(speed == Undef)
111 					retval = j;
112 				else if(a->caps & (has_discfreq|onefreq)){
113 					for(k = 0; k < nelem(a->freqs); k++){
114 						if(a->freqs[k] == speed){
115 							retval = j;
116 							break;
117 						}
118 					}
119 				}else{
120 					if(speed >= a->minfreq && speed <= a->maxfreq)
121 						retval = j;
122 				}
123 			}
124 		}
125 	}
126 	if(usbdebug && retval < 0)
127 		fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed);
128 	return retval;
129 }
130 
131 int
setspeed(int rec,int speed)132 setspeed(int rec, int speed)
133 {
134 	int ps, n, no, dist, i;
135 	Audioalt *a;
136 	Altc *da;
137 	Ep *ep;
138 	uchar buf[3];
139 
140 	if(rec == Record && !setrec)
141 		return Undef;
142 	if(curalt[rec] < 0){
143 		fprint(2, "Must set channels and resolution before speed\n");
144 		return Undef;
145 	}
146 	if(endpt[rec] < 0)
147 		sysfatal("endpt[%s] not set", rec?"Record":"Playback");
148 	ep = ad->usb->ep[endpt[rec]];
149 	if(ep->iface == nil)
150 		sysfatal("no interface");
151 	if(curalt[rec] < 0)
152 		sysfatal("curalt[%s] not set", rec?"Record":"Playback");
153 	da = ep->iface->altc[curalt[rec]];
154 	a = da->aux;
155 	if(a->caps & onefreq){
156 		dprint(2, "setspeed %d: onefreq\n", speed);
157 		/* speed not settable, but packet size must still be set */
158 		speed = a->freqs[0];
159 	}else if(a->caps & has_contfreq){
160 		dprint(2, "setspeed %d: contfreq\n", speed);
161 		if(speed < a->minfreq)
162 			speed = a->minfreq;
163 		else if(speed > a->maxfreq)
164 			speed = a->maxfreq;
165 		dprint(2, "Setting continuously variable %s speed to %d\n",
166 				rec?"record":"playback", speed);
167 	}else if(a->caps & has_discfreq){
168 		dprint(2, "setspeed %d: discfreq\n", speed);
169 		dist = 1000000;
170 		no = -1;
171 		for(i = 0; a->freqs[i] > 0; i++)
172 			if(abs(a->freqs[i] - speed) < dist){
173 				dist = abs(a->freqs[i] - speed);
174 				no = i;
175 			}
176 		if(no == -1){
177 			dprint(2, "no = -1\n");
178 			return Undef;
179 		}
180 		speed = a->freqs[no];
181 		dprint(2, "Setting discreetly variable %s speed to %d\n",
182 				rec?"record":"playback", speed);
183 	}else{
184 		dprint(2, "can't happen\n?");
185 		return Undef;
186 	}
187 	if(a->caps & has_setspeed){
188 		dprint(2, "Setting %s speed to %d Hz;", rec?"record":"playback", speed);
189 		buf[0] = speed;
190 		buf[1] = speed >> 8;
191 		buf[2] = speed >> 16;
192 		n = endpt[rec];
193 		if(rec)
194 			n |= 0x80;
195 		if(usbcmd(ad, Rh2d|Rclass|Rep, Rsetcur, sampling_freq_control<<8, n, buf, 3) < 0){
196 			fprint(2, "Error in setupcmd\n");
197 			return Undef;
198 		}
199 		if((n=usbcmd(ad, Rd2h|Rclass|Rep, Rgetcur, sampling_freq_control<<8, n, buf, 3)) < 0){
200 			fprint(2, "Error in setupreq\n");
201 			return Undef;
202 		}
203 		if(n != 3)
204 			fprint(2, "Error in setupreply: %d\n", n);
205 		else{
206 			n = buf[0] | buf[1] << 8 | buf[2] << 16;
207 			if(buf[2] || n == 0){
208 				dprint(2, "Speed out of bounds %d (0x%x)\n", n, n);
209 			}else if(n != speed && ad->usb->vid == 0x077d &&
210 			    (ad->usb->did == 0x0223 || ad->usb->did == 0x07af)){
211 				/* Griffin iMic responds incorrectly to sample rate inquiry */
212 				dprint(2, " reported as %d (iMic bug?);", n);
213 			}else
214 				speed = n;
215 		}
216 		dprint(2, " speed now %d Hz;", speed);
217 	}
218 	ps = ((speed * da->interval + 999) / 1000)
219 		* controls[rec][Channel_control].value[0]
220 		* controls[rec][Resolution_control].value[0]/8;
221 	if(ps > ep->maxpkt){
222 		fprint(2, "%s: setspeed(rec %d, speed %d): packet size %d > "
223 			"maximum packet size %d\n",
224 			argv0, rec, speed, ps, ep->maxpkt);
225 		return Undef;
226 	}
227 	dprint(2, "Configuring %s endpoint for %d Hz\n",
228 				rec?"record":"playback", speed);
229 	epdev[rec] = openep(ad, endpt[rec]);
230 	if(epdev[rec] == nil)
231 		sysfatal("openep rec %d: %r", rec);
232 
233 	devctl(epdev[rec], "pollival %d", da->interval);
234 	devctl(epdev[rec], "samplesz %ld", controls[rec][Channel_control].value[0] *
235 				controls[rec][Resolution_control].value[0]/8);
236 	devctl(epdev[rec], "hz %d", speed);
237 
238 	/* NO: the client uses the endpoint file directly
239 	if(opendevdata(epdev[rec], rec ? OREAD : OWRITE) < 0)
240 		sysfatal("openep rec %d: %r", rec);
241 	*/
242 	return speed;
243 }
244 
245 long
getspeed(int rec,int which)246 getspeed(int rec, int which)
247 {
248 	int i, n;
249 	Audioalt *a;
250 	Altc *da;
251 	Ep *ep;
252 	uchar buf[3];
253 	int r;
254 
255 	if(curalt[rec] < 0){
256 		fprint(2, "Must set channels and resolution before getspeed\n");
257 		return Undef;
258 	}
259 	if(endpt[rec] < 0)
260 		sysfatal("endpt[%s] not set", rec?"Record":"Playback");
261 	dprint(2, "getspeed: endpt[%d] == %d\n", rec, endpt[rec]);
262 	ep = ad->usb->ep[endpt[rec]];
263 	if(ep->iface == nil)
264 		sysfatal("no interface");
265 	if(curalt[rec] < 0)
266 		sysfatal("curalt[%s] not set", rec?"Record":"Playback");
267 	da = ep->iface->altc[curalt[rec]];
268 	a = da->aux;
269 	if(a->caps & onefreq){
270 		dprint(2, "getspeed: onefreq\n");
271 		if(which == Rgetres)
272 			return Undef;
273 		return a->freqs[0];		/* speed not settable */
274 	}
275 	if(a->caps & has_setspeed){
276 		dprint(2, "getspeed: has_setspeed, ask\n");
277 		n = endpt[rec];
278 		if(rec)
279 			n |= 0x80;
280 		r = Rd2h|Rclass|Rep;
281 		if(usbcmd(ad,r,which,sampling_freq_control<<8, n, buf, 3) < 0)
282 			return Undef;
283 		if(n == 3){
284 			if(buf[2]){
285 				dprint(2, "Speed out of bounds\n");
286 				if((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8)
287 					return a->freqs[buf[0] | buf[1] << 8];
288 			}
289 			return buf[0] | buf[1] << 8 | buf[2] << 16;
290 		}
291 		dprint(2, "getspeed: n = %d\n", n);
292 	}
293 	if(a->caps & has_contfreq){
294 		dprint(2, "getspeed: has_contfreq\n");
295 		if(which == Rgetcur)
296 			return controls[rec][Speed_control].value[0];
297 		if(which == Rgetmin)
298 			return a->minfreq;
299 		if(which == Rgetmax)
300 			return a->maxfreq;
301 		if(which == Rgetres)
302 			return 1;
303 	}
304 	if(a->caps & has_discfreq){
305 		dprint(2, "getspeed: has_discfreq\n");
306 		if(which == Rgetcur)
307 			return controls[rec][Speed_control].value[0];
308 		if(which == Rgetmin)
309 			return a->freqs[0];
310 		for(i = 0; i < 8 && a->freqs[i] > 0; i++)
311 			;
312 		if(which == Rgetmax)
313 			return a->freqs[i-1];
314 		if(which == Rgetres)
315 			return Undef;
316 	}
317 	dprint(2, "can't happen\n?");
318 	return Undef;
319 }
320 
321 int
setcontrol(int rec,char * name,long * value)322 setcontrol(int rec, char *name, long *value)
323 {
324 	int i, ctl, m;
325 	byte buf[3];
326 	int type, req, control, index, count;
327 	Audiocontrol *c;
328 
329 	c = nil;
330 	for(ctl = 0; ctl < Ncontrol; ctl++){
331 		c = &controls[rec][ctl];
332 		if(strcmp(name, c->name) == 0)
333 			break;
334 	}
335 	if(ctl == Ncontrol){
336 		dprint(2, "setcontrol: control not found\n");
337 		return -1;
338 	}
339 	if(c->settable == 0){
340 		dprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl);
341 		if(c->chans){
342 			for(i = 0; i < 8; i++)
343 				if((c->chans & 1 << i) && c->value[i] != value[i])
344 					return -1;
345 			return 0;
346 		}
347 		if(c->value[0] != value[0])
348 			return -1;
349 		return 0;
350 	}
351 	if(c->chans){
352 		value[0] = 0;	// set to average
353 		m = 0;
354 		for(i = 1; i < 8; i++)
355 			if(c->chans & 1 << i){
356 				if(c->min != Undef && value[i] < c->min)
357 					value[i] = c->min;
358 				if(c->max != Undef && value[i] > c->max)
359 					value[i] = c->max;
360 				value[0] += value[i];
361 				m++;
362 			}else
363 				value[i] = Undef;
364 		if(m) value[0] /= m;
365 	}else{
366 		if(c->min != Undef && value[0] < c->min)
367 			value[0] = c->min;
368 		if(c->max != Undef && value[0] > c->max)
369 			value[0] = c->max;
370 	}
371 	req = Rsetcur;
372 	count = 1;
373 	switch(ctl){
374 	default:
375 		dprint(2, "setcontrol: can't happen\n");
376 		return -1;
377 	case Speed_control:
378 		if((rec != Record || setrec) && (value[0] = setspeed(rec, value[0])) < 0)
379 			return -1;
380 		c->value[0] = value[0];
381 		return 0;
382 	case Equalizer_control:
383 		/* not implemented */
384 		return -1;
385 	case Resolution_control:
386 		control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]);
387 		if(control < 0 || setaudioalt(rec, c, control) < 0){
388 			dprint(2, "setcontrol: can't find setting for %s\n", c->name);
389 			return -1;
390 		}
391 		c->value[0] = value[0];
392 		controls[rec][Speed_control].value[0] = defaultspeed[rec];
393 		return 0;
394 	case Volume_control:
395 	case Delay_control:
396 		count = 2;
397 		/* fall through */
398 	case Mute_control:
399 	case Bass_control:
400 	case Mid_control:
401 	case Treble_control:
402 	case Agc_control:
403 	case Bassboost_control:
404 	case Loudness_control:
405 		type = Rh2d|Rclass|Riface;
406 		control = ctl<<8;
407 		index = featureid[rec]<<8;
408 		break;
409 	case Selector_control:
410 		type = Rh2d|Rclass|Riface;
411 		control = 0;
412 		index = selectorid[rec]<<8;
413 		break;
414 	case Channel_control:
415 		control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]);
416 		if(control < 0 || setaudioalt(rec, c, control) < 0){
417 			dprint(2, "setcontrol: can't find setting for %s\n", c->name);
418 			return -1;
419 		}
420 		c->value[0] = value[0];
421 		controls[rec][Speed_control].value[0] = defaultspeed[rec];
422 		return 0;
423 	}
424 	if(c->chans){
425 		for(i = 1; i < 8; i++)
426 			if(c->chans & 1 << i){
427 				switch(count){
428 				case 2:
429 					buf[1] = value[i] >> 8;
430 				case 1:
431 					buf[0] = value[i];
432 				}
433 				if(usbcmd(ad, type, req, control | i, index, buf, count) < 0){
434 					dprint(2, "setcontrol: setupcmd %s failed\n",
435 						controls[rec][ctl].name);
436 					return -1;
437 				}
438 				c->value[i] = value[i];
439 			}
440 	}else{
441 		switch(count){
442 		case 2:
443 			buf[1] = value[0] >> 8;
444 		case 1:
445 			buf[0] = value[0];
446 		}
447 		if(usbcmd(ad, type, req, control, index, buf, count) < 0){
448 			dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
449 			return -1;
450 		}
451 	}
452 	c->value[0] = value[0];
453 	return 0;
454 }
455 
456 int
getspecialcontrol(int rec,int ctl,int req,long * value)457 getspecialcontrol(int rec, int ctl, int req, long *value)
458 {
459 	byte buf[3];
460 	int m, n, i;
461 	int type, control, index, count, signedbyte;
462 	short svalue;
463 
464 	count = 1;
465 	signedbyte = 0;
466 	switch(ctl){
467 	default:
468 		return Undef;
469 	case Speed_control:
470 		value[0] =  getspeed(rec, req);
471 		return 0;
472 	case Channel_control:
473 	case Resolution_control:
474 		if(req == Rgetmin)
475 			value[0] = controls[rec][ctl].min;
476 		if(req == Rgetmax)
477 			value[0] = controls[rec][ctl].max;
478 		if(req == Rgetres)
479 			value[0] = controls[rec][ctl].step;
480 		if(req == Rgetcur)
481 			value[0] = controls[rec][ctl].value[0];
482 		return 0;
483 	case Volume_control:
484 	case Delay_control:
485 		count = 2;
486 		/* fall through */
487 	case Bass_control:
488 	case Mid_control:
489 	case Treble_control:
490 	case Equalizer_control:
491 		signedbyte = 1;
492 		type = Rd2h|Rclass|Riface;
493 		control = ctl<<8;
494 		index = featureid[rec]<<8;
495 		break;
496 	case Selector_control:
497 		type = Rd2h|Rclass|Riface;
498 		control = 0;
499 		index = selectorid[rec]<<8;
500 		break;
501 	case Mute_control:
502 	case Agc_control:
503 	case Bassboost_control:
504 	case Loudness_control:
505 		if(req != Rgetcur)
506 			return Undef;
507 		type = Rd2h|Rclass|Riface;
508 		control = ctl<<8;
509 		index = featureid[rec]<<8;
510 		break;
511 	}
512 	if(controls[rec][ctl].chans){
513 		m = 0;
514 		value[0] = 0; // set to average
515 		for(i = 1; i < 8; i++){
516 			value[i] = Undef;
517 			if(controls[rec][ctl].chans & 1 << i){
518 				n=usbcmd(ad, type,req, control|i,index,buf,count);
519 				if(n < 0)
520 					return Undef;
521 				if(n != count)
522 					return -1;
523 				switch (count){
524 				case 2:
525 					svalue = buf[1] << 8 | buf[0];
526 					if(req == Rgetcur){
527 						value[i] = svalue;
528 						value[0] += svalue;
529 						m++;
530 					}else
531 						value[0] = svalue;
532 					break;
533 				case 1:
534 					svalue = buf[0];
535 					if(signedbyte && (svalue&0x80))
536 						svalue |= 0xFF00;
537 					if(req == Rgetcur){
538 						value[i] = svalue;
539 						value[0] += svalue;
540 						m++;
541 					}else
542 						value[0] = svalue;
543 				}
544 			}
545 		}
546 		if(m) value[0] /= m;
547 		return 0;
548 	}
549 	value[0] = Undef;
550 	if(usbcmd(ad, type, req, control, index, buf, count) != count)
551 		return -1;
552 	switch (count){
553 	case 2:
554 		svalue = buf[1] << 8 | buf[0];
555 		value[0] = svalue;
556 		break;
557 	case 1:
558 		svalue = buf[0];
559 		if(signedbyte && (svalue&0x80))
560 			svalue |= 0xFF00;
561 		value[0] = svalue;
562 	}
563 	return 0;
564 }
565 
566 int
getcontrol(int rec,char * name,long * value)567 getcontrol(int rec, char *name, long *value)
568 {
569 	int i;
570 
571 	for(i = 0; i < Ncontrol; i++){
572 		if(strcmp(name, controls[rec][i].name) == 0)
573 			break;
574 	}
575 	if(i == Ncontrol)
576 		return -1;
577 	if(controls[rec][i].readable == 0)
578 		return -1;
579 	if(getspecialcontrol(rec, i, Rgetcur, value) < 0)
580 		return -1;
581 	memmove(controls[rec][i].value, value, sizeof controls[rec][i].value);
582 	return 0;
583 }
584 
585 void
getcontrols(void)586 getcontrols(void)
587 {
588 	int rec, ctl, i;
589 	Audiocontrol *c;
590 	long v[8];
591 
592 	for(rec = 0; rec < 2; rec++){
593 		if(rec == Record && !setrec)
594 			continue;
595 		for(ctl = 0; ctl < Ncontrol; ctl++){
596 			c = &controls[rec][ctl];
597 			if(c->readable){
598 				if(verbose)
599 					fprint(2, "%s %s control",
600 						rec?"Record":"Playback", controls[rec][ctl].name);
601 				c->min = (getspecialcontrol(rec, ctl, Rgetmin, v) < 0) ? Undef : v[0];
602 				if(verbose && c->min != Undef)
603 					fprint(2, ", min %ld", c->min);
604 				c->max = (getspecialcontrol(rec, ctl, Rgetmax, v) < 0) ? Undef : v[0];
605 				if(verbose && c->max != Undef)
606 					fprint(2, ", max %ld", c->max);
607 				c->step = (getspecialcontrol(rec, ctl, Rgetres, v) < 0) ? Undef : v[0];
608 				if(verbose && c->step != Undef)
609 					fprint(2, ", step %ld", c->step);
610 				if(getspecialcontrol(rec, ctl, Rgetcur, c->value) == 0){
611 					if(verbose){
612 						if(c->chans){
613 							fprint(2, ", values");
614 							for(i = 1; i < 8; i++)
615 								if(c->chans & 1 << i)
616 									fprint(2, "[%d] %ld  ", i, c->value[i]);
617 						}else
618 							fprint(2, ", value %ld", c->value[0]);
619 					}
620 				}
621 				if(verbose)
622 					fprint(2, "\n");
623 			}else{
624 				c->min = Undef;
625 				c->max = Undef;
626 				c->step = Undef;
627 				c->value[0] = Undef;
628 				dprint(2, "%s %s control not settable\n",
629 					rec?"Playback":"Record", controls[rec][ctl].name);
630 			}
631 		}
632 	}
633 }
634 
635 int
ctlparse(char * s,Audiocontrol * c,long * v)636 ctlparse(char *s, Audiocontrol *c, long *v)
637 {
638 	int i, j, nf, m;
639 	char *vals[9];
640 	char *p;
641 	long val;
642 
643 	nf = tokenize(s, vals, nelem(vals));
644 	if(nf <= 0)
645 		return -1;
646 	if(c->chans){
647 		j = 0;
648 		m = 0;
649 		SET(val);
650 		v[0] = 0;	// will compute average of v[i]
651 		for(i = 1; i < 8; i++)
652 			if(c->chans & 1 << i){
653 				if(j < nf){
654 					val = strtol(vals[j], &p, 0);
655 					if(val == 0 && *p != '\0' && *p != '%')
656 						return -1;
657 					if(*p == '%' && c->min != Undef)
658 						val = (val*c->max + (100-val)*c->min)/100;
659 					j++;
660 				}
661 				v[i] = val;
662 				v[0] += val;
663 				m++;
664 			}else
665 				v[i] = Undef;
666 		if(m) v[0] /= m;
667 	}else{
668 		val = strtol(vals[0], &p, 0);
669 		if(*p == '%' && c->min != Undef)
670 			val = (val*c->max + (100-val)*c->min)/100;
671 		v[0] = val;
672 	}
673 	return 0;
674 }
675 
676 int
Aconv(Fmt * fp)677 Aconv(Fmt *fp)
678 {
679 	char str[256];
680 	Audiocontrol *c;
681 	int fst, i;
682 	char *p;
683 
684 	c = va_arg(fp->args, Audiocontrol*);
685 	p = str;
686 	if(c->chans){
687 		fst = 1;
688 		for(i = 1; i < 8; i++)
689 			if(c->chans & 1 << i){
690 				p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]);
691 				fst = 0;
692 			}
693 		seprint(p, str+sizeof str, "'");
694 	}else
695 		seprint(p, str+sizeof str, "%ld", c->value[0]);
696 	return fmtstrcpy(fp, str);
697 }
698