summaryrefslogtreecommitdiff
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-18 04:08:06 +0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-18 04:08:06 +0400
commit8c5bd7adb2ce47e6aa39d17b2375f69b0c0aa255 (patch)
tree84ed8b6c9fd4e31eca9adbbbf6be9cd506a2fd46 /drivers/acpi/video.c
parentc04c697cf1fe8f0962ccd3c2392a9b637a5307aa (diff)
downloadlinux-8c5bd7adb2ce47e6aa39d17b2375f69b0c0aa255.tar.xz
ACPI / video / i915: No ACPI backlight if firmware expects Windows 8
According to Matthew Garrett, "Windows 8 leaves backlight control up to individual graphics drivers rather than making ACPI calls itself. There's plenty of evidence to suggest that the Intel driver for Windows [8] doesn't use the ACPI interface, including the fact that it's broken on a bunch of machines when the OS claims to support Windows 8. The simplest thing to do appears to be to disable the ACPI backlight interface on these systems". There's a problem with that approach, however, because simply avoiding to register the ACPI backlight interface if the firmware calls _OSI for Windows 8 may not work in the following situations: (1) The ACPI backlight interface actually works on the given system and the i915 driver is not loaded (e.g. another graphics driver is used). (2) The ACPI backlight interface doesn't work on the given system, but there is a vendor platform driver that will register its own, equally broken, backlight interface if not prevented from doing so by the ACPI subsystem. Therefore we need to allow the ACPI backlight interface to be registered until the i915 driver is loaded which then will unregister it if the firmware has called _OSI for Windows 8 (or will register the ACPI video driver without backlight support if not already present). For this reason, introduce an alternative function for registering ACPI video, acpi_video_register_with_quirks(), that will check whether or not the ACPI video driver has already been registered and whether or not the backlight Windows 8 quirk has to be applied. If the quirk has to be applied, it will block the ACPI backlight support and either unregister the backlight interface if the ACPI video driver has already been registered, or register the ACPI video driver without the backlight interface otherwise. Make the i915 driver use acpi_video_register_with_quirks() instead of acpi_video_register() in i915_driver_load(). This change is based on earlier patches from Matthew Garrett, Chun-Yi Lee and Seth Forshee and includes a fix from Aaron Lu's. References: https://bugzilla.kernel.org/show_bug.cgi?id=51231 Tested-by: Aaron Lu <aaron.lu@intel.com> Tested-by: Igor Gnatenko <i.gnatenko.brain@gmail.com> Tested-by: Yves-Alexis Perez <corsac@debian.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r--drivers/acpi/video.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index f236e172d948..e9d4bb60c35c 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -44,6 +44,8 @@
#include <linux/suspend.h>
#include <acpi/video.h>
+#include "internal.h"
+
#define PREFIX "ACPI: "
#define ACPI_VIDEO_BUS_NAME "Video Bus"
@@ -901,7 +903,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (acpi_video_init_brightness(device))
return;
- if (acpi_video_backlight_support()) {
+ if (acpi_video_verify_backlight_support()) {
struct backlight_properties props;
struct pci_dev *pdev;
acpi_handle acpi_parent;
@@ -1356,8 +1358,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
unsigned long long level_current, level_next;
int result = -EINVAL;
- /* no warning message if acpi_backlight=vendor is used */
- if (!acpi_video_backlight_support())
+ /* no warning message if acpi_backlight=vendor or a quirk is used */
+ if (!acpi_video_verify_backlight_support())
return 0;
if (!device->brightness)
@@ -1859,6 +1861,46 @@ static int acpi_video_bus_remove(struct acpi_device *device)
return 0;
}
+static acpi_status video_unregister_backlight(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ struct acpi_device *acpi_dev;
+ struct acpi_video_bus *video;
+ struct acpi_video_device *dev, *next;
+
+ if (acpi_bus_get_device(handle, &acpi_dev))
+ return AE_OK;
+
+ if (acpi_match_device_ids(acpi_dev, video_device_ids))
+ return AE_OK;
+
+ video = acpi_driver_data(acpi_dev);
+ if (!video)
+ return AE_OK;
+
+ acpi_video_bus_stop_devices(video);
+ mutex_lock(&video->device_list_lock);
+ list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
+ if (dev->backlight) {
+ backlight_device_unregister(dev->backlight);
+ dev->backlight = NULL;
+ kfree(dev->brightness->levels);
+ kfree(dev->brightness);
+ }
+ if (dev->cooling_dev) {
+ sysfs_remove_link(&dev->dev->dev.kobj,
+ "thermal_cooling");
+ sysfs_remove_link(&dev->cooling_dev->device.kobj,
+ "device");
+ thermal_cooling_device_unregister(dev->cooling_dev);
+ dev->cooling_dev = NULL;
+ }
+ }
+ mutex_unlock(&video->device_list_lock);
+ acpi_video_bus_start_devices(video);
+ return AE_OK;
+}
+
static int __init is_i740(struct pci_dev *dev)
{
if (dev->device == 0x00D1)
@@ -1890,14 +1932,25 @@ static int __init intel_opregion_present(void)
return opregion;
}
-int acpi_video_register(void)
+int __acpi_video_register(bool backlight_quirks)
{
- int result = 0;
+ bool no_backlight;
+ int result;
+
+ no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
+
if (register_count) {
/*
- * if the function of acpi_video_register is already called,
- * don't register the acpi_vide_bus again and return no error.
+ * If acpi_video_register() has been called already, don't try
+ * to register acpi_video_bus, but unregister backlight devices
+ * if no backlight support is requested.
*/
+ if (no_backlight)
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ video_unregister_backlight,
+ NULL, NULL, NULL);
+
return 0;
}
@@ -1913,7 +1966,7 @@ int acpi_video_register(void)
return 0;
}
-EXPORT_SYMBOL(acpi_video_register);
+EXPORT_SYMBOL(__acpi_video_register);
void acpi_video_unregister(void)
{