Loading sound/pci/hda/patch_conexant.c +217 −62 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ struct conexant_spec { unsigned int cur_adc_stream_tag; unsigned int cur_adc_format; const struct hda_pcm_stream *capture_stream; /* capture source */ const struct hda_input_mux *input_mux; const hda_nid_t *capsrc_nids; Loading @@ -106,6 +108,7 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; 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]; struct pin_dac_pair dac_info[8]; int dac_info_filled; Loading @@ -119,6 +122,8 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; unsigned int adc_switching:1; unsigned int ext_mic_present; unsigned int recording; void (*capture_prepare)(struct hda_codec *codec); Loading Loading @@ -319,13 +324,19 @@ static int conexant_build_pcms(struct hda_codec *codec) spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; if (spec->capture_stream) info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; else { if (codec->vendor_id == 0x14f15051) info->stream[SNDRV_PCM_STREAM_CAPTURE] = cx5051_pcm_analog_capture; else 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].substreams = spec->num_adc_nids; } } info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; if (spec->multiout.dig_out_nid) { Loading Loading @@ -564,6 +575,7 @@ static const struct hda_codec_ops conexant_patch_ops = { #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control * the private value = nid | (invert << 8) Loading Loading @@ -1906,6 +1918,7 @@ enum { CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ CXT5051_AUTO, /* auto-parser */ CXT5051_MODELS }; Loading @@ -1917,6 +1930,7 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", [CXT5051_IDEAPAD] = "ideapad", [CXT5051_AUTO] = "auto", }; static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { Loading @@ -1937,6 +1951,17 @@ static int patch_cxt5051(struct hda_codec *codec) struct conexant_spec *spec; 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); if (!spec) return -ENOMEM; Loading Loading @@ -1967,9 +1992,6 @@ static int patch_cxt5051(struct hda_codec *codec) 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; switch (board_config) { case CXT5051_HP: Loading Loading @@ -3195,6 +3217,44 @@ static int patch_cxt5066(struct hda_codec *codec) * 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 }; /* get the connection index of @nid in the widget @mux */ Loading @@ -3211,6 +3271,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, 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. * Return the nid if found and reduce the DAC list, or return zero if * not found Loading Loading @@ -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); } 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 */ static void cx_auto_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux = &spec->private_imux; int ext_idx = spec->auto_mic_ext; if (!spec->auto_mic) return; if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { snd_hda_codec_write(codec, spec->adc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, imux->items[ext_idx].index); } else { snd_hda_codec_write(codec, spec->adc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, imux->items[!ext_idx].index); } if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); else cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx); } static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) Loading Loading @@ -3442,22 +3575,33 @@ static void cx_auto_parse_input(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux; int i; int i, j; imux = &spec->private_imux; 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); if (idx >= 0) { const char *label; label = hda_get_autocfg_input_label(codec, cfg, i); snd_hda_add_imux_item(imux, label, idx, NULL); spec->imux_adcs[i] = adc; break; } } } if (imux->num_items == 2 && cfg->num_inputs == 2) cx_auto_check_auto_mic(codec); if (imux->num_items > 1 && !spec->auto_mic) spec->input_mux = imux; if (imux->num_items > 1 && !spec->auto_mic) { 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 */ Loading Loading @@ -3736,39 +3880,37 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) 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) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; static const char *prev_label; int i, err, cidx, conn_len; 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; } int i, err, cidx; prev_label = NULL; cidx = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; const char *label; int j; 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); if (label == prev_label) Loading @@ -3784,18 +3926,23 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) return err; } if (!multi_adc_volume) continue; for (j = 0; j < conn_len; j++) { if (conn[j] == nid) { err = cx_auto_add_volume_idx(codec, label, " Capture", cidx, adc_nid, HDA_INPUT, j); if (cfg->num_inputs == 1) { err = cx_auto_add_capture_volume(codec, nid, "Capture", "", cidx); } else { err = cx_auto_add_capture_volume(codec, nid, label, " Capture", cidx); } if (err < 0) return err; break; } } 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; } Loading Loading @@ -3833,15 +3980,23 @@ static int patch_conexant_auto(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; if (codec->vendor_id == 0x14f15051) { codec->pin_amp_workaround = 1; 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); if (err < 0) { kfree(codec->spec); codec->spec = NULL; return err; } spec->capture_stream = &cx_auto_pcm_analog_capture; codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); Loading Loading
sound/pci/hda/patch_conexant.c +217 −62 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ struct conexant_spec { unsigned int cur_adc_stream_tag; unsigned int cur_adc_format; const struct hda_pcm_stream *capture_stream; /* capture source */ const struct hda_input_mux *input_mux; const hda_nid_t *capsrc_nids; Loading @@ -106,6 +108,7 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; 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]; struct pin_dac_pair dac_info[8]; int dac_info_filled; Loading @@ -119,6 +122,8 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; unsigned int adc_switching:1; unsigned int ext_mic_present; unsigned int recording; void (*capture_prepare)(struct hda_codec *codec); Loading Loading @@ -319,13 +324,19 @@ static int conexant_build_pcms(struct hda_codec *codec) spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; if (spec->capture_stream) info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; else { if (codec->vendor_id == 0x14f15051) info->stream[SNDRV_PCM_STREAM_CAPTURE] = cx5051_pcm_analog_capture; else 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].substreams = spec->num_adc_nids; } } info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; if (spec->multiout.dig_out_nid) { Loading Loading @@ -564,6 +575,7 @@ static const struct hda_codec_ops conexant_patch_ops = { #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control * the private value = nid | (invert << 8) Loading Loading @@ -1906,6 +1918,7 @@ enum { CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ CXT5051_AUTO, /* auto-parser */ CXT5051_MODELS }; Loading @@ -1917,6 +1930,7 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", [CXT5051_IDEAPAD] = "ideapad", [CXT5051_AUTO] = "auto", }; static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { Loading @@ -1937,6 +1951,17 @@ static int patch_cxt5051(struct hda_codec *codec) struct conexant_spec *spec; 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); if (!spec) return -ENOMEM; Loading Loading @@ -1967,9 +1992,6 @@ static int patch_cxt5051(struct hda_codec *codec) 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; switch (board_config) { case CXT5051_HP: Loading Loading @@ -3195,6 +3217,44 @@ static int patch_cxt5066(struct hda_codec *codec) * 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 }; /* get the connection index of @nid in the widget @mux */ Loading @@ -3211,6 +3271,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, 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. * Return the nid if found and reduce the DAC list, or return zero if * not found Loading Loading @@ -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); } 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 */ static void cx_auto_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux = &spec->private_imux; int ext_idx = spec->auto_mic_ext; if (!spec->auto_mic) return; if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { snd_hda_codec_write(codec, spec->adc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, imux->items[ext_idx].index); } else { snd_hda_codec_write(codec, spec->adc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, imux->items[!ext_idx].index); } if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); else cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx); } static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) Loading Loading @@ -3442,22 +3575,33 @@ static void cx_auto_parse_input(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux; int i; int i, j; imux = &spec->private_imux; 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); if (idx >= 0) { const char *label; label = hda_get_autocfg_input_label(codec, cfg, i); snd_hda_add_imux_item(imux, label, idx, NULL); spec->imux_adcs[i] = adc; break; } } } if (imux->num_items == 2 && cfg->num_inputs == 2) cx_auto_check_auto_mic(codec); if (imux->num_items > 1 && !spec->auto_mic) spec->input_mux = imux; if (imux->num_items > 1 && !spec->auto_mic) { 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 */ Loading Loading @@ -3736,39 +3880,37 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) 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) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; static const char *prev_label; int i, err, cidx, conn_len; 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; } int i, err, cidx; prev_label = NULL; cidx = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; const char *label; int j; 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); if (label == prev_label) Loading @@ -3784,18 +3926,23 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) return err; } if (!multi_adc_volume) continue; for (j = 0; j < conn_len; j++) { if (conn[j] == nid) { err = cx_auto_add_volume_idx(codec, label, " Capture", cidx, adc_nid, HDA_INPUT, j); if (cfg->num_inputs == 1) { err = cx_auto_add_capture_volume(codec, nid, "Capture", "", cidx); } else { err = cx_auto_add_capture_volume(codec, nid, label, " Capture", cidx); } if (err < 0) return err; break; } } 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; } Loading Loading @@ -3833,15 +3980,23 @@ static int patch_conexant_auto(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; if (codec->vendor_id == 0x14f15051) { codec->pin_amp_workaround = 1; 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); if (err < 0) { kfree(codec->spec); codec->spec = NULL; return err; } spec->capture_stream = &cx_auto_pcm_analog_capture; codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); Loading