[PATCH 08/17] DRM/KMS/EDID: Use Extension Block Fixup Code also for 'firmware' EDID.
Takashi Iwai
tiwai at suse.de
Tue Nov 20 00:21:24 PST 2012
At Mon, 19 Nov 2012 15:23:09 -0500,
"Egbert Eich " <"eich at novell.com> wrote:
>
> Signed-off-by: Egbert Eich <eich at 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);
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
>
More information about the dri-devel
mailing list