diff options
author | Zhang Rui <rui.zhang@intel.com> | 2009-03-18 04:27:16 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 21:56:45 -0400 |
commit | 1a7c618a3f7bef1a20ae740df512eeba21397fa5 (patch) | |
tree | 51626f0f394e01bdb662d9466db68386c731b06f /drivers/acpi/video.c | |
parent | d80fb99fdcd56f4934f11cc44ca016463842dc8b (diff) |
ACPI video: support _BQC/_BCL/_BCM methods that use index values
The input/output of _BQC/_BCL/_BCM control methods should be represented
by a number between 0 and 100, and can be thought of as a percentage.
But some buggy _BQC/_BCL/_BCM methods use the index values instead.
http://bugzilla.kernel.org/show_bug.cgi?id=12302
http://bugzilla.kernel.org/show_bug.cgi?id=12249
http://bugzilla.kernel.org/show_bug.cgi?id=12037
Add the functionality to support such kind of BIOSes in ACPI video driver.
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 | 91 |
1 files changed, 70 insertions, 21 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index dc84970ce1e9..1f1625c51003 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -171,6 +171,9 @@ struct acpi_video_device_cap { | |||
171 | struct acpi_video_brightness_flags { | 171 | struct acpi_video_brightness_flags { |
172 | u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ | 172 | u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ |
173 | u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ | 173 | u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ |
174 | u8 _BCL_use_index:1; /* levels in _BCL are index values */ | ||
175 | u8 _BCM_use_index:1; /* input of _BCM is an index value */ | ||
176 | u8 _BQC_use_index:1; /* _BQC returns an index value */ | ||
174 | }; | 177 | }; |
175 | 178 | ||
176 | struct acpi_video_device_brightness { | 179 | struct acpi_video_device_brightness { |
@@ -505,7 +508,8 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) | |||
505 | device->brightness->curr = level; | 508 | device->brightness->curr = level; |
506 | for (state = 2; state < device->brightness->count; state++) | 509 | for (state = 2; state < device->brightness->count; state++) |
507 | if (level == device->brightness->levels[state]) { | 510 | if (level == device->brightness->levels[state]) { |
508 | device->backlight->props.brightness = state - 2; | 511 | if (device->backlight) |
512 | device->backlight->props.brightness = state - 2; | ||
509 | return 0; | 513 | return 0; |
510 | } | 514 | } |
511 | 515 | ||
@@ -523,6 +527,13 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, | |||
523 | status = acpi_evaluate_integer(device->dev->handle, "_BQC", | 527 | status = acpi_evaluate_integer(device->dev->handle, "_BQC", |
524 | NULL, level); | 528 | NULL, level); |
525 | if (ACPI_SUCCESS(status)) { | 529 | if (ACPI_SUCCESS(status)) { |
530 | if (device->brightness->flags._BQC_use_index) { | ||
531 | if (device->brightness->flags._BCL_reversed) | ||
532 | *level = device->brightness->count | ||
533 | - 3 - (*level); | ||
534 | *level = device->brightness->levels[*level + 2]; | ||
535 | |||
536 | } | ||
526 | device->brightness->curr = *level; | 537 | device->brightness->curr = *level; |
527 | return 0; | 538 | return 0; |
528 | } else { | 539 | } else { |
@@ -689,8 +700,10 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
689 | { | 700 | { |
690 | union acpi_object *obj = NULL; | 701 | union acpi_object *obj = NULL; |
691 | int i, max_level = 0, count = 0, level_ac_battery = 0; | 702 | int i, max_level = 0, count = 0, level_ac_battery = 0; |
703 | unsigned long long level, level_old; | ||
692 | union acpi_object *o; | 704 | union acpi_object *o; |
693 | struct acpi_video_device_brightness *br = NULL; | 705 | struct acpi_video_device_brightness *br = NULL; |
706 | int result = -EINVAL; | ||
694 | 707 | ||
695 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { | 708 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
696 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " | 709 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " |
@@ -704,13 +717,16 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
704 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 717 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
705 | if (!br) { | 718 | if (!br) { |
706 | printk(KERN_ERR "can't allocate memory\n"); | 719 | printk(KERN_ERR "can't allocate memory\n"); |
720 | result = -ENOMEM; | ||
707 | goto out; | 721 | goto out; |
708 | } | 722 | } |
709 | 723 | ||
710 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), | 724 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), |
711 | GFP_KERNEL); | 725 | GFP_KERNEL); |
712 | if (!br->levels) | 726 | if (!br->levels) { |
727 | result = -ENOMEM; | ||
713 | goto out_free; | 728 | goto out_free; |
729 | } | ||
714 | 730 | ||
715 | for (i = 0; i < obj->package.count; i++) { | 731 | for (i = 0; i < obj->package.count; i++) { |
716 | o = (union acpi_object *)&obj->package.elements[i]; | 732 | o = (union acpi_object *)&obj->package.elements[i]; |
@@ -756,10 +772,55 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
756 | 772 | ||
757 | br->count = count; | 773 | br->count = count; |
758 | device->brightness = br; | 774 | device->brightness = br; |
775 | |||
776 | /* Check the input/output of _BQC/_BCL/_BCM */ | ||
777 | if ((max_level < 100) && (max_level <= (count - 2))) | ||
778 | br->flags._BCL_use_index = 1; | ||
779 | |||
780 | /* | ||
781 | * _BCM is always consistent with _BCL, | ||
782 | * at least for all the laptops we have ever seen. | ||
783 | */ | ||
784 | br->flags._BCM_use_index = br->flags._BCL_use_index; | ||
785 | |||
786 | /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ | ||
787 | br->curr = max_level; | ||
788 | result = acpi_video_device_lcd_get_level_current(device, &level_old); | ||
789 | if (result) | ||
790 | goto out_free_levels; | ||
791 | |||
792 | result = acpi_video_device_lcd_set_level(device, br->curr); | ||
793 | if (result) | ||
794 | goto out_free_levels; | ||
795 | |||
796 | result = acpi_video_device_lcd_get_level_current(device, &level); | ||
797 | if (result) | ||
798 | goto out_free_levels; | ||
799 | |||
800 | if ((level != level_old) && !br->flags._BCM_use_index) { | ||
801 | /* Note: | ||
802 | * This piece of code does not work correctly if the current | ||
803 | * brightness levels is 0. | ||
804 | * But I guess boxes that boot with such a dark screen are rare | ||
805 | * and no more code is needed to cover this specifial case. | ||
806 | */ | ||
807 | |||
808 | if (level_ac_battery != 2) { | ||
809 | /* | ||
810 | * For now, we don't support the _BCL like this: | ||
811 | * 16, 15, 0, 1, 2, 3, ..., 14, 15, 16 | ||
812 | * because we may mess up the index returned by _BQC. | ||
813 | * Plus: we have not got a box like this. | ||
814 | */ | ||
815 | ACPI_ERROR((AE_INFO, "_BCL not supported\n")); | ||
816 | } | ||
817 | br->flags._BQC_use_index = 1; | ||
818 | } | ||
819 | |||
759 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 820 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
760 | "found %d brightness levels\n", count - 2)); | 821 | "found %d brightness levels\n", count - 2)); |
761 | kfree(obj); | 822 | kfree(obj); |
762 | return max_level; | 823 | return result; |
763 | 824 | ||
764 | out_free_levels: | 825 | out_free_levels: |
765 | kfree(br->levels); | 826 | kfree(br->levels); |
@@ -768,7 +829,7 @@ out_free: | |||
768 | out: | 829 | out: |
769 | device->brightness = NULL; | 830 | device->brightness = NULL; |
770 | kfree(obj); | 831 | kfree(obj); |
771 | return 0; | 832 | return result; |
772 | } | 833 | } |
773 | 834 | ||
774 | /* | 835 | /* |
@@ -785,7 +846,6 @@ out: | |||
785 | static void acpi_video_device_find_cap(struct acpi_video_device *device) | 846 | static void acpi_video_device_find_cap(struct acpi_video_device *device) |
786 | { | 847 | { |
787 | acpi_handle h_dummy1; | 848 | acpi_handle h_dummy1; |
788 | u32 max_level = 0; | ||
789 | 849 | ||
790 | 850 | ||
791 | memset(&device->cap, 0, sizeof(device->cap)); | 851 | memset(&device->cap, 0, sizeof(device->cap)); |
@@ -814,13 +874,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
814 | device->cap._DSS = 1; | 874 | device->cap._DSS = 1; |
815 | } | 875 | } |
816 | 876 | ||
817 | if (acpi_video_backlight_support()) | 877 | if (acpi_video_backlight_support()) { |
818 | max_level = acpi_video_init_brightness(device); | ||
819 | |||
820 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { | ||
821 | int result; | 878 | int result; |
822 | static int count = 0; | 879 | static int count = 0; |
823 | char *name; | 880 | char *name; |
881 | |||
882 | result = acpi_video_init_brightness(device); | ||
883 | if (result) | ||
884 | return; | ||
824 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 885 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
825 | if (!name) | 886 | if (!name) |
826 | return; | 887 | return; |
@@ -829,18 +890,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
829 | device->backlight = backlight_device_register(name, | 890 | device->backlight = backlight_device_register(name, |
830 | NULL, device, &acpi_backlight_ops); | 891 | NULL, device, &acpi_backlight_ops); |
831 | device->backlight->props.max_brightness = device->brightness->count-3; | 892 | device->backlight->props.max_brightness = device->brightness->count-3; |
832 | /* | ||
833 | * If there exists the _BQC object, the _BQC object will be | ||
834 | * called to get the current backlight brightness. Otherwise | ||
835 | * the brightness will be set to the maximum. | ||
836 | */ | ||
837 | if (device->cap._BQC) | ||
838 | device->backlight->props.brightness = | ||
839 | acpi_video_get_brightness(device->backlight); | ||
840 | else | ||
841 | device->backlight->props.brightness = | ||
842 | device->backlight->props.max_brightness; | ||
843 | backlight_update_status(device->backlight); | ||
844 | kfree(name); | 893 | kfree(name); |
845 | 894 | ||
846 | device->cdev = thermal_cooling_device_register("LCD", | 895 | device->cdev = thermal_cooling_device_register("LCD", |