summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2018-04-12 16:28:39 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2018-04-20 09:20:45 -0400
commit53a62800efb2f0ebc1972cab242461ae8c57bfd4 (patch)
tree1b5e63dc0512e83a27e907582e69ac8bf2c952cc
parentcb5bd0575c41ac34c62a7784da7232d1c90e6eca (diff)
downloadop-kernel-dev-53a62800efb2f0ebc1972cab242461ae8c57bfd4.zip
op-kernel-dev-53a62800efb2f0ebc1972cab242461ae8c57bfd4.tar.gz
media: rc: mce_kbd decoder: fix race condition
The MCE keyboard sends both key down and key up events. We have a timeout handler mce_kbd_rx_timeout() in case the keyup event is never received; however, this may race with new key down events from occurring. The race is that key down scancode arrives and key down events are generated. The timeout handler races this and generates key up events straight afterwards. Since the keyboard generates scancodes every 100ms, most likely the keys will be repeated 100ms later, and now we have new key down events and the user sees duplicate key presses. Reported-by: Matthias Reichl <hias@horus.com> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c23
-rw-r--r--drivers/media/rc/rc-core-priv.h2
2 files changed, 18 insertions, 7 deletions
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 2fc7871..9574c3d 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -119,19 +119,25 @@ static void mce_kbd_rx_timeout(struct timer_list *t)
{
struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout);
unsigned char maskcode;
+ unsigned long flags;
int i;
dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n");
- for (i = 0; i < 7; i++) {
- maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
- input_report_key(raw->mce_kbd.idev, maskcode, 0);
- }
+ spin_lock_irqsave(&raw->mce_kbd.keylock, flags);
- for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
- input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
+ if (time_is_before_eq_jiffies(raw->mce_kbd.rx_timeout.expires)) {
+ for (i = 0; i < 7; i++) {
+ maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
+ input_report_key(raw->mce_kbd.idev, maskcode, 0);
+ }
- input_sync(raw->mce_kbd.idev);
+ for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
+ input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
+
+ input_sync(raw->mce_kbd.idev);
+ }
+ spin_unlock_irqrestore(&raw->mce_kbd.keylock, flags);
}
static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
@@ -327,6 +333,7 @@ again:
scancode = data->body & 0xffffff;
dev_dbg(&dev->dev, "keyboard data 0x%08x\n",
data->body);
+ spin_lock(&data->keylock);
if (scancode) {
delay = nsecs_to_jiffies(dev->timeout) +
msecs_to_jiffies(100);
@@ -336,6 +343,7 @@ again:
}
/* Pass data to keyboard buffer parser */
ir_mce_kbd_process_keyboard_data(dev, scancode);
+ spin_unlock(&data->keylock);
lsc.rc_proto = RC_PROTO_MCIR2_KBD;
break;
case MCIR2_MOUSE_NBITS:
@@ -400,6 +408,7 @@ static int ir_mce_kbd_register(struct rc_dev *dev)
set_bit(MSC_SCAN, idev->mscbit);
timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0);
+ spin_lock_init(&mce_kbd->keylock);
input_set_drvdata(idev, mce_kbd);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index f785513..07ba77f 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -105,6 +105,8 @@ struct ir_raw_event_ctrl {
} sharp;
struct mce_kbd_dec {
struct input_dev *idev;
+ /* locks key up timer */
+ spinlock_t keylock;
struct timer_list rx_timeout;
char name[64];
char phys[64];
OpenPOWER on IntegriCloud