diff options
author | Aaron Lu <aaron.lu@intel.com> | 2013-04-22 08:08:32 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-22 08:08:32 -0400 |
commit | a50188dae3089dcd15a6ae793528c157680891f1 (patch) | |
tree | adb84d398f5c3e3b2e0b24c46672f5dfc91da862 | |
parent | 34f8f1031cdccc73ab002dfe5f65ec89c3314457 (diff) |
acpi: video: enhance the quirk detect logic of _BQC
Currently we decide if the _BQC is using index by first setting the
level to maximum, and then check if _BQC returned maximum; if not, we
say it is using index.
This is not true for some buggy systems, where the _BQC method will
always return a constant value(e.g. 0 or 100 for the two broken system)
and thus break the current logic. So this patch tries to enhance the
quirk detect logic for _BQC: we do this by picking a test_level, it can
be the maximum level or the mininum one based on some condition. And we
don't make the assumption that if _BQC returned a value that is not what
we just set, it must be using an index. Instead, we will compare the
value returned from _BQC and if it doesn't match, see if the returned
value is an index. And if still no, clear the capability of _BQC.
References: https://bugzilla.kernel.org/show_bug.cgi?id=42861
References: https://bugzilla.kernel.org/show_bug.cgi?id=56011
Reported-and-tested-by: Artem Savkov <artem.savkov@gmail.com>
Reported-by: Luis Medinas <lmedinas@gmail.com>
Reported-by: Cheppes <cheppes@mailinator.com>
Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Acked-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/video.c | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 3cdd0471bc63..ed192e5d82b6 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -632,6 +632,56 @@ acpi_video_cmp_level(const void *a, const void *b) | |||
632 | } | 632 | } |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * Decides if _BQC/_BCQ for this system is usable | ||
636 | * | ||
637 | * We do this by changing the level first and then read out the current | ||
638 | * brightness level, if the value does not match, find out if it is using | ||
639 | * index. If not, clear the _BQC/_BCQ capability. | ||
640 | */ | ||
641 | static int acpi_video_bqc_quirk(struct acpi_video_device *device, | ||
642 | int max_level, int current_level) | ||
643 | { | ||
644 | struct acpi_video_device_brightness *br = device->brightness; | ||
645 | int result; | ||
646 | unsigned long long level; | ||
647 | int test_level; | ||
648 | |||
649 | /* don't mess with existing known broken systems */ | ||
650 | if (bqc_offset_aml_bug_workaround) | ||
651 | return 0; | ||
652 | |||
653 | /* | ||
654 | * Some systems always report current brightness level as maximum | ||
655 | * through _BQC, we need to test another value for them. | ||
656 | */ | ||
657 | test_level = current_level == max_level ? br->levels[2] : max_level; | ||
658 | |||
659 | result = acpi_video_device_lcd_set_level(device, test_level); | ||
660 | if (result) | ||
661 | return result; | ||
662 | |||
663 | result = acpi_video_device_lcd_get_level_current(device, &level, true); | ||
664 | if (result) | ||
665 | return result; | ||
666 | |||
667 | if (level != test_level) { | ||
668 | /* buggy _BQC found, need to find out if it uses index */ | ||
669 | if (level < br->count) { | ||
670 | if (br->flags._BCL_reversed) | ||
671 | level = br->count - 3 - level; | ||
672 | if (br->levels[level + 2] == test_level) | ||
673 | br->flags._BQC_use_index = 1; | ||
674 | } | ||
675 | |||
676 | if (!br->flags._BQC_use_index) | ||
677 | device->cap._BQC = device->cap._BCQ = 0; | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | |||
684 | /* | ||
635 | * Arg: | 685 | * Arg: |
636 | * device : video output device (LCD, CRT, ..) | 686 | * device : video output device (LCD, CRT, ..) |
637 | * | 687 | * |
@@ -742,18 +792,15 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
742 | if (result) | 792 | if (result) |
743 | goto out_free_levels; | 793 | goto out_free_levels; |
744 | 794 | ||
745 | /* | 795 | result = acpi_video_bqc_quirk(device, max_level, level_old); |
746 | * Set the level to maximum and check if _BQC uses indexed value | ||
747 | */ | ||
748 | result = acpi_video_device_lcd_set_level(device, max_level); | ||
749 | if (result) | ||
750 | goto out_free_levels; | ||
751 | |||
752 | result = acpi_video_device_lcd_get_level_current(device, &level, true); | ||
753 | if (result) | 796 | if (result) |
754 | goto out_free_levels; | 797 | goto out_free_levels; |
755 | 798 | /* | |
756 | br->flags._BQC_use_index = (level == max_level ? 0 : 1); | 799 | * cap._BQC may get cleared due to _BQC is found to be broken |
800 | * in acpi_video_bqc_quirk, so check again here. | ||
801 | */ | ||
802 | if (!device->cap._BQC) | ||
803 | goto set_level; | ||
757 | 804 | ||
758 | if (use_bios_initial_backlight) { | 805 | if (use_bios_initial_backlight) { |
759 | level = acpi_video_bqc_value_to_level(device, level_old); | 806 | level = acpi_video_bqc_value_to_level(device, level_old); |