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: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jarod Wilson 2010-09-15 15:56:03 -03:00 committed by Mauro Carvalho Chehab
parent eaf2bcc923
commit 693508df98
1 changed files with 46 additions and 6 deletions

View File

@ -1,7 +1,7 @@
/*
* 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,
* Copyright(C) 2004 Venky Raju(dev@venky.ws)
*
@ -125,6 +125,7 @@ struct imon_context {
struct input_dev *idev; /* input device for panel & IR mouse */
struct input_dev *touch; /* input device for touchscreen */
spinlock_t kc_lock; /* make sure we get keycodes right */
u32 kc; /* current input keycode */
u32 last_keycode; /* last reported input keycode */
u32 rc_scancode; /* the computed remote scancode */
@ -1210,6 +1211,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
u8 right_shift = 1;
bool mouse_input = true;
int dir = 0;
unsigned long flags;
spin_lock_irqsave(&ictx->kc_lock, flags);
/* newer iMON device PAD or mouse button */
if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
@ -1241,6 +1245,8 @@ static bool imon_mouse_event(struct imon_context *ictx,
} else
mouse_input = false;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
if (mouse_input) {
dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
@ -1255,7 +1261,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
buf[1] >> right_shift & 0x1);
}
input_sync(ictx->idev);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
return mouse_input;
@ -1278,6 +1286,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
char rel_x = 0x00, rel_y = 0x00;
u16 timeout, threshold;
u32 scancode = KEY_RESERVED;
unsigned long flags;
/*
* 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)
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
spin_lock_irqsave(&ictx->kc_lock,
flags);
ictx->kc = KEY_UNKNOWN;
spin_unlock_irqrestore(&ictx->kc_lock,
flags);
return;
}
buf[2] = dir & 0xFF;
@ -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,
timeout, threshold);
if (!dir) {
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->kc = KEY_UNKNOWN;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
}
buf[2] = dir & 0xFF;
@ -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);
spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
}
/**
@ -1405,6 +1423,9 @@ static int imon_parse_press_type(struct imon_context *ictx,
unsigned char *buf, u8 ktype)
{
int press_type = 0;
unsigned long flags;
spin_lock_irqsave(&ictx->kc_lock, flags);
/* key release of 0x02XXXXXX key */
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,
else
press_type = 1;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return press_type;
}
@ -1449,6 +1472,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev;
unsigned long flags;
u32 kc;
bool norelease = false;
int i;
@ -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 */
if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc;
@ -1493,6 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard");
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
} else {
ictx->pad_mouse = 0;
@ -1501,6 +1527,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
}
ictx->kc = kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
/* send touchscreen events through input subsystem if touchpad data */
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
@ -1534,8 +1561,10 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type < 0)
goto not_input_data;
spin_lock_irqsave(&ictx->kc_lock, flags);
if (ictx->kc == KEY_UNKNOWN)
goto unknown_key;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
if (ktype != IMON_KEY_PANEL) {
if (press_type == 0)
@ -1543,33 +1572,43 @@ static void imon_incoming_packet(struct imon_context *ictx,
else {
ir_keydown(ictx->rdev, ictx->rc_scancode,
ictx->rc_toggle);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
return;
}
/* Only panel type events left to process now */
spin_lock_irqsave(&ictx->kc_lock, flags);
/* KEY_MUTE repeats from knob need to be suppressed */
if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
do_gettimeofday(&t);
msec = tv2int(&t, &prev_time);
prev_time = t;
if (msec < idev->rep[REP_DELAY])
if (msec < idev->rep[REP_DELAY]) {
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
}
}
kc = ictx->kc;
input_report_key(idev, ictx->kc, press_type);
spin_unlock_irqrestore(&ictx->kc_lock, flags);
input_report_key(idev, kc, press_type);
input_sync(idev);
/* panel keys don't generate a release */
input_report_key(idev, ictx->kc, 0);
input_report_key(idev, kc, 0);
input_sync(idev);
ictx->last_keycode = ictx->kc;
ictx->last_keycode = kc;
return;
unknown_key:
spin_unlock_irqrestore(&ictx->kc_lock, flags);
dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
(long long)scancode);
return;
@ -1927,6 +1966,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
}
mutex_init(&ictx->lock);
spin_lock_init(&ictx->kc_lock);
mutex_lock(&ictx->lock);