diff options
author | Adam Jackson <ajax@redhat.com> | 2009-12-03 17:44:36 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-03 17:53:07 -0500 |
commit | 9cf00977da092096c7a983276dad8b3002d23a99 (patch) | |
tree | 1411812071df84b69cf731d9ebc2eb415457f5c9 | |
parent | 9632b41f00cc2fb2846569cc99dbeef78e5c94a0 (diff) |
drm/edid: Unify detailed block parsing between base and extension blocks
Also fix an embarassing bug in standard timing subblock parsing that
would result in an infinite loop.
Signed-off-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 163 |
1 files changed, 61 insertions, 102 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bdea31308236..999571ab0b69 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -838,8 +838,57 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
838 | return modes; | 838 | return modes; |
839 | } | 839 | } |
840 | 840 | ||
841 | static int add_detailed_modes(struct drm_connector *connector, | ||
842 | struct detailed_timing *timing, | ||
843 | struct edid *edid, u32 quirks, int preferred) | ||
844 | { | ||
845 | int i, modes = 0; | ||
846 | struct detailed_non_pixel *data = &timing->data.other_data; | ||
847 | int timing_level = standard_timing_level(edid); | ||
848 | struct drm_display_mode *newmode; | ||
849 | struct drm_device *dev = connector->dev; | ||
850 | |||
851 | if (timing->pixel_clock) { | ||
852 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
853 | if (!newmode) | ||
854 | return 0; | ||
855 | |||
856 | if (preferred) | ||
857 | newmode->type |= DRM_MODE_TYPE_PREFERRED; | ||
858 | |||
859 | drm_mode_probed_add(connector, newmode); | ||
860 | return 1; | ||
861 | } | ||
862 | |||
863 | /* other timing types */ | ||
864 | switch (data->type) { | ||
865 | case EDID_DETAIL_MONITOR_RANGE: | ||
866 | /* Get monitor range data */ | ||
867 | break; | ||
868 | case EDID_DETAIL_STD_MODES: | ||
869 | /* Six modes per detailed section */ | ||
870 | for (i = 0; i < 6; i++) { | ||
871 | struct std_timing *std; | ||
872 | struct drm_display_mode *newmode; | ||
873 | |||
874 | std = &data->data.timings[i]; | ||
875 | newmode = drm_mode_std(dev, std, edid->revision, | ||
876 | timing_level); | ||
877 | if (newmode) { | ||
878 | drm_mode_probed_add(connector, newmode); | ||
879 | modes++; | ||
880 | } | ||
881 | } | ||
882 | break; | ||
883 | default: | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | return modes; | ||
888 | } | ||
889 | |||
841 | /** | 890 | /** |
842 | * add_detailed_modes - get detailed mode info from EDID data | 891 | * add_detailed_info - get detailed mode info from EDID data |
843 | * @connector: attached connector | 892 | * @connector: attached connector |
844 | * @edid: EDID block to scan | 893 | * @edid: EDID block to scan |
845 | * @quirks: quirks to apply | 894 | * @quirks: quirks to apply |
@@ -850,67 +899,24 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
850 | static int add_detailed_info(struct drm_connector *connector, | 899 | static int add_detailed_info(struct drm_connector *connector, |
851 | struct edid *edid, u32 quirks) | 900 | struct edid *edid, u32 quirks) |
852 | { | 901 | { |
853 | struct drm_device *dev = connector->dev; | 902 | int i, modes = 0; |
854 | int i, j, modes = 0; | ||
855 | int timing_level; | ||
856 | |||
857 | timing_level = standard_timing_level(edid); | ||
858 | 903 | ||
859 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { | 904 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { |
860 | struct detailed_timing *timing = &edid->detailed_timings[i]; | 905 | struct detailed_timing *timing = &edid->detailed_timings[i]; |
861 | struct detailed_non_pixel *data = &timing->data.other_data; | 906 | int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); |
862 | struct drm_display_mode *newmode; | ||
863 | |||
864 | /* X server check is version 1.1 or higher */ | ||
865 | if (edid->version == 1 && edid->revision >= 1 && | ||
866 | !timing->pixel_clock) { | ||
867 | /* Other timing or info */ | ||
868 | switch (data->type) { | ||
869 | case EDID_DETAIL_MONITOR_SERIAL: | ||
870 | break; | ||
871 | case EDID_DETAIL_MONITOR_STRING: | ||
872 | break; | ||
873 | case EDID_DETAIL_MONITOR_RANGE: | ||
874 | /* Get monitor range data */ | ||
875 | break; | ||
876 | case EDID_DETAIL_MONITOR_NAME: | ||
877 | break; | ||
878 | case EDID_DETAIL_MONITOR_CPDATA: | ||
879 | break; | ||
880 | case EDID_DETAIL_STD_MODES: | ||
881 | for (j = 0; j < 6; i++) { | ||
882 | struct std_timing *std; | ||
883 | struct drm_display_mode *newmode; | ||
884 | |||
885 | std = &data->data.timings[j]; | ||
886 | newmode = drm_mode_std(dev, std, | ||
887 | edid->revision, | ||
888 | timing_level); | ||
889 | if (newmode) { | ||
890 | drm_mode_probed_add(connector, newmode); | ||
891 | modes++; | ||
892 | } | ||
893 | } | ||
894 | break; | ||
895 | default: | ||
896 | break; | ||
897 | } | ||
898 | } else { | ||
899 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
900 | if (!newmode) | ||
901 | continue; | ||
902 | 907 | ||
903 | /* First detailed mode is preferred */ | 908 | /* In 1.0, only timings are allowed */ |
904 | if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) | 909 | if (!timing->pixel_clock && edid->version == 1 && |
905 | newmode->type |= DRM_MODE_TYPE_PREFERRED; | 910 | edid->revision == 0) |
906 | drm_mode_probed_add(connector, newmode); | 911 | continue; |
907 | 912 | ||
908 | modes++; | 913 | modes += add_detailed_modes(connector, timing, edid, quirks, |
909 | } | 914 | preferred); |
910 | } | 915 | } |
911 | 916 | ||
912 | return modes; | 917 | return modes; |
913 | } | 918 | } |
919 | |||
914 | /** | 920 | /** |
915 | * add_detailed_mode_eedid - get detailed mode info from addtional timing | 921 | * add_detailed_mode_eedid - get detailed mode info from addtional timing |
916 | * EDID block | 922 | * EDID block |
@@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector *connector, | |||
924 | static int add_detailed_info_eedid(struct drm_connector *connector, | 930 | static int add_detailed_info_eedid(struct drm_connector *connector, |
925 | struct edid *edid, u32 quirks) | 931 | struct edid *edid, u32 quirks) |
926 | { | 932 | { |
927 | struct drm_device *dev = connector->dev; | 933 | int i, modes = 0; |
928 | int i, j, modes = 0; | ||
929 | char *edid_ext = NULL; | 934 | char *edid_ext = NULL; |
930 | struct detailed_timing *timing; | 935 | struct detailed_timing *timing; |
931 | struct detailed_non_pixel *data; | ||
932 | struct drm_display_mode *newmode; | ||
933 | int edid_ext_num; | 936 | int edid_ext_num; |
934 | int start_offset, end_offset; | 937 | int start_offset, end_offset; |
935 | int timing_level; | 938 | int timing_level; |
@@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector, | |||
980 | for (i = start_offset; i < end_offset; | 983 | for (i = start_offset; i < end_offset; |
981 | i += sizeof(struct detailed_timing)) { | 984 | i += sizeof(struct detailed_timing)) { |
982 | timing = (struct detailed_timing *)(edid_ext + i); | 985 | timing = (struct detailed_timing *)(edid_ext + i); |
983 | data = &timing->data.other_data; | 986 | modes += add_detailed_modes(connector, timing, edid, quirks, 0); |
984 | /* Detailed mode timing */ | ||
985 | if (timing->pixel_clock) { | ||
986 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
987 | if (!newmode) | ||
988 | continue; | ||
989 | |||
990 | drm_mode_probed_add(connector, newmode); | ||
991 | |||
992 | modes++; | ||
993 | continue; | ||
994 | } | ||
995 | |||
996 | /* Other timing or info */ | ||
997 | switch (data->type) { | ||
998 | case EDID_DETAIL_MONITOR_SERIAL: | ||
999 | break; | ||
1000 | case EDID_DETAIL_MONITOR_STRING: | ||
1001 | break; | ||
1002 | case EDID_DETAIL_MONITOR_RANGE: | ||
1003 | /* Get monitor range data */ | ||
1004 | break; | ||
1005 | case EDID_DETAIL_MONITOR_NAME: | ||
1006 | break; | ||
1007 | case EDID_DETAIL_MONITOR_CPDATA: | ||
1008 | break; | ||
1009 | case EDID_DETAIL_STD_MODES: | ||
1010 | /* Five modes per detailed section */ | ||
1011 | for (j = 0; j < 5; i++) { | ||
1012 | struct std_timing *std; | ||
1013 | struct drm_display_mode *newmode; | ||
1014 | |||
1015 | std = &data->data.timings[j]; | ||
1016 | newmode = drm_mode_std(dev, std, | ||
1017 | edid->revision, | ||
1018 | timing_level); | ||
1019 | if (newmode) { | ||
1020 | drm_mode_probed_add(connector, newmode); | ||
1021 | modes++; | ||
1022 | } | ||
1023 | } | ||
1024 | break; | ||
1025 | default: | ||
1026 | break; | ||
1027 | } | ||
1028 | } | 987 | } |
1029 | 988 | ||
1030 | return modes; | 989 | return modes; |