diff options
author | Wu Fengguang <fengguang.wu@intel.com> | 2009-10-30 06:44:26 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-10-30 06:44:26 -0400 |
commit | 54a25f87e943fc77f57e86849897ad6602519286 (patch) | |
tree | 669440adf0fa4342f250fb68937a23a879c19a89 | |
parent | ddb8152b054e357907f57fb5ae65d494a3c79065 (diff) |
ALSA: hda - vectorize intelhdmi
The Intel IbexPeak HDMI codec supports 2 converters and 3 pins,
which requires converting the cvt_nid/pin_nid to arrays.
The active pin number (the one connected with a live HDMI monitor/sink)
will be dynamically identified on hotplug events.
It exports two HDMI devices, so that user space can choose the A/V pipe
for sending the audio samples.
It's still undefined behavior when there are two active monitors
connected and routed to the same audio converter.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/hda_eld.c | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_intelhdmi.c | 191 |
3 files changed, 155 insertions, 47 deletions
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9446a5abea13..20fa6aee29c0 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c | |||
@@ -560,13 +560,14 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, | |||
560 | } | 560 | } |
561 | 561 | ||
562 | 562 | ||
563 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) | 563 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, |
564 | int index) | ||
564 | { | 565 | { |
565 | char name[32]; | 566 | char name[32]; |
566 | struct snd_info_entry *entry; | 567 | struct snd_info_entry *entry; |
567 | int err; | 568 | int err; |
568 | 569 | ||
569 | snprintf(name, sizeof(name), "eld#%d", codec->addr); | 570 | snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); |
570 | err = snd_card_proc_new(codec->bus->card, name, &entry); | 571 | err = snd_card_proc_new(codec->bus->card, name, &entry); |
571 | if (err < 0) | 572 | if (err < 0) |
572 | return err; | 573 | return err; |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5f1dcc59002b..461e0c15c77a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -541,11 +541,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); | |||
541 | void snd_hdmi_show_eld(struct hdmi_eld *eld); | 541 | void snd_hdmi_show_eld(struct hdmi_eld *eld); |
542 | 542 | ||
543 | #ifdef CONFIG_PROC_FS | 543 | #ifdef CONFIG_PROC_FS |
544 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); | 544 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, |
545 | int index); | ||
545 | void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); | 546 | void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); |
546 | #else | 547 | #else |
547 | static inline int snd_hda_eld_proc_new(struct hda_codec *codec, | 548 | static inline int snd_hda_eld_proc_new(struct hda_codec *codec, |
548 | struct hdmi_eld *eld) | 549 | struct hdmi_eld *eld, |
550 | int index) | ||
549 | { | 551 | { |
550 | return 0; | 552 | return 0; |
551 | } | 553 | } |
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 6be5ca44a83b..08ea88deba6f 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -33,14 +33,43 @@ | |||
33 | #include "hda_codec.h" | 33 | #include "hda_codec.h" |
34 | #include "hda_local.h" | 34 | #include "hda_local.h" |
35 | 35 | ||
36 | static hda_nid_t cvt_nid; /* audio converter */ | 36 | /* |
37 | static hda_nid_t pin_nid; /* HDMI output pin */ | 37 | * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device |
38 | * could support two independent pipes, each of them can be connected to one or | ||
39 | * more ports (DVI, HDMI or DisplayPort). | ||
40 | * | ||
41 | * The HDA correspondence of pipes/ports are converter/pin nodes. | ||
42 | */ | ||
43 | #define INTEL_HDMI_CVTS 2 | ||
44 | #define INTEL_HDMI_PINS 3 | ||
38 | 45 | ||
39 | #define INTEL_HDMI_EVENT_TAG 0x08 | 46 | static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { |
47 | "INTEL HDMI 0", | ||
48 | "INTEL HDMI 1", | ||
49 | }; | ||
40 | 50 | ||
41 | struct intel_hdmi_spec { | 51 | struct intel_hdmi_spec { |
42 | struct hda_pcm pcm_rec; | 52 | int num_cvts; |
43 | struct hdmi_eld sink_eld; | 53 | int num_pins; |
54 | hda_nid_t cvt[INTEL_HDMI_CVTS+1]; /* audio sources */ | ||
55 | hda_nid_t pin[INTEL_HDMI_PINS+1]; /* audio sinks */ | ||
56 | |||
57 | /* | ||
58 | * source connection for each pin | ||
59 | */ | ||
60 | hda_nid_t pin_cvt[INTEL_HDMI_PINS+1]; | ||
61 | |||
62 | /* | ||
63 | * HDMI sink attached to each pin | ||
64 | */ | ||
65 | bool sink_present[INTEL_HDMI_PINS]; | ||
66 | bool sink_eldv[INTEL_HDMI_PINS]; | ||
67 | struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; | ||
68 | |||
69 | /* | ||
70 | * export one pcm per pipe | ||
71 | */ | ||
72 | struct hda_pcm pcm_rec[INTEL_HDMI_CVTS]; | ||
44 | }; | 73 | }; |
45 | 74 | ||
46 | struct hdmi_audio_infoframe { | 75 | struct hdmi_audio_infoframe { |
@@ -183,6 +212,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { | |||
183 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, | 212 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, |
184 | }; | 213 | }; |
185 | 214 | ||
215 | |||
216 | static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) | ||
217 | { | ||
218 | int i; | ||
219 | |||
220 | for (i = 0; nids[i]; i++) | ||
221 | if (nids[i] == nid) | ||
222 | return i; | ||
223 | |||
224 | snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
186 | /* | 228 | /* |
187 | * HDMI routines | 229 | * HDMI routines |
188 | */ | 230 | */ |
@@ -283,12 +325,12 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) | |||
283 | #endif | 325 | #endif |
284 | } | 326 | } |
285 | 327 | ||
286 | static void hdmi_parse_eld(struct hda_codec *codec) | 328 | static void hdmi_parse_eld(struct hda_codec *codec, int index) |
287 | { | 329 | { |
288 | struct intel_hdmi_spec *spec = codec->spec; | 330 | struct intel_hdmi_spec *spec = codec->spec; |
289 | struct hdmi_eld *eld = &spec->sink_eld; | 331 | struct hdmi_eld *eld = &spec->sink_eld[index]; |
290 | 332 | ||
291 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | 333 | if (!snd_hdmi_get_eld(eld, codec, spec->pin[index])) |
292 | snd_hdmi_show_eld(eld); | 334 | snd_hdmi_show_eld(eld); |
293 | } | 335 | } |
294 | 336 | ||
@@ -395,7 +437,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, | |||
395 | struct hdmi_audio_infoframe *ai) | 437 | struct hdmi_audio_infoframe *ai) |
396 | { | 438 | { |
397 | struct intel_hdmi_spec *spec = codec->spec; | 439 | struct intel_hdmi_spec *spec = codec->spec; |
398 | struct hdmi_eld *eld = &spec->sink_eld; | 440 | struct hdmi_eld *eld; |
399 | int i; | 441 | int i; |
400 | int spk_mask = 0; | 442 | int spk_mask = 0; |
401 | int channels = 1 + (ai->CC02_CT47 & 0x7); | 443 | int channels = 1 + (ai->CC02_CT47 & 0x7); |
@@ -407,6 +449,11 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, | |||
407 | if (channels <= 2) | 449 | if (channels <= 2) |
408 | return 0; | 450 | return 0; |
409 | 451 | ||
452 | i = hda_node_index(spec->pin_cvt, nid); | ||
453 | if (i < 0) | ||
454 | return 0; | ||
455 | eld = &spec->sink_eld[i]; | ||
456 | |||
410 | /* | 457 | /* |
411 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | 458 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. |
412 | * in console or for audio devices. Assume the highest speakers | 459 | * in console or for audio devices. Assume the highest speakers |
@@ -469,6 +516,9 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, | |||
469 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, | 516 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, |
470 | struct snd_pcm_substream *substream) | 517 | struct snd_pcm_substream *substream) |
471 | { | 518 | { |
519 | struct intel_hdmi_spec *spec = codec->spec; | ||
520 | hda_nid_t pin_nid; | ||
521 | int i; | ||
472 | struct hdmi_audio_infoframe ai = { | 522 | struct hdmi_audio_infoframe ai = { |
473 | .type = 0x84, | 523 | .type = 0x84, |
474 | .ver = 0x01, | 524 | .ver = 0x01, |
@@ -479,8 +529,16 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, | |||
479 | hdmi_setup_channel_allocation(codec, nid, &ai); | 529 | hdmi_setup_channel_allocation(codec, nid, &ai); |
480 | hdmi_setup_channel_mapping(codec, nid, &ai); | 530 | hdmi_setup_channel_mapping(codec, nid, &ai); |
481 | 531 | ||
482 | hdmi_fill_audio_infoframe(codec, pin_nid, &ai); | 532 | for (i = 0; i < spec->num_pins; i++) { |
483 | hdmi_start_infoframe_trans(codec, pin_nid); | 533 | if (spec->pin_cvt[i] != nid) |
534 | continue; | ||
535 | if (spec->sink_present[i] != true) | ||
536 | continue; | ||
537 | |||
538 | pin_nid = spec->pin[i]; | ||
539 | hdmi_fill_audio_infoframe(codec, pin_nid, &ai); | ||
540 | hdmi_start_infoframe_trans(codec, pin_nid); | ||
541 | } | ||
484 | } | 542 | } |
485 | 543 | ||
486 | 544 | ||
@@ -490,27 +548,39 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, | |||
490 | 548 | ||
491 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | 549 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) |
492 | { | 550 | { |
551 | struct intel_hdmi_spec *spec = codec->spec; | ||
552 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
493 | int pind = !!(res & AC_UNSOL_RES_PD); | 553 | int pind = !!(res & AC_UNSOL_RES_PD); |
494 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | 554 | int eldv = !!(res & AC_UNSOL_RES_ELDV); |
555 | int index; | ||
495 | 556 | ||
496 | printk(KERN_INFO | 557 | printk(KERN_INFO |
497 | "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", | 558 | "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
498 | pind, eldv); | 559 | tag, pind, eldv); |
560 | |||
561 | index = hda_node_index(spec->pin, tag); | ||
562 | if (index < 0) | ||
563 | return; | ||
564 | |||
565 | spec->sink_present[index] = pind; | ||
566 | spec->sink_eldv[index] = eldv; | ||
499 | 567 | ||
500 | if (pind && eldv) { | 568 | if (pind && eldv) { |
501 | hdmi_parse_eld(codec); | 569 | hdmi_parse_eld(codec, index); |
502 | /* TODO: do real things about ELD */ | 570 | /* TODO: do real things about ELD */ |
503 | } | 571 | } |
504 | } | 572 | } |
505 | 573 | ||
506 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | 574 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) |
507 | { | 575 | { |
576 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
508 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 577 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
509 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); | 578 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); |
510 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); | 579 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); |
511 | 580 | ||
512 | printk(KERN_INFO | 581 | printk(KERN_INFO |
513 | "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", | 582 | "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", |
583 | tag, | ||
514 | subtag, | 584 | subtag, |
515 | cp_state, | 585 | cp_state, |
516 | cp_ready); | 586 | cp_ready); |
@@ -525,10 +595,11 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
525 | 595 | ||
526 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | 596 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) |
527 | { | 597 | { |
598 | struct intel_hdmi_spec *spec = codec->spec; | ||
528 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | 599 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; |
529 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 600 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
530 | 601 | ||
531 | if (tag != INTEL_HDMI_EVENT_TAG) { | 602 | if (hda_node_index(spec->pin, tag) < 0) { |
532 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); | 603 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); |
533 | return; | 604 | return; |
534 | } | 605 | } |
@@ -549,10 +620,10 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
549 | unsigned int format, | 620 | unsigned int format, |
550 | struct snd_pcm_substream *substream) | 621 | struct snd_pcm_substream *substream) |
551 | { | 622 | { |
552 | hdmi_set_channel_count(codec, cvt_nid, | 623 | hdmi_set_channel_count(codec, hinfo->nid, |
553 | substream->runtime->channels); | 624 | substream->runtime->channels); |
554 | 625 | ||
555 | hdmi_setup_audio_infoframe(codec, cvt_nid, substream); | 626 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); |
556 | 627 | ||
557 | snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); | 628 | snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); |
558 | return 0; | 629 | return 0; |
@@ -563,8 +634,14 @@ static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
563 | struct snd_pcm_substream *substream) | 634 | struct snd_pcm_substream *substream) |
564 | { | 635 | { |
565 | struct intel_hdmi_spec *spec = codec->spec; | 636 | struct intel_hdmi_spec *spec = codec->spec; |
637 | int i; | ||
638 | |||
639 | for (i = 0; i < spec->num_pins; i++) { | ||
640 | if (spec->pin_cvt[i] != hinfo->nid) | ||
641 | continue; | ||
566 | 642 | ||
567 | hdmi_stop_infoframe_trans(codec, pin_nid); | 643 | hdmi_stop_infoframe_trans(codec, spec->pin[i]); |
644 | } | ||
568 | 645 | ||
569 | snd_hda_codec_cleanup_stream(codec, hinfo->nid); | 646 | snd_hda_codec_cleanup_stream(codec, hinfo->nid); |
570 | return 0; | 647 | return 0; |
@@ -583,17 +660,19 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { | |||
583 | static int intel_hdmi_build_pcms(struct hda_codec *codec) | 660 | static int intel_hdmi_build_pcms(struct hda_codec *codec) |
584 | { | 661 | { |
585 | struct intel_hdmi_spec *spec = codec->spec; | 662 | struct intel_hdmi_spec *spec = codec->spec; |
586 | struct hda_pcm *info = &spec->pcm_rec; | 663 | struct hda_pcm *info = spec->pcm_rec; |
664 | int i; | ||
587 | 665 | ||
588 | codec->num_pcms = 1; | 666 | codec->num_pcms = spec->num_cvts; |
589 | codec->pcm_info = info; | 667 | codec->pcm_info = info; |
590 | 668 | ||
591 | /* NID to query formats and rates and setup streams */ | 669 | for (i = 0; i < codec->num_pcms; i++, info++) { |
592 | intel_hdmi_pcm_playback.nid = cvt_nid; | 670 | info->name = intel_hdmi_pcm_names[i]; |
593 | 671 | info->pcm_type = HDA_PCM_TYPE_HDMI; | |
594 | info->name = "INTEL HDMI"; | 672 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
595 | info->pcm_type = HDA_PCM_TYPE_HDMI; | 673 | intel_hdmi_pcm_playback; |
596 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; | 674 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; |
675 | } | ||
597 | 676 | ||
598 | return 0; | 677 | return 0; |
599 | } | 678 | } |
@@ -602,29 +681,39 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) | |||
602 | { | 681 | { |
603 | struct intel_hdmi_spec *spec = codec->spec; | 682 | struct intel_hdmi_spec *spec = codec->spec; |
604 | int err; | 683 | int err; |
684 | int i; | ||
605 | 685 | ||
606 | err = snd_hda_create_spdif_out_ctls(codec, cvt_nid); | 686 | for (i = 0; i < codec->num_pcms; i++) { |
607 | if (err < 0) | 687 | err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); |
608 | return err; | 688 | if (err < 0) |
689 | return err; | ||
690 | } | ||
609 | 691 | ||
610 | return 0; | 692 | return 0; |
611 | } | 693 | } |
612 | 694 | ||
613 | static int intel_hdmi_init(struct hda_codec *codec) | 695 | static int intel_hdmi_init(struct hda_codec *codec) |
614 | { | 696 | { |
615 | hdmi_enable_output(codec, pin_nid); | 697 | struct intel_hdmi_spec *spec = codec->spec; |
698 | int i; | ||
616 | 699 | ||
617 | snd_hda_codec_write(codec, pin_nid, 0, | 700 | for (i = 0; spec->pin[i]; i++) { |
618 | AC_VERB_SET_UNSOLICITED_ENABLE, | 701 | hdmi_enable_output(codec, spec->pin[i]); |
619 | AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); | 702 | snd_hda_codec_write(codec, spec->pin[i], 0, |
703 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
704 | AC_USRSP_EN | spec->pin[i]); | ||
705 | } | ||
620 | return 0; | 706 | return 0; |
621 | } | 707 | } |
622 | 708 | ||
623 | static void intel_hdmi_free(struct hda_codec *codec) | 709 | static void intel_hdmi_free(struct hda_codec *codec) |
624 | { | 710 | { |
625 | struct intel_hdmi_spec *spec = codec->spec; | 711 | struct intel_hdmi_spec *spec = codec->spec; |
712 | int i; | ||
713 | |||
714 | for (i = 0; i < spec->num_pins; i++) | ||
715 | snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); | ||
626 | 716 | ||
627 | snd_hda_eld_proc_free(codec, &spec->sink_eld); | ||
628 | kfree(spec); | 717 | kfree(spec); |
629 | } | 718 | } |
630 | 719 | ||
@@ -636,18 +725,38 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { | |||
636 | .unsol_event = intel_hdmi_unsol_event, | 725 | .unsol_event = intel_hdmi_unsol_event, |
637 | }; | 726 | }; |
638 | 727 | ||
639 | static int do_patch_intel_hdmi(struct hda_codec *codec) | 728 | static struct intel_hdmi_spec static_specs[] = { |
729 | { | ||
730 | .num_cvts = 1, | ||
731 | .num_pins = 1, | ||
732 | .cvt = { 0x2 }, | ||
733 | .pin = { 0x3 }, | ||
734 | .pin_cvt = { 0x2 }, | ||
735 | }, | ||
736 | { | ||
737 | .num_cvts = 2, | ||
738 | .num_pins = 3, | ||
739 | .cvt = { 0x2, 0x3 }, | ||
740 | .pin = { 0x4, 0x5, 0x6 }, | ||
741 | .pin_cvt = { 0x2, 0x2, 0x2 }, | ||
742 | }, | ||
743 | }; | ||
744 | |||
745 | static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) | ||
640 | { | 746 | { |
641 | struct intel_hdmi_spec *spec; | 747 | struct intel_hdmi_spec *spec; |
748 | int i; | ||
642 | 749 | ||
643 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 750 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
644 | if (spec == NULL) | 751 | if (spec == NULL) |
645 | return -ENOMEM; | 752 | return -ENOMEM; |
646 | 753 | ||
754 | *spec = static_specs[spec_id]; | ||
647 | codec->spec = spec; | 755 | codec->spec = spec; |
648 | codec->patch_ops = intel_hdmi_patch_ops; | 756 | codec->patch_ops = intel_hdmi_patch_ops; |
649 | 757 | ||
650 | snd_hda_eld_proc_new(codec, &spec->sink_eld); | 758 | for (i = 0; i < spec->num_pins; i++) |
759 | snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); | ||
651 | 760 | ||
652 | init_channel_allocations(); | 761 | init_channel_allocations(); |
653 | 762 | ||
@@ -656,16 +765,12 @@ static int do_patch_intel_hdmi(struct hda_codec *codec) | |||
656 | 765 | ||
657 | static int patch_intel_hdmi(struct hda_codec *codec) | 766 | static int patch_intel_hdmi(struct hda_codec *codec) |
658 | { | 767 | { |
659 | cvt_nid = 0x02; | 768 | return do_patch_intel_hdmi(codec, 0); |
660 | pin_nid = 0x03; | ||
661 | return do_patch_intel_hdmi(codec); | ||
662 | } | 769 | } |
663 | 770 | ||
664 | static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) | 771 | static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) |
665 | { | 772 | { |
666 | cvt_nid = 0x02; | 773 | return do_patch_intel_hdmi(codec, 1); |
667 | pin_nid = 0x04; | ||
668 | return do_patch_intel_hdmi(codec); | ||
669 | } | 774 | } |
670 | 775 | ||
671 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | 776 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { |