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
> 

Reply via email to