From patchwork Thu Nov 22 10:23:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egbert Eich X-Patchwork-Id: 1783481 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 634CADF24C for ; Thu, 22 Nov 2012 11:13:57 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 558C2E5E07 for ; Thu, 22 Nov 2012 03:13:57 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org X-Greylist: delayed 311 seconds by postgrey-1.32 at gabe; Thu, 22 Nov 2012 02:56:14 PST Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.17.10]) by gabe.freedesktop.org (Postfix) with ESMTP id 591B9E5EB0 for ; Thu, 22 Nov 2012 02:56:14 -0800 (PST) Received: from debian (p5DCF0728.dip0.t-ipconnect.de [93.207.7.40]) by mrelayeu.kundenserver.de (node=mrbap1) with ESMTP (Nemesis) id 0MNezy-1TdA7n0BnG-007P5w; Thu, 22 Nov 2012 11:51:05 +0100 Received: from sles11.fritz.box (sles11.fritz.box [192.168.178.22]) by debian (Postfix) with ESMTP id 2F38D3F35C; Thu, 22 Nov 2012 11:51:04 +0100 (CET) From: Egbert Eich To: dri-devel@lists.freedesktop.org Subject: [PATCH v2 12/18] DRM/KMS/EDID: Use Extension Block Fixup Code also for 'firmware' EDID (v2) Date: Thu, 22 Nov 2012 05:23:02 -0500 Message-Id: <1353579788-30637-13-git-send-email-eich@suse.com> X-Mailer: git-send-email 1.7.7 In-Reply-To: <1353579788-30637-1-git-send-email-eich@suse.com> References: <1353356598-10634-1-git-send-email-eich@suse.de> <1353579788-30637-1-git-send-email-eich@suse.com> X-Provags-ID: V02:K0:y1ZcV/hlHT84g5IyYHHtgBQGqjF9Rcfcys5JKJn72BS KYfCmbVZih2vef8+7XWbVTPUwVOwW6XGT/x07U+4sa/0XNk4fC P3EyYsx+Ch67f0veLdKoa9vgc+AEglauRJB13X+YK6m9Amzs8I F4/26vLtOkVkVNnOXqC+XqcGOfJA8O3ColibU1v4lqvGUbMTix q9zu6lARnwquHl2a5bw1MqpKDPJ0Y0ikrSb23dHh8kuD2O3dvB TzWvYvPX55vXO7WP3pUNSLd9d8h5JOXcwUem8PpeV3VeQQ5TcV cMjAnfJPCzdmxfb4CsIyKGWh0N7Wajm/+l0AVpI4dlBP5GIepN mGL5bdcQ5WSCi8whrg+w= Cc: Egbert Eich , tiwai@suse.com 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 in drm_edid.c there's now code to fix extension blockmaps if the number of extensions has changed. This code also rearranges the EDID blocks. Replace the exisiting EDID rearrange code with a call to this code. v2: Make adjustments required by patch reordering, add missing memcpy(). Signed-off-by: Egbert Eich --- drivers/gpu/drm/drm_edid.c | 64 +++++++++++++++++++++++++++++++++++---- drivers/gpu/drm/drm_edid_load.c | 54 +++++++------------------------- include/drm/drm_edid.h | 1 + 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8239c42..a47fa7f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -407,6 +407,18 @@ fixup_blockmaps(u8 **blockp, int eblock_cnt) return eblock_cnt; } +static void +fixup_edid(u8 **blockp, int valid_extensions) +{ + if (valid_extensions != (*blockp)[EDID_EXTENSION_FLAG_OFFSET]) { + if (valid_extensions) + valid_extensions = fixup_blockmaps(blockp, valid_extensions); + + (*blockp)[EDID_CHECKSUM_OFFSET] += (*blockp)[EDID_EXTENSION_FLAG_OFFSET] - valid_extensions; + (*blockp)[EDID_EXTENSION_FLAG_OFFSET] = valid_extensions; + } +} + static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { @@ -487,12 +499,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) } done_fix_extension_count: - if (valid_extensions != block[EDID_EXTENSION_FLAG_OFFSET]) { - if (valid_extensions) - valid_extensions = fixup_blockmaps(&block, valid_extensions); - block[EDID_CHECKSUM_OFFSET] += block[EDID_EXTENSION_FLAG_OFFSET] - valid_extensions; - block[EDID_EXTENSION_FLAG_OFFSET] = valid_extensions; - } + fixup_edid(&block, valid_extensions); return block; @@ -509,6 +516,51 @@ 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) { + int cnt = 0; + n_blocks--; + if ((*blockp)[EDID_EXTENSION_FLAG_OFFSET] < n_blocks) + n_blocks = (*blockp)[EDID_EXTENSION_FLAG_OFFSET]; + + while (n_blocks--) { + cnt++; + if (drm_edid_block_valid(*blockp + cnt * EDID_LENGTH, + valid_extensions + 1, print_bad_edid)) { + valid_extensions++; + if (cnt != valid_extensions) + memcpy(*blockp + valid_extensions * EDID_LENGTH, + *blockp + cnt * EDID_LENGTH, EDID_LENGTH); + } + } + fixup_edid(blockp, valid_extensions); + } else + 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 9c15c4a..8f26790 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -119,11 +119,10 @@ static struct edid *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 struct edid *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 struct edid *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 c0a77bd..53c619c 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -255,5 +255,6 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE struct edid *drm_load_edid_firmware(struct drm_connector *connector); #endif +int drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int len); #endif /* __DRM_EDID_H__ */