At Mon, 19 Nov 2012 15:23:09 -0500, "Egbert Eich " <"eich@xxxxxxxxxx> wrote: > > Signed-off-by: Egbert Eich <eich@xxxxxxx> > --- > 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); So this function returns -ENOMEM if valid_extensions is equal with block[EDID_EXTENSION_FLAG_OFFSET]...? Takashi > +} > + > 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel