aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-08-19 03:05:35 -0400
committerTakashi Iwai <tiwai@suse.de>2011-08-19 03:05:35 -0400
commit23c09b00900c3fa6672148738cad29d6fc6ded7c (patch)
treea41e345353bfe4e3b0eb91e01b2bf0da2deef5f0 /sound/pci/hda/patch_realtek.c
parent2996bdbaa40c52c76ec9b981dfa1c9f3a6191fc3 (diff)
ALSA: hda - Support multiple speakers by Realtek auto-parser
Add the support of multiple speakers by Realtek auto-parser. When all speaker pins have individual DACs, create each speaker volume control. Otherwise, create a bind-volume control for all speaker outs. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c196
1 files changed, 164 insertions, 32 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d330e9717432..e0ecf5a5b097 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -203,6 +203,9 @@ struct alc_spec {
203 /* multi-io */ 203 /* multi-io */
204 int multi_ios; 204 int multi_ios;
205 struct alc_multi_io multi_io[4]; 205 struct alc_multi_io multi_io[4];
206
207 /* bind volumes */
208 struct snd_array bind_ctls;
206}; 209};
207 210
208#define ALC_MODEL_AUTO 0 /* common for all chips */ 211#define ALC_MODEL_AUTO 0 /* common for all chips */
@@ -2369,6 +2372,18 @@ static void alc_free_kctls(struct hda_codec *codec)
2369 snd_array_free(&spec->kctls); 2372 snd_array_free(&spec->kctls);
2370} 2373}
2371 2374
2375static void alc_free_bind_ctls(struct hda_codec *codec)
2376{
2377 struct alc_spec *spec = codec->spec;
2378 if (spec->bind_ctls.list) {
2379 struct hda_bind_ctls **ctl = spec->bind_ctls.list;
2380 int i;
2381 for (i = 0; i < spec->bind_ctls.used; i++)
2382 kfree(ctl[i]);
2383 }
2384 snd_array_free(&spec->bind_ctls);
2385}
2386
2372static void alc_free(struct hda_codec *codec) 2387static void alc_free(struct hda_codec *codec)
2373{ 2388{
2374 struct alc_spec *spec = codec->spec; 2389 struct alc_spec *spec = codec->spec;
@@ -2379,6 +2394,7 @@ static void alc_free(struct hda_codec *codec)
2379 alc_shutup(codec); 2394 alc_shutup(codec);
2380 snd_hda_input_jack_free(codec); 2395 snd_hda_input_jack_free(codec);
2381 alc_free_kctls(codec); 2396 alc_free_kctls(codec);
2397 alc_free_bind_ctls(codec);
2382 kfree(spec); 2398 kfree(spec);
2383 snd_hda_detach_beep_device(codec); 2399 snd_hda_detach_beep_device(codec);
2384} 2400}
@@ -2449,11 +2465,15 @@ enum {
2449 ALC_CTL_WIDGET_VOL, 2465 ALC_CTL_WIDGET_VOL,
2450 ALC_CTL_WIDGET_MUTE, 2466 ALC_CTL_WIDGET_MUTE,
2451 ALC_CTL_BIND_MUTE, 2467 ALC_CTL_BIND_MUTE,
2468 ALC_CTL_BIND_VOL,
2469 ALC_CTL_BIND_SW,
2452}; 2470};
2453static const struct snd_kcontrol_new alc_control_templates[] = { 2471static const struct snd_kcontrol_new alc_control_templates[] = {
2454 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 2472 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2455 HDA_CODEC_MUTE(NULL, 0, 0, 0), 2473 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2456 HDA_BIND_MUTE(NULL, 0, 0, 0), 2474 HDA_BIND_MUTE(NULL, 0, 0, 0),
2475 HDA_BIND_VOL(NULL, 0),
2476 HDA_BIND_SW(NULL, 0),
2457}; 2477};
2458 2478
2459/* add dynamic controls */ 2479/* add dynamic controls */
@@ -2494,13 +2514,14 @@ static int add_control_with_pfx(struct alc_spec *spec, int type,
2494#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 2514#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
2495 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 2515 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
2496 2516
2517static const char * const channel_name[4] = {
2518 "Front", "Surround", "CLFE", "Side"
2519};
2520
2497static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, 2521static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
2498 bool can_be_master, int *index) 2522 bool can_be_master, int *index)
2499{ 2523{
2500 struct auto_pin_cfg *cfg = &spec->autocfg; 2524 struct auto_pin_cfg *cfg = &spec->autocfg;
2501 static const char * const chname[4] = {
2502 "Front", "Surround", NULL /*CLFE*/, "Side"
2503 };
2504 2525
2505 *index = 0; 2526 *index = 0;
2506 if (cfg->line_outs == 1 && !spec->multi_ios && 2527 if (cfg->line_outs == 1 && !spec->multi_ios &&
@@ -2523,7 +2544,10 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
2523 return "PCM"; 2544 return "PCM";
2524 break; 2545 break;
2525 } 2546 }
2526 return chname[ch]; 2547 if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name)))
2548 return "PCM";
2549
2550 return channel_name[ch];
2527} 2551}
2528 2552
2529/* create input playback/capture controls for the given pin */ 2553/* create input playback/capture controls for the given pin */
@@ -2869,6 +2893,28 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
2869 return 0; 2893 return 0;
2870} 2894}
2871 2895
2896/* fill in the dac_nids table for surround speakers, etc */
2897static int alc_auto_fill_extra_dacs(struct hda_codec *codec)
2898{
2899 struct alc_spec *spec = codec->spec;
2900 const struct auto_pin_cfg *cfg = &spec->autocfg;
2901 int i;
2902
2903 if (cfg->speaker_outs < 2 || !spec->multiout.extra_out_nid[0])
2904 return 0;
2905
2906 for (i = 1; i < cfg->speaker_outs; i++)
2907 spec->multiout.extra_out_nid[i] =
2908 get_dac_if_single(codec, cfg->speaker_pins[i]);
2909 for (i = 1; i < cfg->speaker_outs; i++) {
2910 if (spec->multiout.extra_out_nid[i])
2911 continue;
2912 spec->multiout.extra_out_nid[i] =
2913 alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
2914 }
2915 return 0;
2916}
2917
2872static int alc_auto_add_vol_ctl(struct hda_codec *codec, 2918static int alc_auto_add_vol_ctl(struct hda_codec *codec,
2873 const char *pfx, int cidx, 2919 const char *pfx, int cidx,
2874 hda_nid_t nid, unsigned int chs) 2920 hda_nid_t nid, unsigned int chs)
@@ -2991,16 +3037,13 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
2991 return 0; 3037 return 0;
2992} 3038}
2993 3039
2994/* add playback controls for speaker and HP outputs */
2995static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, 3040static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2996 hda_nid_t dac, const char *pfx) 3041 hda_nid_t dac, const char *pfx)
2997{ 3042{
2998 struct alc_spec *spec = codec->spec; 3043 struct alc_spec *spec = codec->spec;
2999 hda_nid_t sw, vol; 3044 hda_nid_t sw, vol;
3000 int err; 3045 int err;
3001 3046
3002 if (!pin)
3003 return 0;
3004 if (!dac) { 3047 if (!dac) {
3005 /* the corresponding DAC is already occupied */ 3048 /* the corresponding DAC is already occupied */
3006 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) 3049 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
@@ -3021,6 +3064,92 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
3021 return 0; 3064 return 0;
3022} 3065}
3023 3066
3067static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
3068 unsigned int nums,
3069 struct hda_ctl_ops *ops)
3070{
3071 struct alc_spec *spec = codec->spec;
3072 struct hda_bind_ctls **ctlp, *ctl;
3073 snd_array_init(&spec->bind_ctls, sizeof(ctl), 8);
3074 ctlp = snd_array_new(&spec->bind_ctls);
3075 if (!ctlp)
3076 return NULL;
3077 ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
3078 *ctlp = ctl;
3079 if (ctl)
3080 ctl->ops = ops;
3081 return ctl;
3082}
3083
3084/* add playback controls for speaker and HP outputs */
3085static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
3086 const hda_nid_t *pins,
3087 const hda_nid_t *dacs,
3088 const char *pfx)
3089{
3090 struct alc_spec *spec = codec->spec;
3091 struct hda_bind_ctls *ctl;
3092 char name[32];
3093 int i, n, err;
3094
3095 if (!num_pins || !pins[0])
3096 return 0;
3097
3098 if (num_pins == 1)
3099 return alc_auto_create_extra_out(codec, *pins, *dacs, pfx);
3100
3101 if (dacs[num_pins - 1]) {
3102 /* OK, we have a multi-output system with individual volumes */
3103 for (i = 0; i < num_pins; i++) {
3104 snprintf(name, sizeof(name), "%s %s",
3105 pfx, channel_name[i]);
3106 err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
3107 name);
3108 if (err < 0)
3109 return err;
3110 }
3111 return 0;
3112 }
3113
3114 /* Let's create a bind-controls */
3115 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
3116 if (!ctl)
3117 return -ENOMEM;
3118 n = 0;
3119 for (i = 0; i < num_pins; i++) {
3120 if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
3121 ctl->values[n++] =
3122 HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
3123 }
3124 if (n) {
3125 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
3126 err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
3127 if (err < 0)
3128 return err;
3129 }
3130
3131 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
3132 if (!ctl)
3133 return -ENOMEM;
3134 n = 0;
3135 for (i = 0; i < num_pins; i++) {
3136 hda_nid_t vol;
3137 if (!pins[i] || !dacs[i])
3138 continue;
3139 vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]);
3140 if (vol)
3141 ctl->values[n++] =
3142 HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
3143 }
3144 if (n) {
3145 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
3146 err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
3147 if (err < 0)
3148 return err;
3149 }
3150 return 0;
3151}
3152
3024static int alc_auto_create_hp_out(struct hda_codec *codec) 3153static int alc_auto_create_hp_out(struct hda_codec *codec)
3025{ 3154{
3026 struct alc_spec *spec = codec->spec; 3155 struct alc_spec *spec = codec->spec;
@@ -3032,9 +3161,10 @@ static int alc_auto_create_hp_out(struct hda_codec *codec)
3032static int alc_auto_create_speaker_out(struct hda_codec *codec) 3161static int alc_auto_create_speaker_out(struct hda_codec *codec)
3033{ 3162{
3034 struct alc_spec *spec = codec->spec; 3163 struct alc_spec *spec = codec->spec;
3035 return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], 3164 return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
3036 spec->multiout.extra_out_nid[0], 3165 spec->autocfg.speaker_pins,
3037 "Speaker"); 3166 spec->multiout.extra_out_nid,
3167 "Speaker");
3038} 3168}
3039 3169
3040static void alc_auto_set_output_and_unmute(struct hda_codec *codec, 3170static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
@@ -3225,27 +3355,13 @@ static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
3225 .put = alc_auto_ch_mode_put, 3355 .put = alc_auto_ch_mode_put,
3226}; 3356};
3227 3357
3228static int alc_auto_add_multi_channel_mode(struct hda_codec *codec, 3358static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
3229 int (*fill_dac)(struct hda_codec *))
3230{ 3359{
3231 struct alc_spec *spec = codec->spec; 3360 struct alc_spec *spec = codec->spec;
3232 struct auto_pin_cfg *cfg = &spec->autocfg; 3361 struct auto_pin_cfg *cfg = &spec->autocfg;
3233 unsigned int location, defcfg; 3362 unsigned int location, defcfg;
3234 int num_pins; 3363 int num_pins;
3235 3364
3236 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
3237 /* use HP as primary out */
3238 cfg->speaker_outs = cfg->line_outs;
3239 memcpy(cfg->speaker_pins, cfg->line_out_pins,
3240 sizeof(cfg->speaker_pins));
3241 cfg->line_outs = cfg->hp_outs;
3242 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3243 cfg->hp_outs = 0;
3244 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3245 cfg->line_out_type = AUTO_PIN_HP_OUT;
3246 if (fill_dac)
3247 fill_dac(codec);
3248 }
3249 if (cfg->line_outs != 1 || 3365 if (cfg->line_outs != 1 ||
3250 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 3366 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
3251 return 0; 3367 return 0;
@@ -3550,27 +3666,43 @@ static int alc_parse_auto_config(struct hda_codec *codec,
3550 const hda_nid_t *ssid_nids) 3666 const hda_nid_t *ssid_nids)
3551{ 3667{
3552 struct alc_spec *spec = codec->spec; 3668 struct alc_spec *spec = codec->spec;
3669 struct auto_pin_cfg *cfg = &spec->autocfg;
3553 int err; 3670 int err;
3554 3671
3555 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 3672 err = snd_hda_parse_pin_def_config(codec, cfg, ignore_nids);
3556 ignore_nids);
3557 if (err < 0) 3673 if (err < 0)
3558 return err; 3674 return err;
3559 if (!spec->autocfg.line_outs) { 3675 if (!cfg->line_outs) {
3560 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { 3676 if (cfg->dig_outs || cfg->dig_in_pin) {
3561 spec->multiout.max_channels = 2; 3677 spec->multiout.max_channels = 2;
3562 spec->no_analog = 1; 3678 spec->no_analog = 1;
3563 goto dig_only; 3679 goto dig_only;
3564 } 3680 }
3565 return 0; /* can't find valid BIOS pin config */ 3681 return 0; /* can't find valid BIOS pin config */
3566 } 3682 }
3683
3684 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
3685 /* use HP as primary out */
3686 cfg->speaker_outs = cfg->line_outs;
3687 memcpy(cfg->speaker_pins, cfg->line_out_pins,
3688 sizeof(cfg->speaker_pins));
3689 cfg->line_outs = cfg->hp_outs;
3690 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3691 cfg->hp_outs = 0;
3692 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3693 cfg->line_out_type = AUTO_PIN_HP_OUT;
3694 }
3695
3567 err = alc_auto_fill_dac_nids(codec); 3696 err = alc_auto_fill_dac_nids(codec);
3568 if (err < 0) 3697 if (err < 0)
3569 return err; 3698 return err;
3570 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids); 3699 err = alc_auto_add_multi_channel_mode(codec);
3700 if (err < 0)
3701 return err;
3702 err = alc_auto_fill_extra_dacs(codec);
3571 if (err < 0) 3703 if (err < 0)
3572 return err; 3704 return err;
3573 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg); 3705 err = alc_auto_create_multi_out_ctls(codec, cfg);
3574 if (err < 0) 3706 if (err < 0)
3575 return err; 3707 return err;
3576 err = alc_auto_create_hp_out(codec); 3708 err = alc_auto_create_hp_out(codec);