linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/49] rc-core: my current patch queue
@ 2014-04-03 23:31 David Härdeman
  2014-04-03 23:31 ` [PATCH 01/49] bt8xx: fixup RC5 decoding David Härdeman
                   ` (50 more replies)
  0 siblings, 51 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The following patches is what I currenly have in my queue:

Patches 1 - 6 should be ok to be committed right now, they contain
some fixes and some reverts (of the NEC32 and generic scancode
functionality).

Patches 7 - 9 are in no hurry and can wait for 3.16, some testing
would be nice even though I believe they are ok.

Patches 10 and 11 are RFC's for the NEC32 scancode handling.

The remaining patches are more of an FYI. It's basically the same
patchset that I've posted a long time ago, but respun to apply to
the current tree. They implement a modern chardev for rc-core which
allows the functionality that has so far only been available through
the LIRC bridge to be exposed to userspace and provide a (hopefully)
sane API for taking advantage of all the features that rc-core
provides (RX, TX, ioctl) as well as some new features (multiple
keymaps is probably the most important one). Lots and lots of cleanups
as well.

Enjoy :)

---

David Härdeman (49):
      bt8xx: fixup RC5 decoding
      rc-core: improve ir-kbd-i2c get_key functions
      rc-core: document the protocol type
      rc-core: do not change 32bit NEC scancode format for now
      rc-core: split dev->s_filter
      rc-core: remove generic scancode filter
      dib0700: NEC scancode cleanup
      lmedm04: NEC scancode cleanup
      saa7134: NEC scancode fix
      [RFC] rc-core: use the full 32 bits for NEC scancodes
      [RFC] rc-core: don't throw away protocol information
      rc-core: simplify sysfs code
      rc-core: remove protocol arrays
      rc-core: rename dev->scanmask to dev->scancode_mask
      rc-core: merge rc5 and streamzap decoders
      rc-core: use an IDA rather than a bitmap
      rc-core: add chardev
      rc-core: allow chardev to be read
      rc-core: use a kfifo for TX data
      rc-core: allow chardev to be written
      rc-core: add ioctl support to the rc chardev
      rc-core: add an ioctl for getting IR RX settings
      rc-loopback: add RCIOCGIRRX ioctl support
      rc-core: add an ioctl for setting IR RX settings
      rc-loopback: add RCIOCSIRRX ioctl support
      rc-core: add an ioctl for getting IR TX settings
      rc-loopback: add RCIOCGIRTX ioctl support
      rc-core: add an ioctl for setting IR TX settings
      rc-loopback: add RCIOCSIRTX ioctl support
      rc-core: leave the internals of rc_dev alone
      rc-core: split rc-main.c into rc-main.c and rc-keytable.c
      rc-core: prepare for multiple keytables
      rc-core: make the keytable of rc_dev an array
      rc-core: add ioctls for adding/removing keytables from userspace
      rc-core: remove redundant spinlock
      rc-core: make keytable RCU-friendly
      rc-core: allow empty keymaps
      rc-core: rename ir-raw.c
      rc-core: make IR raw handling a separate module
      rc-ir-raw: simplify locking
      rc-core: rename mutex
      rc-ir-raw: atomic reads of protocols
      rc-core: fix various sparse warnings
      rc-core: don't report scancodes via input devices
      rc-ir-raw: add various rc_events
      rc-core: use struct rc_event for all rc communication
      rc-core: add keytable events
      rc-core: move remaining keytable functions
      rc-core: make rc-core.h userspace friendly


 Documentation/ioctl/ioctl-number.txt        |    1 
 drivers/hid/hid-picolcd_cir.c               |   20 
 drivers/media/common/siano/smsir.c          |   14 
 drivers/media/common/siano/smsir.h          |    2 
 drivers/media/i2c/cx25840/cx25840-ir.c      |   96 +
 drivers/media/i2c/ir-kbd-i2c.c              |   99 +
 drivers/media/pci/bt8xx/bttv-input.c        |   78 +
 drivers/media/pci/bt8xx/bttvp.h             |    2 
 drivers/media/pci/cx23885/cx23885-input.c   |   26 
 drivers/media/pci/cx23885/cx23888-ir.c      |   93 +
 drivers/media/pci/cx88/cx88-input.c         |   75 +
 drivers/media/pci/dm1105/dm1105.c           |    4 
 drivers/media/pci/ivtv/ivtv-i2c.c           |   11 
 drivers/media/pci/saa7134/saa7134-input.c   |  100 +
 drivers/media/pci/saa7134/saa7134.h         |    2 
 drivers/media/pci/ttpci/budget-ci.c         |   10 
 drivers/media/rc/Kconfig                    |   12 
 drivers/media/rc/Makefile                   |    4 
 drivers/media/rc/ati_remote.c               |   11 
 drivers/media/rc/ene_ir.c                   |   84 +
 drivers/media/rc/ene_ir.h                   |    9 
 drivers/media/rc/fintek-cir.c               |   34 
 drivers/media/rc/gpio-ir-recv.c             |   15 
 drivers/media/rc/iguanair.c                 |   77 +
 drivers/media/rc/img-ir/img-ir-hw.c         |   48 -
 drivers/media/rc/img-ir/img-ir-hw.h         |    3 
 drivers/media/rc/img-ir/img-ir-jvc.c        |    4 
 drivers/media/rc/img-ir/img-ir-nec.c        |   80 -
 drivers/media/rc/img-ir/img-ir-raw.c        |    8 
 drivers/media/rc/img-ir/img-ir-sanyo.c      |    4 
 drivers/media/rc/img-ir/img-ir-sharp.c      |    4 
 drivers/media/rc/img-ir/img-ir-sony.c       |   12 
 drivers/media/rc/imon.c                     |   33 
 drivers/media/rc/ir-jvc-decoder.c           |   52 -
 drivers/media/rc/ir-lirc-codec.c            |  225 ++-
 drivers/media/rc/ir-mce_kbd-decoder.c       |   36 
 drivers/media/rc/ir-nec-decoder.c           |   96 -
 drivers/media/rc/ir-rc5-decoder.c           |  113 +-
 drivers/media/rc/ir-rc5-sz-decoder.c        |  154 --
 drivers/media/rc/ir-rc6-decoder.c           |   91 +
 drivers/media/rc/ir-sanyo-decoder.c         |   60 -
 drivers/media/rc/ir-sharp-decoder.c         |   53 -
 drivers/media/rc/ir-sony-decoder.c          |   58 -
 drivers/media/rc/ite-cir.c                  |   69 -
 drivers/media/rc/ite-cir.h                  |    2 
 drivers/media/rc/keymaps/rc-behold.c        |   68 -
 drivers/media/rc/keymaps/rc-lme2510.c       |  132 +-
 drivers/media/rc/keymaps/rc-nebula.c        |  112 +-
 drivers/media/rc/keymaps/rc-streamzap.c     |    4 
 drivers/media/rc/keymaps/rc-tivo.c          |   95 +
 drivers/media/rc/mceusb.c                   |   67 +
 drivers/media/rc/nuvoton-cir.c              |   88 +
 drivers/media/rc/nuvoton-cir.h              |    9 
 drivers/media/rc/rc-core-priv.h             |  122 +-
 drivers/media/rc/rc-ir-raw.c                |  284 ++--
 drivers/media/rc/rc-keytable.c              |  958 +++++++++++++
 drivers/media/rc/rc-loopback.c              |  200 ++-
 drivers/media/rc/rc-main.c                  | 1974 ++++++++++++---------------
 drivers/media/rc/redrat3.c                  |  156 +-
 drivers/media/rc/st_rc.c                    |    2 
 drivers/media/rc/streamzap.c                |   81 -
 drivers/media/rc/ttusbir.c                  |   42 -
 drivers/media/rc/winbond-cir.c              |  113 +-
 drivers/media/usb/cx231xx/cx231xx-input.c   |   31 
 drivers/media/usb/dvb-usb-v2/af9015.c       |   26 
 drivers/media/usb/dvb-usb-v2/af9035.c       |   20 
 drivers/media/usb/dvb-usb-v2/anysee.c       |    3 
 drivers/media/usb/dvb-usb-v2/az6007.c       |   21 
 drivers/media/usb/dvb-usb-v2/dvb_usb.h      |    5 
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |   14 
 drivers/media/usb/dvb-usb-v2/lmedm04.c      |   22 
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c     |   30 
 drivers/media/usb/dvb-usb/dib0700_core.c    |   39 -
 drivers/media/usb/dvb-usb/dib0700_devices.c |   24 
 drivers/media/usb/dvb-usb/dvb-usb-remote.c  |   15 
 drivers/media/usb/dvb-usb/dvb-usb.h         |    5 
 drivers/media/usb/dvb-usb/dw2102.c          |    7 
 drivers/media/usb/dvb-usb/m920x.c           |    2 
 drivers/media/usb/dvb-usb/pctv452e.c        |    8 
 drivers/media/usb/dvb-usb/technisat-usb2.c  |   17 
 drivers/media/usb/dvb-usb/ttusb2.c          |    6 
 drivers/media/usb/em28xx/em28xx-cards.c     |    1 
 drivers/media/usb/em28xx/em28xx-input.c     |  111 +-
 drivers/media/usb/tm6000/tm6000-input.c     |   60 +
 include/media/ir-kbd-i2c.h                  |    6 
 include/media/rc-core.h                     |  473 ++++--
 include/media/rc-ir-raw.h                   |   68 +
 include/media/rc-map.h                      |   28 
 88 files changed, 4344 insertions(+), 3289 deletions(-)
 delete mode 100644 drivers/media/rc/ir-rc5-sz-decoder.c
 rename drivers/media/rc/{ir-raw.c => rc-ir-raw.c} (52%)
 create mode 100644 drivers/media/rc/rc-keytable.c
 create mode 100644 include/media/rc-ir-raw.h

--
David Härdeman


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

* [PATCH 01/49] bt8xx: fixup RC5 decoding
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-03 23:31 ` [PATCH 02/49] rc-core: improve ir-kbd-i2c get_key functions David Härdeman
                   ` (49 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The bt8xx driver does RC5 decoding for Nebula digi hardware, but includes
some pointless limitations (both start bits must be one, the
device/address/system must be 0x00). Remove those limitations and update
the keymap to use the full RC5 scancode (fortunately the 0x00 address
means that this is perfectly backwards compatible).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/pci/bt8xx/bttv-input.c |   62 ++++++++++---------
 drivers/media/pci/bt8xx/bttvp.h      |    2 -
 drivers/media/rc/keymaps/rc-nebula.c |  112 +++++++++++++++++-----------------
 3 files changed, 88 insertions(+), 88 deletions(-)

diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index 5930bce..ffc0ee1 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -154,10 +154,10 @@ static void bttv_input_timer(unsigned long data)
  * testing.
  */
 
-#define RC5_START(x)	(((x) >> 12) & 3)
-#define RC5_TOGGLE(x)	(((x) >> 11) & 1)
-#define RC5_ADDR(x)	(((x) >> 6) & 31)
-#define RC5_INSTR(x)	((x) & 63)
+#define RC5_START(x)	(((x) >> 12) & 0x03)
+#define RC5_TOGGLE(x)	(((x) >> 11) & 0x01)
+#define RC5_ADDR(x)	(((x) >> 6)  & 0x1f)
+#define RC5_INSTR(x)	(((x) >> 0)  & 0x3f)
 
 /* decode raw bit pattern to RC5 code */
 static u32 bttv_rc5_decode(unsigned int code)
@@ -195,8 +195,8 @@ static void bttv_rc5_timer_end(unsigned long data)
 {
 	struct bttv_ir *ir = (struct bttv_ir *)data;
 	struct timeval tv;
-	u32 gap;
-	u32 rc5 = 0;
+	u32 gap, rc5, scancode;
+	u8 toggle, command, system;
 
 	/* get time */
 	do_gettimeofday(&tv);
@@ -221,26 +221,29 @@ static void bttv_rc5_timer_end(unsigned long data)
 	if (ir->last_bit < 20) {
 		/* ignore spurious codes (caused by light/other remotes) */
 		dprintk("short code: %x\n", ir->code);
-	} else {
-		ir->code = (ir->code << ir->shift_by) | 1;
-		rc5 = bttv_rc5_decode(ir->code);
-
-		/* two start bits? */
-		if (RC5_START(rc5) != ir->start) {
-			pr_info(DEVNAME ":"
-			       " rc5 start bits invalid: %u\n", RC5_START(rc5));
-
-			/* right address? */
-		} else if (RC5_ADDR(rc5) == ir->addr) {
-			u32 toggle = RC5_TOGGLE(rc5);
-			u32 instr = RC5_INSTR(rc5);
-
-			/* Good code */
-			rc_keydown(ir->dev, instr, toggle);
-			dprintk("instruction %x, toggle %x\n",
-				instr, toggle);
-		}
+		return;
 	}
+
+	ir->code = (ir->code << ir->shift_by) | 1;
+	rc5 = bttv_rc5_decode(ir->code);
+
+	toggle = RC5_TOGGLE(rc5);
+	system = RC5_ADDR(rc5);
+	command = RC5_INSTR(rc5);
+
+	switch (RC5_START(rc5)) {
+	case 0x3:
+		break;
+	case 0x2:
+		command += 0x40;
+		break;
+	default:
+		return;
+	}
+
+	scancode = system << 8 | command;
+	rc_keydown(ir->dev, scancode, toggle);
+	dprintk("scancode %x, toggle %x\n", scancode, toggle);
 }
 
 static int bttv_rc5_irq(struct bttv *btv)
@@ -310,8 +313,6 @@ static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
 		/* set timer_end for code completion */
 		setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
 		ir->shift_by = 1;
-		ir->start = 3;
-		ir->addr = 0x0;
 		ir->rc5_remote_gap = ir_rc5_remote_gap;
 	}
 }
@@ -490,8 +491,8 @@ int bttv_input_init(struct bttv *btv)
 		ir->polling      = 50; // ms
 		break;
 	case BTTV_BOARD_NEBULA_DIGITV:
-		ir_codes = RC_MAP_NEBULA;
-		ir->rc5_gpio = true;
+		ir_codes         = RC_MAP_NEBULA;
+		ir->rc5_gpio     = true;
 		break;
 	case BTTV_BOARD_MACHTV_MAGICTV:
 		ir_codes         = RC_MAP_APAC_VIEWCOMP;
@@ -514,7 +515,8 @@ int bttv_input_init(struct bttv *btv)
 						   ir->mask_keycode);
 		break;
 	}
-	if (NULL == ir_codes) {
+
+	if (!ir_codes) {
 		dprintk("Ooops: IR config error [card=%d]\n", btv->c.type);
 		err = -ENODEV;
 		goto err_out_free;
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 6eefb59..9fe19488 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -133,8 +133,6 @@ struct bttv_ir {
 	u32                     polling;
 	u32                     last_gpio;
 	int                     shift_by;
-	int                     start; // What should RC5_START() be
-	int                     addr; // What RC5_ADDR() should be.
 	int                     rc5_remote_gap;
 
 	/* RC5 gpio */
diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index 8ec881a..4c50f33 100644
--- a/drivers/media/rc/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -14,68 +14,68 @@
 #include <linux/module.h>
 
 static struct rc_map_table nebula[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x0a, KEY_TV },
-	{ 0x0b, KEY_AUX },
-	{ 0x0c, KEY_DVD },
-	{ 0x0d, KEY_POWER },
-	{ 0x0e, KEY_CAMERA },	/* labelled 'Picture' */
-	{ 0x0f, KEY_AUDIO },
-	{ 0x10, KEY_INFO },
-	{ 0x11, KEY_F13 },	/* 16:9 */
-	{ 0x12, KEY_F14 },	/* 14:9 */
-	{ 0x13, KEY_EPG },
-	{ 0x14, KEY_EXIT },
-	{ 0x15, KEY_MENU },
-	{ 0x16, KEY_UP },
-	{ 0x17, KEY_DOWN },
-	{ 0x18, KEY_LEFT },
-	{ 0x19, KEY_RIGHT },
-	{ 0x1a, KEY_ENTER },
-	{ 0x1b, KEY_CHANNELUP },
-	{ 0x1c, KEY_CHANNELDOWN },
-	{ 0x1d, KEY_VOLUMEUP },
-	{ 0x1e, KEY_VOLUMEDOWN },
-	{ 0x1f, KEY_RED },
-	{ 0x20, KEY_GREEN },
-	{ 0x21, KEY_YELLOW },
-	{ 0x22, KEY_BLUE },
-	{ 0x23, KEY_SUBTITLE },
-	{ 0x24, KEY_F15 },	/* AD */
-	{ 0x25, KEY_TEXT },
-	{ 0x26, KEY_MUTE },
-	{ 0x27, KEY_REWIND },
-	{ 0x28, KEY_STOP },
-	{ 0x29, KEY_PLAY },
-	{ 0x2a, KEY_FASTFORWARD },
-	{ 0x2b, KEY_F16 },	/* chapter */
-	{ 0x2c, KEY_PAUSE },
-	{ 0x2d, KEY_PLAY },
-	{ 0x2e, KEY_RECORD },
-	{ 0x2f, KEY_F17 },	/* picture in picture */
-	{ 0x30, KEY_KPPLUS },	/* zoom in */
-	{ 0x31, KEY_KPMINUS },	/* zoom out */
-	{ 0x32, KEY_F18 },	/* capture */
-	{ 0x33, KEY_F19 },	/* web */
-	{ 0x34, KEY_EMAIL },
-	{ 0x35, KEY_PHONE },
-	{ 0x36, KEY_PC },
+	{ 0x0000, KEY_0 },
+	{ 0x0001, KEY_1 },
+	{ 0x0002, KEY_2 },
+	{ 0x0003, KEY_3 },
+	{ 0x0004, KEY_4 },
+	{ 0x0005, KEY_5 },
+	{ 0x0006, KEY_6 },
+	{ 0x0007, KEY_7 },
+	{ 0x0008, KEY_8 },
+	{ 0x0009, KEY_9 },
+	{ 0x000a, KEY_TV },
+	{ 0x000b, KEY_AUX },
+	{ 0x000c, KEY_DVD },
+	{ 0x000d, KEY_POWER },
+	{ 0x000e, KEY_CAMERA },	/* labelled 'Picture' */
+	{ 0x000f, KEY_AUDIO },
+	{ 0x0010, KEY_INFO },
+	{ 0x0011, KEY_F13 },	/* 16:9 */
+	{ 0x0012, KEY_F14 },	/* 14:9 */
+	{ 0x0013, KEY_EPG },
+	{ 0x0014, KEY_EXIT },
+	{ 0x0015, KEY_MENU },
+	{ 0x0016, KEY_UP },
+	{ 0x0017, KEY_DOWN },
+	{ 0x0018, KEY_LEFT },
+	{ 0x0019, KEY_RIGHT },
+	{ 0x001a, KEY_ENTER },
+	{ 0x001b, KEY_CHANNELUP },
+	{ 0x001c, KEY_CHANNELDOWN },
+	{ 0x001d, KEY_VOLUMEUP },
+	{ 0x001e, KEY_VOLUMEDOWN },
+	{ 0x001f, KEY_RED },
+	{ 0x0020, KEY_GREEN },
+	{ 0x0021, KEY_YELLOW },
+	{ 0x0022, KEY_BLUE },
+	{ 0x0023, KEY_SUBTITLE },
+	{ 0x0024, KEY_F15 },	/* AD */
+	{ 0x0025, KEY_TEXT },
+	{ 0x0026, KEY_MUTE },
+	{ 0x0027, KEY_REWIND },
+	{ 0x0028, KEY_STOP },
+	{ 0x0029, KEY_PLAY },
+	{ 0x002a, KEY_FASTFORWARD },
+	{ 0x002b, KEY_F16 },	/* chapter */
+	{ 0x002c, KEY_PAUSE },
+	{ 0x002d, KEY_PLAY },
+	{ 0x002e, KEY_RECORD },
+	{ 0x002f, KEY_F17 },	/* picture in picture */
+	{ 0x0030, KEY_KPPLUS },	/* zoom in */
+	{ 0x0031, KEY_KPMINUS },	/* zoom out */
+	{ 0x0032, KEY_F18 },	/* capture */
+	{ 0x0033, KEY_F19 },	/* web */
+	{ 0x0034, KEY_EMAIL },
+	{ 0x0035, KEY_PHONE },
+	{ 0x0036, KEY_PC },
 };
 
 static struct rc_map_list nebula_map = {
 	.map = {
 		.scan    = nebula,
 		.size    = ARRAY_SIZE(nebula),
-		.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */
+		.rc_type = RC_TYPE_RC5,
 		.name    = RC_MAP_NEBULA,
 	}
 };


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

* [PATCH 02/49] rc-core: improve ir-kbd-i2c get_key functions
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
  2014-04-03 23:31 ` [PATCH 01/49] bt8xx: fixup RC5 decoding David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-03 23:31 ` [PATCH 03/49] rc-core: document the protocol type David Härdeman
                   ` (48 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The arguments used for ir-kbd-i2c's get_key() functions are not
really suited for rc-core and the ir_raw/ir_key distinction is
just confusing.

Convert all of them to return a protocol/scancode/toggle triple instead.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/i2c/ir-kbd-i2c.c            |   90 +++++++++++++++--------------
 drivers/media/pci/bt8xx/bttv-input.c      |    8 ++-
 drivers/media/pci/cx88/cx88-input.c       |    8 ++-
 drivers/media/pci/ivtv/ivtv-i2c.c         |    9 ++-
 drivers/media/pci/saa7134/saa7134-input.c |   76 +++++++++++++++---------
 drivers/media/usb/cx231xx/cx231xx-input.c |   20 ++----
 include/media/ir-kbd-i2c.h                |    6 +-
 include/media/rc-map.h                    |   10 +++
 8 files changed, 127 insertions(+), 100 deletions(-)

diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index c8fe135..143cb2b 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -62,8 +62,8 @@ module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
-			       int size, int offset)
+static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol,
+			       u32 *scancode, u8 *ptoggle, int size, int offset)
 {
 	unsigned char buf[6];
 	int start, range, toggle, dev, code, ircode;
@@ -86,19 +86,10 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 	if (!start)
 		/* no key pressed */
 		return 0;
-	/*
-	 * Hauppauge remotes (black/silver) always use
-	 * specific device ids. If we do not filter the
-	 * device ids then messages destined for devices
-	 * such as TVs (id=0) will get through causing
-	 * mis-fired events.
-	 *
-	 * We also filter out invalid key presses which
-	 * produce annoying debug log entries.
-	 */
-	ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
-	if ((ircode & 0x1fff)==0x1fff)
-		/* invalid key press */
+
+	/* filter out invalid key presses */
+	ircode = (start << 12) | (toggle << 11) | (dev << 6) | code;
+	if ((ircode & 0x1fff) == 0x1fff)
 		return 0;
 
 	if (!range)
@@ -107,18 +98,20 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 	dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
 		start, range, toggle, dev, code);
 
-	/* return key */
-	*ir_key = (dev << 8) | code;
-	*ir_raw = ircode;
+	*protocol = RC_TYPE_RC5;
+	*scancode = RC_SCANCODE_RC5(dev, code);
+	*ptoggle = toggle;
 	return 1;
 }
 
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol,
+			u32 *scancode, u8 *toggle)
 {
-	return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+	return get_key_haup_common (ir, protocol, scancode, toggle, 3, 0);
 }
 
-static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol,
+			    u32 *scancode, u8 *toggle)
 {
 	int ret;
 	unsigned char buf[1] = { 0 };
@@ -133,10 +126,11 @@ static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if (ret != 1)
 		return (ret < 0) ? ret : -EINVAL;
 
-	return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+	return get_key_haup_common(ir, protocol, scancode, toggle, 6, 3);
 }
 
-static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol,
+			     u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -145,12 +139,15 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 		dprintk(1,"read error\n");
 		return -EIO;
 	}
-	*ir_key = b;
-	*ir_raw = b;
+
+	*protocol = RC_TYPE_OTHER;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_type *protocol,
+			      u32 *scancode, u8 *toggle)
 {
 	unsigned char buf[4];
 
@@ -168,13 +165,14 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if(buf[0] != 0x1 ||  buf[1] != 0xfe)
 		return 0;
 
-	*ir_key = buf[2];
-	*ir_raw = (buf[2] << 8) | buf[3];
-
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = buf[2];
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, enum rc_type *protocol,
+			u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -197,13 +195,14 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 		/* keep old data */
 		return 1;
 
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_avermedia_cardbus(struct IR_i2c *ir,
-				     u32 *ir_key, u32 *ir_raw)
+static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol,
+				     u32 *scancode, u8 *toggle)
 {
 	unsigned char subaddr, key, keygroup;
 	struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
@@ -237,12 +236,11 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 	}
 	key |= (keygroup & 1) << 6;
 
-	*ir_key = key;
-	*ir_raw = key;
-	if (!strcmp(ir->ir_codes, RC_MAP_AVERMEDIA_M733A_RM_K6)) {
-		*ir_key |= keygroup << 8;
-		*ir_raw |= keygroup << 8;
-	}
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = key;
+	if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */
+		*scancode |= keygroup << 8;
+	*toggle = 0;
 	return 1;
 }
 
@@ -250,19 +248,21 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 
 static int ir_key_poll(struct IR_i2c *ir)
 {
-	static u32 ir_key, ir_raw;
+	enum rc_type protocol;
+	u32 scancode;
+	u8 toggle;
 	int rc;
 
 	dprintk(3, "%s\n", __func__);
-	rc = ir->get_key(ir, &ir_key, &ir_raw);
+	rc = ir->get_key(ir, &protocol, &scancode, &toggle);
 	if (rc < 0) {
 		dprintk(2,"error\n");
 		return rc;
 	}
 
 	if (rc) {
-		dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
-		rc_keydown(ir->rc, ir_key, 0);
+		dprintk(1, "%s: scancode = 0x%08x\n", __func__, scancode);
+		rc_keydown(ir->rc, scancode, toggle);
 	}
 	return 0;
 }
@@ -327,7 +327,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	case 0x6b:
 		name        = "FusionHDTV";
 		ir->get_key = get_key_fusionhdtv;
-		rc_type     = RC_BIT_RC5;
+		rc_type     = RC_BIT_UNKNOWN;
 		ir_codes    = RC_MAP_FUSIONHDTV_MCE;
 		break;
 	case 0x40:
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index ffc0ee1..e745f5a 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -336,7 +336,8 @@ static void bttv_ir_stop(struct bttv *btv)
  * Get_key functions used by I2C remotes
  */
 
-static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol,
+			 u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -363,8 +364,9 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	 * 	   the device is bound to the vendor-provided RC.
 	 */
 
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index f991696..779fc63 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -539,7 +539,8 @@ void cx88_ir_irq(struct cx88_core *core)
 	ir_raw_event_handle(ir->dev);
 }
 
-static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol,
+			   u32 *scancode, u8 *toggle)
 {
 	int flags, code;
 
@@ -563,8 +564,9 @@ static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
 		   code & 0xff, flags & 0xff);
 
-	*ir_key = code & 0xff;
-	*ir_raw = code;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = code & 0xff;
+	*toggle = 0;
 	return 1;
 }
 
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index ceed2d8..1a41ba5 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -148,7 +148,8 @@ static const char * const hw_devicenames[] = {
 	"ir_video",		/* IVTV_HW_I2C_IR_RX_ADAPTEC */
 };
 
-static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol,
+			   u32 *scancode, u8 *toggle)
 {
 	unsigned char keybuf[4];
 
@@ -167,9 +168,9 @@ static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	keybuf[2] &= 0x7f;
 	keybuf[3] |= 0x80;
 
-	*ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
-	*ir_raw = *ir_key;
-
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
+	*toggle = 0;
 	return 1;
 }
 
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 6f43126..73670ed 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -108,7 +108,8 @@ static int build_key(struct saa7134_dev *dev)
 
 /* --------------------- Chip specific I2C key builders ----------------- */
 
-static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol,
+			       u32 *scancode, u8 *toggle)
 {
 	int gpio;
 	int attempt = 0;
@@ -158,13 +159,14 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 		return -EIO;
 	}
 
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
-				       u32 *ir_raw)
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol,
+				       u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 	int gpio;
@@ -205,14 +207,15 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
 	/* Button pressed */
 
 	dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
 /* copied and modified from get_key_msi_tvanywhere_plus() */
-static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
-					u32 *ir_raw)
+static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol,
+				 u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 	unsigned int gpio;
@@ -253,12 +256,14 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
 	/* Button pressed */
 
 	dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol,
+			    u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -276,12 +281,14 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if (b & 0x80)
 		return 1;
 
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol,
+			   u32 *scancode, u8 *toggle)
 {
 	unsigned char buf[5];
 
@@ -299,14 +306,20 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	 * by preserving it into two separate readings
 	 * buf[4] bits 0 and 1, and buf[1] and buf[2] are always
 	 * zero.
+	 *
+	 * Note that the keymap which the hvr1110 uses is RC5.
+	 *
+	 * FIXME: start bits could maybe be used...?
 	 */
-	*ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2));
-	*ir_raw = *ir_key;
+	*protocol = RC_TYPE_RC5;
+	*scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2);
+	*toggle = !!(buf[3] & 0x40);
 	return 1;
 }
 
 
-static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol,
+			      u32 *scancode, u8 *toggle)
 {
 	unsigned char data[12];
 	u32 gpio;
@@ -332,17 +345,18 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if (data[9] != (unsigned char)(~data[8]))
 		return 0;
 
-	*ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
-	*ir_key = *ir_raw;
-
+	*protocol = RC_TYPE_NEC;
+	*scancode = RC_SCANCODE_NECX(((data[10] << 8) | data[11]), data[9]);
+	*toggle = 0;
 	return 1;
 }
 
 /* Common (grey or coloured) pinnacle PCTV remote handling
  *
  */
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
-			    int parity_offset, int marker, int code_modulo)
+static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol,
+			    u32 *scancode, u8 *toggle, int parity_offset,
+			    int marker, int code_modulo)
 {
 	unsigned char b[4];
 	unsigned int start = 0,parity = 0,code = 0;
@@ -377,11 +391,11 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 
 	code %= code_modulo;
 
-	*ir_raw = code;
-	*ir_key = code;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = code;
+	*toggle = 0;
 
 	i2cdprintk("Pinnacle PCTV key %02x\n", code);
-
 	return 1;
 }
 
@@ -394,10 +408,11 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
  *
  * Sylvain Pasche <sylvain.pasche@gmail.com>
  */
-static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol,
+				 u32 *scancode, u8 *toggle)
 {
 
-	return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+	return get_key_pinnacle(ir, protocol, scancode, toggle, 1, 0xfe, 0xff);
 }
 
 
@@ -405,7 +420,8 @@ static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
  *
  * Ricardo Cerqueira <v4l@cerqueira.org>
  */
-static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_type *protocol,
+				  u32 *scancode, u8 *toggle)
 {
 	/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
 	 *
@@ -413,7 +429,7 @@ static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	 * codes < 128
 	 */
 
-	return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+	return get_key_pinnacle(ir, protocol, scancode, toggle, 2, 0x80, 0x88);
 }
 
 void saa7134_input_irq(struct saa7134_dev *dev)
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 46d52fa..adcdd92 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -21,11 +21,12 @@
 #include "cx231xx.h"
 #include <linux/usb.h>
 #include <linux/slab.h>
+#include <linux/bitrev.h>
 
 #define MODULE_NAME "cx231xx-input"
 
-static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
-			 u32 *ir_raw)
+static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
+			 u32 *pscancode, u8 *toggle)
 {
 	int	rc;
 	u8	cmd, scancode;
@@ -46,21 +47,14 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
 	if (cmd == 0xff)
 		return 0;
 
-	scancode =
-		 ((cmd & 0x01) ? 0x80 : 0) |
-		 ((cmd & 0x02) ? 0x40 : 0) |
-		 ((cmd & 0x04) ? 0x20 : 0) |
-		 ((cmd & 0x08) ? 0x10 : 0) |
-		 ((cmd & 0x10) ? 0x08 : 0) |
-		 ((cmd & 0x20) ? 0x04 : 0) |
-		 ((cmd & 0x40) ? 0x02 : 0) |
-		 ((cmd & 0x80) ? 0x01 : 0);
+	scancode = bitrev8(cmd);
 
 	dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
 		cmd, scancode);
 
-	*ir_key = scancode;
-	*ir_raw = scancode;
+	*protocol = RC_TYPE_OTHER;
+	*pscancode = scancode;
+	*toggle = 0;
 	return 1;
 }
 
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index e221bc7..d856435 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -20,7 +20,8 @@ struct IR_i2c {
 	struct delayed_work    work;
 	char                   name[32];
 	char                   phys[32];
-	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+	int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
+					  u32 *scancode, u8 *toggle);
 };
 
 enum ir_kbd_get_key_fn {
@@ -44,7 +45,8 @@ struct IR_i2c_init_data {
 	 * Specify either a function pointer or a value indicating one of
 	 * ir_kbd_i2c's internal get_key functions
 	 */
-	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+	int                    (*get_key)(struct IR_i2c *ir, enum rc_type *protocol,
+					  u32 *scancode, u8 *toggle);
 	enum ir_kbd_get_key_fn internal_get_key_func;
 
 	struct rc_dev		*rc_dev;
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index e5aa240..894c7e4 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -62,6 +62,16 @@ enum rc_type {
 			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP)
 
+#define RC_SCANCODE_UNKNOWN(x)			(x)
+#define RC_SCANCODE_OTHER(x)			(x)
+#define RC_SCANCODE_NEC(addr, cmd)		(((addr) << 8) | (cmd))
+#define RC_SCANCODE_NECX(addr, cmd)		(((addr) << 8) | (cmd))
+#define RC_SCANCODE_NEC32(data)			((data) & 0xffffffff)
+#define RC_SCANCODE_RC5(sys, cmd)		(((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC5_SZ(sys, cmd)		(((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC6_0(sys, cmd)		(((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC6_6A(vendor, sys, cmd)	(((vendor) << 16) | ((sys) << 8) | (cmd))
+
 struct rc_map_table {
 	u32	scancode;
 	u32	keycode;


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

* [PATCH 03/49] rc-core: document the protocol type
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
  2014-04-03 23:31 ` [PATCH 01/49] bt8xx: fixup RC5 decoding David Härdeman
  2014-04-03 23:31 ` [PATCH 02/49] rc-core: improve ir-kbd-i2c get_key functions David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-03 23:31 ` [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now David Härdeman
                   ` (47 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Right now the protocol information is not preserved, rc-core gets handed a
scancode but has no idea which protocol it corresponds to.

This patch (which required reading through the source/keymap for all drivers,
not fun) makes the protocol information explicit which is important
documentation and makes it easier to e.g. support multiple protocols with one
decoder (think rc5 and rc-streamzap). The information isn't used yet so there
should be no functional changes.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/i2c/ir-kbd-i2c.c              |    5 +
 drivers/media/pci/bt8xx/bttv-input.c        |   12 ++-
 drivers/media/pci/cx88/cx88-input.c         |   26 ++++++-
 drivers/media/pci/dm1105/dm1105.c           |    3 +
 drivers/media/pci/saa7134/saa7134-input.c   |    6 +-
 drivers/media/pci/ttpci/budget-ci.c         |    8 +-
 drivers/media/rc/ati_remote.c               |    4 +
 drivers/media/rc/img-ir/img-ir-hw.c         |    8 +-
 drivers/media/rc/img-ir/img-ir-hw.h         |    3 +
 drivers/media/rc/img-ir/img-ir-jvc.c        |    4 +
 drivers/media/rc/img-ir/img-ir-nec.c        |    4 +
 drivers/media/rc/img-ir/img-ir-sanyo.c      |    4 +
 drivers/media/rc/img-ir/img-ir-sharp.c      |    4 +
 drivers/media/rc/img-ir/img-ir-sony.c       |   12 ++-
 drivers/media/rc/imon.c                     |    5 +
 drivers/media/rc/ir-jvc-decoder.c           |    2 -
 drivers/media/rc/ir-nec-decoder.c           |    2 -
 drivers/media/rc/ir-rc5-decoder.c           |    5 +
 drivers/media/rc/ir-rc5-sz-decoder.c        |    2 -
 drivers/media/rc/ir-rc6-decoder.c           |   37 ++++++++--
 drivers/media/rc/ir-sanyo-decoder.c         |    2 -
 drivers/media/rc/ir-sharp-decoder.c         |    2 -
 drivers/media/rc/ir-sony-decoder.c          |    6 +-
 drivers/media/rc/rc-main.c                  |   32 +++++----
 drivers/media/usb/dvb-usb-v2/af9015.c       |   18 +++--
 drivers/media/usb/dvb-usb-v2/af9035.c       |    9 +-
 drivers/media/usb/dvb-usb-v2/anysee.c       |    3 +
 drivers/media/usb/dvb-usb-v2/az6007.c       |   25 ++++---
 drivers/media/usb/dvb-usb-v2/lmedm04.c      |    9 +-
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c     |   12 ++-
 drivers/media/usb/dvb-usb/dib0700_core.c    |   16 +++-
 drivers/media/usb/dvb-usb/dib0700_devices.c |   24 ++++---
 drivers/media/usb/dvb-usb/dw2102.c          |    7 +-
 drivers/media/usb/dvb-usb/m920x.c           |    2 -
 drivers/media/usb/dvb-usb/pctv452e.c        |    8 +-
 drivers/media/usb/dvb-usb/ttusb2.c          |    6 +-
 drivers/media/usb/em28xx/em28xx-input.c     |   98 ++++++++++++++++-----------
 drivers/media/usb/tm6000/tm6000-input.c     |   51 ++++++++++----
 include/media/rc-core.h                     |    6 +-
 39 files changed, 307 insertions(+), 185 deletions(-)

diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 143cb2b..f9c4233 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -261,8 +261,9 @@ static int ir_key_poll(struct IR_i2c *ir)
 	}
 
 	if (rc) {
-		dprintk(1, "%s: scancode = 0x%08x\n", __func__, scancode);
-		rc_keydown(ir->rc, scancode, toggle);
+		dprintk(1, "%s: proto = 0x%04x, scancode = 0x%08x\n",
+			__func__, protocol, scancode);
+		rc_keydown(ir->rc, protocol, scancode, toggle);
 	}
 	return 0;
 }
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index e745f5a..67c8d6b 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -73,12 +73,12 @@ static void ir_handle_key(struct bttv *btv)
 
 	if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
 	    (ir->mask_keyup   && !(gpio & ir->mask_keyup))) {
-		rc_keydown_notimeout(ir->dev, data, 0);
+		rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 	} else {
 		/* HACK: Probably, ir->mask_keydown is missing
 		   for this board */
 		if (btv->c.type == BTTV_BOARD_WINFAST2000)
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 
 		rc_keyup(ir->dev);
 	}
@@ -103,7 +103,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
 			gpio, data,
 			(gpio & ir->mask_keyup) ? " up" : "up/down");
 
-		rc_keydown_notimeout(ir->dev, data, 0);
+		rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		if (keyup)
 			rc_keyup(ir->dev);
 	} else {
@@ -117,7 +117,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
 		if (keyup)
 			rc_keyup(ir->dev);
 		else
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 	}
 
 	ir->last_gpio = data | keyup;
@@ -241,8 +241,8 @@ static void bttv_rc5_timer_end(unsigned long data)
 		return;
 	}
 
-	scancode = system << 8 | command;
-	rc_keydown(ir->dev, scancode, toggle);
+	scancode = RC_SCANCODE_RC5(system, command);
+	rc_keydown(ir->dev, RC_TYPE_RC5, scancode, toggle);
 	dprintk("scancode %x, toggle %x\n", scancode, toggle);
 }
 
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 779fc63..9bf48ca 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -130,25 +130,41 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
 		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
 
-		rc_keydown(ir->dev, data, 0);
+		rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
+
+	} else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR ||
+		   ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) {
+		/* bit cleared on keydown, NEC scancode, 0xAAAACC, A = 0x866b */
+		u16 addr;
+		u8 cmd;
+		u32 scancode;
+
+		addr = (data >> 8) & 0xffff;
+		cmd  = (data >> 0) & 0x00ff;
+		scancode = RC_SCANCODE_NECX(addr, cmd);
+
+		if (0 == (gpio & ir->mask_keyup))
+			rc_keydown_notimeout(ir->dev, RC_TYPE_NEC, scancode, 0);
+		else
+			rc_keyup(ir->dev);
 
 	} else if (ir->mask_keydown) {
 		/* bit set on keydown */
 		if (gpio & ir->mask_keydown)
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		else
 			rc_keyup(ir->dev);
 
 	} else if (ir->mask_keyup) {
 		/* bit cleared on keydown */
 		if (0 == (gpio & ir->mask_keyup))
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		else
 			rc_keyup(ir->dev);
 
 	} else {
 		/* can't distinguish keydown/up :-/ */
-		rc_keydown_notimeout(ir->dev, data, 0);
+		rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		rc_keyup(ir->dev);
 	}
 }
@@ -329,6 +345,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		 * 002-T mini RC, provided with newer PV hardware
 		 */
 		ir_codes = RC_MAP_PIXELVIEW_MK12;
+		rc_type = RC_BIT_NEC;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keyup = 0x80;
 		ir->polling = 10; /* ms */
@@ -416,7 +433,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		break;
 	case CX88_BOARD_TWINHAN_VP1027_DVBS:
 		ir_codes         = RC_MAP_TWINHAN_VP1027_DVBS;
-		rc_type          = RC_BIT_NEC;
 		ir->sampling     = 0xff00; /* address */
 		break;
 	}
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e60ac35..e8826c5 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -678,7 +678,8 @@ static void dm1105_emit_key(struct work_struct *work)
 
 	data = (ircom >> 8) & 0x7f;
 
-	rc_keydown(ir->dev, data, 0);
+	/* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */
+	rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 }
 
 /* work handler */
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 73670ed..43dd8bd 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -83,14 +83,14 @@ static int build_key(struct saa7134_dev *dev)
 		if (data == ir->mask_keycode)
 			rc_keyup(ir->dev);
 		else
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		return 0;
 	}
 
 	if (ir->polling) {
 		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
 		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 		} else {
 			rc_keyup(ir->dev);
 		}
@@ -98,7 +98,7 @@ static int build_key(struct saa7134_dev *dev)
 	else {	/* IRQ driven mode - handle key press and release in one go */
 		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
 		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
 			rc_keyup(ir->dev);
 		}
 	}
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 0acf920..41ce7de 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -161,14 +161,14 @@ static void msp430_ir_interrupt(unsigned long data)
 		return;
 
 	if (budget_ci->ir.full_rc5) {
-		rc_keydown(dev,
-			   budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
-			   (command & 0x20) ? 1 : 0);
+		rc_keydown(dev, RC_TYPE_RC5,
+			   RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key),
+			   !!(command & 0x20));
 		return;
 	}
 
 	/* FIXME: We should generate complete scancodes for all devices */
-	rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+	rc_keydown(dev, RC_TYPE_UNKNOWN, budget_ci->ir.ir_key, !!(command & 0x20));
 }
 
 static int msp430_ir_init(struct budget_ci *budget_ci)
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 2df7c55..8730b32 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -622,8 +622,8 @@ static void ati_remote_input_report(struct urb *urb)
 				* it would cause ghost repeats which would be a
 				* regression for this driver.
 				*/
-				rc_keydown_notimeout(ati_remote->rdev, scancode,
-						     data[2]);
+				rc_keydown_notimeout(ati_remote->rdev, RC_TYPE_OTHER,
+						     scancode, data[2]);
 				rc_keyup(ati_remote->rdev);
 			}
 			return;
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 579a52b..aec79f7 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -778,9 +778,11 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
 	struct img_ir_priv_hw *hw = &priv->hw;
 	const struct img_ir_decoder *dec = hw->decoder;
 	int ret = IMG_IR_SCANCODE;
-	int scancode;
+	u32 scancode;
+	enum rc_type protocol = RC_TYPE_UNKNOWN;
+
 	if (dec->scancode)
-		ret = dec->scancode(len, raw, &scancode, hw->enabled_protocols);
+		ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols);
 	else if (len >= 32)
 		scancode = (u32)raw;
 	else if (len < 32)
@@ -789,7 +791,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
 		len, (unsigned long long)raw);
 	if (ret == IMG_IR_SCANCODE) {
 		dev_dbg(priv->dev, "decoded scan code %#x\n", scancode);
-		rc_keydown(hw->rdev, scancode, 0);
+		rc_keydown(hw->rdev, protocol, scancode, 0);
 		img_ir_end_repeat(priv);
 	} else if (ret == IMG_IR_REPEATCODE) {
 		if (hw->mode == IMG_IR_M_REPEATING) {
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
index 6c9a94a..e5dc98b 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.h
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -157,7 +157,8 @@ struct img_ir_decoder {
 	struct img_ir_control		control;
 
 	/* scancode logic */
-	int (*scancode)(int len, u64 raw, int *scancode, u64 protocols);
+	int (*scancode)(int len, u64 raw, enum rc_type *protocol,
+			u32 *scancode, u64 enabled_protocols);
 	int (*filter)(const struct rc_scancode_filter *in,
 		      struct img_ir_filter *out, u64 protocols);
 };
diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c
index 10209d2..be68a16 100644
--- a/drivers/media/rc/img-ir/img-ir-jvc.c
+++ b/drivers/media/rc/img-ir/img-ir-jvc.c
@@ -7,7 +7,8 @@
 #include "img-ir-hw.h"
 
 /* Convert JVC data to a scancode */
-static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol,
+			       u32 *scancode, u64 enabled_protocols)
 {
 	unsigned int cust, data;
 
@@ -17,6 +18,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols)
 	cust = (raw >> 0) & 0xff;
 	data = (raw >> 8) & 0xff;
 
+	*protocol = RC_TYPE_JVC;
 	*scancode = cust << 8 | data;
 	return IMG_IR_SCANCODE;
 }
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index e7a731b..c0111d6 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -7,7 +7,8 @@
 #include "img-ir-hw.h"
 
 /* Convert NEC data to a scancode */
-static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
+			       u32 *scancode, u64 enabled_protocols)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	/* a repeat code has no data */
@@ -39,6 +40,7 @@ static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols)
 		*scancode = addr << 8 |
 			    data;
 	}
+	*protocol = RC_TYPE_NEC;
 	return IMG_IR_SCANCODE;
 }
 
diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c
index c2c763e..a0a0129 100644
--- a/drivers/media/rc/img-ir/img-ir-sanyo.c
+++ b/drivers/media/rc/img-ir/img-ir-sanyo.c
@@ -18,7 +18,8 @@
 #include "img-ir-hw.h"
 
 /* Convert Sanyo data to a scancode */
-static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol,
+				 u32 *scancode, u64 enabled_protocols)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	/* a repeat code has no data */
@@ -38,6 +39,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols)
 		return -EINVAL;
 
 	/* Normal Sanyo */
+	*protocol = RC_TYPE_SANYO;
 	*scancode = addr << 8 | data;
 	return IMG_IR_SCANCODE;
 }
diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c
index 3397cc5..8624fd2 100644
--- a/drivers/media/rc/img-ir/img-ir-sharp.c
+++ b/drivers/media/rc/img-ir/img-ir-sharp.c
@@ -7,7 +7,8 @@
 #include "img-ir-hw.h"
 
 /* Convert Sharp data to a scancode */
-static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol,
+				 u32 *scancode, u64 enabled_protocols)
 {
 	unsigned int addr, cmd, exp, chk;
 
@@ -26,6 +27,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols)
 		/* probably the second half of the message */
 		return -EINVAL;
 
+	*protocol = RC_TYPE_SHARP;
 	*scancode = addr << 8 | cmd;
 	return IMG_IR_SCANCODE;
 }
diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c
index 993409a..eb11ce8 100644
--- a/drivers/media/rc/img-ir/img-ir-sony.c
+++ b/drivers/media/rc/img-ir/img-ir-sony.c
@@ -7,35 +7,39 @@
 #include "img-ir-hw.h"
 
 /* Convert Sony data to a scancode */
-static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
+				u32 *scancode, u64 enabled_protocols)
 {
 	unsigned int dev, subdev, func;
 
 	switch (len) {
 	case 12:
-		if (!(protocols & RC_BIT_SONY12))
+		if (!(enabled_protocols & RC_BIT_SONY12))
 			return -EINVAL;
 		func   = raw & 0x7f;	/* first 7 bits */
 		raw    >>= 7;
 		dev    = raw & 0x1f;	/* next 5 bits */
 		subdev = 0;
+		*protocol = RC_TYPE_SONY12;
 		break;
 	case 15:
-		if (!(protocols & RC_BIT_SONY15))
+		if (!(enabled_protocols & RC_BIT_SONY15))
 			return -EINVAL;
 		func   = raw & 0x7f;	/* first 7 bits */
 		raw    >>= 7;
 		dev    = raw & 0xff;	/* next 8 bits */
 		subdev = 0;
+		*protocol = RC_TYPE_SONY15;
 		break;
 	case 20:
-		if (!(protocols & RC_BIT_SONY20))
+		if (!(enabled_protocols & RC_BIT_SONY20))
 			return -EINVAL;
 		func   = raw & 0x7f;	/* first 7 bits */
 		raw    >>= 7;
 		dev    = raw & 0x1f;	/* next 5 bits */
 		raw    >>= 5;
 		subdev = raw & 0xff;	/* next 8 bits */
+		*protocol = RC_TYPE_SONY20;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 6f24e77..d1564d1 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1579,7 +1579,10 @@ static void imon_incoming_packet(struct imon_context *ictx,
 		if (press_type == 0)
 			rc_keyup(ictx->rdev);
 		else {
-			rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
+			if (ictx->rc_type == RC_BIT_RC6_MCE)
+			rc_keydown(ictx->rdev,
+				   ictx->rc_type == RC_BIT_RC6_MCE ? RC_TYPE_RC6_MCE : RC_TYPE_OTHER,
+				   ictx->rc_scancode, ictx->rc_toggle);
 			spin_lock_irqsave(&ictx->kc_lock, flags);
 			ictx->last_keycode = ictx->kc;
 			spin_unlock_irqrestore(&ictx->kc_lock, flags);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 4ea62a1..7b79eca 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -140,7 +140,7 @@ again:
 			scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
 				   (bitrev8((data->bits >> 0) & 0xff) << 0);
 			IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
-			rc_keydown(dev, scancode, data->toggle);
+			rc_keydown(dev, RC_TYPE_JVC, scancode, data->toggle);
 			data->first = false;
 			data->old_bits = data->bits;
 		} else if (data->bits == data->old_bits) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 9de1791..735a509 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -192,7 +192,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		if (data->is_nec_x)
 			data->necx_repeat = true;
 
-		rc_keydown(dev, scancode, 0);
+		rc_keydown(dev, RC_TYPE_NEC, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 4295d9b..3d38cbc 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -51,6 +51,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct rc5_dec *data = &dev->raw->rc5;
 	u8 toggle;
 	u32 scancode;
+	enum rc_type protocol;
 
 	if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X))
 		return 0;
@@ -138,6 +139,7 @@ again:
 			toggle   = (data->bits & 0x20000) ? 1 : 0;
 			command += (data->bits & 0x01000) ? 0 : 0x40;
 			scancode = system << 16 | command << 8 | xdata;
+			protocol = RC_TYPE_RC5X;
 
 			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
 				   scancode, toggle);
@@ -154,12 +156,13 @@ again:
 			toggle   = (data->bits & 0x00800) ? 1 : 0;
 			command += (data->bits & 0x01000) ? 0 : 0x40;
 			scancode = system << 8 | command;
+			protocol = RC_TYPE_RC5;
 
 			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
 				   scancode, toggle);
 		}
 
-		rc_keydown(dev, scancode, toggle);
+		rc_keydown(dev, protocol, scancode, toggle);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index dc18b74..85c7711 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -115,7 +115,7 @@ again:
 		IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
 			   scancode, toggle);
 
-		rc_keydown(dev, scancode, toggle);
+		rc_keydown(dev, RC_TYPE_RC5_SZ, scancode, toggle);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index cfbd64e..1dc97a7 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -88,6 +88,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct rc6_dec *data = &dev->raw->rc6;
 	u32 scancode;
 	u8 toggle;
+	enum rc_type protocol;
 
 	if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
 				  RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
@@ -233,9 +234,11 @@ again:
 		case RC6_MODE_0:
 			scancode = data->body;
 			toggle = data->toggle;
+			protocol = RC_TYPE_RC6_0;
 			IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
 				   scancode, toggle);
 			break;
+
 		case RC6_MODE_6A:
 			if (data->count > CHAR_BIT * sizeof data->body) {
 				IR_dprintk(1, "RC6 too many (%u) data bits\n",
@@ -244,23 +247,39 @@ again:
 			}
 
 			scancode = data->body;
-			if (data->count == RC6_6A_32_NBITS &&
-					(scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
-				/* MCE RC */
-				toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
-				scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
-			} else {
+			switch (data->count) {
+			case 20:
+				protocol = RC_TYPE_RC6_6A_20;
+				toggle = 0;
+				break;
+			case 24:
+				protocol = RC_BIT_RC6_6A_24;
 				toggle = 0;
+				break;
+			case 32:
+				if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+					protocol = RC_TYPE_RC6_MCE;
+					scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
+					toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
+				} else {
+					protocol = RC_BIT_RC6_6A_32;
+					toggle = 0;
+				}
+				break;
+			default:
+				IR_dprintk(1, "RC6(6A) unsupported length\n");
+				goto out;
 			}
-			IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
-				   scancode, toggle);
+
+			IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
+				   protocol, scancode, toggle);
 			break;
 		default:
 			IR_dprintk(1, "RC6 unknown mode\n");
 			goto out;
 		}
 
-		rc_keydown(dev, scancode, toggle);
+		rc_keydown(dev, protocol, scancode, toggle);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index eb715f0..5f77022 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -167,7 +167,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 		scancode = address << 8 | command;
 		IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
-		rc_keydown(dev, scancode, 0);
+		rc_keydown(dev, RC_TYPE_SANYO, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index 66d2039..c8f2519 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -162,7 +162,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		scancode = address << 8 | command;
 		IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
 
-		rc_keydown(dev, scancode, 0);
+		rc_keydown(dev, RC_TYPE_SHARP, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 599c19a..f485f9fe 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -42,6 +42,7 @@ enum sony_state {
 static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 {
 	struct sony_dec *data = &dev->raw->sony;
+	enum rc_type protocol;
 	u32 scancode;
 	u8 device, subdevice, function;
 
@@ -131,6 +132,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			device    = bitrev8((data->bits <<  3) & 0xF8);
 			subdevice = 0;
 			function  = bitrev8((data->bits >>  4) & 0xFE);
+			protocol = RC_TYPE_SONY12;
 			break;
 		case 15:
 			if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) {
@@ -140,6 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			device    = bitrev8((data->bits >>  0) & 0xFF);
 			subdevice = 0;
 			function  = bitrev8((data->bits >>  7) & 0xFE);
+			protocol = RC_TYPE_SONY15;
 			break;
 		case 20:
 			if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) {
@@ -149,6 +152,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			device    = bitrev8((data->bits >>  5) & 0xF8);
 			subdevice = bitrev8((data->bits >>  0) & 0xFF);
 			function  = bitrev8((data->bits >> 12) & 0xFE);
+			protocol = RC_TYPE_SONY20;
 			break;
 		default:
 			IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -157,7 +161,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 		scancode = device << 16 | subdevice << 8 | function;
 		IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
-		rc_keydown(dev, scancode, 0);
+		rc_keydown(dev, protocol, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 99697aa..c0bfd50 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -623,6 +623,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
 /**
  * ir_do_keydown() - internal function to process a keypress
  * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol of the keypress
  * @scancode:   the scancode of the keypress
  * @keycode:    the keycode of the keypress
  * @toggle:     the toggle value of the keypress
@@ -630,13 +631,14 @@ EXPORT_SYMBOL_GPL(rc_repeat);
  * This function is used internally to register a keypress, it must be
  * called with keylock held.
  */
-static void ir_do_keydown(struct rc_dev *dev, int scancode,
-			  u32 keycode, u8 toggle)
+static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+			  u32 scancode, u32 keycode, u8 toggle)
 {
 	struct rc_scancode_filter *filter;
-	bool new_event = !dev->keypressed ||
-			 dev->last_scancode != scancode ||
-			 dev->last_toggle != toggle;
+	bool new_event = (!dev->keypressed		 ||
+			  dev->last_protocol != protocol ||
+			  dev->last_scancode != scancode ||
+			  dev->last_toggle   != toggle);
 
 	if (new_event && dev->keypressed)
 		ir_do_keyup(dev, false);
@@ -651,13 +653,14 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
 	if (new_event && keycode != KEY_RESERVED) {
 		/* Register a keypress */
 		dev->keypressed = true;
+		dev->last_protocol = protocol;
 		dev->last_scancode = scancode;
 		dev->last_toggle = toggle;
 		dev->last_keycode = keycode;
 
 		IR_dprintk(1, "%s: key down event, "
-			   "key 0x%04x, scancode 0x%04x\n",
-			   dev->input_name, keycode, scancode);
+			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+			   dev->input_name, keycode, protocol, scancode);
 		input_report_key(dev->input_dev, keycode, 1);
 
 		led_trigger_event(led_feedback, LED_FULL);
@@ -669,20 +672,21 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
 /**
  * rc_keydown() - generates input event for a key press
  * @dev:	the struct rc_dev descriptor of the device
- * @scancode:   the scancode that we're seeking
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
  * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
  *              support toggle values, this should be set to zero)
  *
  * This routine is used to signal that a key has been pressed on the
  * remote control.
  */
-void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
 {
 	unsigned long flags;
 	u32 keycode = rc_g_keycode_from_table(dev, scancode);
 
 	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, scancode, keycode, toggle);
+	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
 
 	if (dev->keypressed) {
 		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
@@ -696,20 +700,22 @@ EXPORT_SYMBOL_GPL(rc_keydown);
  * rc_keydown_notimeout() - generates input event for a key press without
  *                          an automatic keyup event at a later time
  * @dev:	the struct rc_dev descriptor of the device
- * @scancode:   the scancode that we're seeking
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
  * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
  *              support toggle values, this should be set to zero)
  *
  * This routine is used to signal that a key has been pressed on the
  * remote control. The driver must manually call rc_keyup() at a later stage.
  */
-void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
+			  u32 scancode, u8 toggle)
 {
 	unsigned long flags;
 	u32 keycode = rc_g_keycode_from_table(dev, scancode);
 
 	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, scancode, keycode, toggle);
+	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
 	spin_unlock_irqrestore(&dev->keylock, flags);
 }
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index da47d23..5ca738a 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1213,7 +1213,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
 	if ((state->rc_repeat != buf[6] || buf[0]) &&
 			!memcmp(&buf[12], state->rc_last, 4)) {
 		dev_dbg(&d->udev->dev, "%s: key repeated\n", __func__);
-		rc_keydown(d->rc_dev, state->rc_keycode, 0);
+		rc_repeat(d->rc_dev);
 		state->rc_repeat = buf[6];
 		return ret;
 	}
@@ -1233,18 +1233,22 @@ static int af9015_rc_query(struct dvb_usb_device *d)
 		if (buf[14] == (u8) ~buf[15]) {
 			if (buf[12] == (u8) ~buf[13]) {
 				/* NEC */
-				state->rc_keycode = buf[12] << 8 | buf[14];
+				state->rc_keycode = RC_SCANCODE_NEC(buf[12],
+								    buf[14]);
 			} else {
 				/* NEC extended*/
-				state->rc_keycode = buf[12] << 16 |
-					buf[13] << 8 | buf[14];
+				state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 |
+								     buf[13],
+								     buf[14]);
 			}
 		} else {
 			/* 32 bit NEC */
-			state->rc_keycode = buf[12] << 24 | buf[13] << 16 |
-					buf[14] << 8 | buf[15];
+			state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 |
+							      buf[13] << 16 |
+							      buf[14] << 8  |
+							      buf[15]);
 		}
-		rc_keydown(d->rc_dev, state->rc_keycode, 0);
+		rc_keydown(d->rc_dev, RC_TYPE_NEC, state->rc_keycode, 0);
 	} else {
 		dev_dbg(&d->udev->dev, "%s: no key press\n", __func__);
 		/* Invalidate last keypress */
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 021e4d3..3bfba13 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1287,19 +1287,20 @@ static int af9035_rc_query(struct dvb_usb_device *d)
 	if ((buf[2] + buf[3]) == 0xff) {
 		if ((buf[0] + buf[1]) == 0xff) {
 			/* NEC standard 16bit */
-			key = buf[0] << 8 | buf[2];
+			key = RC_SCANCODE_NEC(buf[0], buf[2]);
 		} else {
 			/* NEC extended 24bit */
-			key = buf[0] << 16 | buf[1] << 8 | buf[2];
+			key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]);
 		}
 	} else {
 		/* NEC full code 32bit */
-		key = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+		key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+					buf[2] << 8  | buf[3]);
 	}
 
 	dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf);
 
-	rc_keydown(d->rc_dev, key, 0);
+	rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0);
 
 	return 0;
 
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index eeab79b..e4a2382 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -1038,7 +1038,8 @@ static int anysee_rc_query(struct dvb_usb_device *d)
 	if (ircode[0]) {
 		dev_dbg(&d->udev->dev, "%s: key pressed %02x\n", __func__,
 				ircode[1]);
-		rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
+		rc_keydown(d->rc_dev, RC_TYPE_NEC,
+			   RC_SCANCODE_NEC(0x08, ircode[1]), 0);
 	}
 
 	return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index c3c4b98..935dbaa 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -207,24 +207,27 @@ static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
 static int az6007_rc_query(struct dvb_usb_device *d)
 {
 	struct az6007_device_state *st = d_to_priv(d);
-	unsigned code = 0;
+	unsigned code;
 
 	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
 
 	if (st->data[1] == 0x44)
 		return 0;
 
-	if ((st->data[1] ^ st->data[2]) == 0xff)
-		code = st->data[1];
-	else
-		code = st->data[1] << 8 | st->data[2];
-
-	if ((st->data[3] ^ st->data[4]) == 0xff)
-		code = code << 8 | st->data[3];
-	else
-		code = code << 16 | st->data[3] << 8 | st->data[4];
+	if ((st->data[3] ^ st->data[4]) == 0xff) {
+		if ((st->data[1] ^ st->data[2]) == 0xff)
+			code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
+		else
+			code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
+						st->data[3]);
+	} else {
+		code = RC_SCANCODE_NEC32(st->data[1] << 24 |
+					 st->data[2] << 16 |
+					 st->data[3] << 8  |
+					 st->data[4]);
+	}
 
-	rc_keydown(d->rc_dev, code, st->data[5]);
+	rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
 
 	return 0;
 }
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index f674dc0..31f31fc 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -287,14 +287,13 @@ static void lme2510_int_response(struct urb *lme_urb)
 		case 0xaa:
 			debug_data_snipet(1, "INT Remote data snipet", ibuf);
 			if ((ibuf[4] + ibuf[5]) == 0xff) {
-				key = ibuf[5];
-				key += (ibuf[3] > 0)
-					? (ibuf[3] ^ 0xff) << 8 : 0;
-				key += (ibuf[2] ^ 0xff) << 16;
+				key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 |
+						       (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0,
+						       ibuf[5]);
 				deb_info(1, "INT Key =%08x", key);
 				if (adap_to_d(adap)->rc_dev != NULL)
 					rc_keydown(adap_to_d(adap)->rc_dev,
-						key, 0);
+						   RC_TYPE_NEC, key, 0);
 			}
 			break;
 		case 0xbb:
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index c83c16c..574f4ee 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1249,19 +1249,19 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
 		if (buf[2] == (u8) ~buf[3]) {
 			if (buf[0] == (u8) ~buf[1]) {
 				/* NEC standard (16 bit) */
-				rc_code = buf[0] << 8 | buf[2];
+				rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
 			} else {
 				/* NEC extended (24 bit) */
-				rc_code = buf[0] << 16 |
-						buf[1] << 8 | buf[2];
+				rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1],
+							   buf[2]);
 			}
 		} else {
 			/* NEC full (32 bit) */
-			rc_code = buf[0] << 24 | buf[1] << 16 |
-					buf[2] << 8 | buf[3];
+			rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+						    buf[2] << 8  | buf[3]);
 		}
 
-		rc_keydown(d->rc_dev, rc_code, 0);
+		rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
 
 		ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
 		if (ret)
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index bf2a908..6afe7ea 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -674,7 +674,8 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 {
 	struct dvb_usb_device *d = purb->context;
 	struct dib0700_rc_response *poll_reply;
-	u32 uninitialized_var(keycode);
+	enum rc_type protocol;
+	u32 uninitialized_var(scancode);
 	u8 toggle;
 
 	deb_info("%s()\n", __func__);
@@ -707,6 +708,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 
 	switch (d->props.rc.core.protocol) {
 	case RC_BIT_NEC:
+		protocol = RC_TYPE_NEC;
 		toggle = 0;
 
 		/* NEC protocol sends repeat code as 0 0 0 FF */
@@ -719,19 +721,21 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 		if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
 			deb_data("NEC extended protocol\n");
 			/* NEC extended code - 24 bits */
-			keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
+			scancode = RC_SCANCODE_NECX(be16_to_cpu(poll_reply->system16),
+						    poll_reply->data);
 		} else {
 			deb_data("NEC normal protocol\n");
 			/* normal NEC code - 16 bits */
-			keycode = poll_reply->system << 8 | poll_reply->data;
+			scancode = RC_SCANCODE_NEC(poll_reply->system,
+						   poll_reply->data);
 		}
 
 		break;
 	default:
 		deb_data("RC5 protocol\n");
-		/* RC5 Protocol */
+		protocol = RC_TYPE_RC5;
 		toggle = poll_reply->report_id;
-		keycode = poll_reply->system << 8 | poll_reply->data;
+		scancode = RC_SCANCODE_RC5(poll_reply->system, poll_reply->data);
 
 		break;
 	}
@@ -744,7 +748,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 		goto resubmit;
 	}
 
-	rc_keydown(d->rc_dev, keycode, toggle);
+	rc_keydown(d->rc_dev, protocol, scancode, toggle);
 
 resubmit:
 	/* Clean the buffer before we requeue */
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 829323e..6a70223 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -489,7 +489,8 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
 {
 	u8 key[4];
-	u32 keycode;
+	enum rc_type protocol;
+	u32 scancode;
 	u8 toggle;
 	int i;
 	struct dib0700_state *st = d->priv;
@@ -516,28 +517,29 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
 
 	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
 
-	d->last_event = 0;
 	switch (d->props.rc.core.protocol) {
 	case RC_BIT_NEC:
 		/* NEC protocol sends repeat code as 0 0 0 FF */
 		if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
-		    (key[3] == 0xff))
-			keycode = d->last_event;
-		else {
-			keycode = key[3-2] << 8 | key[3-3];
-			d->last_event = keycode;
+		    (key[3] == 0xff)) {
+			rc_repeat(d->rc_dev);
+			return 0;
 		}
 
-		rc_keydown(d->rc_dev, keycode, 0);
+		protocol = RC_TYPE_NEC;
+		scancode = RC_SCANCODE_NEC(key[3-2], key[3-3]);
+		toggle = 0;
 		break;
+
 	default:
 		/* RC-5 protocol changes toggle bit on new keypress */
-		keycode = key[3-2] << 8 | key[3-3];
+		protocol = RC_TYPE_RC5;
+		scancode = RC_SCANCODE_RC5(key[3-2], key[3-3]);
 		toggle = key[3-1];
-		rc_keydown(d->rc_dev, keycode, toggle);
-
 		break;
 	}
+
+	rc_keydown(d->rc_dev, protocol, scancode, toggle);
 	return 0;
 }
 
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index ae0f56a..8f22d79 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -1482,7 +1482,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d)
 		if (msg.buf[0] != 0xff) {
 			deb_rc("%s: rc code: %x, %x\n",
 					__func__, key[0], key[1]);
-			rc_keydown(d->rc_dev, key[0], 1);
+			rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0], 0);
 		}
 	}
 
@@ -1503,7 +1503,7 @@ static int prof_rc_query(struct dvb_usb_device *d)
 		if (msg.buf[0] != 0xff) {
 			deb_rc("%s: rc code: %x, %x\n",
 					__func__, key[0], key[1]);
-			rc_keydown(d->rc_dev, key[0]^0xff, 1);
+			rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0]^0xff, 0);
 		}
 	}
 
@@ -1524,7 +1524,8 @@ static int su3000_rc_query(struct dvb_usb_device *d)
 		if (msg.buf[0] != 0xff) {
 			deb_rc("%s: rc code: %x, %x\n",
 					__func__, key[0], key[1]);
-			rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1);
+			rc_keydown(d->rc_dev, RC_TYPE_RC5,
+				   RC_SCANCODE_RC5(key[1], key[0]), 0);
 		}
 	}
 
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 0306cb7..abf8ab2 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -245,7 +245,7 @@ static int m920x_rc_core_query(struct dvb_usb_device *d)
 	else if (state == REMOTE_KEY_REPEAT)
 		rc_repeat(d->rc_dev);
 	else
-		rc_keydown(d->rc_dev, rc_state[1], 0);
+		rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, rc_state[1], 0);
 
 out:
 	kfree(rc_state);
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index 449a996..bdfe896 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -565,12 +565,12 @@ static int pctv452e_rc_query(struct dvb_usb_device *d)
 
 	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
 		/* got a "press" event */
-		state->last_rc_key = (rx[7] << 8) | rx[6];
+		state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]);
 		if (debug > 2)
 			info("%s: cmd=0x%02x sys=0x%02x\n",
 				__func__, rx[6], rx[7]);
 
-		rc_keydown(d->rc_dev, state->last_rc_key, 0);
+		rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0);
 	} else if (state->last_rc_key) {
 		rc_keyup(d->rc_dev);
 		state->last_rc_key = 0;
@@ -927,7 +927,7 @@ static struct dvb_usb_device_properties pctv452e_properties = {
 
 	.rc.core = {
 		.rc_codes	= RC_MAP_DIB0700_RC5_TABLE,
-		.allowed_protos	= RC_BIT_UNKNOWN,
+		.allowed_protos	= RC_BIT_RC5,
 		.rc_query	= pctv452e_rc_query,
 		.rc_interval	= 100,
 	},
@@ -980,7 +980,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
 
 	.rc.core = {
 		.rc_codes	= RC_MAP_TT_1500,
-		.allowed_protos	= RC_BIT_UNKNOWN,
+		.allowed_protos	= RC_BIT_RC5,
 		.rc_query	= pctv452e_rc_query,
 		.rc_interval	= 100,
 	},
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index 2ce3d19..f107173 100644
--- a/drivers/media/usb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -438,9 +438,9 @@ static int tt3650_rc_query(struct dvb_usb_device *d)
 
 	if (rx[8] & 0x01) {
 		/* got a "press" event */
-		st->last_rc_key = (rx[3] << 8) | rx[2];
+		st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]);
 		deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
-		rc_keydown(d->rc_dev, st->last_rc_key, rx[1]);
+		rc_keydown(d->rc_dev, RC_TYPE_RC5, st->last_rc_key, rx[1]);
 	} else if (st->last_rc_key) {
 		rc_keyup(d->rc_dev);
 		st->last_rc_key = 0;
@@ -747,7 +747,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
 		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
 		.rc_codes         = RC_MAP_TT_1500,
 		.rc_query         = tt3650_rc_query,
-		.allowed_protos   = RC_BIT_UNKNOWN,
+		.allowed_protos   = RC_BIT_RC5,
 	},
 
 	.num_adapters = 1,
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 56ef49d..014888f 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
+#include <linux/bitrev.h>
 
 #include "em28xx.h"
 
@@ -53,6 +54,7 @@ struct em28xx_ir_poll_result {
 	unsigned int toggle_bit:1;
 	unsigned int read_count:7;
 
+	enum rc_type protocol;
 	u32 scancode;
 };
 
@@ -72,7 +74,7 @@ struct em28xx_IR {
 	/* i2c slave address of external device (if used) */
 	u16 i2c_dev_addr;
 
-	int  (*get_key_i2c)(struct i2c_client *, u32 *);
+	int  (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
 	int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
 };
 
@@ -80,7 +82,8 @@ struct em28xx_IR {
  I2C IR based get keycodes - should be used with ir-kbd-i2c
  **********************************************************/
 
-static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
+				   enum rc_type *protocol, u32 *scancode)
 {
 	unsigned char b;
 
@@ -98,14 +101,15 @@ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
 		/* keep old data */
 		return 1;
 
-	*ir_key = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
 	return 1;
 }
 
-static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
+				  enum rc_type *protocol, u32 *scancode)
 {
 	unsigned char buf[2];
-	u16 code;
 	int size;
 
 	/* poll IR chip */
@@ -127,26 +131,13 @@ static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
 	 * So, the code translation is not complete. Yet, it is enough to
 	 * work with the provided RC5 IR.
 	 */
-	code =
-		 ((buf[0] & 0x01) ? 0x0020 : 0) | /* 		0010 0000 */
-		 ((buf[0] & 0x02) ? 0x0010 : 0) | /* 		0001 0000 */
-		 ((buf[0] & 0x04) ? 0x0008 : 0) | /* 		0000 1000 */
-		 ((buf[0] & 0x08) ? 0x0004 : 0) | /* 		0000 0100 */
-		 ((buf[0] & 0x10) ? 0x0002 : 0) | /* 		0000 0010 */
-		 ((buf[0] & 0x20) ? 0x0001 : 0) | /* 		0000 0001 */
-		 ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000		  */
-		 ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000		  */
-		 ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100		  */
-		 ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010		  */
-		 ((buf[1] & 0x80) ? 0x0100 : 0);  /* 0000 0001		  */
-
-	/* return key */
-	*ir_key = code;
+	*protocol = RC_TYPE_RC5;
+	*scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2;
 	return 1;
 }
 
 static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
-					    u32 *ir_key)
+					    enum rc_type *protocol, u32 *scancode)
 {
 	unsigned char buf[3];
 
@@ -158,13 +149,13 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
 	if (buf[0] != 0x00)
 		return 0;
 
-	*ir_key = buf[2]&0x3f;
-
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = buf[2] & 0x3f;
 	return 1;
 }
 
 static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
-					       u32 *ir_key)
+					       enum rc_type *protocol, u32 *scancode)
 {
 	unsigned char subaddr, keydetect, key;
 
@@ -184,7 +175,8 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
 	if (key == 0x00)
 		return 0;
 
-	*ir_key = key;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = key;
 	return 1;
 }
 
@@ -215,7 +207,22 @@ static int default_polling_getkey(struct em28xx_IR *ir,
 	poll_result->read_count = (msg[0] & 0x7f);
 
 	/* Remote Control Address/Data (Regs 0x46/0x47) */
-	poll_result->scancode = msg[1] << 8 | msg[2];
+	switch (ir->rc_type) {
+	case RC_BIT_RC5:
+		poll_result->protocol = RC_TYPE_RC5;
+		poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
+		break;
+
+	case RC_BIT_NEC:
+		poll_result->protocol = RC_TYPE_NEC;
+		poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]);
+		break;
+
+	default:
+		poll_result->protocol = RC_TYPE_UNKNOWN;
+		poll_result->scancode = msg[1] << 8 | msg[2];
+		break;
+	}
 
 	return 0;
 }
@@ -247,25 +254,32 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 	 */
 	switch (ir->rc_type) {
 	case RC_BIT_RC5:
-		poll_result->scancode = msg[1] << 8 | msg[2];
+		poll_result->protocol = RC_TYPE_RC5;
+		poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
 		break;
+
 	case RC_BIT_NEC:
+		poll_result->protocol = RC_TYPE_RC5;
+		poll_result->scancode = msg[1] << 8 | msg[2];
 		if ((msg[3] ^ msg[4]) != 0xff)		/* 32 bits NEC */
-			poll_result->scancode = (msg[1] << 24) |
-						(msg[2] << 16) |
-						(msg[3] << 8)  |
-						 msg[4];
+			poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
+								  (msg[2] << 16) |
+								  (msg[3] << 8)  |
+								  (msg[4]));
 		else if ((msg[1] ^ msg[2]) != 0xff)	/* 24 bits NEC */
-			poll_result->scancode = (msg[1] << 16) |
-						(msg[2] << 8)  |
-						 msg[3];
+			poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
+								 msg[2], msg[3]); 
 		else					/* Normal NEC */
-			poll_result->scancode = msg[1] << 8 | msg[3];
+			poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
 		break;
+
 	case RC_BIT_RC6_0:
-		poll_result->scancode = msg[1] << 8 | msg[2];
+		poll_result->protocol = RC_TYPE_RC6_0;
+		poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]);
 		break;
+
 	default:
+		poll_result->protocol = RC_TYPE_UNKNOWN;
 		poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
 					(msg[3] << 8)  | msg[4];
 		break;
@@ -281,22 +295,24 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
 {
 	struct em28xx *dev = ir->dev;
-	static u32 ir_key;
+	static u32 scancode;
+	enum rc_type protocol;
 	int rc;
 	struct i2c_client client;
 
 	client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
 	client.addr = ir->i2c_dev_addr;
 
-	rc = ir->get_key_i2c(&client, &ir_key);
+	rc = ir->get_key_i2c(&client, &protocol, &scancode);
 	if (rc < 0) {
 		dprintk("ir->get_key_i2c() failed: %d\n", rc);
 		return rc;
 	}
 
 	if (rc) {
-		dprintk("%s: keycode = 0x%04x\n", __func__, ir_key);
-		rc_keydown(ir->rc, ir_key, 0);
+		dprintk("%s: proto = 0x%04x, scancode = 0x%04x\n",
+			__func__, protocol, scancode);
+		rc_keydown(ir->rc, protocol, scancode, 0);
 	}
 	return 0;
 }
@@ -319,10 +335,12 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
 			poll_result.scancode);
 		if (ir->full_code)
 			rc_keydown(ir->rc,
+				   poll_result.protocol,
 				   poll_result.scancode,
 				   poll_result.toggle_bit);
 		else
 			rc_keydown(ir->rc,
+				   RC_TYPE_UNKNOWN,
 				   poll_result.scancode & 0xff,
 				   poll_result.toggle_bit);
 
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index d1af543..676c0232 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -162,11 +162,42 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
 	return 0;
 }
 
+static void tm6000_ir_keydown(struct tm6000_IR *ir,
+			      const char *buf, unsigned int len)
+{
+	u8 device, command;
+	u32 scancode;
+	enum rc_type protocol;
+
+	if (len < 1)
+		return;
+
+	command = buf[0];
+	device = (len > 1 ? buf[1] : 0x0);
+	switch (ir->rc_type) {
+	case RC_BIT_RC5:
+		protocol = RC_TYPE_RC5;
+		scancode = RC_SCANCODE_RC5(device, command);
+		break;
+	case RC_BIT_NEC:
+		protocol = RC_TYPE_NEC;
+		scancode = RC_SCANCODE_NEC(device, command);
+		break;
+	default:
+		protocol = RC_TYPE_OTHER;
+		scancode = RC_SCANCODE_OTHER(device << 8 | command);
+		break;
+	}
+
+	dprintk(1, "%s, protocol: 0x%04x, scancode: 0x%08x\n",
+		__func__, protocol, scancode);
+	rc_keydown(ir->rc, protocol, scancode, 0);
+}
+
 static void tm6000_ir_urb_received(struct urb *urb)
 {
 	struct tm6000_core *dev = urb->context;
 	struct tm6000_IR *ir = dev->ir;
-	struct tm6000_ir_poll_result poll_result;
 	char *buf;
 
 	dprintk(2, "%s\n",__func__);
@@ -184,12 +215,7 @@ static void tm6000_ir_urb_received(struct urb *urb)
 			       DUMP_PREFIX_OFFSET,16, 1,
 			       buf, urb->actual_length, false);
 
-	poll_result.rc_data = buf[0];
-	if (urb->actual_length > 1)
-		poll_result.rc_data |= buf[1] << 8;
-
-	dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
-	rc_keydown(ir->rc, poll_result.rc_data, 0);
+	tm6000_ir_keydown(ir, urb->transfer_buffer, urb->actual_length);
 
 	usb_submit_urb(urb, GFP_ATOMIC);
 	/*
@@ -204,7 +230,6 @@ static void tm6000_ir_handle_key(struct work_struct *work)
 {
 	struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
 	struct tm6000_core *dev = ir->dev;
-	struct tm6000_ir_poll_result poll_result;
 	int rc;
 	u8 buf[2];
 
@@ -219,13 +244,8 @@ static void tm6000_ir_handle_key(struct work_struct *work)
 	if (rc < 0)
 		return;
 
-	if (rc > 1)
-		poll_result.rc_data = buf[0] | buf[1] << 8;
-	else
-		poll_result.rc_data = buf[0];
-
 	/* Check if something was read */
-	if ((poll_result.rc_data & 0xff) == 0xff) {
+	if ((buf[0] & 0xff) == 0xff) {
 		if (!ir->pwled) {
 			tm6000_flash_led(dev, 1);
 			ir->pwled = 1;
@@ -233,8 +253,7 @@ static void tm6000_ir_handle_key(struct work_struct *work)
 		return;
 	}
 
-	dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
-	rc_keydown(ir->rc, poll_result.rc_data, 0);
+	tm6000_ir_keydown(ir, buf, rc);
 	tm6000_flash_led(dev, 0);
 	ir->pwled = 0;
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 0b9f890..dbbe63e 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -88,6 +88,7 @@ enum rc_filter_type {
  * @keyup_jiffies: time (in jiffies) when the current keypress should be released
  * @timer_keyup: timer for releasing a keypress
  * @last_keycode: keycode of last keypress
+ * @last_protocol: protocol of last keypress
  * @last_scancode: scancode of last keypress
  * @last_toggle: toggle value of last command
  * @timeout: optional time after which device stops sending data
@@ -138,6 +139,7 @@ struct rc_dev {
 	unsigned long			keyup_jiffies;
 	struct timer_list		timer_keyup;
 	u32				last_keycode;
+	enum rc_type			last_protocol;
 	u32				last_scancode;
 	u8				last_toggle;
 	u32				timeout;
@@ -217,8 +219,8 @@ int rc_open(struct rc_dev *rdev);
 void rc_close(struct rc_dev *rdev);
 
 void rc_repeat(struct rc_dev *dev);
-void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle);
-void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle);
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
 void rc_keyup(struct rc_dev *dev);
 u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode);
 


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

* [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (2 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 03/49] rc-core: document the protocol type David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-04 13:18   ` James Hogan
  2014-04-03 23:31 ` [PATCH 05/49] rc-core: split dev->s_filter David Härdeman
                   ` (46 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This reverts 18bc17448147e93f31cc9b1a83be49f1224657b2

The patch ignores the fact that NEC32 scancodes are generated not only in the
NEC raw decoder but also directly in some drivers. Whichever approach is chosen
it should be consistent across drivers and this patch needs more discussion.

Furthermore, I'm convinced that we have to stop playing games trying to
decipher the "meaning" of NEC scancodes (what's the customer/vendor/address,
which byte is the MSB, etc).

This patch is in preparation for the next few patches in this series.

v2: make sure img-ir scancodes are bitrev8():ed as well

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/img-ir/img-ir-nec.c |   27 ++++++-----
 drivers/media/rc/ir-nec-decoder.c    |    5 --
 drivers/media/rc/keymaps/rc-tivo.c   |   86 +++++++++++++++++-----------------
 3 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index c0111d6..ee45795 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -5,6 +5,7 @@
  */
 
 #include "img-ir-hw.h"
+#include <linux/bitrev.h>
 
 /* Convert NEC data to a scancode */
 static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
@@ -23,11 +24,11 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
 	data_inv = (raw >> 24) & 0xff;
 	if ((data_inv ^ data) != 0xff) {
 		/* 32-bit NEC (used by Apple and TiVo remotes) */
-		/* scan encoding: aaAAddDD */
-		*scancode = addr_inv << 24 |
-			    addr     << 16 |
-			    data_inv <<  8 |
-			    data;
+		/* scan encoding: AAaaDDdd (LSBit first) */
+		*scancode = bitrev8(addr)     << 24 |
+			    bitrev8(addr_inv) << 16 |
+			    bitrev8(data)     <<  8 |
+			    bitrev8(data_inv);
 	} else if ((addr_inv ^ addr) != 0xff) {
 		/* Extended NEC */
 		/* scan encoding: AAaaDD */
@@ -56,13 +57,15 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 
 	if ((in->data | in->mask) & 0xff000000) {
 		/* 32-bit NEC (used by Apple and TiVo remotes) */
-		/* scan encoding: aaAAddDD */
-		addr_inv   = (in->data >> 24) & 0xff;
-		addr_inv_m = (in->mask >> 24) & 0xff;
-		addr       = (in->data >> 16) & 0xff;
-		addr_m     = (in->mask >> 16) & 0xff;
-		data_inv   = (in->data >>  8) & 0xff;
-		data_inv_m = (in->mask >>  8) & 0xff;
+		/* scan encoding: AAaaDDdd (LSBit first) */
+		addr       = bitrev8(in->data >> 24);
+		addr_m     = bitrev8(in->mask >> 24);
+		addr_inv   = bitrev8(in->data >> 16);
+		addr_inv_m = bitrev8(in->mask >> 16);
+		data       = bitrev8(in->data >>  8);
+		data_m     = bitrev8(in->mask >>  8);
+		data_inv   = bitrev8(in->data >>  0);
+		data_inv_m = bitrev8(in->mask >>  0);
 	} else if ((in->data | in->mask) & 0x00ff0000) {
 		/* Extended NEC */
 		/* scan encoding AAaaDD */
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 735a509..c4333d5 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -172,10 +172,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		if (send_32bits) {
 			/* NEC transport, but modified protocol, used by at
 			 * least Apple and TiVo remotes */
-			scancode = not_address << 24 |
-				   address     << 16 |
-				   not_command <<  8 |
-				   command;
+			scancode = data->bits;
 			IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
 		} else if ((address ^ not_address) != 0xff) {
 			/* Extended NEC */
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
index 5cc1b45..454e062 100644
--- a/drivers/media/rc/keymaps/rc-tivo.c
+++ b/drivers/media/rc/keymaps/rc-tivo.c
@@ -15,62 +15,62 @@
  * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
  * which also ships with a TiVo-branded IR transceiver, supported by the mceusb
  * driver. Note that the remote uses an NEC-ish protocol, but instead of having
- * a command/not_command pair, it has a vendor ID of 0x3085, but some keys, the
+ * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
  * NEC extended checksums do pass, so the table presently has the intended
  * values and the checksum-passed versions for those keys.
  */
 static struct rc_map_table tivo[] = {
-	{ 0x3085f009, KEY_MEDIA },	/* TiVo Button */
-	{ 0x3085e010, KEY_POWER2 },	/* TV Power */
-	{ 0x3085e011, KEY_TV },		/* Live TV/Swap */
-	{ 0x3085c034, KEY_VIDEO_NEXT },	/* TV Input */
-	{ 0x3085e013, KEY_INFO },
-	{ 0x3085a05f, KEY_CYCLEWINDOWS }, /* Window */
+	{ 0xa10c900f, KEY_MEDIA },	/* TiVo Button */
+	{ 0xa10c0807, KEY_POWER2 },	/* TV Power */
+	{ 0xa10c8807, KEY_TV },		/* Live TV/Swap */
+	{ 0xa10c2c03, KEY_VIDEO_NEXT },	/* TV Input */
+	{ 0xa10cc807, KEY_INFO },
+	{ 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
 	{ 0x0085305f, KEY_CYCLEWINDOWS },
-	{ 0x3085c036, KEY_EPG },	/* Guide */
+	{ 0xa10c6c03, KEY_EPG },	/* Guide */
 
-	{ 0x3085e014, KEY_UP },
-	{ 0x3085e016, KEY_DOWN },
-	{ 0x3085e017, KEY_LEFT },
-	{ 0x3085e015, KEY_RIGHT },
+	{ 0xa10c2807, KEY_UP },
+	{ 0xa10c6807, KEY_DOWN },
+	{ 0xa10ce807, KEY_LEFT },
+	{ 0xa10ca807, KEY_RIGHT },
 
-	{ 0x3085e018, KEY_SCROLLDOWN },	/* Red Thumbs Down */
-	{ 0x3085e019, KEY_SELECT },
-	{ 0x3085e01a, KEY_SCROLLUP },	/* Green Thumbs Up */
+	{ 0xa10c1807, KEY_SCROLLDOWN },	/* Red Thumbs Down */
+	{ 0xa10c9807, KEY_SELECT },
+	{ 0xa10c5807, KEY_SCROLLUP },	/* Green Thumbs Up */
 
-	{ 0x3085e01c, KEY_VOLUMEUP },
-	{ 0x3085e01d, KEY_VOLUMEDOWN },
-	{ 0x3085e01b, KEY_MUTE },
-	{ 0x3085d020, KEY_RECORD },
-	{ 0x3085e01e, KEY_CHANNELUP },
-	{ 0x3085e01f, KEY_CHANNELDOWN },
+	{ 0xa10c3807, KEY_VOLUMEUP },
+	{ 0xa10cb807, KEY_VOLUMEDOWN },
+	{ 0xa10cd807, KEY_MUTE },
+	{ 0xa10c040b, KEY_RECORD },
+	{ 0xa10c7807, KEY_CHANNELUP },
+	{ 0xa10cf807, KEY_CHANNELDOWN },
 	{ 0x0085301f, KEY_CHANNELDOWN },
 
-	{ 0x3085d021, KEY_PLAY },
-	{ 0x3085d023, KEY_PAUSE },
-	{ 0x3085d025, KEY_SLOW },
-	{ 0x3085d022, KEY_REWIND },
-	{ 0x3085d024, KEY_FASTFORWARD },
-	{ 0x3085d026, KEY_PREVIOUS },
-	{ 0x3085d027, KEY_NEXT },	/* ->| */
+	{ 0xa10c840b, KEY_PLAY },
+	{ 0xa10cc40b, KEY_PAUSE },
+	{ 0xa10ca40b, KEY_SLOW },
+	{ 0xa10c440b, KEY_REWIND },
+	{ 0xa10c240b, KEY_FASTFORWARD },
+	{ 0xa10c640b, KEY_PREVIOUS },
+	{ 0xa10ce40b, KEY_NEXT },	/* ->| */
 
-	{ 0x3085b044, KEY_ZOOM },	/* Aspect */
-	{ 0x3085b048, KEY_STOP },
-	{ 0x3085b04a, KEY_DVD },	/* DVD Menu */
+	{ 0xa10c220d, KEY_ZOOM },	/* Aspect */
+	{ 0xa10c120d, KEY_STOP },
+	{ 0xa10c520d, KEY_DVD },	/* DVD Menu */
 
-	{ 0x3085d028, KEY_NUMERIC_1 },
-	{ 0x3085d029, KEY_NUMERIC_2 },
-	{ 0x3085d02a, KEY_NUMERIC_3 },
-	{ 0x3085d02b, KEY_NUMERIC_4 },
-	{ 0x3085d02c, KEY_NUMERIC_5 },
-	{ 0x3085d02d, KEY_NUMERIC_6 },
-	{ 0x3085d02e, KEY_NUMERIC_7 },
-	{ 0x3085d02f, KEY_NUMERIC_8 },
+	{ 0xa10c140b, KEY_NUMERIC_1 },
+	{ 0xa10c940b, KEY_NUMERIC_2 },
+	{ 0xa10c540b, KEY_NUMERIC_3 },
+	{ 0xa10cd40b, KEY_NUMERIC_4 },
+	{ 0xa10c340b, KEY_NUMERIC_5 },
+	{ 0xa10cb40b, KEY_NUMERIC_6 },
+	{ 0xa10c740b, KEY_NUMERIC_7 },
+	{ 0xa10cf40b, KEY_NUMERIC_8 },
 	{ 0x0085302f, KEY_NUMERIC_8 },
-	{ 0x3085c030, KEY_NUMERIC_9 },
-	{ 0x3085c031, KEY_NUMERIC_0 },
-	{ 0x3085c033, KEY_ENTER },
-	{ 0x3085c032, KEY_CLEAR },
+	{ 0xa10c0c03, KEY_NUMERIC_9 },
+	{ 0xa10c8c03, KEY_NUMERIC_0 },
+	{ 0xa10ccc03, KEY_ENTER },
+	{ 0xa10c4c03, KEY_CLEAR },
 };
 
 static struct rc_map_list tivo_map = {


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

* [PATCH 05/49] rc-core: split dev->s_filter
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (3 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-04 13:08   ` James Hogan
  2014-04-03 23:31 ` [PATCH 06/49] rc-core: remove generic scancode filter David Härdeman
                   ` (45 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Overloading dev->s_filter to do two different functions (set wakeup filters
and generic hardware filters) makes it impossible to tell what the
hardware actually supports, so create a separate dev->s_wakeup_filter and
make the distinction explicit.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/img-ir/img-ir-hw.c |   15 ++++++++++++++-
 drivers/media/rc/rc-main.c          |   31 +++++++++++++++++++------------
 include/media/rc-core.h             |    6 ++++--
 3 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index aec79f7..871a9b3 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -504,6 +504,18 @@ unlock:
 	return ret;
 }
 
+static int img_ir_set_normal_filter(struct rc_dev *dev,
+				    struct rc_scancode_filter *sc_filter)
+{
+	return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter); 
+}
+
+static int img_ir_set_wakeup_filter(struct rc_dev *dev,
+				    struct rc_scancode_filter *sc_filter)
+{
+	return img_ir_set_filter(dev, RC_FILTER_WAKEUP, sc_filter);
+}
+
 /**
  * img_ir_set_decoder() - Set the current decoder.
  * @priv:	IR private data.
@@ -988,7 +1000,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
 	rdev->map_name = RC_MAP_EMPTY;
 	rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv));
 	rdev->input_name = "IMG Infrared Decoder";
-	rdev->s_filter = img_ir_set_filter;
+	rdev->s_filter = img_ir_set_normal_filter;
+	rdev->s_wakeup_filter = img_ir_set_wakeup_filter;
 
 	/* Register hardware decoder */
 	error = rc_register_device(rdev);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index c0bfd50..ba955ac 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -929,6 +929,7 @@ static ssize_t store_protocols(struct device *device,
 	int rc, i, count = 0;
 	ssize_t ret;
 	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
+	int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
 	struct rc_scancode_filter local_filter, *filter;
 
 	/* Device is being removed */
@@ -1013,24 +1014,27 @@ static ssize_t store_protocols(struct device *device,
 	 * Fall back to clearing the filter.
 	 */
 	filter = &dev->scancode_filters[fattr->type];
+	set_filter = (fattr->type == RC_FILTER_NORMAL)
+		? dev->s_filter : dev->s_wakeup_filter;
+
 	if (old_type != type && filter->mask) {
 		local_filter = *filter;
 		if (!type) {
 			/* no protocol => clear filter */
 			ret = -1;
-		} else if (!dev->s_filter) {
+		} else if (!set_filter) {
 			/* generic filtering => accept any filter */
 			ret = 0;
 		} else {
 			/* hardware filtering => try setting, otherwise clear */
-			ret = dev->s_filter(dev, fattr->type, &local_filter);
+			ret = set_filter(dev, &local_filter);
 		}
 		if (ret < 0) {
 			/* clear the filter */
 			local_filter.data = 0;
 			local_filter.mask = 0;
-			if (dev->s_filter)
-				dev->s_filter(dev, fattr->type, &local_filter);
+			if (set_filter)
+				set_filter(dev, &local_filter);
 		}
 
 		/* commit the new filter */
@@ -1112,6 +1116,7 @@ static ssize_t store_filter(struct device *device,
 	struct rc_scancode_filter local_filter, *filter;
 	int ret;
 	unsigned long val;
+	int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
 
 	/* Device is being removed */
 	if (!dev)
@@ -1121,9 +1126,11 @@ static ssize_t store_filter(struct device *device,
 	if (ret < 0)
 		return ret;
 
-	/* Scancode filter not supported (but still accept 0) */
-	if (!dev->s_filter && fattr->type != RC_FILTER_NORMAL)
-		return val ? -EINVAL : count;
+	/* Can the scancode filter be set? */
+	set_filter = (fattr->type == RC_FILTER_NORMAL)
+		? dev->s_filter : dev->s_wakeup_filter;
+	if (!set_filter)
+		return -EINVAL;
 
 	mutex_lock(&dev->lock);
 
@@ -1134,16 +1141,16 @@ static ssize_t store_filter(struct device *device,
 		local_filter.mask = val;
 	else
 		local_filter.data = val;
+
 	if (!dev->enabled_protocols[fattr->type] && local_filter.mask) {
 		/* refuse to set a filter unless a protocol is enabled */
 		ret = -EINVAL;
 		goto unlock;
 	}
-	if (dev->s_filter) {
-		ret = dev->s_filter(dev, fattr->type, &local_filter);
-		if (ret < 0)
-			goto unlock;
-	}
+
+	ret = set_filter(dev, &local_filter);
+	if (ret < 0)
+		goto unlock;
 
 	/* Success, commit the new filter */
 	*filter = local_filter;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index dbbe63e..8c31e4a 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -113,7 +113,8 @@ enum rc_filter_type {
  *	device doesn't interrupt host until it sees IR pulses
  * @s_learning_mode: enable wide band receiver used for learning
  * @s_carrier_report: enable carrier reports
- * @s_filter: set the scancode filter of a given type
+ * @s_filter: set the scancode filter 
+ * @s_wakeup_filter: set the wakeup scancode filter
  */
 struct rc_dev {
 	struct device			dev;
@@ -161,8 +162,9 @@ struct rc_dev {
 	int				(*s_learning_mode)(struct rc_dev *dev, int enable);
 	int				(*s_carrier_report) (struct rc_dev *dev, int enable);
 	int				(*s_filter)(struct rc_dev *dev,
-						    enum rc_filter_type type,
 						    struct rc_scancode_filter *filter);
+	int				(*s_wakeup_filter)(struct rc_dev *dev,
+							   struct rc_scancode_filter *filter);
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 06/49] rc-core: remove generic scancode filter
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (4 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 05/49] rc-core: split dev->s_filter David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-04 13:30   ` James Hogan
  2014-04-03 23:31 ` [PATCH 07/49] dib0700: NEC scancode cleanup David Härdeman
                   ` (44 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The generic scancode filtering has questionable value and makes it
impossible to determine from userspace if there is an actual
scancode hw filter present or not.

So revert the generic parts.

Based on a patch from James Hogan <james.hogan@imgtec.com>, but this
version also makes sure that only the valid sysfs files are created
in the first place.

v2: correct dev->s_filter check

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |   67 +++++++++++++++++++++++++++++---------------
 include/media/rc-core.h    |    2 +
 2 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index ba955ac..26c266b 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -634,7 +634,6 @@ EXPORT_SYMBOL_GPL(rc_repeat);
 static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 			  u32 scancode, u32 keycode, u8 toggle)
 {
-	struct rc_scancode_filter *filter;
 	bool new_event = (!dev->keypressed		 ||
 			  dev->last_protocol != protocol ||
 			  dev->last_scancode != scancode ||
@@ -643,11 +642,6 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 	if (new_event && dev->keypressed)
 		ir_do_keyup(dev, false);
 
-	/* Generic scancode filtering */
-	filter = &dev->scancode_filters[RC_FILTER_NORMAL];
-	if (filter->mask && ((scancode ^ filter->data) & filter->mask))
-		return;
-
 	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
 
 	if (new_event && keycode != KEY_RESERVED) {
@@ -1017,14 +1011,11 @@ static ssize_t store_protocols(struct device *device,
 	set_filter = (fattr->type == RC_FILTER_NORMAL)
 		? dev->s_filter : dev->s_wakeup_filter;
 
-	if (old_type != type && filter->mask) {
+	if (set_filter && old_type != type && filter->mask) {
 		local_filter = *filter;
 		if (!type) {
 			/* no protocol => clear filter */
 			ret = -1;
-		} else if (!set_filter) {
-			/* generic filtering => accept any filter */
-			ret = 0;
 		} else {
 			/* hardware filtering => try setting, otherwise clear */
 			ret = set_filter(dev, &local_filter);
@@ -1033,8 +1024,7 @@ static ssize_t store_protocols(struct device *device,
 			/* clear the filter */
 			local_filter.data = 0;
 			local_filter.mask = 0;
-			if (set_filter)
-				set_filter(dev, &local_filter);
+			set_filter(dev, &local_filter);
 		}
 
 		/* commit the new filter */
@@ -1078,7 +1068,10 @@ static ssize_t show_filter(struct device *device,
 		return -EINVAL;
 
 	mutex_lock(&dev->lock);
-	if (fattr->mask)
+	if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) ||
+	    (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter))
+		val = 0;
+	else if (fattr->mask)
 		val = dev->scancode_filters[fattr->type].mask;
 	else
 		val = dev->scancode_filters[fattr->type].data;
@@ -1202,27 +1195,45 @@ static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR,
 static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
 		      show_filter, store_filter, RC_FILTER_WAKEUP, true);
 
-static struct attribute *rc_dev_attrs[] = {
+static struct attribute *rc_dev_protocol_attrs[] = {
 	&dev_attr_protocols.attr.attr,
+	NULL,
+};
+
+static struct attribute_group rc_dev_protocol_attr_grp = {
+	.attrs	= rc_dev_protocol_attrs,
+};
+
+static struct attribute *rc_dev_wakeup_protocol_attrs[] = {
 	&dev_attr_wakeup_protocols.attr.attr,
+	NULL,
+};
+
+static struct attribute_group rc_dev_wakeup_protocol_attr_grp = {
+	.attrs	= rc_dev_wakeup_protocol_attrs,
+};
+
+static struct attribute *rc_dev_filter_attrs[] = {
 	&dev_attr_filter.attr.attr,
 	&dev_attr_filter_mask.attr.attr,
-	&dev_attr_wakeup_filter.attr.attr,
-	&dev_attr_wakeup_filter_mask.attr.attr,
 	NULL,
 };
 
-static struct attribute_group rc_dev_attr_grp = {
-	.attrs	= rc_dev_attrs,
+static struct attribute_group rc_dev_filter_attr_grp = {
+	.attrs	= rc_dev_filter_attrs,
+};
+
+static struct attribute *rc_dev_wakeup_filter_attrs[] = {
+	&dev_attr_wakeup_filter.attr.attr,
+	&dev_attr_wakeup_filter_mask.attr.attr,
+	NULL,
 };
 
-static const struct attribute_group *rc_dev_attr_groups[] = {
-	&rc_dev_attr_grp,
-	NULL
+static struct attribute_group rc_dev_wakeup_filter_attr_grp = {
+	.attrs	= rc_dev_wakeup_filter_attrs,
 };
 
 static struct device_type rc_dev_type = {
-	.groups		= rc_dev_attr_groups,
 	.release	= rc_dev_release,
 	.uevent		= rc_dev_uevent,
 };
@@ -1279,7 +1290,7 @@ int rc_register_device(struct rc_dev *dev)
 	static bool raw_init = false; /* raw decoders loaded? */
 	struct rc_map *rc_map;
 	const char *path;
-	int rc, devno;
+	int rc, devno, attr = 0;
 
 	if (!dev || !dev->map_name)
 		return -EINVAL;
@@ -1307,6 +1318,16 @@ int rc_register_device(struct rc_dev *dev)
 			return -ENOMEM;
 	} while (test_and_set_bit(devno, ir_core_dev_number));
 
+	dev->dev.groups = dev->sysfs_groups;
+	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
+	if (dev->s_filter)
+		dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;	
+	if (dev->s_wakeup_filter)
+		dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
+	if (dev->change_wakeup_protocol)
+		dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
+	dev->sysfs_groups[attr++] = NULL;
+
 	/*
 	 * Take the lock here, as the device sysfs node will appear
 	 * when device_add() is called, which may trigger an ir-keytable udev
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 8c31e4a..2e97b98 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -60,6 +60,7 @@ enum rc_filter_type {
 /**
  * struct rc_dev - represents a remote control device
  * @dev: driver model's view of this device
+ * @sysfs_groups: sysfs attribute groups
  * @input_name: name of the input child device
  * @input_phys: physical path to the input child device
  * @input_id: id of the input child device (struct input_id)
@@ -118,6 +119,7 @@ enum rc_filter_type {
  */
 struct rc_dev {
 	struct device			dev;
+	const struct attribute_group	*sysfs_groups[5];
 	const char			*input_name;
 	const char			*input_phys;
 	struct input_id			input_id;


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

* [PATCH 07/49] dib0700: NEC scancode cleanup
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (5 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 06/49] rc-core: remove generic scancode filter David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-03 23:31 ` [PATCH 08/49] lmedm04: " David Härdeman
                   ` (43 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

the RC RX packet is defined as:

        struct dib0700_rc_response {
		...
                                u8 not_system;
                                u8 system;
		...
                u8 data;
                u8 not_data;

The NEC protocol transmits in the order:
        system
        not_system
        data
        not_data

Note that the code defines the NEC extended scancode as:

        scancode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;

i.e.

        scancode = poll_reply->not_system << 16 |
                   poll_reply->system     << 8  |
                   poll_reply->data;

Which, if the order *is* reversed, would mean that the scancode that
gets defined is in reality:

        scancode = poll_reply->system     << 16 |
                   poll_reply->not_system << 8  |
                   poll_reply->data;

Which is the same as the order used in drivers/media/rc/ir-nec-decoder.c.

This patch changes the code to match my assumption (the generated scancode
should, however, not change).

Signed-off-by: David Härdeman <david@hardeman.nu>
CC: Patrick Boettcher <pboettcher@kernellabs.com>
---
 drivers/media/usb/dvb-usb/dib0700_core.c |   28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 6afe7ea..0d881b9 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -658,13 +658,8 @@ out:
 struct dib0700_rc_response {
 	u8 report_id;
 	u8 data_state;
-	union {
-		u16 system16;
-		struct {
-			u8 not_system;
-			u8 system;
-		};
-	};
+	u8 system;
+	u8 not_system;
 	u8 data;
 	u8 not_data;
 };
@@ -712,20 +707,27 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 		toggle = 0;
 
 		/* NEC protocol sends repeat code as 0 0 0 FF */
-		if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
-		    && (poll_reply->not_data == 0xff)) {
+		if (poll_reply->system     == 0x00 &&
+		    poll_reply->not_system == 0x00 &&
+		    poll_reply->data       == 0x00 &&
+		    poll_reply->not_data   == 0xff) {
 			poll_reply->data_state = 2;
 			break;
 		}
 
-		if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+		if ((poll_reply->data ^ poll_reply->not_data) != 0xff) {
+			deb_data("NEC32 protocol\n");
+			scancode = RC_SCANCODE_NEC32(poll_reply->system     << 24 |
+						     poll_reply->not_system << 16 |
+						     poll_reply->data       << 8  |
+						     poll_reply->not_data);
+		} else if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
 			deb_data("NEC extended protocol\n");
-			/* NEC extended code - 24 bits */
-			scancode = RC_SCANCODE_NECX(be16_to_cpu(poll_reply->system16),
+			scancode = RC_SCANCODE_NECX(poll_reply->system << 8 |
+						    poll_reply->not_system,
 						    poll_reply->data);
 		} else {
 			deb_data("NEC normal protocol\n");
-			/* normal NEC code - 16 bits */
 			scancode = RC_SCANCODE_NEC(poll_reply->system,
 						   poll_reply->data);
 		}


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

* [PATCH 08/49] lmedm04: NEC scancode cleanup
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (6 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 07/49] dib0700: NEC scancode cleanup David Härdeman
@ 2014-04-03 23:31 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 09/49] saa7134: NEC scancode fix David Härdeman
                   ` (42 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:31 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This changes the keymap back to the state before commit 616a4b83
and changes the driver to use full NEC32 scancodes following the
instructions provided by Malcolm Priestley <tvboxspy@gmail.com>.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/keymaps/rc-lme2510.c  |  132 ++++++++++++++++----------------
 drivers/media/usb/dvb-usb-v2/lmedm04.c |   21 +++--
 2 files changed, 77 insertions(+), 76 deletions(-)

diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
index 51f18bb..2b0027c 100644
--- a/drivers/media/rc/keymaps/rc-lme2510.c
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -15,74 +15,74 @@
 
 static struct rc_map_table lme2510_rc[] = {
 	/* Type 1 - 26 buttons */
-	{ 0x10ed45, KEY_0 },
-	{ 0x10ed5f, KEY_1 },
-	{ 0x10ed50, KEY_2 },
-	{ 0x10ed5d, KEY_3 },
-	{ 0x10ed41, KEY_4 },
-	{ 0x10ed0a, KEY_5 },
-	{ 0x10ed42, KEY_6 },
-	{ 0x10ed47, KEY_7 },
-	{ 0x10ed49, KEY_8 },
-	{ 0x10ed05, KEY_9 },
-	{ 0x10ed43, KEY_POWER },
-	{ 0x10ed46, KEY_SUBTITLE },
-	{ 0x10ed06, KEY_PAUSE },
-	{ 0x10ed03, KEY_MEDIA_REPEAT},
-	{ 0x10ed02, KEY_PAUSE },
-	{ 0x10ed5e, KEY_VOLUMEUP },
-	{ 0x10ed5c, KEY_VOLUMEDOWN },
-	{ 0x10ed09, KEY_CHANNELUP },
-	{ 0x10ed1a, KEY_CHANNELDOWN },
-	{ 0x10ed1e, KEY_PLAY },
-	{ 0x10ed1b, KEY_ZOOM },
-	{ 0x10ed59, KEY_MUTE },
-	{ 0x10ed5a, KEY_TV },
-	{ 0x10ed18, KEY_RECORD },
-	{ 0x10ed07, KEY_EPG },
-	{ 0x10ed01, KEY_STOP },
+	{ 0xef12ba45, KEY_0 },
+	{ 0xef12a05f, KEY_1 },
+	{ 0xef12af50, KEY_2 },
+	{ 0xef12a25d, KEY_3 },
+	{ 0xef12be41, KEY_4 },
+	{ 0xef12f50a, KEY_5 },
+	{ 0xef12bd42, KEY_6 },
+	{ 0xef12b847, KEY_7 },
+	{ 0xef12b649, KEY_8 },
+	{ 0xef12fa05, KEY_9 },
+	{ 0xef12bc43, KEY_POWER },
+	{ 0xef12b946, KEY_SUBTITLE },
+	{ 0xef12f906, KEY_PAUSE },
+	{ 0xef12fc03, KEY_MEDIA_REPEAT},
+	{ 0xef12fd02, KEY_PAUSE },
+	{ 0xef12a15e, KEY_VOLUMEUP },
+	{ 0xef12a35c, KEY_VOLUMEDOWN },
+	{ 0xef12f609, KEY_CHANNELUP },
+	{ 0xef12e51a, KEY_CHANNELDOWN },
+	{ 0xef12e11e, KEY_PLAY },
+	{ 0xef12e41b, KEY_ZOOM },
+	{ 0xef12a659, KEY_MUTE },
+	{ 0xef12a55a, KEY_TV },
+	{ 0xef12e718, KEY_RECORD },
+	{ 0xef12f807, KEY_EPG },
+	{ 0xef12fe01, KEY_STOP },
 	/* Type 2 - 20 buttons */
-	{ 0xbf15, KEY_0 },
-	{ 0xbf08, KEY_1 },
-	{ 0xbf09, KEY_2 },
-	{ 0xbf0a, KEY_3 },
-	{ 0xbf0c, KEY_4 },
-	{ 0xbf0d, KEY_5 },
-	{ 0xbf0e, KEY_6 },
-	{ 0xbf10, KEY_7 },
-	{ 0xbf11, KEY_8 },
-	{ 0xbf12, KEY_9 },
-	{ 0xbf00, KEY_POWER },
-	{ 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */
-	{ 0xbf1a, KEY_PAUSE }, /* Timeshift */
-	{ 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
-	{ 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
-	{ 0xbf01, KEY_CHANNELUP },
-	{ 0xbf05, KEY_CHANNELDOWN },
-	{ 0xbf14, KEY_ZOOM },
-	{ 0xbf18, KEY_RECORD },
-	{ 0xbf16, KEY_STOP },
+	{ 0xff40ea15, KEY_0 },
+	{ 0xff40f708, KEY_1 },
+	{ 0xff40f609, KEY_2 },
+	{ 0xff40f50a, KEY_3 },
+	{ 0xff40f30c, KEY_4 },
+	{ 0xff40f20d, KEY_5 },
+	{ 0xff40f10e, KEY_6 },
+	{ 0xff40ef10, KEY_7 },
+	{ 0xff40ee11, KEY_8 },
+	{ 0xff40ed12, KEY_9 },
+	{ 0xff40ff00, KEY_POWER },
+	{ 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
+	{ 0xff40e51a, KEY_PAUSE }, /* Timeshift */
+	{ 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+	{ 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+	{ 0xff40fe01, KEY_CHANNELUP },
+	{ 0xff40fa05, KEY_CHANNELDOWN },
+	{ 0xff40eb14, KEY_ZOOM },
+	{ 0xff40e718, KEY_RECORD },
+	{ 0xff40e916, KEY_STOP },
 	/* Type 3 - 20 buttons */
-	{ 0x1c, KEY_0 },
-	{ 0x07, KEY_1 },
-	{ 0x15, KEY_2 },
-	{ 0x09, KEY_3 },
-	{ 0x16, KEY_4 },
-	{ 0x19, KEY_5 },
-	{ 0x0d, KEY_6 },
-	{ 0x0c, KEY_7 },
-	{ 0x18, KEY_8 },
-	{ 0x5e, KEY_9 },
-	{ 0x45, KEY_POWER },
-	{ 0x44, KEY_MEDIA_REPEAT}, /* Recall */
-	{ 0x4a, KEY_PAUSE }, /* Timeshift */
-	{ 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
-	{ 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
-	{ 0x46, KEY_CHANNELUP },
-	{ 0x40, KEY_CHANNELDOWN },
-	{ 0x08, KEY_ZOOM },
-	{ 0x42, KEY_RECORD },
-	{ 0x5a, KEY_STOP },
+	{ 0xff00e31c, KEY_0 },
+	{ 0xff00f807, KEY_1 },
+	{ 0xff00ea15, KEY_2 },
+	{ 0xff00f609, KEY_3 },
+	{ 0xff00e916, KEY_4 },
+	{ 0xff00e619, KEY_5 },
+	{ 0xff00f20d, KEY_6 },
+	{ 0xff00f30c, KEY_7 },
+	{ 0xff00e718, KEY_8 },
+	{ 0xff00a15e, KEY_9 },
+	{ 0xff00ba45, KEY_POWER },
+	{ 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
+	{ 0xff00b54a, KEY_PAUSE }, /* Timeshift */
+	{ 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+	{ 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+	{ 0xff00b946, KEY_CHANNELUP },
+	{ 0xff00bf40, KEY_CHANNELDOWN },
+	{ 0xff00f708, KEY_ZOOM },
+	{ 0xff00bd42, KEY_RECORD },
+	{ 0xff00a55a, KEY_STOP },
 };
 
 static struct rc_map_list lme2510_map = {
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 31f31fc..a370f5f 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -286,15 +286,16 @@ static void lme2510_int_response(struct urb *lme_urb)
 		switch (ibuf[0]) {
 		case 0xaa:
 			debug_data_snipet(1, "INT Remote data snipet", ibuf);
-			if ((ibuf[4] + ibuf[5]) == 0xff) {
-				key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 |
-						       (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0,
-						       ibuf[5]);
-				deb_info(1, "INT Key =%08x", key);
-				if (adap_to_d(adap)->rc_dev != NULL)
-					rc_keydown(adap_to_d(adap)->rc_dev,
-						   RC_TYPE_NEC, key, 0);
-			}
+			if (!adap_to_d(adap)->rc_dev)
+				break;
+
+			key = RC_SCANCODE_NEC32(ibuf[2] << 24 |
+						ibuf[3] << 16 |
+						ibuf[4] << 8  |
+						ibuf[5]);
+
+			deb_info(1, "INT Key = 0x%08x", key);
+			rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0);
 			break;
 		case 0xbb:
 			switch (st->tuner_config) {
@@ -1367,7 +1368,7 @@ module_usb_driver(lme2510_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("2.06");
+MODULE_VERSION("2.07");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(LME2510_C_S7395);
 MODULE_FIRMWARE(LME2510_C_LG);


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

* [PATCH 09/49] saa7134: NEC scancode fix
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (7 preceding siblings ...)
  2014-04-03 23:31 ` [PATCH 08/49] lmedm04: " David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 10/49] [RFC] rc-core: use the full 32 bits for NEC scancodes David Härdeman
                   ` (41 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This driver codes the two address bytes in reverse order when compared to the
other drivers, so make it consistent (and update the keymap, note that the
result is a prefix change from 0x6b86 -> 0x866b, and the latter is pretty
common among the NECX keymaps. While not conclusive, it's still a strong hint
that the change is correct).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/pci/saa7134/saa7134-input.c |    2 -
 drivers/media/rc/keymaps/rc-behold.c      |   68 +++++++++++++++--------------
 2 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 43dd8bd..887429b 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -346,7 +346,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol,
 		return 0;
 
 	*protocol = RC_TYPE_NEC;
-	*scancode = RC_SCANCODE_NECX(((data[10] << 8) | data[11]), data[9]);
+	*scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]);
 	*toggle = 0;
 	return 1;
 }
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index d6519f8..520a96f 100644
--- a/drivers/media/rc/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -30,8 +30,8 @@ static struct rc_map_table behold[] = {
 	/*  0x1c            0x12  *
 	 *  TV/FM          POWER  *
 	 *                        */
-	{ 0x6b861c, KEY_TUNER },	/* XXX KEY_TV / KEY_RADIO */
-	{ 0x6b8612, KEY_POWER },
+	{ 0x866b1c, KEY_TUNER },	/* XXX KEY_TV / KEY_RADIO */
+	{ 0x866b12, KEY_POWER },
 
 	/*  0x01    0x02    0x03  *
 	 *   1       2       3    *
@@ -42,28 +42,28 @@ static struct rc_map_table behold[] = {
 	 *  0x07    0x08    0x09  *
 	 *   7       8       9    *
 	 *                        */
-	{ 0x6b8601, KEY_1 },
-	{ 0x6b8602, KEY_2 },
-	{ 0x6b8603, KEY_3 },
-	{ 0x6b8604, KEY_4 },
-	{ 0x6b8605, KEY_5 },
-	{ 0x6b8606, KEY_6 },
-	{ 0x6b8607, KEY_7 },
-	{ 0x6b8608, KEY_8 },
-	{ 0x6b8609, KEY_9 },
+	{ 0x866b01, KEY_1 },
+	{ 0x866b02, KEY_2 },
+	{ 0x866b03, KEY_3 },
+	{ 0x866b04, KEY_4 },
+	{ 0x866b05, KEY_5 },
+	{ 0x866b06, KEY_6 },
+	{ 0x866b07, KEY_7 },
+	{ 0x866b08, KEY_8 },
+	{ 0x866b09, KEY_9 },
 
 	/*  0x0a    0x00    0x17  *
 	 * RECALL    0      MODE  *
 	 *                        */
-	{ 0x6b860a, KEY_AGAIN },
-	{ 0x6b8600, KEY_0 },
-	{ 0x6b8617, KEY_MODE },
+	{ 0x866b0a, KEY_AGAIN },
+	{ 0x866b00, KEY_0 },
+	{ 0x866b17, KEY_MODE },
 
 	/*  0x14          0x10    *
 	 * ASPECT      FULLSCREEN *
 	 *                        */
-	{ 0x6b8614, KEY_SCREEN },
-	{ 0x6b8610, KEY_ZOOM },
+	{ 0x866b14, KEY_SCREEN },
+	{ 0x866b10, KEY_ZOOM },
 
 	/*          0x0b          *
 	 *           Up           *
@@ -74,17 +74,17 @@ static struct rc_map_table behold[] = {
 	 *         0x015          *
 	 *         Down           *
 	 *                        */
-	{ 0x6b860b, KEY_CHANNELUP },
-	{ 0x6b8618, KEY_VOLUMEDOWN },
-	{ 0x6b8616, KEY_OK },		/* XXX KEY_ENTER */
-	{ 0x6b860c, KEY_VOLUMEUP },
-	{ 0x6b8615, KEY_CHANNELDOWN },
+	{ 0x866b0b, KEY_CHANNELUP },
+	{ 0x866b18, KEY_VOLUMEDOWN },
+	{ 0x866b16, KEY_OK },		/* XXX KEY_ENTER */
+	{ 0x866b0c, KEY_VOLUMEUP },
+	{ 0x866b15, KEY_CHANNELDOWN },
 
 	/*  0x11            0x0d  *
 	 *  MUTE            INFO  *
 	 *                        */
-	{ 0x6b8611, KEY_MUTE },
-	{ 0x6b860d, KEY_INFO },
+	{ 0x866b11, KEY_MUTE },
+	{ 0x866b0d, KEY_INFO },
 
 	/*  0x0f    0x1b    0x1a  *
 	 * RECORD PLAY/PAUSE STOP *
@@ -93,26 +93,26 @@ static struct rc_map_table behold[] = {
 	 *TELETEXT  AUDIO  SOURCE *
 	 *           RED   YELLOW *
 	 *                        */
-	{ 0x6b860f, KEY_RECORD },
-	{ 0x6b861b, KEY_PLAYPAUSE },
-	{ 0x6b861a, KEY_STOP },
-	{ 0x6b860e, KEY_TEXT },
-	{ 0x6b861f, KEY_RED },	/*XXX KEY_AUDIO	*/
-	{ 0x6b861e, KEY_VIDEO },
+	{ 0x866b0f, KEY_RECORD },
+	{ 0x866b1b, KEY_PLAYPAUSE },
+	{ 0x866b1a, KEY_STOP },
+	{ 0x866b0e, KEY_TEXT },
+	{ 0x866b1f, KEY_RED },	/*XXX KEY_AUDIO	*/
+	{ 0x866b1e, KEY_VIDEO },
 
 	/*  0x1d   0x13     0x19  *
 	 * SLEEP  PREVIEW   DVB   *
 	 *         GREEN    BLUE  *
 	 *                        */
-	{ 0x6b861d, KEY_SLEEP },
-	{ 0x6b8613, KEY_GREEN },
-	{ 0x6b8619, KEY_BLUE },	/* XXX KEY_SAT	*/
+	{ 0x866b1d, KEY_SLEEP },
+	{ 0x866b13, KEY_GREEN },
+	{ 0x866b19, KEY_BLUE },	/* XXX KEY_SAT	*/
 
 	/*  0x58           0x5c   *
 	 * FREEZE        SNAPSHOT *
 	 *                        */
-	{ 0x6b8658, KEY_SLOW },
-	{ 0x6b865c, KEY_CAMERA },
+	{ 0x866b58, KEY_SLOW },
+	{ 0x866b5c, KEY_CAMERA },
 
 };
 


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

* [PATCH 10/49] [RFC] rc-core: use the full 32 bits for NEC scancodes
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (8 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 09/49] saa7134: NEC scancode fix David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 11/49] [RFC] rc-core: don't throw away protocol information David Härdeman
                   ` (40 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Using the full 32 bits for all kinds of NEC scancodes simplifies rc-core
and the nec decoder without any loss of functionality.

In order to maintain backwards compatibility, some heuristics are added
in rc-main.c to convert scancodes to NEC32 as necessary.

I plan to introduce a different ioctl later which makes the protocol
explicit (and which expects all NEC scancodes to be 32 bit, thereby
removing the need for guesswork).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/pci/saa7134/saa7134-input.c |    6 +-
 drivers/media/rc/img-ir/img-ir-nec.c      |   79 ++----------------------
 drivers/media/rc/ir-nec-decoder.c         |   28 ++-------
 drivers/media/rc/keymaps/rc-tivo.c        |   95 ++++++++++++++---------------
 drivers/media/rc/rc-main.c                |   53 ++++++++++++++++
 drivers/media/usb/dvb-usb-v2/af9015.c     |   22 +------
 drivers/media/usb/dvb-usb-v2/af9035.c     |   15 +----
 drivers/media/usb/dvb-usb-v2/az6007.c     |   16 +----
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c   |   16 +----
 drivers/media/usb/dvb-usb/dib0700_core.c  |   21 ++----
 drivers/media/usb/em28xx/em28xx-input.c   |   14 +---
 include/media/rc-map.h                    |   16 ++++-
 12 files changed, 147 insertions(+), 234 deletions(-)

diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 887429b..4ba61ff 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -342,11 +342,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol,
 		return -EIO;
 	}
 
-	if (data[9] != (unsigned char)(~data[8]))
-		return 0;
-
 	*protocol = RC_TYPE_NEC;
-	*scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]);
+	*scancode = RC_SCANCODE_NEC32(data[11] << 24 | data[10] << 16 |
+				      data[9]  << 8  | data[8]);
 	*toggle = 0;
 	return 1;
 }
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index ee45795..133ea45 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -5,42 +5,20 @@
  */
 
 #include "img-ir-hw.h"
-#include <linux/bitrev.h>
 
 /* Convert NEC data to a scancode */
 static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
 			       u32 *scancode, u64 enabled_protocols)
 {
-	unsigned int addr, addr_inv, data, data_inv;
 	/* a repeat code has no data */
 	if (!len)
 		return IMG_IR_REPEATCODE;
+
 	if (len != 32)
 		return -EINVAL;
-	/* raw encoding: ddDDaaAA */
-	addr     = (raw >>  0) & 0xff;
-	addr_inv = (raw >>  8) & 0xff;
-	data     = (raw >> 16) & 0xff;
-	data_inv = (raw >> 24) & 0xff;
-	if ((data_inv ^ data) != 0xff) {
-		/* 32-bit NEC (used by Apple and TiVo remotes) */
-		/* scan encoding: AAaaDDdd (LSBit first) */
-		*scancode = bitrev8(addr)     << 24 |
-			    bitrev8(addr_inv) << 16 |
-			    bitrev8(data)     <<  8 |
-			    bitrev8(data_inv);
-	} else if ((addr_inv ^ addr) != 0xff) {
-		/* Extended NEC */
-		/* scan encoding: AAaaDD */
-		*scancode = addr     << 16 |
-			    addr_inv <<  8 |
-			    data;
-	} else {
-		/* Normal NEC */
-		/* scan encoding: AADD */
-		*scancode = addr << 8 |
-			    data;
-	}
+
+	/* raw encoding : ddDDaaAA -> scan encoding: AAaaDDdd */
+	*scancode = swab32((u32)raw);
 	*protocol = RC_TYPE_NEC;
 	return IMG_IR_SCANCODE;
 }
@@ -49,52 +27,9 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
 static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 			     struct img_ir_filter *out, u64 protocols)
 {
-	unsigned int addr, addr_inv, data, data_inv;
-	unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
-
-	data       = in->data & 0xff;
-	data_m     = in->mask & 0xff;
-
-	if ((in->data | in->mask) & 0xff000000) {
-		/* 32-bit NEC (used by Apple and TiVo remotes) */
-		/* scan encoding: AAaaDDdd (LSBit first) */
-		addr       = bitrev8(in->data >> 24);
-		addr_m     = bitrev8(in->mask >> 24);
-		addr_inv   = bitrev8(in->data >> 16);
-		addr_inv_m = bitrev8(in->mask >> 16);
-		data       = bitrev8(in->data >>  8);
-		data_m     = bitrev8(in->mask >>  8);
-		data_inv   = bitrev8(in->data >>  0);
-		data_inv_m = bitrev8(in->mask >>  0);
-	} else if ((in->data | in->mask) & 0x00ff0000) {
-		/* Extended NEC */
-		/* scan encoding AAaaDD */
-		addr       = (in->data >> 16) & 0xff;
-		addr_m     = (in->mask >> 16) & 0xff;
-		addr_inv   = (in->data >>  8) & 0xff;
-		addr_inv_m = (in->mask >>  8) & 0xff;
-		data_inv   = data ^ 0xff;
-		data_inv_m = data_m;
-	} else {
-		/* Normal NEC */
-		/* scan encoding: AADD */
-		addr       = (in->data >>  8) & 0xff;
-		addr_m     = (in->mask >>  8) & 0xff;
-		addr_inv   = addr ^ 0xff;
-		addr_inv_m = addr_m;
-		data_inv   = data ^ 0xff;
-		data_inv_m = data_m;
-	}
-
-	/* raw encoding: ddDDaaAA */
-	out->data = data_inv << 24 |
-		    data     << 16 |
-		    addr_inv <<  8 |
-		    addr;
-	out->mask = data_inv_m << 24 |
-		    data_m     << 16 |
-		    addr_inv_m <<  8 |
-		    addr_m;
+	/* scan encoding: AAaaDDdd -> raw encoding: ddDDaaAA */
+	out->data = swab32((u32)in->data);
+	out->mask = swab32((u32)in->mask);
 	return 0;
 }
 
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index c4333d5..798e32b 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -50,7 +50,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct nec_dec *data = &dev->raw->nec;
 	u32 scancode;
 	u8 address, not_address, command, not_command;
-	bool send_32bits = false;
 
 	if (!rc_protocols_enabled(dev, RC_BIT_NEC))
 		return 0;
@@ -163,28 +162,11 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		command	    = bitrev8((data->bits >>  8) & 0xff);
 		not_command = bitrev8((data->bits >>  0) & 0xff);
 
-		if ((command ^ not_command) != 0xff) {
-			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
-				   data->bits);
-			send_32bits = true;
-		}
-
-		if (send_32bits) {
-			/* NEC transport, but modified protocol, used by at
-			 * least Apple and TiVo remotes */
-			scancode = data->bits;
-			IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
-		} else 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);
-		}
+		scancode = RC_SCANCODE_NEC32(address	 << 24 |
+					     not_address << 16 |
+					     command	 << 8  |
+					     not_command);
+		IR_dprintk(1, "NEC scancode 0x%08x\n", scancode);
 
 		if (data->is_nec_x)
 			data->necx_repeat = true;
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
index 454e062..63ed7ad 100644
--- a/drivers/media/rc/keymaps/rc-tivo.c
+++ b/drivers/media/rc/keymaps/rc-tivo.c
@@ -15,62 +15,61 @@
  * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
  * which also ships with a TiVo-branded IR transceiver, supported by the mceusb
  * driver. Note that the remote uses an NEC-ish protocol, but instead of having
- * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
- * NEC extended checksums do pass, so the table presently has the intended
- * values and the checksum-passed versions for those keys.
+ * a command/not_command pair, it has a vendor ID of 0x8530, but some keys, the
+ * NEC extended checksums do pass, so the table has the full code for all keys.
  */
 static struct rc_map_table tivo[] = {
-	{ 0xa10c900f, KEY_MEDIA },	/* TiVo Button */
-	{ 0xa10c0807, KEY_POWER2 },	/* TV Power */
-	{ 0xa10c8807, KEY_TV },		/* Live TV/Swap */
-	{ 0xa10c2c03, KEY_VIDEO_NEXT },	/* TV Input */
-	{ 0xa10cc807, KEY_INFO },
-	{ 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
-	{ 0x0085305f, KEY_CYCLEWINDOWS },
-	{ 0xa10c6c03, KEY_EPG },	/* Guide */
+	{ 0x853009f0, KEY_MEDIA },	/* TiVo Button */
+	{ 0x853010e0, KEY_POWER2 },	/* TV Power */
+	{ 0x853011e0, KEY_TV },		/* Live TV/Swap */
+	{ 0x853034c0, KEY_VIDEO_NEXT },	/* TV Input */
+	{ 0x853013e0, KEY_INFO },
+	{ 0x85305fa0, KEY_CYCLEWINDOWS }, /* Window */
+	{ 0x85005f30, KEY_CYCLEWINDOWS },
+	{ 0x853036c0, KEY_EPG },	/* Guide */
 
-	{ 0xa10c2807, KEY_UP },
-	{ 0xa10c6807, KEY_DOWN },
-	{ 0xa10ce807, KEY_LEFT },
-	{ 0xa10ca807, KEY_RIGHT },
+	{ 0x853014e0, KEY_UP },
+	{ 0x853016e0, KEY_DOWN },
+	{ 0x853017e0, KEY_LEFT },
+	{ 0x853015e0, KEY_RIGHT },
 
-	{ 0xa10c1807, KEY_SCROLLDOWN },	/* Red Thumbs Down */
-	{ 0xa10c9807, KEY_SELECT },
-	{ 0xa10c5807, KEY_SCROLLUP },	/* Green Thumbs Up */
+	{ 0x853018e0, KEY_SCROLLDOWN },	/* Red Thumbs Down */
+	{ 0x853019e0, KEY_SELECT },
+	{ 0x85301ae0, KEY_SCROLLUP },	/* Green Thumbs Up */
 
-	{ 0xa10c3807, KEY_VOLUMEUP },
-	{ 0xa10cb807, KEY_VOLUMEDOWN },
-	{ 0xa10cd807, KEY_MUTE },
-	{ 0xa10c040b, KEY_RECORD },
-	{ 0xa10c7807, KEY_CHANNELUP },
-	{ 0xa10cf807, KEY_CHANNELDOWN },
-	{ 0x0085301f, KEY_CHANNELDOWN },
+	{ 0x85301ce0, KEY_VOLUMEUP },
+	{ 0x85301de0, KEY_VOLUMEDOWN },
+	{ 0x85301be0, KEY_MUTE },
+	{ 0x853020d0, KEY_RECORD },
+	{ 0x85301ee0, KEY_CHANNELUP },
+	{ 0x85301fe0, KEY_CHANNELDOWN },
+	{ 0x85001f30, KEY_CHANNELDOWN },
 
-	{ 0xa10c840b, KEY_PLAY },
-	{ 0xa10cc40b, KEY_PAUSE },
-	{ 0xa10ca40b, KEY_SLOW },
-	{ 0xa10c440b, KEY_REWIND },
-	{ 0xa10c240b, KEY_FASTFORWARD },
-	{ 0xa10c640b, KEY_PREVIOUS },
-	{ 0xa10ce40b, KEY_NEXT },	/* ->| */
+	{ 0x853021d0, KEY_PLAY },
+	{ 0x853023d0, KEY_PAUSE },
+	{ 0x853025d0, KEY_SLOW },
+	{ 0x853022d0, KEY_REWIND },
+	{ 0x853024d0, KEY_FASTFORWARD },
+	{ 0x853026d0, KEY_PREVIOUS },
+	{ 0x853027d0, KEY_NEXT },	/* ->| */
 
-	{ 0xa10c220d, KEY_ZOOM },	/* Aspect */
-	{ 0xa10c120d, KEY_STOP },
-	{ 0xa10c520d, KEY_DVD },	/* DVD Menu */
+	{ 0x853044b0, KEY_ZOOM },	/* Aspect */
+	{ 0x853048b0, KEY_STOP },
+	{ 0x85304ab0, KEY_DVD },	/* DVD Menu */
 
-	{ 0xa10c140b, KEY_NUMERIC_1 },
-	{ 0xa10c940b, KEY_NUMERIC_2 },
-	{ 0xa10c540b, KEY_NUMERIC_3 },
-	{ 0xa10cd40b, KEY_NUMERIC_4 },
-	{ 0xa10c340b, KEY_NUMERIC_5 },
-	{ 0xa10cb40b, KEY_NUMERIC_6 },
-	{ 0xa10c740b, KEY_NUMERIC_7 },
-	{ 0xa10cf40b, KEY_NUMERIC_8 },
-	{ 0x0085302f, KEY_NUMERIC_8 },
-	{ 0xa10c0c03, KEY_NUMERIC_9 },
-	{ 0xa10c8c03, KEY_NUMERIC_0 },
-	{ 0xa10ccc03, KEY_ENTER },
-	{ 0xa10c4c03, KEY_CLEAR },
+	{ 0x853028d0, KEY_NUMERIC_1 },
+	{ 0x853029d0, KEY_NUMERIC_2 },
+	{ 0x85302ad0, KEY_NUMERIC_3 },
+	{ 0x85302bd0, KEY_NUMERIC_4 },
+	{ 0x85302cd0, KEY_NUMERIC_5 },
+	{ 0x85302dd0, KEY_NUMERIC_6 },
+	{ 0x85302ed0, KEY_NUMERIC_7 },
+	{ 0x85302fd0, KEY_NUMERIC_8 },
+	{ 0x85002f30, KEY_NUMERIC_8 },
+	{ 0x853030c0, KEY_NUMERIC_9 },
+	{ 0x853031c0, KEY_NUMERIC_0 },
+	{ 0x853033c0, KEY_ENTER },
+	{ 0x853032c0, KEY_CLEAR },
 };
 
 static struct rc_map_list tivo_map = {
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 26c266b..00a0879 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -316,6 +316,49 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 }
 
 /**
+ * guess_protocol() - heuristics to guess the protocol for a scancode
+ * @rdev:	the struct rc_dev device descriptor
+ * @return:	the guessed RC_TYPE_* protocol
+ *
+ * Internal routine to guess the current IR protocol for legacy ioctls.
+ */
+static inline enum rc_type guess_protocol(struct rc_dev *rdev)
+{
+	struct rc_map *rc_map = &rdev->rc_map;
+
+	if (hweight64(rdev->enabled_protocols[RC_FILTER_NORMAL]) == 1)
+		return rc_bitmap_to_type(rdev->enabled_protocols[RC_FILTER_NORMAL]);
+	else if (hweight64(rdev->allowed_protocols[RC_FILTER_NORMAL]) == 1)
+		return rc_bitmap_to_type(rdev->allowed_protocols[RC_FILTER_NORMAL]);
+	else
+		return rc_map->rc_type;
+}
+
+/**
+ * to_nec32() - helper function to try to convert misc NEC scancodes to NEC32
+ * @orig:	original scancode
+ * @return:	NEC32 scancode
+ *
+ * This helper routine is used to provide backwards compatibility.
+ */
+static u32 to_nec32(u32 orig)
+{
+	u8 b3 = (u8)(orig >> 16);
+	u8 b2 = (u8)(orig >>  8);
+	u8 b1 = (u8)(orig >>  0);
+
+	if (orig <= 0xffff)
+		/* Plain old NEC */
+		return b2 << 24 | ((u8)~b2) << 16 |  b1 << 8 | ((u8)~b1);
+	else if (orig <= 0xffffff)
+		/* NEC extended */
+		return b3 << 24 | b2 << 16 |  b1 << 8 | ((u8)~b1);
+	else
+		/* NEC32 */
+		return orig;
+}
+
+/**
  * ir_setkeycode() - set a keycode in the scancode->keycode table
  * @idev:	the struct input_dev device descriptor
  * @scancode:	the desired scancode
@@ -348,6 +391,9 @@ static int ir_setkeycode(struct input_dev *idev,
 		if (retval)
 			goto out;
 
+		if (guess_protocol(rdev) == RC_TYPE_NEC)
+			scancode = to_nec32(scancode);
+
 		index = ir_establish_scancode(rdev, rc_map, scancode, true);
 		if (index >= rc_map->len) {
 			retval = -ENOMEM;
@@ -388,7 +434,10 @@ static int ir_setkeytable(struct rc_dev *dev,
 
 	for (i = 0; i < from->size; i++) {
 		index = ir_establish_scancode(dev, rc_map,
-					      from->scan[i].scancode, false);
+					      from->rc_type == RC_TYPE_NEC ?
+					      to_nec32(from->scan[i].scancode) :
+					      from->scan[i].scancode,
+					      false);
 		if (index >= rc_map->len) {
 			rc = -ENOMEM;
 			break;
@@ -462,6 +511,8 @@ static int ir_getkeycode(struct input_dev *idev,
 		if (retval)
 			goto out;
 
+		if (guess_protocol(rdev) == RC_TYPE_NEC)
+			scancode = to_nec32(scancode);
 		index = ir_lookup_by_scancode(rc_map, scancode);
 	}
 
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index 5ca738a..8776eaf 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1230,24 +1230,10 @@ static int af9015_rc_query(struct dvb_usb_device *d)
 
 		/* Remember this key */
 		memcpy(state->rc_last, &buf[12], 4);
-		if (buf[14] == (u8) ~buf[15]) {
-			if (buf[12] == (u8) ~buf[13]) {
-				/* NEC */
-				state->rc_keycode = RC_SCANCODE_NEC(buf[12],
-								    buf[14]);
-			} else {
-				/* NEC extended*/
-				state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 |
-								     buf[13],
-								     buf[14]);
-			}
-		} else {
-			/* 32 bit NEC */
-			state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 |
-							      buf[13] << 16 |
-							      buf[14] << 8  |
-							      buf[15]);
-		}
+		state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 |
+						      buf[13] << 16 |
+						      buf[14] << 8  |
+						      buf[15]);
 		rc_keydown(d->rc_dev, RC_TYPE_NEC, state->rc_keycode, 0);
 	} else {
 		dev_dbg(&d->udev->dev, "%s: no key press\n", __func__);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 3bfba13..6bc9693 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1284,19 +1284,8 @@ static int af9035_rc_query(struct dvb_usb_device *d)
 	else if (ret < 0)
 		goto err;
 
-	if ((buf[2] + buf[3]) == 0xff) {
-		if ((buf[0] + buf[1]) == 0xff) {
-			/* NEC standard 16bit */
-			key = RC_SCANCODE_NEC(buf[0], buf[2]);
-		} else {
-			/* NEC extended 24bit */
-			key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]);
-		}
-	} else {
-		/* NEC full code 32bit */
-		key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
-					buf[2] << 8  | buf[3]);
-	}
+	key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+				buf[2] << 8  | buf[3]);
 
 	dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf);
 
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 935dbaa..7e38278 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -214,18 +214,10 @@ static int az6007_rc_query(struct dvb_usb_device *d)
 	if (st->data[1] == 0x44)
 		return 0;
 
-	if ((st->data[3] ^ st->data[4]) == 0xff) {
-		if ((st->data[1] ^ st->data[2]) == 0xff)
-			code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
-		else
-			code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
-						st->data[3]);
-	} else {
-		code = RC_SCANCODE_NEC32(st->data[1] << 24 |
-					 st->data[2] << 16 |
-					 st->data[3] << 8  |
-					 st->data[4]);
-	}
+	code = RC_SCANCODE_NEC32(st->data[1] << 24 |
+				 st->data[2] << 16 |
+				 st->data[3] << 8  |
+				 st->data[4]);
 
 	rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
 
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 574f4ee..45c77b1 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1246,20 +1246,8 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
 		goto err;
 
 	if (buf[4] & 0x01) {
-		if (buf[2] == (u8) ~buf[3]) {
-			if (buf[0] == (u8) ~buf[1]) {
-				/* NEC standard (16 bit) */
-				rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
-			} else {
-				/* NEC extended (24 bit) */
-				rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1],
-							   buf[2]);
-			}
-		} else {
-			/* NEC full (32 bit) */
-			rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
-						    buf[2] << 8  | buf[3]);
-		}
+		rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+					    buf[2] << 8  | buf[3]);
 
 		rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
 
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 0d881b9..d7b7932 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -715,22 +715,11 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 			break;
 		}
 
-		if ((poll_reply->data ^ poll_reply->not_data) != 0xff) {
-			deb_data("NEC32 protocol\n");
-			scancode = RC_SCANCODE_NEC32(poll_reply->system     << 24 |
-						     poll_reply->not_system << 16 |
-						     poll_reply->data       << 8  |
-						     poll_reply->not_data);
-		} else if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
-			deb_data("NEC extended protocol\n");
-			scancode = RC_SCANCODE_NECX(poll_reply->system << 8 |
-						    poll_reply->not_system,
-						    poll_reply->data);
-		} else {
-			deb_data("NEC normal protocol\n");
-			scancode = RC_SCANCODE_NEC(poll_reply->system,
-						   poll_reply->data);
-		}
+		deb_data("NEC protocol\n");
+		scancode = RC_SCANCODE_NEC32(poll_reply->system     << 24 |
+					     poll_reply->not_system << 16 |
+					     poll_reply->data       << 8  |
+					     poll_reply->not_data);
 
 		break;
 	default:
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 014888f..4bbd8e4 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -261,16 +261,10 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 	case RC_BIT_NEC:
 		poll_result->protocol = RC_TYPE_RC5;
 		poll_result->scancode = msg[1] << 8 | msg[2];
-		if ((msg[3] ^ msg[4]) != 0xff)		/* 32 bits NEC */
-			poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
-								  (msg[2] << 16) |
-								  (msg[3] << 8)  |
-								  (msg[4]));
-		else if ((msg[1] ^ msg[2]) != 0xff)	/* 24 bits NEC */
-			poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
-								 msg[2], msg[3]); 
-		else					/* Normal NEC */
-			poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
+		poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
+							  (msg[2] << 16) |
+							  (msg[3] << 8)  |
+							  (msg[4]));
 		break;
 
 	case RC_BIT_RC6_0:
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 894c7e4..2e6c659 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -33,6 +33,8 @@ enum rc_type {
 	RC_TYPE_SHARP		= 18,	/* Sharp protocol */
 };
 
+#define rc_bitmap_to_type(x) fls64(x)
+
 #define RC_BIT_NONE		0
 #define RC_BIT_UNKNOWN		(1 << RC_TYPE_UNKNOWN)
 #define RC_BIT_OTHER		(1 << RC_TYPE_OTHER)
@@ -64,13 +66,21 @@ enum rc_type {
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
 #define RC_SCANCODE_OTHER(x)			(x)
-#define RC_SCANCODE_NEC(addr, cmd)		(((addr) << 8) | (cmd))
-#define RC_SCANCODE_NECX(addr, cmd)		(((addr) << 8) | (cmd))
-#define RC_SCANCODE_NEC32(data)			((data) & 0xffffffff)
 #define RC_SCANCODE_RC5(sys, cmd)		(((sys) << 8) | (cmd))
 #define RC_SCANCODE_RC5_SZ(sys, cmd)		(((sys) << 8) | (cmd))
 #define RC_SCANCODE_RC6_0(sys, cmd)		(((sys) << 8) | (cmd))
 #define RC_SCANCODE_RC6_6A(vendor, sys, cmd)	(((vendor) << 16) | ((sys) << 8) | (cmd))
+#define RC_SCANCODE_NEC(addr, cmd)  \
+	((( (addr) & 0xff) << 24) | \
+	 ((~(addr) & 0xff) << 16) | \
+	 (( (cmd)  & 0xff) << 8 ) | \
+	 ((~(cmd)  & 0xff) << 0 ))
+#define RC_SCANCODE_NECX(addr, cmd)   \
+        ((( (addr) & 0xffff) << 16) | \
+         (( (cmd)  & 0x00ff) << 8)  | \
+         ((~(cmd)  & 0x00ff) << 0))
+#define RC_SCANCODE_NEC32(data) ((data) & 0xffffffff)
+
 
 struct rc_map_table {
 	u32	scancode;


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

* [PATCH 11/49] [RFC] rc-core: don't throw away protocol information
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (9 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 10/49] [RFC] rc-core: use the full 32 bits for NEC scancodes David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 12/49] rc-core: simplify sysfs code David Härdeman
                   ` (39 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Setting and getting keycodes in the input subsystem used to be done via
the EVIOC[GS]KEYCODE ioctl and "unsigned int[2]" (one int for scancode
and one for the keycode).

The interface has now been extended to use the EVIOC[GS]KEYCODE_V2 ioctl
which uses the following struct:

struct input_keymap_entry {
	__u8  flags;
	__u8  len;
	__u16 index;
	__u32 keycode;
	__u8  scancode[32];
};

(scancode can of course be even bigger, thanks to the len member).

This patch changes how the "input_keymap_entry" struct is interpreted
by rc-core by casting it to "rc_keymap_entry":

struct rc_scancode {
	__u16 protocol;
	__u16 reserved[3];
	__u64 scancode;
}

struct rc_keymap_entry {
	__u8  flags;
	__u8  len;
	__u16 index;
	__u32 keycode;
	union {
		struct rc_scancode rc;
		__u8 raw[32];
	};
};

The u64 scancode member is large enough for all current protocols and it
would be possible to extend it in the future should it be necessary for
some exotic protocol.

The main advantage with this change is that the protocol is made explicit,
which means that we're not throwing away data (the protocol type) and that
it'll be easier to support multiple protocols with one decoder (think rc5
and rc5-streamzap).

Heuristics are also added to hopefully do the right thing with older
ioctls in order to preserve backwards compatibility.

Further patches will also add the ability to communicate the protocol to
userspace.

This needs review by the input maintainer as well.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ati_remote.c |    1 
 drivers/media/rc/imon.c       |   12 ++-
 drivers/media/rc/rc-main.c    |  182 +++++++++++++++++++++++++++++------------
 include/media/rc-core.h       |   20 ++++-
 include/media/rc-map.h        |    8 +-
 5 files changed, 163 insertions(+), 60 deletions(-)

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 8730b32..7098fa5 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -548,6 +548,7 @@ static void ati_remote_input_report(struct urb *urb)
 		 * set, assume this is a scrollwheel up/down event.
 		 */
 		wheel_keycode = rc_g_keycode_from_table(ati_remote->rdev,
+							RC_TYPE_OTHER,
 							scancode & 0x78);
 
 		if (wheel_keycode == KEY_RESERVED) {
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index d1564d1..8abbb8d 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1166,14 +1166,20 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
 	bool is_release_code = false;
 
 	/* Look for the initial press of a button */
-	keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+	keycode = rc_g_keycode_from_table(ictx->rdev,
+					  ictx->rc_type == RC_BIT_RC6_MCE ?
+					  RC_TYPE_RC6_MCE : RC_TYPE_OTHER,
+					  scancode);
 	ictx->rc_toggle = 0x0;
 	ictx->rc_scancode = scancode;
 
 	/* Look for the release of a button */
 	if (keycode == KEY_RESERVED) {
 		release = scancode & ~0x4000;
-		keycode = rc_g_keycode_from_table(ictx->rdev, release);
+		keycode = rc_g_keycode_from_table(ictx->rdev,
+						  ictx->rc_type == RC_BIT_RC6_MCE ?
+						  RC_TYPE_RC6_MCE : RC_TYPE_OTHER,
+						  release);
 		if (keycode != KEY_RESERVED)
 			is_release_code = true;
 	}
@@ -1202,7 +1208,7 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
 		scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
 
 	ictx->rc_scancode = scancode;
-	keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+	keycode = rc_g_keycode_from_table(ictx->rdev, RC_TYPE_RC6_MCE, scancode);
 
 	/* not used in mce mode, but make sure we know its false */
 	ictx->release_code = false;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 00a0879..ee77ad3 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(rc_map_unregister);
 
 
 static struct rc_map_table empty[] = {
-	{ 0x2a, KEY_COFFEE },
+	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
 };
 
 static struct rc_map_list empty_map = {
@@ -118,7 +118,6 @@ static struct rc_map_list empty_map = {
  * ir_create_table() - initializes a scancode table
  * @rc_map:	the rc_map to initialize
  * @name:	name to assign to the table
- * @rc_type:	ir type to assign to the new table
  * @size:	initial size of the table
  * @return:	zero on success or a negative error code
  *
@@ -126,10 +125,9 @@ static struct rc_map_list empty_map = {
  * memory to hold at least the specified number of elements.
  */
 static int ir_create_table(struct rc_map *rc_map,
-			   const char *name, u64 rc_type, size_t size)
+			   const char *name, size_t size)
 {
 	rc_map->name = name;
-	rc_map->rc_type = rc_type;
 	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
 	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
 	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
@@ -224,16 +222,20 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 
 	/* Did the user wish to remove the mapping? */
 	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
-		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
-			   index, rc_map->scan[index].scancode);
+		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
+			   index, rc_map->scan[index].protocol,
+			   (unsigned long long)rc_map->scan[index].scancode);
 		rc_map->len--;
 		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
 			(rc_map->len - index) * sizeof(struct rc_map_table));
 	} else {
-		IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
+			   "with key 0x%04x\n",
 			   index,
 			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
-			   rc_map->scan[index].scancode, new_keycode);
+			   rc_map->scan[index].protocol,
+			   (unsigned long long)rc_map->scan[index].scancode,
+			   new_keycode);
 		rc_map->scan[index].keycode = new_keycode;
 		__set_bit(new_keycode, dev->input_dev->keybit);
 	}
@@ -260,9 +262,9 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
  * ir_establish_scancode() - set a keycode in the scancode->keycode table
  * @dev:	the struct rc_dev device descriptor
  * @rc_map:	scancode table to be searched
- * @scancode:	the desired scancode
- * @resize:	controls whether we allowed to resize the table to
- *		accommodate not yet present scancodes
+ * @entry:	the entry to be added to the table
+ * @resize:	controls whether we are allowed to resize the table to
+ *		accomodate not yet present scancodes
  * @return:	index of the mapping containing scancode in question
  *		or -1U in case of failure.
  *
@@ -272,7 +274,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
  */
 static unsigned int ir_establish_scancode(struct rc_dev *dev,
 					  struct rc_map *rc_map,
-					  unsigned int scancode,
+					  struct rc_map_table *entry,
 					  bool resize)
 {
 	unsigned int i;
@@ -286,16 +288,27 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 	 * indicate the valid bits of the scancodes.
 	 */
 	if (dev->scanmask)
-		scancode &= dev->scanmask;
+		entry->scancode &= dev->scanmask;
 
-	/* First check if we already have a mapping for this ir command */
+	/*
+	 * First check if we already have a mapping for this command.
+	 * Note that the keytable is sorted first on protocol and second
+	 * on scancode (lowest to highest).
+	 */
 	for (i = 0; i < rc_map->len; i++) {
-		if (rc_map->scan[i].scancode == scancode)
-			return i;
+		if (rc_map->scan[i].protocol < entry->protocol)
+			continue;
+
+		if (rc_map->scan[i].protocol > entry->protocol)
+			break;
+
+		if (rc_map->scan[i].scancode < entry->scancode)
+			continue;
 
-		/* Keytable is sorted from lowest to highest scancode */
-		if (rc_map->scan[i].scancode >= scancode)
+		if (rc_map->scan[i].scancode > entry->scancode)
 			break;
+
+		return i;
 	}
 
 	/* No previous mapping found, we might need to grow the table */
@@ -308,7 +321,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 	if (i < rc_map->len)
 		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
 			(rc_map->len - i) * sizeof(struct rc_map_table));
-	rc_map->scan[i].scancode = scancode;
+	rc_map->scan[i].scancode = entry->scancode;
+	rc_map->scan[i].protocol = entry->protocol;
 	rc_map->scan[i].keycode = KEY_RESERVED;
 	rc_map->len++;
 
@@ -330,8 +344,10 @@ static inline enum rc_type guess_protocol(struct rc_dev *rdev)
 		return rc_bitmap_to_type(rdev->enabled_protocols[RC_FILTER_NORMAL]);
 	else if (hweight64(rdev->allowed_protocols[RC_FILTER_NORMAL]) == 1)
 		return rc_bitmap_to_type(rdev->allowed_protocols[RC_FILTER_NORMAL]);
+	else if (rc_map->len > 0)
+		return rc_map->scan[0].protocol;
 	else
-		return rc_map->rc_type;
+		return RC_TYPE_OTHER;
 }
 
 /**
@@ -374,10 +390,12 @@ static int ir_setkeycode(struct input_dev *idev,
 	struct rc_dev *rdev = input_get_drvdata(idev);
 	struct rc_map *rc_map = &rdev->rc_map;
 	unsigned int index;
-	unsigned int scancode;
+	struct rc_map_table entry;
 	int retval = 0;
 	unsigned long flags;
 
+	entry.keycode = ke->keycode;
+
 	spin_lock_irqsave(&rc_map->lock, flags);
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
@@ -386,19 +404,42 @@ static int ir_setkeycode(struct input_dev *idev,
 			retval = -EINVAL;
 			goto out;
 		}
-	} else {
+	} else if (ke->len == sizeof(int)) {
+		/* Legacy EVIOCSKEYCODE ioctl */
+		u32 scancode;
 		retval = input_scancode_to_scalar(ke, &scancode);
 		if (retval)
 			goto out;
 
-		if (guess_protocol(rdev) == RC_TYPE_NEC)
-			scancode = to_nec32(scancode);
+		entry.scancode = scancode;
+		entry.protocol = guess_protocol(rdev);
+		if (entry.protocol == RC_TYPE_NEC)
+			entry.scancode = to_nec32(scancode);
 
-		index = ir_establish_scancode(rdev, rc_map, scancode, true);
+		index = ir_establish_scancode(rdev, rc_map, &entry, true);
 		if (index >= rc_map->len) {
 			retval = -ENOMEM;
 			goto out;
 		}
+	} else if (ke->len == sizeof(struct rc_scancode)) {
+		/* New EVIOCSKEYCODE_V2 ioctl */
+		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+		entry.protocol = rke->rc.protocol;
+		entry.scancode = rke->rc.scancode;
+
+		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
+			retval = -EINVAL;
+			goto out;
+		}
+
+		index = ir_establish_scancode(rdev, rc_map, &entry, true);
+		if (index >= rc_map->len) {
+			retval = -ENOMEM;
+			goto out;
+		}
+	} else {
+		retval = -EINVAL;
+		goto out;
 	}
 
 	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
@@ -421,11 +462,11 @@ static int ir_setkeytable(struct rc_dev *dev,
 			  const struct rc_map *from)
 {
 	struct rc_map *rc_map = &dev->rc_map;
+	struct rc_map_table entry;
 	unsigned int i, index;
 	int rc;
 
-	rc = ir_create_table(rc_map, from->name,
-			     from->rc_type, from->size);
+	rc = ir_create_table(rc_map, from->name, from->size);
 	if (rc)
 		return rc;
 
@@ -433,18 +474,19 @@ static int ir_setkeytable(struct rc_dev *dev,
 		   rc_map->size, rc_map->alloc);
 
 	for (i = 0; i < from->size; i++) {
-		index = ir_establish_scancode(dev, rc_map,
-					      from->rc_type == RC_TYPE_NEC ?
-					      to_nec32(from->scan[i].scancode) :
-					      from->scan[i].scancode,
-					      false);
+		if (from->rc_type == RC_TYPE_NEC)
+			entry.scancode = to_nec32(from->scan[i].scancode);
+		else
+			entry.scancode = from->scan[i].scancode;
+
+		entry.protocol = from->rc_type;
+		index = ir_establish_scancode(dev, rc_map, &entry, false);
 		if (index >= rc_map->len) {
 			rc = -ENOMEM;
 			break;
 		}
 
-		ir_update_mapping(dev, rc_map, index,
-				  from->scan[i].keycode);
+		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
 	}
 
 	if (rc)
@@ -456,6 +498,7 @@ static int ir_setkeytable(struct rc_dev *dev,
 /**
  * ir_lookup_by_scancode() - locate mapping by scancode
  * @rc_map:	the struct rc_map to search
+ * @protocol:	protocol to look for in the table
  * @scancode:	scancode to look for in the table
  * @return:	index in the table, -1U if not found
  *
@@ -463,17 +506,24 @@ static int ir_setkeytable(struct rc_dev *dev,
  * given scancode.
  */
 static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
-					  unsigned int scancode)
+					  u16 protocol, u64 scancode)
 {
 	int start = 0;
 	int end = rc_map->len - 1;
 	int mid;
+	struct rc_map_table *m;
 
 	while (start <= end) {
 		mid = (start + end) / 2;
-		if (rc_map->scan[mid].scancode < scancode)
+		m = &rc_map->scan[mid];
+
+		if (m->protocol < protocol)
+			start = mid + 1;
+		else if (m->protocol > protocol)
+			end = mid - 1;
+		else if (m->scancode < scancode)
 			start = mid + 1;
-		else if (rc_map->scan[mid].scancode > scancode)
+		else if (m->scancode > scancode)
 			end = mid - 1;
 		else
 			return mid;
@@ -494,35 +544,60 @@ static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
 static int ir_getkeycode(struct input_dev *idev,
 			 struct input_keymap_entry *ke)
 {
+	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
 	struct rc_dev *rdev = input_get_drvdata(idev);
 	struct rc_map *rc_map = &rdev->rc_map;
 	struct rc_map_table *entry;
 	unsigned long flags;
 	unsigned int index;
-	unsigned int scancode;
 	int retval;
 
 	spin_lock_irqsave(&rc_map->lock, flags);
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
 		index = ke->index;
-	} else {
+	} else if (ke->len == sizeof(int)) {
+		/* Legacy EVIOCGKEYCODE ioctl */
+		u32 scancode;
+		u16 protocol;
+
 		retval = input_scancode_to_scalar(ke, &scancode);
 		if (retval)
 			goto out;
 
-		if (guess_protocol(rdev) == RC_TYPE_NEC)
+		protocol = guess_protocol(rdev);
+		if (protocol == RC_TYPE_NEC)
 			scancode = to_nec32(scancode);
-		index = ir_lookup_by_scancode(rc_map, scancode);
+
+		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+
+	} else if (ke->len == sizeof(struct rc_scancode)) {
+		/* New EVIOCGKEYCODE_V2 ioctl */
+		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
+			retval = -EINVAL;
+			goto out;
+		}
+
+		index = ir_lookup_by_scancode(rc_map,
+					      rke->rc.protocol, rke->rc.scancode);
+
+	} else {
+		retval = -EINVAL;
+		goto out;
 	}
 
 	if (index < rc_map->len) {
 		entry = &rc_map->scan[index];
-
 		ke->index = index;
 		ke->keycode = entry->keycode;
-		ke->len = sizeof(entry->scancode);
-		memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+		if (ke->len == sizeof(int)) {
+			u32 scancode = entry->scancode;
+			memcpy(ke->scancode, &scancode, sizeof(scancode));
+		} else {
+			ke->len = sizeof(struct rc_scancode);
+			rke->rc.protocol = entry->protocol;
+			rke->rc.scancode = entry->scancode;
+		}
 
 	} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
 		/*
@@ -547,6 +622,7 @@ out:
 /**
  * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
  * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol to look for
  * @scancode:	the scancode to look for
  * @return:	the corresponding keycode, or KEY_RESERVED
  *
@@ -554,7 +630,8 @@ out:
  * keycode. Normally it should not be used since drivers should have no
  * interest in keycodes.
  */
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+			    enum rc_type protocol, u64 scancode)
 {
 	struct rc_map *rc_map = &dev->rc_map;
 	unsigned int keycode;
@@ -563,15 +640,16 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
 
 	spin_lock_irqsave(&rc_map->lock, flags);
 
-	index = ir_lookup_by_scancode(rc_map, scancode);
+	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
 	keycode = index < rc_map->len ?
 			rc_map->scan[index].keycode : KEY_RESERVED;
 
 	spin_unlock_irqrestore(&rc_map->lock, flags);
 
 	if (keycode != KEY_RESERVED)
-		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
-			   dev->input_name, scancode, keycode);
+		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
+			   dev->input_name, protocol,
+			   (unsigned long long)scancode, keycode);
 
 	return keycode;
 }
@@ -728,7 +806,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
 {
 	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, scancode);
+	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
 
 	spin_lock_irqsave(&dev->keylock, flags);
 	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
@@ -757,7 +835,7 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
 			  u32 scancode, u8 toggle)
 {
 	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, scancode);
+	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
 
 	spin_lock_irqsave(&dev->keylock, flags);
 	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
@@ -1447,8 +1525,8 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_input;
 	}
 
-	if (dev->change_protocol) {
-		u64 rc_type = (1 << rc_map->rc_type);
+	if (dev->change_protocol && rc_map->len > 0) {
+		u64 rc_type = (1 << rc_map->scan[0].protocol);
 		rc = dev->change_protocol(dev, &rc_type);
 		if (rc < 0)
 			goto out_raw;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 2e97b98..6f66305 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -34,6 +34,24 @@ enum rc_driver_type {
 	RC_DRIVER_IR_RAW,	/* Needs a Infra-Red pulse/space decoder */
 };
 
+/* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
+struct rc_scancode {
+	__u16 protocol;
+	__u16 reserved[3];
+	__u64 scancode;
+};
+
+struct rc_keymap_entry {
+	__u8  flags;
+	__u8  len;
+	__u16 index;
+	__u32 keycode;
+	union {
+		struct rc_scancode rc;
+		__u8 raw[32];
+	};
+};
+
 /**
  * struct rc_scancode_filter - Filter scan codes.
  * @data:	Scancode data to match.
@@ -226,7 +244,7 @@ void rc_repeat(struct rc_dev *dev);
 void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
 void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
 void rc_keyup(struct rc_dev *dev);
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode);
+u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
 
 /*
  * From rc-raw.c
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 2e6c659..bfa27fc 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -81,10 +81,10 @@ enum rc_type {
          ((~(cmd)  & 0x00ff) << 0))
 #define RC_SCANCODE_NEC32(data) ((data) & 0xffffffff)
 
-
 struct rc_map_table {
-	u32	scancode;
-	u32	keycode;
+	u64		scancode;
+	u32		keycode;
+	enum rc_type	protocol;
 };
 
 struct rc_map {
@@ -92,7 +92,7 @@ struct rc_map {
 	unsigned int		size;	/* Max number of entries */
 	unsigned int		len;	/* Used number of entries */
 	unsigned int		alloc;	/* Size of *scan in bytes */
-	enum rc_type		rc_type;
+	enum rc_type		rc_type; /* For in-kernel keymaps */
 	const char		*name;
 	spinlock_t		lock;
 };


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

* [PATCH 12/49] rc-core: simplify sysfs code
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (10 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 11/49] [RFC] rc-core: don't throw away protocol information David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 13/49] rc-core: remove protocol arrays David Härdeman
                   ` (38 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Simplify and cleanup the sysfs code a bit.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ir-raw.c  |    6 +
 drivers/media/rc/rc-main.c |  265 ++++++++++++++++++++++++--------------------
 2 files changed, 150 insertions(+), 121 deletions(-)

diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 763c9d1..f38557f 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -240,6 +240,11 @@ ir_raw_get_allowed_protocols(void)
 	return protocols;
 }
 
+static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
+	/* the caller will update dev->enabled_protocols */
+	return 0;
+}
+
 /*
  * Used to (un)register raw event clients
  */
@@ -257,6 +262,7 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 	dev->raw->dev = dev;
 	rc_set_enabled_protocols(dev, ~0);
+	dev->change_protocol = change_protocol;
 	rc = kfifo_alloc(&dev->raw->kfifo,
 			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
 			 GFP_KERNEL);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index ee77ad3..df3175d 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -959,7 +959,7 @@ struct rc_filter_attribute {
 /**
  * show_protocols() - shows the current/wakeup IR protocol(s)
  * @device:	the device descriptor
- * @mattr:	the device attribute struct (unused)
+ * @mattr:	the device attribute struct
  * @buf:	a pointer to the output buffer
  *
  * This routine is a callback routine for input read the IR protocol type(s).
@@ -985,20 +985,21 @@ static ssize_t show_protocols(struct device *device,
 
 	mutex_lock(&dev->lock);
 
-	enabled = dev->enabled_protocols[fattr->type];
-	if (dev->driver_type == RC_DRIVER_SCANCODE ||
-	    fattr->type == RC_FILTER_WAKEUP)
-		allowed = dev->allowed_protocols[fattr->type];
-	else if (dev->raw)
-		allowed = ir_raw_get_allowed_protocols();
-	else {
-		mutex_unlock(&dev->lock);
-		return -ENODEV;
+	if (fattr->type == RC_FILTER_NORMAL) {
+		enabled = dev->enabled_protocols[RC_FILTER_NORMAL];
+		if (dev->raw)
+			allowed = ir_raw_get_allowed_protocols();
+		else
+			allowed = dev->allowed_protocols[RC_FILTER_NORMAL];
+	} else {
+		enabled = dev->enabled_protocols[RC_FILTER_WAKEUP];
+		allowed = dev->allowed_protocols[RC_FILTER_WAKEUP];
 	}
 
-	IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
-		   (long long)allowed,
-		   (long long)enabled);
+	mutex_unlock(&dev->lock);
+
+	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
+		   __func__, (long long)allowed, (long long)enabled);
 
 	for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
 		if (allowed & enabled & proto_names[i].type)
@@ -1014,62 +1015,29 @@ static ssize_t show_protocols(struct device *device,
 		tmp--;
 	*tmp = '\n';
 
-	mutex_unlock(&dev->lock);
-
 	return tmp + 1 - buf;
 }
 
 /**
- * store_protocols() - changes the current/wakeup IR protocol(s)
- * @device:	the device descriptor
- * @mattr:	the device attribute struct (unused)
- * @buf:	a pointer to the input buffer
- * @len:	length of the input buffer
+ * parse_protocol_change() - parses a protocol change request
+ * @protocols:	pointer to the bitmask of current protocols
+ * @buf:	pointer to the buffer with a list of changes
  *
- * This routine is for changing the IR protocol type.
- * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
- * Writing "+proto" will add a protocol to the list of enabled protocols.
- * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "+proto" will add a protocol to the protocol mask.
+ * Writing "-proto" will remove a protocol from protocol mask.
  * Writing "proto" will enable only "proto".
  * Writing "none" will disable all protocols.
- * Returns -EINVAL if an invalid protocol combination or unknown protocol name
- * is used, otherwise @len.
- *
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * Returns the number of changes performed or a negative error code.
  */
-static ssize_t store_protocols(struct device *device,
-			       struct device_attribute *mattr,
-			       const char *data,
-			       size_t len)
+static int parse_protocol_change(u64 *protocols, const char *buf)
 {
-	struct rc_dev *dev = to_rc_dev(device);
-	struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
-	bool enable, disable;
 	const char *tmp;
-	u64 old_type, type;
+	unsigned count = 0;
+	bool enable, disable;
 	u64 mask;
-	int rc, i, count = 0;
-	ssize_t ret;
-	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
-	int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
-	struct rc_scancode_filter local_filter, *filter;
-
-	/* Device is being removed */
-	if (!dev)
-		return -EINVAL;
-
-	mutex_lock(&dev->lock);
-
-	if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
-		IR_dprintk(1, "Protocol switching not supported\n");
-		ret = -EINVAL;
-		goto out;
-	}
-	old_type = dev->enabled_protocols[fattr->type];
-	type = old_type;
+	int i;
 
-	while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+	while ((tmp = strsep((char **)&buf, " \n")) != NULL) {
 		if (!*tmp)
 			break;
 
@@ -1095,76 +1063,124 @@ static ssize_t store_protocols(struct device *device,
 
 		if (i == ARRAY_SIZE(proto_names)) {
 			IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
-			ret = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 
 		count++;
 
 		if (enable)
-			type |= mask;
+			*protocols |= mask;
 		else if (disable)
-			type &= ~mask;
+			*protocols &= ~mask;
 		else
-			type = mask;
+			*protocols = mask;
 	}
 
 	if (!count) {
 		IR_dprintk(1, "Protocol not specified\n");
-		ret = -EINVAL;
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+/**
+ * store_protocols() - changes the current/wakeup IR protocol(s)
+ * @device:	the device descriptor
+ * @mattr:	the device attribute struct
+ * @buf:	a pointer to the input buffer
+ * @len:	length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
+ * See parse_protocol_change() for the valid commands.
+ * Returns @len on success or a negative error code.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t store_protocols(struct device *device,
+			       struct device_attribute *mattr,
+			       const char *buf, size_t len)
+{
+	struct rc_dev *dev = to_rc_dev(device);
+	struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
+	u64 *current_protocols;
+	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
+	struct rc_scancode_filter *filter;
+	int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
+	u64 old_protocols, new_protocols;
+	ssize_t rc;
+
+	/* Device is being removed */
+	if (!dev)
+		return -EINVAL;
+
+	if (fattr->type == RC_FILTER_NORMAL) {
+		IR_dprintk(1, "Normal protocol change requested\n");
+		current_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
+		change_protocol = dev->change_protocol;
+		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+		set_filter = dev->s_filter;
+	} else {
+		IR_dprintk(1, "Wakeup protocol change requested\n");
+		current_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
+		change_protocol = dev->change_wakeup_protocol;
+		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+		set_filter = dev->s_wakeup_filter;
+	}
+
+	if (!change_protocol) {
+		IR_dprintk(1, "Protocol switching not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->lock);
+
+	old_protocols = *current_protocols;
+	new_protocols = old_protocols;
+	rc = parse_protocol_change(&new_protocols, buf);
+	if (rc < 0)
+		goto out;
+
+	rc = change_protocol(dev, &new_protocols);
+	if (rc < 0) {
+		IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+			   (long long)new_protocols);
 		goto out;
 	}
 
-	change_protocol = (fattr->type == RC_FILTER_NORMAL)
-		? dev->change_protocol : dev->change_wakeup_protocol;
-	if (change_protocol) {
-		rc = change_protocol(dev, &type);
-		if (rc < 0) {
-			IR_dprintk(1, "Error setting protocols to 0x%llx\n",
-				   (long long)type);
-			ret = -EINVAL;
-			goto out;
-		}
+	if (new_protocols == old_protocols) {
+		rc = len;
+		goto out;
 	}
 
-	dev->enabled_protocols[fattr->type] = type;
-	IR_dprintk(1, "Current protocol(s): 0x%llx\n",
-		   (long long)type);
+	*current_protocols = new_protocols;
+	IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols);
 
 	/*
 	 * If the protocol is changed the filter needs updating.
 	 * Try setting the same filter with the new protocol (if any).
 	 * Fall back to clearing the filter.
 	 */
-	filter = &dev->scancode_filters[fattr->type];
-	set_filter = (fattr->type == RC_FILTER_NORMAL)
-		? dev->s_filter : dev->s_wakeup_filter;
-
-	if (set_filter && old_type != type && filter->mask) {
-		local_filter = *filter;
-		if (!type) {
-			/* no protocol => clear filter */
-			ret = -1;
-		} else {
-			/* hardware filtering => try setting, otherwise clear */
-			ret = set_filter(dev, &local_filter);
-		}
-		if (ret < 0) {
-			/* clear the filter */
-			local_filter.data = 0;
-			local_filter.mask = 0;
-			set_filter(dev, &local_filter);
-		}
+	if (set_filter && filter->mask) {
+		if (new_protocols)
+			rc = set_filter(dev, filter);
+		else
+			rc = -1;
 
-		/* commit the new filter */
-		*filter = local_filter;
+		if (rc < 0) {
+			filter->data = 0;
+			filter->mask = 0;
+			set_filter(dev, filter);
+		}
 	}
 
-	ret = len;
+	rc = len;
 
 out:
 	mutex_unlock(&dev->lock);
-	return ret;
+	return rc;
 }
 
 /**
@@ -1190,20 +1206,23 @@ static ssize_t show_filter(struct device *device,
 {
 	struct rc_dev *dev = to_rc_dev(device);
 	struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
+	struct rc_scancode_filter *filter;
 	u32 val;
 
 	/* Device is being removed */
 	if (!dev)
 		return -EINVAL;
 
+	if (fattr->type == RC_FILTER_NORMAL)
+		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+	else
+		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+
 	mutex_lock(&dev->lock);
-	if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) ||
-	    (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter))
-		val = 0;
-	else if (fattr->mask)
-		val = dev->scancode_filters[fattr->type].mask;
+	if (fattr->mask)
+		val = filter->mask;
 	else
-		val = dev->scancode_filters[fattr->type].data;
+		val = filter->data;
 	mutex_unlock(&dev->lock);
 
 	return sprintf(buf, "%#x\n", val);
@@ -1230,15 +1249,15 @@ static ssize_t show_filter(struct device *device,
  */
 static ssize_t store_filter(struct device *device,
 			    struct device_attribute *attr,
-			    const char *buf,
-			    size_t count)
+			    const char *buf, size_t len)
 {
 	struct rc_dev *dev = to_rc_dev(device);
 	struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
-	struct rc_scancode_filter local_filter, *filter;
+	struct rc_scancode_filter new_filter, *filter;
 	int ret;
 	unsigned long val;
 	int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
+	u64 *enabled_protocols;
 
 	/* Device is being removed */
 	if (!dev)
@@ -1248,38 +1267,42 @@ static ssize_t store_filter(struct device *device,
 	if (ret < 0)
 		return ret;
 
-	/* Can the scancode filter be set? */
-	set_filter = (fattr->type == RC_FILTER_NORMAL)
-		? dev->s_filter : dev->s_wakeup_filter;
+	if (fattr->type == RC_FILTER_NORMAL) {
+		set_filter = dev->s_filter;
+		enabled_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
+		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+	} else {
+		set_filter = dev->s_wakeup_filter;
+		enabled_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
+		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+	}
+
 	if (!set_filter)
 		return -EINVAL;
 
 	mutex_lock(&dev->lock);
 
-	/* Tell the driver about the new filter */
-	filter = &dev->scancode_filters[fattr->type];
-	local_filter = *filter;
+	new_filter = *filter;
 	if (fattr->mask)
-		local_filter.mask = val;
+		new_filter.mask = val;
 	else
-		local_filter.data = val;
+		new_filter.data = val;
 
-	if (!dev->enabled_protocols[fattr->type] && local_filter.mask) {
+	if (!*enabled_protocols && val) {
 		/* refuse to set a filter unless a protocol is enabled */
 		ret = -EINVAL;
 		goto unlock;
 	}
 
-	ret = set_filter(dev, &local_filter);
+	ret = set_filter(dev, &new_filter);
 	if (ret < 0)
 		goto unlock;
 
-	/* Success, commit the new filter */
-	*filter = local_filter;
+	*filter = new_filter;
 
 unlock:
 	mutex_unlock(&dev->lock);
-	return (ret < 0) ? ret : count;
+	return (ret < 0) ? ret : len;
 }
 
 static void rc_dev_release(struct device *device)


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

* [PATCH 13/49] rc-core: remove protocol arrays
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (11 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 12/49] rc-core: simplify sysfs code David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 14/49] rc-core: rename dev->scanmask to dev->scancode_mask David Härdeman
                   ` (37 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The basic API of rc-core used to be:

	dev = rc_allocate_device();
	dev->x = a;
	dev->y = b;
	dev->z = c;
	rc_register_device();

which is a pretty common pattern in the kernel, after the introduction of
protocol arrays the API looks something like:

	dev = rc_allocate_device();
	dev->x = a;
	rc_set_allowed_protocols(dev, RC_BIT_X);
	dev->z = c;
	rc_register_device();

There's no real need for the protocols to be an array, so change it
back to be consistent (and in preparation for the following patches).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/hid/hid-picolcd_cir.c               |    2 -
 drivers/media/common/siano/smsir.c          |    2 -
 drivers/media/i2c/ir-kbd-i2c.c              |    4 +-
 drivers/media/pci/cx23885/cx23885-input.c   |    2 -
 drivers/media/pci/cx88/cx88-input.c         |    2 -
 drivers/media/rc/ati_remote.c               |    2 -
 drivers/media/rc/ene_ir.c                   |    2 -
 drivers/media/rc/fintek-cir.c               |    2 -
 drivers/media/rc/gpio-ir-recv.c             |    4 +-
 drivers/media/rc/iguanair.c                 |    2 -
 drivers/media/rc/img-ir/img-ir-hw.c         |   16 ++++----
 drivers/media/rc/imon.c                     |    7 +--
 drivers/media/rc/ir-jvc-decoder.c           |    2 -
 drivers/media/rc/ir-lirc-codec.c            |    2 -
 drivers/media/rc/ir-mce_kbd-decoder.c       |    2 -
 drivers/media/rc/ir-nec-decoder.c           |    2 -
 drivers/media/rc/ir-raw.c                   |    2 -
 drivers/media/rc/ir-rc5-decoder.c           |    6 +--
 drivers/media/rc/ir-rc5-sz-decoder.c        |    2 -
 drivers/media/rc/ir-rc6-decoder.c           |    6 +--
 drivers/media/rc/ir-sanyo-decoder.c         |    2 -
 drivers/media/rc/ir-sharp-decoder.c         |    2 -
 drivers/media/rc/ir-sony-decoder.c          |   10 ++---
 drivers/media/rc/ite-cir.c                  |    2 -
 drivers/media/rc/mceusb.c                   |    2 -
 drivers/media/rc/nuvoton-cir.c              |    2 -
 drivers/media/rc/rc-loopback.c              |    2 -
 drivers/media/rc/rc-main.c                  |   38 +++++++++---------
 drivers/media/rc/redrat3.c                  |    2 -
 drivers/media/rc/st_rc.c                    |    2 -
 drivers/media/rc/streamzap.c                |    2 -
 drivers/media/rc/ttusbir.c                  |    2 -
 drivers/media/rc/winbond-cir.c              |    2 -
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |    2 -
 drivers/media/usb/dvb-usb/dvb-usb-remote.c  |    2 -
 drivers/media/usb/em28xx/em28xx-input.c     |    8 ++--
 drivers/media/usb/tm6000/tm6000-input.c     |    2 -
 include/media/rc-core.h                     |   56 ++++++---------------------
 38 files changed, 89 insertions(+), 122 deletions(-)

diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index cf1a9f1..59d5eb1 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
 
 	rdev->priv             = data;
 	rdev->driver_type      = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protos   = RC_BIT_ALL;
 	rdev->open             = picolcd_cir_open;
 	rdev->close            = picolcd_cir_close;
 	rdev->input_name       = data->hdev->name;
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 6d7c0c8..273043e 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 
 	dev->priv = coredev;
 	dev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(dev, RC_BIT_ALL);
+	dev->allowed_protocols = RC_BIT_ALL;
 	dev->map_name = sms_get_board(board_id)->rc_codes;
 	dev->driver_name = MODULE_NAME;
 
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index f9c4233..8311f1a 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -432,8 +432,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	 * Initialize the other fields of rc_dev
 	 */
 	rc->map_name       = ir->ir_codes;
-	rc_set_allowed_protocols(rc, rc_type);
-	rc_set_enabled_protocols(rc, rc_type);
+	rc->allowed_protocols = rc_type;
+	rc->enabled_protocols = rc_type;
 	if (!rc->driver_name)
 		rc->driver_name = MODULE_NAME;
 
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 097d0a0..1940c18 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -346,7 +346,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	}
 	rc->dev.parent = &dev->pci->dev;
 	rc->driver_type = driver_type;
-	rc_set_allowed_protocols(rc, allowed_protos);
+	rc->allowed_protocols = allowed_protos;
 	rc->priv = kernel_ir;
 	rc->open = cx23885_input_ir_open;
 	rc->close = cx23885_input_ir_close;
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 9bf48ca..93ff6a7 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -485,7 +485,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
 	} else {
 		dev->driver_type = RC_DRIVER_SCANCODE;
-		rc_set_allowed_protocols(dev, rc_type);
+		dev->allowed_protocols = rc_type;
 	}
 
 	ir->core = core;
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 7098fa5..3ada4dc 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -785,7 +785,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
 
 	rdev->priv = ati_remote;
 	rdev->driver_type = RC_DRIVER_SCANCODE;
-	rc_set_allowed_protocols(rdev, RC_BIT_OTHER);
+	rdev->allowed_protocols = RC_BIT_OTHER;
 	rdev->driver_name = "ati_remote";
 
 	rdev->open = ati_remote_rc_open;
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index fc9d23f..d16d9b4 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 		learning_mode_force = false;
 
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->priv = dev;
 	rdev->open = ene_open;
 	rdev->close = ene_close;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 46b66e5..f000faf 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
 	/* Set up the rc device */
 	rdev->priv = fintek;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = fintek_open;
 	rdev->close = fintek_close;
 	rdev->input_name = FINTEK_DESCRIPTION;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 29b5f89..5985308 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -145,9 +145,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	rcdev->dev.parent = &pdev->dev;
 	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
 	if (pdata->allowed_protos)
-		rc_set_allowed_protocols(rcdev, pdata->allowed_protos);
+		rcdev->allowed_protocols = pdata->allowed_protos;
 	else
-		rc_set_allowed_protocols(rcdev, RC_BIT_ALL);
+		rcdev->allowed_protocols = RC_BIT_ALL;
 	rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 
 	gpio_dev->rcdev = rcdev;
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 627ddfd..ee60e17 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -495,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf,
 	usb_to_input_id(ir->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rc, RC_BIT_ALL);
+	rc->allowed_protocols = RC_BIT_ALL;
 	rc->priv = ir;
 	rc->open = iguanair_open;
 	rc->close = iguanair_close;
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 871a9b3..9fc41780 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -551,8 +551,8 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
 	hw->mode = IMG_IR_M_NORMAL;
 
 	/* clear the wakeup scancode filter */
-	rdev->scancode_filters[RC_FILTER_WAKEUP].data = 0;
-	rdev->scancode_filters[RC_FILTER_WAKEUP].mask = 0;
+	rdev->scancode_wakeup_filter.data = 0;
+	rdev->scancode_wakeup_filter.mask = 0;
 
 	/* clear raw filters */
 	_img_ir_set_filter(priv, NULL);
@@ -656,8 +656,8 @@ success:
 	wakeup_protocols = *ir_type;
 	if (!hw->decoder || !hw->decoder->filter)
 		wakeup_protocols = 0;
-	rc_set_allowed_wakeup_protocols(rdev, wakeup_protocols);
-	rc_set_enabled_wakeup_protocols(rdev, wakeup_protocols);
+	rdev->allowed_wakeup_protocols = wakeup_protocols;
+	rdev->enabled_wakeup_protocols = wakeup_protocols;
 	return 0;
 }
 
@@ -671,9 +671,9 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
 	spin_unlock_irq(&rdev->rc_map.lock);
 
 	mutex_lock(&rdev->lock);
-	rc_set_enabled_protocols(rdev, proto);
-	rc_set_allowed_wakeup_protocols(rdev, proto);
-	rc_set_enabled_wakeup_protocols(rdev, proto);
+	rdev->enabled_protocols = proto;
+	rdev->allowed_wakeup_protocols = proto;
+	rdev->enabled_wakeup_protocols = proto;
 	mutex_unlock(&rdev->lock);
 }
 
@@ -998,7 +998,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
 	}
 	rdev->priv = priv;
 	rdev->map_name = RC_MAP_EMPTY;
-	rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv));
+	rdev->allowed_protocols = img_ir_allowed_protos(priv);
 	rdev->input_name = "IMG Infrared Decoder";
 	rdev->s_filter = img_ir_set_normal_filter;
 	rdev->s_wakeup_filter = img_ir_set_wakeup_filter;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 8abbb8d..2461933 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1017,7 +1017,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type)
 	unsigned char ir_proto_packet[] = {
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
 
-	if (*rc_type && !rc_protocols_allowed(rc, *rc_type))
+	if (*rc_type && !(*rc_type & rc->allowed_protocols))
 		dev_warn(dev, "Looks like you're trying to use an IR protocol "
 			 "this device does not support\n");
 
@@ -1876,8 +1876,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
 
 	rdev->priv = ictx;
 	rdev->driver_type = RC_DRIVER_SCANCODE;
-					/* iMON PAD or MCE */
-	rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE);
+	rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
 	rdev->change_protocol = imon_ir_change_protocol;
 	rdev->driver_name = MOD_NAME;
 
@@ -1890,7 +1889,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
 
 	if (ictx->product == 0xffdc) {
 		imon_get_ffdc_type(ictx);
-		rc_set_allowed_protocols(rdev, ictx->rc_type);
+		rdev->allowed_protocols = ictx->rc_type;
 	}
 
 	imon_set_display_type(ictx);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 7b79eca..30bcf18 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 {
 	struct jvc_dec *data = &dev->raw->jvc;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_JVC))
+	if (!(dev->enabled_protocols & RC_BIT_JVC))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index d731da6..ed2c8a1 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct lirc_codec *lirc = &dev->raw->lirc;
 	int sample;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_LIRC))
+	if (!(dev->enabled_protocols & RC_BIT_LIRC))
 		return 0;
 
 	if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 0c55f79..9f3c9b5 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u32 scancode;
 	unsigned long delay;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_MCE_KBD))
+	if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 798e32b..1683aaa 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -51,7 +51,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u32 scancode;
 	u8 address, not_address, command, not_command;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_NEC))
+	if (!(dev->enabled_protocols & RC_BIT_NEC))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index f38557f..2a7f858 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -261,7 +261,7 @@ int ir_raw_event_register(struct rc_dev *dev)
 		return -ENOMEM;
 
 	dev->raw->dev = dev;
-	rc_set_enabled_protocols(dev, ~0);
+	dev->enabled_protocols = ~0;
 	dev->change_protocol = change_protocol;
 	rc = kfifo_alloc(&dev->raw->kfifo,
 			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 3d38cbc..04ce42f 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -53,7 +53,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u32 scancode;
 	enum rc_type protocol;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X))
+	if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
 		return 0;
 
 	if (!is_timing_event(ev)) {
@@ -129,7 +129,7 @@ again:
 		if (data->wanted_bits == RC5X_NBITS) {
 			/* RC5X */
 			u8 xdata, command, system;
-			if (!rc_protocols_enabled(dev, RC_BIT_RC5X)) {
+			if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
 				data->state = STATE_INACTIVE;
 				return 0;
 			}
@@ -147,7 +147,7 @@ again:
 		} else {
 			/* RC5 */
 			u8 command, system;
-			if (!rc_protocols_enabled(dev, RC_BIT_RC5)) {
+			if (!(dev->enabled_protocols & RC_BIT_RC5)) {
 				data->state = STATE_INACTIVE;
 				return 0;
 			}
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index 85c7711..771e9fc 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u8 toggle, command, system;
 	u32 scancode;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_RC5_SZ))
+	if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 1dc97a7..f1f098e 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -90,9 +90,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u8 toggle;
 	enum rc_type protocol;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
-				  RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
-				  RC_BIT_RC6_MCE))
+	if (!(dev->enabled_protocols &
+	      (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
+	       RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 5f77022..ad1dc6a 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u32 scancode;
 	u8 address, command, not_command;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_SANYO))
+	if (!(dev->enabled_protocols & RC_BIT_SANYO))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index c8f2519..b7acdba 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -48,7 +48,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct sharp_dec *data = &dev->raw->sharp;
 	u32 msg, echo, address, command, scancode;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_SHARP))
+	if (!(dev->enabled_protocols & RC_BIT_SHARP))
 		return 0;
 
 	if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index f485f9fe..d12dc3d 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -46,8 +46,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	u32 scancode;
 	u8 device, subdevice, function;
 
-	if (!rc_protocols_enabled(dev, RC_BIT_SONY12 | RC_BIT_SONY15 |
-				  RC_BIT_SONY20))
+	if (!(dev->enabled_protocols &
+	      (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
 		return 0;
 
 	if (!is_timing_event(ev)) {
@@ -125,7 +125,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 		switch (data->count) {
 		case 12:
-			if (!rc_protocols_enabled(dev, RC_BIT_SONY12)) {
+			if (!(dev->enabled_protocols & RC_BIT_SONY12)) {
 				data->state = STATE_INACTIVE;
 				return 0;
 			}
@@ -135,7 +135,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			protocol = RC_TYPE_SONY12;
 			break;
 		case 15:
-			if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) {
+			if (!(dev->enabled_protocols & RC_BIT_SONY15)) {
 				data->state = STATE_INACTIVE;
 				return 0;
 			}
@@ -145,7 +145,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			protocol = RC_TYPE_SONY15;
 			break;
 		case 20:
-			if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) {
+			if (!(dev->enabled_protocols & RC_BIT_SONY20)) {
 				data->state = STATE_INACTIVE;
 				return 0;
 			}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index ab24cc6..32fd5f4 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 	/* set up ir-core props */
 	rdev->priv = itdev;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = ite_open;
 	rdev->close = ite_close;
 	rdev->s_idle = ite_s_idle;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 5d8f3d4..a347736 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1211,7 +1211,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 	rc->dev.parent = dev;
 	rc->priv = ir;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rc, RC_BIT_ALL);
+	rc->allowed_protocols = RC_BIT_ALL;
 	rc->timeout = MS_TO_NS(100);
 	if (!ir->flags.no_tx) {
 		rc->s_tx_mask = mceusb_set_tx_mask;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index d244e1a..8c6008f 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1044,7 +1044,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 	/* Set up the rc device */
 	rdev->priv = nvt;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = nvt_open;
 	rdev->close = nvt_close;
 	rdev->tx_ir = nvt_tx_ir;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 0a88e0c..63dace8 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -195,7 +195,7 @@ static int __init loop_init(void)
 	rc->map_name		= RC_MAP_EMPTY;
 	rc->priv		= &loopdev;
 	rc->driver_type		= RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rc, RC_BIT_ALL);
+	rc->allowed_protocols	= RC_BIT_ALL;
 	rc->timeout		= 100 * 1000 * 1000; /* 100 ms */
 	rc->min_timeout		= 1;
 	rc->max_timeout		= UINT_MAX;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index df3175d..287191b 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -340,10 +340,10 @@ static inline enum rc_type guess_protocol(struct rc_dev *rdev)
 {
 	struct rc_map *rc_map = &rdev->rc_map;
 
-	if (hweight64(rdev->enabled_protocols[RC_FILTER_NORMAL]) == 1)
-		return rc_bitmap_to_type(rdev->enabled_protocols[RC_FILTER_NORMAL]);
-	else if (hweight64(rdev->allowed_protocols[RC_FILTER_NORMAL]) == 1)
-		return rc_bitmap_to_type(rdev->allowed_protocols[RC_FILTER_NORMAL]);
+	if (hweight64(rdev->enabled_protocols) == 1)
+		return rc_bitmap_to_type(rdev->enabled_protocols);
+	else if (hweight64(rdev->allowed_protocols) == 1)
+		return rc_bitmap_to_type(rdev->allowed_protocols);
 	else if (rc_map->len > 0)
 		return rc_map->scan[0].protocol;
 	else
@@ -986,14 +986,14 @@ static ssize_t show_protocols(struct device *device,
 	mutex_lock(&dev->lock);
 
 	if (fattr->type == RC_FILTER_NORMAL) {
-		enabled = dev->enabled_protocols[RC_FILTER_NORMAL];
+		enabled = dev->enabled_protocols;
 		if (dev->raw)
 			allowed = ir_raw_get_allowed_protocols();
 		else
-			allowed = dev->allowed_protocols[RC_FILTER_NORMAL];
+			allowed = dev->allowed_protocols;
 	} else {
-		enabled = dev->enabled_protocols[RC_FILTER_WAKEUP];
-		allowed = dev->allowed_protocols[RC_FILTER_WAKEUP];
+		enabled = dev->enabled_wakeup_protocols;
+		allowed = dev->allowed_wakeup_protocols;
 	}
 
 	mutex_unlock(&dev->lock);
@@ -1118,15 +1118,15 @@ static ssize_t store_protocols(struct device *device,
 
 	if (fattr->type == RC_FILTER_NORMAL) {
 		IR_dprintk(1, "Normal protocol change requested\n");
-		current_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
+		current_protocols = &dev->enabled_protocols;
 		change_protocol = dev->change_protocol;
-		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+		filter = &dev->scancode_filter;
 		set_filter = dev->s_filter;
 	} else {
 		IR_dprintk(1, "Wakeup protocol change requested\n");
-		current_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
+		current_protocols = &dev->enabled_wakeup_protocols;
 		change_protocol = dev->change_wakeup_protocol;
-		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+		filter = &dev->scancode_wakeup_filter;
 		set_filter = dev->s_wakeup_filter;
 	}
 
@@ -1214,9 +1214,9 @@ static ssize_t show_filter(struct device *device,
 		return -EINVAL;
 
 	if (fattr->type == RC_FILTER_NORMAL)
-		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+		filter = &dev->scancode_filter;
 	else
-		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+		filter = &dev->scancode_wakeup_filter;
 
 	mutex_lock(&dev->lock);
 	if (fattr->mask)
@@ -1269,12 +1269,12 @@ static ssize_t store_filter(struct device *device,
 
 	if (fattr->type == RC_FILTER_NORMAL) {
 		set_filter = dev->s_filter;
-		enabled_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
-		filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+		enabled_protocols = &dev->enabled_protocols;
+		filter = &dev->scancode_filter;
 	} else {
 		set_filter = dev->s_wakeup_filter;
-		enabled_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
-		filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
+		enabled_protocols = &dev->enabled_wakeup_protocols;
+		filter = &dev->scancode_wakeup_filter;
 	}
 
 	if (!set_filter)
@@ -1553,7 +1553,7 @@ int rc_register_device(struct rc_dev *dev)
 		rc = dev->change_protocol(dev, &rc_type);
 		if (rc < 0)
 			goto out_raw;
-		dev->enabled_protocols[RC_FILTER_NORMAL] = rc_type;
+		dev->enabled_protocols = rc_type;
 	}
 
 	mutex_unlock(&dev->lock);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 47cd373..3f45e1a 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -922,7 +922,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	rc->dev.parent = dev;
 	rc->priv = rr3;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rc, RC_BIT_ALL);
+	rc->allowed_protocols = RC_BIT_ALL;
 	rc->timeout = US_TO_NS(2750);
 	rc->tx_ir = redrat3_transmit_ir;
 	rc->s_tx_carrier = redrat3_set_tx_carrier;
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 22e4c1f..8f0cddb 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -287,7 +287,7 @@ static int st_rc_probe(struct platform_device *pdev)
 	st_rc_hardware_init(rc_dev);
 
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protos = RC_BIT_ALL;
 	/* rx sampling rate is 10Mhz */
 	rdev->rx_resolution = 100;
 	rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index f4e0bc3..7d7be0c 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -322,7 +322,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
 	rdev->dev.parent = dev;
 	rdev->priv = sz;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->driver_name = DRIVER_NAME;
 	rdev->map_name = RC_MAP_STREAMZAP;
 
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index c5be38e..bc214e2 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf,
 	usb_to_input_id(tt->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rc, RC_BIT_ALL);
+	rc->allowed_protocols = RC_BIT_ALL;
 	rc->priv = tt;
 	rc->driver_name = DRIVER_NAME;
 	rc->map_name = RC_MAP_TT_1500;
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index a8b981f..d839f73 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1082,7 +1082,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	data->dev->dev.parent = &device->dev;
 	data->dev->timeout = MS_TO_NS(100);
 	data->dev->rx_resolution = US_TO_NS(2);
-	rc_set_allowed_protocols(data->dev, RC_BIT_ALL);
+	data->dev->allowed_protocols = RC_BIT_ALL;
 
 	err = rc_register_device(data->dev);
 	if (err)
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index de02db8..eaa76ef 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
 	dev->driver_name = (char *) d->props->driver_name;
 	dev->map_name = d->rc.map_name;
 	dev->driver_type = d->rc.driver_type;
-	rc_set_allowed_protocols(dev, d->rc.allowed_protos);
+	dev->allowed_protocols = d->rc.allowed_protos;
 	dev->change_protocol = d->rc.change_protocol;
 	dev->priv = d;
 
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 4058aea..7b5dae3 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
 	dev->driver_name = d->props.rc.core.module_name;
 	dev->map_name = d->props.rc.core.rc_codes;
 	dev->change_protocol = d->props.rc.core.change_protocol;
-	rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos);
+	dev->allowed_protocols = d->props.rc.core.allowed_protos;
 	dev->driver_type = d->props.rc.core.driver_type;
 	usb_to_input_id(d->udev, &dev->input_id);
 	dev->input_name = "IR-receiver inside an USB DVB receiver";
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 4bbd8e4..1232e32 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -739,7 +739,7 @@ static int em28xx_ir_init(struct em28xx *dev)
 		case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
 			rc->map_name = RC_MAP_HAUPPAUGE;
 			ir->get_key_i2c = em28xx_get_key_em_haup;
-			rc_set_allowed_protocols(rc, RC_BIT_RC5);
+			rc->allowed_protocols = RC_BIT_RC5;
 			break;
 		case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
 			rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
@@ -755,7 +755,7 @@ static int em28xx_ir_init(struct em28xx *dev)
 		switch (dev->chip_id) {
 		case CHIP_ID_EM2860:
 		case CHIP_ID_EM2883:
-			rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
+			rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
 			ir->get_key = default_polling_getkey;
 			break;
 		case CHIP_ID_EM2884:
@@ -763,8 +763,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 		case CHIP_ID_EM28174:
 		case CHIP_ID_EM28178:
 			ir->get_key = em2874_polling_getkey;
-			rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC |
-						 RC_BIT_RC6_0);
+			rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC |
+					     RC_BIT_RC6_0;
 			break;
 		default:
 			err = -ENODEV;
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 676c0232..8a519f5 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -441,7 +441,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
 	ir->rc = rc;
 
 	/* input setup */
-	rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
+	rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
 	/* Neded, in order to support NEC remotes with 24 or 32 bits */
 	rc->scanmask = 0xffff;
 	rc->priv = ir;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 6f66305..e6784e8 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -92,10 +92,12 @@ enum rc_filter_type {
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
- * @allowed_protocols: bitmask with the supported RC_BIT_* protocols for each
- *	filter type
- * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols for each
- *	filter type
+ * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
+ * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
+ * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
+ * @enabled_wakeup_protocols: bitmask with the enabled RC_BIT_* wakeup protocols
+ * @scancode_filter: scancode filter
+ * @scancode_wakeup_filter: scancode wakeup filters
  * @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
  *	anything with it. Yet, as the same keycode table can be used with other
@@ -115,7 +117,6 @@ enum rc_filter_type {
  * @max_timeout: maximum timeout supported by device
  * @rx_resolution : resolution (in ns) of input sampler
  * @tx_resolution: resolution (in ns) of output sampler
- * @scancode_filters: scancode filters (indexed by enum rc_filter_type)
  * @change_protocol: allow changing the protocol used on hardware decoders
  * @change_wakeup_protocol: allow changing the protocol used for wakeup
  *	filtering
@@ -150,8 +151,12 @@ struct rc_dev {
 	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;
 	bool				idle;
-	u64				allowed_protocols[RC_FILTER_MAX];
-	u64				enabled_protocols[RC_FILTER_MAX];
+	u64				allowed_protocols;
+	u64				enabled_protocols;
+	u64				allowed_wakeup_protocols;
+	u64				enabled_wakeup_protocols;
+	struct rc_scancode_filter	scancode_filter;
+	struct rc_scancode_filter	scancode_wakeup_filter;
 	u32				users;
 	u32				scanmask;
 	void				*priv;
@@ -168,7 +173,6 @@ struct rc_dev {
 	u32				max_timeout;
 	u32				rx_resolution;
 	u32				tx_resolution;
-	struct rc_scancode_filter	scancode_filters[RC_FILTER_MAX];
 	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*open)(struct rc_dev *dev);
@@ -189,42 +193,6 @@ struct rc_dev {
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
 
-static inline bool rc_protocols_allowed(struct rc_dev *rdev, u64 protos)
-{
-	return rdev->allowed_protocols[RC_FILTER_NORMAL] & protos;
-}
-
-/* should be called prior to registration or with mutex held */
-static inline void rc_set_allowed_protocols(struct rc_dev *rdev, u64 protos)
-{
-	rdev->allowed_protocols[RC_FILTER_NORMAL] = protos;
-}
-
-static inline bool rc_protocols_enabled(struct rc_dev *rdev, u64 protos)
-{
-	return rdev->enabled_protocols[RC_FILTER_NORMAL] & protos;
-}
-
-/* should be called prior to registration or with mutex held */
-static inline void rc_set_enabled_protocols(struct rc_dev *rdev, u64 protos)
-{
-	rdev->enabled_protocols[RC_FILTER_NORMAL] = protos;
-}
-
-/* should be called prior to registration or with mutex held */
-static inline void rc_set_allowed_wakeup_protocols(struct rc_dev *rdev,
-						   u64 protos)
-{
-	rdev->allowed_protocols[RC_FILTER_WAKEUP] = protos;
-}
-
-/* should be called prior to registration or with mutex held */
-static inline void rc_set_enabled_wakeup_protocols(struct rc_dev *rdev,
-						   u64 protos)
-{
-	rdev->enabled_protocols[RC_FILTER_WAKEUP] = protos;
-}
-
 /*
  * From rc-main.c
  * Those functions can be used on any type of Remote Controller. They


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

* [PATCH 14/49] rc-core: rename dev->scanmask to dev->scancode_mask
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (12 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 13/49] rc-core: remove protocol arrays David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 15/49] rc-core: merge rc5 and streamzap decoders David Härdeman
                   ` (36 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

We already have dev->scancode_filter and dev->scancode_wakeup_filter
so rename dev->scanmask to dev->scancode_mask for consistency.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/pci/cx88/cx88-input.c       |    2 +-
 drivers/media/pci/ttpci/budget-ci.c       |    2 +-
 drivers/media/rc/rc-main.c                |    4 ++--
 drivers/media/usb/cx231xx/cx231xx-input.c |    2 +-
 drivers/media/usb/tm6000/tm6000-input.c   |    2 +-
 include/media/rc-core.h                   |    5 +++--
 6 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 93ff6a7..3f1342c 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -478,7 +478,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 	dev->priv = core;
 	dev->open = cx88_ir_open;
 	dev->close = cx88_ir_close;
-	dev->scanmask = hardware_mask;
+	dev->scancode_mask = hardware_mask;
 
 	if (ir->sampling) {
 		dev->driver_type = RC_DRIVER_IR_RAW;
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 41ce7de..1feeeff 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -234,7 +234,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 		break;
 	}
 	if (!budget_ci->ir.full_rc5)
-		dev->scanmask = 0xff;
+		dev->scancode_mask = 0xff;
 
 	error = rc_register_device(dev);
 	if (error) {
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 287191b..2788102 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -287,8 +287,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 	 * IR tables from other remotes. So, we support specifying a mask to
 	 * indicate the valid bits of the scancodes.
 	 */
-	if (dev->scanmask)
-		entry->scancode &= dev->scanmask;
+	if (dev->scancode_mask)
+		entry->scancode &= dev->scancode_mask;
 
 	/*
 	 * First check if we already have a mapping for this command.
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index adcdd92..05f0434 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -91,7 +91,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
 	dev->init_data.get_key = get_key_isdbt;
 	dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name;
 	/* The i2c micro-controller only outputs the cmd part of NEC protocol */
-	dev->init_data.rc_dev->scanmask = 0xff;
+	dev->init_data.rc_dev->scancode_mask = 0xff;
 	dev->init_data.rc_dev->driver_name = "cx231xx";
 	dev->init_data.type = RC_BIT_NEC;
 	info.addr = 0x30;
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 8a519f5..26b2ebb 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -443,7 +443,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
 	/* input setup */
 	rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
 	/* Neded, in order to support NEC remotes with 24 or 32 bits */
-	rc->scanmask = 0xffff;
+	rc->scancode_mask = 0xffff;
 	rc->priv = ir;
 	rc->change_protocol = tm6000_ir_change_protocol;
 	if (dev->int_in.endp) {
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e6784e8..5a082e7 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -98,11 +98,12 @@ enum rc_filter_type {
  * @enabled_wakeup_protocols: bitmask with the enabled RC_BIT_* wakeup protocols
  * @scancode_filter: scancode filter
  * @scancode_wakeup_filter: scancode wakeup filters
- * @scanmask: some hardware decoders are not capable of providing the full
+ * @scancode_mask: some hardware decoders are not capable of providing the full
  *	scancode to the application. As this is a hardware limit, we can't do
  *	anything with it. Yet, as the same keycode table can be used with other
  *	devices, a mask is provided to allow its usage. Drivers should generally
  *	leave this field in blank
+ * @users: number of current users of the device
  * @priv: driver-specific data
  * @keylock: protects the remaining members of the struct
  * @keypressed: whether a key is currently pressed
@@ -157,8 +158,8 @@ struct rc_dev {
 	u64				enabled_wakeup_protocols;
 	struct rc_scancode_filter	scancode_filter;
 	struct rc_scancode_filter	scancode_wakeup_filter;
+	u32				scancode_mask;
 	u32				users;
-	u32				scanmask;
 	void				*priv;
 	spinlock_t			keylock;
 	bool				keypressed;


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

* [PATCH 15/49] rc-core: merge rc5 and streamzap decoders
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (13 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 14/49] rc-core: rename dev->scanmask to dev->scancode_mask David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 16/49] rc-core: use an IDA rather than a bitmap David Härdeman
                   ` (35 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Now that the protocol is part of the scancode, it is pretty easy to merge
the rc5 and streamzap decoders. An additional advantage is that the decoder
is now stricter as it waits for the trailing silence before determining that
a command is a valid rc5/streamzap command (which avoids collisions that I've
seen with e.g. Sony protocols).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/Kconfig                |   12 --
 drivers/media/rc/Makefile               |    1 
 drivers/media/rc/ir-rc5-decoder.c       |   72 ++++++++------
 drivers/media/rc/ir-rc5-sz-decoder.c    |  154 -------------------------------
 drivers/media/rc/keymaps/rc-streamzap.c |    4 -
 drivers/media/rc/rc-core-priv.h         |    8 --
 drivers/media/rc/streamzap.c            |   10 --
 7 files changed, 43 insertions(+), 218 deletions(-)
 delete mode 100644 drivers/media/rc/ir-rc5-sz-decoder.c

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8fbd377..6097ff4 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -84,18 +84,6 @@ config IR_SONY_DECODER
 	   Enable this option if you have an infrared remote control which
 	   uses the Sony protocol, and you need software decoding support.
 
-config IR_RC5_SZ_DECODER
-	tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
-	depends on RC_CORE
-	select BITREVERSE
-	default y
-
-	---help---
-	   Enable this option if you have IR with RC-5 (streamzap) protocol,
-	   and if the IR is decoded in software. (The Streamzap PC Remote
-	   uses an IR protocol that is almost standard RC-5, but not quite,
-	   as it uses an additional bit).
-
 config IR_SANYO_DECODER
 	tristate "Enable IR raw decoder for the Sanyo protocol"
 	depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f8b54ff..d326d4d 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
 obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
-obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
 obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
 obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
 obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 04ce42f..93168da 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -1,6 +1,7 @@
-/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
+/* ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols
  *
  * Copyright (C) 2010 by Mauro Carvalho Chehab
+ * Copyright (C) 2010 by Jarod Wilson <jarod@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
@@ -13,23 +14,22 @@
  */
 
 /*
- * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
- * There are other variants that use a different number of bits.
- * This is currently unsupported.
- * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
- * the first two bits are start bits, and a third one is a filing bit
+ * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol
+ * and 20 bit RC5x protocol.
  */
 
 #include "rc-core-priv.h"
 #include <linux/module.h>
 
 #define RC5_NBITS		14
+#define RC5_SZ_NBITS		15
 #define RC5X_NBITS		20
 #define CHECK_RC5X_NBITS	8
 #define RC5_UNIT		888888 /* ns */
 #define RC5_BIT_START		(1 * RC5_UNIT)
 #define RC5_BIT_END		(1 * RC5_UNIT)
 #define RC5X_SPACE		(4 * RC5_UNIT)
+#define RC5_TRAILER		(10 * RC5_UNIT) /* In reality, approx 100 */
 
 enum rc5_state {
 	STATE_INACTIVE,
@@ -66,7 +66,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		goto out;
 
 again:
-	IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
+	IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
 		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
@@ -80,12 +80,15 @@ again:
 
 		data->state = STATE_BIT_START;
 		data->count = 1;
-		/* We just need enough bits to get to STATE_CHECK_RC5X */
-		data->wanted_bits = RC5X_NBITS;
 		decrease_duration(&ev, RC5_BIT_START);
 		goto again;
 
 	case STATE_BIT_START:
+		if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
+			data->state = STATE_FINISHED;
+			goto again;
+		}
+
 		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
 			break;
 
@@ -100,9 +103,7 @@ again:
 		if (!is_transition(&ev, &dev->raw->prev_ev))
 			break;
 
-		if (data->count == data->wanted_bits)
-			data->state = STATE_FINISHED;
-		else if (data->count == CHECK_RC5X_NBITS)
+		if (data->count == CHECK_RC5X_NBITS)
 			data->state = STATE_CHECK_RC5X;
 		else
 			data->state = STATE_BIT_START;
@@ -112,13 +113,10 @@ again:
 
 	case STATE_CHECK_RC5X:
 		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
-			/* RC5X */
-			data->wanted_bits = RC5X_NBITS;
+			data->is_rc5x = true;
 			decrease_duration(&ev, RC5X_SPACE);
-		} else {
-			/* RC5 */
-			data->wanted_bits = RC5_NBITS;
-		}
+		} else
+			data->is_rc5x = false;
 		data->state = STATE_BIT_START;
 		goto again;
 
@@ -126,7 +124,7 @@ again:
 		if (ev.pulse)
 			break;
 
-		if (data->wanted_bits == RC5X_NBITS) {
+		if (data->is_rc5x && data->count == RC5X_NBITS) {
 			/* RC5X */
 			u8 xdata, command, system;
 			if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
@@ -141,10 +139,7 @@ again:
 			scancode = system << 16 | command << 8 | xdata;
 			protocol = RC_TYPE_RC5X;
 
-			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
-				   scancode, toggle);
-
-		} else {
+		} else if (!data->is_rc5x && data->count == RC5_NBITS) {
 			/* RC5 */
 			u8 command, system;
 			if (!(dev->enabled_protocols & RC_BIT_RC5)) {
@@ -158,9 +153,24 @@ again:
 			scancode = system << 8 | command;
 			protocol = RC_TYPE_RC5;
 
-			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
-				   scancode, toggle);
-		}
+		} else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) {
+			/* RC5 StreamZap */
+			u8 command, system;
+			if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) {
+				data->state = STATE_INACTIVE;
+				return 0;
+			}
+			command  = (data->bits & 0x0003F) >> 0;
+			system   = (data->bits & 0x02FC0) >> 6;
+			toggle   = (data->bits & 0x01000) ? 1 : 0;
+			scancode = system << 6 | command;
+			protocol = RC_TYPE_RC5_SZ;
+
+		} else
+			break;
+
+		IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
+			   scancode, protocol, toggle);
 
 		rc_keydown(dev, protocol, scancode, toggle);
 		data->state = STATE_INACTIVE;
@@ -168,14 +178,14 @@ again:
 	}
 
 out:
-	IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
+	IR_dprintk(1, "RC5(x/sz) decode failed at state %i (%uus %s)\n",
 		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
 
 static struct ir_raw_handler rc5_handler = {
-	.protocols	= RC_BIT_RC5 | RC_BIT_RC5X,
+	.protocols	= RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
 	.decode		= ir_rc5_decode,
 };
 
@@ -183,7 +193,7 @@ static int __init ir_rc5_decode_init(void)
 {
 	ir_raw_handler_register(&rc5_handler);
 
-	printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
+	printk(KERN_INFO "IR RC5(x/sz) protocol handler initialized\n");
 	return 0;
 }
 
@@ -196,6 +206,6 @@ module_init(ir_rc5_decode_init);
 module_exit(ir_rc5_decode_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_AUTHOR("Mauro Carvalho Chehab and Jarod Wilson");
 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
+MODULE_DESCRIPTION("RC5(x/sz) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
deleted file mode 100644
index 771e9fc..0000000
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab
- * Copyright (C) 2010 by Jarod Wilson <jarod@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.
- */
-
-/*
- * This code handles the 15 bit RC5-ish protocol used by the Streamzap
- * PC Remote.
- * It considers a carrier of 36 kHz, with a total of 15 bits, where
- * the first two bits are start bits, and a third one is a filing bit
- */
-
-#include "rc-core-priv.h"
-#include <linux/module.h>
-
-#define RC5_SZ_NBITS		15
-#define RC5_UNIT		888888 /* ns */
-#define RC5_BIT_START		(1 * RC5_UNIT)
-#define RC5_BIT_END		(1 * RC5_UNIT)
-
-enum rc5_sz_state {
-	STATE_INACTIVE,
-	STATE_BIT_START,
-	STATE_BIT_END,
-	STATE_FINISHED,
-};
-
-/**
- * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
- * @dev:	the struct rc_dev descriptor of the device
- * @ev:		the struct ir_raw_event descriptor of the pulse/space
- *
- * This function returns -EINVAL if the pulse violates the state machine
- */
-static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
-{
-	struct rc5_sz_dec *data = &dev->raw->rc5_sz;
-	u8 toggle, command, system;
-	u32 scancode;
-
-	if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
-		return 0;
-
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
-		return 0;
-	}
-
-	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
-		goto out;
-
-again:
-	IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
-
-	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
-		return 0;
-
-	switch (data->state) {
-
-	case STATE_INACTIVE:
-		if (!ev.pulse)
-			break;
-
-		data->state = STATE_BIT_START;
-		data->count = 1;
-		data->wanted_bits = RC5_SZ_NBITS;
-		decrease_duration(&ev, RC5_BIT_START);
-		goto again;
-
-	case STATE_BIT_START:
-		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
-			break;
-
-		data->bits <<= 1;
-		if (!ev.pulse)
-			data->bits |= 1;
-		data->count++;
-		data->state = STATE_BIT_END;
-		return 0;
-
-	case STATE_BIT_END:
-		if (!is_transition(&ev, &dev->raw->prev_ev))
-			break;
-
-		if (data->count == data->wanted_bits)
-			data->state = STATE_FINISHED;
-		else
-			data->state = STATE_BIT_START;
-
-		decrease_duration(&ev, RC5_BIT_END);
-		goto again;
-
-	case STATE_FINISHED:
-		if (ev.pulse)
-			break;
-
-		/* RC5-sz */
-		command  = (data->bits & 0x0003F) >> 0;
-		system   = (data->bits & 0x02FC0) >> 6;
-		toggle   = (data->bits & 0x01000) ? 1 : 0;
-		scancode = system << 6 | command;
-
-		IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
-			   scancode, toggle);
-
-		rc_keydown(dev, RC_TYPE_RC5_SZ, scancode, toggle);
-		data->state = STATE_INACTIVE;
-		return 0;
-	}
-
-out:
-	IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
-	data->state = STATE_INACTIVE;
-	return -EINVAL;
-}
-
-static struct ir_raw_handler rc5_sz_handler = {
-	.protocols	= RC_BIT_RC5_SZ,
-	.decode		= ir_rc5_sz_decode,
-};
-
-static int __init ir_rc5_sz_decode_init(void)
-{
-	ir_raw_handler_register(&rc5_sz_handler);
-
-	printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
-	return 0;
-}
-
-static void __exit ir_rc5_sz_decode_exit(void)
-{
-	ir_raw_handler_unregister(&rc5_sz_handler);
-}
-
-module_init(ir_rc5_sz_decode_init);
-module_exit(ir_rc5_sz_decode_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
index f9a0757..23c0611 100644
--- a/drivers/media/rc/keymaps/rc-streamzap.c
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -15,9 +15,7 @@
 static struct rc_map_table streamzap[] = {
 /*
  * The Streamzap remote is almost, but not quite, RC-5, as it has an extra
- * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
- * an additional RC-5-sz decoder is being deployed to support it, but it
- * may be possible to merge it back with the standard RC-5 decoder.
+ * bit in it.
  */
 	{ 0x28c0, KEY_NUMERIC_0 },
 	{ 0x28c1, KEY_NUMERIC_1 },
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index da536c9..dea7aff 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -54,7 +54,7 @@ struct ir_raw_event_ctrl {
 		int state;
 		u32 bits;
 		unsigned count;
-		unsigned wanted_bits;
+		bool is_rc5x;
 	} rc5;
 	struct rc6_dec {
 		int state;
@@ -77,12 +77,6 @@ struct ir_raw_event_ctrl {
 		bool first;
 		bool toggle;
 	} jvc;
-	struct rc5_sz_dec {
-		int state;
-		u32 bits;
-		unsigned count;
-		unsigned wanted_bits;
-	} rc5_sz;
 	struct sanyo_dec {
 		int state;
 		unsigned count;
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 7d7be0c..2659f66 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -69,13 +69,6 @@ MODULE_DEVICE_TABLE(usb, streamzap_table);
 /* number of samples buffered */
 #define SZ_BUF_LEN 128
 
-/* from ir-rc5-sz-decoder.c */
-#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
-#define load_rc5_sz_decode()    request_module("ir-rc5-sz-decoder")
-#else
-#define load_rc5_sz_decode()    {}
-#endif
-
 enum StreamzapDecoderState {
 	PulseSpace,
 	FullPulse,
@@ -458,9 +451,6 @@ static int streamzap_probe(struct usb_interface *intf,
 	dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
 		 usbdev->bus->busnum, usbdev->devnum);
 
-	/* Load the streamzap not-quite-rc5 decoder too */
-	load_rc5_sz_decode();
-
 	return 0;
 
 rc_dev_fail:


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

* [PATCH 16/49] rc-core: use an IDA rather than a bitmap
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (14 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 15/49] rc-core: merge rc5 and streamzap decoders David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-07-25 22:39   ` Mauro Carvalho Chehab
  2014-04-03 23:32 ` [PATCH 17/49] rc-core: add chardev David Härdeman
                   ` (34 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This patch changes rc-core to use an IDA rather than a bitmap to assign
unique numbers to each rc device. This is in preparation for introducing
rc-core chardevs.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ir-raw.c  |    2 +-
 drivers/media/rc/rc-main.c |   40 ++++++++++++++++++++--------------------
 include/media/rc-core.h    |    4 ++--
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 2a7f858..aed2997 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -271,7 +271,7 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 	spin_lock_init(&dev->raw->lock);
 	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
-				       "rc%ld", dev->devno);
+				       "rc%u", dev->minor);
 
 	if (IS_ERR(dev->raw->thread)) {
 		rc = PTR_ERR(dev->raw->thread);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 2788102..42268f3 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -18,17 +18,15 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include "rc-core-priv.h"
 
-/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */
-#define IRRCV_NUM_DEVICES      256
-static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES);
-
 /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
 #define IR_TAB_MIN_SIZE	256
 #define IR_TAB_MAX_SIZE	8192
+#define RC_DEV_MAX	256
 
 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
 #define IR_KEYPRESS_TIMEOUT 250
@@ -38,6 +36,9 @@ static LIST_HEAD(rc_map_list);
 static DEFINE_SPINLOCK(rc_map_lock);
 static struct led_trigger *led_feedback;
 
+/* Used to keep track of rc devices */
+static DEFINE_IDA(rc_ida);
+
 static struct rc_map_list *seek_rc_map(const char *name)
 {
 	struct rc_map_list *map = NULL;
@@ -1442,7 +1443,9 @@ int rc_register_device(struct rc_dev *dev)
 	static bool raw_init = false; /* raw decoders loaded? */
 	struct rc_map *rc_map;
 	const char *path;
-	int rc, devno, attr = 0;
+	int attr = 0;
+	int minor;
+	int rc;
 
 	if (!dev || !dev->map_name)
 		return -EINVAL;
@@ -1462,13 +1465,13 @@ int rc_register_device(struct rc_dev *dev)
 	if (dev->close)
 		dev->input_dev->close = ir_close;
 
-	do {
-		devno = find_first_zero_bit(ir_core_dev_number,
-					    IRRCV_NUM_DEVICES);
-		/* No free device slots */
-		if (devno >= IRRCV_NUM_DEVICES)
-			return -ENOMEM;
-	} while (test_and_set_bit(devno, ir_core_dev_number));
+	minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
+	if (minor < 0)
+		return minor;
+
+	dev->minor = minor;
+	dev_set_name(&dev->dev, "rc%u", dev->minor);
+	dev_set_drvdata(&dev->dev, dev);
 
 	dev->dev.groups = dev->sysfs_groups;
 	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
@@ -1488,9 +1491,6 @@ int rc_register_device(struct rc_dev *dev)
 	 */
 	mutex_lock(&dev->lock);
 
-	dev->devno = devno;
-	dev_set_name(&dev->dev, "rc%ld", dev->devno);
-	dev_set_drvdata(&dev->dev, dev);
 	rc = device_add(&dev->dev);
 	if (rc)
 		goto out_unlock;
@@ -1558,8 +1558,8 @@ int rc_register_device(struct rc_dev *dev)
 
 	mutex_unlock(&dev->lock);
 
-	IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
-		   dev->devno,
+	IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
+		   dev->minor,
 		   dev->driver_name ? dev->driver_name : "unknown",
 		   rc_map->name ? rc_map->name : "unknown",
 		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
@@ -1578,7 +1578,7 @@ out_dev:
 	device_del(&dev->dev);
 out_unlock:
 	mutex_unlock(&dev->lock);
-	clear_bit(dev->devno, ir_core_dev_number);
+	ida_simple_remove(&rc_ida, minor);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(rc_register_device);
@@ -1590,8 +1590,6 @@ void rc_unregister_device(struct rc_dev *dev)
 
 	del_timer_sync(&dev->timer_keyup);
 
-	clear_bit(dev->devno, ir_core_dev_number);
-
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
@@ -1604,6 +1602,8 @@ void rc_unregister_device(struct rc_dev *dev)
 
 	device_del(&dev->dev);
 
+	ida_simple_remove(&rc_ida, dev->minor);
+
 	rc_free_device(dev);
 }
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 5a082e7..ca3d836 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -87,7 +87,7 @@ enum rc_filter_type {
  * @rc_map: current scan/key table
  * @lock: used to ensure we've filled in all protocol details before
  *	anyone can call show_protocols or store_protocols
- * @devno: unique remote control device number
+ * @minor: unique minor remote control device number
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
@@ -147,7 +147,7 @@ struct rc_dev {
 	const char			*map_name;
 	struct rc_map			rc_map;
 	struct mutex			lock;
-	unsigned long			devno;
+	unsigned int			minor;
 	struct ir_raw_event_ctrl	*raw;
 	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;


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

* [PATCH 17/49] rc-core: add chardev
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (15 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 16/49] rc-core: use an IDA rather than a bitmap David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 18/49] rc-core: allow chardev to be read David Härdeman
                   ` (33 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This patch lays the groundwork for adding a rc-core chardev.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ir-raw.c  |    2 
 drivers/media/rc/rc-main.c |  284 +++++++++++++++++++++++++++++++++++---------
 include/media/rc-core.h    |   11 +-
 3 files changed, 238 insertions(+), 59 deletions(-)

diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index aed2997..7eb347a 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -271,7 +271,7 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 	spin_lock_init(&dev->raw->lock);
 	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
-				       "rc%u", dev->minor);
+				       dev_name(&dev->dev));
 
 	if (IS_ERR(dev->raw->thread)) {
 		rc = PTR_ERR(dev->raw->thread);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 42268f3..9c7bdb8 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -18,6 +18,7 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/idr.h>
 #include <linux/device.h>
 #include <linux/module.h>
@@ -38,6 +39,20 @@ static struct led_trigger *led_feedback;
 
 /* Used to keep track of rc devices */
 static DEFINE_IDA(rc_ida);
+static dev_t rc_devt;
+
+/**
+ * struct rc_client - keeps track of processes which have opened a rc chardev
+ * @dev: the &struct rc_dev which is being controlled
+ * @fasync: keeps track of the fasync queue
+ * @node: list of current clients for the rc device (protected by client_lock
+ *	in &struct rc_dev)
+ */
+struct rc_client {
+	struct rc_dev *dev;
+	struct fasync_struct *fasync;
+	struct list_head node;
+};
 
 static struct rc_map_list *seek_rc_map(const char *name)
 {
@@ -844,47 +859,45 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
 }
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 
-int rc_open(struct rc_dev *rdev)
+int rc_open(struct rc_dev *dev)
 {
-	int rval = 0;
-
-	if (!rdev)
-		return -EINVAL;
+	int err = 0;
 
-	mutex_lock(&rdev->lock);
-	if (!rdev->users++ && rdev->open != NULL)
-		rval = rdev->open(rdev);
+	mutex_lock(&dev->lock);
 
-	if (rval)
-		rdev->users--;
+	if (dev->dead)
+		err = -ENODEV;
+	else if (!dev->users++ && dev->open) {
+		err = dev->open(dev);
+		if (err)
+			dev->users--;
+	}
 
-	mutex_unlock(&rdev->lock);
+	mutex_unlock(&dev->lock);
 
-	return rval;
+	return err;
 }
 EXPORT_SYMBOL_GPL(rc_open);
 
-static int ir_open(struct input_dev *idev)
+static int rc_input_open(struct input_dev *idev)
 {
 	struct rc_dev *rdev = input_get_drvdata(idev);
 
 	return rc_open(rdev);
 }
 
-void rc_close(struct rc_dev *rdev)
+void rc_close(struct rc_dev *dev)
 {
-	if (rdev) {
-		mutex_lock(&rdev->lock);
+	mutex_lock(&dev->lock);
 
-		 if (!--rdev->users && rdev->close != NULL)
-			rdev->close(rdev);
+	if (!dev->dead && !--dev->users && dev->close)
+		dev->close(dev);
 
-		mutex_unlock(&rdev->lock);
-	}
+	mutex_unlock(&dev->lock);
 }
 EXPORT_SYMBOL_GPL(rc_close);
 
-static void ir_close(struct input_dev *idev)
+static void rc_input_close(struct input_dev *idev)
 {
 	struct rc_dev *rdev = input_get_drvdata(idev);
 	rc_close(rdev);
@@ -1306,8 +1319,136 @@ unlock:
 	return (ret < 0) ? ret : len;
 }
 
+/**
+ * rc_attach_client() - attaches a new userspace client to a rc device
+ * @dev:	the rc device
+ * @client:	the client to attach
+ */
+static void rc_attach_client(struct rc_dev *dev, struct rc_client *client)
+{
+	spin_lock(&dev->client_lock);
+	list_add_tail_rcu(&client->node, &dev->client_list);
+	spin_unlock(&dev->client_lock);
+}
+
+/**
+ * rc_detach_client() - detaches a userspace client from a rc device
+ * @dev:	the rc device
+ * @client:	the client to detach
+ */
+static void rc_detach_client(struct rc_dev *dev, struct rc_client *client)
+{
+	spin_lock(&dev->client_lock);
+	list_del_rcu(&client->node);
+	spin_unlock(&dev->client_lock);
+	synchronize_rcu();
+}
+	
+/**
+ * rc_dev_open() - allows userspace to open() a rc device file
+ * @inode:	the &struct inode corresponding to the device file
+ * @file:	the &struct file corresponding to the open() attempt
+ * @return:	zero on success, or a negative error code
+ *
+ * This function (which implements open in &struct file_operations)
+ * allows userspace to open() a rc device file.
+ */
+static int rc_dev_open(struct inode *inode, struct file *file)
+{
+	struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, cdev);
+	struct rc_client *client;
+	int err;
+
+	IR_dprintk(2, "Open attempt on %u\n", iminor(inode));
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
+
+	client->dev = dev;
+
+	rc_attach_client(dev, client);
+
+	err = rc_open(dev);
+	if (err)
+		goto out;
+
+	file->private_data = client;
+	nonseekable_open(inode, file);
+
+	IR_dprintk(2, "Device %u opened\n", iminor(inode));
+	return 0;
+
+out:
+	rc_detach_client(dev, client);
+	kfree(client);
+	return err;
+}
+
+/**
+ * rc_release() - allows userspace to close() a rc device file
+ * @inode:	the &struct inode corresponding to the device file
+ * @file:	the &struct file corresponding to the previous open()
+ * @return:	zero on success, or a negative error code
+ *
+ * This function (which implements release in &struct file_operations)
+ * allows userspace to close() a rc device file.
+ */
+static int rc_release(struct inode *inode, struct file *file)
+{
+	struct rc_client *client = file->private_data;
+	struct rc_dev *dev = client->dev;
+
+	rc_detach_client(dev, client);
+	kfree(client);
+	rc_close(dev);
+
+	IR_dprintk(2, "Device %u closed\n", iminor(inode));
+	return 0;
+}
+
+/**
+ * rc_fasync() - allows userspace to recieve asynchronous notifications
+ * @fd:		the file descriptor corresponding to the opened rc device
+ * @file:	the &struct file corresponding to the previous open()
+ * @on:		whether notifications should be enabled or disabled
+ * @return:	zero on success, or a negative error code
+ *
+ * This function (which implements fasync in &struct file_operations)
+ * allows userspace to receive asynchronous signal notifications
+ * when the state of a rc device file changes.
+ */
+static int rc_fasync(int fd, struct file *file, int on)
+{
+	struct rc_client *client = file->private_data;
+
+	return fasync_helper(fd, file, on, &client->fasync);
+}
+
+static const struct file_operations rc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rc_dev_open,
+	.release	= rc_release,
+	.fasync		= rc_fasync,
+	.llseek		= no_llseek,
+};
+
+/**
+ * rc_dev_release() - release a &struct rc_dev
+ * @device: the &struct device which corresponds to the &struct rc_dev
+ *
+ * This function is called by the driver core when the refcount
+ * for the &device reaches zero.
+ */
 static void rc_dev_release(struct device *device)
 {
+	struct rc_dev *dev = to_rc_dev(device);
+
+	if (dev->input_dev)
+		input_free_device(dev->input_dev);
+
+	kfree(dev);
+	module_put(THIS_MODULE);
 }
 
 #define ADD_HOTPLUG_VAR(fmt, val...)					\
@@ -1409,6 +1550,9 @@ struct rc_dev *rc_allocate_device(void)
 	dev->input_dev->setkeycode = ir_setkeycode;
 	input_set_drvdata(dev->input_dev, dev);
 
+	INIT_LIST_HEAD(&dev->client_list);
+	spin_lock_init(&dev->client_lock);
+
 	spin_lock_init(&dev->rc_map.lock);
 	spin_lock_init(&dev->keylock);
 	mutex_init(&dev->lock);
@@ -1418,23 +1562,27 @@ struct rc_dev *rc_allocate_device(void)
 	dev->dev.class = &rc_class;
 	device_initialize(&dev->dev);
 
+	cdev_init(&dev->cdev, &rc_fops);
+	dev->cdev.kobj.parent = &dev->dev.kobj;
+	dev->cdev.owner = THIS_MODULE;
+
 	__module_get(THIS_MODULE);
 	return dev;
 }
 EXPORT_SYMBOL_GPL(rc_allocate_device);
 
+/**
+ * rc_free_device() - free an allocated struct rc_dev
+ * @dev:	the &struct rc_dev to free
+ *
+ * This function is used by drivers to free a &struct rc_dev which has
+ * been allocated with rc_allocate_device(). It must not be used
+ * after rc_register_device() has been successfully called.
+ */
 void rc_free_device(struct rc_dev *dev)
 {
-	if (!dev)
-		return;
-
-	if (dev->input_dev)
-		input_free_device(dev->input_dev);
-
-	put_device(&dev->dev);
-
-	kfree(dev);
-	module_put(THIS_MODULE);
+	if (dev)
+		put_device(&dev->dev);
 }
 EXPORT_SYMBOL_GPL(rc_free_device);
 
@@ -1460,17 +1608,15 @@ int rc_register_device(struct rc_dev *dev)
 	set_bit(EV_REP, dev->input_dev->evbit);
 	set_bit(EV_MSC, dev->input_dev->evbit);
 	set_bit(MSC_SCAN, dev->input_dev->mscbit);
-	if (dev->open)
-		dev->input_dev->open = ir_open;
-	if (dev->close)
-		dev->input_dev->close = ir_close;
+	dev->input_dev->open = rc_input_open;
+	dev->input_dev->close = rc_input_close;
 
 	minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
 	if (minor < 0)
 		return minor;
 
-	dev->minor = minor;
-	dev_set_name(&dev->dev, "rc%u", dev->minor);
+	dev->dev.devt = MKDEV(MAJOR(rc_devt), minor);
+	dev_set_name(&dev->dev, "rc%u", minor);
 	dev_set_drvdata(&dev->dev, dev);
 
 	dev->dev.groups = dev->sysfs_groups;
@@ -1491,10 +1637,14 @@ int rc_register_device(struct rc_dev *dev)
 	 */
 	mutex_lock(&dev->lock);
 
-	rc = device_add(&dev->dev);
+	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
 	if (rc)
 		goto out_unlock;
 
+	rc = device_add(&dev->dev);
+	if (rc)
+		goto out_cdev;
+
 	rc = ir_setkeytable(dev, rc_map);
 	if (rc)
 		goto out_dev;
@@ -1558,8 +1708,8 @@ int rc_register_device(struct rc_dev *dev)
 
 	mutex_unlock(&dev->lock);
 
-	IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
-		   dev->minor,
+	IR_dprintk(1, "Registered %s (driver: %s, remote: %s, mode %s)\n",
+		   dev_name(&dev->dev),
 		   dev->driver_name ? dev->driver_name : "unknown",
 		   rc_map->name ? rc_map->name : "unknown",
 		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
@@ -1576,6 +1726,8 @@ out_table:
 	ir_free_table(&dev->rc_map);
 out_dev:
 	device_del(&dev->dev);
+out_cdev:
+	cdev_del(&dev->cdev);
 out_unlock:
 	mutex_unlock(&dev->lock);
 	ida_simple_remove(&rc_ida, minor);
@@ -1585,42 +1737,61 @@ EXPORT_SYMBOL_GPL(rc_register_device);
 
 void rc_unregister_device(struct rc_dev *dev)
 {
+	struct rc_client *client;
+
 	if (!dev)
 		return;
 
+	mutex_lock(&dev->lock);
+	dev->dead = true;
+	mutex_unlock(&dev->lock);
+
+	spin_lock(&dev->client_lock);
+	list_for_each_entry(client, &dev->client_list, node)
+		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+	spin_unlock(&dev->client_lock);
+
+	cdev_del(&dev->cdev);
+
 	del_timer_sync(&dev->timer_keyup);
 
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
-	/* Freeing the table should also call the stop callback */
 	ir_free_table(&dev->rc_map);
-	IR_dprintk(1, "Freed keycode table\n");
 
 	input_unregister_device(dev->input_dev);
 	dev->input_dev = NULL;
 
-	device_del(&dev->dev);
-
-	ida_simple_remove(&rc_ida, dev->minor);
+	/* dev is marked as dead so no one changes dev->users */
+	if (dev->users && dev->close)
+		dev->close(dev);
 
-	rc_free_device(dev);
+	device_del(&dev->dev);
+	ida_simple_remove(&rc_ida, MINOR(dev->dev.devt));
+	put_device(&dev->dev);
 }
 
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
-/*
- * Init/exit code for the module. Basically, creates/removes /sys/class/rc
- */
-
 static int __init rc_core_init(void)
 {
-	int rc = class_register(&rc_class);
-	if (rc) {
-		printk(KERN_ERR "rc_core: unable to register rc class\n");
-		return rc;
+	int err;
+
+	err = class_register(&rc_class);
+	if (err) {
+		printk(KERN_ERR "rc_core: unable to create class\n");
+		return err;
 	}
 
+	err = alloc_chrdev_region(&rc_devt, 0, RC_DEV_MAX, "rc-core");
+	if (err) {
+		printk(KERN_ERR "rc_core: unable to allocate chardev region\n");
+		class_unregister(&rc_class);
+		return err;
+	}
+
+	IR_dprintk(1, "Allocated char dev: %u\n", MAJOR(rc_devt));
 	led_trigger_register_simple("rc-feedback", &led_feedback);
 	rc_map_register(&empty_map);
 
@@ -1629,9 +1800,10 @@ static int __init rc_core_init(void)
 
 static void __exit rc_core_exit(void)
 {
-	class_unregister(&rc_class);
-	led_trigger_unregister_simple(led_feedback);
 	rc_map_unregister(&empty_map);
+	led_trigger_unregister_simple(led_feedback);
+	unregister_chrdev_region(rc_devt, RC_DEV_MAX);
+	class_unregister(&rc_class);
 }
 
 subsys_initcall(rc_core_init);
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index ca3d836..e2615e7 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -20,6 +20,7 @@
 #include <linux/kfifo.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#include <linux/cdev.h>
 #include <media/rc-map.h>
 
 extern int rc_core_debug;
@@ -78,6 +79,7 @@ enum rc_filter_type {
 /**
  * struct rc_dev - represents a remote control device
  * @dev: driver model's view of this device
+ * @cdev: character device structure
  * @sysfs_groups: sysfs attribute groups
  * @input_name: name of the input child device
  * @input_phys: physical path to the input child device
@@ -87,7 +89,9 @@ enum rc_filter_type {
  * @rc_map: current scan/key table
  * @lock: used to ensure we've filled in all protocol details before
  *	anyone can call show_protocols or store_protocols
- * @minor: unique minor remote control device number
+ * @dead: used to determine if the device is still alive
+ * @client_list: list of clients (processes which have opened the rc chardev)
+ * @client_lock: protects client_list
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
@@ -139,6 +143,7 @@ enum rc_filter_type {
  */
 struct rc_dev {
 	struct device			dev;
+	struct cdev			cdev;
 	const struct attribute_group	*sysfs_groups[5];
 	const char			*input_name;
 	const char			*input_phys;
@@ -147,7 +152,9 @@ struct rc_dev {
 	const char			*map_name;
 	struct rc_map			rc_map;
 	struct mutex			lock;
-	unsigned int			minor;
+	bool				dead;
+	struct list_head		client_list;
+	spinlock_t			client_lock;
 	struct ir_raw_event_ctrl	*raw;
 	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;


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

* [PATCH 18/49] rc-core: allow chardev to be read
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (16 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 17/49] rc-core: add chardev David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 19/49] rc-core: use a kfifo for TX data David Härdeman
                   ` (32 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This patch is the first step towards making the rc chardev usable by adding
read functionality.

Basically the implementation mimics what evdev does. Userspace applications can
open the rc device and read rc_event structs with data. Only some basic events
are supported for now but later patches will add further events.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |  154 +++++++++++++++++++++++++++++++++++++++++++-
 include/media/rc-core.h    |   40 +++++++++++
 2 files changed, 189 insertions(+), 5 deletions(-)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 9c7bdb8..5ce0cdb 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -22,12 +22,14 @@
 #include <linux/idr.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/poll.h>
 #include "rc-core-priv.h"
 
 /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE	256
-#define IR_TAB_MAX_SIZE	8192
-#define RC_DEV_MAX	256
+#define IR_TAB_MIN_SIZE		256
+#define IR_TAB_MAX_SIZE		8192
+#define RC_DEV_MAX		256
+#define RC_RX_BUFFER_SIZE	1024
 
 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
 #define IR_KEYPRESS_TIMEOUT 250
@@ -44,16 +46,75 @@ static dev_t rc_devt;
 /**
  * struct rc_client - keeps track of processes which have opened a rc chardev
  * @dev: the &struct rc_dev which is being controlled
+ * @rxlock: protects the rxfifo
+ * @rxfifo: stores rx events which can be read by the process
  * @fasync: keeps track of the fasync queue
  * @node: list of current clients for the rc device (protected by client_lock
  *	in &struct rc_dev)
  */
 struct rc_client {
 	struct rc_dev *dev;
+	spinlock_t rxlock;
+	DECLARE_KFIFO(rxfifo, struct rc_event, RC_RX_BUFFER_SIZE);
 	struct fasync_struct *fasync;
 	struct list_head node;
 };
 
+/**
+ * rc_client_event() - passes an rc event to a specific client
+ * @client:	the &struct rc_client for this client
+ * @type:	the event type
+ * @code:	the event code (type specific)
+ * @val:	the event value (type and code specific)
+ *
+ * This function writes a &struct rc_event entry to the client kfifo
+ * for later reading from userspace.
+ */
+static void rc_client_event(struct rc_client *client, u16 type,
+			    u16 code, u32 val)
+{
+	unsigned long flags;
+	struct rc_event ev;
+
+	ev.type = type;
+	ev.code = code;
+	ev.val = val;
+
+	spin_lock_irqsave(&client->rxlock, flags);
+	if (kfifo_is_full(&client->rxfifo)) {
+		kfifo_skip(&client->rxfifo);
+		ev.type = RC_CORE;
+		ev.code = RC_CORE_DROPPED;
+		ev.val = 1;
+	}
+
+	kfifo_in(&client->rxfifo, &ev, 1);
+	kill_fasync(&client->fasync, SIGIO, POLL_IN);
+	spin_unlock_irqrestore(&client->rxlock, flags);
+}
+
+/**
+ * rc_event() - sends an rc_event to all listeners
+ * @dev:	the struct rc_dev of the device generating the event
+ * @type:	the event type
+ * @code:	the event code (type specific)
+ * @val:	the event value (type and code specific)
+ *
+ * This function passes an rc event to all clients.
+ */
+void rc_event(struct rc_dev *dev, u16 type, u16 code, u32 val)
+{
+	struct rc_client *client;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(client, &dev->client_list, node)
+		rc_client_event(client, type, code, val);
+	rcu_read_unlock();
+
+	wake_up_interruptible(&dev->rxwait);
+}
+EXPORT_SYMBOL_GPL(rc_event);
+
 static struct rc_map_list *seek_rc_map(const char *name)
 {
 	struct rc_map_list *map = NULL;
@@ -753,6 +814,7 @@ void rc_repeat(struct rc_dev *dev)
 
 	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
 	input_sync(dev->input_dev);
+	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
 
 	if (!dev->keypressed)
 		goto out;
@@ -788,6 +850,15 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 		ir_do_keyup(dev, false);
 
 	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+	/*
+	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
+	 *	 scancode into 32 bit pieces and feed them to userspace
+	 *	 as one or more RC_KEY_SCANCODE_PART events followed
+	 *	 by a final RC_KEY_SCANCODE event.
+	 */
+	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
 
 	if (new_event && keycode != KEY_RESERVED) {
 		/* Register a keypress */
@@ -997,6 +1068,7 @@ static ssize_t show_protocols(struct device *device,
 	if (!dev)
 		return -EINVAL;
 
+	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
 	mutex_lock(&dev->lock);
 
 	if (fattr->type == RC_FILTER_NORMAL) {
@@ -1366,6 +1438,8 @@ static int rc_dev_open(struct inode *inode, struct file *file)
 		return -ENOMEM;
 
 	client->dev = dev;
+	spin_lock_init(&client->rxlock);
+	INIT_KFIFO(client->rxfifo);
 
 	rc_attach_client(dev, client);
 
@@ -1408,6 +1482,74 @@ static int rc_release(struct inode *inode, struct file *file)
 }
 
 /**
+ * rc_read() - allows userspace to read rc events
+ * @file:	the &struct file corresponding to the previous open()
+ * @buffer:	the userspace buffer to read data to
+ * @count:	the number of bytes to read
+ * @ppos:	the file offset
+ * @return:	the number of bytes read, or a negative error code
+ *
+ * This function (which implements read in &struct file_operations)
+ * allows userspace to read events from the rc device file.
+ */
+static ssize_t rc_read(struct file *file, char __user *buffer,
+		       size_t count, loff_t *ppos)
+{
+	struct rc_client *client = file->private_data;
+	struct rc_dev *dev = client->dev;
+	struct rc_event ev;
+	int ret;
+
+	if (count < sizeof(ev))
+		return -EINVAL;
+
+	if ((file->f_flags & O_NONBLOCK) &&
+	    kfifo_is_empty(&client->rxfifo) &&
+	    !dev->dead)
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(dev->rxwait,
+				       !kfifo_is_empty(&client->rxfifo) ||
+				       dev->dead);
+
+	if (ret)
+		return ret;
+
+	if (dev->dead)
+		return -ENODEV;
+
+	for (ret = 0; ret + sizeof(ev) <= count; ret += sizeof(ev)) {
+		if (kfifo_out_spinlocked(&client->rxfifo, &ev, 1,
+					 &client->rxlock) != 1)
+			break;
+
+		if (copy_to_user(buffer + ret, &ev, sizeof(ev)))
+			return -EFAULT;
+	}
+
+	return ret;
+}
+
+/**
+ * rc_poll() - allows userspace to poll rc device files
+ * @file:	the &struct file corresponding to the previous open()
+ * @wait:	used to keep track of processes waiting for poll events
+ * @return:	a mask of poll events which have occurred
+ *
+ * This function (which implements poll in &struct file_operations)
+ * allows userspace to poll/select on the rc device file.
+ */
+static unsigned int rc_poll(struct file *file, poll_table *wait)
+{
+	struct rc_client *client = file->private_data;
+	struct rc_dev *dev = client->dev;
+
+	poll_wait(file, &dev->rxwait, wait);
+	return ((kfifo_is_empty(&client->rxfifo) ? 0 : (POLLIN | POLLRDNORM)) |
+		(!dev->dead ? 0 : (POLLHUP | POLLERR)));
+}
+
+/**
  * rc_fasync() - allows userspace to recieve asynchronous notifications
  * @fd:		the file descriptor corresponding to the opened rc device
  * @file:	the &struct file corresponding to the previous open()
@@ -1429,6 +1571,8 @@ static const struct file_operations rc_fops = {
 	.owner		= THIS_MODULE,
 	.open		= rc_dev_open,
 	.release	= rc_release,
+	.read		= rc_read,
+	.poll		= rc_poll,
 	.fasync		= rc_fasync,
 	.llseek		= no_llseek,
 };
@@ -1552,7 +1696,7 @@ struct rc_dev *rc_allocate_device(void)
 
 	INIT_LIST_HEAD(&dev->client_list);
 	spin_lock_init(&dev->client_lock);
-
+	init_waitqueue_head(&dev->rxwait);
 	spin_lock_init(&dev->rc_map.lock);
 	spin_lock_init(&dev->keylock);
 	mutex_init(&dev->lock);
@@ -1750,6 +1894,7 @@ void rc_unregister_device(struct rc_dev *dev)
 	list_for_each_entry(client, &dev->client_list, node)
 		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
 	spin_unlock(&dev->client_lock);
+	wake_up_interruptible_all(&dev->rxwait);
 
 	cdev_del(&dev->cdev);
 
@@ -1771,7 +1916,6 @@ void rc_unregister_device(struct rc_dev *dev)
 	ida_simple_remove(&rc_ida, MINOR(dev->dev.devt));
 	put_device(&dev->dev);
 }
-
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
 static int __init rc_core_init(void)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e2615e7..d31ccdd 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -53,6 +53,43 @@ struct rc_keymap_entry {
 	};
 };
 
+/* rc_event.type value */
+#define RC_DEBUG		0x0
+#define RC_CORE			0x1
+#define RC_KEY			0x2
+#define RC_IR			0x3
+
+/* RC_CORE codes */
+#define RC_CORE_DROPPED		0x0
+
+/* RC_KEY codes */
+#define RC_KEY_REPEAT		0x0
+#define RC_KEY_PROTOCOL		0x1
+#define RC_KEY_SCANCODE		0x2
+#define RC_KEY_SCANCODE_PART	0x3
+#define RC_KEY_TOGGLE		0x4
+
+/* RC_IR codes */
+#define RC_IR_SPACE		0x0
+#define RC_IR_PULSE		0x1
+#define RC_IR_START		0x2
+#define RC_IR_STOP		0x3
+#define RC_IR_RESET		0x4
+#define RC_IR_CARRIER		0x5
+#define RC_IR_DUTY_CYCLE	0x6
+
+/**
+ * struct rc_event - used to communicate rc events to/from userspace
+ * @type:	the event type
+ * @code:	the event code (type specific)
+ * @val:	the event value (type and code specific)
+ */
+struct rc_event {
+	__u16 type;
+	__u16 code;
+	__u32 val;
+} __packed;
+
 /**
  * struct rc_scancode_filter - Filter scan codes.
  * @data:	Scancode data to match.
@@ -92,6 +129,7 @@ enum rc_filter_type {
  * @dead: used to determine if the device is still alive
  * @client_list: list of clients (processes which have opened the rc chardev)
  * @client_lock: protects client_list
+ * @rxwait: waitqueue for processes waiting for data to read
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
@@ -155,6 +193,7 @@ struct rc_dev {
 	bool				dead;
 	struct list_head		client_list;
 	spinlock_t			client_lock;
+	wait_queue_head_t		rxwait;
 	struct ir_raw_event_ctrl	*raw;
 	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;
@@ -212,6 +251,7 @@ struct rc_dev *rc_allocate_device(void);
 void rc_free_device(struct rc_dev *dev);
 int rc_register_device(struct rc_dev *dev);
 void rc_unregister_device(struct rc_dev *dev);
+void rc_event(struct rc_dev *dev, u16 type, u16 code, u32 val);
 
 int rc_open(struct rc_dev *rdev);
 void rc_close(struct rc_dev *rdev);


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

* [PATCH 19/49] rc-core: use a kfifo for TX data
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (17 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 18/49] rc-core: allow chardev to be read David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:32 ` [PATCH 20/49] rc-core: allow chardev to be written David Härdeman
                   ` (31 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Using a per rc_dev TX kfifo for TX data simplifies the device drivers and lays
the ground for the next patch.

This means that every driver with TX capabilities need to be changed at the
same time.

It should be noted that the TX functionality in nuvoton-cir.c is, and was,
probably broken before and after this patch.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ene_ir.c        |   61 +++++++++------------
 drivers/media/rc/ene_ir.h        |    9 +--
 drivers/media/rc/iguanair.c      |   51 ++++++++++++-----
 drivers/media/rc/ir-lirc-codec.c |  100 ++++++++++++++++++----------------
 drivers/media/rc/ir-raw.c        |   41 ++++++++++++++
 drivers/media/rc/ite-cir.c       |   35 +++++-------
 drivers/media/rc/mceusb.c        |   43 ++++++++------
 drivers/media/rc/nuvoton-cir.c   |   57 +++++++++++--------
 drivers/media/rc/nuvoton-cir.h   |    9 ---
 drivers/media/rc/rc-loopback.c   |   25 +++++---
 drivers/media/rc/rc-main.c       |    9 +++
 drivers/media/rc/redrat3.c       |  113 ++++++++++++++++++++++----------------
 drivers/media/rc/winbond-cir.c   |   79 +++++++++++----------------
 include/media/rc-core.h          |    9 +++
 14 files changed, 363 insertions(+), 278 deletions(-)

diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index d16d9b4..cab5da9 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -615,7 +615,8 @@ static void ene_tx_enable(struct ene_device *dev)
 static void ene_tx_disable(struct ene_device *dev)
 {
 	ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
-	dev->tx_buffer = NULL;
+	dev->tx_ev.val = 0;
+	kfifo_reset_out(&dev->rdev->txfifo);
 }
 
 
@@ -623,18 +624,16 @@ static void ene_tx_disable(struct ene_device *dev)
 static void ene_tx_sample(struct ene_device *dev)
 {
 	u8 raw_tx;
-	u32 sample;
-	bool pulse = dev->tx_sample_pulse;
-
-	if (!dev->tx_buffer) {
-		pr_warn("TX: BUG: attempt to transmit NULL buffer\n");
-		return;
-	}
 
 	/* Grab next TX sample */
-	if (!dev->tx_sample) {
+	while (!dev->tx_ev.val) {
+		int tmp;
 
-		if (dev->tx_pos == dev->tx_len) {
+		tmp = ir_raw_get_tx_event(dev->rdev, &dev->tx_ev);
+		if (tmp < 0) {
+			dev->tx_ev.val = 0;
+			continue;
+		} else if (tmp == 0) {
 			if (!dev->tx_done) {
 				dbg("TX: no more data to send");
 				dev->tx_done = true;
@@ -647,25 +646,23 @@ static void ene_tx_sample(struct ene_device *dev)
 			}
 		}
 
-		sample = dev->tx_buffer[dev->tx_pos++];
-		dev->tx_sample_pulse = !dev->tx_sample_pulse;
-
-		dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
-
-		if (!dev->tx_sample)
-			dev->tx_sample = 1;
+		dev->tx_ev.val = DIV_ROUND_CLOSEST(dev->tx_ev.val,
+						   US_TO_NS(sample_period));
+		if (!dev->tx_ev.val)
+			dev->tx_ev.val = 1;
 	}
 
-	raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
-	dev->tx_sample -= raw_tx;
+	raw_tx = min_t(unsigned, dev->tx_ev.val, ENE_CIRRLC_OUT_MASK);
+	dev->tx_ev.val -= raw_tx;
 
 	dbg("TX: sample %8d (%s)", raw_tx * sample_period,
-						pulse ? "pulse" : "space");
-	if (pulse)
+	    dev->tx_ev.code == RC_IR_PULSE ? "pulse" : "space");
+
+	if (dev->tx_ev.code == RC_IR_PULSE)
 		raw_tx |= ENE_CIRRLC_OUT_PULSE;
 
 	ene_write_reg(dev,
-		dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
+		      dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
 
 	dev->tx_reg = !dev->tx_reg;
 exit:
@@ -968,20 +965,16 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle)
 }
 
 /* outside interface: transmit */
-static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
+static int ene_transmit(struct rc_dev *rdev, unsigned count)
 {
 	struct ene_device *dev = rdev->priv;
 	unsigned long flags;
 
-	dev->tx_buffer = buf;
-	dev->tx_len = n;
-	dev->tx_pos = 0;
 	dev->tx_reg = 0;
-	dev->tx_done = 0;
-	dev->tx_sample = 0;
-	dev->tx_sample_pulse = 0;
+	dev->tx_done = false;
 
-	dbg("TX: %d samples", dev->tx_len);
+	dev->tx_ev.val = 0;
+	dbg("TX: %d samples", count);
 
 	spin_lock_irqsave(&dev->hw_lock, flags);
 
@@ -998,9 +991,11 @@ static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
 		spin_lock_irqsave(&dev->hw_lock, flags);
 		ene_tx_disable(dev);
 		spin_unlock_irqrestore(&dev->hw_lock, flags);
-	} else
-		dbg("TX: done");
-	return n;
+		return -EIO;
+	}
+
+	dbg("TX: done");
+	return count;
 }
 
 /* probe entry */
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
index a7911e3..9eb0b57 100644
--- a/drivers/media/rc/ene_ir.h
+++ b/drivers/media/rc/ene_ir.h
@@ -222,15 +222,10 @@ struct ene_device {
 	bool rx_fan_input_inuse;		/* is fan input in use for rx*/
 	int tx_reg;				/* current reg used for TX */
 	u8  saved_conf1;			/* saved FEC0 reg */
-	unsigned int tx_sample;			/* current sample for TX */
-	bool tx_sample_pulse;			/* current sample is pulse */
 
 	/* TX buffer */
-	unsigned *tx_buffer;			/* input samples buffer*/
-	int tx_pos;				/* position in that buffer */
-	int tx_len;				/* current len of tx buffer */
-	int tx_done;				/* done transmitting */
-						/* one more sample pending*/
+	struct rc_event tx_ev;			/* current sample for TX */
+	bool tx_done;				/* done transmitting */
 	struct completion tx_complete;		/* TX completion */
 	struct timer_list tx_sim_timer;
 
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index ee60e17..8a4baf5 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -347,29 +347,46 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
 	return 0;
 }
 
-static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+static int iguanair_tx(struct rc_dev *dev, unsigned count)
 {
 	struct iguanair *ir = dev->priv;
-	uint8_t space;
-	unsigned i, size, periods, bytes;
+	struct rc_event ev;
+	unsigned size = 0;
 	int rc;
 
 	mutex_lock(&ir->lock);
 
-	/* convert from us to carrier periods */
-	for (i = space = size = 0; i < count; i++) {
-		periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
-		bytes = DIV_ROUND_UP(periods, 127);
+	while (kfifo_peek(&dev->txfifo, &ev)) {
+		unsigned p, bytes;
+
+		if ((ev.type != RC_IR) ||
+		    (ev.code != RC_IR_SPACE && ev.code != RC_IR_PULSE) ||
+		    (ev.val == 0))
+			continue;
+
+		/* convert from ns to carrier periods */
+		p = DIV_ROUND_CLOSEST(ev.val * ir->carrier, 1000000000);
+		bytes = DIV_ROUND_UP(p, 127);
 		if (size + bytes > ir->bufsize) {
-			rc = -EINVAL;
-			goto out;
+			size = 0;
+			break;
 		}
-		while (periods) {
-			unsigned p = min(periods, 127u);
-			ir->packet->payload[size++] = p | space;
-			periods -= p;
+	
+		while (p > 0) {
+			u8 byte = min_t(u8, p, 127);
+			p -= byte;
+			if (ev.code == RC_IR_SPACE)
+				byte |= 0x80;
+			ir->packet->payload[size++] = byte;
 		}
-		space ^= 0x80;
+
+		kfifo_skip(&dev->txfifo);
+	}
+
+	if (size == 0) {
+		rc = -EINVAL;
+		kfifo_reset_out(&dev->txfifo);
+		goto out;
 	}
 
 	ir->packet->header.start = 0;
@@ -386,8 +403,10 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 
 out:
 	mutex_unlock(&ir->lock);
-
-	return rc ? rc : count;
+	if (rc == 0)
+		return count;
+	else
+		return rc;
 }
 
 static int iguanair_open(struct rc_dev *rdev)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index ed2c8a1..7d58eea 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -102,75 +102,81 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 				   size_t n, loff_t *ppos)
 {
-	struct lirc_codec *lirc;
+	struct lirc_codec *lirc = lirc_get_pdata(file);
 	struct rc_dev *dev;
-	unsigned int *txbuf; /* buffer with values to transmit */
-	ssize_t ret = -EINVAL;
-	size_t count;
-	ktime_t start;
-	s64 towait;
-	unsigned int duration = 0; /* signal duration in us */
-	int i;
-
-	start = ktime_get();
+	ktime_t start = ktime_get();
+	ssize_t ret;
+	unsigned duration = 0; /* signal duration in us */
+	unsigned tostore, stored;
 
-	lirc = lirc_get_pdata(file);
-	if (!lirc)
+	if (!lirc || !lirc->dev)
 		return -EFAULT;
 
-	if (n < sizeof(unsigned) || n % sizeof(unsigned))
-		return -EINVAL;
+	dev = lirc->dev;
+	if (!dev->tx_ir)
+		return -ENOSYS;
 
-	count = n / sizeof(unsigned);
-	if (count > LIRCBUF_SIZE || count % 2 == 0)
+	/*
+	 * LIRC TX API:
+	 * Userspace writes an odd number of u32 samples which
+	 * represent a sequence of pulse-space-pulse...etc values
+	 */
+	if (n % sizeof(u32) != 0)
 		return -EINVAL;
 
-	txbuf = memdup_user(buf, n);
-	if (IS_ERR(txbuf))
-		return PTR_ERR(txbuf);
+	tostore = n / sizeof(u32);
+	if (tostore % 2 == 0)
+		return -EINVAL;
 
-	dev = lirc->dev;
-	if (!dev) {
-		ret = -EFAULT;
-		goto out;
-	}
+	mutex_lock(&dev->txmutex);
 
-	if (!dev->tx_ir) {
-		ret = -ENOSYS;
-		goto out;
-	}
+	for (stored = 0; stored < tostore; stored++) {
+		bool pulse = true;
+		u32 val;
+		struct rc_event ev;
 
-	for (i = 0; i < count; i++) {
-		if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) {
-			ret = -EINVAL;
-			goto out;
+		if (copy_from_user(&val, buf, sizeof(u32)) ||
+		    val == 0 ||
+		    val > IR_MAX_DURATION / 1000 - duration) {
+			kfifo_reset_out(&dev->txfifo);
+			mutex_unlock(&dev->txmutex);
+			return -EFAULT;
 		}
 
-		duration += txbuf[i];
-	}
-
-	ret = dev->tx_ir(dev, txbuf, count);
-	if (ret < 0)
-		goto out;
+		ev.type = RC_IR;
+		ev.code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
+		ev.val = val;
+		if (kfifo_in(&dev->txfifo, &ev, 1) != 1)
+			break;
 
-	for (duration = i = 0; i < ret; i++)
-		duration += txbuf[i];
+		pulse = !pulse;
+		duration += val;
+		buf += sizeof(u32);
+	}
 
-	ret *= sizeof(unsigned int);
+	ret = dev->tx_ir(dev, stored);
+	mutex_unlock(&dev->txmutex);
 
 	/*
 	 * The lircd gap calculation expects the write function to
 	 * wait for the actual IR signal to be transmitted before
 	 * returning.
+	 *
+	 * Only do this if the driver didn't have to truncate the
+	 * TX data.
 	 */
-	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
-	if (towait > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(usecs_to_jiffies(towait));
+	if (ret == stored) {
+		s64 towait = ktime_us_delta(ktime_add_us(start, duration),
+					    ktime_get());
+		if (towait > 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(usecs_to_jiffies(towait));
+		}
 	}
 
-out:
-	kfree(txbuf);
+	if (ret > 0)
+		ret *= sizeof(u32);
+
 	return ret;
 }
 
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 7eb347a..af23f4d 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -211,6 +211,47 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
 EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
 
 /**
+ * ir_raw_get_tx_event() - fetches the next ir tx event from the tx fifo
+ * @dev:	the struct rc_dev device descriptor
+ * @ev:		the struct rc_event to fill in with the next tx event
+ *
+ * Fetches the next ir tx event from the kfifo while taking care of
+ * details such as merging consecutive events of the same type.
+ *
+ * Return: the number of events consumed from the kfifo, or a negative error
+ */
+int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev)
+{
+	struct rc_event tmp;
+	unsigned consumed = 1;
+
+	if (!kfifo_get(&dev->txfifo, ev))
+		return 0;
+
+	/* Sanity check */
+	if ((ev->type != RC_IR) ||
+	    (ev->code != RC_IR_SPACE && ev->code != RC_IR_PULSE) ||
+	    (ev->val == 0))
+		return -EINVAL;
+
+	/* Merge consecutive entries of same type */
+	while (kfifo_peek(&dev->txfifo, &tmp)) {
+		if (tmp.type != ev->type || tmp.code != ev->code)
+			break;
+		if (tmp.val == 0)
+			return -EINVAL;
+		/* No check for overflow, which is ok */
+		ev->val += tmp.val;
+		kfifo_skip(&dev->txfifo);
+		consumed++;
+	}
+
+	/* Done */
+	return consumed;
+}
+EXPORT_SYMBOL_GPL(ir_raw_get_tx_event);
+
+/**
  * ir_raw_event_handle() - schedules the decoding of stored ir data
  * @dev:	the struct rc_dev device descriptor
  *
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 32fd5f4..0d404a2 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -382,16 +382,15 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)
 /* transmit out IR pulses; what you get here is a batch of alternating
  * pulse/space/pulse/space lengths that we should write out completely through
  * the FIFO, blocking on a full FIFO */
-static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
+static int ite_tx_ir(struct rc_dev *rcdev, unsigned count)
 {
 	unsigned long flags;
 	struct ite_dev *dev = rcdev->priv;
-	bool is_pulse = false;
 	int remaining_us, fifo_avail, fifo_remaining, last_idx = 0;
-	int max_rle_us, next_rle_us;
-	int ret = n;
+	int max_rle_us, next_rle_us, tmp;
 	u8 last_sent[ITE_TX_FIFO_LEN];
 	u8 val;
+	struct rc_event ev;
 
 	ite_dbg("%s called", __func__);
 
@@ -421,22 +420,21 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 	fifo_avail =
 	    ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev);
 
-	while (n > 0 && dev->in_use) {
+	while ((tmp = ir_raw_get_tx_event(rcdev, &ev)) != 0 && dev->in_use) {
+		if (tmp < 0)
+			continue;
+
 		/* transmit the next sample */
-		is_pulse = !is_pulse;
-		remaining_us = *(txbuf++);
-		n--;
+		remaining_us = ev.val;
 
-		ite_dbg("%s: %ld",
-				      ((is_pulse) ? "pulse" : "space"),
-				      (long int)
-				      remaining_us);
+		ite_dbg("%s: %i",
+			(ev.code == RC_IR_PULSE ? "pulse" : "space"),
+			remaining_us);
 
 		/* repeat while the pulse is non-zero length */
 		while (remaining_us > 0 && dev->in_use) {
 			if (remaining_us > max_rle_us)
 				next_rle_us = max_rle_us;
-
 			else
 				next_rle_us = remaining_us;
 
@@ -453,9 +451,8 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 			val = (val - 1) & ITE_TX_RLE_MASK;
 
 			/* take into account pulse/space prefix */
-			if (is_pulse)
+			if (ev.code == RC_IR_PULSE)
 				val |= ITE_TX_PULSE;
-
 			else
 				val |= ITE_TX_SPACE;
 
@@ -469,8 +466,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 			/* if it's still full */
 			if (fifo_avail <= 0) {
 				/* enable the tx interrupt */
-				dev->params.
-				enable_tx_interrupt(dev);
+				dev->params.enable_tx_interrupt(dev);
 
 				/* drop the spinlock */
 				spin_unlock_irqrestore(&dev->lock, flags);
@@ -482,8 +478,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 				spin_lock_irqsave(&dev->lock, flags);
 
 				/* disable the tx interrupt again. */
-				dev->params.
-				disable_tx_interrupt(dev);
+				dev->params.disable_tx_interrupt(dev);
 			}
 
 			/* now send the byte through the FIFO */
@@ -529,7 +524,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	return ret;
+	return count;
 }
 
 /* idle the receiver if needed */
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index a347736..e0c8552 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -797,12 +797,13 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
 }
 
 /* Send data out the IR blaster port(s) */
-static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+static int mceusb_tx_ir(struct rc_dev *dev, unsigned count)
 {
 	struct mceusb_dev *ir = dev->priv;
-	int i, length, ret = 0;
+	int tmp, ret = 0;
 	int cmdcount = 0;
 	unsigned char cmdbuf[MCE_CMDBUF_SIZE];
+	struct rc_event ev;
 
 	/* MCE tx init header */
 	cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
@@ -814,8 +815,9 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	cmdcount = 0;
 
 	/* Generate mce packet data */
-	for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
-		txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
+	while ((tmp = ir_raw_get_tx_event(dev, &ev)) > 0) {
+		ret += tmp;
+		ev.val /= MCE_TIME_UNIT;
 
 		do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
 
@@ -824,30 +826,34 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 			    (cmdcount % MCE_CODE_LENGTH) == 0)
 				cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
 
-			/* Insert mce packet data */
-			if (cmdcount < MCE_CMDBUF_SIZE)
-				cmdbuf[cmdcount++] =
-					(txbuf[i] < MCE_PULSE_BIT ?
-					 txbuf[i] : MCE_MAX_PULSE_LENGTH) |
-					 (i & 1 ? 0x00 : MCE_PULSE_BIT);
-			else {
-				ret = -EINVAL;
+			if (cmdcount >= MCE_CMDBUF_SIZE) {
+				ret = -EMSGSIZE;
 				goto out;
 			}
 
-		} while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
-			 (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
+			/* Insert mce packet data */
+			cmdbuf[cmdcount++] =
+				min_t(u32, ev.val, MCE_MAX_PULSE_LENGTH) |
+				(ev.code == RC_IR_PULSE ? MCE_PULSE_BIT : 0x0);
+
+		} while ((ev.val > MCE_MAX_PULSE_LENGTH) &&
+			 (ev.val -= MCE_MAX_PULSE_LENGTH));
+	}
+
+	if (tmp < 0) {
+		ret = tmp;
+		goto out;
 	}
 
 	/* Check if we have room for the empty packet at the end */
 	if (cmdcount >= MCE_CMDBUF_SIZE) {
-		ret = -EINVAL;
+		ret = -EMSGSIZE;
 		goto out;
 	}
 
 	/* Fix packet length in last header */
-	length = cmdcount % MCE_CODE_LENGTH;
-	cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length;
+	tmp = cmdcount % MCE_CODE_LENGTH;
+	cmdbuf[cmdcount - tmp] -= MCE_CODE_LENGTH - tmp;
 
 	/* All mce commands end with an empty packet (0x80) */
 	cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
@@ -856,7 +862,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	mce_async_out(ir, cmdbuf, cmdcount);
 
 out:
-	return ret ? ret : count;
+	kfifo_reset_out(&dev->txfifo);
+	return ret;
 }
 
 /* Sets active IR outputs -- mce devices typically have two */
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 8c6008f..160d685 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -545,21 +545,16 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
  * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
  * set TXFCONT as 0xff, until buf_count less than 0xff.
  */
-static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
+static int nvt_tx_ir(struct rc_dev *dev, unsigned count)
 {
 	struct nvt_dev *nvt = dev->priv;
 	unsigned long flags;
 	unsigned int i;
 	u8 iren;
-	int ret;
 
 	spin_lock_irqsave(&nvt->tx.lock, flags);
 
-	ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n);
-	nvt->tx.buf_count = (ret * sizeof(unsigned));
-
-	memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
-
+	nvt->tx.buf_count = 0;
 	nvt->tx.cur_buf_num = 0;
 
 	/* save currently enabled interrupts */
@@ -588,7 +583,7 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
 	/* restore enabled interrupts to prior state */
 	nvt_cir_reg_write(nvt, iren, CIR_IREN);
 
-	return ret;
+	return count;
 }
 
 /* dump contents of the last rx buffer we got from the hw rx fifo */
@@ -821,27 +816,43 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
 	if (status & CIR_IRSTS_TE)
 		nvt_clear_tx_fifo(nvt);
 
+	/*
+	 * FIXME: The TX code is quite unlikely to do the right thing as it
+	 *	  merely sends unsigned ints with host-specific endianness to
+	 *	  the hardware without any hints of pulse/space, etc.
+	 */
 	if (status & CIR_IRSTS_TTR) {
-		unsigned int pos, count;
-		u8 tmp;
-
 		spin_lock_irqsave(&nvt->tx.lock, flags);
 
-		pos = nvt->tx.cur_buf_num;
-		count = nvt->tx.buf_count;
-
-		/* Write data into the hardware tx fifo while pos < count */
-		if (pos < count) {
-			nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
-			nvt->tx.cur_buf_num++;
-		/* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
-		} else {
-			tmp = nvt_cir_reg_read(nvt, CIR_IREN);
-			nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+		/* Any data in tx buffer? */
+		while (nvt->tx.cur_buf_num >= nvt->tx.buf_count) {
+			struct rc_event ev;
+			int tmp;
+
+			tmp = ir_raw_get_tx_event(nvt->rdev, &ev);
+			if (tmp < 0)
+				continue;
+			else if (tmp == 0) {
+				/* No more data, disable TTR interrupt */
+				u8 tmp = nvt_cir_reg_read(nvt, CIR_IREN);
+				nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+				break;
+			} else {
+				unsigned sample = ev.val / 1000;
+				nvt->tx.buf_count = sizeof(sample);
+				nvt->tx.cur_buf_num = 0;
+				memcpy(nvt->tx.buf, &sample, sizeof(sample));
+			}
 		}
 
-		spin_unlock_irqrestore(&nvt->tx.lock, flags);
+		/* Write data into the hardware tx fifo if we have any */
+		if (nvt->tx.cur_buf_num < nvt->tx.buf_count) {
+			nvt_cir_reg_write(nvt,
+					  nvt->tx.buf[nvt->tx.cur_buf_num++],
+					  CIR_STXFIFO);
+		}
 
+		spin_unlock_irqrestore(&nvt->tx.lock, flags);
 	}
 
 	if (status & CIR_IRSTS_TFU) {
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index e1cf23c..5c69a2e 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -54,15 +54,8 @@ static int debug;
 			KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
 
 
-/*
- * Original lirc driver said min value of 76, and recommended value of 256
- * for the buffer length, but then used 2048. Never mind that the size of the
- * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
- * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
- * and I don't have TX-capable hardware to test/debug on...
- */
-#define TX_BUF_LEN 256
 #define RX_BUF_LEN 32
+#define TX_BUF_LEN sizeof(unsigned)
 
 struct nvt_dev {
 	struct pnp_dev *pdev;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 63dace8..bc67d2f 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -101,17 +101,19 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
 	return 0;
 }
 
-static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+static int loop_tx_ir(struct rc_dev *dev, unsigned count)
 {
 	struct loopback_dev *lodev = dev->priv;
 	u32 rxmask;
-	unsigned i;
+	struct rc_event ev;
 	DEFINE_IR_RAW_EVENT(rawir);
+	int tmp;
 
 	if (lodev->txcarrier < lodev->rxcarriermin ||
 	    lodev->txcarrier > lodev->rxcarriermax) {
 		dprintk("ignoring tx, carrier out of range\n");
-		goto out;
+		kfifo_reset_out(&dev->txfifo);
+		return 0;
 	}
 
 	if (lodev->learning)
@@ -121,24 +123,27 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 
 	if (!(rxmask & lodev->txmask)) {
 		dprintk("ignoring tx, rx mask mismatch\n");
-		goto out;
+		kfifo_reset_out(&dev->txfifo);
+		return count;
 	}
 
-	for (i = 0; i < count; i++) {
-		rawir.pulse = i % 2 ? false : true;
-		rawir.duration = txbuf[i] * 1000;
-		if (rawir.duration)
-			ir_raw_event_store_with_filter(dev, &rawir);
+	while ((tmp = ir_raw_get_tx_event(dev, &ev)) != 0) {
+		if (tmp < 0)
+			continue;
+		init_ir_raw_event(&rawir);
+		rawir.pulse = (ev.code == RC_IR_PULSE);
+		rawir.duration = ev.val;
+		ir_raw_event_store_with_filter(dev, &rawir);
 	}
 
 	/* Fake a silence long enough to cause us to go idle */
+	init_ir_raw_event(&rawir);
 	rawir.pulse = false;
 	rawir.duration = dev->timeout;
 	ir_raw_event_store_with_filter(dev, &rawir);
 
 	ir_raw_event_handle(dev);
 
-out:
 	return count;
 }
 
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 5ce0cdb..43789b4 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1591,6 +1591,7 @@ static void rc_dev_release(struct device *device)
 	if (dev->input_dev)
 		input_free_device(dev->input_dev);
 
+	kfifo_free(&dev->txfifo);
 	kfree(dev);
 	module_put(THIS_MODULE);
 }
@@ -1696,6 +1697,7 @@ struct rc_dev *rc_allocate_device(void)
 
 	INIT_LIST_HEAD(&dev->client_list);
 	spin_lock_init(&dev->client_lock);
+	mutex_init(&dev->txmutex);
 	init_waitqueue_head(&dev->rxwait);
 	spin_lock_init(&dev->rc_map.lock);
 	spin_lock_init(&dev->keylock);
@@ -1763,6 +1765,12 @@ int rc_register_device(struct rc_dev *dev)
 	dev_set_name(&dev->dev, "rc%u", minor);
 	dev_set_drvdata(&dev->dev, dev);
 
+	if (dev->tx_ir) {
+		rc = kfifo_alloc(&dev->txfifo, RC_TX_KFIFO_SIZE, GFP_KERNEL);
+		if (rc)
+			goto out_minor;
+	}
+
 	dev->dev.groups = dev->sysfs_groups;
 	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
 	if (dev->s_filter)
@@ -1874,6 +1882,7 @@ out_cdev:
 	cdev_del(&dev->cdev);
 out_unlock:
 	mutex_unlock(&dev->lock);
+out_minor:
 	ida_simple_remove(&rc_ida, minor);
 	return rc;
 }
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 3f45e1a..3a931a5 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -752,90 +752,105 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
 	return carrier;
 }
 
-static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
-				unsigned count)
+static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned count)
 {
 	struct redrat3_dev *rr3 = rcdev->priv;
 	struct device *dev = rr3->dev;
 	struct redrat3_irdata *irdata = NULL;
-	int ret, ret_len;
-	int lencheck, cur_sample_len, pipe;
-	int *sample_lens = NULL;
-	u8 curlencheck = 0;
-	unsigned i, sendbuf_len;
+	int ret = 0;
+	int pipe, tmp;
+	unsigned sendbuf_len;
+	struct rc_event ev;
+	unsigned events_consumed = 0;
+	unsigned short sample_lens[RR3_DRIVER_MAXLENS];
+	unsigned n_sample_lens = 0;
+	unsigned n_sigs = 0;
+	bool send_pulse = true;
 
 	rr3_ftr(dev, "Entering %s\n", __func__);
 
 	if (rr3->transmitting) {
 		dev_warn(dev, "%s: transmitter already in use\n", __func__);
-		return -EAGAIN;
+		ret = -EAGAIN;
+		goto out;
 	}
 
-	if (count > RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN)
-		return -EINVAL;
-
 	/* rr3 will disable rc detector on transmit */
 	rr3->transmitting = true;
 
-	sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
-	if (!sample_lens) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	irdata = kzalloc(sizeof(*irdata), GFP_KERNEL);
 	if (!irdata) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	for (i = 0; i < count; i++) {
-		cur_sample_len = redrat3_us_to_len(txbuf[i]);
-		if (cur_sample_len > 0xffff) {
-			dev_warn(dev, "transmit period of %uus truncated to %uus\n",
-					txbuf[i], redrat3_len_to_us(0xffff));
-			cur_sample_len = 0xffff;
+	while ((tmp = ir_raw_get_tx_event(rcdev, &ev)) > 0) {
+		unsigned sample_len;
+		unsigned i;
+
+		/* Sanity check */
+		if ((ev.code == RC_IR_SPACE && send_pulse) ||
+		    (ev.code == RC_IR_PULSE && !send_pulse)) {
+			ret = -EINVAL;
+			goto out;
 		}
-		for (lencheck = 0; lencheck < curlencheck; lencheck++) {
-			if (sample_lens[lencheck] == cur_sample_len)
+
+		events_consumed += tmp;
+		send_pulse = !send_pulse;
+		sample_len = redrat3_us_to_len(ev.val);
+
+		if (sample_len > 0xffff) {
+			dev_warn(dev, "transmitting %uus not supported\n",
+				 redrat3_len_to_us(sample_len));
+			ret = -EMSGSIZE;
+			goto out;
+		}
+
+		/* See if a sample of this length is already in the array... */
+		for (i = 0; i < n_sample_lens; i++) {
+			if (sample_lens[i] == sample_len)
 				break;
 		}
-		if (lencheck == curlencheck) {
-			rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
-				i, txbuf[i], curlencheck, cur_sample_len);
-			if (curlencheck < RR3_DRIVER_MAXLENS) {
-				/* now convert the value to a proper
-				 * rr3 value.. */
-				sample_lens[curlencheck] = cur_sample_len;
-				put_unaligned_be16(cur_sample_len,
-						&irdata->lens[curlencheck]);
-				curlencheck++;
-			} else {
-				ret = -EINVAL;
+
+		if (i == n_sample_lens) {
+			/* ...nope, add it */
+			rr3_dbg(dev, "pos %u, enc %u\n", i, sample_len);
+
+			if (i >= RR3_DRIVER_MAXLENS) {
+				ret = -EMSGSIZE;
 				goto out;
 			}
+
+			sample_lens[i] = sample_len;
+			put_unaligned_be16(sample_len, &irdata->lens[i]);
+			n_sample_lens++;
+		}
+
+		if (n_sigs >= RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN) {
+			ret = -EMSGSIZE;
+			goto out;
 		}
-		irdata->sigdata[i] = lencheck;
+
+		irdata->sigdata[n_sigs++] = i;
 	}
 
-	irdata->sigdata[count] = RR3_END_OF_SIGNAL;
-	irdata->sigdata[count + 1] = RR3_END_OF_SIGNAL;
+	irdata->sigdata[n_sigs++] = RR3_END_OF_SIGNAL;
+	irdata->sigdata[n_sigs++] = RR3_END_OF_SIGNAL;
+	sendbuf_len = offsetof(struct redrat3_irdata, sigdata[n_sigs]);
 
-	sendbuf_len = offsetof(struct redrat3_irdata,
-					sigdata[count + RR3_TX_TRAILER_LEN]);
 	/* fill in our packet header */
 	irdata->header.length = cpu_to_be16(sendbuf_len -
-						sizeof(struct redrat3_header));
+					    sizeof(struct redrat3_header));
 	irdata->header.transfer_type = cpu_to_be16(RR3_MOD_SIGNAL_OUT);
 	irdata->pause = cpu_to_be32(redrat3_len_to_us(100));
 	irdata->mod_freq_count = cpu_to_be16(mod_freq_to_val(rr3->carrier));
-	irdata->no_lengths = curlencheck;
-	irdata->sig_size = cpu_to_be16(count + RR3_TX_TRAILER_LEN);
+	irdata->no_lengths = n_sample_lens;
+	irdata->sig_size = cpu_to_be16(n_sigs);
 
 	pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
 	ret = usb_bulk_msg(rr3->udev, pipe, irdata,
-			    sendbuf_len, &ret_len, 10 * HZ);
-	rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret);
+			   sendbuf_len, &tmp, 10 * HZ);
+	rr3_dbg(dev, "sent %d bytes, (ret %d)\n", tmp, ret);
 
 	/* now tell the hardware to transmit what we sent it */
 	pipe = usb_rcvctrlpipe(rr3->udev, 0);
@@ -846,11 +861,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
 	if (ret < 0)
 		dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
 	else
-		ret = count;
+		ret = events_consumed;
 
 out:
-	kfree(sample_lens);
 	kfree(irdata);
+	kfifo_reset_out(&rcdev->txfifo);
 
 	rr3->transmitting = false;
 	/* rr3 re-enables rc detector because it was enabled before */
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index d839f73..8871109 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -218,9 +218,8 @@ struct wbcir_data {
 
 	/* TX state */
 	enum wbcir_txstate txstate;
-	u32 txlen;
-	u32 txoff;
-	u32 *txbuf;
+	struct led_trigger *txtrigger;
+	struct rc_event txev;
 	u8 txmask;
 	u32 txcarrier;
 };
@@ -413,9 +412,6 @@ wbcir_irq_tx(struct wbcir_data *data)
 	u8 bytes[16];
 	u8 byte;
 
-	if (!data->txbuf)
-		return;
-
 	switch (data->txstate) {
 	case WBCIR_TXSTATE_INACTIVE:
 		/* TX FIFO empty */
@@ -437,31 +433,43 @@ wbcir_irq_tx(struct wbcir_data *data)
 	 * Y = space (1) or pulse (0)
 	 * X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us)
 	 */
-	for (used = 0; used < space && data->txoff != data->txlen; used++) {
-		if (data->txbuf[data->txoff] == 0) {
-			data->txoff++;
-			continue;
+	for (used = 0; used < space; used++) {
+		while (data->txev.val == 0) {
+			int tmp;
+
+			tmp = ir_raw_get_tx_event(data->dev, &data->txev);
+			if (tmp < 1) {
+				data->txev.val = 0;
+				if (tmp < 0)
+					continue;
+				else
+					break;
+			}
+
+			/* Convert duration to multiples of 10us */
+			data->txev.val = DIV_ROUND_CLOSEST(data->txev.val,
+							   10 * 1000);
 		}
-		byte = min((u32)0x80, data->txbuf[data->txoff]);
-		data->txbuf[data->txoff] -= byte;
+
+		if (data->txev.val == 0)
+			break;
+
+		byte = min_t(u32, 0x80, data->txev.val);
+		data->txev.val -= byte;
 		byte--;
-		byte |= (data->txoff % 2 ? 0x80 : 0x00); /* pulse/space */
+		byte |= (data->txev.code == RC_IR_PULSE ? 0x80 : 0x00);
 		bytes[used] = byte;
 	}
 
-	while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen)
-		data->txoff++;
-
 	if (used == 0) {
 		/* Finished */
 		if (data->txstate == WBCIR_TXSTATE_ERROR)
 			/* Clear TX underrun bit */
 			outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR);
 		wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
-		kfree(data->txbuf);
-		data->txbuf = NULL;
 		data->txstate = WBCIR_TXSTATE_INACTIVE;
-	} else if (data->txoff == data->txlen) {
+		data->txev.val = 0;
+	} else if (data->txev.val == 0 && kfifo_is_empty(&data->dev->txfifo)) {
 		/* At the end of transmission, tell the hw before last byte */
 		outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
 		outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR);
@@ -649,37 +657,17 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
 }
 
 static int
-wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count)
+wbcir_tx(struct rc_dev *dev, unsigned count)
 {
 	struct wbcir_data *data = dev->priv;
-	unsigned *buf;
-	unsigned i;
 	unsigned long flags;
 
-	buf = kmalloc(count * sizeof(*b), GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* Convert values to multiples of 10us */
-	for (i = 0; i < count; i++)
-		buf[i] = DIV_ROUND_CLOSEST(b[i], 10);
-
-	/* Not sure if this is possible, but better safe than sorry */
 	spin_lock_irqsave(&data->spinlock, flags);
-	if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
-		spin_unlock_irqrestore(&data->spinlock, flags);
-		kfree(buf);
-		return -EBUSY;
-	}
-
-	/* Fill the TX fifo once, the irq handler will do the rest */
-	data->txbuf = buf;
-	data->txlen = count;
-	data->txoff = 0;
-	wbcir_irq_tx(data);
-
-	/* We're done */
+	if (data->txstate == WBCIR_TXSTATE_INACTIVE)
+		/* Kick the tx irq handler once, it will do the rest */
+		wbcir_irq_tx(data);
 	spin_unlock_irqrestore(&data->spinlock, flags);
+
 	return count;
 }
 
@@ -990,9 +978,8 @@ wbcir_init_hw(struct wbcir_data *data)
 
 	/* Clear TX state */
 	if (data->txstate == WBCIR_TXSTATE_ACTIVE) {
-		kfree(data->txbuf);
-		data->txbuf = NULL;
 		data->txstate = WBCIR_TXSTATE_INACTIVE;
+		data->txev.val = 0;
 	}
 
 	/* Enable interrupts */
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index d31ccdd..ca22cf7 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -90,6 +90,8 @@ struct rc_event {
 	__u32 val;
 } __packed;
 
+#define RC_TX_KFIFO_SIZE	1024
+
 /**
  * struct rc_scancode_filter - Filter scan codes.
  * @data:	Scancode data to match.
@@ -129,6 +131,8 @@ enum rc_filter_type {
  * @dead: used to determine if the device is still alive
  * @client_list: list of clients (processes which have opened the rc chardev)
  * @client_lock: protects client_list
+ * @txfifo: fifo with tx data to transmit
+ * @txmutex: protects txfifo and serializes calls to @tx_ir
  * @rxwait: waitqueue for processes waiting for data to read
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
@@ -193,6 +197,8 @@ struct rc_dev {
 	bool				dead;
 	struct list_head		client_list;
 	spinlock_t			client_lock;
+	DECLARE_KFIFO_PTR(txfifo, struct rc_event);
+	struct mutex			txmutex;
 	wait_queue_head_t		rxwait;
 	struct ir_raw_event_ctrl	*raw;
 	struct input_dev		*input_dev;
@@ -228,7 +234,7 @@ struct rc_dev {
 	int				(*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
 	int				(*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
 	int				(*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
-	int				(*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
+	int				(*tx_ir)(struct rc_dev *dev, unsigned count);
 	void				(*s_idle)(struct rc_dev *dev, bool enable);
 	int				(*s_learning_mode)(struct rc_dev *dev, int enable);
 	int				(*s_carrier_report) (struct rc_dev *dev, int enable);
@@ -315,6 +321,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(struct rc_dev *dev,
 				struct ir_raw_event *ev);
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
+int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {


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

* [PATCH 20/49] rc-core: allow chardev to be written
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (18 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 19/49] rc-core: use a kfifo for TX data David Härdeman
@ 2014-04-03 23:32 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 21/49] rc-core: add ioctl support to the rc chardev David Härdeman
                   ` (30 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:32 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Add write functionality to the rc chardev (for use in transmitting remote
control commands on capable hardware).

The data format of the TX data is probably going to have to be dependent
on the rc_driver_type.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |   71 ++++++++++++++++++++++++++++++++++++++++++++
 include/media/rc-core.h    |    2 +
 2 files changed, 73 insertions(+)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 43789b4..d7b24a1 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1531,6 +1531,72 @@ static ssize_t rc_read(struct file *file, char __user *buffer,
 }
 
 /**
+ * rc_write() - allows userspace to write data to transmit
+ * @file:	the &struct file corresponding to the previous open()
+ * @buffer:	the userspace buffer to read data from
+ * @count:	the number of bytes to read
+ * @ppos:	the file offset
+ * @return:	the number of bytes written, or a negative error code
+ *
+ * This function (which implements write in &struct file_operations)
+ * allows userspace to transmit data using a suitable rc device
+ */
+static ssize_t rc_write(struct file *file, const char __user *buffer,
+			size_t count, loff_t *ppos)
+{
+	struct rc_client *client = file->private_data;
+	struct rc_dev *dev = client->dev;
+	ssize_t ret;
+	struct rc_event ev;
+
+	if (!dev->tx_ir)
+		return -ENOSYS;
+
+	if (count < sizeof(ev) || count % sizeof(ev))
+		return -EINVAL;
+
+again:
+	if (kfifo_is_full(&dev->txfifo) && !dev->dead &&
+	    (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(dev->txwait,
+				       !kfifo_is_full(&dev->txfifo) ||
+				       dev->dead);
+	if (ret)
+		return ret;
+
+	if (dev->dead)
+		return -ENODEV;
+
+	mutex_lock(&dev->txmutex);
+	for (ret = 0; ret + sizeof(ev) <= count; ret += sizeof(ev)) {
+		if (copy_from_user(&ev, buffer + ret, sizeof(ev))) {
+			kfifo_reset_out(&dev->txfifo);
+			mutex_unlock(&dev->txmutex);
+			return -EFAULT;
+		}
+
+		if (kfifo_in(&dev->txfifo, &ev, 1) != 1)
+			break;
+	}
+
+	if (ret == 0) {
+		mutex_unlock(&dev->txmutex);
+		goto again;
+	}
+
+	ret = dev->tx_ir(dev, ret / sizeof(ev));
+	mutex_unlock(&dev->txmutex);
+	wake_up_interruptible(&dev->txwait);
+
+	if (ret > 0)
+		ret *= sizeof(ev);
+
+	return ret;
+}
+
+/**
  * rc_poll() - allows userspace to poll rc device files
  * @file:	the &struct file corresponding to the previous open()
  * @wait:	used to keep track of processes waiting for poll events
@@ -1544,8 +1610,10 @@ static unsigned int rc_poll(struct file *file, poll_table *wait)
 	struct rc_client *client = file->private_data;
 	struct rc_dev *dev = client->dev;
 
+	poll_wait(file, &dev->txwait, wait);
 	poll_wait(file, &dev->rxwait, wait);
 	return ((kfifo_is_empty(&client->rxfifo) ? 0 : (POLLIN | POLLRDNORM)) |
+		(kfifo_is_full(&dev->txfifo) ? 0 : (POLLOUT | POLLWRNORM)) |
 		(!dev->dead ? 0 : (POLLHUP | POLLERR)));
 }
 
@@ -1572,6 +1640,7 @@ static const struct file_operations rc_fops = {
 	.open		= rc_dev_open,
 	.release	= rc_release,
 	.read		= rc_read,
+	.write		= rc_write,
 	.poll		= rc_poll,
 	.fasync		= rc_fasync,
 	.llseek		= no_llseek,
@@ -1698,6 +1767,7 @@ struct rc_dev *rc_allocate_device(void)
 	INIT_LIST_HEAD(&dev->client_list);
 	spin_lock_init(&dev->client_lock);
 	mutex_init(&dev->txmutex);
+	init_waitqueue_head(&dev->txwait);
 	init_waitqueue_head(&dev->rxwait);
 	spin_lock_init(&dev->rc_map.lock);
 	spin_lock_init(&dev->keylock);
@@ -1904,6 +1974,7 @@ void rc_unregister_device(struct rc_dev *dev)
 		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
 	spin_unlock(&dev->client_lock);
 	wake_up_interruptible_all(&dev->rxwait);
+	wake_up_interruptible_all(&dev->txwait);
 
 	cdev_del(&dev->cdev);
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index ca22cf7..39f3794 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -133,6 +133,7 @@ enum rc_filter_type {
  * @client_lock: protects client_list
  * @txfifo: fifo with tx data to transmit
  * @txmutex: protects txfifo and serializes calls to @tx_ir
+ * @txwait: waitqueue for processes waiting to write data to the txfifo
  * @rxwait: waitqueue for processes waiting for data to read
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
@@ -199,6 +200,7 @@ struct rc_dev {
 	spinlock_t			client_lock;
 	DECLARE_KFIFO_PTR(txfifo, struct rc_event);
 	struct mutex			txmutex;
+	wait_queue_head_t		txwait;
 	wait_queue_head_t		rxwait;
 	struct ir_raw_event_ctrl	*raw;
 	struct input_dev		*input_dev;


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

* [PATCH 21/49] rc-core: add ioctl support to the rc chardev
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (19 preceding siblings ...)
  2014-04-03 23:32 ` [PATCH 20/49] rc-core: allow chardev to be written David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 22/49] rc-core: add an ioctl for getting IR RX settings David Härdeman
                   ` (29 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Add basic support for ioctl operations on the rc chardev.

Only two ioctl's are defined for now: one to get the rc-core
version and one to get the driver type of a given chardev.

Userspace is expected to make sure that both match the expected
values before proceeding with any ioctl/read/write ops.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 Documentation/ioctl/ioctl-number.txt |    1 +
 drivers/media/rc/rc-main.c           |   65 ++++++++++++++++++++++++++++++++++
 include/media/rc-core.h              |   19 ++++++++++
 3 files changed, 85 insertions(+)

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index d7e43fa..2868bc8 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -270,6 +270,7 @@ Code  Seq#(hex)	Include File		Comments
 'v'	00-0F	linux/sonypi.h		conflict!
 'v'	C0-FF	linux/meye.h		conflict!
 'w'	all				CERN SCI driver
+'x'	all	media/rc-core.h		Remote Control drivers
 'y'	00-1F				packet based user level communications
 					<mailto:zapman@interlan.net>
 'z'	00-3F				CAN bus card	conflict!
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index d7b24a1..477ad49 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1635,6 +1635,67 @@ static int rc_fasync(int fd, struct file *file, int on)
 	return fasync_helper(fd, file, on, &client->fasync);
 }
 
+/**
+ * rc_do_ioctl() - internal implementation of ioctl handling
+ * @dev:	the &struct rc_dev to perform the command on
+ * @cmd:	the ioctl command to perform
+ * @arg:	the argument to the ioctl cmd
+ * @return:	zero on success, or a negative error code
+ *
+ * This function (which is called with the @dev mutex held) performs
+ * the actual processing of ioctl commands.
+ */
+static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	unsigned int __user *ip = (unsigned int __user *)p;
+
+	switch (cmd) {
+
+	case RCIOCGVERSION:
+		return put_user(RC_VERSION, ip);
+
+	case RCIOCGTYPE:
+		return put_user(dev->driver_type, ip);
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * rc_ioctl() - allows userspace to do ioctl operations on the rc device file
+ * @fd:		the file descriptor corresponding to the opened rc device
+ * @file:	the &struct file corresponding to the previous open()
+ * @cmd:	the ioctl command to perform
+ * @arg:	the argument to the ioctl cmd
+ * @return:	zero on success, or a negative error code
+ *
+ * This function (which implements the ioctl functionality in
+ * &struct file_operations) allows userspace to perform various ioctl
+ * operations on a rc device file.
+ */
+static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct rc_client *client = file->private_data;
+	struct rc_dev *dev = client->dev;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->lock);
+	if (ret)
+		return ret;
+
+	if (dev->dead) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = rc_do_ioctl(dev, cmd, arg);
+
+out:
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
 static const struct file_operations rc_fops = {
 	.owner		= THIS_MODULE,
 	.open		= rc_dev_open,
@@ -1644,6 +1705,10 @@ static const struct file_operations rc_fops = {
 	.poll		= rc_poll,
 	.fasync		= rc_fasync,
 	.llseek		= no_llseek,
+	.unlocked_ioctl	= rc_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= rc_ioctl,
+#endif
 };
 
 /**
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 39f3794..660a331 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -30,6 +30,25 @@ do {								\
 		pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);	\
 } while (0)
 
+#define RC_VERSION 0x010000
+
+/*
+ * ioctl definitions
+ *
+ * Note: userspace programs which wish to interact with /dev/rc/rc? devices
+ *	 should make sure that the RC version and driver type is known
+ *	 (by using RCIOCGVERSION and RCIOCGTYPE) before continuing with any
+ *	 read/write/ioctl ops.
+ */
+#define RC_IOC_MAGIC	'x'
+
+/* get rc version */
+#define RCIOCGVERSION	_IOR(RC_IOC_MAGIC, 0x01, unsigned int)
+
+/* get driver/hardware type */
+#define RCIOCGTYPE	_IOR(RC_IOC_MAGIC, 0x02, unsigned int)
+
+
 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 */


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

* [PATCH 22/49] rc-core: add an ioctl for getting IR RX settings
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (20 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 21/49] rc-core: add ioctl support to the rc chardev David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 23/49] rc-loopback: add RCIOCGIRRX ioctl support David Härdeman
                   ` (28 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

LIRC currently supports quite a number of ioctl's for getting/setting
various TX and RX parameters. One problem with the one-ioctl-per-parameter
approach is that it might be quite elaborate to reprogram the hardware
(an operation which will have to be done once for every parameter change).

LIRC has approached this problem by providing something similar to
database transactions (ioctl commands LIRC_SETUP_START and LIRC_SETUP_END)
which is one (complicated) way of doing it.

The proposed approach for rc-core instead uses a struct with all known
parameters defined in one go. Drivers are expected to fill in the struct
with all the parameters that apply to them while leaving the rest intact.

I've looked at parameters defined in: LIRC, current rc-core, and in Microsoft
CIRClass drivers. The current struct rc_ir_rx should be a superset of all
three and also has room for further additions. Hopefully this should be fairly
complete and future-proof, please check carefully that you favourite
parameter is supported to satisfy your OCD.

Also, it would be interesting to know if carrier reporting is actually an
expensive operation (which should be explicitly enabled by setting the
appropriate flag as now) or not (in which case it should always be on).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |   28 +++++++++++++++++++
 include/media/rc-core.h    |   65 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 477ad49..c391518 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1649,6 +1649,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 {
 	void __user *p = (void __user *)arg;
 	unsigned int __user *ip = (unsigned int __user *)p;
+	struct rc_ir_rx rx;
 
 	switch (cmd) {
 
@@ -1657,6 +1658,33 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 
 	case RCIOCGTYPE:
 		return put_user(dev->driver_type, ip);
+
+	case RCIOCGIRPSIZE:
+		return put_user(ARRAY_SIZE(rx.protocols_supported), ip);
+
+	case RCIOCGIRRX:
+		memset(&rx, 0, sizeof(rx));
+		rx.rx_supported = 0x1;
+		rx.rx_enabled = 0x1;
+		rx.rx_connected = 0x1;
+		rx.protocols_enabled[0] = dev->enabled_protocols;
+		if (dev->driver_type == RC_DRIVER_SCANCODE)
+			rx.protocols_supported[0] = dev->allowed_protocols;
+		else
+			rx.protocols_supported[0] = ir_raw_get_allowed_protocols();
+		rx.timeout = dev->timeout;
+		rx.timeout_min = dev->min_timeout;
+		rx.timeout_max = dev->max_timeout;
+		rx.resolution = dev->rx_resolution;
+
+		/* See if the driver wishes to override anything */
+		if (dev->get_ir_rx)
+			dev->get_ir_rx(dev, &rx);
+
+		if (copy_to_user(p, &rx, sizeof(rx)))
+			return -EFAULT;
+
+		return 0;
 	}
 
 	return -EINVAL;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 660a331..7392258 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -48,6 +48,69 @@ do {								\
 /* get driver/hardware type */
 #define RCIOCGTYPE	_IOR(RC_IOC_MAGIC, 0x02, unsigned int)
 
+/* get size of protocols array (i.e. multiples of u64) for struct rc_ir_rx */
+#define RCIOCGIRPSIZE	_IOR(RC_IOC_MAGIC, 0x03, unsigned int)
+
+/* get ir rx parameters */
+#define RCIOCGIRRX	_IOC(_IOC_READ, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
+
+/**
+ * struct rc_ir_rx - used to get all IR RX parameters in one go
+ * @flags: device specific flags (only %RC_IR_RX_MEASURE_CARRIER is
+ *	currently defined)
+ * @rx_supported: bitmask of supported (i.e. possible) receivers
+ * @rx_enabled: bitmask of enabled receivers
+ * @rx_connected: bitmask of connected receivers
+ * @rx_learning: bitmask of learning receivers
+ * @protocols_supported: bitmask of supported protocols
+ * @protocols_enabled: bitmask of enabled protocols
+ * @freq_min: min carrier frequency
+ * @freq_max: max carrier frequency
+ * @duty_min: min duty cycle
+ * @duty_max: max duty cycle
+ * @timeout: current timeout (i.e. silence-before-idle)
+ * @timeout_min: min timeout
+ * @timeout_max: max timeout
+ * @filter_space: shorter spaces may be filtered
+ * @filter_space_min: min space filter value
+ * @filter_space_max: max space filter value
+ * @filter_pulse: shorter pulses may be filtered
+ * @filter_pulse_min: min pulse filter value
+ * @filter_pulse_max: max pulse filter value
+ * @resolution: current pulse/space resolution
+ * @resolution_min: min resolution
+ * @resolution_max: max resolution
+ * @reserved: for future use, set to zero
+ */
+struct rc_ir_rx {
+	__u32 flags;
+#define RC_IR_RX_MEASURE_CARRIER	0x01
+	__u32 rx_supported;
+	__u32 rx_enabled;
+	__u32 rx_connected;
+	__u32 rx_learning;
+	__u64 protocols_supported[1];
+	__u64 protocols_enabled[1];
+	__u32 freq_min;
+	__u32 freq_max;
+	__u32 duty_min;
+	__u32 duty_max;
+	__u32 timeout;
+	__u32 timeout_min;
+	__u32 timeout_max;
+	__u32 filter_space;
+	__u32 filter_space_min;
+	__u32 filter_space_max;
+	__u32 filter_pulse;
+	__u32 filter_pulse_min;
+	__u32 filter_pulse_max;
+	__u32 resolution;
+	__u32 resolution_min;
+	__u32 resolution_max;
+	__u32 reserved[9];
+} __packed;
+
+
 
 enum rc_driver_type {
 	RC_DRIVER_SCANCODE = 0,	/* Driver or hardware generates a scancode */
@@ -202,6 +265,7 @@ enum rc_filter_type {
  * @s_carrier_report: enable carrier reports
  * @s_filter: set the scancode filter 
  * @s_wakeup_filter: set the wakeup scancode filter
+ * @get_ir_rx: allow driver to provide rx settings
  */
 struct rc_dev {
 	struct device			dev;
@@ -263,6 +327,7 @@ struct rc_dev {
 						    struct rc_scancode_filter *filter);
 	int				(*s_wakeup_filter)(struct rc_dev *dev,
 							   struct rc_scancode_filter *filter);
+	void				(*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 23/49] rc-loopback: add RCIOCGIRRX ioctl support
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (21 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 22/49] rc-core: add an ioctl for getting IR RX settings David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 24/49] rc-core: add an ioctl for setting IR RX settings David Härdeman
                   ` (27 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

As an example, this patch adds support for the new RCIOCGIRRX ioctl
to rc-loopback.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-loopback.c |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index bc67d2f..565318c 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -181,6 +181,27 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
 	return 0;
 }
 
+/**
+ * loop_get_ir_rx() - returns the current RX settings
+ * @dev: the &struct rc_dev to get the settings for
+ * @rx: the &struct rc_ir_rx to fill in with the current settings
+ *
+ * This function is used to return the current RX settings.
+ */
+static void loop_get_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+	struct loopback_dev *lodev = dev->priv;
+
+	rx->rx_supported = RXMASK_REGULAR | RXMASK_LEARNING;
+	rx->rx_connected = RXMASK_REGULAR | RXMASK_LEARNING;
+	rx->rx_enabled = lodev->learning ? RXMASK_LEARNING : RXMASK_REGULAR;
+	rx->rx_learning = RXMASK_LEARNING;
+	rx->freq_min = lodev->rxcarriermin;
+	rx->freq_max = lodev->rxcarriermax;
+	rx->duty_min = 1;
+	rx->duty_max = 99;
+}
+
 static int __init loop_init(void)
 {
 	struct rc_dev *rc;
@@ -214,6 +235,7 @@ static int __init loop_init(void)
 	rc->s_idle		= loop_set_idle;
 	rc->s_learning_mode	= loop_set_learning_mode;
 	rc->s_carrier_report	= loop_set_carrier_report;
+	rc->get_ir_rx		= loop_get_ir_rx;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;


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

* [PATCH 24/49] rc-core: add an ioctl for setting IR RX settings
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (22 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 23/49] rc-loopback: add RCIOCGIRRX ioctl support David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 25/49] rc-loopback: add RCIOCSIRRX ioctl support David Härdeman
                   ` (26 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This adds a complementary ioctl to allow IR RX settings to be
changed.

Userspace is expected to first call RCIOCGIRRX, change the relevant parameters
in struct rc_ir_rx and then call RCIOCSIRRX.

The struct will be updated to reflect what the driver actually set the
parameters to (as all values may not be possible and some might have
to be approximated, e.g. because the hardware only supports some fixed
values) so that userspace knows the end result.

The LIRC driver is also changed to use the new RCIOCGIRRX and RCIOCSIRRX
methods as an alternative to the old functionality. This allows several
operations in struct rc_dev to be deprecated.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ir-lirc-codec.c |   53 +++++++++++++++++++++++++++++---------
 drivers/media/rc/rc-core-priv.h  |    3 ++
 drivers/media/rc/rc-main.c       |   53 +++++++++++++++++++++++++++++---------
 include/media/rc-core.h          |    9 +++++-
 4 files changed, 90 insertions(+), 28 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 7d58eea..6e31c83 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -188,6 +188,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	u32 __user *argp = (u32 __user *)(arg);
 	int ret = 0;
 	__u32 val = 0, tmp;
+	struct rc_ir_rx rx;
 
 	lirc = lirc_get_pdata(filep);
 	if (!lirc)
@@ -239,15 +240,23 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 
 	/* RX settings */
 	case LIRC_SET_REC_CARRIER:
-		if (!dev->s_rx_carrier_range)
-			return -ENOSYS;
-
-		if (val <= 0)
+		if (val <= 0 || val < dev->raw->lirc.carrier_low)
 			return -EINVAL;
 
-		return dev->s_rx_carrier_range(dev,
-					       dev->raw->lirc.carrier_low,
-					       val);
+		if (dev->s_rx_carrier_range)
+			return dev->s_rx_carrier_range(dev,
+						       dev->raw->lirc.carrier_low,
+						       val);
+
+		if (dev->get_ir_rx && dev->set_ir_rx) {
+			rc_init_ir_rx(dev, &rx);
+			dev->get_ir_rx(dev, &rx);
+			rx.freq_min = dev->raw->lirc.carrier_low;
+			rx.freq_max = val;
+			return dev->set_ir_rx(dev, &rx);
+		}
+
+		return -ENOSYS;
 
 	case LIRC_SET_REC_CARRIER_RANGE:
 		if (val <= 0)
@@ -261,16 +270,34 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		break;
 
 	case LIRC_SET_WIDEBAND_RECEIVER:
-		if (!dev->s_learning_mode)
-			return -ENOSYS;
+		if (dev->s_learning_mode)
+			return dev->s_learning_mode(dev, !!val);
+
+		if (dev->get_ir_rx && dev->set_ir_rx) {
+			rc_init_ir_rx(dev, &rx);
+			dev->get_ir_rx(dev, &rx);
+			rx.rx_enabled = (!!val) ? rx.rx_learning : ~rx.rx_learning;
+			rx.rx_enabled &= rx.rx_supported;
+			return dev->set_ir_rx(dev, &rx);
+		}
 
-		return dev->s_learning_mode(dev, !!val);
+		return -ENOSYS;
 
 	case LIRC_SET_MEASURE_CARRIER_MODE:
-		if (!dev->s_carrier_report)
-			return -ENOSYS;
+		if (dev->s_carrier_report)
+			return dev->s_carrier_report(dev, !!val);
+
+		if (dev->get_ir_rx && dev->set_ir_rx) {
+			rc_init_ir_rx(dev, &rx);
+			dev->get_ir_rx(dev, &rx);
+			if (!!val)
+				rx.flags |= RC_IR_RX_MEASURE_CARRIER;
+			else
+				rx.flags &= ~RC_IR_RX_MEASURE_CARRIER;
+			return dev->set_ir_rx(dev, &rx);
+		}
 
-		return dev->s_carrier_report(dev, !!val);
+		return -ENOSYS;
 
 	/* Generic timeout support */
 	case LIRC_GET_MIN_TIMEOUT:
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index dea7aff..aacc192 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -155,6 +155,9 @@ 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);
 
+/* Only to be used by rc-core and ir-lirc-codec */
+void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
+
 /*
  * Decoder initialization code
  *
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index c391518..3ad565f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1636,6 +1636,31 @@ static int rc_fasync(int fd, struct file *file, int on)
 }
 
 /**
+ * rc_init_ir_rx() - initializes a &struct rc_ir_rx to sane defaults
+ * @dev:	the &struct rc_dev to take initial settings from
+ * @rx:		the &struct rx_ir_rx to fill in with default values
+ *
+ * This function should only to be used by rc-core and ir-lirc-codec.
+ */
+void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+	memset(rx, 0, sizeof(*rx));
+	rx->rx_supported = 0x1;
+	rx->rx_enabled = 0x1;
+	rx->rx_connected = 0x1;
+	rx->protocols_enabled[0] = dev->enabled_protocols;
+	if (dev->driver_type == RC_DRIVER_SCANCODE)
+		rx->protocols_supported[0] = dev->allowed_protocols;
+	else
+		rx->protocols_supported[0] = ir_raw_get_allowed_protocols();
+	rx->timeout = dev->timeout;
+	rx->timeout_min = dev->min_timeout;
+	rx->timeout_max = dev->max_timeout;
+	rx->resolution = dev->rx_resolution;
+}
+EXPORT_SYMBOL_GPL(rc_init_ir_rx);
+
+/**
  * rc_do_ioctl() - internal implementation of ioctl handling
  * @dev:	the &struct rc_dev to perform the command on
  * @cmd:	the ioctl command to perform
@@ -1650,6 +1675,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 	void __user *p = (void __user *)arg;
 	unsigned int __user *ip = (unsigned int __user *)p;
 	struct rc_ir_rx rx;
+	int error;
 
 	switch (cmd) {
 
@@ -1662,20 +1688,21 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 	case RCIOCGIRPSIZE:
 		return put_user(ARRAY_SIZE(rx.protocols_supported), ip);
 
+	case RCIOCSIRRX:
+		if (!dev->set_ir_rx)
+			return -ENOSYS;
+
+		if (copy_from_user(&rx, p, sizeof(rx)))
+			return -EFAULT;
+
+		error = dev->set_ir_rx(dev, &rx);
+		if (error)
+			return error;
+
+		/* Fall through */
+
 	case RCIOCGIRRX:
-		memset(&rx, 0, sizeof(rx));
-		rx.rx_supported = 0x1;
-		rx.rx_enabled = 0x1;
-		rx.rx_connected = 0x1;
-		rx.protocols_enabled[0] = dev->enabled_protocols;
-		if (dev->driver_type == RC_DRIVER_SCANCODE)
-			rx.protocols_supported[0] = dev->allowed_protocols;
-		else
-			rx.protocols_supported[0] = ir_raw_get_allowed_protocols();
-		rx.timeout = dev->timeout;
-		rx.timeout_min = dev->min_timeout;
-		rx.timeout_max = dev->max_timeout;
-		rx.resolution = dev->rx_resolution;
+		rc_init_ir_rx(dev, &rx);
 
 		/* See if the driver wishes to override anything */
 		if (dev->get_ir_rx)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 7392258..09bf8b5 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -54,8 +54,11 @@ do {								\
 /* get ir rx parameters */
 #define RCIOCGIRRX	_IOC(_IOC_READ, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
 
+/* set ir rx parameters */
+#define RCIOCSIRRX	_IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
+
 /**
- * struct rc_ir_rx - used to get all IR RX parameters in one go
+ * struct rc_ir_rx - used to get/set all IR RX parameters in one go
  * @flags: device specific flags (only %RC_IR_RX_MEASURE_CARRIER is
  *	currently defined)
  * @rx_supported: bitmask of supported (i.e. possible) receivers
@@ -257,7 +260,7 @@ enum rc_filter_type {
  * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
  * @s_tx_carrier: set transmit carrier frequency
  * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%)
- * @s_rx_carrier: inform driver about carrier it is expected to handle
+ * @s_rx_carrier: inform driver about expected carrier (deprecated)
  * @tx_ir: transmit IR
  * @s_idle: enable/disable hardware idle mode, upon which,
  *	device doesn't interrupt host until it sees IR pulses
@@ -266,6 +269,7 @@ enum rc_filter_type {
  * @s_filter: set the scancode filter 
  * @s_wakeup_filter: set the wakeup scancode filter
  * @get_ir_rx: allow driver to provide rx settings
+ * @set_ir_rx: allow driver to change rx settings
  */
 struct rc_dev {
 	struct device			dev;
@@ -328,6 +332,7 @@ struct rc_dev {
 	int				(*s_wakeup_filter)(struct rc_dev *dev,
 							   struct rc_scancode_filter *filter);
 	void				(*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
+	int				(*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 25/49] rc-loopback: add RCIOCSIRRX ioctl support
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (23 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 24/49] rc-core: add an ioctl for setting IR RX settings David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 26/49] rc-core: add an ioctl for getting IR TX settings David Härdeman
                   ` (25 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

As an example, this patch adds support for the new RCIOCSIRRX ioctl
to rc-loopback and removes deprecated functions without a loss in
functionality (as LIRC will automatically use the new functions).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-loopback.c |   84 ++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 565318c..2ae1b5a 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -86,21 +86,6 @@ static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
 	return 0;
 }
 
-static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	if (min < 1 || min > max) {
-		dprintk("invalid rx carrier range %u to %u\n", min, max);
-		return -EINVAL;
-	}
-
-	dprintk("setting rx carrier range %u to %u\n", min, max);
-	lodev->rxcarriermin = min;
-	lodev->rxcarriermax = max;
-	return 0;
-}
-
 static int loop_tx_ir(struct rc_dev *dev, unsigned count)
 {
 	struct loopback_dev *lodev = dev->priv;
@@ -157,30 +142,6 @@ static void loop_set_idle(struct rc_dev *dev, bool enable)
 	}
 }
 
-static int loop_set_learning_mode(struct rc_dev *dev, int enable)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	if (lodev->learning != enable) {
-		dprintk("%sing learning mode\n", enable ? "enter" : "exit");
-		lodev->learning = !!enable;
-	}
-
-	return 0;
-}
-
-static int loop_set_carrier_report(struct rc_dev *dev, int enable)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	if (lodev->carrierreport != enable) {
-		dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
-		lodev->carrierreport = !!enable;
-	}
-
-	return 0;
-}
-
 /**
  * loop_get_ir_rx() - returns the current RX settings
  * @dev: the &struct rc_dev to get the settings for
@@ -202,6 +163,47 @@ static void loop_get_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
 	rx->duty_max = 99;
 }
 
+/**
+ * loop_set_ir_rx() - changes and returns the current RX settings
+ * @dev: the &struct rc_dev to change the settings for
+ * @rx: the &struct rc_ir_rx with the new settings
+ *
+ * This function is used to change and return the current RX settings.
+ */
+static int loop_set_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+	struct loopback_dev *lodev = dev->priv;
+
+	dprintk("%s called\n", __func__);
+	if (lodev->rxcarriermin != rx->freq_min) {
+		dprintk("changing rx carrier min to %u\n", rx->freq_min);
+		lodev->rxcarriermin = rx->freq_min;
+	}
+
+	if (lodev->rxcarriermax != rx->freq_max) {
+		dprintk("changing rx carrier max to %u\n", rx->freq_max);
+		lodev->rxcarriermax = rx->freq_max;
+	}
+
+	if (lodev->carrierreport == !(rx->flags & RC_IR_RX_MEASURE_CARRIER)) {
+		lodev->carrierreport = !!(rx->flags & RC_IR_RX_MEASURE_CARRIER);
+		dprintk("%sabling carrier reports\n",
+			lodev->carrierreport ? "en" : "dis");
+	}
+
+	if ((rx->rx_enabled == RXMASK_LEARNING) && !lodev->learning) {
+		dprintk("enabling learning mode\n");
+		lodev->learning = true;
+	} else if ((rx->rx_enabled == RXMASK_REGULAR) && lodev->learning) {
+		dprintk("disabling learning mode\n");
+		lodev->learning = false;
+	}
+
+	/* Fill in the correct values after the changes */
+	loop_get_ir_rx(dev, rx);
+	return 0;
+}
+
 static int __init loop_init(void)
 {
 	struct rc_dev *rc;
@@ -230,12 +232,10 @@ static int __init loop_init(void)
 	rc->s_tx_mask		= loop_set_tx_mask;
 	rc->s_tx_carrier	= loop_set_tx_carrier;
 	rc->s_tx_duty_cycle	= loop_set_tx_duty_cycle;
-	rc->s_rx_carrier_range	= loop_set_rx_carrier_range;
 	rc->tx_ir		= loop_tx_ir;
 	rc->s_idle		= loop_set_idle;
-	rc->s_learning_mode	= loop_set_learning_mode;
-	rc->s_carrier_report	= loop_set_carrier_report;
 	rc->get_ir_rx		= loop_get_ir_rx;
+	rc->set_ir_rx		= loop_set_ir_rx;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;


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

* [PATCH 26/49] rc-core: add an ioctl for getting IR TX settings
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (24 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 25/49] rc-loopback: add RCIOCSIRRX ioctl support David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 27/49] rc-loopback: add RCIOCGIRTX ioctl support David Härdeman
                   ` (24 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This ioctl follows the same rationale and structure as the ioctl for
getting IR RX settings (RCIOCGIRRX) but it works on TX settings instead.

As with the RX ioctl, it would be nice if people could check struct
rc_ir_tx carefully to make sure that their favourite parameter
hasn't been left out.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |   12 ++++++++++++
 include/media/rc-core.h    |   38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 3ad565f..611d24d 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1675,6 +1675,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 	void __user *p = (void __user *)arg;
 	unsigned int __user *ip = (unsigned int __user *)p;
 	struct rc_ir_rx rx;
+	struct rc_ir_tx tx;
 	int error;
 
 	switch (cmd) {
@@ -1712,6 +1713,17 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 			return -EFAULT;
 
 		return 0;
+
+	case RCIOCGIRTX:
+		memset(&tx, 0, sizeof(tx));
+
+		if (dev->get_ir_tx)
+			dev->get_ir_tx(dev, &tx);
+
+		if (copy_to_user(p, &tx, sizeof(tx)))
+			return -EFAULT;
+
+		return 0;
 	}
 
 	return -EINVAL;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 09bf8b5..566ae7d 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -113,6 +113,42 @@ struct rc_ir_rx {
 	__u32 reserved[9];
 } __packed;
 
+/* get ir tx parameters */
+#define RCIOCGIRTX	_IOC(_IOC_READ, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
+
+/**
+ * struct rc_ir_tx - used to get all IR TX parameters in one go
+ * @flags: device specific flags
+ * @tx_supported: bitmask of supported transmitters
+ * @tx_enabled: bitmask of enabled transmitters
+ * @tx_connected: bitmask of connected transmitters
+ * @freq: current carrier frequency
+ * @freq_min: min carrier frequency
+ * @freq_max: max carrier frequency
+ * @duty: current duty cycle
+ * @duty_min: min duty cycle
+ * @duty_max: max duty cycle
+ * @resolution: current resolution
+ * @resolution_min: min resolution
+ * @resolution_max: max resolution
+ * @reserved: for future use, set to zero
+ */
+struct rc_ir_tx {
+	__u32 flags;
+	__u32 tx_supported;
+	__u32 tx_enabled;
+	__u32 tx_connected;
+	__u32 freq;
+	__u32 freq_min;
+	__u32 freq_max;
+	__u32 duty;
+	__u32 duty_min;
+	__u32 duty_max;
+	__u32 resolution;
+	__u32 resolution_min;
+	__u32 resolution_max;
+	__u32 reserved[9];
+} __packed;
 
 
 enum rc_driver_type {
@@ -270,6 +306,7 @@ enum rc_filter_type {
  * @s_wakeup_filter: set the wakeup scancode filter
  * @get_ir_rx: allow driver to provide rx settings
  * @set_ir_rx: allow driver to change rx settings
+ * @get_ir_tx: allow driver to provide tx settings
  */
 struct rc_dev {
 	struct device			dev;
@@ -333,6 +370,7 @@ struct rc_dev {
 							   struct rc_scancode_filter *filter);
 	void				(*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
 	int				(*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
+	void				(*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 27/49] rc-loopback: add RCIOCGIRTX ioctl support
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (25 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 26/49] rc-core: add an ioctl for getting IR TX settings David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 28/49] rc-core: add an ioctl for setting IR TX settings David Härdeman
                   ` (23 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

As an example, this patch adds support for the new RCIOCGIRRX ioctl
to rc-loopback.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-loopback.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 2ae1b5a..ba36fbe 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -204,6 +204,31 @@ static int loop_set_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
 	return 0;
 }
 
+/**
+ * loop_get_ir_tx() - returns the current TX settings
+ * @dev: the &struct rc_dev to get the settings for
+ * @tx: the &struct rc_ir_tx to fill in with the current settings
+ *
+ * This function is used to return the current TX settings.
+ */
+static void loop_get_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
+{
+	struct loopback_dev *lodev = dev->priv;
+
+	tx->tx_supported = RXMASK_REGULAR | RXMASK_LEARNING;
+	tx->tx_connected = RXMASK_REGULAR | RXMASK_LEARNING;
+	tx->tx_enabled = lodev->txmask;
+	tx->freq = lodev->txcarrier;
+	tx->freq_min = 1;
+	tx->freq_max = UINT_MAX;
+	tx->duty = lodev->txduty;
+	tx->duty_min = 1;
+	tx->duty_max = 99;
+	tx->resolution = 1;
+	tx->resolution_min = 1;
+	tx->resolution_max = 1;
+}
+
 static int __init loop_init(void)
 {
 	struct rc_dev *rc;
@@ -236,6 +261,7 @@ static int __init loop_init(void)
 	rc->s_idle		= loop_set_idle;
 	rc->get_ir_rx		= loop_get_ir_rx;
 	rc->set_ir_rx		= loop_set_ir_rx;
+	rc->get_ir_tx		= loop_get_ir_tx;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;


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

* [PATCH 28/49] rc-core: add an ioctl for setting IR TX settings
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (26 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 27/49] rc-loopback: add RCIOCGIRTX ioctl support David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 29/49] rc-loopback: add RCIOCSIRTX ioctl support David Härdeman
                   ` (22 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This adds a complementary ioctl to allow IR TX settings to be
changed.

Much like the RCIOCSIRRX functionality, userspace is expected to call
RCIOCGIRTX, change values and then call RCIOCSIRTX and finally inspect
the struct rc_ir_tx to see the results.

Also, LIRC is changed to use the new functionality as an alternative to the
old one and another bunch of operations in struct rc_dev are now deprecated.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ir-lirc-codec.c |   42 +++++++++++++++++++++++++++++---------
 drivers/media/rc/rc-main.c       |   13 ++++++++++++
 include/media/rc-core.h          |   13 ++++++++----
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 6e31c83..7b56f21 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -189,6 +189,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	int ret = 0;
 	__u32 val = 0, tmp;
 	struct rc_ir_rx rx;
+	struct rc_ir_tx tx;
 
 	lirc = lirc_get_pdata(filep);
 	if (!lirc)
@@ -218,25 +219,46 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 
 	/* TX settings */
 	case LIRC_SET_TRANSMITTER_MASK:
-		if (!dev->s_tx_mask)
-			return -ENOSYS;
+		if (dev->s_tx_mask)
+			return dev->s_tx_mask(dev, val);
 
-		return dev->s_tx_mask(dev, val);
+		if (dev->get_ir_tx && dev->set_ir_tx) {
+			memset(&tx, 0, sizeof(tx));
+			dev->get_ir_tx(dev, &tx);
+			tx.tx_enabled = val;
+			return dev->set_ir_tx(dev, &tx);
+		}
+
+		return -ENOSYS;
 
 	case LIRC_SET_SEND_CARRIER:
-		if (!dev->s_tx_carrier)
-			return -ENOSYS;
+		if (dev->s_tx_carrier)
+			return dev->s_tx_carrier(dev, val);
 
-		return dev->s_tx_carrier(dev, val);
+		if (dev->get_ir_tx && dev->set_ir_tx) {
+			memset(&tx, 0, sizeof(tx));
+			dev->get_ir_tx(dev, &tx);
+			tx.freq = val;
+			return dev->set_ir_tx(dev, &tx);
+		}
 
-	case LIRC_SET_SEND_DUTY_CYCLE:
-		if (!dev->s_tx_duty_cycle)
-			return -ENOSYS;
+		return -ENOSYS;
 
+	case LIRC_SET_SEND_DUTY_CYCLE:
 		if (val <= 0 || val >= 100)
 			return -EINVAL;
 
-		return dev->s_tx_duty_cycle(dev, val);
+		if (dev->s_tx_duty_cycle)
+			return dev->s_tx_duty_cycle(dev, val);
+
+		if (dev->get_ir_tx && dev->set_ir_tx) {
+			memset(&tx, 0, sizeof(tx));
+			dev->get_ir_tx(dev, &tx);
+			tx.duty = val;
+			return dev->set_ir_tx(dev, &tx);
+		}
+
+		return -ENOSYS;
 
 	/* RX settings */
 	case LIRC_SET_REC_CARRIER:
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 611d24d..cc2f713 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1714,6 +1714,19 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 
 		return 0;
 
+	case RCIOCSIRTX:
+		if (!dev->set_ir_tx)
+			return -ENOSYS;
+
+		if (copy_from_user(&tx, p, sizeof(tx)))
+			return -EFAULT;
+
+		error = dev->set_ir_tx(dev, &tx);
+		if (error)
+			return error;
+
+		/* Fall through */
+
 	case RCIOCGIRTX:
 		memset(&tx, 0, sizeof(tx));
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 566ae7d..eacb735 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -116,8 +116,11 @@ struct rc_ir_rx {
 /* get ir tx parameters */
 #define RCIOCGIRTX	_IOC(_IOC_READ, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
 
+/* set ir tx parameters */
+#define RCIOCSIRTX	_IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
+
 /**
- * struct rc_ir_tx - used to get all IR TX parameters in one go
+ * struct rc_ir_tx - used to get/set all IR TX parameters in one go
  * @flags: device specific flags
  * @tx_supported: bitmask of supported transmitters
  * @tx_enabled: bitmask of enabled transmitters
@@ -293,9 +296,9 @@ enum rc_filter_type {
  *	is opened.
  * @close: callback to allow drivers to disable polling/irq when IR input device
  *	is opened.
- * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
- * @s_tx_carrier: set transmit carrier frequency
- * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%)
+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs, deprecated)
+ * @s_tx_carrier: set transmit carrier frequency (deprecated)
+ * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%, deprecated)
  * @s_rx_carrier: inform driver about expected carrier (deprecated)
  * @tx_ir: transmit IR
  * @s_idle: enable/disable hardware idle mode, upon which,
@@ -307,6 +310,7 @@ enum rc_filter_type {
  * @get_ir_rx: allow driver to provide rx settings
  * @set_ir_rx: allow driver to change rx settings
  * @get_ir_tx: allow driver to provide tx settings
+ * @set_ir_tx: allow driver to change tx settings
  */
 struct rc_dev {
 	struct device			dev;
@@ -371,6 +375,7 @@ struct rc_dev {
 	void				(*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
 	int				(*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
 	void				(*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
+	int				(*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 29/49] rc-loopback: add RCIOCSIRTX ioctl support
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (27 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 28/49] rc-core: add an ioctl for setting IR TX settings David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-04-03 23:33 ` [PATCH 30/49] rc-core: leave the internals of rc_dev alone David Härdeman
                   ` (21 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

As an example, this patch adds support for the new RCIOCSIRTX ioctl
to rc-loopback and removes deprecated functions without a loss in
functionality (as LIRC will automatically use the new functions).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-loopback.c |   59 +++++++++++++---------------------------
 1 file changed, 19 insertions(+), 40 deletions(-)

diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index ba36fbe..628e834 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -49,43 +49,6 @@ struct loopback_dev {
 
 static struct loopback_dev loopdev;
 
-static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
-		dprintk("invalid tx mask: %u\n", mask);
-		return -EINVAL;
-	}
-
-	dprintk("setting tx mask: %u\n", mask);
-	lodev->txmask = mask;
-	return 0;
-}
-
-static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	dprintk("setting tx carrier: %u\n", carrier);
-	lodev->txcarrier = carrier;
-	return 0;
-}
-
-static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
-{
-	struct loopback_dev *lodev = dev->priv;
-
-	if (duty_cycle < 1 || duty_cycle > 99) {
-		dprintk("invalid duty cycle: %u\n", duty_cycle);
-		return -EINVAL;
-	}
-
-	dprintk("setting duty cycle: %u\n", duty_cycle);
-	lodev->txduty = duty_cycle;
-	return 0;
-}
-
 static int loop_tx_ir(struct rc_dev *dev, unsigned count)
 {
 	struct loopback_dev *lodev = dev->priv;
@@ -229,6 +192,24 @@ static void loop_get_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
 	tx->resolution_max = 1;
 }
 
+/**
+ * loop_set_ir_tx() - changes and returns the current TX settings
+ * @dev: the &struct rc_dev to change the settings for
+ * @tx: the &struct rc_ir_tx with the new settings
+ *
+ * This function is used to change and return the current TX settings.
+ */
+static int loop_set_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
+{
+	struct loopback_dev *lodev = dev->priv;
+
+	lodev->txmask = tx->tx_enabled & (RXMASK_REGULAR | RXMASK_LEARNING);
+	lodev->txcarrier = tx->freq;
+	lodev->txduty = tx->duty;
+
+	return 0;
+}
+
 static int __init loop_init(void)
 {
 	struct rc_dev *rc;
@@ -254,14 +235,12 @@ static int __init loop_init(void)
 	rc->max_timeout		= UINT_MAX;
 	rc->rx_resolution	= 1000;
 	rc->tx_resolution	= 1000;
-	rc->s_tx_mask		= loop_set_tx_mask;
-	rc->s_tx_carrier	= loop_set_tx_carrier;
-	rc->s_tx_duty_cycle	= loop_set_tx_duty_cycle;
 	rc->tx_ir		= loop_tx_ir;
 	rc->s_idle		= loop_set_idle;
 	rc->get_ir_rx		= loop_get_ir_rx;
 	rc->set_ir_rx		= loop_set_ir_rx;
 	rc->get_ir_tx		= loop_get_ir_tx;
+	rc->set_ir_tx		= loop_set_ir_tx;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;


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

* [PATCH 30/49] rc-core: leave the internals of rc_dev alone
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (28 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 29/49] rc-loopback: add RCIOCSIRTX ioctl support David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-07-24  1:50   ` Mauro Carvalho Chehab
  2014-04-03 23:33 ` [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c David Härdeman
                   ` (20 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Several drivers poke around in the internals of rc_dev, try to
fix them up in preparation for the next round of patches.

drivers/media/rc/ati_remote.c:
	Removing the REP_DELAY setting on the input device should not
	change how to driver works (as it does a keydown/keyup and has
	no real repeat handling).

drivers/media/rc/img-ir/img-ir-hw.c
	Changing the protocol does not imply that the keymap changes.

drivers/media/rc/ir-nec-decoder.c
	Obvious fix, leave repeat handling to rc-core

drivers/media/rc/ir-raw.c
	Replaced the REP_DELAY value with a static value, which makes more
	sense anyway. Why should the time before automatic repeat handling
	kicks in define the drivers idea of "a long time"?

drivers/media/rc/ir-sanyo-decoder.c
	Obvious fix, leave repeat handling to rc-core

drivers/media/video/cx231xx/cx231xx-input.c
	Just some debug statements to change

drivers/media/video/tm6000/tm6000-input.c
	Not sure what the driver is trying to do, however, IR
	handling seems incomplete ATM so deleting the offending
	parts shouldn't affect functionality

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/ati_remote.c             |    3 ---
 drivers/media/rc/img-ir/img-ir-hw.c       |    4 ----
 drivers/media/rc/ir-nec-decoder.c         |   10 +++-------
 drivers/media/rc/ir-raw.c                 |    4 +---
 drivers/media/rc/ir-sanyo-decoder.c       |   10 +++-------
 drivers/media/usb/cx231xx/cx231xx-input.c |    5 ++---
 drivers/media/usb/tm6000/tm6000-input.c   |    4 ----
 7 files changed, 9 insertions(+), 31 deletions(-)

diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 3ada4dc..6ef5716 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -932,9 +932,6 @@ static int ati_remote_probe(struct usb_interface *interface,
 	if (err)
 		goto exit_kill_urbs;
 
-	/* use our delay for rc_dev */
-	ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
-
 	/* Set up and register mouse input device */
 	if (mouse) {
 		input_dev = input_allocate_device();
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 9fc41780..3bb6a32 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -666,10 +666,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
 {
 	struct rc_dev *rdev = priv->hw.rdev;
 
-	spin_lock_irq(&rdev->rc_map.lock);
-	rdev->rc_map.rc_type = __ffs64(proto);
-	spin_unlock_irq(&rdev->rc_map.lock);
-
 	mutex_lock(&rdev->lock);
 	rdev->enabled_protocols = proto;
 	rdev->allowed_wakeup_protocols = proto;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 1683aaa..861fd86 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -89,13 +89,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			data->state = STATE_BIT_PULSE;
 			return 0;
 		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
-			if (!dev->keypressed) {
-				IR_dprintk(1, "Discarding last key repeat: event after key up\n");
-			} else {
-				rc_repeat(dev);
-				IR_dprintk(1, "Repeat last key\n");
-				data->state = STATE_TRAILER_PULSE;
-			}
+			rc_repeat(dev);
+			IR_dprintk(1, "Repeat last key\n");
+			data->state = STATE_TRAILER_PULSE;
 			return 0;
 		}
 
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index af23f4d..aa2503d 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -109,20 +109,18 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
 	s64			delta; /* ns */
 	DEFINE_IR_RAW_EVENT(ev);
 	int			rc = 0;
-	int			delay;
 
 	if (!dev->raw)
 		return -EINVAL;
 
 	now = ktime_get();
 	delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
-	delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
 
 	/* 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 > delay || !dev->raw->last_type)
+	if (delta > MS_TO_NS(500) || !dev->raw->last_type)
 		type |= IR_START_EVENT;
 	else
 		ev.duration = delta;
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index ad1dc6a..9f97648 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -112,13 +112,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			break;
 
 		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
-			if (!dev->keypressed) {
-				IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
-			} else {
-				rc_repeat(dev);
-				IR_dprintk(1, "SANYO repeat last key\n");
-				data->state = STATE_INACTIVE;
-			}
+			rc_repeat(dev);
+			IR_dprintk(1, "SANYO repeat last key\n");
+			data->state = STATE_INACTIVE;
 			return 0;
 		}
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 05f0434..5480fb1 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -31,7 +31,7 @@ static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
 	int	rc;
 	u8	cmd, scancode;
 
-	dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
+	dev_dbg(&ir->rc->dev, "%s\n", __func__);
 
 		/* poll IR chip */
 	rc = i2c_master_recv(ir->c, &cmd, 1);
@@ -49,8 +49,7 @@ static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
 
 	scancode = bitrev8(cmd);
 
-	dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
-		cmd, scancode);
+	dev_dbg(&ir->rc->dev, "cmd %02x, scan = %02x\n", cmd, scancode);
 
 	*protocol = RC_TYPE_OTHER;
 	*pscancode = scancode;
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 26b2ebb..7c9b58d 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -67,7 +67,6 @@ struct tm6000_IR {
 	u8			wait:1;
 	u8			pwled:2;
 	u8			submit_urb:1;
-	u16			key_addr;
 	struct urb		*int_urb;
 
 	/* IR device properties */
@@ -325,9 +324,6 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_type)
 
 	dprintk(2, "%s\n",__func__);
 
-	if ((rc->rc_map.scan) && (*rc_type == RC_BIT_NEC))
-		ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
-
 	ir->rc_type = *rc_type;
 
 	tm6000_ir_config(ir);


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

* [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (29 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 30/49] rc-core: leave the internals of rc_dev alone David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-07-25 22:44   ` Mauro Carvalho Chehab
  2014-04-03 23:33 ` [PATCH 32/49] rc-core: prepare for multiple keytables David Härdeman
                   ` (19 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

rc-main.c is getting quite large and contains two distinct parts, one
related to the chardev (fops, sysfs, etc) and one related to all
key functionality. Split off the key functionality to a separate file in
preparation for the coming patches.

I've done the splitting as a separate patch with the absolute minimum changes
(making some methods non-static) because it's nigh impossible to review
code changes and this code of split in the same patch.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/Makefile       |    2 
 drivers/media/rc/rc-core-priv.h |   17 +
 drivers/media/rc/rc-keytable.c  |  851 +++++++++++++++++++++++++++++++++++++++
 drivers/media/rc/rc-main.c      |  853 +--------------------------------------
 4 files changed, 883 insertions(+), 840 deletions(-)
 create mode 100644 drivers/media/rc/rc-keytable.c

diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index d326d4d..de08ee6 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,4 +1,4 @@
-rc-core-objs	:= rc-main.o ir-raw.o
+rc-core-objs	:= rc-main.o rc-keytable.o ir-raw.o
 
 obj-y += keymaps/
 
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index aacc192..6da8a0d 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -155,9 +155,26 @@ 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);
 
+/*
+ * Methods from rc-keytable.c to be used internally
+ */
+void ir_timer_keyup(unsigned long cookie);
+int rc_input_open(struct input_dev *idev);
+void rc_input_close(struct input_dev *idev);
+int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from);
+void ir_free_table(struct rc_map *rc_map);
+int ir_getkeycode(struct input_dev *idev,
+		  struct input_keymap_entry *ke);
+int ir_setkeycode(struct input_dev *idev,
+		  const struct input_keymap_entry *ke,
+		  unsigned int *old_keycode);
+
 /* Only to be used by rc-core and ir-lirc-codec */
 void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
 
+/* Only to be used by rc-keytable.c */
+extern struct led_trigger *led_feedback;
+
 /*
  * Decoder initialization code
  *
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
new file mode 100644
index 0000000..25faeba
--- /dev/null
+++ b/drivers/media/rc/rc-keytable.c
@@ -0,0 +1,851 @@
+/* rc-keytable.c - Remote Controller keytable handling
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab
+ *
+ * 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/rc-core.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/idr.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include "rc-core-priv.h"
+
+/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
+#define IR_TAB_MIN_SIZE		256
+#define IR_TAB_MAX_SIZE		8192
+
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
+#define IR_KEYPRESS_TIMEOUT 250
+
+/* Used to keep track of known keymaps */
+static LIST_HEAD(rc_map_list);
+static DEFINE_SPINLOCK(rc_map_lock);
+
+static struct rc_map_list *seek_rc_map(const char *name)
+{
+	struct rc_map_list *map = NULL;
+
+	spin_lock(&rc_map_lock);
+	list_for_each_entry(map, &rc_map_list, list) {
+		if (!strcmp(name, map->map.name)) {
+			spin_unlock(&rc_map_lock);
+			return map;
+		}
+	}
+	spin_unlock(&rc_map_lock);
+
+	return NULL;
+}
+
+struct rc_map *rc_map_get(const char *name)
+{
+
+	struct rc_map_list *map;
+
+	map = seek_rc_map(name);
+#ifdef MODULE
+	if (!map) {
+		int rc = request_module("%s", name);
+		if (rc < 0) {
+			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
+			return NULL;
+		}
+		msleep(20);	/* Give some time for IR to register */
+
+		map = seek_rc_map(name);
+	}
+#endif
+	if (!map) {
+		printk(KERN_ERR "IR keymap %s not found\n", name);
+		return NULL;
+	}
+
+	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
+
+	return &map->map;
+}
+EXPORT_SYMBOL_GPL(rc_map_get);
+
+int rc_map_register(struct rc_map_list *map)
+{
+	spin_lock(&rc_map_lock);
+	list_add_tail(&map->list, &rc_map_list);
+	spin_unlock(&rc_map_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rc_map_register);
+
+void rc_map_unregister(struct rc_map_list *map)
+{
+	spin_lock(&rc_map_lock);
+	list_del(&map->list);
+	spin_unlock(&rc_map_lock);
+}
+EXPORT_SYMBOL_GPL(rc_map_unregister);
+
+/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_map:	the rc_map to initialize
+ * @name:	name to assign to the table
+ * @size:	initial size of the table
+ * @return:	zero on success or a negative error code
+ *
+ * This routine will initialize the rc_map and will allocate
+ * memory to hold at least the specified number of elements.
+ */
+static int ir_create_table(struct rc_map *rc_map,
+			   const char *name, size_t size)
+{
+	rc_map->name = name;
+	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
+	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
+	if (!rc_map->scan)
+		return -ENOMEM;
+
+	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+		   rc_map->size, rc_map->alloc);
+	return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_map:	the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+void ir_free_table(struct rc_map *rc_map)
+{
+	rc_map->size = 0;
+	kfree(rc_map->scan);
+	rc_map->scan = NULL;
+}
+
+/**
+ * ir_resize_table() - resizes a scancode table if necessary
+ * @rc_map:	the rc_map to resize
+ * @gfp_flags:	gfp flags to use when allocating memory
+ * @return:	zero on success or a negative error code
+ *
+ * This routine will shrink the rc_map if it has lots of
+ * unused entries and grow it if it is full.
+ */
+static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+{
+	unsigned int oldalloc = rc_map->alloc;
+	unsigned int newalloc = oldalloc;
+	struct rc_map_table *oldscan = rc_map->scan;
+	struct rc_map_table *newscan;
+
+	if (rc_map->size == rc_map->len) {
+		/* All entries in use -> grow keytable */
+		if (rc_map->alloc >= IR_TAB_MAX_SIZE)
+			return -ENOMEM;
+
+		newalloc *= 2;
+		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+	}
+
+	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
+		/* Less than 1/3 of entries in use -> shrink keytable */
+		newalloc /= 2;
+		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+	}
+
+	if (newalloc == oldalloc)
+		return 0;
+
+	newscan = kmalloc(newalloc, gfp_flags);
+	if (!newscan) {
+		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+		return -ENOMEM;
+	}
+
+	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
+	rc_map->scan = newscan;
+	rc_map->alloc = newalloc;
+	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+	kfree(oldscan);
+	return 0;
+}
+
+/**
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
+ * @dev:	the struct rc_dev device descriptor
+ * @rc_map:	scancode table to be adjusted
+ * @index:	index of the mapping that needs to be updated
+ * @keycode:	the desired keycode
+ * @return:	previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycode mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct rc_dev *dev,
+				      struct rc_map *rc_map,
+				      unsigned int index,
+				      unsigned int new_keycode)
+{
+	int old_keycode = rc_map->scan[index].keycode;
+	int i;
+
+	/* Did the user wish to remove the mapping? */
+	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
+			   index, rc_map->scan[index].protocol,
+			   (unsigned long long)rc_map->scan[index].scancode);
+		rc_map->len--;
+		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
+			(rc_map->len - index) * sizeof(struct rc_map_table));
+	} else {
+		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
+			   "with key 0x%04x\n",
+			   index,
+			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
+			   rc_map->scan[index].protocol,
+			   (unsigned long long)rc_map->scan[index].scancode,
+			   new_keycode);
+		rc_map->scan[index].keycode = new_keycode;
+		__set_bit(new_keycode, dev->input_dev->keybit);
+	}
+
+	if (old_keycode != KEY_RESERVED) {
+		/* A previous mapping was updated... */
+		__clear_bit(old_keycode, dev->input_dev->keybit);
+		/* ... but another scancode might use the same keycode */
+		for (i = 0; i < rc_map->len; i++) {
+			if (rc_map->scan[i].keycode == old_keycode) {
+				__set_bit(old_keycode, dev->input_dev->keybit);
+				break;
+			}
+		}
+
+		/* Possibly shrink the keytable, failure is not a problem */
+		ir_resize_table(rc_map, GFP_ATOMIC);
+	}
+
+	return old_keycode;
+}
+
+/**
+ * ir_establish_scancode() - set a keycode in the scancode->keycode table
+ * @dev:	the struct rc_dev device descriptor
+ * @rc_map:	scancode table to be searched
+ * @entry:	the entry to be added to the table
+ * @resize:	controls whether we are allowed to resize the table to
+ *		accomodate not yet present scancodes
+ * @return:	index of the mapping containing scancode in question
+ *		or -1U in case of failure.
+ *
+ * This routine is used to locate given scancode in rc_map.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
+ */
+static unsigned int ir_establish_scancode(struct rc_dev *dev,
+					  struct rc_map *rc_map,
+					  struct rc_map_table *entry,
+					  bool resize)
+{
+	unsigned int i;
+
+	/*
+	 * Unfortunately, some hardware-based IR decoders don't provide
+	 * all bits for the complete IR code. In general, they provide only
+	 * the command part of the IR code. Yet, as it is possible to replace
+	 * the provided IR with another one, it is needed to allow loading
+	 * IR tables from other remotes. So, we support specifying a mask to
+	 * indicate the valid bits of the scancodes.
+	 */
+	if (dev->scancode_mask)
+		entry->scancode &= dev->scancode_mask;
+
+	/*
+	 * First check if we already have a mapping for this command.
+	 * Note that the keytable is sorted first on protocol and second
+	 * on scancode (lowest to highest).
+	 */
+	for (i = 0; i < rc_map->len; i++) {
+		if (rc_map->scan[i].protocol < entry->protocol)
+			continue;
+
+		if (rc_map->scan[i].protocol > entry->protocol)
+			break;
+
+		if (rc_map->scan[i].scancode < entry->scancode)
+			continue;
+
+		if (rc_map->scan[i].scancode > entry->scancode)
+			break;
+
+		return i;
+	}
+
+	/* No previous mapping found, we might need to grow the table */
+	if (rc_map->size == rc_map->len) {
+		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+			return -1U;
+	}
+
+	/* i is the proper index to insert our new keycode */
+	if (i < rc_map->len)
+		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
+			(rc_map->len - i) * sizeof(struct rc_map_table));
+	rc_map->scan[i].scancode = entry->scancode;
+	rc_map->scan[i].protocol = entry->protocol;
+	rc_map->scan[i].keycode = KEY_RESERVED;
+	rc_map->len++;
+
+	return i;
+}
+
+/**
+ * guess_protocol() - heuristics to guess the protocol for a scancode
+ * @rdev:	the struct rc_dev device descriptor
+ * @return:	the guessed RC_TYPE_* protocol
+ *
+ * Internal routine to guess the current IR protocol for legacy ioctls.
+ */
+static inline enum rc_type guess_protocol(struct rc_dev *rdev)
+{
+	struct rc_map *rc_map = &rdev->rc_map;
+
+	if (hweight64(rdev->enabled_protocols) == 1)
+		return rc_bitmap_to_type(rdev->enabled_protocols);
+	else if (hweight64(rdev->allowed_protocols) == 1)
+		return rc_bitmap_to_type(rdev->allowed_protocols);
+	else if (rc_map->len > 0)
+		return rc_map->scan[0].protocol;
+	else
+		return RC_TYPE_OTHER;
+}
+
+/**
+ * to_nec32() - helper function to try to convert misc NEC scancodes to NEC32
+ * @orig:	original scancode
+ * @return:	NEC32 scancode
+ *
+ * This helper routine is used to provide backwards compatibility.
+ */
+static u32 to_nec32(u32 orig)
+{
+	u8 b3 = (u8)(orig >> 16);
+	u8 b2 = (u8)(orig >>  8);
+	u8 b1 = (u8)(orig >>  0);
+
+	if (orig <= 0xffff)
+		/* Plain old NEC */
+		return b2 << 24 | ((u8)~b2) << 16 |  b1 << 8 | ((u8)~b1);
+	else if (orig <= 0xffffff)
+		/* NEC extended */
+		return b3 << 24 | b2 << 16 |  b1 << 8 | ((u8)~b1);
+	else
+		/* NEC32 */
+		return orig;
+}
+
+/**
+ * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * @idev:	the struct input_dev device descriptor
+ * @scancode:	the desired scancode
+ * @keycode:	result
+ * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ */
+int ir_setkeycode(struct input_dev *idev,
+		  const struct input_keymap_entry *ke,
+		  unsigned int *old_keycode)
+{
+	struct rc_dev *rdev = input_get_drvdata(idev);
+	struct rc_map *rc_map = &rdev->rc_map;
+	unsigned int index;
+	struct rc_map_table entry;
+	int retval = 0;
+	unsigned long flags;
+
+	entry.keycode = ke->keycode;
+
+	spin_lock_irqsave(&rc_map->lock, flags);
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		index = ke->index;
+		if (index >= rc_map->len) {
+			retval = -EINVAL;
+			goto out;
+		}
+	} else if (ke->len == sizeof(int)) {
+		/* Legacy EVIOCSKEYCODE ioctl */
+		u32 scancode;
+		retval = input_scancode_to_scalar(ke, &scancode);
+		if (retval)
+			goto out;
+
+		entry.scancode = scancode;
+		entry.protocol = guess_protocol(rdev);
+		if (entry.protocol == RC_TYPE_NEC)
+			entry.scancode = to_nec32(scancode);
+
+		index = ir_establish_scancode(rdev, rc_map, &entry, true);
+		if (index >= rc_map->len) {
+			retval = -ENOMEM;
+			goto out;
+		}
+	} else if (ke->len == sizeof(struct rc_scancode)) {
+		/* New EVIOCSKEYCODE_V2 ioctl */
+		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+		entry.protocol = rke->rc.protocol;
+		entry.scancode = rke->rc.scancode;
+
+		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
+			retval = -EINVAL;
+			goto out;
+		}
+
+		index = ir_establish_scancode(rdev, rc_map, &entry, true);
+		if (index >= rc_map->len) {
+			retval = -ENOMEM;
+			goto out;
+		}
+	} else {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
+
+out:
+	spin_unlock_irqrestore(&rc_map->lock, flags);
+	return retval;
+}
+
+/**
+ * ir_setkeytable() - sets several entries in the scancode->keycode table
+ * @dev:	the struct rc_dev device descriptor
+ * @to:		the struct rc_map to copy entries to
+ * @from:	the struct rc_map to copy entries from
+ * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle table initialization.
+ */
+int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
+{
+	struct rc_map *rc_map = &dev->rc_map;
+	struct rc_map_table entry;
+	unsigned int i, index;
+	int rc;
+
+	rc = ir_create_table(rc_map, from->name, from->size);
+	if (rc)
+		return rc;
+
+	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+		   rc_map->size, rc_map->alloc);
+
+	for (i = 0; i < from->size; i++) {
+		if (from->rc_type == RC_TYPE_NEC)
+			entry.scancode = to_nec32(from->scan[i].scancode);
+		else
+			entry.scancode = from->scan[i].scancode;
+
+		entry.protocol = from->rc_type;
+		index = ir_establish_scancode(dev, rc_map, &entry, false);
+		if (index >= rc_map->len) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
+	}
+
+	if (rc)
+		ir_free_table(rc_map);
+
+	return rc;
+}
+
+/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_map:	the struct rc_map to search
+ * @protocol:	protocol to look for in the table
+ * @scancode:	scancode to look for in the table
+ * @return:	index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
+					  u16 protocol, u64 scancode)
+{
+	int start = 0;
+	int end = rc_map->len - 1;
+	int mid;
+	struct rc_map_table *m;
+
+	while (start <= end) {
+		mid = (start + end) / 2;
+		m = &rc_map->scan[mid];
+
+		if (m->protocol < protocol)
+			start = mid + 1;
+		else if (m->protocol > protocol)
+			end = mid - 1;
+		else if (m->scancode < scancode)
+			start = mid + 1;
+		else if (m->scancode > scancode)
+			end = mid - 1;
+		else
+			return mid;
+	}
+
+	return -1U;
+}
+
+/**
+ * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * @idev:	the struct input_dev device descriptor
+ * @scancode:	the desired scancode
+ * @keycode:	used to return the keycode, if found, or KEY_RESERVED
+ * @return:	always returns zero.
+ *
+ * This routine is used to handle evdev EVIOCGKEY ioctl.
+ */
+int ir_getkeycode(struct input_dev *idev,
+		  struct input_keymap_entry *ke)
+{
+	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+	struct rc_dev *rdev = input_get_drvdata(idev);
+	struct rc_map *rc_map = &rdev->rc_map;
+	struct rc_map_table *entry;
+	unsigned long flags;
+	unsigned int index;
+	int retval;
+
+	spin_lock_irqsave(&rc_map->lock, flags);
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		index = ke->index;
+	} else if (ke->len == sizeof(int)) {
+		/* Legacy EVIOCGKEYCODE ioctl */
+		u32 scancode;
+		u16 protocol;
+
+		retval = input_scancode_to_scalar(ke, &scancode);
+		if (retval)
+			goto out;
+
+		protocol = guess_protocol(rdev);
+		if (protocol == RC_TYPE_NEC)
+			scancode = to_nec32(scancode);
+
+		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+
+	} else if (ke->len == sizeof(struct rc_scancode)) {
+		/* New EVIOCGKEYCODE_V2 ioctl */
+		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
+			retval = -EINVAL;
+			goto out;
+		}
+
+		index = ir_lookup_by_scancode(rc_map,
+					      rke->rc.protocol, rke->rc.scancode);
+
+	} else {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	if (index < rc_map->len) {
+		entry = &rc_map->scan[index];
+		ke->index = index;
+		ke->keycode = entry->keycode;
+		if (ke->len == sizeof(int)) {
+			u32 scancode = entry->scancode;
+			memcpy(ke->scancode, &scancode, sizeof(scancode));
+		} else {
+			ke->len = sizeof(struct rc_scancode);
+			rke->rc.protocol = entry->protocol;
+			rke->rc.scancode = entry->scancode;
+		}
+
+	} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
+		/*
+		 * We do not really know the valid range of scancodes
+		 * so let's respond with KEY_RESERVED to anything we
+		 * do not have mapping for [yet].
+		 */
+		ke->index = index;
+		ke->keycode = KEY_RESERVED;
+	} else {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	retval = 0;
+
+out:
+	spin_unlock_irqrestore(&rc_map->lock, flags);
+	return retval;
+}
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol to look for
+ * @scancode:	the scancode to look for
+ * @return:	the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. Normally it should not be used since drivers should have no
+ * interest in keycodes.
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+			    enum rc_type protocol, u64 scancode)
+{
+	struct rc_map *rc_map = &dev->rc_map;
+	unsigned int keycode;
+	unsigned int index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rc_map->lock, flags);
+
+	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+	keycode = index < rc_map->len ?
+			rc_map->scan[index].keycode : KEY_RESERVED;
+
+	spin_unlock_irqrestore(&rc_map->lock, flags);
+
+	if (keycode != KEY_RESERVED)
+		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
+			   dev->input_name, protocol,
+			   (unsigned long long)scancode, keycode);
+
+	return keycode;
+}
+EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
+
+/**
+ * ir_do_keyup() - internal function to signal the release of a keypress
+ * @dev:	the struct rc_dev descriptor of the device
+ * @sync:	whether or not to call input_sync
+ *
+ * This function is used internally to release a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keyup(struct rc_dev *dev, bool sync)
+{
+	if (!dev->keypressed)
+		return;
+
+	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+	input_report_key(dev->input_dev, dev->last_keycode, 0);
+	led_trigger_event(led_feedback, LED_OFF);
+	if (sync)
+		input_sync(dev->input_dev);
+	dev->keypressed = false;
+}
+
+/**
+ * rc_keyup() - signals the release of a keypress
+ * @dev:	the struct rc_dev descriptor of the device
+ *
+ * This routine is used to signal that a key has been released on the
+ * remote control.
+ */
+void rc_keyup(struct rc_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->keylock, flags);
+	ir_do_keyup(dev, true);
+	spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keyup);
+
+/**
+ * ir_timer_keyup() - generates a keyup event after a timeout
+ * @cookie:	a pointer to the struct rc_dev for the device
+ *
+ * This routine will generate a keyup event some time after a keydown event
+ * is generated when no further activity has been detected.
+ */
+void ir_timer_keyup(unsigned long cookie)
+{
+	struct rc_dev *dev = (struct rc_dev *)cookie;
+	unsigned long flags;
+
+	/*
+	 * ir->keyup_jiffies is used to prevent a race condition if a
+	 * hardware interrupt occurs at this point and the keyup timer
+	 * event is moved further into the future as a result.
+	 *
+	 * The timer will then be reactivated and this function called
+	 * again in the future. We need to exit gracefully in that case
+	 * to allow the input subsystem to do its auto-repeat magic or
+	 * a keyup event might follow immediately after the keydown.
+	 */
+	spin_lock_irqsave(&dev->keylock, flags);
+	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
+		ir_do_keyup(dev, true);
+	spin_unlock_irqrestore(&dev->keylock, flags);
+}
+
+/**
+ * rc_repeat() - signals that a key is still pressed
+ * @dev:	the struct rc_dev descriptor of the device
+ *
+ * This routine is used by IR decoders when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
+ */
+void rc_repeat(struct rc_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->keylock, flags);
+
+	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
+	input_sync(dev->input_dev);
+	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
+
+	if (!dev->keypressed)
+		goto out;
+
+	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+
+out:
+	spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_repeat);
+
+/**
+ * ir_do_keydown() - internal function to process a keypress
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol of the keypress
+ * @scancode:   the scancode of the keypress
+ * @keycode:    the keycode of the keypress
+ * @toggle:     the toggle value of the keypress
+ *
+ * This function is used internally to register a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+			  u32 scancode, u32 keycode, u8 toggle)
+{
+	bool new_event = (!dev->keypressed		 ||
+			  dev->last_protocol != protocol ||
+			  dev->last_scancode != scancode ||
+			  dev->last_toggle   != toggle);
+
+	if (new_event && dev->keypressed)
+		ir_do_keyup(dev, false);
+
+	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+	/*
+	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
+	 *	 scancode into 32 bit pieces and feed them to userspace
+	 *	 as one or more RC_KEY_SCANCODE_PART events followed
+	 *	 by a final RC_KEY_SCANCODE event.
+	 */
+	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
+
+	if (new_event && keycode != KEY_RESERVED) {
+		/* Register a keypress */
+		dev->keypressed = true;
+		dev->last_protocol = protocol;
+		dev->last_scancode = scancode;
+		dev->last_toggle = toggle;
+		dev->last_keycode = keycode;
+
+		IR_dprintk(1, "%s: key down event, "
+			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+			   dev->input_name, keycode, protocol, scancode);
+		input_report_key(dev->input_dev, keycode, 1);
+
+		led_trigger_event(led_feedback, LED_FULL);
+	}
+
+	input_sync(dev->input_dev);
+}
+
+/**
+ * rc_keydown() - generates input event for a key press
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
+ * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
+ *              support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control.
+ */
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
+{
+	unsigned long flags;
+	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
+
+	spin_lock_irqsave(&dev->keylock, flags);
+	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
+
+	if (dev->keypressed) {
+		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+	}
+	spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown);
+
+/**
+ * rc_keydown_notimeout() - generates input event for a key press without
+ *                          an automatic keyup event at a later time
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
+ * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
+ *              support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control. The driver must manually call rc_keyup() at a later stage.
+ */
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
+			  u32 scancode, u8 toggle)
+{
+	unsigned long flags;
+	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
+
+	spin_lock_irqsave(&dev->keylock, flags);
+	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
+	spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
+
+int rc_input_open(struct input_dev *idev)
+{
+	struct rc_dev *rdev = input_get_drvdata(idev);
+
+	return rc_open(rdev);
+}
+
+void rc_input_close(struct input_dev *idev)
+{
+	struct rc_dev *rdev = input_get_drvdata(idev);
+	rc_close(rdev);
+}
+
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index cc2f713..a01fce2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -25,19 +25,9 @@
 #include <linux/poll.h>
 #include "rc-core-priv.h"
 
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE		256
-#define IR_TAB_MAX_SIZE		8192
 #define RC_DEV_MAX		256
 #define RC_RX_BUFFER_SIZE	1024
-
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
-
-/* Used to keep track of known keymaps */
-static LIST_HEAD(rc_map_list);
-static DEFINE_SPINLOCK(rc_map_lock);
-static struct led_trigger *led_feedback;
+struct led_trigger *led_feedback;
 
 /* Used to keep track of rc devices */
 static DEFINE_IDA(rc_ida);
@@ -115,821 +105,6 @@ void rc_event(struct rc_dev *dev, u16 type, u16 code, u32 val)
 }
 EXPORT_SYMBOL_GPL(rc_event);
 
-static struct rc_map_list *seek_rc_map(const char *name)
-{
-	struct rc_map_list *map = NULL;
-
-	spin_lock(&rc_map_lock);
-	list_for_each_entry(map, &rc_map_list, list) {
-		if (!strcmp(name, map->map.name)) {
-			spin_unlock(&rc_map_lock);
-			return map;
-		}
-	}
-	spin_unlock(&rc_map_lock);
-
-	return NULL;
-}
-
-struct rc_map *rc_map_get(const char *name)
-{
-
-	struct rc_map_list *map;
-
-	map = seek_rc_map(name);
-#ifdef MODULE
-	if (!map) {
-		int rc = request_module("%s", name);
-		if (rc < 0) {
-			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
-			return NULL;
-		}
-		msleep(20);	/* Give some time for IR to register */
-
-		map = seek_rc_map(name);
-	}
-#endif
-	if (!map) {
-		printk(KERN_ERR "IR keymap %s not found\n", name);
-		return NULL;
-	}
-
-	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
-
-	return &map->map;
-}
-EXPORT_SYMBOL_GPL(rc_map_get);
-
-int rc_map_register(struct rc_map_list *map)
-{
-	spin_lock(&rc_map_lock);
-	list_add_tail(&map->list, &rc_map_list);
-	spin_unlock(&rc_map_lock);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rc_map_register);
-
-void rc_map_unregister(struct rc_map_list *map)
-{
-	spin_lock(&rc_map_lock);
-	list_del(&map->list);
-	spin_unlock(&rc_map_lock);
-}
-EXPORT_SYMBOL_GPL(rc_map_unregister);
-
-
-static struct rc_map_table empty[] = {
-	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
-};
-
-static struct rc_map_list empty_map = {
-	.map = {
-		.scan    = empty,
-		.size    = ARRAY_SIZE(empty),
-		.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */
-		.name    = RC_MAP_EMPTY,
-	}
-};
-
-/**
- * ir_create_table() - initializes a scancode table
- * @rc_map:	the rc_map to initialize
- * @name:	name to assign to the table
- * @size:	initial size of the table
- * @return:	zero on success or a negative error code
- *
- * This routine will initialize the rc_map and will allocate
- * memory to hold at least the specified number of elements.
- */
-static int ir_create_table(struct rc_map *rc_map,
-			   const char *name, size_t size)
-{
-	rc_map->name = name;
-	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
-	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
-	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
-	if (!rc_map->scan)
-		return -ENOMEM;
-
-	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-		   rc_map->size, rc_map->alloc);
-	return 0;
-}
-
-/**
- * ir_free_table() - frees memory allocated by a scancode table
- * @rc_map:	the table whose mappings need to be freed
- *
- * This routine will free memory alloctaed for key mappings used by given
- * scancode table.
- */
-static void ir_free_table(struct rc_map *rc_map)
-{
-	rc_map->size = 0;
-	kfree(rc_map->scan);
-	rc_map->scan = NULL;
-}
-
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_map:	the rc_map to resize
- * @gfp_flags:	gfp flags to use when allocating memory
- * @return:	zero on success or a negative error code
- *
- * This routine will shrink the rc_map if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
-{
-	unsigned int oldalloc = rc_map->alloc;
-	unsigned int newalloc = oldalloc;
-	struct rc_map_table *oldscan = rc_map->scan;
-	struct rc_map_table *newscan;
-
-	if (rc_map->size == rc_map->len) {
-		/* All entries in use -> grow keytable */
-		if (rc_map->alloc >= IR_TAB_MAX_SIZE)
-			return -ENOMEM;
-
-		newalloc *= 2;
-		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
-	}
-
-	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
-		/* Less than 1/3 of entries in use -> shrink keytable */
-		newalloc /= 2;
-		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
-	}
-
-	if (newalloc == oldalloc)
-		return 0;
-
-	newscan = kmalloc(newalloc, gfp_flags);
-	if (!newscan) {
-		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
-		return -ENOMEM;
-	}
-
-	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
-	rc_map->scan = newscan;
-	rc_map->alloc = newalloc;
-	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
-	kfree(oldscan);
-	return 0;
-}
-
-/**
- * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
- * @rc_map:	scancode table to be adjusted
- * @index:	index of the mapping that needs to be updated
- * @keycode:	the desired keycode
- * @return:	previous keycode assigned to the mapping
- *
- * This routine is used to update scancode->keycode mapping at given
- * position.
- */
-static unsigned int ir_update_mapping(struct rc_dev *dev,
-				      struct rc_map *rc_map,
-				      unsigned int index,
-				      unsigned int new_keycode)
-{
-	int old_keycode = rc_map->scan[index].keycode;
-	int i;
-
-	/* Did the user wish to remove the mapping? */
-	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
-		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
-			   index, rc_map->scan[index].protocol,
-			   (unsigned long long)rc_map->scan[index].scancode);
-		rc_map->len--;
-		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
-			(rc_map->len - index) * sizeof(struct rc_map_table));
-	} else {
-		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
-			   "with key 0x%04x\n",
-			   index,
-			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
-			   rc_map->scan[index].protocol,
-			   (unsigned long long)rc_map->scan[index].scancode,
-			   new_keycode);
-		rc_map->scan[index].keycode = new_keycode;
-		__set_bit(new_keycode, dev->input_dev->keybit);
-	}
-
-	if (old_keycode != KEY_RESERVED) {
-		/* A previous mapping was updated... */
-		__clear_bit(old_keycode, dev->input_dev->keybit);
-		/* ... but another scancode might use the same keycode */
-		for (i = 0; i < rc_map->len; i++) {
-			if (rc_map->scan[i].keycode == old_keycode) {
-				__set_bit(old_keycode, dev->input_dev->keybit);
-				break;
-			}
-		}
-
-		/* Possibly shrink the keytable, failure is not a problem */
-		ir_resize_table(rc_map, GFP_ATOMIC);
-	}
-
-	return old_keycode;
-}
-
-/**
- * ir_establish_scancode() - set a keycode in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
- * @rc_map:	scancode table to be searched
- * @entry:	the entry to be added to the table
- * @resize:	controls whether we are allowed to resize the table to
- *		accomodate not yet present scancodes
- * @return:	index of the mapping containing scancode in question
- *		or -1U in case of failure.
- *
- * This routine is used to locate given scancode in rc_map.
- * If scancode is not yet present the routine will allocate a new slot
- * for it.
- */
-static unsigned int ir_establish_scancode(struct rc_dev *dev,
-					  struct rc_map *rc_map,
-					  struct rc_map_table *entry,
-					  bool resize)
-{
-	unsigned int i;
-
-	/*
-	 * Unfortunately, some hardware-based IR decoders don't provide
-	 * all bits for the complete IR code. In general, they provide only
-	 * the command part of the IR code. Yet, as it is possible to replace
-	 * the provided IR with another one, it is needed to allow loading
-	 * IR tables from other remotes. So, we support specifying a mask to
-	 * indicate the valid bits of the scancodes.
-	 */
-	if (dev->scancode_mask)
-		entry->scancode &= dev->scancode_mask;
-
-	/*
-	 * First check if we already have a mapping for this command.
-	 * Note that the keytable is sorted first on protocol and second
-	 * on scancode (lowest to highest).
-	 */
-	for (i = 0; i < rc_map->len; i++) {
-		if (rc_map->scan[i].protocol < entry->protocol)
-			continue;
-
-		if (rc_map->scan[i].protocol > entry->protocol)
-			break;
-
-		if (rc_map->scan[i].scancode < entry->scancode)
-			continue;
-
-		if (rc_map->scan[i].scancode > entry->scancode)
-			break;
-
-		return i;
-	}
-
-	/* No previous mapping found, we might need to grow the table */
-	if (rc_map->size == rc_map->len) {
-		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
-			return -1U;
-	}
-
-	/* i is the proper index to insert our new keycode */
-	if (i < rc_map->len)
-		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
-			(rc_map->len - i) * sizeof(struct rc_map_table));
-	rc_map->scan[i].scancode = entry->scancode;
-	rc_map->scan[i].protocol = entry->protocol;
-	rc_map->scan[i].keycode = KEY_RESERVED;
-	rc_map->len++;
-
-	return i;
-}
-
-/**
- * guess_protocol() - heuristics to guess the protocol for a scancode
- * @rdev:	the struct rc_dev device descriptor
- * @return:	the guessed RC_TYPE_* protocol
- *
- * Internal routine to guess the current IR protocol for legacy ioctls.
- */
-static inline enum rc_type guess_protocol(struct rc_dev *rdev)
-{
-	struct rc_map *rc_map = &rdev->rc_map;
-
-	if (hweight64(rdev->enabled_protocols) == 1)
-		return rc_bitmap_to_type(rdev->enabled_protocols);
-	else if (hweight64(rdev->allowed_protocols) == 1)
-		return rc_bitmap_to_type(rdev->allowed_protocols);
-	else if (rc_map->len > 0)
-		return rc_map->scan[0].protocol;
-	else
-		return RC_TYPE_OTHER;
-}
-
-/**
- * to_nec32() - helper function to try to convert misc NEC scancodes to NEC32
- * @orig:	original scancode
- * @return:	NEC32 scancode
- *
- * This helper routine is used to provide backwards compatibility.
- */
-static u32 to_nec32(u32 orig)
-{
-	u8 b3 = (u8)(orig >> 16);
-	u8 b2 = (u8)(orig >>  8);
-	u8 b1 = (u8)(orig >>  0);
-
-	if (orig <= 0xffff)
-		/* Plain old NEC */
-		return b2 << 24 | ((u8)~b2) << 16 |  b1 << 8 | ((u8)~b1);
-	else if (orig <= 0xffffff)
-		/* NEC extended */
-		return b3 << 24 | b2 << 16 |  b1 << 8 | ((u8)~b1);
-	else
-		/* NEC32 */
-		return orig;
-}
-
-/**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
- * @idev:	the struct input_dev device descriptor
- * @scancode:	the desired scancode
- * @keycode:	result
- * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
- *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
- */
-static int ir_setkeycode(struct input_dev *idev,
-			 const struct input_keymap_entry *ke,
-			 unsigned int *old_keycode)
-{
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	struct rc_map *rc_map = &rdev->rc_map;
-	unsigned int index;
-	struct rc_map_table entry;
-	int retval = 0;
-	unsigned long flags;
-
-	entry.keycode = ke->keycode;
-
-	spin_lock_irqsave(&rc_map->lock, flags);
-
-	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
-		index = ke->index;
-		if (index >= rc_map->len) {
-			retval = -EINVAL;
-			goto out;
-		}
-	} else if (ke->len == sizeof(int)) {
-		/* Legacy EVIOCSKEYCODE ioctl */
-		u32 scancode;
-		retval = input_scancode_to_scalar(ke, &scancode);
-		if (retval)
-			goto out;
-
-		entry.scancode = scancode;
-		entry.protocol = guess_protocol(rdev);
-		if (entry.protocol == RC_TYPE_NEC)
-			entry.scancode = to_nec32(scancode);
-
-		index = ir_establish_scancode(rdev, rc_map, &entry, true);
-		if (index >= rc_map->len) {
-			retval = -ENOMEM;
-			goto out;
-		}
-	} else if (ke->len == sizeof(struct rc_scancode)) {
-		/* New EVIOCSKEYCODE_V2 ioctl */
-		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
-		entry.protocol = rke->rc.protocol;
-		entry.scancode = rke->rc.scancode;
-
-		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
-			retval = -EINVAL;
-			goto out;
-		}
-
-		index = ir_establish_scancode(rdev, rc_map, &entry, true);
-		if (index >= rc_map->len) {
-			retval = -ENOMEM;
-			goto out;
-		}
-	} else {
-		retval = -EINVAL;
-		goto out;
-	}
-
-	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
-
-out:
-	spin_unlock_irqrestore(&rc_map->lock, flags);
-	return retval;
-}
-
-/**
- * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
- * @to:		the struct rc_map to copy entries to
- * @from:	the struct rc_map to copy entries from
- * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-static int ir_setkeytable(struct rc_dev *dev,
-			  const struct rc_map *from)
-{
-	struct rc_map *rc_map = &dev->rc_map;
-	struct rc_map_table entry;
-	unsigned int i, index;
-	int rc;
-
-	rc = ir_create_table(rc_map, from->name, from->size);
-	if (rc)
-		return rc;
-
-	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-		   rc_map->size, rc_map->alloc);
-
-	for (i = 0; i < from->size; i++) {
-		if (from->rc_type == RC_TYPE_NEC)
-			entry.scancode = to_nec32(from->scan[i].scancode);
-		else
-			entry.scancode = from->scan[i].scancode;
-
-		entry.protocol = from->rc_type;
-		index = ir_establish_scancode(dev, rc_map, &entry, false);
-		if (index >= rc_map->len) {
-			rc = -ENOMEM;
-			break;
-		}
-
-		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
-	}
-
-	if (rc)
-		ir_free_table(rc_map);
-
-	return rc;
-}
-
-/**
- * ir_lookup_by_scancode() - locate mapping by scancode
- * @rc_map:	the struct rc_map to search
- * @protocol:	protocol to look for in the table
- * @scancode:	scancode to look for in the table
- * @return:	index in the table, -1U if not found
- *
- * This routine performs binary search in RC keykeymap table for
- * given scancode.
- */
-static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
-					  u16 protocol, u64 scancode)
-{
-	int start = 0;
-	int end = rc_map->len - 1;
-	int mid;
-	struct rc_map_table *m;
-
-	while (start <= end) {
-		mid = (start + end) / 2;
-		m = &rc_map->scan[mid];
-
-		if (m->protocol < protocol)
-			start = mid + 1;
-		else if (m->protocol > protocol)
-			end = mid - 1;
-		else if (m->scancode < scancode)
-			start = mid + 1;
-		else if (m->scancode > scancode)
-			end = mid - 1;
-		else
-			return mid;
-	}
-
-	return -1U;
-}
-
-/**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
- * @idev:	the struct input_dev device descriptor
- * @scancode:	the desired scancode
- * @keycode:	used to return the keycode, if found, or KEY_RESERVED
- * @return:	always returns zero.
- *
- * This routine is used to handle evdev EVIOCGKEY ioctl.
- */
-static int ir_getkeycode(struct input_dev *idev,
-			 struct input_keymap_entry *ke)
-{
-	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	struct rc_map *rc_map = &rdev->rc_map;
-	struct rc_map_table *entry;
-	unsigned long flags;
-	unsigned int index;
-	int retval;
-
-	spin_lock_irqsave(&rc_map->lock, flags);
-
-	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
-		index = ke->index;
-	} else if (ke->len == sizeof(int)) {
-		/* Legacy EVIOCGKEYCODE ioctl */
-		u32 scancode;
-		u16 protocol;
-
-		retval = input_scancode_to_scalar(ke, &scancode);
-		if (retval)
-			goto out;
-
-		protocol = guess_protocol(rdev);
-		if (protocol == RC_TYPE_NEC)
-			scancode = to_nec32(scancode);
-
-		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
-
-	} else if (ke->len == sizeof(struct rc_scancode)) {
-		/* New EVIOCGKEYCODE_V2 ioctl */
-		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
-			retval = -EINVAL;
-			goto out;
-		}
-
-		index = ir_lookup_by_scancode(rc_map,
-					      rke->rc.protocol, rke->rc.scancode);
-
-	} else {
-		retval = -EINVAL;
-		goto out;
-	}
-
-	if (index < rc_map->len) {
-		entry = &rc_map->scan[index];
-		ke->index = index;
-		ke->keycode = entry->keycode;
-		if (ke->len == sizeof(int)) {
-			u32 scancode = entry->scancode;
-			memcpy(ke->scancode, &scancode, sizeof(scancode));
-		} else {
-			ke->len = sizeof(struct rc_scancode);
-			rke->rc.protocol = entry->protocol;
-			rke->rc.scancode = entry->scancode;
-		}
-
-	} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
-		/*
-		 * We do not really know the valid range of scancodes
-		 * so let's respond with KEY_RESERVED to anything we
-		 * do not have mapping for [yet].
-		 */
-		ke->index = index;
-		ke->keycode = KEY_RESERVED;
-	} else {
-		retval = -EINVAL;
-		goto out;
-	}
-
-	retval = 0;
-
-out:
-	spin_unlock_irqrestore(&rc_map->lock, flags);
-	return retval;
-}
-
-/**
- * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol to look for
- * @scancode:	the scancode to look for
- * @return:	the corresponding keycode, or KEY_RESERVED
- *
- * This routine is used by drivers which need to convert a scancode to a
- * keycode. Normally it should not be used since drivers should have no
- * interest in keycodes.
- */
-u32 rc_g_keycode_from_table(struct rc_dev *dev,
-			    enum rc_type protocol, u64 scancode)
-{
-	struct rc_map *rc_map = &dev->rc_map;
-	unsigned int keycode;
-	unsigned int index;
-	unsigned long flags;
-
-	spin_lock_irqsave(&rc_map->lock, flags);
-
-	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
-	keycode = index < rc_map->len ?
-			rc_map->scan[index].keycode : KEY_RESERVED;
-
-	spin_unlock_irqrestore(&rc_map->lock, flags);
-
-	if (keycode != KEY_RESERVED)
-		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
-			   dev->input_name, protocol,
-			   (unsigned long long)scancode, keycode);
-
-	return keycode;
-}
-EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
-
-/**
- * ir_do_keyup() - internal function to signal the release of a keypress
- * @dev:	the struct rc_dev descriptor of the device
- * @sync:	whether or not to call input_sync
- *
- * This function is used internally to release a keypress, it must be
- * called with keylock held.
- */
-static void ir_do_keyup(struct rc_dev *dev, bool sync)
-{
-	if (!dev->keypressed)
-		return;
-
-	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
-	input_report_key(dev->input_dev, dev->last_keycode, 0);
-	led_trigger_event(led_feedback, LED_OFF);
-	if (sync)
-		input_sync(dev->input_dev);
-	dev->keypressed = false;
-}
-
-/**
- * rc_keyup() - signals the release of a keypress
- * @dev:	the struct rc_dev descriptor of the device
- *
- * This routine is used to signal that a key has been released on the
- * remote control.
- */
-void rc_keyup(struct rc_dev *dev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keyup(dev, true);
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keyup);
-
-/**
- * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie:	a pointer to the struct rc_dev for the device
- *
- * This routine will generate a keyup event some time after a keydown event
- * is generated when no further activity has been detected.
- */
-static void ir_timer_keyup(unsigned long cookie)
-{
-	struct rc_dev *dev = (struct rc_dev *)cookie;
-	unsigned long flags;
-
-	/*
-	 * ir->keyup_jiffies is used to prevent a race condition if a
-	 * hardware interrupt occurs at this point and the keyup timer
-	 * event is moved further into the future as a result.
-	 *
-	 * The timer will then be reactivated and this function called
-	 * again in the future. We need to exit gracefully in that case
-	 * to allow the input subsystem to do its auto-repeat magic or
-	 * a keyup event might follow immediately after the keydown.
-	 */
-	spin_lock_irqsave(&dev->keylock, flags);
-	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
-		ir_do_keyup(dev, true);
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-
-/**
- * rc_repeat() - signals that a key is still pressed
- * @dev:	the struct rc_dev descriptor of the device
- *
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
- */
-void rc_repeat(struct rc_dev *dev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->keylock, flags);
-
-	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
-	input_sync(dev->input_dev);
-	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
-
-	if (!dev->keypressed)
-		goto out;
-
-	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
-	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
-
-out:
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_repeat);
-
-/**
- * ir_do_keydown() - internal function to process a keypress
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol of the keypress
- * @scancode:   the scancode of the keypress
- * @keycode:    the keycode of the keypress
- * @toggle:     the toggle value of the keypress
- *
- * This function is used internally to register a keypress, it must be
- * called with keylock held.
- */
-static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
-			  u32 scancode, u32 keycode, u8 toggle)
-{
-	bool new_event = (!dev->keypressed		 ||
-			  dev->last_protocol != protocol ||
-			  dev->last_scancode != scancode ||
-			  dev->last_toggle   != toggle);
-
-	if (new_event && dev->keypressed)
-		ir_do_keyup(dev, false);
-
-	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
-	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
-	/*
-	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
-	 *	 scancode into 32 bit pieces and feed them to userspace
-	 *	 as one or more RC_KEY_SCANCODE_PART events followed
-	 *	 by a final RC_KEY_SCANCODE event.
-	 */
-	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
-	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
-
-	if (new_event && keycode != KEY_RESERVED) {
-		/* Register a keypress */
-		dev->keypressed = true;
-		dev->last_protocol = protocol;
-		dev->last_scancode = scancode;
-		dev->last_toggle = toggle;
-		dev->last_keycode = keycode;
-
-		IR_dprintk(1, "%s: key down event, "
-			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
-			   dev->input_name, keycode, protocol, scancode);
-		input_report_key(dev->input_dev, keycode, 1);
-
-		led_trigger_event(led_feedback, LED_FULL);
-	}
-
-	input_sync(dev->input_dev);
-}
-
-/**
- * rc_keydown() - generates input event for a key press
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol for the keypress
- * @scancode:	the scancode for the keypress
- * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
- *              support toggle values, this should be set to zero)
- *
- * This routine is used to signal that a key has been pressed on the
- * remote control.
- */
-void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
-{
-	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
-
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
-
-	if (dev->keypressed) {
-		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
-		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
-	}
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keydown);
-
-/**
- * rc_keydown_notimeout() - generates input event for a key press without
- *                          an automatic keyup event at a later time
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol for the keypress
- * @scancode:	the scancode for the keypress
- * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
- *              support toggle values, this should be set to zero)
- *
- * This routine is used to signal that a key has been pressed on the
- * remote control. The driver must manually call rc_keyup() at a later stage.
- */
-void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
-			  u32 scancode, u8 toggle)
-{
-	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
-
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
-
 int rc_open(struct rc_dev *dev)
 {
 	int err = 0;
@@ -950,13 +125,6 @@ int rc_open(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_open);
 
-static int rc_input_open(struct input_dev *idev)
-{
-	struct rc_dev *rdev = input_get_drvdata(idev);
-
-	return rc_open(rdev);
-}
-
 void rc_close(struct rc_dev *dev)
 {
 	mutex_lock(&dev->lock);
@@ -968,12 +136,6 @@ void rc_close(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_close);
 
-static void rc_input_close(struct input_dev *idev)
-{
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	rc_close(rdev);
-}
-
 /* class for /sys/class/rc */
 static char *rc_devnode(struct device *dev, umode_t *mode)
 {
@@ -2143,6 +1305,19 @@ void rc_unregister_device(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
+static struct rc_map_table empty[] = {
+	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
+};
+
+static struct rc_map_list empty_map = {
+	.map = {
+		.scan    = empty,
+		.size    = ARRAY_SIZE(empty),
+		.rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
+		.name    = RC_MAP_EMPTY,
+	}
+};
+
 static int __init rc_core_init(void)
 {
 	int err;


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

* [PATCH 32/49] rc-core: prepare for multiple keytables
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (30 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c David Härdeman
@ 2014-04-03 23:33 ` David Härdeman
  2014-07-25 22:52   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 33/49] rc-core: make the keytable of rc_dev an array David Härdeman
                   ` (18 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:33 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Introduce struct rc_keytable which essentially maintains an input device
and a table with scancode,protocol <-> keycode mappings. Move the relevant
members from struct rc_dev into struct rc_keytable.

This is in preparation for supporting multiple keytables, where each
keytable would correspond to one physical remote controller, each with
its own keymap and input device for reporting events to userspace.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |   16 +-
 drivers/media/rc/rc-keytable.c  |  341 ++++++++++++++++++++++-----------------
 drivers/media/rc/rc-main.c      |  224 +++++++++++---------------
 include/media/rc-core.h         |   62 +++++--
 4 files changed, 338 insertions(+), 305 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 6da8a0d..7a7770e 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -158,16 +158,12 @@ void ir_raw_init(void);
 /*
  * Methods from rc-keytable.c to be used internally
  */
-void ir_timer_keyup(unsigned long cookie);
-int rc_input_open(struct input_dev *idev);
-void rc_input_close(struct input_dev *idev);
-int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from);
-void ir_free_table(struct rc_map *rc_map);
-int ir_getkeycode(struct input_dev *idev,
-		  struct input_keymap_entry *ke);
-int ir_setkeycode(struct input_dev *idev,
-		  const struct input_keymap_entry *ke,
-		  unsigned int *old_keycode);
+void rc_keytable_keyup(struct rc_keytable *kt);
+void rc_keytable_repeat(struct rc_keytable *kt);
+void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+			 u32 scancode, u8 toggle, bool autokeyup);
+int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map);
+void rc_keytable_del(struct rc_dev *dev);
 
 /* Only to be used by rc-core and ir-lirc-codec */
 void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 25faeba..0f1b817 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -187,7 +187,7 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
 
 /**
  * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
+ * @kt:		the struct rc_keytable
  * @rc_map:	scancode table to be adjusted
  * @index:	index of the mapping that needs to be updated
  * @keycode:	the desired keycode
@@ -196,7 +196,7 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
  * This routine is used to update scancode->keycode mapping at given
  * position.
  */
-static unsigned int ir_update_mapping(struct rc_dev *dev,
+static unsigned int ir_update_mapping(struct rc_keytable *kt,
 				      struct rc_map *rc_map,
 				      unsigned int index,
 				      unsigned int new_keycode)
@@ -221,16 +221,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 			   (unsigned long long)rc_map->scan[index].scancode,
 			   new_keycode);
 		rc_map->scan[index].keycode = new_keycode;
-		__set_bit(new_keycode, dev->input_dev->keybit);
+		__set_bit(new_keycode, kt->idev->keybit);
 	}
 
 	if (old_keycode != KEY_RESERVED) {
 		/* A previous mapping was updated... */
-		__clear_bit(old_keycode, dev->input_dev->keybit);
+		__clear_bit(old_keycode, kt->idev->keybit);
 		/* ... but another scancode might use the same keycode */
 		for (i = 0; i < rc_map->len; i++) {
 			if (rc_map->scan[i].keycode == old_keycode) {
-				__set_bit(old_keycode, dev->input_dev->keybit);
+				__set_bit(old_keycode, kt->idev->keybit);
 				break;
 			}
 		}
@@ -244,7 +244,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 
 /**
  * ir_establish_scancode() - set a keycode in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
+ * @kt:		the struct rc_keytable descriptor
  * @rc_map:	scancode table to be searched
  * @entry:	the entry to be added to the table
  * @resize:	controls whether we are allowed to resize the table to
@@ -256,7 +256,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
  * If scancode is not yet present the routine will allocate a new slot
  * for it.
  */
-static unsigned int ir_establish_scancode(struct rc_dev *dev,
+static unsigned int ir_establish_scancode(struct rc_keytable *kt,
 					  struct rc_map *rc_map,
 					  struct rc_map_table *entry,
 					  bool resize)
@@ -271,8 +271,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 	 * IR tables from other remotes. So, we support specifying a mask to
 	 * indicate the valid bits of the scancodes.
 	 */
-	if (dev->scancode_mask)
-		entry->scancode &= dev->scancode_mask;
+	if (kt->dev->scancode_mask)
+		entry->scancode &= kt->dev->scancode_mask;
 
 	/*
 	 * First check if we already have a mapping for this command.
@@ -322,7 +322,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
  */
 static inline enum rc_type guess_protocol(struct rc_dev *rdev)
 {
-	struct rc_map *rc_map = &rdev->rc_map;
+	struct rc_map *rc_map = &rdev->kt->rc_map;
 
 	if (hweight64(rdev->enabled_protocols) == 1)
 		return rc_bitmap_to_type(rdev->enabled_protocols);
@@ -367,12 +367,13 @@ static u32 to_nec32(u32 orig)
  *
  * This routine is used to handle evdev EVIOCSKEY ioctl.
  */
-int ir_setkeycode(struct input_dev *idev,
-		  const struct input_keymap_entry *ke,
-		  unsigned int *old_keycode)
+static int ir_setkeycode(struct input_dev *idev,
+			 const struct input_keymap_entry *ke,
+			 unsigned int *old_keycode)
 {
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	struct rc_map *rc_map = &rdev->rc_map;
+	struct rc_keytable *kt = input_get_drvdata(idev);
+	struct rc_dev *rdev = kt->dev;
+	struct rc_map *rc_map = &kt->rc_map;
 	unsigned int index;
 	struct rc_map_table entry;
 	int retval = 0;
@@ -400,7 +401,7 @@ int ir_setkeycode(struct input_dev *idev,
 		if (entry.protocol == RC_TYPE_NEC)
 			entry.scancode = to_nec32(scancode);
 
-		index = ir_establish_scancode(rdev, rc_map, &entry, true);
+		index = ir_establish_scancode(kt, rc_map, &entry, true);
 		if (index >= rc_map->len) {
 			retval = -ENOMEM;
 			goto out;
@@ -416,7 +417,7 @@ int ir_setkeycode(struct input_dev *idev,
 			goto out;
 		}
 
-		index = ir_establish_scancode(rdev, rc_map, &entry, true);
+		index = ir_establish_scancode(kt, rc_map, &entry, true);
 		if (index >= rc_map->len) {
 			retval = -ENOMEM;
 			goto out;
@@ -426,7 +427,7 @@ int ir_setkeycode(struct input_dev *idev,
 		goto out;
 	}
 
-	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
+	*old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
 
 out:
 	spin_unlock_irqrestore(&rc_map->lock, flags);
@@ -435,16 +436,16 @@ out:
 
 /**
  * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @dev:	the struct rc_dev device descriptor
+ * @kt:		the struct rc_keytable descriptor
  * @to:		the struct rc_map to copy entries to
  * @from:	the struct rc_map to copy entries from
  * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
  *
  * This routine is used to handle table initialization.
  */
-int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
+int rc_setkeytable(struct rc_keytable *kt, const struct rc_map *from)
 {
-	struct rc_map *rc_map = &dev->rc_map;
+	struct rc_map *rc_map = &kt->rc_map;
 	struct rc_map_table entry;
 	unsigned int i, index;
 	int rc;
@@ -463,13 +464,13 @@ int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
 			entry.scancode = from->scan[i].scancode;
 
 		entry.protocol = from->rc_type;
-		index = ir_establish_scancode(dev, rc_map, &entry, false);
+		index = ir_establish_scancode(kt, rc_map, &entry, false);
 		if (index >= rc_map->len) {
 			rc = -ENOMEM;
 			break;
 		}
 
-		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
+		ir_update_mapping(kt, rc_map, index, from->scan[i].keycode);
 	}
 
 	if (rc)
@@ -528,8 +529,9 @@ int ir_getkeycode(struct input_dev *idev,
 		  struct input_keymap_entry *ke)
 {
 	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	struct rc_map *rc_map = &rdev->rc_map;
+	struct rc_keytable *kt = input_get_drvdata(idev);
+	struct rc_dev *rdev = kt->dev;
+	struct rc_map *rc_map = &kt->rc_map;
 	struct rc_map_table *entry;
 	unsigned long flags;
 	unsigned int index;
@@ -616,7 +618,7 @@ out:
 u32 rc_g_keycode_from_table(struct rc_dev *dev,
 			    enum rc_type protocol, u64 scancode)
 {
-	struct rc_map *rc_map = &dev->rc_map;
+	struct rc_map *rc_map = &dev->kt->rc_map;
 	unsigned int keycode;
 	unsigned int index;
 	unsigned long flags;
@@ -639,53 +641,51 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
 EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
 
 /**
- * ir_do_keyup() - internal function to signal the release of a keypress
- * @dev:	the struct rc_dev descriptor of the device
+ * rc_do_keyup() - internal function to signal the release of a keypress
+ * @kt:		the keytable
  * @sync:	whether or not to call input_sync
  *
  * This function is used internally to release a keypress, it must be
  * called with keylock held.
  */
-static void ir_do_keyup(struct rc_dev *dev, bool sync)
+static void rc_do_keyup(struct rc_keytable *kt, bool sync)
 {
-	if (!dev->keypressed)
+	if (!kt->keypressed)
 		return;
 
-	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
-	input_report_key(dev->input_dev, dev->last_keycode, 0);
+	IR_dprintk(1, "keyup key 0x%04x\n", kt->last_keycode);
+	input_report_key(kt->idev, kt->last_keycode, 0);
 	led_trigger_event(led_feedback, LED_OFF);
 	if (sync)
-		input_sync(dev->input_dev);
-	dev->keypressed = false;
+		input_sync(kt->idev);
+	kt->keypressed = false;
 }
 
 /**
- * rc_keyup() - signals the release of a keypress
- * @dev:	the struct rc_dev descriptor of the device
+ * rc_keytable_keyup() - signals the release of a keypress
+ * @kt:		the keytable
  *
- * This routine is used to signal that a key has been released on the
- * remote control.
+ * This routine is used to generate input keyup events.
  */
-void rc_keyup(struct rc_dev *dev)
+void rc_keytable_keyup(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keyup(dev, true);
-	spin_unlock_irqrestore(&dev->keylock, flags);
+	spin_lock_irqsave(&kt->keylock, flags);
+	rc_do_keyup(kt, true);
+	spin_unlock_irqrestore(&kt->keylock, flags);
 }
-EXPORT_SYMBOL_GPL(rc_keyup);
 
 /**
  * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie:	a pointer to the struct rc_dev for the device
+ * @cookie:	a pointer to the struct rc_keytable
  *
  * This routine will generate a keyup event some time after a keydown event
  * is generated when no further activity has been detected.
  */
-void ir_timer_keyup(unsigned long cookie)
+static void rc_timer_keyup(unsigned long cookie)
 {
-	struct rc_dev *dev = (struct rc_dev *)cookie;
+	struct rc_keytable *kt = (struct rc_keytable *)cookie;
 	unsigned long flags;
 
 	/*
@@ -698,154 +698,203 @@ void ir_timer_keyup(unsigned long cookie)
 	 * to allow the input subsystem to do its auto-repeat magic or
 	 * a keyup event might follow immediately after the keydown.
 	 */
-	spin_lock_irqsave(&dev->keylock, flags);
-	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
-		ir_do_keyup(dev, true);
-	spin_unlock_irqrestore(&dev->keylock, flags);
+	spin_lock_irqsave(&kt->keylock, flags);
+	if (time_is_before_eq_jiffies(kt->keyup_jiffies))
+		rc_do_keyup(kt, true);
+	spin_unlock_irqrestore(&kt->keylock, flags);
 }
 
 /**
- * rc_repeat() - signals that a key is still pressed
- * @dev:	the struct rc_dev descriptor of the device
+ * rc_keytable_repeat() - signals that a key is still pressed
+ * @kt:		the keytable
  *
  * This routine is used by IR decoders when a repeat message which does
  * not include the necessary bits to reproduce the scancode has been
  * received.
  */
-void rc_repeat(struct rc_dev *dev)
+void rc_keytable_repeat(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->keylock, flags);
+	spin_lock_irqsave(&kt->keylock, flags);
 
-	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
-	input_sync(dev->input_dev);
-	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
+	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
+	input_sync(kt->idev);
 
-	if (!dev->keypressed)
+	if (!kt->keypressed)
 		goto out;
 
-	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
-	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+	kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
 
 out:
-	spin_unlock_irqrestore(&dev->keylock, flags);
+	spin_unlock_irqrestore(&kt->keylock, flags);
 }
-EXPORT_SYMBOL_GPL(rc_repeat);
 
 /**
- * ir_do_keydown() - internal function to process a keypress
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol of the keypress
- * @scancode:   the scancode of the keypress
- * @keycode:    the keycode of the keypress
- * @toggle:     the toggle value of the keypress
+ * rc_keytable_keydown() - generates input event for a key press
+ * @kt:		the struct rc_keytable descriptor of the keytable
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
+ * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
+ *		support toggle values, this should be set to zero)
+ * @autoup:	should an automatic keyup event be generated in the future
  *
- * This function is used internally to register a keypress, it must be
- * called with keylock held.
+ * This routine is used to signal that a keypress has been detected.
  */
-static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
-			  u32 scancode, u32 keycode, u8 toggle)
+void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+			 u32 scancode, u8 toggle, bool autoup)
 {
-	bool new_event = (!dev->keypressed		 ||
-			  dev->last_protocol != protocol ||
-			  dev->last_scancode != scancode ||
-			  dev->last_toggle   != toggle);
+	unsigned long flags;
+	u32 keycode;
+	bool new_event;
 
-	if (new_event && dev->keypressed)
-		ir_do_keyup(dev, false);
+	spin_lock_irqsave(&kt->keylock, flags);
 
-	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
-	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
-	/*
-	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
-	 *	 scancode into 32 bit pieces and feed them to userspace
-	 *	 as one or more RC_KEY_SCANCODE_PART events followed
-	 *	 by a final RC_KEY_SCANCODE event.
-	 */
-	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
-	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
+	keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
+	new_event = (!kt->keypressed ||
+		     kt->last_protocol != protocol ||
+		     kt->last_scancode != scancode ||
+		     kt->last_toggle != toggle);
+
+	if (new_event && kt->keypressed)
+		rc_do_keyup(kt, false);
+
+	input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
 
 	if (new_event && keycode != KEY_RESERVED) {
 		/* Register a keypress */
-		dev->keypressed = true;
-		dev->last_protocol = protocol;
-		dev->last_scancode = scancode;
-		dev->last_toggle = toggle;
-		dev->last_keycode = keycode;
+		kt->keypressed = true;
+		kt->last_protocol = protocol;
+		kt->last_scancode = scancode;
+		kt->last_toggle = toggle;
+		kt->last_keycode = keycode;
 
 		IR_dprintk(1, "%s: key down event, "
-			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
-			   dev->input_name, keycode, protocol, scancode);
-		input_report_key(dev->input_dev, keycode, 1);
-
-		led_trigger_event(led_feedback, LED_FULL);
+			   "key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
+			   kt->dev->input_name, keycode, protocol,
+			   (long long unsigned)scancode);
+		input_report_key(kt->idev, keycode, 1);
 	}
+	input_sync(kt->idev);
 
-	input_sync(dev->input_dev);
+	if (autoup && kt->keypressed) {
+		kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+	}
+	spin_unlock_irqrestore(&kt->keylock, flags);
 }
 
-/**
- * rc_keydown() - generates input event for a key press
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol for the keypress
- * @scancode:	the scancode for the keypress
- * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
- *              support toggle values, this should be set to zero)
- *
- * This routine is used to signal that a key has been pressed on the
- * remote control.
- */
-void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
+static int rc_input_open(struct input_dev *idev)
 {
-	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
+	struct rc_keytable *kt = input_get_drvdata(idev);
 
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
+	return rc_open(kt->dev);
+}
 
-	if (dev->keypressed) {
-		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
-		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
-	}
-	spin_unlock_irqrestore(&dev->keylock, flags);
+static void rc_input_close(struct input_dev *idev)
+{
+	struct rc_keytable *kt = input_get_drvdata(idev);
+
+	rc_close(kt->dev);
 }
-EXPORT_SYMBOL_GPL(rc_keydown);
 
 /**
- * rc_keydown_notimeout() - generates input event for a key press without
- *                          an automatic keyup event at a later time
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol for the keypress
- * @scancode:	the scancode for the keypress
- * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
- *              support toggle values, this should be set to zero)
+ * rc_keytable_add() - adds a new keytable
+ * @dev:	the struct rc_dev device this keytable should belong to
+ * @rc_map:	the keymap to use for the new keytable
+ * @return:	zero on success or a negative error code
  *
- * This routine is used to signal that a key has been pressed on the
- * remote control. The driver must manually call rc_keyup() at a later stage.
+ * This function add a new keytable (essentially the combination of a keytable
+ * and an input device along with some state (whether a key is currently
+ * pressed or not, etc).
  */
-void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
-			  u32 scancode, u8 toggle)
+int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
 {
-	unsigned long flags;
-	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
+	struct rc_keytable *kt;
+	struct input_dev *idev = NULL;
+	int err;
 
-	spin_lock_irqsave(&dev->keylock, flags);
-	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
-	spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
+	kt = kzalloc(sizeof(*kt), GFP_KERNEL);
+	if (!kt) {
+		err = -ENOMEM;
+		goto out;
+	}
 
-int rc_input_open(struct input_dev *idev)
-{
-	struct rc_dev *rdev = input_get_drvdata(idev);
+	idev = input_allocate_device();
+	if (!idev) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	kt->idev = idev;
+	kt->dev = dev;
+	spin_lock_init(&kt->keylock);
+	spin_lock_init(&kt->rc_map.lock);
+	idev->getkeycode = ir_getkeycode;
+	idev->setkeycode = ir_setkeycode;
+	idev->open = rc_input_open;
+	idev->close = rc_input_close;
+	set_bit(EV_KEY, idev->evbit);
+	set_bit(EV_REP, idev->evbit);
+	set_bit(EV_MSC, idev->evbit);
+	set_bit(MSC_SCAN, idev->mscbit);
+	input_set_drvdata(idev, kt);
+	setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
+
+	err = rc_setkeytable(kt, rc_map);
+	if (err)
+		goto out;
+
+	idev->dev.parent = &dev->dev;
+	memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id));
+	idev->phys = dev->input_phys;
+	idev->name = dev->input_name;
 
-	return rc_open(rdev);
+	err = input_register_device(idev);
+	if (err)
+		goto out;
+
+	/*
+	 * Default delay of 250ms is too short for some protocols, especially
+	 * since the timeout is currently set to 250ms. Increase it to 500ms,
+	 * to avoid wrong repetition of the keycodes. Note that this must be
+	 * set after the call to input_register_device().
+	 */
+	idev->rep[REP_DELAY] = 500;
+
+	/*
+	 * As a repeat event on protocols like RC-5 and NEC take as long as
+	 * 110/114ms, using 33ms as a repeat period is not the right thing
+	 * to do.
+	 */
+	idev->rep[REP_PERIOD] = 125;
+
+	dev->kt = kt;
+	return 0;
+
+out:
+	ir_free_table(&kt->rc_map);
+	input_free_device(idev);
+	kfree(kt);
+	return err;
 }
 
-void rc_input_close(struct input_dev *idev)
+/**
+ * rc_keytable_del() - unregisters and deletes a keytable
+ * @dev:       the struct rc_dev device with the keytable
+ *
+ * This function unregisters and deletes an existing keytable.
+ */
+void rc_keytable_del(struct rc_dev *dev)
 {
-	struct rc_dev *rdev = input_get_drvdata(idev);
-	rc_close(rdev);
+	if (!dev->kt)
+		return;
+
+	del_timer_sync(&dev->kt->timer_keyup);
+	ir_free_table(&dev->kt->rc_map);
+	input_unregister_device(dev->kt->idev);
+	kfree(dev->kt);
+	dev->kt = NULL;
 }
 
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index a01fce2..23a6701 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -136,6 +136,54 @@ void rc_close(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_close);
 
+/**
+ * rc_do_keydown() - report a key press event
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
+ * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
+ *		support toggle values, this should be set to zero)
+ * @autoup:	whether to automatically generate a keyup event later
+ *
+ * Report that a keypress has been received.
+ */
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+		   u32 scancode, u8 toggle, bool autoup)
+{
+	led_trigger_event(led_feedback, LED_FULL);
+	rc_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
+	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
+}
+EXPORT_SYMBOL_GPL(rc_do_keydown);
+
+/**
+ * rc_keyup() - signals the release of a keypress
+ * @dev:       the struct rc_dev descriptor of the device
+ *
+ * Report that a key is no longer pressed.
+ */
+void rc_keyup(struct rc_dev *dev)
+{
+	rc_keytable_keyup(dev->kt);
+}
+EXPORT_SYMBOL_GPL(rc_keyup);
+
+/**
+ * rc_repeat() - report that a key is still pressed
+ * @dev:	the struct rc_dev descriptor of the device
+ *
+ * Report that a repeat message (which does not include the necessary bits to
+ * reproduce the scancode) has been received.
+ */
+void rc_repeat(struct rc_dev *dev)
+{
+	rc_keytable_repeat(dev->kt);
+	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
+}
+EXPORT_SYMBOL_GPL(rc_repeat);
+
 /* class for /sys/class/rc */
 static char *rc_devnode(struct device *dev, umode_t *mode)
 {
@@ -214,8 +262,8 @@ struct rc_filter_attribute {
  * It returns the protocol names of supported protocols.
  * Enabled protocols are printed in brackets.
  *
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * dev->lock is taken to guard against races between store_protocols and
+ * show_protocols.
  */
 static ssize_t show_protocols(struct device *device,
 			      struct device_attribute *mattr, char *buf)
@@ -344,8 +392,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
  * See parse_protocol_change() for the valid commands.
  * Returns @len on success or a negative error code.
  *
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * dev->lock is taken to guard against races between store_protocols and
+ * show_protocols.
  */
 static ssize_t store_protocols(struct device *device,
 			       struct device_attribute *mattr,
@@ -445,8 +493,8 @@ out:
  * Bits of the filter value corresponding to set bits in the filter mask are
  * compared against input scancodes and non-matching scancodes are discarded.
  *
- * dev->lock is taken to guard against races between device registration,
- * store_filter and show_filter.
+ * dev->lock is taken to guard against races between store_filter and
+ * show_filter.
  */
 static ssize_t show_filter(struct device *device,
 			   struct device_attribute *attr,
@@ -492,8 +540,8 @@ static ssize_t show_filter(struct device *device,
  * Bits of the filter value corresponding to set bits in the filter mask are
  * compared against input scancodes and non-matching scancodes are discarded.
  *
- * dev->lock is taken to guard against races between device registration,
- * store_filter and show_filter.
+ * dev->lock is taken to guard against races between store_filter and
+ * show_filter.
  */
 static ssize_t store_filter(struct device *device,
 			    struct device_attribute *attr,
@@ -964,8 +1012,8 @@ static void rc_dev_release(struct device *device)
 {
 	struct rc_dev *dev = to_rc_dev(device);
 
-	if (dev->input_dev)
-		input_free_device(dev->input_dev);
+	if (dev->driver_type == RC_DRIVER_IR_RAW)
+		ir_raw_event_unregister(dev);
 
 	kfifo_free(&dev->txfifo);
 	kfree(dev);
@@ -983,11 +1031,8 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
 	struct rc_dev *dev = to_rc_dev(device);
 
-	if (!dev || !dev->input_dev)
-		return -ENODEV;
-
-	if (dev->rc_map.name)
-		ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
+	if (dev->map_name)
+		ADD_HOTPLUG_VAR("NAME=%s", dev->map_name);
 	if (dev->driver_name)
 		ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
 
@@ -1061,25 +1106,12 @@ struct rc_dev *rc_allocate_device(void)
 	if (!dev)
 		return NULL;
 
-	dev->input_dev = input_allocate_device();
-	if (!dev->input_dev) {
-		kfree(dev);
-		return NULL;
-	}
-
-	dev->input_dev->getkeycode = ir_getkeycode;
-	dev->input_dev->setkeycode = ir_setkeycode;
-	input_set_drvdata(dev->input_dev, dev);
-
 	INIT_LIST_HEAD(&dev->client_list);
 	spin_lock_init(&dev->client_lock);
 	mutex_init(&dev->txmutex);
 	init_waitqueue_head(&dev->txwait);
 	init_waitqueue_head(&dev->rxwait);
-	spin_lock_init(&dev->rc_map.lock);
-	spin_lock_init(&dev->keylock);
 	mutex_init(&dev->lock);
-	setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
 
 	dev->dev.type = &rc_dev_type;
 	dev->dev.class = &rc_class;
@@ -1112,28 +1144,14 @@ EXPORT_SYMBOL_GPL(rc_free_device);
 int rc_register_device(struct rc_dev *dev)
 {
 	static bool raw_init = false; /* raw decoders loaded? */
-	struct rc_map *rc_map;
-	const char *path;
+	struct rc_map *rc_map = NULL;
 	int attr = 0;
 	int minor;
 	int rc;
 
-	if (!dev || !dev->map_name)
-		return -EINVAL;
-
-	rc_map = rc_map_get(dev->map_name);
-	if (!rc_map)
-		rc_map = rc_map_get(RC_MAP_EMPTY);
-	if (!rc_map || !rc_map->scan || rc_map->size == 0)
+	if (!dev)
 		return -EINVAL;
 
-	set_bit(EV_KEY, dev->input_dev->evbit);
-	set_bit(EV_REP, dev->input_dev->evbit);
-	set_bit(EV_MSC, dev->input_dev->evbit);
-	set_bit(MSC_SCAN, dev->input_dev->mscbit);
-	dev->input_dev->open = rc_input_open;
-	dev->input_dev->close = rc_input_close;
-
 	minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
 	if (minor < 0)
 		return minor;
@@ -1148,6 +1166,18 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_minor;
 	}
 
+	if (dev->driver_type == RC_DRIVER_IR_RAW) {
+		/* Load raw decoders, if they aren't already */
+		if (!raw_init) {
+			IR_dprintk(1, "Loading raw decoders\n");
+			ir_raw_init();
+			raw_init = true;
+		}
+		rc = ir_raw_event_register(dev);
+		if (rc < 0)
+			goto out_minor;
+	}
+
 	dev->dev.groups = dev->sysfs_groups;
 	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
 	if (dev->s_filter)
@@ -1158,73 +1188,15 @@ int rc_register_device(struct rc_dev *dev)
 		dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
 	dev->sysfs_groups[attr++] = NULL;
 
-	/*
-	 * Take the lock here, as the device sysfs node will appear
-	 * when device_add() is called, which may trigger an ir-keytable udev
-	 * rule, which will in turn call show_protocols and access
-	 * dev->enabled_protocols before it has been initialized.
-	 */
-	mutex_lock(&dev->lock);
-
-	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
-	if (rc)
-		goto out_unlock;
-
-	rc = device_add(&dev->dev);
-	if (rc)
-		goto out_cdev;
-
-	rc = ir_setkeytable(dev, rc_map);
-	if (rc)
-		goto out_dev;
-
-	dev->input_dev->dev.parent = &dev->dev;
-	memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
-	dev->input_dev->phys = dev->input_phys;
-	dev->input_dev->name = dev->input_name;
-
-	/* input_register_device can call ir_open, so unlock mutex here */
-	mutex_unlock(&dev->lock);
-
-	rc = input_register_device(dev->input_dev);
-
-	mutex_lock(&dev->lock);
-
-	if (rc)
-		goto out_table;
+	if (dev->map_name)
+		rc_map = rc_map_get(dev->map_name);
 
-	/*
-	 * Default delay of 250ms is too short for some protocols, especially
-	 * since the timeout is currently set to 250ms. Increase it to 500ms,
-	 * to avoid wrong repetition of the keycodes. Note that this must be
-	 * set after the call to input_register_device().
-	 */
-	dev->input_dev->rep[REP_DELAY] = 500;
-
-	/*
-	 * As a repeat event on protocols like RC-5 and NEC take as long as
-	 * 110/114ms, using 33ms as a repeat period is not the right thing
-	 * to do.
-	 */
-	dev->input_dev->rep[REP_PERIOD] = 125;
-
-	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
-	printk(KERN_INFO "%s: %s as %s\n",
-		dev_name(&dev->dev),
-		dev->input_name ? dev->input_name : "Unspecified device",
-		path ? path : "N/A");
-	kfree(path);
+	if (!rc_map)
+		rc_map = rc_map_get(RC_MAP_EMPTY);
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW) {
-		/* Load raw decoders, if they aren't already */
-		if (!raw_init) {
-			IR_dprintk(1, "Loading raw decoders\n");
-			ir_raw_init();
-			raw_init = true;
-		}
-		rc = ir_raw_event_register(dev);
-		if (rc < 0)
-			goto out_input;
+	if (!rc_map || !rc_map->scan || rc_map->size == 0) {
+		rc = -EFAULT;
+		goto out_raw;
 	}
 
 	if (dev->change_protocol && rc_map->len > 0) {
@@ -1234,31 +1206,34 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_raw;
 		dev->enabled_protocols = rc_type;
 	}
+	
+	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
+	if (rc)
+		goto out_raw;
 
-	mutex_unlock(&dev->lock);
+	rc = device_add(&dev->dev);
+	if (rc)
+		goto out_cdev;
+
+	rc = rc_keytable_add(dev, rc_map);
+	if (rc)
+		goto out_dev;
 
 	IR_dprintk(1, "Registered %s (driver: %s, remote: %s, mode %s)\n",
 		   dev_name(&dev->dev),
 		   dev->driver_name ? dev->driver_name : "unknown",
-		   rc_map->name ? rc_map->name : "unknown",
+		   dev->map_name ? dev->map_name : "unknown",
 		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
 
 	return 0;
 
-out_raw:
-	if (dev->driver_type == RC_DRIVER_IR_RAW)
-		ir_raw_event_unregister(dev);
-out_input:
-	input_unregister_device(dev->input_dev);
-	dev->input_dev = NULL;
-out_table:
-	ir_free_table(&dev->rc_map);
 out_dev:
 	device_del(&dev->dev);
 out_cdev:
 	cdev_del(&dev->cdev);
-out_unlock:
-	mutex_unlock(&dev->lock);
+out_raw:
+	if (dev->driver_type == RC_DRIVER_IR_RAW)
+		ir_raw_event_unregister(dev);
 out_minor:
 	ida_simple_remove(&rc_ida, minor);
 	return rc;
@@ -1285,15 +1260,10 @@ void rc_unregister_device(struct rc_dev *dev)
 
 	cdev_del(&dev->cdev);
 
-	del_timer_sync(&dev->timer_keyup);
-
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
-	ir_free_table(&dev->rc_map);
-
-	input_unregister_device(dev->input_dev);
-	dev->input_dev = NULL;
+	rc_keytable_del(dev);
 
 	/* dev is marked as dead so no one changes dev->users */
 	if (dev->users && dev->close)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index eacb735..e64d47c 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -249,7 +249,7 @@ enum rc_filter_type {
  * @input_id: id of the input child device (struct input_id)
  * @driver_name: name of the hardware driver which registered this device
  * @map_name: name of the default keymap
- * @rc_map: current scan/key table
+ * @rc_kt: current rc_keytable
  * @lock: used to ensure we've filled in all protocol details before
  *	anyone can call show_protocols or store_protocols
  * @dead: used to determine if the device is still alive
@@ -260,7 +260,6 @@ enum rc_filter_type {
  * @txwait: waitqueue for processes waiting to write data to the txfifo
  * @rxwait: waitqueue for processes waiting for data to read
  * @raw: additional data for raw pulse/space devices
- * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
  * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
@@ -276,14 +275,6 @@ enum rc_filter_type {
  *	leave this field in blank
  * @users: number of current users of the device
  * @priv: driver-specific data
- * @keylock: protects the remaining members of the struct
- * @keypressed: whether a key is currently pressed
- * @keyup_jiffies: time (in jiffies) when the current keypress should be released
- * @timer_keyup: timer for releasing a keypress
- * @last_keycode: keycode of last keypress
- * @last_protocol: protocol of last keypress
- * @last_scancode: scancode of last keypress
- * @last_toggle: toggle value of last command
  * @timeout: optional time after which device stops sending data
  * @min_timeout: minimum timeout supported by device
  * @max_timeout: maximum timeout supported by device
@@ -321,7 +312,7 @@ struct rc_dev {
 	struct input_id			input_id;
 	char				*driver_name;
 	const char			*map_name;
-	struct rc_map			rc_map;
+	struct rc_keytable		*kt;
 	struct mutex			lock;
 	bool				dead;
 	struct list_head		client_list;
@@ -331,7 +322,6 @@ struct rc_dev {
 	wait_queue_head_t		txwait;
 	wait_queue_head_t		rxwait;
 	struct ir_raw_event_ctrl	*raw;
-	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;
 	bool				idle;
 	u64				allowed_protocols;
@@ -343,14 +333,6 @@ struct rc_dev {
 	u32				scancode_mask;
 	u32				users;
 	void				*priv;
-	spinlock_t			keylock;
-	bool				keypressed;
-	unsigned long			keyup_jiffies;
-	struct timer_list		timer_keyup;
-	u32				last_keycode;
-	enum rc_type			last_protocol;
-	u32				last_scancode;
-	u8				last_toggle;
 	u32				timeout;
 	u32				min_timeout;
 	u32				max_timeout;
@@ -378,6 +360,34 @@ struct rc_dev {
 	int				(*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 };
 
+/**
+ * struct rc_keytable - represents one keytable for a rc_dev device
+ * @dev:		the rc_dev device this keytable belongs to
+ * @idev:		the input_dev device which belongs to this keytable
+ * @rc_map:		holds the scancode <-> keycode mappings
+ * @keypressed:		whether a key is currently pressed or not
+ * @keyup_jiffies:	when the key should be auto-released
+ * @timer_keyup:	responsible for the auto-release of keys
+ * @keylock:		protects the key state
+ * @last_keycode:	keycode of the last keypress
+ * @last_protocol:	protocol of the last keypress
+ * @last_scancode:	scancode of the last keypress
+ * @last_toggle:	toggle of the last keypress
+ */
+struct rc_keytable {
+	struct rc_dev			*dev;
+	struct input_dev		*idev;
+	struct rc_map			rc_map;
+	bool				keypressed;
+	unsigned long			keyup_jiffies;
+	struct timer_list		timer_keyup;
+	spinlock_t			keylock;
+	u32				last_keycode;
+	enum rc_type			last_protocol;
+	u32				last_scancode;
+	u8				last_toggle;
+};
+
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
 
 /*
@@ -397,11 +407,19 @@ int rc_open(struct rc_dev *rdev);
 void rc_close(struct rc_dev *rdev);
 
 void rc_repeat(struct rc_dev *dev);
-void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
-void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+		   u32 scancode, u8 toggle, bool autoup);
 void rc_keyup(struct rc_dev *dev);
 u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
 
+static inline void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) {
+	rc_do_keydown(dev, protocol, scancode, toggle, true);
+}
+
+static inline void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) {
+	rc_do_keydown(dev, protocol, scancode, toggle, false);
+}
+
 /*
  * From rc-raw.c
  * The Raw interface is specific to InfraRed. It may be a good idea to


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

* [PATCH 33/49] rc-core: make the keytable of rc_dev an array
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (31 preceding siblings ...)
  2014-04-03 23:33 ` [PATCH 32/49] rc-core: prepare for multiple keytables David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 34/49] rc-core: add ioctls for adding/removing keytables from userspace David Härdeman
                   ` (17 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

This is another step towards allowing multiple keytables per rc_dev.

struct rc_dev is changed to hold an array of keytables (used later for
indexed access to keytables) as well as a list of the same keytables
(used for iteration in fast paths).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |    4 +-
 drivers/media/rc/rc-keytable.c  |   95 ++++++++++++++++++++++++---------------
 drivers/media/rc/rc-main.c      |   74 ++++++++++++++++++++++++++++--
 include/media/rc-core.h         |    6 ++
 4 files changed, 134 insertions(+), 45 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 7a7770e..02b538c 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -162,8 +162,8 @@ void rc_keytable_keyup(struct rc_keytable *kt);
 void rc_keytable_repeat(struct rc_keytable *kt);
 void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 			 u32 scancode, u8 toggle, bool autokeyup);
-int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map);
-void rc_keytable_del(struct rc_dev *dev);
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map);
+void rc_keytable_destroy(struct rc_keytable *kt);
 
 /* Only to be used by rc-core and ir-lirc-codec */
 void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 0f1b817..412d342 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -322,7 +322,7 @@ static unsigned int ir_establish_scancode(struct rc_keytable *kt,
  */
 static inline enum rc_type guess_protocol(struct rc_dev *rdev)
 {
-	struct rc_map *rc_map = &rdev->kt->rc_map;
+	struct rc_map *rc_map = &rdev->keytables[0]->rc_map;
 
 	if (hweight64(rdev->enabled_protocols) == 1)
 		return rc_bitmap_to_type(rdev->enabled_protocols);
@@ -604,40 +604,63 @@ out:
 	return retval;
 }
 
-/**
- * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol to look for
- * @scancode:	the scancode to look for
- * @return:	the corresponding keycode, or KEY_RESERVED
- *
- * This routine is used by drivers which need to convert a scancode to a
- * keycode. Normally it should not be used since drivers should have no
- * interest in keycodes.
- */
-u32 rc_g_keycode_from_table(struct rc_dev *dev,
-			    enum rc_type protocol, u64 scancode)
+static u32 rc_get_keycode(struct rc_keytable *kt,
+			  enum rc_type protocol, u64 scancode)
 {
-	struct rc_map *rc_map = &dev->kt->rc_map;
-	unsigned int keycode;
+	struct rc_map *rc_map;
+	unsigned int keycode = KEY_RESERVED;
 	unsigned int index;
 	unsigned long flags;
 
+	rc_map = &kt->rc_map;
+	if (!rc_map)
+		return KEY_RESERVED;
+
 	spin_lock_irqsave(&rc_map->lock, flags);
 
 	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
-	keycode = index < rc_map->len ?
-			rc_map->scan[index].keycode : KEY_RESERVED;
+	if (index < rc_map->len)
+		keycode = rc_map->scan[index].keycode;
 
 	spin_unlock_irqrestore(&rc_map->lock, flags);
 
 	if (keycode != KEY_RESERVED)
 		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
-			   dev->input_name, protocol,
+			   kt->dev->input_name, protocol,
 			   (unsigned long long)scancode, keycode);
 
 	return keycode;
 }
+
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol to look for
+ * @scancode:	the scancode to look for
+ * @return:	the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. It should not be used since drivers should have no
+ * interest in keycodes. (deprecated)
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+			    enum rc_type protocol, u64 scancode)
+{
+	struct rc_keytable *kt;
+	unsigned int keycode = KEY_RESERVED;
+
+	/* FIXME: This entire function is a hack. Remove it */
+	rcu_read_lock();
+	kt = rcu_dereference(dev->keytables[0]);
+	if (!kt)
+		goto out;
+	keycode = rc_get_keycode(kt, protocol, scancode);
+
+out:
+	rcu_read_unlock();
+	return keycode;
+}
 EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
 
 /**
@@ -751,7 +774,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 
 	spin_lock_irqsave(&kt->keylock, flags);
 
-	keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
+	keycode = rc_get_keycode(kt, protocol, scancode);
 	new_event = (!kt->keypressed ||
 		     kt->last_protocol != protocol ||
 		     kt->last_scancode != scancode ||
@@ -800,16 +823,16 @@ static void rc_input_close(struct input_dev *idev)
 }
 
 /**
- * rc_keytable_add() - adds a new keytable
+ * rc_keytable_create() - create a new keytable
  * @dev:	the struct rc_dev device this keytable should belong to
  * @rc_map:	the keymap to use for the new keytable
  * @return:	zero on success or a negative error code
  *
- * This function add a new keytable (essentially the combination of a keytable
- * and an input device along with some state (whether a key is currently
- * pressed or not, etc).
+ * This function creates a new keytable (essentially the combination of a
+ * keytable and an input device along with some state (whether a key is
+ * currently pressed or not, etc).
  */
-int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map)
 {
 	struct rc_keytable *kt;
 	struct input_dev *idev = NULL;
@@ -870,31 +893,29 @@ int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
 	 */
 	idev->rep[REP_PERIOD] = 125;
 
-	dev->kt = kt;
-	return 0;
+	return kt;
 
 out:
 	ir_free_table(&kt->rc_map);
 	input_free_device(idev);
 	kfree(kt);
-	return err;
+	return ERR_PTR(err);
 }
 
 /**
- * rc_keytable_del() - unregisters and deletes a keytable
- * @dev:       the struct rc_dev device with the keytable
+ * rc_keytable_del() - unregisters and frees a keytable
+ * @kt:		the struct rc_keytable to destroy
  *
  * This function unregisters and deletes an existing keytable.
  */
-void rc_keytable_del(struct rc_dev *dev)
+void rc_keytable_destroy(struct rc_keytable *kt)
 {
-	if (!dev->kt)
+	if (!kt)
 		return;
 
-	del_timer_sync(&dev->kt->timer_keyup);
-	ir_free_table(&dev->kt->rc_map);
-	input_unregister_device(dev->kt->idev);
-	kfree(dev->kt);
-	dev->kt = NULL;
+	del_timer_sync(&kt->timer_keyup);
+	ir_free_table(&kt->rc_map);
+	input_unregister_device(kt->idev);
+	kfree(kt);
 }
 
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 23a6701..bc2d479 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -150,8 +150,14 @@ EXPORT_SYMBOL_GPL(rc_close);
 void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 		   u32 scancode, u8 toggle, bool autoup)
 {
+	struct rc_keytable *kt;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+		rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
+	rcu_read_unlock();
+
 	led_trigger_event(led_feedback, LED_FULL);
-	rc_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
 	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
 	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
 	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
@@ -166,7 +172,12 @@ EXPORT_SYMBOL_GPL(rc_do_keydown);
  */
 void rc_keyup(struct rc_dev *dev)
 {
-	rc_keytable_keyup(dev->kt);
+	struct rc_keytable *kt;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+		rc_keytable_keyup(kt);
+	rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rc_keyup);
 
@@ -179,11 +190,60 @@ EXPORT_SYMBOL_GPL(rc_keyup);
  */
 void rc_repeat(struct rc_dev *dev)
 {
-	rc_keytable_repeat(dev->kt);
+	struct rc_keytable *kt;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+		rc_keytable_repeat(kt);
+	rcu_read_unlock();
+
 	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
 }
 EXPORT_SYMBOL_GPL(rc_repeat);
 
+static int rc_add_keytable(struct rc_dev *dev, struct rc_map *rc_map)
+{
+	struct rc_keytable *kt;
+	unsigned i;
+
+	if (!rc_map)
+		rc_map = rc_map_get(RC_MAP_EMPTY);
+
+	if (!rc_map)
+		return -EFAULT;
+
+	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+		if (!dev->keytables[i])
+			break;
+
+	if (i >= ARRAY_SIZE(dev->keytables))
+		return -ENFILE;
+
+	kt = rc_keytable_create(dev, rc_map);
+	if (IS_ERR(kt))
+		return PTR_ERR(kt);
+
+	rcu_assign_pointer(dev->keytables[i], kt);
+	list_add_rcu(&kt->node, &dev->keytable_list);
+	synchronize_rcu();
+	return 0;
+}
+
+static void rc_remove_keytable(struct rc_dev *dev, unsigned i)
+{
+	struct rc_keytable *kt;
+
+	if (i >= ARRAY_SIZE(dev->keytables))
+		return;
+
+	kt = dev->keytables[i];
+	rcu_assign_pointer(dev->keytables[i], NULL);
+	if (kt)
+		list_del_rcu(&kt->node);
+	synchronize_rcu();
+	rc_keytable_destroy(kt);
+}
+
 /* class for /sys/class/rc */
 static char *rc_devnode(struct device *dev, umode_t *mode)
 {
@@ -1108,6 +1168,7 @@ struct rc_dev *rc_allocate_device(void)
 
 	INIT_LIST_HEAD(&dev->client_list);
 	spin_lock_init(&dev->client_lock);
+	INIT_LIST_HEAD(&dev->keytable_list);
 	mutex_init(&dev->txmutex);
 	init_waitqueue_head(&dev->txwait);
 	init_waitqueue_head(&dev->rxwait);
@@ -1215,7 +1276,7 @@ int rc_register_device(struct rc_dev *dev)
 	if (rc)
 		goto out_cdev;
 
-	rc = rc_keytable_add(dev, rc_map);
+	rc = rc_add_keytable(dev, rc_map);
 	if (rc)
 		goto out_dev;
 
@@ -1243,6 +1304,7 @@ EXPORT_SYMBOL_GPL(rc_register_device);
 void rc_unregister_device(struct rc_dev *dev)
 {
 	struct rc_client *client;
+	unsigned i;
 
 	if (!dev)
 		return;
@@ -1263,7 +1325,8 @@ void rc_unregister_device(struct rc_dev *dev)
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
-	rc_keytable_del(dev);
+	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+		rc_remove_keytable(dev, i);
 
 	/* dev is marked as dead so no one changes dev->users */
 	if (dev->users && dev->close)
@@ -1329,3 +1392,4 @@ module_param_named(debug, rc_core_debug, int, 0644);
 
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
+
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e64d47c..f48d5cd 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -303,6 +303,7 @@ enum rc_filter_type {
  * @get_ir_tx: allow driver to provide tx settings
  * @set_ir_tx: allow driver to change tx settings
  */
+#define RC_MAX_KEYTABLES		1
 struct rc_dev {
 	struct device			dev;
 	struct cdev			cdev;
@@ -312,7 +313,8 @@ struct rc_dev {
 	struct input_id			input_id;
 	char				*driver_name;
 	const char			*map_name;
-	struct rc_keytable		*kt;
+	struct rc_keytable		*keytables[RC_MAX_KEYTABLES];
+	struct list_head		keytable_list;
 	struct mutex			lock;
 	bool				dead;
 	struct list_head		client_list;
@@ -362,6 +364,7 @@ struct rc_dev {
 
 /**
  * struct rc_keytable - represents one keytable for a rc_dev device
+ * @node:		used to iterate over all keytables for a rc_dev device
  * @dev:		the rc_dev device this keytable belongs to
  * @idev:		the input_dev device which belongs to this keytable
  * @rc_map:		holds the scancode <-> keycode mappings
@@ -375,6 +378,7 @@ struct rc_dev {
  * @last_toggle:	toggle of the last keypress
  */
 struct rc_keytable {
+	struct list_head		node;
 	struct rc_dev			*dev;
 	struct input_dev		*idev;
 	struct rc_map			rc_map;


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

* [PATCH 34/49] rc-core: add ioctls for adding/removing keytables from userspace
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (32 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 33/49] rc-core: make the keytable of rc_dev an array David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 35/49] rc-core: remove redundant spinlock David Härdeman
                   ` (16 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

As all the basics are now in place, we can finally add the ioctls
for adding/removing keytables from userspace.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |    2 -
 drivers/media/rc/rc-keytable.c  |    5 ++
 drivers/media/rc/rc-main.c      |   81 ++++++++++++++++++++++++++++++++++++---
 include/media/rc-core.h         |   27 +++++++++++++
 4 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 02b538c..0159836 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -162,7 +162,7 @@ void rc_keytable_keyup(struct rc_keytable *kt);
 void rc_keytable_repeat(struct rc_keytable *kt);
 void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 			 u32 scancode, u8 toggle, bool autokeyup);
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map);
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, struct rc_map *rc_map);
 void rc_keytable_destroy(struct rc_keytable *kt);
 
 /* Only to be used by rc-core and ir-lirc-codec */
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 412d342..6d04b8f 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -825,6 +825,7 @@ static void rc_input_close(struct input_dev *idev)
 /**
  * rc_keytable_create() - create a new keytable
  * @dev:	the struct rc_dev device this keytable should belong to
+ * @name:	the userfriendly name of this keymap
  * @rc_map:	the keymap to use for the new keytable
  * @return:	zero on success or a negative error code
  *
@@ -832,7 +833,8 @@ static void rc_input_close(struct input_dev *idev)
  * keytable and an input device along with some state (whether a key is
  * currently pressed or not, etc).
  */
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map)
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
+				       struct rc_map *rc_map)
 {
 	struct rc_keytable *kt;
 	struct input_dev *idev = NULL;
@@ -854,6 +856,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map
 	kt->dev = dev;
 	spin_lock_init(&kt->keylock);
 	spin_lock_init(&kt->rc_map.lock);
+	snprintf(kt->name, sizeof(*kt->name), name ? name : "undefined");
 	idev->getkeycode = ir_getkeycode;
 	idev->setkeycode = ir_setkeycode;
 	idev->open = rc_input_open;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index bc2d479..ad784c8 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -201,7 +201,8 @@ void rc_repeat(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_repeat);
 
-static int rc_add_keytable(struct rc_dev *dev, struct rc_map *rc_map)
+static int rc_add_keytable(struct rc_dev *dev, const char *name,
+			   struct rc_map *rc_map)
 {
 	struct rc_keytable *kt;
 	unsigned i;
@@ -219,7 +220,7 @@ static int rc_add_keytable(struct rc_dev *dev, struct rc_map *rc_map)
 	if (i >= ARRAY_SIZE(dev->keytables))
 		return -ENFILE;
 
-	kt = rc_keytable_create(dev, rc_map);
+	kt = rc_keytable_create(dev, name, rc_map);
 	if (IS_ERR(kt))
 		return PTR_ERR(kt);
 
@@ -229,19 +230,24 @@ static int rc_add_keytable(struct rc_dev *dev, struct rc_map *rc_map)
 	return 0;
 }
 
-static void rc_remove_keytable(struct rc_dev *dev, unsigned i)
+static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
 {
 	struct rc_keytable *kt;
 
 	if (i >= ARRAY_SIZE(dev->keytables))
-		return;
+		return -EINVAL;
 
 	kt = dev->keytables[i];
 	rcu_assign_pointer(dev->keytables[i], NULL);
 	if (kt)
 		list_del_rcu(&kt->node);
 	synchronize_rcu();
+
+	if (!kt)
+		return -EINVAL;
+
 	rc_keytable_destroy(kt);
+	return 0;
 }
 
 /* class for /sys/class/rc */
@@ -946,6 +952,8 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 	unsigned int __user *ip = (unsigned int __user *)p;
 	struct rc_ir_rx rx;
 	struct rc_ir_tx tx;
+	struct rc_keytable_ioctl ktio;
+	struct rc_keytable *kt;
 	int error;
 
 	switch (cmd) {
@@ -1007,8 +1015,69 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 			return -EFAULT;
 
 		return 0;
-	}
 
+	case RCIOCADDTABLE:
+		if (copy_from_user(&ktio, p, sizeof(ktio)))
+			return -EFAULT;
+
+		if (ktio.id >= RC_MAX_KEYTABLES)
+			return -EINVAL;
+
+		if (ktio.flags)
+			return -EINVAL;
+
+		ktio.name[sizeof(ktio.name) - 1] = '\0';
+		if (strlen(ktio.name) < 1)
+			return -EINVAL;
+
+		error = rc_add_keytable(dev, ktio.name, NULL);
+		if (error < 0)
+			return error;
+		ktio.id = error;
+
+		if (copy_to_user(p, &ktio, sizeof(ktio)))
+			return -EFAULT;
+
+		return 0;
+
+	case RCIOCGTABLENAME:
+		if (copy_from_user(&ktio, p, sizeof(ktio)))
+			return -EFAULT;
+
+		if (ktio.id >= RC_MAX_KEYTABLES)
+			return -EINVAL;
+
+		if (ktio.flags)
+			return -EINVAL;
+
+		rcu_read_lock();
+		kt = rcu_dereference(dev->keytables[ktio.id]);
+		if (kt) {
+			ktio.name[0] = '\0';
+			strncat(ktio.name, kt->name, sizeof(ktio.name));
+		}
+		rcu_read_unlock();
+
+		if (!kt)
+			return -EINVAL;
+
+		if (copy_to_user(p, &ktio, sizeof(ktio)))
+			return -EFAULT;
+
+		return 0;
+
+	case RCIOCDELTABLE:
+		if (copy_from_user(&ktio, p, sizeof(ktio)))
+			return -EFAULT;
+
+		if (ktio.id >= RC_MAX_KEYTABLES)
+			return -EINVAL;
+
+		if (ktio.flags)
+			return -EINVAL;
+
+		return rc_remove_keytable(dev, ktio.id);
+	}
 	return -EINVAL;
 }
 
@@ -1276,7 +1345,7 @@ int rc_register_device(struct rc_dev *dev)
 	if (rc)
 		goto out_cdev;
 
-	rc = rc_add_keytable(dev, rc_map);
+	rc = rc_add_keytable(dev, dev->map_name, rc_map);
 	if (rc)
 		goto out_dev;
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index f48d5cd..6f282e6 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -153,6 +153,29 @@ struct rc_ir_tx {
 	__u32 reserved[9];
 } __packed;
 
+/* add a keytable */
+#define RCIOCADDTABLE	_IOC(_IOC_READ | _IOC_WRITE, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/* get the name of a keytable */
+#define RCIOCGTABLENAME	_IOC(_IOC_READ, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/* remove a keytable */
+#define RCIOCDELTABLE	_IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/**
+ * struct rc_keytable_ioctl - used to alter keytables
+ * @id: the id of the keytable
+ * @flags: flags for the keytable
+ * @reserved: for future use, set to zero
+ * @name: a user-friendly name for the keytable
+ */
+#define RC_KEYTABLE_NAME_SIZE	128
+struct rc_keytable_ioctl {
+	__u32 id;
+	__u32 flags;
+	__u32 reserved[4];
+	char name[RC_KEYTABLE_NAME_SIZE];
+} __packed;
 
 enum rc_driver_type {
 	RC_DRIVER_SCANCODE = 0,	/* Driver or hardware generates a scancode */
@@ -303,7 +326,7 @@ enum rc_filter_type {
  * @get_ir_tx: allow driver to provide tx settings
  * @set_ir_tx: allow driver to change tx settings
  */
-#define RC_MAX_KEYTABLES		1
+#define RC_MAX_KEYTABLES		32
 struct rc_dev {
 	struct device			dev;
 	struct cdev			cdev;
@@ -367,6 +390,7 @@ struct rc_dev {
  * @node:		used to iterate over all keytables for a rc_dev device
  * @dev:		the rc_dev device this keytable belongs to
  * @idev:		the input_dev device which belongs to this keytable
+ * @name:		the user-friendly name of this keytable
  * @rc_map:		holds the scancode <-> keycode mappings
  * @keypressed:		whether a key is currently pressed or not
  * @keyup_jiffies:	when the key should be auto-released
@@ -381,6 +405,7 @@ struct rc_keytable {
 	struct list_head		node;
 	struct rc_dev			*dev;
 	struct input_dev		*idev;
+	char				name[RC_KEYTABLE_NAME_SIZE];
 	struct rc_map			rc_map;
 	bool				keypressed;
 	unsigned long			keyup_jiffies;


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

* [PATCH 35/49] rc-core: remove redundant spinlock
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (33 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 34/49] rc-core: add ioctls for adding/removing keytables from userspace David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 36/49] rc-core: make keytable RCU-friendly David Härdeman
                   ` (15 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Remove a redundant spinlock from struct rc_map.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-keytable.c |   43 +++++++++++++++++-----------------------
 include/media/rc-core.h        |    4 ++--
 include/media/rc-map.h         |    1 -
 3 files changed, 20 insertions(+), 28 deletions(-)

diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 6d04b8f..f4d03d2 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -381,7 +381,7 @@ static int ir_setkeycode(struct input_dev *idev,
 
 	entry.keycode = ke->keycode;
 
-	spin_lock_irqsave(&rc_map->lock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
 		index = ke->index;
@@ -430,7 +430,7 @@ static int ir_setkeycode(struct input_dev *idev,
 	*old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
 
 out:
-	spin_unlock_irqrestore(&rc_map->lock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 	return retval;
 }
 
@@ -537,7 +537,7 @@ int ir_getkeycode(struct input_dev *idev,
 	unsigned int index;
 	int retval;
 
-	spin_lock_irqsave(&rc_map->lock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
 		index = ke->index;
@@ -600,7 +600,7 @@ int ir_getkeycode(struct input_dev *idev,
 	retval = 0;
 
 out:
-	spin_unlock_irqrestore(&rc_map->lock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 	return retval;
 }
 
@@ -610,25 +610,15 @@ static u32 rc_get_keycode(struct rc_keytable *kt,
 	struct rc_map *rc_map;
 	unsigned int keycode = KEY_RESERVED;
 	unsigned int index;
-	unsigned long flags;
 
 	rc_map = &kt->rc_map;
 	if (!rc_map)
 		return KEY_RESERVED;
 
-	spin_lock_irqsave(&rc_map->lock, flags);
-
 	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
 	if (index < rc_map->len)
 		keycode = rc_map->scan[index].keycode;
 
-	spin_unlock_irqrestore(&rc_map->lock, flags);
-
-	if (keycode != KEY_RESERVED)
-		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
-			   kt->dev->input_name, protocol,
-			   (unsigned long long)scancode, keycode);
-
 	return keycode;
 }
 
@@ -649,13 +639,17 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
 {
 	struct rc_keytable *kt;
 	unsigned int keycode = KEY_RESERVED;
+	unsigned long flags;
 
 	/* FIXME: This entire function is a hack. Remove it */
 	rcu_read_lock();
 	kt = rcu_dereference(dev->keytables[0]);
 	if (!kt)
 		goto out;
+
+	spin_lock_irqsave(&kt->lock, flags);
 	keycode = rc_get_keycode(kt, protocol, scancode);
+	spin_unlock_irqrestore(&kt->lock, flags);
 
 out:
 	rcu_read_unlock();
@@ -669,7 +663,7 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
  * @sync:	whether or not to call input_sync
  *
  * This function is used internally to release a keypress, it must be
- * called with keylock held.
+ * called with kt->lock held.
  */
 static void rc_do_keyup(struct rc_keytable *kt, bool sync)
 {
@@ -694,9 +688,9 @@ void rc_keytable_keyup(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->keylock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 	rc_do_keyup(kt, true);
-	spin_unlock_irqrestore(&kt->keylock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 }
 
 /**
@@ -721,10 +715,10 @@ static void rc_timer_keyup(unsigned long cookie)
 	 * to allow the input subsystem to do its auto-repeat magic or
 	 * a keyup event might follow immediately after the keydown.
 	 */
-	spin_lock_irqsave(&kt->keylock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 	if (time_is_before_eq_jiffies(kt->keyup_jiffies))
 		rc_do_keyup(kt, true);
-	spin_unlock_irqrestore(&kt->keylock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 }
 
 /**
@@ -739,7 +733,7 @@ void rc_keytable_repeat(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->keylock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 
 	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
 	input_sync(kt->idev);
@@ -751,7 +745,7 @@ void rc_keytable_repeat(struct rc_keytable *kt)
 	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
 
 out:
-	spin_unlock_irqrestore(&kt->keylock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 }
 
 /**
@@ -772,7 +766,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 	u32 keycode;
 	bool new_event;
 
-	spin_lock_irqsave(&kt->keylock, flags);
+	spin_lock_irqsave(&kt->lock, flags);
 
 	keycode = rc_get_keycode(kt, protocol, scancode);
 	new_event = (!kt->keypressed ||
@@ -805,7 +799,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 		kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
 		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
 	}
-	spin_unlock_irqrestore(&kt->keylock, flags);
+	spin_unlock_irqrestore(&kt->lock, flags);
 }
 
 static int rc_input_open(struct input_dev *idev)
@@ -854,8 +848,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 
 	kt->idev = idev;
 	kt->dev = dev;
-	spin_lock_init(&kt->keylock);
-	spin_lock_init(&kt->rc_map.lock);
+	spin_lock_init(&kt->lock);
 	snprintf(kt->name, sizeof(*kt->name), name ? name : "undefined");
 	idev->getkeycode = ir_getkeycode;
 	idev->setkeycode = ir_setkeycode;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 6f282e6..af63188 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -395,7 +395,7 @@ struct rc_dev {
  * @keypressed:		whether a key is currently pressed or not
  * @keyup_jiffies:	when the key should be auto-released
  * @timer_keyup:	responsible for the auto-release of keys
- * @keylock:		protects the key state
+ * @lock:		protects the key state
  * @last_keycode:	keycode of the last keypress
  * @last_protocol:	protocol of the last keypress
  * @last_scancode:	scancode of the last keypress
@@ -410,7 +410,7 @@ struct rc_keytable {
 	bool				keypressed;
 	unsigned long			keyup_jiffies;
 	struct timer_list		timer_keyup;
-	spinlock_t			keylock;
+	spinlock_t			lock;
 	u32				last_keycode;
 	enum rc_type			last_protocol;
 	u32				last_scancode;
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index bfa27fc..34c192f 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -94,7 +94,6 @@ struct rc_map {
 	unsigned int		alloc;	/* Size of *scan in bytes */
 	enum rc_type		rc_type; /* For in-kernel keymaps */
 	const char		*name;
-	spinlock_t		lock;
 };
 
 struct rc_map_list {


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

* [PATCH 36/49] rc-core: make keytable RCU-friendly
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (34 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 35/49] rc-core: remove redundant spinlock David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 37/49] rc-core: allow empty keymaps David Härdeman
                   ` (14 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Change struct rc_keytable to be RCU-friendly by kmalloc():ing an
entire new scancode,protocol <-> keycode table every time the table
is changed (i.e. via EVIOCSKEYCODE(_V2)).

The advantage is that the performance-critical keycode lookup path
can be made entirely lock-free and that GFP_ATOMIC allocations
can be avoided entirely at the cost of a couple of extra kmalloc()
calls when changing a keytable (which is normally done once during
boot).

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-keytable.c |  668 +++++++++++++++++++---------------------
 include/media/rc-core.h        |   32 +-
 2 files changed, 332 insertions(+), 368 deletions(-)

diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index f4d03d2..89295f3 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -25,12 +25,10 @@
 #include <linux/poll.h>
 #include "rc-core-priv.h"
 
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE		256
-#define IR_TAB_MAX_SIZE		8192
+#define RC_TAB_MAX_SIZE		1024 /* entries */
 
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
+/* FIXME: RC_KEYPRESS_TIMEOUT should be protocol specific */
+#define RC_KEYPRESS_TIMEOUT 250
 
 /* Used to keep track of known keymaps */
 static LIST_HEAD(rc_map_list);
@@ -99,237 +97,189 @@ void rc_map_unregister(struct rc_map_list *map)
 EXPORT_SYMBOL_GPL(rc_map_unregister);
 
 /**
- * ir_create_table() - initializes a scancode table
- * @rc_map:	the rc_map to initialize
- * @name:	name to assign to the table
- * @size:	initial size of the table
- * @return:	zero on success or a negative error code
- *
- * This routine will initialize the rc_map and will allocate
- * memory to hold at least the specified number of elements.
+ * rc_scan_size() - determine the necessary size for a rc_scan struct
+ * @len:	the number of keytable entries the struct should hold
+ * @return:	the size of the struct in bytes
  */
-static int ir_create_table(struct rc_map *rc_map,
-			   const char *name, size_t size)
+static inline size_t rc_scan_size(unsigned len)
 {
-	rc_map->name = name;
-	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
-	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
-	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
-	if (!rc_map->scan)
-		return -ENOMEM;
-
-	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-		   rc_map->size, rc_map->alloc);
-	return 0;
+	return sizeof(struct rc_scan) + len * sizeof(struct rc_map_table);
 }
 
 /**
- * ir_free_table() - frees memory allocated by a scancode table
- * @rc_map:	the table whose mappings need to be freed
+ * rc_keytable_update_entry() - update an existing entry in the keytable
+ * @kt:		the keytable to update
+ * @i:		the index of the entry to update
+ * @entry:	the new values for the entry
+ * @return:	the old rc_scan struct, NULL if memory could not be allocated
  *
- * This routine will free memory alloctaed for key mappings used by given
- * scancode table.
+ * Updates a keytable by replacing an existing entry at the given index.
+ * The old rc_scan struct is returned so that it can be freed at a
+ * later stage.
  */
-void ir_free_table(struct rc_map *rc_map)
+static struct rc_scan *rc_keytable_update_entry(struct rc_keytable *kt,
+						unsigned i,
+						struct rc_map_table *entry)
 {
-	rc_map->size = 0;
-	kfree(rc_map->scan);
-	rc_map->scan = NULL;
-}
+	struct rc_scan *old_scan = kt->scan;
+	struct rc_scan *new_scan = kt->scan;
+	u32 old_keycode;
 
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_map:	the rc_map to resize
- * @gfp_flags:	gfp flags to use when allocating memory
- * @return:	zero on success or a negative error code
- *
- * This routine will shrink the rc_map if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
-{
-	unsigned int oldalloc = rc_map->alloc;
-	unsigned int newalloc = oldalloc;
-	struct rc_map_table *oldscan = rc_map->scan;
-	struct rc_map_table *newscan;
-
-	if (rc_map->size == rc_map->len) {
-		/* All entries in use -> grow keytable */
-		if (rc_map->alloc >= IR_TAB_MAX_SIZE)
-			return -ENOMEM;
-
-		newalloc *= 2;
-		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
-	}
+	if (i >= old_scan->len)
+		return NULL;
 
-	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
-		/* Less than 1/3 of entries in use -> shrink keytable */
-		newalloc /= 2;
-		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
-	}
+	new_scan = kmalloc(rc_scan_size(old_scan->len), GFP_KERNEL);
+	if (!new_scan)
+		return NULL;
+	memcpy(new_scan, old_scan, rc_scan_size(old_scan->len));
 
-	if (newalloc == oldalloc)
-		return 0;
+	IR_dprintk(1, "#%d: New keycode 0x%04x\n", i, entry->keycode);
+	new_scan->table[i].keycode = entry->keycode;
 
-	newscan = kmalloc(newalloc, gfp_flags);
-	if (!newscan) {
-		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
-		return -ENOMEM;
-	}
+	/* Another scancode might use the old keycode... */
+	__set_bit(entry->keycode, kt->idev->keybit);
+	old_keycode = old_scan->table[i].keycode;
+	for (i = 0; i < new_scan->len; i++)
+		if (new_scan->table[i].keycode == old_keycode)
+			break;
 
-	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
-	rc_map->scan = newscan;
-	rc_map->alloc = newalloc;
-	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
-	kfree(oldscan);
-	return 0;
+	if (i >= new_scan->len)
+		/* ...nope */
+		__clear_bit(old_keycode, kt->idev->keybit);
+
+	rcu_assign_pointer(kt->scan, new_scan);
+	return old_scan;
 }
 
 /**
- * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @kt:		the struct rc_keytable
- * @rc_map:	scancode table to be adjusted
- * @index:	index of the mapping that needs to be updated
- * @keycode:	the desired keycode
- * @return:	previous keycode assigned to the mapping
+ * rc_keytable_remove_entry() - remove an existing entry in the keytable
+ * @kt:		the keytable to update
+ * @i:		the index of the entry to remove
+ * @return:	the old rc_scan struct, NULL if memory could not be allocated
  *
- * This routine is used to update scancode->keycode mapping at given
- * position.
+ * Updates a keytable by removing an existing entry at the given index.
+ * The old rc_scan struct is returned so that it can be freed at a
+ * later stage.
  */
-static unsigned int ir_update_mapping(struct rc_keytable *kt,
-				      struct rc_map *rc_map,
-				      unsigned int index,
-				      unsigned int new_keycode)
+static struct rc_scan *rc_keytable_remove_entry(struct rc_keytable *kt,
+						unsigned i)
 {
-	int old_keycode = rc_map->scan[index].keycode;
-	int i;
-
-	/* Did the user wish to remove the mapping? */
-	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
-		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
-			   index, rc_map->scan[index].protocol,
-			   (unsigned long long)rc_map->scan[index].scancode);
-		rc_map->len--;
-		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
-			(rc_map->len - index) * sizeof(struct rc_map_table));
-	} else {
-		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
-			   "with key 0x%04x\n",
-			   index,
-			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
-			   rc_map->scan[index].protocol,
-			   (unsigned long long)rc_map->scan[index].scancode,
-			   new_keycode);
-		rc_map->scan[index].keycode = new_keycode;
-		__set_bit(new_keycode, kt->idev->keybit);
-	}
+	struct rc_scan *old_scan = kt->scan;
+	struct rc_scan *new_scan = kt->scan;
+	u32 old_keycode;
 
-	if (old_keycode != KEY_RESERVED) {
-		/* A previous mapping was updated... */
-		__clear_bit(old_keycode, kt->idev->keybit);
-		/* ... but another scancode might use the same keycode */
-		for (i = 0; i < rc_map->len; i++) {
-			if (rc_map->scan[i].keycode == old_keycode) {
-				__set_bit(old_keycode, kt->idev->keybit);
-				break;
-			}
-		}
+	if (i >= old_scan->len)
+		return NULL;
 
-		/* Possibly shrink the keytable, failure is not a problem */
-		ir_resize_table(rc_map, GFP_ATOMIC);
-	}
+	new_scan = kmalloc(rc_scan_size(old_scan->len - 1), GFP_ATOMIC);
+	if (!new_scan)
+		return NULL;
+	new_scan->len = old_scan->len - 1;
+	memcpy(&new_scan->table[0], &old_scan->table[0],
+	       i * sizeof(struct rc_map_table));
+	memcpy(&new_scan->table[i], &old_scan->table[i + 1],
+	       (new_scan->len - i) * sizeof(struct rc_map_table));
+	IR_dprintk(1, "#%d: Deleted\n", i);
+
+	/* Another scancode might use the removed keycode... */
+	old_keycode = old_scan->table[i].keycode;
+	for (i = 0; i < new_scan->len; i++)
+		if (new_scan->table[i].keycode == old_keycode)
+			break;
+
+	if (i >= new_scan->len)
+		/* ...nope */
+		__clear_bit(old_keycode, kt->idev->keybit);
 
-	return old_keycode;
+	rcu_assign_pointer(kt->scan, new_scan);
+	return old_scan;
 }
 
 /**
- * ir_establish_scancode() - set a keycode in the scancode->keycode table
- * @kt:		the struct rc_keytable descriptor
- * @rc_map:	scancode table to be searched
- * @entry:	the entry to be added to the table
- * @resize:	controls whether we are allowed to resize the table to
- *		accomodate not yet present scancodes
- * @return:	index of the mapping containing scancode in question
- *		or -1U in case of failure.
+ * rc_keytable_add_entry() - add an existing entry in the keytable
+ * @kt:		the keytable to update
+ * @entry:	the new entry to insert
+ * @init:	whether the keytable is being initialized for the first time
+ * @return:	the old rc_scan struct, NULL if memory could not be allocated
  *
- * This routine is used to locate given scancode in rc_map.
- * If scancode is not yet present the routine will allocate a new slot
- * for it.
+ * Updates a keytable by inserting an entry at the proper index. Unless @init is
+ * %true, the old rc_scan struct is returned so that it can be freed at a
+ * later stage.
  */
-static unsigned int ir_establish_scancode(struct rc_keytable *kt,
-					  struct rc_map *rc_map,
-					  struct rc_map_table *entry,
-					  bool resize)
+static struct rc_scan *rc_keytable_add_entry(struct rc_keytable *kt,
+					     struct rc_map_table *entry,
+					     bool init)
 {
-	unsigned int i;
+	struct rc_scan *old_scan = kt->scan;
+	struct rc_scan *new_scan = kt->scan;
+	unsigned i;
 
-	/*
-	 * Unfortunately, some hardware-based IR decoders don't provide
-	 * all bits for the complete IR code. In general, they provide only
-	 * the command part of the IR code. Yet, as it is possible to replace
-	 * the provided IR with another one, it is needed to allow loading
-	 * IR tables from other remotes. So, we support specifying a mask to
-	 * indicate the valid bits of the scancodes.
-	 */
-	if (kt->dev->scancode_mask)
-		entry->scancode &= kt->dev->scancode_mask;
+	if (old_scan->len >= RC_TAB_MAX_SIZE)
+		return NULL;
 
-	/*
-	 * First check if we already have a mapping for this command.
-	 * Note that the keytable is sorted first on protocol and second
-	 * on scancode (lowest to highest).
-	 */
-	for (i = 0; i < rc_map->len; i++) {
-		if (rc_map->scan[i].protocol < entry->protocol)
+	/* Find the right index to insert the new entry at */
+	for (i = 0; i < old_scan->len; i++) {
+		if (old_scan->table[i].protocol < entry->protocol)
 			continue;
 
-		if (rc_map->scan[i].protocol > entry->protocol)
+		if (old_scan->table[i].protocol > entry->protocol)
 			break;
 
-		if (rc_map->scan[i].scancode < entry->scancode)
+		if (old_scan->table[i].scancode < entry->scancode)
 			continue;
 
-		if (rc_map->scan[i].scancode > entry->scancode)
+		if (old_scan->table[i].scancode > entry->scancode)
 			break;
 
-		return i;
+		/* BUG: We already have a matching entry */
+		return NULL;
 	}
 
-	/* No previous mapping found, we might need to grow the table */
-	if (rc_map->size == rc_map->len) {
-		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
-			return -1U;
+	if (init) {
+		/* The init code already allocates a suitably sized table */
+		memmove(&new_scan->table[i + 1], &new_scan->table[i],
+			(new_scan->len - i) * sizeof(struct rc_map_table));
+		new_scan->len++;
+	} else {
+		new_scan = kmalloc(rc_scan_size(old_scan->len + 1), GFP_ATOMIC);
+		if (!new_scan)
+			return NULL;
+		new_scan->len = old_scan->len + 1;
+		memcpy(&new_scan->table[0], &old_scan->table[0],
+		       i * sizeof(struct rc_map_table));
+		memcpy(&new_scan->table[i + 1], &old_scan->table[i],
+		       (old_scan->len - i) * sizeof(struct rc_map_table));
 	}
 
-	/* i is the proper index to insert our new keycode */
-	if (i < rc_map->len)
-		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
-			(rc_map->len - i) * sizeof(struct rc_map_table));
-	rc_map->scan[i].scancode = entry->scancode;
-	rc_map->scan[i].protocol = entry->protocol;
-	rc_map->scan[i].keycode = KEY_RESERVED;
-	rc_map->len++;
+	new_scan->table[i].scancode = entry->scancode;
+	new_scan->table[i].protocol = entry->protocol;
+	new_scan->table[i].keycode = entry->keycode;
+	IR_dprintk(1, "#%d: New proto 0x%04x, scan 0x%08llx with key 0x%04x\n",
+		   i, entry->protocol, (unsigned long long)entry->scancode,
+		   entry->keycode);
+	__set_bit(entry->keycode, kt->idev->keybit);
 
-	return i;
+	rcu_assign_pointer(kt->scan, new_scan);
+	return old_scan;
 }
 
 /**
  * guess_protocol() - heuristics to guess the protocol for a scancode
  * @rdev:	the struct rc_dev device descriptor
- * @return:	the guessed RC_TYPE_* protocol
+ * @scan:	the struct rc_scan table to use
+ * @return:     the guessed RC_TYPE_* protocol
  *
  * Internal routine to guess the current IR protocol for legacy ioctls.
  */
-static inline enum rc_type guess_protocol(struct rc_dev *rdev)
+static inline enum rc_type guess_protocol(struct rc_dev *rdev,
+					  struct rc_scan *scan)
 {
-	struct rc_map *rc_map = &rdev->keytables[0]->rc_map;
-
 	if (hweight64(rdev->enabled_protocols) == 1)
 		return rc_bitmap_to_type(rdev->enabled_protocols);
 	else if (hweight64(rdev->allowed_protocols) == 1)
 		return rc_bitmap_to_type(rdev->allowed_protocols);
-	else if (rc_map->len > 0)
-		return rc_map->scan[0].protocol;
+	else if (scan->len > 0)
+		return scan->table[0].protocol;
 	else
 		return RC_TYPE_OTHER;
 }
@@ -359,33 +309,71 @@ static u32 to_nec32(u32 orig)
 }
 
 /**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * rc_scancode_to_index() - locate keytable index by scancode
+ * @rc_scan:	the struct rc_scan to search
+ * @protocol:	protocol to look for in the table
+ * @scancode:	scancode to look for in the table
+ * @return:	index in the table, -1U if not found
+ *
+ * This routine performs a binary search in a keytable for a
+ * given scancode.
+ */
+static unsigned rc_scancode_to_index(struct rc_scan *scan,
+				     u16 protocol, u64 scancode)
+{
+	int start = 0;
+	int end = scan->len - 1;
+	int mid;
+	struct rc_map_table *m;
+
+	while (start <= end) {
+		mid = (start + end) / 2;
+		m = &scan->table[mid];
+
+		if (m->protocol < protocol)
+			start = mid + 1;
+		else if (m->protocol > protocol)
+			end = mid - 1;
+		else if (m->scancode < scancode)
+			start = mid + 1;
+		else if (m->scancode > scancode)
+			end = mid - 1;
+		else
+			return mid;
+	}
+
+	return -1U;
+}
+
+/**
+ * rc_keytable_set() - add/update/remove an entry in the keytable
  * @idev:	the struct input_dev device descriptor
- * @scancode:	the desired scancode
- * @keycode:	result
- * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
+ * @ke:		the keymap entry to add/update/remove
+ * @old_keycode:used to return the previous keycode for this entry
+ * @return:	zero on success or a negative error code
  *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
+ * This function handles the evdev EVIOCSKEYCODE(_V2) ioctls.
  */
-static int ir_setkeycode(struct input_dev *idev,
-			 const struct input_keymap_entry *ke,
-			 unsigned int *old_keycode)
+static int rc_keytable_set(struct input_dev *idev,
+			   const struct input_keymap_entry *ke,
+			   unsigned int *old_keycode)
 {
 	struct rc_keytable *kt = input_get_drvdata(idev);
 	struct rc_dev *rdev = kt->dev;
-	struct rc_map *rc_map = &kt->rc_map;
+	struct rc_scan *old_scan = NULL;
 	unsigned int index;
 	struct rc_map_table entry;
 	int retval = 0;
-	unsigned long flags;
 
 	entry.keycode = ke->keycode;
 
-	spin_lock_irqsave(&kt->lock, flags);
+	retval = mutex_lock_interruptible(&kt->scan_mutex);
+	if (retval)
+		return retval;
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
 		index = ke->index;
-		if (index >= rc_map->len) {
+		if (index >= kt->scan->len) {
 			retval = -EINVAL;
 			goto out;
 		}
@@ -397,15 +385,16 @@ static int ir_setkeycode(struct input_dev *idev,
 			goto out;
 
 		entry.scancode = scancode;
-		entry.protocol = guess_protocol(rdev);
+		entry.protocol = guess_protocol(rdev, kt->scan);
 		if (entry.protocol == RC_TYPE_NEC)
 			entry.scancode = to_nec32(scancode);
 
-		index = ir_establish_scancode(kt, rc_map, &entry, true);
-		if (index >= rc_map->len) {
-			retval = -ENOMEM;
-			goto out;
-		}
+		if (kt->dev->scancode_mask)
+			entry.scancode &= kt->dev->scancode_mask;
+
+		index = rc_scancode_to_index(kt->scan, entry.protocol,
+					     entry.scancode);
+
 	} else if (ke->len == sizeof(struct rc_scancode)) {
 		/* New EVIOCSKEYCODE_V2 ioctl */
 		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
@@ -417,127 +406,63 @@ static int ir_setkeycode(struct input_dev *idev,
 			goto out;
 		}
 
-		index = ir_establish_scancode(kt, rc_map, &entry, true);
-		if (index >= rc_map->len) {
-			retval = -ENOMEM;
-			goto out;
-		}
+		if (kt->dev->scancode_mask)
+			entry.scancode &= kt->dev->scancode_mask;
+
+		index = rc_scancode_to_index(kt->scan, entry.protocol,
+					     entry.scancode);
+
 	} else {
 		retval = -EINVAL;
 		goto out;
 	}
 
-	*old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
-
-out:
-	spin_unlock_irqrestore(&kt->lock, flags);
-	return retval;
-}
-
-/**
- * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @kt:		the struct rc_keytable descriptor
- * @to:		the struct rc_map to copy entries to
- * @from:	the struct rc_map to copy entries from
- * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-int rc_setkeytable(struct rc_keytable *kt, const struct rc_map *from)
-{
-	struct rc_map *rc_map = &kt->rc_map;
-	struct rc_map_table entry;
-	unsigned int i, index;
-	int rc;
-
-	rc = ir_create_table(rc_map, from->name, from->size);
-	if (rc)
-		return rc;
-
-	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-		   rc_map->size, rc_map->alloc);
-
-	for (i = 0; i < from->size; i++) {
-		if (from->rc_type == RC_TYPE_NEC)
-			entry.scancode = to_nec32(from->scan[i].scancode);
+	if (index >= kt->scan->len) {
+		/* Old entry not found */
+		*old_keycode = KEY_RESERVED;
+		if (ke->keycode == KEY_RESERVED)
+			/* removing a non-existing entry eh? */
+			goto out;
+		old_scan = rc_keytable_add_entry(kt, &entry, false);
+	} else {
+		/* Previous entry found */
+		*old_keycode = kt->scan->table[index].keycode;
+		if (ke->keycode == KEY_RESERVED)
+			old_scan = rc_keytable_remove_entry(kt, index);
 		else
-			entry.scancode = from->scan[i].scancode;
-
-		entry.protocol = from->rc_type;
-		index = ir_establish_scancode(kt, rc_map, &entry, false);
-		if (index >= rc_map->len) {
-			rc = -ENOMEM;
-			break;
-		}
-
-		ir_update_mapping(kt, rc_map, index, from->scan[i].keycode);
+			old_scan = rc_keytable_update_entry(kt, index, &entry);
 	}
 
-	if (rc)
-		ir_free_table(rc_map);
-
-	return rc;
-}
-
-/**
- * ir_lookup_by_scancode() - locate mapping by scancode
- * @rc_map:	the struct rc_map to search
- * @protocol:	protocol to look for in the table
- * @scancode:	scancode to look for in the table
- * @return:	index in the table, -1U if not found
- *
- * This routine performs binary search in RC keykeymap table for
- * given scancode.
- */
-static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
-					  u16 protocol, u64 scancode)
-{
-	int start = 0;
-	int end = rc_map->len - 1;
-	int mid;
-	struct rc_map_table *m;
-
-	while (start <= end) {
-		mid = (start + end) / 2;
-		m = &rc_map->scan[mid];
-
-		if (m->protocol < protocol)
-			start = mid + 1;
-		else if (m->protocol > protocol)
-			end = mid - 1;
-		else if (m->scancode < scancode)
-			start = mid + 1;
-		else if (m->scancode > scancode)
-			end = mid - 1;
-		else
-			return mid;
+out:
+	mutex_unlock(&kt->scan_mutex);
+	if (old_scan) {
+		synchronize_rcu();
+		kfree(old_scan);
 	}
-
-	return -1U;
+	return retval;
 }
 
 /**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * rc_keytable_get() - get an entry from the keytable
  * @idev:	the struct input_dev device descriptor
- * @scancode:	the desired scancode
- * @keycode:	used to return the keycode, if found, or KEY_RESERVED
- * @return:	always returns zero.
+ * @ke:		the requested entry which is filled in by this function
+ * @return:	zero on success, or a negative error code
  *
- * This routine is used to handle evdev EVIOCGKEY ioctl.
+ * This function handles the evdev EVIOCGKEYCODE(_V2) ioctls.
  */
-int ir_getkeycode(struct input_dev *idev,
-		  struct input_keymap_entry *ke)
+static int rc_keytable_get(struct input_dev *idev,
+			   struct input_keymap_entry *ke)
 {
 	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
 	struct rc_keytable *kt = input_get_drvdata(idev);
 	struct rc_dev *rdev = kt->dev;
-	struct rc_map *rc_map = &kt->rc_map;
+	struct rc_scan *scan;
 	struct rc_map_table *entry;
-	unsigned long flags;
 	unsigned int index;
 	int retval;
 
-	spin_lock_irqsave(&kt->lock, flags);
+	rcu_read_lock();
+	scan = rcu_dereference(kt->scan);
 
 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
 		index = ke->index;
@@ -550,11 +475,11 @@ int ir_getkeycode(struct input_dev *idev,
 		if (retval)
 			goto out;
 
-		protocol = guess_protocol(rdev);
+		protocol = guess_protocol(rdev, scan);
 		if (protocol == RC_TYPE_NEC)
 			scancode = to_nec32(scancode);
 
-		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+		index = rc_scancode_to_index(scan, protocol, scancode);
 
 	} else if (ke->len == sizeof(struct rc_scancode)) {
 		/* New EVIOCGKEYCODE_V2 ioctl */
@@ -563,16 +488,17 @@ int ir_getkeycode(struct input_dev *idev,
 			goto out;
 		}
 
-		index = ir_lookup_by_scancode(rc_map,
-					      rke->rc.protocol, rke->rc.scancode);
+		index = rc_scancode_to_index(scan,
+					     rke->rc.protocol,
+					     rke->rc.scancode);
 
 	} else {
 		retval = -EINVAL;
 		goto out;
 	}
 
-	if (index < rc_map->len) {
-		entry = &rc_map->scan[index];
+	if (index < scan->len) {
+		entry = &scan->table[index];
 		ke->index = index;
 		ke->keycode = entry->keycode;
 		if (ke->len == sizeof(int)) {
@@ -600,29 +526,10 @@ int ir_getkeycode(struct input_dev *idev,
 	retval = 0;
 
 out:
-	spin_unlock_irqrestore(&kt->lock, flags);
+	rcu_read_unlock();
 	return retval;
 }
 
-static u32 rc_get_keycode(struct rc_keytable *kt,
-			  enum rc_type protocol, u64 scancode)
-{
-	struct rc_map *rc_map;
-	unsigned int keycode = KEY_RESERVED;
-	unsigned int index;
-
-	rc_map = &kt->rc_map;
-	if (!rc_map)
-		return KEY_RESERVED;
-
-	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
-	if (index < rc_map->len)
-		keycode = rc_map->scan[index].keycode;
-
-	return keycode;
-}
-
-
 /**
  * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
  * @dev:	the struct rc_dev descriptor of the device
@@ -638,18 +545,20 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
 			    enum rc_type protocol, u64 scancode)
 {
 	struct rc_keytable *kt;
-	unsigned int keycode = KEY_RESERVED;
-	unsigned long flags;
+	struct rc_scan *scan;
+	unsigned keycode = KEY_RESERVED;
+	unsigned index;
 
 	/* FIXME: This entire function is a hack. Remove it */
 	rcu_read_lock();
 	kt = rcu_dereference(dev->keytables[0]);
 	if (!kt)
 		goto out;
+	scan = rcu_dereference(kt->scan);
 
-	spin_lock_irqsave(&kt->lock, flags);
-	keycode = rc_get_keycode(kt, protocol, scancode);
-	spin_unlock_irqrestore(&kt->lock, flags);
+	index = rc_scancode_to_index(scan, protocol, scancode);
+	if (index < scan->len)
+		keycode = scan->table[index].keycode;
 
 out:
 	rcu_read_unlock();
@@ -663,11 +572,11 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
  * @sync:	whether or not to call input_sync
  *
  * This function is used internally to release a keypress, it must be
- * called with kt->lock held.
+ * called with kt->key_lock held.
  */
 static void rc_do_keyup(struct rc_keytable *kt, bool sync)
 {
-	if (!kt->keypressed)
+	if (!kt->key_pressed)
 		return;
 
 	IR_dprintk(1, "keyup key 0x%04x\n", kt->last_keycode);
@@ -675,7 +584,7 @@ static void rc_do_keyup(struct rc_keytable *kt, bool sync)
 	led_trigger_event(led_feedback, LED_OFF);
 	if (sync)
 		input_sync(kt->idev);
-	kt->keypressed = false;
+	kt->key_pressed = false;
 }
 
 /**
@@ -688,14 +597,14 @@ void rc_keytable_keyup(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->lock, flags);
+	spin_lock_irqsave(&kt->key_lock, flags);
 	rc_do_keyup(kt, true);
-	spin_unlock_irqrestore(&kt->lock, flags);
+	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
 /**
- * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie:	a pointer to the struct rc_keytable
+ * rc_timer_keyup() - generates a keyup event after a timeout
+ * @cookie:	a pointer to the struct rc_keytable descriptor of the keytable
  *
  * This routine will generate a keyup event some time after a keydown event
  * is generated when no further activity has been detected.
@@ -715,37 +624,36 @@ static void rc_timer_keyup(unsigned long cookie)
 	 * to allow the input subsystem to do its auto-repeat magic or
 	 * a keyup event might follow immediately after the keydown.
 	 */
-	spin_lock_irqsave(&kt->lock, flags);
+	spin_lock_irqsave(&kt->key_lock, flags);
 	if (time_is_before_eq_jiffies(kt->keyup_jiffies))
 		rc_do_keyup(kt, true);
-	spin_unlock_irqrestore(&kt->lock, flags);
+	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
 /**
  * rc_keytable_repeat() - signals that a key is still pressed
  * @kt:		the keytable
  *
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
+ * This routine is used when a repeat message which does not include the
+ * necessary bits to reproduce the scancode has been received.
  */
 void rc_keytable_repeat(struct rc_keytable *kt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->lock, flags);
+	spin_lock_irqsave(&kt->key_lock, flags);
 
 	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
 	input_sync(kt->idev);
 
-	if (!kt->keypressed)
+	if (!kt->key_pressed)
 		goto out;
 
-	kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
 	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
 
 out:
-	spin_unlock_irqrestore(&kt->lock, flags);
+	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
 /**
@@ -762,26 +670,33 @@ out:
 void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 			 u32 scancode, u8 toggle, bool autoup)
 {
+	struct rc_scan *scan;
+	unsigned index;
+	u32 keycode = KEY_RESERVED;
 	unsigned long flags;
-	u32 keycode;
 	bool new_event;
 
-	spin_lock_irqsave(&kt->lock, flags);
+	rcu_read_lock();
+	scan = rcu_dereference(kt->scan);
+	index = rc_scancode_to_index(scan, protocol, scancode);
+	if (index < scan->len)
+		keycode = scan->table[index].keycode;
+	rcu_read_unlock();
 
-	keycode = rc_get_keycode(kt, protocol, scancode);
-	new_event = (!kt->keypressed ||
+	spin_lock_irqsave(&kt->key_lock, flags);
+	new_event = (!kt->key_pressed ||
 		     kt->last_protocol != protocol ||
 		     kt->last_scancode != scancode ||
 		     kt->last_toggle != toggle);
 
-	if (new_event && kt->keypressed)
+	if (new_event)
 		rc_do_keyup(kt, false);
 
 	input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
 
 	if (new_event && keycode != KEY_RESERVED) {
 		/* Register a keypress */
-		kt->keypressed = true;
+		kt->key_pressed = true;
 		kt->last_protocol = protocol;
 		kt->last_scancode = scancode;
 		kt->last_toggle = toggle;
@@ -795,11 +710,11 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 	}
 	input_sync(kt->idev);
 
-	if (autoup && kt->keypressed) {
-		kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+	if (autoup && kt->key_pressed) {
+		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
 		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
 	}
-	spin_unlock_irqrestore(&kt->lock, flags);
+	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
 static int rc_input_open(struct input_dev *idev)
@@ -817,6 +732,42 @@ static void rc_input_close(struct input_dev *idev)
 }
 
 /**
+ * rc_keytable_init() - performs initial setup of a keytable
+ * @dev:	the struct rc_dev device descriptor
+ * @from:	the struct rc_map to copy entries from
+ * @return:	zero on success, or a negative error code
+ *
+ * This function is used to handle table initialization.
+ */
+static int rc_keytable_init(struct rc_keytable *kt,
+			    const struct rc_map *from)
+{
+	unsigned size;
+	unsigned i;
+	struct rc_map_table entry;
+
+	size = from ? from->size : 0;
+	kt->scan = kmalloc(rc_scan_size(size), GFP_KERNEL);
+	if (!kt->scan)
+		return -ENOMEM;
+
+	kt->scan->len = 0;
+	for (i = 0; i < size; i++) {
+		entry.protocol = from->rc_type;
+		if (entry.protocol == RC_TYPE_NEC)
+			entry.scancode = to_nec32(from->scan[i].scancode);
+		else
+			entry.scancode = from->scan[i].scancode;
+		if (kt->dev->scancode_mask)
+			entry.scancode &= kt->dev->scancode_mask;
+		entry.keycode = from->scan[i].keycode;
+		rc_keytable_add_entry(kt, &entry, true);
+	}
+
+	return 0;
+}
+
+/**
  * rc_keytable_create() - create a new keytable
  * @dev:	the struct rc_dev device this keytable should belong to
  * @name:	the userfriendly name of this keymap
@@ -848,10 +799,11 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 
 	kt->idev = idev;
 	kt->dev = dev;
-	spin_lock_init(&kt->lock);
+	spin_lock_init(&kt->key_lock);
+	mutex_init(&kt->scan_mutex);
 	snprintf(kt->name, sizeof(*kt->name), name ? name : "undefined");
-	idev->getkeycode = ir_getkeycode;
-	idev->setkeycode = ir_setkeycode;
+	idev->getkeycode = rc_keytable_get;
+	idev->setkeycode = rc_keytable_set;
 	idev->open = rc_input_open;
 	idev->close = rc_input_close;
 	set_bit(EV_KEY, idev->evbit);
@@ -861,7 +813,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 	input_set_drvdata(idev, kt);
 	setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
 
-	err = rc_setkeytable(kt, rc_map);
+	err = rc_keytable_init(kt, rc_map);
 	if (err)
 		goto out;
 
@@ -892,8 +844,8 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 	return kt;
 
 out:
-	ir_free_table(&kt->rc_map);
 	input_free_device(idev);
+	kfree(kt->scan);
 	kfree(kt);
 	return ERR_PTR(err);
 }
@@ -910,8 +862,8 @@ void rc_keytable_destroy(struct rc_keytable *kt)
 		return;
 
 	del_timer_sync(&kt->timer_keyup);
-	ir_free_table(&kt->rc_map);
 	input_unregister_device(kt->idev);
+	kfree(kt->scan);
 	kfree(kt);
 }
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index af63188..228510e 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -386,35 +386,47 @@ struct rc_dev {
 };
 
 /**
+ * struct rc_scan - rcu-friendly scancode<->keycode table
+ * @len:	number of elements in the table array
+ * @table:	array of struct rc_map_table elements
+ */
+struct rc_scan {
+	unsigned len;
+	struct rc_map_table table[];
+};
+
+/**
  * struct rc_keytable - represents one keytable for a rc_dev device
  * @node:		used to iterate over all keytables for a rc_dev device
  * @dev:		the rc_dev device this keytable belongs to
  * @idev:		the input_dev device which belongs to this keytable
  * @name:		the user-friendly name of this keytable
- * @rc_map:		holds the scancode <-> keycode mappings
- * @keypressed:		whether a key is currently pressed or not
- * @keyup_jiffies:	when the key should be auto-released
- * @timer_keyup:	responsible for the auto-release of keys
- * @lock:		protects the key state
+ * @scan_mutex:		protects @scan against concurrent writers
+ * @scan:		the current scancode<->keycode table
+ * @key_lock:		protects the key state
+ * @key_pressed:	whether a key is currently pressed or not
  * @last_keycode:	keycode of the last keypress
  * @last_protocol:	protocol of the last keypress
  * @last_scancode:	scancode of the last keypress
  * @last_toggle:	toggle of the last keypress
+ * @timer_keyup:	responsible for the auto-release of keys
+ * @keyup_jiffies:	when the key should be auto-released
  */
 struct rc_keytable {
 	struct list_head		node;
 	struct rc_dev			*dev;
 	struct input_dev		*idev;
 	char				name[RC_KEYTABLE_NAME_SIZE];
-	struct rc_map			rc_map;
-	bool				keypressed;
-	unsigned long			keyup_jiffies;
-	struct timer_list		timer_keyup;
-	spinlock_t			lock;
+	struct mutex			scan_mutex;
+	struct rc_scan __rcu		*scan;
+	spinlock_t			key_lock;
+	bool				key_pressed;
 	u32				last_keycode;
 	enum rc_type			last_protocol;
 	u32				last_scancode;
 	u8				last_toggle;
+	struct timer_list		timer_keyup;
+	unsigned long			keyup_jiffies;
 };
 
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)


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

* [PATCH 37/49] rc-core: allow empty keymaps
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (35 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 36/49] rc-core: make keytable RCU-friendly David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-07-25 22:58   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 38/49] rc-core: rename ir-raw.c David Härdeman
                   ` (13 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Remove the RC_MAP_EMPTY hack and instead allow for empty keymaps.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/i2c/ir-kbd-i2c.c             |    4 +--
 drivers/media/pci/cx88/cx88-input.c        |    6 -----
 drivers/media/pci/ivtv/ivtv-i2c.c          |    2 +-
 drivers/media/rc/gpio-ir-recv.c            |    2 +-
 drivers/media/rc/img-ir/img-ir-hw.c        |    1 -
 drivers/media/rc/img-ir/img-ir-raw.c       |    1 -
 drivers/media/rc/rc-keytable.c             |    3 +++
 drivers/media/rc/rc-loopback.c             |    1 -
 drivers/media/rc/rc-main.c                 |   33 ++--------------------------
 drivers/media/usb/dvb-usb-v2/af9015.c      |    4 ---
 drivers/media/usb/dvb-usb-v2/af9035.c      |    4 ---
 drivers/media/usb/dvb-usb-v2/az6007.c      |    4 ++-
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c    |    4 ---
 drivers/media/usb/dvb-usb/dvb-usb-remote.c |    4 +--
 drivers/media/usb/em28xx/em28xx-cards.c    |    1 -
 include/media/rc-map.h                     |    1 -
 16 files changed, 11 insertions(+), 64 deletions(-)

diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 8311f1a..5393558 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -309,7 +309,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		name        = "Pixelview";
 		ir->get_key = get_key_pixelview;
 		rc_type     = RC_BIT_OTHER;
-		ir_codes    = RC_MAP_EMPTY;
 		break;
 	case 0x18:
 	case 0x1f:
@@ -323,7 +322,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		name        = "KNC One";
 		ir->get_key = get_key_knc1;
 		rc_type     = RC_BIT_OTHER;
-		ir_codes    = RC_MAP_EMPTY;
 		break;
 	case 0x6b:
 		name        = "FusionHDTV";
@@ -405,7 +403,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	ir->rc = rc;
 
 	/* Make sure we are all setup before going on */
-	if (!name || !ir->get_key || !rc_type || !ir_codes) {
+	if (!name || !ir->get_key || !rc_type) {
 		dprintk(1, ": Unsupported device at address 0x%02x\n",
 			addr);
 		err = -ENODEV;
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 3f1342c..cb587ce 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -437,11 +437,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		break;
 	}
 
-	if (!ir_codes) {
-		err = -ENODEV;
-		goto err_out_free;
-	}
-
 	/*
 	 * The usage of mask_keycode were very convenient, due to several
 	 * reasons. Among others, the scancode tables were using the scancode
@@ -612,7 +607,6 @@ void cx88_i2c_init_ir(struct cx88_core *core)
 		core->init_data.name = "cx88 Leadtek PVR 2000 remote";
 		core->init_data.type = RC_BIT_UNKNOWN;
 		core->init_data.get_key = get_key_pvr2000;
-		core->init_data.ir_codes = RC_MAP_EMPTY;
 		break;
 	}
 
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index 1a41ba5..846bb51 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -222,7 +222,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
 		init_data->get_key = get_key_adaptec;
 		init_data->name = itv->card_name;
 		/* FIXME: The protocol and RC_MAP needs to be corrected */
-		init_data->ir_codes = RC_MAP_EMPTY;
+		/* init_data->ir_codes = RC_MAP_? */
 		init_data->type = RC_BIT_UNKNOWN;
 		break;
 	}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 5985308..7d01560 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -148,7 +148,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 		rcdev->allowed_protocols = pdata->allowed_protos;
 	else
 		rcdev->allowed_protocols = RC_BIT_ALL;
-	rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
+	rcdev->map_name = pdata->map_name;
 
 	gpio_dev->rcdev = rcdev;
 	gpio_dev->gpio_nr = pdata->gpio_nr;
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 3bb6a32..5bc7903 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -993,7 +993,6 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
 		goto err_alloc_rc;
 	}
 	rdev->priv = priv;
-	rdev->map_name = RC_MAP_EMPTY;
 	rdev->allowed_protocols = img_ir_allowed_protos(priv);
 	rdev->input_name = "IMG Infrared Decoder";
 	rdev->s_filter = img_ir_set_normal_filter;
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
index cfb01d9..5b6d8e9 100644
--- a/drivers/media/rc/img-ir/img-ir-raw.c
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -111,7 +111,6 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
 		return -ENOMEM;
 	}
 	rdev->priv = priv;
-	rdev->map_name = RC_MAP_EMPTY;
 	rdev->input_name = "IMG Infrared Decoder Raw";
 	rdev->driver_type = RC_DRIVER_IR_RAW;
 
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 89295f3..5709ae6 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -55,6 +55,9 @@ struct rc_map *rc_map_get(const char *name)
 
 	struct rc_map_list *map;
 
+	if (!name)
+		return NULL;
+
 	map = seek_rc_map(name);
 #ifdef MODULE
 	if (!map) {
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 628e834..f201395 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -226,7 +226,6 @@ static int __init loop_init(void)
 	rc->input_id.bustype	= BUS_VIRTUAL;
 	rc->input_id.version	= 1;
 	rc->driver_name		= DRIVER_NAME;
-	rc->map_name		= RC_MAP_EMPTY;
 	rc->priv		= &loopdev;
 	rc->driver_type		= RC_DRIVER_IR_RAW;
 	rc->allowed_protocols	= RC_BIT_ALL;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index ad784c8..8729d0a 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -207,12 +207,6 @@ static int rc_add_keytable(struct rc_dev *dev, const char *name,
 	struct rc_keytable *kt;
 	unsigned i;
 
-	if (!rc_map)
-		rc_map = rc_map_get(RC_MAP_EMPTY);
-
-	if (!rc_map)
-		return -EFAULT;
-
 	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
 		if (!dev->keytables[i])
 			break;
@@ -1321,22 +1315,14 @@ int rc_register_device(struct rc_dev *dev)
 	if (dev->map_name)
 		rc_map = rc_map_get(dev->map_name);
 
-	if (!rc_map)
-		rc_map = rc_map_get(RC_MAP_EMPTY);
-
-	if (!rc_map || !rc_map->scan || rc_map->size == 0) {
-		rc = -EFAULT;
-		goto out_raw;
-	}
-
-	if (dev->change_protocol && rc_map->len > 0) {
+	if (dev->change_protocol && rc_map && rc_map->len > 0) {
 		u64 rc_type = (1 << rc_map->scan[0].protocol);
 		rc = dev->change_protocol(dev, &rc_type);
 		if (rc < 0)
 			goto out_raw;
 		dev->enabled_protocols = rc_type;
 	}
-	
+
 	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
 	if (rc)
 		goto out_raw;
@@ -1407,19 +1393,6 @@ void rc_unregister_device(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
-static struct rc_map_table empty[] = {
-	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
-};
-
-static struct rc_map_list empty_map = {
-	.map = {
-		.scan    = empty,
-		.size    = ARRAY_SIZE(empty),
-		.rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
-		.name    = RC_MAP_EMPTY,
-	}
-};
-
 static int __init rc_core_init(void)
 {
 	int err;
@@ -1439,14 +1412,12 @@ static int __init rc_core_init(void)
 
 	IR_dprintk(1, "Allocated char dev: %u\n", MAJOR(rc_devt));
 	led_trigger_register_simple("rc-feedback", &led_feedback);
-	rc_map_register(&empty_map);
 
 	return 0;
 }
 
 static void __exit rc_core_exit(void)
 {
-	rc_map_unregister(&empty_map);
 	led_trigger_unregister_simple(led_feedback);
 	unregister_chrdev_region(rc_devt, RC_DEV_MAX);
 	class_unregister(&rc_class);
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index 8776eaf..31066e8 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1297,10 +1297,6 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
 		}
 	}
 
-	/* load empty to enable rc */
-	if (!rc->map_name)
-		rc->map_name = RC_MAP_EMPTY;
-
 	rc->allowed_protos = RC_BIT_NEC;
 	rc->query = af9015_rc_query;
 	rc->interval = 500;
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 6bc9693..cfe0be7 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1332,10 +1332,6 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
 
 		rc->query = af9035_rc_query;
 		rc->interval = 500;
-
-		/* load empty to enable rc */
-		if (!rc->map_name)
-			rc->map_name = RC_MAP_EMPTY;
 	}
 
 	return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 7e38278..9c2a07e 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -922,13 +922,13 @@ static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
 
 static struct usb_device_id az6007_usb_table[] = {
 	{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
-		&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
+		&az6007_props, "Azurewave 6007", NULL)},
 	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
 		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
 	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
 		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
 	{DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
-		&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
+		&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", NULL)},
 	{0},
 };
 
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 45c77b1..15f1e70 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1270,7 +1270,6 @@ err:
 static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
 		struct dvb_usb_rc *rc)
 {
-	rc->map_name = RC_MAP_EMPTY;
 	rc->allowed_protos = RC_BIT_NEC;
 	rc->query = rtl2831u_rc_query;
 	rc->interval = 400;
@@ -1373,9 +1372,6 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
 	if (rtl28xxu_disable_rc)
 		return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
 
-	/* load empty to enable rc */
-	if (!rc->map_name)
-		rc->map_name = RC_MAP_EMPTY;
 	rc->allowed_protos = RC_BIT_ALL;
 	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->query = rtl2832u_rc_query;
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 7b5dae3..5986626 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -313,10 +313,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
 
 	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
 		d->props.rc.mode = DVB_RC_LEGACY;
-	else if (d->props.rc.core.rc_codes)
-		d->props.rc.mode = DVB_RC_CORE;
 	else
-		return 0;
+		d->props.rc.mode = DVB_RC_CORE;
 
 	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
 	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 50aa5a5..cf803f2 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -1120,7 +1120,6 @@ struct em28xx_board em28xx_boards[] = {
 		.has_dvb      = 1,
 		/* FIXME: Add analog support - need a saa7136 driver */
 		.tuner_type = TUNER_ABSENT,	/* Digital-only TDA18271HD */
-		.ir_codes     = RC_MAP_EMPTY,
 		.def_i2c_bus  = 1,
 		.i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE,
 		.dvb_gpio     = c3tech_digital_duo_digital,
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 34c192f..417cce3 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -140,7 +140,6 @@ void rc_map_init(void);
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
-#define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
 #define RC_MAP_ENCORE_ENLTV_FM53         "rc-encore-enltv-fm53"


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

* [PATCH 38/49] rc-core: rename ir-raw.c
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (36 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 37/49] rc-core: allow empty keymaps David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 39/49] rc-core: make IR raw handling a separate module David Härdeman
                   ` (12 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Move drivers/media/rc/ir-raw.c to drivers/media/rc/rc-ir-raw.c in
preparation for the next patch.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/Makefile    |    2 +-
 drivers/media/rc/rc-ir-raw.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename drivers/media/rc/{ir-raw.c => rc-ir-raw.c} (99%)

diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index de08ee6..661f449 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,4 +1,4 @@
-rc-core-objs	:= rc-main.o rc-keytable.o ir-raw.o
+rc-core-objs	:= rc-main.o rc-keytable.o rc-ir-raw.o
 
 obj-y += keymaps/
 
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/rc-ir-raw.c
similarity index 99%
rename from drivers/media/rc/ir-raw.c
rename to drivers/media/rc/rc-ir-raw.c
index aa2503d..5ed8007 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -1,4 +1,4 @@
-/* ir-raw.c - handle IR pulse/space events
+/* rc-ir-raw.c - handle IR pulse/space events
  *
  * Copyright (C) 2010 by Mauro Carvalho Chehab
  *


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

* [PATCH 39/49] rc-core: make IR raw handling a separate module
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (37 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 38/49] rc-core: rename ir-raw.c David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-07-25 23:04   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 40/49] rc-ir-raw: simplify locking David Härdeman
                   ` (11 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Make drivers/media/rc/rc-ir-raw.c a separate kernel module.

Drivers which use IR decoding must use these functions:
	rc_register_ir_raw_device()
	rc_unregister_ir_raw_device()
instead of:
	rc_register_device()
	rc_unregister_device()

This allows scancode drivers to skip lots of unnecessary functionality.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/common/siano/smsir.c          |    5 +-
 drivers/media/common/siano/smsir.h          |    2 -
 drivers/media/i2c/cx25840/cx25840-ir.c      |    2 -
 drivers/media/pci/cx23885/cx23885-input.c   |   13 +---
 drivers/media/pci/cx23885/cx23888-ir.c      |    2 -
 drivers/media/pci/cx88/cx88-input.c         |   18 +++---
 drivers/media/pci/dm1105/dm1105.c           |    1 
 drivers/media/pci/saa7134/saa7134-input.c   |   14 +++--
 drivers/media/pci/saa7134/saa7134.h         |    2 -
 drivers/media/rc/Makefile                   |    3 +
 drivers/media/rc/ati_remote.c               |    1 
 drivers/media/rc/ene_ir.c                   |    9 +--
 drivers/media/rc/fintek-cir.c               |    7 +-
 drivers/media/rc/gpio-ir-recv.c             |    9 +--
 drivers/media/rc/iguanair.c                 |    7 +-
 drivers/media/rc/img-ir/img-ir-raw.c        |    7 +-
 drivers/media/rc/imon.c                     |    1 
 drivers/media/rc/ite-cir.c                  |    9 +--
 drivers/media/rc/mceusb.c                   |    7 +-
 drivers/media/rc/nuvoton-cir.c              |    7 +-
 drivers/media/rc/rc-core-priv.h             |   10 ++-
 drivers/media/rc/rc-ir-raw.c                |   39 +++++++++----
 drivers/media/rc/rc-loopback.c              |    7 +-
 drivers/media/rc/rc-main.c                  |   36 +-----------
 drivers/media/rc/redrat3.c                  |    7 +-
 drivers/media/rc/streamzap.c                |    7 +-
 drivers/media/rc/ttusbir.c                  |    9 +--
 drivers/media/rc/winbond-cir.c              |    9 +--
 drivers/media/usb/dvb-usb-v2/dvb_usb.h      |    5 +-
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |   12 +++-
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c     |    2 -
 drivers/media/usb/dvb-usb/dvb-usb-remote.c  |    9 ++-
 drivers/media/usb/dvb-usb/dvb-usb.h         |    5 +-
 drivers/media/usb/dvb-usb/technisat-usb2.c  |    2 -
 drivers/media/usb/em28xx/em28xx-input.c     |    5 --
 drivers/media/usb/tm6000/tm6000-input.c     |    1 
 include/media/rc-core.h                     |   73 +-----------------------
 include/media/rc-ir-raw.h                   |   83 +++++++++++++++++++++++++++
 38 files changed, 222 insertions(+), 225 deletions(-)
 create mode 100644 include/media/rc-ir-raw.h

diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 273043e..f6938f4 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -87,14 +87,13 @@ int sms_ir_init(struct smscore_device_t *coredev)
 #endif
 
 	dev->priv = coredev;
-	dev->driver_type = RC_DRIVER_IR_RAW;
 	dev->allowed_protocols = RC_BIT_ALL;
 	dev->map_name = sms_get_board(board_id)->rc_codes;
 	dev->driver_name = MODULE_NAME;
 
 	sms_log("Input device (IR) %s is set for key events", dev->input_name);
 
-	err = rc_register_device(dev);
+	err = rc_register_ir_raw_device(dev);
 	if (err < 0) {
 		sms_err("Failed to register device");
 		rc_free_device(dev);
@@ -108,7 +107,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 void sms_ir_exit(struct smscore_device_t *coredev)
 {
 	if (coredev->ir.dev)
-		rc_unregister_device(coredev->ir.dev);
+		rc_unregister_ir_raw_device(coredev->ir.dev);
 
 	sms_log("");
 }
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
index fc8b792..05a2b01 100644
--- a/drivers/media/common/siano/smsir.h
+++ b/drivers/media/common/siano/smsir.h
@@ -28,7 +28,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define __SMS_IR_H__
 
 #include <linux/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define IR_DEFAULT_TIMEOUT		100
 
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index e6588ee..119d4e8 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -25,7 +25,7 @@
 #include <linux/kfifo.h>
 #include <linux/module.h>
 #include <media/cx25840.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #include "cx25840-core.h"
 
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 1940c18..e2ba28d 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -36,7 +36,7 @@
  */
 
 #include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <media/v4l2-subdev.h>
 
 #include "cx23885.h"
@@ -258,7 +258,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	struct cx23885_kernel_ir *kernel_ir;
 	struct rc_dev *rc;
 	char *rc_map;
-	enum rc_driver_type driver_type;
 	unsigned long allowed_protos;
 
 	int ret;
@@ -276,28 +275,24 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 		/* Integrated CX2388[58] IR controller */
-		driver_type = RC_DRIVER_IR_RAW;
 		allowed_protos = RC_BIT_ALL;
 		/* The grey Hauppauge RC-5 remote */
 		rc_map = RC_MAP_HAUPPAUGE;
 		break;
 	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
 		/* Integrated CX23885 IR controller */
-		driver_type = RC_DRIVER_IR_RAW;
 		allowed_protos = RC_BIT_NEC;
 		/* The grey Terratec remote with orange buttons */
 		rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
 		break;
 	case CX23885_BOARD_TEVII_S470:
 		/* Integrated CX23885 IR controller */
-		driver_type = RC_DRIVER_IR_RAW;
 		allowed_protos = RC_BIT_ALL;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TEVII_NEC;
 		break;
 	case CX23885_BOARD_MYGICA_X8507:
 		/* Integrated CX23885 IR controller */
-		driver_type = RC_DRIVER_IR_RAW;
 		allowed_protos = RC_BIT_ALL;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
@@ -305,7 +300,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_TBS_6980:
 	case CX23885_BOARD_TBS_6981:
 		/* Integrated CX23885 IR controller */
-		driver_type = RC_DRIVER_IR_RAW;
 		allowed_protos = RC_BIT_ALL;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TBS_NEC;
@@ -345,7 +339,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
 		rc->input_id.product = dev->pci->device;
 	}
 	rc->dev.parent = &dev->pci->dev;
-	rc->driver_type = driver_type;
 	rc->allowed_protocols = allowed_protos;
 	rc->priv = kernel_ir;
 	rc->open = cx23885_input_ir_open;
@@ -355,7 +348,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
 
 	/* Go */
 	dev->kernel_ir = kernel_ir;
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret)
 		goto err_out_stop;
 
@@ -379,7 +372,7 @@ void cx23885_input_fini(struct cx23885_dev *dev)
 
 	if (dev->kernel_ir == NULL)
 		return;
-	rc_unregister_device(dev->kernel_ir->rc);
+	rc_unregister_ir_raw_device(dev->kernel_ir->rc);
 	kfree(dev->kernel_ir->phys);
 	kfree(dev->kernel_ir->name);
 	kfree(dev->kernel_ir);
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index 2c951de..c4961f8 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 
 #include <media/v4l2-device.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #include "cx23885.h"
 #include "cx23888-ir.h"
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index cb587ce..2b68ede 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -29,7 +29,7 @@
 #include <linux/module.h>
 
 #include "cx88.h"
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define MODULE_NAME "cx88xx"
 
@@ -474,20 +474,17 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 	dev->open = cx88_ir_open;
 	dev->close = cx88_ir_close;
 	dev->scancode_mask = hardware_mask;
+	ir->core = core;
+	core->ir = ir;
 
 	if (ir->sampling) {
-		dev->driver_type = RC_DRIVER_IR_RAW;
 		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+		err = rc_register_ir_raw_device(dev);
 	} else {
-		dev->driver_type = RC_DRIVER_SCANCODE;
 		dev->allowed_protocols = rc_type;
+		err = rc_register_device(dev);
 	}
 
-	ir->core = core;
-	core->ir = ir;
-
-	/* all done */
-	err = rc_register_device(dev);
 	if (err)
 		goto err_out_free;
 
@@ -509,7 +506,10 @@ int cx88_ir_fini(struct cx88_core *core)
 		return 0;
 
 	cx88_ir_stop(core);
-	rc_unregister_device(ir->dev);
+	if (ir->sampling)
+		rc_unregister_ir_raw_device(ir->dev);
+	else
+		rc_unregister_device(ir->dev);
 	kfree(ir);
 
 	/* done */
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e8826c5..015aa07 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -752,7 +752,6 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105)
 
 	dev->driver_name = MODULE_NAME;
 	dev->map_name = RC_MAP_DM1105_NEC;
-	dev->driver_type = RC_DRIVER_SCANCODE;
 	dev->input_name = "DVB on-card IR receiver";
 	dev->input_phys = dm1105->ir.input_phys;
 	dev->input_id.bustype = BUS_PCI;
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 4ba61ff..27a3f48 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -864,9 +864,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	rc->priv = dev;
 	rc->open = saa7134_ir_open;
 	rc->close = saa7134_ir_close;
-	if (raw_decode)
-		rc->driver_type = RC_DRIVER_IR_RAW;
-
 	rc->input_name = ir->name;
 	rc->input_phys = ir->phys;
 	rc->input_id.bustype = BUS_PCI;
@@ -882,7 +879,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	rc->map_name = ir_codes;
 	rc->driver_name = MODULE_NAME;
 
-	err = rc_register_device(rc);
+	if (raw_decode)
+		err = rc_register_ir_raw_device(rc);
+	else
+		err = rc_register_device(rc);
+
 	if (err)
 		goto err_out_free;
 
@@ -901,7 +902,10 @@ void saa7134_input_fini(struct saa7134_dev *dev)
 		return;
 
 	saa7134_ir_stop(dev);
-	rc_unregister_device(dev->remote->dev);
+	if (dev->remote->raw_decode)
+		rc_unregister_ir_raw_device(dev->remote->dev);
+	else
+		rc_unregister_device(dev->remote->dev);
 	kfree(dev->remote);
 	dev->remote = NULL;
 }
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 2474e84..5a25486 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -39,7 +39,7 @@
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/videobuf-dma-sg.h>
 #include <sound/core.h>
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 661f449..ac39628 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,8 +1,9 @@
-rc-core-objs	:= rc-main.o rc-keytable.o rc-ir-raw.o
+rc-core-objs	:= rc-main.o rc-keytable.o
 
 obj-y += keymaps/
 
 obj-$(CONFIG_RC_CORE) += rc-core.o
+obj-$(CONFIG_RC_CORE) += rc-ir-raw.o
 obj-$(CONFIG_LIRC) += lirc_dev.o
 obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
 obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 6ef5716..170aac8 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -784,7 +784,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
 	struct rc_dev *rdev = ati_remote->rdev;
 
 	rdev->priv = ati_remote;
-	rdev->driver_type = RC_DRIVER_SCANCODE;
 	rdev->allowed_protocols = RC_BIT_OTHER;
 	rdev->driver_name = "ati_remote";
 
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index cab5da9..57d61e5 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include "ene_ir.h"
 
 static int sample_period;
@@ -1053,7 +1053,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 	if (!dev->hw_learning_and_tx_capable)
 		learning_mode_force = false;
 
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->priv = dev;
 	rdev->open = ene_open;
@@ -1083,7 +1082,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 	device_set_wakeup_capable(&pnp_dev->dev, true);
 	device_set_wakeup_enable(&pnp_dev->dev, true);
 
-	error = rc_register_device(rdev);
+	error = rc_register_ir_raw_device(rdev);
 	if (error < 0)
 		goto exit_free_dev_rdev;
 
@@ -1104,7 +1103,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 exit_release_hw_io:
 	release_region(dev->hw_io, ENE_IO_SIZE);
 exit_unregister_device:
-	rc_unregister_device(rdev);
+	rc_unregister_ir_raw_device(rdev);
 	rdev = NULL;
 exit_free_dev_rdev:
 	rc_free_device(rdev);
@@ -1125,7 +1124,7 @@ static void ene_remove(struct pnp_dev *pnp_dev)
 
 	free_irq(dev->irq, dev);
 	release_region(dev->hw_io, ENE_IO_SIZE);
-	rc_unregister_device(dev->rdev);
+	rc_unregister_ir_raw_device(dev->rdev);
 	kfree(dev);
 }
 
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index f000faf..ce2db15 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -32,7 +32,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <linux/pci_ids.h>
 
 #include "fintek-cir.h"
@@ -540,7 +540,6 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
 
 	/* Set up the rc device */
 	rdev->priv = fintek;
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = fintek_open;
 	rdev->close = fintek_close;
@@ -569,7 +568,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
 			FINTEK_DRIVER_NAME, (void *)fintek))
 		goto exit_free_cir_addr;
 
-	ret = rc_register_device(rdev);
+	ret = rc_register_ir_raw_device(rdev);
 	if (ret)
 		goto exit_free_irq;
 
@@ -609,7 +608,7 @@ static void fintek_remove(struct pnp_dev *pdev)
 	free_irq(fintek->cir_irq, fintek);
 	release_region(fintek->cir_addr, fintek->cir_port_len);
 
-	rc_unregister_device(fintek->rdev);
+	rc_unregister_ir_raw_device(fintek->rdev);
 
 	kfree(fintek);
 }
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 7d01560..ff30bdb 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -20,7 +20,7 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <media/gpio-ir-recv.h>
 
 #define GPIO_IR_DRIVER_NAME	"gpio-rc-recv"
@@ -135,7 +135,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	}
 
 	rcdev->priv = gpio_dev;
-	rcdev->driver_type = RC_DRIVER_IR_RAW;
 	rcdev->input_name = GPIO_IR_DEVICE_NAME;
 	rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
 	rcdev->input_id.bustype = BUS_HOST;
@@ -161,7 +160,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	if (rc < 0)
 		goto err_gpio_direction_input;
 
-	rc = rc_register_device(rcdev);
+	rc = rc_register_ir_raw_device(rcdev);
 	if (rc < 0) {
 		dev_err(&pdev->dev, "failed to register rc device\n");
 		goto err_register_rc_device;
@@ -179,7 +178,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	return 0;
 
 err_request_irq:
-	rc_unregister_device(rcdev);
+	rc_unregister_ir_raw_device(rcdev);
 	rcdev = NULL;
 err_register_rc_device:
 err_gpio_direction_input:
@@ -196,7 +195,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
 	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 
 	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
-	rc_unregister_device(gpio_dev->rcdev);
+	rc_unregister_ir_raw_device(gpio_dev->rcdev);
 	gpio_free(gpio_dev->gpio_nr);
 	kfree(gpio_dev);
 	return 0;
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 8a4baf5..3b7327a 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -25,7 +25,7 @@
 #include <linux/usb/input.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRIVER_NAME "iguanair"
 #define BUF_SIZE 152
@@ -513,7 +513,6 @@ static int iguanair_probe(struct usb_interface *intf,
 	rc->input_phys = ir->phys;
 	usb_to_input_id(ir->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
-	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->allowed_protocols = RC_BIT_ALL;
 	rc->priv = ir;
 	rc->open = iguanair_open;
@@ -529,7 +528,7 @@ static int iguanair_probe(struct usb_interface *intf,
 	iguanair_set_tx_carrier(rc, 38000);
 	iguanair_set_tx_mask(rc, 0);
 
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret < 0) {
 		dev_err(&intf->dev, "failed to register rc device %d", ret);
 		goto out2;
@@ -558,7 +557,7 @@ static void iguanair_disconnect(struct usb_interface *intf)
 {
 	struct iguanair *ir = usb_get_intfdata(intf);
 
-	rc_unregister_device(ir->rc);
+	rc_unregister_ir_raw_device(ir->rc);
 	usb_set_intfdata(intf, NULL);
 	usb_kill_urb(ir->urb_in);
 	usb_kill_urb(ir->urb_out);
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
index 5b6d8e9..95a4da1 100644
--- a/drivers/media/rc/img-ir/img-ir-raw.c
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -8,7 +8,7 @@
  */
 
 #include <linux/spinlock.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include "img-ir.h"
 
 #define ECHO_TIMEOUT_MS 150	/* ms between echos */
@@ -112,10 +112,9 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
 	}
 	rdev->priv = priv;
 	rdev->input_name = "IMG Infrared Decoder Raw";
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 
 	/* Register raw decoder */
-	error = rc_register_device(rdev);
+	error = rc_register_ir_raw_device(rdev);
 	if (error) {
 		dev_err(priv->dev, "failed to register raw IR input device\n");
 		rc_free_device(rdev);
@@ -144,7 +143,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv)
 	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
 	spin_unlock_irq(&priv->lock);
 
-	rc_unregister_device(rdev);
+	rc_unregister_ir_raw_device(rdev);
 
 	del_timer_sync(&raw->timer);
 }
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 2461933..1aa2ac0 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1875,7 +1875,6 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
 	rdev->dev.parent = ictx->dev;
 
 	rdev->priv = ictx;
-	rdev->driver_type = RC_DRIVER_SCANCODE;
 	rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
 	rdev->change_protocol = imon_ir_change_protocol;
 	rdev->driver_name = MOD_NAME;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 0d404a2..795fbc6 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -40,7 +40,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/bitops.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <linux/pci_ids.h>
 
 #include "ite-cir.h"
@@ -1557,7 +1557,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 
 	/* set up ir-core props */
 	rdev->priv = itdev;
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = ite_open;
 	rdev->close = ite_close;
@@ -1586,7 +1585,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 	rdev->driver_name = ITE_DRIVER_NAME;
 	rdev->map_name = RC_MAP_RC6_MCE;
 
-	ret = rc_register_device(rdev);
+	ret = rc_register_ir_raw_device(rdev);
 	if (ret)
 		goto exit_free_dev_rdev;
 
@@ -1607,7 +1606,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 exit_release_cir_addr:
 	release_region(itdev->cir_addr, itdev->params.io_region_size);
 exit_unregister_device:
-	rc_unregister_device(rdev);
+	rc_unregister_ir_raw_device(rdev);
 	rdev = NULL;
 exit_free_dev_rdev:
 	rc_free_device(rdev);
@@ -1634,7 +1633,7 @@ static void ite_remove(struct pnp_dev *pdev)
 	free_irq(dev->cir_irq, dev);
 	release_region(dev->cir_addr, dev->params.io_region_size);
 
-	rc_unregister_device(dev->rdev);
+	rc_unregister_ir_raw_device(dev->rdev);
 
 	kfree(dev);
 }
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index e0c8552..eac87ec 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -43,7 +43,7 @@
 #include <linux/usb.h>
 #include <linux/usb/input.h>
 #include <linux/pm_wakeup.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRIVER_VERSION	"1.92"
 #define DRIVER_AUTHOR	"Jarod Wilson <jarod@redhat.com>"
@@ -1217,7 +1217,6 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 	usb_to_input_id(ir->usbdev, &rc->input_id);
 	rc->dev.parent = dev;
 	rc->priv = ir;
-	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->allowed_protocols = RC_BIT_ALL;
 	rc->timeout = MS_TO_NS(100);
 	if (!ir->flags.no_tx) {
@@ -1229,7 +1228,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 	rc->map_name = mceusb_model[ir->model].rc_map ?
 			mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
 
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret < 0) {
 		dev_err(dev, "remote dev registration failed");
 		goto out;
@@ -1414,7 +1413,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
 		return;
 
 	ir->usbdev = NULL;
-	rc_unregister_device(ir->rc);
+	rc_unregister_ir_raw_device(ir->rc);
 	usb_kill_urb(ir->urb_in);
 	usb_free_urb(ir->urb_in);
 	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 160d685..a8c9b5f 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -34,7 +34,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 #include <linux/pci_ids.h>
 
 #include "nuvoton-cir.h"
@@ -1054,7 +1054,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
 	/* Set up the rc device */
 	rdev->priv = nvt;
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open = nvt_open;
 	rdev->close = nvt_close;
@@ -1119,7 +1118,7 @@ exit_free_irq:
 exit_release_cir_addr:
 	release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
 exit_unregister_device:
-	rc_unregister_device(rdev);
+	rc_unregister_ir_raw_device(rdev);
 	rdev = NULL;
 exit_free_dev_rdev:
 	rc_free_device(rdev);
@@ -1147,7 +1146,7 @@ static void nvt_remove(struct pnp_dev *pdev)
 	release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
 	release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
 
-	rc_unregister_device(nvt->rdev);
+	rc_unregister_ir_raw_device(nvt->rdev);
 
 	kfree(nvt);
 }
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 0159836..0b32ef8 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -19,6 +19,12 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
+
+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 */
+};
 
 struct ir_raw_handler {
 	struct list_head list;
@@ -148,12 +154,8 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
-u64 ir_raw_get_allowed_protocols(void);
-int ir_raw_event_register(struct rc_dev *dev);
-void ir_raw_event_unregister(struct rc_dev *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);
 
 /*
  * Methods from rc-keytable.c to be used internally
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 5ed8007..86f5aa7 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -16,6 +16,7 @@
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/kmod.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/freezer.h>
 #include "rc-core-priv.h"
@@ -269,8 +270,7 @@ void ir_raw_event_handle(struct rc_dev *dev)
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
 /* used internally by the sysfs interface */
-u64
-ir_raw_get_allowed_protocols(void)
+static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
 {
 	u64 protocols;
 	mutex_lock(&ir_raw_handler_lock);
@@ -287,7 +287,7 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
 /*
  * Used to (un)register raw event clients
  */
-int ir_raw_event_register(struct rc_dev *dev)
+int rc_register_ir_raw_device(struct rc_dev *dev)
 {
 	int rc;
 	struct ir_raw_handler *handler;
@@ -301,14 +301,16 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 	dev->raw->dev = dev;
 	dev->enabled_protocols = ~0;
+	dev->get_protocols = ir_raw_get_allowed_protocols;
+	dev->driver_type = RC_DRIVER_IR_RAW;
 	dev->change_protocol = change_protocol;
+	spin_lock_init(&dev->raw->lock);
 	rc = kfifo_alloc(&dev->raw->kfifo,
 			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
 			 GFP_KERNEL);
 	if (rc < 0)
 		goto out;
 
-	spin_lock_init(&dev->raw->lock);
 	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
 				       dev_name(&dev->dev));
 
@@ -317,6 +319,10 @@ int ir_raw_event_register(struct rc_dev *dev)
 		goto out;
 	}
 
+	rc = rc_register_device(dev);
+	if (rc < 0)
+		goto out_thread;
+
 	mutex_lock(&ir_raw_handler_lock);
 	list_add_tail(&dev->raw->list, &ir_raw_client_list);
 	list_for_each_entry(handler, &ir_raw_handler_list, list)
@@ -326,13 +332,16 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 	return 0;
 
+out_thread:
+	kthread_stop(dev->raw->thread);
 out:
 	kfree(dev->raw);
 	dev->raw = NULL;
 	return rc;
 }
+EXPORT_SYMBOL_GPL(rc_register_ir_raw_device);
 
-void ir_raw_event_unregister(struct rc_dev *dev)
+void rc_unregister_ir_raw_device(struct rc_dev *dev)
 {
 	struct ir_raw_handler *handler;
 
@@ -351,7 +360,9 @@ void ir_raw_event_unregister(struct rc_dev *dev)
 	kfifo_free(&dev->raw->kfifo);
 	kfree(dev->raw);
 	dev->raw = NULL;
+	rc_unregister_device(dev);
 }
+EXPORT_SYMBOL_GPL(rc_unregister_ir_raw_device);
 
 /*
  * Extension interface - used to register the IR decoders
@@ -387,10 +398,11 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
 
-void ir_raw_init(void)
+static struct work_struct wq_load;
+
+static void rc_ir_raw_init_decoders(struct work_struct *work)
 {
 	/* Load the decoder modules */
-
 	load_nec_decode();
 	load_rc5_decode();
 	load_rc6_decode();
@@ -400,8 +412,15 @@ void ir_raw_init(void)
 	load_sharp_decode();
 	load_mce_kbd_decode();
 	load_lirc_codec();
+}
 
-	/* If needed, we may later add some init code. In this case,
-	   it is needed to change the CONFIG_MODULE test at rc-core.h
-	 */
+static int __init rc_ir_raw_init(void)
+{
+	INIT_WORK(&wq_load, rc_ir_raw_init_decoders);
+	schedule_work(&wq_load);
+	return 0;
 }
+subsys_initcall(rc_ir_raw_init);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index f201395..343c8d0 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -26,7 +26,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRIVER_NAME	"rc-loopback"
 #define dprintk(x...)	if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
@@ -227,7 +227,6 @@ static int __init loop_init(void)
 	rc->input_id.version	= 1;
 	rc->driver_name		= DRIVER_NAME;
 	rc->priv		= &loopdev;
-	rc->driver_type		= RC_DRIVER_IR_RAW;
 	rc->allowed_protocols	= RC_BIT_ALL;
 	rc->timeout		= 100 * 1000 * 1000; /* 100 ms */
 	rc->min_timeout		= 1;
@@ -250,7 +249,7 @@ static int __init loop_init(void)
 	loopdev.learning	= false;
 	loopdev.carrierreport	= false;
 
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret < 0) {
 		printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
 		rc_free_device(rc);
@@ -263,7 +262,7 @@ static int __init loop_init(void)
 
 static void __exit loop_exit(void)
 {
-	rc_unregister_device(loopdev.dev);
+	rc_unregister_ir_raw_device(loopdev.dev);
 }
 
 module_init(loop_init);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 8729d0a..7caca4f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -343,10 +343,7 @@ static ssize_t show_protocols(struct device *device,
 
 	if (fattr->type == RC_FILTER_NORMAL) {
 		enabled = dev->enabled_protocols;
-		if (dev->raw)
-			allowed = ir_raw_get_allowed_protocols();
-		else
-			allowed = dev->allowed_protocols;
+		allowed = dev->allowed_protocols;
 	} else {
 		enabled = dev->enabled_wakeup_protocols;
 		allowed = dev->allowed_wakeup_protocols;
@@ -919,10 +916,7 @@ void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
 	rx->rx_enabled = 0x1;
 	rx->rx_connected = 0x1;
 	rx->protocols_enabled[0] = dev->enabled_protocols;
-	if (dev->driver_type == RC_DRIVER_SCANCODE)
-		rx->protocols_supported[0] = dev->allowed_protocols;
-	else
-		rx->protocols_supported[0] = ir_raw_get_allowed_protocols();
+	rx->protocols_supported[0] = dev->allowed_protocols;
 	rx->timeout = dev->timeout;
 	rx->timeout_min = dev->min_timeout;
 	rx->timeout_max = dev->max_timeout;
@@ -1135,9 +1129,6 @@ static void rc_dev_release(struct device *device)
 {
 	struct rc_dev *dev = to_rc_dev(device);
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW)
-		ir_raw_event_unregister(dev);
-
 	kfifo_free(&dev->txfifo);
 	kfree(dev);
 	module_put(THIS_MODULE);
@@ -1267,7 +1258,6 @@ EXPORT_SYMBOL_GPL(rc_free_device);
 
 int rc_register_device(struct rc_dev *dev)
 {
-	static bool raw_init = false; /* raw decoders loaded? */
 	struct rc_map *rc_map = NULL;
 	int attr = 0;
 	int minor;
@@ -1290,18 +1280,6 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_minor;
 	}
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW) {
-		/* Load raw decoders, if they aren't already */
-		if (!raw_init) {
-			IR_dprintk(1, "Loading raw decoders\n");
-			ir_raw_init();
-			raw_init = true;
-		}
-		rc = ir_raw_event_register(dev);
-		if (rc < 0)
-			goto out_minor;
-	}
-
 	dev->dev.groups = dev->sysfs_groups;
 	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
 	if (dev->s_filter)
@@ -1319,13 +1297,13 @@ int rc_register_device(struct rc_dev *dev)
 		u64 rc_type = (1 << rc_map->scan[0].protocol);
 		rc = dev->change_protocol(dev, &rc_type);
 		if (rc < 0)
-			goto out_raw;
+			goto out_minor;
 		dev->enabled_protocols = rc_type;
 	}
 
 	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
 	if (rc)
-		goto out_raw;
+		goto out_minor;
 
 	rc = device_add(&dev->dev);
 	if (rc)
@@ -1347,9 +1325,6 @@ out_dev:
 	device_del(&dev->dev);
 out_cdev:
 	cdev_del(&dev->cdev);
-out_raw:
-	if (dev->driver_type == RC_DRIVER_IR_RAW)
-		ir_raw_event_unregister(dev);
 out_minor:
 	ida_simple_remove(&rc_ida, minor);
 	return rc;
@@ -1377,9 +1352,6 @@ void rc_unregister_device(struct rc_dev *dev)
 
 	cdev_del(&dev->cdev);
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW)
-		ir_raw_event_unregister(dev);
-
 	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
 		rc_remove_keytable(dev, i);
 
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 3a931a5..17974bf 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -52,7 +52,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 /* Driver Information */
 #define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
@@ -936,7 +936,6 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	usb_to_input_id(rr3->udev, &rc->input_id);
 	rc->dev.parent = dev;
 	rc->priv = rr3;
-	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->allowed_protocols = RC_BIT_ALL;
 	rc->timeout = US_TO_NS(2750);
 	rc->tx_ir = redrat3_transmit_ir;
@@ -945,7 +944,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	rc->rx_resolution = US_TO_NS(2);
 	rc->map_name = RC_MAP_HAUPPAUGE;
 
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret < 0) {
 		dev_err(dev, "remote dev registration failed\n");
 		goto out;
@@ -1114,7 +1113,7 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
 		return;
 
 	usb_set_intfdata(intf, NULL);
-	rc_unregister_device(rr3->rc);
+	rc_unregister_ir_raw_device(rr3->rc);
 	led_classdev_unregister(&rr3->led);
 	del_timer_sync(&rr3->rx_timeout);
 	redrat3_delete(rr3, udev);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 2659f66..149e824 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -36,7 +36,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRIVER_VERSION	"1.61"
 #define DRIVER_NAME	"streamzap"
@@ -314,12 +314,11 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
 	usb_to_input_id(sz->usbdev, &rdev->input_id);
 	rdev->dev.parent = dev;
 	rdev->priv = sz;
-	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->driver_name = DRIVER_NAME;
 	rdev->map_name = RC_MAP_STREAMZAP;
 
-	ret = rc_register_device(rdev);
+	ret = rc_register_ir_raw_device(rdev);
 	if (ret < 0) {
 		dev_err(dev, "remote input device register failed\n");
 		goto out;
@@ -484,7 +483,7 @@ static void streamzap_disconnect(struct usb_interface *interface)
 		return;
 
 	sz->usbdev = NULL;
-	rc_unregister_device(sz->rdev);
+	rc_unregister_ir_raw_device(sz->rdev);
 	usb_kill_urb(sz->urb_in);
 	usb_free_urb(sz->urb_in);
 	usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index bc214e2..19317e2 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -23,7 +23,7 @@
 #include <linux/usb/input.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRIVER_NAME	"ttusbir"
 #define DRIVER_DESC	"TechnoTrend USB IR Receiver"
@@ -317,7 +317,6 @@ static int ttusbir_probe(struct usb_interface *intf,
 	rc->input_phys = tt->phys;
 	usb_to_input_id(tt->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
-	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->allowed_protocols = RC_BIT_ALL;
 	rc->priv = tt;
 	rc->driver_name = DRIVER_NAME;
@@ -329,7 +328,7 @@ static int ttusbir_probe(struct usb_interface *intf,
 	 */
 	rc->rx_resolution = NS_PER_BIT;
 
-	ret = rc_register_device(rc);
+	ret = rc_register_ir_raw_device(rc);
 	if (ret) {
 		dev_err(&intf->dev, "failed to register rc device %d\n", ret);
 		goto out2;
@@ -347,7 +346,7 @@ static int ttusbir_probe(struct usb_interface *intf,
 
 	return 0;
 out3:
-	rc_unregister_device(rc);
+	rc_unregister_ir_raw_device(rc);
 	rc = NULL;
 out2:
 	led_classdev_unregister(&tt->led);
@@ -378,7 +377,7 @@ static void ttusbir_disconnect(struct usb_interface *intf)
 
 	tt->udev = NULL;
 
-	rc_unregister_device(tt->rc);
+	rc_unregister_ir_raw_device(tt->rc);
 	led_classdev_unregister(&tt->led);
 	for (i = 0; i < NUM_URBS; i++) {
 		usb_kill_urb(tt->urb[i]);
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 8871109..07da3e0 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -54,7 +54,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #define DRVNAME "winbond-cir"
 
@@ -1051,7 +1051,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 		goto exit_unregister_led;
 	}
 
-	data->dev->driver_type = RC_DRIVER_IR_RAW;
 	data->dev->driver_name = DRVNAME;
 	data->dev->input_name = WBCIR_NAME;
 	data->dev->input_phys = "wbcir/cir0";
@@ -1071,7 +1070,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	data->dev->rx_resolution = US_TO_NS(2);
 	data->dev->allowed_protocols = RC_BIT_ALL;
 
-	err = rc_register_device(data->dev);
+	err = rc_register_ir_raw_device(data->dev);
 	if (err)
 		goto exit_free_rc;
 
@@ -1117,7 +1116,7 @@ exit_release_ebase:
 exit_release_wbase:
 	release_region(data->wbase, WAKEUP_IOMEM_LEN);
 exit_unregister_device:
-	rc_unregister_device(data->dev);
+	rc_unregister_ir_raw_device(data->dev);
 	data->dev = NULL;
 exit_free_rc:
 	rc_free_device(data->dev);
@@ -1148,7 +1147,7 @@ wbcir_remove(struct pnp_dev *device)
 	/* Clear BUFF_EN, END_EN, MATCH_EN */
 	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
 
-	rc_unregister_device(data->dev);
+	rc_unregister_ir_raw_device(data->dev);
 
 	led_classdev_unregister(&data->led);
 
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 124b4ba..ccdf0c6 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -25,6 +25,7 @@
 #include <linux/usb/input.h>
 #include <linux/firmware.h>
 #include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -131,7 +132,7 @@ struct dvb_usb_driver_info {
  * @change_protocol: callback to change protocol
  * @query: called to query an event from the device
  * @interval: time in ms between two queries
- * @driver_type: used to point if a device supports raw mode
+ * @rc_raw: used to point if a device supports raw mode
  * @bulk_mode: device supports bulk mode for rc (disable polling mode)
  */
 struct dvb_usb_rc {
@@ -140,7 +141,7 @@ struct dvb_usb_rc {
 	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int (*query) (struct dvb_usb_device *d);
 	unsigned int interval;
-	enum rc_driver_type driver_type;
+	bool rc_raw;
 	bool bulk_mode;
 };
 
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index eaa76ef..ea84894b 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -163,12 +163,15 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
 	/* TODO: likely RC-core should took const char * */
 	dev->driver_name = (char *) d->props->driver_name;
 	dev->map_name = d->rc.map_name;
-	dev->driver_type = d->rc.driver_type;
 	dev->allowed_protocols = d->rc.allowed_protos;
 	dev->change_protocol = d->rc.change_protocol;
 	dev->priv = d;
 
-	ret = rc_register_device(dev);
+	if (d->rc.rc_raw)
+		ret = rc_register_ir_raw_device(dev);
+	else
+		ret = rc_register_device(dev);
+
 	if (ret < 0) {
 		rc_free_device(dev);
 		goto err;
@@ -201,7 +204,10 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
 
 	if (d->rc_dev) {
 		cancel_delayed_work_sync(&d->rc_query_work);
-		rc_unregister_device(d->rc_dev);
+		if (d->rc.rc_raw)
+			rc_unregister_ir_raw_device(d->rc_dev);
+		else
+			rc_unregister_device(d->rc_dev);
 		d->rc_dev = NULL;
 	}
 
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 15f1e70..0412862 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1373,7 +1373,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
 		return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
 
 	rc->allowed_protos = RC_BIT_ALL;
-	rc->driver_type = RC_DRIVER_IR_RAW;
+	rc->rc_raw = true;
 	rc->query = rtl2832u_rc_query;
 	rc->interval = 400;
 
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 5986626..88574d0 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -273,14 +273,17 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
 	dev->map_name = d->props.rc.core.rc_codes;
 	dev->change_protocol = d->props.rc.core.change_protocol;
 	dev->allowed_protocols = d->props.rc.core.allowed_protos;
-	dev->driver_type = d->props.rc.core.driver_type;
 	usb_to_input_id(d->udev, &dev->input_id);
 	dev->input_name = "IR-receiver inside an USB DVB receiver";
 	dev->input_phys = d->rc_phys;
 	dev->dev.parent = &d->udev->dev;
 	dev->priv = d;
 
-	err = rc_register_device(dev);
+	if (d->props.rc.core.rc_raw)
+		err = rc_register_ir_raw_device(dev);
+	else
+		err = rc_register_device(dev);
+
 	if (err < 0) {
 		rc_free_device(dev);
 		return err;
@@ -341,6 +344,8 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
 		cancel_delayed_work_sync(&d->rc_query_work);
 		if (d->props.rc.mode == DVB_RC_LEGACY)
 			input_unregister_device(d->input_dev);
+		else if (d->props.rc.core.rc_raw)
+			rc_unregister_ir_raw_device(d->rc_dev);
 		else
 			rc_unregister_device(d->rc_dev);
 	}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
index ce4c4e3..8e4b31e 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -15,6 +15,7 @@
 #include <linux/firmware.h>
 #include <linux/mutex.h>
 #include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -191,7 +192,7 @@ struct dvb_rc_legacy {
  * @rc_codes: name of rc codes table
  * @protocol: type of protocol(s) currently used by the driver
  * @allowed_protos: protocol(s) supported by the driver
- * @driver_type: Used to point if a device supports raw mode
+ * @rc_raw: Used to point if a device supports raw mode
  * @change_protocol: callback to change protocol
  * @rc_query: called to query an event event.
  * @rc_interval: time in ms between two queries.
@@ -201,7 +202,7 @@ struct dvb_rc {
 	char *rc_codes;
 	u64 protocol;
 	u64 allowed_protos;
-	enum rc_driver_type driver_type;
+	bool rc_raw;
 	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
 	char *module_name;
 	int (*rc_query) (struct dvb_usb_device *d);
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 98d24ae..288f24c 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -733,7 +733,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
 		.module_name = "technisat-usb2",
 		.rc_query    = technisat_usb2_rc_query,
 		.allowed_protos = RC_BIT_ALL,
-		.driver_type    = RC_DRIVER_IR_RAW,
+		.rc_raw      = true,
 	}
 };
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 1232e32..8fdb515 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -856,9 +856,6 @@ static int em28xx_ir_suspend(struct em28xx *dev)
 	if (ir)
 		cancel_delayed_work_sync(&ir->work);
 	cancel_delayed_work_sync(&dev->buttons_query_work);
-	/* is canceling delayed work sufficient or does the rc event
-	   kthread needs stopping? kthread is stopped in
-	   ir_raw_event_unregister() */
 	return 0;
 }
 
@@ -870,8 +867,6 @@ static int em28xx_ir_resume(struct em28xx *dev)
 		return 0;
 
 	em28xx_info("Resuming input extension");
-	/* if suspend calls ir_raw_event_unregister(), the should call
-	   ir_raw_event_register() */
 	if (ir)
 		schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 	if (dev->num_button_polling_addresses)
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 7c9b58d..1d4b191 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -452,7 +452,6 @@ int tm6000_ir_init(struct tm6000_core *dev)
 		ir->polling = 50;
 		INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
 	}
-	rc->driver_type = RC_DRIVER_SCANCODE;
 
 	snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
 						dev->name);
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 228510e..25c1d38 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -177,11 +177,6 @@ struct rc_keytable_ioctl {
 	char name[RC_KEYTABLE_NAME_SIZE];
 } __packed;
 
-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 */
-};
-
 /* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
 struct rc_scancode {
 	__u16 protocol;
@@ -304,6 +299,7 @@ enum rc_filter_type {
  * @rx_resolution : resolution (in ns) of input sampler
  * @tx_resolution: resolution (in ns) of output sampler
  * @change_protocol: allow changing the protocol used on hardware decoders
+ * @get_protocols: returns a bitmask of allowed protocols
  * @change_wakeup_protocol: allow changing the protocol used for wakeup
  *	filtering
  * @open: callback to allow drivers to enable polling/irq when IR input device
@@ -347,7 +343,7 @@ struct rc_dev {
 	wait_queue_head_t		txwait;
 	wait_queue_head_t		rxwait;
 	struct ir_raw_event_ctrl	*raw;
-	enum rc_driver_type		driver_type;
+	unsigned			driver_type;
 	bool				idle;
 	u64				allowed_protocols;
 	u64				enabled_protocols;
@@ -363,6 +359,7 @@ struct rc_dev {
 	u32				max_timeout;
 	u32				rx_resolution;
 	u32				tx_resolution;
+	u64				(*get_protocols)(struct rc_dev *dev);
 	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*open)(struct rc_dev *dev);
@@ -461,70 +458,6 @@ static inline void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protoco
 	rc_do_keydown(dev, protocol, scancode, toggle, false);
 }
 
-/*
- * From rc-raw.c
- * The Raw interface is specific to InfraRed. It may be a good idea to
- * split it later into a separate header.
- */
-
-enum raw_event_type {
-	IR_SPACE        = (1 << 0),
-	IR_PULSE        = (1 << 1),
-	IR_START_EVENT  = (1 << 2),
-	IR_STOP_EVENT   = (1 << 3),
-};
-
-struct ir_raw_event {
-	union {
-		u32             duration;
-
-		struct {
-			u32     carrier;
-			u8      duty_cycle;
-		};
-	};
-
-	unsigned                pulse:1;
-	unsigned                reset:1;
-	unsigned                timeout:1;
-	unsigned                carrier_report:1;
-};
-
-#define DEFINE_IR_RAW_EVENT(event) \
-	struct ir_raw_event event = { \
-		{ .duration = 0 } , \
-		.pulse = 0, \
-		.reset = 0, \
-		.timeout = 0, \
-		.carrier_report = 0 }
-
-static inline void init_ir_raw_event(struct ir_raw_event *ev)
-{
-	memset(ev, 0, sizeof(*ev));
-}
-
-#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
-#define US_TO_NS(usec)		((usec) * 1000)
-#define MS_TO_US(msec)		((msec) * 1000)
-#define MS_TO_NS(msec)		((msec) * 1000 * 1000)
-
-void ir_raw_event_handle(struct rc_dev *dev);
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
-int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
-int ir_raw_event_store_with_filter(struct rc_dev *dev,
-				struct ir_raw_event *ev);
-void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
-int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
-
-static inline void ir_raw_event_reset(struct rc_dev *dev)
-{
-	DEFINE_IR_RAW_EVENT(ev);
-	ev.reset = true;
-
-	ir_raw_event_store(dev, &ev);
-	ir_raw_event_handle(dev);
-}
-
 /* extract mask bits out of data and pack them into the result */
 static inline u32 ir_extract_bits(u32 data, u32 mask)
 {
diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
new file mode 100644
index 0000000..dad3eb2
--- /dev/null
+++ b/include/media/rc-ir-raw.h
@@ -0,0 +1,83 @@
+/*
+ * Remote Controller core header
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab
+ *
+ * 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 _RC_IR_RAW
+#define _RC_IR_RAW
+
+#include <linux/spinlock.h>
+#include <linux/kfifo.h>
+#include <media/rc-core.h>
+
+enum raw_event_type {
+	IR_SPACE        = (1 << 0),
+	IR_PULSE        = (1 << 1),
+	IR_START_EVENT  = (1 << 2),
+	IR_STOP_EVENT   = (1 << 3),
+};
+
+struct ir_raw_event {
+	union {
+		u32             duration;
+
+		struct {
+			u32     carrier;
+			u8      duty_cycle;
+		};
+	};
+
+	unsigned                pulse:1;
+	unsigned                reset:1;
+	unsigned                timeout:1;
+	unsigned                carrier_report:1;
+};
+
+#define DEFINE_IR_RAW_EVENT(event) \
+	struct ir_raw_event event = { \
+		{ .duration = 0 } , \
+		.pulse = 0, \
+		.reset = 0, \
+		.timeout = 0, \
+		.carrier_report = 0 }
+
+static inline void init_ir_raw_event(struct ir_raw_event *ev)
+{
+	memset(ev, 0, sizeof(*ev));
+}
+
+#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
+#define US_TO_NS(usec)		((usec) * 1000)
+#define MS_TO_US(msec)		((msec) * 1000)
+#define MS_TO_NS(msec)		((msec) * 1000 * 1000)
+
+void ir_raw_event_handle(struct rc_dev *dev);
+int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
+int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
+int ir_raw_event_store_with_filter(struct rc_dev *dev,
+				struct ir_raw_event *ev);
+void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
+int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
+int rc_register_ir_raw_device(struct rc_dev *dev);
+void rc_unregister_ir_raw_device(struct rc_dev *dev);
+
+static inline void ir_raw_event_reset(struct rc_dev *dev)
+{
+	DEFINE_IR_RAW_EVENT(ev);
+	ev.reset = true;
+
+	ir_raw_event_store(dev, &ev);
+	ir_raw_event_handle(dev);
+}
+
+#endif /* _RC_IR_RAW */


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

* [PATCH 40/49] rc-ir-raw: simplify locking
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (38 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 39/49] rc-core: make IR raw handling a separate module David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-07-25 23:08   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 41/49] rc-core: rename mutex David Härdeman
                   ` (10 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Simplify and improve the locking in rc-ir-raw by making better use of
the existing kfifo functionality and by using RCU where possible.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |    6 +-
 drivers/media/rc/rc-ir-raw.c    |  124 ++++++++++++++++-----------------------
 2 files changed, 55 insertions(+), 75 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 0b32ef8..c3de26b 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -37,11 +37,13 @@ struct ir_raw_handler {
 	int (*raw_unregister)(struct rc_dev *dev);
 };
 
+/* max number of pulse/space transitions to buffer */
+#define RC_MAX_IR_EVENTS	512
+
 struct ir_raw_event_ctrl {
 	struct list_head		list;		/* to keep track of raw clients */
 	struct task_struct		*thread;
-	spinlock_t			lock;
-	struct kfifo_rec_ptr_1		kfifo;		/* fifo for the pulse/space durations */
+	DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
 	ktime_t				last_event;	/* when last event occurred */
 	enum raw_event_type		last_type;	/* last event type */
 	struct rc_dev			*dev;		/* pointer to the parent rc_dev */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 86f5aa7..9631825 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -21,15 +21,12 @@
 #include <linux/freezer.h>
 #include "rc-core-priv.h"
 
-/* Define the max number of pulse/space transitions to buffer */
-#define MAX_IR_EVENT_SIZE      512
-
-/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+/* IR raw clients/handlers, writers synchronize with ir_raw_mutex */
+static DEFINE_MUTEX(ir_raw_mutex);
 static LIST_HEAD(ir_raw_client_list);
-
-/* Used to handle IR raw handler extensions */
-static DEFINE_MUTEX(ir_raw_handler_lock);
 static LIST_HEAD(ir_raw_handler_list);
+
+/* protocols supported by the currently loaded decoders */
 static u64 available_protocols;
 
 static int ir_raw_event_thread(void *data)
@@ -37,32 +34,19 @@ static int ir_raw_event_thread(void *data)
 	struct ir_raw_event ev;
 	struct ir_raw_handler *handler;
 	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
-	int retval;
 
 	while (!kthread_should_stop()) {
-
-		spin_lock_irq(&raw->lock);
-		retval = kfifo_len(&raw->kfifo);
-
-		if (retval < sizeof(ev)) {
+		if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
 			set_current_state(TASK_INTERRUPTIBLE);
-
-			if (kthread_should_stop())
-				set_current_state(TASK_RUNNING);
-
-			spin_unlock_irq(&raw->lock);
 			schedule();
 			continue;
 		}
 
-		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
-		spin_unlock_irq(&raw->lock);
-
-		mutex_lock(&ir_raw_handler_lock);
-		list_for_each_entry(handler, &ir_raw_handler_list, list)
+		rcu_read_lock();
+		list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
 			handler->decode(raw->dev, ev);
+		rcu_read_unlock();
 		raw->prev_ev = ev;
-		mutex_unlock(&ir_raw_handler_lock);
 	}
 
 	return 0;
@@ -76,7 +60,8 @@ static int ir_raw_event_thread(void *data)
  * 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.
+ * will reset the decoding state machines. Drivers are responsible for
+ * synchronizing calls to this function.
  */
 int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
 {
@@ -86,7 +71,7 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
 	IR_dprintk(2, "sample: (%05dus %s)\n",
 		   TO_US(ev->duration), TO_STR(ev->pulse));
 
-	if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
 		return -ENOMEM;
 
 	return 0;
@@ -258,14 +243,8 @@ EXPORT_SYMBOL_GPL(ir_raw_get_tx_event);
  */
 void ir_raw_event_handle(struct rc_dev *dev)
 {
-	unsigned long flags;
-
-	if (!dev->raw)
-		return;
-
-	spin_lock_irqsave(&dev->raw->lock, flags);
-	wake_up_process(dev->raw->thread);
-	spin_unlock_irqrestore(&dev->raw->lock, flags);
+	if (dev->raw)
+		wake_up_process(dev->raw->thread);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -273,9 +252,9 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
 {
 	u64 protocols;
-	mutex_lock(&ir_raw_handler_lock);
+	mutex_lock(&ir_raw_mutex);
 	protocols = available_protocols;
-	mutex_unlock(&ir_raw_handler_lock);
+	mutex_unlock(&ir_raw_mutex);
 	return protocols;
 }
 
@@ -290,52 +269,49 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
 int rc_register_ir_raw_device(struct rc_dev *dev)
 {
 	int rc;
+	struct ir_raw_event_ctrl *raw;
 	struct ir_raw_handler *handler;
 
 	if (!dev)
 		return -EINVAL;
 
-	dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
-	if (!dev->raw)
+	raw = kzalloc(sizeof(*raw), GFP_KERNEL);
+	if (!raw)
 		return -ENOMEM;
 
-	dev->raw->dev = dev;
-	dev->enabled_protocols = ~0;
-	dev->get_protocols = ir_raw_get_allowed_protocols;
-	dev->driver_type = RC_DRIVER_IR_RAW;
-	dev->change_protocol = change_protocol;
-	spin_lock_init(&dev->raw->lock);
-	rc = kfifo_alloc(&dev->raw->kfifo,
-			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
-			 GFP_KERNEL);
-	if (rc < 0)
-		goto out;
-
-	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
-				       dev_name(&dev->dev));
+	raw->dev = dev;
+	INIT_KFIFO(raw->kfifo);
+	raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+				  dev_name(&dev->dev));
 
-	if (IS_ERR(dev->raw->thread)) {
-		rc = PTR_ERR(dev->raw->thread);
+	if (IS_ERR(raw->thread)) {
+		rc = PTR_ERR(raw->thread);
 		goto out;
 	}
 
+	dev->raw = raw;
+	dev->enabled_protocols = ~0;
+	dev->get_protocols = ir_raw_get_allowed_protocols;
+	dev->driver_type = RC_DRIVER_IR_RAW;
+	dev->change_protocol = change_protocol;
 	rc = rc_register_device(dev);
 	if (rc < 0)
 		goto out_thread;
 
-	mutex_lock(&ir_raw_handler_lock);
-	list_add_tail(&dev->raw->list, &ir_raw_client_list);
-	list_for_each_entry(handler, &ir_raw_handler_list, list)
+	mutex_lock(&ir_raw_mutex);
+	list_add_tail_rcu(&dev->raw->list, &ir_raw_client_list);
+	list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
 		if (handler->raw_register)
 			handler->raw_register(dev);
-	mutex_unlock(&ir_raw_handler_lock);
+	mutex_unlock(&ir_raw_mutex);
+	synchronize_rcu();
 
 	return 0;
 
 out_thread:
-	kthread_stop(dev->raw->thread);
+	kthread_stop(raw->thread);
 out:
-	kfree(dev->raw);
+	kfree(raw);
 	dev->raw = NULL;
 	return rc;
 }
@@ -350,14 +326,14 @@ void rc_unregister_ir_raw_device(struct rc_dev *dev)
 
 	kthread_stop(dev->raw->thread);
 
-	mutex_lock(&ir_raw_handler_lock);
-	list_del(&dev->raw->list);
-	list_for_each_entry(handler, &ir_raw_handler_list, list)
+	mutex_lock(&ir_raw_mutex);
+	list_del_rcu(&dev->raw->list);
+	list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
 		if (handler->raw_unregister)
 			handler->raw_unregister(dev);
-	mutex_unlock(&ir_raw_handler_lock);
+	mutex_unlock(&ir_raw_mutex);
+	synchronize_rcu();
 
-	kfifo_free(&dev->raw->kfifo);
 	kfree(dev->raw);
 	dev->raw = NULL;
 	rc_unregister_device(dev);
@@ -372,13 +348,14 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
 {
 	struct ir_raw_event_ctrl *raw;
 
-	mutex_lock(&ir_raw_handler_lock);
-	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+	mutex_lock(&ir_raw_mutex);
+	list_add_tail_rcu(&ir_raw_handler->list, &ir_raw_handler_list);
 	if (ir_raw_handler->raw_register)
-		list_for_each_entry(raw, &ir_raw_client_list, list)
+		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
 			ir_raw_handler->raw_register(raw->dev);
 	available_protocols |= ir_raw_handler->protocols;
-	mutex_unlock(&ir_raw_handler_lock);
+	mutex_unlock(&ir_raw_mutex);
+	synchronize_rcu();
 
 	return 0;
 }
@@ -388,13 +365,14 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 {
 	struct ir_raw_event_ctrl *raw;
 
-	mutex_lock(&ir_raw_handler_lock);
-	list_del(&ir_raw_handler->list);
+	mutex_lock(&ir_raw_mutex);
+	list_del_rcu(&ir_raw_handler->list);
 	if (ir_raw_handler->raw_unregister)
-		list_for_each_entry(raw, &ir_raw_client_list, list)
+		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
 			ir_raw_handler->raw_unregister(raw->dev);
 	available_protocols &= ~ir_raw_handler->protocols;
-	mutex_unlock(&ir_raw_handler_lock);
+	mutex_unlock(&ir_raw_mutex);
+	synchronize_rcu();
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
 


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

* [PATCH 41/49] rc-core: rename mutex
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (39 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 40/49] rc-ir-raw: simplify locking David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-10 21:28   ` James Hogan
  2014-07-25 23:12   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 42/49] rc-ir-raw: atomic reads of protocols David Härdeman
                   ` (9 subsequent siblings)
  50 siblings, 2 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Having a mutex named "lock" is a bit misleading.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/img-ir/img-ir-hw.c |    4 ++-
 drivers/media/rc/rc-main.c          |   42 ++++++++++++++++++-----------------
 include/media/rc-core.h             |    5 ++--
 3 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 5bc7903..a9abbb4 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -666,11 +666,11 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
 {
 	struct rc_dev *rdev = priv->hw.rdev;
 
-	mutex_lock(&rdev->lock);
+	mutex_lock(&rdev->mutex);
 	rdev->enabled_protocols = proto;
 	rdev->allowed_wakeup_protocols = proto;
 	rdev->enabled_wakeup_protocols = proto;
-	mutex_unlock(&rdev->lock);
+	mutex_unlock(&rdev->mutex);
 }
 
 /* Set up IR decoders */
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 7caca4f..bd4dfab 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -109,7 +109,7 @@ int rc_open(struct rc_dev *dev)
 {
 	int err = 0;
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 
 	if (dev->dead)
 		err = -ENODEV;
@@ -119,7 +119,7 @@ int rc_open(struct rc_dev *dev)
 			dev->users--;
 	}
 
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 
 	return err;
 }
@@ -127,12 +127,12 @@ EXPORT_SYMBOL_GPL(rc_open);
 
 void rc_close(struct rc_dev *dev)
 {
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 
 	if (!dev->dead && !--dev->users && dev->close)
 		dev->close(dev);
 
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 }
 EXPORT_SYMBOL_GPL(rc_close);
 
@@ -322,7 +322,7 @@ struct rc_filter_attribute {
  * It returns the protocol names of supported protocols.
  * Enabled protocols are printed in brackets.
  *
- * dev->lock is taken to guard against races between store_protocols and
+ * dev->mutex is taken to guard against races between store_protocols and
  * show_protocols.
  */
 static ssize_t show_protocols(struct device *device,
@@ -339,7 +339,7 @@ static ssize_t show_protocols(struct device *device,
 		return -EINVAL;
 
 	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 
 	if (fattr->type == RC_FILTER_NORMAL) {
 		enabled = dev->enabled_protocols;
@@ -349,7 +349,7 @@ static ssize_t show_protocols(struct device *device,
 		allowed = dev->allowed_wakeup_protocols;
 	}
 
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 
 	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
 		   __func__, (long long)allowed, (long long)enabled);
@@ -449,7 +449,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
  * See parse_protocol_change() for the valid commands.
  * Returns @len on success or a negative error code.
  *
- * dev->lock is taken to guard against races between store_protocols and
+ * dev->mutex is taken to guard against races between store_protocols and
  * show_protocols.
  */
 static ssize_t store_protocols(struct device *device,
@@ -488,7 +488,7 @@ static ssize_t store_protocols(struct device *device,
 		return -EINVAL;
 	}
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 
 	old_protocols = *current_protocols;
 	new_protocols = old_protocols;
@@ -532,7 +532,7 @@ static ssize_t store_protocols(struct device *device,
 	rc = len;
 
 out:
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 	return rc;
 }
 
@@ -550,7 +550,7 @@ out:
  * Bits of the filter value corresponding to set bits in the filter mask are
  * compared against input scancodes and non-matching scancodes are discarded.
  *
- * dev->lock is taken to guard against races between store_filter and
+ * dev->mutex is taken to guard against races between store_filter and
  * show_filter.
  */
 static ssize_t show_filter(struct device *device,
@@ -571,12 +571,12 @@ static ssize_t show_filter(struct device *device,
 	else
 		filter = &dev->scancode_wakeup_filter;
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 	if (fattr->mask)
 		val = filter->mask;
 	else
 		val = filter->data;
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 
 	return sprintf(buf, "%#x\n", val);
 }
@@ -597,7 +597,7 @@ static ssize_t show_filter(struct device *device,
  * Bits of the filter value corresponding to set bits in the filter mask are
  * compared against input scancodes and non-matching scancodes are discarded.
  *
- * dev->lock is taken to guard against races between store_filter and
+ * dev->mutex is taken to guard against races between store_filter and
  * show_filter.
  */
 static ssize_t store_filter(struct device *device,
@@ -633,7 +633,7 @@ static ssize_t store_filter(struct device *device,
 	if (!set_filter)
 		return -EINVAL;
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 
 	new_filter = *filter;
 	if (fattr->mask)
@@ -654,7 +654,7 @@ static ssize_t store_filter(struct device *device,
 	*filter = new_filter;
 
 unlock:
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 	return (ret < 0) ? ret : len;
 }
 
@@ -1087,7 +1087,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	struct rc_dev *dev = client->dev;
 	int ret;
 
-	ret = mutex_lock_interruptible(&dev->lock);
+	ret = mutex_lock_interruptible(&dev->mutex);
 	if (ret)
 		return ret;
 
@@ -1099,7 +1099,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	ret = rc_do_ioctl(dev, cmd, arg);
 
 out:
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 	return ret;
 }
 
@@ -1226,7 +1226,7 @@ struct rc_dev *rc_allocate_device(void)
 	mutex_init(&dev->txmutex);
 	init_waitqueue_head(&dev->txwait);
 	init_waitqueue_head(&dev->rxwait);
-	mutex_init(&dev->lock);
+	mutex_init(&dev->mutex);
 
 	dev->dev.type = &rc_dev_type;
 	dev->dev.class = &rc_class;
@@ -1339,9 +1339,9 @@ void rc_unregister_device(struct rc_dev *dev)
 	if (!dev)
 		return;
 
-	mutex_lock(&dev->lock);
+	mutex_lock(&dev->mutex);
 	dev->dead = true;
-	mutex_unlock(&dev->lock);
+	mutex_unlock(&dev->mutex);
 
 	spin_lock(&dev->client_lock);
 	list_for_each_entry(client, &dev->client_list, node)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 25c1d38..a310e5b 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -268,8 +268,7 @@ enum rc_filter_type {
  * @driver_name: name of the hardware driver which registered this device
  * @map_name: name of the default keymap
  * @rc_kt: current rc_keytable
- * @lock: used to ensure we've filled in all protocol details before
- *	anyone can call show_protocols or store_protocols
+ * @mutex: used where a more specific lock/mutex/etc is not available
  * @dead: used to determine if the device is still alive
  * @client_list: list of clients (processes which have opened the rc chardev)
  * @client_lock: protects client_list
@@ -334,7 +333,7 @@ struct rc_dev {
 	const char			*map_name;
 	struct rc_keytable		*keytables[RC_MAX_KEYTABLES];
 	struct list_head		keytable_list;
-	struct mutex			lock;
+	struct mutex			mutex;
 	bool				dead;
 	struct list_head		client_list;
 	spinlock_t			client_lock;


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

* [PATCH 42/49] rc-ir-raw: atomic reads of protocols
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (40 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 41/49] rc-core: rename mutex David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-07-25 23:13   ` Mauro Carvalho Chehab
  2014-04-03 23:34 ` [PATCH 43/49] rc-core: fix various sparse warnings David Härdeman
                   ` (8 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Use atomic reads to avoid having to take a mutex when getting
the bitmask of supported protocols.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |    2 +-
 drivers/media/rc/rc-ir-raw.c    |   12 ++++--------
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index c3de26b..04776e8 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -29,7 +29,7 @@ enum rc_driver_type {
 struct ir_raw_handler {
 	struct list_head list;
 
-	u64 protocols; /* which are handled by this handler */
+	unsigned protocols; /* which are handled by this handler */
 	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
 
 	/* These two should only be used by the lirc decoder */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 9631825..bf5215b 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -27,7 +27,7 @@ static LIST_HEAD(ir_raw_client_list);
 static LIST_HEAD(ir_raw_handler_list);
 
 /* protocols supported by the currently loaded decoders */
-static u64 available_protocols;
+static atomic_t available_protocols = ATOMIC_INIT(0);
 
 static int ir_raw_event_thread(void *data)
 {
@@ -251,11 +251,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 /* used internally by the sysfs interface */
 static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
 {
-	u64 protocols;
-	mutex_lock(&ir_raw_mutex);
-	protocols = available_protocols;
-	mutex_unlock(&ir_raw_mutex);
-	return protocols;
+	return atomic_read(&available_protocols);
 }
 
 static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
@@ -353,7 +349,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
 	if (ir_raw_handler->raw_register)
 		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
 			ir_raw_handler->raw_register(raw->dev);
-	available_protocols |= ir_raw_handler->protocols;
+	atomic_set_mask(ir_raw_handler->protocols, &available_protocols);
 	mutex_unlock(&ir_raw_mutex);
 	synchronize_rcu();
 
@@ -370,7 +366,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 	if (ir_raw_handler->raw_unregister)
 		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
 			ir_raw_handler->raw_unregister(raw->dev);
-	available_protocols &= ~ir_raw_handler->protocols;
+	atomic_clear_mask(ir_raw_handler->protocols, &available_protocols);
 	mutex_unlock(&ir_raw_mutex);
 	synchronize_rcu();
 }


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

* [PATCH 43/49] rc-core: fix various sparse warnings
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (41 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 42/49] rc-ir-raw: atomic reads of protocols David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-04-03 23:34 ` [PATCH 44/49] rc-core: don't report scancodes via input devices David Härdeman
                   ` (7 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Fix various sparse warnings under drivers/media/rc/*.c, mostly
by making functions static.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/fintek-cir.c  |    4 ++--
 drivers/media/rc/imon.c        |    8 ++++----
 drivers/media/rc/ite-cir.c     |    4 ++--
 drivers/media/rc/nuvoton-cir.c |    4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index ce2db15..dd49c28 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -685,12 +685,12 @@ static struct pnp_driver fintek_driver = {
 	.shutdown	= fintek_shutdown,
 };
 
-static int fintek_init(void)
+static int __init fintek_init(void)
 {
 	return pnp_register_driver(&fintek_driver);
 }
 
-static void fintek_exit(void)
+static void __exit fintek_exit(void)
 {
 	pnp_unregister_driver(&fintek_driver);
 }
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 1aa2ac0..287edf6 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -78,11 +78,11 @@ static int display_open(struct inode *inode, struct file *file);
 static int display_close(struct inode *inode, struct file *file);
 
 /* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
 			 size_t n_bytes, loff_t *pos);
 
 /* LCD file_operations override function prototypes */
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
 			 size_t n_bytes, loff_t *pos);
 
 /*** G L O B A L S ***/
@@ -825,7 +825,7 @@ static struct attribute_group imon_rf_attr_group = {
  * than 32 bytes are provided spaces will be appended to
  * generate a full screen.
  */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
 			 size_t n_bytes, loff_t *pos)
 {
 	int i;
@@ -912,7 +912,7 @@ exit:
  * display whatever diacritics you need, and so on), but it's also
  * a lot more complicated than most LCDs...
  */
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
 			 size_t n_bytes, loff_t *pos)
 {
 	int retval = 0;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 795fbc6..2755e06 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1703,12 +1703,12 @@ static struct pnp_driver ite_driver = {
 	.shutdown	= ite_shutdown,
 };
 
-static int ite_init(void)
+static int __init ite_init(void)
 {
 	return pnp_register_driver(&ite_driver);
 }
 
-static void ite_exit(void)
+static void __exit ite_exit(void)
 {
 	pnp_unregister_driver(&ite_driver);
 }
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index a8c9b5f..9e63ee6 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1231,12 +1231,12 @@ static struct pnp_driver nvt_driver = {
 	.shutdown	= nvt_shutdown,
 };
 
-static int nvt_init(void)
+static int __init nvt_init(void)
 {
 	return pnp_register_driver(&nvt_driver);
 }
 
-static void nvt_exit(void)
+static void __exit nvt_exit(void)
 {
 	pnp_unregister_driver(&nvt_driver);
 }


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

* [PATCH 44/49] rc-core: don't report scancodes via input devices
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (42 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 43/49] rc-core: fix various sparse warnings David Härdeman
@ 2014-04-03 23:34 ` David Härdeman
  2014-07-25 23:16   ` Mauro Carvalho Chehab
  2014-04-03 23:35 ` [PATCH 45/49] rc-ir-raw: add various rc_events David Härdeman
                   ` (6 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:34 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

The scancode that is reported via the input device(s) is now incomplete
(missing the protocol) and redundant.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-keytable.c |   21 +++++----------------
 1 file changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 5709ae6..23a66c7 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -645,17 +645,10 @@ void rc_keytable_repeat(struct rc_keytable *kt)
 	unsigned long flags;
 
 	spin_lock_irqsave(&kt->key_lock, flags);
-
-	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
-	input_sync(kt->idev);
-
-	if (!kt->key_pressed)
-		goto out;
-
-	kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
-	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
-
-out:
+	if (kt->key_pressed) {
+		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
+		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+	}
 	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
@@ -695,8 +688,6 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 	if (new_event)
 		rc_do_keyup(kt, false);
 
-	input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
-
 	if (new_event && keycode != KEY_RESERVED) {
 		/* Register a keypress */
 		kt->key_pressed = true;
@@ -710,8 +701,8 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 			   kt->dev->input_name, keycode, protocol,
 			   (long long unsigned)scancode);
 		input_report_key(kt->idev, keycode, 1);
+		input_sync(kt->idev);
 	}
-	input_sync(kt->idev);
 
 	if (autoup && kt->key_pressed) {
 		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
@@ -811,8 +802,6 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 	idev->close = rc_input_close;
 	set_bit(EV_KEY, idev->evbit);
 	set_bit(EV_REP, idev->evbit);
-	set_bit(EV_MSC, idev->evbit);
-	set_bit(MSC_SCAN, idev->mscbit);
 	input_set_drvdata(idev, kt);
 	setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
 


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

* [PATCH 45/49] rc-ir-raw: add various rc_events
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (43 preceding siblings ...)
  2014-04-03 23:34 ` [PATCH 44/49] rc-core: don't report scancodes via input devices David Härdeman
@ 2014-04-03 23:35 ` David Härdeman
  2014-07-25 23:16   ` Mauro Carvalho Chehab
  2014-04-03 23:35 ` [PATCH 46/49] rc-core: use struct rc_event for all rc communication David Härdeman
                   ` (5 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:35 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Reporting pulse/space events via the /dev/rc/rcX device node is an
important step towards having feature parity with LIRC.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-ir-raw.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index bf5215b..3b68975 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -71,6 +71,17 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
 	IR_dprintk(2, "sample: (%05dus %s)\n",
 		   TO_US(ev->duration), TO_STR(ev->pulse));
 
+	if (ev->reset)
+		rc_event(dev, RC_IR, RC_IR_RESET, 1);
+	else if (ev->carrier_report)
+		rc_event(dev, RC_IR, RC_IR_CARRIER, ev->carrier);
+	else if (ev->timeout)
+		rc_event(dev, RC_IR, RC_IR_STOP, 1);
+	else if (ev->pulse)
+		rc_event(dev, RC_IR, RC_IR_PULSE, ev->duration);
+	else
+		rc_event(dev, RC_IR, RC_IR_SPACE, ev->duration);
+
 	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
 		return -ENOMEM;
 


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

* [PATCH 46/49] rc-core: use struct rc_event for all rc communication
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (44 preceding siblings ...)
  2014-04-03 23:35 ` [PATCH 45/49] rc-ir-raw: add various rc_events David Härdeman
@ 2014-04-03 23:35 ` David Härdeman
  2014-07-25 23:19   ` Mauro Carvalho Chehab
  2014-04-03 23:35 ` [PATCH 47/49] rc-core: add keytable events David Härdeman
                   ` (4 subsequent siblings)
  50 siblings, 1 reply; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:35 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Remove struct ir_raw_event and use struct rc_event in all stages
of IR processing. This should help future flexibility and also
cuts down on the confusing number of structs that are flying
around in rc-*.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/hid/hid-picolcd_cir.c              |   18 +++--
 drivers/media/common/siano/smsir.c         |    7 +-
 drivers/media/i2c/cx25840/cx25840-ir.c     |   94 +++++++++++++++-------------
 drivers/media/pci/cx23885/cx23885-input.c  |   11 +--
 drivers/media/pci/cx23885/cx23888-ir.c     |   91 ++++++++++++++-------------
 drivers/media/pci/cx88/cx88-input.c        |   13 +++-
 drivers/media/rc/ene_ir.c                  |   12 ++--
 drivers/media/rc/fintek-cir.c              |   21 +++---
 drivers/media/rc/iguanair.c                |   17 ++---
 drivers/media/rc/ir-jvc-decoder.c          |   48 +++++++-------
 drivers/media/rc/ir-lirc-codec.c           |   28 ++++----
 drivers/media/rc/ir-mce_kbd-decoder.c      |   34 +++++-----
 drivers/media/rc/ir-nec-decoder.c          |   51 ++++++++-------
 drivers/media/rc/ir-rc5-decoder.c          |   32 +++++-----
 drivers/media/rc/ir-rc6-decoder.c          |   48 +++++++-------
 drivers/media/rc/ir-sanyo-decoder.c        |   46 +++++++-------
 drivers/media/rc/ir-sharp-decoder.c        |   49 +++++++--------
 drivers/media/rc/ir-sony-decoder.c         |   42 +++++++------
 drivers/media/rc/ite-cir.c                 |   19 ++----
 drivers/media/rc/ite-cir.h                 |    2 -
 drivers/media/rc/mceusb.c                  |   15 +++-
 drivers/media/rc/nuvoton-cir.c             |   18 +++--
 drivers/media/rc/rc-core-priv.h            |   40 +++++++-----
 drivers/media/rc/rc-ir-raw.c               |   89 +++++++++++++++------------
 drivers/media/rc/rc-loopback.c             |   14 +---
 drivers/media/rc/redrat3.c                 |   34 ++++------
 drivers/media/rc/streamzap.c               |   62 +++++++++---------
 drivers/media/rc/ttusbir.c                 |   31 ++++-----
 drivers/media/rc/winbond-cir.c             |   23 +++----
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c    |    6 +-
 drivers/media/usb/dvb-usb/technisat-usb2.c |   15 +++-
 include/media/rc-ir-raw.h                  |   47 +++++---------
 32 files changed, 548 insertions(+), 529 deletions(-)

diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index 59d5eb1..1f9021f 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -45,7 +45,7 @@ int picolcd_raw_cir(struct picolcd_data *data,
 {
 	unsigned long flags;
 	int i, w, sz;
-	DEFINE_IR_RAW_EVENT(rawir);
+	DEFINE_IR_RAW_EVENT(ev);
 
 	/* ignore if rc_dev is NULL or status is shunned */
 	spin_lock_irqsave(&data->lock, flags);
@@ -67,14 +67,18 @@ int picolcd_raw_cir(struct picolcd_data *data,
 	 */
 	sz = size > 0 ? min((int)raw_data[0], size-1) : 0;
 	for (i = 0; i+1 < sz; i += 2) {
-		init_ir_raw_event(&rawir);
 		w = (raw_data[i] << 8) | (raw_data[i+1]);
-		rawir.pulse = !!(w & 0x8000);
-		rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w);
+		if (w & 0x8000) {
+			ev.code = RC_IR_PULSE;
+			ev.val = US_TO_NS(65536 - w);
+		} else {
+			ev.code = RC_IR_SPACE;
+			ev.val = US_TO_NS(w);
+		}
 		/* Quirk!! - see above */
-		if (i == 0 && rawir.duration > 15000000)
-			rawir.duration -= 15000000;
-		ir_raw_event_store(data->rc_dev, &rawir);
+		if (i == 0 && ev.val > 15000000)
+			ev.val -= 15000000;
+		ir_raw_event_store(data->rc_dev, &ev);
 	}
 	ir_raw_event_handle(data->rc_dev);
 
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index f6938f4..3959a572 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -38,12 +38,11 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
 {
 	int i;
 	const s32 *samples = (const void *)buf;
+	DEFINE_IR_RAW_EVENT(ev);
 
 	for (i = 0; i < len >> 2; i++) {
-		DEFINE_IR_RAW_EVENT(ev);
-
-		ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
-		ev.pulse = (samples[i] > 0) ? false : true;
+		ev.val = US_TO_NS(abs(samples[i]));
+		ev.code = (samples[i] > 0) ? RC_IR_SPACE : RC_IR_PULSE;
 
 		ir_raw_event_store(coredev->ir.dev, &ev);
 	}
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 119d4e8..1672f0e 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -98,12 +98,12 @@ MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
 
 /*
  * We use this union internally for convenience, but callers to tx_write
- * and rx_read will be expecting records of type struct ir_raw_event.
- * Always ensure the size of this union is dictated by struct ir_raw_event.
+ * and rx_read will be expecting records of type struct rc_event.
+ * Always ensure the size of this union is dictated by struct rc_event.
  */
 union cx25840_ir_fifo_rec {
 	u32 hw_fifo_data;
-	struct ir_raw_event ir_core_data;
+	struct rc_event ir_core_data;
 };
 
 #define CX25840_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
@@ -659,63 +659,67 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
 }
 
 /* Receiver */
-static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
-			      ssize_t *num)
+static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
+			      ssize_t *bytes_read)
 {
-	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct cx25840_ir_state *state = to_ir_state(sd);
 	bool invert;
 	u16 divider;
-	unsigned int i, n;
-	union cx25840_ir_fifo_rec *p;
-	unsigned u, v, w;
-
-	if (ir_state == NULL)
+	struct rc_event *ev = (struct rc_event *)buf;
+	union cx25840_ir_fifo_rec rec;
+	unsigned max_events;
+	unsigned events = 0;
+	bool pulse, timeout;
+	u64 val;
+
+	if (!state)
 		return -ENODEV;
 
-	invert = (bool) atomic_read(&ir_state->rx_invert);
-	divider = (u16) atomic_read(&ir_state->rxclk_divider);
-
-	n = count / sizeof(union cx25840_ir_fifo_rec)
-		* sizeof(union cx25840_ir_fifo_rec);
-	if (n == 0) {
-		*num = 0;
-		return 0;
-	}
-
-	n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
-			     &ir_state->rx_kfifo_lock);
+	invert = (bool)atomic_read(&state->rx_invert);
+	divider = (u16)atomic_read(&state->rxclk_divider);
+	max_events = bufsize / sizeof(union cx25840_ir_fifo_rec);
 
-	n /= sizeof(union cx25840_ir_fifo_rec);
-	*num = n * sizeof(union cx25840_ir_fifo_rec);
-
-	for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+	while (events + 2 <= max_events) {
+		if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
+					 &state->rx_kfifo_lock) != sizeof(rec))
+			break;
 
-		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+		if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
 			/* Assume RTO was because of no IR light input */
-			u = 0;
-			w = 1;
+			pulse = false;
+			timeout = true;
 		} else {
-			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+			pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
 			if (invert)
-				u = u ? 0 : 1;
-			w = 0;
+				pulse = !pulse;
+			timeout = false;
 		}
 
-		v = (unsigned) pulse_width_count_to_ns(
-				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
-		if (v > IR_MAX_DURATION)
-			v = IR_MAX_DURATION;
-
-		init_ir_raw_event(&p->ir_core_data);
-		p->ir_core_data.pulse = u;
-		p->ir_core_data.duration = v;
-		p->ir_core_data.timeout = w;
+		val = min_t(u64, IR_MAX_DURATION,
+			    pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
+						    divider));
+
+		if (val) {
+			init_ir_raw_event(ev);
+			ev->code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
+			ev->val = val;
+			events++;
+			ev++;
+			v4l2_dbg(2, ir_debug, sd, "rx read: %10llu ns %s\n",
+				 (long long unsigned)val, pulse ? "pulse" : "space");
+		}
 
-		v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s  %s\n",
-			 v, u ? "mark" : "space", w ? "(timed out)" : "");
-		if (w)
+		if (timeout) {
+			init_ir_raw_event(ev);
+			ev->code = RC_IR_STOP;
+			ev->val = 1;
+			events++;
+			ev++;
 			v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
+		}
 	}
+
+	*bytes_read = events * sizeof(union cx25840_ir_fifo_rec);
 	return 0;
 }
 
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index e2ba28d..5eac866 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -52,18 +52,17 @@ static void cx23885_input_process_measurements(struct cx23885_dev *dev,
 	ssize_t num;
 	int count, i;
 	bool handle = false;
-	struct ir_raw_event ir_core_event[64];
+	struct rc_event ev[64];
 
 	do {
 		num = 0;
-		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
-				 sizeof(ir_core_event), &num);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *)ev,
+				 sizeof(rc_event), &num);
 
-		count = num / sizeof(struct ir_raw_event);
+		count = num / sizeof(struct rc_event);
 
 		for (i = 0; i < count; i++) {
-			ir_raw_event_store(kernel_ir->rc,
-					   &ir_core_event[i]);
+			ir_raw_event_store(kernel_ir->rc, &ev[i]);
 			handle = true;
 		}
 	} while (num != 0);
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index c4961f8..da1b43e 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -116,12 +116,12 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
 
 /*
  * We use this union internally for convenience, but callers to tx_write
- * and rx_read will be expecting records of type struct ir_raw_event.
- * Always ensure the size of this union is dictated by struct ir_raw_event.
+ * and rx_read will be expecting records of type struct rc_event.
+ * Always ensure the size of this union is dictated by struct rc_event.
  */
 union cx23888_ir_fifo_rec {
 	u32 hw_fifo_data;
-	struct ir_raw_event ir_core_data;
+	struct rc_event ir_core_data;
 };
 
 #define CX23888_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx23888_ir_fifo_rec))
@@ -660,57 +660,62 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
 }
 
 /* Receiver */
-static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
-			      ssize_t *num)
+static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
+			      ssize_t *bytes_read)
 {
 	struct cx23888_ir_state *state = to_state(sd);
-	bool invert = (bool) atomic_read(&state->rx_invert);
-	u16 divider = (u16) atomic_read(&state->rxclk_divider);
-
-	unsigned int i, n;
-	union cx23888_ir_fifo_rec *p;
-	unsigned u, v, w;
-
-	n = count / sizeof(union cx23888_ir_fifo_rec)
-		* sizeof(union cx23888_ir_fifo_rec);
-	if (n == 0) {
-		*num = 0;
-		return 0;
-	}
-
-	n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
-
-	n /= sizeof(union cx23888_ir_fifo_rec);
-	*num = n * sizeof(union cx23888_ir_fifo_rec);
-
-	for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+	bool invert = (bool)atomic_read(&state->rx_invert);
+	u16 divider = (u16)atomic_read(&state->rxclk_divider);
+	struct rc_event *ev = (struct rc_event *)buf;
+	union cx23888_ir_fifo_rec rec;
+	unsigned max_events;
+	unsigned events = 0;
+	bool pulse, timeout;
+	u64 val;
+
+	max_events = bufsize / sizeof(union cx23888_ir_fifo_rec);
+
+	while (events + 2 <= max_events) {
+		if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
+					 &state->rx_kfifo_lock) != sizeof(rec))
+			break;
 
-		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+		if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
 			/* Assume RTO was because of no IR light input */
-			u = 0;
-			w = 1;
+			pulse = false;
+			timeout = true;
 		} else {
-			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+			pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
 			if (invert)
-				u = u ? 0 : 1;
-			w = 0;
+				pulse = !pulse;
+			timeout = false;
 		}
 
-		v = (unsigned) pulse_width_count_to_ns(
-				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
-		if (v > IR_MAX_DURATION)
-			v = IR_MAX_DURATION;
-
-		init_ir_raw_event(&p->ir_core_data);
-		p->ir_core_data.pulse = u;
-		p->ir_core_data.duration = v;
-		p->ir_core_data.timeout = w;
+		val = min_t(u64, IR_MAX_DURATION,
+			    pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
+						    divider));
+
+		if (val) {
+			init_ir_raw_event(ev);
+			ev->code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
+			ev->val = val;
+			events++;
+			ev++;
+			v4l2_dbg(2, ir_888_debug, sd, "rx read: %10llu ns %s\n",
+				 (long long unsigned)val, pulse ? "pulse" : "space");
+		}
 
-		v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s  %s\n",
-			 v, u ? "mark" : "space", w ? "(timed out)" : "");
-		if (w)
+		if (timeout) {
+			init_ir_raw_event(ev);
+			ev->code = RC_IR_STOP;
+			ev->val = 1;
+			events++;
+			ev++;
 			v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
+		}
 	}
+
+	*bytes_read = events * sizeof(union cx23888_ir_fifo_rec);
 	return 0;
 }
 
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 2b68ede..b8d3534 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core)
 	struct cx88_IR *ir = core->ir;
 	u32 samples;
 	unsigned todo, bits;
-	struct ir_raw_event ev;
+	DEFINE_IR_RAW_EVENT(ev);
 
 	if (!ir || !ir->sampling)
 		return;
@@ -541,9 +541,14 @@ void cx88_ir_irq(struct cx88_core *core)
 
 	init_ir_raw_event(&ev);
 	for (todo = 32; todo > 0; todo -= bits) {
-		ev.pulse = samples & 0x80000000 ? false : true;
-		bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
-		ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
+		if (samples & 0x80000000) {
+			ev.code = RC_IR_PULSE;
+			bits = min(todo, 32U - fls(samples));
+		} else {
+			ev.code = RC_IR_SPACE;
+			bits = min(todo, 32U - fls(~samples));
+		}
+		ev.val = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
 		ir_raw_event_store_with_filter(ir->dev, &ev);
 		samples <<= bits;
 	}
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 57d61e5..df05b2c 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -353,9 +353,11 @@ static void ene_rx_sense_carrier(struct ene_device *dev)
 	dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
 						carrier, duty_cycle);
 	if (dev->carrier_detect_enabled) {
-		ev.carrier_report = true;
-		ev.carrier = carrier;
-		ev.duty_cycle = duty_cycle;
+		ev.code = RC_IR_CARRIER;
+		ev.val = carrier;
+		ir_raw_event_store(dev->rdev, &ev);
+		ev.code = RC_IR_DUTY_CYCLE;
+		ev.val = duty_cycle;
 		ir_raw_event_store(dev->rdev, &ev);
 	}
 }
@@ -810,8 +812,8 @@ static irqreturn_t ene_isr(int irq, void *data)
 
 		dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
 
-		ev.duration = US_TO_NS(hw_sample);
-		ev.pulse = pulse;
+		ev.val = US_TO_NS(hw_sample);
+		ev.code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
 		ir_raw_event_store_with_filter(dev->rdev, &ev);
 	}
 
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index dd49c28..bdccef0 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -293,7 +293,7 @@ static int fintek_cmdsize(u8 cmd, u8 subcmd)
 /* process ir data stored in driver buffer */
 static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
 {
-	DEFINE_IR_RAW_EVENT(rawir);
+	DEFINE_IR_RAW_EVENT(ev);
 	u8 sample;
 	bool event = false;
 	int i;
@@ -325,17 +325,18 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
 			break;
 		case PARSE_IRDATA:
 			fintek->rem--;
-			init_ir_raw_event(&rawir);
-			rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
-			rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
+			init_ir_raw_event(&ev);
+			ev.code = RC_IR_SPACE;
+			if (sample & BUF_PULSE_BIT)
+				ev.code = RC_IR_PULSE;
+			ev.val = US_TO_NS((sample & BUF_SAMPLE_MASK)
 					  * CIR_SAMPLE_PERIOD);
 
-			fit_dbg("Storing %s with duration %d",
-				rawir.pulse ? "pulse" : "space",
-				rawir.duration);
-			if (ir_raw_event_store_with_filter(fintek->rdev,
-									&rawir))
-				event = true;
+			fit_dbg("Storing %s with duration %llu",
+				ev.code == RC_IR_PULSE ? "pulse" : "space",
+				(long long unsigned)ev.val);
+			ir_raw_event_store_with_filter(fintek->rdev, &ev);
+			event = true;
 			break;
 		}
 
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 3b7327a..1ab94d2 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -132,23 +132,22 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
 			break;
 		}
 	} else if (len >= 7) {
-		DEFINE_IR_RAW_EVENT(rawir);
+		DEFINE_IR_RAW_EVENT(ev);
 		unsigned i;
 		bool event = false;
 
-		init_ir_raw_event(&rawir);
-
 		for (i = 0; i < 7; i++) {
 			if (ir->buf_in[i] == 0x80) {
-				rawir.pulse = false;
-				rawir.duration = US_TO_NS(21845);
+				ev.code = RC_IR_SPACE;
+				ev.val = US_TO_NS(21845);
 			} else {
-				rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
-				rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
-								 RX_RESOLUTION;
+				ev.code = ir->buf_in[i] & 0x80 ?
+					  RC_IR_SPACE : RC_IR_PULSE;
+				ev.val = ((ir->buf_in[i] & 0x7f) + 1) *
+					 RX_RESOLUTION;
 			}
 
-			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
+			if (ir_raw_event_store_with_filter(ir->rc, &ev))
 				event = true;
 		}
 
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 30bcf18..081cc3f 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -39,37 +39,39 @@ enum jvc_state {
 /**
  * ir_jvc_decode() - Decode one JVC pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @duration:   the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_jvc_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct jvc_dec *data = &dev->raw->jvc;
 
 	if (!(dev->enabled_protocols & RC_BIT_JVC))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
+	if (!geq_margin(ev.val, JVC_UNIT, JVC_UNIT / 2))
 		goto out;
 
 	IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
 again:
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+		if (!eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
 			break;
 
 		data->count = 0;
@@ -79,34 +81,34 @@ again:
 		return 0;
 
 	case STATE_HEADER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
+		if (!eq_margin(ev.val, JVC_HEADER_SPACE, JVC_UNIT / 2))
 			break;
 
 		data->state = STATE_BIT_PULSE;
 		return 0;
 
 	case STATE_BIT_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
+		if (!eq_margin(ev.val, JVC_BIT_PULSE, JVC_UNIT / 2))
 			break;
 
 		data->state = STATE_BIT_SPACE;
 		return 0;
 
 	case STATE_BIT_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		data->bits <<= 1;
-		if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
+		if (eq_margin(ev.val, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
 			data->bits |= 1;
 			decrease_duration(&ev, JVC_BIT_1_SPACE);
-		} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
+		} else if (eq_margin(ev.val, JVC_BIT_0_SPACE, JVC_UNIT / 2))
 			decrease_duration(&ev, JVC_BIT_0_SPACE);
 		else
 			break;
@@ -119,20 +121,20 @@ again:
 		return 0;
 
 	case STATE_TRAILER_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
+		if (!eq_margin(ev.val, JVC_TRAILER_PULSE, JVC_UNIT / 2))
 			break;
 
 		data->state = STATE_TRAILER_SPACE;
 		return 0;
 
 	case STATE_TRAILER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
+		if (!geq_margin(ev.val, JVC_TRAILER_SPACE, JVC_UNIT / 2))
 			break;
 
 		if (data->first) {
@@ -156,10 +158,10 @@ again:
 		return 0;
 
 	case STATE_CHECK_REPEAT:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+		if (eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
 			data->state = STATE_INACTIVE;
   else
 			data->state = STATE_BIT_PULSE;
@@ -168,7 +170,7 @@ again:
 
 out:
 	IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 7b56f21..1b4d1ff 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -25,12 +25,12 @@
 /**
  * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
  *		      lircd userspace daemon for decoding.
- * @input_dev:	the struct rc_dev descriptor of the device
- * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ * @dev:	the struct rc_dev descriptor of the device
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the lirc interfaces aren't wired up.
  */
-static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_lirc_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct lirc_codec *lirc = &dev->raw->lirc;
 	int sample;
@@ -42,29 +42,29 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return -EINVAL;
 
 	/* Packet start */
-	if (ev.reset)
+	if (ev.code == RC_IR_RESET)
 		return 0;
 
 	/* Carrier reports */
-	if (ev.carrier_report) {
-		sample = LIRC_FREQUENCY(ev.carrier);
+	if (ev.code == RC_IR_CARRIER) {
+		sample = LIRC_FREQUENCY(ev.val);
 		IR_dprintk(2, "carrier report (freq: %d)\n", sample);
 
 	/* Packet end */
-	} else if (ev.timeout) {
+	} else if (ev.code == RC_IR_STOP) {
 
 		if (lirc->gap)
 			return 0;
 
 		lirc->gap_start = ktime_get();
 		lirc->gap = true;
-		lirc->gap_duration = ev.duration;
+		lirc->gap_duration = 0;
 
 		if (!lirc->send_timeout_reports)
 			return 0;
 
-		sample = LIRC_TIMEOUT(ev.duration / 1000);
-		IR_dprintk(2, "timeout report (duration: %d)\n", sample);
+		sample = LIRC_TIMEOUT(0);
+		IR_dprintk(2, "timeout report\n");
 
 	/* Normal sample */
 	} else {
@@ -86,10 +86,10 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			lirc->gap = false;
 		}
 
-		sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
-					LIRC_SPACE(ev.duration / 1000);
+		sample = is_pulse(ev) ? LIRC_PULSE(ev.val / 1000) :
+					LIRC_SPACE(ev.val / 1000);
 		IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
-			   TO_US(ev.duration), TO_STR(ev.pulse));
+			   TO_US(ev.val), TO_STR(ev.code));
 	}
 
 	lirc_buffer_write(dev->raw->lirc.drv->rbuf,
@@ -436,7 +436,7 @@ static int ir_lirc_register(struct rc_dev *dev)
 	drv->rbuf = rbuf;
 	drv->set_use_inc = &ir_lirc_open;
 	drv->set_use_dec = &ir_lirc_close;
-	drv->code_length = sizeof(struct ir_raw_event) * 8;
+	drv->code_length = sizeof(struct rc_event) * 8;
 	drv->fops = &lirc_fops;
 	drv->dev = &dev->dev;
 	drv->rdev = dev;
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 9f3c9b5..14538dd 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -206,11 +206,11 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
 /**
  * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_mce_kbd_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct mce_kbd_dec *data = &dev->raw->mce_kbd;
 	u32 scancode;
@@ -219,32 +219,34 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
+	if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
 		goto out;
 
 again:
 	IR_dprintk(2, "started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
-	if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+	if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
 		return 0;
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
 		/* Note: larger margin on first pulse since each MCIR2_UNIT
 		   is quite short and some hardware takes some time to
 		   adjust to the signal */
-		if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
+		if (!eq_margin(ev.val, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
 			break;
 
 		data->state = STATE_HEADER_BIT_START;
@@ -253,11 +255,11 @@ again:
 		return 0;
 
 	case STATE_HEADER_BIT_START:
-		if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+		if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
 			break;
 
 		data->header <<= 1;
-		if (ev.pulse)
+		if (is_pulse(ev))
 			data->header |= 1;
 		data->count++;
 		data->state = STATE_HEADER_BIT_END;
@@ -292,11 +294,11 @@ again:
 		goto again;
 
 	case STATE_BODY_BIT_START:
-		if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+		if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
 			break;
 
 		data->body <<= 1;
-		if (ev.pulse)
+		if (is_pulse(ev))
 			data->body |= 1;
 		data->count++;
 		data->state = STATE_BODY_BIT_END;
@@ -315,7 +317,7 @@ again:
 		goto again;
 
 	case STATE_FINISHED:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		switch (data->wanted_bits) {
@@ -348,7 +350,7 @@ again:
 
 out:
 	IR_dprintk(1, "failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	input_sync(data->idev);
 	return -EINVAL;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 861fd86..cf4b8be 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -41,11 +41,11 @@ enum nec_state {
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
- * This function returns -EINVAL if the pulse violates the state machine
+ * This function returns -EINVAL if the event violates the state machine
  */
-static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_nec_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct nec_dec *data = &dev->raw->nec;
 	u32 scancode;
@@ -54,25 +54,27 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!(dev->enabled_protocols & RC_BIT_NEC))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
 	IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
+		if (eq_margin(ev.val, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
 			data->is_nec_x = false;
 			data->necx_repeat = false;
-		} else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
+		} else if (eq_margin(ev.val, NECX_HEADER_PULSE, NEC_UNIT / 2))
 			data->is_nec_x = true;
 		else
 			break;
@@ -82,13 +84,13 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_HEADER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {
+		if (eq_margin(ev.val, NEC_HEADER_SPACE, NEC_UNIT)) {
 			data->state = STATE_BIT_PULSE;
 			return 0;
-		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
+		} else if (eq_margin(ev.val, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
 			rc_repeat(dev);
 			IR_dprintk(1, "Repeat last key\n");
 			data->state = STATE_TRAILER_PULSE;
@@ -98,22 +100,21 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		break;
 
 	case STATE_BIT_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
+		if (!eq_margin(ev.val, NEC_BIT_PULSE, NEC_UNIT / 2))
 			break;
 
 		data->state = STATE_BIT_SPACE;
 		return 0;
 
 	case STATE_BIT_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
-			geq_margin(ev.duration,
-			NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
+		    geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
 				IR_dprintk(1, "Repeat last key\n");
 				rc_repeat(dev);
 				data->state = STATE_INACTIVE;
@@ -123,9 +124,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			data->necx_repeat = false;
 
 		data->bits <<= 1;
-		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
+		if (eq_margin(ev.val, NEC_BIT_1_SPACE, NEC_UNIT / 2))
 			data->bits |= 1;
-		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
+		else if (!eq_margin(ev.val, NEC_BIT_0_SPACE, NEC_UNIT / 2))
 			break;
 		data->count++;
 
@@ -137,20 +138,20 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_TRAILER_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
+		if (!eq_margin(ev.val, NEC_TRAILER_PULSE, NEC_UNIT / 2))
 			break;
 
 		data->state = STATE_TRAILER_SPACE;
 		return 0;
 
 	case STATE_TRAILER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
+		if (!geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2))
 			break;
 
 		address     = bitrev8((data->bits >> 24) & 0xff);
@@ -173,7 +174,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 	IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 93168da..be43c0d 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -42,11 +42,11 @@ enum rc5_state {
 /**
  * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_rc5_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct rc5_dec *data = &dev->raw->rc5;
 	u8 toggle;
@@ -56,26 +56,28 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
+	if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
 		goto out;
 
 again:
 	IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
-	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+	if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
 		return 0;
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
 		data->state = STATE_BIT_START;
@@ -84,16 +86,16 @@ again:
 		goto again;
 
 	case STATE_BIT_START:
-		if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
+		if (is_space(ev) && geq_margin(ev.val, RC5_TRAILER, RC5_UNIT / 2)) {
 			data->state = STATE_FINISHED;
 			goto again;
 		}
 
-		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+		if (!eq_margin(ev.val, RC5_BIT_START, RC5_UNIT / 2))
 			break;
 
 		data->bits <<= 1;
-		if (!ev.pulse)
+		if (is_space(ev))
 			data->bits |= 1;
 		data->count++;
 		data->state = STATE_BIT_END;
@@ -112,7 +114,7 @@ again:
 		goto again;
 
 	case STATE_CHECK_RC5X:
-		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
+		if (is_space(ev) && geq_margin(ev.val, RC5X_SPACE, RC5_UNIT / 2)) {
 			data->is_rc5x = true;
 			decrease_duration(&ev, RC5X_SPACE);
 		} else
@@ -121,7 +123,7 @@ again:
 		goto again;
 
 	case STATE_FINISHED:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		if (data->is_rc5x && data->count == RC5X_NBITS) {
@@ -179,7 +181,7 @@ again:
 
 out:
 	IR_dprintk(1, "RC5(x/sz) decode failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index f1f098e..20db209 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -79,11 +79,11 @@ static enum rc6_mode rc6_mode(struct rc6_dec *data)
 /**
  * ir_rc6_decode() - Decode one RC6 pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_rc6_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct rc6_dec *data = &dev->raw->rc6;
 	u32 scancode;
@@ -95,32 +95,34 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	       RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
+	if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
 		goto out;
 
 again:
 	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
-	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+	if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
 		return 0;
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
 		/* Note: larger margin on first pulse since each RC6_UNIT
 		   is quite short and some hardware takes some time to
 		   adjust to the signal */
-		if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
+		if (!eq_margin(ev.val, RC6_PREFIX_PULSE, RC6_UNIT))
 			break;
 
 		data->state = STATE_PREFIX_SPACE;
@@ -128,10 +130,10 @@ again:
 		return 0;
 
 	case STATE_PREFIX_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
+		if (!eq_margin(ev.val, RC6_PREFIX_SPACE, RC6_UNIT / 2))
 			break;
 
 		data->state = STATE_HEADER_BIT_START;
@@ -139,11 +141,11 @@ again:
 		return 0;
 
 	case STATE_HEADER_BIT_START:
-		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
+		if (!eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2))
 			break;
 
 		data->header <<= 1;
-		if (ev.pulse)
+		if (is_pulse(ev))
 			data->header |= 1;
 		data->count++;
 		data->state = STATE_HEADER_BIT_END;
@@ -162,16 +164,16 @@ again:
 		goto again;
 
 	case STATE_TOGGLE_START:
-		if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
+		if (!eq_margin(ev.val, RC6_TOGGLE_START, RC6_UNIT / 2))
 			break;
 
-		data->toggle = ev.pulse;
+		data->toggle = is_pulse(ev);
 		data->state = STATE_TOGGLE_END;
 		return 0;
 
 	case STATE_TOGGLE_END:
 		if (!is_transition(&ev, &dev->raw->prev_ev) ||
-		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
+		    !geq_margin(ev.val, RC6_TOGGLE_END, RC6_UNIT / 2))
 			break;
 
 		if (!(data->header & RC6_STARTBIT_MASK)) {
@@ -198,17 +200,17 @@ again:
 		goto again;
 
 	case STATE_BODY_BIT_START:
-		if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
+		if (eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2)) {
 			/* Discard LSB's that won't fit in data->body */
 			if (data->count++ < CHAR_BIT * sizeof data->body) {
 				data->body <<= 1;
-				if (ev.pulse)
+				if (is_pulse(ev))
 					data->body |= 1;
 			}
 			data->state = STATE_BODY_BIT_END;
 			return 0;
-		} else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
-				geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
+		} else if (RC6_MODE_6A == rc6_mode(data) && is_space(ev) &&
+				geq_margin(ev.val, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
 			data->state = STATE_FINISHED;
 			goto again;
 		}
@@ -227,7 +229,7 @@ again:
 		goto again;
 
 	case STATE_FINISHED:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		switch (rc6_mode(data)) {
@@ -286,7 +288,7 @@ again:
 
 out:
 	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 9f97648..b1be396 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -48,11 +48,11 @@ enum sanyo_state {
 /**
  * ir_sanyo_decode() - Decode one SANYO pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_sanyo_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct sanyo_dec *data = &dev->raw->sanyo;
 	u32 scancode;
@@ -61,24 +61,24 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!(dev->enabled_protocols & RC_BIT_SANYO))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset) {
-			IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
-			data->state = STATE_INACTIVE;
-		}
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
 	IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
+		if (eq_margin(ev.val, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
 			data->count = 0;
 			data->state = STATE_HEADER_SPACE;
 			return 0;
@@ -87,10 +87,10 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 
 	case STATE_HEADER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
+		if (eq_margin(ev.val, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
 			data->state = STATE_BIT_PULSE;
 			return 0;
 		}
@@ -98,20 +98,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		break;
 
 	case STATE_BIT_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
+		if (!eq_margin(ev.val, SANYO_BIT_PULSE, SANYO_UNIT / 2))
 			break;
 
 		data->state = STATE_BIT_SPACE;
 		return 0;
 
 	case STATE_BIT_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
+		if (!data->count && geq_margin(ev.val, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
 			rc_repeat(dev);
 			IR_dprintk(1, "SANYO repeat last key\n");
 			data->state = STATE_INACTIVE;
@@ -119,9 +119,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		}
 
 		data->bits <<= 1;
-		if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
+		if (eq_margin(ev.val, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
 			data->bits |= 1;
-		else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
+		else if (!eq_margin(ev.val, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
 			break;
 		data->count++;
 
@@ -133,20 +133,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_TRAILER_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
+		if (!eq_margin(ev.val, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
 			break;
 
 		data->state = STATE_TRAILER_SPACE;
 		return 0;
 
 	case STATE_TRAILER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
+		if (!geq_margin(ev.val, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
 			break;
 
 		address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
@@ -169,7 +169,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 	IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index b7acdba..435f0ac 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -39,11 +39,11 @@ enum sharp_state {
 /**
  * ir_sharp_decode() - Decode one Sharp pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_sharp_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct sharp_dec *data = &dev->raw->sharp;
 	u32 msg, echo, address, command, scancode;
@@ -51,51 +51,53 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!(dev->enabled_protocols & RC_BIT_SHARP))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
 	IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
+		if (!eq_margin(ev.val, SHARP_BIT_PULSE,
 			       SHARP_BIT_PULSE / 2))
 			break;
 
 		data->count = 0;
-		data->pulse_len = ev.duration;
+		data->pulse_len = ev.val;
 		data->state = STATE_BIT_SPACE;
 		return 0;
 
 	case STATE_BIT_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
+		if (!eq_margin(ev.val, SHARP_BIT_PULSE,
 			       SHARP_BIT_PULSE / 2))
 			break;
 
-		data->pulse_len = ev.duration;
+		data->pulse_len = ev.val;
 		data->state = STATE_BIT_SPACE;
 		return 0;
 
 	case STATE_BIT_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
 		data->bits <<= 1;
-		if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
+		if (eq_margin(data->pulse_len + ev.val, SHARP_BIT_1_PERIOD,
 			      SHARP_BIT_PULSE * 2))
 			data->bits |= 1;
-		else if (!eq_margin(data->pulse_len + ev.duration,
+		else if (!eq_margin(data->pulse_len + ev.val,
 				    SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
 			break;
 		data->count++;
@@ -109,11 +111,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_TRAILER_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
-			       SHARP_BIT_PULSE / 2))
+		if (!eq_margin(ev.val, SHARP_BIT_PULSE, SHARP_BIT_PULSE / 2))
 			break;
 
 		if (data->count == SHARP_NBITS) {
@@ -127,11 +128,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_ECHO_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
-			       SHARP_ECHO_SPACE / 4))
+		if (!eq_margin(ev.val, SHARP_ECHO_SPACE, SHARP_ECHO_SPACE / 4))
 			break;
 
 		data->state = STATE_BIT_PULSE;
@@ -139,10 +139,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_TRAILER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
+		if (!geq_margin(ev.val, SHARP_TRAILER_SPACE,
 				SHARP_BIT_PULSE / 2))
 			break;
 
@@ -168,8 +168,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 	IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration),
-		   TO_STR(ev.pulse));
+		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index d12dc3d..f7c4aa1 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -35,11 +35,11 @@ enum sony_state {
 /**
  * ir_sony_decode() - Decode one Sony pulse or space
  * @dev:	the struct rc_dev descriptor of the device
- * @ev:         the struct ir_raw_event descriptor of the pulse/space
+ * @ev:         the struct rc_event descriptor of the event
  *
  * This function returns -EINVAL if the pulse violates the state machine
  */
-static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_sony_decode(struct rc_dev *dev, struct rc_event ev)
 {
 	struct sony_dec *data = &dev->raw->sony;
 	enum rc_type protocol;
@@ -50,25 +50,27 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	      (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
 		return 0;
 
-	if (!is_timing_event(ev)) {
-		if (ev.reset)
-			data->state = STATE_INACTIVE;
+	if (ev.code == RC_IR_RESET) {
+		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
+	if (!is_ir_raw_timing_event(ev))
+		return 0;
+
+	if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2))
 		goto out;
 
 	IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 
 	switch (data->state) {
 
 	case STATE_INACTIVE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
+		if (!eq_margin(ev.val, SONY_HEADER_PULSE, SONY_UNIT / 2))
 			break;
 
 		data->count = 0;
@@ -76,23 +78,23 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_HEADER_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
+		if (!eq_margin(ev.val, SONY_HEADER_SPACE, SONY_UNIT / 2))
 			break;
 
 		data->state = STATE_BIT_PULSE;
 		return 0;
 
 	case STATE_BIT_PULSE:
-		if (!ev.pulse)
+		if (is_space(ev))
 			break;
 
 		data->bits <<= 1;
-		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
+		if (eq_margin(ev.val, SONY_BIT_1_PULSE, SONY_UNIT / 2))
 			data->bits |= 1;
-		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
+		else if (!eq_margin(ev.val, SONY_BIT_0_PULSE, SONY_UNIT / 2))
 			break;
 
 		data->count++;
@@ -100,15 +102,15 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 
 	case STATE_BIT_SPACE:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
+		if (!geq_margin(ev.val, SONY_BIT_SPACE, SONY_UNIT / 2))
 			break;
 
 		decrease_duration(&ev, SONY_BIT_SPACE);
 
-		if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
+		if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2)) {
 			data->state = STATE_BIT_PULSE;
 			return 0;
 		}
@@ -117,10 +119,10 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		/* Fall through */
 
 	case STATE_FINISHED:
-		if (ev.pulse)
+		if (is_pulse(ev))
 			break;
 
-		if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
+		if (!geq_margin(ev.val, SONY_TRAILER_SPACE, SONY_UNIT / 2))
 			break;
 
 		switch (data->count) {
@@ -168,7 +170,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 out:
 	IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+		   data->state, TO_US(ev.val), TO_STR(ev.code));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 2755e06..c3eb7e6 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -190,16 +190,15 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
 	size = length << 3;
 	next_one = find_next_bit_le(ldata, size, 0);
 	if (next_one > 0) {
-		ev.pulse = true;
-		ev.duration =
-		    ITE_BITS_TO_NS(next_one, sample_period);
+		ev.code = RC_IR_PULSE;
+		ev.val = ITE_BITS_TO_NS(next_one, sample_period);
 		ir_raw_event_store_with_filter(dev->rdev, &ev);
 	}
 
 	while (next_one < size) {
 		next_zero = find_next_zero_bit_le(ldata, size, next_one + 1);
-		ev.pulse = false;
-		ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
+		ev.code = RC_IR_SPACE;
+		ev.val = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
 		ir_raw_event_store_with_filter(dev->rdev, &ev);
 
 		if (next_zero < size) {
@@ -207,12 +206,10 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
 			    find_next_bit_le(ldata,
 						     size,
 						     next_zero + 1);
-			ev.pulse = true;
-			ev.duration =
-			    ITE_BITS_TO_NS(next_one - next_zero,
-					   sample_period);
-			ir_raw_event_store_with_filter
-			    (dev->rdev, &ev);
+			ev.code = RC_IR_PULSE;
+			ev.val = ITE_BITS_TO_NS(next_one - next_zero,
+						sample_period);
+			ir_raw_event_store_with_filter(dev->rdev, &ev);
 		} else
 			next_one = size;
 	}
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
index aa899a0..5c1fa57 100644
--- a/drivers/media/rc/ite-cir.h
+++ b/drivers/media/rc/ite-cir.h
@@ -125,7 +125,7 @@ struct ite_dev_params {
 struct ite_dev {
 	struct pnp_dev *pdev;
 	struct rc_dev *rdev;
-	struct ir_raw_event rawir;
+	struct rc_event rawir;
 
 	/* sync data */
 	spinlock_t lock;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index eac87ec..7f95d78 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -994,13 +994,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 		case PARSE_IRDATA:
 			ir->rem--;
 			init_ir_raw_event(&rawir);
-			rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
-			rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
-					 * US_TO_NS(MCE_TIME_UNIT);
+			if (ir->buf_in[i] & MCE_PULSE_BIT)
+				rawir.code = RC_IR_PULSE;
+			else
+				rawir.code = RC_IR_SPACE;
+			rawir.val = (ir->buf_in[i] & MCE_PULSE_MASK) *
+				    US_TO_NS(MCE_TIME_UNIT);
 
-			dev_dbg(ir->dev, "Storing %s with duration %d",
-				rawir.pulse ? "pulse" : "space",
-				rawir.duration);
+			dev_dbg(ir->dev, "Storing %s with duration %llu\n",
+				rawir.code == RC_IR_PULSE ? "pulse" : "space",
+				(long long unsigned)rawir.val);
 
 			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
 				event = true;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 9e63ee6..3a54760 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -611,7 +611,7 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
  */
 static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
 {
-	DEFINE_IR_RAW_EVENT(rawir);
+	DEFINE_IR_RAW_EVENT(ev);
 	u8 sample;
 	int i;
 
@@ -622,19 +622,19 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
 
 	nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
 
-	init_ir_raw_event(&rawir);
-
 	for (i = 0; i < nvt->pkts; i++) {
 		sample = nvt->buf[i];
 
-		rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
-		rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
-					  * SAMPLE_PERIOD);
+		ev.code = RC_IR_SPACE;
+		if (sample & BUF_PULSE_BIT)
+			ev.code = RC_IR_PULSE;
+		ev.val = US_TO_NS((sample & BUF_LEN_MASK) * SAMPLE_PERIOD);
 
-		nvt_dbg("Storing %s with duration %d",
-			rawir.pulse ? "pulse" : "space", rawir.duration);
+		nvt_dbg("Storing %s with duration %llu",
+			ev.code == RC_IR_PULSE ? "pulse" : "space",
+			(long long unsigned)ev.val);
 
-		ir_raw_event_store_with_filter(nvt->rdev, &rawir);
+		ir_raw_event_store_with_filter(nvt->rdev, &ev);
 
 		/*
 		 * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 04776e8..4945727 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -18,7 +18,6 @@
 
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <media/rc-core.h>
 #include <media/rc-ir-raw.h>
 
 enum rc_driver_type {
@@ -30,7 +29,7 @@ struct ir_raw_handler {
 	struct list_head list;
 
 	unsigned protocols; /* which are handled by this handler */
-	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
+	int (*decode)(struct rc_dev *dev, struct rc_event event);
 
 	/* These two should only be used by the lirc decoder */
 	int (*raw_register)(struct rc_dev *dev);
@@ -43,14 +42,14 @@ struct ir_raw_handler {
 struct ir_raw_event_ctrl {
 	struct list_head		list;		/* to keep track of raw clients */
 	struct task_struct		*thread;
-	DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
+	DECLARE_KFIFO(kfifo, struct rc_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
 	ktime_t				last_event;	/* when last event occurred */
 	enum raw_event_type		last_type;	/* last event type */
 	struct rc_dev			*dev;		/* pointer to the parent rc_dev */
 
 	/* raw decoder state follows */
-	struct ir_raw_event prev_ev;
-	struct ir_raw_event this_ev;
+	struct rc_event prev_ev;
+	struct rc_event this_ev;
 	struct nec_dec {
 		int state;
 		unsigned count;
@@ -131,27 +130,34 @@ static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
 	return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
 }
 
-static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
+static inline bool is_transition(struct rc_event *x, struct rc_event *y)
 {
-	return x->pulse != y->pulse;
+	return x->code != y->code;
 }
 
-static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
+static inline void decrease_duration(struct rc_event *ev, unsigned duration)
 {
-	if (duration > ev->duration)
-		ev->duration = 0;
-	else
-		ev->duration -= duration;
+	ev->val -= min_t(u64, ev->val, duration);
 }
 
-/* Returns true if event is normal pulse/space event */
-static inline bool is_timing_event(struct ir_raw_event ev)
+static inline bool is_pulse(struct rc_event ev)
 {
-	return !ev.carrier_report && !ev.reset;
+	return ev.type == RC_IR && ev.code == RC_IR_PULSE;
 }
 
-#define TO_US(duration)			DIV_ROUND_CLOSEST((duration), 1000)
-#define TO_STR(is_pulse)		((is_pulse) ? "pulse" : "space")
+static inline bool is_space(struct rc_event ev)
+{
+	return ev.type == RC_IR && ev.code == RC_IR_SPACE;
+}
+
+static inline bool is_ir_raw_timing_event(struct rc_event ev)
+{
+	return ev.type == RC_IR &&
+	       (ev.code == RC_IR_SPACE || ev.code == RC_IR_PULSE);
+}
+
+#define TO_US(duration)			((unsigned)DIV_ROUND_CLOSEST((duration), 1000))
+#define TO_STR(code)			((code == RC_IR_PULSE) ? "pulse" : "space")
 
 /*
  * Routines from rc-raw.c to be used internally and by decoders
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 3b68975..0c1923a 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -19,6 +19,8 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/freezer.h>
+#include <media/rc-ir-raw.h>
+
 #include "rc-core-priv.h"
 
 /* IR raw clients/handlers, writers synchronize with ir_raw_mutex */
@@ -31,12 +33,12 @@ static atomic_t available_protocols = ATOMIC_INIT(0);
 
 static int ir_raw_event_thread(void *data)
 {
-	struct ir_raw_event ev;
+	struct rc_event ev;
 	struct ir_raw_handler *handler;
 	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
 
 	while (!kthread_should_stop()) {
-		if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
+		if (!kfifo_get(&raw->kfifo, &ev)) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			continue;
@@ -55,36 +57,26 @@ static int ir_raw_event_thread(void *data)
 /**
  * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
  * @dev:	the struct rc_dev device descriptor
- * @ev:		the struct ir_raw_event descriptor of the pulse/space
+ * @ev:		the struct rc_event descriptor of the event
+ *
+ * This routine (which may be called from an interrupt context) stores an
+ * event for the raw ir decoding state machines and interested userspace
+ * processes.
  *
- * 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. Drivers are responsible for
- * synchronizing calls to this function.
+ * Drivers are responsible for synchronizing calls to this function.
  */
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
+int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev)
 {
 	if (!dev->raw)
 		return -EINVAL;
 
-	IR_dprintk(2, "sample: (%05dus %s)\n",
-		   TO_US(ev->duration), TO_STR(ev->pulse));
-
-	if (ev->reset)
-		rc_event(dev, RC_IR, RC_IR_RESET, 1);
-	else if (ev->carrier_report)
-		rc_event(dev, RC_IR, RC_IR_CARRIER, ev->carrier);
-	else if (ev->timeout)
-		rc_event(dev, RC_IR, RC_IR_STOP, 1);
-	else if (ev->pulse)
-		rc_event(dev, RC_IR, RC_IR_PULSE, ev->duration);
-	else
-		rc_event(dev, RC_IR, RC_IR_SPACE, ev->duration);
+	if (ev->type != RC_IR)
+		return -EINVAL;
 
-	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
+	if (!kfifo_put(&dev->raw->kfifo, *ev))
 		return -ENOMEM;
 
+	rc_event(dev, ev->type, ev->code, ev->val);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_store);
@@ -120,15 +112,15 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
 	if (delta > MS_TO_NS(500) || !dev->raw->last_type)
 		type |= IR_START_EVENT;
 	else
-		ev.duration = delta;
+		ev.val = delta;
 
 	if (type & IR_START_EVENT)
 		ir_raw_event_reset(dev);
 	else if (dev->raw->last_type & IR_SPACE) {
-		ev.pulse = false;
+		ev.code = RC_IR_SPACE;
 		rc = ir_raw_event_store(dev, &ev);
 	} else if (dev->raw->last_type & IR_PULSE) {
-		ev.pulse = true;
+		ev.code = RC_IR_PULSE;
 		rc = ir_raw_event_store(dev, &ev);
 	} else
 		return 0;
@@ -142,7 +134,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
 /**
  * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
  * @dev:	the struct rc_dev device descriptor
- * @type:	the type of the event that has occurred
+ * @ev:		the struct rc_event descriptor of the event
  *
  * This routine (which may be called from an interrupt context) works
  * in similar manner to ir_raw_event_store_edge.
@@ -151,29 +143,35 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
  * if the event was added, and zero if the event was ignored due to idle
  * processing.
  */
-int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev)
 {
 	if (!dev->raw)
 		return -EINVAL;
 
 	/* Ignore spaces in idle mode */
-	if (dev->idle && !ev->pulse)
-		return 0;
-	else if (dev->idle)
+	if (dev->idle) {
+		if (ev->code == RC_IR_SPACE)
+			return 0;
 		ir_raw_event_set_idle(dev, false);
+	}
+
+	if (!is_ir_raw_timing_event(*ev)) {
+		ir_raw_event_store(dev, &dev->raw->this_ev);
+		return 0;
+	}
 
-	if (!dev->raw->this_ev.duration)
+	if (!dev->raw->this_ev.val)
 		dev->raw->this_ev = *ev;
-	else if (ev->pulse == dev->raw->this_ev.pulse)
-		dev->raw->this_ev.duration += ev->duration;
+	else if (ev->code == dev->raw->this_ev.code)
+		dev->raw->this_ev.val += ev->val;
 	else {
 		ir_raw_event_store(dev, &dev->raw->this_ev);
 		dev->raw->this_ev = *ev;
 	}
 
 	/* Enter idle mode if nessesary */
-	if (!ev->pulse && dev->timeout &&
-	    dev->raw->this_ev.duration >= dev->timeout)
+	if (ev->code == RC_IR_SPACE && dev->timeout &&
+	    dev->raw->this_ev.val >= dev->timeout)
 		ir_raw_event_set_idle(dev, true);
 
 	return 1;
@@ -187,17 +185,30 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
  */
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
 {
+	DEFINE_IR_RAW_EVENT(ev);
+
 	if (!dev->raw)
 		return;
 
+	if (dev->idle == idle)
+		return;
+
 	IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
 
+
 	if (idle) {
-		dev->raw->this_ev.timeout = true;
-		ir_raw_event_store(dev, &dev->raw->this_ev);
-		init_ir_raw_event(&dev->raw->this_ev);
+		if (dev->raw->this_ev.val > 0)
+			ir_raw_event_store(dev, &dev->raw->this_ev);
+		ev.code = RC_IR_STOP;
+		ev.val = 1;
+	} else {
+		ev.code = RC_IR_START;
+		ev.val = 1;
 	}
 
+	init_ir_raw_event(&dev->raw->this_ev);
+	ir_raw_event_store(dev, &ev);
+
 	if (dev->s_idle)
 		dev->s_idle(dev, idle);
 
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 343c8d0..26c03bd 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -54,7 +54,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned count)
 	struct loopback_dev *lodev = dev->priv;
 	u32 rxmask;
 	struct rc_event ev;
-	DEFINE_IR_RAW_EVENT(rawir);
 	int tmp;
 
 	if (lodev->txcarrier < lodev->rxcarriermin ||
@@ -78,17 +77,14 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned count)
 	while ((tmp = ir_raw_get_tx_event(dev, &ev)) != 0) {
 		if (tmp < 0)
 			continue;
-		init_ir_raw_event(&rawir);
-		rawir.pulse = (ev.code == RC_IR_PULSE);
-		rawir.duration = ev.val;
-		ir_raw_event_store_with_filter(dev, &rawir);
+		ir_raw_event_store_with_filter(dev, &ev);
 	}
 
 	/* Fake a silence long enough to cause us to go idle */
-	init_ir_raw_event(&rawir);
-	rawir.pulse = false;
-	rawir.duration = dev->timeout;
-	ir_raw_event_store_with_filter(dev, &rawir);
+	ev.type = RC_IR;
+	ev.code = RC_IR_SPACE;
+	ev.val = dev->timeout;
+	ir_raw_event_store_with_filter(dev, &ev);
 
 	ir_raw_event_handle(dev);
 
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 17974bf..e93a593 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -365,7 +365,7 @@ static void redrat3_rx_timeout(unsigned long data)
 
 static void redrat3_process_ir_data(struct redrat3_dev *rr3)
 {
-	DEFINE_IR_RAW_EVENT(rawir);
+	struct rc_event ev;
 	struct device *dev;
 	unsigned i, trailer = 0;
 	unsigned sig_size, single_len, offset, val;
@@ -396,34 +396,28 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
 		single_len = redrat3_len_to_us(val);
 
 		/* we should always get pulse/space/pulse/space samples */
-		if (i % 2)
-			rawir.pulse = false;
-		else
-			rawir.pulse = true;
+		ev.type = RC_IR;
+		ev.code = i % 2 ? RC_IR_SPACE : RC_IR_PULSE;
+		ev.val = min_t(u64, IR_MAX_DURATION, US_TO_NS(single_len));
 
-		rawir.duration = US_TO_NS(single_len);
 		/* Save initial pulse length to fudge trailer */
 		if (i == 0)
-			trailer = rawir.duration;
-		/* cap the value to IR_MAX_DURATION */
-		rawir.duration &= IR_MAX_DURATION;
+			trailer = single_len;
 
-		rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
-			rawir.pulse ? "pulse" : "space", rawir.duration, i);
-		ir_raw_event_store_with_filter(rr3->rc, &rawir);
+		rr3_dbg(dev, "storing %s with duration %llu (i: %d)\n",
+			ev.code == RC_IR_PULSE ? "pulse" : "space",
+			(long long unsigned)ev.val, i);
+		ir_raw_event_store_with_filter(rr3->rc, &ev);
 	}
 
 	/* add a trailing space, if need be */
 	if (i % 2) {
-		rawir.pulse = false;
+		ev.code = RC_IR_SPACE;
 		/* this duration is made up, and may not be ideal... */
-		if (trailer < US_TO_NS(1000))
-			rawir.duration = US_TO_NS(2800);
-		else
-			rawir.duration = trailer;
-		rr3_dbg(dev, "storing trailing space with duration %d\n",
-			rawir.duration);
-		ir_raw_event_store_with_filter(rr3->rc, &rawir);
+		ev.val = US_TO_NS(trailer < 1000 ? 2800 : trailer);
+		rr3_dbg(dev, "storing trailing space with duration %llu\n",
+			(long long unsigned)ev.val);
+		ir_raw_event_store_with_filter(rr3->rc, &ev);
 	}
 
 	rr3_dbg(dev, "calling ir_raw_event_handle\n");
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 149e824..d30e3f7 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -129,17 +129,18 @@ static struct usb_driver streamzap_driver = {
 	.id_table =	streamzap_table,
 };
 
-static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
+static void sz_push(struct streamzap_ir *sz, struct rc_event ev)
 {
 	dev_dbg(sz->dev, "Storing %s with duration %u us\n",
-		(rawir.pulse ? "pulse" : "space"), rawir.duration);
-	ir_raw_event_store_with_filter(sz->rdev, &rawir);
+		(ev.code == RC_IR_PULSE ? "pulse" : "space"),
+		(unsigned)(ev.val / 1000));
+	ir_raw_event_store_with_filter(sz->rdev, &ev);
 }
 
 static void sz_push_full_pulse(struct streamzap_ir *sz,
 			       unsigned char value)
 {
-	DEFINE_IR_RAW_EVENT(rawir);
+	DEFINE_IR_RAW_EVENT(ev);
 
 	if (sz->idle) {
 		long deltv;
@@ -148,31 +149,29 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
 		do_gettimeofday(&sz->signal_start);
 
 		deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
-		rawir.pulse = false;
+		ev.code = RC_IR_SPACE;
 		if (deltv > 15) {
 			/* really long time */
-			rawir.duration = IR_MAX_DURATION;
+			ev.val = IR_MAX_DURATION;
 		} else {
-			rawir.duration = (int)(deltv * 1000000 +
-				sz->signal_start.tv_usec -
-				sz->signal_last.tv_usec);
-			rawir.duration -= sz->sum;
-			rawir.duration = US_TO_NS(rawir.duration);
-			rawir.duration &= IR_MAX_DURATION;
+			ev.val = (deltv * 1000000 +
+				  sz->signal_start.tv_usec -
+				  sz->signal_last.tv_usec);
+			ev.val -= sz->sum;
+			ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
 		}
-		sz_push(sz, rawir);
+		sz_push(sz, ev);
 
 		sz->idle = false;
 		sz->sum = 0;
 	}
 
-	rawir.pulse = true;
-	rawir.duration = ((int) value) * SZ_RESOLUTION;
-	rawir.duration += SZ_RESOLUTION / 2;
-	sz->sum += rawir.duration;
-	rawir.duration = US_TO_NS(rawir.duration);
-	rawir.duration &= IR_MAX_DURATION;
-	sz_push(sz, rawir);
+	ev.code = RC_IR_PULSE;
+	ev.val = value * SZ_RESOLUTION;
+	ev.val += SZ_RESOLUTION / 2;
+	sz->sum += ev.val;
+	ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
+	sz_push(sz, ev);
 }
 
 static void sz_push_half_pulse(struct streamzap_ir *sz,
@@ -184,14 +183,13 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
 static void sz_push_full_space(struct streamzap_ir *sz,
 			       unsigned char value)
 {
-	DEFINE_IR_RAW_EVENT(rawir);
-
-	rawir.pulse = false;
-	rawir.duration = ((int) value) * SZ_RESOLUTION;
-	rawir.duration += SZ_RESOLUTION / 2;
-	sz->sum += rawir.duration;
-	rawir.duration = US_TO_NS(rawir.duration);
-	sz_push(sz, rawir);
+	DEFINE_IR_RAW_EVENT(ev);
+
+	ev.code = RC_IR_SPACE;
+	ev.val = value * SZ_RESOLUTION + SZ_RESOLUTION / 2;
+	sz->sum += ev.val;
+	ev.val = US_TO_NS(ev.val);
+	sz_push(sz, ev);
 }
 
 static void sz_push_half_space(struct streamzap_ir *sz,
@@ -258,13 +256,13 @@ static void streamzap_callback(struct urb *urb)
 			break;
 		case FullSpace:
 			if (sz->buf_in[i] == SZ_TIMEOUT) {
-				DEFINE_IR_RAW_EVENT(rawir);
+				DEFINE_IR_RAW_EVENT(ev);
 
-				rawir.pulse = false;
-				rawir.duration = sz->rdev->timeout;
+				ev.code = RC_IR_STOP;
+				ev.val = 1;
 				sz->idle = true;
 				if (sz->timeout_enabled)
-					sz_push(sz, rawir);
+					sz_push(sz, ev);
 				ir_raw_event_handle(sz->rdev);
 				ir_raw_event_reset(sz->rdev);
 			} else {
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 19317e2..0e9b05c 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -121,44 +121,43 @@ static void ttusbir_bulk_complete(struct urb *urb)
  */
 static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
 {
-	struct ir_raw_event rawir;
+	DEFINE_IR_RAW_EVENT(ev);
 	unsigned i, v, b;
 	bool event = false;
 
-	init_ir_raw_event(&rawir);
-
 	for (i = 0; i < 128; i++) {
 		v = buf[i] & 0xfe;
 		switch (v) {
 		case 0xfe:
-			rawir.pulse = false;
-			rawir.duration = NS_PER_BYTE;
-			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+			ev.code = RC_IR_SPACE;
+			ev.val = NS_PER_BYTE;
+			if (ir_raw_event_store_with_filter(tt->rc, &ev))
 				event = true;
 			break;
 		case 0:
-			rawir.pulse = true;
-			rawir.duration = NS_PER_BYTE;
-			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+			ev.code = RC_IR_PULSE;
+			ev.val = NS_PER_BYTE;
+			if (ir_raw_event_store_with_filter(tt->rc, &ev))
 				event = true;
 			break;
 		default:
 			/* one edge per byte */
 			if (v & 2) {
 				b = ffz(v | 1);
-				rawir.pulse = true;
+				ev.code = RC_IR_PULSE;
 			} else {
 				b = ffs(v) - 1;
-				rawir.pulse = false;
+				ev.code = RC_IR_SPACE;
 			}
 
-			rawir.duration = NS_PER_BIT * (8 - b);
-			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+			ev.val = NS_PER_BIT * (8 - b);
+			if (ir_raw_event_store_with_filter(tt->rc, &ev))
 				event = true;
 
-			rawir.pulse = !rawir.pulse;
-			rawir.duration = NS_PER_BIT * b;
-			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+			ev.val = ev.val == RC_IR_SPACE ?
+				 RC_IR_PULSE : RC_IR_SPACE;
+			ev.code = NS_PER_BIT * b;
+			if (ir_raw_event_store_with_filter(tt->rc, &ev))
 				event = true;
 			break;
 		}
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 07da3e0..930a34e 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -342,20 +342,18 @@ wbcir_carrier_report(struct wbcir_data *data)
 
 	if (counter > 0 && counter < 0xffff) {
 		DEFINE_IR_RAW_EVENT(ev);
-
-		ev.carrier_report = 1;
-		ev.carrier = DIV_ROUND_CLOSEST(counter * 1000000u,
-						data->pulse_duration);
-
+		ev.code = RC_IR_CARRIER;
+		ev.val = DIV_ROUND_CLOSEST(counter * 1000000u,
+					   data->pulse_duration);
 		ir_raw_event_store(data->dev, &ev);
 	}
 
 	/* reset and restart the counter */
 	data->pulse_duration = 0;
 	wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R,
-						WBCIR_CNTR_EN | WBCIR_CNTR_R);
+		       WBCIR_CNTR_EN | WBCIR_CNTR_R);
 	wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_EN,
-						WBCIR_CNTR_EN | WBCIR_CNTR_R);
+		       WBCIR_CNTR_EN | WBCIR_CNTR_R);
 }
 
 static void
@@ -381,7 +379,7 @@ static void
 wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
 {
 	u8 irdata;
-	DEFINE_IR_RAW_EVENT(rawir);
+	struct rc_event ev;
 	unsigned duration;
 
 	/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
@@ -392,13 +390,14 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
 
 		duration = ((irdata & 0x7F) + 1) *
 			(data->carrier_report_enabled ? 2 : 10);
-		rawir.pulse = irdata & 0x80 ? false : true;
-		rawir.duration = US_TO_NS(duration);
+		ev.type = RC_IR;
+		ev.code = irdata & 0x80 ? RC_IR_SPACE : RC_IR_PULSE;
+		ev.val = US_TO_NS(duration);
 
-		if (rawir.pulse)
+		if (ev.code == RC_IR_PULSE)
 			data->pulse_duration += duration;
 
-		ir_raw_event_store_with_filter(data->dev, &rawir);
+		ir_raw_event_store_with_filter(data->dev, &ev);
 	}
 
 	ir_raw_event_handle(data->dev);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 0412862..dc5d075 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1281,7 +1281,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
 {
 	int ret, i, len;
 	struct rtl28xxu_priv *priv = d->priv;
-	struct ir_raw_event ev;
+	struct rc_event ev;
 	u8 buf[128];
 	static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
 		{IR_RX_IF,               0x03, 0xff},
@@ -1350,8 +1350,8 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
 	init_ir_raw_event(&ev);
 
 	for (i = 0; i < len; i++) {
-		ev.pulse = buf[i] >> 7;
-		ev.duration = 50800 * (buf[i] & 0x7f);
+		ev.code = buf[i] >> 7 ? RC_IR_PULSE : RC_IR_SPACE;
+		ev.val = 50800 * (buf[i] & 0x7f);
 		ir_raw_event_store_with_filter(d->rc_dev, &ev);
 	}
 
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 288f24c..624a073 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -593,7 +593,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
 {
 	u8 buf[62], *b;
 	int ret;
-	struct ir_raw_event ev;
+	DEFINE_IR_RAW_EVENT(ev);
 
 	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
 	buf[1] = 0x08;
@@ -636,16 +636,19 @@ unlock:
 	debug_dump(b, ret, deb_rc);
 #endif
 
-	ev.pulse = 0;
 	while (1) {
-		ev.pulse = !ev.pulse;
-		ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
+		if (ev.code == RC_IR_SPACE)
+			ev.code = RC_IR_PULSE;
+		else
+			ev.code = RC_IR_SPACE;
+
+		ev.val = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
 		ir_raw_event_store(d->rc_dev, &ev);
 
 		b++;
 		if (*b == 0xff) {
-			ev.pulse = 0;
-			ev.duration = 888888*2;
+			ev.code = RC_IR_SPACE;
+			ev.val = 888888*2;
 			ir_raw_event_store(d->rc_dev, &ev);
 			break;
 		}
diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
index dad3eb2..89bf2f7 100644
--- a/include/media/rc-ir-raw.h
+++ b/include/media/rc-ir-raw.h
@@ -27,33 +27,17 @@ enum raw_event_type {
 	IR_STOP_EVENT   = (1 << 3),
 };
 
-struct ir_raw_event {
-	union {
-		u32             duration;
+#define DEFINE_IR_RAW_EVENT(ev)			\
+	struct rc_event ev = {			\
+		.type = RC_IR,			\
+		.code = RC_IR_PULSE,		\
+		.val = 0 }
 
-		struct {
-			u32     carrier;
-			u8      duty_cycle;
-		};
-	};
-
-	unsigned                pulse:1;
-	unsigned                reset:1;
-	unsigned                timeout:1;
-	unsigned                carrier_report:1;
-};
-
-#define DEFINE_IR_RAW_EVENT(event) \
-	struct ir_raw_event event = { \
-		{ .duration = 0 } , \
-		.pulse = 0, \
-		.reset = 0, \
-		.timeout = 0, \
-		.carrier_report = 0 }
-
-static inline void init_ir_raw_event(struct ir_raw_event *ev)
+static inline void init_ir_raw_event(struct rc_event *ev)
 {
-	memset(ev, 0, sizeof(*ev));
+	ev->type = RC_IR;
+	ev->code = RC_IR_PULSE;
+	ev->val = 0;
 }
 
 #define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
@@ -62,10 +46,9 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
 #define MS_TO_NS(msec)		((msec) * 1000 * 1000)
 
 void ir_raw_event_handle(struct rc_dev *dev);
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
+int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev);
 int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
-int ir_raw_event_store_with_filter(struct rc_dev *dev,
-				struct ir_raw_event *ev);
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev);
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
 int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
 int rc_register_ir_raw_device(struct rc_dev *dev);
@@ -73,9 +56,11 @@ void rc_unregister_ir_raw_device(struct rc_dev *dev);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
-	DEFINE_IR_RAW_EVENT(ev);
-	ev.reset = true;
-
+	struct rc_event ev = {
+		.type = RC_IR,
+		.code = RC_IR_RESET,
+		.val = 1
+	};
 	ir_raw_event_store(dev, &ev);
 	ir_raw_event_handle(dev);
 }


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

* [PATCH 47/49] rc-core: add keytable events
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (45 preceding siblings ...)
  2014-04-03 23:35 ` [PATCH 46/49] rc-core: use struct rc_event for all rc communication David Härdeman
@ 2014-04-03 23:35 ` David Härdeman
  2014-04-03 23:35 ` [PATCH 48/49] rc-core: move remaining keytable functions David Härdeman
                   ` (3 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:35 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Add separe rc device events on keytable addition/removal.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-main.c |    2 ++
 include/media/rc-core.h    |    2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index bd4dfab..b3db1dd 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -221,6 +221,7 @@ static int rc_add_keytable(struct rc_dev *dev, const char *name,
 	rcu_assign_pointer(dev->keytables[i], kt);
 	list_add_rcu(&kt->node, &dev->keytable_list);
 	synchronize_rcu();
+	rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
 	return 0;
 }
 
@@ -241,6 +242,7 @@ static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
 		return -EINVAL;
 
 	rc_keytable_destroy(kt);
+	rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
 	return 0;
 }
 
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index a310e5b..a7354b7 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -203,6 +203,8 @@ struct rc_keymap_entry {
 
 /* RC_CORE codes */
 #define RC_CORE_DROPPED		0x0
+#define RC_CORE_KT_ADDED	0x1
+#define RC_CORE_KT_REMOVED	0x2
 
 /* RC_KEY codes */
 #define RC_KEY_REPEAT		0x0


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

* [PATCH 48/49] rc-core: move remaining keytable functions
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (46 preceding siblings ...)
  2014-04-03 23:35 ` [PATCH 47/49] rc-core: add keytable events David Härdeman
@ 2014-04-03 23:35 ` David Härdeman
  2014-04-03 23:35 ` [PATCH 49/49] rc-core: make rc-core.h userspace friendly David Härdeman
                   ` (2 subsequent siblings)
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:35 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

Move some more keytable related functionality over to rc-keytable.c which
allows more implementational details to be obscured away.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 drivers/media/rc/rc-core-priv.h |   54 +++++++++++-
 drivers/media/rc/rc-keytable.c  |  169 +++++++++++++++++++++++++++++++--------
 drivers/media/rc/rc-main.c      |  136 ++-----------------------------
 include/media/rc-core.h         |   44 ----------
 4 files changed, 191 insertions(+), 212 deletions(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 4945727..1c6c066 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -168,12 +168,54 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
 /*
  * Methods from rc-keytable.c to be used internally
  */
-void rc_keytable_keyup(struct rc_keytable *kt);
-void rc_keytable_repeat(struct rc_keytable *kt);
-void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
-			 u32 scancode, u8 toggle, bool autokeyup);
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, struct rc_map *rc_map);
-void rc_keytable_destroy(struct rc_keytable *kt);
+int rc_keytable_add(struct rc_dev *dev, const char *name, struct rc_map *rc_map);
+int rc_keytable_del(struct rc_dev *dev, unsigned i);
+int rc_keytable_get_name(struct rc_dev *dev, unsigned i,
+			 char *buf, size_t bufsize);
+
+/**
+ * struct rc_scan - rcu-friendly scancode<->keycode table
+ * @len:	number of elements in the table array
+ * @table:	array of struct rc_map_table elements
+ */
+struct rc_scan {
+	unsigned len;
+	struct rc_map_table table[];
+};
+
+/**
+ * struct rc_keytable - represents one keytable for a rc_dev device
+ * @node:		used to iterate over all keytables for a rc_dev device
+ * @dev:		the rc_dev device this keytable belongs to
+ * @idev:		the input_dev device which belongs to this keytable
+ * @name:		the user-friendly name of this keytable
+ * @scan_mutex:		protects @scan against concurrent writers
+ * @scan:		the current scancode<->keycode table
+ * @key_lock:		protects the key state
+ * @key_pressed:	whether a key is currently pressed or not
+ * @last_keycode:	keycode of the last keypress
+ * @last_protocol:	protocol of the last keypress
+ * @last_scancode:	scancode of the last keypress
+ * @last_toggle:	toggle of the last keypress
+ * @timer_keyup:	responsible for the auto-release of keys
+ * @keyup_jiffies:	when the key should be auto-released
+ */
+struct rc_keytable {
+	struct list_head		node;
+	struct rc_dev			*dev;
+	struct input_dev		*idev;
+	char				name[RC_KEYTABLE_NAME_SIZE];
+	struct mutex			scan_mutex;
+	struct rc_scan __rcu		*scan;
+	spinlock_t			key_lock;
+	bool				key_pressed;
+	u32				last_keycode;
+	enum rc_type			last_protocol;
+	u32				last_scancode;
+	u8				last_toggle;
+	struct timer_list		timer_keyup;
+	unsigned long			keyup_jiffies;
+};
 
 /* Only to be used by rc-core and ir-lirc-codec */
 void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 23a66c7..1dd75e2 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -591,19 +591,25 @@ static void rc_do_keyup(struct rc_keytable *kt, bool sync)
 }
 
 /**
- * rc_keytable_keyup() - signals the release of a keypress
- * @kt:		the keytable
+ * rc_keyup() - signals the release of a keypress
+ * @dev:       the struct rc_dev descriptor of the device
  *
- * This routine is used to generate input keyup events.
+ * Report that a key is no longer pressed.
  */
-void rc_keytable_keyup(struct rc_keytable *kt)
+void rc_keyup(struct rc_dev *dev)
 {
+	struct rc_keytable *kt;
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->key_lock, flags);
-	rc_do_keyup(kt, true);
-	spin_unlock_irqrestore(&kt->key_lock, flags);
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node) {
+		spin_lock_irqsave(&kt->key_lock, flags);
+		rc_do_keyup(kt, true);
+		spin_unlock_irqrestore(&kt->key_lock, flags);
+	}
+	rcu_read_unlock();
 }
+EXPORT_SYMBOL_GPL(rc_keyup);
 
 /**
  * rc_timer_keyup() - generates a keyup event after a timeout
@@ -634,23 +640,31 @@ static void rc_timer_keyup(unsigned long cookie)
 }
 
 /**
- * rc_keytable_repeat() - signals that a key is still pressed
- * @kt:		the keytable
+ * rc_repeat() - signals that a key is still pressed
+ * @dev:	the struct rc_dev descriptor of the device
  *
  * This routine is used when a repeat message which does not include the
  * necessary bits to reproduce the scancode has been received.
  */
-void rc_keytable_repeat(struct rc_keytable *kt)
+void rc_repeat(struct rc_dev *dev)
 {
+	struct rc_keytable *kt;
 	unsigned long flags;
 
-	spin_lock_irqsave(&kt->key_lock, flags);
-	if (kt->key_pressed) {
-		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
-		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node) {
+		spin_lock_irqsave(&kt->key_lock, flags);
+		if (kt->key_pressed) {
+			kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
+			mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+		}
+		spin_unlock_irqrestore(&kt->key_lock, flags);
 	}
-	spin_unlock_irqrestore(&kt->key_lock, flags);
+	rcu_read_unlock();
+
+	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
 }
+EXPORT_SYMBOL_GPL(rc_repeat);
 
 /**
  * rc_keytable_keydown() - generates input event for a key press
@@ -663,8 +677,8 @@ void rc_keytable_repeat(struct rc_keytable *kt)
  *
  * This routine is used to signal that a keypress has been detected.
  */
-void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
-			 u32 scancode, u8 toggle, bool autoup)
+static void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+				u32 scancode, u8 toggle, bool autoup)
 {
 	struct rc_scan *scan;
 	unsigned index;
@@ -711,6 +725,34 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
 	spin_unlock_irqrestore(&kt->key_lock, flags);
 }
 
+/**
+ * rc_do_keydown() - report a key press event
+ * @dev:	the struct rc_dev descriptor of the device
+ * @protocol:	the protocol for the keypress
+ * @scancode:	the scancode for the keypress
+ * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
+ *		support toggle values, this should be set to zero)
+ * @autoup:	whether to automatically generate a keyup event later
+ *
+ * Report that a keypress has been received.
+ */
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+		   u32 scancode, u8 toggle, bool autoup)
+{
+	struct rc_keytable *kt;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+		rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
+	rcu_read_unlock();
+
+	led_trigger_event(led_feedback, LED_FULL);
+	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
+}
+EXPORT_SYMBOL_GPL(rc_do_keydown);
+
 static int rc_input_open(struct input_dev *idev)
 {
 	struct rc_keytable *kt = input_get_drvdata(idev);
@@ -762,33 +804,65 @@ static int rc_keytable_init(struct rc_keytable *kt,
 }
 
 /**
- * rc_keytable_create() - create a new keytable
+ * rc_keytable_get_name() - get the name of a keytable
+ * @dev:
+ * @dev:       the struct rc_dev device the keytable belongs to
+ * @i:         the index of the keytable
+ * @buf:       the buffer to write the name to
+ * @bufsize:   the size of the buffer
+ * @return:    zero on success or negative error code
+ *
+ * This function is used to get the userfriendly name of a keytable.
+ */
+int rc_keytable_get_name(struct rc_dev *dev, unsigned i,
+			 char *buf, size_t bufsize)
+{
+	struct rc_keytable *kt;
+
+	rcu_read_lock();
+	kt = rcu_dereference(dev->keytables[i]);
+	if (kt) {
+		buf[0] = '\0';
+		strncat(buf, kt->name, bufsize);
+	}
+	rcu_read_unlock();
+
+	return kt ? 0 : -EINVAL;
+}
+
+/**
+ * rc_keytable_add() - create a new keytable
  * @dev:	the struct rc_dev device this keytable should belong to
  * @name:	the userfriendly name of this keymap
- * @rc_map:	the keymap to use for the new keytable
- * @return:	zero on success or a negative error code
+ * @rc_map:	the keymap to use for the new keytable (if any)
+ * @return:	the index of the new rc_keytable or a negative error code
  *
  * This function creates a new keytable (essentially the combination of a
  * keytable and an input device along with some state (whether a key is
  * currently pressed or not, etc).
  */
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
-				       struct rc_map *rc_map)
+int rc_keytable_add(struct rc_dev *dev, const char *name, struct rc_map *rc_map)
 {
 	struct rc_keytable *kt;
+	unsigned i;
 	struct input_dev *idev = NULL;
 	int err;
 
+	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+		if (!dev->keytables[i])
+			break;
+
+	if (i >= ARRAY_SIZE(dev->keytables))
+		return -ENFILE;
+
 	kt = kzalloc(sizeof(*kt), GFP_KERNEL);
-	if (!kt) {
-		err = -ENOMEM;
-		goto out;
-	}
+	if (!kt)
+		return -ENOMEM;
 
 	idev = input_allocate_device();
 	if (!idev) {
 		err = -ENOMEM;
-		goto out;
+		goto out_kt;
 	}
 
 	kt->idev = idev;
@@ -807,7 +881,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 
 	err = rc_keytable_init(kt, rc_map);
 	if (err)
-		goto out;
+		goto out_idev;
 
 	idev->dev.parent = &dev->dev;
 	memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id));
@@ -816,7 +890,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 
 	err = input_register_device(idev);
 	if (err)
-		goto out;
+		goto out_scan;
 
 	/*
 	 * Default delay of 250ms is too short for some protocols, especially
@@ -833,29 +907,52 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
 	 */
 	idev->rep[REP_PERIOD] = 125;
 
-	return kt;
+	rcu_assign_pointer(dev->keytables[i], kt);
+	list_add_rcu(&kt->node, &dev->keytable_list);
+	synchronize_rcu();
+	rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
 
-out:
-	input_free_device(idev);
+	return i;
+
+out_scan:
 	kfree(kt->scan);
+out_idev:
+	input_free_device(idev);
+out_kt:
 	kfree(kt);
-	return ERR_PTR(err);
+	return err;
 }
 
 /**
  * rc_keytable_del() - unregisters and frees a keytable
- * @kt:		the struct rc_keytable to destroy
+ * @dev:       the struct rc_dev device the keytable belongs to
+ * @i:         the index of the keytable
+ * @return:    zero on success or negative error number
  *
  * This function unregisters and deletes an existing keytable.
  */
-void rc_keytable_destroy(struct rc_keytable *kt)
+int rc_keytable_del(struct rc_dev *dev, unsigned i)
 {
+	struct rc_keytable *kt;
+
+	if (i >= ARRAY_SIZE(dev->keytables))
+		return -EINVAL;
+
+	kt = dev->keytables[i];
+	rcu_assign_pointer(dev->keytables[i], NULL);
+	if (kt)
+		list_del_rcu(&kt->node);
+	synchronize_rcu();
+
 	if (!kt)
-		return;
+		return -EINVAL;
 
+	rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
 	del_timer_sync(&kt->timer_keyup);
 	input_unregister_device(kt->idev);
 	kfree(kt->scan);
 	kfree(kt);
+
+	return 0;
 }
 
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b3db1dd..12f61ae 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -136,116 +136,6 @@ void rc_close(struct rc_dev *dev)
 }
 EXPORT_SYMBOL_GPL(rc_close);
 
-/**
- * rc_do_keydown() - report a key press event
- * @dev:	the struct rc_dev descriptor of the device
- * @protocol:	the protocol for the keypress
- * @scancode:	the scancode for the keypress
- * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
- *		support toggle values, this should be set to zero)
- * @autoup:	whether to automatically generate a keyup event later
- *
- * Report that a keypress has been received.
- */
-void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
-		   u32 scancode, u8 toggle, bool autoup)
-{
-	struct rc_keytable *kt;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
-		rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
-	rcu_read_unlock();
-
-	led_trigger_event(led_feedback, LED_FULL);
-	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
-	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
-	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
-}
-EXPORT_SYMBOL_GPL(rc_do_keydown);
-
-/**
- * rc_keyup() - signals the release of a keypress
- * @dev:       the struct rc_dev descriptor of the device
- *
- * Report that a key is no longer pressed.
- */
-void rc_keyup(struct rc_dev *dev)
-{
-	struct rc_keytable *kt;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
-		rc_keytable_keyup(kt);
-	rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(rc_keyup);
-
-/**
- * rc_repeat() - report that a key is still pressed
- * @dev:	the struct rc_dev descriptor of the device
- *
- * Report that a repeat message (which does not include the necessary bits to
- * reproduce the scancode) has been received.
- */
-void rc_repeat(struct rc_dev *dev)
-{
-	struct rc_keytable *kt;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(kt, &dev->keytable_list, node)
-		rc_keytable_repeat(kt);
-	rcu_read_unlock();
-
-	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
-}
-EXPORT_SYMBOL_GPL(rc_repeat);
-
-static int rc_add_keytable(struct rc_dev *dev, const char *name,
-			   struct rc_map *rc_map)
-{
-	struct rc_keytable *kt;
-	unsigned i;
-
-	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
-		if (!dev->keytables[i])
-			break;
-
-	if (i >= ARRAY_SIZE(dev->keytables))
-		return -ENFILE;
-
-	kt = rc_keytable_create(dev, name, rc_map);
-	if (IS_ERR(kt))
-		return PTR_ERR(kt);
-
-	rcu_assign_pointer(dev->keytables[i], kt);
-	list_add_rcu(&kt->node, &dev->keytable_list);
-	synchronize_rcu();
-	rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
-	return 0;
-}
-
-static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
-{
-	struct rc_keytable *kt;
-
-	if (i >= ARRAY_SIZE(dev->keytables))
-		return -EINVAL;
-
-	kt = dev->keytables[i];
-	rcu_assign_pointer(dev->keytables[i], NULL);
-	if (kt)
-		list_del_rcu(&kt->node);
-	synchronize_rcu();
-
-	if (!kt)
-		return -EINVAL;
-
-	rc_keytable_destroy(kt);
-	rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
-	return 0;
-}
-
 /* class for /sys/class/rc */
 static char *rc_devnode(struct device *dev, umode_t *mode)
 {
@@ -943,7 +833,6 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 	struct rc_ir_rx rx;
 	struct rc_ir_tx tx;
 	struct rc_keytable_ioctl ktio;
-	struct rc_keytable *kt;
 	int error;
 
 	switch (cmd) {
@@ -1020,7 +909,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 		if (strlen(ktio.name) < 1)
 			return -EINVAL;
 
-		error = rc_add_keytable(dev, ktio.name, NULL);
+		error = rc_keytable_add(dev, ktio.name, NULL);
 		if (error < 0)
 			return error;
 		ktio.id = error;
@@ -1040,16 +929,10 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 		if (ktio.flags)
 			return -EINVAL;
 
-		rcu_read_lock();
-		kt = rcu_dereference(dev->keytables[ktio.id]);
-		if (kt) {
-			ktio.name[0] = '\0';
-			strncat(ktio.name, kt->name, sizeof(ktio.name));
-		}
-		rcu_read_unlock();
-
-		if (!kt)
-			return -EINVAL;
+		error = rc_keytable_get_name(dev, ktio.id,
+					     ktio.name, sizeof(ktio.name));
+		if (error)
+			return error;
 
 		if (copy_to_user(p, &ktio, sizeof(ktio)))
 			return -EFAULT;
@@ -1066,7 +949,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
 		if (ktio.flags)
 			return -EINVAL;
 
-		return rc_remove_keytable(dev, ktio.id);
+		return rc_keytable_del(dev, ktio.id);
 	}
 	return -EINVAL;
 }
@@ -1295,6 +1178,7 @@ int rc_register_device(struct rc_dev *dev)
 	if (dev->map_name)
 		rc_map = rc_map_get(dev->map_name);
 
+	/* FIXME: kind of a hack...the driver should probably do this */
 	if (dev->change_protocol && rc_map && rc_map->len > 0) {
 		u64 rc_type = (1 << rc_map->scan[0].protocol);
 		rc = dev->change_protocol(dev, &rc_type);
@@ -1311,8 +1195,8 @@ int rc_register_device(struct rc_dev *dev)
 	if (rc)
 		goto out_cdev;
 
-	rc = rc_add_keytable(dev, dev->map_name, rc_map);
-	if (rc)
+	rc = rc_keytable_add(dev, dev->map_name, rc_map);
+	if (rc < 0)
 		goto out_dev;
 
 	IR_dprintk(1, "Registered %s (driver: %s, remote: %s, mode %s)\n",
@@ -1355,7 +1239,7 @@ void rc_unregister_device(struct rc_dev *dev)
 	cdev_del(&dev->cdev);
 
 	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
-		rc_remove_keytable(dev, i);
+		rc_keytable_del(dev, i);
 
 	/* dev is marked as dead so no one changes dev->users */
 	if (dev->users && dev->close)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index a7354b7..aff3bdd 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -383,50 +383,6 @@ struct rc_dev {
 	int				(*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 };
 
-/**
- * struct rc_scan - rcu-friendly scancode<->keycode table
- * @len:	number of elements in the table array
- * @table:	array of struct rc_map_table elements
- */
-struct rc_scan {
-	unsigned len;
-	struct rc_map_table table[];
-};
-
-/**
- * struct rc_keytable - represents one keytable for a rc_dev device
- * @node:		used to iterate over all keytables for a rc_dev device
- * @dev:		the rc_dev device this keytable belongs to
- * @idev:		the input_dev device which belongs to this keytable
- * @name:		the user-friendly name of this keytable
- * @scan_mutex:		protects @scan against concurrent writers
- * @scan:		the current scancode<->keycode table
- * @key_lock:		protects the key state
- * @key_pressed:	whether a key is currently pressed or not
- * @last_keycode:	keycode of the last keypress
- * @last_protocol:	protocol of the last keypress
- * @last_scancode:	scancode of the last keypress
- * @last_toggle:	toggle of the last keypress
- * @timer_keyup:	responsible for the auto-release of keys
- * @keyup_jiffies:	when the key should be auto-released
- */
-struct rc_keytable {
-	struct list_head		node;
-	struct rc_dev			*dev;
-	struct input_dev		*idev;
-	char				name[RC_KEYTABLE_NAME_SIZE];
-	struct mutex			scan_mutex;
-	struct rc_scan __rcu		*scan;
-	spinlock_t			key_lock;
-	bool				key_pressed;
-	u32				last_keycode;
-	enum rc_type			last_protocol;
-	u32				last_scancode;
-	u8				last_toggle;
-	struct timer_list		timer_keyup;
-	unsigned long			keyup_jiffies;
-};
-
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
 
 /*


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

* [PATCH 49/49] rc-core: make rc-core.h userspace friendly
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (47 preceding siblings ...)
  2014-04-03 23:35 ` [PATCH 48/49] rc-core: move remaining keytable functions David Härdeman
@ 2014-04-03 23:35 ` David Härdeman
  2014-04-04  2:05 ` [PATCH 00/49] rc-core: my current patch queue Mauro Carvalho Chehab
  2014-06-26 20:07 ` David Härdeman
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-04-03 23:35 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

A few ifdef __KERNEL__ and some reorganisation to make rc-core.h usable from
userspace programs. A split into include/uapi/ might be a good idea later.

Signed-off-by: David Härdeman <david@hardeman.nu>
---
 include/media/rc-core.h |   71 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index aff3bdd..caa159f 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -16,21 +16,22 @@
 #ifndef _RC_CORE
 #define _RC_CORE
 
+#ifdef __KERNEL__
 #include <linux/spinlock.h>
 #include <linux/kfifo.h>
 #include <linux/time.h>
 #include <linux/timer.h>
 #include <linux/cdev.h>
 #include <media/rc-map.h>
+#else
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#endif
 
-extern int rc_core_debug;
-#define IR_dprintk(level, fmt, ...)				\
-do {								\
-	if (rc_core_debug >= level)				\
-		pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);	\
-} while (0)
-
-#define RC_VERSION 0x010000
+#define RC_VERSION		0x010000
+#define RC_MAX_KEYTABLES	32
 
 /*
  * ioctl definitions
@@ -177,13 +178,27 @@ struct rc_keytable_ioctl {
 	char name[RC_KEYTABLE_NAME_SIZE];
 } __packed;
 
-/* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
+/**
+ * struct rc_scancode - protocol/scancode pair
+ * @protocol:	the protocol of the rc command
+ * @reserved:	for future use and padding, set to zero
+ * @scancode:	the scancode of the command
+ */
 struct rc_scancode {
 	__u16 protocol;
 	__u16 reserved[3];
 	__u64 scancode;
 };
 
+/**
+ * struct rc_keymap_entry - used in EVIOC[SG]KEYCODE_V2 ioctls
+ * @flags:	see &struct input_keymap_entry
+ * @len:	see &struct input_keymap_entry
+ * @index:	see &struct input_keymap_entry
+ * @keycode:	see &struct input_keymap_entry
+ * @rc:		the scancode/protocol definition, see &struct rc_scancode
+ * @raw:	alternative representation of @rc
+ */
 struct rc_keymap_entry {
 	__u8  flags;
 	__u8  len;
@@ -236,6 +251,9 @@ struct rc_event {
 
 #define RC_TX_KFIFO_SIZE	1024
 
+#ifdef __KERNEL__
+/* The rest is implementational details which shouldn't concern userspace */
+
 /**
  * struct rc_scancode_filter - Filter scan codes.
  * @data:	Scancode data to match.
@@ -323,7 +341,6 @@ enum rc_filter_type {
  * @get_ir_tx: allow driver to provide tx settings
  * @set_ir_tx: allow driver to change tx settings
  */
-#define RC_MAX_KEYTABLES		32
 struct rc_dev {
 	struct device			dev;
 	struct cdev			cdev;
@@ -382,31 +399,23 @@ struct rc_dev {
 	void				(*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 	int				(*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
 };
-
 #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
 
-/*
- * From rc-main.c
- * Those functions can be used on any type of Remote Controller. They
- * basically creates an input_dev and properly reports the device as a
- * Remote Controller, at sys/class/rc.
- */
-
+/* From rc-main.c - see inline kerneldoc */
 struct rc_dev *rc_allocate_device(void);
 void rc_free_device(struct rc_dev *dev);
 int rc_register_device(struct rc_dev *dev);
 void rc_unregister_device(struct rc_dev *dev);
 void rc_event(struct rc_dev *dev, u16 type, u16 code, u32 val);
-
 int rc_open(struct rc_dev *rdev);
 void rc_close(struct rc_dev *rdev);
 
+/* From rc-keytable.c - see inline kerneldoc */
 void rc_repeat(struct rc_dev *dev);
-void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
-		   u32 scancode, u8 toggle, bool autoup);
 void rc_keyup(struct rc_dev *dev);
 u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
-
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+		   u32 scancode, u8 toggle, bool autoup);
 static inline void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) {
 	rc_do_keydown(dev, protocol, scancode, toggle, true);
 }
@@ -415,7 +424,22 @@ static inline void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protoco
 	rc_do_keydown(dev, protocol, scancode, toggle, false);
 }
 
-/* extract mask bits out of data and pack them into the result */
+extern int rc_core_debug;
+#define IR_dprintk(level, fmt, ...)				\
+do {								\
+	if (rc_core_debug >= level)				\
+		pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);	\
+} while (0)
+
+/**
+ * ir_extract_bits() - extract bits of data according to a mask
+ * @data:	the data to extract bits from
+ * @mask:	the mask of bits to extract
+ * @return:	the extracted bits packed together
+ *
+ * This helper function is used by some drivers to extract the relevant
+ * (masked) bits of data.
+ */
 static inline u32 ir_extract_bits(u32 data, u32 mask)
 {
 	u32 vbit = 1, value = 0;
@@ -432,4 +456,5 @@ static inline u32 ir_extract_bits(u32 data, u32 mask)
 	return value;
 }
 
+#endif /* __KERNEL__ */
 #endif /* _RC_CORE */


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

* Re: [PATCH 00/49] rc-core: my current patch queue
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (48 preceding siblings ...)
  2014-04-03 23:35 ` [PATCH 49/49] rc-core: make rc-core.h userspace friendly David Härdeman
@ 2014-04-04  2:05 ` Mauro Carvalho Chehab
  2014-06-26 20:07 ` David Härdeman
  50 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-04-04  2:05 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media, James Hogan

Em Fri, 04 Apr 2014 01:31:15 +0200
David Härdeman <david@hardeman.nu> escreveu:

> The following patches is what I currenly have in my queue:
> 
> Patches 1 - 6 should be ok to be committed right now, they contain
> some fixes and some reverts (of the NEC32 and generic scancode
> functionality).

I did just a very quick look in this series, so my comments
here are subject to changes.

Patch 4 is obviously OK for 3.15, as it fixes a regression.

With regards to patch 6, yes, if we need to change the API,
it should be sent for 3.15, before becoming too late.
Of course, if we change it, we'll also need to patch the
DocBook and the sysfs ABI descriptions accordingly.
I'll review it carefully latter.

The patches that touch on img-ir (patch 5) can also be applied
during -rc, as this is a new driver. So, no regressions. Of
course, we need James ack on such changes.

It sounds likely too late for the other patches for 3.15
(patches 1, 2 and 3), as they're not so obvious, and
some may require tests on those devices they're supposing
to fix.

> Patches 7 - 9 are in no hurry and can wait for 3.16, some testing
> would be nice even though I believe they are ok.
> 
> Patches 10 and 11 are RFC's for the NEC32 scancode handling.
> 
> The remaining patches are more of an FYI. It's basically the same
> patchset that I've posted a long time ago, but respun to apply to
> the current tree. They implement a modern chardev for rc-core which
> allows the functionality that has so far only been available through
> the LIRC bridge to be exposed to userspace and provide a (hopefully)
> sane API for taking advantage of all the features that rc-core
> provides (RX, TX, ioctl) as well as some new features (multiple
> keymaps is probably the most important one). Lots and lots of cleanups
> as well.

Ok, I'll review the remaining patches after the merge window.

> 
> Enjoy :)

Thanks!
> 
> ---
> 
> David Härdeman (49):
>       bt8xx: fixup RC5 decoding
>       rc-core: improve ir-kbd-i2c get_key functions
>       rc-core: document the protocol type
>       rc-core: do not change 32bit NEC scancode format for now
>       rc-core: split dev->s_filter
>       rc-core: remove generic scancode filter
>       dib0700: NEC scancode cleanup
>       lmedm04: NEC scancode cleanup
>       saa7134: NEC scancode fix
>       [RFC] rc-core: use the full 32 bits for NEC scancodes
>       [RFC] rc-core: don't throw away protocol information
>       rc-core: simplify sysfs code
>       rc-core: remove protocol arrays
>       rc-core: rename dev->scanmask to dev->scancode_mask
>       rc-core: merge rc5 and streamzap decoders
>       rc-core: use an IDA rather than a bitmap
>       rc-core: add chardev
>       rc-core: allow chardev to be read
>       rc-core: use a kfifo for TX data
>       rc-core: allow chardev to be written
>       rc-core: add ioctl support to the rc chardev
>       rc-core: add an ioctl for getting IR RX settings
>       rc-loopback: add RCIOCGIRRX ioctl support
>       rc-core: add an ioctl for setting IR RX settings
>       rc-loopback: add RCIOCSIRRX ioctl support
>       rc-core: add an ioctl for getting IR TX settings
>       rc-loopback: add RCIOCGIRTX ioctl support
>       rc-core: add an ioctl for setting IR TX settings
>       rc-loopback: add RCIOCSIRTX ioctl support
>       rc-core: leave the internals of rc_dev alone
>       rc-core: split rc-main.c into rc-main.c and rc-keytable.c
>       rc-core: prepare for multiple keytables
>       rc-core: make the keytable of rc_dev an array
>       rc-core: add ioctls for adding/removing keytables from userspace
>       rc-core: remove redundant spinlock
>       rc-core: make keytable RCU-friendly
>       rc-core: allow empty keymaps
>       rc-core: rename ir-raw.c
>       rc-core: make IR raw handling a separate module
>       rc-ir-raw: simplify locking
>       rc-core: rename mutex
>       rc-ir-raw: atomic reads of protocols
>       rc-core: fix various sparse warnings
>       rc-core: don't report scancodes via input devices
>       rc-ir-raw: add various rc_events
>       rc-core: use struct rc_event for all rc communication
>       rc-core: add keytable events
>       rc-core: move remaining keytable functions
>       rc-core: make rc-core.h userspace friendly
> 
> 
>  Documentation/ioctl/ioctl-number.txt        |    1 
>  drivers/hid/hid-picolcd_cir.c               |   20 
>  drivers/media/common/siano/smsir.c          |   14 
>  drivers/media/common/siano/smsir.h          |    2 
>  drivers/media/i2c/cx25840/cx25840-ir.c      |   96 +
>  drivers/media/i2c/ir-kbd-i2c.c              |   99 +
>  drivers/media/pci/bt8xx/bttv-input.c        |   78 +
>  drivers/media/pci/bt8xx/bttvp.h             |    2 
>  drivers/media/pci/cx23885/cx23885-input.c   |   26 
>  drivers/media/pci/cx23885/cx23888-ir.c      |   93 +
>  drivers/media/pci/cx88/cx88-input.c         |   75 +
>  drivers/media/pci/dm1105/dm1105.c           |    4 
>  drivers/media/pci/ivtv/ivtv-i2c.c           |   11 
>  drivers/media/pci/saa7134/saa7134-input.c   |  100 +
>  drivers/media/pci/saa7134/saa7134.h         |    2 
>  drivers/media/pci/ttpci/budget-ci.c         |   10 
>  drivers/media/rc/Kconfig                    |   12 
>  drivers/media/rc/Makefile                   |    4 
>  drivers/media/rc/ati_remote.c               |   11 
>  drivers/media/rc/ene_ir.c                   |   84 +
>  drivers/media/rc/ene_ir.h                   |    9 
>  drivers/media/rc/fintek-cir.c               |   34 
>  drivers/media/rc/gpio-ir-recv.c             |   15 
>  drivers/media/rc/iguanair.c                 |   77 +
>  drivers/media/rc/img-ir/img-ir-hw.c         |   48 -
>  drivers/media/rc/img-ir/img-ir-hw.h         |    3 
>  drivers/media/rc/img-ir/img-ir-jvc.c        |    4 
>  drivers/media/rc/img-ir/img-ir-nec.c        |   80 -
>  drivers/media/rc/img-ir/img-ir-raw.c        |    8 
>  drivers/media/rc/img-ir/img-ir-sanyo.c      |    4 
>  drivers/media/rc/img-ir/img-ir-sharp.c      |    4 
>  drivers/media/rc/img-ir/img-ir-sony.c       |   12 
>  drivers/media/rc/imon.c                     |   33 
>  drivers/media/rc/ir-jvc-decoder.c           |   52 -
>  drivers/media/rc/ir-lirc-codec.c            |  225 ++-
>  drivers/media/rc/ir-mce_kbd-decoder.c       |   36 
>  drivers/media/rc/ir-nec-decoder.c           |   96 -
>  drivers/media/rc/ir-rc5-decoder.c           |  113 +-
>  drivers/media/rc/ir-rc5-sz-decoder.c        |  154 --
>  drivers/media/rc/ir-rc6-decoder.c           |   91 +
>  drivers/media/rc/ir-sanyo-decoder.c         |   60 -
>  drivers/media/rc/ir-sharp-decoder.c         |   53 -
>  drivers/media/rc/ir-sony-decoder.c          |   58 -
>  drivers/media/rc/ite-cir.c                  |   69 -
>  drivers/media/rc/ite-cir.h                  |    2 
>  drivers/media/rc/keymaps/rc-behold.c        |   68 -
>  drivers/media/rc/keymaps/rc-lme2510.c       |  132 +-
>  drivers/media/rc/keymaps/rc-nebula.c        |  112 +-
>  drivers/media/rc/keymaps/rc-streamzap.c     |    4 
>  drivers/media/rc/keymaps/rc-tivo.c          |   95 +
>  drivers/media/rc/mceusb.c                   |   67 +
>  drivers/media/rc/nuvoton-cir.c              |   88 +
>  drivers/media/rc/nuvoton-cir.h              |    9 
>  drivers/media/rc/rc-core-priv.h             |  122 +-
>  drivers/media/rc/rc-ir-raw.c                |  284 ++--
>  drivers/media/rc/rc-keytable.c              |  958 +++++++++++++
>  drivers/media/rc/rc-loopback.c              |  200 ++-
>  drivers/media/rc/rc-main.c                  | 1974 ++++++++++++---------------
>  drivers/media/rc/redrat3.c                  |  156 +-
>  drivers/media/rc/st_rc.c                    |    2 
>  drivers/media/rc/streamzap.c                |   81 -
>  drivers/media/rc/ttusbir.c                  |   42 -
>  drivers/media/rc/winbond-cir.c              |  113 +-
>  drivers/media/usb/cx231xx/cx231xx-input.c   |   31 
>  drivers/media/usb/dvb-usb-v2/af9015.c       |   26 
>  drivers/media/usb/dvb-usb-v2/af9035.c       |   20 
>  drivers/media/usb/dvb-usb-v2/anysee.c       |    3 
>  drivers/media/usb/dvb-usb-v2/az6007.c       |   21 
>  drivers/media/usb/dvb-usb-v2/dvb_usb.h      |    5 
>  drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |   14 
>  drivers/media/usb/dvb-usb-v2/lmedm04.c      |   22 
>  drivers/media/usb/dvb-usb-v2/rtl28xxu.c     |   30 
>  drivers/media/usb/dvb-usb/dib0700_core.c    |   39 -
>  drivers/media/usb/dvb-usb/dib0700_devices.c |   24 
>  drivers/media/usb/dvb-usb/dvb-usb-remote.c  |   15 
>  drivers/media/usb/dvb-usb/dvb-usb.h         |    5 
>  drivers/media/usb/dvb-usb/dw2102.c          |    7 
>  drivers/media/usb/dvb-usb/m920x.c           |    2 
>  drivers/media/usb/dvb-usb/pctv452e.c        |    8 
>  drivers/media/usb/dvb-usb/technisat-usb2.c  |   17 
>  drivers/media/usb/dvb-usb/ttusb2.c          |    6 
>  drivers/media/usb/em28xx/em28xx-cards.c     |    1 
>  drivers/media/usb/em28xx/em28xx-input.c     |  111 +-
>  drivers/media/usb/tm6000/tm6000-input.c     |   60 +
>  include/media/ir-kbd-i2c.h                  |    6 
>  include/media/rc-core.h                     |  473 ++++--
>  include/media/rc-ir-raw.h                   |   68 +
>  include/media/rc-map.h                      |   28 
>  88 files changed, 4344 insertions(+), 3289 deletions(-)
>  delete mode 100644 drivers/media/rc/ir-rc5-sz-decoder.c
>  rename drivers/media/rc/{ir-raw.c => rc-ir-raw.c} (52%)
>  create mode 100644 drivers/media/rc/rc-keytable.c
>  create mode 100644 include/media/rc-ir-raw.h
> 
> --
> David Härdeman
> 


-- 

Regards,
Mauro

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

* Re: [PATCH 05/49] rc-core: split dev->s_filter
  2014-04-03 23:31 ` [PATCH 05/49] rc-core: split dev->s_filter David Härdeman
@ 2014-04-04 13:08   ` James Hogan
  0 siblings, 0 replies; 68+ messages in thread
From: James Hogan @ 2014-04-04 13:08 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media, Mauro Carvalho Chehab, James Hogan

Hi David,

On 4 April 2014 00:31, David Härdeman <david@hardeman.nu> wrote:
> Overloading dev->s_filter to do two different functions (set wakeup filters
> and generic hardware filters) makes it impossible to tell what the
> hardware actually supports, so create a separate dev->s_wakeup_filter and
> make the distinction explicit.
>
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/img-ir/img-ir-hw.c |   15 ++++++++++++++-

I think we crossed emails. My comments on your earlier submission of
this patch about the removal of generic scancode filter code that has
crept in to the patch apply here too (sorry I didn't spot that when I
first looked at it!).

But if you fix that you're welcome to my:
Acked-by: James Hogan <james.hogan@imgtec.com>

Cheers
James

>  drivers/media/rc/rc-main.c          |   31 +++++++++++++++++++------------
>  include/media/rc-core.h             |    6 ++++--
>  3 files changed, 37 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
> index aec79f7..871a9b3 100644
> --- a/drivers/media/rc/img-ir/img-ir-hw.c
> +++ b/drivers/media/rc/img-ir/img-ir-hw.c
> @@ -504,6 +504,18 @@ unlock:
>         return ret;
>  }
>
> +static int img_ir_set_normal_filter(struct rc_dev *dev,
> +                                   struct rc_scancode_filter *sc_filter)
> +{
> +       return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter);
> +}
> +
> +static int img_ir_set_wakeup_filter(struct rc_dev *dev,
> +                                   struct rc_scancode_filter *sc_filter)
> +{
> +       return img_ir_set_filter(dev, RC_FILTER_WAKEUP, sc_filter);
> +}
> +
>  /**
>   * img_ir_set_decoder() - Set the current decoder.
>   * @priv:      IR private data.
> @@ -988,7 +1000,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
>         rdev->map_name = RC_MAP_EMPTY;
>         rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv));
>         rdev->input_name = "IMG Infrared Decoder";
> -       rdev->s_filter = img_ir_set_filter;
> +       rdev->s_filter = img_ir_set_normal_filter;
> +       rdev->s_wakeup_filter = img_ir_set_wakeup_filter;
>
>         /* Register hardware decoder */
>         error = rc_register_device(rdev);
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index c0bfd50..ba955ac 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -929,6 +929,7 @@ static ssize_t store_protocols(struct device *device,
>         int rc, i, count = 0;
>         ssize_t ret;
>         int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
> +       int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
>         struct rc_scancode_filter local_filter, *filter;
>
>         /* Device is being removed */
> @@ -1013,24 +1014,27 @@ static ssize_t store_protocols(struct device *device,
>          * Fall back to clearing the filter.
>          */
>         filter = &dev->scancode_filters[fattr->type];
> +       set_filter = (fattr->type == RC_FILTER_NORMAL)
> +               ? dev->s_filter : dev->s_wakeup_filter;
> +
>         if (old_type != type && filter->mask) {
>                 local_filter = *filter;
>                 if (!type) {
>                         /* no protocol => clear filter */
>                         ret = -1;
> -               } else if (!dev->s_filter) {
> +               } else if (!set_filter) {
>                         /* generic filtering => accept any filter */
>                         ret = 0;
>                 } else {
>                         /* hardware filtering => try setting, otherwise clear */
> -                       ret = dev->s_filter(dev, fattr->type, &local_filter);
> +                       ret = set_filter(dev, &local_filter);
>                 }
>                 if (ret < 0) {
>                         /* clear the filter */
>                         local_filter.data = 0;
>                         local_filter.mask = 0;
> -                       if (dev->s_filter)
> -                               dev->s_filter(dev, fattr->type, &local_filter);
> +                       if (set_filter)
> +                               set_filter(dev, &local_filter);
>                 }
>
>                 /* commit the new filter */
> @@ -1112,6 +1116,7 @@ static ssize_t store_filter(struct device *device,
>         struct rc_scancode_filter local_filter, *filter;
>         int ret;
>         unsigned long val;
> +       int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
>
>         /* Device is being removed */
>         if (!dev)
> @@ -1121,9 +1126,11 @@ static ssize_t store_filter(struct device *device,
>         if (ret < 0)
>                 return ret;
>
> -       /* Scancode filter not supported (but still accept 0) */
> -       if (!dev->s_filter && fattr->type != RC_FILTER_NORMAL)
> -               return val ? -EINVAL : count;
> +       /* Can the scancode filter be set? */
> +       set_filter = (fattr->type == RC_FILTER_NORMAL)
> +               ? dev->s_filter : dev->s_wakeup_filter;
> +       if (!set_filter)
> +               return -EINVAL;
>
>         mutex_lock(&dev->lock);
>
> @@ -1134,16 +1141,16 @@ static ssize_t store_filter(struct device *device,
>                 local_filter.mask = val;
>         else
>                 local_filter.data = val;
> +
>         if (!dev->enabled_protocols[fattr->type] && local_filter.mask) {
>                 /* refuse to set a filter unless a protocol is enabled */
>                 ret = -EINVAL;
>                 goto unlock;
>         }
> -       if (dev->s_filter) {
> -               ret = dev->s_filter(dev, fattr->type, &local_filter);
> -               if (ret < 0)
> -                       goto unlock;
> -       }
> +
> +       ret = set_filter(dev, &local_filter);
> +       if (ret < 0)
> +               goto unlock;
>
>         /* Success, commit the new filter */
>         *filter = local_filter;
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index dbbe63e..8c31e4a 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -113,7 +113,8 @@ enum rc_filter_type {
>   *     device doesn't interrupt host until it sees IR pulses
>   * @s_learning_mode: enable wide band receiver used for learning
>   * @s_carrier_report: enable carrier reports
> - * @s_filter: set the scancode filter of a given type
> + * @s_filter: set the scancode filter
> + * @s_wakeup_filter: set the wakeup scancode filter
>   */
>  struct rc_dev {
>         struct device                   dev;
> @@ -161,8 +162,9 @@ struct rc_dev {
>         int                             (*s_learning_mode)(struct rc_dev *dev, int enable);
>         int                             (*s_carrier_report) (struct rc_dev *dev, int enable);
>         int                             (*s_filter)(struct rc_dev *dev,
> -                                                   enum rc_filter_type type,
>                                                     struct rc_scancode_filter *filter);
> +       int                             (*s_wakeup_filter)(struct rc_dev *dev,
> +                                                          struct rc_scancode_filter *filter);
>  };
>
>  #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now
  2014-04-03 23:31 ` [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now David Härdeman
@ 2014-04-04 13:18   ` James Hogan
  0 siblings, 0 replies; 68+ messages in thread
From: James Hogan @ 2014-04-04 13:18 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media, Mauro Carvalho Chehab, James Hogan

Hi David,

On 4 April 2014 00:31, David Härdeman <david@hardeman.nu> wrote:
> diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
> index c0111d6..ee45795 100644
> --- a/drivers/media/rc/img-ir/img-ir-nec.c
> +++ b/drivers/media/rc/img-ir/img-ir-nec.c

>  /* Convert NEC data to a scancode */
>  static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
> @@ -23,11 +24,11 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
>         data_inv = (raw >> 24) & 0xff;
>         if ((data_inv ^ data) != 0xff) {
>                 /* 32-bit NEC (used by Apple and TiVo remotes) */
> -               /* scan encoding: aaAAddDD */
> -               *scancode = addr_inv << 24 |
> -                           addr     << 16 |
> -                           data_inv <<  8 |
> -                           data;
> +               /* scan encoding: AAaaDDdd (LSBit first) */

This scan encoding of NEC32 interprets the  raw data MSBit first (i.e.
the MSBit of scancode is the first bit received), so this comment is
wrong.

> +               *scancode = bitrev8(addr)     << 24 |
> +                           bitrev8(addr_inv) << 16 |
> +                           bitrev8(data)     <<  8 |
> +                           bitrev8(data_inv);
>         } else if ((addr_inv ^ addr) != 0xff) {
>                 /* Extended NEC */
>                 /* scan encoding: AAaaDD */
> @@ -56,13 +57,15 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
>
>         if ((in->data | in->mask) & 0xff000000) {
>                 /* 32-bit NEC (used by Apple and TiVo remotes) */
> -               /* scan encoding: aaAAddDD */
> -               addr_inv   = (in->data >> 24) & 0xff;
> -               addr_inv_m = (in->mask >> 24) & 0xff;
> -               addr       = (in->data >> 16) & 0xff;
> -               addr_m     = (in->mask >> 16) & 0xff;
> -               data_inv   = (in->data >>  8) & 0xff;
> -               data_inv_m = (in->mask >>  8) & 0xff;
> +               /* scan encoding: AAaaDDdd (LSBit first) */

same here

The actual code looks fine now though. If you fix those two comments:
Acked-by: James Hogan <james.hogan@imgtec.com>

Cheers
James

> +               addr       = bitrev8(in->data >> 24);
> +               addr_m     = bitrev8(in->mask >> 24);
> +               addr_inv   = bitrev8(in->data >> 16);
> +               addr_inv_m = bitrev8(in->mask >> 16);
> +               data       = bitrev8(in->data >>  8);
> +               data_m     = bitrev8(in->mask >>  8);
> +               data_inv   = bitrev8(in->data >>  0);
> +               data_inv_m = bitrev8(in->mask >>  0);
>         } else if ((in->data | in->mask) & 0x00ff0000) {
>                 /* Extended NEC */
>                 /* scan encoding AAaaDD */

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

* Re: [PATCH 06/49] rc-core: remove generic scancode filter
  2014-04-03 23:31 ` [PATCH 06/49] rc-core: remove generic scancode filter David Härdeman
@ 2014-04-04 13:30   ` James Hogan
  0 siblings, 0 replies; 68+ messages in thread
From: James Hogan @ 2014-04-04 13:30 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media, Mauro Carvalho Chehab, James Hogan

Hi David,

On 4 April 2014 00:31, David Härdeman <david@hardeman.nu> wrote:
> The generic scancode filtering has questionable value and makes it
> impossible to determine from userspace if there is an actual
> scancode hw filter present or not.
>
> So revert the generic parts.

I've already mentioned in a different email that reverting the last
two hunks of b8c7d915087c97a21fa415fa0e860e59739da202 should be in
this patch rather than combined into patch 5.

But if you fix that you're welcome to my:
Reviewed-by: James Hogan <james.hogan@imgtec.com>

Thanks
James

>
> Based on a patch from James Hogan <james.hogan@imgtec.com>, but this
> version also makes sure that only the valid sysfs files are created
> in the first place.
>
> v2: correct dev->s_filter check
>
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-main.c |   67 +++++++++++++++++++++++++++++---------------
>  include/media/rc-core.h    |    2 +
>  2 files changed, 46 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index ba955ac..26c266b 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -634,7 +634,6 @@ EXPORT_SYMBOL_GPL(rc_repeat);
>  static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
>                           u32 scancode, u32 keycode, u8 toggle)
>  {
> -       struct rc_scancode_filter *filter;
>         bool new_event = (!dev->keypressed               ||
>                           dev->last_protocol != protocol ||
>                           dev->last_scancode != scancode ||
> @@ -643,11 +642,6 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
>         if (new_event && dev->keypressed)
>                 ir_do_keyup(dev, false);
>
> -       /* Generic scancode filtering */
> -       filter = &dev->scancode_filters[RC_FILTER_NORMAL];
> -       if (filter->mask && ((scancode ^ filter->data) & filter->mask))
> -               return;
> -
>         input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
>
>         if (new_event && keycode != KEY_RESERVED) {
> @@ -1017,14 +1011,11 @@ static ssize_t store_protocols(struct device *device,
>         set_filter = (fattr->type == RC_FILTER_NORMAL)
>                 ? dev->s_filter : dev->s_wakeup_filter;
>
> -       if (old_type != type && filter->mask) {
> +       if (set_filter && old_type != type && filter->mask) {
>                 local_filter = *filter;
>                 if (!type) {
>                         /* no protocol => clear filter */
>                         ret = -1;
> -               } else if (!set_filter) {
> -                       /* generic filtering => accept any filter */
> -                       ret = 0;
>                 } else {
>                         /* hardware filtering => try setting, otherwise clear */
>                         ret = set_filter(dev, &local_filter);
> @@ -1033,8 +1024,7 @@ static ssize_t store_protocols(struct device *device,
>                         /* clear the filter */
>                         local_filter.data = 0;
>                         local_filter.mask = 0;
> -                       if (set_filter)
> -                               set_filter(dev, &local_filter);
> +                       set_filter(dev, &local_filter);
>                 }
>
>                 /* commit the new filter */
> @@ -1078,7 +1068,10 @@ static ssize_t show_filter(struct device *device,
>                 return -EINVAL;
>
>         mutex_lock(&dev->lock);
> -       if (fattr->mask)
> +       if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) ||
> +           (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter))
> +               val = 0;
> +       else if (fattr->mask)
>                 val = dev->scancode_filters[fattr->type].mask;
>         else
>                 val = dev->scancode_filters[fattr->type].data;
> @@ -1202,27 +1195,45 @@ static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR,
>  static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
>                       show_filter, store_filter, RC_FILTER_WAKEUP, true);
>
> -static struct attribute *rc_dev_attrs[] = {
> +static struct attribute *rc_dev_protocol_attrs[] = {
>         &dev_attr_protocols.attr.attr,
> +       NULL,
> +};
> +
> +static struct attribute_group rc_dev_protocol_attr_grp = {
> +       .attrs  = rc_dev_protocol_attrs,
> +};
> +
> +static struct attribute *rc_dev_wakeup_protocol_attrs[] = {
>         &dev_attr_wakeup_protocols.attr.attr,
> +       NULL,
> +};
> +
> +static struct attribute_group rc_dev_wakeup_protocol_attr_grp = {
> +       .attrs  = rc_dev_wakeup_protocol_attrs,
> +};
> +
> +static struct attribute *rc_dev_filter_attrs[] = {
>         &dev_attr_filter.attr.attr,
>         &dev_attr_filter_mask.attr.attr,
> -       &dev_attr_wakeup_filter.attr.attr,
> -       &dev_attr_wakeup_filter_mask.attr.attr,
>         NULL,
>  };
>
> -static struct attribute_group rc_dev_attr_grp = {
> -       .attrs  = rc_dev_attrs,
> +static struct attribute_group rc_dev_filter_attr_grp = {
> +       .attrs  = rc_dev_filter_attrs,
> +};
> +
> +static struct attribute *rc_dev_wakeup_filter_attrs[] = {
> +       &dev_attr_wakeup_filter.attr.attr,
> +       &dev_attr_wakeup_filter_mask.attr.attr,
> +       NULL,
>  };
>
> -static const struct attribute_group *rc_dev_attr_groups[] = {
> -       &rc_dev_attr_grp,
> -       NULL
> +static struct attribute_group rc_dev_wakeup_filter_attr_grp = {
> +       .attrs  = rc_dev_wakeup_filter_attrs,
>  };
>
>  static struct device_type rc_dev_type = {
> -       .groups         = rc_dev_attr_groups,
>         .release        = rc_dev_release,
>         .uevent         = rc_dev_uevent,
>  };
> @@ -1279,7 +1290,7 @@ int rc_register_device(struct rc_dev *dev)
>         static bool raw_init = false; /* raw decoders loaded? */
>         struct rc_map *rc_map;
>         const char *path;
> -       int rc, devno;
> +       int rc, devno, attr = 0;
>
>         if (!dev || !dev->map_name)
>                 return -EINVAL;
> @@ -1307,6 +1318,16 @@ int rc_register_device(struct rc_dev *dev)
>                         return -ENOMEM;
>         } while (test_and_set_bit(devno, ir_core_dev_number));
>
> +       dev->dev.groups = dev->sysfs_groups;
> +       dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
> +       if (dev->s_filter)
> +               dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;
> +       if (dev->s_wakeup_filter)
> +               dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
> +       if (dev->change_wakeup_protocol)
> +               dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
> +       dev->sysfs_groups[attr++] = NULL;
> +
>         /*
>          * Take the lock here, as the device sysfs node will appear
>          * when device_add() is called, which may trigger an ir-keytable udev
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 8c31e4a..2e97b98 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -60,6 +60,7 @@ enum rc_filter_type {
>  /**
>   * struct rc_dev - represents a remote control device
>   * @dev: driver model's view of this device
> + * @sysfs_groups: sysfs attribute groups
>   * @input_name: name of the input child device
>   * @input_phys: physical path to the input child device
>   * @input_id: id of the input child device (struct input_id)
> @@ -118,6 +119,7 @@ enum rc_filter_type {
>   */
>  struct rc_dev {
>         struct device                   dev;
> +       const struct attribute_group    *sysfs_groups[5];
>         const char                      *input_name;
>         const char                      *input_phys;
>         struct input_id                 input_id;
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 41/49] rc-core: rename mutex
  2014-04-03 23:34 ` [PATCH 41/49] rc-core: rename mutex David Härdeman
@ 2014-04-10 21:28   ` James Hogan
  2014-07-25 23:12   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 68+ messages in thread
From: James Hogan @ 2014-04-10 21:28 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media, m.chehab

[-- Attachment #1: Type: text/plain, Size: 8332 bytes --]

On Friday 04 April 2014 01:34:43 David Härdeman wrote:
> Having a mutex named "lock" is a bit misleading.

Why? A mutex is a type of lock so what's the problem?

A little grep'ing and sed'ing reveals that out of the 1578 unique mutex names 
in the kernel source I have to hand, 540 contain "lock", and 921 contain 
"mutex".

Cheers
James

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/img-ir/img-ir-hw.c |    4 ++-
>  drivers/media/rc/rc-main.c          |   42
> ++++++++++++++++++----------------- include/media/rc-core.h             |  
>  5 ++--
>  3 files changed, 25 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/media/rc/img-ir/img-ir-hw.c
> b/drivers/media/rc/img-ir/img-ir-hw.c index 5bc7903..a9abbb4 100644
> --- a/drivers/media/rc/img-ir/img-ir-hw.c
> +++ b/drivers/media/rc/img-ir/img-ir-hw.c
> @@ -666,11 +666,11 @@ static void img_ir_set_protocol(struct img_ir_priv
> *priv, u64 proto) {
>  	struct rc_dev *rdev = priv->hw.rdev;
> 
> -	mutex_lock(&rdev->lock);
> +	mutex_lock(&rdev->mutex);
>  	rdev->enabled_protocols = proto;
>  	rdev->allowed_wakeup_protocols = proto;
>  	rdev->enabled_wakeup_protocols = proto;
> -	mutex_unlock(&rdev->lock);
> +	mutex_unlock(&rdev->mutex);
>  }
> 
>  /* Set up IR decoders */
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index 7caca4f..bd4dfab 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -109,7 +109,7 @@ int rc_open(struct rc_dev *dev)
>  {
>  	int err = 0;
> 
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
> 
>  	if (dev->dead)
>  		err = -ENODEV;
> @@ -119,7 +119,7 @@ int rc_open(struct rc_dev *dev)
>  			dev->users--;
>  	}
> 
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
> 
>  	return err;
>  }
> @@ -127,12 +127,12 @@ EXPORT_SYMBOL_GPL(rc_open);
> 
>  void rc_close(struct rc_dev *dev)
>  {
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
> 
>  	if (!dev->dead && !--dev->users && dev->close)
>  		dev->close(dev);
> 
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  }
>  EXPORT_SYMBOL_GPL(rc_close);
> 
> @@ -322,7 +322,7 @@ struct rc_filter_attribute {
>   * It returns the protocol names of supported protocols.
>   * Enabled protocols are printed in brackets.
>   *
> - * dev->lock is taken to guard against races between store_protocols and
> + * dev->mutex is taken to guard against races between store_protocols and
>   * show_protocols.
>   */
>  static ssize_t show_protocols(struct device *device,
> @@ -339,7 +339,7 @@ static ssize_t show_protocols(struct device *device,
>  		return -EINVAL;
> 
>  	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
> 
>  	if (fattr->type == RC_FILTER_NORMAL) {
>  		enabled = dev->enabled_protocols;
> @@ -349,7 +349,7 @@ static ssize_t show_protocols(struct device *device,
>  		allowed = dev->allowed_wakeup_protocols;
>  	}
> 
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
> 
>  	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
>  		   __func__, (long long)allowed, (long long)enabled);
> @@ -449,7 +449,7 @@ static int parse_protocol_change(u64 *protocols, const
> char *buf) * See parse_protocol_change() for the valid commands.
>   * Returns @len on success or a negative error code.
>   *
> - * dev->lock is taken to guard against races between store_protocols and
> + * dev->mutex is taken to guard against races between store_protocols and
>   * show_protocols.
>   */
>  static ssize_t store_protocols(struct device *device,
> @@ -488,7 +488,7 @@ static ssize_t store_protocols(struct device *device,
>  		return -EINVAL;
>  	}
> 
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
> 
>  	old_protocols = *current_protocols;
>  	new_protocols = old_protocols;
> @@ -532,7 +532,7 @@ static ssize_t store_protocols(struct device *device,
>  	rc = len;
> 
>  out:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return rc;
>  }
> 
> @@ -550,7 +550,7 @@ out:
>   * Bits of the filter value corresponding to set bits in the filter mask
> are * compared against input scancodes and non-matching scancodes are
> discarded. *
> - * dev->lock is taken to guard against races between store_filter and
> + * dev->mutex is taken to guard against races between store_filter and
>   * show_filter.
>   */
>  static ssize_t show_filter(struct device *device,
> @@ -571,12 +571,12 @@ static ssize_t show_filter(struct device *device,
>  	else
>  		filter = &dev->scancode_wakeup_filter;
> 
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  	if (fattr->mask)
>  		val = filter->mask;
>  	else
>  		val = filter->data;
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
> 
>  	return sprintf(buf, "%#x\n", val);
>  }
> @@ -597,7 +597,7 @@ static ssize_t show_filter(struct device *device,
>   * Bits of the filter value corresponding to set bits in the filter mask
> are * compared against input scancodes and non-matching scancodes are
> discarded. *
> - * dev->lock is taken to guard against races between store_filter and
> + * dev->mutex is taken to guard against races between store_filter and
>   * show_filter.
>   */
>  static ssize_t store_filter(struct device *device,
> @@ -633,7 +633,7 @@ static ssize_t store_filter(struct device *device,
>  	if (!set_filter)
>  		return -EINVAL;
> 
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
> 
>  	new_filter = *filter;
>  	if (fattr->mask)
> @@ -654,7 +654,7 @@ static ssize_t store_filter(struct device *device,
>  	*filter = new_filter;
> 
>  unlock:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return (ret < 0) ? ret : len;
>  }
> 
> @@ -1087,7 +1087,7 @@ static long rc_ioctl(struct file *file, unsigned int
> cmd, unsigned long arg) struct rc_dev *dev = client->dev;
>  	int ret;
> 
> -	ret = mutex_lock_interruptible(&dev->lock);
> +	ret = mutex_lock_interruptible(&dev->mutex);
>  	if (ret)
>  		return ret;
> 
> @@ -1099,7 +1099,7 @@ static long rc_ioctl(struct file *file, unsigned int
> cmd, unsigned long arg) ret = rc_do_ioctl(dev, cmd, arg);
> 
>  out:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return ret;
>  }
> 
> @@ -1226,7 +1226,7 @@ struct rc_dev *rc_allocate_device(void)
>  	mutex_init(&dev->txmutex);
>  	init_waitqueue_head(&dev->txwait);
>  	init_waitqueue_head(&dev->rxwait);
> -	mutex_init(&dev->lock);
> +	mutex_init(&dev->mutex);
> 
>  	dev->dev.type = &rc_dev_type;
>  	dev->dev.class = &rc_class;
> @@ -1339,9 +1339,9 @@ void rc_unregister_device(struct rc_dev *dev)
>  	if (!dev)
>  		return;
> 
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  	dev->dead = true;
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
> 
>  	spin_lock(&dev->client_lock);
>  	list_for_each_entry(client, &dev->client_list, node)
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 25c1d38..a310e5b 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -268,8 +268,7 @@ enum rc_filter_type {
>   * @driver_name: name of the hardware driver which registered this device
>   * @map_name: name of the default keymap
>   * @rc_kt: current rc_keytable
> - * @lock: used to ensure we've filled in all protocol details before
> - *	anyone can call show_protocols or store_protocols
> + * @mutex: used where a more specific lock/mutex/etc is not available
>   * @dead: used to determine if the device is still alive
>   * @client_list: list of clients (processes which have opened the rc
> chardev) * @client_lock: protects client_list
> @@ -334,7 +333,7 @@ struct rc_dev {
>  	const char			*map_name;
>  	struct rc_keytable		*keytables[RC_MAX_KEYTABLES];
>  	struct list_head		keytable_list;
> -	struct mutex			lock;
> +	struct mutex			mutex;
>  	bool				dead;
>  	struct list_head		client_list;
>  	spinlock_t			client_lock;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 00/49] rc-core: my current patch queue
  2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
                   ` (49 preceding siblings ...)
  2014-04-04  2:05 ` [PATCH 00/49] rc-core: my current patch queue Mauro Carvalho Chehab
@ 2014-06-26 20:07 ` David Härdeman
  50 siblings, 0 replies; 68+ messages in thread
From: David Härdeman @ 2014-06-26 20:07 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

On Fri, Apr 04, 2014 at 01:31:15AM +0200, David Härdeman wrote:
>The following patches is what I currenly have in my queue:
>
>Patches 1 - 6 should be ok to be committed right now, they contain
>some fixes and some reverts (of the NEC32 and generic scancode
>functionality).
>
>Patches 7 - 9 are in no hurry and can wait for 3.16, some testing
>would be nice even though I believe they are ok.
>
>Patches 10 and 11 are RFC's for the NEC32 scancode handling.
>
>The remaining patches are more of an FYI. It's basically the same
>patchset that I've posted a long time ago, but respun to apply to
>the current tree. They implement a modern chardev for rc-core which
>allows the functionality that has so far only been available through
>the LIRC bridge to be exposed to userspace and provide a (hopefully)
>sane API for taking advantage of all the features that rc-core
>provides (RX, TX, ioctl) as well as some new features (multiple
>keymaps is probably the most important one). Lots and lots of cleanups
>as well.
>
>Enjoy :)

Mauro? Any progress on this? The patches seem to be rotting again and
there's not much activity to be seen in the rc-core area? I haven't seen
any better or alternative solutions and the current state of rc-core is
certainly not where it should be...

-- 
David Härdeman

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

* Re: [PATCH 30/49] rc-core: leave the internals of rc_dev alone
  2014-04-03 23:33 ` [PATCH 30/49] rc-core: leave the internals of rc_dev alone David Härdeman
@ 2014-07-24  1:50   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-24  1:50 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:33:47 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Several drivers poke around in the internals of rc_dev, try to
> fix them up in preparation for the next round of patches.

You're not fixing them. You're just removing code that are there
to fix some things. Before removing those, we need to test each
one of the affected drivers, to see if they won't be introducing
any regressions. Also, we should break it into one change per patch,
to make easier to revert if someone later complains.

Regards,
Mauro

> 
> drivers/media/rc/ati_remote.c:
> 	Removing the REP_DELAY setting on the input device should not
> 	change how to driver works (as it does a keydown/keyup and has
> 	no real repeat handling).
> 
> drivers/media/rc/img-ir/img-ir-hw.c
> 	Changing the protocol does not imply that the keymap changes.
> 
> drivers/media/rc/ir-nec-decoder.c
> 	Obvious fix, leave repeat handling to rc-core
> 
> drivers/media/rc/ir-raw.c
> 	Replaced the REP_DELAY value with a static value, which makes more
> 	sense anyway. Why should the time before automatic repeat handling
> 	kicks in define the drivers idea of "a long time"?
> 
> drivers/media/rc/ir-sanyo-decoder.c
> 	Obvious fix, leave repeat handling to rc-core
> 
> drivers/media/video/cx231xx/cx231xx-input.c
> 	Just some debug statements to change
> 
> drivers/media/video/tm6000/tm6000-input.c
> 	Not sure what the driver is trying to do, however, IR
> 	handling seems incomplete ATM so deleting the offending
> 	parts shouldn't affect functionality
> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/ati_remote.c             |    3 ---
>  drivers/media/rc/img-ir/img-ir-hw.c       |    4 ----
>  drivers/media/rc/ir-nec-decoder.c         |   10 +++-------
>  drivers/media/rc/ir-raw.c                 |    4 +---
>  drivers/media/rc/ir-sanyo-decoder.c       |   10 +++-------
>  drivers/media/usb/cx231xx/cx231xx-input.c |    5 ++---
>  drivers/media/usb/tm6000/tm6000-input.c   |    4 ----
>  7 files changed, 9 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
> index 3ada4dc..6ef5716 100644
> --- a/drivers/media/rc/ati_remote.c
> +++ b/drivers/media/rc/ati_remote.c
> @@ -932,9 +932,6 @@ static int ati_remote_probe(struct usb_interface *interface,
>  	if (err)
>  		goto exit_kill_urbs;
>  
> -	/* use our delay for rc_dev */
> -	ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
> -
>  	/* Set up and register mouse input device */
>  	if (mouse) {
>  		input_dev = input_allocate_device();
> diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
> index 9fc41780..3bb6a32 100644
> --- a/drivers/media/rc/img-ir/img-ir-hw.c
> +++ b/drivers/media/rc/img-ir/img-ir-hw.c
> @@ -666,10 +666,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
>  {
>  	struct rc_dev *rdev = priv->hw.rdev;
>  
> -	spin_lock_irq(&rdev->rc_map.lock);
> -	rdev->rc_map.rc_type = __ffs64(proto);
> -	spin_unlock_irq(&rdev->rc_map.lock);
> -
>  	mutex_lock(&rdev->lock);
>  	rdev->enabled_protocols = proto;
>  	rdev->allowed_wakeup_protocols = proto;
> diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
> index 1683aaa..861fd86 100644
> --- a/drivers/media/rc/ir-nec-decoder.c
> +++ b/drivers/media/rc/ir-nec-decoder.c
> @@ -89,13 +89,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  			data->state = STATE_BIT_PULSE;
>  			return 0;
>  		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
> -			if (!dev->keypressed) {
> -				IR_dprintk(1, "Discarding last key repeat: event after key up\n");
> -			} else {
> -				rc_repeat(dev);
> -				IR_dprintk(1, "Repeat last key\n");
> -				data->state = STATE_TRAILER_PULSE;
> -			}
> +			rc_repeat(dev);
> +			IR_dprintk(1, "Repeat last key\n");
> +			data->state = STATE_TRAILER_PULSE;
>  			return 0;
>  		}
>  
> diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
> index af23f4d..aa2503d 100644
> --- a/drivers/media/rc/ir-raw.c
> +++ b/drivers/media/rc/ir-raw.c
> @@ -109,20 +109,18 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
>  	s64			delta; /* ns */
>  	DEFINE_IR_RAW_EVENT(ev);
>  	int			rc = 0;
> -	int			delay;
>  
>  	if (!dev->raw)
>  		return -EINVAL;
>  
>  	now = ktime_get();
>  	delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
> -	delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
>  
>  	/* 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 > delay || !dev->raw->last_type)
> +	if (delta > MS_TO_NS(500) || !dev->raw->last_type)
>  		type |= IR_START_EVENT;
>  	else
>  		ev.duration = delta;
> diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
> index ad1dc6a..9f97648 100644
> --- a/drivers/media/rc/ir-sanyo-decoder.c
> +++ b/drivers/media/rc/ir-sanyo-decoder.c
> @@ -112,13 +112,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  			break;
>  
>  		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
> -			if (!dev->keypressed) {
> -				IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
> -			} else {
> -				rc_repeat(dev);
> -				IR_dprintk(1, "SANYO repeat last key\n");
> -				data->state = STATE_INACTIVE;
> -			}
> +			rc_repeat(dev);
> +			IR_dprintk(1, "SANYO repeat last key\n");
> +			data->state = STATE_INACTIVE;
>  			return 0;
>  		}
>  
> diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
> index 05f0434..5480fb1 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-input.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-input.c
> @@ -31,7 +31,7 @@ static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
>  	int	rc;
>  	u8	cmd, scancode;
>  
> -	dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
> +	dev_dbg(&ir->rc->dev, "%s\n", __func__);
>  
>  		/* poll IR chip */
>  	rc = i2c_master_recv(ir->c, &cmd, 1);
> @@ -49,8 +49,7 @@ static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
>  
>  	scancode = bitrev8(cmd);
>  
> -	dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
> -		cmd, scancode);
> +	dev_dbg(&ir->rc->dev, "cmd %02x, scan = %02x\n", cmd, scancode);
>  
>  	*protocol = RC_TYPE_OTHER;
>  	*pscancode = scancode;
> diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
> index 26b2ebb..7c9b58d 100644
> --- a/drivers/media/usb/tm6000/tm6000-input.c
> +++ b/drivers/media/usb/tm6000/tm6000-input.c
> @@ -67,7 +67,6 @@ struct tm6000_IR {
>  	u8			wait:1;
>  	u8			pwled:2;
>  	u8			submit_urb:1;
> -	u16			key_addr;
>  	struct urb		*int_urb;
>  
>  	/* IR device properties */
> @@ -325,9 +324,6 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_type)
>  
>  	dprintk(2, "%s\n",__func__);
>  
> -	if ((rc->rc_map.scan) && (*rc_type == RC_BIT_NEC))
> -		ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
> -
>  	ir->rc_type = *rc_type;
>  
>  	tm6000_ir_config(ir);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 16/49] rc-core: use an IDA rather than a bitmap
  2014-04-03 23:32 ` [PATCH 16/49] rc-core: use an IDA rather than a bitmap David Härdeman
@ 2014-07-25 22:39   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 22:39 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

As I commented on a private e-mail, based on the patch descriptions:

Patch 17 deserves a bigger explanation. Well, the best is if you
could send a separate RFC describing what you have in mind with
patches 16-29, for our discussions, explaining what usage are you
expecting for a non-LIRC chardev, as its description doesn't help
at all, and why LIRC's way doesn't fulfill our needs any more.

Patch 18 looks silly... why to replicate evdev on a separate device?

Patches 19 and 20 might make sense, but why not use LIRC instead?

As patch 16 is also part of this change, I'm skipping those patches
from my review. Please re-submit latter after some RFC discussions
about the API changes that are being proposed by those patches.

Thanks,

Em Fri, 04 Apr 2014 01:32:36 +0200
David Härdeman <david@hardeman.nu> escreveu:

> This patch changes rc-core to use an IDA rather than a bitmap to assign
> unique numbers to each rc device. This is in preparation for introducing
> rc-core chardevs.
> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/ir-raw.c  |    2 +-
>  drivers/media/rc/rc-main.c |   40 ++++++++++++++++++++--------------------
>  include/media/rc-core.h    |    4 ++--
>  3 files changed, 23 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
> index 2a7f858..aed2997 100644
> --- a/drivers/media/rc/ir-raw.c
> +++ b/drivers/media/rc/ir-raw.c
> @@ -271,7 +271,7 @@ int ir_raw_event_register(struct rc_dev *dev)
>  
>  	spin_lock_init(&dev->raw->lock);
>  	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
> -				       "rc%ld", dev->devno);
> +				       "rc%u", dev->minor);
>  
>  	if (IS_ERR(dev->raw->thread)) {
>  		rc = PTR_ERR(dev->raw->thread);
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index 2788102..42268f3 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -18,17 +18,15 @@
>  #include <linux/input.h>
>  #include <linux/leds.h>
>  #include <linux/slab.h>
> +#include <linux/idr.h>
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include "rc-core-priv.h"
>  
> -/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */
> -#define IRRCV_NUM_DEVICES      256
> -static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES);
> -
>  /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
>  #define IR_TAB_MIN_SIZE	256
>  #define IR_TAB_MAX_SIZE	8192
> +#define RC_DEV_MAX	256
>  
>  /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
>  #define IR_KEYPRESS_TIMEOUT 250
> @@ -38,6 +36,9 @@ static LIST_HEAD(rc_map_list);
>  static DEFINE_SPINLOCK(rc_map_lock);
>  static struct led_trigger *led_feedback;
>  
> +/* Used to keep track of rc devices */
> +static DEFINE_IDA(rc_ida);
> +
>  static struct rc_map_list *seek_rc_map(const char *name)
>  {
>  	struct rc_map_list *map = NULL;
> @@ -1442,7 +1443,9 @@ int rc_register_device(struct rc_dev *dev)
>  	static bool raw_init = false; /* raw decoders loaded? */
>  	struct rc_map *rc_map;
>  	const char *path;
> -	int rc, devno, attr = 0;
> +	int attr = 0;
> +	int minor;
> +	int rc;
>  
>  	if (!dev || !dev->map_name)
>  		return -EINVAL;
> @@ -1462,13 +1465,13 @@ int rc_register_device(struct rc_dev *dev)
>  	if (dev->close)
>  		dev->input_dev->close = ir_close;
>  
> -	do {
> -		devno = find_first_zero_bit(ir_core_dev_number,
> -					    IRRCV_NUM_DEVICES);
> -		/* No free device slots */
> -		if (devno >= IRRCV_NUM_DEVICES)
> -			return -ENOMEM;
> -	} while (test_and_set_bit(devno, ir_core_dev_number));
> +	minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
> +	if (minor < 0)
> +		return minor;
> +
> +	dev->minor = minor;
> +	dev_set_name(&dev->dev, "rc%u", dev->minor);
> +	dev_set_drvdata(&dev->dev, dev);
>  
>  	dev->dev.groups = dev->sysfs_groups;
>  	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
> @@ -1488,9 +1491,6 @@ int rc_register_device(struct rc_dev *dev)
>  	 */
>  	mutex_lock(&dev->lock);
>  
> -	dev->devno = devno;
> -	dev_set_name(&dev->dev, "rc%ld", dev->devno);
> -	dev_set_drvdata(&dev->dev, dev);
>  	rc = device_add(&dev->dev);
>  	if (rc)
>  		goto out_unlock;
> @@ -1558,8 +1558,8 @@ int rc_register_device(struct rc_dev *dev)
>  
>  	mutex_unlock(&dev->lock);
>  
> -	IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
> -		   dev->devno,
> +	IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
> +		   dev->minor,
>  		   dev->driver_name ? dev->driver_name : "unknown",
>  		   rc_map->name ? rc_map->name : "unknown",
>  		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
> @@ -1578,7 +1578,7 @@ out_dev:
>  	device_del(&dev->dev);
>  out_unlock:
>  	mutex_unlock(&dev->lock);
> -	clear_bit(dev->devno, ir_core_dev_number);
> +	ida_simple_remove(&rc_ida, minor);
>  	return rc;
>  }
>  EXPORT_SYMBOL_GPL(rc_register_device);
> @@ -1590,8 +1590,6 @@ void rc_unregister_device(struct rc_dev *dev)
>  
>  	del_timer_sync(&dev->timer_keyup);
>  
> -	clear_bit(dev->devno, ir_core_dev_number);
> -
>  	if (dev->driver_type == RC_DRIVER_IR_RAW)
>  		ir_raw_event_unregister(dev);
>  
> @@ -1604,6 +1602,8 @@ void rc_unregister_device(struct rc_dev *dev)
>  
>  	device_del(&dev->dev);
>  
> +	ida_simple_remove(&rc_ida, dev->minor);
> +
>  	rc_free_device(dev);
>  }
>  
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 5a082e7..ca3d836 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -87,7 +87,7 @@ enum rc_filter_type {
>   * @rc_map: current scan/key table
>   * @lock: used to ensure we've filled in all protocol details before
>   *	anyone can call show_protocols or store_protocols
> - * @devno: unique remote control device number
> + * @minor: unique minor remote control device number
>   * @raw: additional data for raw pulse/space devices
>   * @input_dev: the input child device used to communicate events to userspace
>   * @driver_type: specifies if protocol decoding is done in hardware or software
> @@ -147,7 +147,7 @@ struct rc_dev {
>  	const char			*map_name;
>  	struct rc_map			rc_map;
>  	struct mutex			lock;
> -	unsigned long			devno;
> +	unsigned int			minor;
>  	struct ir_raw_event_ctrl	*raw;
>  	struct input_dev		*input_dev;
>  	enum rc_driver_type		driver_type;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c
  2014-04-03 23:33 ` [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c David Härdeman
@ 2014-07-25 22:44   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 22:44 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:33:52 +0200
David Härdeman <david@hardeman.nu> escreveu:

> rc-main.c is getting quite large and contains two distinct parts, one
> related to the chardev (fops, sysfs, etc) and one related to all
> key functionality. Split off the key functionality to a separate file in
> preparation for the coming patches.
> 
> I've done the splitting as a separate patch with the absolute minimum changes
> (making some methods non-static) because it's nigh impossible to review
> code changes and this code of split in the same patch.

The idea makes sense for me. Please rebase it and re-send before the
chardev stuff. Better to do it earlier and not depending on the RFC
discussions that could take some time.

Regards,
Mauro

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/Makefile       |    2 
>  drivers/media/rc/rc-core-priv.h |   17 +
>  drivers/media/rc/rc-keytable.c  |  851 +++++++++++++++++++++++++++++++++++++++
>  drivers/media/rc/rc-main.c      |  853 +--------------------------------------
>  4 files changed, 883 insertions(+), 840 deletions(-)
>  create mode 100644 drivers/media/rc/rc-keytable.c
> 
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index d326d4d..de08ee6 100644
> --- a/drivers/media/rc/Makefile
> +++ b/drivers/media/rc/Makefile
> @@ -1,4 +1,4 @@
> -rc-core-objs	:= rc-main.o ir-raw.o
> +rc-core-objs	:= rc-main.o rc-keytable.o ir-raw.o
>  
>  obj-y += keymaps/
>  
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index aacc192..6da8a0d 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -155,9 +155,26 @@ 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);
>  
> +/*
> + * Methods from rc-keytable.c to be used internally
> + */
> +void ir_timer_keyup(unsigned long cookie);
> +int rc_input_open(struct input_dev *idev);
> +void rc_input_close(struct input_dev *idev);
> +int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from);
> +void ir_free_table(struct rc_map *rc_map);
> +int ir_getkeycode(struct input_dev *idev,
> +		  struct input_keymap_entry *ke);
> +int ir_setkeycode(struct input_dev *idev,
> +		  const struct input_keymap_entry *ke,
> +		  unsigned int *old_keycode);
> +
>  /* Only to be used by rc-core and ir-lirc-codec */
>  void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
>  
> +/* Only to be used by rc-keytable.c */
> +extern struct led_trigger *led_feedback;
> +
>  /*
>   * Decoder initialization code
>   *
> diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
> new file mode 100644
> index 0000000..25faeba
> --- /dev/null
> +++ b/drivers/media/rc/rc-keytable.c
> @@ -0,0 +1,851 @@
> +/* rc-keytable.c - Remote Controller keytable handling
> + *
> + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab
> + *
> + * 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/rc-core.h>
> +#include <linux/spinlock.h>
> +#include <linux/delay.h>
> +#include <linux/input.h>
> +#include <linux/leds.h>
> +#include <linux/slab.h>
> +#include <linux/sched.h>
> +#include <linux/idr.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/poll.h>
> +#include "rc-core-priv.h"
> +
> +/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
> +#define IR_TAB_MIN_SIZE		256
> +#define IR_TAB_MAX_SIZE		8192
> +
> +/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
> +#define IR_KEYPRESS_TIMEOUT 250
> +
> +/* Used to keep track of known keymaps */
> +static LIST_HEAD(rc_map_list);
> +static DEFINE_SPINLOCK(rc_map_lock);
> +
> +static struct rc_map_list *seek_rc_map(const char *name)
> +{
> +	struct rc_map_list *map = NULL;
> +
> +	spin_lock(&rc_map_lock);
> +	list_for_each_entry(map, &rc_map_list, list) {
> +		if (!strcmp(name, map->map.name)) {
> +			spin_unlock(&rc_map_lock);
> +			return map;
> +		}
> +	}
> +	spin_unlock(&rc_map_lock);
> +
> +	return NULL;
> +}
> +
> +struct rc_map *rc_map_get(const char *name)
> +{
> +
> +	struct rc_map_list *map;
> +
> +	map = seek_rc_map(name);
> +#ifdef MODULE
> +	if (!map) {
> +		int rc = request_module("%s", name);
> +		if (rc < 0) {
> +			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
> +			return NULL;
> +		}
> +		msleep(20);	/* Give some time for IR to register */
> +
> +		map = seek_rc_map(name);
> +	}
> +#endif
> +	if (!map) {
> +		printk(KERN_ERR "IR keymap %s not found\n", name);
> +		return NULL;
> +	}
> +
> +	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
> +
> +	return &map->map;
> +}
> +EXPORT_SYMBOL_GPL(rc_map_get);
> +
> +int rc_map_register(struct rc_map_list *map)
> +{
> +	spin_lock(&rc_map_lock);
> +	list_add_tail(&map->list, &rc_map_list);
> +	spin_unlock(&rc_map_lock);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(rc_map_register);
> +
> +void rc_map_unregister(struct rc_map_list *map)
> +{
> +	spin_lock(&rc_map_lock);
> +	list_del(&map->list);
> +	spin_unlock(&rc_map_lock);
> +}
> +EXPORT_SYMBOL_GPL(rc_map_unregister);
> +
> +/**
> + * ir_create_table() - initializes a scancode table
> + * @rc_map:	the rc_map to initialize
> + * @name:	name to assign to the table
> + * @size:	initial size of the table
> + * @return:	zero on success or a negative error code
> + *
> + * This routine will initialize the rc_map and will allocate
> + * memory to hold at least the specified number of elements.
> + */
> +static int ir_create_table(struct rc_map *rc_map,
> +			   const char *name, size_t size)
> +{
> +	rc_map->name = name;
> +	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
> +	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
> +	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
> +	if (!rc_map->scan)
> +		return -ENOMEM;
> +
> +	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
> +		   rc_map->size, rc_map->alloc);
> +	return 0;
> +}
> +
> +/**
> + * ir_free_table() - frees memory allocated by a scancode table
> + * @rc_map:	the table whose mappings need to be freed
> + *
> + * This routine will free memory alloctaed for key mappings used by given
> + * scancode table.
> + */
> +void ir_free_table(struct rc_map *rc_map)
> +{
> +	rc_map->size = 0;
> +	kfree(rc_map->scan);
> +	rc_map->scan = NULL;
> +}
> +
> +/**
> + * ir_resize_table() - resizes a scancode table if necessary
> + * @rc_map:	the rc_map to resize
> + * @gfp_flags:	gfp flags to use when allocating memory
> + * @return:	zero on success or a negative error code
> + *
> + * This routine will shrink the rc_map if it has lots of
> + * unused entries and grow it if it is full.
> + */
> +static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
> +{
> +	unsigned int oldalloc = rc_map->alloc;
> +	unsigned int newalloc = oldalloc;
> +	struct rc_map_table *oldscan = rc_map->scan;
> +	struct rc_map_table *newscan;
> +
> +	if (rc_map->size == rc_map->len) {
> +		/* All entries in use -> grow keytable */
> +		if (rc_map->alloc >= IR_TAB_MAX_SIZE)
> +			return -ENOMEM;
> +
> +		newalloc *= 2;
> +		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
> +	}
> +
> +	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
> +		/* Less than 1/3 of entries in use -> shrink keytable */
> +		newalloc /= 2;
> +		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
> +	}
> +
> +	if (newalloc == oldalloc)
> +		return 0;
> +
> +	newscan = kmalloc(newalloc, gfp_flags);
> +	if (!newscan) {
> +		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
> +		return -ENOMEM;
> +	}
> +
> +	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
> +	rc_map->scan = newscan;
> +	rc_map->alloc = newalloc;
> +	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
> +	kfree(oldscan);
> +	return 0;
> +}
> +
> +/**
> + * ir_update_mapping() - set a keycode in the scancode->keycode table
> + * @dev:	the struct rc_dev device descriptor
> + * @rc_map:	scancode table to be adjusted
> + * @index:	index of the mapping that needs to be updated
> + * @keycode:	the desired keycode
> + * @return:	previous keycode assigned to the mapping
> + *
> + * This routine is used to update scancode->keycode mapping at given
> + * position.
> + */
> +static unsigned int ir_update_mapping(struct rc_dev *dev,
> +				      struct rc_map *rc_map,
> +				      unsigned int index,
> +				      unsigned int new_keycode)
> +{
> +	int old_keycode = rc_map->scan[index].keycode;
> +	int i;
> +
> +	/* Did the user wish to remove the mapping? */
> +	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
> +		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
> +			   index, rc_map->scan[index].protocol,
> +			   (unsigned long long)rc_map->scan[index].scancode);
> +		rc_map->len--;
> +		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
> +			(rc_map->len - index) * sizeof(struct rc_map_table));
> +	} else {
> +		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
> +			   "with key 0x%04x\n",
> +			   index,
> +			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
> +			   rc_map->scan[index].protocol,
> +			   (unsigned long long)rc_map->scan[index].scancode,
> +			   new_keycode);
> +		rc_map->scan[index].keycode = new_keycode;
> +		__set_bit(new_keycode, dev->input_dev->keybit);
> +	}
> +
> +	if (old_keycode != KEY_RESERVED) {
> +		/* A previous mapping was updated... */
> +		__clear_bit(old_keycode, dev->input_dev->keybit);
> +		/* ... but another scancode might use the same keycode */
> +		for (i = 0; i < rc_map->len; i++) {
> +			if (rc_map->scan[i].keycode == old_keycode) {
> +				__set_bit(old_keycode, dev->input_dev->keybit);
> +				break;
> +			}
> +		}
> +
> +		/* Possibly shrink the keytable, failure is not a problem */
> +		ir_resize_table(rc_map, GFP_ATOMIC);
> +	}
> +
> +	return old_keycode;
> +}
> +
> +/**
> + * ir_establish_scancode() - set a keycode in the scancode->keycode table
> + * @dev:	the struct rc_dev device descriptor
> + * @rc_map:	scancode table to be searched
> + * @entry:	the entry to be added to the table
> + * @resize:	controls whether we are allowed to resize the table to
> + *		accomodate not yet present scancodes
> + * @return:	index of the mapping containing scancode in question
> + *		or -1U in case of failure.
> + *
> + * This routine is used to locate given scancode in rc_map.
> + * If scancode is not yet present the routine will allocate a new slot
> + * for it.
> + */
> +static unsigned int ir_establish_scancode(struct rc_dev *dev,
> +					  struct rc_map *rc_map,
> +					  struct rc_map_table *entry,
> +					  bool resize)
> +{
> +	unsigned int i;
> +
> +	/*
> +	 * Unfortunately, some hardware-based IR decoders don't provide
> +	 * all bits for the complete IR code. In general, they provide only
> +	 * the command part of the IR code. Yet, as it is possible to replace
> +	 * the provided IR with another one, it is needed to allow loading
> +	 * IR tables from other remotes. So, we support specifying a mask to
> +	 * indicate the valid bits of the scancodes.
> +	 */
> +	if (dev->scancode_mask)
> +		entry->scancode &= dev->scancode_mask;
> +
> +	/*
> +	 * First check if we already have a mapping for this command.
> +	 * Note that the keytable is sorted first on protocol and second
> +	 * on scancode (lowest to highest).
> +	 */
> +	for (i = 0; i < rc_map->len; i++) {
> +		if (rc_map->scan[i].protocol < entry->protocol)
> +			continue;
> +
> +		if (rc_map->scan[i].protocol > entry->protocol)
> +			break;
> +
> +		if (rc_map->scan[i].scancode < entry->scancode)
> +			continue;
> +
> +		if (rc_map->scan[i].scancode > entry->scancode)
> +			break;
> +
> +		return i;
> +	}
> +
> +	/* No previous mapping found, we might need to grow the table */
> +	if (rc_map->size == rc_map->len) {
> +		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
> +			return -1U;
> +	}
> +
> +	/* i is the proper index to insert our new keycode */
> +	if (i < rc_map->len)
> +		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
> +			(rc_map->len - i) * sizeof(struct rc_map_table));
> +	rc_map->scan[i].scancode = entry->scancode;
> +	rc_map->scan[i].protocol = entry->protocol;
> +	rc_map->scan[i].keycode = KEY_RESERVED;
> +	rc_map->len++;
> +
> +	return i;
> +}
> +
> +/**
> + * guess_protocol() - heuristics to guess the protocol for a scancode
> + * @rdev:	the struct rc_dev device descriptor
> + * @return:	the guessed RC_TYPE_* protocol
> + *
> + * Internal routine to guess the current IR protocol for legacy ioctls.
> + */
> +static inline enum rc_type guess_protocol(struct rc_dev *rdev)
> +{
> +	struct rc_map *rc_map = &rdev->rc_map;
> +
> +	if (hweight64(rdev->enabled_protocols) == 1)
> +		return rc_bitmap_to_type(rdev->enabled_protocols);
> +	else if (hweight64(rdev->allowed_protocols) == 1)
> +		return rc_bitmap_to_type(rdev->allowed_protocols);
> +	else if (rc_map->len > 0)
> +		return rc_map->scan[0].protocol;
> +	else
> +		return RC_TYPE_OTHER;
> +}
> +
> +/**
> + * to_nec32() - helper function to try to convert misc NEC scancodes to NEC32
> + * @orig:	original scancode
> + * @return:	NEC32 scancode
> + *
> + * This helper routine is used to provide backwards compatibility.
> + */
> +static u32 to_nec32(u32 orig)
> +{
> +	u8 b3 = (u8)(orig >> 16);
> +	u8 b2 = (u8)(orig >>  8);
> +	u8 b1 = (u8)(orig >>  0);
> +
> +	if (orig <= 0xffff)
> +		/* Plain old NEC */
> +		return b2 << 24 | ((u8)~b2) << 16 |  b1 << 8 | ((u8)~b1);
> +	else if (orig <= 0xffffff)
> +		/* NEC extended */
> +		return b3 << 24 | b2 << 16 |  b1 << 8 | ((u8)~b1);
> +	else
> +		/* NEC32 */
> +		return orig;
> +}
> +
> +/**
> + * ir_setkeycode() - set a keycode in the scancode->keycode table
> + * @idev:	the struct input_dev device descriptor
> + * @scancode:	the desired scancode
> + * @keycode:	result
> + * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
> + *
> + * This routine is used to handle evdev EVIOCSKEY ioctl.
> + */
> +int ir_setkeycode(struct input_dev *idev,
> +		  const struct input_keymap_entry *ke,
> +		  unsigned int *old_keycode)
> +{
> +	struct rc_dev *rdev = input_get_drvdata(idev);
> +	struct rc_map *rc_map = &rdev->rc_map;
> +	unsigned int index;
> +	struct rc_map_table entry;
> +	int retval = 0;
> +	unsigned long flags;
> +
> +	entry.keycode = ke->keycode;
> +
> +	spin_lock_irqsave(&rc_map->lock, flags);
> +
> +	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
> +		index = ke->index;
> +		if (index >= rc_map->len) {
> +			retval = -EINVAL;
> +			goto out;
> +		}
> +	} else if (ke->len == sizeof(int)) {
> +		/* Legacy EVIOCSKEYCODE ioctl */
> +		u32 scancode;
> +		retval = input_scancode_to_scalar(ke, &scancode);
> +		if (retval)
> +			goto out;
> +
> +		entry.scancode = scancode;
> +		entry.protocol = guess_protocol(rdev);
> +		if (entry.protocol == RC_TYPE_NEC)
> +			entry.scancode = to_nec32(scancode);
> +
> +		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> +		if (index >= rc_map->len) {
> +			retval = -ENOMEM;
> +			goto out;
> +		}
> +	} else if (ke->len == sizeof(struct rc_scancode)) {
> +		/* New EVIOCSKEYCODE_V2 ioctl */
> +		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
> +		entry.protocol = rke->rc.protocol;
> +		entry.scancode = rke->rc.scancode;
> +
> +		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
> +			retval = -EINVAL;
> +			goto out;
> +		}
> +
> +		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> +		if (index >= rc_map->len) {
> +			retval = -ENOMEM;
> +			goto out;
> +		}
> +	} else {
> +		retval = -EINVAL;
> +		goto out;
> +	}
> +
> +	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
> +
> +out:
> +	spin_unlock_irqrestore(&rc_map->lock, flags);
> +	return retval;
> +}
> +
> +/**
> + * ir_setkeytable() - sets several entries in the scancode->keycode table
> + * @dev:	the struct rc_dev device descriptor
> + * @to:		the struct rc_map to copy entries to
> + * @from:	the struct rc_map to copy entries from
> + * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
> + *
> + * This routine is used to handle table initialization.
> + */
> +int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
> +{
> +	struct rc_map *rc_map = &dev->rc_map;
> +	struct rc_map_table entry;
> +	unsigned int i, index;
> +	int rc;
> +
> +	rc = ir_create_table(rc_map, from->name, from->size);
> +	if (rc)
> +		return rc;
> +
> +	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
> +		   rc_map->size, rc_map->alloc);
> +
> +	for (i = 0; i < from->size; i++) {
> +		if (from->rc_type == RC_TYPE_NEC)
> +			entry.scancode = to_nec32(from->scan[i].scancode);
> +		else
> +			entry.scancode = from->scan[i].scancode;
> +
> +		entry.protocol = from->rc_type;
> +		index = ir_establish_scancode(dev, rc_map, &entry, false);
> +		if (index >= rc_map->len) {
> +			rc = -ENOMEM;
> +			break;
> +		}
> +
> +		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
> +	}
> +
> +	if (rc)
> +		ir_free_table(rc_map);
> +
> +	return rc;
> +}
> +
> +/**
> + * ir_lookup_by_scancode() - locate mapping by scancode
> + * @rc_map:	the struct rc_map to search
> + * @protocol:	protocol to look for in the table
> + * @scancode:	scancode to look for in the table
> + * @return:	index in the table, -1U if not found
> + *
> + * This routine performs binary search in RC keykeymap table for
> + * given scancode.
> + */
> +static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
> +					  u16 protocol, u64 scancode)
> +{
> +	int start = 0;
> +	int end = rc_map->len - 1;
> +	int mid;
> +	struct rc_map_table *m;
> +
> +	while (start <= end) {
> +		mid = (start + end) / 2;
> +		m = &rc_map->scan[mid];
> +
> +		if (m->protocol < protocol)
> +			start = mid + 1;
> +		else if (m->protocol > protocol)
> +			end = mid - 1;
> +		else if (m->scancode < scancode)
> +			start = mid + 1;
> +		else if (m->scancode > scancode)
> +			end = mid - 1;
> +		else
> +			return mid;
> +	}
> +
> +	return -1U;
> +}
> +
> +/**
> + * ir_getkeycode() - get a keycode from the scancode->keycode table
> + * @idev:	the struct input_dev device descriptor
> + * @scancode:	the desired scancode
> + * @keycode:	used to return the keycode, if found, or KEY_RESERVED
> + * @return:	always returns zero.
> + *
> + * This routine is used to handle evdev EVIOCGKEY ioctl.
> + */
> +int ir_getkeycode(struct input_dev *idev,
> +		  struct input_keymap_entry *ke)
> +{
> +	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
> +	struct rc_dev *rdev = input_get_drvdata(idev);
> +	struct rc_map *rc_map = &rdev->rc_map;
> +	struct rc_map_table *entry;
> +	unsigned long flags;
> +	unsigned int index;
> +	int retval;
> +
> +	spin_lock_irqsave(&rc_map->lock, flags);
> +
> +	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
> +		index = ke->index;
> +	} else if (ke->len == sizeof(int)) {
> +		/* Legacy EVIOCGKEYCODE ioctl */
> +		u32 scancode;
> +		u16 protocol;
> +
> +		retval = input_scancode_to_scalar(ke, &scancode);
> +		if (retval)
> +			goto out;
> +
> +		protocol = guess_protocol(rdev);
> +		if (protocol == RC_TYPE_NEC)
> +			scancode = to_nec32(scancode);
> +
> +		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
> +
> +	} else if (ke->len == sizeof(struct rc_scancode)) {
> +		/* New EVIOCGKEYCODE_V2 ioctl */
> +		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
> +			retval = -EINVAL;
> +			goto out;
> +		}
> +
> +		index = ir_lookup_by_scancode(rc_map,
> +					      rke->rc.protocol, rke->rc.scancode);
> +
> +	} else {
> +		retval = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (index < rc_map->len) {
> +		entry = &rc_map->scan[index];
> +		ke->index = index;
> +		ke->keycode = entry->keycode;
> +		if (ke->len == sizeof(int)) {
> +			u32 scancode = entry->scancode;
> +			memcpy(ke->scancode, &scancode, sizeof(scancode));
> +		} else {
> +			ke->len = sizeof(struct rc_scancode);
> +			rke->rc.protocol = entry->protocol;
> +			rke->rc.scancode = entry->scancode;
> +		}
> +
> +	} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
> +		/*
> +		 * We do not really know the valid range of scancodes
> +		 * so let's respond with KEY_RESERVED to anything we
> +		 * do not have mapping for [yet].
> +		 */
> +		ke->index = index;
> +		ke->keycode = KEY_RESERVED;
> +	} else {
> +		retval = -EINVAL;
> +		goto out;
> +	}
> +
> +	retval = 0;
> +
> +out:
> +	spin_unlock_irqrestore(&rc_map->lock, flags);
> +	return retval;
> +}
> +
> +/**
> + * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
> + * @dev:	the struct rc_dev descriptor of the device
> + * @protocol:	the protocol to look for
> + * @scancode:	the scancode to look for
> + * @return:	the corresponding keycode, or KEY_RESERVED
> + *
> + * This routine is used by drivers which need to convert a scancode to a
> + * keycode. Normally it should not be used since drivers should have no
> + * interest in keycodes.
> + */
> +u32 rc_g_keycode_from_table(struct rc_dev *dev,
> +			    enum rc_type protocol, u64 scancode)
> +{
> +	struct rc_map *rc_map = &dev->rc_map;
> +	unsigned int keycode;
> +	unsigned int index;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&rc_map->lock, flags);
> +
> +	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
> +	keycode = index < rc_map->len ?
> +			rc_map->scan[index].keycode : KEY_RESERVED;
> +
> +	spin_unlock_irqrestore(&rc_map->lock, flags);
> +
> +	if (keycode != KEY_RESERVED)
> +		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
> +			   dev->input_name, protocol,
> +			   (unsigned long long)scancode, keycode);
> +
> +	return keycode;
> +}
> +EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
> +
> +/**
> + * ir_do_keyup() - internal function to signal the release of a keypress
> + * @dev:	the struct rc_dev descriptor of the device
> + * @sync:	whether or not to call input_sync
> + *
> + * This function is used internally to release a keypress, it must be
> + * called with keylock held.
> + */
> +static void ir_do_keyup(struct rc_dev *dev, bool sync)
> +{
> +	if (!dev->keypressed)
> +		return;
> +
> +	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
> +	input_report_key(dev->input_dev, dev->last_keycode, 0);
> +	led_trigger_event(led_feedback, LED_OFF);
> +	if (sync)
> +		input_sync(dev->input_dev);
> +	dev->keypressed = false;
> +}
> +
> +/**
> + * rc_keyup() - signals the release of a keypress
> + * @dev:	the struct rc_dev descriptor of the device
> + *
> + * This routine is used to signal that a key has been released on the
> + * remote control.
> + */
> +void rc_keyup(struct rc_dev *dev)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->keylock, flags);
> +	ir_do_keyup(dev, true);
> +	spin_unlock_irqrestore(&dev->keylock, flags);
> +}
> +EXPORT_SYMBOL_GPL(rc_keyup);
> +
> +/**
> + * ir_timer_keyup() - generates a keyup event after a timeout
> + * @cookie:	a pointer to the struct rc_dev for the device
> + *
> + * This routine will generate a keyup event some time after a keydown event
> + * is generated when no further activity has been detected.
> + */
> +void ir_timer_keyup(unsigned long cookie)
> +{
> +	struct rc_dev *dev = (struct rc_dev *)cookie;
> +	unsigned long flags;
> +
> +	/*
> +	 * ir->keyup_jiffies is used to prevent a race condition if a
> +	 * hardware interrupt occurs at this point and the keyup timer
> +	 * event is moved further into the future as a result.
> +	 *
> +	 * The timer will then be reactivated and this function called
> +	 * again in the future. We need to exit gracefully in that case
> +	 * to allow the input subsystem to do its auto-repeat magic or
> +	 * a keyup event might follow immediately after the keydown.
> +	 */
> +	spin_lock_irqsave(&dev->keylock, flags);
> +	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
> +		ir_do_keyup(dev, true);
> +	spin_unlock_irqrestore(&dev->keylock, flags);
> +}
> +
> +/**
> + * rc_repeat() - signals that a key is still pressed
> + * @dev:	the struct rc_dev descriptor of the device
> + *
> + * This routine is used by IR decoders when a repeat message which does
> + * not include the necessary bits to reproduce the scancode has been
> + * received.
> + */
> +void rc_repeat(struct rc_dev *dev)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->keylock, flags);
> +
> +	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
> +	input_sync(dev->input_dev);
> +	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> +
> +	if (!dev->keypressed)
> +		goto out;
> +
> +	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> +	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> +
> +out:
> +	spin_unlock_irqrestore(&dev->keylock, flags);
> +}
> +EXPORT_SYMBOL_GPL(rc_repeat);
> +
> +/**
> + * ir_do_keydown() - internal function to process a keypress
> + * @dev:	the struct rc_dev descriptor of the device
> + * @protocol:	the protocol of the keypress
> + * @scancode:   the scancode of the keypress
> + * @keycode:    the keycode of the keypress
> + * @toggle:     the toggle value of the keypress
> + *
> + * This function is used internally to register a keypress, it must be
> + * called with keylock held.
> + */
> +static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
> +			  u32 scancode, u32 keycode, u8 toggle)
> +{
> +	bool new_event = (!dev->keypressed		 ||
> +			  dev->last_protocol != protocol ||
> +			  dev->last_scancode != scancode ||
> +			  dev->last_toggle   != toggle);
> +
> +	if (new_event && dev->keypressed)
> +		ir_do_keyup(dev, false);
> +
> +	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
> +	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
> +	/*
> +	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
> +	 *	 scancode into 32 bit pieces and feed them to userspace
> +	 *	 as one or more RC_KEY_SCANCODE_PART events followed
> +	 *	 by a final RC_KEY_SCANCODE event.
> +	 */
> +	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
> +	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
> +
> +	if (new_event && keycode != KEY_RESERVED) {
> +		/* Register a keypress */
> +		dev->keypressed = true;
> +		dev->last_protocol = protocol;
> +		dev->last_scancode = scancode;
> +		dev->last_toggle = toggle;
> +		dev->last_keycode = keycode;
> +
> +		IR_dprintk(1, "%s: key down event, "
> +			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
> +			   dev->input_name, keycode, protocol, scancode);
> +		input_report_key(dev->input_dev, keycode, 1);
> +
> +		led_trigger_event(led_feedback, LED_FULL);
> +	}
> +
> +	input_sync(dev->input_dev);
> +}
> +
> +/**
> + * rc_keydown() - generates input event for a key press
> + * @dev:	the struct rc_dev descriptor of the device
> + * @protocol:	the protocol for the keypress
> + * @scancode:	the scancode for the keypress
> + * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> + *              support toggle values, this should be set to zero)
> + *
> + * This routine is used to signal that a key has been pressed on the
> + * remote control.
> + */
> +void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
> +{
> +	unsigned long flags;
> +	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> +
> +	spin_lock_irqsave(&dev->keylock, flags);
> +	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> +
> +	if (dev->keypressed) {
> +		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> +		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> +	}
> +	spin_unlock_irqrestore(&dev->keylock, flags);
> +}
> +EXPORT_SYMBOL_GPL(rc_keydown);
> +
> +/**
> + * rc_keydown_notimeout() - generates input event for a key press without
> + *                          an automatic keyup event at a later time
> + * @dev:	the struct rc_dev descriptor of the device
> + * @protocol:	the protocol for the keypress
> + * @scancode:	the scancode for the keypress
> + * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> + *              support toggle values, this should be set to zero)
> + *
> + * This routine is used to signal that a key has been pressed on the
> + * remote control. The driver must manually call rc_keyup() at a later stage.
> + */
> +void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
> +			  u32 scancode, u8 toggle)
> +{
> +	unsigned long flags;
> +	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> +
> +	spin_lock_irqsave(&dev->keylock, flags);
> +	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> +	spin_unlock_irqrestore(&dev->keylock, flags);
> +}
> +EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
> +
> +int rc_input_open(struct input_dev *idev)
> +{
> +	struct rc_dev *rdev = input_get_drvdata(idev);
> +
> +	return rc_open(rdev);
> +}
> +
> +void rc_input_close(struct input_dev *idev)
> +{
> +	struct rc_dev *rdev = input_get_drvdata(idev);
> +	rc_close(rdev);
> +}
> +
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index cc2f713..a01fce2 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -25,19 +25,9 @@
>  #include <linux/poll.h>
>  #include "rc-core-priv.h"
>  
> -/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
> -#define IR_TAB_MIN_SIZE		256
> -#define IR_TAB_MAX_SIZE		8192
>  #define RC_DEV_MAX		256
>  #define RC_RX_BUFFER_SIZE	1024
> -
> -/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
> -#define IR_KEYPRESS_TIMEOUT 250
> -
> -/* Used to keep track of known keymaps */
> -static LIST_HEAD(rc_map_list);
> -static DEFINE_SPINLOCK(rc_map_lock);
> -static struct led_trigger *led_feedback;
> +struct led_trigger *led_feedback;
>  
>  /* Used to keep track of rc devices */
>  static DEFINE_IDA(rc_ida);
> @@ -115,821 +105,6 @@ void rc_event(struct rc_dev *dev, u16 type, u16 code, u32 val)
>  }
>  EXPORT_SYMBOL_GPL(rc_event);
>  
> -static struct rc_map_list *seek_rc_map(const char *name)
> -{
> -	struct rc_map_list *map = NULL;
> -
> -	spin_lock(&rc_map_lock);
> -	list_for_each_entry(map, &rc_map_list, list) {
> -		if (!strcmp(name, map->map.name)) {
> -			spin_unlock(&rc_map_lock);
> -			return map;
> -		}
> -	}
> -	spin_unlock(&rc_map_lock);
> -
> -	return NULL;
> -}
> -
> -struct rc_map *rc_map_get(const char *name)
> -{
> -
> -	struct rc_map_list *map;
> -
> -	map = seek_rc_map(name);
> -#ifdef MODULE
> -	if (!map) {
> -		int rc = request_module("%s", name);
> -		if (rc < 0) {
> -			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
> -			return NULL;
> -		}
> -		msleep(20);	/* Give some time for IR to register */
> -
> -		map = seek_rc_map(name);
> -	}
> -#endif
> -	if (!map) {
> -		printk(KERN_ERR "IR keymap %s not found\n", name);
> -		return NULL;
> -	}
> -
> -	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
> -
> -	return &map->map;
> -}
> -EXPORT_SYMBOL_GPL(rc_map_get);
> -
> -int rc_map_register(struct rc_map_list *map)
> -{
> -	spin_lock(&rc_map_lock);
> -	list_add_tail(&map->list, &rc_map_list);
> -	spin_unlock(&rc_map_lock);
> -	return 0;
> -}
> -EXPORT_SYMBOL_GPL(rc_map_register);
> -
> -void rc_map_unregister(struct rc_map_list *map)
> -{
> -	spin_lock(&rc_map_lock);
> -	list_del(&map->list);
> -	spin_unlock(&rc_map_lock);
> -}
> -EXPORT_SYMBOL_GPL(rc_map_unregister);
> -
> -
> -static struct rc_map_table empty[] = {
> -	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
> -};
> -
> -static struct rc_map_list empty_map = {
> -	.map = {
> -		.scan    = empty,
> -		.size    = ARRAY_SIZE(empty),
> -		.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */
> -		.name    = RC_MAP_EMPTY,
> -	}
> -};
> -
> -/**
> - * ir_create_table() - initializes a scancode table
> - * @rc_map:	the rc_map to initialize
> - * @name:	name to assign to the table
> - * @size:	initial size of the table
> - * @return:	zero on success or a negative error code
> - *
> - * This routine will initialize the rc_map and will allocate
> - * memory to hold at least the specified number of elements.
> - */
> -static int ir_create_table(struct rc_map *rc_map,
> -			   const char *name, size_t size)
> -{
> -	rc_map->name = name;
> -	rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
> -	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
> -	rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
> -	if (!rc_map->scan)
> -		return -ENOMEM;
> -
> -	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
> -		   rc_map->size, rc_map->alloc);
> -	return 0;
> -}
> -
> -/**
> - * ir_free_table() - frees memory allocated by a scancode table
> - * @rc_map:	the table whose mappings need to be freed
> - *
> - * This routine will free memory alloctaed for key mappings used by given
> - * scancode table.
> - */
> -static void ir_free_table(struct rc_map *rc_map)
> -{
> -	rc_map->size = 0;
> -	kfree(rc_map->scan);
> -	rc_map->scan = NULL;
> -}
> -
> -/**
> - * ir_resize_table() - resizes a scancode table if necessary
> - * @rc_map:	the rc_map to resize
> - * @gfp_flags:	gfp flags to use when allocating memory
> - * @return:	zero on success or a negative error code
> - *
> - * This routine will shrink the rc_map if it has lots of
> - * unused entries and grow it if it is full.
> - */
> -static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
> -{
> -	unsigned int oldalloc = rc_map->alloc;
> -	unsigned int newalloc = oldalloc;
> -	struct rc_map_table *oldscan = rc_map->scan;
> -	struct rc_map_table *newscan;
> -
> -	if (rc_map->size == rc_map->len) {
> -		/* All entries in use -> grow keytable */
> -		if (rc_map->alloc >= IR_TAB_MAX_SIZE)
> -			return -ENOMEM;
> -
> -		newalloc *= 2;
> -		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
> -	}
> -
> -	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
> -		/* Less than 1/3 of entries in use -> shrink keytable */
> -		newalloc /= 2;
> -		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
> -	}
> -
> -	if (newalloc == oldalloc)
> -		return 0;
> -
> -	newscan = kmalloc(newalloc, gfp_flags);
> -	if (!newscan) {
> -		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
> -		return -ENOMEM;
> -	}
> -
> -	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
> -	rc_map->scan = newscan;
> -	rc_map->alloc = newalloc;
> -	rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
> -	kfree(oldscan);
> -	return 0;
> -}
> -
> -/**
> - * ir_update_mapping() - set a keycode in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> - * @rc_map:	scancode table to be adjusted
> - * @index:	index of the mapping that needs to be updated
> - * @keycode:	the desired keycode
> - * @return:	previous keycode assigned to the mapping
> - *
> - * This routine is used to update scancode->keycode mapping at given
> - * position.
> - */
> -static unsigned int ir_update_mapping(struct rc_dev *dev,
> -				      struct rc_map *rc_map,
> -				      unsigned int index,
> -				      unsigned int new_keycode)
> -{
> -	int old_keycode = rc_map->scan[index].keycode;
> -	int i;
> -
> -	/* Did the user wish to remove the mapping? */
> -	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
> -		IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
> -			   index, rc_map->scan[index].protocol,
> -			   (unsigned long long)rc_map->scan[index].scancode);
> -		rc_map->len--;
> -		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
> -			(rc_map->len - index) * sizeof(struct rc_map_table));
> -	} else {
> -		IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
> -			   "with key 0x%04x\n",
> -			   index,
> -			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
> -			   rc_map->scan[index].protocol,
> -			   (unsigned long long)rc_map->scan[index].scancode,
> -			   new_keycode);
> -		rc_map->scan[index].keycode = new_keycode;
> -		__set_bit(new_keycode, dev->input_dev->keybit);
> -	}
> -
> -	if (old_keycode != KEY_RESERVED) {
> -		/* A previous mapping was updated... */
> -		__clear_bit(old_keycode, dev->input_dev->keybit);
> -		/* ... but another scancode might use the same keycode */
> -		for (i = 0; i < rc_map->len; i++) {
> -			if (rc_map->scan[i].keycode == old_keycode) {
> -				__set_bit(old_keycode, dev->input_dev->keybit);
> -				break;
> -			}
> -		}
> -
> -		/* Possibly shrink the keytable, failure is not a problem */
> -		ir_resize_table(rc_map, GFP_ATOMIC);
> -	}
> -
> -	return old_keycode;
> -}
> -
> -/**
> - * ir_establish_scancode() - set a keycode in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> - * @rc_map:	scancode table to be searched
> - * @entry:	the entry to be added to the table
> - * @resize:	controls whether we are allowed to resize the table to
> - *		accomodate not yet present scancodes
> - * @return:	index of the mapping containing scancode in question
> - *		or -1U in case of failure.
> - *
> - * This routine is used to locate given scancode in rc_map.
> - * If scancode is not yet present the routine will allocate a new slot
> - * for it.
> - */
> -static unsigned int ir_establish_scancode(struct rc_dev *dev,
> -					  struct rc_map *rc_map,
> -					  struct rc_map_table *entry,
> -					  bool resize)
> -{
> -	unsigned int i;
> -
> -	/*
> -	 * Unfortunately, some hardware-based IR decoders don't provide
> -	 * all bits for the complete IR code. In general, they provide only
> -	 * the command part of the IR code. Yet, as it is possible to replace
> -	 * the provided IR with another one, it is needed to allow loading
> -	 * IR tables from other remotes. So, we support specifying a mask to
> -	 * indicate the valid bits of the scancodes.
> -	 */
> -	if (dev->scancode_mask)
> -		entry->scancode &= dev->scancode_mask;
> -
> -	/*
> -	 * First check if we already have a mapping for this command.
> -	 * Note that the keytable is sorted first on protocol and second
> -	 * on scancode (lowest to highest).
> -	 */
> -	for (i = 0; i < rc_map->len; i++) {
> -		if (rc_map->scan[i].protocol < entry->protocol)
> -			continue;
> -
> -		if (rc_map->scan[i].protocol > entry->protocol)
> -			break;
> -
> -		if (rc_map->scan[i].scancode < entry->scancode)
> -			continue;
> -
> -		if (rc_map->scan[i].scancode > entry->scancode)
> -			break;
> -
> -		return i;
> -	}
> -
> -	/* No previous mapping found, we might need to grow the table */
> -	if (rc_map->size == rc_map->len) {
> -		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
> -			return -1U;
> -	}
> -
> -	/* i is the proper index to insert our new keycode */
> -	if (i < rc_map->len)
> -		memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
> -			(rc_map->len - i) * sizeof(struct rc_map_table));
> -	rc_map->scan[i].scancode = entry->scancode;
> -	rc_map->scan[i].protocol = entry->protocol;
> -	rc_map->scan[i].keycode = KEY_RESERVED;
> -	rc_map->len++;
> -
> -	return i;
> -}
> -
> -/**
> - * guess_protocol() - heuristics to guess the protocol for a scancode
> - * @rdev:	the struct rc_dev device descriptor
> - * @return:	the guessed RC_TYPE_* protocol
> - *
> - * Internal routine to guess the current IR protocol for legacy ioctls.
> - */
> -static inline enum rc_type guess_protocol(struct rc_dev *rdev)
> -{
> -	struct rc_map *rc_map = &rdev->rc_map;
> -
> -	if (hweight64(rdev->enabled_protocols) == 1)
> -		return rc_bitmap_to_type(rdev->enabled_protocols);
> -	else if (hweight64(rdev->allowed_protocols) == 1)
> -		return rc_bitmap_to_type(rdev->allowed_protocols);
> -	else if (rc_map->len > 0)
> -		return rc_map->scan[0].protocol;
> -	else
> -		return RC_TYPE_OTHER;
> -}
> -
> -/**
> - * to_nec32() - helper function to try to convert misc NEC scancodes to NEC32
> - * @orig:	original scancode
> - * @return:	NEC32 scancode
> - *
> - * This helper routine is used to provide backwards compatibility.
> - */
> -static u32 to_nec32(u32 orig)
> -{
> -	u8 b3 = (u8)(orig >> 16);
> -	u8 b2 = (u8)(orig >>  8);
> -	u8 b1 = (u8)(orig >>  0);
> -
> -	if (orig <= 0xffff)
> -		/* Plain old NEC */
> -		return b2 << 24 | ((u8)~b2) << 16 |  b1 << 8 | ((u8)~b1);
> -	else if (orig <= 0xffffff)
> -		/* NEC extended */
> -		return b3 << 24 | b2 << 16 |  b1 << 8 | ((u8)~b1);
> -	else
> -		/* NEC32 */
> -		return orig;
> -}
> -
> -/**
> - * ir_setkeycode() - set a keycode in the scancode->keycode table
> - * @idev:	the struct input_dev device descriptor
> - * @scancode:	the desired scancode
> - * @keycode:	result
> - * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
> - *
> - * This routine is used to handle evdev EVIOCSKEY ioctl.
> - */
> -static int ir_setkeycode(struct input_dev *idev,
> -			 const struct input_keymap_entry *ke,
> -			 unsigned int *old_keycode)
> -{
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	struct rc_map *rc_map = &rdev->rc_map;
> -	unsigned int index;
> -	struct rc_map_table entry;
> -	int retval = 0;
> -	unsigned long flags;
> -
> -	entry.keycode = ke->keycode;
> -
> -	spin_lock_irqsave(&rc_map->lock, flags);
> -
> -	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
> -		index = ke->index;
> -		if (index >= rc_map->len) {
> -			retval = -EINVAL;
> -			goto out;
> -		}
> -	} else if (ke->len == sizeof(int)) {
> -		/* Legacy EVIOCSKEYCODE ioctl */
> -		u32 scancode;
> -		retval = input_scancode_to_scalar(ke, &scancode);
> -		if (retval)
> -			goto out;
> -
> -		entry.scancode = scancode;
> -		entry.protocol = guess_protocol(rdev);
> -		if (entry.protocol == RC_TYPE_NEC)
> -			entry.scancode = to_nec32(scancode);
> -
> -		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> -		if (index >= rc_map->len) {
> -			retval = -ENOMEM;
> -			goto out;
> -		}
> -	} else if (ke->len == sizeof(struct rc_scancode)) {
> -		/* New EVIOCSKEYCODE_V2 ioctl */
> -		const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
> -		entry.protocol = rke->rc.protocol;
> -		entry.scancode = rke->rc.scancode;
> -
> -		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
> -			retval = -EINVAL;
> -			goto out;
> -		}
> -
> -		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> -		if (index >= rc_map->len) {
> -			retval = -ENOMEM;
> -			goto out;
> -		}
> -	} else {
> -		retval = -EINVAL;
> -		goto out;
> -	}
> -
> -	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
> -
> -out:
> -	spin_unlock_irqrestore(&rc_map->lock, flags);
> -	return retval;
> -}
> -
> -/**
> - * ir_setkeytable() - sets several entries in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> - * @to:		the struct rc_map to copy entries to
> - * @from:	the struct rc_map to copy entries from
> - * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
> - *
> - * This routine is used to handle table initialization.
> - */
> -static int ir_setkeytable(struct rc_dev *dev,
> -			  const struct rc_map *from)
> -{
> -	struct rc_map *rc_map = &dev->rc_map;
> -	struct rc_map_table entry;
> -	unsigned int i, index;
> -	int rc;
> -
> -	rc = ir_create_table(rc_map, from->name, from->size);
> -	if (rc)
> -		return rc;
> -
> -	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
> -		   rc_map->size, rc_map->alloc);
> -
> -	for (i = 0; i < from->size; i++) {
> -		if (from->rc_type == RC_TYPE_NEC)
> -			entry.scancode = to_nec32(from->scan[i].scancode);
> -		else
> -			entry.scancode = from->scan[i].scancode;
> -
> -		entry.protocol = from->rc_type;
> -		index = ir_establish_scancode(dev, rc_map, &entry, false);
> -		if (index >= rc_map->len) {
> -			rc = -ENOMEM;
> -			break;
> -		}
> -
> -		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
> -	}
> -
> -	if (rc)
> -		ir_free_table(rc_map);
> -
> -	return rc;
> -}
> -
> -/**
> - * ir_lookup_by_scancode() - locate mapping by scancode
> - * @rc_map:	the struct rc_map to search
> - * @protocol:	protocol to look for in the table
> - * @scancode:	scancode to look for in the table
> - * @return:	index in the table, -1U if not found
> - *
> - * This routine performs binary search in RC keykeymap table for
> - * given scancode.
> - */
> -static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
> -					  u16 protocol, u64 scancode)
> -{
> -	int start = 0;
> -	int end = rc_map->len - 1;
> -	int mid;
> -	struct rc_map_table *m;
> -
> -	while (start <= end) {
> -		mid = (start + end) / 2;
> -		m = &rc_map->scan[mid];
> -
> -		if (m->protocol < protocol)
> -			start = mid + 1;
> -		else if (m->protocol > protocol)
> -			end = mid - 1;
> -		else if (m->scancode < scancode)
> -			start = mid + 1;
> -		else if (m->scancode > scancode)
> -			end = mid - 1;
> -		else
> -			return mid;
> -	}
> -
> -	return -1U;
> -}
> -
> -/**
> - * ir_getkeycode() - get a keycode from the scancode->keycode table
> - * @idev:	the struct input_dev device descriptor
> - * @scancode:	the desired scancode
> - * @keycode:	used to return the keycode, if found, or KEY_RESERVED
> - * @return:	always returns zero.
> - *
> - * This routine is used to handle evdev EVIOCGKEY ioctl.
> - */
> -static int ir_getkeycode(struct input_dev *idev,
> -			 struct input_keymap_entry *ke)
> -{
> -	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	struct rc_map *rc_map = &rdev->rc_map;
> -	struct rc_map_table *entry;
> -	unsigned long flags;
> -	unsigned int index;
> -	int retval;
> -
> -	spin_lock_irqsave(&rc_map->lock, flags);
> -
> -	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
> -		index = ke->index;
> -	} else if (ke->len == sizeof(int)) {
> -		/* Legacy EVIOCGKEYCODE ioctl */
> -		u32 scancode;
> -		u16 protocol;
> -
> -		retval = input_scancode_to_scalar(ke, &scancode);
> -		if (retval)
> -			goto out;
> -
> -		protocol = guess_protocol(rdev);
> -		if (protocol == RC_TYPE_NEC)
> -			scancode = to_nec32(scancode);
> -
> -		index = ir_lookup_by_scancode(rc_map, protocol, scancode);
> -
> -	} else if (ke->len == sizeof(struct rc_scancode)) {
> -		/* New EVIOCGKEYCODE_V2 ioctl */
> -		if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[2]) {
> -			retval = -EINVAL;
> -			goto out;
> -		}
> -
> -		index = ir_lookup_by_scancode(rc_map,
> -					      rke->rc.protocol, rke->rc.scancode);
> -
> -	} else {
> -		retval = -EINVAL;
> -		goto out;
> -	}
> -
> -	if (index < rc_map->len) {
> -		entry = &rc_map->scan[index];
> -		ke->index = index;
> -		ke->keycode = entry->keycode;
> -		if (ke->len == sizeof(int)) {
> -			u32 scancode = entry->scancode;
> -			memcpy(ke->scancode, &scancode, sizeof(scancode));
> -		} else {
> -			ke->len = sizeof(struct rc_scancode);
> -			rke->rc.protocol = entry->protocol;
> -			rke->rc.scancode = entry->scancode;
> -		}
> -
> -	} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
> -		/*
> -		 * We do not really know the valid range of scancodes
> -		 * so let's respond with KEY_RESERVED to anything we
> -		 * do not have mapping for [yet].
> -		 */
> -		ke->index = index;
> -		ke->keycode = KEY_RESERVED;
> -	} else {
> -		retval = -EINVAL;
> -		goto out;
> -	}
> -
> -	retval = 0;
> -
> -out:
> -	spin_unlock_irqrestore(&rc_map->lock, flags);
> -	return retval;
> -}
> -
> -/**
> - * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol to look for
> - * @scancode:	the scancode to look for
> - * @return:	the corresponding keycode, or KEY_RESERVED
> - *
> - * This routine is used by drivers which need to convert a scancode to a
> - * keycode. Normally it should not be used since drivers should have no
> - * interest in keycodes.
> - */
> -u32 rc_g_keycode_from_table(struct rc_dev *dev,
> -			    enum rc_type protocol, u64 scancode)
> -{
> -	struct rc_map *rc_map = &dev->rc_map;
> -	unsigned int keycode;
> -	unsigned int index;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&rc_map->lock, flags);
> -
> -	index = ir_lookup_by_scancode(rc_map, protocol, scancode);
> -	keycode = index < rc_map->len ?
> -			rc_map->scan[index].keycode : KEY_RESERVED;
> -
> -	spin_unlock_irqrestore(&rc_map->lock, flags);
> -
> -	if (keycode != KEY_RESERVED)
> -		IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
> -			   dev->input_name, protocol,
> -			   (unsigned long long)scancode, keycode);
> -
> -	return keycode;
> -}
> -EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
> -
> -/**
> - * ir_do_keyup() - internal function to signal the release of a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> - * @sync:	whether or not to call input_sync
> - *
> - * This function is used internally to release a keypress, it must be
> - * called with keylock held.
> - */
> -static void ir_do_keyup(struct rc_dev *dev, bool sync)
> -{
> -	if (!dev->keypressed)
> -		return;
> -
> -	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
> -	input_report_key(dev->input_dev, dev->last_keycode, 0);
> -	led_trigger_event(led_feedback, LED_OFF);
> -	if (sync)
> -		input_sync(dev->input_dev);
> -	dev->keypressed = false;
> -}
> -
> -/**
> - * rc_keyup() - signals the release of a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> - *
> - * This routine is used to signal that a key has been released on the
> - * remote control.
> - */
> -void rc_keyup(struct rc_dev *dev)
> -{
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keyup(dev, true);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -EXPORT_SYMBOL_GPL(rc_keyup);
> -
> -/**
> - * ir_timer_keyup() - generates a keyup event after a timeout
> - * @cookie:	a pointer to the struct rc_dev for the device
> - *
> - * This routine will generate a keyup event some time after a keydown event
> - * is generated when no further activity has been detected.
> - */
> -static void ir_timer_keyup(unsigned long cookie)
> -{
> -	struct rc_dev *dev = (struct rc_dev *)cookie;
> -	unsigned long flags;
> -
> -	/*
> -	 * ir->keyup_jiffies is used to prevent a race condition if a
> -	 * hardware interrupt occurs at this point and the keyup timer
> -	 * event is moved further into the future as a result.
> -	 *
> -	 * The timer will then be reactivated and this function called
> -	 * again in the future. We need to exit gracefully in that case
> -	 * to allow the input subsystem to do its auto-repeat magic or
> -	 * a keyup event might follow immediately after the keydown.
> -	 */
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
> -		ir_do_keyup(dev, true);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -
> -/**
> - * rc_repeat() - signals that a key is still pressed
> - * @dev:	the struct rc_dev descriptor of the device
> - *
> - * This routine is used by IR decoders when a repeat message which does
> - * not include the necessary bits to reproduce the scancode has been
> - * received.
> - */
> -void rc_repeat(struct rc_dev *dev)
> -{
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&dev->keylock, flags);
> -
> -	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
> -	input_sync(dev->input_dev);
> -	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> -
> -	if (!dev->keypressed)
> -		goto out;
> -
> -	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> -	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> -
> -out:
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -EXPORT_SYMBOL_GPL(rc_repeat);
> -
> -/**
> - * ir_do_keydown() - internal function to process a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol of the keypress
> - * @scancode:   the scancode of the keypress
> - * @keycode:    the keycode of the keypress
> - * @toggle:     the toggle value of the keypress
> - *
> - * This function is used internally to register a keypress, it must be
> - * called with keylock held.
> - */
> -static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
> -			  u32 scancode, u32 keycode, u8 toggle)
> -{
> -	bool new_event = (!dev->keypressed		 ||
> -			  dev->last_protocol != protocol ||
> -			  dev->last_scancode != scancode ||
> -			  dev->last_toggle   != toggle);
> -
> -	if (new_event && dev->keypressed)
> -		ir_do_keyup(dev, false);
> -
> -	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
> -	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
> -	/*
> -	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
> -	 *	 scancode into 32 bit pieces and feed them to userspace
> -	 *	 as one or more RC_KEY_SCANCODE_PART events followed
> -	 *	 by a final RC_KEY_SCANCODE event.
> -	 */
> -	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
> -	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
> -
> -	if (new_event && keycode != KEY_RESERVED) {
> -		/* Register a keypress */
> -		dev->keypressed = true;
> -		dev->last_protocol = protocol;
> -		dev->last_scancode = scancode;
> -		dev->last_toggle = toggle;
> -		dev->last_keycode = keycode;
> -
> -		IR_dprintk(1, "%s: key down event, "
> -			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
> -			   dev->input_name, keycode, protocol, scancode);
> -		input_report_key(dev->input_dev, keycode, 1);
> -
> -		led_trigger_event(led_feedback, LED_FULL);
> -	}
> -
> -	input_sync(dev->input_dev);
> -}
> -
> -/**
> - * rc_keydown() - generates input event for a key press
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol for the keypress
> - * @scancode:	the scancode for the keypress
> - * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> - *              support toggle values, this should be set to zero)
> - *
> - * This routine is used to signal that a key has been pressed on the
> - * remote control.
> - */
> -void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
> -{
> -	unsigned long flags;
> -	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> -
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> -
> -	if (dev->keypressed) {
> -		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> -		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> -	}
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -EXPORT_SYMBOL_GPL(rc_keydown);
> -
> -/**
> - * rc_keydown_notimeout() - generates input event for a key press without
> - *                          an automatic keyup event at a later time
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol for the keypress
> - * @scancode:	the scancode for the keypress
> - * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> - *              support toggle values, this should be set to zero)
> - *
> - * This routine is used to signal that a key has been pressed on the
> - * remote control. The driver must manually call rc_keyup() at a later stage.
> - */
> -void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
> -			  u32 scancode, u8 toggle)
> -{
> -	unsigned long flags;
> -	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> -
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
> -
>  int rc_open(struct rc_dev *dev)
>  {
>  	int err = 0;
> @@ -950,13 +125,6 @@ int rc_open(struct rc_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(rc_open);
>  
> -static int rc_input_open(struct input_dev *idev)
> -{
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -
> -	return rc_open(rdev);
> -}
> -
>  void rc_close(struct rc_dev *dev)
>  {
>  	mutex_lock(&dev->lock);
> @@ -968,12 +136,6 @@ void rc_close(struct rc_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(rc_close);
>  
> -static void rc_input_close(struct input_dev *idev)
> -{
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	rc_close(rdev);
> -}
> -
>  /* class for /sys/class/rc */
>  static char *rc_devnode(struct device *dev, umode_t *mode)
>  {
> @@ -2143,6 +1305,19 @@ void rc_unregister_device(struct rc_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(rc_unregister_device);
>  
> +static struct rc_map_table empty[] = {
> +	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
> +};
> +
> +static struct rc_map_list empty_map = {
> +	.map = {
> +		.scan    = empty,
> +		.size    = ARRAY_SIZE(empty),
> +		.rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
> +		.name    = RC_MAP_EMPTY,
> +	}
> +};
> +
>  static int __init rc_core_init(void)
>  {
>  	int err;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 32/49] rc-core: prepare for multiple keytables
  2014-04-03 23:33 ` [PATCH 32/49] rc-core: prepare for multiple keytables David Härdeman
@ 2014-07-25 22:52   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 22:52 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:33:57 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Introduce struct rc_keytable which essentially maintains an input device
> and a table with scancode,protocol <-> keycode mappings. Move the relevant
> members from struct rc_dev into struct rc_keytable.

I can't apply this patch (and probably the other patches above patch 31,
because of the file split.

> This is in preparation for supporting multiple keytables, where each
> keytable would correspond to one physical remote controller, each with
> its own keymap and input device for reporting events to userspace.

Again, it deserves some RFC discussions. Why do you need multiple
keytables? How to update them from userspace without breaking the
existing support? 

Also, there are some devices where it is an impossible goal. For
example, there are several dib0700 devices that are identical to
the dibcom SDK hardware. Even the USB ID is the same. The only thing
that differs one device from the others is the IR layout.

This is solved at Kernel level with a table with several devices
inside it.

Ok, we could still use multiple keytables and associate those
generic USB ID to those tables, but it seems overkill, at least
at a first glance.

P.S.: I'll just tag the patches related to multiple keytables
as "Changes requested" just like this one without further notice,
as I'm expecting you to submit this patch series as a separate
patchset, after we have an agreement on your RFC.

Regards,
Mauro

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-core-priv.h |   16 +-
>  drivers/media/rc/rc-keytable.c  |  341 ++++++++++++++++++++++-----------------
>  drivers/media/rc/rc-main.c      |  224 +++++++++++---------------
>  include/media/rc-core.h         |   62 +++++--
>  4 files changed, 338 insertions(+), 305 deletions(-)
> 
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index 6da8a0d..7a7770e 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -158,16 +158,12 @@ void ir_raw_init(void);
>  /*
>   * Methods from rc-keytable.c to be used internally
>   */
> -void ir_timer_keyup(unsigned long cookie);
> -int rc_input_open(struct input_dev *idev);
> -void rc_input_close(struct input_dev *idev);
> -int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from);
> -void ir_free_table(struct rc_map *rc_map);
> -int ir_getkeycode(struct input_dev *idev,
> -		  struct input_keymap_entry *ke);
> -int ir_setkeycode(struct input_dev *idev,
> -		  const struct input_keymap_entry *ke,
> -		  unsigned int *old_keycode);
> +void rc_keytable_keyup(struct rc_keytable *kt);
> +void rc_keytable_repeat(struct rc_keytable *kt);
> +void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
> +			 u32 scancode, u8 toggle, bool autokeyup);
> +int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map);
> +void rc_keytable_del(struct rc_dev *dev);
>  
>  /* Only to be used by rc-core and ir-lirc-codec */
>  void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
> diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
> index 25faeba..0f1b817 100644
> --- a/drivers/media/rc/rc-keytable.c
> +++ b/drivers/media/rc/rc-keytable.c
> @@ -187,7 +187,7 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
>  
>  /**
>   * ir_update_mapping() - set a keycode in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> + * @kt:		the struct rc_keytable
>   * @rc_map:	scancode table to be adjusted
>   * @index:	index of the mapping that needs to be updated
>   * @keycode:	the desired keycode
> @@ -196,7 +196,7 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
>   * This routine is used to update scancode->keycode mapping at given
>   * position.
>   */
> -static unsigned int ir_update_mapping(struct rc_dev *dev,
> +static unsigned int ir_update_mapping(struct rc_keytable *kt,
>  				      struct rc_map *rc_map,
>  				      unsigned int index,
>  				      unsigned int new_keycode)
> @@ -221,16 +221,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
>  			   (unsigned long long)rc_map->scan[index].scancode,
>  			   new_keycode);
>  		rc_map->scan[index].keycode = new_keycode;
> -		__set_bit(new_keycode, dev->input_dev->keybit);
> +		__set_bit(new_keycode, kt->idev->keybit);
>  	}
>  
>  	if (old_keycode != KEY_RESERVED) {
>  		/* A previous mapping was updated... */
> -		__clear_bit(old_keycode, dev->input_dev->keybit);
> +		__clear_bit(old_keycode, kt->idev->keybit);
>  		/* ... but another scancode might use the same keycode */
>  		for (i = 0; i < rc_map->len; i++) {
>  			if (rc_map->scan[i].keycode == old_keycode) {
> -				__set_bit(old_keycode, dev->input_dev->keybit);
> +				__set_bit(old_keycode, kt->idev->keybit);
>  				break;
>  			}
>  		}
> @@ -244,7 +244,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
>  
>  /**
>   * ir_establish_scancode() - set a keycode in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> + * @kt:		the struct rc_keytable descriptor
>   * @rc_map:	scancode table to be searched
>   * @entry:	the entry to be added to the table
>   * @resize:	controls whether we are allowed to resize the table to
> @@ -256,7 +256,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
>   * If scancode is not yet present the routine will allocate a new slot
>   * for it.
>   */
> -static unsigned int ir_establish_scancode(struct rc_dev *dev,
> +static unsigned int ir_establish_scancode(struct rc_keytable *kt,
>  					  struct rc_map *rc_map,
>  					  struct rc_map_table *entry,
>  					  bool resize)
> @@ -271,8 +271,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
>  	 * IR tables from other remotes. So, we support specifying a mask to
>  	 * indicate the valid bits of the scancodes.
>  	 */
> -	if (dev->scancode_mask)
> -		entry->scancode &= dev->scancode_mask;
> +	if (kt->dev->scancode_mask)
> +		entry->scancode &= kt->dev->scancode_mask;
>  
>  	/*
>  	 * First check if we already have a mapping for this command.
> @@ -322,7 +322,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
>   */
>  static inline enum rc_type guess_protocol(struct rc_dev *rdev)
>  {
> -	struct rc_map *rc_map = &rdev->rc_map;
> +	struct rc_map *rc_map = &rdev->kt->rc_map;
>  
>  	if (hweight64(rdev->enabled_protocols) == 1)
>  		return rc_bitmap_to_type(rdev->enabled_protocols);
> @@ -367,12 +367,13 @@ static u32 to_nec32(u32 orig)
>   *
>   * This routine is used to handle evdev EVIOCSKEY ioctl.
>   */
> -int ir_setkeycode(struct input_dev *idev,
> -		  const struct input_keymap_entry *ke,
> -		  unsigned int *old_keycode)
> +static int ir_setkeycode(struct input_dev *idev,
> +			 const struct input_keymap_entry *ke,
> +			 unsigned int *old_keycode)
>  {
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	struct rc_map *rc_map = &rdev->rc_map;
> +	struct rc_keytable *kt = input_get_drvdata(idev);
> +	struct rc_dev *rdev = kt->dev;
> +	struct rc_map *rc_map = &kt->rc_map;
>  	unsigned int index;
>  	struct rc_map_table entry;
>  	int retval = 0;
> @@ -400,7 +401,7 @@ int ir_setkeycode(struct input_dev *idev,
>  		if (entry.protocol == RC_TYPE_NEC)
>  			entry.scancode = to_nec32(scancode);
>  
> -		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> +		index = ir_establish_scancode(kt, rc_map, &entry, true);
>  		if (index >= rc_map->len) {
>  			retval = -ENOMEM;
>  			goto out;
> @@ -416,7 +417,7 @@ int ir_setkeycode(struct input_dev *idev,
>  			goto out;
>  		}
>  
> -		index = ir_establish_scancode(rdev, rc_map, &entry, true);
> +		index = ir_establish_scancode(kt, rc_map, &entry, true);
>  		if (index >= rc_map->len) {
>  			retval = -ENOMEM;
>  			goto out;
> @@ -426,7 +427,7 @@ int ir_setkeycode(struct input_dev *idev,
>  		goto out;
>  	}
>  
> -	*old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
> +	*old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
>  
>  out:
>  	spin_unlock_irqrestore(&rc_map->lock, flags);
> @@ -435,16 +436,16 @@ out:
>  
>  /**
>   * ir_setkeytable() - sets several entries in the scancode->keycode table
> - * @dev:	the struct rc_dev device descriptor
> + * @kt:		the struct rc_keytable descriptor
>   * @to:		the struct rc_map to copy entries to
>   * @from:	the struct rc_map to copy entries from
>   * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
>   *
>   * This routine is used to handle table initialization.
>   */
> -int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
> +int rc_setkeytable(struct rc_keytable *kt, const struct rc_map *from)
>  {
> -	struct rc_map *rc_map = &dev->rc_map;
> +	struct rc_map *rc_map = &kt->rc_map;
>  	struct rc_map_table entry;
>  	unsigned int i, index;
>  	int rc;
> @@ -463,13 +464,13 @@ int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
>  			entry.scancode = from->scan[i].scancode;
>  
>  		entry.protocol = from->rc_type;
> -		index = ir_establish_scancode(dev, rc_map, &entry, false);
> +		index = ir_establish_scancode(kt, rc_map, &entry, false);
>  		if (index >= rc_map->len) {
>  			rc = -ENOMEM;
>  			break;
>  		}
>  
> -		ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
> +		ir_update_mapping(kt, rc_map, index, from->scan[i].keycode);
>  	}
>  
>  	if (rc)
> @@ -528,8 +529,9 @@ int ir_getkeycode(struct input_dev *idev,
>  		  struct input_keymap_entry *ke)
>  {
>  	struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	struct rc_map *rc_map = &rdev->rc_map;
> +	struct rc_keytable *kt = input_get_drvdata(idev);
> +	struct rc_dev *rdev = kt->dev;
> +	struct rc_map *rc_map = &kt->rc_map;
>  	struct rc_map_table *entry;
>  	unsigned long flags;
>  	unsigned int index;
> @@ -616,7 +618,7 @@ out:
>  u32 rc_g_keycode_from_table(struct rc_dev *dev,
>  			    enum rc_type protocol, u64 scancode)
>  {
> -	struct rc_map *rc_map = &dev->rc_map;
> +	struct rc_map *rc_map = &dev->kt->rc_map;
>  	unsigned int keycode;
>  	unsigned int index;
>  	unsigned long flags;
> @@ -639,53 +641,51 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
>  EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
>  
>  /**
> - * ir_do_keyup() - internal function to signal the release of a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> + * rc_do_keyup() - internal function to signal the release of a keypress
> + * @kt:		the keytable
>   * @sync:	whether or not to call input_sync
>   *
>   * This function is used internally to release a keypress, it must be
>   * called with keylock held.
>   */
> -static void ir_do_keyup(struct rc_dev *dev, bool sync)
> +static void rc_do_keyup(struct rc_keytable *kt, bool sync)
>  {
> -	if (!dev->keypressed)
> +	if (!kt->keypressed)
>  		return;
>  
> -	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
> -	input_report_key(dev->input_dev, dev->last_keycode, 0);
> +	IR_dprintk(1, "keyup key 0x%04x\n", kt->last_keycode);
> +	input_report_key(kt->idev, kt->last_keycode, 0);
>  	led_trigger_event(led_feedback, LED_OFF);
>  	if (sync)
> -		input_sync(dev->input_dev);
> -	dev->keypressed = false;
> +		input_sync(kt->idev);
> +	kt->keypressed = false;
>  }
>  
>  /**
> - * rc_keyup() - signals the release of a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> + * rc_keytable_keyup() - signals the release of a keypress
> + * @kt:		the keytable
>   *
> - * This routine is used to signal that a key has been released on the
> - * remote control.
> + * This routine is used to generate input keyup events.
>   */
> -void rc_keyup(struct rc_dev *dev)
> +void rc_keytable_keyup(struct rc_keytable *kt)
>  {
>  	unsigned long flags;
>  
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keyup(dev, true);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> +	spin_lock_irqsave(&kt->keylock, flags);
> +	rc_do_keyup(kt, true);
> +	spin_unlock_irqrestore(&kt->keylock, flags);
>  }
> -EXPORT_SYMBOL_GPL(rc_keyup);
>  
>  /**
>   * ir_timer_keyup() - generates a keyup event after a timeout
> - * @cookie:	a pointer to the struct rc_dev for the device
> + * @cookie:	a pointer to the struct rc_keytable
>   *
>   * This routine will generate a keyup event some time after a keydown event
>   * is generated when no further activity has been detected.
>   */
> -void ir_timer_keyup(unsigned long cookie)
> +static void rc_timer_keyup(unsigned long cookie)
>  {
> -	struct rc_dev *dev = (struct rc_dev *)cookie;
> +	struct rc_keytable *kt = (struct rc_keytable *)cookie;
>  	unsigned long flags;
>  
>  	/*
> @@ -698,154 +698,203 @@ void ir_timer_keyup(unsigned long cookie)
>  	 * to allow the input subsystem to do its auto-repeat magic or
>  	 * a keyup event might follow immediately after the keydown.
>  	 */
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
> -		ir_do_keyup(dev, true);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> +	spin_lock_irqsave(&kt->keylock, flags);
> +	if (time_is_before_eq_jiffies(kt->keyup_jiffies))
> +		rc_do_keyup(kt, true);
> +	spin_unlock_irqrestore(&kt->keylock, flags);
>  }
>  
>  /**
> - * rc_repeat() - signals that a key is still pressed
> - * @dev:	the struct rc_dev descriptor of the device
> + * rc_keytable_repeat() - signals that a key is still pressed
> + * @kt:		the keytable
>   *
>   * This routine is used by IR decoders when a repeat message which does
>   * not include the necessary bits to reproduce the scancode has been
>   * received.
>   */
> -void rc_repeat(struct rc_dev *dev)
> +void rc_keytable_repeat(struct rc_keytable *kt)
>  {
>  	unsigned long flags;
>  
> -	spin_lock_irqsave(&dev->keylock, flags);
> +	spin_lock_irqsave(&kt->keylock, flags);
>  
> -	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
> -	input_sync(dev->input_dev);
> -	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> +	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
> +	input_sync(kt->idev);
>  
> -	if (!dev->keypressed)
> +	if (!kt->keypressed)
>  		goto out;
>  
> -	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> -	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> +	kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> +	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
>  
>  out:
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> +	spin_unlock_irqrestore(&kt->keylock, flags);
>  }
> -EXPORT_SYMBOL_GPL(rc_repeat);
>  
>  /**
> - * ir_do_keydown() - internal function to process a keypress
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol of the keypress
> - * @scancode:   the scancode of the keypress
> - * @keycode:    the keycode of the keypress
> - * @toggle:     the toggle value of the keypress
> + * rc_keytable_keydown() - generates input event for a key press
> + * @kt:		the struct rc_keytable descriptor of the keytable
> + * @protocol:	the protocol for the keypress
> + * @scancode:	the scancode for the keypress
> + * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
> + *		support toggle values, this should be set to zero)
> + * @autoup:	should an automatic keyup event be generated in the future
>   *
> - * This function is used internally to register a keypress, it must be
> - * called with keylock held.
> + * This routine is used to signal that a keypress has been detected.
>   */
> -static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
> -			  u32 scancode, u32 keycode, u8 toggle)
> +void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
> +			 u32 scancode, u8 toggle, bool autoup)
>  {
> -	bool new_event = (!dev->keypressed		 ||
> -			  dev->last_protocol != protocol ||
> -			  dev->last_scancode != scancode ||
> -			  dev->last_toggle   != toggle);
> +	unsigned long flags;
> +	u32 keycode;
> +	bool new_event;
>  
> -	if (new_event && dev->keypressed)
> -		ir_do_keyup(dev, false);
> +	spin_lock_irqsave(&kt->keylock, flags);
>  
> -	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
> -	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
> -	/*
> -	 * NOTE: If we ever get > 32 bit scancodes, we need to break the
> -	 *	 scancode into 32 bit pieces and feed them to userspace
> -	 *	 as one or more RC_KEY_SCANCODE_PART events followed
> -	 *	 by a final RC_KEY_SCANCODE event.
> -	 */
> -	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
> -	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
> +	keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
> +	new_event = (!kt->keypressed ||
> +		     kt->last_protocol != protocol ||
> +		     kt->last_scancode != scancode ||
> +		     kt->last_toggle != toggle);
> +
> +	if (new_event && kt->keypressed)
> +		rc_do_keyup(kt, false);
> +
> +	input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
>  
>  	if (new_event && keycode != KEY_RESERVED) {
>  		/* Register a keypress */
> -		dev->keypressed = true;
> -		dev->last_protocol = protocol;
> -		dev->last_scancode = scancode;
> -		dev->last_toggle = toggle;
> -		dev->last_keycode = keycode;
> +		kt->keypressed = true;
> +		kt->last_protocol = protocol;
> +		kt->last_scancode = scancode;
> +		kt->last_toggle = toggle;
> +		kt->last_keycode = keycode;
>  
>  		IR_dprintk(1, "%s: key down event, "
> -			   "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
> -			   dev->input_name, keycode, protocol, scancode);
> -		input_report_key(dev->input_dev, keycode, 1);
> -
> -		led_trigger_event(led_feedback, LED_FULL);
> +			   "key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
> +			   kt->dev->input_name, keycode, protocol,
> +			   (long long unsigned)scancode);
> +		input_report_key(kt->idev, keycode, 1);
>  	}
> +	input_sync(kt->idev);
>  
> -	input_sync(dev->input_dev);
> +	if (autoup && kt->keypressed) {
> +		kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> +		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
> +	}
> +	spin_unlock_irqrestore(&kt->keylock, flags);
>  }
>  
> -/**
> - * rc_keydown() - generates input event for a key press
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol for the keypress
> - * @scancode:	the scancode for the keypress
> - * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> - *              support toggle values, this should be set to zero)
> - *
> - * This routine is used to signal that a key has been pressed on the
> - * remote control.
> - */
> -void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
> +static int rc_input_open(struct input_dev *idev)
>  {
> -	unsigned long flags;
> -	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> +	struct rc_keytable *kt = input_get_drvdata(idev);
>  
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> +	return rc_open(kt->dev);
> +}
>  
> -	if (dev->keypressed) {
> -		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
> -		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
> -	}
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> +static void rc_input_close(struct input_dev *idev)
> +{
> +	struct rc_keytable *kt = input_get_drvdata(idev);
> +
> +	rc_close(kt->dev);
>  }
> -EXPORT_SYMBOL_GPL(rc_keydown);
>  
>  /**
> - * rc_keydown_notimeout() - generates input event for a key press without
> - *                          an automatic keyup event at a later time
> - * @dev:	the struct rc_dev descriptor of the device
> - * @protocol:	the protocol for the keypress
> - * @scancode:	the scancode for the keypress
> - * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
> - *              support toggle values, this should be set to zero)
> + * rc_keytable_add() - adds a new keytable
> + * @dev:	the struct rc_dev device this keytable should belong to
> + * @rc_map:	the keymap to use for the new keytable
> + * @return:	zero on success or a negative error code
>   *
> - * This routine is used to signal that a key has been pressed on the
> - * remote control. The driver must manually call rc_keyup() at a later stage.
> + * This function add a new keytable (essentially the combination of a keytable
> + * and an input device along with some state (whether a key is currently
> + * pressed or not, etc).
>   */
> -void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
> -			  u32 scancode, u8 toggle)
> +int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
>  {
> -	unsigned long flags;
> -	u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
> +	struct rc_keytable *kt;
> +	struct input_dev *idev = NULL;
> +	int err;
>  
> -	spin_lock_irqsave(&dev->keylock, flags);
> -	ir_do_keydown(dev, protocol, scancode, keycode, toggle);
> -	spin_unlock_irqrestore(&dev->keylock, flags);
> -}
> -EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
> +	kt = kzalloc(sizeof(*kt), GFP_KERNEL);
> +	if (!kt) {
> +		err = -ENOMEM;
> +		goto out;
> +	}
>  
> -int rc_input_open(struct input_dev *idev)
> -{
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> +	idev = input_allocate_device();
> +	if (!idev) {
> +		err = -ENOMEM;
> +		goto out;
> +	}
> +
> +	kt->idev = idev;
> +	kt->dev = dev;
> +	spin_lock_init(&kt->keylock);
> +	spin_lock_init(&kt->rc_map.lock);
> +	idev->getkeycode = ir_getkeycode;
> +	idev->setkeycode = ir_setkeycode;
> +	idev->open = rc_input_open;
> +	idev->close = rc_input_close;
> +	set_bit(EV_KEY, idev->evbit);
> +	set_bit(EV_REP, idev->evbit);
> +	set_bit(EV_MSC, idev->evbit);
> +	set_bit(MSC_SCAN, idev->mscbit);
> +	input_set_drvdata(idev, kt);
> +	setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
> +
> +	err = rc_setkeytable(kt, rc_map);
> +	if (err)
> +		goto out;
> +
> +	idev->dev.parent = &dev->dev;
> +	memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id));
> +	idev->phys = dev->input_phys;
> +	idev->name = dev->input_name;
>  
> -	return rc_open(rdev);
> +	err = input_register_device(idev);
> +	if (err)
> +		goto out;
> +
> +	/*
> +	 * Default delay of 250ms is too short for some protocols, especially
> +	 * since the timeout is currently set to 250ms. Increase it to 500ms,
> +	 * to avoid wrong repetition of the keycodes. Note that this must be
> +	 * set after the call to input_register_device().
> +	 */
> +	idev->rep[REP_DELAY] = 500;
> +
> +	/*
> +	 * As a repeat event on protocols like RC-5 and NEC take as long as
> +	 * 110/114ms, using 33ms as a repeat period is not the right thing
> +	 * to do.
> +	 */
> +	idev->rep[REP_PERIOD] = 125;
> +
> +	dev->kt = kt;
> +	return 0;
> +
> +out:
> +	ir_free_table(&kt->rc_map);
> +	input_free_device(idev);
> +	kfree(kt);
> +	return err;
>  }
>  
> -void rc_input_close(struct input_dev *idev)
> +/**
> + * rc_keytable_del() - unregisters and deletes a keytable
> + * @dev:       the struct rc_dev device with the keytable
> + *
> + * This function unregisters and deletes an existing keytable.
> + */
> +void rc_keytable_del(struct rc_dev *dev)
>  {
> -	struct rc_dev *rdev = input_get_drvdata(idev);
> -	rc_close(rdev);
> +	if (!dev->kt)
> +		return;
> +
> +	del_timer_sync(&dev->kt->timer_keyup);
> +	ir_free_table(&dev->kt->rc_map);
> +	input_unregister_device(dev->kt->idev);
> +	kfree(dev->kt);
> +	dev->kt = NULL;
>  }
>  
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index a01fce2..23a6701 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -136,6 +136,54 @@ void rc_close(struct rc_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(rc_close);
>  
> +/**
> + * rc_do_keydown() - report a key press event
> + * @dev:	the struct rc_dev descriptor of the device
> + * @protocol:	the protocol for the keypress
> + * @scancode:	the scancode for the keypress
> + * @toggle:	the toggle value (protocol dependent, if the protocol doesn't
> + *		support toggle values, this should be set to zero)
> + * @autoup:	whether to automatically generate a keyup event later
> + *
> + * Report that a keypress has been received.
> + */
> +void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
> +		   u32 scancode, u8 toggle, bool autoup)
> +{
> +	led_trigger_event(led_feedback, LED_FULL);
> +	rc_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
> +	rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
> +	rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
> +	rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
> +}
> +EXPORT_SYMBOL_GPL(rc_do_keydown);
> +
> +/**
> + * rc_keyup() - signals the release of a keypress
> + * @dev:       the struct rc_dev descriptor of the device
> + *
> + * Report that a key is no longer pressed.
> + */
> +void rc_keyup(struct rc_dev *dev)
> +{
> +	rc_keytable_keyup(dev->kt);
> +}
> +EXPORT_SYMBOL_GPL(rc_keyup);
> +
> +/**
> + * rc_repeat() - report that a key is still pressed
> + * @dev:	the struct rc_dev descriptor of the device
> + *
> + * Report that a repeat message (which does not include the necessary bits to
> + * reproduce the scancode) has been received.
> + */
> +void rc_repeat(struct rc_dev *dev)
> +{
> +	rc_keytable_repeat(dev->kt);
> +	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> +}
> +EXPORT_SYMBOL_GPL(rc_repeat);
> +
>  /* class for /sys/class/rc */
>  static char *rc_devnode(struct device *dev, umode_t *mode)
>  {
> @@ -214,8 +262,8 @@ struct rc_filter_attribute {
>   * It returns the protocol names of supported protocols.
>   * Enabled protocols are printed in brackets.
>   *
> - * dev->lock is taken to guard against races between device
> - * registration, store_protocols and show_protocols.
> + * dev->lock is taken to guard against races between store_protocols and
> + * show_protocols.
>   */
>  static ssize_t show_protocols(struct device *device,
>  			      struct device_attribute *mattr, char *buf)
> @@ -344,8 +392,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
>   * See parse_protocol_change() for the valid commands.
>   * Returns @len on success or a negative error code.
>   *
> - * dev->lock is taken to guard against races between device
> - * registration, store_protocols and show_protocols.
> + * dev->lock is taken to guard against races between store_protocols and
> + * show_protocols.
>   */
>  static ssize_t store_protocols(struct device *device,
>  			       struct device_attribute *mattr,
> @@ -445,8 +493,8 @@ out:
>   * Bits of the filter value corresponding to set bits in the filter mask are
>   * compared against input scancodes and non-matching scancodes are discarded.
>   *
> - * dev->lock is taken to guard against races between device registration,
> - * store_filter and show_filter.
> + * dev->lock is taken to guard against races between store_filter and
> + * show_filter.
>   */
>  static ssize_t show_filter(struct device *device,
>  			   struct device_attribute *attr,
> @@ -492,8 +540,8 @@ static ssize_t show_filter(struct device *device,
>   * Bits of the filter value corresponding to set bits in the filter mask are
>   * compared against input scancodes and non-matching scancodes are discarded.
>   *
> - * dev->lock is taken to guard against races between device registration,
> - * store_filter and show_filter.
> + * dev->lock is taken to guard against races between store_filter and
> + * show_filter.
>   */
>  static ssize_t store_filter(struct device *device,
>  			    struct device_attribute *attr,
> @@ -964,8 +1012,8 @@ static void rc_dev_release(struct device *device)
>  {
>  	struct rc_dev *dev = to_rc_dev(device);
>  
> -	if (dev->input_dev)
> -		input_free_device(dev->input_dev);
> +	if (dev->driver_type == RC_DRIVER_IR_RAW)
> +		ir_raw_event_unregister(dev);
>  
>  	kfifo_free(&dev->txfifo);
>  	kfree(dev);
> @@ -983,11 +1031,8 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
>  {
>  	struct rc_dev *dev = to_rc_dev(device);
>  
> -	if (!dev || !dev->input_dev)
> -		return -ENODEV;
> -
> -	if (dev->rc_map.name)
> -		ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
> +	if (dev->map_name)
> +		ADD_HOTPLUG_VAR("NAME=%s", dev->map_name);
>  	if (dev->driver_name)
>  		ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
>  
> @@ -1061,25 +1106,12 @@ struct rc_dev *rc_allocate_device(void)
>  	if (!dev)
>  		return NULL;
>  
> -	dev->input_dev = input_allocate_device();
> -	if (!dev->input_dev) {
> -		kfree(dev);
> -		return NULL;
> -	}
> -
> -	dev->input_dev->getkeycode = ir_getkeycode;
> -	dev->input_dev->setkeycode = ir_setkeycode;
> -	input_set_drvdata(dev->input_dev, dev);
> -
>  	INIT_LIST_HEAD(&dev->client_list);
>  	spin_lock_init(&dev->client_lock);
>  	mutex_init(&dev->txmutex);
>  	init_waitqueue_head(&dev->txwait);
>  	init_waitqueue_head(&dev->rxwait);
> -	spin_lock_init(&dev->rc_map.lock);
> -	spin_lock_init(&dev->keylock);
>  	mutex_init(&dev->lock);
> -	setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
>  
>  	dev->dev.type = &rc_dev_type;
>  	dev->dev.class = &rc_class;
> @@ -1112,28 +1144,14 @@ EXPORT_SYMBOL_GPL(rc_free_device);
>  int rc_register_device(struct rc_dev *dev)
>  {
>  	static bool raw_init = false; /* raw decoders loaded? */
> -	struct rc_map *rc_map;
> -	const char *path;
> +	struct rc_map *rc_map = NULL;
>  	int attr = 0;
>  	int minor;
>  	int rc;
>  
> -	if (!dev || !dev->map_name)
> -		return -EINVAL;
> -
> -	rc_map = rc_map_get(dev->map_name);
> -	if (!rc_map)
> -		rc_map = rc_map_get(RC_MAP_EMPTY);
> -	if (!rc_map || !rc_map->scan || rc_map->size == 0)
> +	if (!dev)
>  		return -EINVAL;
>  
> -	set_bit(EV_KEY, dev->input_dev->evbit);
> -	set_bit(EV_REP, dev->input_dev->evbit);
> -	set_bit(EV_MSC, dev->input_dev->evbit);
> -	set_bit(MSC_SCAN, dev->input_dev->mscbit);
> -	dev->input_dev->open = rc_input_open;
> -	dev->input_dev->close = rc_input_close;
> -
>  	minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
>  	if (minor < 0)
>  		return minor;
> @@ -1148,6 +1166,18 @@ int rc_register_device(struct rc_dev *dev)
>  			goto out_minor;
>  	}
>  
> +	if (dev->driver_type == RC_DRIVER_IR_RAW) {
> +		/* Load raw decoders, if they aren't already */
> +		if (!raw_init) {
> +			IR_dprintk(1, "Loading raw decoders\n");
> +			ir_raw_init();
> +			raw_init = true;
> +		}
> +		rc = ir_raw_event_register(dev);
> +		if (rc < 0)
> +			goto out_minor;
> +	}
> +
>  	dev->dev.groups = dev->sysfs_groups;
>  	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
>  	if (dev->s_filter)
> @@ -1158,73 +1188,15 @@ int rc_register_device(struct rc_dev *dev)
>  		dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
>  	dev->sysfs_groups[attr++] = NULL;
>  
> -	/*
> -	 * Take the lock here, as the device sysfs node will appear
> -	 * when device_add() is called, which may trigger an ir-keytable udev
> -	 * rule, which will in turn call show_protocols and access
> -	 * dev->enabled_protocols before it has been initialized.
> -	 */
> -	mutex_lock(&dev->lock);
> -
> -	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
> -	if (rc)
> -		goto out_unlock;
> -
> -	rc = device_add(&dev->dev);
> -	if (rc)
> -		goto out_cdev;
> -
> -	rc = ir_setkeytable(dev, rc_map);
> -	if (rc)
> -		goto out_dev;
> -
> -	dev->input_dev->dev.parent = &dev->dev;
> -	memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
> -	dev->input_dev->phys = dev->input_phys;
> -	dev->input_dev->name = dev->input_name;
> -
> -	/* input_register_device can call ir_open, so unlock mutex here */
> -	mutex_unlock(&dev->lock);
> -
> -	rc = input_register_device(dev->input_dev);
> -
> -	mutex_lock(&dev->lock);
> -
> -	if (rc)
> -		goto out_table;
> +	if (dev->map_name)
> +		rc_map = rc_map_get(dev->map_name);
>  
> -	/*
> -	 * Default delay of 250ms is too short for some protocols, especially
> -	 * since the timeout is currently set to 250ms. Increase it to 500ms,
> -	 * to avoid wrong repetition of the keycodes. Note that this must be
> -	 * set after the call to input_register_device().
> -	 */
> -	dev->input_dev->rep[REP_DELAY] = 500;
> -
> -	/*
> -	 * As a repeat event on protocols like RC-5 and NEC take as long as
> -	 * 110/114ms, using 33ms as a repeat period is not the right thing
> -	 * to do.
> -	 */
> -	dev->input_dev->rep[REP_PERIOD] = 125;
> -
> -	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
> -	printk(KERN_INFO "%s: %s as %s\n",
> -		dev_name(&dev->dev),
> -		dev->input_name ? dev->input_name : "Unspecified device",
> -		path ? path : "N/A");
> -	kfree(path);
> +	if (!rc_map)
> +		rc_map = rc_map_get(RC_MAP_EMPTY);
>  
> -	if (dev->driver_type == RC_DRIVER_IR_RAW) {
> -		/* Load raw decoders, if they aren't already */
> -		if (!raw_init) {
> -			IR_dprintk(1, "Loading raw decoders\n");
> -			ir_raw_init();
> -			raw_init = true;
> -		}
> -		rc = ir_raw_event_register(dev);
> -		if (rc < 0)
> -			goto out_input;
> +	if (!rc_map || !rc_map->scan || rc_map->size == 0) {
> +		rc = -EFAULT;
> +		goto out_raw;
>  	}
>  
>  	if (dev->change_protocol && rc_map->len > 0) {
> @@ -1234,31 +1206,34 @@ int rc_register_device(struct rc_dev *dev)
>  			goto out_raw;
>  		dev->enabled_protocols = rc_type;
>  	}
> +	
> +	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
> +	if (rc)
> +		goto out_raw;
>  
> -	mutex_unlock(&dev->lock);
> +	rc = device_add(&dev->dev);
> +	if (rc)
> +		goto out_cdev;
> +
> +	rc = rc_keytable_add(dev, rc_map);
> +	if (rc)
> +		goto out_dev;
>  
>  	IR_dprintk(1, "Registered %s (driver: %s, remote: %s, mode %s)\n",
>  		   dev_name(&dev->dev),
>  		   dev->driver_name ? dev->driver_name : "unknown",
> -		   rc_map->name ? rc_map->name : "unknown",
> +		   dev->map_name ? dev->map_name : "unknown",
>  		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
>  
>  	return 0;
>  
> -out_raw:
> -	if (dev->driver_type == RC_DRIVER_IR_RAW)
> -		ir_raw_event_unregister(dev);
> -out_input:
> -	input_unregister_device(dev->input_dev);
> -	dev->input_dev = NULL;
> -out_table:
> -	ir_free_table(&dev->rc_map);
>  out_dev:
>  	device_del(&dev->dev);
>  out_cdev:
>  	cdev_del(&dev->cdev);
> -out_unlock:
> -	mutex_unlock(&dev->lock);
> +out_raw:
> +	if (dev->driver_type == RC_DRIVER_IR_RAW)
> +		ir_raw_event_unregister(dev);
>  out_minor:
>  	ida_simple_remove(&rc_ida, minor);
>  	return rc;
> @@ -1285,15 +1260,10 @@ void rc_unregister_device(struct rc_dev *dev)
>  
>  	cdev_del(&dev->cdev);
>  
> -	del_timer_sync(&dev->timer_keyup);
> -
>  	if (dev->driver_type == RC_DRIVER_IR_RAW)
>  		ir_raw_event_unregister(dev);
>  
> -	ir_free_table(&dev->rc_map);
> -
> -	input_unregister_device(dev->input_dev);
> -	dev->input_dev = NULL;
> +	rc_keytable_del(dev);
>  
>  	/* dev is marked as dead so no one changes dev->users */
>  	if (dev->users && dev->close)
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index eacb735..e64d47c 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -249,7 +249,7 @@ enum rc_filter_type {
>   * @input_id: id of the input child device (struct input_id)
>   * @driver_name: name of the hardware driver which registered this device
>   * @map_name: name of the default keymap
> - * @rc_map: current scan/key table
> + * @rc_kt: current rc_keytable
>   * @lock: used to ensure we've filled in all protocol details before
>   *	anyone can call show_protocols or store_protocols
>   * @dead: used to determine if the device is still alive
> @@ -260,7 +260,6 @@ enum rc_filter_type {
>   * @txwait: waitqueue for processes waiting to write data to the txfifo
>   * @rxwait: waitqueue for processes waiting for data to read
>   * @raw: additional data for raw pulse/space devices
> - * @input_dev: the input child device used to communicate events to userspace
>   * @driver_type: specifies if protocol decoding is done in hardware or software
>   * @idle: used to keep track of RX state
>   * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
> @@ -276,14 +275,6 @@ enum rc_filter_type {
>   *	leave this field in blank
>   * @users: number of current users of the device
>   * @priv: driver-specific data
> - * @keylock: protects the remaining members of the struct
> - * @keypressed: whether a key is currently pressed
> - * @keyup_jiffies: time (in jiffies) when the current keypress should be released
> - * @timer_keyup: timer for releasing a keypress
> - * @last_keycode: keycode of last keypress
> - * @last_protocol: protocol of last keypress
> - * @last_scancode: scancode of last keypress
> - * @last_toggle: toggle value of last command
>   * @timeout: optional time after which device stops sending data
>   * @min_timeout: minimum timeout supported by device
>   * @max_timeout: maximum timeout supported by device
> @@ -321,7 +312,7 @@ struct rc_dev {
>  	struct input_id			input_id;
>  	char				*driver_name;
>  	const char			*map_name;
> -	struct rc_map			rc_map;
> +	struct rc_keytable		*kt;
>  	struct mutex			lock;
>  	bool				dead;
>  	struct list_head		client_list;
> @@ -331,7 +322,6 @@ struct rc_dev {
>  	wait_queue_head_t		txwait;
>  	wait_queue_head_t		rxwait;
>  	struct ir_raw_event_ctrl	*raw;
> -	struct input_dev		*input_dev;
>  	enum rc_driver_type		driver_type;
>  	bool				idle;
>  	u64				allowed_protocols;
> @@ -343,14 +333,6 @@ struct rc_dev {
>  	u32				scancode_mask;
>  	u32				users;
>  	void				*priv;
> -	spinlock_t			keylock;
> -	bool				keypressed;
> -	unsigned long			keyup_jiffies;
> -	struct timer_list		timer_keyup;
> -	u32				last_keycode;
> -	enum rc_type			last_protocol;
> -	u32				last_scancode;
> -	u8				last_toggle;
>  	u32				timeout;
>  	u32				min_timeout;
>  	u32				max_timeout;
> @@ -378,6 +360,34 @@ struct rc_dev {
>  	int				(*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
>  };
>  
> +/**
> + * struct rc_keytable - represents one keytable for a rc_dev device
> + * @dev:		the rc_dev device this keytable belongs to
> + * @idev:		the input_dev device which belongs to this keytable
> + * @rc_map:		holds the scancode <-> keycode mappings
> + * @keypressed:		whether a key is currently pressed or not
> + * @keyup_jiffies:	when the key should be auto-released
> + * @timer_keyup:	responsible for the auto-release of keys
> + * @keylock:		protects the key state
> + * @last_keycode:	keycode of the last keypress
> + * @last_protocol:	protocol of the last keypress
> + * @last_scancode:	scancode of the last keypress
> + * @last_toggle:	toggle of the last keypress
> + */
> +struct rc_keytable {
> +	struct rc_dev			*dev;
> +	struct input_dev		*idev;
> +	struct rc_map			rc_map;
> +	bool				keypressed;
> +	unsigned long			keyup_jiffies;
> +	struct timer_list		timer_keyup;
> +	spinlock_t			keylock;
> +	u32				last_keycode;
> +	enum rc_type			last_protocol;
> +	u32				last_scancode;
> +	u8				last_toggle;
> +};
> +
>  #define to_rc_dev(d) container_of(d, struct rc_dev, dev)
>  
>  /*
> @@ -397,11 +407,19 @@ int rc_open(struct rc_dev *rdev);
>  void rc_close(struct rc_dev *rdev);
>  
>  void rc_repeat(struct rc_dev *dev);
> -void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
> -void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle);
> +void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
> +		   u32 scancode, u8 toggle, bool autoup);
>  void rc_keyup(struct rc_dev *dev);
>  u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
>  
> +static inline void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) {
> +	rc_do_keydown(dev, protocol, scancode, toggle, true);
> +}
> +
> +static inline void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) {
> +	rc_do_keydown(dev, protocol, scancode, toggle, false);
> +}
> +
>  /*
>   * From rc-raw.c
>   * The Raw interface is specific to InfraRed. It may be a good idea to
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 37/49] rc-core: allow empty keymaps
  2014-04-03 23:34 ` [PATCH 37/49] rc-core: allow empty keymaps David Härdeman
@ 2014-07-25 22:58   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 22:58 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:23 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Remove the RC_MAP_EMPTY hack and instead allow for empty keymaps.

Doesn't apply anymore, but makes sense.

There's just one thing that we need to double check: if a given
device is with an empty keytable, it doesn't make sense to start
IR polling, as IR polling costs power.

So, we need to be sure that we'll only call the IR start method
if the table is filled.

I think the current behavior already takes this into account, but
we need to test it.

Regards,
Mauro

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/i2c/ir-kbd-i2c.c             |    4 +--
>  drivers/media/pci/cx88/cx88-input.c        |    6 -----
>  drivers/media/pci/ivtv/ivtv-i2c.c          |    2 +-
>  drivers/media/rc/gpio-ir-recv.c            |    2 +-
>  drivers/media/rc/img-ir/img-ir-hw.c        |    1 -
>  drivers/media/rc/img-ir/img-ir-raw.c       |    1 -
>  drivers/media/rc/rc-keytable.c             |    3 +++
>  drivers/media/rc/rc-loopback.c             |    1 -
>  drivers/media/rc/rc-main.c                 |   33 ++--------------------------
>  drivers/media/usb/dvb-usb-v2/af9015.c      |    4 ---
>  drivers/media/usb/dvb-usb-v2/af9035.c      |    4 ---
>  drivers/media/usb/dvb-usb-v2/az6007.c      |    4 ++-
>  drivers/media/usb/dvb-usb-v2/rtl28xxu.c    |    4 ---
>  drivers/media/usb/dvb-usb/dvb-usb-remote.c |    4 +--
>  drivers/media/usb/em28xx/em28xx-cards.c    |    1 -
>  include/media/rc-map.h                     |    1 -
>  16 files changed, 11 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
> index 8311f1a..5393558 100644
> --- a/drivers/media/i2c/ir-kbd-i2c.c
> +++ b/drivers/media/i2c/ir-kbd-i2c.c
> @@ -309,7 +309,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  		name        = "Pixelview";
>  		ir->get_key = get_key_pixelview;
>  		rc_type     = RC_BIT_OTHER;
> -		ir_codes    = RC_MAP_EMPTY;
>  		break;
>  	case 0x18:
>  	case 0x1f:
> @@ -323,7 +322,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  		name        = "KNC One";
>  		ir->get_key = get_key_knc1;
>  		rc_type     = RC_BIT_OTHER;
> -		ir_codes    = RC_MAP_EMPTY;
>  		break;
>  	case 0x6b:
>  		name        = "FusionHDTV";
> @@ -405,7 +403,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  	ir->rc = rc;
>  
>  	/* Make sure we are all setup before going on */
> -	if (!name || !ir->get_key || !rc_type || !ir_codes) {
> +	if (!name || !ir->get_key || !rc_type) {
>  		dprintk(1, ": Unsupported device at address 0x%02x\n",
>  			addr);
>  		err = -ENODEV;
> diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
> index 3f1342c..cb587ce 100644
> --- a/drivers/media/pci/cx88/cx88-input.c
> +++ b/drivers/media/pci/cx88/cx88-input.c
> @@ -437,11 +437,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
>  		break;
>  	}
>  
> -	if (!ir_codes) {
> -		err = -ENODEV;
> -		goto err_out_free;
> -	}
> -
>  	/*
>  	 * The usage of mask_keycode were very convenient, due to several
>  	 * reasons. Among others, the scancode tables were using the scancode
> @@ -612,7 +607,6 @@ void cx88_i2c_init_ir(struct cx88_core *core)
>  		core->init_data.name = "cx88 Leadtek PVR 2000 remote";
>  		core->init_data.type = RC_BIT_UNKNOWN;
>  		core->init_data.get_key = get_key_pvr2000;
> -		core->init_data.ir_codes = RC_MAP_EMPTY;
>  		break;
>  	}
>  
> diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
> index 1a41ba5..846bb51 100644
> --- a/drivers/media/pci/ivtv/ivtv-i2c.c
> +++ b/drivers/media/pci/ivtv/ivtv-i2c.c
> @@ -222,7 +222,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
>  		init_data->get_key = get_key_adaptec;
>  		init_data->name = itv->card_name;
>  		/* FIXME: The protocol and RC_MAP needs to be corrected */
> -		init_data->ir_codes = RC_MAP_EMPTY;
> +		/* init_data->ir_codes = RC_MAP_? */
>  		init_data->type = RC_BIT_UNKNOWN;
>  		break;
>  	}
> diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
> index 5985308..7d01560 100644
> --- a/drivers/media/rc/gpio-ir-recv.c
> +++ b/drivers/media/rc/gpio-ir-recv.c
> @@ -148,7 +148,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
>  		rcdev->allowed_protocols = pdata->allowed_protos;
>  	else
>  		rcdev->allowed_protocols = RC_BIT_ALL;
> -	rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
> +	rcdev->map_name = pdata->map_name;
>  
>  	gpio_dev->rcdev = rcdev;
>  	gpio_dev->gpio_nr = pdata->gpio_nr;
> diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
> index 3bb6a32..5bc7903 100644
> --- a/drivers/media/rc/img-ir/img-ir-hw.c
> +++ b/drivers/media/rc/img-ir/img-ir-hw.c
> @@ -993,7 +993,6 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
>  		goto err_alloc_rc;
>  	}
>  	rdev->priv = priv;
> -	rdev->map_name = RC_MAP_EMPTY;
>  	rdev->allowed_protocols = img_ir_allowed_protos(priv);
>  	rdev->input_name = "IMG Infrared Decoder";
>  	rdev->s_filter = img_ir_set_normal_filter;
> diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
> index cfb01d9..5b6d8e9 100644
> --- a/drivers/media/rc/img-ir/img-ir-raw.c
> +++ b/drivers/media/rc/img-ir/img-ir-raw.c
> @@ -111,7 +111,6 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
>  		return -ENOMEM;
>  	}
>  	rdev->priv = priv;
> -	rdev->map_name = RC_MAP_EMPTY;
>  	rdev->input_name = "IMG Infrared Decoder Raw";
>  	rdev->driver_type = RC_DRIVER_IR_RAW;
>  
> diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
> index 89295f3..5709ae6 100644
> --- a/drivers/media/rc/rc-keytable.c
> +++ b/drivers/media/rc/rc-keytable.c
> @@ -55,6 +55,9 @@ struct rc_map *rc_map_get(const char *name)
>  
>  	struct rc_map_list *map;
>  
> +	if (!name)
> +		return NULL;
> +
>  	map = seek_rc_map(name);
>  #ifdef MODULE
>  	if (!map) {
> diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
> index 628e834..f201395 100644
> --- a/drivers/media/rc/rc-loopback.c
> +++ b/drivers/media/rc/rc-loopback.c
> @@ -226,7 +226,6 @@ static int __init loop_init(void)
>  	rc->input_id.bustype	= BUS_VIRTUAL;
>  	rc->input_id.version	= 1;
>  	rc->driver_name		= DRIVER_NAME;
> -	rc->map_name		= RC_MAP_EMPTY;
>  	rc->priv		= &loopdev;
>  	rc->driver_type		= RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols	= RC_BIT_ALL;
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index ad784c8..8729d0a 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -207,12 +207,6 @@ static int rc_add_keytable(struct rc_dev *dev, const char *name,
>  	struct rc_keytable *kt;
>  	unsigned i;
>  
> -	if (!rc_map)
> -		rc_map = rc_map_get(RC_MAP_EMPTY);
> -
> -	if (!rc_map)
> -		return -EFAULT;
> -
>  	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
>  		if (!dev->keytables[i])
>  			break;
> @@ -1321,22 +1315,14 @@ int rc_register_device(struct rc_dev *dev)
>  	if (dev->map_name)
>  		rc_map = rc_map_get(dev->map_name);
>  
> -	if (!rc_map)
> -		rc_map = rc_map_get(RC_MAP_EMPTY);
> -
> -	if (!rc_map || !rc_map->scan || rc_map->size == 0) {
> -		rc = -EFAULT;
> -		goto out_raw;
> -	}
> -
> -	if (dev->change_protocol && rc_map->len > 0) {
> +	if (dev->change_protocol && rc_map && rc_map->len > 0) {
>  		u64 rc_type = (1 << rc_map->scan[0].protocol);
>  		rc = dev->change_protocol(dev, &rc_type);
>  		if (rc < 0)
>  			goto out_raw;
>  		dev->enabled_protocols = rc_type;
>  	}
> -	
> +
>  	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
>  	if (rc)
>  		goto out_raw;
> @@ -1407,19 +1393,6 @@ void rc_unregister_device(struct rc_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(rc_unregister_device);
>  
> -static struct rc_map_table empty[] = {
> -	{ RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
> -};
> -
> -static struct rc_map_list empty_map = {
> -	.map = {
> -		.scan    = empty,
> -		.size    = ARRAY_SIZE(empty),
> -		.rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
> -		.name    = RC_MAP_EMPTY,
> -	}
> -};
> -
>  static int __init rc_core_init(void)
>  {
>  	int err;
> @@ -1439,14 +1412,12 @@ static int __init rc_core_init(void)
>  
>  	IR_dprintk(1, "Allocated char dev: %u\n", MAJOR(rc_devt));
>  	led_trigger_register_simple("rc-feedback", &led_feedback);
> -	rc_map_register(&empty_map);
>  
>  	return 0;
>  }
>  
>  static void __exit rc_core_exit(void)
>  {
> -	rc_map_unregister(&empty_map);
>  	led_trigger_unregister_simple(led_feedback);
>  	unregister_chrdev_region(rc_devt, RC_DEV_MAX);
>  	class_unregister(&rc_class);
> diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
> index 8776eaf..31066e8 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9015.c
> +++ b/drivers/media/usb/dvb-usb-v2/af9015.c
> @@ -1297,10 +1297,6 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
>  		}
>  	}
>  
> -	/* load empty to enable rc */
> -	if (!rc->map_name)
> -		rc->map_name = RC_MAP_EMPTY;
> -
>  	rc->allowed_protos = RC_BIT_NEC;
>  	rc->query = af9015_rc_query;
>  	rc->interval = 500;
> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
> index 6bc9693..cfe0be7 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9035.c
> +++ b/drivers/media/usb/dvb-usb-v2/af9035.c
> @@ -1332,10 +1332,6 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
>  
>  		rc->query = af9035_rc_query;
>  		rc->interval = 500;
> -
> -		/* load empty to enable rc */
> -		if (!rc->map_name)
> -			rc->map_name = RC_MAP_EMPTY;
>  	}
>  
>  	return 0;
> diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
> index 7e38278..9c2a07e 100644
> --- a/drivers/media/usb/dvb-usb-v2/az6007.c
> +++ b/drivers/media/usb/dvb-usb-v2/az6007.c
> @@ -922,13 +922,13 @@ static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
>  
>  static struct usb_device_id az6007_usb_table[] = {
>  	{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
> -		&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
> +		&az6007_props, "Azurewave 6007", NULL)},
>  	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
>  		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
>  	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
>  		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
>  	{DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
> -		&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
> +		&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", NULL)},
>  	{0},
>  };
>  
> diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> index 45c77b1..15f1e70 100644
> --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> @@ -1270,7 +1270,6 @@ err:
>  static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
>  		struct dvb_usb_rc *rc)
>  {
> -	rc->map_name = RC_MAP_EMPTY;
>  	rc->allowed_protos = RC_BIT_NEC;
>  	rc->query = rtl2831u_rc_query;
>  	rc->interval = 400;
> @@ -1373,9 +1372,6 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
>  	if (rtl28xxu_disable_rc)
>  		return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
>  
> -	/* load empty to enable rc */
> -	if (!rc->map_name)
> -		rc->map_name = RC_MAP_EMPTY;
>  	rc->allowed_protos = RC_BIT_ALL;
>  	rc->driver_type = RC_DRIVER_IR_RAW;
>  	rc->query = rtl2832u_rc_query;
> diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> index 7b5dae3..5986626 100644
> --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> @@ -313,10 +313,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
>  
>  	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
>  		d->props.rc.mode = DVB_RC_LEGACY;
> -	else if (d->props.rc.core.rc_codes)
> -		d->props.rc.mode = DVB_RC_CORE;
>  	else
> -		return 0;
> +		d->props.rc.mode = DVB_RC_CORE;
>  
>  	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
>  	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 50aa5a5..cf803f2 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -1120,7 +1120,6 @@ struct em28xx_board em28xx_boards[] = {
>  		.has_dvb      = 1,
>  		/* FIXME: Add analog support - need a saa7136 driver */
>  		.tuner_type = TUNER_ABSENT,	/* Digital-only TDA18271HD */
> -		.ir_codes     = RC_MAP_EMPTY,
>  		.def_i2c_bus  = 1,
>  		.i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE,
>  		.dvb_gpio     = c3tech_digital_duo_digital,
> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
> index 34c192f..417cce3 100644
> --- a/include/media/rc-map.h
> +++ b/include/media/rc-map.h
> @@ -140,7 +140,6 @@ void rc_map_init(void);
>  #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
>  #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
>  #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
> -#define RC_MAP_EMPTY                     "rc-empty"
>  #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
>  #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
>  #define RC_MAP_ENCORE_ENLTV_FM53         "rc-encore-enltv-fm53"
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 39/49] rc-core: make IR raw handling a separate module
  2014-04-03 23:34 ` [PATCH 39/49] rc-core: make IR raw handling a separate module David Härdeman
@ 2014-07-25 23:04   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:04 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:33 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Make drivers/media/rc/rc-ir-raw.c a separate kernel module.
> 
> Drivers which use IR decoding must use these functions:
> 	rc_register_ir_raw_device()
> 	rc_unregister_ir_raw_device()
> instead of:
> 	rc_register_device()
> 	rc_unregister_device()
> 
> This allows scancode drivers to skip lots of unnecessary functionality.

Makes sense to me. Please rebase.

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/common/siano/smsir.c          |    5 +-
>  drivers/media/common/siano/smsir.h          |    2 -
>  drivers/media/i2c/cx25840/cx25840-ir.c      |    2 -
>  drivers/media/pci/cx23885/cx23885-input.c   |   13 +---
>  drivers/media/pci/cx23885/cx23888-ir.c      |    2 -
>  drivers/media/pci/cx88/cx88-input.c         |   18 +++---
>  drivers/media/pci/dm1105/dm1105.c           |    1 
>  drivers/media/pci/saa7134/saa7134-input.c   |   14 +++--
>  drivers/media/pci/saa7134/saa7134.h         |    2 -
>  drivers/media/rc/Makefile                   |    3 +
>  drivers/media/rc/ati_remote.c               |    1 
>  drivers/media/rc/ene_ir.c                   |    9 +--
>  drivers/media/rc/fintek-cir.c               |    7 +-
>  drivers/media/rc/gpio-ir-recv.c             |    9 +--
>  drivers/media/rc/iguanair.c                 |    7 +-
>  drivers/media/rc/img-ir/img-ir-raw.c        |    7 +-
>  drivers/media/rc/imon.c                     |    1 
>  drivers/media/rc/ite-cir.c                  |    9 +--
>  drivers/media/rc/mceusb.c                   |    7 +-
>  drivers/media/rc/nuvoton-cir.c              |    7 +-
>  drivers/media/rc/rc-core-priv.h             |   10 ++-
>  drivers/media/rc/rc-ir-raw.c                |   39 +++++++++----
>  drivers/media/rc/rc-loopback.c              |    7 +-
>  drivers/media/rc/rc-main.c                  |   36 +-----------
>  drivers/media/rc/redrat3.c                  |    7 +-
>  drivers/media/rc/streamzap.c                |    7 +-
>  drivers/media/rc/ttusbir.c                  |    9 +--
>  drivers/media/rc/winbond-cir.c              |    9 +--
>  drivers/media/usb/dvb-usb-v2/dvb_usb.h      |    5 +-
>  drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |   12 +++-
>  drivers/media/usb/dvb-usb-v2/rtl28xxu.c     |    2 -
>  drivers/media/usb/dvb-usb/dvb-usb-remote.c  |    9 ++-
>  drivers/media/usb/dvb-usb/dvb-usb.h         |    5 +-
>  drivers/media/usb/dvb-usb/technisat-usb2.c  |    2 -
>  drivers/media/usb/em28xx/em28xx-input.c     |    5 --
>  drivers/media/usb/tm6000/tm6000-input.c     |    1 
>  include/media/rc-core.h                     |   73 +-----------------------
>  include/media/rc-ir-raw.h                   |   83 +++++++++++++++++++++++++++
>  38 files changed, 222 insertions(+), 225 deletions(-)
>  create mode 100644 include/media/rc-ir-raw.h
> 
> diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
> index 273043e..f6938f4 100644
> --- a/drivers/media/common/siano/smsir.c
> +++ b/drivers/media/common/siano/smsir.c
> @@ -87,14 +87,13 @@ int sms_ir_init(struct smscore_device_t *coredev)
>  #endif
>  
>  	dev->priv = coredev;
> -	dev->driver_type = RC_DRIVER_IR_RAW;
>  	dev->allowed_protocols = RC_BIT_ALL;
>  	dev->map_name = sms_get_board(board_id)->rc_codes;
>  	dev->driver_name = MODULE_NAME;
>  
>  	sms_log("Input device (IR) %s is set for key events", dev->input_name);
>  
> -	err = rc_register_device(dev);
> +	err = rc_register_ir_raw_device(dev);
>  	if (err < 0) {
>  		sms_err("Failed to register device");
>  		rc_free_device(dev);
> @@ -108,7 +107,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
>  void sms_ir_exit(struct smscore_device_t *coredev)
>  {
>  	if (coredev->ir.dev)
> -		rc_unregister_device(coredev->ir.dev);
> +		rc_unregister_ir_raw_device(coredev->ir.dev);
>  
>  	sms_log("");
>  }
> diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
> index fc8b792..05a2b01 100644
> --- a/drivers/media/common/siano/smsir.h
> +++ b/drivers/media/common/siano/smsir.h
> @@ -28,7 +28,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
>  #define __SMS_IR_H__
>  
>  #include <linux/input.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define IR_DEFAULT_TIMEOUT		100
>  
> diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
> index e6588ee..119d4e8 100644
> --- a/drivers/media/i2c/cx25840/cx25840-ir.c
> +++ b/drivers/media/i2c/cx25840/cx25840-ir.c
> @@ -25,7 +25,7 @@
>  #include <linux/kfifo.h>
>  #include <linux/module.h>
>  #include <media/cx25840.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #include "cx25840-core.h"
>  
> diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
> index 1940c18..e2ba28d 100644
> --- a/drivers/media/pci/cx23885/cx23885-input.c
> +++ b/drivers/media/pci/cx23885/cx23885-input.c
> @@ -36,7 +36,7 @@
>   */
>  
>  #include <linux/slab.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <media/v4l2-subdev.h>
>  
>  #include "cx23885.h"
> @@ -258,7 +258,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  	struct cx23885_kernel_ir *kernel_ir;
>  	struct rc_dev *rc;
>  	char *rc_map;
> -	enum rc_driver_type driver_type;
>  	unsigned long allowed_protos;
>  
>  	int ret;
> @@ -276,28 +275,24 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  	case CX23885_BOARD_HAUPPAUGE_HVR1290:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
>  		/* Integrated CX2388[58] IR controller */
> -		driver_type = RC_DRIVER_IR_RAW;
>  		allowed_protos = RC_BIT_ALL;
>  		/* The grey Hauppauge RC-5 remote */
>  		rc_map = RC_MAP_HAUPPAUGE;
>  		break;
>  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
>  		/* Integrated CX23885 IR controller */
> -		driver_type = RC_DRIVER_IR_RAW;
>  		allowed_protos = RC_BIT_NEC;
>  		/* The grey Terratec remote with orange buttons */
>  		rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
>  		break;
>  	case CX23885_BOARD_TEVII_S470:
>  		/* Integrated CX23885 IR controller */
> -		driver_type = RC_DRIVER_IR_RAW;
>  		allowed_protos = RC_BIT_ALL;
>  		/* A guess at the remote */
>  		rc_map = RC_MAP_TEVII_NEC;
>  		break;
>  	case CX23885_BOARD_MYGICA_X8507:
>  		/* Integrated CX23885 IR controller */
> -		driver_type = RC_DRIVER_IR_RAW;
>  		allowed_protos = RC_BIT_ALL;
>  		/* A guess at the remote */
>  		rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
> @@ -305,7 +300,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  	case CX23885_BOARD_TBS_6980:
>  	case CX23885_BOARD_TBS_6981:
>  		/* Integrated CX23885 IR controller */
> -		driver_type = RC_DRIVER_IR_RAW;
>  		allowed_protos = RC_BIT_ALL;
>  		/* A guess at the remote */
>  		rc_map = RC_MAP_TBS_NEC;
> @@ -345,7 +339,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  		rc->input_id.product = dev->pci->device;
>  	}
>  	rc->dev.parent = &dev->pci->dev;
> -	rc->driver_type = driver_type;
>  	rc->allowed_protocols = allowed_protos;
>  	rc->priv = kernel_ir;
>  	rc->open = cx23885_input_ir_open;
> @@ -355,7 +348,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  
>  	/* Go */
>  	dev->kernel_ir = kernel_ir;
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret)
>  		goto err_out_stop;
>  
> @@ -379,7 +372,7 @@ void cx23885_input_fini(struct cx23885_dev *dev)
>  
>  	if (dev->kernel_ir == NULL)
>  		return;
> -	rc_unregister_device(dev->kernel_ir->rc);
> +	rc_unregister_ir_raw_device(dev->kernel_ir->rc);
>  	kfree(dev->kernel_ir->phys);
>  	kfree(dev->kernel_ir->name);
>  	kfree(dev->kernel_ir);
> diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
> index 2c951de..c4961f8 100644
> --- a/drivers/media/pci/cx23885/cx23888-ir.c
> +++ b/drivers/media/pci/cx23885/cx23888-ir.c
> @@ -25,7 +25,7 @@
>  #include <linux/slab.h>
>  
>  #include <media/v4l2-device.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #include "cx23885.h"
>  #include "cx23888-ir.h"
> diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
> index cb587ce..2b68ede 100644
> --- a/drivers/media/pci/cx88/cx88-input.c
> +++ b/drivers/media/pci/cx88/cx88-input.c
> @@ -29,7 +29,7 @@
>  #include <linux/module.h>
>  
>  #include "cx88.h"
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define MODULE_NAME "cx88xx"
>  
> @@ -474,20 +474,17 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
>  	dev->open = cx88_ir_open;
>  	dev->close = cx88_ir_close;
>  	dev->scancode_mask = hardware_mask;
> +	ir->core = core;
> +	core->ir = ir;
>  
>  	if (ir->sampling) {
> -		dev->driver_type = RC_DRIVER_IR_RAW;
>  		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
> +		err = rc_register_ir_raw_device(dev);
>  	} else {
> -		dev->driver_type = RC_DRIVER_SCANCODE;
>  		dev->allowed_protocols = rc_type;
> +		err = rc_register_device(dev);
>  	}
>  
> -	ir->core = core;
> -	core->ir = ir;
> -
> -	/* all done */
> -	err = rc_register_device(dev);
>  	if (err)
>  		goto err_out_free;
>  
> @@ -509,7 +506,10 @@ int cx88_ir_fini(struct cx88_core *core)
>  		return 0;
>  
>  	cx88_ir_stop(core);
> -	rc_unregister_device(ir->dev);
> +	if (ir->sampling)
> +		rc_unregister_ir_raw_device(ir->dev);
> +	else
> +		rc_unregister_device(ir->dev);
>  	kfree(ir);
>  
>  	/* done */
> diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
> index e8826c5..015aa07 100644
> --- a/drivers/media/pci/dm1105/dm1105.c
> +++ b/drivers/media/pci/dm1105/dm1105.c
> @@ -752,7 +752,6 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105)
>  
>  	dev->driver_name = MODULE_NAME;
>  	dev->map_name = RC_MAP_DM1105_NEC;
> -	dev->driver_type = RC_DRIVER_SCANCODE;
>  	dev->input_name = "DVB on-card IR receiver";
>  	dev->input_phys = dm1105->ir.input_phys;
>  	dev->input_id.bustype = BUS_PCI;
> diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
> index 4ba61ff..27a3f48 100644
> --- a/drivers/media/pci/saa7134/saa7134-input.c
> +++ b/drivers/media/pci/saa7134/saa7134-input.c
> @@ -864,9 +864,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
>  	rc->priv = dev;
>  	rc->open = saa7134_ir_open;
>  	rc->close = saa7134_ir_close;
> -	if (raw_decode)
> -		rc->driver_type = RC_DRIVER_IR_RAW;
> -
>  	rc->input_name = ir->name;
>  	rc->input_phys = ir->phys;
>  	rc->input_id.bustype = BUS_PCI;
> @@ -882,7 +879,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
>  	rc->map_name = ir_codes;
>  	rc->driver_name = MODULE_NAME;
>  
> -	err = rc_register_device(rc);
> +	if (raw_decode)
> +		err = rc_register_ir_raw_device(rc);
> +	else
> +		err = rc_register_device(rc);
> +
>  	if (err)
>  		goto err_out_free;
>  
> @@ -901,7 +902,10 @@ void saa7134_input_fini(struct saa7134_dev *dev)
>  		return;
>  
>  	saa7134_ir_stop(dev);
> -	rc_unregister_device(dev->remote->dev);
> +	if (dev->remote->raw_decode)
> +		rc_unregister_ir_raw_device(dev->remote->dev);
> +	else
> +		rc_unregister_device(dev->remote->dev);
>  	kfree(dev->remote);
>  	dev->remote = NULL;
>  }
> diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
> index 2474e84..5a25486 100644
> --- a/drivers/media/pci/saa7134/saa7134.h
> +++ b/drivers/media/pci/saa7134/saa7134.h
> @@ -39,7 +39,7 @@
>  #include <media/v4l2-fh.h>
>  #include <media/v4l2-ctrls.h>
>  #include <media/tuner.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <media/ir-kbd-i2c.h>
>  #include <media/videobuf-dma-sg.h>
>  #include <sound/core.h>
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index 661f449..ac39628 100644
> --- a/drivers/media/rc/Makefile
> +++ b/drivers/media/rc/Makefile
> @@ -1,8 +1,9 @@
> -rc-core-objs	:= rc-main.o rc-keytable.o rc-ir-raw.o
> +rc-core-objs	:= rc-main.o rc-keytable.o
>  
>  obj-y += keymaps/
>  
>  obj-$(CONFIG_RC_CORE) += rc-core.o
> +obj-$(CONFIG_RC_CORE) += rc-ir-raw.o
>  obj-$(CONFIG_LIRC) += lirc_dev.o
>  obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
>  obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
> diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
> index 6ef5716..170aac8 100644
> --- a/drivers/media/rc/ati_remote.c
> +++ b/drivers/media/rc/ati_remote.c
> @@ -784,7 +784,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
>  	struct rc_dev *rdev = ati_remote->rdev;
>  
>  	rdev->priv = ati_remote;
> -	rdev->driver_type = RC_DRIVER_SCANCODE;
>  	rdev->allowed_protocols = RC_BIT_OTHER;
>  	rdev->driver_name = "ati_remote";
>  
> diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
> index cab5da9..57d61e5 100644
> --- a/drivers/media/rc/ene_ir.c
> +++ b/drivers/media/rc/ene_ir.c
> @@ -39,7 +39,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include "ene_ir.h"
>  
>  static int sample_period;
> @@ -1053,7 +1053,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
>  	if (!dev->hw_learning_and_tx_capable)
>  		learning_mode_force = false;
>  
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  	rdev->allowed_protocols = RC_BIT_ALL;
>  	rdev->priv = dev;
>  	rdev->open = ene_open;
> @@ -1083,7 +1082,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
>  	device_set_wakeup_capable(&pnp_dev->dev, true);
>  	device_set_wakeup_enable(&pnp_dev->dev, true);
>  
> -	error = rc_register_device(rdev);
> +	error = rc_register_ir_raw_device(rdev);
>  	if (error < 0)
>  		goto exit_free_dev_rdev;
>  
> @@ -1104,7 +1103,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
>  exit_release_hw_io:
>  	release_region(dev->hw_io, ENE_IO_SIZE);
>  exit_unregister_device:
> -	rc_unregister_device(rdev);
> +	rc_unregister_ir_raw_device(rdev);
>  	rdev = NULL;
>  exit_free_dev_rdev:
>  	rc_free_device(rdev);
> @@ -1125,7 +1124,7 @@ static void ene_remove(struct pnp_dev *pnp_dev)
>  
>  	free_irq(dev->irq, dev);
>  	release_region(dev->hw_io, ENE_IO_SIZE);
> -	rc_unregister_device(dev->rdev);
> +	rc_unregister_ir_raw_device(dev->rdev);
>  	kfree(dev);
>  }
>  
> diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
> index f000faf..ce2db15 100644
> --- a/drivers/media/rc/fintek-cir.c
> +++ b/drivers/media/rc/fintek-cir.c
> @@ -32,7 +32,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <linux/pci_ids.h>
>  
>  #include "fintek-cir.h"
> @@ -540,7 +540,6 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
>  
>  	/* Set up the rc device */
>  	rdev->priv = fintek;
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  	rdev->allowed_protocols = RC_BIT_ALL;
>  	rdev->open = fintek_open;
>  	rdev->close = fintek_close;
> @@ -569,7 +568,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
>  			FINTEK_DRIVER_NAME, (void *)fintek))
>  		goto exit_free_cir_addr;
>  
> -	ret = rc_register_device(rdev);
> +	ret = rc_register_ir_raw_device(rdev);
>  	if (ret)
>  		goto exit_free_irq;
>  
> @@ -609,7 +608,7 @@ static void fintek_remove(struct pnp_dev *pdev)
>  	free_irq(fintek->cir_irq, fintek);
>  	release_region(fintek->cir_addr, fintek->cir_port_len);
>  
> -	rc_unregister_device(fintek->rdev);
> +	rc_unregister_ir_raw_device(fintek->rdev);
>  
>  	kfree(fintek);
>  }
> diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
> index 7d01560..ff30bdb 100644
> --- a/drivers/media/rc/gpio-ir-recv.c
> +++ b/drivers/media/rc/gpio-ir-recv.c
> @@ -20,7 +20,7 @@
>  #include <linux/of_gpio.h>
>  #include <linux/platform_device.h>
>  #include <linux/irq.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <media/gpio-ir-recv.h>
>  
>  #define GPIO_IR_DRIVER_NAME	"gpio-rc-recv"
> @@ -135,7 +135,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
>  	}
>  
>  	rcdev->priv = gpio_dev;
> -	rcdev->driver_type = RC_DRIVER_IR_RAW;
>  	rcdev->input_name = GPIO_IR_DEVICE_NAME;
>  	rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
>  	rcdev->input_id.bustype = BUS_HOST;
> @@ -161,7 +160,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
>  	if (rc < 0)
>  		goto err_gpio_direction_input;
>  
> -	rc = rc_register_device(rcdev);
> +	rc = rc_register_ir_raw_device(rcdev);
>  	if (rc < 0) {
>  		dev_err(&pdev->dev, "failed to register rc device\n");
>  		goto err_register_rc_device;
> @@ -179,7 +178,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
>  	return 0;
>  
>  err_request_irq:
> -	rc_unregister_device(rcdev);
> +	rc_unregister_ir_raw_device(rcdev);
>  	rcdev = NULL;
>  err_register_rc_device:
>  err_gpio_direction_input:
> @@ -196,7 +195,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
>  	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
>  
>  	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
> -	rc_unregister_device(gpio_dev->rcdev);
> +	rc_unregister_ir_raw_device(gpio_dev->rcdev);
>  	gpio_free(gpio_dev->gpio_nr);
>  	kfree(gpio_dev);
>  	return 0;
> diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
> index 8a4baf5..3b7327a 100644
> --- a/drivers/media/rc/iguanair.c
> +++ b/drivers/media/rc/iguanair.c
> @@ -25,7 +25,7 @@
>  #include <linux/usb/input.h>
>  #include <linux/slab.h>
>  #include <linux/completion.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRIVER_NAME "iguanair"
>  #define BUF_SIZE 152
> @@ -513,7 +513,6 @@ static int iguanair_probe(struct usb_interface *intf,
>  	rc->input_phys = ir->phys;
>  	usb_to_input_id(ir->udev, &rc->input_id);
>  	rc->dev.parent = &intf->dev;
> -	rc->driver_type = RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols = RC_BIT_ALL;
>  	rc->priv = ir;
>  	rc->open = iguanair_open;
> @@ -529,7 +528,7 @@ static int iguanair_probe(struct usb_interface *intf,
>  	iguanair_set_tx_carrier(rc, 38000);
>  	iguanair_set_tx_mask(rc, 0);
>  
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret < 0) {
>  		dev_err(&intf->dev, "failed to register rc device %d", ret);
>  		goto out2;
> @@ -558,7 +557,7 @@ static void iguanair_disconnect(struct usb_interface *intf)
>  {
>  	struct iguanair *ir = usb_get_intfdata(intf);
>  
> -	rc_unregister_device(ir->rc);
> +	rc_unregister_ir_raw_device(ir->rc);
>  	usb_set_intfdata(intf, NULL);
>  	usb_kill_urb(ir->urb_in);
>  	usb_kill_urb(ir->urb_out);
> diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
> index 5b6d8e9..95a4da1 100644
> --- a/drivers/media/rc/img-ir/img-ir-raw.c
> +++ b/drivers/media/rc/img-ir/img-ir-raw.c
> @@ -8,7 +8,7 @@
>   */
>  
>  #include <linux/spinlock.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include "img-ir.h"
>  
>  #define ECHO_TIMEOUT_MS 150	/* ms between echos */
> @@ -112,10 +112,9 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
>  	}
>  	rdev->priv = priv;
>  	rdev->input_name = "IMG Infrared Decoder Raw";
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  
>  	/* Register raw decoder */
> -	error = rc_register_device(rdev);
> +	error = rc_register_ir_raw_device(rdev);
>  	if (error) {
>  		dev_err(priv->dev, "failed to register raw IR input device\n");
>  		rc_free_device(rdev);
> @@ -144,7 +143,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv)
>  	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
>  	spin_unlock_irq(&priv->lock);
>  
> -	rc_unregister_device(rdev);
> +	rc_unregister_ir_raw_device(rdev);
>  
>  	del_timer_sync(&raw->timer);
>  }
> diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
> index 2461933..1aa2ac0 100644
> --- a/drivers/media/rc/imon.c
> +++ b/drivers/media/rc/imon.c
> @@ -1875,7 +1875,6 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
>  	rdev->dev.parent = ictx->dev;
>  
>  	rdev->priv = ictx;
> -	rdev->driver_type = RC_DRIVER_SCANCODE;
>  	rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
>  	rdev->change_protocol = imon_ir_change_protocol;
>  	rdev->driver_name = MOD_NAME;
> diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
> index 0d404a2..795fbc6 100644
> --- a/drivers/media/rc/ite-cir.c
> +++ b/drivers/media/rc/ite-cir.c
> @@ -40,7 +40,7 @@
>  #include <linux/slab.h>
>  #include <linux/input.h>
>  #include <linux/bitops.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <linux/pci_ids.h>
>  
>  #include "ite-cir.h"
> @@ -1557,7 +1557,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
>  
>  	/* set up ir-core props */
>  	rdev->priv = itdev;
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  	rdev->allowed_protocols = RC_BIT_ALL;
>  	rdev->open = ite_open;
>  	rdev->close = ite_close;
> @@ -1586,7 +1585,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
>  	rdev->driver_name = ITE_DRIVER_NAME;
>  	rdev->map_name = RC_MAP_RC6_MCE;
>  
> -	ret = rc_register_device(rdev);
> +	ret = rc_register_ir_raw_device(rdev);
>  	if (ret)
>  		goto exit_free_dev_rdev;
>  
> @@ -1607,7 +1606,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
>  exit_release_cir_addr:
>  	release_region(itdev->cir_addr, itdev->params.io_region_size);
>  exit_unregister_device:
> -	rc_unregister_device(rdev);
> +	rc_unregister_ir_raw_device(rdev);
>  	rdev = NULL;
>  exit_free_dev_rdev:
>  	rc_free_device(rdev);
> @@ -1634,7 +1633,7 @@ static void ite_remove(struct pnp_dev *pdev)
>  	free_irq(dev->cir_irq, dev);
>  	release_region(dev->cir_addr, dev->params.io_region_size);
>  
> -	rc_unregister_device(dev->rdev);
> +	rc_unregister_ir_raw_device(dev->rdev);
>  
>  	kfree(dev);
>  }
> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
> index e0c8552..eac87ec 100644
> --- a/drivers/media/rc/mceusb.c
> +++ b/drivers/media/rc/mceusb.c
> @@ -43,7 +43,7 @@
>  #include <linux/usb.h>
>  #include <linux/usb/input.h>
>  #include <linux/pm_wakeup.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRIVER_VERSION	"1.92"
>  #define DRIVER_AUTHOR	"Jarod Wilson <jarod@redhat.com>"
> @@ -1217,7 +1217,6 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
>  	usb_to_input_id(ir->usbdev, &rc->input_id);
>  	rc->dev.parent = dev;
>  	rc->priv = ir;
> -	rc->driver_type = RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols = RC_BIT_ALL;
>  	rc->timeout = MS_TO_NS(100);
>  	if (!ir->flags.no_tx) {
> @@ -1229,7 +1228,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
>  	rc->map_name = mceusb_model[ir->model].rc_map ?
>  			mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
>  
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret < 0) {
>  		dev_err(dev, "remote dev registration failed");
>  		goto out;
> @@ -1414,7 +1413,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
>  		return;
>  
>  	ir->usbdev = NULL;
> -	rc_unregister_device(ir->rc);
> +	rc_unregister_ir_raw_device(ir->rc);
>  	usb_kill_urb(ir->urb_in);
>  	usb_free_urb(ir->urb_in);
>  	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
> diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
> index 160d685..a8c9b5f 100644
> --- a/drivers/media/rc/nuvoton-cir.c
> +++ b/drivers/media/rc/nuvoton-cir.c
> @@ -34,7 +34,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  #include <linux/pci_ids.h>
>  
>  #include "nuvoton-cir.h"
> @@ -1054,7 +1054,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
>  
>  	/* Set up the rc device */
>  	rdev->priv = nvt;
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  	rdev->allowed_protocols = RC_BIT_ALL;
>  	rdev->open = nvt_open;
>  	rdev->close = nvt_close;
> @@ -1119,7 +1118,7 @@ exit_free_irq:
>  exit_release_cir_addr:
>  	release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
>  exit_unregister_device:
> -	rc_unregister_device(rdev);
> +	rc_unregister_ir_raw_device(rdev);
>  	rdev = NULL;
>  exit_free_dev_rdev:
>  	rc_free_device(rdev);
> @@ -1147,7 +1146,7 @@ static void nvt_remove(struct pnp_dev *pdev)
>  	release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
>  	release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
>  
> -	rc_unregister_device(nvt->rdev);
> +	rc_unregister_ir_raw_device(nvt->rdev);
>  
>  	kfree(nvt);
>  }
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index 0159836..0b32ef8 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -19,6 +19,12 @@
>  #include <linux/slab.h>
>  #include <linux/spinlock.h>
>  #include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
> +
> +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 */
> +};
>  
>  struct ir_raw_handler {
>  	struct list_head list;
> @@ -148,12 +154,8 @@ static inline bool is_timing_event(struct ir_raw_event ev)
>  /*
>   * Routines from rc-raw.c to be used internally and by decoders
>   */
> -u64 ir_raw_get_allowed_protocols(void);
> -int ir_raw_event_register(struct rc_dev *dev);
> -void ir_raw_event_unregister(struct rc_dev *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);
>  
>  /*
>   * Methods from rc-keytable.c to be used internally
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index 5ed8007..86f5aa7 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -16,6 +16,7 @@
>  #include <linux/kthread.h>
>  #include <linux/mutex.h>
>  #include <linux/kmod.h>
> +#include <linux/module.h>
>  #include <linux/sched.h>
>  #include <linux/freezer.h>
>  #include "rc-core-priv.h"
> @@ -269,8 +270,7 @@ void ir_raw_event_handle(struct rc_dev *dev)
>  EXPORT_SYMBOL_GPL(ir_raw_event_handle);
>  
>  /* used internally by the sysfs interface */
> -u64
> -ir_raw_get_allowed_protocols(void)
> +static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
>  {
>  	u64 protocols;
>  	mutex_lock(&ir_raw_handler_lock);
> @@ -287,7 +287,7 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
>  /*
>   * Used to (un)register raw event clients
>   */
> -int ir_raw_event_register(struct rc_dev *dev)
> +int rc_register_ir_raw_device(struct rc_dev *dev)
>  {
>  	int rc;
>  	struct ir_raw_handler *handler;
> @@ -301,14 +301,16 @@ int ir_raw_event_register(struct rc_dev *dev)
>  
>  	dev->raw->dev = dev;
>  	dev->enabled_protocols = ~0;
> +	dev->get_protocols = ir_raw_get_allowed_protocols;
> +	dev->driver_type = RC_DRIVER_IR_RAW;
>  	dev->change_protocol = change_protocol;
> +	spin_lock_init(&dev->raw->lock);
>  	rc = kfifo_alloc(&dev->raw->kfifo,
>  			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
>  			 GFP_KERNEL);
>  	if (rc < 0)
>  		goto out;
>  
> -	spin_lock_init(&dev->raw->lock);
>  	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
>  				       dev_name(&dev->dev));
>  
> @@ -317,6 +319,10 @@ int ir_raw_event_register(struct rc_dev *dev)
>  		goto out;
>  	}
>  
> +	rc = rc_register_device(dev);
> +	if (rc < 0)
> +		goto out_thread;
> +
>  	mutex_lock(&ir_raw_handler_lock);
>  	list_add_tail(&dev->raw->list, &ir_raw_client_list);
>  	list_for_each_entry(handler, &ir_raw_handler_list, list)
> @@ -326,13 +332,16 @@ int ir_raw_event_register(struct rc_dev *dev)
>  
>  	return 0;
>  
> +out_thread:
> +	kthread_stop(dev->raw->thread);
>  out:
>  	kfree(dev->raw);
>  	dev->raw = NULL;
>  	return rc;
>  }
> +EXPORT_SYMBOL_GPL(rc_register_ir_raw_device);
>  
> -void ir_raw_event_unregister(struct rc_dev *dev)
> +void rc_unregister_ir_raw_device(struct rc_dev *dev)
>  {
>  	struct ir_raw_handler *handler;
>  
> @@ -351,7 +360,9 @@ void ir_raw_event_unregister(struct rc_dev *dev)
>  	kfifo_free(&dev->raw->kfifo);
>  	kfree(dev->raw);
>  	dev->raw = NULL;
> +	rc_unregister_device(dev);
>  }
> +EXPORT_SYMBOL_GPL(rc_unregister_ir_raw_device);
>  
>  /*
>   * Extension interface - used to register the IR decoders
> @@ -387,10 +398,11 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
>  }
>  EXPORT_SYMBOL(ir_raw_handler_unregister);
>  
> -void ir_raw_init(void)
> +static struct work_struct wq_load;
> +
> +static void rc_ir_raw_init_decoders(struct work_struct *work)
>  {
>  	/* Load the decoder modules */
> -
>  	load_nec_decode();
>  	load_rc5_decode();
>  	load_rc6_decode();
> @@ -400,8 +412,15 @@ void ir_raw_init(void)
>  	load_sharp_decode();
>  	load_mce_kbd_decode();
>  	load_lirc_codec();
> +}
>  
> -	/* If needed, we may later add some init code. In this case,
> -	   it is needed to change the CONFIG_MODULE test at rc-core.h
> -	 */
> +static int __init rc_ir_raw_init(void)
> +{
> +	INIT_WORK(&wq_load, rc_ir_raw_init_decoders);
> +	schedule_work(&wq_load);
> +	return 0;
>  }
> +subsys_initcall(rc_ir_raw_init);
> +
> +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
> index f201395..343c8d0 100644
> --- a/drivers/media/rc/rc-loopback.c
> +++ b/drivers/media/rc/rc-loopback.c
> @@ -26,7 +26,7 @@
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/sched.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRIVER_NAME	"rc-loopback"
>  #define dprintk(x...)	if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
> @@ -227,7 +227,6 @@ static int __init loop_init(void)
>  	rc->input_id.version	= 1;
>  	rc->driver_name		= DRIVER_NAME;
>  	rc->priv		= &loopdev;
> -	rc->driver_type		= RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols	= RC_BIT_ALL;
>  	rc->timeout		= 100 * 1000 * 1000; /* 100 ms */
>  	rc->min_timeout		= 1;
> @@ -250,7 +249,7 @@ static int __init loop_init(void)
>  	loopdev.learning	= false;
>  	loopdev.carrierreport	= false;
>  
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret < 0) {
>  		printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
>  		rc_free_device(rc);
> @@ -263,7 +262,7 @@ static int __init loop_init(void)
>  
>  static void __exit loop_exit(void)
>  {
> -	rc_unregister_device(loopdev.dev);
> +	rc_unregister_ir_raw_device(loopdev.dev);
>  }
>  
>  module_init(loop_init);
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index 8729d0a..7caca4f 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -343,10 +343,7 @@ static ssize_t show_protocols(struct device *device,
>  
>  	if (fattr->type == RC_FILTER_NORMAL) {
>  		enabled = dev->enabled_protocols;
> -		if (dev->raw)
> -			allowed = ir_raw_get_allowed_protocols();
> -		else
> -			allowed = dev->allowed_protocols;
> +		allowed = dev->allowed_protocols;
>  	} else {
>  		enabled = dev->enabled_wakeup_protocols;
>  		allowed = dev->allowed_wakeup_protocols;
> @@ -919,10 +916,7 @@ void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
>  	rx->rx_enabled = 0x1;
>  	rx->rx_connected = 0x1;
>  	rx->protocols_enabled[0] = dev->enabled_protocols;
> -	if (dev->driver_type == RC_DRIVER_SCANCODE)
> -		rx->protocols_supported[0] = dev->allowed_protocols;
> -	else
> -		rx->protocols_supported[0] = ir_raw_get_allowed_protocols();
> +	rx->protocols_supported[0] = dev->allowed_protocols;
>  	rx->timeout = dev->timeout;
>  	rx->timeout_min = dev->min_timeout;
>  	rx->timeout_max = dev->max_timeout;
> @@ -1135,9 +1129,6 @@ static void rc_dev_release(struct device *device)
>  {
>  	struct rc_dev *dev = to_rc_dev(device);
>  
> -	if (dev->driver_type == RC_DRIVER_IR_RAW)
> -		ir_raw_event_unregister(dev);
> -
>  	kfifo_free(&dev->txfifo);
>  	kfree(dev);
>  	module_put(THIS_MODULE);
> @@ -1267,7 +1258,6 @@ EXPORT_SYMBOL_GPL(rc_free_device);
>  
>  int rc_register_device(struct rc_dev *dev)
>  {
> -	static bool raw_init = false; /* raw decoders loaded? */
>  	struct rc_map *rc_map = NULL;
>  	int attr = 0;
>  	int minor;
> @@ -1290,18 +1280,6 @@ int rc_register_device(struct rc_dev *dev)
>  			goto out_minor;
>  	}
>  
> -	if (dev->driver_type == RC_DRIVER_IR_RAW) {
> -		/* Load raw decoders, if they aren't already */
> -		if (!raw_init) {
> -			IR_dprintk(1, "Loading raw decoders\n");
> -			ir_raw_init();
> -			raw_init = true;
> -		}
> -		rc = ir_raw_event_register(dev);
> -		if (rc < 0)
> -			goto out_minor;
> -	}
> -
>  	dev->dev.groups = dev->sysfs_groups;
>  	dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
>  	if (dev->s_filter)
> @@ -1319,13 +1297,13 @@ int rc_register_device(struct rc_dev *dev)
>  		u64 rc_type = (1 << rc_map->scan[0].protocol);
>  		rc = dev->change_protocol(dev, &rc_type);
>  		if (rc < 0)
> -			goto out_raw;
> +			goto out_minor;
>  		dev->enabled_protocols = rc_type;
>  	}
>  
>  	rc = cdev_add(&dev->cdev, dev->dev.devt, 1);
>  	if (rc)
> -		goto out_raw;
> +		goto out_minor;
>  
>  	rc = device_add(&dev->dev);
>  	if (rc)
> @@ -1347,9 +1325,6 @@ out_dev:
>  	device_del(&dev->dev);
>  out_cdev:
>  	cdev_del(&dev->cdev);
> -out_raw:
> -	if (dev->driver_type == RC_DRIVER_IR_RAW)
> -		ir_raw_event_unregister(dev);
>  out_minor:
>  	ida_simple_remove(&rc_ida, minor);
>  	return rc;
> @@ -1377,9 +1352,6 @@ void rc_unregister_device(struct rc_dev *dev)
>  
>  	cdev_del(&dev->cdev);
>  
> -	if (dev->driver_type == RC_DRIVER_IR_RAW)
> -		ir_raw_event_unregister(dev);
> -
>  	for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
>  		rc_remove_keytable(dev, i);
>  
> diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
> index 3a931a5..17974bf 100644
> --- a/drivers/media/rc/redrat3.c
> +++ b/drivers/media/rc/redrat3.c
> @@ -52,7 +52,7 @@
>  #include <linux/slab.h>
>  #include <linux/usb.h>
>  #include <linux/usb/input.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  /* Driver Information */
>  #define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
> @@ -936,7 +936,6 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
>  	usb_to_input_id(rr3->udev, &rc->input_id);
>  	rc->dev.parent = dev;
>  	rc->priv = rr3;
> -	rc->driver_type = RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols = RC_BIT_ALL;
>  	rc->timeout = US_TO_NS(2750);
>  	rc->tx_ir = redrat3_transmit_ir;
> @@ -945,7 +944,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
>  	rc->rx_resolution = US_TO_NS(2);
>  	rc->map_name = RC_MAP_HAUPPAUGE;
>  
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret < 0) {
>  		dev_err(dev, "remote dev registration failed\n");
>  		goto out;
> @@ -1114,7 +1113,7 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
>  		return;
>  
>  	usb_set_intfdata(intf, NULL);
> -	rc_unregister_device(rr3->rc);
> +	rc_unregister_ir_raw_device(rr3->rc);
>  	led_classdev_unregister(&rr3->led);
>  	del_timer_sync(&rr3->rx_timeout);
>  	redrat3_delete(rr3, udev);
> diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
> index 2659f66..149e824 100644
> --- a/drivers/media/rc/streamzap.c
> +++ b/drivers/media/rc/streamzap.c
> @@ -36,7 +36,7 @@
>  #include <linux/slab.h>
>  #include <linux/usb.h>
>  #include <linux/usb/input.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRIVER_VERSION	"1.61"
>  #define DRIVER_NAME	"streamzap"
> @@ -314,12 +314,11 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
>  	usb_to_input_id(sz->usbdev, &rdev->input_id);
>  	rdev->dev.parent = dev;
>  	rdev->priv = sz;
> -	rdev->driver_type = RC_DRIVER_IR_RAW;
>  	rdev->allowed_protocols = RC_BIT_ALL;
>  	rdev->driver_name = DRIVER_NAME;
>  	rdev->map_name = RC_MAP_STREAMZAP;
>  
> -	ret = rc_register_device(rdev);
> +	ret = rc_register_ir_raw_device(rdev);
>  	if (ret < 0) {
>  		dev_err(dev, "remote input device register failed\n");
>  		goto out;
> @@ -484,7 +483,7 @@ static void streamzap_disconnect(struct usb_interface *interface)
>  		return;
>  
>  	sz->usbdev = NULL;
> -	rc_unregister_device(sz->rdev);
> +	rc_unregister_ir_raw_device(sz->rdev);
>  	usb_kill_urb(sz->urb_in);
>  	usb_free_urb(sz->urb_in);
>  	usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
> diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
> index bc214e2..19317e2 100644
> --- a/drivers/media/rc/ttusbir.c
> +++ b/drivers/media/rc/ttusbir.c
> @@ -23,7 +23,7 @@
>  #include <linux/usb/input.h>
>  #include <linux/slab.h>
>  #include <linux/leds.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRIVER_NAME	"ttusbir"
>  #define DRIVER_DESC	"TechnoTrend USB IR Receiver"
> @@ -317,7 +317,6 @@ static int ttusbir_probe(struct usb_interface *intf,
>  	rc->input_phys = tt->phys;
>  	usb_to_input_id(tt->udev, &rc->input_id);
>  	rc->dev.parent = &intf->dev;
> -	rc->driver_type = RC_DRIVER_IR_RAW;
>  	rc->allowed_protocols = RC_BIT_ALL;
>  	rc->priv = tt;
>  	rc->driver_name = DRIVER_NAME;
> @@ -329,7 +328,7 @@ static int ttusbir_probe(struct usb_interface *intf,
>  	 */
>  	rc->rx_resolution = NS_PER_BIT;
>  
> -	ret = rc_register_device(rc);
> +	ret = rc_register_ir_raw_device(rc);
>  	if (ret) {
>  		dev_err(&intf->dev, "failed to register rc device %d\n", ret);
>  		goto out2;
> @@ -347,7 +346,7 @@ static int ttusbir_probe(struct usb_interface *intf,
>  
>  	return 0;
>  out3:
> -	rc_unregister_device(rc);
> +	rc_unregister_ir_raw_device(rc);
>  	rc = NULL;
>  out2:
>  	led_classdev_unregister(&tt->led);
> @@ -378,7 +377,7 @@ static void ttusbir_disconnect(struct usb_interface *intf)
>  
>  	tt->udev = NULL;
>  
> -	rc_unregister_device(tt->rc);
> +	rc_unregister_ir_raw_device(tt->rc);
>  	led_classdev_unregister(&tt->led);
>  	for (i = 0; i < NUM_URBS; i++) {
>  		usb_kill_urb(tt->urb[i]);
> diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
> index 8871109..07da3e0 100644
> --- a/drivers/media/rc/winbond-cir.c
> +++ b/drivers/media/rc/winbond-cir.c
> @@ -54,7 +54,7 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>  #include <linux/sched.h>
> -#include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #define DRVNAME "winbond-cir"
>  
> @@ -1051,7 +1051,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
>  		goto exit_unregister_led;
>  	}
>  
> -	data->dev->driver_type = RC_DRIVER_IR_RAW;
>  	data->dev->driver_name = DRVNAME;
>  	data->dev->input_name = WBCIR_NAME;
>  	data->dev->input_phys = "wbcir/cir0";
> @@ -1071,7 +1070,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
>  	data->dev->rx_resolution = US_TO_NS(2);
>  	data->dev->allowed_protocols = RC_BIT_ALL;
>  
> -	err = rc_register_device(data->dev);
> +	err = rc_register_ir_raw_device(data->dev);
>  	if (err)
>  		goto exit_free_rc;
>  
> @@ -1117,7 +1116,7 @@ exit_release_ebase:
>  exit_release_wbase:
>  	release_region(data->wbase, WAKEUP_IOMEM_LEN);
>  exit_unregister_device:
> -	rc_unregister_device(data->dev);
> +	rc_unregister_ir_raw_device(data->dev);
>  	data->dev = NULL;
>  exit_free_rc:
>  	rc_free_device(data->dev);
> @@ -1148,7 +1147,7 @@ wbcir_remove(struct pnp_dev *device)
>  	/* Clear BUFF_EN, END_EN, MATCH_EN */
>  	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
>  
> -	rc_unregister_device(data->dev);
> +	rc_unregister_ir_raw_device(data->dev);
>  
>  	led_classdev_unregister(&data->led);
>  
> diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
> index 124b4ba..ccdf0c6 100644
> --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
> +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
> @@ -25,6 +25,7 @@
>  #include <linux/usb/input.h>
>  #include <linux/firmware.h>
>  #include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #include "dvb_frontend.h"
>  #include "dvb_demux.h"
> @@ -131,7 +132,7 @@ struct dvb_usb_driver_info {
>   * @change_protocol: callback to change protocol
>   * @query: called to query an event from the device
>   * @interval: time in ms between two queries
> - * @driver_type: used to point if a device supports raw mode
> + * @rc_raw: used to point if a device supports raw mode
>   * @bulk_mode: device supports bulk mode for rc (disable polling mode)
>   */
>  struct dvb_usb_rc {
> @@ -140,7 +141,7 @@ struct dvb_usb_rc {
>  	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	int (*query) (struct dvb_usb_device *d);
>  	unsigned int interval;
> -	enum rc_driver_type driver_type;
> +	bool rc_raw;
>  	bool bulk_mode;
>  };
>  
> diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
> index eaa76ef..ea84894b 100644
> --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
> +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
> @@ -163,12 +163,15 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
>  	/* TODO: likely RC-core should took const char * */
>  	dev->driver_name = (char *) d->props->driver_name;
>  	dev->map_name = d->rc.map_name;
> -	dev->driver_type = d->rc.driver_type;
>  	dev->allowed_protocols = d->rc.allowed_protos;
>  	dev->change_protocol = d->rc.change_protocol;
>  	dev->priv = d;
>  
> -	ret = rc_register_device(dev);
> +	if (d->rc.rc_raw)
> +		ret = rc_register_ir_raw_device(dev);
> +	else
> +		ret = rc_register_device(dev);
> +
>  	if (ret < 0) {
>  		rc_free_device(dev);
>  		goto err;
> @@ -201,7 +204,10 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
>  
>  	if (d->rc_dev) {
>  		cancel_delayed_work_sync(&d->rc_query_work);
> -		rc_unregister_device(d->rc_dev);
> +		if (d->rc.rc_raw)
> +			rc_unregister_ir_raw_device(d->rc_dev);
> +		else
> +			rc_unregister_device(d->rc_dev);
>  		d->rc_dev = NULL;
>  	}
>  
> diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> index 15f1e70..0412862 100644
> --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> @@ -1373,7 +1373,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
>  		return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
>  
>  	rc->allowed_protos = RC_BIT_ALL;
> -	rc->driver_type = RC_DRIVER_IR_RAW;
> +	rc->rc_raw = true;
>  	rc->query = rtl2832u_rc_query;
>  	rc->interval = 400;
>  
> diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> index 5986626..88574d0 100644
> --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
> @@ -273,14 +273,17 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
>  	dev->map_name = d->props.rc.core.rc_codes;
>  	dev->change_protocol = d->props.rc.core.change_protocol;
>  	dev->allowed_protocols = d->props.rc.core.allowed_protos;
> -	dev->driver_type = d->props.rc.core.driver_type;
>  	usb_to_input_id(d->udev, &dev->input_id);
>  	dev->input_name = "IR-receiver inside an USB DVB receiver";
>  	dev->input_phys = d->rc_phys;
>  	dev->dev.parent = &d->udev->dev;
>  	dev->priv = d;
>  
> -	err = rc_register_device(dev);
> +	if (d->props.rc.core.rc_raw)
> +		err = rc_register_ir_raw_device(dev);
> +	else
> +		err = rc_register_device(dev);
> +
>  	if (err < 0) {
>  		rc_free_device(dev);
>  		return err;
> @@ -341,6 +344,8 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
>  		cancel_delayed_work_sync(&d->rc_query_work);
>  		if (d->props.rc.mode == DVB_RC_LEGACY)
>  			input_unregister_device(d->input_dev);
> +		else if (d->props.rc.core.rc_raw)
> +			rc_unregister_ir_raw_device(d->rc_dev);
>  		else
>  			rc_unregister_device(d->rc_dev);
>  	}
> diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
> index ce4c4e3..8e4b31e 100644
> --- a/drivers/media/usb/dvb-usb/dvb-usb.h
> +++ b/drivers/media/usb/dvb-usb/dvb-usb.h
> @@ -15,6 +15,7 @@
>  #include <linux/firmware.h>
>  #include <linux/mutex.h>
>  #include <media/rc-core.h>
> +#include <media/rc-ir-raw.h>
>  
>  #include "dvb_frontend.h"
>  #include "dvb_demux.h"
> @@ -191,7 +192,7 @@ struct dvb_rc_legacy {
>   * @rc_codes: name of rc codes table
>   * @protocol: type of protocol(s) currently used by the driver
>   * @allowed_protos: protocol(s) supported by the driver
> - * @driver_type: Used to point if a device supports raw mode
> + * @rc_raw: Used to point if a device supports raw mode
>   * @change_protocol: callback to change protocol
>   * @rc_query: called to query an event event.
>   * @rc_interval: time in ms between two queries.
> @@ -201,7 +202,7 @@ struct dvb_rc {
>  	char *rc_codes;
>  	u64 protocol;
>  	u64 allowed_protos;
> -	enum rc_driver_type driver_type;
> +	bool rc_raw;
>  	int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	char *module_name;
>  	int (*rc_query) (struct dvb_usb_device *d);
> diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
> index 98d24ae..288f24c 100644
> --- a/drivers/media/usb/dvb-usb/technisat-usb2.c
> +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
> @@ -733,7 +733,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
>  		.module_name = "technisat-usb2",
>  		.rc_query    = technisat_usb2_rc_query,
>  		.allowed_protos = RC_BIT_ALL,
> -		.driver_type    = RC_DRIVER_IR_RAW,
> +		.rc_raw      = true,
>  	}
>  };
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 1232e32..8fdb515 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -856,9 +856,6 @@ static int em28xx_ir_suspend(struct em28xx *dev)
>  	if (ir)
>  		cancel_delayed_work_sync(&ir->work);
>  	cancel_delayed_work_sync(&dev->buttons_query_work);
> -	/* is canceling delayed work sufficient or does the rc event
> -	   kthread needs stopping? kthread is stopped in
> -	   ir_raw_event_unregister() */
>  	return 0;
>  }
>  
> @@ -870,8 +867,6 @@ static int em28xx_ir_resume(struct em28xx *dev)
>  		return 0;
>  
>  	em28xx_info("Resuming input extension");
> -	/* if suspend calls ir_raw_event_unregister(), the should call
> -	   ir_raw_event_register() */
>  	if (ir)
>  		schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
>  	if (dev->num_button_polling_addresses)
> diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
> index 7c9b58d..1d4b191 100644
> --- a/drivers/media/usb/tm6000/tm6000-input.c
> +++ b/drivers/media/usb/tm6000/tm6000-input.c
> @@ -452,7 +452,6 @@ int tm6000_ir_init(struct tm6000_core *dev)
>  		ir->polling = 50;
>  		INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
>  	}
> -	rc->driver_type = RC_DRIVER_SCANCODE;
>  
>  	snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
>  						dev->name);
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 228510e..25c1d38 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -177,11 +177,6 @@ struct rc_keytable_ioctl {
>  	char name[RC_KEYTABLE_NAME_SIZE];
>  } __packed;
>  
> -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 */
> -};
> -
>  /* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
>  struct rc_scancode {
>  	__u16 protocol;
> @@ -304,6 +299,7 @@ enum rc_filter_type {
>   * @rx_resolution : resolution (in ns) of input sampler
>   * @tx_resolution: resolution (in ns) of output sampler
>   * @change_protocol: allow changing the protocol used on hardware decoders
> + * @get_protocols: returns a bitmask of allowed protocols
>   * @change_wakeup_protocol: allow changing the protocol used for wakeup
>   *	filtering
>   * @open: callback to allow drivers to enable polling/irq when IR input device
> @@ -347,7 +343,7 @@ struct rc_dev {
>  	wait_queue_head_t		txwait;
>  	wait_queue_head_t		rxwait;
>  	struct ir_raw_event_ctrl	*raw;
> -	enum rc_driver_type		driver_type;
> +	unsigned			driver_type;
>  	bool				idle;
>  	u64				allowed_protocols;
>  	u64				enabled_protocols;
> @@ -363,6 +359,7 @@ struct rc_dev {
>  	u32				max_timeout;
>  	u32				rx_resolution;
>  	u32				tx_resolution;
> +	u64				(*get_protocols)(struct rc_dev *dev);
>  	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	int				(*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	int				(*open)(struct rc_dev *dev);
> @@ -461,70 +458,6 @@ static inline void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protoco
>  	rc_do_keydown(dev, protocol, scancode, toggle, false);
>  }
>  
> -/*
> - * From rc-raw.c
> - * The Raw interface is specific to InfraRed. It may be a good idea to
> - * split it later into a separate header.
> - */
> -
> -enum raw_event_type {
> -	IR_SPACE        = (1 << 0),
> -	IR_PULSE        = (1 << 1),
> -	IR_START_EVENT  = (1 << 2),
> -	IR_STOP_EVENT   = (1 << 3),
> -};
> -
> -struct ir_raw_event {
> -	union {
> -		u32             duration;
> -
> -		struct {
> -			u32     carrier;
> -			u8      duty_cycle;
> -		};
> -	};
> -
> -	unsigned                pulse:1;
> -	unsigned                reset:1;
> -	unsigned                timeout:1;
> -	unsigned                carrier_report:1;
> -};
> -
> -#define DEFINE_IR_RAW_EVENT(event) \
> -	struct ir_raw_event event = { \
> -		{ .duration = 0 } , \
> -		.pulse = 0, \
> -		.reset = 0, \
> -		.timeout = 0, \
> -		.carrier_report = 0 }
> -
> -static inline void init_ir_raw_event(struct ir_raw_event *ev)
> -{
> -	memset(ev, 0, sizeof(*ev));
> -}
> -
> -#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
> -#define US_TO_NS(usec)		((usec) * 1000)
> -#define MS_TO_US(msec)		((msec) * 1000)
> -#define MS_TO_NS(msec)		((msec) * 1000 * 1000)
> -
> -void ir_raw_event_handle(struct rc_dev *dev);
> -int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
> -int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
> -int ir_raw_event_store_with_filter(struct rc_dev *dev,
> -				struct ir_raw_event *ev);
> -void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
> -int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
> -
> -static inline void ir_raw_event_reset(struct rc_dev *dev)
> -{
> -	DEFINE_IR_RAW_EVENT(ev);
> -	ev.reset = true;
> -
> -	ir_raw_event_store(dev, &ev);
> -	ir_raw_event_handle(dev);
> -}
> -
>  /* extract mask bits out of data and pack them into the result */
>  static inline u32 ir_extract_bits(u32 data, u32 mask)
>  {
> diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
> new file mode 100644
> index 0000000..dad3eb2
> --- /dev/null
> +++ b/include/media/rc-ir-raw.h
> @@ -0,0 +1,83 @@
> +/*
> + * Remote Controller core header
> + *
> + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab
> + *
> + * 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 _RC_IR_RAW
> +#define _RC_IR_RAW
> +
> +#include <linux/spinlock.h>
> +#include <linux/kfifo.h>
> +#include <media/rc-core.h>
> +
> +enum raw_event_type {
> +	IR_SPACE        = (1 << 0),
> +	IR_PULSE        = (1 << 1),
> +	IR_START_EVENT  = (1 << 2),
> +	IR_STOP_EVENT   = (1 << 3),
> +};
> +
> +struct ir_raw_event {
> +	union {
> +		u32             duration;
> +
> +		struct {
> +			u32     carrier;
> +			u8      duty_cycle;
> +		};
> +	};
> +
> +	unsigned                pulse:1;
> +	unsigned                reset:1;
> +	unsigned                timeout:1;
> +	unsigned                carrier_report:1;
> +};
> +
> +#define DEFINE_IR_RAW_EVENT(event) \
> +	struct ir_raw_event event = { \
> +		{ .duration = 0 } , \
> +		.pulse = 0, \
> +		.reset = 0, \
> +		.timeout = 0, \
> +		.carrier_report = 0 }
> +
> +static inline void init_ir_raw_event(struct ir_raw_event *ev)
> +{
> +	memset(ev, 0, sizeof(*ev));
> +}
> +
> +#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
> +#define US_TO_NS(usec)		((usec) * 1000)
> +#define MS_TO_US(msec)		((msec) * 1000)
> +#define MS_TO_NS(msec)		((msec) * 1000 * 1000)
> +
> +void ir_raw_event_handle(struct rc_dev *dev);
> +int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
> +int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
> +int ir_raw_event_store_with_filter(struct rc_dev *dev,
> +				struct ir_raw_event *ev);
> +void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
> +int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
> +int rc_register_ir_raw_device(struct rc_dev *dev);
> +void rc_unregister_ir_raw_device(struct rc_dev *dev);
> +
> +static inline void ir_raw_event_reset(struct rc_dev *dev)
> +{
> +	DEFINE_IR_RAW_EVENT(ev);
> +	ev.reset = true;
> +
> +	ir_raw_event_store(dev, &ev);
> +	ir_raw_event_handle(dev);
> +}
> +
> +#endif /* _RC_IR_RAW */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 40/49] rc-ir-raw: simplify locking
  2014-04-03 23:34 ` [PATCH 40/49] rc-ir-raw: simplify locking David Härdeman
@ 2014-07-25 23:08   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:08 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:38 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Simplify and improve the locking in rc-ir-raw by making better use of
> the existing kfifo functionality and by using RCU where possible.

Please rebase.

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-core-priv.h |    6 +-
>  drivers/media/rc/rc-ir-raw.c    |  124 ++++++++++++++++-----------------------
>  2 files changed, 55 insertions(+), 75 deletions(-)
> 
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index 0b32ef8..c3de26b 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -37,11 +37,13 @@ struct ir_raw_handler {
>  	int (*raw_unregister)(struct rc_dev *dev);
>  };
>  
> +/* max number of pulse/space transitions to buffer */
> +#define RC_MAX_IR_EVENTS	512
> +
>  struct ir_raw_event_ctrl {
>  	struct list_head		list;		/* to keep track of raw clients */
>  	struct task_struct		*thread;
> -	spinlock_t			lock;
> -	struct kfifo_rec_ptr_1		kfifo;		/* fifo for the pulse/space durations */
> +	DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
>  	ktime_t				last_event;	/* when last event occurred */
>  	enum raw_event_type		last_type;	/* last event type */
>  	struct rc_dev			*dev;		/* pointer to the parent rc_dev */
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index 86f5aa7..9631825 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -21,15 +21,12 @@
>  #include <linux/freezer.h>
>  #include "rc-core-priv.h"
>  
> -/* Define the max number of pulse/space transitions to buffer */
> -#define MAX_IR_EVENT_SIZE      512
> -
> -/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
> +/* IR raw clients/handlers, writers synchronize with ir_raw_mutex */
> +static DEFINE_MUTEX(ir_raw_mutex);
>  static LIST_HEAD(ir_raw_client_list);
> -
> -/* Used to handle IR raw handler extensions */
> -static DEFINE_MUTEX(ir_raw_handler_lock);
>  static LIST_HEAD(ir_raw_handler_list);
> +
> +/* protocols supported by the currently loaded decoders */
>  static u64 available_protocols;
>  
>  static int ir_raw_event_thread(void *data)
> @@ -37,32 +34,19 @@ static int ir_raw_event_thread(void *data)
>  	struct ir_raw_event ev;
>  	struct ir_raw_handler *handler;
>  	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
> -	int retval;
>  
>  	while (!kthread_should_stop()) {
> -
> -		spin_lock_irq(&raw->lock);
> -		retval = kfifo_len(&raw->kfifo);
> -
> -		if (retval < sizeof(ev)) {
> +		if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
>  			set_current_state(TASK_INTERRUPTIBLE);
> -
> -			if (kthread_should_stop())
> -				set_current_state(TASK_RUNNING);
> -
> -			spin_unlock_irq(&raw->lock);
>  			schedule();
>  			continue;
>  		}
>  
> -		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
> -		spin_unlock_irq(&raw->lock);
> -
> -		mutex_lock(&ir_raw_handler_lock);
> -		list_for_each_entry(handler, &ir_raw_handler_list, list)
> +		rcu_read_lock();
> +		list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
>  			handler->decode(raw->dev, ev);
> +		rcu_read_unlock();
>  		raw->prev_ev = ev;
> -		mutex_unlock(&ir_raw_handler_lock);
>  	}
>  
>  	return 0;
> @@ -76,7 +60,8 @@ static int ir_raw_event_thread(void *data)
>   * 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.
> + * will reset the decoding state machines. Drivers are responsible for
> + * synchronizing calls to this function.
>   */
>  int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
>  {
> @@ -86,7 +71,7 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
>  	IR_dprintk(2, "sample: (%05dus %s)\n",
>  		   TO_US(ev->duration), TO_STR(ev->pulse));
>  
> -	if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
> +	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
>  		return -ENOMEM;
>  
>  	return 0;
> @@ -258,14 +243,8 @@ EXPORT_SYMBOL_GPL(ir_raw_get_tx_event);
>   */
>  void ir_raw_event_handle(struct rc_dev *dev)
>  {
> -	unsigned long flags;
> -
> -	if (!dev->raw)
> -		return;
> -
> -	spin_lock_irqsave(&dev->raw->lock, flags);
> -	wake_up_process(dev->raw->thread);
> -	spin_unlock_irqrestore(&dev->raw->lock, flags);
> +	if (dev->raw)
> +		wake_up_process(dev->raw->thread);
>  }
>  EXPORT_SYMBOL_GPL(ir_raw_event_handle);
>  
> @@ -273,9 +252,9 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
>  static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
>  {
>  	u64 protocols;
> -	mutex_lock(&ir_raw_handler_lock);
> +	mutex_lock(&ir_raw_mutex);
>  	protocols = available_protocols;
> -	mutex_unlock(&ir_raw_handler_lock);
> +	mutex_unlock(&ir_raw_mutex);
>  	return protocols;
>  }
>  
> @@ -290,52 +269,49 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
>  int rc_register_ir_raw_device(struct rc_dev *dev)
>  {
>  	int rc;
> +	struct ir_raw_event_ctrl *raw;
>  	struct ir_raw_handler *handler;
>  
>  	if (!dev)
>  		return -EINVAL;
>  
> -	dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
> -	if (!dev->raw)
> +	raw = kzalloc(sizeof(*raw), GFP_KERNEL);
> +	if (!raw)
>  		return -ENOMEM;
>  
> -	dev->raw->dev = dev;
> -	dev->enabled_protocols = ~0;
> -	dev->get_protocols = ir_raw_get_allowed_protocols;
> -	dev->driver_type = RC_DRIVER_IR_RAW;
> -	dev->change_protocol = change_protocol;
> -	spin_lock_init(&dev->raw->lock);
> -	rc = kfifo_alloc(&dev->raw->kfifo,
> -			 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
> -			 GFP_KERNEL);
> -	if (rc < 0)
> -		goto out;
> -
> -	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
> -				       dev_name(&dev->dev));
> +	raw->dev = dev;
> +	INIT_KFIFO(raw->kfifo);
> +	raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
> +				  dev_name(&dev->dev));
>  
> -	if (IS_ERR(dev->raw->thread)) {
> -		rc = PTR_ERR(dev->raw->thread);
> +	if (IS_ERR(raw->thread)) {
> +		rc = PTR_ERR(raw->thread);
>  		goto out;
>  	}
>  
> +	dev->raw = raw;
> +	dev->enabled_protocols = ~0;
> +	dev->get_protocols = ir_raw_get_allowed_protocols;
> +	dev->driver_type = RC_DRIVER_IR_RAW;
> +	dev->change_protocol = change_protocol;
>  	rc = rc_register_device(dev);
>  	if (rc < 0)
>  		goto out_thread;
>  
> -	mutex_lock(&ir_raw_handler_lock);
> -	list_add_tail(&dev->raw->list, &ir_raw_client_list);
> -	list_for_each_entry(handler, &ir_raw_handler_list, list)
> +	mutex_lock(&ir_raw_mutex);
> +	list_add_tail_rcu(&dev->raw->list, &ir_raw_client_list);
> +	list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
>  		if (handler->raw_register)
>  			handler->raw_register(dev);
> -	mutex_unlock(&ir_raw_handler_lock);
> +	mutex_unlock(&ir_raw_mutex);
> +	synchronize_rcu();
>  
>  	return 0;
>  
>  out_thread:
> -	kthread_stop(dev->raw->thread);
> +	kthread_stop(raw->thread);
>  out:
> -	kfree(dev->raw);
> +	kfree(raw);
>  	dev->raw = NULL;
>  	return rc;
>  }
> @@ -350,14 +326,14 @@ void rc_unregister_ir_raw_device(struct rc_dev *dev)
>  
>  	kthread_stop(dev->raw->thread);
>  
> -	mutex_lock(&ir_raw_handler_lock);
> -	list_del(&dev->raw->list);
> -	list_for_each_entry(handler, &ir_raw_handler_list, list)
> +	mutex_lock(&ir_raw_mutex);
> +	list_del_rcu(&dev->raw->list);
> +	list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
>  		if (handler->raw_unregister)
>  			handler->raw_unregister(dev);
> -	mutex_unlock(&ir_raw_handler_lock);
> +	mutex_unlock(&ir_raw_mutex);
> +	synchronize_rcu();
>  
> -	kfifo_free(&dev->raw->kfifo);
>  	kfree(dev->raw);
>  	dev->raw = NULL;
>  	rc_unregister_device(dev);
> @@ -372,13 +348,14 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
>  {
>  	struct ir_raw_event_ctrl *raw;
>  
> -	mutex_lock(&ir_raw_handler_lock);
> -	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
> +	mutex_lock(&ir_raw_mutex);
> +	list_add_tail_rcu(&ir_raw_handler->list, &ir_raw_handler_list);
>  	if (ir_raw_handler->raw_register)
> -		list_for_each_entry(raw, &ir_raw_client_list, list)
> +		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
>  			ir_raw_handler->raw_register(raw->dev);
>  	available_protocols |= ir_raw_handler->protocols;
> -	mutex_unlock(&ir_raw_handler_lock);
> +	mutex_unlock(&ir_raw_mutex);
> +	synchronize_rcu();
>  
>  	return 0;
>  }
> @@ -388,13 +365,14 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
>  {
>  	struct ir_raw_event_ctrl *raw;
>  
> -	mutex_lock(&ir_raw_handler_lock);
> -	list_del(&ir_raw_handler->list);
> +	mutex_lock(&ir_raw_mutex);
> +	list_del_rcu(&ir_raw_handler->list);
>  	if (ir_raw_handler->raw_unregister)
> -		list_for_each_entry(raw, &ir_raw_client_list, list)
> +		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
>  			ir_raw_handler->raw_unregister(raw->dev);
>  	available_protocols &= ~ir_raw_handler->protocols;
> -	mutex_unlock(&ir_raw_handler_lock);
> +	mutex_unlock(&ir_raw_mutex);
> +	synchronize_rcu();
>  }
>  EXPORT_SYMBOL(ir_raw_handler_unregister);
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 41/49] rc-core: rename mutex
  2014-04-03 23:34 ` [PATCH 41/49] rc-core: rename mutex David Härdeman
  2014-04-10 21:28   ` James Hogan
@ 2014-07-25 23:12   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:12 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:43 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Having a mutex named "lock" is a bit misleading.

Please rebase.

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/img-ir/img-ir-hw.c |    4 ++-
>  drivers/media/rc/rc-main.c          |   42 ++++++++++++++++++-----------------
>  include/media/rc-core.h             |    5 ++--
>  3 files changed, 25 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
> index 5bc7903..a9abbb4 100644
> --- a/drivers/media/rc/img-ir/img-ir-hw.c
> +++ b/drivers/media/rc/img-ir/img-ir-hw.c
> @@ -666,11 +666,11 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
>  {
>  	struct rc_dev *rdev = priv->hw.rdev;
>  
> -	mutex_lock(&rdev->lock);
> +	mutex_lock(&rdev->mutex);
>  	rdev->enabled_protocols = proto;
>  	rdev->allowed_wakeup_protocols = proto;
>  	rdev->enabled_wakeup_protocols = proto;
> -	mutex_unlock(&rdev->lock);
> +	mutex_unlock(&rdev->mutex);
>  }
>  
>  /* Set up IR decoders */
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index 7caca4f..bd4dfab 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -109,7 +109,7 @@ int rc_open(struct rc_dev *dev)
>  {
>  	int err = 0;
>  
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  
>  	if (dev->dead)
>  		err = -ENODEV;
> @@ -119,7 +119,7 @@ int rc_open(struct rc_dev *dev)
>  			dev->users--;
>  	}
>  
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  
>  	return err;
>  }
> @@ -127,12 +127,12 @@ EXPORT_SYMBOL_GPL(rc_open);
>  
>  void rc_close(struct rc_dev *dev)
>  {
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  
>  	if (!dev->dead && !--dev->users && dev->close)
>  		dev->close(dev);
>  
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  }
>  EXPORT_SYMBOL_GPL(rc_close);
>  
> @@ -322,7 +322,7 @@ struct rc_filter_attribute {
>   * It returns the protocol names of supported protocols.
>   * Enabled protocols are printed in brackets.
>   *
> - * dev->lock is taken to guard against races between store_protocols and
> + * dev->mutex is taken to guard against races between store_protocols and
>   * show_protocols.
>   */
>  static ssize_t show_protocols(struct device *device,
> @@ -339,7 +339,7 @@ static ssize_t show_protocols(struct device *device,
>  		return -EINVAL;
>  
>  	rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  
>  	if (fattr->type == RC_FILTER_NORMAL) {
>  		enabled = dev->enabled_protocols;
> @@ -349,7 +349,7 @@ static ssize_t show_protocols(struct device *device,
>  		allowed = dev->allowed_wakeup_protocols;
>  	}
>  
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  
>  	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
>  		   __func__, (long long)allowed, (long long)enabled);
> @@ -449,7 +449,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
>   * See parse_protocol_change() for the valid commands.
>   * Returns @len on success or a negative error code.
>   *
> - * dev->lock is taken to guard against races between store_protocols and
> + * dev->mutex is taken to guard against races between store_protocols and
>   * show_protocols.
>   */
>  static ssize_t store_protocols(struct device *device,
> @@ -488,7 +488,7 @@ static ssize_t store_protocols(struct device *device,
>  		return -EINVAL;
>  	}
>  
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  
>  	old_protocols = *current_protocols;
>  	new_protocols = old_protocols;
> @@ -532,7 +532,7 @@ static ssize_t store_protocols(struct device *device,
>  	rc = len;
>  
>  out:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return rc;
>  }
>  
> @@ -550,7 +550,7 @@ out:
>   * Bits of the filter value corresponding to set bits in the filter mask are
>   * compared against input scancodes and non-matching scancodes are discarded.
>   *
> - * dev->lock is taken to guard against races between store_filter and
> + * dev->mutex is taken to guard against races between store_filter and
>   * show_filter.
>   */
>  static ssize_t show_filter(struct device *device,
> @@ -571,12 +571,12 @@ static ssize_t show_filter(struct device *device,
>  	else
>  		filter = &dev->scancode_wakeup_filter;
>  
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  	if (fattr->mask)
>  		val = filter->mask;
>  	else
>  		val = filter->data;
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  
>  	return sprintf(buf, "%#x\n", val);
>  }
> @@ -597,7 +597,7 @@ static ssize_t show_filter(struct device *device,
>   * Bits of the filter value corresponding to set bits in the filter mask are
>   * compared against input scancodes and non-matching scancodes are discarded.
>   *
> - * dev->lock is taken to guard against races between store_filter and
> + * dev->mutex is taken to guard against races between store_filter and
>   * show_filter.
>   */
>  static ssize_t store_filter(struct device *device,
> @@ -633,7 +633,7 @@ static ssize_t store_filter(struct device *device,
>  	if (!set_filter)
>  		return -EINVAL;
>  
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  
>  	new_filter = *filter;
>  	if (fattr->mask)
> @@ -654,7 +654,7 @@ static ssize_t store_filter(struct device *device,
>  	*filter = new_filter;
>  
>  unlock:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return (ret < 0) ? ret : len;
>  }
>  
> @@ -1087,7 +1087,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  	struct rc_dev *dev = client->dev;
>  	int ret;
>  
> -	ret = mutex_lock_interruptible(&dev->lock);
> +	ret = mutex_lock_interruptible(&dev->mutex);
>  	if (ret)
>  		return ret;
>  
> @@ -1099,7 +1099,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  	ret = rc_do_ioctl(dev, cmd, arg);
>  
>  out:
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  	return ret;
>  }
>  
> @@ -1226,7 +1226,7 @@ struct rc_dev *rc_allocate_device(void)
>  	mutex_init(&dev->txmutex);
>  	init_waitqueue_head(&dev->txwait);
>  	init_waitqueue_head(&dev->rxwait);
> -	mutex_init(&dev->lock);
> +	mutex_init(&dev->mutex);
>  
>  	dev->dev.type = &rc_dev_type;
>  	dev->dev.class = &rc_class;
> @@ -1339,9 +1339,9 @@ void rc_unregister_device(struct rc_dev *dev)
>  	if (!dev)
>  		return;
>  
> -	mutex_lock(&dev->lock);
> +	mutex_lock(&dev->mutex);
>  	dev->dead = true;
> -	mutex_unlock(&dev->lock);
> +	mutex_unlock(&dev->mutex);
>  
>  	spin_lock(&dev->client_lock);
>  	list_for_each_entry(client, &dev->client_list, node)
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 25c1d38..a310e5b 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -268,8 +268,7 @@ enum rc_filter_type {
>   * @driver_name: name of the hardware driver which registered this device
>   * @map_name: name of the default keymap
>   * @rc_kt: current rc_keytable
> - * @lock: used to ensure we've filled in all protocol details before
> - *	anyone can call show_protocols or store_protocols
> + * @mutex: used where a more specific lock/mutex/etc is not available
>   * @dead: used to determine if the device is still alive
>   * @client_list: list of clients (processes which have opened the rc chardev)
>   * @client_lock: protects client_list
> @@ -334,7 +333,7 @@ struct rc_dev {
>  	const char			*map_name;
>  	struct rc_keytable		*keytables[RC_MAX_KEYTABLES];
>  	struct list_head		keytable_list;
> -	struct mutex			lock;
> +	struct mutex			mutex;
>  	bool				dead;
>  	struct list_head		client_list;
>  	spinlock_t			client_lock;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 42/49] rc-ir-raw: atomic reads of protocols
  2014-04-03 23:34 ` [PATCH 42/49] rc-ir-raw: atomic reads of protocols David Härdeman
@ 2014-07-25 23:13   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:13 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:48 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Use atomic reads to avoid having to take a mutex when getting
> the bitmask of supported protocols.

This also belongs to that RCU change series, and doesn't apply.

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-core-priv.h |    2 +-
>  drivers/media/rc/rc-ir-raw.c    |   12 ++++--------
>  2 files changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index c3de26b..04776e8 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -29,7 +29,7 @@ enum rc_driver_type {
>  struct ir_raw_handler {
>  	struct list_head list;
>  
> -	u64 protocols; /* which are handled by this handler */
> +	unsigned protocols; /* which are handled by this handler */
>  	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
>  
>  	/* These two should only be used by the lirc decoder */
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index 9631825..bf5215b 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -27,7 +27,7 @@ static LIST_HEAD(ir_raw_client_list);
>  static LIST_HEAD(ir_raw_handler_list);
>  
>  /* protocols supported by the currently loaded decoders */
> -static u64 available_protocols;
> +static atomic_t available_protocols = ATOMIC_INIT(0);
>  
>  static int ir_raw_event_thread(void *data)
>  {
> @@ -251,11 +251,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
>  /* used internally by the sysfs interface */
>  static u64 ir_raw_get_allowed_protocols(struct rc_dev *dev)
>  {
> -	u64 protocols;
> -	mutex_lock(&ir_raw_mutex);
> -	protocols = available_protocols;
> -	mutex_unlock(&ir_raw_mutex);
> -	return protocols;
> +	return atomic_read(&available_protocols);
>  }
>  
>  static int change_protocol(struct rc_dev *dev, u64 *rc_type) {
> @@ -353,7 +349,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
>  	if (ir_raw_handler->raw_register)
>  		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
>  			ir_raw_handler->raw_register(raw->dev);
> -	available_protocols |= ir_raw_handler->protocols;
> +	atomic_set_mask(ir_raw_handler->protocols, &available_protocols);
>  	mutex_unlock(&ir_raw_mutex);
>  	synchronize_rcu();
>  
> @@ -370,7 +366,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
>  	if (ir_raw_handler->raw_unregister)
>  		list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
>  			ir_raw_handler->raw_unregister(raw->dev);
> -	available_protocols &= ~ir_raw_handler->protocols;
> +	atomic_clear_mask(ir_raw_handler->protocols, &available_protocols);
>  	mutex_unlock(&ir_raw_mutex);
>  	synchronize_rcu();
>  }
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 44/49] rc-core: don't report scancodes via input devices
  2014-04-03 23:34 ` [PATCH 44/49] rc-core: don't report scancodes via input devices David Härdeman
@ 2014-07-25 23:16   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:16 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:34:58 +0200
David Härdeman <david@hardeman.nu> escreveu:

> The scancode that is reported via the input device(s) is now incomplete
> (missing the protocol) and redundant.

Not true yet, and I'm not sure if this is the right direction. Why?

Let's discuss it together with the RFC related to the usage of chardevs.


> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-keytable.c |   21 +++++----------------
>  1 file changed, 5 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
> index 5709ae6..23a66c7 100644
> --- a/drivers/media/rc/rc-keytable.c
> +++ b/drivers/media/rc/rc-keytable.c
> @@ -645,17 +645,10 @@ void rc_keytable_repeat(struct rc_keytable *kt)
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&kt->key_lock, flags);
> -
> -	input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
> -	input_sync(kt->idev);
> -
> -	if (!kt->key_pressed)
> -		goto out;
> -
> -	kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
> -	mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
> -
> -out:
> +	if (kt->key_pressed) {
> +		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
> +		mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
> +	}
>  	spin_unlock_irqrestore(&kt->key_lock, flags);
>  }
>  
> @@ -695,8 +688,6 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
>  	if (new_event)
>  		rc_do_keyup(kt, false);
>  
> -	input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
> -
>  	if (new_event && keycode != KEY_RESERVED) {
>  		/* Register a keypress */
>  		kt->key_pressed = true;
> @@ -710,8 +701,8 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
>  			   kt->dev->input_name, keycode, protocol,
>  			   (long long unsigned)scancode);
>  		input_report_key(kt->idev, keycode, 1);
> +		input_sync(kt->idev);
>  	}
> -	input_sync(kt->idev);
>  
>  	if (autoup && kt->key_pressed) {
>  		kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
> @@ -811,8 +802,6 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
>  	idev->close = rc_input_close;
>  	set_bit(EV_KEY, idev->evbit);
>  	set_bit(EV_REP, idev->evbit);
> -	set_bit(EV_MSC, idev->evbit);
> -	set_bit(MSC_SCAN, idev->mscbit);
>  	input_set_drvdata(idev, kt);
>  	setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 45/49] rc-ir-raw: add various rc_events
  2014-04-03 23:35 ` [PATCH 45/49] rc-ir-raw: add various rc_events David Härdeman
@ 2014-07-25 23:16   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:16 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:35:03 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Reporting pulse/space events via the /dev/rc/rcX device node is an
> important step towards having feature parity with LIRC.

Why to duplicate LIRC?

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/media/rc/rc-ir-raw.c |   11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index bf5215b..3b68975 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -71,6 +71,17 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
>  	IR_dprintk(2, "sample: (%05dus %s)\n",
>  		   TO_US(ev->duration), TO_STR(ev->pulse));
>  
> +	if (ev->reset)
> +		rc_event(dev, RC_IR, RC_IR_RESET, 1);
> +	else if (ev->carrier_report)
> +		rc_event(dev, RC_IR, RC_IR_CARRIER, ev->carrier);
> +	else if (ev->timeout)
> +		rc_event(dev, RC_IR, RC_IR_STOP, 1);
> +	else if (ev->pulse)
> +		rc_event(dev, RC_IR, RC_IR_PULSE, ev->duration);
> +	else
> +		rc_event(dev, RC_IR, RC_IR_SPACE, ev->duration);
> +
>  	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
>  		return -ENOMEM;
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

* Re: [PATCH 46/49] rc-core: use struct rc_event for all rc communication
  2014-04-03 23:35 ` [PATCH 46/49] rc-core: use struct rc_event for all rc communication David Härdeman
@ 2014-07-25 23:19   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 68+ messages in thread
From: Mauro Carvalho Chehab @ 2014-07-25 23:19 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-media

Em Fri, 04 Apr 2014 01:35:08 +0200
David Härdeman <david@hardeman.nu> escreveu:

> Remove struct ir_raw_event and use struct rc_event in all stages
> of IR processing. This should help future flexibility and also
> cuts down on the confusing number of structs that are flying
> around in rc-*.

You should rebase this one. Please also add a better explanation,
as I didn't get what you want to do here nor why.

> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> ---
>  drivers/hid/hid-picolcd_cir.c              |   18 +++--
>  drivers/media/common/siano/smsir.c         |    7 +-
>  drivers/media/i2c/cx25840/cx25840-ir.c     |   94 +++++++++++++++-------------
>  drivers/media/pci/cx23885/cx23885-input.c  |   11 +--
>  drivers/media/pci/cx23885/cx23888-ir.c     |   91 ++++++++++++++-------------
>  drivers/media/pci/cx88/cx88-input.c        |   13 +++-
>  drivers/media/rc/ene_ir.c                  |   12 ++--
>  drivers/media/rc/fintek-cir.c              |   21 +++---
>  drivers/media/rc/iguanair.c                |   17 ++---
>  drivers/media/rc/ir-jvc-decoder.c          |   48 +++++++-------
>  drivers/media/rc/ir-lirc-codec.c           |   28 ++++----
>  drivers/media/rc/ir-mce_kbd-decoder.c      |   34 +++++-----
>  drivers/media/rc/ir-nec-decoder.c          |   51 ++++++++-------
>  drivers/media/rc/ir-rc5-decoder.c          |   32 +++++-----
>  drivers/media/rc/ir-rc6-decoder.c          |   48 +++++++-------
>  drivers/media/rc/ir-sanyo-decoder.c        |   46 +++++++-------
>  drivers/media/rc/ir-sharp-decoder.c        |   49 +++++++--------
>  drivers/media/rc/ir-sony-decoder.c         |   42 +++++++------
>  drivers/media/rc/ite-cir.c                 |   19 ++----
>  drivers/media/rc/ite-cir.h                 |    2 -
>  drivers/media/rc/mceusb.c                  |   15 +++-
>  drivers/media/rc/nuvoton-cir.c             |   18 +++--
>  drivers/media/rc/rc-core-priv.h            |   40 +++++++-----
>  drivers/media/rc/rc-ir-raw.c               |   89 +++++++++++++++------------
>  drivers/media/rc/rc-loopback.c             |   14 +---
>  drivers/media/rc/redrat3.c                 |   34 ++++------
>  drivers/media/rc/streamzap.c               |   62 +++++++++---------
>  drivers/media/rc/ttusbir.c                 |   31 ++++-----
>  drivers/media/rc/winbond-cir.c             |   23 +++----
>  drivers/media/usb/dvb-usb-v2/rtl28xxu.c    |    6 +-
>  drivers/media/usb/dvb-usb/technisat-usb2.c |   15 +++-
>  include/media/rc-ir-raw.h                  |   47 +++++---------
>  32 files changed, 548 insertions(+), 529 deletions(-)
> 
> diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
> index 59d5eb1..1f9021f 100644
> --- a/drivers/hid/hid-picolcd_cir.c
> +++ b/drivers/hid/hid-picolcd_cir.c
> @@ -45,7 +45,7 @@ int picolcd_raw_cir(struct picolcd_data *data,
>  {
>  	unsigned long flags;
>  	int i, w, sz;
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	DEFINE_IR_RAW_EVENT(ev);
>  
>  	/* ignore if rc_dev is NULL or status is shunned */
>  	spin_lock_irqsave(&data->lock, flags);
> @@ -67,14 +67,18 @@ int picolcd_raw_cir(struct picolcd_data *data,
>  	 */
>  	sz = size > 0 ? min((int)raw_data[0], size-1) : 0;
>  	for (i = 0; i+1 < sz; i += 2) {
> -		init_ir_raw_event(&rawir);
>  		w = (raw_data[i] << 8) | (raw_data[i+1]);
> -		rawir.pulse = !!(w & 0x8000);
> -		rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w);
> +		if (w & 0x8000) {
> +			ev.code = RC_IR_PULSE;
> +			ev.val = US_TO_NS(65536 - w);
> +		} else {
> +			ev.code = RC_IR_SPACE;
> +			ev.val = US_TO_NS(w);
> +		}
>  		/* Quirk!! - see above */
> -		if (i == 0 && rawir.duration > 15000000)
> -			rawir.duration -= 15000000;
> -		ir_raw_event_store(data->rc_dev, &rawir);
> +		if (i == 0 && ev.val > 15000000)
> +			ev.val -= 15000000;
> +		ir_raw_event_store(data->rc_dev, &ev);
>  	}
>  	ir_raw_event_handle(data->rc_dev);
>  
> diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
> index f6938f4..3959a572 100644
> --- a/drivers/media/common/siano/smsir.c
> +++ b/drivers/media/common/siano/smsir.c
> @@ -38,12 +38,11 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
>  {
>  	int i;
>  	const s32 *samples = (const void *)buf;
> +	DEFINE_IR_RAW_EVENT(ev);
>  
>  	for (i = 0; i < len >> 2; i++) {
> -		DEFINE_IR_RAW_EVENT(ev);
> -
> -		ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
> -		ev.pulse = (samples[i] > 0) ? false : true;
> +		ev.val = US_TO_NS(abs(samples[i]));
> +		ev.code = (samples[i] > 0) ? RC_IR_SPACE : RC_IR_PULSE;
>  
>  		ir_raw_event_store(coredev->ir.dev, &ev);
>  	}
> diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
> index 119d4e8..1672f0e 100644
> --- a/drivers/media/i2c/cx25840/cx25840-ir.c
> +++ b/drivers/media/i2c/cx25840/cx25840-ir.c
> @@ -98,12 +98,12 @@ MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
>  
>  /*
>   * We use this union internally for convenience, but callers to tx_write
> - * and rx_read will be expecting records of type struct ir_raw_event.
> - * Always ensure the size of this union is dictated by struct ir_raw_event.
> + * and rx_read will be expecting records of type struct rc_event.
> + * Always ensure the size of this union is dictated by struct rc_event.
>   */
>  union cx25840_ir_fifo_rec {
>  	u32 hw_fifo_data;
> -	struct ir_raw_event ir_core_data;
> +	struct rc_event ir_core_data;
>  };
>  
>  #define CX25840_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
> @@ -659,63 +659,67 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
>  }
>  
>  /* Receiver */
> -static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
> -			      ssize_t *num)
> +static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
> +			      ssize_t *bytes_read)
>  {
> -	struct cx25840_ir_state *ir_state = to_ir_state(sd);
> +	struct cx25840_ir_state *state = to_ir_state(sd);
>  	bool invert;
>  	u16 divider;
> -	unsigned int i, n;
> -	union cx25840_ir_fifo_rec *p;
> -	unsigned u, v, w;
> -
> -	if (ir_state == NULL)
> +	struct rc_event *ev = (struct rc_event *)buf;
> +	union cx25840_ir_fifo_rec rec;
> +	unsigned max_events;
> +	unsigned events = 0;
> +	bool pulse, timeout;
> +	u64 val;
> +
> +	if (!state)
>  		return -ENODEV;
>  
> -	invert = (bool) atomic_read(&ir_state->rx_invert);
> -	divider = (u16) atomic_read(&ir_state->rxclk_divider);
> -
> -	n = count / sizeof(union cx25840_ir_fifo_rec)
> -		* sizeof(union cx25840_ir_fifo_rec);
> -	if (n == 0) {
> -		*num = 0;
> -		return 0;
> -	}
> -
> -	n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
> -			     &ir_state->rx_kfifo_lock);
> +	invert = (bool)atomic_read(&state->rx_invert);
> +	divider = (u16)atomic_read(&state->rxclk_divider);
> +	max_events = bufsize / sizeof(union cx25840_ir_fifo_rec);
>  
> -	n /= sizeof(union cx25840_ir_fifo_rec);
> -	*num = n * sizeof(union cx25840_ir_fifo_rec);
> -
> -	for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
> +	while (events + 2 <= max_events) {
> +		if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
> +					 &state->rx_kfifo_lock) != sizeof(rec))
> +			break;
>  
> -		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
> +		if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
>  			/* Assume RTO was because of no IR light input */
> -			u = 0;
> -			w = 1;
> +			pulse = false;
> +			timeout = true;
>  		} else {
> -			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
> +			pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
>  			if (invert)
> -				u = u ? 0 : 1;
> -			w = 0;
> +				pulse = !pulse;
> +			timeout = false;
>  		}
>  
> -		v = (unsigned) pulse_width_count_to_ns(
> -				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
> -		if (v > IR_MAX_DURATION)
> -			v = IR_MAX_DURATION;
> -
> -		init_ir_raw_event(&p->ir_core_data);
> -		p->ir_core_data.pulse = u;
> -		p->ir_core_data.duration = v;
> -		p->ir_core_data.timeout = w;
> +		val = min_t(u64, IR_MAX_DURATION,
> +			    pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
> +						    divider));
> +
> +		if (val) {
> +			init_ir_raw_event(ev);
> +			ev->code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
> +			ev->val = val;
> +			events++;
> +			ev++;
> +			v4l2_dbg(2, ir_debug, sd, "rx read: %10llu ns %s\n",
> +				 (long long unsigned)val, pulse ? "pulse" : "space");
> +		}
>  
> -		v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s  %s\n",
> -			 v, u ? "mark" : "space", w ? "(timed out)" : "");
> -		if (w)
> +		if (timeout) {
> +			init_ir_raw_event(ev);
> +			ev->code = RC_IR_STOP;
> +			ev->val = 1;
> +			events++;
> +			ev++;
>  			v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
> +		}
>  	}
> +
> +	*bytes_read = events * sizeof(union cx25840_ir_fifo_rec);
>  	return 0;
>  }
>  
> diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
> index e2ba28d..5eac866 100644
> --- a/drivers/media/pci/cx23885/cx23885-input.c
> +++ b/drivers/media/pci/cx23885/cx23885-input.c
> @@ -52,18 +52,17 @@ static void cx23885_input_process_measurements(struct cx23885_dev *dev,
>  	ssize_t num;
>  	int count, i;
>  	bool handle = false;
> -	struct ir_raw_event ir_core_event[64];
> +	struct rc_event ev[64];
>  
>  	do {
>  		num = 0;
> -		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
> -				 sizeof(ir_core_event), &num);
> +		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *)ev,
> +				 sizeof(rc_event), &num);
>  
> -		count = num / sizeof(struct ir_raw_event);
> +		count = num / sizeof(struct rc_event);
>  
>  		for (i = 0; i < count; i++) {
> -			ir_raw_event_store(kernel_ir->rc,
> -					   &ir_core_event[i]);
> +			ir_raw_event_store(kernel_ir->rc, &ev[i]);
>  			handle = true;
>  		}
>  	} while (num != 0);
> diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
> index c4961f8..da1b43e 100644
> --- a/drivers/media/pci/cx23885/cx23888-ir.c
> +++ b/drivers/media/pci/cx23885/cx23888-ir.c
> @@ -116,12 +116,12 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
>  
>  /*
>   * We use this union internally for convenience, but callers to tx_write
> - * and rx_read will be expecting records of type struct ir_raw_event.
> - * Always ensure the size of this union is dictated by struct ir_raw_event.
> + * and rx_read will be expecting records of type struct rc_event.
> + * Always ensure the size of this union is dictated by struct rc_event.
>   */
>  union cx23888_ir_fifo_rec {
>  	u32 hw_fifo_data;
> -	struct ir_raw_event ir_core_data;
> +	struct rc_event ir_core_data;
>  };
>  
>  #define CX23888_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx23888_ir_fifo_rec))
> @@ -660,57 +660,62 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
>  }
>  
>  /* Receiver */
> -static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
> -			      ssize_t *num)
> +static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
> +			      ssize_t *bytes_read)
>  {
>  	struct cx23888_ir_state *state = to_state(sd);
> -	bool invert = (bool) atomic_read(&state->rx_invert);
> -	u16 divider = (u16) atomic_read(&state->rxclk_divider);
> -
> -	unsigned int i, n;
> -	union cx23888_ir_fifo_rec *p;
> -	unsigned u, v, w;
> -
> -	n = count / sizeof(union cx23888_ir_fifo_rec)
> -		* sizeof(union cx23888_ir_fifo_rec);
> -	if (n == 0) {
> -		*num = 0;
> -		return 0;
> -	}
> -
> -	n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
> -
> -	n /= sizeof(union cx23888_ir_fifo_rec);
> -	*num = n * sizeof(union cx23888_ir_fifo_rec);
> -
> -	for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
> +	bool invert = (bool)atomic_read(&state->rx_invert);
> +	u16 divider = (u16)atomic_read(&state->rxclk_divider);
> +	struct rc_event *ev = (struct rc_event *)buf;
> +	union cx23888_ir_fifo_rec rec;
> +	unsigned max_events;
> +	unsigned events = 0;
> +	bool pulse, timeout;
> +	u64 val;
> +
> +	max_events = bufsize / sizeof(union cx23888_ir_fifo_rec);
> +
> +	while (events + 2 <= max_events) {
> +		if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
> +					 &state->rx_kfifo_lock) != sizeof(rec))
> +			break;
>  
> -		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
> +		if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
>  			/* Assume RTO was because of no IR light input */
> -			u = 0;
> -			w = 1;
> +			pulse = false;
> +			timeout = true;
>  		} else {
> -			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
> +			pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
>  			if (invert)
> -				u = u ? 0 : 1;
> -			w = 0;
> +				pulse = !pulse;
> +			timeout = false;
>  		}
>  
> -		v = (unsigned) pulse_width_count_to_ns(
> -				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
> -		if (v > IR_MAX_DURATION)
> -			v = IR_MAX_DURATION;
> -
> -		init_ir_raw_event(&p->ir_core_data);
> -		p->ir_core_data.pulse = u;
> -		p->ir_core_data.duration = v;
> -		p->ir_core_data.timeout = w;
> +		val = min_t(u64, IR_MAX_DURATION,
> +			    pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
> +						    divider));
> +
> +		if (val) {
> +			init_ir_raw_event(ev);
> +			ev->code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
> +			ev->val = val;
> +			events++;
> +			ev++;
> +			v4l2_dbg(2, ir_888_debug, sd, "rx read: %10llu ns %s\n",
> +				 (long long unsigned)val, pulse ? "pulse" : "space");
> +		}
>  
> -		v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s  %s\n",
> -			 v, u ? "mark" : "space", w ? "(timed out)" : "");
> -		if (w)
> +		if (timeout) {
> +			init_ir_raw_event(ev);
> +			ev->code = RC_IR_STOP;
> +			ev->val = 1;
> +			events++;
> +			ev++;
>  			v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
> +		}
>  	}
> +
> +	*bytes_read = events * sizeof(union cx23888_ir_fifo_rec);
>  	return 0;
>  }
>  
> diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
> index 2b68ede..b8d3534 100644
> --- a/drivers/media/pci/cx88/cx88-input.c
> +++ b/drivers/media/pci/cx88/cx88-input.c
> @@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core)
>  	struct cx88_IR *ir = core->ir;
>  	u32 samples;
>  	unsigned todo, bits;
> -	struct ir_raw_event ev;
> +	DEFINE_IR_RAW_EVENT(ev);
>  
>  	if (!ir || !ir->sampling)
>  		return;
> @@ -541,9 +541,14 @@ void cx88_ir_irq(struct cx88_core *core)
>  
>  	init_ir_raw_event(&ev);
>  	for (todo = 32; todo > 0; todo -= bits) {
> -		ev.pulse = samples & 0x80000000 ? false : true;
> -		bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
> -		ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
> +		if (samples & 0x80000000) {
> +			ev.code = RC_IR_PULSE;
> +			bits = min(todo, 32U - fls(samples));
> +		} else {
> +			ev.code = RC_IR_SPACE;
> +			bits = min(todo, 32U - fls(~samples));
> +		}
> +		ev.val = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
>  		ir_raw_event_store_with_filter(ir->dev, &ev);
>  		samples <<= bits;
>  	}
> diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
> index 57d61e5..df05b2c 100644
> --- a/drivers/media/rc/ene_ir.c
> +++ b/drivers/media/rc/ene_ir.c
> @@ -353,9 +353,11 @@ static void ene_rx_sense_carrier(struct ene_device *dev)
>  	dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
>  						carrier, duty_cycle);
>  	if (dev->carrier_detect_enabled) {
> -		ev.carrier_report = true;
> -		ev.carrier = carrier;
> -		ev.duty_cycle = duty_cycle;
> +		ev.code = RC_IR_CARRIER;
> +		ev.val = carrier;
> +		ir_raw_event_store(dev->rdev, &ev);
> +		ev.code = RC_IR_DUTY_CYCLE;
> +		ev.val = duty_cycle;
>  		ir_raw_event_store(dev->rdev, &ev);
>  	}
>  }
> @@ -810,8 +812,8 @@ static irqreturn_t ene_isr(int irq, void *data)
>  
>  		dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
>  
> -		ev.duration = US_TO_NS(hw_sample);
> -		ev.pulse = pulse;
> +		ev.val = US_TO_NS(hw_sample);
> +		ev.code = pulse ? RC_IR_PULSE : RC_IR_SPACE;
>  		ir_raw_event_store_with_filter(dev->rdev, &ev);
>  	}
>  
> diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
> index dd49c28..bdccef0 100644
> --- a/drivers/media/rc/fintek-cir.c
> +++ b/drivers/media/rc/fintek-cir.c
> @@ -293,7 +293,7 @@ static int fintek_cmdsize(u8 cmd, u8 subcmd)
>  /* process ir data stored in driver buffer */
>  static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
>  {
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	DEFINE_IR_RAW_EVENT(ev);
>  	u8 sample;
>  	bool event = false;
>  	int i;
> @@ -325,17 +325,18 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
>  			break;
>  		case PARSE_IRDATA:
>  			fintek->rem--;
> -			init_ir_raw_event(&rawir);
> -			rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
> -			rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
> +			init_ir_raw_event(&ev);
> +			ev.code = RC_IR_SPACE;
> +			if (sample & BUF_PULSE_BIT)
> +				ev.code = RC_IR_PULSE;
> +			ev.val = US_TO_NS((sample & BUF_SAMPLE_MASK)
>  					  * CIR_SAMPLE_PERIOD);
>  
> -			fit_dbg("Storing %s with duration %d",
> -				rawir.pulse ? "pulse" : "space",
> -				rawir.duration);
> -			if (ir_raw_event_store_with_filter(fintek->rdev,
> -									&rawir))
> -				event = true;
> +			fit_dbg("Storing %s with duration %llu",
> +				ev.code == RC_IR_PULSE ? "pulse" : "space",
> +				(long long unsigned)ev.val);
> +			ir_raw_event_store_with_filter(fintek->rdev, &ev);
> +			event = true;
>  			break;
>  		}
>  
> diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
> index 3b7327a..1ab94d2 100644
> --- a/drivers/media/rc/iguanair.c
> +++ b/drivers/media/rc/iguanair.c
> @@ -132,23 +132,22 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
>  			break;
>  		}
>  	} else if (len >= 7) {
> -		DEFINE_IR_RAW_EVENT(rawir);
> +		DEFINE_IR_RAW_EVENT(ev);
>  		unsigned i;
>  		bool event = false;
>  
> -		init_ir_raw_event(&rawir);
> -
>  		for (i = 0; i < 7; i++) {
>  			if (ir->buf_in[i] == 0x80) {
> -				rawir.pulse = false;
> -				rawir.duration = US_TO_NS(21845);
> +				ev.code = RC_IR_SPACE;
> +				ev.val = US_TO_NS(21845);
>  			} else {
> -				rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
> -				rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
> -								 RX_RESOLUTION;
> +				ev.code = ir->buf_in[i] & 0x80 ?
> +					  RC_IR_SPACE : RC_IR_PULSE;
> +				ev.val = ((ir->buf_in[i] & 0x7f) + 1) *
> +					 RX_RESOLUTION;
>  			}
>  
> -			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
> +			if (ir_raw_event_store_with_filter(ir->rc, &ev))
>  				event = true;
>  		}
>  
> diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
> index 30bcf18..081cc3f 100644
> --- a/drivers/media/rc/ir-jvc-decoder.c
> +++ b/drivers/media/rc/ir-jvc-decoder.c
> @@ -39,37 +39,39 @@ enum jvc_state {
>  /**
>   * ir_jvc_decode() - Decode one JVC pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @duration:   the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_jvc_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct jvc_dec *data = &dev->raw->jvc;
>  
>  	if (!(dev->enabled_protocols & RC_BIT_JVC))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> -	if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
> +	if (!geq_margin(ev.val, JVC_UNIT, JVC_UNIT / 2))
>  		goto out;
>  
>  	IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
>  again:
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
> +		if (!eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
>  			break;
>  
>  		data->count = 0;
> @@ -79,34 +81,34 @@ again:
>  		return 0;
>  
>  	case STATE_HEADER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
> +		if (!eq_margin(ev.val, JVC_HEADER_SPACE, JVC_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_BIT_PULSE;
>  		return 0;
>  
>  	case STATE_BIT_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
> +		if (!eq_margin(ev.val, JVC_BIT_PULSE, JVC_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_BIT_SPACE;
>  		return 0;
>  
>  	case STATE_BIT_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		data->bits <<= 1;
> -		if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
> +		if (eq_margin(ev.val, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
>  			data->bits |= 1;
>  			decrease_duration(&ev, JVC_BIT_1_SPACE);
> -		} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
> +		} else if (eq_margin(ev.val, JVC_BIT_0_SPACE, JVC_UNIT / 2))
>  			decrease_duration(&ev, JVC_BIT_0_SPACE);
>  		else
>  			break;
> @@ -119,20 +121,20 @@ again:
>  		return 0;
>  
>  	case STATE_TRAILER_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
> +		if (!eq_margin(ev.val, JVC_TRAILER_PULSE, JVC_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_TRAILER_SPACE;
>  		return 0;
>  
>  	case STATE_TRAILER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
> +		if (!geq_margin(ev.val, JVC_TRAILER_SPACE, JVC_UNIT / 2))
>  			break;
>  
>  		if (data->first) {
> @@ -156,10 +158,10 @@ again:
>  		return 0;
>  
>  	case STATE_CHECK_REPEAT:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
> +		if (eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
>  			data->state = STATE_INACTIVE;
>    else
>  			data->state = STATE_BIT_PULSE;
> @@ -168,7 +170,7 @@ again:
>  
>  out:
>  	IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
> index 7b56f21..1b4d1ff 100644
> --- a/drivers/media/rc/ir-lirc-codec.c
> +++ b/drivers/media/rc/ir-lirc-codec.c
> @@ -25,12 +25,12 @@
>  /**
>   * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
>   *		      lircd userspace daemon for decoding.
> - * @input_dev:	the struct rc_dev descriptor of the device
> - * @duration:	the struct ir_raw_event descriptor of the pulse/space
> + * @dev:	the struct rc_dev descriptor of the device
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the lirc interfaces aren't wired up.
>   */
> -static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_lirc_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct lirc_codec *lirc = &dev->raw->lirc;
>  	int sample;
> @@ -42,29 +42,29 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return -EINVAL;
>  
>  	/* Packet start */
> -	if (ev.reset)
> +	if (ev.code == RC_IR_RESET)
>  		return 0;
>  
>  	/* Carrier reports */
> -	if (ev.carrier_report) {
> -		sample = LIRC_FREQUENCY(ev.carrier);
> +	if (ev.code == RC_IR_CARRIER) {
> +		sample = LIRC_FREQUENCY(ev.val);
>  		IR_dprintk(2, "carrier report (freq: %d)\n", sample);
>  
>  	/* Packet end */
> -	} else if (ev.timeout) {
> +	} else if (ev.code == RC_IR_STOP) {
>  
>  		if (lirc->gap)
>  			return 0;
>  
>  		lirc->gap_start = ktime_get();
>  		lirc->gap = true;
> -		lirc->gap_duration = ev.duration;
> +		lirc->gap_duration = 0;
>  
>  		if (!lirc->send_timeout_reports)
>  			return 0;
>  
> -		sample = LIRC_TIMEOUT(ev.duration / 1000);
> -		IR_dprintk(2, "timeout report (duration: %d)\n", sample);
> +		sample = LIRC_TIMEOUT(0);
> +		IR_dprintk(2, "timeout report\n");
>  
>  	/* Normal sample */
>  	} else {
> @@ -86,10 +86,10 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  			lirc->gap = false;
>  		}
>  
> -		sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
> -					LIRC_SPACE(ev.duration / 1000);
> +		sample = is_pulse(ev) ? LIRC_PULSE(ev.val / 1000) :
> +					LIRC_SPACE(ev.val / 1000);
>  		IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
> -			   TO_US(ev.duration), TO_STR(ev.pulse));
> +			   TO_US(ev.val), TO_STR(ev.code));
>  	}
>  
>  	lirc_buffer_write(dev->raw->lirc.drv->rbuf,
> @@ -436,7 +436,7 @@ static int ir_lirc_register(struct rc_dev *dev)
>  	drv->rbuf = rbuf;
>  	drv->set_use_inc = &ir_lirc_open;
>  	drv->set_use_dec = &ir_lirc_close;
> -	drv->code_length = sizeof(struct ir_raw_event) * 8;
> +	drv->code_length = sizeof(struct rc_event) * 8;
>  	drv->fops = &lirc_fops;
>  	drv->dev = &dev->dev;
>  	drv->rdev = dev;
> diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
> index 9f3c9b5..14538dd 100644
> --- a/drivers/media/rc/ir-mce_kbd-decoder.c
> +++ b/drivers/media/rc/ir-mce_kbd-decoder.c
> @@ -206,11 +206,11 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
>  /**
>   * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @ev:		the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_mce_kbd_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct mce_kbd_dec *data = &dev->raw->mce_kbd;
>  	u32 scancode;
> @@ -219,32 +219,34 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> -	if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
> +	if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
>  		goto out;
>  
>  again:
>  	IR_dprintk(2, "started at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
> -	if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
> +	if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
>  		return 0;
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
>  		/* Note: larger margin on first pulse since each MCIR2_UNIT
>  		   is quite short and some hardware takes some time to
>  		   adjust to the signal */
> -		if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
> +		if (!eq_margin(ev.val, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
>  			break;
>  
>  		data->state = STATE_HEADER_BIT_START;
> @@ -253,11 +255,11 @@ again:
>  		return 0;
>  
>  	case STATE_HEADER_BIT_START:
> -		if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
> +		if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
>  			break;
>  
>  		data->header <<= 1;
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			data->header |= 1;
>  		data->count++;
>  		data->state = STATE_HEADER_BIT_END;
> @@ -292,11 +294,11 @@ again:
>  		goto again;
>  
>  	case STATE_BODY_BIT_START:
> -		if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
> +		if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
>  			break;
>  
>  		data->body <<= 1;
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			data->body |= 1;
>  		data->count++;
>  		data->state = STATE_BODY_BIT_END;
> @@ -315,7 +317,7 @@ again:
>  		goto again;
>  
>  	case STATE_FINISHED:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		switch (data->wanted_bits) {
> @@ -348,7 +350,7 @@ again:
>  
>  out:
>  	IR_dprintk(1, "failed at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	input_sync(data->idev);
>  	return -EINVAL;
> diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
> index 861fd86..cf4b8be 100644
> --- a/drivers/media/rc/ir-nec-decoder.c
> +++ b/drivers/media/rc/ir-nec-decoder.c
> @@ -41,11 +41,11 @@ enum nec_state {
>  /**
>   * ir_nec_decode() - Decode one NEC pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @duration:	the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
> - * This function returns -EINVAL if the pulse violates the state machine
> + * This function returns -EINVAL if the event violates the state machine
>   */
> -static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_nec_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct nec_dec *data = &dev->raw->nec;
>  	u32 scancode;
> @@ -54,25 +54,27 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	if (!(dev->enabled_protocols & RC_BIT_NEC))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
>  	IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
> +		if (eq_margin(ev.val, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
>  			data->is_nec_x = false;
>  			data->necx_repeat = false;
> -		} else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
> +		} else if (eq_margin(ev.val, NECX_HEADER_PULSE, NEC_UNIT / 2))
>  			data->is_nec_x = true;
>  		else
>  			break;
> @@ -82,13 +84,13 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_HEADER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {
> +		if (eq_margin(ev.val, NEC_HEADER_SPACE, NEC_UNIT)) {
>  			data->state = STATE_BIT_PULSE;
>  			return 0;
> -		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
> +		} else if (eq_margin(ev.val, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
>  			rc_repeat(dev);
>  			IR_dprintk(1, "Repeat last key\n");
>  			data->state = STATE_TRAILER_PULSE;
> @@ -98,22 +100,21 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		break;
>  
>  	case STATE_BIT_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
> +		if (!eq_margin(ev.val, NEC_BIT_PULSE, NEC_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_BIT_SPACE;
>  		return 0;
>  
>  	case STATE_BIT_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
> -			geq_margin(ev.duration,
> -			NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
> +		    geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
>  				IR_dprintk(1, "Repeat last key\n");
>  				rc_repeat(dev);
>  				data->state = STATE_INACTIVE;
> @@ -123,9 +124,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  			data->necx_repeat = false;
>  
>  		data->bits <<= 1;
> -		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
> +		if (eq_margin(ev.val, NEC_BIT_1_SPACE, NEC_UNIT / 2))
>  			data->bits |= 1;
> -		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
> +		else if (!eq_margin(ev.val, NEC_BIT_0_SPACE, NEC_UNIT / 2))
>  			break;
>  		data->count++;
>  
> @@ -137,20 +138,20 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_TRAILER_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
> +		if (!eq_margin(ev.val, NEC_TRAILER_PULSE, NEC_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_TRAILER_SPACE;
>  		return 0;
>  
>  	case STATE_TRAILER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
> +		if (!geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2))
>  			break;
>  
>  		address     = bitrev8((data->bits >> 24) & 0xff);
> @@ -173,7 +174,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	}
>  
>  	IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
> -		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
> index 93168da..be43c0d 100644
> --- a/drivers/media/rc/ir-rc5-decoder.c
> +++ b/drivers/media/rc/ir-rc5-decoder.c
> @@ -42,11 +42,11 @@ enum rc5_state {
>  /**
>   * ir_rc5_decode() - Decode one RC-5 pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @ev:		the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_rc5_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct rc5_dec *data = &dev->raw->rc5;
>  	u8 toggle;
> @@ -56,26 +56,28 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> -	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
> +	if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
>  		goto out;
>  
>  again:
>  	IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
> -	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
> +	if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
>  		return 0;
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
>  		data->state = STATE_BIT_START;
> @@ -84,16 +86,16 @@ again:
>  		goto again;
>  
>  	case STATE_BIT_START:
> -		if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
> +		if (is_space(ev) && geq_margin(ev.val, RC5_TRAILER, RC5_UNIT / 2)) {
>  			data->state = STATE_FINISHED;
>  			goto again;
>  		}
>  
> -		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
> +		if (!eq_margin(ev.val, RC5_BIT_START, RC5_UNIT / 2))
>  			break;
>  
>  		data->bits <<= 1;
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			data->bits |= 1;
>  		data->count++;
>  		data->state = STATE_BIT_END;
> @@ -112,7 +114,7 @@ again:
>  		goto again;
>  
>  	case STATE_CHECK_RC5X:
> -		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
> +		if (is_space(ev) && geq_margin(ev.val, RC5X_SPACE, RC5_UNIT / 2)) {
>  			data->is_rc5x = true;
>  			decrease_duration(&ev, RC5X_SPACE);
>  		} else
> @@ -121,7 +123,7 @@ again:
>  		goto again;
>  
>  	case STATE_FINISHED:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		if (data->is_rc5x && data->count == RC5X_NBITS) {
> @@ -179,7 +181,7 @@ again:
>  
>  out:
>  	IR_dprintk(1, "RC5(x/sz) decode failed at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
> index f1f098e..20db209 100644
> --- a/drivers/media/rc/ir-rc6-decoder.c
> +++ b/drivers/media/rc/ir-rc6-decoder.c
> @@ -79,11 +79,11 @@ static enum rc6_mode rc6_mode(struct rc6_dec *data)
>  /**
>   * ir_rc6_decode() - Decode one RC6 pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @ev:		the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_rc6_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct rc6_dec *data = &dev->raw->rc6;
>  	u32 scancode;
> @@ -95,32 +95,34 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	       RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> -	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
> +	if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
>  		goto out;
>  
>  again:
>  	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
> -	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
> +	if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
>  		return 0;
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
>  		/* Note: larger margin on first pulse since each RC6_UNIT
>  		   is quite short and some hardware takes some time to
>  		   adjust to the signal */
> -		if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
> +		if (!eq_margin(ev.val, RC6_PREFIX_PULSE, RC6_UNIT))
>  			break;
>  
>  		data->state = STATE_PREFIX_SPACE;
> @@ -128,10 +130,10 @@ again:
>  		return 0;
>  
>  	case STATE_PREFIX_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
> +		if (!eq_margin(ev.val, RC6_PREFIX_SPACE, RC6_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_HEADER_BIT_START;
> @@ -139,11 +141,11 @@ again:
>  		return 0;
>  
>  	case STATE_HEADER_BIT_START:
> -		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
> +		if (!eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2))
>  			break;
>  
>  		data->header <<= 1;
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			data->header |= 1;
>  		data->count++;
>  		data->state = STATE_HEADER_BIT_END;
> @@ -162,16 +164,16 @@ again:
>  		goto again;
>  
>  	case STATE_TOGGLE_START:
> -		if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
> +		if (!eq_margin(ev.val, RC6_TOGGLE_START, RC6_UNIT / 2))
>  			break;
>  
> -		data->toggle = ev.pulse;
> +		data->toggle = is_pulse(ev);
>  		data->state = STATE_TOGGLE_END;
>  		return 0;
>  
>  	case STATE_TOGGLE_END:
>  		if (!is_transition(&ev, &dev->raw->prev_ev) ||
> -		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
> +		    !geq_margin(ev.val, RC6_TOGGLE_END, RC6_UNIT / 2))
>  			break;
>  
>  		if (!(data->header & RC6_STARTBIT_MASK)) {
> @@ -198,17 +200,17 @@ again:
>  		goto again;
>  
>  	case STATE_BODY_BIT_START:
> -		if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
> +		if (eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2)) {
>  			/* Discard LSB's that won't fit in data->body */
>  			if (data->count++ < CHAR_BIT * sizeof data->body) {
>  				data->body <<= 1;
> -				if (ev.pulse)
> +				if (is_pulse(ev))
>  					data->body |= 1;
>  			}
>  			data->state = STATE_BODY_BIT_END;
>  			return 0;
> -		} else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
> -				geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
> +		} else if (RC6_MODE_6A == rc6_mode(data) && is_space(ev) &&
> +				geq_margin(ev.val, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
>  			data->state = STATE_FINISHED;
>  			goto again;
>  		}
> @@ -227,7 +229,7 @@ again:
>  		goto again;
>  
>  	case STATE_FINISHED:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		switch (rc6_mode(data)) {
> @@ -286,7 +288,7 @@ again:
>  
>  out:
>  	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
> index 9f97648..b1be396 100644
> --- a/drivers/media/rc/ir-sanyo-decoder.c
> +++ b/drivers/media/rc/ir-sanyo-decoder.c
> @@ -48,11 +48,11 @@ enum sanyo_state {
>  /**
>   * ir_sanyo_decode() - Decode one SANYO pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @duration:	the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_sanyo_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct sanyo_dec *data = &dev->raw->sanyo;
>  	u32 scancode;
> @@ -61,24 +61,24 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	if (!(dev->enabled_protocols & RC_BIT_SANYO))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset) {
> -			IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
> -			data->state = STATE_INACTIVE;
> -		}
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
>  	IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
> +		if (eq_margin(ev.val, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
>  			data->count = 0;
>  			data->state = STATE_HEADER_SPACE;
>  			return 0;
> @@ -87,10 +87,10 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  
>  
>  	case STATE_HEADER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
> +		if (eq_margin(ev.val, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
>  			data->state = STATE_BIT_PULSE;
>  			return 0;
>  		}
> @@ -98,20 +98,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		break;
>  
>  	case STATE_BIT_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
> +		if (!eq_margin(ev.val, SANYO_BIT_PULSE, SANYO_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_BIT_SPACE;
>  		return 0;
>  
>  	case STATE_BIT_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
> +		if (!data->count && geq_margin(ev.val, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
>  			rc_repeat(dev);
>  			IR_dprintk(1, "SANYO repeat last key\n");
>  			data->state = STATE_INACTIVE;
> @@ -119,9 +119,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		}
>  
>  		data->bits <<= 1;
> -		if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
> +		if (eq_margin(ev.val, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
>  			data->bits |= 1;
> -		else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
> +		else if (!eq_margin(ev.val, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
>  			break;
>  		data->count++;
>  
> @@ -133,20 +133,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_TRAILER_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
> +		if (!eq_margin(ev.val, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_TRAILER_SPACE;
>  		return 0;
>  
>  	case STATE_TRAILER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
> +		if (!geq_margin(ev.val, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
>  			break;
>  
>  		address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
> @@ -169,7 +169,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	}
>  
>  	IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
> -		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
> index b7acdba..435f0ac 100644
> --- a/drivers/media/rc/ir-sharp-decoder.c
> +++ b/drivers/media/rc/ir-sharp-decoder.c
> @@ -39,11 +39,11 @@ enum sharp_state {
>  /**
>   * ir_sharp_decode() - Decode one Sharp pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @duration:	the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_sharp_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct sharp_dec *data = &dev->raw->sharp;
>  	u32 msg, echo, address, command, scancode;
> @@ -51,51 +51,53 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	if (!(dev->enabled_protocols & RC_BIT_SHARP))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
>  	IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
> +		if (!eq_margin(ev.val, SHARP_BIT_PULSE,
>  			       SHARP_BIT_PULSE / 2))
>  			break;
>  
>  		data->count = 0;
> -		data->pulse_len = ev.duration;
> +		data->pulse_len = ev.val;
>  		data->state = STATE_BIT_SPACE;
>  		return 0;
>  
>  	case STATE_BIT_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
> +		if (!eq_margin(ev.val, SHARP_BIT_PULSE,
>  			       SHARP_BIT_PULSE / 2))
>  			break;
>  
> -		data->pulse_len = ev.duration;
> +		data->pulse_len = ev.val;
>  		data->state = STATE_BIT_SPACE;
>  		return 0;
>  
>  	case STATE_BIT_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
>  		data->bits <<= 1;
> -		if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
> +		if (eq_margin(data->pulse_len + ev.val, SHARP_BIT_1_PERIOD,
>  			      SHARP_BIT_PULSE * 2))
>  			data->bits |= 1;
> -		else if (!eq_margin(data->pulse_len + ev.duration,
> +		else if (!eq_margin(data->pulse_len + ev.val,
>  				    SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
>  			break;
>  		data->count++;
> @@ -109,11 +111,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_TRAILER_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
> -			       SHARP_BIT_PULSE / 2))
> +		if (!eq_margin(ev.val, SHARP_BIT_PULSE, SHARP_BIT_PULSE / 2))
>  			break;
>  
>  		if (data->count == SHARP_NBITS) {
> @@ -127,11 +128,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_ECHO_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
> -			       SHARP_ECHO_SPACE / 4))
> +		if (!eq_margin(ev.val, SHARP_ECHO_SPACE, SHARP_ECHO_SPACE / 4))
>  			break;
>  
>  		data->state = STATE_BIT_PULSE;
> @@ -139,10 +139,10 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_TRAILER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
> +		if (!geq_margin(ev.val, SHARP_TRAILER_SPACE,
>  				SHARP_BIT_PULSE / 2))
>  			break;
>  
> @@ -168,8 +168,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	}
>  
>  	IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
> -		   data->count, data->state, TO_US(ev.duration),
> -		   TO_STR(ev.pulse));
> +		   data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
> index d12dc3d..f7c4aa1 100644
> --- a/drivers/media/rc/ir-sony-decoder.c
> +++ b/drivers/media/rc/ir-sony-decoder.c
> @@ -35,11 +35,11 @@ enum sony_state {
>  /**
>   * ir_sony_decode() - Decode one Sony pulse or space
>   * @dev:	the struct rc_dev descriptor of the device
> - * @ev:         the struct ir_raw_event descriptor of the pulse/space
> + * @ev:         the struct rc_event descriptor of the event
>   *
>   * This function returns -EINVAL if the pulse violates the state machine
>   */
> -static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +static int ir_sony_decode(struct rc_dev *dev, struct rc_event ev)
>  {
>  	struct sony_dec *data = &dev->raw->sony;
>  	enum rc_type protocol;
> @@ -50,25 +50,27 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	      (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
>  		return 0;
>  
> -	if (!is_timing_event(ev)) {
> -		if (ev.reset)
> -			data->state = STATE_INACTIVE;
> +	if (ev.code == RC_IR_RESET) {
> +		data->state = STATE_INACTIVE;
>  		return 0;
>  	}
>  
> -	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
> +	if (!is_ir_raw_timing_event(ev))
> +		return 0;
> +
> +	if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2))
>  		goto out;
>  
>  	IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  
>  	switch (data->state) {
>  
>  	case STATE_INACTIVE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
> +		if (!eq_margin(ev.val, SONY_HEADER_PULSE, SONY_UNIT / 2))
>  			break;
>  
>  		data->count = 0;
> @@ -76,23 +78,23 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_HEADER_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
> +		if (!eq_margin(ev.val, SONY_HEADER_SPACE, SONY_UNIT / 2))
>  			break;
>  
>  		data->state = STATE_BIT_PULSE;
>  		return 0;
>  
>  	case STATE_BIT_PULSE:
> -		if (!ev.pulse)
> +		if (is_space(ev))
>  			break;
>  
>  		data->bits <<= 1;
> -		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
> +		if (eq_margin(ev.val, SONY_BIT_1_PULSE, SONY_UNIT / 2))
>  			data->bits |= 1;
> -		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
> +		else if (!eq_margin(ev.val, SONY_BIT_0_PULSE, SONY_UNIT / 2))
>  			break;
>  
>  		data->count++;
> @@ -100,15 +102,15 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		return 0;
>  
>  	case STATE_BIT_SPACE:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
> +		if (!geq_margin(ev.val, SONY_BIT_SPACE, SONY_UNIT / 2))
>  			break;
>  
>  		decrease_duration(&ev, SONY_BIT_SPACE);
>  
> -		if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
> +		if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2)) {
>  			data->state = STATE_BIT_PULSE;
>  			return 0;
>  		}
> @@ -117,10 +119,10 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  		/* Fall through */
>  
>  	case STATE_FINISHED:
> -		if (ev.pulse)
> +		if (is_pulse(ev))
>  			break;
>  
> -		if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
> +		if (!geq_margin(ev.val, SONY_TRAILER_SPACE, SONY_UNIT / 2))
>  			break;
>  
>  		switch (data->count) {
> @@ -168,7 +170,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  
>  out:
>  	IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
> -		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
> +		   data->state, TO_US(ev.val), TO_STR(ev.code));
>  	data->state = STATE_INACTIVE;
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
> index 2755e06..c3eb7e6 100644
> --- a/drivers/media/rc/ite-cir.c
> +++ b/drivers/media/rc/ite-cir.c
> @@ -190,16 +190,15 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
>  	size = length << 3;
>  	next_one = find_next_bit_le(ldata, size, 0);
>  	if (next_one > 0) {
> -		ev.pulse = true;
> -		ev.duration =
> -		    ITE_BITS_TO_NS(next_one, sample_period);
> +		ev.code = RC_IR_PULSE;
> +		ev.val = ITE_BITS_TO_NS(next_one, sample_period);
>  		ir_raw_event_store_with_filter(dev->rdev, &ev);
>  	}
>  
>  	while (next_one < size) {
>  		next_zero = find_next_zero_bit_le(ldata, size, next_one + 1);
> -		ev.pulse = false;
> -		ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
> +		ev.code = RC_IR_SPACE;
> +		ev.val = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
>  		ir_raw_event_store_with_filter(dev->rdev, &ev);
>  
>  		if (next_zero < size) {
> @@ -207,12 +206,10 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
>  			    find_next_bit_le(ldata,
>  						     size,
>  						     next_zero + 1);
> -			ev.pulse = true;
> -			ev.duration =
> -			    ITE_BITS_TO_NS(next_one - next_zero,
> -					   sample_period);
> -			ir_raw_event_store_with_filter
> -			    (dev->rdev, &ev);
> +			ev.code = RC_IR_PULSE;
> +			ev.val = ITE_BITS_TO_NS(next_one - next_zero,
> +						sample_period);
> +			ir_raw_event_store_with_filter(dev->rdev, &ev);
>  		} else
>  			next_one = size;
>  	}
> diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
> index aa899a0..5c1fa57 100644
> --- a/drivers/media/rc/ite-cir.h
> +++ b/drivers/media/rc/ite-cir.h
> @@ -125,7 +125,7 @@ struct ite_dev_params {
>  struct ite_dev {
>  	struct pnp_dev *pdev;
>  	struct rc_dev *rdev;
> -	struct ir_raw_event rawir;
> +	struct rc_event rawir;
>  
>  	/* sync data */
>  	spinlock_t lock;
> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
> index eac87ec..7f95d78 100644
> --- a/drivers/media/rc/mceusb.c
> +++ b/drivers/media/rc/mceusb.c
> @@ -994,13 +994,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
>  		case PARSE_IRDATA:
>  			ir->rem--;
>  			init_ir_raw_event(&rawir);
> -			rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
> -			rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
> -					 * US_TO_NS(MCE_TIME_UNIT);
> +			if (ir->buf_in[i] & MCE_PULSE_BIT)
> +				rawir.code = RC_IR_PULSE;
> +			else
> +				rawir.code = RC_IR_SPACE;
> +			rawir.val = (ir->buf_in[i] & MCE_PULSE_MASK) *
> +				    US_TO_NS(MCE_TIME_UNIT);
>  
> -			dev_dbg(ir->dev, "Storing %s with duration %d",
> -				rawir.pulse ? "pulse" : "space",
> -				rawir.duration);
> +			dev_dbg(ir->dev, "Storing %s with duration %llu\n",
> +				rawir.code == RC_IR_PULSE ? "pulse" : "space",
> +				(long long unsigned)rawir.val);
>  
>  			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
>  				event = true;
> diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
> index 9e63ee6..3a54760 100644
> --- a/drivers/media/rc/nuvoton-cir.c
> +++ b/drivers/media/rc/nuvoton-cir.c
> @@ -611,7 +611,7 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
>   */
>  static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
>  {
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	DEFINE_IR_RAW_EVENT(ev);
>  	u8 sample;
>  	int i;
>  
> @@ -622,19 +622,19 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
>  
>  	nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
>  
> -	init_ir_raw_event(&rawir);
> -
>  	for (i = 0; i < nvt->pkts; i++) {
>  		sample = nvt->buf[i];
>  
> -		rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
> -		rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
> -					  * SAMPLE_PERIOD);
> +		ev.code = RC_IR_SPACE;
> +		if (sample & BUF_PULSE_BIT)
> +			ev.code = RC_IR_PULSE;
> +		ev.val = US_TO_NS((sample & BUF_LEN_MASK) * SAMPLE_PERIOD);
>  
> -		nvt_dbg("Storing %s with duration %d",
> -			rawir.pulse ? "pulse" : "space", rawir.duration);
> +		nvt_dbg("Storing %s with duration %llu",
> +			ev.code == RC_IR_PULSE ? "pulse" : "space",
> +			(long long unsigned)ev.val);
>  
> -		ir_raw_event_store_with_filter(nvt->rdev, &rawir);
> +		ir_raw_event_store_with_filter(nvt->rdev, &ev);
>  
>  		/*
>  		 * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index 04776e8..4945727 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -18,7 +18,6 @@
>  
>  #include <linux/slab.h>
>  #include <linux/spinlock.h>
> -#include <media/rc-core.h>
>  #include <media/rc-ir-raw.h>
>  
>  enum rc_driver_type {
> @@ -30,7 +29,7 @@ struct ir_raw_handler {
>  	struct list_head list;
>  
>  	unsigned protocols; /* which are handled by this handler */
> -	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
> +	int (*decode)(struct rc_dev *dev, struct rc_event event);
>  
>  	/* These two should only be used by the lirc decoder */
>  	int (*raw_register)(struct rc_dev *dev);
> @@ -43,14 +42,14 @@ struct ir_raw_handler {
>  struct ir_raw_event_ctrl {
>  	struct list_head		list;		/* to keep track of raw clients */
>  	struct task_struct		*thread;
> -	DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
> +	DECLARE_KFIFO(kfifo, struct rc_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
>  	ktime_t				last_event;	/* when last event occurred */
>  	enum raw_event_type		last_type;	/* last event type */
>  	struct rc_dev			*dev;		/* pointer to the parent rc_dev */
>  
>  	/* raw decoder state follows */
> -	struct ir_raw_event prev_ev;
> -	struct ir_raw_event this_ev;
> +	struct rc_event prev_ev;
> +	struct rc_event this_ev;
>  	struct nec_dec {
>  		int state;
>  		unsigned count;
> @@ -131,27 +130,34 @@ static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
>  	return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
>  }
>  
> -static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
> +static inline bool is_transition(struct rc_event *x, struct rc_event *y)
>  {
> -	return x->pulse != y->pulse;
> +	return x->code != y->code;
>  }
>  
> -static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
> +static inline void decrease_duration(struct rc_event *ev, unsigned duration)
>  {
> -	if (duration > ev->duration)
> -		ev->duration = 0;
> -	else
> -		ev->duration -= duration;
> +	ev->val -= min_t(u64, ev->val, duration);
>  }
>  
> -/* Returns true if event is normal pulse/space event */
> -static inline bool is_timing_event(struct ir_raw_event ev)
> +static inline bool is_pulse(struct rc_event ev)
>  {
> -	return !ev.carrier_report && !ev.reset;
> +	return ev.type == RC_IR && ev.code == RC_IR_PULSE;
>  }
>  
> -#define TO_US(duration)			DIV_ROUND_CLOSEST((duration), 1000)
> -#define TO_STR(is_pulse)		((is_pulse) ? "pulse" : "space")
> +static inline bool is_space(struct rc_event ev)
> +{
> +	return ev.type == RC_IR && ev.code == RC_IR_SPACE;
> +}
> +
> +static inline bool is_ir_raw_timing_event(struct rc_event ev)
> +{
> +	return ev.type == RC_IR &&
> +	       (ev.code == RC_IR_SPACE || ev.code == RC_IR_PULSE);
> +}
> +
> +#define TO_US(duration)			((unsigned)DIV_ROUND_CLOSEST((duration), 1000))
> +#define TO_STR(code)			((code == RC_IR_PULSE) ? "pulse" : "space")
>  
>  /*
>   * Routines from rc-raw.c to be used internally and by decoders
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index 3b68975..0c1923a 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -19,6 +19,8 @@
>  #include <linux/module.h>
>  #include <linux/sched.h>
>  #include <linux/freezer.h>
> +#include <media/rc-ir-raw.h>
> +
>  #include "rc-core-priv.h"
>  
>  /* IR raw clients/handlers, writers synchronize with ir_raw_mutex */
> @@ -31,12 +33,12 @@ static atomic_t available_protocols = ATOMIC_INIT(0);
>  
>  static int ir_raw_event_thread(void *data)
>  {
> -	struct ir_raw_event ev;
> +	struct rc_event ev;
>  	struct ir_raw_handler *handler;
>  	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
>  
>  	while (!kthread_should_stop()) {
> -		if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
> +		if (!kfifo_get(&raw->kfifo, &ev)) {
>  			set_current_state(TASK_INTERRUPTIBLE);
>  			schedule();
>  			continue;
> @@ -55,36 +57,26 @@ static int ir_raw_event_thread(void *data)
>  /**
>   * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
>   * @dev:	the struct rc_dev device descriptor
> - * @ev:		the struct ir_raw_event descriptor of the pulse/space
> + * @ev:		the struct rc_event descriptor of the event
> + *
> + * This routine (which may be called from an interrupt context) stores an
> + * event for the raw ir decoding state machines and interested userspace
> + * processes.
>   *
> - * 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. Drivers are responsible for
> - * synchronizing calls to this function.
> + * Drivers are responsible for synchronizing calls to this function.
>   */
> -int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
> +int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev)
>  {
>  	if (!dev->raw)
>  		return -EINVAL;
>  
> -	IR_dprintk(2, "sample: (%05dus %s)\n",
> -		   TO_US(ev->duration), TO_STR(ev->pulse));
> -
> -	if (ev->reset)
> -		rc_event(dev, RC_IR, RC_IR_RESET, 1);
> -	else if (ev->carrier_report)
> -		rc_event(dev, RC_IR, RC_IR_CARRIER, ev->carrier);
> -	else if (ev->timeout)
> -		rc_event(dev, RC_IR, RC_IR_STOP, 1);
> -	else if (ev->pulse)
> -		rc_event(dev, RC_IR, RC_IR_PULSE, ev->duration);
> -	else
> -		rc_event(dev, RC_IR, RC_IR_SPACE, ev->duration);
> +	if (ev->type != RC_IR)
> +		return -EINVAL;
>  
> -	if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
> +	if (!kfifo_put(&dev->raw->kfifo, *ev))
>  		return -ENOMEM;
>  
> +	rc_event(dev, ev->type, ev->code, ev->val);
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(ir_raw_event_store);
> @@ -120,15 +112,15 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
>  	if (delta > MS_TO_NS(500) || !dev->raw->last_type)
>  		type |= IR_START_EVENT;
>  	else
> -		ev.duration = delta;
> +		ev.val = delta;
>  
>  	if (type & IR_START_EVENT)
>  		ir_raw_event_reset(dev);
>  	else if (dev->raw->last_type & IR_SPACE) {
> -		ev.pulse = false;
> +		ev.code = RC_IR_SPACE;
>  		rc = ir_raw_event_store(dev, &ev);
>  	} else if (dev->raw->last_type & IR_PULSE) {
> -		ev.pulse = true;
> +		ev.code = RC_IR_PULSE;
>  		rc = ir_raw_event_store(dev, &ev);
>  	} else
>  		return 0;
> @@ -142,7 +134,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
>  /**
>   * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
>   * @dev:	the struct rc_dev device descriptor
> - * @type:	the type of the event that has occurred
> + * @ev:		the struct rc_event descriptor of the event
>   *
>   * This routine (which may be called from an interrupt context) works
>   * in similar manner to ir_raw_event_store_edge.
> @@ -151,29 +143,35 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
>   * if the event was added, and zero if the event was ignored due to idle
>   * processing.
>   */
> -int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
> +int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev)
>  {
>  	if (!dev->raw)
>  		return -EINVAL;
>  
>  	/* Ignore spaces in idle mode */
> -	if (dev->idle && !ev->pulse)
> -		return 0;
> -	else if (dev->idle)
> +	if (dev->idle) {
> +		if (ev->code == RC_IR_SPACE)
> +			return 0;
>  		ir_raw_event_set_idle(dev, false);
> +	}
> +
> +	if (!is_ir_raw_timing_event(*ev)) {
> +		ir_raw_event_store(dev, &dev->raw->this_ev);
> +		return 0;
> +	}
>  
> -	if (!dev->raw->this_ev.duration)
> +	if (!dev->raw->this_ev.val)
>  		dev->raw->this_ev = *ev;
> -	else if (ev->pulse == dev->raw->this_ev.pulse)
> -		dev->raw->this_ev.duration += ev->duration;
> +	else if (ev->code == dev->raw->this_ev.code)
> +		dev->raw->this_ev.val += ev->val;
>  	else {
>  		ir_raw_event_store(dev, &dev->raw->this_ev);
>  		dev->raw->this_ev = *ev;
>  	}
>  
>  	/* Enter idle mode if nessesary */
> -	if (!ev->pulse && dev->timeout &&
> -	    dev->raw->this_ev.duration >= dev->timeout)
> +	if (ev->code == RC_IR_SPACE && dev->timeout &&
> +	    dev->raw->this_ev.val >= dev->timeout)
>  		ir_raw_event_set_idle(dev, true);
>  
>  	return 1;
> @@ -187,17 +185,30 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
>   */
>  void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
>  {
> +	DEFINE_IR_RAW_EVENT(ev);
> +
>  	if (!dev->raw)
>  		return;
>  
> +	if (dev->idle == idle)
> +		return;
> +
>  	IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
>  
> +
>  	if (idle) {
> -		dev->raw->this_ev.timeout = true;
> -		ir_raw_event_store(dev, &dev->raw->this_ev);
> -		init_ir_raw_event(&dev->raw->this_ev);
> +		if (dev->raw->this_ev.val > 0)
> +			ir_raw_event_store(dev, &dev->raw->this_ev);
> +		ev.code = RC_IR_STOP;
> +		ev.val = 1;
> +	} else {
> +		ev.code = RC_IR_START;
> +		ev.val = 1;
>  	}
>  
> +	init_ir_raw_event(&dev->raw->this_ev);
> +	ir_raw_event_store(dev, &ev);
> +
>  	if (dev->s_idle)
>  		dev->s_idle(dev, idle);
>  
> diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
> index 343c8d0..26c03bd 100644
> --- a/drivers/media/rc/rc-loopback.c
> +++ b/drivers/media/rc/rc-loopback.c
> @@ -54,7 +54,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned count)
>  	struct loopback_dev *lodev = dev->priv;
>  	u32 rxmask;
>  	struct rc_event ev;
> -	DEFINE_IR_RAW_EVENT(rawir);
>  	int tmp;
>  
>  	if (lodev->txcarrier < lodev->rxcarriermin ||
> @@ -78,17 +77,14 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned count)
>  	while ((tmp = ir_raw_get_tx_event(dev, &ev)) != 0) {
>  		if (tmp < 0)
>  			continue;
> -		init_ir_raw_event(&rawir);
> -		rawir.pulse = (ev.code == RC_IR_PULSE);
> -		rawir.duration = ev.val;
> -		ir_raw_event_store_with_filter(dev, &rawir);
> +		ir_raw_event_store_with_filter(dev, &ev);
>  	}
>  
>  	/* Fake a silence long enough to cause us to go idle */
> -	init_ir_raw_event(&rawir);
> -	rawir.pulse = false;
> -	rawir.duration = dev->timeout;
> -	ir_raw_event_store_with_filter(dev, &rawir);
> +	ev.type = RC_IR;
> +	ev.code = RC_IR_SPACE;
> +	ev.val = dev->timeout;
> +	ir_raw_event_store_with_filter(dev, &ev);
>  
>  	ir_raw_event_handle(dev);
>  
> diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
> index 17974bf..e93a593 100644
> --- a/drivers/media/rc/redrat3.c
> +++ b/drivers/media/rc/redrat3.c
> @@ -365,7 +365,7 @@ static void redrat3_rx_timeout(unsigned long data)
>  
>  static void redrat3_process_ir_data(struct redrat3_dev *rr3)
>  {
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	struct rc_event ev;
>  	struct device *dev;
>  	unsigned i, trailer = 0;
>  	unsigned sig_size, single_len, offset, val;
> @@ -396,34 +396,28 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
>  		single_len = redrat3_len_to_us(val);
>  
>  		/* we should always get pulse/space/pulse/space samples */
> -		if (i % 2)
> -			rawir.pulse = false;
> -		else
> -			rawir.pulse = true;
> +		ev.type = RC_IR;
> +		ev.code = i % 2 ? RC_IR_SPACE : RC_IR_PULSE;
> +		ev.val = min_t(u64, IR_MAX_DURATION, US_TO_NS(single_len));
>  
> -		rawir.duration = US_TO_NS(single_len);
>  		/* Save initial pulse length to fudge trailer */
>  		if (i == 0)
> -			trailer = rawir.duration;
> -		/* cap the value to IR_MAX_DURATION */
> -		rawir.duration &= IR_MAX_DURATION;
> +			trailer = single_len;
>  
> -		rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
> -			rawir.pulse ? "pulse" : "space", rawir.duration, i);
> -		ir_raw_event_store_with_filter(rr3->rc, &rawir);
> +		rr3_dbg(dev, "storing %s with duration %llu (i: %d)\n",
> +			ev.code == RC_IR_PULSE ? "pulse" : "space",
> +			(long long unsigned)ev.val, i);
> +		ir_raw_event_store_with_filter(rr3->rc, &ev);
>  	}
>  
>  	/* add a trailing space, if need be */
>  	if (i % 2) {
> -		rawir.pulse = false;
> +		ev.code = RC_IR_SPACE;
>  		/* this duration is made up, and may not be ideal... */
> -		if (trailer < US_TO_NS(1000))
> -			rawir.duration = US_TO_NS(2800);
> -		else
> -			rawir.duration = trailer;
> -		rr3_dbg(dev, "storing trailing space with duration %d\n",
> -			rawir.duration);
> -		ir_raw_event_store_with_filter(rr3->rc, &rawir);
> +		ev.val = US_TO_NS(trailer < 1000 ? 2800 : trailer);
> +		rr3_dbg(dev, "storing trailing space with duration %llu\n",
> +			(long long unsigned)ev.val);
> +		ir_raw_event_store_with_filter(rr3->rc, &ev);
>  	}
>  
>  	rr3_dbg(dev, "calling ir_raw_event_handle\n");
> diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
> index 149e824..d30e3f7 100644
> --- a/drivers/media/rc/streamzap.c
> +++ b/drivers/media/rc/streamzap.c
> @@ -129,17 +129,18 @@ static struct usb_driver streamzap_driver = {
>  	.id_table =	streamzap_table,
>  };
>  
> -static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
> +static void sz_push(struct streamzap_ir *sz, struct rc_event ev)
>  {
>  	dev_dbg(sz->dev, "Storing %s with duration %u us\n",
> -		(rawir.pulse ? "pulse" : "space"), rawir.duration);
> -	ir_raw_event_store_with_filter(sz->rdev, &rawir);
> +		(ev.code == RC_IR_PULSE ? "pulse" : "space"),
> +		(unsigned)(ev.val / 1000));
> +	ir_raw_event_store_with_filter(sz->rdev, &ev);
>  }
>  
>  static void sz_push_full_pulse(struct streamzap_ir *sz,
>  			       unsigned char value)
>  {
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	DEFINE_IR_RAW_EVENT(ev);
>  
>  	if (sz->idle) {
>  		long deltv;
> @@ -148,31 +149,29 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
>  		do_gettimeofday(&sz->signal_start);
>  
>  		deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
> -		rawir.pulse = false;
> +		ev.code = RC_IR_SPACE;
>  		if (deltv > 15) {
>  			/* really long time */
> -			rawir.duration = IR_MAX_DURATION;
> +			ev.val = IR_MAX_DURATION;
>  		} else {
> -			rawir.duration = (int)(deltv * 1000000 +
> -				sz->signal_start.tv_usec -
> -				sz->signal_last.tv_usec);
> -			rawir.duration -= sz->sum;
> -			rawir.duration = US_TO_NS(rawir.duration);
> -			rawir.duration &= IR_MAX_DURATION;
> +			ev.val = (deltv * 1000000 +
> +				  sz->signal_start.tv_usec -
> +				  sz->signal_last.tv_usec);
> +			ev.val -= sz->sum;
> +			ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
>  		}
> -		sz_push(sz, rawir);
> +		sz_push(sz, ev);
>  
>  		sz->idle = false;
>  		sz->sum = 0;
>  	}
>  
> -	rawir.pulse = true;
> -	rawir.duration = ((int) value) * SZ_RESOLUTION;
> -	rawir.duration += SZ_RESOLUTION / 2;
> -	sz->sum += rawir.duration;
> -	rawir.duration = US_TO_NS(rawir.duration);
> -	rawir.duration &= IR_MAX_DURATION;
> -	sz_push(sz, rawir);
> +	ev.code = RC_IR_PULSE;
> +	ev.val = value * SZ_RESOLUTION;
> +	ev.val += SZ_RESOLUTION / 2;
> +	sz->sum += ev.val;
> +	ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
> +	sz_push(sz, ev);
>  }
>  
>  static void sz_push_half_pulse(struct streamzap_ir *sz,
> @@ -184,14 +183,13 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
>  static void sz_push_full_space(struct streamzap_ir *sz,
>  			       unsigned char value)
>  {
> -	DEFINE_IR_RAW_EVENT(rawir);
> -
> -	rawir.pulse = false;
> -	rawir.duration = ((int) value) * SZ_RESOLUTION;
> -	rawir.duration += SZ_RESOLUTION / 2;
> -	sz->sum += rawir.duration;
> -	rawir.duration = US_TO_NS(rawir.duration);
> -	sz_push(sz, rawir);
> +	DEFINE_IR_RAW_EVENT(ev);
> +
> +	ev.code = RC_IR_SPACE;
> +	ev.val = value * SZ_RESOLUTION + SZ_RESOLUTION / 2;
> +	sz->sum += ev.val;
> +	ev.val = US_TO_NS(ev.val);
> +	sz_push(sz, ev);
>  }
>  
>  static void sz_push_half_space(struct streamzap_ir *sz,
> @@ -258,13 +256,13 @@ static void streamzap_callback(struct urb *urb)
>  			break;
>  		case FullSpace:
>  			if (sz->buf_in[i] == SZ_TIMEOUT) {
> -				DEFINE_IR_RAW_EVENT(rawir);
> +				DEFINE_IR_RAW_EVENT(ev);
>  
> -				rawir.pulse = false;
> -				rawir.duration = sz->rdev->timeout;
> +				ev.code = RC_IR_STOP;
> +				ev.val = 1;
>  				sz->idle = true;
>  				if (sz->timeout_enabled)
> -					sz_push(sz, rawir);
> +					sz_push(sz, ev);
>  				ir_raw_event_handle(sz->rdev);
>  				ir_raw_event_reset(sz->rdev);
>  			} else {
> diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
> index 19317e2..0e9b05c 100644
> --- a/drivers/media/rc/ttusbir.c
> +++ b/drivers/media/rc/ttusbir.c
> @@ -121,44 +121,43 @@ static void ttusbir_bulk_complete(struct urb *urb)
>   */
>  static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
>  {
> -	struct ir_raw_event rawir;
> +	DEFINE_IR_RAW_EVENT(ev);
>  	unsigned i, v, b;
>  	bool event = false;
>  
> -	init_ir_raw_event(&rawir);
> -
>  	for (i = 0; i < 128; i++) {
>  		v = buf[i] & 0xfe;
>  		switch (v) {
>  		case 0xfe:
> -			rawir.pulse = false;
> -			rawir.duration = NS_PER_BYTE;
> -			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
> +			ev.code = RC_IR_SPACE;
> +			ev.val = NS_PER_BYTE;
> +			if (ir_raw_event_store_with_filter(tt->rc, &ev))
>  				event = true;
>  			break;
>  		case 0:
> -			rawir.pulse = true;
> -			rawir.duration = NS_PER_BYTE;
> -			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
> +			ev.code = RC_IR_PULSE;
> +			ev.val = NS_PER_BYTE;
> +			if (ir_raw_event_store_with_filter(tt->rc, &ev))
>  				event = true;
>  			break;
>  		default:
>  			/* one edge per byte */
>  			if (v & 2) {
>  				b = ffz(v | 1);
> -				rawir.pulse = true;
> +				ev.code = RC_IR_PULSE;
>  			} else {
>  				b = ffs(v) - 1;
> -				rawir.pulse = false;
> +				ev.code = RC_IR_SPACE;
>  			}
>  
> -			rawir.duration = NS_PER_BIT * (8 - b);
> -			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
> +			ev.val = NS_PER_BIT * (8 - b);
> +			if (ir_raw_event_store_with_filter(tt->rc, &ev))
>  				event = true;
>  
> -			rawir.pulse = !rawir.pulse;
> -			rawir.duration = NS_PER_BIT * b;
> -			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
> +			ev.val = ev.val == RC_IR_SPACE ?
> +				 RC_IR_PULSE : RC_IR_SPACE;
> +			ev.code = NS_PER_BIT * b;
> +			if (ir_raw_event_store_with_filter(tt->rc, &ev))
>  				event = true;
>  			break;
>  		}
> diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
> index 07da3e0..930a34e 100644
> --- a/drivers/media/rc/winbond-cir.c
> +++ b/drivers/media/rc/winbond-cir.c
> @@ -342,20 +342,18 @@ wbcir_carrier_report(struct wbcir_data *data)
>  
>  	if (counter > 0 && counter < 0xffff) {
>  		DEFINE_IR_RAW_EVENT(ev);
> -
> -		ev.carrier_report = 1;
> -		ev.carrier = DIV_ROUND_CLOSEST(counter * 1000000u,
> -						data->pulse_duration);
> -
> +		ev.code = RC_IR_CARRIER;
> +		ev.val = DIV_ROUND_CLOSEST(counter * 1000000u,
> +					   data->pulse_duration);
>  		ir_raw_event_store(data->dev, &ev);
>  	}
>  
>  	/* reset and restart the counter */
>  	data->pulse_duration = 0;
>  	wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R,
> -						WBCIR_CNTR_EN | WBCIR_CNTR_R);
> +		       WBCIR_CNTR_EN | WBCIR_CNTR_R);
>  	wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_EN,
> -						WBCIR_CNTR_EN | WBCIR_CNTR_R);
> +		       WBCIR_CNTR_EN | WBCIR_CNTR_R);
>  }
>  
>  static void
> @@ -381,7 +379,7 @@ static void
>  wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
>  {
>  	u8 irdata;
> -	DEFINE_IR_RAW_EVENT(rawir);
> +	struct rc_event ev;
>  	unsigned duration;
>  
>  	/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
> @@ -392,13 +390,14 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
>  
>  		duration = ((irdata & 0x7F) + 1) *
>  			(data->carrier_report_enabled ? 2 : 10);
> -		rawir.pulse = irdata & 0x80 ? false : true;
> -		rawir.duration = US_TO_NS(duration);
> +		ev.type = RC_IR;
> +		ev.code = irdata & 0x80 ? RC_IR_SPACE : RC_IR_PULSE;
> +		ev.val = US_TO_NS(duration);
>  
> -		if (rawir.pulse)
> +		if (ev.code == RC_IR_PULSE)
>  			data->pulse_duration += duration;
>  
> -		ir_raw_event_store_with_filter(data->dev, &rawir);
> +		ir_raw_event_store_with_filter(data->dev, &ev);
>  	}
>  
>  	ir_raw_event_handle(data->dev);
> diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> index 0412862..dc5d075 100644
> --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
> @@ -1281,7 +1281,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  {
>  	int ret, i, len;
>  	struct rtl28xxu_priv *priv = d->priv;
> -	struct ir_raw_event ev;
> +	struct rc_event ev;
>  	u8 buf[128];
>  	static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
>  		{IR_RX_IF,               0x03, 0xff},
> @@ -1350,8 +1350,8 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  	init_ir_raw_event(&ev);
>  
>  	for (i = 0; i < len; i++) {
> -		ev.pulse = buf[i] >> 7;
> -		ev.duration = 50800 * (buf[i] & 0x7f);
> +		ev.code = buf[i] >> 7 ? RC_IR_PULSE : RC_IR_SPACE;
> +		ev.val = 50800 * (buf[i] & 0x7f);
>  		ir_raw_event_store_with_filter(d->rc_dev, &ev);
>  	}
>  
> diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
> index 288f24c..624a073 100644
> --- a/drivers/media/usb/dvb-usb/technisat-usb2.c
> +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
> @@ -593,7 +593,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
>  {
>  	u8 buf[62], *b;
>  	int ret;
> -	struct ir_raw_event ev;
> +	DEFINE_IR_RAW_EVENT(ev);
>  
>  	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
>  	buf[1] = 0x08;
> @@ -636,16 +636,19 @@ unlock:
>  	debug_dump(b, ret, deb_rc);
>  #endif
>  
> -	ev.pulse = 0;
>  	while (1) {
> -		ev.pulse = !ev.pulse;
> -		ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
> +		if (ev.code == RC_IR_SPACE)
> +			ev.code = RC_IR_PULSE;
> +		else
> +			ev.code = RC_IR_SPACE;
> +
> +		ev.val = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
>  		ir_raw_event_store(d->rc_dev, &ev);
>  
>  		b++;
>  		if (*b == 0xff) {
> -			ev.pulse = 0;
> -			ev.duration = 888888*2;
> +			ev.code = RC_IR_SPACE;
> +			ev.val = 888888*2;
>  			ir_raw_event_store(d->rc_dev, &ev);
>  			break;
>  		}
> diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
> index dad3eb2..89bf2f7 100644
> --- a/include/media/rc-ir-raw.h
> +++ b/include/media/rc-ir-raw.h
> @@ -27,33 +27,17 @@ enum raw_event_type {
>  	IR_STOP_EVENT   = (1 << 3),
>  };
>  
> -struct ir_raw_event {
> -	union {
> -		u32             duration;
> +#define DEFINE_IR_RAW_EVENT(ev)			\
> +	struct rc_event ev = {			\
> +		.type = RC_IR,			\
> +		.code = RC_IR_PULSE,		\
> +		.val = 0 }
>  
> -		struct {
> -			u32     carrier;
> -			u8      duty_cycle;
> -		};
> -	};
> -
> -	unsigned                pulse:1;
> -	unsigned                reset:1;
> -	unsigned                timeout:1;
> -	unsigned                carrier_report:1;
> -};
> -
> -#define DEFINE_IR_RAW_EVENT(event) \
> -	struct ir_raw_event event = { \
> -		{ .duration = 0 } , \
> -		.pulse = 0, \
> -		.reset = 0, \
> -		.timeout = 0, \
> -		.carrier_report = 0 }
> -
> -static inline void init_ir_raw_event(struct ir_raw_event *ev)
> +static inline void init_ir_raw_event(struct rc_event *ev)
>  {
> -	memset(ev, 0, sizeof(*ev));
> +	ev->type = RC_IR;
> +	ev->code = RC_IR_PULSE;
> +	ev->val = 0;
>  }
>  
>  #define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
> @@ -62,10 +46,9 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
>  #define MS_TO_NS(msec)		((msec) * 1000 * 1000)
>  
>  void ir_raw_event_handle(struct rc_dev *dev);
> -int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
> +int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev);
>  int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
> -int ir_raw_event_store_with_filter(struct rc_dev *dev,
> -				struct ir_raw_event *ev);
> +int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev);
>  void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
>  int ir_raw_get_tx_event(struct rc_dev *dev, struct rc_event *ev);
>  int rc_register_ir_raw_device(struct rc_dev *dev);
> @@ -73,9 +56,11 @@ void rc_unregister_ir_raw_device(struct rc_dev *dev);
>  
>  static inline void ir_raw_event_reset(struct rc_dev *dev)
>  {
> -	DEFINE_IR_RAW_EVENT(ev);
> -	ev.reset = true;
> -
> +	struct rc_event ev = {
> +		.type = RC_IR,
> +		.code = RC_IR_RESET,
> +		.val = 1
> +	};
>  	ir_raw_event_store(dev, &ev);
>  	ir_raw_event_handle(dev);
>  }
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" 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	[flat|nested] 68+ messages in thread

end of thread, other threads:[~2014-07-25 23:19 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-03 23:31 [PATCH 00/49] rc-core: my current patch queue David Härdeman
2014-04-03 23:31 ` [PATCH 01/49] bt8xx: fixup RC5 decoding David Härdeman
2014-04-03 23:31 ` [PATCH 02/49] rc-core: improve ir-kbd-i2c get_key functions David Härdeman
2014-04-03 23:31 ` [PATCH 03/49] rc-core: document the protocol type David Härdeman
2014-04-03 23:31 ` [PATCH 04/49] rc-core: do not change 32bit NEC scancode format for now David Härdeman
2014-04-04 13:18   ` James Hogan
2014-04-03 23:31 ` [PATCH 05/49] rc-core: split dev->s_filter David Härdeman
2014-04-04 13:08   ` James Hogan
2014-04-03 23:31 ` [PATCH 06/49] rc-core: remove generic scancode filter David Härdeman
2014-04-04 13:30   ` James Hogan
2014-04-03 23:31 ` [PATCH 07/49] dib0700: NEC scancode cleanup David Härdeman
2014-04-03 23:31 ` [PATCH 08/49] lmedm04: " David Härdeman
2014-04-03 23:32 ` [PATCH 09/49] saa7134: NEC scancode fix David Härdeman
2014-04-03 23:32 ` [PATCH 10/49] [RFC] rc-core: use the full 32 bits for NEC scancodes David Härdeman
2014-04-03 23:32 ` [PATCH 11/49] [RFC] rc-core: don't throw away protocol information David Härdeman
2014-04-03 23:32 ` [PATCH 12/49] rc-core: simplify sysfs code David Härdeman
2014-04-03 23:32 ` [PATCH 13/49] rc-core: remove protocol arrays David Härdeman
2014-04-03 23:32 ` [PATCH 14/49] rc-core: rename dev->scanmask to dev->scancode_mask David Härdeman
2014-04-03 23:32 ` [PATCH 15/49] rc-core: merge rc5 and streamzap decoders David Härdeman
2014-04-03 23:32 ` [PATCH 16/49] rc-core: use an IDA rather than a bitmap David Härdeman
2014-07-25 22:39   ` Mauro Carvalho Chehab
2014-04-03 23:32 ` [PATCH 17/49] rc-core: add chardev David Härdeman
2014-04-03 23:32 ` [PATCH 18/49] rc-core: allow chardev to be read David Härdeman
2014-04-03 23:32 ` [PATCH 19/49] rc-core: use a kfifo for TX data David Härdeman
2014-04-03 23:32 ` [PATCH 20/49] rc-core: allow chardev to be written David Härdeman
2014-04-03 23:33 ` [PATCH 21/49] rc-core: add ioctl support to the rc chardev David Härdeman
2014-04-03 23:33 ` [PATCH 22/49] rc-core: add an ioctl for getting IR RX settings David Härdeman
2014-04-03 23:33 ` [PATCH 23/49] rc-loopback: add RCIOCGIRRX ioctl support David Härdeman
2014-04-03 23:33 ` [PATCH 24/49] rc-core: add an ioctl for setting IR RX settings David Härdeman
2014-04-03 23:33 ` [PATCH 25/49] rc-loopback: add RCIOCSIRRX ioctl support David Härdeman
2014-04-03 23:33 ` [PATCH 26/49] rc-core: add an ioctl for getting IR TX settings David Härdeman
2014-04-03 23:33 ` [PATCH 27/49] rc-loopback: add RCIOCGIRTX ioctl support David Härdeman
2014-04-03 23:33 ` [PATCH 28/49] rc-core: add an ioctl for setting IR TX settings David Härdeman
2014-04-03 23:33 ` [PATCH 29/49] rc-loopback: add RCIOCSIRTX ioctl support David Härdeman
2014-04-03 23:33 ` [PATCH 30/49] rc-core: leave the internals of rc_dev alone David Härdeman
2014-07-24  1:50   ` Mauro Carvalho Chehab
2014-04-03 23:33 ` [PATCH 31/49] rc-core: split rc-main.c into rc-main.c and rc-keytable.c David Härdeman
2014-07-25 22:44   ` Mauro Carvalho Chehab
2014-04-03 23:33 ` [PATCH 32/49] rc-core: prepare for multiple keytables David Härdeman
2014-07-25 22:52   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 33/49] rc-core: make the keytable of rc_dev an array David Härdeman
2014-04-03 23:34 ` [PATCH 34/49] rc-core: add ioctls for adding/removing keytables from userspace David Härdeman
2014-04-03 23:34 ` [PATCH 35/49] rc-core: remove redundant spinlock David Härdeman
2014-04-03 23:34 ` [PATCH 36/49] rc-core: make keytable RCU-friendly David Härdeman
2014-04-03 23:34 ` [PATCH 37/49] rc-core: allow empty keymaps David Härdeman
2014-07-25 22:58   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 38/49] rc-core: rename ir-raw.c David Härdeman
2014-04-03 23:34 ` [PATCH 39/49] rc-core: make IR raw handling a separate module David Härdeman
2014-07-25 23:04   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 40/49] rc-ir-raw: simplify locking David Härdeman
2014-07-25 23:08   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 41/49] rc-core: rename mutex David Härdeman
2014-04-10 21:28   ` James Hogan
2014-07-25 23:12   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 42/49] rc-ir-raw: atomic reads of protocols David Härdeman
2014-07-25 23:13   ` Mauro Carvalho Chehab
2014-04-03 23:34 ` [PATCH 43/49] rc-core: fix various sparse warnings David Härdeman
2014-04-03 23:34 ` [PATCH 44/49] rc-core: don't report scancodes via input devices David Härdeman
2014-07-25 23:16   ` Mauro Carvalho Chehab
2014-04-03 23:35 ` [PATCH 45/49] rc-ir-raw: add various rc_events David Härdeman
2014-07-25 23:16   ` Mauro Carvalho Chehab
2014-04-03 23:35 ` [PATCH 46/49] rc-core: use struct rc_event for all rc communication David Härdeman
2014-07-25 23:19   ` Mauro Carvalho Chehab
2014-04-03 23:35 ` [PATCH 47/49] rc-core: add keytable events David Härdeman
2014-04-03 23:35 ` [PATCH 48/49] rc-core: move remaining keytable functions David Härdeman
2014-04-03 23:35 ` [PATCH 49/49] rc-core: make rc-core.h userspace friendly David Härdeman
2014-04-04  2:05 ` [PATCH 00/49] rc-core: my current patch queue Mauro Carvalho Chehab
2014-06-26 20:07 ` David Härdeman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).