At Mon, 2 Apr 2012 15:40:27 +0200, David Henningsson wrote:
The internal mic input is phase inverted on one channel. To avoid people in userspace summing the channels together and get zero result, use a separate mixer control for the inverted channel.
BugLink: https://bugs.launchpad.net/bugs/903853 Signed-off-by: David Henningsson david.henningsson@canonical.com
Thanks, applied now to topic/hda branch of sound git tree.
Takashi
sound/pci/hda/patch_conexant.c | 88 ++++++++++++++++++++++++++++++++++------ 1 files changed, 75 insertions(+), 13 deletions(-)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e6eafb1..c18e3b1 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -142,6 +142,7 @@ struct conexant_spec { unsigned int asus:1; unsigned int pin_eapd_ctrls:1; unsigned int single_adc_amp:1;
unsigned int fixup_stereo_dmic:1;
unsigned int adc_switching:1;
@@ -4107,9 +4108,9 @@ static int cx_auto_init(struct hda_codec *codec)
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, const char *dir, int cidx,
hda_nid_t nid, int hda_dir, int amp_idx)
hda_nid_t nid, int hda_dir, int amp_idx, int chs)
{
- static char name[32];
- static char name[44]; static struct snd_kcontrol_new knew[] = { HDA_CODEC_VOLUME(name, 0, 0, 0), HDA_CODEC_MUTE(name, 0, 0, 0),
@@ -4119,7 +4120,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
for (i = 0; i < 2; i++) { struct snd_kcontrol *kctl;
knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; knew[i].index = cidx;knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx, hda_dir);
@@ -4138,7 +4139,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, }
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
- cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
- cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
#define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) @@ -4208,6 +4209,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) return 0; }
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
- be split in two independent channels.
- dest_label must be at least 44 characters. */
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
char *dest_label, int nid)
+{
- struct conexant_spec *spec = codec->spec;
- int i;
- if (!spec->fixup_stereo_dmic)
return 0;
- for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
int def_conf;
if (spec->autocfg.inputs[i].pin != nid)
continue;
if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
return 0;
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
return 0;
/* Finally found the inverted internal mic! */
snprintf(dest_label, 44, "Inverted %s", label);
return 1;
- }
- return 0;
+}
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, const char *label, const char *pfx, int cidx) @@ -4216,14 +4247,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int i;
for (i = 0; i < spec->num_adc_nids; i++) {
hda_nid_t adc_nid = spec->adc_nids[i]; int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; if (spec->single_adc_amp) idx = 0;char rightch_label[44];
if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
/* Make two independent kcontrols for left and right */
int err = cx_auto_add_volume_idx(codec, label, pfx,
cidx, adc_nid, HDA_INPUT, idx, 1);
if (err < 0)
return err;
return cx_auto_add_volume_idx(codec, rightch_label, pfx,
cidx, adc_nid, HDA_INPUT, idx, 2);
return cx_auto_add_volume_idx(codec, label, pfx,}
cidx, adc_nid, HDA_INPUT, idx);
} return 0;cidx, adc_nid, HDA_INPUT, idx, 3);
} @@ -4236,9 +4278,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, int i, con;
nid = spec->imux_info[idx].pin;
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
char rightch_label[44];
if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
int err = cx_auto_add_volume_idx(codec, label, " Boost",
cidx, nid, HDA_INPUT, 0, 1);
if (err < 0)
return err;
return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
cidx, nid, HDA_INPUT, 0, 2);
return cx_auto_add_volume(codec, label, " Boost", cidx, nid, HDA_INPUT);}
- } con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, &mux, false, 0); if (con < 0)
@@ -4405,22 +4457,30 @@ static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
}
-static void apply_pin_fixup(struct hda_codec *codec, +enum {
- CXT_PINCFG_LENOVO_X200,
- CXT_FIXUP_STEREO_DMIC,
+};
+static void apply_fixup(struct hda_codec *codec, const struct snd_pci_quirk *quirk, const struct cxt_pincfg **table) {
- struct conexant_spec *spec = codec->spec;
- quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (quirk) {
- if (quirk && table[quirk->value]) { snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n", quirk->name); apply_pincfg(codec, table[quirk->value]); }
- if (quirk->value == CXT_FIXUP_STEREO_DMIC) {
snd_printdd(KERN_INFO "hda_codec: applying internal mic workaround for %s\n",
quirk->name);
spec->fixup_stereo_dmic = 1;
- }
}
-enum {
- CXT_PINCFG_LENOVO_X200,
-};
static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ { 0x17, 0x21a11000 }, /* dock-mic */ @@ -4431,10 +4491,12 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
static const struct cxt_pincfg *cxt_pincfg_tbl[] = { [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
- [CXT_FIXUP_STEREO_DMIC] = NULL,
};
static const struct snd_pci_quirk cxt_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
- SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), {}
};
@@ -4477,7 +4539,7 @@ static int patch_conexant_auto(struct hda_codec *codec) break; }
- apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
apply_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
/* Show mute-led control only on HP laptops
- This is a sort of white-list: on HP laptops, EAPD corresponds
-- 1.7.9.1