ALSA: hda - Add auto-parser support to cxt5051 / CX20561 Hermosa
Extend the existing auto-parser for CX2064x for cxt5051 codec. Now the auto-parser supports ADC-switching for this codec. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
0ad1b5b619
commit
6764bcef4c
1 changed files with 217 additions and 62 deletions
|
@ -89,6 +89,8 @@ struct conexant_spec {
|
||||||
unsigned int cur_adc_stream_tag;
|
unsigned int cur_adc_stream_tag;
|
||||||
unsigned int cur_adc_format;
|
unsigned int cur_adc_format;
|
||||||
|
|
||||||
|
const struct hda_pcm_stream *capture_stream;
|
||||||
|
|
||||||
/* capture source */
|
/* capture source */
|
||||||
const struct hda_input_mux *input_mux;
|
const struct hda_input_mux *input_mux;
|
||||||
const hda_nid_t *capsrc_nids;
|
const hda_nid_t *capsrc_nids;
|
||||||
|
@ -106,6 +108,7 @@ struct conexant_spec {
|
||||||
/* dynamic controls, init_verbs and input_mux */
|
/* dynamic controls, init_verbs and input_mux */
|
||||||
struct auto_pin_cfg autocfg;
|
struct auto_pin_cfg autocfg;
|
||||||
struct hda_input_mux private_imux;
|
struct hda_input_mux private_imux;
|
||||||
|
hda_nid_t imux_adcs[HDA_MAX_NUM_INPUTS];
|
||||||
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
||||||
struct pin_dac_pair dac_info[8];
|
struct pin_dac_pair dac_info[8];
|
||||||
int dac_info_filled;
|
int dac_info_filled;
|
||||||
|
@ -119,6 +122,8 @@ struct conexant_spec {
|
||||||
unsigned int hp_laptop:1;
|
unsigned int hp_laptop:1;
|
||||||
unsigned int asus:1;
|
unsigned int asus:1;
|
||||||
|
|
||||||
|
unsigned int adc_switching:1;
|
||||||
|
|
||||||
unsigned int ext_mic_present;
|
unsigned int ext_mic_present;
|
||||||
unsigned int recording;
|
unsigned int recording;
|
||||||
void (*capture_prepare)(struct hda_codec *codec);
|
void (*capture_prepare)(struct hda_codec *codec);
|
||||||
|
@ -319,13 +324,19 @@ static int conexant_build_pcms(struct hda_codec *codec)
|
||||||
spec->multiout.max_channels;
|
spec->multiout.max_channels;
|
||||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
||||||
spec->multiout.dac_nids[0];
|
spec->multiout.dac_nids[0];
|
||||||
if (codec->vendor_id == 0x14f15051)
|
if (spec->capture_stream)
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream;
|
||||||
cx5051_pcm_analog_capture;
|
else {
|
||||||
else
|
if (codec->vendor_id == 0x14f15051)
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
|
||||||
conexant_pcm_analog_capture;
|
cx5051_pcm_analog_capture;
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
|
else {
|
||||||
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
|
||||||
|
conexant_pcm_analog_capture;
|
||||||
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
|
||||||
|
spec->num_adc_nids;
|
||||||
|
}
|
||||||
|
}
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
|
||||||
|
|
||||||
if (spec->multiout.dig_out_nid) {
|
if (spec->multiout.dig_out_nid) {
|
||||||
|
@ -564,6 +575,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
|
||||||
#define set_beep_amp(spec, nid, idx, dir) /* NOP */
|
#define set_beep_amp(spec, nid, idx, dir) /* NOP */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int patch_conexant_auto(struct hda_codec *codec);
|
||||||
/*
|
/*
|
||||||
* EAPD control
|
* EAPD control
|
||||||
* the private value = nid | (invert << 8)
|
* the private value = nid | (invert << 8)
|
||||||
|
@ -1906,6 +1918,7 @@ enum {
|
||||||
CXT5051_F700, /* HP Compaq Presario F700 */
|
CXT5051_F700, /* HP Compaq Presario F700 */
|
||||||
CXT5051_TOSHIBA, /* Toshiba M300 & co */
|
CXT5051_TOSHIBA, /* Toshiba M300 & co */
|
||||||
CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
|
CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
|
||||||
|
CXT5051_AUTO, /* auto-parser */
|
||||||
CXT5051_MODELS
|
CXT5051_MODELS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1917,6 +1930,7 @@ static const char *const cxt5051_models[CXT5051_MODELS] = {
|
||||||
[CXT5051_F700] = "hp-700",
|
[CXT5051_F700] = "hp-700",
|
||||||
[CXT5051_TOSHIBA] = "toshiba",
|
[CXT5051_TOSHIBA] = "toshiba",
|
||||||
[CXT5051_IDEAPAD] = "ideapad",
|
[CXT5051_IDEAPAD] = "ideapad",
|
||||||
|
[CXT5051_AUTO] = "auto",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
||||||
|
@ -1937,6 +1951,17 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||||
struct conexant_spec *spec;
|
struct conexant_spec *spec;
|
||||||
int board_config;
|
int board_config;
|
||||||
|
|
||||||
|
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
|
||||||
|
cxt5051_models,
|
||||||
|
cxt5051_cfg_tbl);
|
||||||
|
if (board_config < 0)
|
||||||
|
board_config = CXT5051_AUTO;
|
||||||
|
if (board_config == CXT5051_AUTO) {
|
||||||
|
printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
|
||||||
|
codec->chip_name);
|
||||||
|
return patch_conexant_auto(codec);
|
||||||
|
}
|
||||||
|
|
||||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||||
if (!spec)
|
if (!spec)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1967,9 +1992,6 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||||
|
|
||||||
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
|
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
|
||||||
|
|
||||||
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
|
|
||||||
cxt5051_models,
|
|
||||||
cxt5051_cfg_tbl);
|
|
||||||
spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
|
spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
|
||||||
switch (board_config) {
|
switch (board_config) {
|
||||||
case CXT5051_HP:
|
case CXT5051_HP:
|
||||||
|
@ -3195,6 +3217,44 @@ static int patch_cxt5066(struct hda_codec *codec)
|
||||||
* Automatic parser for CX20641 & co
|
* Automatic parser for CX20641 & co
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static int cx_auto_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 conexant_spec *spec = codec->spec;
|
||||||
|
hda_nid_t adc = spec->imux_adcs[spec->cur_mux[0]];
|
||||||
|
if (spec->adc_switching) {
|
||||||
|
spec->cur_adc = adc;
|
||||||
|
spec->cur_adc_stream_tag = stream_tag;
|
||||||
|
spec->cur_adc_format = format;
|
||||||
|
}
|
||||||
|
snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||||||
|
struct hda_codec *codec,
|
||||||
|
struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
|
||||||
|
spec->cur_adc = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
|
||||||
|
.substreams = 1,
|
||||||
|
.channels_min = 2,
|
||||||
|
.channels_max = 2,
|
||||||
|
.nid = 0, /* fill later */
|
||||||
|
.ops = {
|
||||||
|
.prepare = cx_auto_capture_pcm_prepare,
|
||||||
|
.cleanup = cx_auto_capture_pcm_cleanup
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
|
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
|
||||||
|
|
||||||
/* get the connection index of @nid in the widget @mux */
|
/* get the connection index of @nid in the widget @mux */
|
||||||
|
@ -3211,6 +3271,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int has_multi_connection(struct hda_codec *codec, hda_nid_t mux)
|
||||||
|
{
|
||||||
|
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
|
||||||
|
int nums;
|
||||||
|
|
||||||
|
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
|
||||||
|
return nums > 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* get an unassigned DAC from the given list.
|
/* get an unassigned DAC from the given list.
|
||||||
* Return the nid if found and reduce the DAC list, or return zero if
|
* Return the nid if found and reduce the DAC list, or return zero if
|
||||||
* not found
|
* not found
|
||||||
|
@ -3362,25 +3431,89 @@ static void cx_auto_hp_automute(struct hda_codec *codec)
|
||||||
cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, !present);
|
cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, !present);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
|
||||||
|
return snd_hda_input_mux_info(&spec->private_imux, uinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
|
||||||
|
ucontrol->value.enumerated.item[0] = spec->cur_mux[0];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cx_auto_mux_enum_update(struct hda_codec *codec,
|
||||||
|
const struct hda_input_mux *imux,
|
||||||
|
unsigned int idx)
|
||||||
|
{
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
hda_nid_t adc;
|
||||||
|
|
||||||
|
if (!imux->num_items)
|
||||||
|
return 0;
|
||||||
|
if (idx >= imux->num_items)
|
||||||
|
idx = imux->num_items - 1;
|
||||||
|
if (spec->cur_mux[0] == idx)
|
||||||
|
return 0;
|
||||||
|
adc = spec->imux_adcs[idx];
|
||||||
|
if (has_multi_connection(codec, adc))
|
||||||
|
snd_hda_codec_write(codec, adc, 0,
|
||||||
|
AC_VERB_SET_CONNECT_SEL,
|
||||||
|
imux->items[idx].index);
|
||||||
|
if (spec->cur_adc && spec->cur_adc != adc) {
|
||||||
|
/* stream is running, let's swap the current ADC */
|
||||||
|
__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
|
||||||
|
spec->cur_adc = adc;
|
||||||
|
snd_hda_codec_setup_stream(codec, adc,
|
||||||
|
spec->cur_adc_stream_tag, 0,
|
||||||
|
spec->cur_adc_format);
|
||||||
|
}
|
||||||
|
spec->cur_mux[0] = idx;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
|
||||||
|
return cx_auto_mux_enum_update(codec, &spec->private_imux,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snd_kcontrol_new cx_auto_capture_mixers[] = {
|
||||||
|
{
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.name = "Capture Source",
|
||||||
|
.info = cx_auto_mux_enum_info,
|
||||||
|
.get = cx_auto_mux_enum_get,
|
||||||
|
.put = cx_auto_mux_enum_put
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
/* automatic switch internal and external mic */
|
/* automatic switch internal and external mic */
|
||||||
static void cx_auto_automic(struct hda_codec *codec)
|
static void cx_auto_automic(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct conexant_spec *spec = codec->spec;
|
struct conexant_spec *spec = codec->spec;
|
||||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
struct hda_input_mux *imux = &spec->private_imux;
|
|
||||||
int ext_idx = spec->auto_mic_ext;
|
int ext_idx = spec->auto_mic_ext;
|
||||||
|
|
||||||
if (!spec->auto_mic)
|
if (!spec->auto_mic)
|
||||||
return;
|
return;
|
||||||
if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
|
if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin))
|
||||||
snd_hda_codec_write(codec, spec->adc_nids[0], 0,
|
cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx);
|
||||||
AC_VERB_SET_CONNECT_SEL,
|
else
|
||||||
imux->items[ext_idx].index);
|
cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx);
|
||||||
} else {
|
|
||||||
snd_hda_codec_write(codec, spec->adc_nids[0], 0,
|
|
||||||
AC_VERB_SET_CONNECT_SEL,
|
|
||||||
imux->items[!ext_idx].index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
|
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||||
|
@ -3442,22 +3575,33 @@ static void cx_auto_parse_input(struct hda_codec *codec)
|
||||||
struct conexant_spec *spec = codec->spec;
|
struct conexant_spec *spec = codec->spec;
|
||||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
struct hda_input_mux *imux;
|
struct hda_input_mux *imux;
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
imux = &spec->private_imux;
|
imux = &spec->private_imux;
|
||||||
for (i = 0; i < cfg->num_inputs; i++) {
|
for (i = 0; i < cfg->num_inputs; i++) {
|
||||||
int idx = get_connection_index(codec, spec->adc_nids[0],
|
for (j = 0; j < spec->num_adc_nids; j++) {
|
||||||
|
hda_nid_t adc = spec->adc_nids[j];
|
||||||
|
int idx = get_connection_index(codec, adc,
|
||||||
cfg->inputs[i].pin);
|
cfg->inputs[i].pin);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
const char *label;
|
const char *label;
|
||||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||||
snd_hda_add_imux_item(imux, label, idx, NULL);
|
snd_hda_add_imux_item(imux, label, idx, NULL);
|
||||||
|
spec->imux_adcs[i] = adc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imux->num_items == 2 && cfg->num_inputs == 2)
|
if (imux->num_items == 2 && cfg->num_inputs == 2)
|
||||||
cx_auto_check_auto_mic(codec);
|
cx_auto_check_auto_mic(codec);
|
||||||
if (imux->num_items > 1 && !spec->auto_mic)
|
if (imux->num_items > 1 && !spec->auto_mic) {
|
||||||
spec->input_mux = imux;
|
for (i = 1; i < imux->num_items; i++) {
|
||||||
|
if (spec->imux_adcs[i] != spec->imux_adcs[0]) {
|
||||||
|
spec->adc_switching = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get digital-input audio widget corresponding to the given pin */
|
/* get digital-input audio widget corresponding to the given pin */
|
||||||
|
@ -3736,39 +3880,37 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
|
||||||
return 0;
|
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)
|
||||||
|
{
|
||||||
|
struct conexant_spec *spec = codec->spec;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < spec->num_adc_nids; i++) {
|
||||||
|
hda_nid_t adc_nid = spec->adc_nids[i];
|
||||||
|
int idx = get_connection_index(codec, adc_nid, nid);
|
||||||
|
if (idx < 0)
|
||||||
|
continue;
|
||||||
|
return cx_auto_add_volume_idx(codec, label, pfx,
|
||||||
|
cidx, adc_nid, HDA_INPUT, idx);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int cx_auto_build_input_controls(struct hda_codec *codec)
|
static int cx_auto_build_input_controls(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct conexant_spec *spec = codec->spec;
|
struct conexant_spec *spec = codec->spec;
|
||||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
static const char *prev_label;
|
static const char *prev_label;
|
||||||
int i, err, cidx, conn_len;
|
int i, err, cidx;
|
||||||
hda_nid_t conn[HDA_MAX_CONNECTIONS];
|
|
||||||
|
|
||||||
int multi_adc_volume = 0; /* If the ADC nid has several input volumes */
|
|
||||||
int adc_nid = spec->adc_nids[0];
|
|
||||||
|
|
||||||
conn_len = snd_hda_get_connections(codec, adc_nid, conn,
|
|
||||||
HDA_MAX_CONNECTIONS);
|
|
||||||
if (conn_len < 0)
|
|
||||||
return conn_len;
|
|
||||||
|
|
||||||
multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1;
|
|
||||||
if (!multi_adc_volume) {
|
|
||||||
err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid,
|
|
||||||
HDA_INPUT);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_label = NULL;
|
prev_label = NULL;
|
||||||
cidx = 0;
|
cidx = 0;
|
||||||
for (i = 0; i < cfg->num_inputs; i++) {
|
for (i = 0; i < cfg->num_inputs; i++) {
|
||||||
hda_nid_t nid = cfg->inputs[i].pin;
|
hda_nid_t nid = cfg->inputs[i].pin;
|
||||||
const char *label;
|
const char *label;
|
||||||
int j;
|
|
||||||
int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
|
int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
|
||||||
if (!pin_amp && !multi_adc_volume)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||||
if (label == prev_label)
|
if (label == prev_label)
|
||||||
|
@ -3784,18 +3926,23 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!multi_adc_volume)
|
if (cfg->num_inputs == 1) {
|
||||||
continue;
|
err = cx_auto_add_capture_volume(codec, nid,
|
||||||
for (j = 0; j < conn_len; j++) {
|
"Capture", "", cidx);
|
||||||
if (conn[j] == nid) {
|
} else {
|
||||||
err = cx_auto_add_volume_idx(codec, label,
|
err = cx_auto_add_capture_volume(codec, nid,
|
||||||
" Capture", cidx, adc_nid, HDA_INPUT, j);
|
label, " Capture", cidx);
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spec->private_imux.num_items > 1 && !spec->auto_mic) {
|
||||||
|
err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3833,15 +3980,23 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
||||||
if (!spec)
|
if (!spec)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
codec->spec = spec;
|
codec->spec = spec;
|
||||||
spec->adc_nids = cx_auto_adc_nids;
|
if (codec->vendor_id == 0x14f15051) {
|
||||||
spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
|
codec->pin_amp_workaround = 1;
|
||||||
spec->capsrc_nids = spec->adc_nids;
|
spec->adc_nids = cxt5051_adc_nids;
|
||||||
|
spec->num_adc_nids = ARRAY_SIZE(cxt5051_adc_nids);
|
||||||
|
spec->capsrc_nids = spec->adc_nids;
|
||||||
|
} else {
|
||||||
|
spec->adc_nids = cx_auto_adc_nids;
|
||||||
|
spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
|
||||||
|
spec->capsrc_nids = spec->adc_nids;
|
||||||
|
}
|
||||||
err = cx_auto_parse_auto_config(codec);
|
err = cx_auto_parse_auto_config(codec);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
kfree(codec->spec);
|
kfree(codec->spec);
|
||||||
codec->spec = NULL;
|
codec->spec = NULL;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
spec->capture_stream = &cx_auto_pcm_analog_capture;
|
||||||
codec->patch_ops = cx_auto_patch_ops;
|
codec->patch_ops = cx_auto_patch_ops;
|
||||||
if (spec->beep_amp)
|
if (spec->beep_amp)
|
||||||
snd_hda_attach_beep_device(codec, spec->beep_amp);
|
snd_hda_attach_beep_device(codec, spec->beep_amp);
|
||||||
|
|
Loading…
Add table
Reference in a new issue