diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-12-06 09:45:38 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-10 04:34:26 -0500 |
commit | 30dcd3b40409a4db272998b0cba1b9e80c15b1c8 (patch) | |
tree | 37873f6d3d8f4727d6c88f16929cabe86d0d0dfd /sound/pci/hda/patch_realtek.c | |
parent | 463419de865622e4b13e977e1536375ab897a53f (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.c | 139 |
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 | */ | ||
111 | struct 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 | |||
102 | struct alc_spec { | 119 | struct 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 */ | ||
2965 | static 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 | */ | ||
3016 | static 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 | |||
2948 | static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) | 3033 | static 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, | |||
3016 | static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, | 3101 | static 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 | ||
3104 | static 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 | |||
3019 | static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, | 3121 | static 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) { |