diff options
Diffstat (limited to 'sound/pci/hda/hda_auto_parser.c')
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 106 |
1 files changed, 47 insertions, 59 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4ec6dc88b7f8..7da883a464e3 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/export.h> | 13 | #include <linux/export.h> |
14 | #include <linux/sort.h> | ||
14 | #include <sound/core.h> | 15 | #include <sound/core.h> |
15 | #include "hda_codec.h" | 16 | #include "hda_codec.h" |
16 | #include "hda_local.h" | 17 | #include "hda_local.h" |
@@ -30,29 +31,30 @@ static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) | |||
30 | return 0; | 31 | return 0; |
31 | } | 32 | } |
32 | 33 | ||
34 | /* a pair of input pin and its sequence */ | ||
35 | struct auto_out_pin { | ||
36 | hda_nid_t pin; | ||
37 | short seq; | ||
38 | }; | ||
39 | |||
40 | static int compare_seq(const void *ap, const void *bp) | ||
41 | { | ||
42 | const struct auto_out_pin *a = ap; | ||
43 | const struct auto_out_pin *b = bp; | ||
44 | return (int)(a->seq - b->seq); | ||
45 | } | ||
33 | 46 | ||
34 | /* | 47 | /* |
35 | * Sort an associated group of pins according to their sequence numbers. | 48 | * Sort an associated group of pins according to their sequence numbers. |
49 | * then store it to a pin array. | ||
36 | */ | 50 | */ |
37 | static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, | 51 | static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, |
38 | int num_pins) | 52 | int num_pins) |
39 | { | 53 | { |
40 | int i, j; | 54 | int i; |
41 | short seq; | 55 | sort(list, num_pins, sizeof(list[0]), compare_seq, NULL); |
42 | hda_nid_t nid; | 56 | for (i = 0; i < num_pins; i++) |
43 | 57 | pins[i] = list[i].pin; | |
44 | for (i = 0; i < num_pins; i++) { | ||
45 | for (j = i + 1; j < num_pins; j++) { | ||
46 | if (sequences[i] > sequences[j]) { | ||
47 | seq = sequences[i]; | ||
48 | sequences[i] = sequences[j]; | ||
49 | sequences[j] = seq; | ||
50 | nid = pins[i]; | ||
51 | pins[i] = pins[j]; | ||
52 | pins[j] = nid; | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | 58 | } |
57 | 59 | ||
58 | 60 | ||
@@ -67,21 +69,11 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, | |||
67 | } | 69 | } |
68 | } | 70 | } |
69 | 71 | ||
70 | /* sort inputs in the order of AUTO_PIN_* type */ | 72 | static int compare_input_type(const void *ap, const void *bp) |
71 | static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) | ||
72 | { | 73 | { |
73 | int i, j; | 74 | const struct auto_pin_cfg_item *a = ap; |
74 | 75 | const struct auto_pin_cfg_item *b = bp; | |
75 | for (i = 0; i < cfg->num_inputs; i++) { | 76 | return (int)(a->type - b->type); |
76 | for (j = i + 1; j < cfg->num_inputs; j++) { | ||
77 | if (cfg->inputs[i].type > cfg->inputs[j].type) { | ||
78 | struct auto_pin_cfg_item tmp; | ||
79 | tmp = cfg->inputs[i]; | ||
80 | cfg->inputs[i] = cfg->inputs[j]; | ||
81 | cfg->inputs[j] = tmp; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | } | 77 | } |
86 | 78 | ||
87 | /* Reorder the surround channels | 79 | /* Reorder the surround channels |
@@ -129,16 +121,16 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
129 | { | 121 | { |
130 | hda_nid_t nid, end_nid; | 122 | hda_nid_t nid, end_nid; |
131 | short seq, assoc_line_out; | 123 | short seq, assoc_line_out; |
132 | short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; | 124 | struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; |
133 | short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; | 125 | struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; |
134 | short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; | 126 | struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; |
135 | int i; | 127 | int i; |
136 | 128 | ||
137 | memset(cfg, 0, sizeof(*cfg)); | 129 | memset(cfg, 0, sizeof(*cfg)); |
138 | 130 | ||
139 | memset(sequences_line_out, 0, sizeof(sequences_line_out)); | 131 | memset(line_out, 0, sizeof(line_out)); |
140 | memset(sequences_speaker, 0, sizeof(sequences_speaker)); | 132 | memset(speaker_out, 0, sizeof(speaker_out)); |
141 | memset(sequences_hp, 0, sizeof(sequences_hp)); | 133 | memset(hp_out, 0, sizeof(hp_out)); |
142 | assoc_line_out = 0; | 134 | assoc_line_out = 0; |
143 | 135 | ||
144 | end_nid = codec->start_nid + codec->num_nodes; | 136 | end_nid = codec->start_nid + codec->num_nodes; |
@@ -184,8 +176,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
184 | continue; | 176 | continue; |
185 | if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) | 177 | if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) |
186 | continue; | 178 | continue; |
187 | cfg->line_out_pins[cfg->line_outs] = nid; | 179 | line_out[cfg->line_outs].pin = nid; |
188 | sequences_line_out[cfg->line_outs] = seq; | 180 | line_out[cfg->line_outs].seq = seq; |
189 | cfg->line_outs++; | 181 | cfg->line_outs++; |
190 | break; | 182 | break; |
191 | case AC_JACK_SPEAKER: | 183 | case AC_JACK_SPEAKER: |
@@ -193,8 +185,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
193 | assoc = get_defcfg_association(def_conf); | 185 | assoc = get_defcfg_association(def_conf); |
194 | if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) | 186 | if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) |
195 | continue; | 187 | continue; |
196 | cfg->speaker_pins[cfg->speaker_outs] = nid; | 188 | speaker_out[cfg->speaker_outs].pin = nid; |
197 | sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; | 189 | speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; |
198 | cfg->speaker_outs++; | 190 | cfg->speaker_outs++; |
199 | break; | 191 | break; |
200 | case AC_JACK_HP_OUT: | 192 | case AC_JACK_HP_OUT: |
@@ -202,8 +194,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
202 | assoc = get_defcfg_association(def_conf); | 194 | assoc = get_defcfg_association(def_conf); |
203 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) | 195 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) |
204 | continue; | 196 | continue; |
205 | cfg->hp_pins[cfg->hp_outs] = nid; | 197 | hp_out[cfg->hp_outs].pin = nid; |
206 | sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; | 198 | hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; |
207 | cfg->hp_outs++; | 199 | cfg->hp_outs++; |
208 | break; | 200 | break; |
209 | case AC_JACK_MIC_IN: | 201 | case AC_JACK_MIC_IN: |
@@ -248,34 +240,28 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
248 | int i = 0; | 240 | int i = 0; |
249 | while (i < cfg->hp_outs) { | 241 | while (i < cfg->hp_outs) { |
250 | /* The real HPs should have the sequence 0x0f */ | 242 | /* The real HPs should have the sequence 0x0f */ |
251 | if ((sequences_hp[i] & 0x0f) == 0x0f) { | 243 | if ((hp_out[i].seq & 0x0f) == 0x0f) { |
252 | i++; | 244 | i++; |
253 | continue; | 245 | continue; |
254 | } | 246 | } |
255 | /* Move it to the line-out table */ | 247 | /* Move it to the line-out table */ |
256 | cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; | 248 | line_out[cfg->line_outs++] = hp_out[i]; |
257 | sequences_line_out[cfg->line_outs] = sequences_hp[i]; | ||
258 | cfg->line_outs++; | ||
259 | cfg->hp_outs--; | 249 | cfg->hp_outs--; |
260 | memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, | 250 | memmove(hp_out + i, hp_out + i + 1, |
261 | sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); | 251 | sizeof(hp_out[0]) * (cfg->hp_outs - i)); |
262 | memmove(sequences_hp + i, sequences_hp + i + 1, | ||
263 | sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); | ||
264 | } | 252 | } |
265 | memset(cfg->hp_pins + cfg->hp_outs, 0, | 253 | memset(hp_out + cfg->hp_outs, 0, |
266 | sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); | 254 | sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); |
267 | if (!cfg->hp_outs) | 255 | if (!cfg->hp_outs) |
268 | cfg->line_out_type = AUTO_PIN_HP_OUT; | 256 | cfg->line_out_type = AUTO_PIN_HP_OUT; |
269 | 257 | ||
270 | } | 258 | } |
271 | 259 | ||
272 | /* sort by sequence */ | 260 | /* sort by sequence */ |
273 | sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, | 261 | sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); |
274 | cfg->line_outs); | 262 | sort_pins_by_sequence(cfg->speaker_pins, speaker_out, |
275 | sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, | ||
276 | cfg->speaker_outs); | 263 | cfg->speaker_outs); |
277 | sort_pins_by_sequence(cfg->hp_pins, sequences_hp, | 264 | sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); |
278 | cfg->hp_outs); | ||
279 | 265 | ||
280 | /* | 266 | /* |
281 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin | 267 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin |
@@ -304,7 +290,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, | |||
304 | reorder_outputs(cfg->hp_outs, cfg->hp_pins); | 290 | reorder_outputs(cfg->hp_outs, cfg->hp_pins); |
305 | reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); | 291 | reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); |
306 | 292 | ||
307 | sort_autocfg_input_pins(cfg); | 293 | /* sort inputs in the order of AUTO_PIN_* type */ |
294 | sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), | ||
295 | compare_input_type, NULL); | ||
308 | 296 | ||
309 | /* | 297 | /* |
310 | * debug prints of the parsed results | 298 | * debug prints of the parsed results |