[PATCH] ACPI: disable the ACPI backlight control on laptops with buggy _BCL methods

Zhang Rui
2009-01-08T02:57:00Z

[-- Attachment #1: Type: text/plain, Size: 3916 bytes --]

From: Zhang Rui <rui.zhang@intel.com>
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 <trenn@suse.de>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
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;
}

[-- Attachment #2: patch-video-check-_BCL --]
[-- Type: message/rfc822, Size: 4036 bytes --]

From: Zhang Rui <rui.zhang@intel.com>
Subject: don't use buggy _BCL/_BCM/_BQC for backlight control
Date: Thu, 08 Jan 2009 10:56:50 +0800
Message-ID: <1231383410.20746.42.camel@rzhang-dt>

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 <trenn@suse.de>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
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;
}