Re: [PATCH v5 1/1] media: rc: rcmm decoder

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sean,

    I have a new release adding all the features, but not really tested. I will update the mailing list soon. Finding some time is not so easy.

Best Regards,
Patrick Lerda.

Sean Young wrote:
Hi Patrick,

On Sat, Dec 08, 2018 at 02:18:05AM +0100, Patrick Lerda wrote:
media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@xxxxxxx>
Sorry about the delay in getting this reviewed. December was a very
busy month for me.

---
  MAINTAINERS                        |   5 +
  drivers/media/rc/Kconfig           |   7 ++
  drivers/media/rc/Makefile          |   1 +
  drivers/media/rc/ir-rcmm-decoder.c | 164 +++++++++++++++++++++++++++++
  drivers/media/rc/rc-core-priv.h    |   5 +
  drivers/media/rc/rc-main.c         |   3 +
  include/media/rc-map.h             |   6 +-
  include/uapi/linux/lirc.h          |   2 +
  tools/include/uapi/linux/lirc.h    |   2 +
  9 files changed, 193 insertions(+), 2 deletions(-)
  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3e9f1710ed13..80426d1faaba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16277,6 +16277,11 @@ M:	David Härdeman <david@xxxxxxxxxxx>
  S:	Maintained
  F:	drivers/media/rc/winbond-cir.c
+RCMM REMOTE CONTROLS DECODER
+M:	Patrick Lerda <patrick9876@xxxxxxx>
+S:	Maintained
+F:	drivers/media/rc/ir-rcmm-decoder.c
+
  WINSYSTEMS EBC-C384 WATCHDOG DRIVER
  M:	William Breathitt Gray <vilhelm.gray@xxxxxxxxx>
  L:	linux-watchdog@xxxxxxxxxxxxxxx
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8a216068a35a..43775ac74268 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,13 @@ config IR_IMON_DECODER
  	   remote control and you would like to use it with a raw IR
  	   receiver, or if you wish to use an encoder to transmit this IR.
+config IR_RCMM_DECODER
+	tristate "Enable IR raw decoder for the RC-MM protocol"
+	depends on RC_CORE
+	help
+	   Enable this option if you have IR with RC-MM protocol, and
+	   if the IR is decoded in software
checkpatch.pl --strict complains it wants a longer explanation here.

+
  endif #RC_DECODERS
menuconfig RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 92c163816849..48d23433b3c0 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
  obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
  obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
  obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o
+obj-$(CONFIG_IR_RCMM_DECODER) += ir-rcmm-decoder.o
# stand-alone IR receivers/transmitters
  obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c
