diff options
author | Zhang Rui <rui.zhang@intel.com> | 2009-03-18 04:27:12 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 21:55:58 -0400 |
commit | d32f69470c2081ffdfd82740ac19f940790f9e93 (patch) | |
tree | e15e8d5bd6dbc9c1aa03cf1da78bcc75c3ac21fa /drivers/acpi/video.c | |
parent | 24450c7add575cef53097738f16a4c1a720fa5cb (diff) |
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 <rui.zhang@intel.com>
Acked-by: Matthew Garrett <mjg59@srcf.ucam.org>
Acked-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 37 |
1 files 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 { | |||
168 | u8 _DSS:1; /*Device state set */ | 168 | u8 _DSS:1; /*Device state set */ |
169 | }; | 169 | }; |
170 | 170 | ||
171 | struct acpi_video_brightness_flags { | ||
172 | u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ | ||
173 | }; | ||
174 | |||
171 | struct acpi_video_device_brightness { | 175 | struct acpi_video_device_brightness { |
172 | int curr; | 176 | int curr; |
173 | int count; | 177 | int count; |
174 | int *levels; | 178 | int *levels; |
179 | struct acpi_video_brightness_flags flags; | ||
175 | }; | 180 | }; |
176 | 181 | ||
177 | struct acpi_video_device { | 182 | struct acpi_video_device { |
@@ -682,7 +687,7 @@ static int | |||
682 | acpi_video_init_brightness(struct acpi_video_device *device) | 687 | acpi_video_init_brightness(struct acpi_video_device *device) |
683 | { | 688 | { |
684 | union acpi_object *obj = NULL; | 689 | union acpi_object *obj = NULL; |
685 | int i, max_level = 0, count = 0; | 690 | int i, max_level = 0, count = 0, level_ac_battery = 0; |
686 | union acpi_object *o; | 691 | union acpi_object *o; |
687 | struct acpi_video_device_brightness *br = NULL; | 692 | struct acpi_video_device_brightness *br = NULL; |
688 | 693 | ||
@@ -701,7 +706,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
701 | goto out; | 706 | goto out; |
702 | } | 707 | } |
703 | 708 | ||
704 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), | 709 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), |
705 | GFP_KERNEL); | 710 | GFP_KERNEL); |
706 | if (!br->levels) | 711 | if (!br->levels) |
707 | goto out_free; | 712 | goto out_free; |
@@ -719,16 +724,34 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
719 | count++; | 724 | count++; |
720 | } | 725 | } |
721 | 726 | ||
722 | /* don't sort the first two brightness levels */ | 727 | /* |
728 | * some buggy BIOS don't export the levels | ||
729 | * when machine is on AC/Battery in _BCL package. | ||
730 | * In this case, the first two elements in _BCL packages | ||
731 | * are also supported brightness levels that OS should take care of. | ||
732 | */ | ||
733 | for (i = 2; i < count; i++) | ||
734 | if (br->levels[i] == br->levels[0] || | ||
735 | br->levels[i] == br->levels[1]) | ||
736 | level_ac_battery++; | ||
737 | |||
738 | if (level_ac_battery < 2) { | ||
739 | level_ac_battery = 2 - level_ac_battery; | ||
740 | br->flags._BCL_no_ac_battery_levels = 1; | ||
741 | for (i = (count - 1 + level_ac_battery); i >= 2; i--) | ||
742 | br->levels[i] = br->levels[i - level_ac_battery]; | ||
743 | count += level_ac_battery; | ||
744 | } else if (level_ac_battery > 2) | ||
745 | ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); | ||
746 | |||
747 | /* sort all the supported brightness levels */ | ||
723 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | 748 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), |
724 | acpi_video_cmp_level, NULL); | 749 | acpi_video_cmp_level, NULL); |
725 | 750 | ||
726 | if (count < 2) | ||
727 | goto out_free_levels; | ||
728 | |||
729 | br->count = count; | 751 | br->count = count; |
730 | device->brightness = br; | 752 | device->brightness = br; |
731 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); | 753 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
754 | "found %d brightness levels\n", count - 2)); | ||
732 | kfree(obj); | 755 | kfree(obj); |
733 | return max_level; | 756 | return max_level; |
734 | 757 | ||