linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add ir-rcmm-driver
@ 2018-12-04 20:20 patrick9876
  2018-12-04 20:57 ` Sean Young
  0 siblings, 1 reply; 19+ messages in thread
From: patrick9876 @ 2018-12-04 20:20 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick LERDA

From: Patrick LERDA <patrick9876@free.fr>

---
 drivers/media/rc/Kconfig           |  10 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
 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          |   1 +
 tools/include/uapi/linux/lirc.h    |   1 +
 8 files changed, 210 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 1021c08a9ba4..b7e08324b874 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,16 @@ 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
+	select BITREVERSE
+	default y
+
+	---help---
+	   Enable this option if you have IR with RC-MM protocol, and
+	   if the IR is decoded in software
+
 endif #RC_DECODERS
 
 menuconfig RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index e0340d043fe8..fc4058013234 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..b05063f0a552
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,185 @@
+/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+ *
+ * Copyright (C) 2016 by Patrick Lerda
+ *
+ * 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 "rc-core-priv.h"
+#include <linux/module.h>
+#include <linux/version.h>
+
+
+#define RCMM_UNIT		166667	/* nanosecs */
+#define RCMM_0_NBITS		64
+#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) */
+#define RCMM_MODE_MASK          0x0000
+
+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;
+
+	if (!(dev->enabled_protocols & RC_PROTO_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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+	        {
+			int value;
+
+			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;
+		}
+
+		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_RCMM,
+	.decode		= ir_rcmm_decode,
+};
+
+static int __init ir_rcmm_decode_init(void)
+{
+	ir_raw_handler_register(&rcmm_handler);
+
+	printk(KERN_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..c63d4ad007cc 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 count;
+		u64 bits;
+	} 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 552bbe82a160..ad1dee921f5b 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 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1004,6 +1006,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"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index bfa3017cecba..28e8e7692b38 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_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..2bc7915ff33a 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -218,6 +218,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..c03e9562e349 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -212,6 +212,7 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM		= 24,
 };
 
 #endif
-- 
2.19.2


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

* Re: [PATCH] Add ir-rcmm-driver
  2018-12-04 20:20 [PATCH] Add ir-rcmm-driver patrick9876
@ 2018-12-04 20:57 ` Sean Young
  2018-12-04 21:06   ` patrick9876
  0 siblings, 1 reply; 19+ messages in thread
From: Sean Young @ 2018-12-04 20:57 UTC (permalink / raw)
  To: patrick9876; +Cc: linux-media

On Tue, Dec 04, 2018 at 09:20:25PM +0100, patrick9876@free.fr wrote:
> From: Patrick LERDA <patrick9876@free.fr>
> 
> ---
>  drivers/media/rc/Kconfig           |  10 ++
>  drivers/media/rc/Makefile          |   1 +
>  drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
>  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          |   1 +
>  tools/include/uapi/linux/lirc.h    |   1 +
>  8 files changed, 210 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

We have a rc-mm decoder written in BPF, see:

https://git.linuxtv.org/v4l-utils.git/tree/utils/keytable/bpf_protocols/rc_mm.c

This is in v4l-utils 1.16 and higher.

Any reason to have it in the kernel rather than in BPF?


Sean


> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index 1021c08a9ba4..b7e08324b874 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -133,6 +133,16 @@ 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
> +	select BITREVERSE
> +	default y
> +
> +	---help---
> +	   Enable this option if you have IR with RC-MM protocol, and
> +	   if the IR is decoded in software
> +
>  endif #RC_DECODERS
>  
>  menuconfig RC_DEVICES
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index e0340d043fe8..fc4058013234 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..b05063f0a552
> --- /dev/null
> +++ b/drivers/media/rc/ir-rcmm-decoder.c
> @@ -0,0 +1,185 @@
> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
> + *
> + * Copyright (C) 2016 by Patrick Lerda
> + *
> + * 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 "rc-core-priv.h"
> +#include <linux/module.h>
> +#include <linux/version.h>
> +
> +
> +#define RCMM_UNIT		166667	/* nanosecs */
> +#define RCMM_0_NBITS		64
> +#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) */
> +#define RCMM_MODE_MASK          0x0000
> +
> +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;
> +
> +	if (!(dev->enabled_protocols & RC_PROTO_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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */
> +		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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */
> +		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;
> +	        {
> +			int value;
> +
> +			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;
> +		}
> +
> +		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_RCMM,
> +	.decode		= ir_rcmm_decode,
> +};
> +
> +static int __init ir_rcmm_decode_init(void)
> +{
> +	ir_raw_handler_register(&rcmm_handler);
> +
> +	printk(KERN_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..c63d4ad007cc 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 count;
> +		u64 bits;
> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>  };
>  
>  /* Used to keep track of known keymaps */
> @@ -1004,6 +1006,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"	},
>  };
>  
>  /**
> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
> index bfa3017cecba..28e8e7692b38 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_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..2bc7915ff33a 100644
> --- a/include/uapi/linux/lirc.h
> +++ b/include/uapi/linux/lirc.h
> @@ -218,6 +218,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..c03e9562e349 100644
> --- a/tools/include/uapi/linux/lirc.h
> +++ b/tools/include/uapi/linux/lirc.h
> @@ -212,6 +212,7 @@ enum rc_proto {
>  	RC_PROTO_XMP		= 21,
>  	RC_PROTO_CEC		= 22,
>  	RC_PROTO_IMON		= 23,
> +	RC_PROTO_RCMM		= 24,
>  };
>  
>  #endif
> -- 
> 2.19.2

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

* Re: [PATCH] Add ir-rcmm-driver
  2018-12-04 20:57 ` Sean Young
@ 2018-12-04 21:06   ` patrick9876
  2018-12-04 21:32     ` patrick9876
  2018-12-05  0:29     ` [PATCHv2] " patrick9876
  0 siblings, 2 replies; 19+ messages in thread
From: patrick9876 @ 2018-12-04 21:06 UTC (permalink / raw)
  To: Sean Young; +Cc: linux-media, linux-media-owner

We have so many decoders at the linux kernel level now. I'm not sure of 
the best option.

Patrick.

On 04/12/2018 21:57, Sean Young wrote:
> On Tue, Dec 04, 2018 at 09:20:25PM +0100, patrick9876@free.fr wrote:
>> From: Patrick LERDA <patrick9876@free.fr>
>> 
>> ---
>>  drivers/media/rc/Kconfig           |  10 ++
>>  drivers/media/rc/Makefile          |   1 +
>>  drivers/media/rc/ir-rcmm-decoder.c | 185 
>> +++++++++++++++++++++++++++++
>>  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          |   1 +
>>  tools/include/uapi/linux/lirc.h    |   1 +
>>  8 files changed, 210 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c
> 
> We have a rc-mm decoder written in BPF, see:
> 
> https://git.linuxtv.org/v4l-utils.git/tree/utils/keytable/bpf_protocols/rc_mm.c
> 
> This is in v4l-utils 1.16 and higher.
> 
> Any reason to have it in the kernel rather than in BPF?
> 
> 
> Sean
> 
> 
>> 
>> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
>> index 1021c08a9ba4..b7e08324b874 100644
>> --- a/drivers/media/rc/Kconfig
>> +++ b/drivers/media/rc/Kconfig
>> @@ -133,6 +133,16 @@ 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
>> +	select BITREVERSE
>> +	default y
>> +
>> +	---help---
>> +	   Enable this option if you have IR with RC-MM protocol, and
>> +	   if the IR is decoded in software
>> +
>>  endif #RC_DECODERS
>> 
>>  menuconfig RC_DEVICES
>> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
>> index e0340d043fe8..fc4058013234 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..b05063f0a552
>> --- /dev/null
>> +++ b/drivers/media/rc/ir-rcmm-decoder.c
>> @@ -0,0 +1,185 @@
>> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
>> + *
>> + * Copyright (C) 2016 by Patrick Lerda
>> + *
>> + * 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 "rc-core-priv.h"
>> +#include <linux/module.h>
>> +#include <linux/version.h>
>> +
>> +
>> +#define RCMM_UNIT		166667	/* nanosecs */
>> +#define RCMM_0_NBITS		64
>> +#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) 
>> */
>> +#define RCMM_MODE_MASK          0x0000
>> +
>> +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;
>> +
>> +	if (!(dev->enabled_protocols & RC_PROTO_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;
>> +
>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>> +		   is quite short and some hardware takes some time to
>> +		   adjust to the signal */
>> +		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;
>> +
>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>> +		   is quite short and some hardware takes some time to
>> +		   adjust to the signal */
>> +		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;
>> +	        {
>> +			int value;
>> +
>> +			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;
>> +		}
>> +
>> +		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_RCMM,
>> +	.decode		= ir_rcmm_decode,
>> +};
>> +
>> +static int __init ir_rcmm_decode_init(void)
>> +{
>> +	ir_raw_handler_register(&rcmm_handler);
>> +
>> +	printk(KERN_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..c63d4ad007cc 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 count;
>> +		u64 bits;
>> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>>  };
>> 
>>  /* Used to keep track of known keymaps */
>> @@ -1004,6 +1006,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"	},
>>  };
>> 
>>  /**
>> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
>> index bfa3017cecba..28e8e7692b38 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_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..2bc7915ff33a 100644
>> --- a/include/uapi/linux/lirc.h
>> +++ b/include/uapi/linux/lirc.h
>> @@ -218,6 +218,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..c03e9562e349 100644
>> --- a/tools/include/uapi/linux/lirc.h
>> +++ b/tools/include/uapi/linux/lirc.h
>> @@ -212,6 +212,7 @@ enum rc_proto {
>>  	RC_PROTO_XMP		= 21,
>>  	RC_PROTO_CEC		= 22,
>>  	RC_PROTO_IMON		= 23,
>> +	RC_PROTO_RCMM		= 24,
>>  };
>> 
>>  #endif
>> --
>> 2.19.2

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

* Re: [PATCH] Add ir-rcmm-driver
  2018-12-04 21:06   ` patrick9876
