diff options
| author | Takashi Iwai <tiwai@suse.de> | 2011-05-17 03:53:31 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-05-17 03:57:19 -0400 |
| commit | 03697e2acce9b8818cdb5fc0ebd5e5199dea1c32 (patch) | |
| tree | 2ec01404917d4a1d55041511a4b809ba4cbc96fb | |
| parent | a3a85d3983f7e18c46fba9f92c21d8a713de9791 (diff) | |
ALSA: hda - Add automute-mode enum to Conexant auto-parser
Implement the same functionality as Realtek's auto-mute mode control.
Now Conexant auto-parser can also mutes line-out and provide the enum
control for different automute behavior.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/hda_local.h | 5 | ||||
| -rw-r--r-- | sound/pci/hda/patch_conexant.c | 259 |
2 files changed, 215 insertions, 49 deletions
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 1ed6ee5a1e70..01a7cf6b5fb1 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
| @@ -493,6 +493,11 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); | |||
| 493 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 493 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
| 494 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 494 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); |
| 495 | 495 | ||
| 496 | static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) | ||
| 497 | { | ||
| 498 | return !!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT); | ||
| 499 | } | ||
| 500 | |||
| 496 | /* flags for hda_nid_item */ | 501 | /* flags for hda_nid_item */ |
| 497 | #define HDA_NID_ITEM_AMP (1<<0) | 502 | #define HDA_NID_ITEM_AMP (1<<0) |
| 498 | 503 | ||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 703dda69ad7c..ac595363e0e0 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | 39 | ||
| 40 | #define CONEXANT_HP_EVENT 0x37 | 40 | #define CONEXANT_HP_EVENT 0x37 |
| 41 | #define CONEXANT_MIC_EVENT 0x38 | 41 | #define CONEXANT_MIC_EVENT 0x38 |
| 42 | #define CONEXANT_LINE_EVENT 0x39 | ||
| 42 | 43 | ||
| 43 | /* Conexant 5051 specific */ | 44 | /* Conexant 5051 specific */ |
| 44 | 45 | ||
| @@ -81,6 +82,7 @@ struct conexant_spec { | |||
| 81 | */ | 82 | */ |
| 82 | unsigned int cur_eapd; | 83 | unsigned int cur_eapd; |
| 83 | unsigned int hp_present; | 84 | unsigned int hp_present; |
| 85 | unsigned int line_present; | ||
| 84 | unsigned int auto_mic; | 86 | unsigned int auto_mic; |
| 85 | int auto_mic_ext; /* imux_pins[] index for ext mic */ | 87 | int auto_mic_ext; /* imux_pins[] index for ext mic */ |
| 86 | unsigned int need_dac_fix; | 88 | unsigned int need_dac_fix; |
| @@ -123,6 +125,9 @@ struct conexant_spec { | |||
| 123 | 125 | ||
| 124 | unsigned int port_d_mode; | 126 | unsigned int port_d_mode; |
| 125 | unsigned int auto_mute:1; /* used in auto-parser */ | 127 | unsigned int auto_mute:1; /* used in auto-parser */ |
| 128 | unsigned int detect_line:1; /* Line-out detection enabled */ | ||
| 129 | unsigned int automute_lines:1; /* automute line-out as well */ | ||
| 130 | unsigned int automute_hp_lo:1; /* both HP and LO available */ | ||
| 126 | unsigned int dell_automute:1; | 131 | unsigned int dell_automute:1; |
| 127 | unsigned int dell_vostro:1; | 132 | unsigned int dell_vostro:1; |
| 128 | unsigned int ideapad:1; | 133 | unsigned int ideapad:1; |
| @@ -3420,48 +3425,193 @@ static void cx_auto_parse_output(struct hda_codec *codec) | |||
| 3420 | spec->multiout.dac_nids = spec->private_dac_nids; | 3425 | spec->multiout.dac_nids = spec->private_dac_nids; |
| 3421 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 3426 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
| 3422 | 3427 | ||
| 3423 | if (cfg->hp_outs > 0) | 3428 | for (i = 0; i < cfg->hp_outs; i++) { |
| 3424 | spec->auto_mute = 1; | 3429 | if (is_jack_detectable(codec, cfg->hp_pins[i])) { |
| 3430 | spec->auto_mute = 1; | ||
| 3431 | break; | ||
| 3432 | } | ||
| 3433 | } | ||
| 3434 | if (spec->auto_mute && cfg->line_out_pins[0] && | ||
| 3435 | cfg->line_out_pins[0] != cfg->hp_pins[0] && | ||
| 3436 | cfg->line_out_pins[0] != cfg->speaker_pins[0]) { | ||
| 3437 | for (i = 0; i < cfg->line_outs; i++) { | ||
| 3438 | if (is_jack_detectable(codec, cfg->line_out_pins[i])) { | ||
| 3439 | spec->detect_line = 1; | ||
| 3440 | break; | ||
| 3441 | } | ||
| 3442 | } | ||
| 3443 | spec->automute_lines = spec->detect_line; | ||
| 3444 | } | ||
| 3445 | |||
| 3425 | spec->vmaster_nid = spec->private_dac_nids[0]; | 3446 | spec->vmaster_nid = spec->private_dac_nids[0]; |
| 3426 | } | 3447 | } |
| 3427 | 3448 | ||
| 3428 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, | 3449 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, |
| 3429 | hda_nid_t *pins, bool on); | 3450 | hda_nid_t *pins, bool on); |
| 3430 | 3451 | ||
| 3452 | static void do_automute(struct hda_codec *codec, int num_pins, | ||
| 3453 | hda_nid_t *pins, bool on) | ||
| 3454 | { | ||
| 3455 | int i; | ||
| 3456 | for (i = 0; i < num_pins; i++) | ||
| 3457 | snd_hda_codec_write(codec, pins[i], 0, | ||
| 3458 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 3459 | on ? PIN_OUT : 0); | ||
| 3460 | cx_auto_turn_eapd(codec, num_pins, pins, on); | ||
| 3461 | } | ||
| 3462 | |||
| 3463 | static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | ||
| 3464 | { | ||
| 3465 | int i, present = 0; | ||
| 3466 | |||
| 3467 | for (i = 0; i < num_pins; i++) { | ||
| 3468 | hda_nid_t nid = pins[i]; | ||
| 3469 | if (!nid || !is_jack_detectable(codec, nid)) | ||
| 3470 | break; | ||
| 3471 | snd_hda_input_jack_report(codec, nid); | ||
| 3472 | present |= snd_hda_jack_detect(codec, nid); | ||
| 3473 | } | ||
| 3474 | return present; | ||
| 3475 | } | ||
| 3476 | |||
| 3431 | /* auto-mute/unmute speaker and line outs according to headphone jack */ | 3477 | /* auto-mute/unmute speaker and line outs according to headphone jack */ |
| 3478 | static void cx_auto_update_speakers(struct hda_codec *codec) | ||
| 3479 | { | ||
| 3480 | struct conexant_spec *spec = codec->spec; | ||
| 3481 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 3482 | int on; | ||
| 3483 | |||
| 3484 | if (!spec->auto_mute) | ||
| 3485 | on = 0; | ||
| 3486 | else | ||
| 3487 | on = spec->hp_present | spec->line_present; | ||
| 3488 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); | ||
| 3489 | do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on); | ||
| 3490 | |||
| 3491 | /* toggle line-out mutes if needed, too */ | ||
| 3492 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ | ||
| 3493 | if (cfg->line_out_pins[0] == cfg->hp_pins[0] || | ||
| 3494 | cfg->line_out_pins[0] == cfg->speaker_pins[0]) | ||
| 3495 | return; | ||
| 3496 | if (!spec->automute_lines || !spec->auto_mute) | ||
| 3497 | on = 0; | ||
| 3498 | else | ||
| 3499 | on = spec->hp_present; | ||
| 3500 | do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on); | ||
| 3501 | } | ||
| 3502 | |||
| 3432 | static void cx_auto_hp_automute(struct hda_codec *codec) | 3503 | static void cx_auto_hp_automute(struct hda_codec *codec) |
| 3433 | { | 3504 | { |
| 3434 | struct conexant_spec *spec = codec->spec; | 3505 | struct conexant_spec *spec = codec->spec; |
| 3435 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3506 | struct auto_pin_cfg *cfg = &spec->autocfg; |
| 3436 | int i, present; | ||
| 3437 | 3507 | ||
| 3438 | if (!spec->auto_mute) | 3508 | if (!spec->auto_mute) |
| 3439 | return; | 3509 | return; |
| 3440 | present = 0; | 3510 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); |
| 3441 | for (i = 0; i < cfg->hp_outs; i++) { | 3511 | cx_auto_update_speakers(codec); |
| 3442 | if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { | 3512 | } |
| 3443 | present = 1; | 3513 | |
| 3444 | break; | 3514 | static void cx_auto_line_automute(struct hda_codec *codec) |
| 3445 | } | 3515 | { |
| 3446 | } | 3516 | struct conexant_spec *spec = codec->spec; |
| 3447 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, present); | 3517 | struct auto_pin_cfg *cfg = &spec->autocfg; |
| 3448 | for (i = 0; i < cfg->line_outs; i++) { | 3518 | |
| 3449 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | 3519 | if (!spec->auto_mute || !spec->detect_line) |
| 3450 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 3520 | return; |
| 3451 | present ? 0 : PIN_OUT); | 3521 | spec->line_present = detect_jacks(codec, cfg->line_outs, |
| 3522 | cfg->line_out_pins); | ||
| 3523 | cx_auto_update_speakers(codec); | ||
| 3524 | } | ||
| 3525 | |||
| 3526 | static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, | ||
| 3527 | struct snd_ctl_elem_info *uinfo) | ||
| 3528 | { | ||
| 3529 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 3530 | struct conexant_spec *spec = codec->spec; | ||
| 3531 | static const char * const texts2[] = { | ||
| 3532 | "Disabled", "Enabled" | ||
| 3533 | }; | ||
| 3534 | static const char * const texts3[] = { | ||
| 3535 | "Disabled", "Speaker Only", "Line-Out+Speaker" | ||
| 3536 | }; | ||
| 3537 | const char * const *texts; | ||
| 3538 | |||
| 3539 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 3540 | uinfo->count = 1; | ||
| 3541 | if (spec->automute_hp_lo) { | ||
| 3542 | uinfo->value.enumerated.items = 3; | ||
| 3543 | texts = texts3; | ||
| 3544 | } else { | ||
| 3545 | uinfo->value.enumerated.items = 2; | ||
| 3546 | texts = texts2; | ||
| 3452 | } | 3547 | } |
| 3453 | cx_auto_turn_eapd(codec, cfg->line_outs, cfg->line_out_pins, !present); | 3548 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
| 3454 | for (i = 0; !present && i < cfg->line_outs; i++) | 3549 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; |
| 3455 | if (snd_hda_jack_detect(codec, cfg->line_out_pins[i])) | 3550 | strcpy(uinfo->value.enumerated.name, |
| 3456 | present = 1; | 3551 | texts[uinfo->value.enumerated.item]); |
| 3457 | for (i = 0; i < cfg->speaker_outs; i++) { | 3552 | return 0; |
| 3458 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | 3553 | } |
| 3459 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 3554 | |
| 3460 | present ? 0 : PIN_OUT); | 3555 | static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, |
| 3556 | struct snd_ctl_elem_value *ucontrol) | ||
| 3557 | { | ||
| 3558 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 3559 | struct conexant_spec *spec = codec->spec; | ||
| 3560 | unsigned int val; | ||
| 3561 | if (!spec->auto_mute) | ||
| 3562 | val = 0; | ||
| 3563 | else if (!spec->automute_lines) | ||
| 3564 | val = 1; | ||
| 3565 | else | ||
| 3566 | val = 2; | ||
| 3567 | ucontrol->value.enumerated.item[0] = val; | ||
| 3568 | return 0; | ||
| 3569 | } | ||
| 3570 | |||
| 3571 | static int cx_automute_mode_put(struct snd_kcontrol *kcontrol, | ||
| 3572 | struct snd_ctl_elem_value *ucontrol) | ||
| 3573 | { | ||
| 3574 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 3575 | struct conexant_spec *spec = codec->spec; | ||
| 3576 | |||
| 3577 | switch (ucontrol->value.enumerated.item[0]) { | ||
| 3578 | case 0: | ||
| 3579 | if (!spec->auto_mute) | ||
| 3580 | return 0; | ||
| 3581 | spec->auto_mute = 0; | ||
| 3582 | break; | ||
| 3583 | case 1: | ||
| 3584 | if (spec->auto_mute && !spec->automute_lines) | ||
| 3585 | return 0; | ||
| 3586 | spec->auto_mute = 1; | ||
| 3587 | spec->automute_lines = 0; | ||
| 3588 | break; | ||
| 3589 | case 2: | ||
| 3590 | if (!spec->automute_hp_lo) | ||
| 3591 | return -EINVAL; | ||
| 3592 | if (spec->auto_mute && spec->automute_lines) | ||
| 3593 | return 0; | ||
| 3594 | spec->auto_mute = 1; | ||
| 3595 | spec->automute_lines = 1; | ||
| 3596 | break; | ||
| 3597 | default: | ||
| 3598 | return -EINVAL; | ||
| 3461 | } | 3599 | } |
| 3462 | cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, !present); | 3600 | cx_auto_update_speakers(codec); |
| 3601 | return 1; | ||
| 3463 | } | 3602 | } |
| 3464 | 3603 | ||
| 3604 | static const struct snd_kcontrol_new cx_automute_mode_enum[] = { | ||
| 3605 | { | ||
| 3606 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3607 | .name = "Auto-Mute Mode", | ||
| 3608 | .info = cx_automute_mode_info, | ||
| 3609 | .get = cx_automute_mode_get, | ||
| 3610 | .put = cx_automute_mode_put, | ||
| 3611 | }, | ||
| 3612 | { } | ||
| 3613 | }; | ||
| 3614 | |||
| 3465 | static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, | 3615 | static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, |
| 3466 | struct snd_ctl_elem_info *uinfo) | 3616 | struct snd_ctl_elem_info *uinfo) |
| 3467 | { | 3617 | { |
| @@ -3607,7 +3757,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | |||
| 3607 | switch (res >> 26) { | 3757 | switch (res >> 26) { |
| 3608 | case CONEXANT_HP_EVENT: | 3758 | case CONEXANT_HP_EVENT: |
| 3609 | cx_auto_hp_automute(codec); | 3759 | cx_auto_hp_automute(codec); |
| 3610 | snd_hda_input_jack_report(codec, nid); | 3760 | break; |
| 3761 | case CONEXANT_LINE_EVENT: | ||
| 3762 | cx_auto_line_automute(codec); | ||
| 3611 | break; | 3763 | break; |
| 3612 | case CONEXANT_MIC_EVENT: | 3764 | case CONEXANT_MIC_EVENT: |
| 3613 | cx_auto_automic(codec); | 3765 | cx_auto_automic(codec); |
| @@ -3630,7 +3782,7 @@ static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) | |||
| 3630 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | 3782 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); |
| 3631 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | 3783 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && |
| 3632 | snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && | 3784 | snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && |
| 3633 | (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT); | 3785 | is_jack_detectable(codec, pin); |
| 3634 | } | 3786 | } |
| 3635 | 3787 | ||
| 3636 | /* check whether the pin config is suitable for auto-mic switching; | 3788 | /* check whether the pin config is suitable for auto-mic switching; |
| @@ -3794,6 +3946,16 @@ static void mute_outputs(struct hda_codec *codec, int num_nids, | |||
| 3794 | } | 3946 | } |
| 3795 | } | 3947 | } |
| 3796 | 3948 | ||
| 3949 | static void enable_unsol_pins(struct hda_codec *codec, int num_pins, | ||
| 3950 | hda_nid_t *pins, unsigned int tag) | ||
| 3951 | { | ||
| 3952 | int i; | ||
| 3953 | for (i = 0; i < num_pins; i++) | ||
| 3954 | snd_hda_codec_write(codec, pins[i], 0, | ||
| 3955 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
| 3956 | AC_USRSP_EN | tag); | ||
| 3957 | } | ||
| 3958 | |||
| 3797 | static void cx_auto_init_output(struct hda_codec *codec) | 3959 | static void cx_auto_init_output(struct hda_codec *codec) |
| 3798 | { | 3960 | { |
| 3799 | struct conexant_spec *spec = codec->spec; | 3961 | struct conexant_spec *spec = codec->spec; |
| @@ -3808,35 +3970,27 @@ static void cx_auto_init_output(struct hda_codec *codec) | |||
| 3808 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); | 3970 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); |
| 3809 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); | 3971 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); |
| 3810 | mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); | 3972 | mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); |
| 3811 | if (spec->auto_mute) { | ||
| 3812 | for (i = 0; i < cfg->hp_outs; i++) { | ||
| 3813 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | ||
| 3814 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
| 3815 | AC_USRSP_EN | CONEXANT_HP_EVENT); | ||
| 3816 | } | ||
| 3817 | cx_auto_hp_automute(codec); | ||
| 3818 | } else { | ||
| 3819 | for (i = 0; i < cfg->line_outs; i++) | ||
| 3820 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | ||
| 3821 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
| 3822 | for (i = 0; i < cfg->speaker_outs; i++) | ||
| 3823 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | ||
| 3824 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
| 3825 | /* turn on EAPD */ | ||
| 3826 | cx_auto_turn_eapd(codec, cfg->line_outs, cfg->line_out_pins, | ||
| 3827 | true); | ||
| 3828 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, | ||
| 3829 | true); | ||
| 3830 | cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, | ||
| 3831 | true); | ||
| 3832 | } | ||
| 3833 | |||
| 3834 | for (i = 0; i < spec->dac_info_filled; i++) { | 3973 | for (i = 0; i < spec->dac_info_filled; i++) { |
| 3835 | nid = spec->dac_info[i].dac; | 3974 | nid = spec->dac_info[i].dac; |
| 3836 | if (!nid) | 3975 | if (!nid) |
| 3837 | nid = spec->multiout.dac_nids[0]; | 3976 | nid = spec->multiout.dac_nids[0]; |
| 3838 | select_connection(codec, spec->dac_info[i].pin, nid); | 3977 | select_connection(codec, spec->dac_info[i].pin, nid); |
| 3839 | } | 3978 | } |
| 3979 | if (spec->auto_mute) { | ||
| 3980 | enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, | ||
| 3981 | CONEXANT_HP_EVENT); | ||
| 3982 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, | ||
| 3983 | cfg->hp_pins); | ||
| 3984 | if (spec->detect_line) { | ||
| 3985 | enable_unsol_pins(codec, cfg->line_outs, | ||
| 3986 | cfg->line_out_pins, | ||
| 3987 | CONEXANT_LINE_EVENT); | ||
| 3988 | spec->line_present = | ||
| 3989 | detect_jacks(codec, cfg->line_outs, | ||
| 3990 | cfg->line_out_pins); | ||
| 3991 | } | ||
| 3992 | } | ||
| 3993 | cx_auto_update_speakers(codec); | ||
| 3840 | } | 3994 | } |
| 3841 | 3995 | ||
| 3842 | static void cx_auto_init_input(struct hda_codec *codec) | 3996 | static void cx_auto_init_input(struct hda_codec *codec) |
| @@ -3992,6 +4146,13 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
| 3992 | if (err < 0) | 4146 | if (err < 0) |
| 3993 | return err; | 4147 | return err; |
| 3994 | } | 4148 | } |
| 4149 | |||
| 4150 | if (spec->auto_mute) { | ||
| 4151 | err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); | ||
| 4152 | if (err < 0) | ||
| 4153 | return err; | ||
| 4154 | } | ||
| 4155 | |||
| 3995 | return 0; | 4156 | return 0; |
| 3996 | } | 4157 | } |
| 3997 | 4158 | ||
