diff options
Diffstat (limited to 'drivers/media/rc/rc-ir-raw.c')
-rw-r--r-- | drivers/media/rc/rc-ir-raw.c | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 18504870b9f0..374f83105a23 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -65,8 +65,8 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) if (!dev->raw) return -EINVAL; - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); + dev_dbg(&dev->dev, "sample: (%05dus %s)\n", + TO_US(ev->duration), TO_STR(ev->pulse)); if (!kfifo_put(&dev->raw->kfifo, *ev)) { dev_err(&dev->dev, "IR event FIFO is full!\n"); @@ -92,7 +92,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) { ktime_t now; DEFINE_IR_RAW_EVENT(ev); - int rc = 0; if (!dev->raw) return -EINVAL; @@ -101,7 +100,33 @@ 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; - rc = ir_raw_event_store(dev, &ev); + return ir_raw_event_store_with_timeout(dev, &ev); +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); + +/* + * ir_raw_event_store_with_timeout() - pass a pulse/space duration to the raw + * ir decoders, schedule decoding and + * timeout + * @dev: the struct rc_dev device descriptor + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This routine (which may be called from an interrupt context) stores a + * pulse/space duration for the raw ir decoding state machines, schedules + * decoding and generates a timeout. + */ +int ir_raw_event_store_with_timeout(struct rc_dev *dev, struct ir_raw_event *ev) +{ + ktime_t now; + int rc = 0; + + if (!dev->raw) + return -EINVAL; + + now = ktime_get(); + + spin_lock(&dev->raw->edge_spinlock); + rc = ir_raw_event_store(dev, ev); dev->raw->last_event = now; @@ -112,10 +137,11 @@ 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; } -EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); +EXPORT_SYMBOL_GPL(ir_raw_event_store_with_timeout); /** * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing @@ -168,7 +194,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) if (!dev->raw) return; - IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); + dev_dbg(&dev->dev, "%s idle mode\n", idle ? "enter" : "leave"); if (idle) { dev->raw->this_ev.timeout = true; @@ -462,12 +488,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 +520,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 +569,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; |