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