@ 2018-12-04 21:32     ` patrick9876
  2018-12-05  0:29     ` [PATCHv2] " patrick9876
  1 sibling, 0 replies; 19+ messages in thread
From: patrick9876 @ 2018-12-04 21:32 UTC (permalink / raw)
  To: Sean Young; +Cc: linux-media, linux-media-owner

The toggle flag is well handled with this code and at the kernel level; 
This adds reliability.

Patrick.


On 04/12/2018 22:06, patrick9876@free.fr wrote:
> We have so many decoders at the linux kernel level now. I'm not sure
> of the best option.
> 
> Patrick.
> 
> On 04/12/2018 21:57, Sean Young wrote:
>> On Tue, Dec 04, 2018 at 09:20:25PM +0100, patrick9876@free.fr wrote:
>>> From: Patrick LERDA <patrick9876@free.fr>
>>> 
>>> ---
>>>  drivers/media/rc/Kconfig           |  10 ++
>>>  drivers/media/rc/Makefile          |   1 +
>>>  drivers/media/rc/ir-rcmm-decoder.c | 185 
>>> +++++++++++++++++++++++++++++
>>>  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          |   1 +
>>>  tools/include/uapi/linux/lirc.h    |   1 +
>>>  8 files changed, 210 insertions(+), 2 deletions(-)
>>>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c
>> 
>> We have a rc-mm decoder written in BPF, see:
>> 
>> https://git.linuxtv.org/v4l-utils.git/tree/utils/keytable/bpf_protocols/rc_mm.c
>> 
>> This is in v4l-utils 1.16 and higher.
>> 
>> Any reason to have it in the kernel rather than in BPF?
>> 
>> 
>> Sean
>> 
>> 
>>> 
>>> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
>>> index 1021c08a9ba4..b7e08324b874 100644
>>> --- a/drivers/media/rc/Kconfig
>>> +++ b/drivers/media/rc/Kconfig
>>> @@ -133,6 +133,16 @@ 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
>>> +	select BITREVERSE
>>> +	default y
>>> +
>>> +	---help---
>>> +	   Enable this option if you have IR with RC-MM protocol, and
>>> +	   if the IR is decoded in software
>>> +
>>>  endif #RC_DECODERS
>>> 
>>>  menuconfig RC_DEVICES
>>> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
>>> index e0340d043fe8..fc4058013234 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..b05063f0a552
>>> --- /dev/null
>>> +++ b/drivers/media/rc/ir-rcmm-decoder.c
>>> @@ -0,0 +1,185 @@
>>> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
>>> + *
>>> + * Copyright (C) 2016 by Patrick Lerda
>>> + *
>>> + * 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 "rc-core-priv.h"
>>> +#include <linux/module.h>
>>> +#include <linux/version.h>
>>> +
>>> +
>>> +#define RCMM_UNIT		166667	/* nanosecs */
>>> +#define RCMM_0_NBITS		64
>>> +#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) 
>>> */
>>> +#define RCMM_MODE_MASK          0x0000
>>> +
>>> +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;
>>> +
>>> +	if (!(dev->enabled_protocols & RC_PROTO_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;
>>> +
>>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>>> +		   is quite short and some hardware takes some time to
>>> +		   adjust to the signal */
>>> +		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;
>>> +
>>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>>> +		   is quite short and some hardware takes some time to
>>> +		   adjust to the signal */
>>> +		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;
>>> +	        {
>>> +			int value;
>>> +
>>> +			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;
>>> +		}
>>> +
>>> +		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_RCMM,
>>> +	.decode		= ir_rcmm_decode,
>>> +};
>>> +
>>> +static int __init ir_rcmm_decode_init(void)
>>> +{
>>> +	ir_raw_handler_register(&rcmm_handler);
>>> +
>>> +	printk(KERN_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..c63d4ad007cc 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 count;
>>> +		u64 bits;
>>> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>>>  };
>>> 
>>>  /* Used to keep track of known keymaps */
>>> @@ -1004,6 +1006,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"	},
>>>  };
>>> 
>>>  /**
>>> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
>>> index bfa3017cecba..28e8e7692b38 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_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..2bc7915ff33a 100644
>>> --- a/include/uapi/linux/lirc.h
>>> +++ b/include/uapi/linux/lirc.h
>>> @@ -218,6 +218,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..c03e9562e349 100644
>>> --- a/tools/include/uapi/linux/lirc.h
>>> +++ b/tools/include/uapi/linux/lirc.h
>>> @@ -212,6 +212,7 @@ enum rc_proto {
>>>  	RC_PROTO_XMP		= 21,
>>>  	RC_PROTO_CEC		= 22,
>>>  	RC_PROTO_IMON		= 23,
>>> +	RC_PROTO_RCMM		= 24,
>>>  };
>>> 
>>>  #endif
>>> --
>>> 2.19.2

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

* [PATCHv2] Add ir-rcmm-driver
  2018-12-04 21:06   ` patrick9876
  2018-12-04 21:32     ` patrick9876
@ 2018-12-05  0:29     ` patrick9876
  2018-12-05  0:29       ` [PATCH] " patrick9876
  1 sibling, 1 reply; 19+ messages in thread
From: patrick9876 @ 2018-12-05  0:29 UTC (permalink / raw)
  To: linux-media; +Cc: sean, linux-media-owner

Fix typo RC_PROTO_BIT_RCMM issue.


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

* [PATCH] [PATCHv2] Add ir-rcmm-driver
  2018-12-05  0:29     ` [PATCHv2] " patrick9876
@ 2018-12-05  0:29       ` patrick9876
  2018-12-06 14:49         ` Sean Young
  2018-12-07  9:57         ` [PATCHv3 1/1] " Patrick LERDA
  0 siblings, 2 replies; 19+ messages in thread
From: patrick9876 @ 2018-12-05  0:29 UTC (permalink / raw)
  To: linux-media; +Cc: sean, linux-media-owner, Patrick LERDA

From: Patrick LERDA <patrick9876@free.fr>

---
 drivers/media/rc/Kconfig           |  10 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
 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          |   1 +
 tools/include/uapi/linux/lirc.h    |   1 +
 8 files changed, 210 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 1021c08a9ba4..b7e08324b874 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,16 @@ 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
+	select BITREVERSE
+	default y
+
+	---help---
+	   Enable this option if you have IR with RC-MM protocol, and
+	   if the IR is decoded in software
+
 endif #RC_DECODERS
 
 menuconfig RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index e0340d043fe8..fc4058013234 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..94d5b70f7a0f
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,185 @@
+/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+ *
+ * Copyright (C) 2016 by Patrick Lerda
+ *
+ * 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 "rc-core-priv.h"
+#include <linux/module.h>
+#include <linux/version.h>
+
+
+#define RCMM_UNIT		166667	/* nanosecs */
+#define RCMM_0_NBITS		64
+#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) */
+#define RCMM_MODE_MASK          0x0000
+
+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;
+
+	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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+	        {
+			int value;
+
+			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;
+		}
+
+		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,
+};
+
+static int __init ir_rcmm_decode_init(void)
+{
+	ir_raw_handler_register(&rcmm_handler);
+
+	printk(KERN_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..c63d4ad007cc 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 count;
+		u64 bits;
+	} 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 552bbe82a160..ad1dee921f5b 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 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1004,6 +1006,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"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index bfa3017cecba..f06200362a3c 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..2bc7915ff33a 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -218,6 +218,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..c03e9562e349 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -212,6 +212,7 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM		= 24,
 };
 
 #endif
-- 
2.19.2


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

