aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/rc/rc-main.c
diff options
context:
space:
mode:
authorSean Young2017-11-23 17:37:10 -0500
committerMauro Carvalho Chehab2017-12-14 10:35:30 -0500
commit57c642cb45d6f7d0d950c3bc67439989062ac743 (patch)
treea8bb6ccd399309d7c359917291cc58f01cbffb7f /drivers/media/rc/rc-main.c
parent6d4a36d183fe1ca051961e1e4a79853427605a01 (diff)
media: cec: move cec autorepeat handling to rc-core
CEC autorepeat is different than other protocols. Autorepeat is triggered by the first repeated user control pressed CEC message, rather than a fixed REP_DELAY. This change also does away with the KEY_UP event directly after the first KEY_DOWN event, which was used to stop autorepeat from starting. See commit a9a249a2c997 ("media: cec: fix remote control passthrough") for the original change. Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/rc/rc-main.c')
-rw-r--r--drivers/media/rc/rc-main.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 5830cb2c5943..1870b7999062 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -597,6 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync)
return;
IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+ del_timer_sync(&dev->timer_repeat);
input_report_key(dev->input_dev, dev->last_keycode, 0);
led_trigger_event(led_feedback, LED_OFF);
if (sync)
@@ -651,6 +652,31 @@ static void ir_timer_keyup(struct timer_list *t)
}
/**
+ * ir_timer_repeat() - generates a repeat event after a timeout
+ *
+ * @t: a pointer to the struct timer_list
+ *
+ * This routine will generate a soft repeat event every REP_PERIOD
+ * milliseconds.
+ */
+static void ir_timer_repeat(struct timer_list *t)
+{
+ struct rc_dev *dev = from_timer(dev, t, timer_repeat);
+ struct input_dev *input = dev->input_dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ if (dev->keypressed) {
+ input_event(input, EV_KEY, dev->last_keycode, 2);
+ input_sync(input);
+ if (input->rep[REP_PERIOD])
+ mod_timer(&dev->timer_repeat, jiffies +
+ msecs_to_jiffies(input->rep[REP_PERIOD]));
+ }
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+
+/**
* rc_repeat() - signals that a key is still pressed
* @dev: the struct rc_dev descriptor of the device
*
@@ -732,6 +758,22 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
led_trigger_event(led_feedback, LED_FULL);
}
+ /*
+ * For CEC, start sending repeat messages as soon as the first
+ * repeated message is sent, as long as REP_DELAY = 0 and REP_PERIOD
+ * is non-zero. Otherwise, the input layer will generate repeat
+ * messages.
+ */
+ if (!new_event && keycode != KEY_RESERVED &&
+ dev->allowed_protocols == RC_PROTO_BIT_CEC &&
+ !timer_pending(&dev->timer_repeat) &&
+ dev->input_dev->rep[REP_PERIOD] &&
+ !dev->input_dev->rep[REP_DELAY]) {
+ input_event(dev->input_dev, EV_KEY, keycode, 2);
+ mod_timer(&dev->timer_repeat, jiffies +
+ msecs_to_jiffies(dev->input_dev->rep[REP_PERIOD]));
+ }
+
input_sync(dev->input_dev);
}
@@ -1599,6 +1641,7 @@ struct rc_dev *rc_allocate_device(enum rc_driver_type type)
input_set_drvdata(dev->input_dev, dev);
timer_setup(&dev->timer_keyup, ir_timer_keyup, 0);
+ timer_setup(&dev->timer_repeat, ir_timer_repeat, 0);
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
@@ -1732,7 +1775,10 @@ static int rc_setup_rx_device(struct rc_dev *dev)
* to avoid wrong repetition of the keycodes. Note that this must be
* set after the call to input_register_device().
*/
- dev->input_dev->rep[REP_DELAY] = 500;
+ if (dev->allowed_protocols == RC_PROTO_BIT_CEC)
+ dev->input_dev->rep[REP_DELAY] = 0;
+ else
+ dev->input_dev->rep[REP_DELAY] = 500;
/*
* As a repeat event on protocols like RC-5 and NEC take as long as
@@ -1884,6 +1930,7 @@ void rc_unregister_device(struct rc_dev *dev)
return;
del_timer_sync(&dev->timer_keyup);
+ del_timer_sync(&dev->timer_repeat);
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);