Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206469
b: refs/heads/master
c: 840b64c
h: refs/heads/master
i:
  206467: 51e4d03
v: v3
  • Loading branch information
Takashi Iwai committed Jul 13, 2010
1 parent 67db051 commit 33a190f
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 32e0191d7909022e5016beb75dda6710a28b3c61
refs/heads/master: 840b64c08032a86ab39b85ddd342918da0d559c8
178 changes: 154 additions & 24 deletions trunk/sound/pci/hda/patch_realtek.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ struct alc_spec {
hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */

/* capture setup for dynamic dual-adc switch */
unsigned int cur_adc_idx;
hda_nid_t cur_adc;
unsigned int cur_adc_stream_tag;
unsigned int cur_adc_format;

/* capture source */
unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
Expand Down Expand Up @@ -374,6 +380,7 @@ struct alc_spec {

/* other flags */
unsigned int no_analog :1; /* digital I/O only */
unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
int init_amp;

/* for virtual master */
Expand Down Expand Up @@ -1010,6 +1017,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
return -1;
}

/* switch the current ADC according to the jack state */
static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
unsigned int present;
hda_nid_t new_adc;

present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
if (present)
spec->cur_adc_idx = 1;
else
spec->cur_adc_idx = 0;
new_adc = spec->adc_nids[spec->cur_adc_idx];
if (spec->cur_adc && spec->cur_adc != new_adc) {
/* stream is running, let's swap the current ADC */
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
spec->cur_adc = new_adc;
snd_hda_codec_setup_stream(codec, new_adc,
spec->cur_adc_stream_tag, 0,
spec->cur_adc_format);
}
}

static void alc_mic_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
Expand All @@ -1024,6 +1054,11 @@ static void alc_mic_automute(struct hda_codec *codec)
if (snd_BUG_ON(!spec->adc_nids))
return;

if (spec->dual_adc_switch) {
alc_dual_mic_adc_auto_switch(codec);
return;
}

cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];

present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Expand Down Expand Up @@ -3614,6 +3649,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}

/* analog capture with dynamic dual-adc changes */
static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct alc_spec *spec = codec->spec;
spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format;
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
return 0;
}

static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct alc_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
spec->cur_adc = 0;
return 0;
}

static struct hda_pcm_stream dualmic_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.nid = 0, /* fill later */
.ops = {
.prepare = dualmic_capture_pcm_prepare,
.cleanup = dualmic_capture_pcm_cleanup
},
};

/*
*/
Expand Down Expand Up @@ -5052,24 +5122,12 @@ static void fixup_automic_adc(struct hda_codec *codec)
spec->auto_mic = 0; /* disable auto-mic to be sure */
}

/* choose the ADC/MUX containing the input pin and initialize the setup */
static void fixup_single_adc(struct hda_codec *codec)
/* set the default connection to that pin */
static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin = 0;
int i;

/* search for the input pin; there must be only one */
for (i = 0; i < AUTO_PIN_LAST; i++) {
if (spec->autocfg.input_pins[i]) {
pin = spec->autocfg.input_pins[i];
break;
}
}
if (!pin)
return;

/* set the default connection to that pin */
for (i = 0; i < spec->num_adc_nids; i++) {
hda_nid_t cap = spec->capsrc_nids ?
spec->capsrc_nids[i] : spec->adc_nids[i];
Expand All @@ -5078,11 +5136,6 @@ static void fixup_single_adc(struct hda_codec *codec)
idx = get_connection_index(codec, cap, pin);
if (idx < 0)
continue;
/* use only this ADC */
if (spec->capsrc_nids)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
/* select or unmute this route */
if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
Expand All @@ -5091,10 +5144,45 @@ static void fixup_single_adc(struct hda_codec *codec)
snd_hda_codec_write_cache(codec, cap, 0,
AC_VERB_SET_CONNECT_SEL, idx);
}
return i; /* return the found index */
}
return -1; /* not found */
}

/* choose the ADC/MUX containing the input pin and initialize the setup */
static void fixup_single_adc(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin = 0;
int i;

/* search for the input pin; there must be only one */
for (i = 0; i < AUTO_PIN_LAST; i++) {
if (spec->autocfg.input_pins[i]) {
pin = spec->autocfg.input_pins[i];
break;
}
}
if (!pin)
return;
i = init_capsrc_for_pin(codec, pin);
if (i >= 0) {
/* use only this ADC */
if (spec->capsrc_nids)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
}
}

/* initialize dual adcs */
static void fixup_dual_adc_switch(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
init_capsrc_for_pin(codec, spec->ext_mic.pin);
init_capsrc_for_pin(codec, spec->int_mic.pin);
}

static void set_capture_mixer(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
Expand All @@ -5108,15 +5196,20 @@ static void set_capture_mixer(struct hda_codec *codec)
};
if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
int mux = 0;
if (spec->auto_mic)
int num_adcs = spec->num_adc_nids;
if (spec->dual_adc_switch)
fixup_dual_adc_switch(codec);
else if (spec->auto_mic)
fixup_automic_adc(codec);
else if (spec->input_mux) {
if (spec->input_mux->num_items > 1)
mux = 1;
else if (spec->input_mux->num_items == 1)
fixup_single_adc(codec);
}
spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
if (spec->dual_adc_switch)
num_adcs = 1;
spec->cap_mixer = caps[mux][num_adcs - 1];
}
}

Expand Down Expand Up @@ -14141,6 +14234,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */

static int alc275_setup_dual_adc(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;

if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
return 0;
if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
(spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
if (spec->ext_mic.pin <= 0x12) {
spec->private_adc_nids[0] = 0x08;
spec->private_adc_nids[1] = 0x11;
spec->private_capsrc_nids[0] = 0x23;
spec->private_capsrc_nids[1] = 0x22;
} else {
spec->private_adc_nids[0] = 0x11;
spec->private_adc_nids[1] = 0x08;
spec->private_capsrc_nids[0] = 0x22;
spec->private_capsrc_nids[1] = 0x23;
}
spec->adc_nids = spec->private_adc_nids;
spec->capsrc_nids = spec->private_capsrc_nids;
spec->num_adc_nids = 2;
spec->dual_adc_switch = 1;
snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
spec->adc_nids[0], spec->adc_nids[1]);
return 1;
}
return 0;
}

/*
* BIOS auto configuration
*/
Expand Down Expand Up @@ -14180,11 +14303,14 @@ static int alc269_parse_auto_config(struct hda_codec *codec)

spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
fillup_priv_adc_nids(codec, alc269_adc_candidates,
sizeof(alc269_adc_candidates));

if (!alc275_setup_dual_adc(codec))
fillup_priv_adc_nids(codec, alc269_adc_candidates,
sizeof(alc269_adc_candidates));

/* set default input source */
snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
if (!spec->dual_adc_switch)
snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
0, AC_VERB_SET_CONNECT_SEL,
spec->input_mux->items[0].index);

Expand Down Expand Up @@ -14480,6 +14606,10 @@ static int patch_alc269(struct hda_codec *codec)
*/
spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
} else if (spec->dual_adc_switch) {
spec->stream_analog_playback = &alc269_pcm_analog_playback;
/* switch ADC dynamically */
spec->stream_analog_capture = &dualmic_pcm_analog_capture;
} else {
spec->stream_analog_playback = &alc269_pcm_analog_playback;
spec->stream_analog_capture = &alc269_pcm_analog_capture;
Expand Down

0 comments on commit 33a190f

Please sign in to comment.