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