Skip to content

Commit

Permalink
drm/edid: Unify detailed block parsing between base and extension blocks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Adam Jackson authored and Dave Airlie committed Dec 3, 2009
1 parent 9632b41 commit 9cf0097
Showing 1 changed file with 61 additions and 102 deletions.
163 changes: 61 additions & 102 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 9cf0097

Please sign in to comment.