Also fix an embarassing bug in standard timing subblock parsing that
would result in an infinite loop.

Signed-off-by: Adam Jackson <a...@redhat.com>
---
 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 bdea313..999571a 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
        return modes;
 }
 
+static int add_detailed_modes(struct drm_connector *connector,
+                             struct detailed_timing *timing,
+                             struct edid *edid, u32 quirks, int preferred)
+{
+       int i, modes = 0;
+       struct detailed_non_pixel *data = &timing->data.other_data;
+       int timing_level = standard_timing_level(edid);
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+
+       if (timing->pixel_clock) {
+               newmode = drm_mode_detailed(dev, edid, timing, quirks);
+               if (!newmode)
+                       return 0;
+
+               if (preferred)
+                       newmode->type |= DRM_MODE_TYPE_PREFERRED;
+
+               drm_mode_probed_add(connector, newmode);
+               return 1;
+       }
+
+       /* other timing types */
+       switch (data->type) {
+       case EDID_DETAIL_MONITOR_RANGE:
+               /* Get monitor range data */
+               break;
+       case EDID_DETAIL_STD_MODES:
+               /* Six modes per detailed section */
+               for (i = 0; i < 6; i++) {
+                       struct std_timing *std;
+                       struct drm_display_mode *newmode;
+
+                       std = &data->data.timings[i];
+                       newmode = drm_mode_std(dev, std, edid->revision,
+                                              timing_level);
+                       if (newmode) {
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+
+       return modes;
+}
+
 /**
- * add_detailed_modes - get detailed mode info from EDID data
+ * add_detailed_info - get detailed mode info from EDID data
  * @connector: attached connector
  * @edid: EDID block to scan
  * @quirks: quirks to apply
@@ -850,67 +899,24 @@ static int add_standard_modes(struct drm_connector 
*connector, struct edid *edid
 static int add_detailed_info(struct drm_connector *connector,
                             struct edid *edid, u32 quirks)
 {
-       struct drm_device *dev = connector->dev;
-       int i, j, modes = 0;
-       int timing_level;
-
-       timing_level = standard_timing_level(edid);
+       int i, modes = 0;
 
        for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
                struct detailed_timing *timing = &edid->detailed_timings[i];
-               struct detailed_non_pixel *data = &timing->data.other_data;
-               struct drm_display_mode *newmode;
-
-               /* X server check is version 1.1 or higher */
-               if (edid->version == 1 && edid->revision >= 1 &&
-                   !timing->pixel_clock) {
-                       /* Other timing or info */
-                       switch (data->type) {
-                       case EDID_DETAIL_MONITOR_SERIAL:
-                               break;
-                       case EDID_DETAIL_MONITOR_STRING:
-                               break;
-                       case EDID_DETAIL_MONITOR_RANGE:
-                               /* Get monitor range data */
-                               break;
-                       case EDID_DETAIL_MONITOR_NAME:
-                               break;
-                       case EDID_DETAIL_MONITOR_CPDATA:
-                               break;
-                       case EDID_DETAIL_STD_MODES:
-                               for (j = 0; j < 6; i++) {
-                                       struct std_timing *std;
-                                       struct drm_display_mode *newmode;
-
-                                       std = &data->data.timings[j];
-                                       newmode = drm_mode_std(dev, std,
-                                                              edid->revision,
-                                                              timing_level);
-                                       if (newmode) {
-                                               drm_mode_probed_add(connector, 
newmode);
-                                               modes++;
-                                       }
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-               } else {
-                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
-                       if (!newmode)
-                               continue;
+               int preferred = (i == 0) && (edid->features & 
DRM_EDID_FEATURE_PREFERRED_TIMING);
 
-                       /* First detailed mode is preferred */
-                       if (i == 0 && (edid->features & 
DRM_EDID_FEATURE_PREFERRED_TIMING))
-                               newmode->type |= DRM_MODE_TYPE_PREFERRED;
-                       drm_mode_probed_add(connector, newmode);
+               /* In 1.0, only timings are allowed */
+               if (!timing->pixel_clock && edid->version == 1 &&
+                       edid->revision == 0)
+                       continue;
 
-                       modes++;
-               }
+               modes += add_detailed_modes(connector, timing, edid, quirks,
+                                           preferred);
        }
 
        return modes;
 }
+
 /**
  * add_detailed_mode_eedid - get detailed mode info from addtional timing
  *                     EDID block
@@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector 
*connector,
 static int add_detailed_info_eedid(struct drm_connector *connector,
                             struct edid *edid, u32 quirks)
 {
-       struct drm_device *dev = connector->dev;
-       int i, j, modes = 0;
+       int i, modes = 0;
        char *edid_ext = NULL;
        struct detailed_timing *timing;
-       struct detailed_non_pixel *data;
-       struct drm_display_mode *newmode;
        int edid_ext_num;
        int start_offset, end_offset;
        int timing_level;
@@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector 
*connector,
        for (i = start_offset; i < end_offset;
                        i += sizeof(struct detailed_timing)) {
                timing = (struct detailed_timing *)(edid_ext + i);
-               data = &timing->data.other_data;
-               /* Detailed mode timing */
-               if (timing->pixel_clock) {
-                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
-                       if (!newmode)
-                               continue;
-
-                       drm_mode_probed_add(connector, newmode);
-
-                       modes++;
-                       continue;
-               }
-
-               /* Other timing or info */
-               switch (data->type) {
-               case EDID_DETAIL_MONITOR_SERIAL:
-                       break;
-               case EDID_DETAIL_MONITOR_STRING:
-                       break;
-               case EDID_DETAIL_MONITOR_RANGE:
-                       /* Get monitor range data */
-                       break;
-               case EDID_DETAIL_MONITOR_NAME:
-                       break;
-               case EDID_DETAIL_MONITOR_CPDATA:
-                       break;
-               case EDID_DETAIL_STD_MODES:
-                       /* Five modes per detailed section */
-                       for (j = 0; j < 5; i++) {
-                               struct std_timing *std;
-                               struct drm_display_mode *newmode;
-
-                               std = &data->data.timings[j];
-                               newmode = drm_mode_std(dev, std,
-                                                      edid->revision,
-                                                      timing_level);
-                               if (newmode) {
-                                       drm_mode_probed_add(connector, newmode);
-                                       modes++;
-                               }
-                       }
-                       break;
-               default:
-                       break;
-               }
+               modes += add_detailed_modes(connector, timing, edid, quirks, 0);
        }
 
        return modes;
-- 
1.6.5.2


------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to