Commit a3572c34 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

V4L/DVB: ir-core: Add logic to decode IR protocols at the IR core



Adds a method to pass IR raw pulse/code events into ir-core. This is
needed in order to support LIRC. It also helps to move common code
from the drivers into the core.

In order to allow testing, it implements a simple NEC protocol decoder
at ir-nec-decoder.c file. The logic is about the same used at saa7134
driver that handles Avermedia M135A and Encore FM53 boards.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 02108949
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
ir-common-objs  := ir-functions.o ir-keymaps.o
ir-core-objs	:= ir-keytable.o ir-sysfs.o
ir-core-objs	:= ir-keytable.o ir-sysfs.o ir-raw-event.o ir-nec-decoder.o

obj-$(CONFIG_IR_CORE) += ir-core.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
+131 −0
Original line number Diff line number Diff line
/* ir-raw-event.c - handle IR Pulse/Space event
 *
 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

#include <media/ir-core.h>

/* Start time: 4.5 ms  */
#define MIN_START_TIME	3900000
#define MAX_START_TIME	5100000

/* Pulse time: 560 us  */
#define MIN_PULSE_TIME	460000
#define MAX_PULSE_TIME	660000

/* Bit 1 space time: 2.25ms-560 us */
#define MIN_BIT1_TIME	1490000
#define MAX_BIT1_TIME	1890000

/* Bit 0 space time: 1.12ms-560 us */
#define MIN_BIT0_TIME	360000
#define MAX_BIT0_TIME	760000


/** Decode NEC pulsecode. This code can take up to 76.5 ms to run.
	Unfortunately, using IRQ to decode pulse didn't work, since it uses
	a pulse train of 38KHz. This means one pulse on each 52 us
*/

int ir_nec_decode(struct input_dev *input_dev,
		  struct ir_raw_event *evs,
		  int len)
{
	int i, count = -1;
	int ircode = 0, not_code = 0;
#if 0
	/* Needed only after porting the event code to the decoder */
	struct ir_input_dev *ir = input_get_drvdata(input_dev);
#endif

	/* Be sure that the first event is an start one and is a pulse */
	for (i = 0; i < len; i++) {
		if (evs[i].type & (IR_START_EVENT | IR_PULSE))
			break;
	}
	i++;	/* First event doesn't contain data */

	if (i >= len)
		return 0;

	/* First space should have 4.5 ms otherwise is not NEC protocol */
	if ((evs[i].delta.tv_nsec < MIN_START_TIME) |
	    (evs[i].delta.tv_nsec > MAX_START_TIME) |
	    (evs[i].type != IR_SPACE))
		goto err;

	/*
	 * FIXME: need to implement the repeat sequence
	 */

	count = 0;
	for (i++; i < len; i++) {
		int bit;

		if ((evs[i].delta.tv_nsec < MIN_PULSE_TIME) |
		    (evs[i].delta.tv_nsec > MAX_PULSE_TIME) |
		    (evs[i].type != IR_PULSE))
			goto err;

		if (++i >= len)
			goto err;
		if (evs[i].type != IR_SPACE)
			goto err;

		if ((evs[i].delta.tv_nsec > MIN_BIT1_TIME) &&
		    (evs[i].delta.tv_nsec < MAX_BIT1_TIME))
			bit = 1;
		else if ((evs[i].delta.tv_nsec > MIN_BIT0_TIME) &&
			 (evs[i].delta.tv_nsec < MAX_BIT0_TIME))
			bit = 0;
		else
			goto err;

		if (bit) {
			int shift = count;
			/* Address first, then command */
			if (shift < 8) {
				shift += 8;
				ircode |= 1 << shift;
			} else if (shift < 16) {
				not_code |= 1 << shift;
			} else if (shift < 24) {
				shift -= 16;
				ircode |= 1 << shift;
			} else {
				shift -= 24;
				not_code |= 1 << shift;
			}
		}
		if (++count == 32)
			break;
	}

	/*
	 * Fixme: may need to accept Extended NEC protocol?
	 */
	if ((ircode & ~not_code) != ircode) {
		IR_dprintk(1, "NEC checksum error: code 0x%04x, not-code 0x%04x\n",
			   ircode, not_code);
		return -EINVAL;
	}

	IR_dprintk(1, "NEC scancode 0x%04x\n", ircode);

	return ircode;
err:
	IR_dprintk(1, "NEC decoded failed at bit %d while decoding %luus time\n",
		   count, (evs[i].delta.tv_nsec + 500) / 1000);

	return -EINVAL;
}
EXPORT_SYMBOL_GPL(ir_nec_decode);
+117 −0
Original line number Diff line number Diff line
/* ir-raw-event.c - handle IR Pulse/Space event
 *
 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

#include <media/ir-core.h>

/* Define the max number of bit transitions per IR keycode */
#define MAX_IR_EVENT_SIZE	256

