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