diff options
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 92 |
1 files changed, 81 insertions, 11 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 31df7747990d..f29b97b5de8f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -31,10 +31,15 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/moduleparam.h> | ||
34 | #include <sound/core.h> | 35 | #include <sound/core.h> |
35 | #include "hda_codec.h" | 36 | #include "hda_codec.h" |
36 | #include "hda_local.h" | 37 | #include "hda_local.h" |
37 | 38 | ||
39 | static bool static_hdmi_pcm; | ||
40 | module_param(static_hdmi_pcm, bool, 0644); | ||
41 | MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); | ||
42 | |||
38 | /* | 43 | /* |
39 | * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device | 44 | * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device |
40 | * could support two independent pipes, each of them can be connected to one or | 45 | * could support two independent pipes, each of them can be connected to one or |
@@ -827,7 +832,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, | |||
827 | *codec_pars = *hinfo; | 832 | *codec_pars = *hinfo; |
828 | 833 | ||
829 | eld = &spec->sink_eld[idx]; | 834 | eld = &spec->sink_eld[idx]; |
830 | if (eld->sad_count > 0) { | 835 | if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) { |
831 | hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); | 836 | hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); |
832 | if (hinfo->channels_min > hinfo->channels_max || | 837 | if (hinfo->channels_min > hinfo->channels_max || |
833 | !hinfo->rates || !hinfo->formats) | 838 | !hinfo->rates || !hinfo->formats) |
@@ -904,23 +909,28 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | |||
904 | spec->pin[spec->num_pins] = pin_nid; | 909 | spec->pin[spec->num_pins] = pin_nid; |
905 | spec->num_pins++; | 910 | spec->num_pins++; |
906 | 911 | ||
907 | /* | ||
908 | * It is assumed that converter nodes come first in the node list and | ||
909 | * hence have been registered and usable now. | ||
910 | */ | ||
911 | return hdmi_read_pin_conn(codec, pin_nid); | 912 | return hdmi_read_pin_conn(codec, pin_nid); |
912 | } | 913 | } |
913 | 914 | ||
914 | static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) | 915 | static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) |
915 | { | 916 | { |
917 | int i, found_pin = 0; | ||
916 | struct hdmi_spec *spec = codec->spec; | 918 | struct hdmi_spec *spec = codec->spec; |
917 | 919 | ||
918 | if (spec->num_cvts >= MAX_HDMI_CVTS) { | 920 | for (i = 0; i < spec->num_pins; i++) |
919 | snd_printk(KERN_WARNING | 921 | if (nid == spec->pin_cvt[i]) { |
920 | "HDMI: no space for converter %d\n", nid); | 922 | found_pin = 1; |
921 | return -E2BIG; | 923 | break; |
924 | } | ||
925 | |||
926 | if (!found_pin) { | ||
927 | snd_printdd("HDMI: Skipping node %d (no connection)\n", nid); | ||
928 | return -EINVAL; | ||
922 | } | 929 | } |
923 | 930 | ||
931 | if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) | ||
932 | return -E2BIG; | ||
933 | |||
924 | spec->cvt[spec->num_cvts] = nid; | 934 | spec->cvt[spec->num_cvts] = nid; |
925 | spec->num_cvts++; | 935 | spec->num_cvts++; |
926 | 936 | ||
@@ -931,6 +941,8 @@ static int hdmi_parse_codec(struct hda_codec *codec) | |||
931 | { | 941 | { |
932 | hda_nid_t nid; | 942 | hda_nid_t nid; |
933 | int i, nodes; | 943 | int i, nodes; |
944 | int num_tmp_cvts = 0; | ||
945 | hda_nid_t tmp_cvt[MAX_HDMI_CVTS]; | ||
934 | 946 | ||
935 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | 947 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); |
936 | if (!nid || nodes < 0) { | 948 | if (!nid || nodes < 0) { |
@@ -941,6 +953,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) | |||
941 | for (i = 0; i < nodes; i++, nid++) { | 953 | for (i = 0; i < nodes; i++, nid++) { |
942 | unsigned int caps; | 954 | unsigned int caps; |
943 | unsigned int type; | 955 | unsigned int type; |
956 | unsigned int config; | ||
944 | 957 | ||
945 | caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | 958 | caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); |
946 | type = get_wcaps_type(caps); | 959 | type = get_wcaps_type(caps); |
@@ -950,17 +963,32 @@ static int hdmi_parse_codec(struct hda_codec *codec) | |||
950 | 963 | ||
951 | switch (type) { | 964 | switch (type) { |
952 | case AC_WID_AUD_OUT: | 965 | case AC_WID_AUD_OUT: |
953 | hdmi_add_cvt(codec, nid); | 966 | if (num_tmp_cvts >= MAX_HDMI_CVTS) { |
967 | snd_printk(KERN_WARNING | ||
968 | "HDMI: no space for converter %d\n", nid); | ||
969 | continue; | ||
970 | } | ||
971 | tmp_cvt[num_tmp_cvts] = nid; | ||
972 | num_tmp_cvts++; | ||
954 | break; | 973 | break; |
955 | case AC_WID_PIN: | 974 | case AC_WID_PIN: |
956 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 975 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); |
957 | if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) | 976 | if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) |
958 | continue; | 977 | continue; |
978 | |||
979 | config = snd_hda_codec_read(codec, nid, 0, | ||
980 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
981 | if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) | ||
982 | continue; | ||
983 | |||
959 | hdmi_add_pin(codec, nid); | 984 | hdmi_add_pin(codec, nid); |
960 | break; | 985 | break; |
961 | } | 986 | } |
962 | } | 987 | } |
963 | 988 | ||
989 | for (i = 0; i < num_tmp_cvts; i++) | ||
990 | hdmi_add_cvt(codec, tmp_cvt[i]); | ||
991 | |||
964 | /* | 992 | /* |
965 | * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event | 993 | * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event |
966 | * can be lost and presence sense verb will become inaccurate if the | 994 | * can be lost and presence sense verb will become inaccurate if the |
@@ -1165,11 +1193,53 @@ static int nvhdmi_7x_init(struct hda_codec *codec) | |||
1165 | return 0; | 1193 | return 0; |
1166 | } | 1194 | } |
1167 | 1195 | ||
1196 | static unsigned int channels_2_6_8[] = { | ||
1197 | 2, 6, 8 | ||
1198 | }; | ||
1199 | |||
1200 | static unsigned int channels_2_8[] = { | ||
1201 | 2, 8 | ||
1202 | }; | ||
1203 | |||
1204 | static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { | ||
1205 | .count = ARRAY_SIZE(channels_2_6_8), | ||
1206 | .list = channels_2_6_8, | ||
1207 | .mask = 0, | ||
1208 | }; | ||
1209 | |||
1210 | static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { | ||
1211 | .count = ARRAY_SIZE(channels_2_8), | ||
1212 | .list = channels_2_8, | ||
1213 | .mask = 0, | ||
1214 | }; | ||
1215 | |||
1168 | static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, | 1216 | static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, |
1169 | struct hda_codec *codec, | 1217 | struct hda_codec *codec, |
1170 | struct snd_pcm_substream *substream) | 1218 | struct snd_pcm_substream *substream) |
1171 | { | 1219 | { |
1172 | struct hdmi_spec *spec = codec->spec; | 1220 | struct hdmi_spec *spec = codec->spec; |
1221 | struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; | ||
1222 | |||
1223 | switch (codec->preset->id) { | ||
1224 | case 0x10de0002: | ||
1225 | case 0x10de0003: | ||
1226 | case 0x10de0005: | ||
1227 | case 0x10de0006: | ||
1228 | hw_constraints_channels = &hw_constraints_2_8_channels; | ||
1229 | break; | ||
1230 | case 0x10de0007: | ||
1231 | hw_constraints_channels = &hw_constraints_2_6_8_channels; | ||
1232 | break; | ||
1233 | default: | ||
1234 | break; | ||
1235 | } | ||
1236 | |||
1237 | if (hw_constraints_channels != NULL) { | ||
1238 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
1239 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1240 | hw_constraints_channels); | ||
1241 | } | ||
1242 | |||
1173 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | 1243 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); |
1174 | } | 1244 | } |
1175 | 1245 | ||
@@ -1532,7 +1602,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { | |||
1532 | { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, | 1602 | { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, |
1533 | { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, | 1603 | { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, |
1534 | { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, | 1604 | { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, |
1535 | { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, | 1605 | { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi }, |
1536 | { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, | 1606 | { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, |
1537 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, | 1607 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, |
1538 | { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, | 1608 | { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, |