aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-12-06 09:45:38 -0500
committerTakashi Iwai <tiwai@suse.de>2013-01-10 04:34:26 -0500
commit30dcd3b40409a4db272998b0cba1b9e80c15b1c8 (patch)
tree37873f6d3d8f4727d6c88f16929cabe86d0d0dfd /sound/pci/hda/patch_realtek.c
parent463419de865622e4b13e977e1536375ab897a53f (diff)
ALSA: hda/realtek - Add output path parser
Add the output path parser to Realtek codec driver as we already have in patch_via.c. The nid_path struct represents the complete output path from a DAC to a pin. The alc_spec contains an array of these paths, and a new path is added at each time when a new DAC is assigned. So far, this path list is used only in limited codes: namely in this patch, only alc_is_dac_already_used() checks the list instead of dac arrays in all possible outputs. In the later development, the path list will be referred from more places, such as the mixer control assignment / check, the mute/unmute of active routes, etc. 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.c139
1 files changed, 128 insertions, 11 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8b768a566be0..1f178d6da9d4 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -99,6 +99,23 @@ enum {
99#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD 99#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD
100 100
101 101
102#define MAX_NID_PATH_DEPTH 5
103
104/* output-path: DAC -> ... -> pin
105 * idx[] contains the source index number of the next widget;
106 * e.g. idx[0] is the index of the DAC selected by path[1] widget
107 * multi[] indicates whether it's a selector widget with multi-connectors
108 * (i.e. the connection selection is mandatory)
109 * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
110 */
111struct nid_path {
112 int depth;
113 hda_nid_t path[MAX_NID_PATH_DEPTH];
114 unsigned char idx[MAX_NID_PATH_DEPTH];
115 unsigned char multi[MAX_NID_PATH_DEPTH];
116 unsigned int ctls[2]; /* 0 = volume, 1 = mute */
117};
118
102struct alc_spec { 119struct alc_spec {
103 struct hda_gen_spec gen; 120 struct hda_gen_spec gen;
104 121
@@ -176,6 +193,9 @@ struct alc_spec {
176 int num_all_dacs; 193 int num_all_dacs;
177 hda_nid_t all_dacs[16]; 194 hda_nid_t all_dacs[16];
178 195
196 /* output paths */
197 struct snd_array out_path;
198
179 /* hooks */ 199 /* hooks */
180 void (*init_hook)(struct hda_codec *codec); 200 void (*init_hook)(struct hda_codec *codec);
181#ifdef CONFIG_PM 201#ifdef CONFIG_PM
@@ -2407,6 +2427,7 @@ static void alc_free(struct hda_codec *codec)
2407 2427
2408 alc_free_kctls(codec); 2428 alc_free_kctls(codec);
2409 alc_free_bind_ctls(codec); 2429 alc_free_bind_ctls(codec);
2430 snd_array_free(&spec->out_path);
2410 snd_hda_gen_free(&spec->gen); 2431 snd_hda_gen_free(&spec->gen);
2411 kfree(spec); 2432 kfree(spec);
2412 snd_hda_detach_beep_device(codec); 2433 snd_hda_detach_beep_device(codec);
@@ -2906,15 +2927,10 @@ static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
2906{ 2927{
2907 struct alc_spec *spec = codec->spec; 2928 struct alc_spec *spec = codec->spec;
2908 int i; 2929 int i;
2909 if (found_in_nid_list(nid, spec->multiout.dac_nids, 2930
2910 ARRAY_SIZE(spec->private_dac_nids)) || 2931 for (i = 0; i < spec->out_path.used; i++) {
2911 found_in_nid_list(nid, spec->multiout.hp_out_nid, 2932 struct nid_path *path = snd_array_elem(&spec->out_path, i);
2912 ARRAY_SIZE(spec->multiout.hp_out_nid)) || 2933 if (path->path[0] == nid)
2913 found_in_nid_list(nid, spec->multiout.extra_out_nid,
2914 ARRAY_SIZE(spec->multiout.extra_out_nid)))
2915 return true;
2916 for (i = 0; i < spec->multi_ios; i++) {
2917 if (spec->multi_io[i].dac == nid)
2918 return true; 2934 return true;
2919 } 2935 }
2920 return false; 2936 return false;
@@ -2945,6 +2961,75 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
2945 return 0; 2961 return 0;
2946} 2962}
2947 2963
2964/* called recursively */
2965static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid,
2966 hda_nid_t target_dac, int with_aa_mix,
2967 struct nid_path *path, int depth)
2968{
2969 struct alc_spec *spec = codec->spec;
2970 hda_nid_t conn[8];
2971 int i, nums;
2972
2973 if (nid == spec->mixer_nid) {
2974 if (!with_aa_mix)
2975 return false;
2976 with_aa_mix = 2; /* mark aa-mix is included */
2977 }
2978
2979 nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn));
2980 for (i = 0; i < nums; i++) {
2981 if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT)
2982 continue;
2983 if (conn[i] == target_dac ||
2984 (!target_dac && !alc_is_dac_already_used(codec, conn[i]))) {
2985 /* aa-mix is requested but not included? */
2986 if (!(spec->mixer_nid && with_aa_mix == 1))
2987 goto found;
2988 }
2989 }
2990 if (depth >= MAX_NID_PATH_DEPTH)
2991 return false;
2992 for (i = 0; i < nums; i++) {
2993 unsigned int type;
2994 type = get_wcaps_type(get_wcaps(codec, conn[i]));
2995 if (type == AC_WID_AUD_OUT)
2996 continue;
2997 if (__parse_output_path(codec, conn[i], target_dac,
2998 with_aa_mix, path, depth + 1))
2999 goto found;
3000 }
3001 return false;
3002
3003 found:
3004 path->path[path->depth] = conn[i];
3005 path->idx[path->depth] = i;
3006 if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
3007 path->multi[path->depth] = 1;
3008 path->depth++;
3009 return true;
3010}
3011
3012/* parse the output path from the given nid to the target DAC;
3013 * when target_dac is 0, try to find an empty DAC;
3014 * when with_aa_mix is 0, paths with spec->mixer_nid are excluded
3015 */
3016static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid,
3017 hda_nid_t target_dac, int with_aa_mix,
3018 struct nid_path *path)
3019{
3020 if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) {
3021 path->path[path->depth] = nid;
3022 path->depth++;
3023#if 0
3024 snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n",
3025 path->depth, path->path[0], path->path[1],
3026 path->path[2], path->path[3], path->path[4]);
3027#endif
3028 return true;
3029 }
3030 return false;
3031}
3032
2948static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 3033static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
2949{ 3034{
2950 struct alc_spec *spec = codec->spec; 3035 struct alc_spec *spec = codec->spec;
@@ -3016,6 +3101,23 @@ static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
3016static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, 3101static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
3017 hda_nid_t pin, hda_nid_t dac); 3102 hda_nid_t pin, hda_nid_t dac);
3018 3103
3104static bool add_new_out_path(struct hda_codec *codec, hda_nid_t pin,
3105 hda_nid_t dac)
3106{
3107 struct alc_spec *spec = codec->spec;
3108 struct nid_path *path;
3109
3110 path = snd_array_new(&spec->out_path);
3111 if (!path)
3112 return false;
3113 memset(path, 0, sizeof(*path));
3114 if (parse_output_path(codec, pin, dac, 0, path))
3115 return true;
3116 /* push back */
3117 spec->out_path.used--;
3118 return false;
3119}
3120
3019static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, 3121static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin,
3020 hda_nid_t dac) 3122 hda_nid_t dac)
3021{ 3123{
@@ -3127,6 +3229,8 @@ static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs,
3127 else 3229 else
3128 badness += bad->no_dac; 3230 badness += bad->no_dac;
3129 } 3231 }
3232 if (!add_new_out_path(codec, pin, dac))
3233 dac = dacs[i] = 0;
3130 if (dac) 3234 if (dac)
3131 badness += eval_shared_vol_badness(codec, pin, dac); 3235 badness += eval_shared_vol_badness(codec, pin, dac);
3132 } 3236 }
@@ -3144,11 +3248,16 @@ static bool alc_map_singles(struct hda_codec *codec, int outs,
3144 int i; 3248 int i;
3145 bool found = false; 3249 bool found = false;
3146 for (i = 0; i < outs; i++) { 3250 for (i = 0; i < outs; i++) {
3251 hda_nid_t dac;
3147 if (dacs[i]) 3252 if (dacs[i])
3148 continue; 3253 continue;
3149 dacs[i] = get_dac_if_single(codec, pins[i]); 3254 dac = get_dac_if_single(codec, pins[i]);
3150 if (dacs[i]) 3255 if (!dac)
3256 continue;
3257 if (add_new_out_path(codec, pins[i], dac)) {
3258 dacs[i] = dac;
3151 found = true; 3259 found = true;
3260 }
3152 } 3261 }
3153 return found; 3262 return found;
3154} 3263}
@@ -3169,6 +3278,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
3169 memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 3278 memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
3170 memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 3279 memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
3171 spec->multi_ios = 0; 3280 spec->multi_ios = 0;
3281 snd_array_free(&spec->out_path);
3172 clear_vol_marks(codec); 3282 clear_vol_marks(codec);
3173 badness = 0; 3283 badness = 0;
3174 3284
@@ -3882,6 +3992,10 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
3882 badness++; 3992 badness++;
3883 continue; 3993 continue;
3884 } 3994 }
3995 if (!add_new_out_path(codec, nid, dac)) {
3996 badness++;
3997 continue;
3998 }
3885 spec->multi_io[spec->multi_ios].pin = nid; 3999 spec->multi_io[spec->multi_ios].pin = nid;
3886 spec->multi_io[spec->multi_ios].dac = dac; 4000 spec->multi_io[spec->multi_ios].dac = dac;
3887 spec->multi_ios++; 4001 spec->multi_ios++;
@@ -3899,6 +4013,8 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
3899 return badness; /* no badness if nothing found */ 4013 return badness; /* no badness if nothing found */
3900 } 4014 }
3901 if (!hardwired && spec->multi_ios < 2) { 4015 if (!hardwired && spec->multi_ios < 2) {
4016 /* cancel newly assigned paths */
4017 spec->out_path.used -= spec->multi_ios - old_pins;
3902 spec->multi_ios = old_pins; 4018 spec->multi_ios = old_pins;
3903 return badness; 4019 return badness;
3904 } 4020 }
@@ -4388,6 +4504,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
4388 snd_hda_gen_init(&spec->gen); 4504 snd_hda_gen_init(&spec->gen);
4389 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); 4505 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
4390 snd_array_init(&spec->bind_ctls, sizeof(struct hda_bind_ctls *), 8); 4506 snd_array_init(&spec->bind_ctls, sizeof(struct hda_bind_ctls *), 8);
4507 snd_array_init(&spec->out_path, sizeof(struct nid_path), 8);
4391 4508
4392 err = alc_codec_rename_from_preset(codec); 4509 err = alc_codec_rename_from_preset(codec);
4393 if (err < 0) { 4510 if (err < 0) {