diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-18 08:32:51 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-07-21 07:43:56 -0400 |
commit | 8ab58e8e7e097bae5fe39cbc67eb93a91f7134b7 (patch) | |
tree | 8fd45f56ceeb1857f9e0baaf0cb7ac0a926ac2a8 /drivers/acpi/video.c | |
parent | 9a3c4145af32125c5ee39c0272662b47307a8323 (diff) |
ACPI / video: Fix backlight taking 2 steps on a brightness up/down keypress
In various scenarious userspace will respond to brightness up/down keypresses
by increasing/decreasing the backlight brightness itself. If the kernel then
also changes the brightness this results in the brightness having changed 2
steps for a single keypress which is undesirable. See e.g. :
https://bugs.launchpad.net/gnome-settings-daemon/+bug/527157
http://askubuntu.com/questions/173921/why-does-my-thinkpad-brightness-control-skip-steps
This commit delays responding to brightness up/down keypresses by 100 ms and
if userspace in that time responds by changing the backlight itself, cancels
the kernels own handling of these keypresses, fixing the 2 steps issue.
Link: http://marc.info/?l=linux-kernel&m=140535721100839&w=2
[hdegoede@redhat.com: Move the delayed_work struct into struct
acpi_video_device instead of having it as a global]
[hdegoede@redhat.com: Keep brightness_switch_enabled as a boolean and always
delay the keypress handling]
Tested-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 350d52a8f781..bfe1fa2fb5d1 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -204,6 +204,8 @@ struct acpi_video_device { | |||
204 | struct acpi_video_device_flags flags; | 204 | struct acpi_video_device_flags flags; |
205 | struct acpi_video_device_cap cap; | 205 | struct acpi_video_device_cap cap; |
206 | struct list_head entry; | 206 | struct list_head entry; |
207 | struct delayed_work switch_brightness_work; | ||
208 | int switch_brightness_event; | ||
207 | struct acpi_video_bus *video; | 209 | struct acpi_video_bus *video; |
208 | struct acpi_device *dev; | 210 | struct acpi_device *dev; |
209 | struct acpi_video_device_brightness *brightness; | 211 | struct acpi_video_device_brightness *brightness; |
@@ -230,8 +232,7 @@ static int acpi_video_device_lcd_get_level_current( | |||
230 | unsigned long long *level, bool raw); | 232 | unsigned long long *level, bool raw); |
231 | static int acpi_video_get_next_level(struct acpi_video_device *device, | 233 | static int acpi_video_get_next_level(struct acpi_video_device *device, |
232 | u32 level_current, u32 event); | 234 | u32 level_current, u32 event); |
233 | static int acpi_video_switch_brightness(struct acpi_video_device *device, | 235 | static void acpi_video_switch_brightness(struct work_struct *work); |
234 | int event); | ||
235 | 236 | ||
236 | static bool acpi_video_use_native_backlight(void) | 237 | static bool acpi_video_use_native_backlight(void) |
237 | { | 238 | { |
@@ -275,6 +276,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd) | |||
275 | int request_level = bd->props.brightness + 2; | 276 | int request_level = bd->props.brightness + 2; |
276 | struct acpi_video_device *vd = bl_get_data(bd); | 277 | struct acpi_video_device *vd = bl_get_data(bd); |
277 | 278 | ||
279 | cancel_delayed_work(&vd->switch_brightness_work); | ||
278 | return acpi_video_device_lcd_set_level(vd, | 280 | return acpi_video_device_lcd_set_level(vd, |
279 | vd->brightness->levels[request_level]); | 281 | vd->brightness->levels[request_level]); |
280 | } | 282 | } |
@@ -1188,6 +1190,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device, | |||
1188 | data->device_id = device_id; | 1190 | data->device_id = device_id; |
1189 | data->video = video; | 1191 | data->video = video; |
1190 | data->dev = device; | 1192 | data->dev = device; |
1193 | INIT_DELAYED_WORK(&data->switch_brightness_work, | ||
1194 | acpi_video_switch_brightness); | ||
1191 | 1195 | ||
1192 | attribute = acpi_video_get_device_attr(video, device_id); | 1196 | attribute = acpi_video_get_device_attr(video, device_id); |
1193 | 1197 | ||
@@ -1410,15 +1414,18 @@ acpi_video_get_next_level(struct acpi_video_device *device, | |||
1410 | } | 1414 | } |
1411 | } | 1415 | } |
1412 | 1416 | ||
1413 | static int | 1417 | static void |
1414 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) | 1418 | acpi_video_switch_brightness(struct work_struct *work) |
1415 | { | 1419 | { |
1420 | struct acpi_video_device *device = container_of(to_delayed_work(work), | ||
1421 | struct acpi_video_device, switch_brightness_work); | ||
1416 | unsigned long long level_current, level_next; | 1422 | unsigned long long level_current, level_next; |
1423 | int event = device->switch_brightness_event; | ||
1417 | int result = -EINVAL; | 1424 | int result = -EINVAL; |
1418 | 1425 | ||
1419 | /* no warning message if acpi_backlight=vendor or a quirk is used */ | 1426 | /* no warning message if acpi_backlight=vendor or a quirk is used */ |
1420 | if (!acpi_video_verify_backlight_support()) | 1427 | if (!acpi_video_verify_backlight_support()) |
1421 | return 0; | 1428 | return; |
1422 | 1429 | ||
1423 | if (!device->brightness) | 1430 | if (!device->brightness) |
1424 | goto out; | 1431 | goto out; |
@@ -1440,8 +1447,6 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event) | |||
1440 | out: | 1447 | out: |
1441 | if (result) | 1448 | if (result) |
1442 | printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); | 1449 | printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); |
1443 | |||
1444 | return result; | ||
1445 | } | 1450 | } |
1446 | 1451 | ||
1447 | int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, | 1452 | int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, |
@@ -1609,6 +1614,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) | |||
1609 | return; | 1614 | return; |
1610 | } | 1615 | } |
1611 | 1616 | ||
1617 | static void brightness_switch_event(struct acpi_video_device *video_device, | ||
1618 | u32 event) | ||
1619 | { | ||
1620 | if (!brightness_switch_enabled) | ||
1621 | return; | ||
1622 | |||
1623 | video_device->switch_brightness_event = event; | ||
1624 | schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10); | ||
1625 | } | ||
1626 | |||
1612 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | 1627 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) |
1613 | { | 1628 | { |
1614 | struct acpi_video_device *video_device = data; | 1629 | struct acpi_video_device *video_device = data; |
@@ -1626,28 +1641,23 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | |||
1626 | 1641 | ||
1627 | switch (event) { | 1642 | switch (event) { |
1628 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ | 1643 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ |
1629 | if (brightness_switch_enabled) | 1644 | brightness_switch_event(video_device, event); |
1630 | acpi_video_switch_brightness(video_device, event); | ||
1631 | keycode = KEY_BRIGHTNESS_CYCLE; | 1645 | keycode = KEY_BRIGHTNESS_CYCLE; |
1632 | break; | 1646 | break; |
1633 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ | 1647 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ |
1634 | if (brightness_switch_enabled) | 1648 | brightness_switch_event(video_device, event); |
1635 | acpi_video_switch_brightness(video_device, event); | ||
1636 | keycode = KEY_BRIGHTNESSUP; | 1649 | keycode = KEY_BRIGHTNESSUP; |
1637 | break; | 1650 | break; |
1638 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ | 1651 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ |
1639 | if (brightness_switch_enabled) | 1652 | brightness_switch_event(video_device, event); |
1640 | acpi_video_switch_brightness(video_device, event); | ||
1641 | keycode = KEY_BRIGHTNESSDOWN; | 1653 | keycode = KEY_BRIGHTNESSDOWN; |
1642 | break; | 1654 | break; |
1643 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ | 1655 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ |
1644 | if (brightness_switch_enabled) | 1656 | brightness_switch_event(video_device, event); |
1645 | acpi_video_switch_brightness(video_device, event); | ||
1646 | keycode = KEY_BRIGHTNESS_ZERO; | 1657 | keycode = KEY_BRIGHTNESS_ZERO; |
1647 | break; | 1658 | break; |
1648 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ | 1659 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ |
1649 | if (brightness_switch_enabled) | 1660 | brightness_switch_event(video_device, event); |
1650 | acpi_video_switch_brightness(video_device, event); | ||
1651 | keycode = KEY_DISPLAY_OFF; | 1661 | keycode = KEY_DISPLAY_OFF; |
1652 | break; | 1662 | break; |
1653 | default: | 1663 | default: |