* Re: [PATCH] [PATCHv2] Add ir-rcmm-driver
  2018-12-05  0:29       ` [PATCH] " patrick9876
@ 2018-12-06 14:49         ` Sean Young
  2018-12-07  9:57         ` [PATCHv3 1/1] " Patrick LERDA
  1 sibling, 0 replies; 19+ messages in thread
From: Sean Young @ 2018-12-06 14:49 UTC (permalink / raw)
  To: patrick9876; +Cc: linux-media

On Wed, Dec 05, 2018 at 01:29:33AM +0100, patrick9876@free.fr wrote:
> From: Patrick LERDA <patrick9876@free.fr>
> 

We need a Signed-off-by: here.

https://www.kernel.org/doc/html/v4.12/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin

> ---
>  drivers/media/rc/Kconfig           |  10 ++
>  drivers/media/rc/Makefile          |   1 +
>  drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
>  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          |   1 +
>  tools/include/uapi/linux/lirc.h    |   1 +
>  8 files changed, 210 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c
> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index 1021c08a9ba4..b7e08324b874 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -133,6 +133,16 @@ 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
> +	select BITREVERSE

You're not using bitreverse, so don't depend on it.

> +	default y
> +
> +	---help---
> +	   Enable this option if you have IR with RC-MM protocol, and
> +	   if the IR is decoded in software
> +
>  endif #RC_DECODERS
>  
>  menuconfig RC_DEVICES
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index e0340d043fe8..fc4058013234 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..94d5b70f7a0f
> --- /dev/null
> +++ b/drivers/media/rc/ir-rcmm-decoder.c
> @@ -0,0 +1,185 @@
> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
> + *
> + * Copyright (C) 2016 by Patrick Lerda
> + *
> + * 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.

Replace this with the SPDX-License-Identifier.

> + */
> +
> +#include "rc-core-priv.h"
> +#include <linux/module.h>
> +#include <linux/version.h>
> +
> +
> +#define RCMM_UNIT		166667	/* nanosecs */
> +#define RCMM_0_NBITS		64

Not used.

> +#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) */
> +#define RCMM_MODE_MASK          0x0000

Not used.
> +
> +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;
> +
> +	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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */

Use:
 /*
  * Note:
  */
Type multiline comments please.

> +		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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */

Same here

> +		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;
> +	        {
> +			int value;

Please declare value at the top so you don't need a new block.

> +
> +			if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) {

No { and } needed for oneline statements after if / else if.

> +				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;
> +		}

No braces for single line statements.

> +
> +		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,

It would be nice to have an rcmm encoder as well.

> +};
> +
> +static int __init ir_rcmm_decode_init(void)
> +{
> +	ir_raw_handler_register(&rcmm_handler);
> +
> +	printk(KERN_INFO "IR RCMM protocol handler initialized\n");
Use:
	pr_info()

> +	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..c63d4ad007cc 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 count;
> +		u64 bits;
> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>  };
>  
>  /* Used to keep track of known keymaps */
> @@ -1004,6 +1006,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"	},
>  };
>  
>  /**
> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
> index bfa3017cecba..f06200362a3c 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..2bc7915ff33a 100644
> --- a/include/uapi/linux/lirc.h
> +++ b/include/uapi/linux/lirc.h
> @@ -218,6 +218,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..c03e9562e349 100644
> --- a/tools/include/uapi/linux/lirc.h
> +++ b/tools/include/uapi/linux/lirc.h
> @@ -212,6 +212,7 @@ enum rc_proto {
>  	RC_PROTO_XMP		= 21,
>  	RC_PROTO_CEC		= 22,
>  	RC_PROTO_IMON		= 23,
> +	RC_PROTO_RCMM		= 24,
>  };
>  

An entry in MAINTAINERS would be good, and please run 
./script/checkpatch.pl --strict on your patch and fix any issues you find.

Thanks,

Sean

>  #endif
> -- 
> 2.19.2

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

* [PATCHv3 1/1] Add ir-rcmm-driver
  2018-12-05  0:29       ` [PATCH] " patrick9876
  2018-12-06 14:49         ` Sean Young
@ 2018-12-07  9:57         ` Patrick LERDA
  2018-12-07 10:12           ` Sean Young
  2018-12-08  0:14           ` [PATCHv3 1/1] Add ir-rcmm-driver kbuild test robot
  1 sibling, 2 replies; 19+ messages in thread
From: Patrick LERDA @ 2018-12-07  9:57 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick LERDA, sean

Add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
---
 drivers/media/rc/Kconfig           |  10 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
 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          |   1 +
 tools/include/uapi/linux/lirc.h    |   1 +
 8 files changed, 210 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 1021c08a9ba4..b7e08324b874 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,16 @@ 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
+	select BITREVERSE
+	default y
+
+	---help---
+	   Enable this option if you have IR with RC-MM protocol, and
+	   if the IR is decoded in software
+
 endif #RC_DECODERS
 
 menuconfig RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index e0340d043fe8..fc4058013234 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..94d5b70f7a0f
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,185 @@
+/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+ *
+ * Copyright (C) 2016 by Patrick Lerda
+ *
+ * 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 "rc-core-priv.h"
+#include <linux/module.h>
+#include <linux/version.h>
+
+
+#define RCMM_UNIT		166667	/* nanosecs */
+#define RCMM_0_NBITS		64
+#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) */
+#define RCMM_MODE_MASK          0x0000
+
+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;
+
+	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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+
+		/* Note: larger margin on first pulse since each RCMM_UNIT
+		   is quite short and some hardware takes some time to
+		   adjust to the signal */
+		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;
+	        {
+			int value;
+
+			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;
+		}
+
+		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,
+};
+
+static int __init ir_rcmm_decode_init(void)
+{
+	ir_raw_handler_register(&rcmm_handler);
+
+	printk(KERN_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..c63d4ad007cc 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 count;
+		u64 bits;
+	} 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 552bbe82a160..ad1dee921f5b 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 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1004,6 +1006,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"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index bfa3017cecba..f06200362a3c 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..2bc7915ff33a 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -218,6 +218,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..c03e9562e349 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -212,6 +212,7 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM		= 24,
 };
 
 #endif
-- 
2.19.2


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

* Re: [PATCHv3 1/1] Add ir-rcmm-driver
  2018-12-07  9:57         ` [PATCHv3 1/1] " Patrick LERDA
@ 2018-12-07 10:12           ` Sean Young
  2018-12-07 12:58             ` patrick9876
  2018-12-08  1:18             ` [PATCH v5 1/1] media: rc: rcmm decoder Patrick Lerda
  2018-12-08  0:14           ` [PATCHv3 1/1] Add ir-rcmm-driver kbuild test robot
  1 sibling, 2 replies; 19+ messages in thread
From: Sean Young @ 2018-12-07 10:12 UTC (permalink / raw)
  To: Patrick LERDA; +Cc: linux-media

Hi Patrick,

On Fri, Dec 07, 2018 at 10:57:21AM +0100, Patrick LERDA wrote:
> Add support for RCMM infrared remote controls.
> 
> Signed-off-by: Patrick Lerda <patrick9876@free.fr>

Other than the Signed-off-by this looks exactly like the v2 version;
did you see my other comments on the v2 patch?

Thanks

Sean

> ---
>  drivers/media/rc/Kconfig           |  10 ++
>  drivers/media/rc/Makefile          |   1 +
>  drivers/media/rc/ir-rcmm-decoder.c | 185 +++++++++++++++++++++++++++++
>  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          |   1 +
>  tools/include/uapi/linux/lirc.h    |   1 +
>  8 files changed, 210 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c
> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index 1021c08a9ba4..b7e08324b874 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -133,6 +133,16 @@ 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
> +	select BITREVERSE
> +	default y
> +
> +	---help---
> +	   Enable this option if you have IR with RC-MM protocol, and
> +	   if the IR is decoded in software
> +
>  endif #RC_DECODERS
>  
>  menuconfig RC_DEVICES
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index e0340d043fe8..fc4058013234 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..94d5b70f7a0f
> --- /dev/null
> +++ b/drivers/media/rc/ir-rcmm-decoder.c
> @@ -0,0 +1,185 @@
> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
> + *
> + * Copyright (C) 2016 by Patrick Lerda
> + *
> + * 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 "rc-core-priv.h"
> +#include <linux/module.h>
> +#include <linux/version.h>
> +
> +
> +#define RCMM_UNIT		166667	/* nanosecs */
> +#define RCMM_0_NBITS		64
> +#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) */
> +#define RCMM_MODE_MASK          0x0000
> +
> +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;
> +
> +	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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */
> +		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;
> +
> +		/* Note: larger margin on first pulse since each RCMM_UNIT
> +		   is quite short and some hardware takes some time to
> +		   adjust to the signal */
> +		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;
> +	        {
> +			int value;
> +
> +			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;
> +		}
> +
> +		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,
> +};
> +
> +static int __init ir_rcmm_decode_init(void)
> +{
> +	ir_raw_handler_register(&rcmm_handler);
> +
> +	printk(KERN_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..c63d4ad007cc 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 count;
> +		u64 bits;
> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>  };
>  
>  /* Used to keep track of known keymaps */
> @@ -1004,6 +1006,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"	},
>  };
>  
>  /**
> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
> index bfa3017cecba..f06200362a3c 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..2bc7915ff33a 100644
> --- a/include/uapi/linux/lirc.h
> +++ b/include/uapi/linux/lirc.h
> @@ -218,6 +218,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..c03e9562e349 100644
> --- a/tools/include/uapi/linux/lirc.h
> +++ b/tools/include/uapi/linux/lirc.h
> @@ -212,6 +212,7 @@ enum rc_proto {
>  	RC_PROTO_XMP		= 21,
>  	RC_PROTO_CEC		= 22,
>  	RC_PROTO_IMON		= 23,
> +	RC_PROTO_RCMM		= 24,
>  };
>  
>  #endif
> -- 
> 2.19.2

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

* Re: [PATCHv3 1/1] Add ir-rcmm-driver
  2018-12-07 10:12           ` Sean Young
@ 2018-12-07 12:58             ` patrick9876
  2018-12-08  1:18             ` [PATCH v5 1/1] media: rc: rcmm decoder Patrick Lerda
  1 sibling, 0 replies; 19+ messages in thread
From: patrick9876 @ 2018-12-07 12:58 UTC (permalink / raw)
  To: Sean Young; +Cc: linux-media, linux-media-owner

Hi Sean,

    Sorry, I just checked the first paragraph.

    I will send you a new release.

    Thanks,

Patrick.


