From d32f69470c2081ffdfd82740ac19f940790f9e93 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:12 +0800 Subject: [PATCH] ACPI video: support _BCL packages that don't export brightness levels when machine is on AC/Battery Many buggy BIOSes don't export the brightness levels when machine is on AC/Battery in the _BCL method. Reformat the _BCL package for these laptops: now the elements in device->brightness->levels[] are like: levels[0]: brightness level when on AC power. levels[1]: brightness level when on Battery power. levels[2]: supported brightness level 1. levels[3]: supported brightness level 2. ... levels[n]: supported brightness level n-1. levels[n + 1]: supported brightness level n. So if there are n supported brightness levels on this laptop, we will have n+2 entries in device->brightnes->levels[]. level[0] and level[1] are invalid on the laptops that don't export the brightness levels on AC/Battery. Fortunately, we never use these two values at all, even for the valid ones. http://bugzilla.kernel.org/show_bug.cgi?id=12249 Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 52f52b32b63f..398b3eee37fb 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -168,10 +168,15 @@ struct acpi_video_device_cap { u8 _DSS:1; /*Device state set */ }; +struct acpi_video_brightness_flags { + u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ +}; + struct acpi_video_device_brightness { int curr; int count; int *levels; + struct acpi_video_brightness_flags flags; }; struct acpi_video_device { @@ -682,7 +687,7 @@ static int acpi_video_init_brightness(struct acpi_video_device *device) { union acpi_object *obj = NULL; - int i, max_level = 0, count = 0; + int i, max_level = 0, count = 0, level_ac_battery = 0; union acpi_object *o; struct acpi_video_device_brightness *br = NULL; @@ -701,7 +706,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) goto out; } - br->levels = kmalloc(obj->package.count * sizeof *(br->levels), + br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), GFP_KERNEL); if (!br->levels) goto out_free; @@ -719,16 +724,34 @@ acpi_video_init_brightness(struct acpi_video_device *device) count++; } - /* don't sort the first two brightness levels */ + /* + * some buggy BIOS don't export the levels + * when machine is on AC/Battery in _BCL package. + * In this case, the first two elements in _BCL packages + * are also supported brightness levels that OS should take care of. + */ + for (i = 2; i < count; i++) + if (br->levels[i] == br->levels[0] || + br->levels[i] == br->levels[1]) + level_ac_battery++; + + if (level_ac_battery < 2) { + level_ac_battery = 2 - level_ac_battery; + br->flags._BCL_no_ac_battery_levels = 1; + for (i = (count - 1 + level_ac_battery); i >= 2; i--) + br->levels[i] = br->levels[i - level_ac_battery]; + count += level_ac_battery; + } else if (level_ac_battery > 2) + ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); + + /* sort all the supported brightness levels */ sort(&br->levels[2], count - 2, sizeof(br->levels[2]), acpi_video_cmp_level, NULL); - if (count < 2) - goto out_free_levels; - br->count = count; device->brightness = br; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "found %d brightness levels\n", count - 2)); kfree(obj); return max_level;