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