int ir_raw_event_register(struct input_dev *input_dev)
{
	struct ir_input_dev *ir = input_get_drvdata(input_dev);
	int rc, size;

	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);

	size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
	size = roundup_pow_of_two(size);

	rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);

	return rc;
}
EXPORT_SYMBOL_GPL(ir_raw_event_register);

void ir_raw_event_unregister(struct input_dev *input_dev)
{
	struct ir_input_dev *ir = input_get_drvdata(input_dev);

	if (!ir->raw)
		return;

	kfifo_free(&ir->raw->kfifo);
	kfree(ir->raw);
	ir->raw = NULL;
}
EXPORT_SYMBOL_GPL(ir_raw_event_unregister);

int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
{
	struct ir_input_dev	*ir = input_get_drvdata(input_dev);
	struct timespec		ts;
	struct ir_raw_event	event;
	int			rc;

	if (!ir->raw)
		return -EINVAL;

	event.type = type;
	event.delta.tv_sec = 0;
	event.delta.tv_nsec = 0;

	ktime_get_ts(&ts);

	if (timespec_equal(&ir->raw->last_event, &event.delta))
		event.type |= IR_START_EVENT;
	else
		event.delta = timespec_sub(ts, ir->raw->last_event);

	memcpy(&ir->raw->last_event, &ts, sizeof(ts));

	if (event.delta.tv_sec) {
		event.type |= IR_START_EVENT;
		event.delta.tv_sec = 0;
		event.delta.tv_nsec = 0;
	}

	kfifo_in(&ir->raw->kfifo, &event, sizeof(event));

	return rc;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store);

int ir_raw_event_handle(struct input_dev *input_dev)
{
	struct ir_input_dev		*ir = input_get_drvdata(input_dev);
	int				rc;
	struct ir_raw_event		*evs;
	int 				len, i;

	/*
	 * Store the events into a temporary buffer. This allows calling more than
	 * one decoder to deal with the received data
	 */
	len = kfifo_len(&ir->raw->kfifo) / sizeof(*evs);
	if (!len)
		return 0;
	evs = kmalloc(len * sizeof(*evs), GFP_ATOMIC);

	for (i = 0; i < len; i++) {
		rc = kfifo_out(&ir->raw->kfifo, &evs[i], sizeof(*evs));
		if (rc != sizeof(*evs)) {
			IR_dprintk(1, "overflow error: received %d instead of %zd\n",
				   rc, sizeof(*evs));
			return -EINVAL;
		}
		IR_dprintk(2, "event type %d, time before event: %07luus\n",
			evs[i].type, (evs[i].delta.tv_nsec + 500) / 1000);
	}

	rc = ir_nec_decode(input_dev, evs, len);

	kfree(evs);

	return rc;
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
+81 −4
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
static int saa7134_rc5_irq(struct saa7134_dev *dev);
static int saa7134_nec_irq(struct saa7134_dev *dev);
static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
static void nec_task(unsigned long data);
static void saa7134_nec_timer(unsigned long data);

@@ -403,10 +404,12 @@ void saa7134_input_irq(struct saa7134_dev *dev)

	if (ir->nec_gpio) {
		saa7134_nec_irq(dev);
	} else if (!ir->polling && !ir->rc5_gpio) {
	} else if (!ir->polling && !ir->rc5_gpio && !ir->raw_decode) {
		build_key(dev);
	} else if (ir->rc5_gpio) {
		saa7134_rc5_irq(dev);
	} else if (ir->raw_decode) {
		saa7134_raw_decode_irq(dev);
	}
}

@@ -419,6 +422,23 @@ static void saa7134_input_timer(unsigned long data)
	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}

void ir_raw_decode_timer_end(unsigned long data)
{
	struct saa7134_dev *dev = (struct saa7134_dev *)data;
	struct card_ir *ir = dev->remote;
	int rc;

	/*
	 * FIXME: the IR key handling code should be called by the decoder,
	 * after implementing the repeat mode
	 */
	rc = ir_raw_event_handle(dev->remote->dev);
	if (rc >= 0) {
		ir_input_keydown(ir->dev, &ir->ir, rc);
		ir_input_nokey(ir->dev, &ir->ir);
	}
}

