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>
This commit is contained in:
parent
34f8f1031c
commit
a50188dae3
@ -631,6 +631,56 @@ acpi_video_cmp_level(const void *a, const void *b)
|
|||||||
return *(int *)a - *(int *)b;
|
return *(int *)a - *(int *)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decides if _BQC/_BCQ for this system is usable
|
||||||
|
*
|
||||||
|
* We do this by changing the level first and then read out the current
|
||||||
|
* brightness level, if the value does not match, find out if it is using
|
||||||
|
* index. If not, clear the _BQC/_BCQ capability.
|
||||||
|
*/
|
||||||
|
static int acpi_video_bqc_quirk(struct acpi_video_device *device,
|
||||||
|
int max_level, int current_level)
|
||||||
|
{
|
||||||
|
struct acpi_video_device_brightness *br = device->brightness;
|
||||||
|
int result;
|
||||||
|
unsigned long long level;
|
||||||
|
int test_level;
|
||||||
|
|
||||||
|
/* don't mess with existing known broken systems */
|
||||||
|
if (bqc_offset_aml_bug_workaround)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some systems always report current brightness level as maximum
|
||||||
|
* through _BQC, we need to test another value for them.
|
||||||
|
*/
|
||||||
|
test_level = current_level == max_level ? br->levels[2] : max_level;
|
||||||
|
|
||||||
|
result = acpi_video_device_lcd_set_level(device, test_level);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = acpi_video_device_lcd_get_level_current(device, &level, true);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (level != test_level) {
|
||||||
|
/* buggy _BQC found, need to find out if it uses index */
|
||||||
|
if (level < br->count) {
|
||||||
|
if (br->flags._BCL_reversed)
|
||||||
|
level = br->count - 3 - level;
|
||||||
|
if (br->levels[level + 2] == test_level)
|
||||||
|
br->flags._BQC_use_index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!br->flags._BQC_use_index)
|
||||||
|
device->cap._BQC = device->cap._BCQ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arg:
|
* Arg:
|
||||||
* device : video output device (LCD, CRT, ..)
|
* device : video output device (LCD, CRT, ..)
|
||||||
@ -742,18 +792,15 @@ acpi_video_init_brightness(struct acpi_video_device *device)
|
|||||||
if (result)
|
if (result)
|
||||||
goto out_free_levels;
|
goto out_free_levels;
|
||||||
|
|
||||||
|
result = acpi_video_bqc_quirk(device, max_level, level_old);
|
||||||
|
if (result)
|
||||||
|
goto out_free_levels;
|
||||||
/*
|
/*
|
||||||
* Set the level to maximum and check if _BQC uses indexed value
|
* cap._BQC may get cleared due to _BQC is found to be broken
|
||||||
|
* in acpi_video_bqc_quirk, so check again here.
|
||||||
*/
|
*/
|
||||||
result = acpi_video_device_lcd_set_level(device, max_level);
|
if (!device->cap._BQC)
|
||||||
if (result)
|
goto set_level;
|
||||||
goto out_free_levels;
|
|
||||||
|
|
||||||
result = acpi_video_device_lcd_get_level_current(device, &level, true);
|
|
||||||
if (result)
|
|
||||||
goto out_free_levels;
|
|
||||||
|
|
||||||
br->flags._BQC_use_index = (level == max_level ? 0 : 1);
|
|
||||||
|
|
||||||
if (use_bios_initial_backlight) {
|
if (use_bios_initial_backlight) {
|
||||||
level = acpi_video_bqc_value_to_level(device, level_old);
|
level = acpi_video_bqc_value_to_level(device, level_old);
|
||||||
|
Loading…
Reference in New Issue
Block a user