On 07/12/2018 11:12, Sean Young wrote:
> Hi Patrick,
> 
> On Fri, Dec 07, 2018 at 10:57:21AM +0100, Patrick LERDA wrote:
>> Add support for RCMM infrared remote controls.
>> 
>> Signed-off-by: Patrick Lerda <patrick9876@free.fr>
> 
> Other than the Signed-off-by this looks exactly like the v2 version;
> did you see my other comments on the v2 patch?
> 
> Thanks
> 
> Sean
> 
>> ---
>>  drivers/media/rc/Kconfig           |  10 ++
>>  drivers/media/rc/Makefile          |   1 +
>>  drivers/media/rc/ir-rcmm-decoder.c | 185 
>> +++++++++++++++++++++++++++++
>>  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          |   1 +
>>  tools/include/uapi/linux/lirc.h    |   1 +
>>  8 files changed, 210 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/media/rc/ir-rcmm-decoder.c
>> 
>> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
>> index 1021c08a9ba4..b7e08324b874 100644
>> --- a/drivers/media/rc/Kconfig
>> +++ b/drivers/media/rc/Kconfig
>> @@ -133,6 +133,16 @@ 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
>> +	select BITREVERSE
>> +	default y
>> +
>> +	---help---
>> +	   Enable this option if you have IR with RC-MM protocol, and
>> +	   if the IR is decoded in software
>> +
>>  endif #RC_DECODERS
>> 
>>  menuconfig RC_DEVICES
>> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
>> index e0340d043fe8..fc4058013234 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..94d5b70f7a0f
>> --- /dev/null
>> +++ b/drivers/media/rc/ir-rcmm-decoder.c
>> @@ -0,0 +1,185 @@
>> +/* ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
>> + *
>> + * Copyright (C) 2016 by Patrick Lerda
>> + *
>> + * 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 "rc-core-priv.h"
>> +#include <linux/module.h>
>> +#include <linux/version.h>
>> +
>> +
>> +#define RCMM_UNIT		166667	/* nanosecs */
>> +#define RCMM_0_NBITS		64
>> +#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) 
>> */
>> +#define RCMM_MODE_MASK          0x0000
>> +
>> +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;
>> +
>> +	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;
>> +
>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>> +		   is quite short and some hardware takes some time to
>> +		   adjust to the signal */
>> +		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;
>> +
>> +		/* Note: larger margin on first pulse since each RCMM_UNIT
>> +		   is quite short and some hardware takes some time to
>> +		   adjust to the signal */
>> +		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;
>> +	        {
>> +			int value;
>> +
>> +			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;
>> +		}
>> +
>> +		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,
>> +};
>> +
>> +static int __init ir_rcmm_decode_init(void)
>> +{
>> +	ir_raw_handler_register(&rcmm_handler);
>> +
>> +	printk(KERN_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..c63d4ad007cc 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 count;
>> +		u64 bits;
>> +	} 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 552bbe82a160..ad1dee921f5b 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 },
>>  };
>> 
>>  /* Used to keep track of known keymaps */
>> @@ -1004,6 +1006,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"	},
>>  };
>> 
>>  /**
>> diff --git a/include/media/rc-map.h b/include/media/rc-map.h
>> index bfa3017cecba..f06200362a3c 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..2bc7915ff33a 100644
>> --- a/include/uapi/linux/lirc.h
>> +++ b/include/uapi/linux/lirc.h
>> @@ -218,6 +218,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..c03e9562e349 100644
>> --- a/tools/include/uapi/linux/lirc.h
>> +++ b/tools/include/uapi/linux/lirc.h
>> @@ -212,6 +212,7 @@ enum rc_proto {
>>  	RC_PROTO_XMP		= 21,
>>  	RC_PROTO_CEC		= 22,
>>  	RC_PROTO_IMON		= 23,
>> +	RC_PROTO_RCMM		= 24,
>>  };
>> 
>>  #endif
>> --
>> 2.19.2

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

* Re: [PATCHv3 1/1] Add ir-rcmm-driver
  2018-12-07  9:57         ` [PATCHv3 1/1] " Patrick LERDA
  2018-12-07 10:12           ` Sean Young
@ 2018-12-08  0:14           ` kbuild test robot
  1 sibling, 0 replies; 19+ messages in thread
From: kbuild test robot @ 2018-12-08  0:14 UTC (permalink / raw)
  To: Patrick LERDA; +Cc: kbuild-all, linux-media, Patrick LERDA, sean

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

Hi Patrick,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on v4.20-rc5 next-20181207]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Patrick-LERDA/Add-ir-rcmm-driver/20181208-025555
base:   git://linuxtv.org/media_tree.git master
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   include/net/mac80211.h:477: warning: cannot understand function prototype: 'struct ieee80211_ftm_responder_params '
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'rx_stats_avg' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'rx_stats_avg.signal' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'rx_stats_avg.chain_signal' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.filtered' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.retry_failed' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.retry_count' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.lost_packets' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.last_tdls_pkt_time' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.msdu_retries' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.msdu_failed' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.last_ack' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.last_ack_signal' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.ack_signal_filled' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'status_stats.avg_ack_signal' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'tx_stats.packets' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'tx_stats.bytes' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'tx_stats.last_rate' not described in 'sta_info'
   net/mac80211/sta_info.h:588: warning: Function parameter or member 'tx_stats.msdu' not described in 'sta_info'
   kernel/rcu/tree.c:685: warning: Excess function parameter 'irq' description in 'rcu_nmi_exit'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.active' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.active' not described in 'dma_buf'
   include/linux/dma-fence-array.h:54: warning: Function parameter or member 'work' not described in 'dma_fence_array'
   include/linux/gpio/driver.h:375: warning: Function parameter or member 'init_valid_mask' not described in 'gpio_chip'
   include/linux/iio/hw-consumer.h:1: warning: no structured comments found
   include/linux/input/sparse-keymap.h:46: warning: Function parameter or member 'sw' not described in 'key_entry'
   include/linux/regulator/driver.h:227: warning: Function parameter or member 'resume' not described in 'regulator_ops'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw0' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw1' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw2' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw3' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.eadm' not described in 'irb'
   drivers/slimbus/stream.c:1: warning: no structured comments found
   include/linux/spi/spi.h:177: warning: Function parameter or member 'driver_override' not described in 'spi_device'
   drivers/target/target_core_device.c:1: warning: no structured comments found
   drivers/usb/typec/bus.c:1: warning: no structured comments found
   drivers/usb/typec/class.c:1: warning: no structured comments found
   include/linux/w1.h:281: warning: Function parameter or member 'of_match_table' not described in 'w1_family'
   fs/direct-io.c:257: warning: Excess function parameter 'offset' description in 'dio_complete'
   fs/file_table.c:1: warning: no structured comments found
   fs/libfs.c:477: warning: Excess function parameter 'available' description in 'simple_write_end'
   fs/posix_acl.c:646: warning: Function parameter or member 'inode' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'mode_p' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'acl' not described in 'posix_acl_update_mode'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:183: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:254: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_invalidate_range_start_gfx'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:302: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:382: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:383: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'end' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:848: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1356: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1523: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:3100: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_pin' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_unpin' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_res_obj' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_get_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_import_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_vmap' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_vunmap' not described in 'drm_driver'
   include/drm/drm_drv.h:609: warning: Function parameter or member 'gem_prime_mmap' not described in 'drm_driver'
   include/drm/drm_mode_config.h:869: warning: Function parameter or member 'quirk_addfb_prefer_xbgr_30bpp' not described in 'drm_mode_config'
   drivers/gpu/drm/i915/i915_vma.h:49: warning: cannot understand function prototype: 'struct i915_vma '
   drivers/gpu/drm/i915/i915_vma.h:1: warning: no structured comments found
   drivers/gpu/drm/i915/intel_guc_fwif.h:554: warning: cannot understand function prototype: 'struct guc_log_buffer_state '
   drivers/gpu/drm/i915/i915_trace.h:1: warning: no structured comments found
>> include/uapi/linux/lirc.h:222: warning: Enum value 'RC_PROTO_RCMM' not described in enum 'rc_proto'
   include/linux/skbuff.h:862: warning: Function parameter or member 'dev_scratch' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'list' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'ip_defrag_offset' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'skb_mstamp_ns' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member '__cloned_offset' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'head_frag' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member '__pkt_type_offset' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'encapsulation' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'encap_hdr_csum' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'csum_valid' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'csum_complete_sw' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'csum_level' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'inner_protocol_type' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'remcsum_offload' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'offload_fwd_mark' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'offload_mr_fwd_mark' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'sender_cpu' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'reserved_tailroom' not described in 'sk_buff'
   include/linux/skbuff.h:862: warning: Function parameter or member 'inner_ipproto' not described in 'sk_buff'
   include/net/sock.h:238: warning: Function parameter or member 'skc_addrpair' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_portpair' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_ipv6only' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_net_refcnt' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_v6_daddr' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_v6_rcv_saddr' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_cookie' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_listener' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_tw_dr' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_rcv_wnd' not described in 'sock_common'
   include/net/sock.h:238: warning: Function parameter or member 'skc_tw_rcv_nxt' not described in 'sock_common'
   include/net/sock.h:509: warning: Function parameter or member 'sk_backlog.rmem_alloc' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_backlog.len' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_backlog.head' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_backlog.tail' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_wq_raw' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'tcp_rtx_queue' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_route_forced_caps' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_txtime_report_errors' not described in 'sock'
   include/net/sock.h:509: warning: Function parameter or member 'sk_validate_xmit_skb' not described in 'sock'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'adj_list.upper' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'adj_list.lower' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'gso_partial_features' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'switchdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'l3mdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'xfrmdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'tlsdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'name_assign_type' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'ieee802154_ptr' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'mpls_ptr' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'xdp_prog' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'gro_flush_timeout' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'nf_hooks_ingress' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member '____cacheline_aligned_in_smp' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'qdisc_hash' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'xps_cpus_map' not described in 'net_device'
   include/linux/netdevice.h:2052: warning: Function parameter or member 'xps_rxqs_map' not described in 'net_device'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising' not described in 'phylink_link_state'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising' not described in 'phylink_link_state'
   Documentation/admin-guide/cgroup-v2.rst:1507: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/admin-guide/cgroup-v2.rst:1509: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/admin-guide/cgroup-v2.rst:1510: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/net/mac80211.h:1211: ERROR: Unexpected indentation.
   include/net/mac80211.h:1218: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:110: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:113: ERROR: Unexpected indentation.
   include/linux/wait.h:115: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/time/hrtimer.c:1129: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/signal.c:344: WARNING: Inline literal start-string without end-string.
   include/linux/kernel.h:137: WARNING: Inline interpreted text or phrase reference start-string without end-string.
   include/uapi/linux/firewire-cdev.h:312: WARNING: Inline literal start-string without end-string.
   Documentation/driver-api/gpio/board.rst:209: ERROR: Unexpected indentation.
   drivers/ata/libata-core.c:5958: ERROR: Unknown target name: "hw".
   drivers/message/fusion/mptbase.c:5057: WARNING: Definition list ends without a blank line; unexpected unindent.
   drivers/tty/serial/serial_core.c:1938: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/mtd/rawnand.h:1189: WARNING: Inline strong start-string without end-string.
   include/linux/mtd/rawnand.h:1191: WARNING: Inline strong start-string without end-string.
   include/linux/regulator/driver.h:286: ERROR: Unknown target name: "regulator_regmap_x_voltage".
   Documentation/driver-api/soundwire/locking.rst:50: ERROR: Inconsistent literal block quoting.
   Documentation/driver-api/soundwire/locking.rst:51: WARNING: Line block ends without a blank line.
   Documentation/driver-api/soundwire/locking.rst:55: WARNING: Inline substitution_reference start-string without end-string.
   Documentation/driver-api/soundwire/locking.rst:56: WARNING: Line block ends without a blank line.
   include/linux/spi/spi.h:365: ERROR: Unexpected indentation.
   Documentation/driver-api/usb/typec_bus.rst:76: WARNING: Definition list ends without a blank line; unexpected unindent.
   block/bio.c:883: WARNING: Inline emphasis start-string without end-string.
   fs/posix_acl.c:635: WARNING: Inline emphasis start-string without end-string.
   drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1573: WARNING: Inline emphasis start-string without end-string.
   drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1575: WARNING: Inline emphasis start-string without end-string.
   include/drm/drm_drv.h:656: ERROR: Unknown target name: "driver".
   Documentation/laptops/lg-laptop.rst:2: WARNING: Explicit markup ends without a blank line; unexpected unindent.
   Documentation/laptops/lg-laptop.rst:16: ERROR: Unexpected indentation.
   Documentation/laptops/lg-laptop.rst:17: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/misc-devices/ibmvmc.rst:2: WARNING: Explicit markup ends without a blank line; unexpected unindent.
   Documentation/networking/dpaa2/dpio-driver.rst:30: ERROR: Unexpected indentation.
   Documentation/networking/dpaa2/dpio-driver.rst:42: WARNING: Definition list ends without a blank line; unexpected unindent.
   Documentation/networking/dpaa2/dpio-driver.rst:62: ERROR: Unexpected indentation.
   Documentation/networking/dpaa2/dpio-driver.rst:143: ERROR: Unexpected indentation.
   include/linux/netdevice.h:3452: WARNING: Inline emphasis start-string without end-string.
   include/linux/netdevice.h:3452: WARNING: Inline emphasis start-string without end-string.
   net/core/dev.c:4949: ERROR: Unknown target name: "page_is".
   Documentation/security/keys/core.rst:1597: WARNING: Inline literal start-string without end-string.

vim +222 include/uapi/linux/lirc.h

9b6192589 Sean Young    2017-02-25  167  
9b6192589 Sean Young    2017-02-25  168  /**
9b6192589 Sean Young    2017-02-25  169   * enum rc_proto - the Remote Controller protocol
9b6192589 Sean Young    2017-02-25  170   *
9b6192589 Sean Young    2017-02-25  171   * @RC_PROTO_UNKNOWN: Protocol not known
9b6192589 Sean Young    2017-02-25  172   * @RC_PROTO_OTHER: Protocol known but proprietary
9b6192589 Sean Young    2017-02-25  173   * @RC_PROTO_RC5: Philips RC5 protocol
9b6192589 Sean Young    2017-02-25  174   * @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol
9b6192589 Sean Young    2017-02-25  175   * @RC_PROTO_RC5_SZ: StreamZap variant of RC5
9b6192589 Sean Young    2017-02-25  176   * @RC_PROTO_JVC: JVC protocol
9b6192589 Sean Young    2017-02-25  177   * @RC_PROTO_SONY12: Sony 12 bit protocol
9b6192589 Sean Young    2017-02-25  178   * @RC_PROTO_SONY15: Sony 15 bit protocol
9b6192589 Sean Young    2017-02-25  179   * @RC_PROTO_SONY20: Sony 20 bit protocol
9b6192589 Sean Young    2017-02-25  180   * @RC_PROTO_NEC: NEC protocol
9b6192589 Sean Young    2017-02-25  181   * @RC_PROTO_NECX: Extended NEC protocol
9b6192589 Sean Young    2017-02-25  182   * @RC_PROTO_NEC32: NEC 32 bit protocol
9b6192589 Sean Young    2017-02-25  183   * @RC_PROTO_SANYO: Sanyo protocol
9b6192589 Sean Young    2017-02-25  184   * @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard
9b6192589 Sean Young    2017-02-25  185   * @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse
9b6192589 Sean Young    2017-02-25  186   * @RC_PROTO_RC6_0: Philips RC6-0-16 protocol
9b6192589 Sean Young    2017-02-25  187   * @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol
9b6192589 Sean Young    2017-02-25  188   * @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol
9b6192589 Sean Young    2017-02-25  189   * @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol
9b6192589 Sean Young    2017-02-25  190   * @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
9b6192589 Sean Young    2017-02-25  191   * @RC_PROTO_SHARP: Sharp protocol
9b6192589 Sean Young    2017-02-25  192   * @RC_PROTO_XMP: XMP protocol
9b6192589 Sean Young    2017-02-25  193   * @RC_PROTO_CEC: CEC protocol
447dcc0cf Sean Young    2017-12-03  194   * @RC_PROTO_IMON: iMon Pad protocol
9b6192589 Sean Young    2017-02-25  195   */
9b6192589 Sean Young    2017-02-25  196  enum rc_proto {
9b6192589 Sean Young    2017-02-25  197  	RC_PROTO_UNKNOWN	= 0,
9b6192589 Sean Young    2017-02-25  198  	RC_PROTO_OTHER		= 1,
9b6192589 Sean Young    2017-02-25  199  	RC_PROTO_RC5		= 2,
9b6192589 Sean Young    2017-02-25  200  	RC_PROTO_RC5X_20	= 3,
9b6192589 Sean Young    2017-02-25  201  	RC_PROTO_RC5_SZ		= 4,
9b6192589 Sean Young    2017-02-25  202  	RC_PROTO_JVC		= 5,
9b6192589 Sean Young    2017-02-25  203  	RC_PROTO_SONY12		= 6,
9b6192589 Sean Young    2017-02-25  204  	RC_PROTO_SONY15		= 7,
9b6192589 Sean Young    2017-02-25  205  	RC_PROTO_SONY20		= 8,
9b6192589 Sean Young    2017-02-25  206  	RC_PROTO_NEC		= 9,
9b6192589 Sean Young    2017-02-25  207  	RC_PROTO_NECX		= 10,
9b6192589 Sean Young    2017-02-25  208  	RC_PROTO_NEC32		= 11,
9b6192589 Sean Young    2017-02-25  209  	RC_PROTO_SANYO		= 12,
9b6192589 Sean Young    2017-02-25  210  	RC_PROTO_MCIR2_KBD	= 13,
9b6192589 Sean Young    2017-02-25  211  	RC_PROTO_MCIR2_MSE	= 14,
9b6192589 Sean Young    2017-02-25  212  	RC_PROTO_RC6_0		= 15,
9b6192589 Sean Young    2017-02-25  213  	RC_PROTO_RC6_6A_20	= 16,
9b6192589 Sean Young    2017-02-25  214  	RC_PROTO_RC6_6A_24	= 17,
9b6192589 Sean Young    2017-02-25  215  	RC_PROTO_RC6_6A_32	= 18,
9b6192589 Sean Young    2017-02-25  216  	RC_PROTO_RC6_MCE	= 19,
9b6192589 Sean Young    2017-02-25  217  	RC_PROTO_SHARP		= 20,
9b6192589 Sean Young    2017-02-25  218  	RC_PROTO_XMP		= 21,
9b6192589 Sean Young    2017-02-25  219  	RC_PROTO_CEC		= 22,
447dcc0cf Sean Young    2017-12-03  220  	RC_PROTO_IMON		= 23,
d66d06430 Patrick LERDA 2018-12-07  221  	RC_PROTO_RCMM		= 24,
9b6192589 Sean Young    2017-02-25 @222  };
9b6192589 Sean Young    2017-02-25  223  

