Skip to content

Commit

Permalink
V4L/DVB: IR/imon: protect ictx's kc and last_keycode w/spinlock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jarod Wilson authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent eaf2bcc commit 693508d
Showing 1 changed file with 46 additions and 6 deletions.
52 changes: 46 additions & 6 deletions drivers/media/IR/imon.c
Original file line number Diff line number Diff line change
@@ -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)
*
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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");

Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

/**
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -1486,13 +1510,15 @@ 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;
if (!nomouse) {
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;
Expand All @@ -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 &&
Expand Down Expand Up @@ -1534,42 +1561,54 @@ 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)
ir_keyup(irdev);
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;

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);

/* 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;
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 693508d

Please sign in to comment.