aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-04-04 19:43:51 -0400
committerLen Brown <len.brown@intel.com>2010-04-06 17:02:00 -0400
commitac7729da880e742613129ee6dea0045328670d2d (patch)
tree6af1dcc2a3aa141164cfb7e3c177186fe3ec22d8 /drivers/acpi/video.c
parent7da23b86e14b77c094b11a9fa5ef5b3758fc9193 (diff)
ACPI / PM: Move ACPI video resume to a PM notifier
There is a problem with the ACPI video resume routine that it's executed before the GPU that may be accessed by it. To fix this issue, move the ACPI video resume to a power management notifier, so that's executed after resuming all devices, including the GPU. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15096, which is a listed regression from 2.6.31. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Tested-by: Rafał Miłecki <zajec5@gmail.com> Acked-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r--drivers/acpi/video.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 6a0143796772..416eb0303a83 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -44,6 +44,7 @@
44#include <linux/dmi.h> 44#include <linux/dmi.h>
45#include <acpi/acpi_bus.h> 45#include <acpi/acpi_bus.h>
46#include <acpi/acpi_drivers.h> 46#include <acpi/acpi_drivers.h>
47#include <linux/suspend.h>
47 48
48#define PREFIX "ACPI: " 49#define PREFIX "ACPI: "
49 50
@@ -89,7 +90,6 @@ module_param(allow_duplicates, bool, 0644);
89static int register_count = 0; 90static int register_count = 0;
90static int acpi_video_bus_add(struct acpi_device *device); 91static int acpi_video_bus_add(struct acpi_device *device);
91static int acpi_video_bus_remove(struct acpi_device *device, int type); 92static int acpi_video_bus_remove(struct acpi_device *device, int type);
92static int acpi_video_resume(struct acpi_device *device);
93static void acpi_video_bus_notify(struct acpi_device *device, u32 event); 93static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
94 94
95static const struct acpi_device_id video_device_ids[] = { 95static const struct acpi_device_id video_device_ids[] = {
@@ -105,7 +105,6 @@ static struct acpi_driver acpi_video_bus = {
105 .ops = { 105 .ops = {
106 .add = acpi_video_bus_add, 106 .add = acpi_video_bus_add,
107 .remove = acpi_video_bus_remove, 107 .remove = acpi_video_bus_remove,
108 .resume = acpi_video_resume,
109 .notify = acpi_video_bus_notify, 108 .notify = acpi_video_bus_notify,
110 }, 109 },
111}; 110};
@@ -160,6 +159,7 @@ struct acpi_video_bus {
160 struct proc_dir_entry *dir; 159 struct proc_dir_entry *dir;
161 struct input_dev *input; 160 struct input_dev *input;
162 char phys[32]; /* for input device */ 161 char phys[32]; /* for input device */
162 struct notifier_block pm_nb;
163}; 163};
164 164
165struct acpi_video_device_flags { 165struct acpi_video_device_flags {
@@ -1021,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
1021 if (IS_ERR(device->backlight)) 1021 if (IS_ERR(device->backlight))
1022 return; 1022 return;
1023 1023
1024 /*
1025 * Save current brightness level in case we have to restore it
1026 * before acpi_video_device_lcd_set_level() is called next time.
1027 */
1028 device->backlight->props.brightness =
1029 acpi_video_get_brightness(device->backlight);
1030
1024 result = sysfs_create_link(&device->backlight->dev.kobj, 1031 result = sysfs_create_link(&device->backlight->dev.kobj,
1025 &device->dev->dev.kobj, "device"); 1032 &device->dev->dev.kobj, "device");
1026 if (result) 1033 if (result)
@@ -2236,24 +2243,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
2236 return; 2243 return;
2237} 2244}
2238 2245
2239static int instance; 2246static int acpi_video_resume(struct notifier_block *nb,
2240static int acpi_video_resume(struct acpi_device *device) 2247 unsigned long val, void *ign)
2241{ 2248{
2242 struct acpi_video_bus *video; 2249 struct acpi_video_bus *video;
2243 struct acpi_video_device *video_device; 2250 struct acpi_video_device *video_device;
2244 int i; 2251 int i;
2245 2252
2246 if (!device || !acpi_driver_data(device)) 2253 switch (val) {
2247 return -EINVAL; 2254 case PM_HIBERNATION_PREPARE:
2255 case PM_SUSPEND_PREPARE:
2256 case PM_RESTORE_PREPARE:
2257 return NOTIFY_DONE;
2258 }
2248 2259
2249 video = acpi_driver_data(device); 2260 video = container_of(nb, struct acpi_video_bus, pm_nb);
2261
2262 dev_info(&video->device->dev, "Restoring backlight state\n");
2250 2263
2251 for (i = 0; i < video->attached_count; i++) { 2264 for (i = 0; i < video->attached_count; i++) {
2252 video_device = video->attached_array[i].bind_info; 2265 video_device = video->attached_array[i].bind_info;
2253 if (video_device && video_device->backlight) 2266 if (video_device && video_device->backlight)
2254 acpi_video_set_brightness(video_device->backlight); 2267 acpi_video_set_brightness(video_device->backlight);
2255 } 2268 }
2256 return AE_OK; 2269
2270 return NOTIFY_OK;
2257} 2271}
2258 2272
2259static acpi_status 2273static acpi_status
@@ -2277,6 +2291,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
2277 return AE_OK; 2291 return AE_OK;
2278} 2292}
2279 2293
2294static int instance;
2295
2280static int acpi_video_bus_add(struct acpi_device *device) 2296static int acpi_video_bus_add(struct acpi_device *device)
2281{ 2297{
2282 struct acpi_video_bus *video; 2298 struct acpi_video_bus *video;
@@ -2370,6 +2386,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
2370 video->flags.rom ? "yes" : "no", 2386 video->flags.rom ? "yes" : "no",
2371 video->flags.post ? "yes" : "no"); 2387 video->flags.post ? "yes" : "no");
2372 2388
2389 video->pm_nb.notifier_call = acpi_video_resume;
2390 video->pm_nb.priority = 0;
2391 register_pm_notifier(&video->pm_nb);
2392
2373 return 0; 2393 return 0;
2374 2394
2375 err_free_input_dev: 2395 err_free_input_dev:
@@ -2396,6 +2416,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
2396 2416
2397 video = acpi_driver_data(device); 2417 video = acpi_driver_data(device);
2398 2418
2419 unregister_pm_notifier(&video->pm_nb);
2420
2399 acpi_video_bus_stop_devices(video); 2421 acpi_video_bus_stop_devices(video);
2400 acpi_video_bus_put_devices(video); 2422 acpi_video_bus_put_devices(video);
2401 acpi_video_bus_remove_fs(device); 2423 acpi_video_bus_remove_fs(device);