:::::: The code at line 222 was first introduced by commit
:::::: 9b6192589be788dec73a0e99fe49b8f8ddaf825e media: lirc: implement scancode sending

:::::: TO: Sean Young <sean@mess.org>
:::::: CC: Mauro Carvalho Chehab <mchehab@s-opensource.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6598 bytes --]

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

* [PATCH v5 1/1] media: rc: rcmm decoder
  2018-12-07 10:12           ` Sean Young
  2018-12-07 12:58             ` patrick9876
@ 2018-12-08  1:18             ` Patrick Lerda
  2018-12-13 22:41               ` Patrick Lerda
  2019-01-09 11:25               ` Sean Young
  1 sibling, 2 replies; 19+ messages in thread
From: Patrick Lerda @ 2018-12-08  1:18 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick Lerda, sean, linux-media-owner

media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
---
 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@hardeman.nu>
 S:	Maintained
 F:	drivers/media/rc/winbond-cir.c
 
+RCMM REMOTE CONTROLS DECODER
+M:	Patrick Lerda <patrick9876@free.fr>
+S:	Maintained
+F:	drivers/media/rc/ir-rcmm-decoder.c
+
 WINSYSTEMS EBC-C384 WATCHDOG DRIVER
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-watchdog@vger.kernel.org
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
+
 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@free.fr>
+
+#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;
+
+		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,
+};
+
+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;
+	} 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 },
 };
 
 /* 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"	},
 };
 
 /**
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


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

* Re: [PATCH v5 1/1] media: rc: rcmm decoder
  2018-12-08  1:18             ` [PATCH v5 1/1] media: rc: rcmm decoder Patrick Lerda
