Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: rc: rcmm decoder and encoder

media: add support for RCMM infrared remote controls.

Signed-off-by: Patrick Lerda <patrick9876@free.fr>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>

authored by

Patrick Lerda and committed by
Mauro Carvalho Chehab
721074b0 12aceee1

+328 -3
+3
Documentation/media/lirc.h.rst.exceptions
··· 60 60 ignore symbol RC_PROTO_XMP 61 61 ignore symbol RC_PROTO_CEC 62 62 ignore symbol RC_PROTO_IMON 63 + ignore symbol RC_PROTO_RCMM12 64 + ignore symbol RC_PROTO_RCMM24 65 + ignore symbol RC_PROTO_RCMM32 63 66 64 67 # Undocumented macros 65 68
+5
MAINTAINERS
··· 16536 16536 S: Maintained 16537 16537 F: drivers/media/rc/winbond-cir.c 16538 16538 16539 + RCMM REMOTE CONTROLS DECODER 16540 + M: Patrick Lerda <patrick9876@free.fr> 16541 + S: Maintained 16542 + F: drivers/media/rc/ir-rcmm-decoder.c 16543 + 16539 16544 WINSYSTEMS EBC-C384 WATCHDOG DRIVER 16540 16545 M: William Breathitt Gray <vilhelm.gray@gmail.com> 16541 16546 L: linux-watchdog@vger.kernel.org
+13
drivers/media/rc/Kconfig
··· 133 133 remote control and you would like to use it with a raw IR 134 134 receiver, or if you wish to use an encoder to transmit this IR. 135 135 136 + config IR_RCMM_DECODER 137 + tristate "Enable IR raw decoder for the RC-MM protocol" 138 + depends on RC_CORE 139 + help 140 + Enable this option when you have IR with RC-MM protocol, and 141 + you need the software decoder. The driver supports 12, 142 + 24 and 32 bits RC-MM variants. You can enable or disable the 143 + different modes using the following RC protocol keywords: 144 + 'rc-mm-12', 'rc-mm-24' and 'rc-mm-32'. 145 + 146 + To compile this driver as a module, choose M here: the module 147 + will be called ir-rcmm-decoder. 148 + 136 149 endif #RC_DECODERS 137 150 138 151 menuconfig RC_DEVICES
+1
drivers/media/rc/Makefile
··· 16 16 obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o 17 17 obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o 18 18 obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o 19 + obj-$(CONFIG_IR_RCMM_DECODER) += ir-rcmm-decoder.o 19 20 20 21 # stand-alone IR receivers/transmitters 21 22 obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
+254
drivers/media/rc/ir-rcmm-decoder.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + // ir-rcmm-decoder.c - A decoder for the RCMM IR protocol 3 + // 4 + // Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr> 5 + 6 + #include "rc-core-priv.h" 7 + #include <linux/module.h> 8 + #include <linux/version.h> 9 + 10 + #define RCMM_UNIT 166667 /* nanosecs */ 11 + #define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */ 12 + #define RCMM_PULSE_0 277777 /* 166666.666666666*(1+2/3) */ 13 + #define RCMM_PULSE_1 444444 /* 166666.666666666*(2+2/3) */ 14 + #define RCMM_PULSE_2 611111 /* 166666.666666666*(3+2/3) */ 15 + #define RCMM_PULSE_3 777778 /* 166666.666666666*(4+2/3) */ 16 + 17 + enum rcmm_state { 18 + STATE_INACTIVE, 19 + STATE_LOW, 20 + STATE_BUMP, 21 + STATE_VALUE, 22 + STATE_FINISHED, 23 + }; 24 + 25 + static bool rcmm_mode(const struct rcmm_dec *data) 26 + { 27 + return !((0x000c0000 & data->bits) == 0x000c0000); 28 + } 29 + 30 + static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data) 31 + { 32 + switch (data->count) { 33 + case 24: 34 + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) { 35 + rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0); 36 + data->state = STATE_INACTIVE; 37 + return 0; 38 + } 39 + return -1; 40 + 41 + case 12: 42 + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) { 43 + rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0); 44 + data->state = STATE_INACTIVE; 45 + return 0; 46 + } 47 + return -1; 48 + } 49 + 50 + return -1; 51 + } 52 + 53 + /** 54 + * ir_rcmm_decode() - Decode one RCMM pulse or space 55 + * @dev: the struct rc_dev descriptor of the device 56 + * @ev: the struct ir_raw_event descriptor of the pulse/space 57 + * 58 + * This function returns -EINVAL if the pulse violates the state machine 59 + */ 60 + static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) 61 + { 62 + struct rcmm_dec *data = &dev->raw->rcmm; 63 + u32 scancode; 64 + u8 toggle; 65 + int value; 66 + 67 + if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 | 68 + RC_PROTO_BIT_RCMM24 | 69 + RC_PROTO_BIT_RCMM12))) 70 + return 0; 71 + 72 + if (!is_timing_event(ev)) { 73 + if (ev.reset) 74 + data->state = STATE_INACTIVE; 75 + return 0; 76 + } 77 + 78 + switch (data->state) { 79 + case STATE_INACTIVE: 80 + if (!ev.pulse) 81 + break; 82 + 83 + if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2)) 84 + break; 85 + 86 + data->state = STATE_LOW; 87 + data->count = 0; 88 + data->bits = 0; 89 + return 0; 90 + 91 + case STATE_LOW: 92 + if (ev.pulse) 93 + break; 94 + 95 + if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) 96 + break; 97 + 98 + data->state = STATE_BUMP; 99 + return 0; 100 + 101 + case STATE_BUMP: 102 + if (!ev.pulse) 103 + break; 104 + 105 + if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) 106 + break; 107 + 108 + data->state = STATE_VALUE; 109 + return 0; 110 + 111 + case STATE_VALUE: 112 + if (ev.pulse) 113 + break; 114 + 115 + if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) 116 + value = 0; 117 + else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2)) 118 + value = 1; 119 + else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2)) 120 + value = 2; 121 + else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2)) 122 + value = 3; 123 + else 124 + value = -1; 125 + 126 + if (value == -1) { 127 + if (!rcmm_miscmode(dev, data)) 128 + return 0; 129 + break; 130 + } 131 + 132 + data->bits <<= 2; 133 + data->bits |= value; 134 + 135 + data->count += 2; 136 + 137 + if (data->count < 32) 138 + data->state = STATE_BUMP; 139 + else 140 + data->state = STATE_FINISHED; 141 + 142 + return 0; 143 + 144 + case STATE_FINISHED: 145 + if (!ev.pulse) 146 + break; 147 + 148 + if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) 149 + break; 150 + 151 + if (rcmm_mode(data)) { 152 + toggle = !!(0x8000 & data->bits); 153 + scancode = data->bits & ~0x8000; 154 + } else { 155 + toggle = 0; 156 + scancode = data->bits; 157 + } 158 + 159 + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) { 160 + rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle); 161 + data->state = STATE_INACTIVE; 162 + return 0; 163 + } 164 + 165 + break; 166 + } 167 + 168 + data->state = STATE_INACTIVE; 169 + return -EINVAL; 170 + } 171 + 172 + static const int rcmmspace[] = { 173 + RCMM_PULSE_0, 174 + RCMM_PULSE_1, 175 + RCMM_PULSE_2, 176 + RCMM_PULSE_3, 177 + }; 178 + 179 + static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max, 180 + unsigned int n, u32 data) 181 + { 182 + int i; 183 + int ret; 184 + 185 + ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0); 186 + if (ret) 187 + return ret; 188 + 189 + for (i = n - 2; i >= 0; i -= 2) { 190 + const unsigned int space = rcmmspace[(data >> i) & 3]; 191 + 192 + ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space); 193 + if (ret) 194 + return ret; 195 + } 196 + 197 + return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); 198 + } 199 + 200 + static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode, 201 + struct ir_raw_event *events, unsigned int max) 202 + { 203 + struct ir_raw_event *e = events; 204 + int ret; 205 + 206 + switch (protocol) { 207 + case RC_PROTO_RCMM32: 208 + ret = ir_rcmm_rawencoder(&e, max, 32, scancode); 209 + break; 210 + case RC_PROTO_RCMM24: 211 + ret = ir_rcmm_rawencoder(&e, max, 24, scancode); 212 + break; 213 + case RC_PROTO_RCMM12: 214 + ret = ir_rcmm_rawencoder(&e, max, 12, scancode); 215 + break; 216 + default: 217 + ret = -EINVAL; 218 + } 219 + 220 + if (ret < 0) 221 + return ret; 222 + 223 + return e - events; 224 + } 225 + 226 + static struct ir_raw_handler rcmm_handler = { 227 + .protocols = RC_PROTO_BIT_RCMM32 | 228 + RC_PROTO_BIT_RCMM24 | 229 + RC_PROTO_BIT_RCMM12, 230 + .decode = ir_rcmm_decode, 231 + .encode = ir_rcmm_encode, 232 + .carrier = 36000, 233 + .min_timeout = RCMM_PULSE_3 + RCMM_UNIT, 234 + }; 235 + 236 + static int __init ir_rcmm_decode_init(void) 237 + { 238 + ir_raw_handler_register(&rcmm_handler); 239 + 240 + pr_info("IR RCMM protocol handler initialized\n"); 241 + return 0; 242 + } 243 + 244 + static void __exit ir_rcmm_decode_exit(void) 245 + { 246 + ir_raw_handler_unregister(&rcmm_handler); 247 + } 248 + 249 + module_init(ir_rcmm_decode_init); 250 + module_exit(ir_rcmm_decode_exit); 251 + 252 + MODULE_LICENSE("GPL"); 253 + MODULE_AUTHOR("Patrick Lerda"); 254 + MODULE_DESCRIPTION("RCMM IR protocol decoder");
+5
drivers/media/rc/rc-core-priv.h
··· 131 131 unsigned int bits; 132 132 bool stick_keyboard; 133 133 } imon; 134 + struct rcmm_dec { 135 + int state; 136 + unsigned int count; 137 + u32 bits; 138 + } rcmm; 134 139 }; 135 140 136 141 /* Mutex for locking raw IR processing and handler change */
+9
drivers/media/rc/rc-main.c
··· 70 70 [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 }, 71 71 [RC_PROTO_IMON] = { .name = "imon", 72 72 .scancode_bits = 0x7fffffff, .repeat_period = 114 }, 73 + [RC_PROTO_RCMM12] = { .name = "rc-mm-12", 74 + .scancode_bits = 0x00000fff, .repeat_period = 114 }, 75 + [RC_PROTO_RCMM24] = { .name = "rc-mm-24", 76 + .scancode_bits = 0x00ffffff, .repeat_period = 114 }, 77 + [RC_PROTO_RCMM32] = { .name = "rc-mm-32", 78 + .scancode_bits = 0xffffffff, .repeat_period = 114 }, 73 79 }; 74 80 75 81 /* Used to keep track of known keymaps */ ··· 1012 1006 { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, 1013 1007 { RC_PROTO_BIT_CEC, "cec", NULL }, 1014 1008 { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" }, 1009 + { RC_PROTO_BIT_RCMM12 | 1010 + RC_PROTO_BIT_RCMM24 | 1011 + RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, 1015 1012 }; 1016 1013 1017 1014 /**
+11 -3
include/media/rc-map.h
··· 37 37 #define RC_PROTO_BIT_XMP BIT_ULL(RC_PROTO_XMP) 38 38 #define RC_PROTO_BIT_CEC BIT_ULL(RC_PROTO_CEC) 39 39 #define RC_PROTO_BIT_IMON BIT_ULL(RC_PROTO_IMON) 40 + #define RC_PROTO_BIT_RCMM12 BIT_ULL(RC_PROTO_RCMM12) 41 + #define RC_PROTO_BIT_RCMM24 BIT_ULL(RC_PROTO_RCMM24) 42 + #define RC_PROTO_BIT_RCMM32 BIT_ULL(RC_PROTO_RCMM32) 40 43 41 44 #define RC_PROTO_BIT_ALL \ 42 45 (RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \ ··· 54 51 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ 55 52 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ 56 53 RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \ 57 - RC_PROTO_BIT_IMON) 54 + RC_PROTO_BIT_IMON | RC_PROTO_BIT_RCMM12 | \ 55 + RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32) 58 56 /* All rc protocols for which we have decoders */ 59 57 #define RC_PROTO_BIT_ALL_IR_DECODER \ 60 58 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ ··· 68 64 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ 69 65 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ 70 66 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ 71 - RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON) 67 + RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON | \ 68 + RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | \ 69 + RC_PROTO_BIT_RCMM32) 72 70 73 71 #define RC_PROTO_BIT_ALL_IR_ENCODER \ 74 72 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ ··· 83 77 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ 84 78 RC_PROTO_BIT_RC6_6A_24 | \ 85 79 RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \ 86 - RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON) 80 + RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON | \ 81 + RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | \ 82 + RC_PROTO_BIT_RCMM32) 87 83 88 84 #define RC_SCANCODE_UNKNOWN(x) (x) 89 85 #define RC_SCANCODE_OTHER(x) (x)
+6
include/uapi/linux/lirc.h
··· 192 192 * @RC_PROTO_XMP: XMP protocol 193 193 * @RC_PROTO_CEC: CEC protocol 194 194 * @RC_PROTO_IMON: iMon Pad protocol 195 + * @RC_PROTO_RCMM12: RC-MM protocol 12 bits 196 + * @RC_PROTO_RCMM24: RC-MM protocol 24 bits 197 + * @RC_PROTO_RCMM32: RC-MM protocol 32 bits 195 198 */ 196 199 enum rc_proto { 197 200 RC_PROTO_UNKNOWN = 0, ··· 221 218 RC_PROTO_XMP = 21, 222 219 RC_PROTO_CEC = 22, 223 220 RC_PROTO_IMON = 23, 221 + RC_PROTO_RCMM12 = 24, 222 + RC_PROTO_RCMM24 = 25, 223 + RC_PROTO_RCMM32 = 26, 224 224 }; 225 225 226 226 #endif
+12
tools/include/uapi/linux/lirc.h
··· 134 134 #define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) 135 135 136 136 /* 137 + * Return the recording timeout, which is either set by 138 + * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols. 139 + */ 140 + #define LIRC_GET_REC_TIMEOUT _IOR('i', 0x00000024, __u32) 141 + 142 + /* 137 143 * struct lirc_scancode - decoded scancode with protocol for use with 138 144 * LIRC_MODE_SCANCODE 139 145 * ··· 192 186 * @RC_PROTO_XMP: XMP protocol 193 187 * @RC_PROTO_CEC: CEC protocol 194 188 * @RC_PROTO_IMON: iMon Pad protocol 189 + * @RC_PROTO_RCMM12: RC-MM protocol 12 bits 190 + * @RC_PROTO_RCMM24: RC-MM protocol 24 bits 191 + * @RC_PROTO_RCMM32: RC-MM protocol 32 bits 195 192 */ 196 193 enum rc_proto { 197 194 RC_PROTO_UNKNOWN = 0, ··· 221 212 RC_PROTO_XMP = 21, 222 213 RC_PROTO_CEC = 22, 223 214 RC_PROTO_IMON = 23, 215 + RC_PROTO_RCMM12 = 24, 216 + RC_PROTO_RCMM24 = 25, 217 + RC_PROTO_RCMM32 = 26, 224 218 }; 225 219 226 220 #endif
+9
tools/testing/selftests/ir/ir_loopback.c
··· 51 51 { RC_PROTO_RC6_6A_32, "rc-6-6a-32", 0xffffffff, "rc-6" }, 52 52 { RC_PROTO_RC6_MCE, "rc-6-mce", 0x00007fff, "rc-6" }, 53 53 { RC_PROTO_SHARP, "sharp", 0x1fff, "sharp" }, 54 + { RC_PROTO_IMON, "imon", 0x7fffffff, "imon" }, 55 + { RC_PROTO_RCMM12, "rcmm-12", 0x00000fff, "rcmm" }, 56 + { RC_PROTO_RCMM24, "rcmm-24", 0x00ffffff, "rcmm" }, 57 + { RC_PROTO_RCMM32, "rcmm-32", 0xffffffff, "rcmm" }, 54 58 }; 55 59 56 60 int lirc_open(const char *rc) ··· 141 137 142 138 if (rc_proto == RC_PROTO_NEC32 && 143 139 (((scancode >> 8) ^ ~scancode) & 0xff) == 0) 140 + continue; 141 + 142 + if (rc_proto == RC_PROTO_RCMM32 && 143 + (scancode & 0x000c0000) != 0x000c0000 && 144 + scancode & 0x00008000) 144 145 continue; 145 146 146 147 struct lirc_scancode lsc = {