From patchwork Thu Nov 22 10:22:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egbert Eich X-Patchwork-Id: 1783271 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 3B906DF24C for ; Thu, 22 Nov 2012 10:54:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 29583436E4 for ; Thu, 22 Nov 2012 02:54:39 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.17.8]) by gabe.freedesktop.org (Postfix) with ESMTP id 35CDFE5CCE for ; Thu, 22 Nov 2012 02:51:06 -0800 (PST) Received: from debian (p5DCF0728.dip0.t-ipconnect.de [93.207.7.40]) by mrelayeu.kundenserver.de (node=mrbap2) with ESMTP (Nemesis) id 0LoJRp-1T4vZJ2T4z-00gi4P; 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 CA91D3F362; Thu, 22 Nov 2012 11:51:01 +0100 (CET) From: Egbert Eich To: dri-devel@lists.freedesktop.org Subject: [PATCH v2 08/18] DRM/KMS/EDID: Fix up EEDID Map Blogs if Extension Block Count has changed (v2) Date: Thu, 22 Nov 2012 05:22:58 -0500 Message-Id: <1353579788-30637-9-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:B5u+XuFpvKxxlGdWTE/2b10L+hyLvIqZRAuE/OnYMkW QRqAqZPvTo0bbZCdCwFQSkNRt9m+kT1iSBG/NN5cT3ZBxCyeKO B54CsWowx5NkBpi0MF+5LuM+J1ZxJLIEUP/r3xDnGgis/koyZF BgTDwnvvpil5kf/4WAxH1B2zax7tLveBiM47tfugDIMZDD7tLo 7H/rDNEVHT92bwT6UhIGpQSNL+Nh0S4teqcoQa1SsP/v8f0nP9 qca8/++B6Bem9w7aypIgXNDWvkaL2InL2Tu+jMW4vunldZOuEs p6GnbMdKrnHZb4K0ti2/5GgLXJli0LztGHkhCrgz26V3sBptzG 1Y0TNIFcMVSBvgsY48NI= 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 EEDID v1.3 mandates map blogs if more than one EDID extension block is used while in v1.4 they are optional. If the extension count has been changed (because some extension blocks were not readable) those map blocks need fixing. In case of v1.4 or higher we simply eliminate all map blogs as this is less time consuming. For v1.3 we scrap any exsisting map blocks and recreate them from scratch. v2: Fixed conflits due to reordering of commits. Signed-off-by: Egbert Eich --- drivers/gpu/drm/drm_edid.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 89 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0fe61fb..9b298fc 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -47,6 +47,7 @@ #define EDID_CHECKSUM_OFFSET offsetof(struct edid, checksum) #define EDID_VERSION_MAJOR_OFFSET offsetof(struct edid, version) #define EDID_VERSION_MINOR_OFFSET offsetof(struct edid, revision) +#define EEDID_BLOCK_MAP_FLAG 0xF0 /* * EDID blocks out in the wild have a variety of bugs, try to collect * them here (note that userspace may work around broken monitors first, @@ -320,6 +321,92 @@ static bool drm_edid_is_zero(u8 *in_edid, int length) return true; } +static void +fix_map(u8 *block, int cnt) +{ + int i; + u8 csum; + + if (--cnt > 127) + cnt = 127; + memset(block, 0, 128); + block[0] = EEDID_BLOCK_MAP_FLAG; + csum = block[0]; + + for (i = 1; i < cnt; i++) { + block[i] = block[i * EDID_LENGTH]; + csum += block[i]; + } + block[127] = (u8)(0x100 - csum); +} + +static int +fixup_blockmaps(u8 **blockp, int eblock_cnt) +{ + int i; + u8 *block = *blockp; + + if (block[EDID_VERSION_MAJOR_OFFSET] > 1) + return 0; + if (block[EDID_VERSION_MINOR_OFFSET] < 3) + return 0; + if (eblock_cnt == 1) { + if (block[EDID_LENGTH] == EEDID_BLOCK_MAP_FLAG) + return 0; + else + return 1; + } + if (block[EDID_VERSION_MINOR_OFFSET] >= 4) { + /* blockmaps are optional: simply toss them */ + for (i = 1; i <= eblock_cnt; i++) { + if (block[i * EDID_LENGTH] == EEDID_BLOCK_MAP_FLAG) { + if (i < eblock_cnt) + memmove(&block[i * EDID_LENGTH], + &block[(i + 1) * EDID_LENGTH], + (eblock_cnt-i) * EDID_LENGTH); + i--; + eblock_cnt--; + } + } + } else { + int total_cnt = block[EDID_EXTENSION_FLAG_OFFSET]; + for (i = 1; i <= eblock_cnt; i++) { + if (block[i * EDID_LENGTH] == EEDID_BLOCK_MAP_FLAG) { + if (i == 1 || i == 128) /* correct map block locations */ + continue; + if (i < eblock_cnt) + memmove(&block[i * EDID_LENGTH], + &block[(i + 1) * EDID_LENGTH], + (eblock_cnt-i) * EDID_LENGTH); + i--; + eblock_cnt--; + continue; + } else if (i == 1 || i == 128) { + if (eblock_cnt >= total_cnt) { + u8 *tmp_p; + tmp_p = krealloc(block, (eblock_cnt + 2) * EDID_LENGTH, GFP_KERNEL); + if (!tmp_p) + return eblock_cnt; + *blockp = block = tmp_p; + total_cnt = eblock_cnt + 1; + } + eblock_cnt++; + memmove(&block[(i + 1) * EDID_LENGTH], + &block[i * EDID_LENGTH], + (eblock_cnt-i) * EDID_LENGTH); + } + } + fix_map(&block[EDID_LENGTH], eblock_cnt); + + if (eblock_cnt == 129) + return 128; + + if (eblock_cnt > 129) + fix_map(&block[EDID_LENGTH * 128], eblock_cnt - 127); + } + return eblock_cnt; +} + static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { @@ -394,6 +481,8 @@ 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; }