Commit 53a62800 authored by Sean Young's avatar Sean Young Committed by Mauro Carvalho Chehab

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: default avatarMatthias Reichl <hias@horus.com>
Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent cb5bd057
...@@ -119,10 +119,14 @@ static void mce_kbd_rx_timeout(struct timer_list *t) ...@@ -119,10 +119,14 @@ static void mce_kbd_rx_timeout(struct timer_list *t)
{ {
struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout); struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout);
unsigned char maskcode; unsigned char maskcode;
unsigned long flags;
int i; int i;
dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n"); dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n");
spin_lock_irqsave(&raw->mce_kbd.keylock, flags);
if (time_is_before_eq_jiffies(raw->mce_kbd.rx_timeout.expires)) {
for (i = 0; i < 7; i++) { for (i = 0; i < 7; i++) {
maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
input_report_key(raw->mce_kbd.idev, maskcode, 0); input_report_key(raw->mce_kbd.idev, maskcode, 0);
...@@ -132,6 +136,8 @@ static void mce_kbd_rx_timeout(struct timer_list *t) ...@@ -132,6 +136,8 @@ static void mce_kbd_rx_timeout(struct timer_list *t)
input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
input_sync(raw->mce_kbd.idev); 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) static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
...@@ -327,6 +333,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) ...@@ -327,6 +333,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
scancode = data->body & 0xffffff; scancode = data->body & 0xffffff;
dev_dbg(&dev->dev, "keyboard data 0x%08x\n", dev_dbg(&dev->dev, "keyboard data 0x%08x\n",
data->body); data->body);
spin_lock(&data->keylock);
if (scancode) { if (scancode) {
delay = nsecs_to_jiffies(dev->timeout) + delay = nsecs_to_jiffies(dev->timeout) +
msecs_to_jiffies(100); msecs_to_jiffies(100);
...@@ -336,6 +343,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) ...@@ -336,6 +343,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
} }
/* Pass data to keyboard buffer parser */ /* Pass data to keyboard buffer parser */
ir_mce_kbd_process_keyboard_data(dev, scancode); ir_mce_kbd_process_keyboard_data(dev, scancode);
spin_unlock(&data->keylock);
lsc.rc_proto = RC_PROTO_MCIR2_KBD; lsc.rc_proto = RC_PROTO_MCIR2_KBD;
break; break;
case MCIR2_MOUSE_NBITS: case MCIR2_MOUSE_NBITS:
...@@ -400,6 +408,7 @@ static int ir_mce_kbd_register(struct rc_dev *dev) ...@@ -400,6 +408,7 @@ static int ir_mce_kbd_register(struct rc_dev *dev)
set_bit(MSC_SCAN, idev->mscbit); set_bit(MSC_SCAN, idev->mscbit);
timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0); timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0);
spin_lock_init(&mce_kbd->keylock);
input_set_drvdata(idev, mce_kbd); input_set_drvdata(idev, mce_kbd);
......
...@@ -105,6 +105,8 @@ struct ir_raw_event_ctrl { ...@@ -105,6 +105,8 @@ struct ir_raw_event_ctrl {
} sharp; } sharp;
struct mce_kbd_dec { struct mce_kbd_dec {
struct input_dev *idev; struct input_dev *idev;
/* locks key up timer */
spinlock_t keylock;
struct timer_list rx_timeout; struct timer_list rx_timeout;
char name[64]; char name[64];
char phys[64]; char phys[64];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment