1230130Smav/*-
2230130Smav * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3230130Smav * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4230130Smav * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
5230130Smav * All rights reserved.
6230130Smav *
7230130Smav * Redistribution and use in source and binary forms, with or without
8230130Smav * modification, are permitted provided that the following conditions
9230130Smav * are met:
10230130Smav * 1. Redistributions of source code must retain the above copyright
11230130Smav *    notice, this list of conditions and the following disclaimer.
12230130Smav * 2. Redistributions in binary form must reproduce the above copyright
13230130Smav *    notice, this list of conditions and the following disclaimer in the
14230130Smav *    documentation and/or other materials provided with the distribution.
15230130Smav *
16230130Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17230130Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18230130Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19230130Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20230130Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21230130Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22230130Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23230130Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24230130Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25230130Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26230130Smav * SUCH DAMAGE.
27230130Smav */
28230130Smav
29230130Smav/*
30230130Smav * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
31230130Smav */
32230130Smav
33230130Smav#ifdef HAVE_KERNEL_OPTION_HEADERS
34230130Smav#include "opt_snd.h"
35230130Smav#endif
36230130Smav
37230130Smav#include <dev/sound/pcm/sound.h>
38230130Smav
39230130Smav#include <sys/ctype.h>
40230130Smav
41230130Smav#include <dev/sound/pci/hda/hdac.h>
42230130Smav#include <dev/sound/pci/hda/hdaa.h>
43230130Smav#include <dev/sound/pci/hda/hda_reg.h>
44230130Smav
45230130SmavSND_DECLARE_FILE("$FreeBSD$");
46230130Smav
47230130Smavstatic const struct {
48230130Smav	uint32_t model;
49230130Smav	uint32_t id;
50230130Smav	uint32_t set, unset;
51230130Smav	uint32_t gpio;
52230130Smav} hdac_quirks[] = {
53230130Smav	/*
54230130Smav	 * XXX Force stereo quirk. Monoural recording / playback
55230130Smav	 *     on few codecs (especially ALC880) seems broken or
56230130Smav	 *     perhaps unsupported.
57230130Smav	 */
58230130Smav	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
59230130Smav	    HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
60230130Smav	    0 },
61230130Smav	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
62230130Smav	    0, 0,
63230130Smav	    HDAA_GPIO_SET(0) },
64230130Smav	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
65230130Smav	    0, 0,
66230130Smav	    HDAA_GPIO_SET(0) },
67230130Smav	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
68230130Smav	    0, 0,
69230130Smav	    HDAA_GPIO_SET(0) },
70230130Smav	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
71230130Smav	    0, 0,
72230130Smav	    HDAA_GPIO_SET(0) },
73230130Smav	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
74230130Smav	    0, 0,
75230130Smav	    HDAA_GPIO_SET(0) },
76230130Smav	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
77230130Smav	    0, 0,
78230130Smav	    HDAA_GPIO_SET(0) },
79230130Smav	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
80230130Smav	    HDAA_QUIRK_EAPDINV, 0,
81230130Smav	    0 },
82230130Smav	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
83230130Smav	    HDAA_QUIRK_EAPDINV, 0,
84230130Smav	    0 },
85230130Smav	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
86230130Smav	    HDAA_QUIRK_OVREF, 0,
87230130Smav	    0 },
88230130Smav	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
89230130Smav	    HDAA_QUIRK_OVREF, 0,
90230130Smav	    0 },
91230130Smav	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
92230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
93230130Smav	    0 },*/
94230130Smav	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
95230130Smav	    0, 0,
96230130Smav	    HDAA_GPIO_SET(1) },
97230130Smav	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
98230130Smav	    HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
99230130Smav	    0 },
100230130Smav	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
101230130Smav	    HDAA_QUIRK_EAPDINV, 0,
102230130Smav	    0 },
103230130Smav	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
104230130Smav	    HDAA_QUIRK_OVREF50, 0,
105230130Smav	    HDAA_GPIO_SET(0) },
106230130Smav	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
107230130Smav	    0, 0,
108230130Smav	    HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
109261793Shselasky	{ APPLE_MACBOOKAIR31, HDA_CODEC_CS4206,
110261793Shselasky	    0, 0,
111261793Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
112230130Smav	{ APPLE_MACBOOKPRO55, HDA_CODEC_CS4206,
113230130Smav	    0, 0,
114230130Smav	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
115261793Shselasky	{ APPLE_MACBOOKPRO71, HDA_CODEC_CS4206,
116261793Shselasky	    0, 0,
117261793Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
118261793Shselasky	{ HDA_INTEL_MACBOOKPRO92, HDA_CODEC_CS4206,
119261793Shselasky	    0, 0,
120261793Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
121230130Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
122230130Smav	    0, 0,
123230130Smav	    HDAA_GPIO_SET(0) },
124230130Smav	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
125230130Smav	    0, 0,
126230130Smav	    HDAA_GPIO_SET(2) },
127230130Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
128230130Smav	    0, 0,
129230130Smav	    HDAA_GPIO_SET(0) },
130230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
131230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
132230130Smav	    0 },
133230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
134230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
135230130Smav	    0 },
136230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_CX20549,
137230130Smav	    0, HDAA_QUIRK_FORCESTEREO,
138230130Smav	    0 }
139230130Smav};
140230130Smav#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
141230130Smav
142230130Smavstatic void
143230130Smavhdac_pin_patch(struct hdaa_widget *w)
144230130Smav{
145230130Smav	const char *patch = NULL;
146230130Smav	uint32_t config, orig, id, subid;
147230130Smav	nid_t nid = w->nid;
148230130Smav
149230130Smav	config = orig = w->wclass.pin.config;
150230130Smav	id = hdaa_codec_id(w->devinfo);
151243060Smav	subid = hdaa_card_id(w->devinfo);
152230130Smav
153230130Smav	/* XXX: Old patches require complete review.
154230130Smav	 * Now they may create more problem then solve due to
155230130Smav	 * incorrect associations.
156230130Smav	 */
157230130Smav	if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
158230130Smav		switch (nid) {
159230130Smav		case 26:
160230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
161230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
162230130Smav			break;
163230130Smav		case 27:
164230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
165230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
166230130Smav			break;
167230130Smav		default:
168230130Smav			break;
169230130Smav		}
170230130Smav	} else if (id == HDA_CODEC_ALC880 &&
171230130Smav	    (subid == CLEVO_D900T_SUBVENDOR ||
172230130Smav	    subid == ASUS_M5200_SUBVENDOR)) {
173230130Smav		/*
174230130Smav		 * Super broken BIOS
175230130Smav		 */
176230130Smav		switch (nid) {
177230130Smav		case 24:	/* MIC1 */
178230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
179230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
180230130Smav			break;
181230130Smav		case 25:	/* XXX MIC2 */
182230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
183230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
184230130Smav			break;
185230130Smav		case 26:	/* LINE1 */
186230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
187230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
188230130Smav			break;
189230130Smav		case 27:	/* XXX LINE2 */
190230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
191230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
192230130Smav			break;
193230130Smav		case 28:	/* CD */
194230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
195230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
196230130Smav			break;
197230130Smav		}
198230130Smav	} else if (id == HDA_CODEC_ALC883 &&
199230130Smav	    (subid == MSI_MS034A_SUBVENDOR ||
200230130Smav	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
201230130Smav		switch (nid) {
202230130Smav		case 25:
203230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
204230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
205230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
206230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
207230130Smav			break;
208230130Smav		case 28:
209230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
210230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
211230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
212230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
213230130Smav			break;
214230130Smav		}
215230130Smav	} else if (id == HDA_CODEC_CX20549 && subid ==
216230130Smav	    HP_V3000_SUBVENDOR) {
217230130Smav		switch (nid) {
218230130Smav		case 18:
219230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
220230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
221230130Smav			break;
222230130Smav		case 20:
223230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
224230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
225230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
226230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
227230130Smav			break;
228230130Smav		case 21:
229230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
230230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
231230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
232230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
233230130Smav			break;
234230130Smav		}
235230130Smav	} else if (id == HDA_CODEC_CX20551 && subid ==
236230130Smav	    HP_DV5000_SUBVENDOR) {
237230130Smav		switch (nid) {
238230130Smav		case 20:
239230130Smav		case 21:
240230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
241230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
242230130Smav			break;
243230130Smav		}
244230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
245230130Smav	    ASUS_W6F_SUBVENDOR) {
246230130Smav		switch (nid) {
247230130Smav		case 11:
248230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
249230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
250230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
251230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
252230130Smav			break;
253230130Smav		case 12:
254230130Smav		case 14:
255230130Smav		case 16:
256230130Smav		case 31:
257230130Smav		case 32:
258230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
259230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
260230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
261230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
262230130Smav			break;
263230130Smav		case 15:
264230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
265230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
266230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
267230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
268230130Smav			break;
269230130Smav		}
270230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
271230130Smav	    UNIWILL_9075_SUBVENDOR) {
272230130Smav		switch (nid) {
273230130Smav		case 15:
274230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
275230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
276230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
277230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
278230130Smav			break;
279230130Smav		}
280230130Smav	}
281230130Smav
282230130Smav	/* New patches */
283244712Smav	if (id == HDA_CODEC_AD1984A &&
284244712Smav	    subid == LENOVO_X300_SUBVENDOR) {
285244712Smav		switch (nid) {
286244712Smav		case 17: /* Headphones with redirection */
287244712Smav			patch = "as=1 seq=15";
288244712Smav			break;
289244712Smav		case 20: /* Two mics together */
290244712Smav			patch = "as=2 seq=15";
291244712Smav			break;
292244712Smav		}
293244712Smav	} else if (id == HDA_CODEC_AD1986A &&
294230130Smav	    (subid == ASUS_M2NPVMX_SUBVENDOR ||
295230130Smav	    subid == ASUS_A8NVMCSM_SUBVENDOR ||
296230130Smav	    subid == ASUS_P5PL2_SUBVENDOR)) {
297230130Smav		switch (nid) {
298230130Smav		case 26: /* Headphones with redirection */
299230130Smav			patch = "as=1 seq=15";
300230130Smav			break;
301230130Smav		case 28: /* 5.1 out => 2.0 out + 1 input */
302230130Smav			patch = "device=Line-in as=8 seq=1";
303230130Smav			break;
304230130Smav		case 29: /* Can't use this as input, as the only available mic
305230130Smav			  * preamplifier is busy by front panel mic (nid 31).
306230130Smav			  * If you want to use this rear connector as mic input,
307230130Smav			  * you have to disable the front panel one. */
308230130Smav			patch = "as=0";
309230130Smav			break;
310230130Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
311230130Smav			patch = "as=8 seq=3";
312230130Smav			break;
313230130Smav		case 32:
314230130Smav			patch = "as=8 seq=4";
315230130Smav			break;
316230130Smav		case 34:
317230130Smav			patch = "as=8 seq=5";
318230130Smav			break;
319230130Smav		case 36:
320230130Smav			patch = "as=8 seq=6";
321230130Smav			break;
322230130Smav		}
323230130Smav	} else if (id == HDA_CODEC_ALC260 &&
324230130Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
325230130Smav		switch (nid) {
326230130Smav		case 16:
327230130Smav			patch = "seq=15 device=Headphones";
328230130Smav			break;
329230130Smav		}
330230130Smav	} else if (id == HDA_CODEC_ALC268) {
331230130Smav	    if (subid == ACER_T5320_SUBVENDOR) {
332230130Smav		switch (nid) {
333230130Smav		case 20: /* Headphones Jack */
334230130Smav			patch = "as=1 seq=15";
335230130Smav			break;
336230130Smav		}
337230130Smav	    }
338230130Smav	} else if (id == HDA_CODEC_CX20561 &&
339230130Smav	    subid == LENOVO_B450_SUBVENDOR) {
340230130Smav		switch (nid) {
341230130Smav		case 22:
342230130Smav			patch = "as=1 seq=15";
343230130Smav			break;
344230130Smav		}
345248148Smav	} else if (id == HDA_CODEC_CX20590 &&
346252148Sglebius	    (subid == LENOVO_X1_SUBVENDOR ||
347252148Sglebius	    subid == LENOVO_X220_SUBVENDOR ||
348252148Sglebius	    subid == LENOVO_T420_SUBVENDOR ||
349252148Sglebius	    subid == LENOVO_T520_SUBVENDOR)) {
350248148Smav		switch (nid) {
351248148Smav		case 25:
352248148Smav			patch = "as=1 seq=15";
353248148Smav			break;
354264957Smarius		/*
355252148Sglebius		 * Group onboard mic and headphone mic
356252148Sglebius		 * together.  Fixes onboard mic.
357252148Sglebius		 */
358252148Sglebius		case 27:
359252148Sglebius			patch = "as=2 seq=15";
360252148Sglebius			break;
361252148Sglebius		case 35:
362252148Sglebius			patch = "as=2";
363252148Sglebius			break;
364248148Smav		}
365252148Sglebius	} else if (id == HDA_CODEC_ALC269 &&
366252148Sglebius	    (subid == LENOVO_X1CRBN_SUBVENDOR ||
367252148Sglebius	    subid == LENOVO_T430_SUBVENDOR ||
368252148Sglebius	    subid == LENOVO_T430S_SUBVENDOR ||
369252148Sglebius	    subid == LENOVO_T530_SUBVENDOR)) {
370252148Sglebius		switch (nid) {
371252148Sglebius		case 21:
372252148Sglebius			patch = "as=1 seq=15";
373252148Sglebius			break;
374252148Sglebius		}
375253193Smav	} else if (id == HDA_CODEC_ALC269 &&
376253193Smav	    subid == ASUS_UX31A_SUBVENDOR) {
377253193Smav		switch (nid) {
378253193Smav		case 33:
379253193Smav			patch = "as=1 seq=15";
380253193Smav			break;
381253193Smav		}
382264957Smarius	} else if (id == HDA_CODEC_ALC892 &&
383264957Smarius	    subid == INTEL_DH87RL_SUBVENDOR) {
384264957Smarius		switch (nid) {
385264957Smarius		case 27:
386264957Smarius			patch = "as=1 seq=15";
387264957Smarius			break;
388264957Smarius		}
389230130Smav	}
390230130Smav
391230130Smav	if (patch != NULL)
392230130Smav		config = hdaa_widget_pin_patch(config, patch);
393230130Smav	HDA_BOOTVERBOSE(
394230130Smav		if (config != orig)
395230130Smav			device_printf(w->devinfo->dev,
396230130Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
397230130Smav			    nid, orig, config);
398230130Smav	);
399230130Smav	w->wclass.pin.config = config;
400230130Smav}
401230130Smav
402230130Smavstatic void
403230130Smavhdaa_widget_patch(struct hdaa_widget *w)
404230130Smav{
405230130Smav	struct hdaa_devinfo *devinfo = w->devinfo;
406230130Smav	uint32_t orig;
407230130Smav	nid_t beeper = -1;
408230130Smav
409230130Smav	orig = w->param.widget_cap;
410230130Smav	/* On some codecs beeper is an input pin, but it is not recordable
411230130Smav	   alone. Also most of BIOSes does not declare beeper pin.
412230130Smav	   Change beeper pin node type to beeper to help parser. */
413230130Smav	switch (hdaa_codec_id(devinfo)) {
414230130Smav	case HDA_CODEC_AD1882:
415230130Smav	case HDA_CODEC_AD1883:
416230130Smav	case HDA_CODEC_AD1984:
417230130Smav	case HDA_CODEC_AD1984A:
418230130Smav	case HDA_CODEC_AD1984B:
419230130Smav	case HDA_CODEC_AD1987:
420230130Smav	case HDA_CODEC_AD1988:
421230130Smav	case HDA_CODEC_AD1988B:
422230130Smav	case HDA_CODEC_AD1989B:
423230130Smav		beeper = 26;
424230130Smav		break;
425230130Smav	case HDA_CODEC_ALC260:
426230130Smav		beeper = 23;
427230130Smav		break;
428230130Smav	}
429230130Smav	if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
430230130Smav	    hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
431230130Smav		beeper = 29;
432230130Smav	if (w->nid == beeper) {
433230130Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
434230130Smav		w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
435230130Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
436230130Smav		w->waspin = 1;
437230130Smav	}
438244712Smav	/*
439244712Smav	 * Clear "digital" flag from digital mic input, as its signal then goes
440244712Smav	 * to "analog" mixer and this separation just limits functionaity.
441244712Smav	 */
442244712Smav	if (hdaa_codec_id(devinfo) == HDA_CODEC_AD1984A &&
443244712Smav	    w->nid == 23)
444244712Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK;
445230130Smav	HDA_BOOTVERBOSE(
446230130Smav		if (w->param.widget_cap != orig) {
447230130Smav			device_printf(w->devinfo->dev,
448230130Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
449230130Smav			    w->nid, orig, w->param.widget_cap);
450230130Smav		}
451230130Smav	);
452230130Smav
453230130Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
454230130Smav		hdac_pin_patch(w);
455230130Smav}
456230130Smav
457230130Smavvoid
458230130Smavhdaa_patch(struct hdaa_devinfo *devinfo)
459230130Smav{
460230130Smav	struct hdaa_widget *w;
461230130Smav	uint32_t id, subid;
462230130Smav	int i;
463230130Smav
464230130Smav	id = hdaa_codec_id(devinfo);
465243060Smav	subid = hdaa_card_id(devinfo);
466230130Smav
467230130Smav	/*
468230130Smav	 * Quirks
469230130Smav	 */
470230130Smav	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
471230130Smav		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
472230130Smav		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
473230130Smav			continue;
474238131Smav		devinfo->quirks |= hdac_quirks[i].set;
475238131Smav		devinfo->quirks &= ~(hdac_quirks[i].unset);
476238131Smav		devinfo->gpio = hdac_quirks[i].gpio;
477230130Smav	}
478230130Smav
479230130Smav	/* Apply per-widget patch. */
480230130Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
481230130Smav		w = hdaa_widget_get(devinfo, i);
482230130Smav		if (w == NULL)
483230130Smav			continue;
484230130Smav		hdaa_widget_patch(w);
485230130Smav	}
486230130Smav
487230130Smav	switch (id) {
488230130Smav	case HDA_CODEC_AD1983:
489230130Smav		/*
490230130Smav		 * This CODEC has several possible usages, but none
491230130Smav		 * fit the parser best. Help parser to choose better.
492230130Smav		 */
493230130Smav		/* Disable direct unmixed playback to get pcm volume. */
494230130Smav		w = hdaa_widget_get(devinfo, 5);
495230130Smav		if (w != NULL)
496230130Smav			w->connsenable[0] = 0;
497230130Smav		w = hdaa_widget_get(devinfo, 6);
498230130Smav		if (w != NULL)
499230130Smav			w->connsenable[0] = 0;
500230130Smav		w = hdaa_widget_get(devinfo, 11);
501230130Smav		if (w != NULL)
502230130Smav			w->connsenable[0] = 0;
503230130Smav		/* Disable mic and line selectors. */
504230130Smav		w = hdaa_widget_get(devinfo, 12);
505230130Smav		if (w != NULL)
506230130Smav			w->connsenable[1] = 0;
507230130Smav		w = hdaa_widget_get(devinfo, 13);
508230130Smav		if (w != NULL)
509230130Smav			w->connsenable[1] = 0;
510230130Smav		/* Disable recording from mono playback mix. */
511230130Smav		w = hdaa_widget_get(devinfo, 20);
512230130Smav		if (w != NULL)
513230130Smav			w->connsenable[3] = 0;
514230130Smav		break;
515230130Smav	case HDA_CODEC_AD1986A:
516230130Smav		/*
517230130Smav		 * This CODEC has overcomplicated input mixing.
518230130Smav		 * Make some cleaning there.
519230130Smav		 */
520230130Smav		/* Disable input mono mixer. Not needed and not supported. */
521230130Smav		w = hdaa_widget_get(devinfo, 43);
522230130Smav		if (w != NULL)
523230130Smav			w->enable = 0;
524230130Smav		/* Disable any with any input mixing mesh. Use separately. */
525230130Smav		w = hdaa_widget_get(devinfo, 39);
526230130Smav		if (w != NULL)
527230130Smav			w->enable = 0;
528230130Smav		w = hdaa_widget_get(devinfo, 40);
529230130Smav		if (w != NULL)
530230130Smav			w->enable = 0;
531230130Smav		w = hdaa_widget_get(devinfo, 41);
532230130Smav		if (w != NULL)
533230130Smav			w->enable = 0;
534230130Smav		w = hdaa_widget_get(devinfo, 42);
535230130Smav		if (w != NULL)
536230130Smav			w->enable = 0;
537230130Smav		/* Disable duplicate mixer node connector. */
538230130Smav		w = hdaa_widget_get(devinfo, 15);
539230130Smav		if (w != NULL)
540230130Smav			w->connsenable[3] = 0;
541230130Smav		/* There is only one mic preamplifier, use it effectively. */
542230130Smav		w = hdaa_widget_get(devinfo, 31);
543230130Smav		if (w != NULL) {
544230130Smav			if ((w->wclass.pin.config &
545230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
546230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
547230130Smav				w = hdaa_widget_get(devinfo, 16);
548230130Smav				if (w != NULL)
549230130Smav				    w->connsenable[2] = 0;
550230130Smav			} else {
551230130Smav				w = hdaa_widget_get(devinfo, 15);
552230130Smav				if (w != NULL)
553230130Smav				    w->connsenable[0] = 0;
554230130Smav			}
555230130Smav		}
556230130Smav		w = hdaa_widget_get(devinfo, 32);
557230130Smav		if (w != NULL) {
558230130Smav			if ((w->wclass.pin.config &
559230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
560230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
561230130Smav				w = hdaa_widget_get(devinfo, 16);
562230130Smav				if (w != NULL)
563230130Smav				    w->connsenable[0] = 0;
564230130Smav			} else {
565230130Smav				w = hdaa_widget_get(devinfo, 15);
566230130Smav				if (w != NULL)
567230130Smav				    w->connsenable[1] = 0;
568230130Smav			}
569230130Smav		}
570230130Smav
571230130Smav		if (subid == ASUS_A8X_SUBVENDOR) {
572230130Smav			/*
573230130Smav			 * This is just plain ridiculous.. There
574230130Smav			 * are several A8 series that share the same
575230130Smav			 * pci id but works differently (EAPD).
576230130Smav			 */
577230130Smav			w = hdaa_widget_get(devinfo, 26);
578230130Smav			if (w != NULL && w->type ==
579230130Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
580230130Smav			    (w->wclass.pin.config &
581230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
582230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
583230130Smav				devinfo->quirks &=
584230130Smav				    ~HDAA_QUIRK_EAPDINV;
585230130Smav		}
586230130Smav		break;
587230130Smav	case HDA_CODEC_AD1981HD:
588230130Smav		/*
589230130Smav		 * This CODEC has very unusual design with several
590230130Smav		 * points inappropriate for the present parser.
591230130Smav		 */
592230130Smav		/* Disable recording from mono playback mix. */
593230130Smav		w = hdaa_widget_get(devinfo, 21);
594230130Smav		if (w != NULL)
595230130Smav			w->connsenable[3] = 0;
596230130Smav		/* Disable rear to front mic mixer, use separately. */
597230130Smav		w = hdaa_widget_get(devinfo, 31);
598230130Smav		if (w != NULL)
599230130Smav			w->enable = 0;
600230130Smav		/* Disable direct playback, use mixer. */
601230130Smav		w = hdaa_widget_get(devinfo, 5);
602230130Smav		if (w != NULL)
603230130Smav			w->connsenable[0] = 0;
604230130Smav		w = hdaa_widget_get(devinfo, 6);
605230130Smav		if (w != NULL)
606230130Smav			w->connsenable[0] = 0;
607230130Smav		w = hdaa_widget_get(devinfo, 9);
608230130Smav		if (w != NULL)
609230130Smav			w->connsenable[0] = 0;
610230130Smav		w = hdaa_widget_get(devinfo, 24);
611230130Smav		if (w != NULL)
612230130Smav			w->connsenable[0] = 0;
613230130Smav		break;
614243064Smav	case HDA_CODEC_ALC269:
615243064Smav		/*
616243064Smav		 * ASUS EeePC 1001px has strange variant of ALC269 CODEC,
617243064Smav		 * that mutes speaker if unused mixer at NID 15 is muted.
618243064Smav		 * Probably CODEC incorrectly reports internal connections.
619243064Smav		 * Hide that muter from the driver.  There are several CODECs
620243064Smav		 * sharing this ID and I have not enough information about
621243064Smav		 * them to implement more universal solution.
622243064Smav		 */
623243064Smav		if (subid == 0x84371043) {
624243064Smav			w = hdaa_widget_get(devinfo, 15);
625243064Smav			if (w != NULL)
626243064Smav				w->param.inamp_cap = 0;
627243064Smav		}
628243064Smav		break;
629230130Smav	case HDA_CODEC_CX20582:
630230130Smav	case HDA_CODEC_CX20583:
631230130Smav	case HDA_CODEC_CX20584:
632230130Smav	case HDA_CODEC_CX20585:
633230130Smav	case HDA_CODEC_CX20590:
634230130Smav		/*
635230130Smav		 * These codecs have extra connectivity on record side
636230130Smav		 * too reach for the present parser.
637230130Smav		 */
638230130Smav		w = hdaa_widget_get(devinfo, 20);
639230130Smav		if (w != NULL)
640230130Smav			w->connsenable[1] = 0;
641230130Smav		w = hdaa_widget_get(devinfo, 21);
642230130Smav		if (w != NULL)
643230130Smav			w->connsenable[1] = 0;
644230130Smav		w = hdaa_widget_get(devinfo, 22);
645230130Smav		if (w != NULL)
646230130Smav			w->connsenable[0] = 0;
647230130Smav		break;
648230130Smav	case HDA_CODEC_VT1708S_0:
649230130Smav	case HDA_CODEC_VT1708S_1:
650230130Smav	case HDA_CODEC_VT1708S_2:
651230130Smav	case HDA_CODEC_VT1708S_3:
652230130Smav	case HDA_CODEC_VT1708S_4:
653230130Smav	case HDA_CODEC_VT1708S_5:
654230130Smav	case HDA_CODEC_VT1708S_6:
655230130Smav	case HDA_CODEC_VT1708S_7:
656230130Smav		/*
657230130Smav		 * These codecs have hidden mic boost controls.
658230130Smav		 */
659230130Smav		w = hdaa_widget_get(devinfo, 26);
660230130Smav		if (w != NULL)
661230130Smav			w->param.inamp_cap =
662230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
663230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
664230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
665230130Smav		w = hdaa_widget_get(devinfo, 30);
666230130Smav		if (w != NULL)
667230130Smav			w->param.inamp_cap =
668230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
669230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
670230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
671230130Smav		break;
672230130Smav	}
673230130Smav}
674230130Smav
675230130Smavvoid
676230130Smavhdaa_patch_direct(struct hdaa_devinfo *devinfo)
677230130Smav{
678230130Smav	device_t dev = devinfo->dev;
679230130Smav	uint32_t id, subid, val;
680230130Smav
681230130Smav	id = hdaa_codec_id(devinfo);
682243060Smav	subid = hdaa_card_id(devinfo);
683230130Smav
684230130Smav	switch (id) {
685230130Smav	case HDA_CODEC_VT1708S_0:
686230130Smav	case HDA_CODEC_VT1708S_1:
687230130Smav	case HDA_CODEC_VT1708S_2:
688230130Smav	case HDA_CODEC_VT1708S_3:
689230130Smav	case HDA_CODEC_VT1708S_4:
690230130Smav	case HDA_CODEC_VT1708S_5:
691230130Smav	case HDA_CODEC_VT1708S_6:
692230130Smav	case HDA_CODEC_VT1708S_7:
693230130Smav		/* Enable Mic Boost Volume controls. */
694230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
695230130Smav		    0xf98, 0x01));
696241742Smav		/* Fall though */
697241742Smav	case HDA_CODEC_VT1818S:
698230130Smav		/* Don't bypass mixer. */
699230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
700230130Smav		    0xf88, 0xc0));
701230130Smav		break;
702230130Smav	}
703230130Smav	if (subid == APPLE_INTEL_MAC)
704230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
705230130Smav		    0x7e7, 0));
706230130Smav	if (id == HDA_CODEC_ALC269) {
707232798Smav		if (subid == 0x16e31043 || subid == 0x831a1043 ||
708232798Smav		    subid == 0x834a1043 || subid == 0x83981043 ||
709232798Smav		    subid == 0x83ce1043) {
710230130Smav			/*
711230130Smav			 * The ditital mics on some Asus laptops produce
712230130Smav			 * differential signals instead of expected stereo.
713230130Smav			 * That results in silence if downmix it to mono.
714230130Smav			 * To workaround, make codec to handle signal as mono.
715230130Smav			 */
716230130Smav			hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
717230130Smav			val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, 0x20));
718230130Smav			hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
719230130Smav			hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, 0x20, val|0x80));
720230130Smav		}
721230130Smav	}
722230130Smav}
723