xref: /freebsd/sys/dev/sound/pci/hda/hdaa_patches.c (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
5  * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
6  * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
33  */
34 
35 #ifdef HAVE_KERNEL_OPTION_HEADERS
36 #include "opt_snd.h"
37 #endif
38 
39 #include <dev/sound/pcm/sound.h>
40 
41 #include <sys/ctype.h>
42 
43 #include <dev/sound/pci/hda/hdac.h>
44 #include <dev/sound/pci/hda/hdaa.h>
45 #include <dev/sound/pci/hda/hda_reg.h>
46 
47 #include "pin_patch.h"
48 #include "pin_patch_realtek.h"
49 
50 static const struct {
51 	uint32_t model;
52 	uint32_t id;
53 	uint32_t subsystemid;
54 	uint32_t set, unset;
55 	uint32_t gpio;
56 } hdac_quirks[] = {
57 	/*
58 	 * XXX Force stereo quirk. Monoural recording / playback
59 	 *     on few codecs (especially ALC880) seems broken or
60 	 *     perhaps unsupported.
61 	 */
62 	{ HDA_MATCH_ALL, HDA_MATCH_ALL, HDA_MATCH_ALL,
63 	    HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
64 	    0 },
65 	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, HDA_MATCH_ALL,
66 	    0, 0,
67 	    HDAA_GPIO_SET(0) },
68 	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660, HDA_MATCH_ALL,
69 	    0, 0,
70 	    HDAA_GPIO_SET(0) },
71 	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
72 	    0, 0,
73 	    HDAA_GPIO_SET(0) },
74 	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
75 	    0, 0,
76 	    HDAA_GPIO_SET(0) },
77 	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
78 	    0, 0,
79 	    HDAA_GPIO_SET(0) },
80 	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
81 	    0, 0,
82 	    HDAA_GPIO_SET(0) },
83 	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
84 	    HDAA_QUIRK_EAPDINV, 0,
85 	    0 },
86 	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
87 	    HDAA_QUIRK_EAPDINV, 0,
88 	    0 },
89 	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
90 	    HDAA_QUIRK_OVREF, 0,
91 	    0 },
92 	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
93 	    HDAA_QUIRK_OVREF, 0,
94 	    0 },
95 	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988, HDA_MATCH_ALL,
96 	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
97 	    0 },*/
98 	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
99 	    0, 0,
100 	    HDAA_GPIO_SET(1) },
101 	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
102 	    HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
103 	    0 },
104 	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
105 	    HDAA_QUIRK_EAPDINV, 0,
106 	    0 },
107 	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDA_MATCH_ALL,
108 	    HDAA_QUIRK_OVREF50, 0,
109 	    HDAA_GPIO_SET(0) },
110 	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDA_MATCH_ALL,
111 	    0, 0,
112 	    HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
113 	{ APPLE_MACBOOKAIR31, HDA_CODEC_CS4206, HDA_MATCH_ALL,
114 	    0, 0,
115 	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
116 	{ APPLE_MACBOOKPRO55, HDA_CODEC_CS4206, HDA_MATCH_ALL,
117 	    0, 0,
118 	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
119 	{ APPLE_MACBOOKPRO71, HDA_CODEC_CS4206, HDA_MATCH_ALL,
120 	    0, 0,
121 	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
122 	{ HDA_INTEL_MACBOOKPRO92, HDA_CODEC_CS4206, HDA_MATCH_ALL,
123 	    0, 0,
124 	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
125 	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
126 	    0, 0,
127 	    HDAA_GPIO_SET(0) },
128 	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X, HDA_MATCH_ALL,
129 	    0, 0,
130 	    HDAA_GPIO_SET(2) },
131 	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
132 	    0, 0,
133 	    HDAA_GPIO_SET(0) },
134 	{ HDA_MATCH_ALL, HDA_CODEC_AD1988, HDA_MATCH_ALL,
135 	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
136 	    0 },
137 	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B, HDA_MATCH_ALL,
138 	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
139 	    0 },
140 	{ HDA_MATCH_ALL, HDA_CODEC_CX20549, HDA_MATCH_ALL,
141 	    0, HDAA_QUIRK_FORCESTEREO,
142 	    0 },
143 	/* Mac Pro 1,1 requires ovref for proper volume level. */
144 	{ 0x00000000, HDA_CODEC_ALC885, 0x106b0c00,
145 	    0, HDAA_QUIRK_OVREF,
146 	    0 }
147 };
148 
149 static struct pin_patch_t *
150 match_pin_patches(int vendor_id, int vendor_subid)
151 {
152 	for (int ci = 0; ci < nitems(realtek_model_pin_patches); ci++) {
153 		struct hdaa_model_pin_patch_t *p = &realtek_model_pin_patches[ci];
154 		if (vendor_id != p->id)
155 			continue;
156 		for (struct model_pin_patch_t *pp =  p->patches; pp->models; pp++) {
157 			for (struct pin_machine_model_t *model = pp->models; model->id != 0; model++) {
158 				if (HDA_DEV_MATCH(model->id, vendor_subid))
159 					return (pp->pin_patches);
160 			}
161 		}
162 	}
163 
164 	return (0);
165 }
166 
167 static void
168 hdac_pin_patch(struct hdaa_widget *w)
169 {
170 	const char *patch_str = NULL;
171 	uint32_t config, orig, id, subid;
172 	nid_t nid = w->nid;
173 
174 	config = orig = w->wclass.pin.config;
175 	id = hdaa_codec_id(w->devinfo);
176 	subid = hdaa_card_id(w->devinfo);
177 
178 	if (id == HDA_CODEC_ALC883 && HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid)) {
179 		switch (nid) {
180 		case 25:
181 			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
182 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
183 			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
184 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
185 			break;
186 		case 28:
187 			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
188 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
189 			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
190 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
191 			break;
192 		}
193 	} else if (id == HDA_CODEC_CX20549 && subid ==
194 	    HP_V3000_SUBVENDOR) {
195 		switch (nid) {
196 		case 18:
197 			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
198 			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
199 			break;
200 		case 20:
201 			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
202 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
203 			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
204 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
205 			break;
206 		case 21:
207 			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
208 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
209 			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
210 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
211 			break;
212 		}
213 	} else if (id == HDA_CODEC_CX20551 && subid ==
214 	    HP_DV5000_SUBVENDOR) {
215 		switch (nid) {
216 		case 20:
217 		case 21:
218 			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
219 			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
220 			break;
221 		}
222 	}
223 
224 	/* New patches */
225 	if (id == HDA_CODEC_AD1984A &&
226 	    subid == LENOVO_X300_SUBVENDOR) {
227 		switch (nid) {
228 		case 17: /* Headphones with redirection */
229 			patch_str = "as=1 seq=15";
230 			break;
231 		case 20: /* Two mics together */
232 			patch_str = "as=2 seq=15";
233 			break;
234 		}
235 	} else if (id == HDA_CODEC_AD1986A &&
236 	    (subid == ASUS_M2NPVMX_SUBVENDOR ||
237 	    subid == ASUS_A8NVMCSM_SUBVENDOR ||
238 	    subid == ASUS_P5PL2_SUBVENDOR)) {
239 		switch (nid) {
240 		case 26: /* Headphones with redirection */
241 			patch_str = "as=1 seq=15";
242 			break;
243 		case 28: /* 5.1 out => 2.0 out + 1 input */
244 			patch_str = "device=Line-in as=8 seq=1";
245 			break;
246 		case 29: /* Can't use this as input, as the only available mic
247 			  * preamplifier is busy by front panel mic (nid 31).
248 			  * If you want to use this rear connector as mic input,
249 			  * you have to disable the front panel one. */
250 			patch_str = "as=0";
251 			break;
252 		case 31: /* Lot of inputs configured with as=15 and unusable */
253 			patch_str = "as=8 seq=3";
254 			break;
255 		case 32:
256 			patch_str = "as=8 seq=4";
257 			break;
258 		case 34:
259 			patch_str = "as=8 seq=5";
260 			break;
261 		case 36:
262 			patch_str = "as=8 seq=6";
263 			break;
264 		}
265 	} else if (id == HDA_CODEC_CX20561 &&
266 	    subid == LENOVO_B450_SUBVENDOR) {
267 		switch (nid) {
268 		case 22:
269 			patch_str = "as=1 seq=15";
270 			break;
271 		}
272 	} else if (id == HDA_CODEC_CX20561 &&
273 	    subid == LENOVO_T400_SUBVENDOR) {
274 		switch (nid) {
275 		case 22:
276 			patch_str = "as=1 seq=15";
277 			break;
278 		case 26:
279 			patch_str = "as=1 seq=0";
280 			break;
281 		}
282 	} else if (id == HDA_CODEC_CX20590 &&
283 	    (subid == LENOVO_X1_SUBVENDOR ||
284 	    subid == LENOVO_X220_SUBVENDOR ||
285 	    subid == LENOVO_T420_SUBVENDOR ||
286 	    subid == LENOVO_T520_SUBVENDOR ||
287 	    subid == LENOVO_G580_SUBVENDOR)) {
288 		switch (nid) {
289 		case 25:
290 			patch_str = "as=1 seq=15";
291 			break;
292 		/*
293 		 * Group onboard mic and headphone mic
294 		 * together.  Fixes onboard mic.
295 		 */
296 		case 27:
297 			patch_str = "as=2 seq=15";
298 			break;
299 		case 35:
300 			patch_str = "as=2";
301 			break;
302 		}
303 	} else if (id == HDA_CODEC_ALC235 && subid == ASUS_GL553VE_SUBVENDOR) {
304 		switch (nid) {
305 		case 33:
306 			patch_str = "as=1 seq=15";
307 			break;
308 		}
309 	} else if (id == HDA_CODEC_ALC256 && (subid == DELL_I7577_SUBVENDOR ||
310 	    subid == DELL_L7480_SUBVENDOR)) {
311 		switch (nid) {
312 		case 20:
313 			patch_str = "as=1 seq=0";
314 			break;
315 		case 33:
316 			patch_str = "as=1 seq=15";
317 			break;
318 		}
319 	} else if (id == HDA_CODEC_ALC257 &&
320 	    (subid == LENOVO_L5AMD_SUBVENDOR ||
321 	    subid == LENOVO_L5INTEL_SUBVENDOR)) {
322 		switch (nid) {
323 		case 20:
324 			patch_str = "as=1 seq=0";
325 			break;
326 		case 33:
327 			patch_str = "as=1 seq=15";
328 			break;
329 		}
330 	} else if (id == HDA_CODEC_IDT92HD95B &&
331 	    (subid == FRAMEWORK_LAPTOP_0001_SUBVENDOR ||
332 	    subid == FRAMEWORK_LAPTOP_0002_SUBVENDOR)) {
333 		switch (nid) {
334 		case 10:
335 			patch_str = "as=1 seq=15 color=Black loc=Left";
336 			break;
337 		case 11:
338 			patch_str = "as=3 seq=15 color=Black loc=Left";
339 			break;
340 		}
341 	} else if (id == HDA_CODEC_ALC230 &&
342 	    subid == LENOVO_I330_SUBVENDOR) {
343 		switch (nid) {
344 		case 20:
345 			patch_str = "as=1 seq=0 device=Speaker";
346 			break;
347 		case 33:
348 			patch_str = "as=1 seq=15 device=Headphones";
349 			break;
350 		}
351 	} else if (id == HDA_CODEC_ALC269 &&
352 	    subid == LENOVO_X230_SUBVENDOR) {
353 		switch (nid) {
354 		case 21:
355 			patch_str = "as=1 seq=15";
356 			break;
357 		case 24:
358 			patch_str = "as=4 seq=15";
359 			break;
360 		}
361 	} else {
362 		/*
363 		 * loop over hdaa_model_pin_patch
364 		 */
365 		struct pin_patch_t *pin_patches = NULL;
366 
367 		pin_patches = match_pin_patches(id, subid);
368 
369 		if (pin_patches != NULL) {
370 			for (struct pin_patch_t *patch = pin_patches; patch->type; patch++) {
371 				if (nid == patch->nid) {
372 					switch (patch->type) {
373 					case PIN_PATCH_TYPE_STRING:
374 						patch_str = patch->patch.string;
375 						break;
376 					case PIN_PATCH_TYPE_MASK:
377 						config &= ~patch->patch.mask[0];
378 						config |= patch->patch.mask[1];
379 						break;
380 					case PIN_PATCH_TYPE_OVERRIDE:
381 						config = patch->patch.override;
382 						break;
383 					default:
384 						/* should panic hard */
385 						break;
386 					}
387 					break;
388 				}
389 			}
390 		}
391 	}
392 
393 	if (patch_str != NULL)
394 		config = hdaa_widget_pin_patch(config, patch_str);
395 	HDA_BOOTVERBOSE(
396 		if (config != orig)
397 			device_printf(w->devinfo->dev,
398 			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
399 			    nid, orig, config);
400 	);
401 	w->wclass.pin.config = config;
402 }
403 
404 static void
405 hdaa_widget_patch(struct hdaa_widget *w)
406 {
407 	struct hdaa_devinfo *devinfo = w->devinfo;
408 	uint32_t orig;
409 	nid_t beeper = -1;
410 
411 	orig = w->param.widget_cap;
412 	/* On some codecs beeper is an input pin, but it is not recordable
413 	   alone. Also most of BIOSes does not declare beeper pin.
414 	   Change beeper pin node type to beeper to help parser. */
415 	switch (hdaa_codec_id(devinfo)) {
416 	case HDA_CODEC_AD1882:
417 	case HDA_CODEC_AD1883:
418 	case HDA_CODEC_AD1984:
419 	case HDA_CODEC_AD1984A:
420 	case HDA_CODEC_AD1984B:
421 	case HDA_CODEC_AD1987:
422 	case HDA_CODEC_AD1988:
423 	case HDA_CODEC_AD1988B:
424 	case HDA_CODEC_AD1989B:
425 		beeper = 26;
426 		break;
427 	case HDA_CODEC_ALC260:
428 		beeper = 23;
429 		break;
430 	}
431 	if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
432 	    hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
433 		beeper = 29;
434 	if (w->nid == beeper) {
435 		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
436 		w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
437 		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
438 		w->waspin = 1;
439 	}
440 	/*
441 	 * Clear "digital" flag from digital mic input, as its signal then goes
442 	 * to "analog" mixer and this separation just limits functionaity.
443 	 */
444 	if (hdaa_codec_id(devinfo) == HDA_CODEC_AD1984A &&
445 	    w->nid == 23)
446 		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK;
447 	HDA_BOOTVERBOSE(
448 		if (w->param.widget_cap != orig) {
449 			device_printf(w->devinfo->dev,
450 			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
451 			    w->nid, orig, w->param.widget_cap);
452 		}
453 	);
454 
455 	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
456 		hdac_pin_patch(w);
457 }
458 
459 void
460 hdaa_patch(struct hdaa_devinfo *devinfo)
461 {
462 	struct hdaa_widget *w;
463 	uint32_t id, subid, subsystemid;
464 	int i;
465 
466 	id = hdaa_codec_id(devinfo);
467 	subid = hdaa_card_id(devinfo);
468 	subsystemid = hda_get_subsystem_id(devinfo->dev);
469 
470 	/*
471 	 * Quirks
472 	 */
473 	for (i = 0; i < nitems(hdac_quirks); i++) {
474 		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
475 		    HDA_DEV_MATCH(hdac_quirks[i].id, id) &&
476 		    HDA_DEV_MATCH(hdac_quirks[i].subsystemid, subsystemid)))
477 			continue;
478 		devinfo->quirks |= hdac_quirks[i].set;
479 		devinfo->quirks &= ~(hdac_quirks[i].unset);
480 		devinfo->gpio = hdac_quirks[i].gpio;
481 	}
482 
483 	/* Apply per-widget patch. */
484 	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
485 		w = hdaa_widget_get(devinfo, i);
486 		if (w == NULL)
487 			continue;
488 		hdaa_widget_patch(w);
489 	}
490 
491 	switch (id) {
492 	case HDA_CODEC_AD1983:
493 		/*
494 		 * This CODEC has several possible usages, but none
495 		 * fit the parser best. Help parser to choose better.
496 		 */
497 		/* Disable direct unmixed playback to get pcm volume. */
498 		w = hdaa_widget_get(devinfo, 5);
499 		if (w != NULL)
500 			w->connsenable[0] = 0;
501 		w = hdaa_widget_get(devinfo, 6);
502 		if (w != NULL)
503 			w->connsenable[0] = 0;
504 		w = hdaa_widget_get(devinfo, 11);
505 		if (w != NULL)
506 			w->connsenable[0] = 0;
507 		/* Disable mic and line selectors. */
508 		w = hdaa_widget_get(devinfo, 12);
509 		if (w != NULL)
510 			w->connsenable[1] = 0;
511 		w = hdaa_widget_get(devinfo, 13);
512 		if (w != NULL)
513 			w->connsenable[1] = 0;
514 		/* Disable recording from mono playback mix. */
515 		w = hdaa_widget_get(devinfo, 20);
516 		if (w != NULL)
517 			w->connsenable[3] = 0;
518 		break;
519 	case HDA_CODEC_AD1986A:
520 		/*
521 		 * This CODEC has overcomplicated input mixing.
522 		 * Make some cleaning there.
523 		 */
524 		/* Disable input mono mixer. Not needed and not supported. */
525 		w = hdaa_widget_get(devinfo, 43);
526 		if (w != NULL)
527 			w->enable = 0;
528 		/* Disable any with any input mixing mesh. Use separately. */
529 		w = hdaa_widget_get(devinfo, 39);
530 		if (w != NULL)
531 			w->enable = 0;
532 		w = hdaa_widget_get(devinfo, 40);
533 		if (w != NULL)
534 			w->enable = 0;
535 		w = hdaa_widget_get(devinfo, 41);
536 		if (w != NULL)
537 			w->enable = 0;
538 		w = hdaa_widget_get(devinfo, 42);
539 		if (w != NULL)
540 			w->enable = 0;
541 		/* Disable duplicate mixer node connector. */
542 		w = hdaa_widget_get(devinfo, 15);
543 		if (w != NULL)
544 			w->connsenable[3] = 0;
545 		/* There is only one mic preamplifier, use it effectively. */
546 		w = hdaa_widget_get(devinfo, 31);
547 		if (w != NULL) {
548 			if ((w->wclass.pin.config &
549 			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
550 			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
551 				w = hdaa_widget_get(devinfo, 16);
552 				if (w != NULL)
553 				    w->connsenable[2] = 0;
554 			} else {
555 				w = hdaa_widget_get(devinfo, 15);
556 				if (w != NULL)
557 				    w->connsenable[0] = 0;
558 			}
559 		}
560 		w = hdaa_widget_get(devinfo, 32);
561 		if (w != NULL) {
562 			if ((w->wclass.pin.config &
563 			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
564 			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
565 				w = hdaa_widget_get(devinfo, 16);
566 				if (w != NULL)
567 				    w->connsenable[0] = 0;
568 			} else {
569 				w = hdaa_widget_get(devinfo, 15);
570 				if (w != NULL)
571 				    w->connsenable[1] = 0;
572 			}
573 		}
574 
575 		if (subid == ASUS_A8X_SUBVENDOR) {
576 			/*
577 			 * This is just plain ridiculous.. There
578 			 * are several A8 series that share the same
579 			 * pci id but works differently (EAPD).
580 			 */
581 			w = hdaa_widget_get(devinfo, 26);
582 			if (w != NULL && w->type ==
583 			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
584 			    (w->wclass.pin.config &
585 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
586 			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
587 				devinfo->quirks &=
588 				    ~HDAA_QUIRK_EAPDINV;
589 		}
590 		break;
591 	case HDA_CODEC_AD1981HD:
592 		/*
593 		 * This CODEC has very unusual design with several
594 		 * points inappropriate for the present parser.
595 		 */
596 		/* Disable recording from mono playback mix. */
597 		w = hdaa_widget_get(devinfo, 21);
598 		if (w != NULL)
599 			w->connsenable[3] = 0;
600 		/* Disable rear to front mic mixer, use separately. */
601 		w = hdaa_widget_get(devinfo, 31);
602 		if (w != NULL)
603 			w->enable = 0;
604 		/* Disable direct playback, use mixer. */
605 		w = hdaa_widget_get(devinfo, 5);
606 		if (w != NULL)
607 			w->connsenable[0] = 0;
608 		w = hdaa_widget_get(devinfo, 6);
609 		if (w != NULL)
610 			w->connsenable[0] = 0;
611 		w = hdaa_widget_get(devinfo, 9);
612 		if (w != NULL)
613 			w->connsenable[0] = 0;
614 		w = hdaa_widget_get(devinfo, 24);
615 		if (w != NULL)
616 			w->connsenable[0] = 0;
617 		break;
618 	case HDA_CODEC_ALC269:
619 		/*
620 		 * ASUS EeePC 1001px has strange variant of ALC269 CODEC,
621 		 * that mutes speaker if unused mixer at NID 15 is muted.
622 		 * Probably CODEC incorrectly reports internal connections.
623 		 * Hide that muter from the driver.  There are several CODECs
624 		 * sharing this ID and I have not enough information about
625 		 * them to implement more universal solution.
626 		 */
627 		if (subid == 0x84371043) {
628 			w = hdaa_widget_get(devinfo, 15);
629 			if (w != NULL)
630 				w->param.inamp_cap = 0;
631 		}
632 		break;
633 	case HDA_CODEC_CX20582:
634 	case HDA_CODEC_CX20583:
635 	case HDA_CODEC_CX20584:
636 	case HDA_CODEC_CX20585:
637 	case HDA_CODEC_CX20590:
638 		/*
639 		 * These codecs have extra connectivity on record side
640 		 * too reach for the present parser.
641 		 */
642 		w = hdaa_widget_get(devinfo, 20);
643 		if (w != NULL)
644 			w->connsenable[1] = 0;
645 		w = hdaa_widget_get(devinfo, 21);
646 		if (w != NULL)
647 			w->connsenable[1] = 0;
648 		w = hdaa_widget_get(devinfo, 22);
649 		if (w != NULL)
650 			w->connsenable[0] = 0;
651 		break;
652 	case HDA_CODEC_VT1708S_0:
653 	case HDA_CODEC_VT1708S_1:
654 	case HDA_CODEC_VT1708S_2:
655 	case HDA_CODEC_VT1708S_3:
656 	case HDA_CODEC_VT1708S_4:
657 	case HDA_CODEC_VT1708S_5:
658 	case HDA_CODEC_VT1708S_6:
659 	case HDA_CODEC_VT1708S_7:
660 		/*
661 		 * These codecs have hidden mic boost controls.
662 		 */
663 		w = hdaa_widget_get(devinfo, 26);
664 		if (w != NULL)
665 			w->param.inamp_cap =
666 			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
667 			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
668 			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
669 		w = hdaa_widget_get(devinfo, 30);
670 		if (w != NULL)
671 			w->param.inamp_cap =
672 			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
673 			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
674 			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
675 		break;
676 	}
677 }
678 
679 static uint32_t
680 hdaa_read_coef(device_t dev, nid_t nid, uint16_t idx)
681 {
682 
683 	hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, idx));
684 	return (hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, nid)));
685 }
686 
687 static uint32_t
688 hdaa_write_coef(device_t dev, nid_t nid, uint16_t idx, uint16_t val)
689 {
690 
691 	hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, idx));
692 	return (hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, nid, val)));
693 }
694 
695 void
696 hdaa_patch_direct(struct hdaa_devinfo *devinfo)
697 {
698 	device_t dev = devinfo->dev;
699 	uint32_t id, subid, val;
700 
701 	id = hdaa_codec_id(devinfo);
702 	subid = hdaa_card_id(devinfo);
703 
704 	switch (id) {
705 	case HDA_CODEC_VT1708S_0:
706 	case HDA_CODEC_VT1708S_1:
707 	case HDA_CODEC_VT1708S_2:
708 	case HDA_CODEC_VT1708S_3:
709 	case HDA_CODEC_VT1708S_4:
710 	case HDA_CODEC_VT1708S_5:
711 	case HDA_CODEC_VT1708S_6:
712 	case HDA_CODEC_VT1708S_7:
713 		/* Enable Mic Boost Volume controls. */
714 		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
715 		    0xf98, 0x01));
716 		/* Fall though */
717 	case HDA_CODEC_VT1818S:
718 		/* Don't bypass mixer. */
719 		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
720 		    0xf88, 0xc0));
721 		break;
722 	case HDA_CODEC_ALC1150:
723 		if (subid == 0xd9781462) {
724 			/* Too low volume on MSI H170 GAMING M3. */
725 			hdaa_write_coef(dev, 0x20, 0x07, 0x7cb);
726 		}
727 		break;
728 	}
729 	if (id == HDA_CODEC_ALC255 || id == HDA_CODEC_ALC256) {
730 		val = hdaa_read_coef(dev, 0x20, 0x46);
731 		hdaa_write_coef(dev, 0x20, 0x46, val|0x3000);
732 	}
733 	if (subid == APPLE_INTEL_MAC)
734 		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
735 		    0x7e7, 0));
736 	if (id == HDA_CODEC_ALC269) {
737 		if (subid == 0x16e31043 || subid == 0x831a1043 ||
738 		    subid == 0x834a1043 || subid == 0x83981043 ||
739 		    subid == 0x83ce1043) {
740 			/*
741 			 * The digital mics on some Asus laptops produce
742 			 * differential signals instead of expected stereo.
743 			 * That results in silence if downmixing to mono.
744 			 * To workaround, make codec handle the signal as mono.
745 			 */
746 			val = hdaa_read_coef(dev, 0x20, 0x07);
747 			hdaa_write_coef(dev, 0x20, 0x07, val|0x80);
748 		}
749 		if (subid == 0x15171043) {
750 			/* Increase output amp on ASUS UX31A by +5dB. */
751 			hdaa_write_coef(dev, 0x20, 0x12, 0x2800);
752 		}
753 	}
754 }
755