aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-07-18 08:32:51 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-21 07:43:56 -0400
commit8ab58e8e7e097bae5fe39cbc67eb93a91f7134b7 (patch)
tree8fd45f56ceeb1857f9e0baaf0cb7ac0a926ac2a8 /drivers/acpi/video.c
parent9a3c4145af32125c5ee39c0272662b47307a8323 (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.c44
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);
231static int acpi_video_get_next_level(struct acpi_video_device *device, 233static int acpi_video_get_next_level(struct acpi_video_device *device,
232 u32 level_current, u32 event); 234 u32 level_current, u32 event);
233static int acpi_video_switch_brightness(struct acpi_video_device *device, 235static void acpi_video_switch_brightness(struct work_struct *work);
234 int event);
235 236
236static bool acpi_video_use_native_backlight(void) 237static 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
1413static int 1417static void
1414acpi_video_switch_brightness(struct acpi_video_device *device, int event) 1418acpi_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)
1440out: 1447out:
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
1447int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, 1452int 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
1617static 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
1612static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) 1627static 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: