From patchwork Mon Nov 19 20:23:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egbert Eich X-Patchwork-Id: 1769051 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id 07F8CDF264 for ; Mon, 19 Nov 2012 20:49:19 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DF19FE6265 for ; Mon, 19 Nov 2012 12:49:18 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTP id A6744E622F for ; Mon, 19 Nov 2012 12:41:29 -0800 (PST) Received: from relay2.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id 06CEEA3B06; Mon, 19 Nov 2012 21:41:29 +0100 (CET) Received: from sles11.fritz.box (sles11.fritz.box [192.168.178.22]) by debian (Postfix) with ESMTP id EAF273F32A; Mon, 19 Nov 2012 21:41:27 +0100 (CET) From: Egbert Eich To: dri-devel@lists.freedesktop.org Subject: [PATCH 08/17] DRM/KMS/EDID: Use Extension Block Fixup Code also for 'firmware' EDID. Date: Mon, 19 Nov 2012 15:23:09 -0500 Message-Id: <1353356598-10634-9-git-send-email-eich@suse.de> X-Mailer: git-send-email 1.7.7 In-Reply-To: <1353356598-10634-1-git-send-email-eich@suse.de> References: <1353356598-10634-1-git-send-email-eich@suse.de> Cc: Egbert Eich , Takashi Iwai X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Signed-off-by: Egbert Eich --- 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__ */