summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/rc/rc-core-priv.h5
-rw-r--r--drivers/media/rc/rc-ir-raw.c24
2 files changed, 24 insertions, 5 deletions
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index d09a06e1c17f..5e80b4273e2d 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -50,8 +50,9 @@ struct ir_raw_event_ctrl {
DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE);
ktime_t last_event; /* when last event occurred */
struct rc_dev *dev; /* pointer to the parent rc_dev */
- /* edge driver */
- struct timer_list edge_handle;
+ /* handle delayed ir_raw_event_store_edge processing */
+ spinlock_t edge_spinlock;
+ struct timer_list edge_handle;
/* raw decoder state follows */
struct ir_raw_event prev_ev;
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 2790a0d268fd..984bb82851f9 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -101,6 +101,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
ev.pulse = !pulse;
+ spin_lock(&dev->raw->edge_spinlock);
rc = ir_raw_event_store(dev, &ev);
dev->raw->last_event = now;
@@ -112,6 +113,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
mod_timer(&dev->raw->edge_handle,
jiffies + msecs_to_jiffies(15));
}
+ spin_unlock(&dev->raw->edge_spinlock);
return rc;
}
@@ -462,12 +464,26 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode,
}
EXPORT_SYMBOL(ir_raw_encode_scancode);
-static void edge_handle(struct timer_list *t)
+/**
+ * ir_raw_edge_handle() - Handle ir_raw_event_store_edge() processing
+ *
+ * @t: timer_list
+ *
+ * This callback is armed by ir_raw_event_store_edge(). It does two things:
+ * first of all, rather than calling ir_raw_event_handle() for each
+ * edge and waking up the rc thread, 15 ms after the first edge
+ * ir_raw_event_handle() is called. Secondly, generate a timeout event
+ * no more IR is received after the rc_dev timeout.
+ */
+static void ir_raw_edge_handle(struct timer_list *t)
{
struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle);
struct rc_dev *dev = raw->dev;
- ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event);
+ unsigned long flags;
+ ktime_t interval;
+ spin_lock_irqsave(&dev->raw->edge_spinlock, flags);
+ interval = ktime_sub(ktime_get(), dev->raw->last_event);
if (ktime_to_ns(interval) >= dev->timeout) {
DEFINE_IR_RAW_EVENT(ev);
@@ -480,6 +496,7 @@ static void edge_handle(struct timer_list *t)
jiffies + nsecs_to_jiffies(dev->timeout -
ktime_to_ns(interval)));
}
+ spin_unlock_irqrestore(&dev->raw->edge_spinlock, flags);
ir_raw_event_handle(dev);
}
@@ -528,7 +545,8 @@ int ir_raw_event_prepare(struct rc_dev *dev)
dev->raw->dev = dev;
dev->change_protocol = change_protocol;
- timer_setup(&dev->raw->edge_handle, edge_handle, 0);
+ spin_lock_init(&dev->raw->edge_spinlock);
+ timer_setup(&dev->raw->edge_handle, ir_raw_edge_handle, 0);
INIT_KFIFO(dev->raw->kfifo);
return 0;