From: David Henningsson <david.henningsson@canonical.com>
To: Takashi Iwai <tiwai@suse.de>,
ALSA Development Mailing List <alsa-devel@alsa-project.org>
Cc: 903853@bugs.launchpad.net
Subject: [RFC PATCH] Inverted internal mic
Date: Tue, 28 Feb 2012 09:57:56 +0100 [thread overview]
Message-ID: <4F4C9714.1080307@canonical.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 2040 bytes --]
Hi,
One of the more common problems on laptop machines, is that the internal
mic provides a stereo signal but with one channel phase inverted, or
differential output.
This means problems for applications recording two channels but later
merging them into one, leaving them with zero or near-zero output.
There are various ways we can work around this in both the kernel,
alsa-lib and PulseAudio layers. It's a matter of picking the right one.
I'm leaning towards trying to fix it in the kernel's codec drivers, because
1) we already have quirking infrastructure there
2) we already have some working quirks already in that layer
3) it would benefit other sound applications that use ALSA directly.
The downside to that is really that we're silencing out one channel for
everyone, leading to no application being able to use both channels,
even if they would implement some kind of
"auto-detect-and-reverse-one-channel" functionality.
For the most part, this has been some Acer Aspire machines running
Realtek ALC268 / ALC269 / ALC271X / ALC272X, and for two of these we
have proc coefs we can set, but for the other two these proc coefs, if
they exist, are unknown to us.
Recently I came across a Conexant as well, and I decided to write a
patch for it, that would take the approach that the internal mic is
forced mono on the kcontrol, and make sure the right channel is always
muted. The patch is verified by the reporter to fix this problem. It
could use some perfection though - it would make sense to to the same to
the internal mic boost as well, and the strcmp('Internal Mic') call
could maybe be turned into something more elegant. But before going
ahead with that, I'd like to hear your opinion on the matter, if you
agree that this is a good approach to the problem?
References:
https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/903853/+attachment/2631623/+files/alsa-info.txt.VmCN7lMBL4
https://bugs.launchpad.net/bugs/903853
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
[-- Attachment #2: 0001-Fix-internal-mic-for-Lenovo-Ideapad-U300s.patch --]
[-- Type: text/x-patch, Size: 4831 bytes --]
>From 3ef2a105a85195c14e25190bca53bb55260feffa Mon Sep 17 00:00:00 2001
From: David Henningsson <david.henningsson@canonical.com>
Date: Fri, 24 Feb 2012 14:57:44 +0100
Subject: [PATCH] Fix internal mic for Lenovo Ideapad U300s
The internal mic input is phase inverted on one channel.
To avoid people in userspace summing the channels together
and get zero result, mute the right channel and make sure
they can't unmute it.
BugLink: https://bugs.launchpad.net/bugs/903853
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
---
sound/pci/hda/patch_conexant.c | 41 +++++++++++++++++++++++++++++----------
1 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 266e5a6..4a05817 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -140,6 +140,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;
@@ -4044,7 +4045,7 @@ 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 struct snd_kcontrol_new knew[] = {
@@ -4056,7 +4057,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].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
hda_dir);
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
knew[i].index = cidx;
@@ -4074,7 +4075,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)
@@ -4152,14 +4153,22 @@ 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++) {
+ int chs = 3;
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;
+
+ if (spec->fixup_stereo_dmic && (strcmp("Internal Mic", label) == 0)) {
+ /* Make left channel controllable and right channel muted */
+ chs = 1;
+ snd_hda_codec_write_cache(codec, adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT | (idx << AC_AMP_SET_INDEX_SHIFT) | AC_AMP_MUTE);
+ }
return cx_auto_add_volume_idx(codec, label, pfx,
- cidx, adc_nid, HDA_INPUT, idx);
+ cidx, adc_nid, HDA_INPUT, idx, chs);
}
return 0;
}
@@ -4335,22 +4344,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 */
@@ -4360,10 +4377,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),
{}
};
@@ -4387,7 +4406,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);
err = cx_auto_search_adcs(codec);
if (err < 0)
--
1.7.9
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next reply other threads:[~2012-02-28 8:57 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-28 8:57 David Henningsson [this message]
2012-02-28 9:24 ` [RFC PATCH] Inverted internal mic Takashi Iwai
2012-02-28 9:54 ` David Henningsson
2012-02-28 10:38 ` Takashi Iwai
2012-02-28 13:07 ` David Henningsson
2012-02-28 13:22 ` Takashi Iwai
2012-02-28 14:19 ` David Henningsson
2012-02-28 15:20 ` Takashi Iwai
2012-02-28 18:11 ` David Henningsson
2012-02-28 19:42 ` Takashi Iwai
2012-02-29 9:21 ` David Henningsson
2012-02-29 9:56 ` Takashi Iwai
2012-02-29 10:45 ` David Henningsson
2012-02-29 16:36 ` Takashi Iwai
2012-06-19 3:07 ` Eliot Blennerhassett
2012-06-19 7:43 ` David Henningsson
2012-06-20 13:31 ` Takashi Iwai
2012-06-21 1:15 ` David Henningsson
2012-06-21 12:52 ` Takashi Iwai
2012-06-21 13:04 ` David Henningsson
2012-06-21 13:19 ` Takashi Iwai
2012-06-21 14:23 ` David Henningsson
2012-06-22 9:33 ` Takashi Iwai
2012-06-22 10:46 ` David Henningsson
2012-06-22 11:00 ` Takashi Iwai
2012-06-22 12:46 ` Takashi Iwai
2012-06-22 15:27 ` David Henningsson
2012-06-22 15:37 ` Takashi Iwai
2012-06-22 17:33 ` David Henningsson
2012-06-23 2:58 ` Eliot Blennerhassett
2012-06-23 8:40 ` Takashi Iwai
2012-06-23 8:39 ` Takashi Iwai
2012-06-25 8:04 ` David Henningsson
2012-06-25 8:18 ` Takashi Iwai
2012-06-20 8:02 ` Takashi Iwai
2012-06-20 10:54 ` Eliot Blennerhassett
2012-02-29 11:02 ` Raymond Yau
2012-06-20 21:53 ` James Courtier-Dutton
2012-06-21 5:56 ` Takashi Iwai
-- strict thread matches above, loose matches on Subject: below --
2014-10-20 13:52 rodney byne
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4F4C9714.1080307@canonical.com \
--to=david.henningsson@canonical.com \
--cc=903853@bugs.launchpad.net \
--cc=alsa-devel@alsa-project.org \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.