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