new file mode 100644
index 000000000000..a3c09885da5f
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+//
+// Copyright (C) 2018 by Patrick Lerda <patrick9876@xxxxxxx>
+
+#include "rc-core-priv.h"
+#include <linux/module.h>
+#include <linux/version.h>
+
+#define RCMM_UNIT		166667	/* nanosecs */
+#define RCMM_PREFIX_PULSE	416666  /* 166666.666666666*2.5 */
+#define RCMM_PULSE_0            277777  /* 166666.666666666*(1+2/3) */
+#define RCMM_PULSE_1            444444  /* 166666.666666666*(2+2/3) */
+#define RCMM_PULSE_2            611111  /* 166666.666666666*(3+2/3) */
+#define RCMM_PULSE_3            777778  /* 166666.666666666*(4+2/3) */
+
+enum rcmm_state {
+	STATE_INACTIVE,
+	STATE_LOW,
+	STATE_BUMP,
+	STATE_VALUE,
+	STATE_FINISHED,
+};
+
+static bool rcmm_mode(struct rcmm_dec *data)
+{
+	return !((0x000c0000 & data->bits) == 0x000c0000);
+}
+
+/**
+ * ir_rcmm_decode() - Decode one RCMM 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_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+	struct rcmm_dec *data = &dev->raw->rcmm;
+	u32 scancode;
+	u8 toggle;
+	int value;
+
+	if (!(dev->enabled_protocols & RC_PROTO_BIT_RCMM))
+		return 0;
+
+	if (!is_timing_event(ev)) {
+		if (ev.reset)
+			data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	if (ev.duration > RCMM_PULSE_3 + RCMM_UNIT)
+		goto out;
+
+	switch (data->state) {
+	case STATE_INACTIVE:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2))
+			break;
+
+		data->state = STATE_LOW;
+		data->count = 0;
+		data->bits  = 0;
+		return 0;
+
+	case STATE_LOW:
+		if (ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2))
+			break;
+
+		data->state = STATE_BUMP;
+		return 0;
+
+	case STATE_BUMP:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2))
+			break;
+
+		data->state = STATE_VALUE;
+		return 0;
+
+	case STATE_VALUE:
+		if (ev.pulse)
+			break;
+
+		if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2))
+			value = 0;
+		else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2))
+			value = 1;
+		else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2))
+			value = 2;
+		else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2))
+			value = 3;
+		else
+			break;
+
+		data->bits <<= 2;
+		data->bits |= value;
+
+		data->count += 2;
+
+		if (data->count < 32)
+			data->state = STATE_BUMP;
+		else
+			data->state = STATE_FINISHED;
Your rcmm implementation only supports the 32 bits variant. There are
other bit lengths; lirc supports 12 bits for example:

http://lirc.sourceforge.net/remotes/philips/KW-1009-01

24 bits also possible according to:

https://www.sbprojects.net/knowledge/ir/rcmm.php

Now there is nothing wrong with just supporting 32 bits, but I think
the name should make that clear, so that if we ever need to add order
bit length variants, we can do so without it ending up messy.

So we should call it rcmm-32, I think.

+
+		return 0;
+
+	case STATE_FINISHED:
+		if (!ev.pulse)
+			break;
+
+		if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2))
+			break;
+
+		if (rcmm_mode(data)) {
+			toggle = !!(0x8000 & data->bits);
+			scancode = data->bits & ~0x8000;
+		} else {
+			toggle = 0;
+			scancode = data->bits;
+		}
+
+		rc_keydown(dev, RC_PROTO_RCMM, scancode, toggle);
+		data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+out:
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static struct ir_raw_handler rcmm_handler = {
+	.protocols	= RC_PROTO_BIT_RCMM,
+	.decode		= ir_rcmm_decode,
Again an encoder would be great. This is not only useful for transmission
but also for self-testing. We now have a self-test in the kernel tree
for this. Just nice to have of course.

+};
+
+static int __init ir_rcmm_decode_init(void)
+{
+	ir_raw_handler_register(&rcmm_handler);
+
+	pr_info("IR RCMM protocol handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_rcmm_decode_exit(void)
+{
+	ir_raw_handler_unregister(&rcmm_handler);
+}
+
+module_init(ir_rcmm_decode_init);
+module_exit(ir_rcmm_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Lerda");
+MODULE_DESCRIPTION("RCMM IR protocol decoder");
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index c2cbe7f6266c..2266f61f887f 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -131,6 +131,11 @@ struct ir_raw_event_ctrl {
  		unsigned int bits;
  		bool stick_keyboard;
  	} imon;
+	struct rcmm_dec {
+		int state;
+		unsigned int count;
+		u64 bits;
bits can be u32.

+	} rcmm;
  };
/* Mutex for locking raw IR processing and handler change */
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 66a174979b3c..7df40578dac0 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -70,6 +70,8 @@ static const struct {
  	[RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 },
  	[RC_PROTO_IMON] = { .name = "imon",
  		.scancode_bits = 0x7fffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM] = { .name = "rcmm",
+		.scancode_bits = 0xffffffff, .repeat_period = 114 },
So I think this should be:

	[RC_PROTO_RCMM_32] = { .name = "rcmm-32",

  };
/* Used to keep track of known keymaps */
@@ -1006,6 +1008,7 @@ static const struct {
  	{ RC_PROTO_BIT_XMP,	"xmp",		"ir-xmp-decoder"	},
  	{ RC_PROTO_BIT_CEC,	"cec",		NULL			},
  	{ RC_PROTO_BIT_IMON,	"imon",		"ir-imon-decoder"	},
+	{ RC_PROTO_BIT_RCMM,	"rcmm",		"ir-rcmm-decoder"	},
Same here.

  };
/**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index d621acadfbf3..ff5e3b002f91 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -37,6 +37,7 @@
  #define RC_PROTO_BIT_XMP		BIT_ULL(RC_PROTO_XMP)
  #define RC_PROTO_BIT_CEC		BIT_ULL(RC_PROTO_CEC)
  #define RC_PROTO_BIT_IMON		BIT_ULL(RC_PROTO_IMON)
+#define RC_PROTO_BIT_RCMM		BIT_ULL(RC_PROTO_RCMM)
#define RC_PROTO_BIT_ALL \
  			(RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -51,7 +52,7 @@
  			 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \
  			 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
  			 RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \
-			 RC_PROTO_BIT_IMON)
+			 RC_PROTO_BIT_IMON | RC_PROTO_BIT_RCMM)
  /* All rc protocols for which we have decoders */
  #define RC_PROTO_BIT_ALL_IR_DECODER \
  			(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -64,7 +65,8 @@
  			 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
  			 RC_PROTO_BIT_RC6_6A_24 |  RC_PROTO_BIT_RC6_6A_32 | \
  			 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
-			 RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON)
+			 RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON | \
+			 RC_PROTO_BIT_RCMM)
#define RC_PROTO_BIT_ALL_IR_ENCODER \
  			(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 6b319581882f..56106ccea2cb 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -192,6 +192,7 @@ struct lirc_scancode {
   * @RC_PROTO_XMP: XMP protocol
   * @RC_PROTO_CEC: CEC protocol
   * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM: RC-MM protocol
   */
  enum rc_proto {
  	RC_PROTO_UNKNOWN	= 0,
@@ -218,6 +219,7 @@ enum rc_proto {
  	RC_PROTO_XMP		= 21,
  	RC_PROTO_CEC		= 22,
  	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM		= 24,
  };
#endif
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
index f189931042a7..c1e5850c56e1 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -186,6 +186,7 @@ struct lirc_scancode {
   * @RC_PROTO_XMP: XMP protocol
   * @RC_PROTO_CEC: CEC protocol
   * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM: RC-MM protocol
   */
  enum rc_proto {
  	RC_PROTO_UNKNOWN	= 0,
@@ -212,6 +213,7 @@ enum rc_proto {
  	RC_PROTO_XMP		= 21,
  	RC_PROTO_CEC		= 22,
  	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM		= 24,
  };
#endif
--
2.19.2
Again sorry for getting a timely review done. Unfortunately we had
already missed the 4.21/5.0 deadline so was not going to make it to
that release.

Thanks,

Sean





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux