1 // SPDX-License-Identifier: GPL-2.0+
2 // ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
4 // Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr>
6 #include "rc-core-priv.h"
7 #include <linux/module.h>
9 #define RCMM_UNIT 166 /* microseconds */
10 #define RCMM_PREFIX_PULSE 417 /* 166.666666666666*2.5 */
11 #define RCMM_PULSE_0 278 /* 166.666666666666*(1+2/3) */
12 #define RCMM_PULSE_1 444 /* 166.666666666666*(2+2/3) */
13 #define RCMM_PULSE_2 611 /* 166.666666666666*(3+2/3) */
14 #define RCMM_PULSE_3 778 /* 166.666666666666*(4+2/3) */
24 static bool rcmm_mode(const struct rcmm_dec
*data
)
26 return !((0x000c0000 & data
->bits
) == 0x000c0000);
29 static int rcmm_miscmode(struct rc_dev
*dev
, struct rcmm_dec
*data
)
31 switch (data
->count
) {
33 if (dev
->enabled_protocols
& RC_PROTO_BIT_RCMM24
) {
34 rc_keydown(dev
, RC_PROTO_RCMM24
, data
->bits
, 0);
35 data
->state
= STATE_INACTIVE
;
41 if (dev
->enabled_protocols
& RC_PROTO_BIT_RCMM12
) {
42 rc_keydown(dev
, RC_PROTO_RCMM12
, data
->bits
, 0);
43 data
->state
= STATE_INACTIVE
;
53 * ir_rcmm_decode() - Decode one RCMM pulse or space
54 * @dev: the struct rc_dev descriptor of the device
55 * @ev: the struct ir_raw_event descriptor of the pulse/space
57 * This function returns -EINVAL if the pulse violates the state machine
59 static int ir_rcmm_decode(struct rc_dev
*dev
, struct ir_raw_event ev
)
61 struct rcmm_dec
*data
= &dev
->raw
->rcmm
;
66 if (!(dev
->enabled_protocols
& (RC_PROTO_BIT_RCMM32
|
68 RC_PROTO_BIT_RCMM12
)))
71 if (!is_timing_event(ev
)) {
73 data
->state
= STATE_INACTIVE
;
77 switch (data
->state
) {
82 if (!eq_margin(ev
.duration
, RCMM_PREFIX_PULSE
, RCMM_UNIT
))
85 data
->state
= STATE_LOW
;
94 if (!eq_margin(ev
.duration
, RCMM_PULSE_0
, RCMM_UNIT
))
97 data
->state
= STATE_BUMP
;
104 if (!eq_margin(ev
.duration
, RCMM_UNIT
, RCMM_UNIT
/ 2))
107 data
->state
= STATE_VALUE
;
114 if (eq_margin(ev
.duration
, RCMM_PULSE_0
, RCMM_UNIT
/ 2))
116 else if (eq_margin(ev
.duration
, RCMM_PULSE_1
, RCMM_UNIT
/ 2))
118 else if (eq_margin(ev
.duration
, RCMM_PULSE_2
, RCMM_UNIT
/ 2))
120 else if (eq_margin(ev
.duration
, RCMM_PULSE_3
, RCMM_UNIT
/ 2))
126 if (!rcmm_miscmode(dev
, data
))
136 if (data
->count
< 32)
137 data
->state
= STATE_BUMP
;
139 data
->state
= STATE_FINISHED
;
147 if (!eq_margin(ev
.duration
, RCMM_UNIT
, RCMM_UNIT
/ 2))
150 if (rcmm_mode(data
)) {
151 toggle
= !!(0x8000 & data
->bits
);
152 scancode
= data
->bits
& ~0x8000;
155 scancode
= data
->bits
;
158 if (dev
->enabled_protocols
& RC_PROTO_BIT_RCMM32
) {
159 rc_keydown(dev
, RC_PROTO_RCMM32
, scancode
, toggle
);
160 data
->state
= STATE_INACTIVE
;
167 dev_dbg(&dev
->dev
, "RC-MM decode failed at count %d state %d (%uus %s)\n",
168 data
->count
, data
->state
, ev
.duration
, TO_STR(ev
.pulse
));
169 data
->state
= STATE_INACTIVE
;
173 static const int rcmmspace
[] = {
180 static int ir_rcmm_rawencoder(struct ir_raw_event
**ev
, unsigned int max
,
181 unsigned int n
, u32 data
)
186 ret
= ir_raw_gen_pulse_space(ev
, &max
, RCMM_PREFIX_PULSE
, RCMM_PULSE_0
);
190 for (i
= n
- 2; i
>= 0; i
-= 2) {
191 const unsigned int space
= rcmmspace
[(data
>> i
) & 3];
193 ret
= ir_raw_gen_pulse_space(ev
, &max
, RCMM_UNIT
, space
);
198 return ir_raw_gen_pulse_space(ev
, &max
, RCMM_UNIT
, RCMM_PULSE_3
* 2);
201 static int ir_rcmm_encode(enum rc_proto protocol
, u32 scancode
,
202 struct ir_raw_event
*events
, unsigned int max
)
204 struct ir_raw_event
*e
= events
;
208 case RC_PROTO_RCMM32
:
209 ret
= ir_rcmm_rawencoder(&e
, max
, 32, scancode
);
211 case RC_PROTO_RCMM24
:
212 ret
= ir_rcmm_rawencoder(&e
, max
, 24, scancode
);
214 case RC_PROTO_RCMM12
:
215 ret
= ir_rcmm_rawencoder(&e
, max
, 12, scancode
);
227 static struct ir_raw_handler rcmm_handler
= {
228 .protocols
= RC_PROTO_BIT_RCMM32
|
229 RC_PROTO_BIT_RCMM24
|
231 .decode
= ir_rcmm_decode
,
232 .encode
= ir_rcmm_encode
,
234 .min_timeout
= RCMM_PULSE_3
+ RCMM_UNIT
,
237 static int __init
ir_rcmm_decode_init(void)
239 ir_raw_handler_register(&rcmm_handler
);
241 pr_info("IR RCMM protocol handler initialized\n");
245 static void __exit
ir_rcmm_decode_exit(void)
247 ir_raw_handler_unregister(&rcmm_handler
);
250 module_init(ir_rcmm_decode_init
);
251 module_exit(ir_rcmm_decode_exit
);
253 MODULE_LICENSE("GPL");
254 MODULE_AUTHOR("Patrick Lerda");
255 MODULE_DESCRIPTION("RCMM IR protocol decoder");