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