forked from Minki/linux
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:
parent
eaf2bcc923
commit
693508df98
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user