xref: /openbsd/sys/dev/pci/azalia_codec.c (revision 8529ddd3)
1 /*	$OpenBSD: azalia_codec.c,v 1.166 2015/04/25 11:37:24 jturner Exp $	*/
2 /*	$NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $	*/
3 
4 /*-
5  * Copyright (c) 2005 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by TAMURA Kent
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
37 #include <dev/pci/azalia.h>
38 
39 #define XNAME(co)	(((struct device *)co->az)->dv_xname)
40 #define MIXER_DELTA(n)	(AUDIO_MAX_GAIN / (n))
41 
42 int	azalia_add_convgroup(codec_t *, convgroupset_t *,
43     struct io_pin *, int, nid_t *, int, uint32_t, uint32_t);
44 
45 int	azalia_mixer_fix_indexes(codec_t *);
46 int	azalia_mixer_default(codec_t *);
47 int	azalia_mixer_ensure_capacity(codec_t *, size_t);
48 u_char	azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t );
49 uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char);
50 
51 void	azalia_devinfo_offon(mixer_devinfo_t *);
52 void	azalia_pin_config_ov(widget_t *, int, int);
53 void	azalia_ampcap_ov(widget_t *, int, int, int, int, int, int);
54 int	azalia_gpio_unmute(codec_t *, int);
55 
56 
57 int
58 azalia_codec_init_vtbl(codec_t *this)
59 {
60 	/**
61 	 * We can refer this->vid and this->subid.
62 	 */
63 	this->name = NULL;
64 	this->qrks = AZ_QRK_NONE;
65 	switch (this->vid) {
66 	case 0x10134206:
67 		this->name = "Cirrus Logic CS4206";
68 		if (this->subid == 0xcb8910de ||	/* APPLE_MBA3_1 */
69 		    this->subid == 0x72708086) {	/* APPLE_MBA4_1 */
70 			this->qrks |= AZ_QRK_GPIO_UNMUTE_1 |
71 			    AZ_QRK_GPIO_UNMUTE_3;
72 		}
73 		break;
74 	case 0x10134208:
75 		this->name = "Cirrus Logic CS4208";
76 		if (this->subid == 0x72708086) {	/* APPLE_MBA6_1 */
77 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0 |
78 			    AZ_QRK_GPIO_UNMUTE_1;
79 		}
80 		break;
81 	case 0x10ec0221:
82 		this->name = "Realtek ALC221";
83 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
84 		break;
85 	case 0x10ec0260:
86 		this->name = "Realtek ALC260";
87 		if (this->subid == 0x008f1025)
88 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
89 		break;
90 	case 0x10ec0262:
91 		this->name = "Realtek ALC262";
92 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
93 		break;
94 	case 0x10ec0268:
95 		this->name = "Realtek ALC268";
96 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
97 		break;
98 	case 0x10ec0269:
99 		this->name = "Realtek ALC269";
100 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
101 		break;
102 	case 0x10ec0272:
103 		this->name = "Realtek ALC272";
104 		break;
105 	case 0x10ec0282:
106 		this->name = "Realtek ALC282";
107 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
108 		break;
109 	case 0x10ec0292:
110 		this->name = "Realtek ALC292";
111 		break;
112 	case 0x10ec0660:
113 		this->name = "Realtek ALC660";
114 		if (this->subid == 0x13391043) {	/* ASUS_G2K */
115 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
116 		}
117 		break;
118 	case 0x10ec0662:
119 		this->name = "Realtek ALC662";
120 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
121 		break;
122 	case 0x10ec0663:
123 		this->name = "Realtek ALC663";
124 		break;
125 	case 0x10ec0861:
126 		this->name = "Realtek ALC861";
127 		break;
128 	case 0x10ec0880:
129 		this->name = "Realtek ALC880";
130 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
131 		if (this->subid == 0x19931043 ||	/* ASUS_M5200 */
132 		    this->subid == 0x13231043) {	/* ASUS_A7M */
133 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
134 		}
135 		if (this->subid == 0x203d161f) {	/* MEDION_MD95257 */
136 			this->qrks |= AZ_QRK_GPIO_UNMUTE_1;
137 		}
138 		break;
139 	case 0x10ec0882:
140 		this->name = "Realtek ALC882";
141 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
142 		if (this->subid == 0x13c21043 ||	/* ASUS_A7T */
143 		    this->subid == 0x19711043) {	/* ASUS_W2J */
144 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
145 		}
146 		break;
147 	case 0x10ec0883:
148 		this->name = "Realtek ALC883";
149 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
150 		if (this->subid == 0x00981025) {	/* ACER_ID */
151 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0 |
152 			    AZ_QRK_GPIO_UNMUTE_1;
153 		}
154 		break;
155 	case 0x10ec0885:
156 		this->name = "Realtek ALC885";
157 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
158 		if (this->subid == 0x00a1106b ||	/* APPLE_MB3 */
159 		    this->subid == 0xcb7910de ||	/* APPLE_MACMINI3_1 (line-in + hp) */
160 		    this->subid == 0x00a0106b ||	/* APPLE_MB3_1 */
161 		    this->subid == 0x00a3106b) {	/* APPLE_MB4 */
162 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
163 		}
164 		if (this->subid == 0x00a1106b ||
165 		    this->subid == 0xcb7910de ||	/* APPLE_MACMINI3_1 (internal spkr) */
166 		    this->subid == 0x00a0106b)
167 			this->qrks |= AZ_QRK_WID_OVREF50;
168 		break;
169 	case 0x10ec0888:
170 		this->name = "Realtek ALC888";
171 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
172 		break;
173 	case 0x11060398:
174 	case 0x11061398:
175 	case 0x11062398:
176 	case 0x11063398:
177 	case 0x11064398:
178 	case 0x11065398:
179 	case 0x11066398:
180 	case 0x11067398:
181 		this->name = "VIA VT1702";
182 		break;
183 	case 0x111d7603:
184 		this->name = "IDT 92HD75B3/4";
185 		break;
186 	case 0x111d7604:
187 		this->name = "IDT 92HD83C1X";
188 		break;
189 	case 0x111d7605:
190 		this->name = "IDT 92HD81B1X";
191 		break;
192 	case 0x111d7608:
193 		this->name = "IDT 92HD75B1/2";
194 		if ((this->subid & 0x0000ffff) == 0x0000103c) {	/* HP */
195 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
196 		}
197 		break;
198 	case 0x111d7674:
199 		this->name = "IDT 92HD73D1";
200 		break;
201 	case 0x111d7675:
202 		this->name = "IDT 92HD73C1";	/* aka 92HDW74C1 */
203 		if ((this->subid & 0x0000ffff) == 0x00001028) {	/* DELL */
204 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
205 		}
206 		break;
207 	case 0x111d7676:
208 		this->name = "IDT 92HD73E1";	/* aka 92HDW74E1 */
209 		break;
210 	case 0x111d76b0:
211 		this->name = "IDT 92HD71B8";
212 		break;
213 	case 0x111d76b2:
214 		this->name = "IDT 92HD71B7";
215 		if ((this->subid & 0x0000ffff) == 0x00001028 || /* DELL */
216 		    (this->subid & 0x0000ffff) == 0x0000103c) { /* HP */
217 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
218 		}
219 		break;
220 	case 0x111d76b6:
221 		this->name = "IDT 92HD71B5";
222 		break;
223 	case 0x111d76d4:
224 		this->name = "IDT 92HD83C1C";
225 		break;
226 	case 0x111d76d5:
227 		this->name = "IDT 92HD81B1C";
228 		break;
229 	case 0x11d4184a:
230 		this->name = "Analog Devices AD1884A";
231 		break;
232 	case 0x11d41882:
233 		this->name = "Analog Devices AD1882";
234 		break;
235 	case 0x11d41883:
236 		this->name = "Analog Devices AD1883";
237 		break;
238 	case 0x11d41884:
239 		this->name = "Analog Devices AD1884";
240 		break;
241 	case 0x11d4194a:
242 		this->name = "Analog Devices AD1984A";
243 		break;
244 	case 0x11d41981:
245 		this->name = "Analog Devices AD1981HD";
246 		this->qrks |= AZ_QRK_WID_AD1981_OAMP;
247 		break;
248 	case 0x11d41983:
249 		this->name = "Analog Devices AD1983";
250 		break;
251 	case 0x11d41984:
252 		this->name = "Analog Devices AD1984";
253 		break;
254 	case 0x11d41988:
255 		this->name = "Analog Devices AD1988A";
256 		break;
257 	case 0x11d4198b:
258 		this->name = "Analog Devices AD1988B";
259 		break;
260 	case 0x11d4882a:
261 		this->name = "Analog Devices AD1882A";
262 		break;
263 	case 0x11d4989a:
264 		this->name = "Analog Devices AD1989A";
265 		break;
266 	case 0x11d4989b:
267 		this->name = "Analog Devices AD1989B";
268 		break;
269 	case 0x14f15045:
270 		this->name = "Conexant CX20549";  /* Venice */
271 		break;
272 	case 0x14f15047:
273 		this->name = "Conexant CX20551";  /* Waikiki */
274 		break;
275 	case 0x14f15051:
276 		this->name = "Conexant CX20561";  /* Hermosa */
277 		break;
278 	case 0x434d4980:
279 		this->name = "CMedia CMI9880";
280 		break;
281 	case 0x83847612:
282 		this->name = "Sigmatel STAC9230X";
283 		break;
284 	case 0x83847613:
285 		this->name = "Sigmatel STAC9230D";
286 		break;
287 	case 0x83847614:
288 		this->name = "Sigmatel STAC9229X";
289 		break;
290 	case 0x83847615:
291 		this->name = "Sigmatel STAC9229D";
292 		break;
293 	case 0x83847616:
294 		this->name = "Sigmatel STAC9228X";
295 		if (this->subid == 0x02271028 ||	/* DELL_V1400 */
296 		    this->subid == 0x01f31028) {	/* DELL_I1400 */
297 			this->qrks |= AZ_QRK_GPIO_UNMUTE_2;
298 	 	}
299 		break;
300 	case 0x83847617:
301 		this->name = "Sigmatel STAC9228D";
302 		break;
303 	case 0x83847618:
304 		this->name = "Sigmatel STAC9227X";
305 		break;
306 	case 0x83847619:
307 		this->name = "Sigmatel STAC9227D";
308 		break;
309 	case 0x83847620:
310 		this->name = "Sigmatel STAC9274";
311 		break;
312 	case 0x83847621:
313 		this->name = "Sigmatel STAC9274D";
314 		break;
315 	case 0x83847626:
316 		this->name = "Sigmatel STAC9271X";
317 		break;
318 	case 0x83847627:
319 		this->name = "Sigmatel STAC9271D";
320 		break;
321 	case 0x83847632:
322 		this->name = "Sigmatel STAC9202";
323 		break;
324 	case 0x83847634:
325 		this->name = "Sigmatel STAC9250";
326 		break;
327 	case 0x83847636:
328 		this->name = "Sigmatel STAC9251";
329 		break;
330 	case 0x83847638:
331 		this->name = "IDT 92HD700X";
332 		break;
333 	case 0x83847639:
334 		this->name = "IDT 92HD700D";
335 		break;
336 	case 0x83847645:
337 		this->name = "IDT 92HD206X";
338 		break;
339 	case 0x83847646:
340 		this->name = "IDT 92HD206D";
341 		break;
342 	case 0x83847661:
343 		/* FALLTHROUGH */
344 	case 0x83847662:
345 		this->name = "Sigmatel STAC9225";
346 		break;
347 	case 0x83847680:
348 		this->name = "Sigmatel STAC9220/1";
349 		if (this->subid == 0x76808384) {	/* APPLE_ID */
350 			this->qrks |= AZ_QRK_GPIO_POL_0 | AZ_QRK_GPIO_UNMUTE_0 |
351 			     AZ_QRK_GPIO_UNMUTE_1;
352 		}
353 		break;
354 	case 0x83847682:
355 		/* FALLTHROUGH */
356 	case 0x83847683:
357 		this->name = "Sigmatel STAC9221D";	/* aka IDT 92HD202 */
358 		break;
359 	case 0x83847690:
360 		this->name = "Sigmatel STAC9200";	/* aka IDT 92HD001 */
361 		break;
362 	case 0x83847691:
363 		this->name = "Sigmatel STAC9200D";
364 		break;
365 	case 0x83847698:
366 		this->name = "IDT 92HD005";
367 		break;
368 	case 0x83847699:
369 		this->name = "IDT 92HD005D";
370 		break;
371 	case 0x838476a0:
372 		this->name = "Sigmatel STAC9205X";
373 		if (this->subid == 0x01f91028 ||	/* DELL_D630 */
374 		    this->subid == 0x02281028) {	/* DELL_V1500 */
375 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
376 		}
377 		break;
378 	case 0x838476a1:
379 		this->name = "Sigmatel STAC9205D";
380 		break;
381 	case 0x838476a2:
382 		this->name = "Sigmatel STAC9204X";
383 		break;
384 	case 0x838476a3:
385 		this->name = "Sigmatel STAC9204D";
386 		break;
387 	}
388 	return 0;
389 }
390 
391 /* ----------------------------------------------------------------
392  * functions for generic codecs
393  * ---------------------------------------------------------------- */
394 
395 int
396 azalia_widget_enabled(const codec_t *this, nid_t nid)
397 {
398 	if (!VALID_WIDGET_NID(nid, this) || !this->w[nid].enable)
399 		return 0;
400 	return 1;
401 }
402 
403 int
404 azalia_init_dacgroup(codec_t *this)
405 {
406 	this->dacs.ngroups = 0;
407 	if (this->na_dacs > 0)
408 		azalia_add_convgroup(this, &this->dacs,
409 		    this->opins, this->nopins,
410 		    this->a_dacs, this->na_dacs,
411 		    COP_AWTYPE_AUDIO_OUTPUT, 0);
412 	if (this->na_dacs_d > 0)
413 		azalia_add_convgroup(this, &this->dacs,
414 		    this->opins_d, this->nopins_d,
415 		    this->a_dacs_d, this->na_dacs_d,
416 		    COP_AWTYPE_AUDIO_OUTPUT, COP_AWCAP_DIGITAL);
417 	this->dacs.cur = 0;
418 
419 	this->adcs.ngroups = 0;
420 	if (this->na_adcs > 0)
421 		azalia_add_convgroup(this, &this->adcs,
422 		    this->ipins, this->nipins,
423 		    this->a_adcs, this->na_adcs,
424 		    COP_AWTYPE_AUDIO_INPUT, 0);
425 	if (this->na_adcs_d > 0)
426 		azalia_add_convgroup(this, &this->adcs,
427 		    this->ipins_d, this->nipins_d,
428 		    this->a_adcs_d, this->na_adcs_d,
429 		    COP_AWTYPE_AUDIO_INPUT, COP_AWCAP_DIGITAL);
430 	this->adcs.cur = 0;
431 
432 	return 0;
433 }
434 
435 int
436 azalia_add_convgroup(codec_t *this, convgroupset_t *group,
437     struct io_pin *pins, int npins, nid_t *all_convs, int nall_convs,
438     uint32_t type, uint32_t digital)
439 {
440 	nid_t convs[HDA_MAX_CHANNELS];
441 	int nconvs;
442 	nid_t conv;
443 	int i, j, k;
444 
445 	nconvs = 0;
446 
447 	/* default pin connections */
448 	for (i = 0; i < npins; i++) {
449 		conv = pins[i].conv;
450 		if (conv < 0)
451 			continue;
452 		for (j = 0; j < nconvs; j++) {
453 			if (convs[j] == conv)
454 				break;
455 		}
456 		if (j < nconvs)
457 			continue;
458 		convs[nconvs++] = conv;
459 		if (nconvs >= nall_convs) {
460 			goto done;
461 		}
462 	}
463 	/* non-default connections */
464 	for (i = 0; i < npins; i++) {
465 		for (j = 0; j < nall_convs; j++) {
466 			conv = all_convs[j];
467 			for (k = 0; k < nconvs; k++) {
468 				if (convs[k] == conv)
469 					break;
470 			}
471 			if (k < nconvs)
472 				continue;
473 			if (type == COP_AWTYPE_AUDIO_OUTPUT) {
474 				k = azalia_codec_fnode(this, conv,
475 				    pins[i].nid, 0);
476 				if (k < 0)
477 					continue;
478 			} else {
479 				if (!azalia_widget_enabled(this, conv))
480 					continue;
481 				k = azalia_codec_fnode(this, pins[i].nid,
482 				    conv, 0);
483 				if (k < 0)
484 					continue;
485 			}
486 			convs[nconvs++] = conv;
487 			if (nconvs >= nall_convs) {
488 				goto done;
489 			}
490 		}
491 	}
492 	/* Make sure the speaker dac is part of the analog output convgroup
493 	 * or it won't get connected by azalia_codec_connect_stream().
494 	 */
495 	if (type == COP_AWTYPE_AUDIO_OUTPUT && !digital &&
496 	    nconvs < nall_convs && this->spkr_dac != -1) {
497 		for (i = 0; i < nconvs; i++)
498 			if (convs[i] == this->spkr_dac)
499 				break;
500 		if (i == nconvs)
501 			convs[nconvs++] = this->spkr_dac;
502 	}
503 done:
504 	for (i = 0; i < nconvs; i++)
505 		group->groups[group->ngroups].conv[i] = convs[i];
506 	if (nconvs > 0) {
507 		group->groups[group->ngroups].nconv = i;
508 		group->ngroups++;
509 	}
510 
511 	/* Disable converters that aren't in a convgroup. */
512 	for (i = 0; i < nall_convs; i++) {
513 		conv = all_convs[i];
514 		for (j = 0; j < nconvs; j++)
515 			if (convs[j] == conv)
516 				break;
517 		if (j == nconvs)
518 			this->w[conv].enable = 0;
519 	}
520 
521 	return 0;
522 }
523 
524 int
525 azalia_codec_fnode(codec_t *this, nid_t node, int index, int depth)
526 {
527 	const widget_t *w;
528 	int i, ret;
529 
530 	w = &this->w[index];
531 	if (w->nid == node) {
532 		return index;
533 	}
534 	/* back at the beginning or a bad end */
535 	if (depth > 0 &&
536 	    (w->type == COP_AWTYPE_PIN_COMPLEX ||
537 	    w->type == COP_AWTYPE_BEEP_GENERATOR ||
538 	    w->type == COP_AWTYPE_AUDIO_OUTPUT ||
539 	    w->type == COP_AWTYPE_AUDIO_INPUT))
540 		return -1;
541 	if (++depth >= 10)
542 		return -1;
543 	for (i = 0; i < w->nconnections; i++) {
544 		if (!azalia_widget_enabled(this, w->connections[i]))
545 			continue;
546 		ret = azalia_codec_fnode(this, node, w->connections[i], depth);
547 		if (ret >= 0)
548 			return ret;
549 	}
550 	return -1;
551 }
552 
553 int
554 azalia_unsol_event(codec_t *this, int tag)
555 {
556 	mixer_ctrl_t mc;
557 	uint32_t result;
558 	int i, err, vol, vol2;
559 
560 	err = 0;
561 	tag = CORB_UNSOL_TAG(tag);
562 	switch (tag) {
563 	case AZ_TAG_SPKR:
564 		mc.type = AUDIO_MIXER_ENUM;
565 		vol = 0;
566 		for (i = 0; !vol && !err && i < this->nsense_pins; i++) {
567 			if (!(this->spkr_muters & (1 << i)))
568 				continue;
569 			err = azalia_comresp(this, this->sense_pins[i],
570 			    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
571 			if (err || !(result & CORB_PWC_OUTPUT))
572 				continue;
573 			err = azalia_comresp(this, this->sense_pins[i],
574 			    CORB_GET_PIN_SENSE, 0, &result);
575 			if (!err && (result & CORB_PS_PRESENCE))
576 				vol = 1;
577 		}
578 		if (err)
579 			break;
580 		this->spkr_muted = vol;
581 		switch(this->spkr_mute_method) {
582 		case AZ_SPKR_MUTE_SPKR_MUTE:
583 			mc.un.ord = vol;
584 			err = azalia_mixer_set(this, this->speaker,
585 			    MI_TARGET_OUTAMP, &mc);
586 			if (!err && this->speaker2 != -1 &&
587 			    (this->w[this->speaker2].widgetcap & COP_AWCAP_OUTAMP) &&
588 			    (this->w[this->speaker2].outamp_cap & COP_AMPCAP_MUTE))
589 				err = azalia_mixer_set(this, this->speaker2,
590 				    MI_TARGET_OUTAMP, &mc);
591 			break;
592 		case AZ_SPKR_MUTE_SPKR_DIR:
593 			mc.un.ord = vol ? 0 : 1;
594 			err = azalia_mixer_set(this, this->speaker,
595 			    MI_TARGET_PINDIR, &mc);
596 			if (!err && this->speaker2 != -1 &&
597 			    (this->w[this->speaker2].d.pin.cap & COP_PINCAP_OUTPUT) &&
598 			    (this->w[this->speaker2].d.pin.cap & COP_PINCAP_INPUT))
599 				err = azalia_mixer_set(this, this->speaker2,
600 				    MI_TARGET_PINDIR, &mc);
601 			break;
602 		case AZ_SPKR_MUTE_DAC_MUTE:
603 			mc.un.ord = vol;
604 			err = azalia_mixer_set(this, this->spkr_dac,
605 			    MI_TARGET_OUTAMP, &mc);
606 			break;
607 		}
608 		break;
609 
610 	case AZ_TAG_PLAYVOL:
611 		if (this->playvols.master == this->audiofunc)
612 			return EINVAL;
613 		err = azalia_comresp(this, this->playvols.master,
614 		    CORB_GET_VOLUME_KNOB, 0, &result);
615 		if (err)
616 			return err;
617 
618 		vol = CORB_VKNOB_VOLUME(result) - this->playvols.hw_step;
619 		vol2 = vol * (AUDIO_MAX_GAIN / this->playvols.hw_nsteps);
620 		this->playvols.hw_step = CORB_VKNOB_VOLUME(result);
621 
622 		vol = vol2 + this->playvols.vol_l;
623 		if (vol < 0)
624 			vol = 0;
625 		else if (vol > AUDIO_MAX_GAIN)
626 			vol = AUDIO_MAX_GAIN;
627 		this->playvols.vol_l = vol;
628 
629 		vol = vol2 + this->playvols.vol_r;
630 		if (vol < 0)
631 			vol = 0;
632 		else if (vol > AUDIO_MAX_GAIN)
633 			vol = AUDIO_MAX_GAIN;
634 		this->playvols.vol_r = vol;
635 
636 		mc.type = AUDIO_MIXER_VALUE;
637 		mc.un.value.num_channels = 2;
638 		mc.un.value.level[0] = this->playvols.vol_l;
639 		mc.un.value.level[1] = this->playvols.vol_r;
640 		err = azalia_mixer_set(this, this->playvols.master,
641 		    MI_TARGET_PLAYVOL, &mc);
642 		break;
643 
644 	default:
645 		DPRINTF(("%s: unknown tag %d\n", __func__, tag));
646 		break;
647 	}
648 
649 	return err;
650 }
651 
652 
653 /* ----------------------------------------------------------------
654  * Generic mixer functions
655  * ---------------------------------------------------------------- */
656 
657 int
658 azalia_mixer_init(codec_t *this)
659 {
660 	/*
661 	 * pin		"<color>%2.2x"
662 	 * audio output	"dac%2.2x"
663 	 * audio input	"adc%2.2x"
664 	 * mixer	"mixer%2.2x"
665 	 * selector	"sel%2.2x"
666 	 */
667 	const widget_t *w, *ww;
668 	mixer_item_t *m;
669 	int err, i, j, k, bits;
670 
671 	this->maxmixers = 10;
672 	this->nmixers = 0;
673 	this->mixers = mallocarray(this->maxmixers, sizeof(mixer_item_t),
674 	    M_DEVBUF, M_NOWAIT | M_ZERO);
675 	if (this->mixers == NULL) {
676 		printf("%s: out of memory in %s\n", XNAME(this), __func__);
677 		return ENOMEM;
678 	}
679 
680 	/* register classes */
681 	m = &this->mixers[AZ_CLASS_INPUT];
682 	m->devinfo.index = AZ_CLASS_INPUT;
683 	strlcpy(m->devinfo.label.name, AudioCinputs,
684 	    sizeof(m->devinfo.label.name));
685 	m->devinfo.type = AUDIO_MIXER_CLASS;
686 	m->devinfo.mixer_class = AZ_CLASS_INPUT;
687 	m->devinfo.next = AUDIO_MIXER_LAST;
688 	m->devinfo.prev = AUDIO_MIXER_LAST;
689 	m->nid = 0;
690 
691 	m = &this->mixers[AZ_CLASS_OUTPUT];
692 	m->devinfo.index = AZ_CLASS_OUTPUT;
693 	strlcpy(m->devinfo.label.name, AudioCoutputs,
694 	    sizeof(m->devinfo.label.name));
695 	m->devinfo.type = AUDIO_MIXER_CLASS;
696 	m->devinfo.mixer_class = AZ_CLASS_OUTPUT;
697 	m->devinfo.next = AUDIO_MIXER_LAST;
698 	m->devinfo.prev = AUDIO_MIXER_LAST;
699 	m->nid = 0;
700 
701 	m = &this->mixers[AZ_CLASS_RECORD];
702 	m->devinfo.index = AZ_CLASS_RECORD;
703 	strlcpy(m->devinfo.label.name, AudioCrecord,
704 	    sizeof(m->devinfo.label.name));
705 	m->devinfo.type = AUDIO_MIXER_CLASS;
706 	m->devinfo.mixer_class = AZ_CLASS_RECORD;
707 	m->devinfo.next = AUDIO_MIXER_LAST;
708 	m->devinfo.prev = AUDIO_MIXER_LAST;
709 	m->nid = 0;
710 
711 	this->nmixers = AZ_CLASS_RECORD + 1;
712 
713 #define MIXER_REG_PROLOG	\
714 	mixer_devinfo_t *d; \
715 	err = azalia_mixer_ensure_capacity(this, this->nmixers + 1); \
716 	if (err) \
717 		return err; \
718 	m = &this->mixers[this->nmixers]; \
719 	d = &m->devinfo; \
720 	m->nid = i
721 
722 	FOR_EACH_WIDGET(this, i) {
723 
724 		w = &this->w[i];
725 		if (!w->enable)
726 			continue;
727 
728 		/* selector */
729 		if (w->nconnections > 0 && w->type != COP_AWTYPE_AUDIO_MIXER &&
730 		    !(w->nconnections == 1 &&
731 		    azalia_widget_enabled(this, w->connections[0]) &&
732 		    strcmp(w->name, this->w[w->connections[0]].name) == 0) &&
733 		    w->nid != this->mic) {
734 			MIXER_REG_PROLOG;
735 			snprintf(d->label.name, sizeof(d->label.name),
736 			    "%s_source", w->name);
737 			d->type = AUDIO_MIXER_ENUM;
738 			if (w->mixer_class >= 0)
739 				d->mixer_class = w->mixer_class;
740 			else {
741 				if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
742 					d->mixer_class = AZ_CLASS_INPUT;
743 				else
744 					d->mixer_class = AZ_CLASS_OUTPUT;
745 			}
746 			m->target = MI_TARGET_CONNLIST;
747 			for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
748 				if (!azalia_widget_enabled(this,
749 				    w->connections[j]))
750 					continue;
751 				d->un.e.member[k].ord = j;
752 				strlcpy(d->un.e.member[k].label.name,
753 				    this->w[w->connections[j]].name,
754 				    MAX_AUDIO_DEV_LEN);
755 				k++;
756 			}
757 			d->un.e.num_mem = k;
758 			this->nmixers++;
759 		}
760 
761 		/* output mute */
762 		if (w->widgetcap & COP_AWCAP_OUTAMP &&
763 		    w->outamp_cap & COP_AMPCAP_MUTE &&
764 		    w->nid != this->mic) {
765 			MIXER_REG_PROLOG;
766 			snprintf(d->label.name, sizeof(d->label.name),
767 			    "%s_mute", w->name);
768 			if (w->mixer_class >= 0)
769 				d->mixer_class = w->mixer_class;
770 			else {
771 				if (w->type == COP_AWTYPE_AUDIO_MIXER ||
772 				    w->type == COP_AWTYPE_AUDIO_SELECTOR ||
773 				    w->type == COP_AWTYPE_PIN_COMPLEX)
774 					d->mixer_class = AZ_CLASS_OUTPUT;
775 				else
776 					d->mixer_class = AZ_CLASS_INPUT;
777 			}
778 			m->target = MI_TARGET_OUTAMP;
779 			azalia_devinfo_offon(d);
780 			this->nmixers++;
781 		}
782 
783 		/* output gain */
784 		if (w->widgetcap & COP_AWCAP_OUTAMP &&
785 		    COP_AMPCAP_NUMSTEPS(w->outamp_cap) &&
786 		    w->nid != this->mic) {
787 			MIXER_REG_PROLOG;
788 			snprintf(d->label.name, sizeof(d->label.name),
789 			    "%s", w->name);
790 			d->type = AUDIO_MIXER_VALUE;
791 			if (w->mixer_class >= 0)
792 				d->mixer_class = w->mixer_class;
793 			else {
794 				if (w->type == COP_AWTYPE_AUDIO_MIXER ||
795 				    w->type == COP_AWTYPE_AUDIO_SELECTOR ||
796 				    w->type == COP_AWTYPE_PIN_COMPLEX)
797 					d->mixer_class = AZ_CLASS_OUTPUT;
798 				else
799 					d->mixer_class = AZ_CLASS_INPUT;
800 			}
801 			m->target = MI_TARGET_OUTAMP;
802 			d->un.v.num_channels = WIDGET_CHANNELS(w);
803 			d->un.v.units.name[0] = 0;
804 			d->un.v.delta =
805 			    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap));
806 			this->nmixers++;
807 		}
808 
809 		/* input mute */
810 		if (w->widgetcap & COP_AWCAP_INAMP &&
811 		    w->inamp_cap & COP_AMPCAP_MUTE &&
812 		    w->nid != this->speaker &&
813 		    w->nid != this->speaker2) {
814 			if (w->type != COP_AWTYPE_AUDIO_MIXER) {
815 				MIXER_REG_PROLOG;
816 				snprintf(d->label.name, sizeof(d->label.name),
817 				    "%s_mute", w->name);
818 				if (w->mixer_class >= 0)
819 					d->mixer_class = w->mixer_class;
820 				else
821 					d->mixer_class = AZ_CLASS_INPUT;
822 				m->target = 0;
823 				azalia_devinfo_offon(d);
824 				this->nmixers++;
825 			} else {
826 				MIXER_REG_PROLOG;
827 				snprintf(d->label.name, sizeof(d->label.name),
828 				    "%s_source", w->name);
829 				m->target = MI_TARGET_MUTESET;
830 				d->type = AUDIO_MIXER_SET;
831 				if (w->mixer_class >= 0)
832 					d->mixer_class = w->mixer_class;
833 				else
834 					d->mixer_class = AZ_CLASS_INPUT;
835 				for (j = 0, k = 0;
836 				    j < w->nconnections && k < 32; j++) {
837 					if (!azalia_widget_enabled(this,
838 					    w->connections[j]))
839 						continue;
840 					if (w->connections[j] == this->speaker ||
841 					    w->connections[j] == this->speaker2)
842 						continue;
843 					d->un.s.member[k].mask = 1 << j;
844 					strlcpy(d->un.s.member[k].label.name,
845 					    this->w[w->connections[j]].name,
846 					    MAX_AUDIO_DEV_LEN);
847 					k++;
848 				}
849 				d->un.s.num_mem = k;
850 				if (k != 0)
851 					this->nmixers++;
852 			}
853 		}
854 
855 		/* input gain */
856 		if (w->widgetcap & COP_AWCAP_INAMP &&
857 		    COP_AMPCAP_NUMSTEPS(w->inamp_cap) &&
858 		    w->nid != this->speaker &&
859 		    w->nid != this->speaker2) {
860 			if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
861 			    w->type != COP_AWTYPE_AUDIO_MIXER) {
862 				MIXER_REG_PROLOG;
863 				snprintf(d->label.name, sizeof(d->label.name),
864 				    "%s", w->name);
865 				d->type = AUDIO_MIXER_VALUE;
866 				if (w->mixer_class >= 0)
867 					d->mixer_class = w->mixer_class;
868 				else
869 					d->mixer_class = AZ_CLASS_INPUT;
870 				m->target = 0;
871 				d->un.v.num_channels = WIDGET_CHANNELS(w);
872 				d->un.v.units.name[0] = 0;
873 				d->un.v.delta =
874 				    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
875 				this->nmixers++;
876 			} else {
877 				for (j = 0; j < w->nconnections; j++) {
878 					if (!azalia_widget_enabled(this,
879 					    w->connections[j]))
880 						continue;
881 					if (w->connections[j] == this->speaker ||
882 					    w->connections[j] == this->speaker2)
883 						continue;
884 					MIXER_REG_PROLOG;
885 					snprintf(d->label.name,
886 					    sizeof(d->label.name), "%s_%s",
887 					    w->name,
888 					    this->w[w->connections[j]].name);
889 					d->type = AUDIO_MIXER_VALUE;
890 					if (w->mixer_class >= 0)
891 						d->mixer_class = w->mixer_class;
892 					else
893 						d->mixer_class = AZ_CLASS_INPUT;
894 					m->target = j;
895 					d->un.v.num_channels = WIDGET_CHANNELS(w);
896 					d->un.v.units.name[0] = 0;
897 					d->un.v.delta =
898 					    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
899 					this->nmixers++;
900 				}
901 			}
902 		}
903 
904 		/* hardcoded mixer inputs */
905 		if (w->type == COP_AWTYPE_AUDIO_MIXER &&
906 		    !(w->widgetcap & COP_AWCAP_INAMP)) {
907 			MIXER_REG_PROLOG;
908 			snprintf(d->label.name, sizeof(d->label.name),
909 			    "%s_source", w->name);
910 			m->target = MI_TARGET_MIXERSET;
911 			d->type = AUDIO_MIXER_SET;
912 			if (w->mixer_class >= 0)
913 				d->mixer_class = w->mixer_class;
914 			else
915 				d->mixer_class = AZ_CLASS_INPUT;
916 			for (j = 0, k = 0;
917 			    j < w->nconnections && k < 32; j++) {
918 				if (!azalia_widget_enabled(this,
919 				    w->connections[j]))
920 					continue;
921 				if (w->connections[j] == this->speaker ||
922 				    w->connections[j] == this->speaker2)
923 					continue;
924 				d->un.s.member[k].mask = 1 << j;
925 				strlcpy(d->un.s.member[k].label.name,
926 				    this->w[w->connections[j]].name,
927 				    MAX_AUDIO_DEV_LEN);
928 				k++;
929 			}
930 			d->un.s.num_mem = k;
931 			if (k != 0)
932 				this->nmixers++;
933 		}
934 
935 		/* pin direction */
936 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
937 		    ((w->d.pin.cap & COP_PINCAP_OUTPUT &&
938 		    w->d.pin.cap & COP_PINCAP_INPUT) ||
939 		    COP_PINCAP_VREF(w->d.pin.cap) > 1)) {
940 
941 			MIXER_REG_PROLOG;
942 			snprintf(d->label.name, sizeof(d->label.name),
943 			    "%s_dir", w->name);
944 			d->type = AUDIO_MIXER_ENUM;
945 			d->mixer_class = AZ_CLASS_OUTPUT;
946 			m->target = MI_TARGET_PINDIR;
947 
948 			k = 0;
949 			d->un.e.member[k].ord = 0;
950 			strlcpy(d->un.e.member[k].label.name, "none",
951 			    MAX_AUDIO_DEV_LEN);
952 			k++;
953 
954 			if (w->d.pin.cap & COP_PINCAP_OUTPUT) {
955 				d->un.e.member[k].ord = 1;
956 				strlcpy(d->un.e.member[k].label.name,
957 				    AudioNoutput, MAX_AUDIO_DEV_LEN);
958 				k++;
959 			}
960 
961 			if (w->d.pin.cap & COP_PINCAP_INPUT) {
962 				d->un.e.member[k].ord = 2;
963 				strlcpy(d->un.e.member[k].label.name,
964 				    AudioNinput, MAX_AUDIO_DEV_LEN);
965 				k++;
966 
967 				for (j = 0; j < 4; j++) {
968 					if (j == 0) {
969 						bits = (1 << CORB_PWC_VREF_GND);
970 						strlcpy(d->un.e.member[k].label.name,
971 						    AudioNinput "-vr0",
972 						    MAX_AUDIO_DEV_LEN);
973 					} else if (j == 1) {
974 						bits = (1 << CORB_PWC_VREF_50);
975 						strlcpy(d->un.e.member[k].label.name,
976 						    AudioNinput "-vr50",
977 						    MAX_AUDIO_DEV_LEN);
978 					} else if (j == 2) {
979 						bits = (1 << CORB_PWC_VREF_80);
980 						strlcpy(d->un.e.member[k].label.name,
981 						    AudioNinput "-vr80",
982 						    MAX_AUDIO_DEV_LEN);
983 					} else if (j == 3) {
984 						bits = (1 << CORB_PWC_VREF_100);
985 						strlcpy(d->un.e.member[k].label.name,
986 						    AudioNinput "-vr100",
987 						    MAX_AUDIO_DEV_LEN);
988 					}
989 					if ((COP_PINCAP_VREF(w->d.pin.cap) &
990 					    bits) == bits) {
991 						d->un.e.member[k].ord = j + 3;
992 						k++;
993 					}
994 				}
995 			}
996 			d->un.e.num_mem = k;
997 			this->nmixers++;
998 		}
999 
1000 		/* pin headphone-boost */
1001 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
1002 		    w->d.pin.cap & COP_PINCAP_HEADPHONE &&
1003 		    w->nid != this->mic) {
1004 			MIXER_REG_PROLOG;
1005 			snprintf(d->label.name, sizeof(d->label.name),
1006 			    "%s_boost", w->name);
1007 			d->mixer_class = AZ_CLASS_OUTPUT;
1008 			m->target = MI_TARGET_PINBOOST;
1009 			azalia_devinfo_offon(d);
1010 			this->nmixers++;
1011 		}
1012 
1013 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
1014 		    w->d.pin.cap & COP_PINCAP_EAPD) {
1015 			MIXER_REG_PROLOG;
1016 			snprintf(d->label.name, sizeof(d->label.name),
1017 			    "%s_eapd", w->name);
1018 			d->mixer_class = AZ_CLASS_OUTPUT;
1019 			m->target = MI_TARGET_EAPD;
1020 			azalia_devinfo_offon(d);
1021 			this->nmixers++;
1022 		}
1023 	}
1024 
1025 	/* sense pins */
1026 	for (i = 0; i < this->nsense_pins; i++) {
1027 		if (!azalia_widget_enabled(this, this->sense_pins[i])) {
1028 			DPRINTF(("%s: sense pin %2.2x not found\n",
1029 			    __func__, this->sense_pins[i]));
1030 			continue;
1031 		}
1032 
1033 		MIXER_REG_PROLOG;
1034 		m->nid = this->w[this->sense_pins[i]].nid;
1035 		snprintf(d->label.name, sizeof(d->label.name), "%s_sense",
1036 		    this->w[this->sense_pins[i]].name);
1037 		d->type = AUDIO_MIXER_ENUM;
1038 		d->mixer_class = AZ_CLASS_OUTPUT;
1039 		m->target = MI_TARGET_PINSENSE;
1040 		d->un.e.num_mem = 2;
1041 		d->un.e.member[0].ord = 0;
1042 		strlcpy(d->un.e.member[0].label.name, "unplugged",
1043 		    MAX_AUDIO_DEV_LEN);
1044 		d->un.e.member[1].ord = 1;
1045 		strlcpy(d->un.e.member[1].label.name, "plugged",
1046 		    MAX_AUDIO_DEV_LEN);
1047 		this->nmixers++;
1048 	}
1049 
1050 	/* spkr mute by jack sense */
1051 	this->spkr_mute_method = AZ_SPKR_MUTE_NONE;
1052 	if (this->speaker != -1 && this->spkr_dac != -1 && this->nsense_pins > 0) {
1053 		w = &this->w[this->speaker];
1054 		if ((w->widgetcap & COP_AWCAP_OUTAMP) &&
1055 		    (w->outamp_cap & COP_AMPCAP_MUTE))
1056 			this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_MUTE;
1057 		else if ((w->d.pin.cap & COP_PINCAP_OUTPUT) &&
1058 		    (w->d.pin.cap & COP_PINCAP_INPUT))
1059 			this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_DIR;
1060 		else {
1061 			w = &this->w[this->spkr_dac];
1062 			if (w->nid != this->dacs.groups[0].conv[0] &&
1063 			    (w->widgetcap & COP_AWCAP_OUTAMP) &&
1064 			    (w->outamp_cap & COP_AMPCAP_MUTE))
1065 				this->spkr_mute_method = AZ_SPKR_MUTE_DAC_MUTE;
1066 		}
1067 	}
1068 	if (this->spkr_mute_method != AZ_SPKR_MUTE_NONE) {
1069 		w = &this->w[this->speaker];
1070 		MIXER_REG_PROLOG;
1071 		m->nid = w->nid;
1072 		snprintf(d->label.name, sizeof(d->label.name),
1073 		    "%s_muters", w->name);
1074 		m->target = MI_TARGET_SENSESET;
1075 		d->type = AUDIO_MIXER_SET;
1076 		d->mixer_class = AZ_CLASS_OUTPUT;
1077 		this->spkr_muters = 0;
1078 		for (i = 0, j = 0; i < this->nsense_pins; i++) {
1079 			ww = &this->w[this->sense_pins[i]];
1080 			if (!(ww->d.pin.cap & COP_PINCAP_OUTPUT))
1081 				continue;
1082 			if (!(ww->widgetcap & COP_AWCAP_UNSOL))
1083 				continue;
1084 			d->un.s.member[j].mask = 1 << i;
1085 			this->spkr_muters |= (1 << i);
1086 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1087 			    MAX_AUDIO_DEV_LEN);
1088 		}
1089 		d->un.s.num_mem = j;
1090 		if (j != 0)
1091 			this->nmixers++;
1092 	}
1093 
1094 	/* playback volume group */
1095 	if (this->playvols.nslaves > 0) {
1096 		mixer_devinfo_t *d;
1097 		err = azalia_mixer_ensure_capacity(this,
1098 		    this->nmixers + 3);
1099 
1100 		/* volume */
1101 		m = &this->mixers[this->nmixers];
1102 		m->nid = this->playvols.master;
1103 		m->target = MI_TARGET_PLAYVOL;
1104 		d = &m->devinfo;
1105 		d->mixer_class = AZ_CLASS_OUTPUT;
1106 		snprintf(d->label.name, sizeof(d->label.name),
1107 		    "%s", AudioNmaster);
1108 		d->type = AUDIO_MIXER_VALUE;
1109 		d->un.v.num_channels = 2;
1110 		d->un.v.delta = 8;
1111 		this->nmixers++;
1112 		d->next = this->nmixers;
1113 
1114 		/* mute */
1115 		m = &this->mixers[this->nmixers];
1116 		m->nid = this->playvols.master;
1117 		m->target = MI_TARGET_PLAYVOL;
1118 		d = &m->devinfo;
1119 		d->prev = this->nmixers - 1;
1120 		d->mixer_class = AZ_CLASS_OUTPUT;
1121 		snprintf(d->label.name, sizeof(d->label.name),
1122 		    "%s", AudioNmute);
1123 		azalia_devinfo_offon(d);
1124 		this->nmixers++;
1125 		d->next = this->nmixers;
1126 
1127 		/* slaves */
1128 		m = &this->mixers[this->nmixers];
1129 		m->nid = this->playvols.master;
1130 		m->target = MI_TARGET_PLAYVOL;
1131 		d = &m->devinfo;
1132 		d->prev = this->nmixers - 1;
1133 		d->mixer_class = AZ_CLASS_OUTPUT;
1134 		snprintf(d->label.name, sizeof(d->label.name),
1135 		    "%s", "slaves");
1136 		d->type = AUDIO_MIXER_SET;
1137 		for (i = 0, j = 0; i < this->playvols.nslaves; i++) {
1138 			ww = &this->w[this->playvols.slaves[i]];
1139 			d->un.s.member[j].mask = (1 << i);
1140 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1141 			    MAX_AUDIO_DEV_LEN);
1142 		}
1143 		d->un.s.num_mem = j;
1144 		this->nmixers++;
1145 	}
1146 
1147 	/* recording volume group */
1148 	if (this->recvols.nslaves > 0) {
1149 		mixer_devinfo_t *d;
1150 		err = azalia_mixer_ensure_capacity(this,
1151 		    this->nmixers + 3);
1152 
1153 		/* volume */
1154 		m = &this->mixers[this->nmixers];
1155 		m->nid = this->recvols.master;
1156 		m->target = MI_TARGET_RECVOL;
1157 		d = &m->devinfo;
1158 		d->mixer_class = AZ_CLASS_RECORD;
1159 		snprintf(d->label.name, sizeof(d->label.name),
1160 		    "%s", AudioNvolume);
1161 		d->type = AUDIO_MIXER_VALUE;
1162 		d->un.v.num_channels = 2;
1163 		d->un.v.delta = 8;
1164 		this->nmixers++;
1165 		d->next = this->nmixers;
1166 
1167 		/* mute */
1168 		m = &this->mixers[this->nmixers];
1169 		m->nid = this->recvols.master;
1170 		m->target = MI_TARGET_RECVOL;
1171 		d = &m->devinfo;
1172 		d->prev = this->nmixers - 1;
1173 		d->mixer_class = AZ_CLASS_RECORD;
1174 		snprintf(d->label.name, sizeof(d->label.name),
1175 		    "%s", AudioNmute);
1176 		azalia_devinfo_offon(d);
1177 		this->nmixers++;
1178 		d->next = this->nmixers;
1179 
1180 		/* slaves */
1181 		m = &this->mixers[this->nmixers];
1182 		m->nid = this->recvols.master;
1183 		m->target = MI_TARGET_RECVOL;
1184 		d = &m->devinfo;
1185 		d->prev = this->nmixers - 1;
1186 		d->mixer_class = AZ_CLASS_RECORD;
1187 		snprintf(d->label.name, sizeof(d->label.name),
1188 		    "%s", "slaves");
1189 		d->type = AUDIO_MIXER_SET;
1190 		for (i = 0, j = 0; i < this->recvols.nslaves; i++) {
1191 			ww = &this->w[this->recvols.slaves[i]];
1192 			d->un.s.member[j].mask = (1 << i);
1193 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1194 			    MAX_AUDIO_DEV_LEN);
1195 		}
1196 		d->un.s.num_mem = j;
1197 		this->nmixers++;
1198 	}
1199 
1200 	/* if the codec has more than one DAC group, the first is analog
1201 	 * and the second is digital.
1202 	 */
1203 	if (this->dacs.ngroups > 1) {
1204 		MIXER_REG_PROLOG;
1205 		strlcpy(d->label.name, AudioNmode, sizeof(d->label.name));
1206 		d->type = AUDIO_MIXER_ENUM;
1207 		d->mixer_class = AZ_CLASS_OUTPUT;
1208 		m->target = MI_TARGET_DAC;
1209 		m->nid = this->audiofunc;
1210 		d->un.e.member[0].ord = 0;
1211 		strlcpy(d->un.e.member[0].label.name, "analog",
1212 		    MAX_AUDIO_DEV_LEN);
1213 		d->un.e.member[1].ord = 1;
1214 		strlcpy(d->un.e.member[1].label.name, "digital",
1215 		    MAX_AUDIO_DEV_LEN);
1216 		d->un.e.num_mem = 2;
1217 		this->nmixers++;
1218 	}
1219 
1220 	/* if the codec has more than one ADC group, the first is analog
1221 	 * and the second is digital.
1222 	 */
1223 	if (this->adcs.ngroups > 1) {
1224 		MIXER_REG_PROLOG;
1225 		strlcpy(d->label.name, AudioNmode, sizeof(d->label.name));
1226 		d->type = AUDIO_MIXER_ENUM;
1227 		d->mixer_class = AZ_CLASS_RECORD;
1228 		m->target = MI_TARGET_ADC;
1229 		m->nid = this->audiofunc;
1230 		d->un.e.member[0].ord = 0;
1231 		strlcpy(d->un.e.member[0].label.name, "analog",
1232 		    MAX_AUDIO_DEV_LEN);
1233 		d->un.e.member[1].ord = 1;
1234 		strlcpy(d->un.e.member[1].label.name, "digital",
1235 		    MAX_AUDIO_DEV_LEN);
1236 		d->un.e.num_mem = 2;
1237 		this->nmixers++;
1238 	}
1239 
1240 	azalia_mixer_fix_indexes(this);
1241 	azalia_mixer_default(this);
1242 	return 0;
1243 }
1244 
1245 void
1246 azalia_devinfo_offon(mixer_devinfo_t *d)
1247 {
1248 	d->type = AUDIO_MIXER_ENUM;
1249 	d->un.e.num_mem = 2;
1250 	d->un.e.member[0].ord = 0;
1251 	strlcpy(d->un.e.member[0].label.name, AudioNoff, MAX_AUDIO_DEV_LEN);
1252 	d->un.e.member[1].ord = 1;
1253 	strlcpy(d->un.e.member[1].label.name, AudioNon, MAX_AUDIO_DEV_LEN);
1254 }
1255 
1256 int
1257 azalia_mixer_ensure_capacity(codec_t *this, size_t newsize)
1258 {
1259 	size_t newmax;
1260 	void *newbuf;
1261 
1262 	if (this->maxmixers >= newsize)
1263 		return 0;
1264 	newmax = this->maxmixers + 10;
1265 	if (newmax < newsize)
1266 		newmax = newsize;
1267 	newbuf = mallocarray(newmax, sizeof(mixer_item_t), M_DEVBUF,
1268 	    M_NOWAIT | M_ZERO);
1269 	if (newbuf == NULL) {
1270 		printf("%s: out of memory in %s\n", XNAME(this), __func__);
1271 		return ENOMEM;
1272 	}
1273 	bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t));
1274 	free(this->mixers, M_DEVBUF, 0);
1275 	this->mixers = newbuf;
1276 	this->maxmixers = newmax;
1277 	return 0;
1278 }
1279 
1280 int
1281 azalia_mixer_fix_indexes(codec_t *this)
1282 {
1283 	int i;
1284 	mixer_devinfo_t *d;
1285 
1286 	for (i = 0; i < this->nmixers; i++) {
1287 		d = &this->mixers[i].devinfo;
1288 #ifdef DIAGNOSTIC
1289 		if (d->index != 0 && d->index != i)
1290 			printf("%s: index mismatch %d %d\n", __func__,
1291 			    d->index, i);
1292 #endif
1293 		d->index = i;
1294 		if (d->prev == 0)
1295 			d->prev = AUDIO_MIXER_LAST;
1296 		if (d->next == 0)
1297 			d->next = AUDIO_MIXER_LAST;
1298 	}
1299 	return 0;
1300 }
1301 
1302 int
1303 azalia_mixer_default(codec_t *this)
1304 {
1305 	widget_t *w;
1306 	mixer_item_t *m;
1307 	mixer_ctrl_t mc;
1308 	int i, j, tgt, cap, err;
1309 
1310 	/* unmute all */
1311 	for (i = 0; i < this->nmixers; i++) {
1312 		m = &this->mixers[i];
1313 		if (!IS_MI_TARGET_INAMP(m->target) &&
1314 		    m->target != MI_TARGET_OUTAMP)
1315 			continue;
1316 		if (m->devinfo.type != AUDIO_MIXER_ENUM)
1317 			continue;
1318 		bzero(&mc, sizeof(mc));
1319 		mc.dev = i;
1320 		mc.type = AUDIO_MIXER_ENUM;
1321 		azalia_mixer_set(this, m->nid, m->target, &mc);
1322 	}
1323 
1324 	/* set unextreme volume */
1325 	for (i = 0; i < this->nmixers; i++) {
1326 		m = &this->mixers[i];
1327 		if (!IS_MI_TARGET_INAMP(m->target) &&
1328 		    m->target != MI_TARGET_OUTAMP)
1329 			continue;
1330 		if (m->devinfo.type != AUDIO_MIXER_VALUE)
1331 			continue;
1332 		bzero(&mc, sizeof(mc));
1333 		mc.dev = i;
1334 		mc.type = AUDIO_MIXER_VALUE;
1335 		mc.un.value.num_channels = 1;
1336 		mc.un.value.level[0] = AUDIO_MAX_GAIN / 2;
1337 		if (WIDGET_CHANNELS(&this->w[m->nid]) == 2) {
1338 			mc.un.value.num_channels = 2;
1339 			mc.un.value.level[1] = mc.un.value.level[0];
1340 		}
1341 		azalia_mixer_set(this, m->nid, m->target, &mc);
1342 	}
1343 
1344 	/* unmute all */
1345 	for (i = 0; i < this->nmixers; i++) {
1346 		m = &this->mixers[i];
1347 		if (m->target != MI_TARGET_MUTESET)
1348 			continue;
1349 		if (m->devinfo.type != AUDIO_MIXER_SET)
1350 			continue;
1351 		bzero(&mc, sizeof(mc));
1352 		mc.dev = i;
1353 		mc.type = AUDIO_MIXER_SET;
1354 		if (!azalia_widget_enabled(this, m->nid)) {
1355 			DPRINTF(("%s: invalid set nid\n", __func__));
1356 			return EINVAL;
1357 		}
1358 		w = &this->w[m->nid];
1359 		for (j = 0; j < w->nconnections; j++) {
1360 			if (!azalia_widget_enabled(this, w->connections[j]))
1361 				continue;
1362 			if (w->nid == this->input_mixer &&
1363 			    w->connections[j] == this->mic)
1364 				continue;
1365 			mc.un.mask |= 1 << j;
1366 		}
1367 		azalia_mixer_set(this, m->nid, m->target, &mc);
1368 	}
1369 
1370 	/* make sure default connection is valid */
1371 	for (i = 0; i < this->nmixers; i++) {
1372 		m = &this->mixers[i];
1373 		if (m->target != MI_TARGET_CONNLIST)
1374 			continue;
1375 
1376 		azalia_mixer_get(this, m->nid, m->target, &mc);
1377 		for (j = 0; j < m->devinfo.un.e.num_mem; j++) {
1378 			if (mc.un.ord == m->devinfo.un.e.member[j].ord)
1379 				break;
1380 		}
1381 		if (j >= m->devinfo.un.e.num_mem) {
1382 			bzero(&mc, sizeof(mc));
1383 			mc.dev = i;
1384 			mc.type = AUDIO_MIXER_ENUM;
1385 			mc.un.ord = m->devinfo.un.e.member[0].ord;
1386 		}
1387 		azalia_mixer_set(this, m->nid, m->target, &mc);
1388 	}
1389 
1390 	/* get default value for play group master */
1391 	for (i = 0; i < this->playvols.nslaves; i++) {
1392 		if (!(this->playvols.cur & (1 << i)))
1393  			continue;
1394 		w = &this->w[this->playvols.slaves[i]];
1395 		if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)))
1396 			continue;
1397 		mc.type = AUDIO_MIXER_VALUE;
1398 		tgt = MI_TARGET_OUTAMP;
1399 		azalia_mixer_get(this, w->nid, tgt, &mc);
1400 		this->playvols.vol_l = mc.un.value.level[0];
1401 		this->playvols.vol_r = mc.un.value.level[0];
1402 		break;
1403  	}
1404 	this->playvols.mute = 0;
1405 
1406 	/* get default value for record group master */
1407 	for (i = 0; i < this->recvols.nslaves; i++) {
1408 		if (!(this->recvols.cur & (1 << i)))
1409 			continue;
1410 		w = &this->w[this->recvols.slaves[i]];
1411 		mc.type = AUDIO_MIXER_VALUE;
1412 		tgt = MI_TARGET_OUTAMP;
1413 		cap = w->outamp_cap;
1414 		if (w->type == COP_AWTYPE_PIN_COMPLEX ||
1415 		    w->type == COP_AWTYPE_AUDIO_INPUT) {
1416 			tgt = 0;
1417 			cap = w->inamp_cap;
1418  		}
1419 		if (!(COP_AMPCAP_NUMSTEPS(cap)))
1420 			continue;
1421 		azalia_mixer_get(this, w->nid, tgt, &mc);
1422 		this->recvols.vol_l = mc.un.value.level[0];
1423 		this->recvols.vol_r = mc.un.value.level[0];
1424 		break;
1425  	}
1426 	this->recvols.mute = 0;
1427 
1428 	err = azalia_codec_enable_unsol(this);
1429 	if (err)
1430 		return(err);
1431 
1432 	return 0;
1433 }
1434 
1435 int
1436 azalia_codec_enable_unsol(codec_t *this)
1437 {
1438 	widget_t *w;
1439 	uint32_t result;
1440 	int i, err;
1441 
1442 	/* jack sense */
1443 	for (i = 0; i < this->nsense_pins; i++) {
1444 		if (this->spkr_muters & (1 << i)) {
1445 			azalia_comresp(this, this->sense_pins[i],
1446 			    CORB_SET_UNSOLICITED_RESPONSE,
1447 			    CORB_UNSOL_ENABLE | AZ_TAG_SPKR, NULL);
1448 		}
1449 	}
1450 	if (this->spkr_muters != 0)
1451 		azalia_unsol_event(this, AZ_TAG_SPKR);
1452 
1453 	/* volume knob */
1454 	if (this->playvols.master != this->audiofunc) {
1455 
1456 		w = &this->w[this->playvols.master];
1457 		err = azalia_comresp(this, w->nid, CORB_GET_VOLUME_KNOB,
1458 		    0, &result);
1459 		if (err) {
1460 			DPRINTF(("%s: get volume knob error\n", __func__));
1461 			return err;
1462 		}
1463 
1464 		/* current level */
1465 		this->playvols.hw_step = CORB_VKNOB_VOLUME(result);
1466 		this->playvols.hw_nsteps = COP_VKCAP_NUMSTEPS(w->d.volume.cap);
1467 
1468 		/* indirect mode */
1469 		result &= ~(CORB_VKNOB_DIRECT);
1470 		err = azalia_comresp(this, w->nid, CORB_SET_VOLUME_KNOB,
1471 		    result, NULL);
1472 		if (err) {
1473 			DPRINTF(("%s: set volume knob error\n", __func__));
1474 			/* XXX If there was an error setting indirect
1475 			 * mode, do not return an error.  However, do not
1476 			 * enable unsolicited responses either.  Most
1477 			 * likely the volume knob doesn't work right.
1478 			 * Perhaps it's simply not wired/enabled.
1479 			 */
1480 			return 0;
1481 		}
1482 
1483 		/* enable unsolicited responses */
1484 		result = CORB_UNSOL_ENABLE | AZ_TAG_PLAYVOL;
1485 		err = azalia_comresp(this, w->nid,
1486 		    CORB_SET_UNSOLICITED_RESPONSE, result, NULL);
1487 		if (err) {
1488 			DPRINTF(("%s: set vknob unsol resp error\n", __func__));
1489 			return err;
1490 		}
1491 	}
1492 
1493 	return 0;
1494 }
1495 
1496 int
1497 azalia_mixer_delete(codec_t *this)
1498 {
1499 	if (this->mixers != NULL) {
1500 		free(this->mixers, M_DEVBUF, 0);
1501 		this->mixers = NULL;
1502 	}
1503 	return 0;
1504 }
1505 
1506 /**
1507  * @param mc	mc->type must be set by the caller before the call
1508  */
1509 int
1510 azalia_mixer_get(const codec_t *this, nid_t nid, int target,
1511     mixer_ctrl_t *mc)
1512 {
1513 	uint32_t result, cap, value;
1514 	nid_t n;
1515 	int i, err;
1516 
1517 	if (mc->type == AUDIO_MIXER_CLASS) {
1518 		return(0);
1519 	}
1520 
1521 	/* inamp mute */
1522 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
1523 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1524 		    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1525 		    MI_TARGET_INAMP(target), &result);
1526 		if (err)
1527 			return err;
1528 		mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
1529 	}
1530 
1531 	/* inamp gain */
1532 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
1533 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1534 		      CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1535 		      MI_TARGET_INAMP(target), &result);
1536 		if (err)
1537 			return err;
1538 		mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1539 		    nid, target, CORB_GAGM_GAIN(result));
1540 		if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR ||
1541 		    this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) {
1542 			n = this->w[nid].connections[MI_TARGET_INAMP(target)];
1543 			if (!azalia_widget_enabled(this, n)) {
1544 				DPRINTF(("%s: nid %2.2x invalid index %d\n",
1545 				   __func__, nid,  MI_TARGET_INAMP(target)));
1546 				n = nid;
1547 			}
1548 		} else
1549 			n = nid;
1550 		mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]);
1551 		if (mc->un.value.num_channels == 2) {
1552 			err = azalia_comresp(this, nid,
1553 			    CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1554 			    CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1555 			    &result);
1556 			if (err)
1557 				return err;
1558 			mc->un.value.level[1] = azalia_mixer_from_device_value
1559 			    (this, nid, target, CORB_GAGM_GAIN(result));
1560 		}
1561 	}
1562 
1563 	/* outamp mute */
1564 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
1565 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1566 		    CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
1567 		if (err)
1568 			return err;
1569 		mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
1570 	}
1571 
1572 	/* outamp gain */
1573 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
1574 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1575 		      CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
1576 		if (err)
1577 			return err;
1578 		mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1579 		    nid, target, CORB_GAGM_GAIN(result));
1580 		mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]);
1581 		if (mc->un.value.num_channels == 2) {
1582 			err = azalia_comresp(this, nid,
1583 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1584 			    CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result);
1585 			if (err)
1586 				return err;
1587 			mc->un.value.level[1] = azalia_mixer_from_device_value
1588 			    (this, nid, target, CORB_GAGM_GAIN(result));
1589 		}
1590 	}
1591 
1592 	/* selection */
1593 	else if (target == MI_TARGET_CONNLIST) {
1594 		err = azalia_comresp(this, nid,
1595 		    CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
1596 		if (err)
1597 			return err;
1598 		result = CORB_CSC_INDEX(result);
1599 		if (!azalia_widget_enabled(this,
1600 		    this->w[nid].connections[result]))
1601 			mc->un.ord = -1;
1602 		else
1603 			mc->un.ord = result;
1604 	}
1605 
1606 	/* pin I/O */
1607 	else if (target == MI_TARGET_PINDIR) {
1608 		err = azalia_comresp(this, nid,
1609 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1610 		if (err)
1611 			return err;
1612 
1613 		value = result;
1614 		if (!(result & (CORB_PWC_INPUT | CORB_PWC_OUTPUT)))
1615 			mc->un.ord = 0;
1616 		else if (result & CORB_PWC_OUTPUT)
1617 			mc->un.ord = 1;
1618 		else {
1619 			cap = COP_PINCAP_VREF(this->w[nid].d.pin.cap);
1620 			result &= CORB_PWC_VREF_MASK;
1621 			if (result == CORB_PWC_VREF_GND)
1622 				mc->un.ord = 3;
1623 			else if (result == CORB_PWC_VREF_50)
1624 				mc->un.ord = 4;
1625 			else if (result == CORB_PWC_VREF_80)
1626 				mc->un.ord = 5;
1627 			else if (result == CORB_PWC_VREF_100)
1628 				mc->un.ord = 6;
1629 			else
1630 				mc->un.ord = 2;
1631 		}
1632 	}
1633 
1634 	/* pin headphone-boost */
1635 	else if (target == MI_TARGET_PINBOOST) {
1636 		err = azalia_comresp(this, nid,
1637 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1638 		if (err)
1639 			return err;
1640 		mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0;
1641 	}
1642 
1643 	/* DAC group selection */
1644 	else if (target == MI_TARGET_DAC) {
1645 		mc->un.ord = this->dacs.cur;
1646 	}
1647 
1648 	/* ADC selection */
1649 	else if (target == MI_TARGET_ADC) {
1650 		mc->un.ord = this->adcs.cur;
1651 	}
1652 
1653 	/* S/PDIF */
1654 	else if (target == MI_TARGET_SPDIF) {
1655 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
1656 		    0, &result);
1657 		if (err)
1658 			return err;
1659 		mc->un.mask = result & 0xff & ~(CORB_DCC_DIGEN | CORB_DCC_NAUDIO);
1660 	} else if (target == MI_TARGET_SPDIF_CC) {
1661 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
1662 		    0, &result);
1663 		if (err)
1664 			return err;
1665 		mc->un.value.num_channels = 1;
1666 		mc->un.value.level[0] = CORB_DCC_CC(result);
1667 	}
1668 
1669 	/* EAPD */
1670 	else if (target == MI_TARGET_EAPD) {
1671 		err = azalia_comresp(this, nid, CORB_GET_EAPD_BTL_ENABLE,
1672 		    0, &result);
1673 		if (err)
1674 			return err;
1675 		mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0;
1676 	}
1677 
1678 	/* sense pin */
1679 	else if (target == MI_TARGET_PINSENSE) {
1680 		err = azalia_comresp(this, nid, CORB_GET_PIN_SENSE,
1681 		    0, &result);
1682 		if (err)
1683 			return err;
1684 		mc->un.ord = result & CORB_PS_PRESENCE ? 1 : 0;
1685 	}
1686 
1687 	/* mute set */
1688 	else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) {
1689 		const widget_t *w;
1690 
1691 		if (!azalia_widget_enabled(this, nid)) {
1692 			DPRINTF(("%s: invalid muteset nid\n", XNAME(this)));
1693 			return EINVAL;
1694 		}
1695 		w = &this->w[nid];
1696 		mc->un.mask = 0;
1697 		for (i = 0; i < w->nconnections; i++) {
1698 			if (!azalia_widget_enabled(this, w->connections[i]))
1699 				continue;
1700 			err = azalia_comresp(this, nid,
1701 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1702 			    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1703 			    MI_TARGET_INAMP(i), &result);
1704 			if (err)
1705 				return err;
1706 			mc->un.mask |= (result & CORB_GAGM_MUTE) ? 0 : (1 << i);
1707 		}
1708 	}
1709 
1710 	/* mixer set - show all connections */
1711 	else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) {
1712 		const widget_t *w;
1713 
1714 		if (!azalia_widget_enabled(this, nid)) {
1715 			DPRINTF(("%s: invalid mixerset nid\n", XNAME(this)));
1716 			return EINVAL;
1717 		}
1718 		w = &this->w[nid];
1719 		mc->un.mask = 0;
1720 		for (i = 0; i < w->nconnections; i++) {
1721 			if (!azalia_widget_enabled(this, w->connections[i]))
1722 				continue;
1723 			mc->un.mask |= (1 << i);
1724 		}
1725 	}
1726 
1727 	else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
1728 
1729 		if (nid == this->speaker) {
1730 			mc->un.mask = this->spkr_muters;
1731 		} else {
1732 			DPRINTF(("%s: invalid senseset nid\n", XNAME(this)));
1733 			return EINVAL;
1734 		}
1735 	}
1736 
1737 	else if (target == MI_TARGET_PLAYVOL) {
1738 
1739 		if (mc->type == AUDIO_MIXER_VALUE) {
1740 			mc->un.value.num_channels = 2;
1741 			mc->un.value.level[0] = this->playvols.vol_l;
1742 			mc->un.value.level[1] = this->playvols.vol_r;
1743 
1744 		} else if (mc->type == AUDIO_MIXER_ENUM) {
1745 			mc->un.ord = this->playvols.mute;
1746 
1747 		} else if (mc->type == AUDIO_MIXER_SET) {
1748 			mc->un.mask = this->playvols.cur;
1749 
1750 		} else {
1751 			DPRINTF(("%s: invalid outmaster mixer type\n",
1752 				XNAME(this)));
1753 			return EINVAL;
1754 		}
1755 	}
1756 
1757 	else if (target == MI_TARGET_RECVOL) {
1758 
1759 		if (mc->type == AUDIO_MIXER_VALUE) {
1760 			mc->un.value.num_channels = 2;
1761 			mc->un.value.level[0] = this->recvols.vol_l;
1762 			mc->un.value.level[1] = this->recvols.vol_r;
1763 
1764 		} else if (mc->type == AUDIO_MIXER_ENUM) {
1765 			mc->un.ord = this->recvols.mute;
1766 
1767 		} else if (mc->type == AUDIO_MIXER_SET) {
1768 			mc->un.mask = this->recvols.cur;
1769 
1770 		} else {
1771 			DPRINTF(("%s: invalid inmaster mixer type\n",
1772 				XNAME(this)));
1773 			return EINVAL;
1774 		}
1775 	}
1776 
1777 	else {
1778 		DPRINTF(("%s: internal error in %s: target=%x\n",
1779 		    XNAME(this), __func__, target));
1780 		return -1;
1781 	}
1782 	return 0;
1783 }
1784 
1785 int
1786 azalia_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc)
1787 {
1788 	uint32_t result, value;
1789 	int i, err;
1790 
1791 	if (mc->type == AUDIO_MIXER_CLASS) {
1792 		return(0);
1793 	}
1794 
1795 	/* inamp mute */
1796 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
1797 		/* set stereo mute separately to keep each gain value */
1798 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1799 		    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1800 		    MI_TARGET_INAMP(target), &result);
1801 		if (err)
1802 			return err;
1803 		value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1804 		    (target << CORB_AGM_INDEX_SHIFT) |
1805 		    CORB_GAGM_GAIN(result);
1806 		if (mc->un.ord)
1807 			value |= CORB_AGM_MUTE;
1808 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1809 		    value, &result);
1810 		if (err)
1811 			return err;
1812 		if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1813 			err = azalia_comresp(this, nid,
1814 			    CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1815 			    CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1816 			    &result);
1817 			if (err)
1818 				return err;
1819 			value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1820 			    (target << CORB_AGM_INDEX_SHIFT) |
1821 			    CORB_GAGM_GAIN(result);
1822 			if (mc->un.ord)
1823 				value |= CORB_AGM_MUTE;
1824 			err = azalia_comresp(this, nid,
1825 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1826 			if (err)
1827 				return err;
1828 		}
1829 	}
1830 
1831 	/* inamp gain */
1832 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
1833 		if (mc->un.value.num_channels < 1)
1834 			return EINVAL;
1835 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1836 		      CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1837 		      MI_TARGET_INAMP(target), &result);
1838 		if (err)
1839 			return err;
1840 		value = azalia_mixer_to_device_value(this, nid, target,
1841 		    mc->un.value.level[0]);
1842 		value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1843 		    (target << CORB_AGM_INDEX_SHIFT) |
1844 		    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1845 		    (value & CORB_AGM_GAIN_MASK);
1846 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1847 		    value, &result);
1848 		if (err)
1849 			return err;
1850 		if (mc->un.value.num_channels >= 2 &&
1851 		    WIDGET_CHANNELS(&this->w[nid]) == 2) {
1852 			err = azalia_comresp(this, nid,
1853 			      CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1854 			      CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1855 			      &result);
1856 			if (err)
1857 				return err;
1858 			value = azalia_mixer_to_device_value(this, nid, target,
1859 			    mc->un.value.level[1]);
1860 			value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1861 			    (target << CORB_AGM_INDEX_SHIFT) |
1862 			    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1863 			    (value & CORB_AGM_GAIN_MASK);
1864 			err = azalia_comresp(this, nid,
1865 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1866 			if (err)
1867 				return err;
1868 		}
1869 	}
1870 
1871 	/* outamp mute */
1872 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
1873 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1874 		    CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1875 		if (err)
1876 			return err;
1877 		value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result);
1878 		if (mc->un.ord)
1879 			value |= CORB_AGM_MUTE;
1880 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1881 		    value, &result);
1882 		if (err)
1883 			return err;
1884 		if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1885 			err = azalia_comresp(this, nid,
1886 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1887 			    CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result);
1888 			if (err)
1889 				return err;
1890 			value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1891 			    CORB_GAGM_GAIN(result);
1892 			if (mc->un.ord)
1893 				value |= CORB_AGM_MUTE;
1894 			err = azalia_comresp(this, nid,
1895 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1896 			if (err)
1897 				return err;
1898 		}
1899 	}
1900 
1901 	/* outamp gain */
1902 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
1903 		if (mc->un.value.num_channels < 1)
1904 			return EINVAL;
1905 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1906 		      CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1907 		if (err)
1908 			return err;
1909 		value = azalia_mixer_to_device_value(this, nid, target,
1910 		    mc->un.value.level[0]);
1911 		value = CORB_AGM_OUTPUT | CORB_AGM_LEFT |
1912 		    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1913 		    (value & CORB_AGM_GAIN_MASK);
1914 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1915 		    value, &result);
1916 		if (err)
1917 			return err;
1918 		if (mc->un.value.num_channels >= 2 &&
1919 		    WIDGET_CHANNELS(&this->w[nid]) == 2) {
1920 			err = azalia_comresp(this, nid,
1921 			      CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT |
1922 			      CORB_GAGM_RIGHT, &result);
1923 			if (err)
1924 				return err;
1925 			value = azalia_mixer_to_device_value(this, nid, target,
1926 			    mc->un.value.level[1]);
1927 			value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1928 			    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1929 			    (value & CORB_AGM_GAIN_MASK);
1930 			err = azalia_comresp(this, nid,
1931 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1932 			if (err)
1933 				return err;
1934 		}
1935 	}
1936 
1937 	/* selection */
1938 	else if (target == MI_TARGET_CONNLIST) {
1939 		if (mc->un.ord < 0 ||
1940 		    mc->un.ord >= this->w[nid].nconnections ||
1941 		    !azalia_widget_enabled(this,
1942 		    this->w[nid].connections[mc->un.ord]))
1943 			return EINVAL;
1944 		err = azalia_comresp(this, nid,
1945 		    CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
1946 		if (err)
1947 			return err;
1948 	}
1949 
1950 	/* pin I/O */
1951 	else if (target == MI_TARGET_PINDIR) {
1952 
1953 		err = azalia_comresp(this, nid,
1954 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1955 		if (err)
1956 			return err;
1957 
1958 		value = result;
1959 		value &= ~(CORB_PWC_VREF_MASK);
1960 		if (mc->un.ord == 0) {
1961 			value &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT);
1962 		} else if (mc->un.ord == 1) {
1963 			value &= ~CORB_PWC_INPUT;
1964 			value |= CORB_PWC_OUTPUT;
1965 			if (this->qrks & AZ_QRK_WID_OVREF50)
1966 				value |= CORB_PWC_VREF_50;
1967 		} else {
1968 			value &= ~CORB_PWC_OUTPUT;
1969 			value |= CORB_PWC_INPUT;
1970 
1971 			if (mc->un.ord == 3)
1972 				value |= CORB_PWC_VREF_GND;
1973 			if (mc->un.ord == 4)
1974 				value |= CORB_PWC_VREF_50;
1975 			if (mc->un.ord == 5)
1976 				value |= CORB_PWC_VREF_80;
1977 			if (mc->un.ord == 6)
1978 				value |= CORB_PWC_VREF_100;
1979 		}
1980 		err = azalia_comresp(this, nid,
1981 		    CORB_SET_PIN_WIDGET_CONTROL, value, &result);
1982 		if (err)
1983 			return err;
1984 
1985 		/* Run the unsolicited response handler for speaker mute
1986 		 * since it depends on pin direction.
1987 		 */
1988 		for (i = 0; i < this->nsense_pins; i++) {
1989 			if (this->sense_pins[i] == nid)
1990 				break;
1991 		}
1992 		if (i < this->nsense_pins) {
1993 			azalia_unsol_event(this, AZ_TAG_SPKR);
1994 		}
1995 	}
1996 
1997 	/* pin headphone-boost */
1998 	else if (target == MI_TARGET_PINBOOST) {
1999 		if (mc->un.ord >= 2)
2000 			return EINVAL;
2001 		err = azalia_comresp(this, nid,
2002 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
2003 		if (err)
2004 			return err;
2005 		if (mc->un.ord == 0) {
2006 			result &= ~CORB_PWC_HEADPHONE;
2007 		} else {
2008 			result |= CORB_PWC_HEADPHONE;
2009 		}
2010 		err = azalia_comresp(this, nid,
2011 		    CORB_SET_PIN_WIDGET_CONTROL, result, &result);
2012 		if (err)
2013 			return err;
2014 	}
2015 
2016 	/* DAC group selection */
2017 	else if (target == MI_TARGET_DAC) {
2018 		if (this->running)
2019 			return EBUSY;
2020 		if (mc->un.ord >= this->dacs.ngroups)
2021 			return EINVAL;
2022 		if (mc->un.ord != this->dacs.cur)
2023 			return azalia_codec_construct_format(this,
2024 			    mc->un.ord, this->adcs.cur);
2025 		else
2026 			return 0;
2027 	}
2028 
2029 	/* ADC selection */
2030 	else if (target == MI_TARGET_ADC) {
2031 		if (this->running)
2032 			return EBUSY;
2033 		if (mc->un.ord >= this->adcs.ngroups)
2034 			return EINVAL;
2035 		if (mc->un.ord != this->adcs.cur)
2036 			return azalia_codec_construct_format(this,
2037 			    this->dacs.cur, mc->un.ord);
2038 		else
2039 			return 0;
2040 	}
2041 
2042 	/* S/PDIF */
2043 	else if (target == MI_TARGET_SPDIF) {
2044 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
2045 		    0, &result);
2046 		result &= CORB_DCC_DIGEN | CORB_DCC_NAUDIO;
2047 		result |= mc->un.mask & 0xff & ~CORB_DCC_DIGEN;
2048 		err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L,
2049 		    result, NULL);
2050 		if (err)
2051 			return err;
2052 	} else if (target == MI_TARGET_SPDIF_CC) {
2053 		if (mc->un.value.num_channels != 1)
2054 			return EINVAL;
2055 		if (mc->un.value.level[0] > 127)
2056 			return EINVAL;
2057 		err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_H,
2058 		    mc->un.value.level[0], NULL);
2059 		if (err)
2060 			return err;
2061 	}
2062 
2063 	/* EAPD */
2064 	else if (target == MI_TARGET_EAPD) {
2065 		if (mc->un.ord >= 2)
2066 			return EINVAL;
2067 		err = azalia_comresp(this, nid,
2068 		    CORB_GET_EAPD_BTL_ENABLE, 0, &result);
2069 		if (err)
2070 			return err;
2071 		result &= 0xff;
2072 		if (mc->un.ord == 0) {
2073 			result &= ~CORB_EAPD_EAPD;
2074 		} else {
2075 			result |= CORB_EAPD_EAPD;
2076 		}
2077 		err = azalia_comresp(this, nid,
2078 		    CORB_SET_EAPD_BTL_ENABLE, result, &result);
2079 		if (err)
2080 			return err;
2081 	}
2082 
2083 	else if (target == MI_TARGET_PINSENSE) {
2084 		/* do nothing, control is read only */
2085 	}
2086 
2087 	else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) {
2088 		const widget_t *w;
2089 
2090 		if (!azalia_widget_enabled(this, nid)) {
2091 			DPRINTF(("%s: invalid muteset nid\n", XNAME(this)));
2092 			return EINVAL;
2093 		}
2094 		w = &this->w[nid];
2095 		for (i = 0; i < w->nconnections; i++) {
2096 			if (!azalia_widget_enabled(this, w->connections[i]))
2097 				continue;
2098 
2099 			/* We have to set stereo mute separately
2100 			 * to keep each gain value.
2101 			 */
2102 			err = azalia_comresp(this, nid,
2103 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
2104 			    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
2105 			    MI_TARGET_INAMP(i), &result);
2106 			if (err)
2107 				return err;
2108 			value = CORB_AGM_INPUT | CORB_AGM_LEFT |
2109 			    (i << CORB_AGM_INDEX_SHIFT) |
2110 			    CORB_GAGM_GAIN(result);
2111 			if ((mc->un.mask & (1 << i)) == 0)
2112 				value |= CORB_AGM_MUTE;
2113 			err = azalia_comresp(this, nid,
2114 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
2115 			if (err)
2116 				return err;
2117 
2118 			if (WIDGET_CHANNELS(w) == 2) {
2119 				err = azalia_comresp(this, nid,
2120 				    CORB_GET_AMPLIFIER_GAIN_MUTE,
2121 				    CORB_GAGM_INPUT | CORB_GAGM_RIGHT |
2122 				    MI_TARGET_INAMP(i), &result);
2123 				if (err)
2124 					return err;
2125 				value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
2126 				    (i << CORB_AGM_INDEX_SHIFT) |
2127 				    CORB_GAGM_GAIN(result);
2128 				if ((mc->un.mask & (1 << i)) == 0)
2129 					value |= CORB_AGM_MUTE;
2130 				err = azalia_comresp(this, nid,
2131 				    CORB_SET_AMPLIFIER_GAIN_MUTE,
2132 				    value, &result);
2133 				if (err)
2134 					return err;
2135 			}
2136 		}
2137 	}
2138 
2139 	else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) {
2140 		/* do nothing, control is read only */
2141 	}
2142 
2143 	else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
2144 
2145 		if (nid == this->speaker) {
2146 			this->spkr_muters = mc->un.mask;
2147 			azalia_unsol_event(this, AZ_TAG_SPKR);
2148 		} else {
2149 			DPRINTF(("%s: invalid senseset nid\n", XNAME(this)));
2150 			return EINVAL;
2151 		}
2152 	}
2153 
2154 	else if (target == MI_TARGET_PLAYVOL) {
2155 
2156 		const widget_t *w;
2157 		mixer_ctrl_t mc2;
2158 
2159 		if (mc->type == AUDIO_MIXER_VALUE) {
2160 			if (mc->un.value.num_channels != 2)
2161 				return EINVAL;
2162 			this->playvols.vol_l = mc->un.value.level[0];
2163 			this->playvols.vol_r = mc->un.value.level[1];
2164 			for (i = 0; i < this->playvols.nslaves; i++) {
2165 				if (!(this->playvols.cur & (1 << i)))
2166 					continue;
2167 				w = &this->w[this->playvols.slaves[i]];
2168 				if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)))
2169 					continue;
2170 
2171 				/* don't change volume if muted */
2172 				if (w->outamp_cap & COP_AMPCAP_MUTE) {
2173 					mc2.type = AUDIO_MIXER_ENUM;
2174 					azalia_mixer_get(this, w->nid,
2175 					    MI_TARGET_OUTAMP, &mc2);
2176 					if (mc2.un.ord)
2177 						continue;
2178 				}
2179 				mc2.type = AUDIO_MIXER_VALUE;
2180 				mc2.un.value.num_channels = WIDGET_CHANNELS(w);
2181 				mc2.un.value.level[0] = this->playvols.vol_l;
2182 				mc2.un.value.level[1] = this->playvols.vol_r;
2183 				err = azalia_mixer_set(this, w->nid,
2184 				    MI_TARGET_OUTAMP, &mc2);
2185 				if (err) {
2186 					DPRINTF(("%s: out slave %2.2x vol\n",
2187 					    __func__, w->nid));
2188 					return err;
2189 				}
2190 			}
2191 		} else if (mc->type == AUDIO_MIXER_ENUM) {
2192 			if (mc->un.ord != 0 && mc->un.ord != 1)
2193 				return EINVAL;
2194 			this->playvols.mute = mc->un.ord;
2195 			for (i = 0; i < this->playvols.nslaves; i++) {
2196 				if (!(this->playvols.cur & (1 << i)))
2197 					continue;
2198 				w = &this->w[this->playvols.slaves[i]];
2199 				if (!(w->outamp_cap & COP_AMPCAP_MUTE))
2200 					continue;
2201 				if (this->spkr_muted == 1 &&
2202 				    ((this->spkr_mute_method ==
2203 				    AZ_SPKR_MUTE_SPKR_MUTE &&
2204 				    (w->nid == this->speaker ||
2205 				    w->nid == this->speaker2)) ||
2206 				    (this->spkr_mute_method ==
2207 				    AZ_SPKR_MUTE_DAC_MUTE &&
2208 				    w->nid == this->spkr_dac))) {
2209 					continue;
2210 				}
2211 				mc2.type = AUDIO_MIXER_ENUM;
2212 				mc2.un.ord = this->playvols.mute;
2213 				err = azalia_mixer_set(this, w->nid,
2214 				    MI_TARGET_OUTAMP, &mc2);
2215 				if (err) {
2216 					DPRINTF(("%s: out slave %2.2x mute\n",
2217 					    __func__, w->nid));
2218 					return err;
2219 				}
2220 			}
2221 
2222 		} else if (mc->type == AUDIO_MIXER_SET) {
2223 			this->playvols.cur =
2224 			    (mc->un.mask & this->playvols.mask);
2225 
2226 		} else {
2227 			DPRINTF(("%s: invalid output master mixer type\n",
2228 				XNAME(this)));
2229 			return EINVAL;
2230 		}
2231 	}
2232 
2233 	else if (target == MI_TARGET_RECVOL) {
2234 
2235 		const widget_t *w;
2236 		mixer_ctrl_t mc2;
2237 		uint32_t cap;
2238 		int tgt;
2239 
2240 		if (mc->type == AUDIO_MIXER_VALUE) {
2241 			if (mc->un.value.num_channels != 2)
2242 				return EINVAL;
2243 			this->recvols.vol_l = mc->un.value.level[0];
2244 			this->recvols.vol_r = mc->un.value.level[1];
2245 			for (i = 0; i < this->recvols.nslaves; i++) {
2246 				if (!(this->recvols.cur & (1 << i)))
2247 					continue;
2248 				w = &this->w[this->recvols.slaves[i]];
2249 				tgt = MI_TARGET_OUTAMP;
2250 				cap = w->outamp_cap;
2251 				if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2252 				    w->type == COP_AWTYPE_PIN_COMPLEX) {
2253 					tgt = 0;
2254 					cap = w->inamp_cap;
2255 				}
2256 				if (!(COP_AMPCAP_NUMSTEPS(cap)))
2257 					continue;
2258 				mc2.type = AUDIO_MIXER_VALUE;
2259 				mc2.un.value.num_channels = WIDGET_CHANNELS(w);
2260 				mc2.un.value.level[0] = this->recvols.vol_l;
2261 				mc2.un.value.level[1] = this->recvols.vol_r;
2262 				err = azalia_mixer_set(this, w->nid,
2263 				    tgt, &mc2);
2264 				if (err) {
2265 					DPRINTF(("%s: in slave %2.2x vol\n",
2266 					    __func__, w->nid));
2267 					return err;
2268 				}
2269 			}
2270 		} else if (mc->type == AUDIO_MIXER_ENUM) {
2271 			if (mc->un.ord != 0 && mc->un.ord != 1)
2272 				return EINVAL;
2273 			this->recvols.mute = mc->un.ord;
2274 			for (i = 0; i < this->recvols.nslaves; i++) {
2275 				if (!(this->recvols.cur & (1 << i)))
2276 					continue;
2277 				w = &this->w[this->recvols.slaves[i]];
2278 				tgt = MI_TARGET_OUTAMP;
2279 				cap = w->outamp_cap;
2280 				if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2281 				    w->type == COP_AWTYPE_PIN_COMPLEX) {
2282 					tgt = 0;
2283 					cap = w->inamp_cap;
2284 				}
2285 				if (!(cap & COP_AMPCAP_MUTE))
2286 					continue;
2287 				mc2.type = AUDIO_MIXER_ENUM;
2288 				mc2.un.ord = this->recvols.mute;
2289 				err = azalia_mixer_set(this, w->nid,
2290 				    tgt, &mc2);
2291 				if (err) {
2292 					DPRINTF(("%s: out slave %2.2x mute\n",
2293 					    __func__, w->nid));
2294 					return err;
2295 				}
2296 			}
2297 
2298 		} else if (mc->type == AUDIO_MIXER_SET) {
2299 			this->recvols.cur = (mc->un.mask & this->recvols.mask);
2300 
2301 		} else {
2302 			DPRINTF(("%s: invalid input master mixer type\n",
2303 				XNAME(this)));
2304 			return EINVAL;
2305 		}
2306 	}
2307 
2308 	else {
2309 		DPRINTF(("%s: internal error in %s: target=%x\n",
2310 		    XNAME(this), __func__, target));
2311 		return -1;
2312 	}
2313 	return 0;
2314 }
2315 
2316 u_char
2317 azalia_mixer_from_device_value(const codec_t *this, nid_t nid, int target,
2318     uint32_t dv)
2319 {
2320 	uint32_t steps;
2321 	int max_gain, ctloff;
2322 
2323 	if (IS_MI_TARGET_INAMP(target)) {
2324 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
2325 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap);
2326 	} else if (target == MI_TARGET_OUTAMP) {
2327 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
2328 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap);
2329 	} else {
2330 		DPRINTF(("%s: unknown target: %d\n", __func__, target));
2331 		steps = 255;
2332 		ctloff = 0;
2333 	}
2334 	dv -= ctloff;
2335 	if (dv <= 0 || steps == 0)
2336 		return(AUDIO_MIN_GAIN);
2337 	max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps;
2338 	if (dv >= steps)
2339 		return(max_gain);
2340 	return(dv * max_gain / steps);
2341 }
2342 
2343 uint32_t
2344 azalia_mixer_to_device_value(const codec_t *this, nid_t nid, int target,
2345     u_char uv)
2346 {
2347 	uint32_t steps;
2348 	int max_gain, ctloff;
2349 
2350 	if (IS_MI_TARGET_INAMP(target)) {
2351 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
2352 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap);
2353 	} else if (target == MI_TARGET_OUTAMP) {
2354 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
2355 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap);
2356 	} else {
2357 		DPRINTF(("%s: unknown target: %d\n", __func__, target));
2358 		steps = 255;
2359 		ctloff = 0;
2360 	}
2361 	if (uv <= AUDIO_MIN_GAIN || steps == 0)
2362 		return(ctloff);
2363 	max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps;
2364 	if (uv >= max_gain)
2365 		return(steps + ctloff);
2366 	return(uv * steps / max_gain + ctloff);
2367 }
2368 
2369 int
2370 azalia_gpio_unmute(codec_t *this, int pin)
2371 {
2372 	uint32_t data, mask, dir;
2373 
2374 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data);
2375 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask);
2376 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir);
2377 
2378 	data |= 1 << pin;
2379 	mask |= 1 << pin;
2380 	dir |= 1 << pin;
2381 
2382 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL);
2383 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL);
2384 	DELAY(1000);
2385 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL);
2386 
2387 	return 0;
2388 }
2389 
2390 void
2391 azalia_ampcap_ov(widget_t *w, int type, int offset, int steps, int size,
2392    int ctloff, int mute)
2393 {
2394 	uint32_t cap;
2395 
2396 	cap = (offset & 0x7f) | ((steps & 0x7f) << 8) |
2397 	    ((size & 0x7f) << 16) | ((ctloff & 0x7f) << 24) |
2398 	    (mute ? COP_AMPCAP_MUTE : 0);
2399 
2400 	if (type == COP_OUTPUT_AMPCAP) {
2401 		w->outamp_cap = cap;
2402 	} else if (type == COP_INPUT_AMPCAP) {
2403 		w->inamp_cap = cap;
2404 	}
2405 }
2406 
2407 void
2408 azalia_pin_config_ov(widget_t *w, int mask, int val)
2409 {
2410 	int bits, offset;
2411 
2412 	switch (mask) {
2413 	case CORB_CD_DEVICE_MASK:
2414 		bits = CORB_CD_DEVICE_BITS;
2415 		offset = CORB_CD_DEVICE_OFFSET;
2416 		break;
2417 	case CORB_CD_PORT_MASK:
2418 		bits = CORB_CD_PORT_BITS;
2419 		offset = CORB_CD_PORT_OFFSET;
2420 		break;
2421 	default:
2422 		return;
2423 	}
2424 	val &= bits;
2425 	w->d.pin.config &= ~(mask);
2426 	w->d.pin.config |= val << offset;
2427 	if (mask == CORB_CD_DEVICE_MASK)
2428 		w->d.pin.device = val;
2429 }
2430 
2431 int
2432 azalia_codec_gpio_quirks(codec_t *this)
2433 {
2434 	if (this->qrks & AZ_QRK_GPIO_POL_0) {
2435 		azalia_comresp(this, this->audiofunc,
2436 		    CORB_SET_GPIO_POLARITY, 0, NULL);
2437 	}
2438 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_0) {
2439 		azalia_gpio_unmute(this, 0);
2440 	}
2441 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_1) {
2442 		azalia_gpio_unmute(this, 1);
2443 	}
2444 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_2) {
2445 		azalia_gpio_unmute(this, 2);
2446 	}
2447 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_3) {
2448 		azalia_gpio_unmute(this, 3);
2449 	}
2450 
2451 	return(0);
2452 }
2453 
2454 int
2455 azalia_codec_widget_quirks(codec_t *this, nid_t nid)
2456 {
2457 	widget_t *w;
2458 
2459 	w = &this->w[nid];
2460 
2461 	if (this->qrks & AZ_QRK_WID_BEEP_1D &&
2462 	    nid == 0x1d && w->enable == 0) {
2463 		azalia_pin_config_ov(w, CORB_CD_DEVICE_MASK, CORB_CD_BEEP);
2464 		azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED);
2465 		w->widgetcap |= COP_AWCAP_STEREO;
2466 		w->enable = 1;
2467 	}
2468 
2469 	if (this->qrks & AZ_QRK_WID_CDIN_1C &&
2470 	    nid == 0x1c && w->enable == 0 && w->d.pin.device == CORB_CD_CD) {
2471 		azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED);
2472 		w->widgetcap |= COP_AWCAP_STEREO;
2473 		w->enable = 1;
2474 	}
2475 
2476 	if ((this->qrks & AZ_QRK_WID_AD1981_OAMP) &&
2477 	    ((nid == 0x05) || (nid == 0x06) || (nid == 0x07) ||
2478 	    (nid == 0x09) || (nid == 0x18))) {
2479 		azalia_ampcap_ov(w, COP_OUTPUT_AMPCAP, 31, 33, 6, 30, 1);
2480 	}
2481 
2482 	return(0);
2483 }
2484