[PATCH] media: rc: meson-ir: add timeout on idle
Sean Young
sean at mess.org
Thu Mar 8 08:43:27 PST 2018
Hi Matthias,
On Tue, Mar 06, 2018 at 06:41:22PM +0100, Matthias Reichl wrote:
> Meson doesn't seem to be able to generate timeout events
> in hardware. So install a software timer to generate the
> timeout events required by the decoders to prevent
> "ghost keypresses".
>
> Signed-off-by: Matthias Reichl <hias at horus.com>
> ---
> drivers/media/rc/meson-ir.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
> index f2204eb77e2a..f34c5836412b 100644
> --- a/drivers/media/rc/meson-ir.c
> +++ b/drivers/media/rc/meson-ir.c
> @@ -69,6 +69,7 @@ struct meson_ir {
> void __iomem *reg;
> struct rc_dev *rc;
> spinlock_t lock;
> + struct timer_list timeout_timer;
> };
>
> static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg,
> @@ -98,6 +99,10 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
> rawir.pulse = !!(status & STATUS_IR_DEC_IN);
>
> ir_raw_event_store(ir->rc, &rawir);
> +
> + mod_timer(&ir->timeout_timer,
> + jiffies + nsecs_to_jiffies(ir->rc->timeout));
> +
> ir_raw_event_handle(ir->rc);
>
> spin_unlock(&ir->lock);
> @@ -105,6 +110,17 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
> return IRQ_HANDLED;
> }
>
> +static void meson_ir_timeout_timer(struct timer_list *t)
> +{
> + struct meson_ir *ir = from_timer(ir, t, timeout_timer);
> + DEFINE_IR_RAW_EVENT(rawir);
> +
> + rawir.timeout = true;
> + rawir.duration = ir->rc->timeout;
> + ir_raw_event_store(ir->rc, &rawir);
> + ir_raw_event_handle(ir->rc);
> +}
Now there can be concurrent access to the raw IR kfifo from the interrupt
handler and the timer. As there is a race condition between the timeout
timer and new IR arriving from the interrupt handler, the timeout could
end being generated after new IR and corrupting a message. There is very
similar functionality in rc-ir-raw.c (with a spinlock).
> +
> static int meson_ir_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -145,7 +161,9 @@ static int meson_ir_probe(struct platform_device *pdev)
> ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
> ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
> ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
> + ir->rc->min_timeout = 1;
> ir->rc->timeout = MS_TO_NS(200);
> + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
Any idea why the default timeout is to 200ms? It seems very high.
> ir->rc->driver_name = DRIVER_NAME;
>
> spin_lock_init(&ir->lock);
> @@ -157,6 +175,8 @@ static int meson_ir_probe(struct platform_device *pdev)
> return ret;
> }
>
> + timer_setup(&ir->timeout_timer, meson_ir_timeout_timer, 0);
> +
> ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir);
> if (ret) {
> dev_err(dev, "failed to request irq\n");
> @@ -198,6 +218,8 @@ static int meson_ir_remove(struct platform_device *pdev)
> meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
> spin_unlock_irqrestore(&ir->lock, flags);
>
> + del_timer_sync(&ir->timeout_timer);
> +
> return 0;
> }
>
> --
> 2.11.0
Would you mind trying this patch?
Thanks
Sean
---
>From f98f4fc05d743ac48a95694996985b2c1f0c4a4b Mon Sep 17 00:00:00 2001
From: Sean Young <sean at mess.org>
Date: Thu, 8 Mar 2018 14:42:44 +0000
Subject: [PATCH] media: rc: meson-ir: add timeout on idle
Meson doesn't seem to be able to generate timeout events in hardware. So
install a software timer to generate the timeout events required by the
decoders to prevent "ghost keypresses".
Signed-off-by: Sean Young <sean at mess.org>
---
drivers/media/rc/meson-ir.c | 3 +--
drivers/media/rc/rc-ir-raw.c | 30 +++++++++++++++++++++++++++---
include/media/rc-core.h | 4 +++-
3 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index f2204eb77e2a..64b0aa4f4db7 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -97,8 +97,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
status = readl_relaxed(ir->reg + IR_DEC_STATUS);
rawir.pulse = !!(status & STATUS_IR_DEC_IN);
- ir_raw_event_store(ir->rc, &rawir);
- ir_raw_event_handle(ir->rc);
+ ir_raw_event_store_with_timeout(ir->rc, &rawir);
spin_unlock(&ir->lock);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 984bb82851f9..374f83105a23 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -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,8 +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;
+ 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);
+ rc = ir_raw_event_store(dev, ev);
dev->raw->last_event = now;
@@ -117,7 +141,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
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
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index fc3a92668bab..6742fd86ff65 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -334,7 +334,9 @@ void ir_raw_event_handle(struct rc_dev *dev);
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse);
int ir_raw_event_store_with_filter(struct rc_dev *dev,
- struct ir_raw_event *ev);
+ struct ir_raw_event *ev);
+int ir_raw_event_store_with_timeout(struct rc_dev *dev,
+ struct ir_raw_event *ev);
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode,
struct ir_raw_event *events, unsigned int max);
--
2.14.3
More information about the linux-amlogic
mailing list