Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3fb136f3 authored by Eric Nelson's avatar Eric Nelson Committed by Mauro Carvalho Chehab
Browse files

[media] rc: gpio-ir-recv: add timeout on idle



Many decoders require a trailing space (period without IR illumination)
to be delivered before completing a decode.

Since the gpio-ir-recv driver only delivers events on gpio transitions,
a single IR symbol (caused by a quick touch on an IR remote) will not
be properly decoded without the use of a timer to flush the tail end
state of the IR receiver.

This patch initializes and uses a timer and the timeout field of rcdev
to complete the stream and allow decode.

The timeout can be overridden through the use of the LIRC_SET_REC_TIMEOUT
ioctl.

Signed-off-by: default avatarEric Nelson <eric@nelint.com>
Acked-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent c8e1bbc5
Loading
Loading
Loading
Loading
+22 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ struct gpio_rc_dev {
	struct rc_dev *rcdev;
	struct rc_dev *rcdev;
	int gpio_nr;
	int gpio_nr;
	bool active_low;
	bool active_low;
	struct timer_list flush_timer;
};
};


#ifdef CONFIG_OF
#ifdef CONFIG_OF
@@ -93,12 +94,26 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
	if (rc < 0)
	if (rc < 0)
		goto err_get_value;
		goto err_get_value;


	mod_timer(&gpio_dev->flush_timer,
		  jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));

	ir_raw_event_handle(gpio_dev->rcdev);
	ir_raw_event_handle(gpio_dev->rcdev);


err_get_value:
err_get_value:
	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


static void flush_timer(unsigned long arg)
{
	struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
	DEFINE_IR_RAW_EVENT(ev);

	ev.timeout = true;
	ev.duration = gpio_dev->rcdev->timeout;
	ir_raw_event_store(gpio_dev->rcdev, &ev);
	ir_raw_event_handle(gpio_dev->rcdev);
}

static int gpio_ir_recv_probe(struct platform_device *pdev)
static int gpio_ir_recv_probe(struct platform_device *pdev)
{
{
	struct gpio_rc_dev *gpio_dev;
	struct gpio_rc_dev *gpio_dev;
@@ -144,6 +159,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
	rcdev->input_id.version = 0x0100;
	rcdev->input_id.version = 0x0100;
	rcdev->dev.parent = &pdev->dev;
	rcdev->dev.parent = &pdev->dev;
	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
	rcdev->min_timeout = 0;
	rcdev->timeout = IR_DEFAULT_TIMEOUT;
	rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
	if (pdata->allowed_protos)
	if (pdata->allowed_protos)
		rcdev->allowed_protocols = pdata->allowed_protos;
		rcdev->allowed_protocols = pdata->allowed_protos;
	else
	else
@@ -154,6 +172,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
	gpio_dev->gpio_nr = pdata->gpio_nr;
	gpio_dev->gpio_nr = pdata->gpio_nr;
	gpio_dev->active_low = pdata->active_low;
	gpio_dev->active_low = pdata->active_low;


	setup_timer(&gpio_dev->flush_timer, flush_timer,
		    (unsigned long)gpio_dev);

	rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
	rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
	if (rc < 0)
	if (rc < 0)
		goto err_gpio_request;
		goto err_gpio_request;
@@ -196,6 +217,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);


	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
	del_timer_sync(&gpio_dev->flush_timer);
	rc_unregister_device(gpio_dev->rcdev);
	rc_unregister_device(gpio_dev->rcdev);
	gpio_free(gpio_dev->gpio_nr);
	gpio_free(gpio_dev->gpio_nr);
	kfree(gpio_dev);
	kfree(gpio_dev);