summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci/hda/hdaa_patches.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pci/hda/hdaa_patches.c')
-rw-r--r--sys/dev/sound/pci/hda/hdaa_patches.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/sys/dev/sound/pci/hda/hdaa_patches.c b/sys/dev/sound/pci/hda/hdaa_patches.c
new file mode 100644
index 0000000..b20c339
--- /dev/null
+++ b/sys/dev/sound/pci/hda/hdaa_patches.c
@@ -0,0 +1,638 @@
+/*-
+ * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
+ * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
+ * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
+ */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+
+#include <sys/ctype.h>
+
+#include <dev/sound/pci/hda/hdac.h>
+#include <dev/sound/pci/hda/hdaa.h>
+#include <dev/sound/pci/hda/hda_reg.h>
+
+SND_DECLARE_FILE("$FreeBSD$");
+
+static const struct {
+ uint32_t model;
+ uint32_t id;
+ uint32_t set, unset;
+ uint32_t gpio;
+} hdac_quirks[] = {
+ /*
+ * XXX Force stereo quirk. Monoural recording / playback
+ * on few codecs (especially ALC880) seems broken or
+ * perhaps unsupported.
+ */
+ { HDA_MATCH_ALL, HDA_MATCH_ALL,
+ HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
+ 0 },
+ { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
+ HDAA_QUIRK_EAPDINV, 0,
+ 0 },
+ { ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
+ HDAA_QUIRK_EAPDINV, 0,
+ 0 },
+ { ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
+ HDAA_QUIRK_OVREF, 0,
+ 0 },
+ { UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
+ HDAA_QUIRK_OVREF, 0,
+ 0 },
+ /*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
+ HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
+ 0 },*/
+ { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
+ 0, 0,
+ HDAA_GPIO_SET(1) },
+ { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
+ HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
+ 0 },
+ { SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
+ HDAA_QUIRK_EAPDINV, 0,
+ 0 },
+ { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
+ HDAA_QUIRK_OVREF50, 0,
+ HDAA_GPIO_SET(0) },
+ { APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
+ 0, 0,
+ HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
+ { APPLE_MACBOOKPRO55, HDA_CODEC_CS4206,
+ 0, 0,
+ HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
+ { DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
+ 0, 0,
+ HDAA_GPIO_SET(2) },
+ { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
+ 0, 0,
+ HDAA_GPIO_SET(0) },
+ { HDA_MATCH_ALL, HDA_CODEC_AD1988,
+ HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
+ 0 },
+ { HDA_MATCH_ALL, HDA_CODEC_AD1988B,
+ HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
+ 0 },
+ { HDA_MATCH_ALL, HDA_CODEC_CX20549,
+ 0, HDAA_QUIRK_FORCESTEREO,
+ 0 }
+};
+#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
+
+static void
+hdac_pin_patch(struct hdaa_widget *w)
+{
+ const char *patch = NULL;
+ uint32_t config, orig, id, subid;
+ nid_t nid = w->nid;
+
+ config = orig = w->wclass.pin.config;
+ id = hdaa_codec_id(w->devinfo);
+ subid = hdaa_subvendor_id(w->devinfo);
+
+ /* XXX: Old patches require complete review.
+ * Now they may create more problem then solve due to
+ * incorrect associations.
+ */
+ if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
+ switch (nid) {
+ case 26:
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
+ break;
+ case 27:
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
+ break;
+ default:
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC880 &&
+ (subid == CLEVO_D900T_SUBVENDOR ||
+ subid == ASUS_M5200_SUBVENDOR)) {
+ /*
+ * Super broken BIOS
+ */
+ switch (nid) {
+ case 24: /* MIC1 */
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
+ break;
+ case 25: /* XXX MIC2 */
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
+ break;
+ case 26: /* LINE1 */
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
+ break;
+ case 27: /* XXX LINE2 */
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
+ break;
+ case 28: /* CD */
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC883 &&
+ (subid == MSI_MS034A_SUBVENDOR ||
+ HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
+ switch (nid) {
+ case 25:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ case 28:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ }
+ } else if (id == HDA_CODEC_CX20549 && subid ==
+ HP_V3000_SUBVENDOR) {
+ switch (nid) {
+ case 18:
+ config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
+ break;
+ case 20:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ case 21:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ }
+ } else if (id == HDA_CODEC_CX20551 && subid ==
+ HP_DV5000_SUBVENDOR) {
+ switch (nid) {
+ case 20:
+ case 21:
+ config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
+ config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC861 && subid ==
+ ASUS_W6F_SUBVENDOR) {
+ switch (nid) {
+ case 11:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ case 12:
+ case 14:
+ case 16:
+ case 31:
+ case 32:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
+ break;
+ case 15:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC861 && subid ==
+ UNIWILL_9075_SUBVENDOR) {
+ switch (nid) {
+ case 15:
+ config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
+ break;
+ }
+ }
+
+ /* New patches */
+ if (id == HDA_CODEC_AD1986A &&
+ (subid == ASUS_M2NPVMX_SUBVENDOR ||
+ subid == ASUS_A8NVMCSM_SUBVENDOR ||
+ subid == ASUS_P5PL2_SUBVENDOR)) {
+ switch (nid) {
+ case 26: /* Headphones with redirection */
+ patch = "as=1 seq=15";
+ break;
+ case 28: /* 5.1 out => 2.0 out + 1 input */
+ patch = "device=Line-in as=8 seq=1";
+ break;
+ case 29: /* Can't use this as input, as the only available mic
+ * preamplifier is busy by front panel mic (nid 31).
+ * If you want to use this rear connector as mic input,
+ * you have to disable the front panel one. */
+ patch = "as=0";
+ break;
+ case 31: /* Lot of inputs configured with as=15 and unusable */
+ patch = "as=8 seq=3";
+ break;
+ case 32:
+ patch = "as=8 seq=4";
+ break;
+ case 34:
+ patch = "as=8 seq=5";
+ break;
+ case 36:
+ patch = "as=8 seq=6";
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC260 &&
+ HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
+ switch (nid) {
+ case 16:
+ patch = "seq=15 device=Headphones";
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC268) {
+ if (subid == ACER_T5320_SUBVENDOR) {
+ switch (nid) {
+ case 20: /* Headphones Jack */
+ patch = "as=1 seq=15";
+ break;
+ }
+ }
+ } else if (id == HDA_CODEC_CX20561 &&
+ subid == LENOVO_B450_SUBVENDOR) {
+ switch (nid) {
+ case 22:
+ patch = "as=1 seq=15";
+ break;
+ }
+ }
+
+ if (patch != NULL)
+ config = hdaa_widget_pin_patch(config, patch);
+ HDA_BOOTVERBOSE(
+ if (config != orig)
+ device_printf(w->devinfo->dev,
+ "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
+ nid, orig, config);
+ );
+ w->wclass.pin.config = config;
+}
+
+static void
+hdaa_widget_patch(struct hdaa_widget *w)
+{
+ struct hdaa_devinfo *devinfo = w->devinfo;
+ uint32_t orig;
+ nid_t beeper = -1;
+
+ orig = w->param.widget_cap;
+ /* On some codecs beeper is an input pin, but it is not recordable
+ alone. Also most of BIOSes does not declare beeper pin.
+ Change beeper pin node type to beeper to help parser. */
+ switch (hdaa_codec_id(devinfo)) {
+ case HDA_CODEC_AD1882:
+ case HDA_CODEC_AD1883:
+ case HDA_CODEC_AD1984:
+ case HDA_CODEC_AD1984A:
+ case HDA_CODEC_AD1984B:
+ case HDA_CODEC_AD1987:
+ case HDA_CODEC_AD1988:
+ case HDA_CODEC_AD1988B:
+ case HDA_CODEC_AD1989B:
+ beeper = 26;
+ break;
+ case HDA_CODEC_ALC260:
+ beeper = 23;
+ break;
+ }
+ if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
+ hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
+ beeper = 29;
+ if (w->nid == beeper) {
+ w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
+ w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
+ w->waspin = 1;
+ }
+ HDA_BOOTVERBOSE(
+ if (w->param.widget_cap != orig) {
+ device_printf(w->devinfo->dev,
+ "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
+ w->nid, orig, w->param.widget_cap);
+ }
+ );
+
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ hdac_pin_patch(w);
+}
+
+void
+hdaa_patch(struct hdaa_devinfo *devinfo)
+{
+ struct hdaa_widget *w;
+ uint32_t id, subid;
+ int i;
+
+ id = hdaa_codec_id(devinfo);
+ subid = hdaa_subvendor_id(devinfo);
+
+ /*
+ * Quirks
+ */
+ for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
+ if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
+ HDA_DEV_MATCH(hdac_quirks[i].id, id)))
+ continue;
+ if (hdac_quirks[i].set != 0)
+ devinfo->quirks |=
+ hdac_quirks[i].set;
+ if (hdac_quirks[i].unset != 0)
+ devinfo->quirks &=
+ ~(hdac_quirks[i].unset);
+ }
+
+ /* Apply per-widget patch. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdaa_widget_get(devinfo, i);
+ if (w == NULL)
+ continue;
+ hdaa_widget_patch(w);
+ }
+
+ switch (id) {
+ case HDA_CODEC_AD1983:
+ /*
+ * This CODEC has several possible usages, but none
+ * fit the parser best. Help parser to choose better.
+ */
+ /* Disable direct unmixed playback to get pcm volume. */
+ w = hdaa_widget_get(devinfo, 5);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ w = hdaa_widget_get(devinfo, 6);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ w = hdaa_widget_get(devinfo, 11);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ /* Disable mic and line selectors. */
+ w = hdaa_widget_get(devinfo, 12);
+ if (w != NULL)
+ w->connsenable[1] = 0;
+ w = hdaa_widget_get(devinfo, 13);
+ if (w != NULL)
+ w->connsenable[1] = 0;
+ /* Disable recording from mono playback mix. */
+ w = hdaa_widget_get(devinfo, 20);
+ if (w != NULL)
+ w->connsenable[3] = 0;
+ break;
+ case HDA_CODEC_AD1986A:
+ /*
+ * This CODEC has overcomplicated input mixing.
+ * Make some cleaning there.
+ */
+ /* Disable input mono mixer. Not needed and not supported. */
+ w = hdaa_widget_get(devinfo, 43);
+ if (w != NULL)
+ w->enable = 0;
+ /* Disable any with any input mixing mesh. Use separately. */
+ w = hdaa_widget_get(devinfo, 39);
+ if (w != NULL)
+ w->enable = 0;
+ w = hdaa_widget_get(devinfo, 40);
+ if (w != NULL)
+ w->enable = 0;
+ w = hdaa_widget_get(devinfo, 41);
+ if (w != NULL)
+ w->enable = 0;
+ w = hdaa_widget_get(devinfo, 42);
+ if (w != NULL)
+ w->enable = 0;
+ /* Disable duplicate mixer node connector. */
+ w = hdaa_widget_get(devinfo, 15);
+ if (w != NULL)
+ w->connsenable[3] = 0;
+ /* There is only one mic preamplifier, use it effectively. */
+ w = hdaa_widget_get(devinfo, 31);
+ if (w != NULL) {
+ if ((w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
+ w = hdaa_widget_get(devinfo, 16);
+ if (w != NULL)
+ w->connsenable[2] = 0;
+ } else {
+ w = hdaa_widget_get(devinfo, 15);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ }
+ }
+ w = hdaa_widget_get(devinfo, 32);
+ if (w != NULL) {
+ if ((w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
+ w = hdaa_widget_get(devinfo, 16);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ } else {
+ w = hdaa_widget_get(devinfo, 15);
+ if (w != NULL)
+ w->connsenable[1] = 0;
+ }
+ }
+
+ if (subid == ASUS_A8X_SUBVENDOR) {
+ /*
+ * This is just plain ridiculous.. There
+ * are several A8 series that share the same
+ * pci id but works differently (EAPD).
+ */
+ w = hdaa_widget_get(devinfo, 26);
+ if (w != NULL && w->type ==
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
+ (w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
+ devinfo->quirks &=
+ ~HDAA_QUIRK_EAPDINV;
+ }
+ break;
+ case HDA_CODEC_AD1981HD:
+ /*
+ * This CODEC has very unusual design with several
+ * points inappropriate for the present parser.
+ */
+ /* Disable recording from mono playback mix. */
+ w = hdaa_widget_get(devinfo, 21);
+ if (w != NULL)
+ w->connsenable[3] = 0;
+ /* Disable rear to front mic mixer, use separately. */
+ w = hdaa_widget_get(devinfo, 31);
+ if (w != NULL)
+ w->enable = 0;
+ /* Disable direct playback, use mixer. */
+ w = hdaa_widget_get(devinfo, 5);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ w = hdaa_widget_get(devinfo, 6);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ w = hdaa_widget_get(devinfo, 9);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ w = hdaa_widget_get(devinfo, 24);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ break;
+ case HDA_CODEC_CX20582:
+ case HDA_CODEC_CX20583:
+ case HDA_CODEC_CX20584:
+ case HDA_CODEC_CX20585:
+ case HDA_CODEC_CX20590:
+ /*
+ * These codecs have extra connectivity on record side
+ * too reach for the present parser.
+ */
+ w = hdaa_widget_get(devinfo, 20);
+ if (w != NULL)
+ w->connsenable[1] = 0;
+ w = hdaa_widget_get(devinfo, 21);
+ if (w != NULL)
+ w->connsenable[1] = 0;
+ w = hdaa_widget_get(devinfo, 22);
+ if (w != NULL)
+ w->connsenable[0] = 0;
+ break;
+ case HDA_CODEC_VT1708S_0:
+ case HDA_CODEC_VT1708S_1:
+ case HDA_CODEC_VT1708S_2:
+ case HDA_CODEC_VT1708S_3:
+ case HDA_CODEC_VT1708S_4:
+ case HDA_CODEC_VT1708S_5:
+ case HDA_CODEC_VT1708S_6:
+ case HDA_CODEC_VT1708S_7:
+ /*
+ * These codecs have hidden mic boost controls.
+ */
+ w = hdaa_widget_get(devinfo, 26);
+ if (w != NULL)
+ w->param.inamp_cap =
+ (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
+ (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
+ (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
+ w = hdaa_widget_get(devinfo, 30);
+ if (w != NULL)
+ w->param.inamp_cap =
+ (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
+ (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
+ (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
+ break;
+ }
+}
+
+void
+hdaa_patch_direct(struct hdaa_devinfo *devinfo)
+{
+ device_t dev = devinfo->dev;
+ uint32_t id, subid, val;
+
+ id = hdaa_codec_id(devinfo);
+ subid = hdaa_subvendor_id(devinfo);
+
+ switch (id) {
+ case HDA_CODEC_VT1708S_0:
+ case HDA_CODEC_VT1708S_1:
+ case HDA_CODEC_VT1708S_2:
+ case HDA_CODEC_VT1708S_3:
+ case HDA_CODEC_VT1708S_4:
+ case HDA_CODEC_VT1708S_5:
+ case HDA_CODEC_VT1708S_6:
+ case HDA_CODEC_VT1708S_7:
+ /* Enable Mic Boost Volume controls. */
+ hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
+ 0xf98, 0x01));
+ /* Don't bypass mixer. */
+ hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
+ 0xf88, 0xc0));
+ break;
+ }
+ if (subid == APPLE_INTEL_MAC)
+ hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
+ 0x7e7, 0));
+ if (id == HDA_CODEC_ALC269) {
+ if (subid == 0x104316e3 || subid == 0x1043831a ||
+ subid == 0x1043834a || subid == 0x10438398 ||
+ subid == 0x104383ce) {
+ /*
+ * The ditital mics on some Asus laptops produce
+ * differential signals instead of expected stereo.
+ * That results in silence if downmix it to mono.
+ * To workaround, make codec to handle signal as mono.
+ */
+ hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
+ val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, 0x20));
+ hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
+ hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, 0x20, val|0x80));
+ }
+ }
+}
OpenPOWER on IntegriCloud