void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
	if (ir->running)
@@ -447,6 +467,11 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
		setup_timer(&ir->timer_keyup, saa7134_nec_timer,
			    (unsigned long)dev);
		tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
	} else if (ir->raw_decode) {
		/* set timer_end for code completion */
		init_timer(&ir->timer_end);
		ir->timer_end.function = ir_raw_decode_timer_end;
		ir->timer_end.data = (unsigned long)dev;
	}
}

@@ -462,6 +487,9 @@ void saa7134_ir_stop(struct saa7134_dev *dev)
		del_timer_sync(&ir->timer_end);
	else if (ir->nec_gpio)
		tasklet_kill(&ir->tlet);
	else if (ir->raw_decode)
		del_timer_sync(&ir->timer_end);

	ir->running = 0;
}

@@ -509,6 +537,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
	int polling      = 0;
	int rc5_gpio	 = 0;
	int nec_gpio	 = 0;
	int raw_decode   = 0;
	u64 ir_type = IR_TYPE_OTHER;
	int err;

@@ -574,7 +603,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
		ir_codes     = &ir_codes_avermedia_m135a_rm_jx_table;
		mask_keydown = 0x0040000;
		mask_keycode = 0xffff;
		nec_gpio     = 1;
		raw_decode   = 1;
		break;
	case SAA7134_BOARD_AVERMEDIA_777:
	case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -755,6 +784,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
	ir->polling      = polling;
	ir->rc5_gpio	 = rc5_gpio;
	ir->nec_gpio	 = nec_gpio;
	ir->raw_decode	 = raw_decode;

	/* init input device */
	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -762,7 +792,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
		 pci_name(dev->pci));

	if (ir_codes->ir_type != IR_TYPE_OTHER) {
	if (ir_codes->ir_type != IR_TYPE_OTHER && !raw_decode) {
		ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
		ir->props.priv = dev;
		ir->props.change_protocol = saa7134_ir_change_protocol;
@@ -790,6 +820,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
	err = ir_input_register(ir->dev, ir_codes, &ir->props, MODULE_NAME);
	if (err)
		goto err_out_stop;
	if (ir_codes->ir_type != IR_TYPE_OTHER) {
		err = ir_raw_event_register(ir->dev);
		if (err)
			goto err_out_stop;
	}

	saa7134_ir_start(dev, ir);

@@ -813,6 +848,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
		return;

	saa7134_ir_stop(dev);
	ir_raw_event_unregister(dev->remote->dev);
	ir_input_unregister(dev->remote->dev);
	kfree(dev->remote);
	dev->remote = NULL;
@@ -919,6 +955,48 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
	i2c_new_device(&dev->i2c_adap, &info);
}

static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
{
	struct card_ir	*ir = dev->remote;
	unsigned long 	timeout;
	int count, pulse, oldpulse;

	/* Disable IR IRQ line */
	saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);

	/* Generate initial event */
	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
	pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
	ir_raw_event_store(dev->remote->dev, pulse? IR_PULSE : IR_SPACE);

#if 1
	/* Wait up to 10 ms for event change */
	oldpulse = pulse;
	for (count = 0; count < 1000; count++)  {
		udelay(10);
		/* rising SAA7134_GPIO_GPRESCAN reads the status */
		saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
		saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
		pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
			& ir->mask_keydown;
		if (pulse != oldpulse)
			break;
	}

	/* Store final event */
	ir_raw_event_store(dev->remote->dev, pulse? IR_PULSE : IR_SPACE);
#endif
	/* Wait 15 ms before deciding to do something else */
	timeout = jiffies + jiffies_to_msecs(15);
	mod_timer(&ir->timer_end, timeout);

	/* Enable IR IRQ line */
	saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);

	return 1;
}

static int saa7134_rc5_irq(struct saa7134_dev *dev)
{
	struct card_ir *ir = dev->remote;
@@ -961,7 +1039,6 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev)
	return 1;
}


/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
   The first pulse (start) has 9 + 4.5 ms
 */
+3 −0
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ struct card_ir {
	/* NEC decoding */
	u32			nec_gpio;
	struct tasklet_struct   tlet;

	/* IR core raw decoding */
	u32			raw_decode;
};

/* Routines from ir-functions.c */
Loading