aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_intelhdmi.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
index 3c68aa9742d7..1c374f11ed07 100644
--- a/sound/pci/hda/patch_intelhdmi.c
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -213,6 +213,10 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
213}; 213};
214 214
215 215
216/*
217 * HDA/HDMI auto parsing
218 */
219
216static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) 220static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
217{ 221{
218 int i; 222 int i;
@@ -225,6 +229,113 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
225 return -EINVAL; 229 return -EINVAL;
226} 230}
227 231
232static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
233{
234 struct intel_hdmi_spec *spec = codec->spec;
235 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
236 int conn_len, curr;
237 int index;
238
239 if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
240 snd_printk(KERN_WARNING
241 "HDMI: pin %d wcaps %#x "
242 "does not support connection list\n",
243 pin_nid, get_wcaps(codec, pin_nid));
244 return -EINVAL;
245 }
246
247 conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
248 HDA_MAX_CONNECTIONS);
249 if (conn_len > 1)
250 curr = snd_hda_codec_read(codec, pin_nid, 0,
251 AC_VERB_GET_CONNECT_SEL, 0);
252 else
253 curr = 0;
254
255 index = hda_node_index(spec->pin, pin_nid);
256 if (index < 0)
257 return -EINVAL;
258
259 spec->pin_cvt[index] = conn_list[curr];
260
261 return 0;
262}
263
264static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
265{
266 struct intel_hdmi_spec *spec = codec->spec;
267
268 if (spec->num_pins >= INTEL_HDMI_PINS) {
269 snd_printk(KERN_WARNING
270 "HDMI: no space for pin %d \n", pin_nid);
271 return -EINVAL;
272 }
273
274 spec->pin[spec->num_pins] = pin_nid;
275 spec->num_pins++;
276
277 /*
278 * It is assumed that converter nodes come first in the node list and
279 * hence have been registered and usable now.
280 */
281 return intel_hdmi_read_pin_conn(codec, pin_nid);
282}
283
284static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
285{
286 struct intel_hdmi_spec *spec = codec->spec;
287
288 if (spec->num_cvts >= INTEL_HDMI_CVTS) {
289 snd_printk(KERN_WARNING
290 "HDMI: no space for converter %d \n", nid);
291 return -EINVAL;
292 }
293
294 spec->cvt[spec->num_cvts] = nid;
295 spec->num_cvts++;
296
297 return 0;
298}
299
300static int intel_hdmi_parse_codec(struct hda_codec *codec)
301{
302 hda_nid_t nid;
303 int i, nodes;
304
305 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
306 if (!nid || nodes < 0) {
307 snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
308 return -EINVAL;
309 }
310
311 for (i = 0; i < nodes; i++, nid++) {
312 unsigned int caps;
313 unsigned int type;
314
315 caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
316 type = get_wcaps_type(caps);
317
318 if (!(caps & AC_WCAP_DIGITAL))
319 continue;
320
321 switch (type) {
322 case AC_WID_AUD_OUT:
323 if (intel_hdmi_add_cvt(codec, nid) < 0)
324 return -EINVAL;
325 break;
326 case AC_WID_PIN:
327 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
328 if (!(caps & AC_PINCAP_HDMI))
329 continue;
330 if (intel_hdmi_add_pin(codec, nid) < 0)
331 return -EINVAL;
332 break;
333 }
334 }
335
336 return 0;
337}
338
228/* 339/*
229 * HDMI routines 340 * HDMI routines
230 */ 341 */
@@ -756,8 +867,15 @@ static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id)
756 if (spec == NULL) 867 if (spec == NULL)
757 return -ENOMEM; 868 return -ENOMEM;
758 869
759 *spec = static_specs[spec_id];
760 codec->spec = spec; 870 codec->spec = spec;
871 if (intel_hdmi_parse_codec(codec) < 0) {
872 codec->spec = NULL;
873 kfree(spec);
874 return -EINVAL;
875 }
876 if (memcmp(spec, static_specs + spec_id, sizeof(*spec)))
877 snd_printk(KERN_WARNING
878 "HDMI: auto parse disagree with known config\n");
761 codec->patch_ops = intel_hdmi_patch_ops; 879 codec->patch_ops = intel_hdmi_patch_ops;
762 880
763 for (i = 0; i < spec->num_pins; i++) 881 for (i = 0; i < spec->num_pins; i++)