All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h
       [not found] <cover.1270754989.git.mchehab@redhat.com>
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 21:34   ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 6/8] V4L/DVB: ir-core: fix gcc warning noise Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

ir-core.h has the kABI to be used by the bridge drivers, when needing to register
IR protocols and pass IR events. However, the same file also contains IR subsystem
internal calls, meant to be used inside ir-core and between ir-core and the raw
decoders.

Better to move those functions to an internal header, for some reasons:

1) Header will be a little more cleaner;

2) It avoids the need of recompile everything (bridge/hardware drivers, etc),
   just because a new decoder were added, or some other internal change were needed;

3) Better organize the ir-core API, splitting the functions that are internal to
   IR core and the ancillary drivers (decoders, lirc_dev) from the features that
   should be exported to IR subsystem clients.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

 create mode 100644 drivers/media/IR/ir-core-priv.h

diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
new file mode 100644
index 0000000..ab785bc
--- /dev/null
+++ b/drivers/media/IR/ir-core-priv.h
@@ -0,0 +1,112 @@
+/*
+ * Remote Controller core raw events header
+ *
+ * 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.
+ */
+
+#ifndef _IR_RAW_EVENT
+#define _IR_RAW_EVENT
+
+#include <media/ir-core.h>
+
+struct ir_raw_handler {
+	struct list_head list;
+
+	int (*decode)(struct input_dev *input_dev, s64 duration);
+	int (*raw_register)(struct input_dev *input_dev);
+	int (*raw_unregister)(struct input_dev *input_dev);
+};
+
+struct ir_raw_event_ctrl {
+	struct work_struct		rx_work;	/* for the rx decoding workqueue */
+	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
+	ktime_t				last_event;	/* when last event occurred */
+	enum raw_event_type		last_type;	/* last event type */
+	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
+};
+
+/* macros for IR decoders */
+#define PULSE(units)				((units))
+#define SPACE(units)				(-(units))
+#define IS_RESET(duration)			((duration) == 0)
+#define IS_PULSE(duration)			((duration) > 0)
+#define IS_SPACE(duration)			((duration) < 0)
+#define DURATION(duration)			(abs((duration)))
+#define IS_TRANSITION(x, y)			((x) * (y) < 0)
+#define DECREASE_DURATION(duration, amount)			\
+	do {							\
+		if (IS_SPACE(duration))				\
+			duration += (amount);			\
+		else if (IS_PULSE(duration))			\
+			duration -= (amount);			\
+	} while (0)
+
+#define TO_UNITS(duration, unit_len)				\
+	((int)((duration) > 0 ?					\
+		DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\
+		-DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
+#define TO_US(duration)		((int)TO_UNITS(duration, 1000))
+
+/*
+ * Routines from ir-keytable.c to be used internally on ir-core and decoders
+ */
+
+u32 ir_g_keycode_from_table(struct input_dev *input_dev,
+			    u32 scancode);
+void ir_repeat(struct input_dev *dev);
+void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
+
+/*
+ * Routines from ir-sysfs.c - Meant to be called only internally inside
+ * ir-core
+ */
+
+int ir_register_class(struct input_dev *input_dev);
+void ir_unregister_class(struct input_dev *input_dev);
+
+/*
+ * Routines from ir-raw-event.c to be used internally and by decoders
+ */
+int ir_raw_event_register(struct input_dev *input_dev);
+void ir_raw_event_unregister(struct input_dev *input_dev);
+static inline void ir_raw_event_reset(struct input_dev *input_dev)
+{
+	ir_raw_event_store(input_dev, 0);
+	ir_raw_event_handle(input_dev);
+}
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_init(void);
+
+
+/*
+ * Decoder initialization code
+ *
+ * Those load logic are called during ir-core init, and automatically
+ * loads the compiled decoders for their usage with IR raw events
+ */
+
+/* from ir-nec-decoder.c */
+#ifdef CONFIG_IR_NEC_DECODER_MODULE
+#define load_nec_decode()	request_module("ir-nec-decoder")
+#else
+#define load_nec_decode()	0
+#endif
+
+/* from ir-rc5-decoder.c */
+#ifdef CONFIG_IR_RC5_DECODER_MODULE
+#define load_rc5_decode()	request_module("ir-rc5-decoder")
+#else
+#define load_rc5_decode()	0
+#endif
+
+#endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
index ab06919..db591e4 100644
--- a/drivers/media/IR/ir-functions.c
+++ b/drivers/media/IR/ir-functions.c
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <media/ir-common.h>
+#include "ir-core-priv.h"
 
 /* -------------------------------------------------------------------------- */
 
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 67b2aa1..01bddc4 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -14,7 +14,7 @@
 
 
 #include <linux/input.h>
-#include <media/ir-common.h>
+#include "ir-core-priv.h"
 
 /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
 #define IR_TAB_MIN_SIZE	256
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index 5085f90..f22d1af 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -12,8 +12,8 @@
  *  GNU General Public License for more details.
  */
 
-#include <media/ir-core.h>
 #include <linux/bitrev.h>
+#include "ir-core-priv.h"
 
 #define NEC_NBITS		32
 #define NEC_UNIT		562500  /* ns */
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 3a25d8d..2efc051 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -12,10 +12,10 @@
  *  GNU General Public License for more details.
  */
 
-#include <media/ir-core.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
+#include "ir-core-priv.h"
 
 /* Define the max number of pulse/space transitions to buffer */
 #define MAX_IR_EVENT_SIZE      512
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index d6def8c..59bcaa9 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -19,7 +19,7 @@
  * the first two bits are start bits, and a third one is a filing bit
  */
 
-#include <media/ir-core.h>
+#include "ir-core-priv.h"
 
 #define RC5_NBITS		14
 #define RC5_UNIT		888888 /* ns */
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 17d4341..a222d4f 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -14,7 +14,7 @@
 
 #include <linux/input.h>
 #include <linux/device.h>
-#include <media/ir-core.h>
+#include "ir-core-priv.h"
 
 #define IRRCV_NUM_DEVICES	256
 
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index e9a0cbf..40b6250 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -31,13 +31,6 @@ enum rc_driver_type {
 	RC_DRIVER_IR_RAW,	/* Needs a Infra-Red pulse/space decoder */
 };
 
-enum raw_event_type {
-	IR_SPACE	= (1 << 0),
-	IR_PULSE	= (1 << 1),
-	IR_START_EVENT	= (1 << 2),
-	IR_STOP_EVENT	= (1 << 3),
-};
-
 /**
  * struct ir_dev_props - Allow caller drivers to set special properties
  * @driver_type: specifies if the driver or hardware have already a decoder,
@@ -65,14 +58,6 @@ struct ir_dev_props {
 	void			(*close)(void *priv);
 };
 
-struct ir_raw_event_ctrl {
-	struct work_struct		rx_work;	/* for the rx decoding workqueue */
-	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
-	ktime_t				last_event;	/* when last event occurred */
-	enum raw_event_type		last_type;	/* last event type */
-	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
-};
-
 struct ir_input_dev {
 	struct device			dev;		/* device */
 	char				*driver_name;	/* Name of the driver module */
@@ -92,22 +77,16 @@ struct ir_input_dev {
 	u8				last_toggle;	/* toggle of last command */
 };
 
-struct ir_raw_handler {
-	struct list_head list;
-
-	int (*decode)(struct input_dev *input_dev, s64 duration);
-	int (*raw_register)(struct input_dev *input_dev);
-	int (*raw_unregister)(struct input_dev *input_dev);
+enum raw_event_type {
+	IR_SPACE        = (1 << 0),
+	IR_PULSE        = (1 << 1),
+	IR_START_EVENT  = (1 << 2),
+	IR_STOP_EVENT   = (1 << 3),
 };
 
 #define to_ir_input_dev(_attr) container_of(_attr, struct ir_input_dev, attr)
 
-/* Routines from ir-keytable.c */
-
-u32 ir_g_keycode_from_table(struct input_dev *input_dev,
-			    u32 scancode);
-void ir_repeat(struct input_dev *dev);
-void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
+/* From ir-keytable.c */
 int __ir_input_register(struct input_dev *dev,
 		      const struct ir_scancode_table *ir_codes,
 		      const struct ir_dev_props *props,
@@ -143,60 +122,11 @@ static inline int ir_input_register(struct input_dev *dev,
 
 void ir_input_unregister(struct input_dev *input_dev);
 
-/* Routines from ir-sysfs.c */
+/* From ir-raw-event.c */
 
-int ir_register_class(struct input_dev *input_dev);
-void ir_unregister_class(struct input_dev *input_dev);
-
-/* Routines from ir-raw-event.c */
-int ir_raw_event_register(struct input_dev *input_dev);
-void ir_raw_event_unregister(struct input_dev *input_dev);
 void ir_raw_event_handle(struct input_dev *input_dev);
 int ir_raw_event_store(struct input_dev *input_dev, s64 duration);
 int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
-static inline void ir_raw_event_reset(struct input_dev *input_dev)
-{
-	ir_raw_event_store(input_dev, 0);
-	ir_raw_event_handle(input_dev);
-}
-int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
-void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
-void ir_raw_init(void);
 
-/* from ir-nec-decoder.c */
-#ifdef CONFIG_IR_NEC_DECODER_MODULE
-#define load_nec_decode()	request_module("ir-nec-decoder")
-#else
-#define load_nec_decode()	0
-#endif
-
-/* from ir-rc5-decoder.c */
-#ifdef CONFIG_IR_RC5_DECODER_MODULE
-#define load_rc5_decode()	request_module("ir-rc5-decoder")
-#else
-#define load_rc5_decode()	0
-#endif
-
-/* macros for ir decoders */
-#define PULSE(units)				((units))
-#define SPACE(units)				(-(units))
-#define IS_RESET(duration)			((duration) == 0)
-#define IS_PULSE(duration)			((duration) > 0)
-#define IS_SPACE(duration)			((duration) < 0)
-#define DURATION(duration)			(abs((duration)))
-#define IS_TRANSITION(x, y)			((x) * (y) < 0)
-#define DECREASE_DURATION(duration, amount)			\
-	do {							\
-		if (IS_SPACE(duration))				\
-			duration += (amount);			\
-		else if (IS_PULSE(duration))			\
-			duration -= (amount);			\
-	} while (0)
-
-#define TO_UNITS(duration, unit_len)				\
-	((int)((duration) > 0 ?					\
-		DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\
-		-DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
-#define TO_US(duration)		((int)TO_UNITS(duration, 1000))
 
 #endif /* _IR_CORE */
-- 
1.6.6.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 1/8] V4L/DVB: em28xx: fix a regression caused by the rc-map changes
       [not found] <cover.1270754989.git.mchehab@redhat.com>
                   ` (6 preceding siblings ...)
  2010-04-08 19:37 ` [PATCH 2/8] V4L/DVB: ir: Make sure that the spinlocks are properly initialized Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

The patch that adds the rc-map changes didn't take into account that an
a table with IR_TYPE_UNKNOWN would make change_protocol to return -EINVAL.

As this function is fundamental to initialize some data, including a
callback to the getkey function, this caused the driver to stop working,
hanging the machine most of the times.

The fix were simply to add a handler for the IR type, but, to avoid further
issues, explicitly call change_protocol and handle the error before
initializing the IR. Also, let input_dev to start/stop IR handling,
after the opening of the input device.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 3200f48..dffd026 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -361,14 +361,20 @@ static void em28xx_ir_work(struct work_struct *work)
 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
-static void em28xx_ir_start(struct em28xx_IR *ir)
+static int em28xx_ir_start(void *priv)
 {
+	struct em28xx_IR *ir = priv;
+
 	INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
 	schedule_delayed_work(&ir->work, 0);
+
+	return 0;
 }
 
-static void em28xx_ir_stop(struct em28xx_IR *ir)
+static void em28xx_ir_stop(void *priv)
 {
+	struct em28xx_IR *ir = priv;
+
 	cancel_delayed_work_sync(&ir->work);
 }
 
@@ -388,7 +394,7 @@ int em28xx_ir_change_protocol(void *priv, u64 ir_type)
 		dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
 		ir_config = EM2874_IR_NEC;
 		ir->full_code = 1;
-	} else
+	} else if (ir_type != IR_TYPE_UNKNOWN)
 		rc = -EINVAL;
 
 	em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
@@ -441,6 +447,13 @@ int em28xx_ir_init(struct em28xx *dev)
 	ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
 	ir->props.priv = ir;
 	ir->props.change_protocol = em28xx_ir_change_protocol;
+	ir->props.open = em28xx_ir_start;
+	ir->props.close = em28xx_ir_stop;
+
+	/* By default, keep protocol field untouched */
+	err = em28xx_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+	if (err)
+		goto err_out_free;
 
 	/* This is how often we ask the chip for IR information */
 	ir->polling = 100; /* ms */
@@ -467,7 +480,6 @@ int em28xx_ir_init(struct em28xx *dev)
 	input_dev->dev.parent = &dev->udev->dev;
 
 
-	em28xx_ir_start(ir);
 
 	/* all done */
 	err = ir_input_register(ir->input, dev->board.ir_codes,
@@ -477,7 +489,6 @@ int em28xx_ir_init(struct em28xx *dev)
 
 	return 0;
  err_out_stop:
-	em28xx_ir_stop(ir);
 	dev->ir = NULL;
  err_out_free:
 	kfree(ir);
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/8] V4L/DVB: Teach drivers/media/IR/ir-raw-event.c to use durations
       [not found] <cover.1270754989.git.mchehab@redhat.com>
@ 2010-04-08 19:37   ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 6/8] V4L/DVB: ir-core: fix gcc warning noise Mauro Carvalho Chehab
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

From: David Härdeman <david@hardeman.nu>

drivers/media/IR/ir-raw-event.c is currently written with the assumption
that all "raw" hardware will generate events only on state change (i.e.
when a pulse or space starts).

However, some hardware (like mceusb, probably the most popular IR receiver
out there) only generates duration data (and that data is buffered so using
any kind of timing on the data is futile).

Furthermore, using signed int's to represent pulse/space durations is a
well-known approach when writing ir decoders.

With this patch:

- s64 int's are used to represent pulse/space durations in ns

- a workqueue is used to decode the ir protocols outside of interrupt context

- #defines are added to make decoders clearer

- decoder reset is implemented by passing a zero duration to the kfifo queue
  and decoders are updated accordingly

Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index 48a86cc..5085f90 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -13,15 +13,16 @@
  */
 
 #include <media/ir-core.h>
+#include <linux/bitrev.h>
 
 #define NEC_NBITS		32
-#define NEC_UNIT		559979 /* ns */
-#define NEC_HEADER_MARK		(16 * NEC_UNIT)
-#define NEC_HEADER_SPACE	(8 * NEC_UNIT)
-#define NEC_REPEAT_SPACE	(4 * NEC_UNIT)
-#define NEC_MARK		(NEC_UNIT)
-#define NEC_0_SPACE		(NEC_UNIT)
-#define NEC_1_SPACE		(3 * NEC_UNIT)
+#define NEC_UNIT		562500  /* ns */
+#define NEC_HEADER_PULSE	PULSE(16)
+#define NEC_HEADER_SPACE	SPACE(8)
+#define NEC_REPEAT_SPACE	SPACE(4)
+#define NEC_BIT_PULSE		PULSE(1)
+#define NEC_BIT_0_SPACE		SPACE(1)
+#define NEC_BIT_1_SPACE		SPACE(3)
 
 /* Used to register nec_decoder clients */
 static LIST_HEAD(decoder_list);
@@ -29,21 +30,13 @@ DEFINE_SPINLOCK(decoder_lock);
 
 enum nec_state {
 	STATE_INACTIVE,
-	STATE_HEADER_MARK,
 	STATE_HEADER_SPACE,
-	STATE_MARK,
-	STATE_SPACE,
-	STATE_TRAILER_MARK,
+	STATE_BIT_PULSE,
+	STATE_BIT_SPACE,
+	STATE_TRAILER_PULSE,
 	STATE_TRAILER_SPACE,
 };
 
-struct nec_code {
-	u8	address;
-	u8	not_address;
-	u8	command;
-	u8	not_command;
-};
-
 struct decoder_data {
 	struct list_head	list;
 	struct ir_input_dev	*ir_dev;
@@ -51,7 +44,7 @@ struct decoder_data {
 
 	/* State machine control */
 	enum nec_state		state;
-	struct nec_code		nec_code;
+	u32			nec_bits;
 	unsigned		count;
 };
 
@@ -62,7 +55,6 @@ struct decoder_data {
  *
  * Returns the struct decoder_data that corresponds to a device
  */
-
 static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
 {
 	struct decoder_data *data = NULL;
@@ -123,20 +115,20 @@ static struct attribute_group decoder_attribute_group = {
 	.attrs	= decoder_attributes,
 };
 
-
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
- * @ev:		event array with type/duration of pulse/space
+ * @duration:	duration in ns of pulse/space
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_nec_decode(struct input_dev *input_dev,
-			 struct ir_raw_event *ev)
+static int ir_nec_decode(struct input_dev *input_dev, s64 duration)
 {
 	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	int bit, last_bit;
+	int u;
+	u32 scancode;
+	u8 address, not_address, command, not_command;
 
 	data = get_decoder_data(ir_dev);
 	if (!data)
@@ -145,151 +137,108 @@ static int ir_nec_decode(struct input_dev *input_dev,
 	if (!data->enabled)
 		return 0;
 
-	/* Except for the initial event, what matters is the previous bit */
-	bit = (ev->type & IR_PULSE) ? 1 : 0;
-
-	last_bit = !bit;
-
-	/* Discards spurious space last_bits when inactive */
-
-	/* Very long delays are considered as start events */
-	if (ev->delta.tv_nsec > NEC_HEADER_MARK + NEC_HEADER_SPACE - NEC_UNIT / 2)
+	if (IS_RESET(duration)) {
 		data->state = STATE_INACTIVE;
+		return 0;
+	}
 
-	if (ev->type & IR_START_EVENT)
-		data->state = STATE_INACTIVE;
+	u = TO_UNITS(duration, NEC_UNIT);
+	if (DURATION(u) == 0)
+		goto out;
+
+	IR_dprintk(2, "NEC decode started at state %d (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 
 	switch (data->state) {
+
 	case STATE_INACTIVE:
-		if (!bit)		/* PULSE marks the start event */
-			return 0;
+		if (u == NEC_HEADER_PULSE) {
+			data->count = 0;
+			data->state = STATE_HEADER_SPACE;
+		}
+		return 0;
 
-		data->count = 0;
-		data->state = STATE_HEADER_MARK;
-		memset (&data->nec_code, 0, sizeof(data->nec_code));
-		return 0;
-	case STATE_HEADER_MARK:
-		if (!last_bit)
-			goto err;
-		if (ev->delta.tv_nsec < NEC_HEADER_MARK - 6 * NEC_UNIT)
-			goto err;
-		data->state = STATE_HEADER_SPACE;
-		return 0;
 	case STATE_HEADER_SPACE:
-		if (last_bit)
-			goto err;
-		if (ev->delta.tv_nsec >= NEC_HEADER_SPACE - NEC_UNIT / 2) {
-			data->state = STATE_MARK;
+		if (u == NEC_HEADER_SPACE) {
+			data->state = STATE_BIT_PULSE;
 			return 0;
-		}
-
-		if (ev->delta.tv_nsec >= NEC_REPEAT_SPACE - NEC_UNIT / 2) {
+		} else if (u == NEC_REPEAT_SPACE) {
 			ir_repeat(input_dev);
 			IR_dprintk(1, "Repeat last key\n");
-			data->state = STATE_TRAILER_MARK;
+			data->state = STATE_TRAILER_PULSE;
 			return 0;
 		}
-		goto err;
-	case STATE_MARK:
-		if (!last_bit)
-			goto err;
-		if ((ev->delta.tv_nsec > NEC_MARK + NEC_UNIT / 2) ||
-		    (ev->delta.tv_nsec < NEC_MARK - NEC_UNIT / 2))
-			goto err;
-		data->state = STATE_SPACE;
-		return 0;
-	case STATE_SPACE:
-		if (last_bit)
-			goto err;
+		break;
+
+	case STATE_BIT_PULSE:
+		if (u == NEC_BIT_PULSE) {
+			data->state = STATE_BIT_SPACE;
+			return 0;
+		}
+		break;
+
+	case STATE_BIT_SPACE:
+		if (u != NEC_BIT_0_SPACE && u != NEC_BIT_1_SPACE)
+			break;
 
-		if ((ev->delta.tv_nsec >= NEC_0_SPACE - NEC_UNIT / 2) &&
-		    (ev->delta.tv_nsec < NEC_0_SPACE + NEC_UNIT / 2))
-			bit = 0;
-		else if ((ev->delta.tv_nsec >= NEC_1_SPACE - NEC_UNIT / 2) &&
-		         (ev->delta.tv_nsec < NEC_1_SPACE + NEC_UNIT / 2))
-			bit = 1;
-		else {
-			IR_dprintk(1, "Decode failed at %d-th bit (%s) @%luus\n",
-				data->count,
-				last_bit ? "pulse" : "space",
-				(ev->delta.tv_nsec + 500) / 1000);
+		data->nec_bits <<= 1;
+		if (u == NEC_BIT_1_SPACE)
+			data->nec_bits |= 1;
+		data->count++;
 
-			goto err2;
+		if (data->count != NEC_NBITS) {
+			data->state = STATE_BIT_PULSE;
+			return 0;
 		}
 
-		/* Ok, we've got a valid bit. proccess it */
-		if (bit) {
-			int shift = data->count;
+		address     = bitrev8((data->nec_bits >> 24) & 0xff);
+		not_address = bitrev8((data->nec_bits >> 16) & 0xff);
+		command	    = bitrev8((data->nec_bits >>  8) & 0xff);
+		not_command = bitrev8((data->nec_bits >>  0) & 0xff);
 
-			/*
-			 * NEC transmit bytes on this temporal order:
-			 * address | not address | command | not command
-			 */
-			if (shift < 8) {
-				data->nec_code.address |= 1 << shift;
-			} else if (shift < 16) {
-				data->nec_code.not_address |= 1 << (shift - 8);
-			} else if (shift < 24) {
-				data->nec_code.command |= 1 << (shift - 16);
-			} else {
-				data->nec_code.not_command |= 1 << (shift - 24);
-			}
+		if ((command ^ not_command) != 0xff) {
+			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
+				   data->nec_bits);
+			break;
 		}
-		if (++data->count == NEC_NBITS) {
-			u32 scancode;
-			/*
-			 * Fixme: may need to accept Extended NEC protocol?
-			 */
-			if ((data->nec_code.command ^ data->nec_code.not_command) != 0xff)
-				goto checksum_err;
 
-			if ((data->nec_code.address ^ data->nec_code.not_address) != 0xff) {
-				/* Extended NEC */
-				scancode = data->nec_code.address << 16 |
-					   data->nec_code.not_address << 8 |
-					   data->nec_code.command;
-				IR_dprintk(1, "NEC scancode 0x%06x\n", scancode);
-			} else {
-				/* normal NEC */
-				scancode = data->nec_code.address << 8 |
-					   data->nec_code.command;
-				IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
-			}
-			ir_keydown(input_dev, scancode, 0);
+		if ((address ^ not_address) != 0xff) {
+			/* Extended NEC */
+			scancode = address     << 16 |
+				   not_address <<  8 |
+				   command;
+			IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
+		} else {
+			/* normal NEC */
+			scancode = address << 8 | command;
+			IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
+		}
 
-			data->state = STATE_TRAILER_MARK;
-		} else
-			data->state = STATE_MARK;
-		return 0;
-	case STATE_TRAILER_MARK:
-		if (!last_bit)
-			goto err;
-		data->state = STATE_TRAILER_SPACE;
+		ir_keydown(input_dev, scancode, 0);
+		data->state = STATE_TRAILER_PULSE;
 		return 0;
+
+	case STATE_TRAILER_PULSE:
+		if (u > 0) {
+			data->state = STATE_TRAILER_SPACE;
+			return 0;
+		}
+		break;
+
 	case STATE_TRAILER_SPACE:
-		if (last_bit)
-			goto err;
-		data->state = STATE_INACTIVE;
-		return 0;
+		if (u < 0) {
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+
+		break;
 	}
 
-err:
-	IR_dprintk(1, "NEC decoded failed at state %d (%s) @ %luus\n",
-		   data->state,
-		   bit ? "pulse" : "space",
-		   (ev->delta.tv_nsec + 500) / 1000);
-err2:
+out:
+	IR_dprintk(1, "NEC decode failed at state %d (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
-
-checksum_err:
-	data->state = STATE_INACTIVE;
-	IR_dprintk(1, "NEC checksum error: received 0x%02x%02x%02x%02x\n",
-		   data->nec_code.address,
-		   data->nec_code.not_address,
-		   data->nec_code.command,
-		   data->nec_code.not_command);
-	return -EINVAL;
 }
 
 static int ir_nec_register(struct input_dev *input_dev)
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 5b121d8..3a25d8d 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -15,9 +15,10 @@
 #include <media/ir-core.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/sched.h>
 
-/* Define the max number of bit transitions per IR keycode */
-#define MAX_IR_EVENT_SIZE	256
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE      512
 
 /* Used to handle IR raw handler extensions */
 static LIST_HEAD(ir_raw_handler_list);
@@ -53,19 +54,30 @@ DEFINE_SPINLOCK(ir_raw_handler_lock);
 /* Used to load the decoders */
 static struct work_struct wq_load;
 
+static void ir_raw_event_work(struct work_struct *work)
+{
+	s64 d;
+	struct ir_raw_event_ctrl *raw =
+		container_of(work, struct ir_raw_event_ctrl, rx_work);
+
+	while (kfifo_out(&raw->kfifo, &d, sizeof(d)) == sizeof(d))
+		RUN_DECODER(decode, raw->input_dev, d);
+}
+
 int ir_raw_event_register(struct input_dev *input_dev)
 {
 	struct ir_input_dev *ir = input_get_drvdata(input_dev);
-	int rc, size;
+	int rc;
 
 	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
 	if (!ir->raw)
 		return -ENOMEM;
 
-	size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
-	size = roundup_pow_of_two(size);
+	ir->raw->input_dev = input_dev;
+	INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
 
-	rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
+	rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+			 GFP_KERNEL);
 	if (rc < 0) {
 		kfree(ir->raw);
 		ir->raw = NULL;
@@ -90,6 +102,7 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
 	if (!ir->raw)
 		return;
 
+	cancel_work_sync(&ir->raw->rx_work);
 	RUN_DECODER(raw_unregister, input_dev);
 
 	kfifo_free(&ir->raw->kfifo);
@@ -97,75 +110,91 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
 	ir->raw = NULL;
 }
 
-int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @input_dev:	the struct input_dev device descriptor
+ * @duration:	duration of the pulse or space in ns
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct input_dev *input_dev, s64 duration)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return -EINVAL;
+
+	if (kfifo_in(&ir->raw->kfifo, &duration, sizeof(duration)) != sizeof(duration))
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @input_dev:	the struct input_dev device descriptor
+ * @type:	the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(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;
+	ktime_t			now;
+	s64			delta; /* ns */
+	int			rc = 0;
 
 	if (!ir->raw)
 		return -EINVAL;
 
-	event.type = type;
-	event.delta.tv_sec = 0;
-	event.delta.tv_nsec = 0;
+	now = ktime_get();
+	delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
 
-	ktime_get_ts(&ts);
+	/* Check for a long duration since last event or if we're
+	 * being called for the first time, note that delta can't
+	 * possibly be negative.
+	 */
+	if (delta > NSEC_PER_SEC || !ir->raw->last_type)
+		type |= IR_START_EVENT;
 
-	if (timespec_equal(&ir->raw->last_event, &event.delta))
-		event.type |= IR_START_EVENT;
+	if (type & IR_START_EVENT)
+		ir_raw_event_reset(input_dev);
+	else if (ir->raw->last_type & IR_SPACE)
+		rc = ir_raw_event_store(input_dev, -delta);
+	else if (ir->raw->last_type & IR_PULSE)
+		rc = ir_raw_event_store(input_dev, delta);
 	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		ev;
-	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(ev);
-	if (!len)
 		return 0;
 
-	for (i = 0; i < len; i++) {
-		rc = kfifo_out(&ir->raw->kfifo, &ev, sizeof(ev));
-		if (rc != sizeof(ev)) {
-			IR_dprintk(1, "overflow error: received %d instead of %zd\n",
-				   rc, sizeof(ev));
-			return -EINVAL;
-		}
-		IR_dprintk(2, "event type %d, time before event: %07luus\n",
-			ev.type, (ev.delta.tv_nsec + 500) / 1000);
-		rc = RUN_DECODER(decode, input_dev, &ev);
-	}
-
-	/*
-	 * Call all ir decoders. This allows decoding the same event with
-	 * more than one protocol handler.
-	 */
-
+	ir->raw->last_event = now;
+	ir->raw->last_type = type;
 	return rc;
 }
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @input_dev:	the struct input_dev device descriptor
+ *
+ * This routine will signal the workqueue to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return;
+
+	schedule_work(&ir->raw->rx_work);
+}
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
 /*
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index b8a33ae..d6def8c 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -21,11 +21,8 @@
 
 #include <media/ir-core.h>
 
-static unsigned int ir_rc5_remote_gap = 888888;
-
 #define RC5_NBITS		14
-#define RC5_BIT			(ir_rc5_remote_gap * 2)
-#define RC5_DURATION		(ir_rc5_remote_gap * RC5_NBITS)
+#define RC5_UNIT		888888 /* ns */
 
 /* Used to register rc5_decoder clients */
 static LIST_HEAD(decoder_list);
@@ -33,13 +30,9 @@ DEFINE_SPINLOCK(decoder_lock);
 
 enum rc5_state {
 	STATE_INACTIVE,
-	STATE_MARKSPACE,
-	STATE_TRAILER,
-};
-
-struct rc5_code {
-	u8	address;
-	u8	command;
+	STATE_BIT_START,
+	STATE_BIT_END,
+	STATE_FINISHED,
 };
 
 struct decoder_data {
@@ -49,8 +42,9 @@ struct decoder_data {
 
 	/* State machine control */
 	enum rc5_state		state;
-	struct rc5_code		rc5_code;
-	unsigned		code, elapsed, last_bit, last_code;
+	u32			rc5_bits;
+	int			last_unit;
+	unsigned		count;
 };
 
 
@@ -122,18 +116,19 @@ static struct attribute_group decoder_attribute_group = {
 };
 
 /**
- * handle_event() - Decode one RC-5 pulse or space
+ * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
- * @ev:		event array with type/duration of pulse/space
+ * @duration:	duration of pulse/space in ns
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_rc5_decode(struct input_dev *input_dev,
-			struct ir_raw_event *ev)
+static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
 {
 	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	int is_pulse, scancode, delta, toggle;
+	u8 command, system, toggle;
+	u32 scancode;
+	int u;
 
 	data = get_decoder_data(ir_dev);
 	if (!data)
@@ -142,79 +137,84 @@ static int ir_rc5_decode(struct input_dev *input_dev,
 	if (!data->enabled)
 		return 0;
 
-	delta = DIV_ROUND_CLOSEST(ev->delta.tv_nsec, ir_rc5_remote_gap);
-
-	/* The duration time refers to the last bit time */
-	is_pulse = (ev->type & IR_PULSE) ? 1 : 0;
-
-	/* Very long delays are considered as start events */
-	if (delta > RC5_DURATION || (ev->type & IR_START_EVENT))
+	if (IS_RESET(duration)) {
 		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	u = TO_UNITS(duration, RC5_UNIT);
+	if (DURATION(u) == 0)
+		goto out;
+
+again:
+	IR_dprintk(2, "RC5 decode started at state %i (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
+
+	if (DURATION(u) == 0 && data->state != STATE_FINISHED)
+		return 0;
 
 	switch (data->state) {
+
 	case STATE_INACTIVE:
-	IR_dprintk(2, "currently inative. Start bit (%s) @%uus\n",
-		   is_pulse ? "pulse" : "space",
-		   (unsigned)(ev->delta.tv_nsec + 500) / 1000);
+		if (IS_PULSE(u)) {
+			data->state = STATE_BIT_START;
+			data->count = 1;
+			DECREASE_DURATION(u, 1);
+			goto again;
+		}
+		break;
 
-		/* Discards the initial start space */
-		if (!is_pulse)
-			goto err;
-		data->code = 1;
-		data->last_bit = 1;
-		data->elapsed = 0;
-		memset(&data->rc5_code, 0, sizeof(data->rc5_code));
-		data->state = STATE_MARKSPACE;
-		return 0;
-	case STATE_MARKSPACE:
-		if (delta != 1)
-			data->last_bit = data->last_bit ? 0 : 1;
+	case STATE_BIT_START:
+		if (DURATION(u) == 1) {
+			data->rc5_bits <<= 1;
+			if (IS_SPACE(u))
+				data->rc5_bits |= 1;
+			data->count++;
+			data->last_unit = u;
 
-		data->elapsed += delta;
+			/*
+			 * If the last bit is zero, a space will merge
+			 * with the silence after the command.
+			 */
+			if (IS_PULSE(u) && data->count == RC5_NBITS) {
+				data->state = STATE_FINISHED;
+				goto again;
+			}
 
-		if ((data->elapsed % 2) == 1)
+			data->state = STATE_BIT_END;
 			return 0;
+		}
+		break;
 
-		data->code <<= 1;
-		data->code |= data->last_bit;
-
-		/* Fill the 2 unused bits at the command with 0 */
-		if (data->elapsed / 2 == 6)
-			data->code <<= 2;
-
-		if (data->elapsed >= (RC5_NBITS - 1) * 2) {
-			scancode = data->code;
-
-			/* Check for the start bits */
-			if ((scancode & 0xc000) != 0xc000) {
-				IR_dprintk(1, "Code 0x%04x doesn't have two start bits. It is not RC-5\n", scancode);
-				goto err;
-			}
+	case STATE_BIT_END:
+		if (IS_TRANSITION(u, data->last_unit)) {
+			if (data->count == RC5_NBITS)
+				data->state = STATE_FINISHED;
+			else
+				data->state = STATE_BIT_START;
 
-			toggle = (scancode & 0x2000) ? 1 : 0;
+			DECREASE_DURATION(u, 1);
+			goto again;
+		}
+		break;
 
-			if (scancode == data->last_code) {
-				IR_dprintk(1, "RC-5 repeat\n");
-				ir_repeat(input_dev);
-			} else {
-				data->last_code = scancode;
-				scancode &= 0x1fff;
-				IR_dprintk(1, "RC-5 scancode 0x%04x\n", scancode);
+	case STATE_FINISHED:
+		command  = (data->rc5_bits & 0x0003F) >> 0;
+		system   = (data->rc5_bits & 0x007C0) >> 6;
+		toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
+		command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+		scancode = system << 8 | command;
 
-				ir_keydown(input_dev, scancode, 0);
-			}
-			data->state = STATE_TRAILER;
-		}
-		return 0;
-	case STATE_TRAILER:
+		IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
+			   scancode, toggle);
+		ir_keydown(input_dev, scancode, toggle);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-err:
-	IR_dprintk(1, "RC-5 decoded failed at %s @ %luus\n",
-		   is_pulse ? "pulse" : "space",
-		   (ev->delta.tv_nsec + 500) / 1000);
+out:
+	IR_dprintk(1, "RC5 decode failed at state %i (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index dc4faaf..e02c5be 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -1017,7 +1017,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
 	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
 	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
 	space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
-	ir_raw_event_store(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
+	ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
 
 
 	/*
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index e9fa94f..e9a0cbf 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -65,14 +65,12 @@ struct ir_dev_props {
 	void			(*close)(void *priv);
 };
 
-struct ir_raw_event {
-	struct timespec		delta;	/* Time spent before event */
-	enum raw_event_type	type;	/* event type */
-};
-
 struct ir_raw_event_ctrl {
-	struct kfifo			kfifo;		/* fifo for the pulse/space events */
-	struct timespec			last_event;	/* when last event occurred */
+	struct work_struct		rx_work;	/* for the rx decoding workqueue */
+	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
+	ktime_t				last_event;	/* when last event occurred */
+	enum raw_event_type		last_type;	/* last event type */
+	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
 };
 
 struct ir_input_dev {
@@ -97,8 +95,7 @@ struct ir_input_dev {
 struct ir_raw_handler {
 	struct list_head list;
 
-	int (*decode)(struct input_dev *input_dev,
-		      struct ir_raw_event *ev);
+	int (*decode)(struct input_dev *input_dev, s64 duration);
 	int (*raw_register)(struct input_dev *input_dev);
 	int (*raw_unregister)(struct input_dev *input_dev);
 };
@@ -154,8 +151,14 @@ void ir_unregister_class(struct input_dev *input_dev);
 /* Routines from ir-raw-event.c */
 int ir_raw_event_register(struct input_dev *input_dev);
 void ir_raw_event_unregister(struct input_dev *input_dev);
-int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type);
-int ir_raw_event_handle(struct input_dev *input_dev);
+void ir_raw_event_handle(struct input_dev *input_dev);
+int ir_raw_event_store(struct input_dev *input_dev, s64 duration);
+int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
+static inline void ir_raw_event_reset(struct input_dev *input_dev)
+{
+	ir_raw_event_store(input_dev, 0);
+	ir_raw_event_handle(input_dev);
+}
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_init(void);
@@ -174,4 +177,26 @@ void ir_raw_init(void);
 #define load_rc5_decode()	0
 #endif
 
+/* macros for ir decoders */
+#define PULSE(units)				((units))
+#define SPACE(units)				(-(units))
+#define IS_RESET(duration)			((duration) == 0)
+#define IS_PULSE(duration)			((duration) > 0)
+#define IS_SPACE(duration)			((duration) < 0)
+#define DURATION(duration)			(abs((duration)))
+#define IS_TRANSITION(x, y)			((x) * (y) < 0)
+#define DECREASE_DURATION(duration, amount)			\
+	do {							\
+		if (IS_SPACE(duration))				\
+			duration += (amount);			\
+		else if (IS_PULSE(duration))			\
+			duration -= (amount);			\
+	} while (0)
+
+#define TO_UNITS(duration, unit_len)				\
+	((int)((duration) > 0 ?					\
+		DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\
+		-DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
+#define TO_US(duration)		((int)TO_UNITS(duration, 1000))
+
 #endif /* _IR_CORE */
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/8] V4L/DVB: ir-core: Distinguish sysfs attributes for in-hardware and raw decoders
       [not found] <cover.1270754989.git.mchehab@redhat.com>
  2010-04-08 19:37 ` [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 6/8] V4L/DVB: ir-core: fix gcc warning noise Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 3/8] V4L/DVB: rename sysfs remote controller devices from rcrcv to rc Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

Some devices have in-hardware Remote Controller decoder, while others
need a software decoder to get the IR code. As each software decoder
can be enabled/disabled individually, allowing multiple protocol
decoding capability.

On the other hand, hardware decoders have a limited protocol
support, often being able of decoding just one protocol each time.
So, each type needs a different set of capabilities to control the
supported protocol(s).

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index f509be2..67b2aa1 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -487,11 +487,19 @@ int __ir_input_register(struct input_dev *input_dev,
 	if (rc < 0)
 		goto out_table;
 
+	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
+		rc = ir_raw_event_register(input_dev);
+		if (rc < 0)
+			goto out_event;
+	}
+
 	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
 		   driver_name, rc_tab->name);
 
 	return 0;
 
+out_event:
+	ir_unregister_class(input_dev);
 out_table:
 	kfree(ir_dev->rc_tab.scan);
 out_name:
@@ -508,22 +516,25 @@ EXPORT_SYMBOL_GPL(__ir_input_register);
 
  * This routine is used to free memory and de-register interfaces.
  */
-void ir_input_unregister(struct input_dev *dev)
+void ir_input_unregister(struct input_dev *input_dev)
 {
-	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	struct ir_scancode_table *rc_tab;
 
 	if (!ir_dev)
 		return;
 
 	IR_dprintk(1, "Freed keycode table\n");
+
 	del_timer_sync(&ir_dev->timer_keyup);
+	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
+		ir_raw_event_unregister(input_dev);
 	rc_tab = &ir_dev->rc_tab;
 	rc_tab->size = 0;
 	kfree(rc_tab->scan);
 	rc_tab->scan = NULL;
 
-	ir_unregister_class(dev);
+	ir_unregister_class(input_dev);
 
 	kfree(ir_dev->driver_name);
 	kfree(ir_dev);
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 4ba7074..5b121d8 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -82,7 +82,6 @@ int ir_raw_event_register(struct input_dev *input_dev)
 
 	return rc;
 }
-EXPORT_SYMBOL_GPL(ir_raw_event_register);
 
 void ir_raw_event_unregister(struct input_dev *input_dev)
 {
@@ -97,7 +96,6 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
 	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)
 {
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index e177140..efde912 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -151,22 +151,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
 		   show_protocol, store_protocol);
 
-static struct attribute *ir_dev_attrs[] = {
+static struct attribute *ir_hw_dev_attrs[] = {
 	&dev_attr_current_protocol.attr,
 	NULL,
 };
 
-static struct attribute_group ir_dev_attr_grp = {
-	.attrs	= ir_dev_attrs,
+static struct attribute_group ir_hw_dev_attr_grp = {
+	.attrs	= ir_hw_dev_attrs,
 };
 
-static const struct attribute_group *ir_dev_attr_groups[] = {
-	&ir_dev_attr_grp,
+static const struct attribute_group *ir_hw_dev_attr_groups[] = {
+	&ir_hw_dev_attr_grp,
 	NULL
 };
 
-static struct device_type ir_dev_type = {
-	.groups		= ir_dev_attr_groups,
+static struct device_type rc_dev_type = {
+	.groups		= ir_hw_dev_attr_groups,
+	.uevent		= ir_dev_uevent,
+};
+
+static struct device_type ir_raw_dev_type = {
 	.uevent		= ir_dev_uevent,
 };
 
@@ -180,7 +184,6 @@ int ir_register_class(struct input_dev *input_dev)
 {
 	int rc;
 	const char *path;
-
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	int devno = find_first_zero_bit(&ir_core_dev_number,
 					IRRCV_NUM_DEVICES);
@@ -188,7 +191,11 @@ int ir_register_class(struct input_dev *input_dev)
 	if (unlikely(devno < 0))
 		return devno;
 
-	ir_dev->dev.type = &ir_dev_type;
+	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+		ir_dev->dev.type = &rc_dev_type;
+	else
+		ir_dev->dev.type = &ir_raw_dev_type;
+
 	ir_dev->dev.class = &ir_input_class;
 	ir_dev->dev.parent = input_dev->dev.parent;
 	dev_set_name(&ir_dev->dev, "rc%d", devno);
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 7e95dc8..dc4faaf 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -854,6 +854,9 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	ir->props.open = saa7134_ir_open;
 	ir->props.close = saa7134_ir_close;
 
+	if (raw_decode)
+		ir->props.driver_type = RC_DRIVER_IR_RAW;
+
 	if (!raw_decode && allow_protocol_change) {
 		ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
 		ir->props.change_protocol = saa7134_ir_change_protocol;
@@ -879,11 +882,6 @@ 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_free;
-	if (raw_decode) {
-		err = ir_raw_event_register(ir->dev);
-		if (err)
-			goto err_out_free;
-	}
 
 	/* the remote isn't as bouncy as a keyboard */
 	ir->dev->rep[REP_DELAY] = repeat_delay;
@@ -903,7 +901,6 @@ 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;
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index 4397ea3..e9fa94f 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -26,6 +26,11 @@ extern int ir_core_debug;
 #define IR_dprintk(level, fmt, arg...)	if (ir_core_debug >= level) \
 	printk(KERN_DEBUG "%s: " fmt , __func__, ## arg)
 
+enum rc_driver_type {
+	RC_DRIVER_SCANCODE = 0,	/* Driver or hardware generates a scancode */
+	RC_DRIVER_IR_RAW,	/* Needs a Infra-Red pulse/space decoder */
+};
+
 enum raw_event_type {
 	IR_SPACE	= (1 << 0),
 	IR_PULSE	= (1 << 1),
@@ -35,6 +40,8 @@ enum raw_event_type {
 
 /**
  * struct ir_dev_props - Allow caller drivers to set special properties
+ * @driver_type: specifies if the driver or hardware have already a decoder,
+ *	or if it needs to use the IR raw event decoders to produce a scancode
  * @allowed_protos: bitmask with the supported IR_TYPE_* protocols
  * @scanmask: some hardware decoders are not capable of providing the full
  *	scancode to the application. As this is a hardware limit, we can't do
@@ -49,12 +56,13 @@ enum raw_event_type {
  *	is opened.
  */
 struct ir_dev_props {
-	unsigned long	allowed_protos;
-	u32		scanmask;
-	void 		*priv;
-	int		(*change_protocol)(void *priv, u64 ir_type);
-	int		(*open)(void *priv);
-	void		(*close)(void *priv);
+	enum rc_driver_type	driver_type;
+	unsigned long		allowed_protos;
+	u32			scanmask;
+	void 			*priv;
+	int			(*change_protocol)(void *priv, u64 ir_type);
+	int			(*open)(void *priv);
+	void			(*close)(void *priv);
 };
 
 struct ir_raw_event {
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/8] V4L/DVB: ir-core: properly present the supported and current protocols
       [not found] <cover.1270754989.git.mchehab@redhat.com>
                   ` (3 preceding siblings ...)
  2010-04-08 19:37 ` [PATCH 3/8] V4L/DVB: rename sysfs remote controller devices from rcrcv to rc Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 19:37   ` Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

Hardware decoders have a more limited set of decoders than software ones.
In general, they support just one protocol at a given time, but allow
changing between a few options.

Rename the previous badly named "current_protocol" as just "protocol",
meaning the current protocol(s) accepted by the driver, and
add a "support_protocols" to represent the entire universe of supported
protocols by that specific hardware.

As commented on http://lwn.net/Articles/378884/, the "one file, one value"
rule doesn't fit nor does make much sense for bitmap or enum values. So, the
supported_protocols will enum all supported protocols, and the protocol
will present all active protocols.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index efde912..9d132d0 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -55,13 +55,13 @@ static ssize_t show_protocol(struct device *d,
 	if (ir_type == IR_TYPE_UNKNOWN)
 		s = "Unknown";
 	else if (ir_type == IR_TYPE_RC5)
-		s = "RC-5";
+		s = "rc-5";
 	else if (ir_type == IR_TYPE_PD)
-		s = "Pulse/distance";
+		s = "pulse-distance";
 	else if (ir_type == IR_TYPE_NEC)
-		s = "NEC";
+		s = "nec";
 	else
-		s = "Other";
+		s = "other";
 
 	return sprintf(buf, "%s\n", s);
 }
@@ -85,23 +85,22 @@ static ssize_t store_protocol(struct device *d,
 			      size_t len)
 {
 	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	u64 ir_type = IR_TYPE_UNKNOWN;
+	u64 ir_type = 0;
 	int rc = -EINVAL;
 	unsigned long flags;
 	char *buf;
 
-	buf = strsep((char **) &data, "\n");
+	while (buf = strsep((char **) &data, " \n")) {
+		if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
+			ir_type |= IR_TYPE_RC5;
+		if (!strcasecmp(buf, "pd") || !strcasecmp(buf, "pulse-distance"))
+			ir_type |= IR_TYPE_PD;
+		if (!strcasecmp(buf, "nec"))
+			ir_type |= IR_TYPE_NEC;
+	}
 
-	if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
-		ir_type = IR_TYPE_RC5;
-	else if (!strcasecmp(buf, "pd"))
-		ir_type = IR_TYPE_PD;
-	else if (!strcasecmp(buf, "nec"))
-		ir_type = IR_TYPE_NEC;
-
-	if (ir_type == IR_TYPE_UNKNOWN) {
-		IR_dprintk(1, "Error setting protocol to %lld\n",
-			   (long long)ir_type);
+	if (!ir_type) {
+		IR_dprintk(1, "Unknown protocol\n");
 		return -EINVAL;
 	}
 
@@ -119,12 +118,34 @@ static ssize_t store_protocol(struct device *d,
 	ir_dev->rc_tab.ir_type = ir_type;
 	spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
 
-	IR_dprintk(1, "Current protocol is %lld\n",
+	IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
 		   (long long)ir_type);
 
 	return len;
 }
 
+static ssize_t show_supported_protocols(struct device *d,
+			     struct device_attribute *mattr, char *buf)
+{
+	char *orgbuf = buf;
+	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+
+	/* FIXME: doesn't support multiple protocols at the same time */
+	if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
+		buf += sprintf(buf, "unknown ");
+	if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
+		buf += sprintf(buf, "rc-5 ");
+	if (ir_dev->props->allowed_protos & IR_TYPE_PD)
+		buf += sprintf(buf, "pulse-distance ");
+	if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
+		buf += sprintf(buf, "nec ");
+	if (buf == orgbuf)
+		buf += sprintf(buf, "other ");
+
+	buf += sprintf(buf - 1, "\n");
+
+	return buf - orgbuf;
+}
 
 #define ADD_HOTPLUG_VAR(fmt, val...)					\
 	do {								\
@@ -148,11 +169,15 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
 		   show_protocol, store_protocol);
 
+static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
+		   show_supported_protocols, NULL);
+
 static struct attribute *ir_hw_dev_attrs[] = {
-	&dev_attr_current_protocol.attr,
+	&dev_attr_protocol.attr,
+	&dev_attr_supported_protocols.attr,
 	NULL,
 };
 
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/8] V4L/DVB: ir-core: fix gcc warning noise
       [not found] <cover.1270754989.git.mchehab@redhat.com>
  2010-04-08 19:37 ` [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 4/8] V4L/DVB: ir-core: Distinguish sysfs attributes for in-hardware and raw decoders Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

drivers/media/IR/ir-sysfs.c: In function ‘store_protocol’:
drivers/media/IR/ir-sysfs.c:93: warning: suggest parentheses around assignment used as truth value

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 9d132d0..17d4341 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -90,7 +90,7 @@ static ssize_t store_protocol(struct device *d,
 	unsigned long flags;
 	char *buf;
 
-	while (buf = strsep((char **) &data, " \n")) {
+	while ((buf = strsep((char **) &data, " \n")) != NULL) {
 		if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
 			ir_type |= IR_TYPE_RC5;
 		if (!strcasecmp(buf, "pd") || !strcasecmp(buf, "pulse-distance"))
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/8] V4L/DVB: ir: Make sure that the spinlocks are properly initialized
       [not found] <cover.1270754989.git.mchehab@redhat.com>
                   ` (5 preceding siblings ...)
  2010-04-08 19:37   ` Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 1/8] V4L/DVB: em28xx: fix a regression caused by the rc-map changes Mauro Carvalho Chehab
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

Some spinlocks are not properly initialized on ir core:

[  471.714132] BUG: spinlock bad magic on CPU#0, modprobe/1899
[  471.719838]  lock: f92a08ac, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0
[  471.727301] Pid: 1899, comm: modprobe Not tainted 2.6.33 #36
[  471.733062] Call Trace:
[  471.735537]  [<c1498793>] ? printk+0x1d/0x22
[  471.739866]  [<c12694e3>] spin_bug+0xa3/0xf0
[  471.744224]  [<c126962d>] do_raw_spin_lock+0x7d/0x160
[  471.749364]  [<f92a01ff>] ? ir_rc5_register+0x6f/0xf0 [ir_rc5_decoder]

So, use static initialization for the static spinlocks, instead of the
dynamic ones (currently used), as proposed by David Härdeman on one
of his RFC patches.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index 9d1ada9..48a86cc 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -25,7 +25,7 @@
 
 /* Used to register nec_decoder clients */
 static LIST_HEAD(decoder_list);
-static spinlock_t decoder_lock;
+DEFINE_SPINLOCK(decoder_lock);
 
 enum nec_state {
 	STATE_INACTIVE,
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 57990a3..4ba7074 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -21,7 +21,7 @@
 
 /* Used to handle IR raw handler extensions */
 static LIST_HEAD(ir_raw_handler_list);
-static spinlock_t ir_raw_handler_lock;
+DEFINE_SPINLOCK(ir_raw_handler_lock);
 
 /**
  * RUN_DECODER()	- runs an operation on all IR decoders
@@ -205,8 +205,6 @@ static void init_decoders(struct work_struct *work)
 
 void ir_raw_init(void)
 {
-	spin_lock_init(&ir_raw_handler_lock);
-
 #ifdef MODULE
 	INIT_WORK(&wq_load, init_decoders);
 	schedule_work(&wq_load);
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index a62277b..b8a33ae 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -29,7 +29,7 @@ static unsigned int ir_rc5_remote_gap = 888888;
 
 /* Used to register rc5_decoder clients */
 static LIST_HEAD(decoder_list);
-static spinlock_t decoder_lock;
+DEFINE_SPINLOCK(decoder_lock);
 
 enum rc5_state {
 	STATE_INACTIVE,
diff --git a/drivers/media/IR/rc-map.c b/drivers/media/IR/rc-map.c
index 2f6201c..38b3489 100644
--- a/drivers/media/IR/rc-map.c
+++ b/drivers/media/IR/rc-map.c
@@ -17,8 +17,7 @@
 
 /* Used to handle IR raw handler extensions */
 static LIST_HEAD(rc_map_list);
-static spinlock_t rc_map_lock;
-
+DEFINE_SPINLOCK(rc_map_lock);
 
 static struct rc_keymap *seek_rc_map(const char *name)
 {
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/8] V4L/DVB: rename sysfs remote controller devices from rcrcv to rc
       [not found] <cover.1270754989.git.mchehab@redhat.com>
                   ` (2 preceding siblings ...)
  2010-04-08 19:37 ` [PATCH 4/8] V4L/DVB: ir-core: Distinguish sysfs attributes for in-hardware and raw decoders Mauro Carvalho Chehab
@ 2010-04-08 19:37 ` Mauro Carvalho Chehab
  2010-04-08 19:37 ` [PATCH 5/8] V4L/DVB: ir-core: properly present the supported and current protocols Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

From: David Härdeman <david@hardeman.nu>

When the remote controller class is anyway being renamed from ir to rc
this would be a good time to also rename the devices from rcrcvX to rcX.

I know we haven't reached any agreement on whether transmission will
eventually be handled by the same device, but this change will at
least make the device name non-receive-specific which will make it
possible in the future (and if a different approach is finally
agreed upon, the device name still works).

Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 0b05c7b..e177140 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -39,7 +39,7 @@ static struct class ir_input_class = {
  * @buf:	a pointer to the output buffer
  *
  * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rcrcv?/current_protocol.
+ * it is trigged by reading /sys/class/rc/rc?/current_protocol.
  * It returns the protocol name, as understood by the driver.
  */
 static ssize_t show_protocol(struct device *d,
@@ -74,7 +74,7 @@ static ssize_t show_protocol(struct device *d,
  * @len:	length of the input buffer
  *
  * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rcrcv?/current_protocol.
+ * it is trigged by reading /sys/class/rc/rc?/current_protocol.
  * It changes the IR the protocol name, if the IR type is recognized
  * by the driver.
  * If an unknown protocol name is used, returns -EINVAL.
@@ -171,7 +171,7 @@ static struct device_type ir_dev_type = {
 };
 
 /**
- * ir_register_class() - creates the sysfs for /sys/class/rc/rcrcv?
+ * ir_register_class() - creates the sysfs for /sys/class/rc/rc?
  * @input_dev:	the struct input_dev descriptor of the device
  *
  * This routine is used to register the syfs code for IR class
@@ -191,7 +191,7 @@ int ir_register_class(struct input_dev *input_dev)
 	ir_dev->dev.type = &ir_dev_type;
 	ir_dev->dev.class = &ir_input_class;
 	ir_dev->dev.parent = input_dev->dev.parent;
-	dev_set_name(&ir_dev->dev, "rcrcv%d", devno);
+	dev_set_name(&ir_dev->dev, "rc%d", devno);
 	dev_set_drvdata(&ir_dev->dev, ir_dev);
 	rc = device_register(&ir_dev->dev);
 	if (rc)
@@ -222,7 +222,7 @@ int ir_register_class(struct input_dev *input_dev)
 
 /**
  * ir_unregister_class() - removes the sysfs for sysfs for
- *			   /sys/class/rc/rcrcv?
+ *			   /sys/class/rc/rc?
  * @input_dev:	the struct input_dev descriptor of the device
  *
  * This routine is used to unregister the syfs code for IR class
-- 
1.6.6.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/8] V4L/DVB: Teach drivers/media/IR/ir-raw-event.c to use durations
@ 2010-04-08 19:37   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 19:37 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

From: David Härdeman <david@hardeman.nu>

drivers/media/IR/ir-raw-event.c is currently written with the assumption
that all "raw" hardware will generate events only on state change (i.e.
when a pulse or space starts).

However, some hardware (like mceusb, probably the most popular IR receiver
out there) only generates duration data (and that data is buffered so using
any kind of timing on the data is futile).

Furthermore, using signed int's to represent pulse/space durations is a
well-known approach when writing ir decoders.

With this patch:

- s64 int's are used to represent pulse/space durations in ns

- a workqueue is used to decode the ir protocols outside of interrupt context

- #defines are added to make decoders clearer

- decoder reset is implemented by passing a zero duration to the kfifo queue
  and decoders are updated accordingly

Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index 48a86cc..5085f90 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -13,15 +13,16 @@
  */
 
 #include <media/ir-core.h>
+#include <linux/bitrev.h>
 
 #define NEC_NBITS		32
-#define NEC_UNIT		559979 /* ns */
-#define NEC_HEADER_MARK		(16 * NEC_UNIT)
-#define NEC_HEADER_SPACE	(8 * NEC_UNIT)
-#define NEC_REPEAT_SPACE	(4 * NEC_UNIT)
-#define NEC_MARK		(NEC_UNIT)
-#define NEC_0_SPACE		(NEC_UNIT)
-#define NEC_1_SPACE		(3 * NEC_UNIT)
+#define NEC_UNIT		562500  /* ns */
+#define NEC_HEADER_PULSE	PULSE(16)
+#define NEC_HEADER_SPACE	SPACE(8)
+#define NEC_REPEAT_SPACE	SPACE(4)
+#define NEC_BIT_PULSE		PULSE(1)
+#define NEC_BIT_0_SPACE		SPACE(1)
+#define NEC_BIT_1_SPACE		SPACE(3)
 
 /* Used to register nec_decoder clients */
 static LIST_HEAD(decoder_list);
@@ -29,21 +30,13 @@ DEFINE_SPINLOCK(decoder_lock);
 
 enum nec_state {
 	STATE_INACTIVE,
-	STATE_HEADER_MARK,
 	STATE_HEADER_SPACE,
-	STATE_MARK,
-	STATE_SPACE,
-	STATE_TRAILER_MARK,
+	STATE_BIT_PULSE,
+	STATE_BIT_SPACE,
+	STATE_TRAILER_PULSE,
 	STATE_TRAILER_SPACE,
 };
 
-struct nec_code {
-	u8	address;
-	u8	not_address;
-	u8	command;
-	u8	not_command;
-};
-
 struct decoder_data {
 	struct list_head	list;
 	struct ir_input_dev	*ir_dev;
@@ -51,7 +44,7 @@ struct decoder_data {
 
 	/* State machine control */
 	enum nec_state		state;
-	struct nec_code		nec_code;
+	u32			nec_bits;
 	unsigned		count;
 };
 
@@ -62,7 +55,6 @@ struct decoder_data {
  *
  * Returns the struct decoder_data that corresponds to a device
  */
-
 static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
 {
 	struct decoder_data *data = NULL;
@@ -123,20 +115,20 @@ static struct attribute_group decoder_attribute_group = {
 	.attrs	= decoder_attributes,
 };
 
-
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
- * @ev:		event array with type/duration of pulse/space
+ * @duration:	duration in ns of pulse/space
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_nec_decode(struct input_dev *input_dev,
-			 struct ir_raw_event *ev)
+static int ir_nec_decode(struct input_dev *input_dev, s64 duration)
 {
 	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	int bit, last_bit;
+	int u;
+	u32 scancode;
+	u8 address, not_address, command, not_command;
 
 	data = get_decoder_data(ir_dev);
 	if (!data)
@@ -145,151 +137,108 @@ static int ir_nec_decode(struct input_dev *input_dev,
 	if (!data->enabled)
 		return 0;
 
-	/* Except for the initial event, what matters is the previous bit */
-	bit = (ev->type & IR_PULSE) ? 1 : 0;
-
-	last_bit = !bit;
-
-	/* Discards spurious space last_bits when inactive */
-
-	/* Very long delays are considered as start events */
-	if (ev->delta.tv_nsec > NEC_HEADER_MARK + NEC_HEADER_SPACE - NEC_UNIT / 2)
+	if (IS_RESET(duration)) {
 		data->state = STATE_INACTIVE;
+		return 0;
+	}
 
-	if (ev->type & IR_START_EVENT)
-		data->state = STATE_INACTIVE;
+	u = TO_UNITS(duration, NEC_UNIT);
+	if (DURATION(u) == 0)
+		goto out;
+
+	IR_dprintk(2, "NEC decode started at state %d (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 
 	switch (data->state) {
+
 	case STATE_INACTIVE:
-		if (!bit)		/* PULSE marks the start event */
-			return 0;
+		if (u == NEC_HEADER_PULSE) {
+			data->count = 0;
+			data->state = STATE_HEADER_SPACE;
+		}
+		return 0;
 
-		data->count = 0;
-		data->state = STATE_HEADER_MARK;
-		memset (&data->nec_code, 0, sizeof(data->nec_code));
-		return 0;
-	case STATE_HEADER_MARK:
-		if (!last_bit)
-			goto err;
-		if (ev->delta.tv_nsec < NEC_HEADER_MARK - 6 * NEC_UNIT)
-			goto err;
-		data->state = STATE_HEADER_SPACE;
-		return 0;
 	case STATE_HEADER_SPACE:
-		if (last_bit)
-			goto err;
-		if (ev->delta.tv_nsec >= NEC_HEADER_SPACE - NEC_UNIT / 2) {
-			data->state = STATE_MARK;
+		if (u == NEC_HEADER_SPACE) {
+			data->state = STATE_BIT_PULSE;
 			return 0;
-		}
-
-		if (ev->delta.tv_nsec >= NEC_REPEAT_SPACE - NEC_UNIT / 2) {
+		} else if (u == NEC_REPEAT_SPACE) {
 			ir_repeat(input_dev);
 			IR_dprintk(1, "Repeat last key\n");
-			data->state = STATE_TRAILER_MARK;
+			data->state = STATE_TRAILER_PULSE;
 			return 0;
 		}
-		goto err;
-	case STATE_MARK:
-		if (!last_bit)
-			goto err;
-		if ((ev->delta.tv_nsec > NEC_MARK + NEC_UNIT / 2) ||
-		    (ev->delta.tv_nsec < NEC_MARK - NEC_UNIT / 2))
-			goto err;
-		data->state = STATE_SPACE;
-		return 0;
-	case STATE_SPACE:
-		if (last_bit)
-			goto err;
+		break;
+
+	case STATE_BIT_PULSE:
+		if (u == NEC_BIT_PULSE) {
+			data->state = STATE_BIT_SPACE;
+			return 0;
+		}
+		break;
+
+	case STATE_BIT_SPACE:
+		if (u != NEC_BIT_0_SPACE && u != NEC_BIT_1_SPACE)
+			break;
 
-		if ((ev->delta.tv_nsec >= NEC_0_SPACE - NEC_UNIT / 2) &&
-		    (ev->delta.tv_nsec < NEC_0_SPACE + NEC_UNIT / 2))
-			bit = 0;
-		else if ((ev->delta.tv_nsec >= NEC_1_SPACE - NEC_UNIT / 2) &&
-		         (ev->delta.tv_nsec < NEC_1_SPACE + NEC_UNIT / 2))
-			bit = 1;
-		else {
-			IR_dprintk(1, "Decode failed at %d-th bit (%s) @%luus\n",
-				data->count,
-				last_bit ? "pulse" : "space",
-				(ev->delta.tv_nsec + 500) / 1000);
+		data->nec_bits <<= 1;
+		if (u == NEC_BIT_1_SPACE)
+			data->nec_bits |= 1;
+		data->count++;
 
-			goto err2;
+		if (data->count != NEC_NBITS) {
+			data->state = STATE_BIT_PULSE;
+			return 0;
 		}
 
-		/* Ok, we've got a valid bit. proccess it */
-		if (bit) {
-			int shift = data->count;
+		address     = bitrev8((data->nec_bits >> 24) & 0xff);
+		not_address = bitrev8((data->nec_bits >> 16) & 0xff);
+		command	    = bitrev8((data->nec_bits >>  8) & 0xff);
+		not_command = bitrev8((data->nec_bits >>  0) & 0xff);
 
-			/*
-			 * NEC transmit bytes on this temporal order:
-			 * address | not address | command | not command
-			 */
-			if (shift < 8) {
-				data->nec_code.address |= 1 << shift;
-			} else if (shift < 16) {
-				data->nec_code.not_address |= 1 << (shift - 8);
-			} else if (shift < 24) {
-				data->nec_code.command |= 1 << (shift - 16);
-			} else {
-				data->nec_code.not_command |= 1 << (shift - 24);
-			}
+		if ((command ^ not_command) != 0xff) {
+			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
+				   data->nec_bits);
+			break;
 		}
-		if (++data->count == NEC_NBITS) {
-			u32 scancode;
-			/*
-			 * Fixme: may need to accept Extended NEC protocol?
-			 */
-			if ((data->nec_code.command ^ data->nec_code.not_command) != 0xff)
-				goto checksum_err;
 
-			if ((data->nec_code.address ^ data->nec_code.not_address) != 0xff) {
-				/* Extended NEC */
-				scancode = data->nec_code.address << 16 |
-					   data->nec_code.not_address << 8 |
-					   data->nec_code.command;
-				IR_dprintk(1, "NEC scancode 0x%06x\n", scancode);
-			} else {
-				/* normal NEC */
-				scancode = data->nec_code.address << 8 |
-					   data->nec_code.command;
-				IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
-			}
-			ir_keydown(input_dev, scancode, 0);
+		if ((address ^ not_address) != 0xff) {
+			/* Extended NEC */
+			scancode = address     << 16 |
+				   not_address <<  8 |
+				   command;
+			IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
+		} else {
+			/* normal NEC */
+			scancode = address << 8 | command;
+			IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
+		}
 
-			data->state = STATE_TRAILER_MARK;
-		} else
-			data->state = STATE_MARK;
-		return 0;
-	case STATE_TRAILER_MARK:
-		if (!last_bit)
-			goto err;
-		data->state = STATE_TRAILER_SPACE;
+		ir_keydown(input_dev, scancode, 0);
+		data->state = STATE_TRAILER_PULSE;
 		return 0;
+
+	case STATE_TRAILER_PULSE:
+		if (u > 0) {
+			data->state = STATE_TRAILER_SPACE;
+			return 0;
+		}
+		break;
+
 	case STATE_TRAILER_SPACE:
-		if (last_bit)
-			goto err;
-		data->state = STATE_INACTIVE;
-		return 0;
+		if (u < 0) {
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+
+		break;
 	}
 
-err:
-	IR_dprintk(1, "NEC decoded failed at state %d (%s) @ %luus\n",
-		   data->state,
-		   bit ? "pulse" : "space",
-		   (ev->delta.tv_nsec + 500) / 1000);
-err2:
+out:
+	IR_dprintk(1, "NEC decode failed at state %d (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
-
-checksum_err:
-	data->state = STATE_INACTIVE;
-	IR_dprintk(1, "NEC checksum error: received 0x%02x%02x%02x%02x\n",
-		   data->nec_code.address,
-		   data->nec_code.not_address,
-		   data->nec_code.command,
-		   data->nec_code.not_command);
-	return -EINVAL;
 }
 
 static int ir_nec_register(struct input_dev *input_dev)
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 5b121d8..3a25d8d 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -15,9 +15,10 @@
 #include <media/ir-core.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/sched.h>
 
-/* Define the max number of bit transitions per IR keycode */
-#define MAX_IR_EVENT_SIZE	256
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE      512
 
 /* Used to handle IR raw handler extensions */
 static LIST_HEAD(ir_raw_handler_list);
@@ -53,19 +54,30 @@ DEFINE_SPINLOCK(ir_raw_handler_lock);
 /* Used to load the decoders */
 static struct work_struct wq_load;
 
+static void ir_raw_event_work(struct work_struct *work)
+{
+	s64 d;
+	struct ir_raw_event_ctrl *raw =
+		container_of(work, struct ir_raw_event_ctrl, rx_work);
+
+	while (kfifo_out(&raw->kfifo, &d, sizeof(d)) == sizeof(d))
+		RUN_DECODER(decode, raw->input_dev, d);
+}
+
 int ir_raw_event_register(struct input_dev *input_dev)
 {
 	struct ir_input_dev *ir = input_get_drvdata(input_dev);
-	int rc, size;
+	int rc;
 
 	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
 	if (!ir->raw)
 		return -ENOMEM;
 
-	size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
-	size = roundup_pow_of_two(size);
+	ir->raw->input_dev = input_dev;
+	INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
 
-	rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
+	rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+			 GFP_KERNEL);
 	if (rc < 0) {
 		kfree(ir->raw);
 		ir->raw = NULL;
@@ -90,6 +102,7 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
 	if (!ir->raw)
 		return;
 
+	cancel_work_sync(&ir->raw->rx_work);
 	RUN_DECODER(raw_unregister, input_dev);
 
 	kfifo_free(&ir->raw->kfifo);
@@ -97,75 +110,91 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
 	ir->raw = NULL;
 }
 
-int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @input_dev:	the struct input_dev device descriptor
+ * @duration:	duration of the pulse or space in ns
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct input_dev *input_dev, s64 duration)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return -EINVAL;
+
+	if (kfifo_in(&ir->raw->kfifo, &duration, sizeof(duration)) != sizeof(duration))
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @input_dev:	the struct input_dev device descriptor
+ * @type:	the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(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;
+	ktime_t			now;
+	s64			delta; /* ns */
+	int			rc = 0;
 
 	if (!ir->raw)
 		return -EINVAL;
 
-	event.type = type;
-	event.delta.tv_sec = 0;
-	event.delta.tv_nsec = 0;
+	now = ktime_get();
+	delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
 
-	ktime_get_ts(&ts);
+	/* Check for a long duration since last event or if we're
+	 * being called for the first time, note that delta can't
+	 * possibly be negative.
+	 */
+	if (delta > NSEC_PER_SEC || !ir->raw->last_type)
+		type |= IR_START_EVENT;
 
-	if (timespec_equal(&ir->raw->last_event, &event.delta))
-		event.type |= IR_START_EVENT;
+	if (type & IR_START_EVENT)
+		ir_raw_event_reset(input_dev);
+	else if (ir->raw->last_type & IR_SPACE)
+		rc = ir_raw_event_store(input_dev, -delta);
+	else if (ir->raw->last_type & IR_PULSE)
+		rc = ir_raw_event_store(input_dev, delta);
 	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		ev;
-	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(ev);
-	if (!len)
 		return 0;
 
-	for (i = 0; i < len; i++) {
-		rc = kfifo_out(&ir->raw->kfifo, &ev, sizeof(ev));
-		if (rc != sizeof(ev)) {
-			IR_dprintk(1, "overflow error: received %d instead of %zd\n",
-				   rc, sizeof(ev));
-			return -EINVAL;
-		}
-		IR_dprintk(2, "event type %d, time before event: %07luus\n",
-			ev.type, (ev.delta.tv_nsec + 500) / 1000);
-		rc = RUN_DECODER(decode, input_dev, &ev);
-	}
-
-	/*
-	 * Call all ir decoders. This allows decoding the same event with
-	 * more than one protocol handler.
-	 */
-
+	ir->raw->last_event = now;
+	ir->raw->last_type = type;
 	return rc;
 }
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @input_dev:	the struct input_dev device descriptor
+ *
+ * This routine will signal the workqueue to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+	if (!ir->raw)
+		return;
+
+	schedule_work(&ir->raw->rx_work);
+}
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
 /*
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index b8a33ae..d6def8c 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -21,11 +21,8 @@
 
 #include <media/ir-core.h>
 
-static unsigned int ir_rc5_remote_gap = 888888;
-
 #define RC5_NBITS		14
-#define RC5_BIT			(ir_rc5_remote_gap * 2)
-#define RC5_DURATION		(ir_rc5_remote_gap * RC5_NBITS)
+#define RC5_UNIT		888888 /* ns */
 
 /* Used to register rc5_decoder clients */
 static LIST_HEAD(decoder_list);
@@ -33,13 +30,9 @@ DEFINE_SPINLOCK(decoder_lock);
 
 enum rc5_state {
 	STATE_INACTIVE,
-	STATE_MARKSPACE,
-	STATE_TRAILER,
-};
-
-struct rc5_code {
-	u8	address;
-	u8	command;
+	STATE_BIT_START,
+	STATE_BIT_END,
+	STATE_FINISHED,
 };
 
 struct decoder_data {
@@ -49,8 +42,9 @@ struct decoder_data {
 
 	/* State machine control */
 	enum rc5_state		state;
-	struct rc5_code		rc5_code;
-	unsigned		code, elapsed, last_bit, last_code;
+	u32			rc5_bits;
+	int			last_unit;
+	unsigned		count;
 };
 
 
@@ -122,18 +116,19 @@ static struct attribute_group decoder_attribute_group = {
 };
 
 /**
- * handle_event() - Decode one RC-5 pulse or space
+ * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
- * @ev:		event array with type/duration of pulse/space
+ * @duration:	duration of pulse/space in ns
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_rc5_decode(struct input_dev *input_dev,
-			struct ir_raw_event *ev)
+static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
 {
 	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	int is_pulse, scancode, delta, toggle;
+	u8 command, system, toggle;
+	u32 scancode;
+	int u;
 
 	data = get_decoder_data(ir_dev);
 	if (!data)
@@ -142,79 +137,84 @@ static int ir_rc5_decode(struct input_dev *input_dev,
 	if (!data->enabled)
 		return 0;
 
-	delta = DIV_ROUND_CLOSEST(ev->delta.tv_nsec, ir_rc5_remote_gap);
-
-	/* The duration time refers to the last bit time */
-	is_pulse = (ev->type & IR_PULSE) ? 1 : 0;
-
-	/* Very long delays are considered as start events */
-	if (delta > RC5_DURATION || (ev->type & IR_START_EVENT))
+	if (IS_RESET(duration)) {
 		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	u = TO_UNITS(duration, RC5_UNIT);
+	if (DURATION(u) == 0)
+		goto out;
+
+again:
+	IR_dprintk(2, "RC5 decode started at state %i (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
+
+	if (DURATION(u) == 0 && data->state != STATE_FINISHED)
+		return 0;
 
 	switch (data->state) {
+
 	case STATE_INACTIVE:
-	IR_dprintk(2, "currently inative. Start bit (%s) @%uus\n",
-		   is_pulse ? "pulse" : "space",
-		   (unsigned)(ev->delta.tv_nsec + 500) / 1000);
+		if (IS_PULSE(u)) {
+			data->state = STATE_BIT_START;
+			data->count = 1;
+			DECREASE_DURATION(u, 1);
+			goto again;
+		}
+		break;
 
-		/* Discards the initial start space */
-		if (!is_pulse)
-			goto err;
-		data->code = 1;
-		data->last_bit = 1;
-		data->elapsed = 0;
-		memset(&data->rc5_code, 0, sizeof(data->rc5_code));
-		data->state = STATE_MARKSPACE;
-		return 0;
-	case STATE_MARKSPACE:
-		if (delta != 1)
-			data->last_bit = data->last_bit ? 0 : 1;
+	case STATE_BIT_START:
+		if (DURATION(u) == 1) {
+			data->rc5_bits <<= 1;
+			if (IS_SPACE(u))
+				data->rc5_bits |= 1;
+			data->count++;
+			data->last_unit = u;
 
-		data->elapsed += delta;
+			/*
+			 * If the last bit is zero, a space will merge
+			 * with the silence after the command.
+			 */
+			if (IS_PULSE(u) && data->count == RC5_NBITS) {
+				data->state = STATE_FINISHED;
+				goto again;
+			}
 
-		if ((data->elapsed % 2) == 1)
+			data->state = STATE_BIT_END;
 			return 0;
+		}
+		break;
 
-		data->code <<= 1;
-		data->code |= data->last_bit;
-
-		/* Fill the 2 unused bits at the command with 0 */
-		if (data->elapsed / 2 == 6)
-			data->code <<= 2;
-
-		if (data->elapsed >= (RC5_NBITS - 1) * 2) {
-			scancode = data->code;
-
-			/* Check for the start bits */
-			if ((scancode & 0xc000) != 0xc000) {
-				IR_dprintk(1, "Code 0x%04x doesn't have two start bits. It is not RC-5\n", scancode);
-				goto err;
-			}
+	case STATE_BIT_END:
+		if (IS_TRANSITION(u, data->last_unit)) {
+			if (data->count == RC5_NBITS)
+				data->state = STATE_FINISHED;
+			else
+				data->state = STATE_BIT_START;
 
-			toggle = (scancode & 0x2000) ? 1 : 0;
+			DECREASE_DURATION(u, 1);
+			goto again;
+		}
+		break;
 
-			if (scancode == data->last_code) {
-				IR_dprintk(1, "RC-5 repeat\n");
-				ir_repeat(input_dev);
-			} else {
-				data->last_code = scancode;
-				scancode &= 0x1fff;
-				IR_dprintk(1, "RC-5 scancode 0x%04x\n", scancode);
+	case STATE_FINISHED:
+		command  = (data->rc5_bits & 0x0003F) >> 0;
+		system   = (data->rc5_bits & 0x007C0) >> 6;
+		toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
+		command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+		scancode = system << 8 | command;
 
-				ir_keydown(input_dev, scancode, 0);
-			}
-			data->state = STATE_TRAILER;
-		}
-		return 0;
-	case STATE_TRAILER:
+		IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
+			   scancode, toggle);
+		ir_keydown(input_dev, scancode, toggle);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-err:
-	IR_dprintk(1, "RC-5 decoded failed at %s @ %luus\n",
-		   is_pulse ? "pulse" : "space",
-		   (ev->delta.tv_nsec + 500) / 1000);
+out:
+	IR_dprintk(1, "RC5 decode failed at state %i (%i units, %ius)\n",
+		   data->state, u, TO_US(duration));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index dc4faaf..e02c5be 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -1017,7 +1017,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
 	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
 	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
 	space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
-	ir_raw_event_store(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
+	ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
 
 
 	/*
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index e9fa94f..e9a0cbf 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -65,14 +65,12 @@ struct ir_dev_props {
 	void			(*close)(void *priv);
 };
 
-struct ir_raw_event {
-	struct timespec		delta;	/* Time spent before event */
-	enum raw_event_type	type;	/* event type */
-};
-
 struct ir_raw_event_ctrl {
-	struct kfifo			kfifo;		/* fifo for the pulse/space events */
-	struct timespec			last_event;	/* when last event occurred */
+	struct work_struct		rx_work;	/* for the rx decoding workqueue */
+	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
+	ktime_t				last_event;	/* when last event occurred */
+	enum raw_event_type		last_type;	/* last event type */
+	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
 };
 
 struct ir_input_dev {
@@ -97,8 +95,7 @@ struct ir_input_dev {
 struct ir_raw_handler {
 	struct list_head list;
 
-	int (*decode)(struct input_dev *input_dev,
-		      struct ir_raw_event *ev);
+	int (*decode)(struct input_dev *input_dev, s64 duration);
 	int (*raw_register)(struct input_dev *input_dev);
 	int (*raw_unregister)(struct input_dev *input_dev);
 };
@@ -154,8 +151,14 @@ void ir_unregister_class(struct input_dev *input_dev);
 /* Routines from ir-raw-event.c */
 int ir_raw_event_register(struct input_dev *input_dev);
 void ir_raw_event_unregister(struct input_dev *input_dev);
-int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type);
-int ir_raw_event_handle(struct input_dev *input_dev);
+void ir_raw_event_handle(struct input_dev *input_dev);
+int ir_raw_event_store(struct input_dev *input_dev, s64 duration);
+int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
+static inline void ir_raw_event_reset(struct input_dev *input_dev)
+{
+	ir_raw_event_store(input_dev, 0);
+	ir_raw_event_handle(input_dev);
+}
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_init(void);
@@ -174,4 +177,26 @@ void ir_raw_init(void);
 #define load_rc5_decode()	0
 #endif
 
+/* macros for ir decoders */
+#define PULSE(units)				((units))
+#define SPACE(units)				(-(units))
+#define IS_RESET(duration)			((duration) == 0)
+#define IS_PULSE(duration)			((duration) > 0)
+#define IS_SPACE(duration)			((duration) < 0)
+#define DURATION(duration)			(abs((duration)))
+#define IS_TRANSITION(x, y)			((x) * (y) < 0)
+#define DECREASE_DURATION(duration, amount)			\
+	do {							\
+		if (IS_SPACE(duration))				\
+			duration += (amount);			\
+		else if (IS_PULSE(duration))			\
+			duration -= (amount);			\
+	} while (0)
+
+#define TO_UNITS(duration, unit_len)				\
+	((int)((duration) > 0 ?					\
+		DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\
+		-DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
+#define TO_US(duration)		((int)TO_UNITS(duration, 1000))
+
 #endif /* _IR_CORE */
-- 
1.6.6.1


--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h
  2010-04-08 19:37 ` [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h Mauro Carvalho Chehab
@ 2010-04-08 21:34   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2010-04-08 21:34 UTC (permalink / raw)
  To: linux-input, Linux Media Mailing List

Mauro Carvalho Chehab wrote:
> ir-core.h has the kABI to be used by the bridge drivers, when needing to register
> IR protocols and pass IR events. However, the same file also contains IR subsystem
> internal calls, meant to be used inside ir-core and between ir-core and the raw
> decoders.
> 
> Better to move those functions to an internal header, for some reasons:
> 
> 1) Header will be a little more cleaner;
> 
> 2) It avoids the need of recompile everything (bridge/hardware drivers, etc),
>    just because a new decoder were added, or some other internal change were needed;
> 
> 3) Better organize the ir-core API, splitting the functions that are internal to
>    IR core and the ancillary drivers (decoders, lirc_dev) from the features that
>    should be exported to IR subsystem clients.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> 
>  create mode 100644 drivers/media/IR/ir-core-priv.h

This cleanup were too aggressive:

drivers/media/dvb/ttpci/budget-ci.c: In function ‘msp430_ir_interrupt’:
drivers/media/dvb/ttpci/budget-ci.c:163: error: implicit declaration of function ‘ir_keydown’

We need ir_keydown() / ir_repeat() for in-hardware decoders. I'm folding it
with this patch:

diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index ab785bc..8d97d6c 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -62,8 +62,6 @@ struct ir_raw_event_ctrl {
 
 u32 ir_g_keycode_from_table(struct input_dev *input_dev,
                            u32 scancode);
-void ir_repeat(struct input_dev *dev);
-void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
 
 /*
  * Routines from ir-sysfs.c - Meant to be called only internally inside
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index 40b6250..ab3bd30 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -122,6 +122,9 @@ static inline int ir_input_register(struct input_dev *dev,
 
 void ir_input_unregister(struct input_dev *input_dev);
 
+void ir_repeat(struct input_dev *dev);
+void ir_keydown(struct input_dev *dev, int scancode, u8 toggle);
+
 /* From ir-raw-event.c */
 
 void ir_raw_event_handle(struct input_dev *input_dev);



-- 

Cheers,
Mauro

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-04-08 21:34 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <cover.1270754989.git.mchehab@redhat.com>
2010-04-08 19:37 ` [PATCH 8/8] V4L/DVB: ir-core: move subsystem internal calls to ir-core-priv.h Mauro Carvalho Chehab
2010-04-08 21:34   ` Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 6/8] V4L/DVB: ir-core: fix gcc warning noise Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 4/8] V4L/DVB: ir-core: Distinguish sysfs attributes for in-hardware and raw decoders Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 3/8] V4L/DVB: rename sysfs remote controller devices from rcrcv to rc Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 5/8] V4L/DVB: ir-core: properly present the supported and current protocols Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 7/8] V4L/DVB: Teach drivers/media/IR/ir-raw-event.c to use durations Mauro Carvalho Chehab
2010-04-08 19:37   ` Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 2/8] V4L/DVB: ir: Make sure that the spinlocks are properly initialized Mauro Carvalho Chehab
2010-04-08 19:37 ` [PATCH 1/8] V4L/DVB: em28xx: fix a regression caused by the rc-map changes Mauro Carvalho Chehab

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.