diff --git a/packages/linux/patches/default/linux-903-backport-rcmm-ir-decoder.patch b/packages/linux/patches/default/linux-903-backport-rcmm-ir-decoder.patch new file mode 100644 index 0000000000..ae2cba8494 --- /dev/null +++ b/packages/linux/patches/default/linux-903-backport-rcmm-ir-decoder.patch @@ -0,0 +1,506 @@ +From da8a71104dda4a85a9d9546ff462542347f8efa6 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Wed, 20 Mar 2019 09:11:53 +0100 +Subject: [PATCH] media: rc: rcmm decoder and encoder + +commit 721074b03411327e7bf41555d4cc7c18f49313f7 upstream. + +media: add support for RCMM infrared remote controls. + +Signed-off-by: Patrick Lerda +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Matthias Reichl +--- + Documentation/media/lirc.h.rst.exceptions | 3 + + MAINTAINERS | 5 + + drivers/media/rc/Kconfig | 13 ++ + drivers/media/rc/Makefile | 1 + + drivers/media/rc/ir-rcmm-decoder.c | 254 ++++++++++++++++++++++ + 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 | 12 + + 10 files changed, 319 insertions(+), 3 deletions(-) + create mode 100644 drivers/media/rc/ir-rcmm-decoder.c + +diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions +index 984b61dc3f2e..e7a41d4b3d46 100644 +--- a/Documentation/media/lirc.h.rst.exceptions ++++ b/Documentation/media/lirc.h.rst.exceptions +@@ -58,6 +58,9 @@ ignore symbol RC_PROTO_SHARP + ignore symbol RC_PROTO_XMP + ignore symbol RC_PROTO_CEC + ignore symbol RC_PROTO_IMON ++ignore symbol RC_PROTO_RCMM12 ++ignore symbol RC_PROTO_RCMM24 ++ignore symbol RC_PROTO_RCMM32 + + # Undocumented macros + +diff --git a/MAINTAINERS b/MAINTAINERS +index 9e9b19ecf6f7..57b60dd42729 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15837,6 +15837,11 @@ M: David Härdeman + S: Maintained + F: drivers/media/rc/winbond-cir.c + ++RCMM REMOTE CONTROLS DECODER ++M: Patrick Lerda ++S: Maintained ++F: drivers/media/rc/ir-rcmm-decoder.c ++ + WINSYSTEMS EBC-C384 WATCHDOG DRIVER + M: William Breathitt Gray + L: linux-watchdog@vger.kernel.org +diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig +index 1021c08a9ba4..8164a889011a 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 12, ++ 24 and 32 bits RC-MM variants. You can enable or disable the ++ different modes using the following RC protocol keywords: ++ 'rc-mm-12', 'rc-mm-24' and 'rc-mm-32'. ++ ++ 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 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..f1096ac1e5c5 +--- /dev/null ++++ b/drivers/media/rc/ir-rcmm-decoder.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol ++// ++// Copyright (C) 2018 by Patrick Lerda ++ ++#include "rc-core-priv.h" ++#include ++#include ++ ++#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; ++ } ++ ++ return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); ++} ++ ++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, ++ .min_timeout = RCMM_PULSE_3 + RCMM_UNIT, ++}; ++ ++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 e847bdad5c51..59c252f24194 100644 +--- a/drivers/media/rc/rc-core-priv.h ++++ b/drivers/media/rc/rc-core-priv.h +@@ -136,6 +136,11 @@ struct ir_raw_event_ctrl { + struct input_dev *idev; + char name[64]; + } 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 0f218afdadaa..78e79c37f208 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_RCMM12] = { .name = "rc-mm-12", ++ .scancode_bits = 0x00000fff, .repeat_period = 114 }, ++ [RC_PROTO_RCMM24] = { .name = "rc-mm-24", ++ .scancode_bits = 0x00ffffff, .repeat_period = 114 }, ++ [RC_PROTO_RCMM32] = { .name = "rc-mm-32", ++ .scancode_bits = 0xffffffff, .repeat_period = 114 }, + }; + + /* Used to keep track of known keymaps */ +@@ -1018,6 +1024,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_RCMM12 | ++ RC_PROTO_BIT_RCMM24 | ++ RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, + }; + + /** +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index bfa3017cecba..cf308b73edae 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_RCMM12 BIT_ULL(RC_PROTO_RCMM12) ++#define RC_PROTO_BIT_RCMM24 BIT_ULL(RC_PROTO_RCMM24) ++#define RC_PROTO_BIT_RCMM32 BIT_ULL(RC_PROTO_RCMM32) + + #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_RCMM12 | \ ++ RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32) + /* 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_RCMM12 | RC_PROTO_BIT_RCMM24 | \ ++ RC_PROTO_BIT_RCMM32) + + #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_RCMM12 | RC_PROTO_BIT_RCMM24 | \ ++ RC_PROTO_BIT_RCMM32) + + #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..45fcbf99d72e 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_RCMM12: RC-MM protocol 12 bits ++ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits ++ * @RC_PROTO_RCMM32: RC-MM protocol 32 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_RCMM12 = 24, ++ RC_PROTO_RCMM24 = 25, ++ RC_PROTO_RCMM32 = 26, + }; + + #endif +diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h +index f189931042a7..45fcbf99d72e 100644 +--- a/tools/include/uapi/linux/lirc.h ++++ b/tools/include/uapi/linux/lirc.h +@@ -133,6 +133,12 @@ + + #define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) + ++/* ++ * Return the recording timeout, which is either set by ++ * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols. ++ */ ++#define LIRC_GET_REC_TIMEOUT _IOR('i', 0x00000024, __u32) ++ + /* + * struct lirc_scancode - decoded scancode with protocol for use with + * LIRC_MODE_SCANCODE +@@ -186,6 +192,9 @@ struct lirc_scancode { + * @RC_PROTO_XMP: XMP protocol + * @RC_PROTO_CEC: CEC protocol + * @RC_PROTO_IMON: iMon Pad protocol ++ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits ++ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits ++ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits + */ + enum rc_proto { + RC_PROTO_UNKNOWN = 0, +@@ -212,6 +221,9 @@ enum rc_proto { + RC_PROTO_XMP = 21, + RC_PROTO_CEC = 22, + RC_PROTO_IMON = 23, ++ RC_PROTO_RCMM12 = 24, ++ RC_PROTO_RCMM24 = 25, ++ RC_PROTO_RCMM32 = 26, + }; + + #endif +-- +2.20.1 + diff --git a/packages/linux/patches/raspberrypi/linux-903-backport-rcmm-ir-decoder.patch b/packages/linux/patches/raspberrypi/linux-903-backport-rcmm-ir-decoder.patch new file mode 100644 index 0000000000..ae2cba8494 --- /dev/null +++ b/packages/linux/patches/raspberrypi/linux-903-backport-rcmm-ir-decoder.patch @@ -0,0 +1,506 @@ +From da8a71104dda4a85a9d9546ff462542347f8efa6 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Wed, 20 Mar 2019 09:11:53 +0100 +Subject: [PATCH] media: rc: rcmm decoder and encoder + +commit 721074b03411327e7bf41555d4cc7c18f49313f7 upstream. + +media: add support for RCMM infrared remote controls. + +Signed-off-by: Patrick Lerda +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Matthias Reichl +--- + Documentation/media/lirc.h.rst.exceptions | 3 + + MAINTAINERS | 5 + + drivers/media/rc/Kconfig | 13 ++ + drivers/media/rc/Makefile | 1 + + drivers/media/rc/ir-rcmm-decoder.c | 254 ++++++++++++++++++++++ + 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 | 12 + + 10 files changed, 319 insertions(+), 3 deletions(-) + create mode 100644 drivers/media/rc/ir-rcmm-decoder.c + +diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions +index 984b61dc3f2e..e7a41d4b3d46 100644 +--- a/Documentation/media/lirc.h.rst.exceptions ++++ b/Documentation/media/lirc.h.rst.exceptions +@@ -58,6 +58,9 @@ ignore symbol RC_PROTO_SHARP + ignore symbol RC_PROTO_XMP + ignore symbol RC_PROTO_CEC + ignore symbol RC_PROTO_IMON ++ignore symbol RC_PROTO_RCMM12 ++ignore symbol RC_PROTO_RCMM24 ++ignore symbol RC_PROTO_RCMM32 + + # Undocumented macros + +diff --git a/MAINTAINERS b/MAINTAINERS +index 9e9b19ecf6f7..57b60dd42729 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15837,6 +15837,11 @@ M: David Härdeman + S: Maintained + F: drivers/media/rc/winbond-cir.c + ++RCMM REMOTE CONTROLS DECODER ++M: Patrick Lerda ++S: Maintained ++F: drivers/media/rc/ir-rcmm-decoder.c ++ + WINSYSTEMS EBC-C384 WATCHDOG DRIVER + M: William Breathitt Gray + L: linux-watchdog@vger.kernel.org +diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig +index 1021c08a9ba4..8164a889011a 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 12, ++ 24 and 32 bits RC-MM variants. You can enable or disable the ++ different modes using the following RC protocol keywords: ++ 'rc-mm-12', 'rc-mm-24' and 'rc-mm-32'. ++ ++ 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 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..f1096ac1e5c5 +--- /dev/null ++++ b/drivers/media/rc/ir-rcmm-decoder.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol ++// ++// Copyright (C) 2018 by Patrick Lerda ++ ++#include "rc-core-priv.h" ++#include ++#include ++ ++#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; ++ } ++ ++ return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); ++} ++ ++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, ++ .min_timeout = RCMM_PULSE_3 + RCMM_UNIT, ++}; ++ ++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 e847bdad5c51..59c252f24194 100644 +--- a/drivers/media/rc/rc-core-priv.h ++++ b/drivers/media/rc/rc-core-priv.h +@@ -136,6 +136,11 @@ struct ir_raw_event_ctrl { + struct input_dev *idev; + char name[64]; + } 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 0f218afdadaa..78e79c37f208 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_RCMM12] = { .name = "rc-mm-12", ++ .scancode_bits = 0x00000fff, .repeat_period = 114 }, ++ [RC_PROTO_RCMM24] = { .name = "rc-mm-24", ++ .scancode_bits = 0x00ffffff, .repeat_period = 114 }, ++ [RC_PROTO_RCMM32] = { .name = "rc-mm-32", ++ .scancode_bits = 0xffffffff, .repeat_period = 114 }, + }; + + /* Used to keep track of known keymaps */ +@@ -1018,6 +1024,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_RCMM12 | ++ RC_PROTO_BIT_RCMM24 | ++ RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, + }; + + /** +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index bfa3017cecba..cf308b73edae 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_RCMM12 BIT_ULL(RC_PROTO_RCMM12) ++#define RC_PROTO_BIT_RCMM24 BIT_ULL(RC_PROTO_RCMM24) ++#define RC_PROTO_BIT_RCMM32 BIT_ULL(RC_PROTO_RCMM32) + + #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_RCMM12 | \ ++ RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32) + /* 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_RCMM12 | RC_PROTO_BIT_RCMM24 | \ ++ RC_PROTO_BIT_RCMM32) + + #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_RCMM12 | RC_PROTO_BIT_RCMM24 | \ ++ RC_PROTO_BIT_RCMM32) + + #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..45fcbf99d72e 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_RCMM12: RC-MM protocol 12 bits ++ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits ++ * @RC_PROTO_RCMM32: RC-MM protocol 32 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_RCMM12 = 24, ++ RC_PROTO_RCMM24 = 25, ++ RC_PROTO_RCMM32 = 26, + }; + + #endif +diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h +index f189931042a7..45fcbf99d72e 100644 +--- a/tools/include/uapi/linux/lirc.h ++++ b/tools/include/uapi/linux/lirc.h +@@ -133,6 +133,12 @@ + + #define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) + ++/* ++ * Return the recording timeout, which is either set by ++ * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols. ++ */ ++#define LIRC_GET_REC_TIMEOUT _IOR('i', 0x00000024, __u32) ++ + /* + * struct lirc_scancode - decoded scancode with protocol for use with + * LIRC_MODE_SCANCODE +@@ -186,6 +192,9 @@ struct lirc_scancode { + * @RC_PROTO_XMP: XMP protocol + * @RC_PROTO_CEC: CEC protocol + * @RC_PROTO_IMON: iMon Pad protocol ++ * @RC_PROTO_RCMM12: RC-MM protocol 12 bits ++ * @RC_PROTO_RCMM24: RC-MM protocol 24 bits ++ * @RC_PROTO_RCMM32: RC-MM protocol 32 bits + */ + enum rc_proto { + RC_PROTO_UNKNOWN = 0, +@@ -212,6 +221,9 @@ enum rc_proto { + RC_PROTO_XMP = 21, + RC_PROTO_CEC = 22, + RC_PROTO_IMON = 23, ++ RC_PROTO_RCMM12 = 24, ++ RC_PROTO_RCMM24 = 25, ++ RC_PROTO_RCMM32 = 26, + }; + + #endif +-- +2.20.1 +