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); |
