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