[PATCH] media: rc: meson-ir: add timeout on idle
Matthias Reichl
hias at horus.com
Fri Mar 9 07:54:51 PST 2018
Hi Sean,
On Thu, Mar 08, 2018 at 04:43:27PM +0000, Sean Young wrote:
> 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).
Ah, thanks for the hint! Now I also noticed your commit a few
weeks ago - must have missed that before.
> > +
> > 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.
Indeed it is very high, but I have no idea where that might be
coming from - so I didn't touch it.
I've been testing rc-5 and NEC remotes with 20-50ms timeouts
on meson-ir/upstream kernel and a couple of LibreELEC users are
using 30-50ms timeouts without issues on Amlogic devices as well
(on 3.14 vendor kernel with meson-ir timeout patch):
https://forum.libreelec.tv/thread/11643-le9-0-remote-configs-ir-keytable-amlogic-devices/?postID=83124#post83124
Out of curiosity: where does the 125ms IR_DEFAULT_TIMEOUT value
come from? For raw IR signals processed by the decoders this seems
rather high to me as well. On my RPi3 with gpio-ir-recv I'm
using 30ms timeout (with an rc-5 remote) without issues.
> > 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?
Tested-by: Matthias Reichl <hias at horus.com>
Thanks a lot, this patch works fine! And having a common function
in rc-core looks like a very good idea to me as well.
Only thing I'd like to have added is min/max timeout values set
in meson-ir so it's configurable via ir-ctl. A separate patch for
that would make sense, though, I guess.
so long & thanks,
Hias
>
> 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