@ 2018-12-13 22:41               ` Patrick Lerda
  2018-12-14 12:30                 ` Sean Young
  2019-01-09 11:25               ` Sean Young
  1 sibling, 1 reply; 19+ messages in thread
From: Patrick Lerda @ 2018-12-13 22:41 UTC (permalink / raw)
  To: linux-media; +Cc: sean, linux-media-owner

Hi Sean,

    Is the v5 OK?

    Thanks,

Patrick.



Patrick Lerda wrote:
> media: add support for RCMM infrared remote controls.
>
> Signed-off-by: Patrick Lerda <patrick9876@free.fr>
> ---
>   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@hardeman.nu>
>   S:	Maintained
>   F:	drivers/media/rc/winbond-cir.c
>   
> +RCMM REMOTE CONTROLS DECODER
> +M:	Patrick Lerda <patrick9876@free.fr>
> +S:	Maintained
> +F:	drivers/media/rc/ir-rcmm-decoder.c
> +
>   WINSYSTEMS EBC-C384 WATCHDOG DRIVER
>   M:	William Breathitt Gray <vilhelm.gray@gmail.com>
>   L:	linux-watchdog@vger.kernel.org
> 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
> +
>   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@free.fr>
> +
> +#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;
> +
> +		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,
> +};
> +
> +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;
> +	} 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 },
>   };
>   
>   /* 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"	},
>   };
>   
>   /**
> 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


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

* Re: [PATCH v5 1/1] media: rc: rcmm decoder
  2018-12-13 22:41               ` Patrick Lerda
@ 2018-12-14 12:30                 ` Sean Young
  0 siblings, 0 replies; 19+ messages in thread
From: Sean Young @ 2018-12-14 12:30 UTC (permalink / raw)
  To: Patrick Lerda; +Cc: linux-media

Hi Patrick,

On Thu, Dec 13, 2018 at 11:41:01PM +0100, Patrick Lerda wrote:
> Hi Sean,
> 
>    Is the v5 OK?

Sorry I'm currently at the Linux Foundation Hyperledger event in Basel, I'll
be back next week and then I'll do a proper review. Looks good at first
glance.

Thanks

Sean

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

* Re: [PATCH v5 1/1] media: rc: rcmm decoder
  2018-12-08  1:18             ` [PATCH v5 1/1] media: rc: rcmm decoder Patrick Lerda
  2018-12-13 22:41               ` Patrick Lerda
@ 2019-01-09 11:25               ` Sean Young
  2019-01-15 12:10                 ` Patrick Lerda
                                   ` (2 more replies)
  1 sibling, 3 replies; 19+ messages in thread
From: Sean Young @ 2019-01-09 11:25 UTC (permalink / raw)
  To: Patrick Lerda; +Cc: linux-media

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@free.fr>

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@hardeman.nu>
>  S:	Maintained
>  F:	drivers/media/rc/winbond-cir.c
>  
> +RCMM REMOTE CONTROLS DECODER
> +M:	Patrick Lerda <patrick9876@free.fr>
> +S:	Maintained
> +F:	drivers/media/rc/ir-rcmm-decoder.c
> +
>  WINSYSTEMS EBC-C384 WATCHDOG DRIVER
>  M:	William Breathitt Gray <vilhelm.gray@gmail.com>
>  L:	linux-watchdog@vger.kernel.org
> 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@free.fr>
> +
> +#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

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

* Re: [PATCH v5 1/1] media: rc: rcmm decoder
  2019-01-09 11:25               ` Sean Young
@ 2019-01-15 12:10                 ` Patrick Lerda
  2019-01-17  8:50                 ` [PATCH v6] " repojohnray
  2019-01-17 10:52                 ` [PATCH v7] " Patrick Lerda
  2 siblings, 0 replies; 19+ messages in thread
From: Patrick Lerda @ 2019-01-15 12:10 UTC (permalink / raw)
  To: Sean Young; +Cc: linux-media

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@free.fr>
> 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@hardeman.nu>
>>   S:	Maintained
>>   F:	drivers/media/rc/winbond-cir.c
>>   
>> +RCMM REMOTE CONTROLS DECODER
>> +M:	Patrick Lerda <patrick9876@free.fr>
>> +S:	Maintained
>> +F:	drivers/media/rc/ir-rcmm-decoder.c
>> +
>>   WINSYSTEMS EBC-C384 WATCHDOG DRIVER
>>   M:	William Breathitt Gray <vilhelm.gray@gmail.com>
>>   L:	linux-watchdog@vger.kernel.org
>> 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@free.fr>
>> +
>> +#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
>


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

* [PATCH v6] media: rc: rcmm decoder
  2019-01-09 11:25               ` Sean Young
  2019-01-15 12:10                 ` Patrick Lerda
