Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+46 −6
Original line number Diff line number Diff line
/*
 *   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;

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