Signed-off-by: Egbert Eich <e...@suse.de>
---
 drivers/gpu/drm/drm_edid.c      |   77 ++++++++++++++++++++++++++++++++-------
 drivers/gpu/drm/drm_edid_load.c |   54 ++++++---------------------
 include/drm/drm_edid.h          |    1 +
 3 files changed, 77 insertions(+), 55 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d1b9d67..7bdae6e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -408,6 +408,29 @@ fixup_blockmaps(u8 **blockp, int eblock_cnt)
        return eblock_cnt;
 }
 
+static int
+fixup_edid(u8 **blockp, int valid_extensions)
+{
+       u8 *new = NULL;
+
+       if (valid_extensions != (*blockp)[EDID_EXTENSION_FLAG_OFFSET]) {
+
+               if (valid_extensions)
+                       valid_extensions = fixup_blockmaps(blockp, 
valid_extensions);
+
+               if (valid_extensions >= 0) {
+                       (*blockp)[EDID_CHECKSUM_OFFSET] += 
(*blockp)[EDID_EXTENSION_FLAG_OFFSET] - valid_extensions;
+                       (*blockp)[EDID_EXTENSION_FLAG_OFFSET] = 
valid_extensions;
+                       new = krealloc(*blockp, (valid_extensions + 1) * 
EDID_LENGTH, GFP_KERNEL);
+               }
+               if (!new)
+                       kfree(*blockp);
+
+               *blockp = new;
+       }
+       return (new ? valid_extensions : -ENOMEM);
+}
+
 static u8 *
 drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
@@ -474,19 +497,7 @@ drm_do_get_edid(struct drm_connector *connector, struct 
i2c_adapter *adapter)
        }
 
  no_more:
-       if (valid_extensions != block[EDID_EXTENSION_FLAG_OFFSET]) {
-               if (valid_extensions)
-                       valid_extensions = fixup_blockmaps(&block, 
valid_extensions);
-               if (valid_extensions >= 0) {
-                       block[EDID_CHECKSUM_OFFSET] += 
block[EDID_EXTENSION_FLAG_OFFSET] - valid_extensions;
-                       block[EDID_EXTENSION_FLAG_OFFSET] = valid_extensions;
-                       new = krealloc(block, (valid_extensions + 1) * 
EDID_LENGTH, GFP_KERNEL);
-                       if (!new)
-                               goto out;
-               } else
-                       goto out;
-               block = new;
-       }
+       fixup_edid(&block, valid_extensions);
 
        return block;
 
@@ -503,6 +514,46 @@ out:
 }
 
 /**
+ * Validate an entire EDID blob.
+ * \param connector: drm_connector struct of the used connector.
+ * \param blockp: pointer to address of an raw EDID data block.
+ * \param len: size if block in bytes.
+ *
+ * validate block and return corrected block in \param block.
+ * \return: number of valid extensions or -errno if unsuccessful.
+ */
+int
+drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int len)
+{
+       int n_blocks = len / EDID_LENGTH;
+       int valid_extensions = 0, ret = 0;
+       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & 
DRM_UT_KMS);
+
+       if (!blockp || !*blockp)
+               ret = -EINVAL;
+       else if (!n_blocks || !drm_edid_block_valid(*blockp, 0, 
print_bad_edid)) {
+               kfree(*blockp);
+               *blockp = NULL;
+               ret = -EINVAL;
+       }
+       if (!ret) {
+               n_blocks--;
+               if ((*blockp)[EDID_EXTENSION_FLAG_OFFSET] < n_blocks)
+                       n_blocks = (*blockp)[EDID_EXTENSION_FLAG_OFFSET];
+
+               while (n_blocks--) {
+                       if (drm_edid_block_valid(*blockp + (valid_extensions + 
1) * EDID_LENGTH,
+                                                valid_extensions + 1, 
print_bad_edid))
+                               valid_extensions++;
+               }
+               ret = fixup_edid(blockp, valid_extensions);
+       }
+       if (ret < 0)
+               connector->bad_edid_counter++;
+       return ret;
+}
+
+/**
  * Probe DDC presence.
  *
  * \param adapter : i2c device adaptor
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index 38d3943..6541c1f 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -119,11 +119,10 @@ static u8 *edid_load(struct drm_connector *connector, 
char *name,
 {
        const struct firmware *fw;
        struct platform_device *pdev;
-       u8 *fwdata = NULL, *edid, *new_edid;
+       u8 *fwdata = NULL;
+       struct edid *edid;
        int fwsize, expected;
        int builtin = 0, err = 0;
-       int i, valid_extensions = 0;
-       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & 
DRM_UT_KMS);
 
        pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
        if (IS_ERR(pdev)) {
@@ -137,7 +136,7 @@ static u8 *edid_load(struct drm_connector *connector, char 
*name,
        platform_device_unregister(pdev);
 
        if (err) {
-               i = 0;
+               int i = 0;
                while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
                        i++;
                if (i < GENERIC_EDIDS) {
@@ -174,49 +173,20 @@ static u8 *edid_load(struct drm_connector *connector, 
char *name,
        }
        memcpy(edid, fwdata, fwsize);
 
-       if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
-               connector->bad_edid_counter++;
-               DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
-                   name);
-               kfree(edid);
-               err = -EINVAL;
-               goto relfw_out;
-       }
-
-       for (i = 1; i <= edid[0x7e]; i++) {
-               if (i != valid_extensions + 1)
-                       memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
-                           edid + i * EDID_LENGTH, EDID_LENGTH);
-               if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, 
print_bad_edid))
-                       valid_extensions++;
-       }
-
-       if (valid_extensions != edid[0x7e]) {
-               edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
-               DRM_INFO("Found %d valid extensions instead of %d in EDID data "
-                   "\"%s\" for connector \"%s\"\n", valid_extensions,
-                   edid[0x7e], name, connector_name);
-               edid[0x7e] = valid_extensions;
-               new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
-                   GFP_KERNEL);
-               if (new_edid == NULL) {
-                       err = -ENOMEM;
-                       kfree(edid);
-                       goto relfw_out;
-               }
-               edid = new_edid;
-       }
-
-       DRM_INFO("Got %s EDID base block and %d extension%s from "
-           "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
-           "external", valid_extensions, valid_extensions == 1 ? "" : "s",
-           name, connector_name);
+       err = drm_validate_edid_blob(connector, (u8 **)&edid, fwsize);
+       if (err < 0)
+               DRM_ERROR("EDID firmware \"%s\" is invalid ", name);
+       else
+               DRM_INFO("Got %s EDID base block and %d extension%s from "
+                        "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
+                        "external", edid->extensions, edid->extensions == 1 ? 
"" : "s",
+                        name, connector_name);
 
 relfw_out:
        release_firmware(fw);
 
 out:
-       if (err)
+       if (err < 0)
                return ERR_PTR(err);
 
        return edid;
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 0cac551..3e8ef06 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -253,5 +253,6 @@ int drm_av_sync_delay(struct drm_connector *connector,
 struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
                                     struct drm_display_mode *mode);
 int drm_load_edid_firmware(struct drm_connector *connector);
+int drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int 
len);
 
 #endif /* __DRM_EDID_H__ */
-- 
1.7.7

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to