@ 2019-01-17  8:50                 ` repojohnray
  2019-01-17  9:07                   ` Patrick Lerda
  2019-01-17 10:52                 ` [PATCH v7] " Patrick Lerda
  2 siblings, 1 reply; 19+ messages in thread
From: repojohnray @ 2019-01-17  8:50 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick Lerda, sean, linux-media-owner

From: Patrick Lerda <patrick9876@free.fr>

media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
---
 MAINTAINERS                        |   5 +
 drivers/media/rc/Kconfig           |  13 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 257 +++++++++++++++++++++++++++++
 drivers/media/rc/rc-core-priv.h    |   5 +
 drivers/media/rc/rc-main.c         |   9 +
 include/media/rc-map.h             |  14 +-
 include/uapi/linux/lirc.h          |   6 +
 tools/include/uapi/linux/lirc.h    |   6 +
 9 files changed, 313 insertions(+), 3 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 17ad1d7b5510..65a08454e99c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16496,6 +16496,11 @@ M:	David Härdeman <david@hardeman.nu>
 S:	Maintained
 F:	drivers/media/rc/winbond-cir.c
 
+RCMM REMOTE CONTROLS DECODER
+M:	Patrick Lerda <patrick9876@free.fr>
+S:	Maintained
+F:	drivers/media/rc/ir-rcmm-decoder.c
+
 WINSYSTEMS EBC-C384 WATCHDOG DRIVER
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-watchdog@vger.kernel.org
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8a216068a35a..2c468fa0299f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,19 @@ 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 when you have IR with RC-MM protocol, and
+	   you need the software decoder. The driver supports 32,
+	   24 and 12 bits RC-MM variants. You can enable or disable the
+	   different modes using the following RC protocol keywords:
+	   'rcmm-32', 'rcmm-24' and 'rcmm-12'.
+
+	   To compile this driver as a module, choose M here: the module
+	   will be called ir-rcmm-decoder.
+
 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..cdb85e392527
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0+
+// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+//
+// Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr>
+
+#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(const struct rcmm_dec *data)
+{
+	return !((0x000c0000 & data->bits) == 0x000c0000);
+}
+
+static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data)
+{
+	switch (data->count) {
+	case 24:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) {
+			rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+
+	case 12:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) {
+			rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+	}
+
+	return -1;
+}
+
+/**
+ * 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_RCMM32 |
+							RC_PROTO_BIT_RCMM24 |
+							RC_PROTO_BIT_RCMM12)))
+		return 0;
+
+	if (!is_timing_event(ev)) {
+		if (ev.reset)
+			data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	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
+			value = -1;
+
+		if (value == -1) {
+			if (!rcmm_miscmode(dev, data))
+				return 0;
+			break;
+		}
+
+		data->bits <<= 2;
+		data->bits |= value;
+
+		data->count += 2;
+
+		if (data->count < 32)
+			data->state = STATE_BUMP;
+		else
+			data->state = STATE_FINISHED;
+
+		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;
+		}
+
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) {
+			rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+
+		break;
+	}
+
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static const int rcmmspace[] = {
+	RCMM_PULSE_0,
+	RCMM_PULSE_1,
+	RCMM_PULSE_2,
+	RCMM_PULSE_3,
+};
+
+static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max,
+			      unsigned int n, u32 data)
+{
+	int i;
+	int ret;
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0);
+	if (ret)
+		return ret;
+
+	for (i = n - 2; i >= 0; i -= 2) {
+		const unsigned int space = rcmmspace[(data >> i) & 3];
+
+		ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space);
+		if (ret)
+			return ret;
+	}
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode,
+			  struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+
+	switch (protocol) {
+	case RC_PROTO_RCMM32:
+		ret = ir_rcmm_rawencoder(&e, max, 32, scancode);
+		break;
+	case RC_PROTO_RCMM24:
+		ret = ir_rcmm_rawencoder(&e, max, 24, scancode);
+		break;
+	case RC_PROTO_RCMM12:
+		ret = ir_rcmm_rawencoder(&e, max, 12, scancode);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
+static struct ir_raw_handler rcmm_handler = {
+	.protocols	= RC_PROTO_BIT_RCMM32 |
+			  RC_PROTO_BIT_RCMM24 |
+			  RC_PROTO_BIT_RCMM12,
+	.decode		= ir_rcmm_decode,
+	.encode         = ir_rcmm_encode,
+	.carrier        = 36000,
+};
+
+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..9f21b3e8b377 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;
+		u32 bits;
+	} 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..971c041120e2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -70,6 +70,12 @@ static const struct {
 	[RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 },
 	[RC_PROTO_IMON] = { .name = "imon",
 		.scancode_bits = 0x7fffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM32] = { .name = "rcmm-32",
+		.scancode_bits = 0xffffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM24] = { .name = "rcmm-24",
+		.scancode_bits = 0x00ffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM12] = { .name = "rcmm-12",
+		.scancode_bits = 0x00000fff, .repeat_period = 114 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1006,6 +1012,9 @@ 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_RCMM32,	"rcmm-32",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM24,	"rcmm-24",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM12,	"rcmm-12",	"ir-rcmm-decoder"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index d621acadfbf3..27631659b8ac 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -37,6 +37,9 @@
 #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_RCMM32		BIT_ULL(RC_PROTO_RCMM32)
+#define RC_PROTO_BIT_RCMM24		BIT_ULL(RC_PROTO_RCMM24)
+#define RC_PROTO_BIT_RCMM12		BIT_ULL(RC_PROTO_RCMM12)
 
 #define RC_PROTO_BIT_ALL \
 			(RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -51,7 +54,8 @@
 			 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_RCMM32 | \
+			 RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM12)
 /* 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 +68,9 @@
 			 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_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_PROTO_BIT_ALL_IR_ENCODER \
 			(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -77,7 +83,9 @@
 			 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_IMON)
+			 RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON | \
+			 RC_PROTO_BIT_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
 #define RC_SCANCODE_OTHER(x)			(x)
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 6b319581882f..bd0d54880e6b 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -192,6 +192,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -218,6 +221,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
index f189931042a7..e6ac4f4d66c1 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -186,6 +186,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -212,6 +215,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
-- 
2.20.1


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

* [PATCH v6] media: rc: rcmm decoder
  2019-01-17  8:50                 ` [PATCH v6] " repojohnray
@ 2019-01-17  9:07                   ` Patrick Lerda
  0 siblings, 0 replies; 19+ messages in thread
From: Patrick Lerda @ 2019-01-17  9:07 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick Lerda, sean, linux-media-owner

media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
---
 MAINTAINERS                        |   5 +
 drivers/media/rc/Kconfig           |  13 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 257 +++++++++++++++++++++++++++++
 drivers/media/rc/rc-core-priv.h    |   5 +
 drivers/media/rc/rc-main.c         |   9 +
 include/media/rc-map.h             |  14 +-
 include/uapi/linux/lirc.h          |   6 +
 tools/include/uapi/linux/lirc.h    |   6 +
 9 files changed, 313 insertions(+), 3 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 17ad1d7b5510..65a08454e99c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16496,6 +16496,11 @@ M:	David Härdeman <david@hardeman.nu>
 S:	Maintained
 F:	drivers/media/rc/winbond-cir.c
 
+RCMM REMOTE CONTROLS DECODER
+M:	Patrick Lerda <patrick9876@free.fr>
+S:	Maintained
+F:	drivers/media/rc/ir-rcmm-decoder.c
+
 WINSYSTEMS EBC-C384 WATCHDOG DRIVER
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-watchdog@vger.kernel.org
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8a216068a35a..2c468fa0299f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,19 @@ 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 when you have IR with RC-MM protocol, and
+	   you need the software decoder. The driver supports 32,
+	   24 and 12 bits RC-MM variants. You can enable or disable the
+	   different modes using the following RC protocol keywords:
+	   'rcmm-32', 'rcmm-24' and 'rcmm-12'.
+
+	   To compile this driver as a module, choose M here: the module
+	   will be called ir-rcmm-decoder.
+
 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..cdb85e392527
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0+
+// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+//
+// Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr>
+
+#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(const struct rcmm_dec *data)
+{
+	return !((0x000c0000 & data->bits) == 0x000c0000);
+}
+
+static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data)
+{
+	switch (data->count) {
+	case 24:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) {
+			rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+
+	case 12:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) {
+			rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+	}
+
+	return -1;
+}
+
+/**
+ * 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_RCMM32 |
+							RC_PROTO_BIT_RCMM24 |
+							RC_PROTO_BIT_RCMM12)))
+		return 0;
+
+	if (!is_timing_event(ev)) {
+		if (ev.reset)
+			data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	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
+			value = -1;
+
+		if (value == -1) {
+			if (!rcmm_miscmode(dev, data))
+				return 0;
+			break;
+		}
+
+		data->bits <<= 2;
+		data->bits |= value;
+
+		data->count += 2;
+
+		if (data->count < 32)
+			data->state = STATE_BUMP;
+		else
+			data->state = STATE_FINISHED;
+
+		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;
+		}
+
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) {
+			rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+
+		break;
+	}
+
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static const int rcmmspace[] = {
+	RCMM_PULSE_0,
+	RCMM_PULSE_1,
+	RCMM_PULSE_2,
+	RCMM_PULSE_3,
+};
+
+static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max,
+			      unsigned int n, u32 data)
+{
+	int i;
+	int ret;
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0);
+	if (ret)
+		return ret;
+
+	for (i = n - 2; i >= 0; i -= 2) {
+		const unsigned int space = rcmmspace[(data >> i) & 3];
+
+		ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space);
+		if (ret)
+			return ret;
+	}
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode,
+			  struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+
+	switch (protocol) {
+	case RC_PROTO_RCMM32:
+		ret = ir_rcmm_rawencoder(&e, max, 32, scancode);
+		break;
+	case RC_PROTO_RCMM24:
+		ret = ir_rcmm_rawencoder(&e, max, 24, scancode);
+		break;
+	case RC_PROTO_RCMM12:
+		ret = ir_rcmm_rawencoder(&e, max, 12, scancode);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
+static struct ir_raw_handler rcmm_handler = {
+	.protocols	= RC_PROTO_BIT_RCMM32 |
+			  RC_PROTO_BIT_RCMM24 |
+			  RC_PROTO_BIT_RCMM12,
+	.decode		= ir_rcmm_decode,
+	.encode         = ir_rcmm_encode,
+	.carrier        = 36000,
+};
+
+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..9f21b3e8b377 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;
+		u32 bits;
+	} 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..971c041120e2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -70,6 +70,12 @@ static const struct {
 	[RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 },
 	[RC_PROTO_IMON] = { .name = "imon",
 		.scancode_bits = 0x7fffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM32] = { .name = "rcmm-32",
+		.scancode_bits = 0xffffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM24] = { .name = "rcmm-24",
+		.scancode_bits = 0x00ffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM12] = { .name = "rcmm-12",
+		.scancode_bits = 0x00000fff, .repeat_period = 114 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1006,6 +1012,9 @@ 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_RCMM32,	"rcmm-32",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM24,	"rcmm-24",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM12,	"rcmm-12",	"ir-rcmm-decoder"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index d621acadfbf3..27631659b8ac 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -37,6 +37,9 @@
 #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_RCMM32		BIT_ULL(RC_PROTO_RCMM32)
+#define RC_PROTO_BIT_RCMM24		BIT_ULL(RC_PROTO_RCMM24)
+#define RC_PROTO_BIT_RCMM12		BIT_ULL(RC_PROTO_RCMM12)
 
 #define RC_PROTO_BIT_ALL \
 			(RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -51,7 +54,8 @@
 			 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_RCMM32 | \
+			 RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM12)
 /* 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 +68,9 @@
 			 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_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_PROTO_BIT_ALL_IR_ENCODER \
 			(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -77,7 +83,9 @@
 			 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_IMON)
+			 RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON | \
+			 RC_PROTO_BIT_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
 #define RC_SCANCODE_OTHER(x)			(x)
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 6b319581882f..bd0d54880e6b 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -192,6 +192,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -218,6 +221,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
index f189931042a7..e6ac4f4d66c1 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -186,6 +186,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -212,6 +215,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
-- 
2.20.1


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

* [PATCH v7] media: rc: rcmm decoder
  2019-01-09 11:25               ` Sean Young
  2019-01-15 12:10                 ` Patrick Lerda
  2019-01-17  8:50                 ` [PATCH v6] " repojohnray
