From patchwork Thu Jan 8 02:58:16 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhang Rui X-Patchwork-Id: 1300 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n082ri77026368 for ; Wed, 7 Jan 2009 18:53:44 -0800 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756324AbZAHC5E (ORCPT ); Wed, 7 Jan 2009 21:57:04 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756353AbZAHC5D (ORCPT ); Wed, 7 Jan 2009 21:57:03 -0500 Received: from mga14.intel.com ([143.182.124.37]:12734 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756324AbZAHC5A (ORCPT ); Wed, 7 Jan 2009 21:57:00 -0500 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 07 Jan 2009 18:56:59 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.37,230,1231142400"; d="scan'208";a="97575560" Received: from rzhang-dt.sh.intel.com (HELO [10.239.36.160]) ([10.239.36.160]) by azsmga001.ch.intel.com with ESMTP; 07 Jan 2009 18:56:58 -0800 Subject: [PATCH] ACPI: disable the ACPI backlight control on laptops with buggy _BCL methods From: Zhang Rui To: Len Brown Cc: linux-acpi , trenn@suse.de, "Zhang, Rui" Date: Thu, 08 Jan 2009 10:58:16 +0800 Message-Id: <1231383496.20746.44.camel@rzhang-dt> Mime-Version: 1.0 X-Mailer: Evolution 2.22.1 (2.22.1-2.fc9) Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org From: Zhang Rui Subject: disable the ACPI backlight control on laptops with buggy _BCL methods Some users used to control the backlight via the platform interface. But commit c3d6de698c84efdbdd3781b7058bcc339ab43da8 disables the platform backlight control if ACPI video backlight control is available. This breaks the laptops with buggy _BCL/_BCM/_BQC methods. i.e. only ACPI backlight I/F are available on these laptops but they don't work. With this patch applied, the ACPI backlight control are disabled instead on these laptops. http://bugzilla.kernel.org/show_bug.cgi?id=12037 http://bugzilla.kernel.org/show_bug.cgi?id=12235 http://bugzilla.kernel.org/show_bug.cgi?id=12249 http://bugzilla.kernel.org/show_bug.cgi?id=12302 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/311716 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/301524 CC: Thomas Renninger Signed-off-by: Zhang Rui tested-by: Andy Whitcroft --- drivers/acpi/video_detect.c | 83 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) Some users used to control the backlight via the platform interface. But commit c3d6de698c84efdbdd3781b7058bcc339ab43da8 disables the platform backlight control if ACPI video backlight control is available. This breaks the laptops with buggy _BCL/_BCM/_BQC methods. i.e. only ACPI backlight I/F are available on these laptops but they don't work. With this patch applied, the ACPI backlight control are disabled instead on these laptops. http://bugzilla.kernel.org/show_bug.cgi?id=12037 http://bugzilla.kernel.org/show_bug.cgi?id=12235 http://bugzilla.kernel.org/show_bug.cgi?id=12249 http://bugzilla.kernel.org/show_bug.cgi?id=12302 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/311716 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/301524 CC: Thomas Renninger Signed-off-by: Zhang Rui --- drivers/acpi/video_detect.c | 83 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/acpi/video_detect.c =================================================================== --- linux-2.6.orig/drivers/acpi/video_detect.c +++ linux-2.6/drivers/acpi/video_detect.c @@ -44,17 +44,88 @@ static long acpi_video_support; static bool acpi_video_caps_checked; static acpi_status +acpi_backlight_validate_bcl(acpi_handle handle) +{ + union acpi_object *obj, *obj2; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int level_ac = 0, level_battery = 0; + int i, count; + int *levels; + acpi_status status; + + + status = acpi_evaluate_object(handle, "_BCL", NULL, &buffer); + if (!ACPI_SUCCESS(status)) + return status; + obj = (union acpi_object *)buffer.pointer; + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { + printk(KERN_ERR PREFIX "Invalid _BCL data\n"); + status = AE_BAD_DATA; + goto out; + } + + if (obj->package.count < 2) { + status = AE_BAD_DATA; + goto out; + } + + levels = kzalloc(obj->package.count * sizeof(*levels), GFP_KERNEL); + if (!levels) { + status = AE_NO_MEMORY; + goto out; + } + + for (i = 0, count = 0; i < obj->package.count; i++) { + obj2 = (union acpi_object *)&obj->package.elements[i]; + if (obj2->type != ACPI_TYPE_INTEGER) { + printk(KERN_ERR PREFIX "Invalid data\n"); + continue; + } + levels[i] = (u32) obj2->integer.value; + count ++; + } + + if (count < 2) { + status = AE_BAD_DATA; + goto out_free_levels; + } + + for (i = 2, level_ac = levels[0], level_battery = levels[1]; i < count; i ++) { + if (levels[0] == levels[i]) + level_ac = 1; + if (levels[1] == levels[i]) + level_battery = 1; + } + + if (!level_ac || !level_battery) { + printk(KERN_ERR PREFIX "Invalid _BCL package\n"); + status = AE_BAD_DATA; + goto out_free_levels; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); + +out_free_levels: + kfree(levels); +out: + kfree(obj); + return status; +} + +static acpi_status acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, void **retyurn_value) { long *cap = context; - acpi_handle h_dummy; + acpi_handle h_dummy1, h_dummy2; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " - "support\n")); - *cap |= ACPI_VIDEO_BACKLIGHT; + if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy2))) { + if (ACPI_SUCCESS(acpi_backlight_validate_bcl(h_dummy2))) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " + "support\n")); + *cap |= ACPI_VIDEO_BACKLIGHT; + } /* We have backlight support, no need to scan further */ return AE_CTRL_TERMINATE; } Index: linux-2.6/drivers/acpi/video_detect.c =================================================================== --- linux-2.6.orig/drivers/acpi/video_detect.c +++ linux-2.6/drivers/acpi/video_detect.c @@ -44,17 +44,88 @@ static long acpi_video_support; static bool acpi_video_caps_checked; static acpi_status +acpi_backlight_validate_bcl(acpi_handle handle) +{ + union acpi_object *obj, *obj2; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int level_ac = 0, level_battery = 0; + int i, count; + int *levels; + acpi_status status; + + + status = acpi_evaluate_object(handle, "_BCL", NULL, &buffer); + if (!ACPI_SUCCESS(status)) + return status; + obj = (union acpi_object *)buffer.pointer; + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { + printk(KERN_ERR PREFIX "Invalid _BCL data\n"); + status = AE_BAD_DATA; + goto out; + } + + if (obj->package.count < 2) { + status = AE_BAD_DATA; + goto out; + } + + levels = kzalloc(obj->package.count * sizeof(*levels), GFP_KERNEL); + if (!levels) { + status = AE_NO_MEMORY; + goto out; + } + + for (i = 0, count = 0; i < obj->package.count; i++) { + obj2 = (union acpi_object *)&obj->package.elements[i]; + if (obj2->type != ACPI_TYPE_INTEGER) { + printk(KERN_ERR PREFIX "Invalid data\n"); + continue; + } + levels[i] = (u32) obj2->integer.value; + count ++; + } + + if (count < 2) { + status = AE_BAD_DATA; + goto out_free_levels; + } + + for (i = 2, level_ac = levels[0], level_battery = levels[1]; i < count; i ++) { + if (levels[0] == levels[i]) + level_ac = 1; + if (levels[1] == levels[i]) + level_battery = 1; + } + + if (!level_ac || !level_battery) { + printk(KERN_ERR PREFIX "Invalid _BCL package\n"); + status = AE_BAD_DATA; + goto out_free_levels; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); + +out_free_levels: + kfree(levels); +out: + kfree(obj); + return status; +} + +static acpi_status acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, void **retyurn_value) { long *cap = context; - acpi_handle h_dummy; + acpi_handle h_dummy1, h_dummy2; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " - "support\n")); - *cap |= ACPI_VIDEO_BACKLIGHT; + if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy2))) { + if (ACPI_SUCCESS(acpi_backlight_validate_bcl(h_dummy2))) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " + "support\n")); + *cap |= ACPI_VIDEO_BACKLIGHT; + } /* We have backlight support, no need to scan further */ return AE_CTRL_TERMINATE; }