diff options
author | Gabriele Mazzotta <gabriele.mzt@gmail.com> | 2016-05-24 16:53:08 -0400 |
---|---|---|
committer | Darren Hart <dvhart@linux.intel.com> | 2016-05-27 14:47:56 -0400 |
commit | ff8651237f39cea60dc89b2d9f25d9ede3fc82c0 (patch) | |
tree | 1a67e4a17f92560bc0dad1eff332275d73bc3183 | |
parent | afcedebc6a094224973534f43b396bbbf33fe44e (diff) |
dell-rbtn: Ignore ACPI notifications if device is suspended
Some BIOSes unconditionally send an ACPI notification to RBTN when the
system is resuming from suspend. This makes dell-rbtn send an input
event to userspace as if a function key was pressed. Prevent this by
ignoring all the notifications received while the device is suspended.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=106031
Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
Tested-by: Alex Hung <alex.hung@canonical.com>
Reviewed-by: Pali Rohár <pali.rohar@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
-rw-r--r-- | drivers/platform/x86/dell-rbtn.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c index b51a2008d782..dcd9f40a4b18 100644 --- a/drivers/platform/x86/dell-rbtn.c +++ b/drivers/platform/x86/dell-rbtn.c | |||
@@ -28,6 +28,7 @@ struct rbtn_data { | |||
28 | enum rbtn_type type; | 28 | enum rbtn_type type; |
29 | struct rfkill *rfkill; | 29 | struct rfkill *rfkill; |
30 | struct input_dev *input_dev; | 30 | struct input_dev *input_dev; |
31 | bool suspended; | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | 34 | ||
@@ -235,9 +236,55 @@ static const struct acpi_device_id rbtn_ids[] = { | |||
235 | { "", 0 }, | 236 | { "", 0 }, |
236 | }; | 237 | }; |
237 | 238 | ||
239 | #ifdef CONFIG_PM_SLEEP | ||
240 | static void ACPI_SYSTEM_XFACE rbtn_clear_suspended_flag(void *context) | ||
241 | { | ||
242 | struct rbtn_data *rbtn_data = context; | ||
243 | |||
244 | rbtn_data->suspended = false; | ||
245 | } | ||
246 | |||
247 | static int rbtn_suspend(struct device *dev) | ||
248 | { | ||
249 | struct acpi_device *device = to_acpi_device(dev); | ||
250 | struct rbtn_data *rbtn_data = acpi_driver_data(device); | ||
251 | |||
252 | rbtn_data->suspended = true; | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int rbtn_resume(struct device *dev) | ||
258 | { | ||
259 | struct acpi_device *device = to_acpi_device(dev); | ||
260 | struct rbtn_data *rbtn_data = acpi_driver_data(device); | ||
261 | acpi_status status; | ||
262 | |||
263 | /* | ||
264 | * Upon resume, some BIOSes send an ACPI notification thet triggers | ||
265 | * an unwanted input event. In order to ignore it, we use a flag | ||
266 | * that we set at suspend and clear once we have received the extra | ||
267 | * ACPI notification. Since ACPI notifications are delivered | ||
268 | * asynchronously to drivers, we clear the flag from the workqueue | ||
269 | * used to deliver the notifications. This should be enough | ||
270 | * to have the flag cleared only after we received the extra | ||
271 | * notification, if any. | ||
272 | */ | ||
273 | status = acpi_os_execute(OSL_NOTIFY_HANDLER, | ||
274 | rbtn_clear_suspended_flag, rbtn_data); | ||
275 | if (ACPI_FAILURE(status)) | ||
276 | rbtn_clear_suspended_flag(rbtn_data); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | #endif | ||
281 | |||
282 | static SIMPLE_DEV_PM_OPS(rbtn_pm_ops, rbtn_suspend, rbtn_resume); | ||
283 | |||
238 | static struct acpi_driver rbtn_driver = { | 284 | static struct acpi_driver rbtn_driver = { |
239 | .name = "dell-rbtn", | 285 | .name = "dell-rbtn", |
240 | .ids = rbtn_ids, | 286 | .ids = rbtn_ids, |
287 | .drv.pm = &rbtn_pm_ops, | ||
241 | .ops = { | 288 | .ops = { |
242 | .add = rbtn_add, | 289 | .add = rbtn_add, |
243 | .remove = rbtn_remove, | 290 | .remove = rbtn_remove, |
@@ -399,6 +446,15 @@ static void rbtn_notify(struct acpi_device *device, u32 event) | |||
399 | { | 446 | { |
400 | struct rbtn_data *rbtn_data = device->driver_data; | 447 | struct rbtn_data *rbtn_data = device->driver_data; |
401 | 448 | ||
449 | /* | ||
450 | * Some BIOSes send a notification at resume. | ||
451 | * Ignore it to prevent unwanted input events. | ||
452 | */ | ||
453 | if (rbtn_data->suspended) { | ||
454 | dev_dbg(&device->dev, "ACPI notification ignored\n"); | ||
455 | return; | ||
456 | } | ||
457 | |||
402 | if (event != 0x80) { | 458 | if (event != 0x80) { |
403 | dev_info(&device->dev, "Received unknown event (0x%x)\n", | 459 | dev_info(&device->dev, "Received unknown event (0x%x)\n", |
404 | event); | 460 | event); |