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