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