Commit 693508df authored by Jarod Wilson's avatar Jarod Wilson Committed by Mauro Carvalho Chehab

V4L/DVB: IR/imon: protect ictx's kc and last_keycode w/spinlock

Lest we get our keycodes wrong... Thus far, in practice, I've not found
it to actually matter, but its one of the issues raised in
https://bugzilla.kernel.org/show_bug.cgi?id=16351 that wasn't addressed
by converting to using native IR keydown/up functions.
Signed-off-by: default avatarJarod Wilson <jarod@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent eaf2bcc9
/* /*
* imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
* *
* Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com> * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com>
* Portions based on the original lirc_imon driver, * Portions based on the original lirc_imon driver,
* Copyright(C) 2004 Venky Raju(dev@venky.ws) * Copyright(C) 2004 Venky Raju(dev@venky.ws)
* *
...@@ -125,6 +125,7 @@ struct imon_context { ...@@ -125,6 +125,7 @@ struct imon_context {
struct input_dev *idev; /* input device for panel & IR mouse */ struct input_dev *idev; /* input device for panel & IR mouse */
struct input_dev *touch; /* input device for touchscreen */ struct input_dev *touch; /* input device for touchscreen */
spinlock_t kc_lock; /* make sure we get keycodes right */
u32 kc; /* current input keycode */ u32 kc; /* current input keycode */
u32 last_keycode; /* last reported input keycode */ u32 last_keycode; /* last reported input keycode */
u32 rc_scancode; /* the computed remote scancode */ u32 rc_scancode; /* the computed remote scancode */
...@@ -1210,6 +1211,9 @@ static bool imon_mouse_event(struct imon_context *ictx, ...@@ -1210,6 +1211,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
u8 right_shift = 1; u8 right_shift = 1;
bool mouse_input = true; bool mouse_input = true;
int dir = 0; int dir = 0;
unsigned long flags;
spin_lock_irqsave(&ictx->kc_lock, flags);
/* newer iMON device PAD or mouse button */ /* newer iMON device PAD or mouse button */
if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
...@@ -1241,6 +1245,8 @@ static bool imon_mouse_event(struct imon_context *ictx, ...@@ -1241,6 +1245,8 @@ static bool imon_mouse_event(struct imon_context *ictx,
} else } else
mouse_input = false; mouse_input = false;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
if (mouse_input) { if (mouse_input) {
dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
...@@ -1255,7 +1261,9 @@ static bool imon_mouse_event(struct imon_context *ictx, ...@@ -1255,7 +1261,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
buf[1] >> right_shift & 0x1); buf[1] >> right_shift & 0x1);
} }
input_sync(ictx->idev); input_sync(ictx->idev);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc; ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
} }
return mouse_input; return mouse_input;
...@@ -1278,6 +1286,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) ...@@ -1278,6 +1286,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
char rel_x = 0x00, rel_y = 0x00; char rel_x = 0x00, rel_y = 0x00;
u16 timeout, threshold; u16 timeout, threshold;
u32 scancode = KEY_RESERVED; u32 scancode = KEY_RESERVED;
unsigned long flags;
/* /*
* The imon directional pad functions more like a touchpad. Bytes 3 & 4 * The imon directional pad functions more like a touchpad. Bytes 3 & 4
...@@ -1301,7 +1310,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) ...@@ -1301,7 +1310,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
dir = stabilize((int)rel_x, (int)rel_y, dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold); timeout, threshold);
if (!dir) { if (!dir) {
spin_lock_irqsave(&ictx->kc_lock,
flags);
ictx->kc = KEY_UNKNOWN; ictx->kc = KEY_UNKNOWN;
spin_unlock_irqrestore(&ictx->kc_lock,
flags);
return; return;
} }
buf[2] = dir & 0xFF; buf[2] = dir & 0xFF;
...@@ -1363,7 +1376,9 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) ...@@ -1363,7 +1376,9 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
dir = stabilize((int)rel_x, (int)rel_y, dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold); timeout, threshold);
if (!dir) { if (!dir) {
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->kc = KEY_UNKNOWN; ictx->kc = KEY_UNKNOWN;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return; return;
} }
buf[2] = dir & 0xFF; buf[2] = dir & 0xFF;
...@@ -1392,8 +1407,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) ...@@ -1392,8 +1407,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
} }
} }
if (scancode) if (scancode) {
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->kc = imon_remote_key_lookup(ictx, scancode); ictx->kc = imon_remote_key_lookup(ictx, scancode);
spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
} }
/** /**
...@@ -1405,6 +1423,9 @@ static int imon_parse_press_type(struct imon_context *ictx, ...@@ -1405,6 +1423,9 @@ static int imon_parse_press_type(struct imon_context *ictx,
unsigned char *buf, u8 ktype) unsigned char *buf, u8 ktype)
{ {
int press_type = 0; int press_type = 0;
unsigned long flags;
spin_lock_irqsave(&ictx->kc_lock, flags);
/* key release of 0x02XXXXXX key */ /* key release of 0x02XXXXXX key */
if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
...@@ -1437,6 +1458,8 @@ static int imon_parse_press_type(struct imon_context *ictx, ...@@ -1437,6 +1458,8 @@ static int imon_parse_press_type(struct imon_context *ictx,
else else
press_type = 1; press_type = 1;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return press_type; return press_type;
} }
...@@ -1449,6 +1472,7 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1449,6 +1472,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
int len = urb->actual_length; int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer; unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev; struct device *dev = ictx->dev;
unsigned long flags;
u32 kc; u32 kc;
bool norelease = false; bool norelease = false;
int i; int i;
...@@ -1486,6 +1510,7 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1486,6 +1510,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
} }
} }
spin_lock_irqsave(&ictx->kc_lock, flags);
/* keyboard/mouse mode toggle button */ /* keyboard/mouse mode toggle button */
if (kc == KEY_KEYBOARD && !ictx->release_code) { if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc; ictx->last_keycode = kc;
...@@ -1493,6 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1493,6 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
dev_dbg(dev, "toggling to %s mode\n", dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard"); ictx->pad_mouse ? "mouse" : "keyboard");
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return; return;
} else { } else {
ictx->pad_mouse = 0; ictx->pad_mouse = 0;
...@@ -1501,6 +1527,7 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1501,6 +1527,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
} }
ictx->kc = kc; ictx->kc = kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
/* send touchscreen events through input subsystem if touchpad data */ /* send touchscreen events through input subsystem if touchpad data */
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
...@@ -1534,8 +1561,10 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1534,8 +1561,10 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type < 0) if (press_type < 0)
goto not_input_data; goto not_input_data;
spin_lock_irqsave(&ictx->kc_lock, flags);
if (ictx->kc == KEY_UNKNOWN) if (ictx->kc == KEY_UNKNOWN)
goto unknown_key; goto unknown_key;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
if (ktype != IMON_KEY_PANEL) { if (ktype != IMON_KEY_PANEL) {
if (press_type == 0) if (press_type == 0)
...@@ -1543,33 +1572,43 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1543,33 +1572,43 @@ static void imon_incoming_packet(struct imon_context *ictx,
else { else {
ir_keydown(ictx->rdev, ictx->rc_scancode, ir_keydown(ictx->rdev, ictx->rc_scancode,
ictx->rc_toggle); ictx->rc_toggle);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc; ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
} }
return; return;
} }
/* Only panel type events left to process now */ /* Only panel type events left to process now */
spin_lock_irqsave(&ictx->kc_lock, flags);
/* KEY_MUTE repeats from knob need to be suppressed */ /* KEY_MUTE repeats from knob need to be suppressed */
if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
do_gettimeofday(&t); do_gettimeofday(&t);
msec = tv2int(&t, &prev_time); msec = tv2int(&t, &prev_time);
prev_time = t; prev_time = t;
if (msec < idev->rep[REP_DELAY]) if (msec < idev->rep[REP_DELAY]) {
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return; return;
}
} }
kc = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
input_report_key(idev, ictx->kc, press_type); input_report_key(idev, kc, press_type);
input_sync(idev); input_sync(idev);
/* panel keys don't generate a release */ /* panel keys don't generate a release */
input_report_key(idev, ictx->kc, 0); input_report_key(idev, kc, 0);
input_sync(idev); input_sync(idev);
ictx->last_keycode = ictx->kc; ictx->last_keycode = kc;
return; return;
unknown_key: unknown_key:
spin_unlock_irqrestore(&ictx->kc_lock, flags);
dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
(long long)scancode); (long long)scancode);
return; return;
...@@ -1927,6 +1966,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ...@@ -1927,6 +1966,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
} }
mutex_init(&ictx->lock); mutex_init(&ictx->lock);
spin_lock_init(&ictx->kc_lock);
mutex_lock(&ictx->lock); mutex_lock(&ictx->lock);
......
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