diff options
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 68 |
1 files changed, 47 insertions, 21 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index cbe6f3924a10..a0c93b321482 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -39,10 +39,12 @@ | |||
39 | #include <linux/sort.h> | 39 | #include <linux/sort.h> |
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #include <linux/pci_ids.h> | 41 | #include <linux/pci_ids.h> |
42 | #include <linux/slab.h> | ||
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
43 | #include <linux/dmi.h> | 44 | #include <linux/dmi.h> |
44 | #include <acpi/acpi_bus.h> | 45 | #include <acpi/acpi_bus.h> |
45 | #include <acpi/acpi_drivers.h> | 46 | #include <acpi/acpi_drivers.h> |
47 | #include <linux/suspend.h> | ||
46 | 48 | ||
47 | #define PREFIX "ACPI: " | 49 | #define PREFIX "ACPI: " |
48 | 50 | ||
@@ -88,7 +90,6 @@ module_param(allow_duplicates, bool, 0644); | |||
88 | static int register_count = 0; | 90 | static int register_count = 0; |
89 | static int acpi_video_bus_add(struct acpi_device *device); | 91 | static int acpi_video_bus_add(struct acpi_device *device); |
90 | static int acpi_video_bus_remove(struct acpi_device *device, int type); | 92 | static int acpi_video_bus_remove(struct acpi_device *device, int type); |
91 | static int acpi_video_resume(struct acpi_device *device); | ||
92 | static void acpi_video_bus_notify(struct acpi_device *device, u32 event); | 93 | static void acpi_video_bus_notify(struct acpi_device *device, u32 event); |
93 | 94 | ||
94 | static const struct acpi_device_id video_device_ids[] = { | 95 | static const struct acpi_device_id video_device_ids[] = { |
@@ -104,7 +105,6 @@ static struct acpi_driver acpi_video_bus = { | |||
104 | .ops = { | 105 | .ops = { |
105 | .add = acpi_video_bus_add, | 106 | .add = acpi_video_bus_add, |
106 | .remove = acpi_video_bus_remove, | 107 | .remove = acpi_video_bus_remove, |
107 | .resume = acpi_video_resume, | ||
108 | .notify = acpi_video_bus_notify, | 108 | .notify = acpi_video_bus_notify, |
109 | }, | 109 | }, |
110 | }; | 110 | }; |
@@ -159,6 +159,7 @@ struct acpi_video_bus { | |||
159 | struct proc_dir_entry *dir; | 159 | struct proc_dir_entry *dir; |
160 | struct input_dev *input; | 160 | struct input_dev *input; |
161 | char phys[32]; /* for input device */ | 161 | char phys[32]; /* for input device */ |
162 | struct notifier_block pm_nb; | ||
162 | }; | 163 | }; |
163 | 164 | ||
164 | struct acpi_video_device_flags { | 165 | struct acpi_video_device_flags { |
@@ -1020,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
1020 | if (IS_ERR(device->backlight)) | 1021 | if (IS_ERR(device->backlight)) |
1021 | return; | 1022 | return; |
1022 | 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 | |||
1023 | result = sysfs_create_link(&device->backlight->dev.kobj, | 1031 | result = sysfs_create_link(&device->backlight->dev.kobj, |
1024 | &device->dev->dev.kobj, "device"); | 1032 | &device->dev->dev.kobj, "device"); |
1025 | if (result) | 1033 | if (result) |
@@ -2122,7 +2130,7 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) | |||
2122 | { | 2130 | { |
2123 | struct acpi_video_bus *video = acpi_driver_data(device); | 2131 | struct acpi_video_bus *video = acpi_driver_data(device); |
2124 | struct input_dev *input; | 2132 | struct input_dev *input; |
2125 | int keycode; | 2133 | int keycode = 0; |
2126 | 2134 | ||
2127 | if (!video) | 2135 | if (!video) |
2128 | return; | 2136 | return; |
@@ -2158,17 +2166,19 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) | |||
2158 | break; | 2166 | break; |
2159 | 2167 | ||
2160 | default: | 2168 | default: |
2161 | keycode = KEY_UNKNOWN; | ||
2162 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 2169 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
2163 | "Unsupported event [0x%x]\n", event)); | 2170 | "Unsupported event [0x%x]\n", event)); |
2164 | break; | 2171 | break; |
2165 | } | 2172 | } |
2166 | 2173 | ||
2167 | acpi_notifier_call_chain(device, event, 0); | 2174 | acpi_notifier_call_chain(device, event, 0); |
2168 | input_report_key(input, keycode, 1); | 2175 | |
2169 | input_sync(input); | 2176 | if (keycode) { |
2170 | input_report_key(input, keycode, 0); | 2177 | input_report_key(input, keycode, 1); |
2171 | input_sync(input); | 2178 | input_sync(input); |
2179 | input_report_key(input, keycode, 0); | ||
2180 | input_sync(input); | ||
2181 | } | ||
2172 | 2182 | ||
2173 | return; | 2183 | return; |
2174 | } | 2184 | } |
@@ -2179,7 +2189,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | |||
2179 | struct acpi_device *device = NULL; | 2189 | struct acpi_device *device = NULL; |
2180 | struct acpi_video_bus *bus; | 2190 | struct acpi_video_bus *bus; |
2181 | struct input_dev *input; | 2191 | struct input_dev *input; |
2182 | int keycode; | 2192 | int keycode = 0; |
2183 | 2193 | ||
2184 | if (!video_device) | 2194 | if (!video_device) |
2185 | return; | 2195 | return; |
@@ -2220,39 +2230,48 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | |||
2220 | keycode = KEY_DISPLAY_OFF; | 2230 | keycode = KEY_DISPLAY_OFF; |
2221 | break; | 2231 | break; |
2222 | default: | 2232 | default: |
2223 | keycode = KEY_UNKNOWN; | ||
2224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 2233 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
2225 | "Unsupported event [0x%x]\n", event)); | 2234 | "Unsupported event [0x%x]\n", event)); |
2226 | break; | 2235 | break; |
2227 | } | 2236 | } |
2228 | 2237 | ||
2229 | acpi_notifier_call_chain(device, event, 0); | 2238 | acpi_notifier_call_chain(device, event, 0); |
2230 | input_report_key(input, keycode, 1); | 2239 | |
2231 | input_sync(input); | 2240 | if (keycode) { |
2232 | input_report_key(input, keycode, 0); | 2241 | input_report_key(input, keycode, 1); |
2233 | input_sync(input); | 2242 | input_sync(input); |
2243 | input_report_key(input, keycode, 0); | ||
2244 | input_sync(input); | ||
2245 | } | ||
2234 | 2246 | ||
2235 | return; | 2247 | return; |
2236 | } | 2248 | } |
2237 | 2249 | ||
2238 | static int instance; | 2250 | static int acpi_video_resume(struct notifier_block *nb, |
2239 | static int acpi_video_resume(struct acpi_device *device) | 2251 | unsigned long val, void *ign) |
2240 | { | 2252 | { |
2241 | struct acpi_video_bus *video; | 2253 | struct acpi_video_bus *video; |
2242 | struct acpi_video_device *video_device; | 2254 | struct acpi_video_device *video_device; |
2243 | int i; | 2255 | int i; |
2244 | 2256 | ||
2245 | if (!device || !acpi_driver_data(device)) | 2257 | switch (val) { |
2246 | return -EINVAL; | 2258 | case PM_HIBERNATION_PREPARE: |
2259 | case PM_SUSPEND_PREPARE: | ||
2260 | case PM_RESTORE_PREPARE: | ||
2261 | return NOTIFY_DONE; | ||
2262 | } | ||
2247 | 2263 | ||
2248 | video = acpi_driver_data(device); | 2264 | video = container_of(nb, struct acpi_video_bus, pm_nb); |
2265 | |||
2266 | dev_info(&video->device->dev, "Restoring backlight state\n"); | ||
2249 | 2267 | ||
2250 | for (i = 0; i < video->attached_count; i++) { | 2268 | for (i = 0; i < video->attached_count; i++) { |
2251 | video_device = video->attached_array[i].bind_info; | 2269 | video_device = video->attached_array[i].bind_info; |
2252 | if (video_device && video_device->backlight) | 2270 | if (video_device && video_device->backlight) |
2253 | acpi_video_set_brightness(video_device->backlight); | 2271 | acpi_video_set_brightness(video_device->backlight); |
2254 | } | 2272 | } |
2255 | return AE_OK; | 2273 | |
2274 | return NOTIFY_OK; | ||
2256 | } | 2275 | } |
2257 | 2276 | ||
2258 | static acpi_status | 2277 | static acpi_status |
@@ -2276,6 +2295,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, | |||
2276 | return AE_OK; | 2295 | return AE_OK; |
2277 | } | 2296 | } |
2278 | 2297 | ||
2298 | static int instance; | ||
2299 | |||
2279 | static int acpi_video_bus_add(struct acpi_device *device) | 2300 | static int acpi_video_bus_add(struct acpi_device *device) |
2280 | { | 2301 | { |
2281 | struct acpi_video_bus *video; | 2302 | struct acpi_video_bus *video; |
@@ -2357,7 +2378,6 @@ static int acpi_video_bus_add(struct acpi_device *device) | |||
2357 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); | 2378 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); |
2358 | set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); | 2379 | set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); |
2359 | set_bit(KEY_DISPLAY_OFF, input->keybit); | 2380 | set_bit(KEY_DISPLAY_OFF, input->keybit); |
2360 | set_bit(KEY_UNKNOWN, input->keybit); | ||
2361 | 2381 | ||
2362 | error = input_register_device(input); | 2382 | error = input_register_device(input); |
2363 | if (error) | 2383 | if (error) |
@@ -2369,6 +2389,10 @@ static int acpi_video_bus_add(struct acpi_device *device) | |||
2369 | video->flags.rom ? "yes" : "no", | 2389 | video->flags.rom ? "yes" : "no", |
2370 | video->flags.post ? "yes" : "no"); | 2390 | video->flags.post ? "yes" : "no"); |
2371 | 2391 | ||
2392 | video->pm_nb.notifier_call = acpi_video_resume; | ||
2393 | video->pm_nb.priority = 0; | ||
2394 | register_pm_notifier(&video->pm_nb); | ||
2395 | |||
2372 | return 0; | 2396 | return 0; |
2373 | 2397 | ||
2374 | err_free_input_dev: | 2398 | err_free_input_dev: |
@@ -2395,6 +2419,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2395 | 2419 | ||
2396 | video = acpi_driver_data(device); | 2420 | video = acpi_driver_data(device); |
2397 | 2421 | ||
2422 | unregister_pm_notifier(&video->pm_nb); | ||
2423 | |||
2398 | acpi_video_bus_stop_devices(video); | 2424 | acpi_video_bus_stop_devices(video); |
2399 | acpi_video_bus_put_devices(video); | 2425 | acpi_video_bus_put_devices(video); |
2400 | acpi_video_bus_remove_fs(device); | 2426 | acpi_video_bus_remove_fs(device); |