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