@ 2019-01-17 10:52                 ` Patrick Lerda
  2 siblings, 0 replies; 19+ messages in thread
From: Patrick Lerda @ 2019-01-17 10:52 UTC (permalink / raw)
  To: linux-media; +Cc: Patrick Lerda, sean, linux-media-owner

media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
---
 MAINTAINERS                        |   5 +
 drivers/media/rc/Kconfig           |  13 ++
 drivers/media/rc/Makefile          |   1 +
 drivers/media/rc/ir-rcmm-decoder.c | 257 +++++++++++++++++++++++++++++
 drivers/media/rc/rc-core-priv.h    |   5 +
 drivers/media/rc/rc-main.c         |   9 +
 include/media/rc-map.h             |  14 +-
 include/uapi/linux/lirc.h          |   6 +
 tools/include/uapi/linux/lirc.h    |   6 +
 9 files changed, 313 insertions(+), 3 deletions(-)
 create mode 100644 drivers/media/rc/ir-rcmm-decoder.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 17ad1d7b5510..65a08454e99c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16496,6 +16496,11 @@ M:	David Härdeman <david@hardeman.nu>
 S:	Maintained
 F:	drivers/media/rc/winbond-cir.c
 
+RCMM REMOTE CONTROLS DECODER
+M:	Patrick Lerda <patrick9876@free.fr>
+S:	Maintained
+F:	drivers/media/rc/ir-rcmm-decoder.c
+
 WINSYSTEMS EBC-C384 WATCHDOG DRIVER
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-watchdog@vger.kernel.org
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8a216068a35a..2c468fa0299f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -133,6 +133,19 @@ 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 when you have IR with RC-MM protocol, and
+	   you need the software decoder. The driver supports 32,
+	   24 and 12 bits RC-MM variants. You can enable or disable the
+	   different modes using the following RC protocol keywords:
+	   'rcmm-32', 'rcmm-24' and 'rcmm-12'.
+
+	   To compile this driver as a module, choose M here: the module
+	   will be called ir-rcmm-decoder.
+
 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..cdb85e392527
--- /dev/null
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0+
+// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
+//
+// Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr>
+
+#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(const struct rcmm_dec *data)
+{
+	return !((0x000c0000 & data->bits) == 0x000c0000);
+}
+
+static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data)
+{
+	switch (data->count) {
+	case 24:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) {
+			rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+
+	case 12:
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) {
+			rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+		return -1;
+	}
+
+	return -1;
+}
+
+/**
+ * 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_RCMM32 |
+							RC_PROTO_BIT_RCMM24 |
+							RC_PROTO_BIT_RCMM12)))
+		return 0;
+
+	if (!is_timing_event(ev)) {
+		if (ev.reset)
+			data->state = STATE_INACTIVE;
+		return 0;
+	}
+
+	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
+			value = -1;
+
+		if (value == -1) {
+			if (!rcmm_miscmode(dev, data))
+				return 0;
+			break;
+		}
+
+		data->bits <<= 2;
+		data->bits |= value;
+
+		data->count += 2;
+
+		if (data->count < 32)
+			data->state = STATE_BUMP;
+		else
+			data->state = STATE_FINISHED;
+
+		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;
+		}
+
+		if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) {
+			rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle);
+			data->state = STATE_INACTIVE;
+			return 0;
+		}
+
+		break;
+	}
+
+	data->state = STATE_INACTIVE;
+	return -EINVAL;
+}
+
+static const int rcmmspace[] = {
+	RCMM_PULSE_0,
+	RCMM_PULSE_1,
+	RCMM_PULSE_2,
+	RCMM_PULSE_3,
+};
+
+static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max,
+			      unsigned int n, u32 data)
+{
+	int i;
+	int ret;
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0);
+	if (ret)
+		return ret;
+
+	for (i = n - 2; i >= 0; i -= 2) {
+		const unsigned int space = rcmmspace[(data >> i) & 3];
+
+		ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space);
+		if (ret)
+			return ret;
+	}
+
+	ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode,
+			  struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+
+	switch (protocol) {
+	case RC_PROTO_RCMM32:
+		ret = ir_rcmm_rawencoder(&e, max, 32, scancode);
+		break;
+	case RC_PROTO_RCMM24:
+		ret = ir_rcmm_rawencoder(&e, max, 24, scancode);
+		break;
+	case RC_PROTO_RCMM12:
+		ret = ir_rcmm_rawencoder(&e, max, 12, scancode);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
+static struct ir_raw_handler rcmm_handler = {
+	.protocols	= RC_PROTO_BIT_RCMM32 |
+			  RC_PROTO_BIT_RCMM24 |
+			  RC_PROTO_BIT_RCMM12,
+	.decode		= ir_rcmm_decode,
+	.encode         = ir_rcmm_encode,
+	.carrier        = 36000,
+};
+
+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..9f21b3e8b377 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;
+		u32 bits;
+	} 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..971c041120e2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -70,6 +70,12 @@ static const struct {
 	[RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 },
 	[RC_PROTO_IMON] = { .name = "imon",
 		.scancode_bits = 0x7fffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM32] = { .name = "rcmm-32",
+		.scancode_bits = 0xffffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM24] = { .name = "rcmm-24",
+		.scancode_bits = 0x00ffffff, .repeat_period = 114 },
+	[RC_PROTO_RCMM12] = { .name = "rcmm-12",
+		.scancode_bits = 0x00000fff, .repeat_period = 114 },
 };
 
 /* Used to keep track of known keymaps */
@@ -1006,6 +1012,9 @@ 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_RCMM32,	"rcmm-32",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM24,	"rcmm-24",	"ir-rcmm-decoder"	},
+	{ RC_PROTO_BIT_RCMM12,	"rcmm-12",	"ir-rcmm-decoder"	},
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index d621acadfbf3..27631659b8ac 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -37,6 +37,9 @@
 #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_RCMM32		BIT_ULL(RC_PROTO_RCMM32)
+#define RC_PROTO_BIT_RCMM24		BIT_ULL(RC_PROTO_RCMM24)
+#define RC_PROTO_BIT_RCMM12		BIT_ULL(RC_PROTO_RCMM12)
 
 #define RC_PROTO_BIT_ALL \
 			(RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -51,7 +54,8 @@
 			 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_RCMM32 | \
+			 RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM12)
 /* 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 +68,9 @@
 			 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_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_PROTO_BIT_ALL_IR_ENCODER \
 			(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -77,7 +83,9 @@
 			 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_IMON)
+			 RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON | \
+			 RC_PROTO_BIT_RCMM32 | RC_PROTO_BIT_RCMM24 | \
+			 RC_PROTO_BIT_RCMM12)
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
 #define RC_SCANCODE_OTHER(x)			(x)
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 6b319581882f..bd0d54880e6b 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -192,6 +192,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -218,6 +221,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
index f189931042a7..e6ac4f4d66c1 100644
--- a/tools/include/uapi/linux/lirc.h
+++ b/tools/include/uapi/linux/lirc.h
@@ -186,6 +186,9 @@ struct lirc_scancode {
  * @RC_PROTO_XMP: XMP protocol
  * @RC_PROTO_CEC: CEC protocol
  * @RC_PROTO_IMON: iMon Pad protocol
+ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
+ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
+ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
  */
 enum rc_proto {
 	RC_PROTO_UNKNOWN	= 0,
@@ -212,6 +215,9 @@ enum rc_proto {
 	RC_PROTO_XMP		= 21,
 	RC_PROTO_CEC		= 22,
 	RC_PROTO_IMON		= 23,
+	RC_PROTO_RCMM32		= 24,
+	RC_PROTO_RCMM24		= 25,
+	RC_PROTO_RCMM12		= 26,
 };
 
 #endif
-- 
2.20.1


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

end of thread, other threads:[~2019-01-17 10:53 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-04 20:20 [PATCH] Add ir-rcmm-driver patrick9876
2018-12-04 20:57 ` Sean Young
2018-12-04 21:06   ` patrick9876
2018-12-04 21:32     ` patrick9876
2018-12-05  0:29     ` [PATCHv2] " patrick9876
2018-12-05  0:29       ` [PATCH] " patrick9876
2018-12-06 14:49         ` Sean Young
2018-12-07  9:57         ` [PATCHv3 1/1] " Patrick LERDA
2018-12-07 10:12           ` Sean Young
2018-12-07 12:58             ` patrick9876
2018-12-08  1:18             ` [PATCH v5 1/1] media: rc: rcmm decoder Patrick Lerda
2018-12-13 22:41               ` Patrick Lerda
2018-12-14 12:30                 ` Sean Young
2019-01-09 11:25               ` Sean Young
2019-01-15 12:10                 ` Patrick Lerda
2019-01-17  8:50                 ` [PATCH v6] " repojohnray
2019-01-17  9:07                   ` Patrick Lerda
2019-01-17 10:52                 ` [PATCH v7] " Patrick Lerda
2018-12-08  0:14           ` [PATCHv3 1/1] Add ir-rcmm-driver kbuild test robot

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).