1 // SPDX-License-Identifier: GPL-2.0+
2 // ir-imon-decoder.c - handle iMon protocol
3 //
4 // Copyright (C) 2018 by Sean Young <sean@mess.org>
5 
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 
8 #include <linux/module.h>
9 #include "rc-core-priv.h"
10 
11 #define IMON_UNIT		415662 /* ns */
12 #define IMON_BITS		30
13 #define IMON_CHKBITS		(BIT(30) | BIT(25) | BIT(24) | BIT(22) | \
14 				 BIT(21) | BIT(20) | BIT(19) | BIT(18) | \
15 				 BIT(17) | BIT(16) | BIT(14) | BIT(13) | \
16 				 BIT(12) | BIT(11) | BIT(10) | BIT(9))
17 
18 /*
19  * This protocol has 30 bits. The format is one IMON_UNIT header pulse,
20  * followed by 30 bits. Each bit is one IMON_UNIT check field, and then
21  * one IMON_UNIT field with the actual bit (1=space, 0=pulse).
22  * The check field is always space for some bits, for others it is pulse if
23  * both the preceding and current bit are zero, else space. IMON_CHKBITS
24  * defines which bits are of type check.
25  *
26  * There is no way to distinguish an incomplete message from one where
27  * the lower bits are all set, iow. the last pulse is for the lowest
28  * bit which is 0.
29  */
30 enum imon_state {
31 	STATE_INACTIVE,
32 	STATE_BIT_CHK,
33 	STATE_BIT_START,
34 	STATE_FINISHED
35 };
36 
37 /**
38  * ir_imon_decode() - Decode one iMON pulse or space
39  * @dev:	the struct rc_dev descriptor of the device
40  * @ev:		the struct ir_raw_event descriptor of the pulse/space
41  *
42  * This function returns -EINVAL if the pulse violates the state machine
43  */
44 static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
45 {
46 	struct imon_dec *data = &dev->raw->imon;
47 
48 	if (!is_timing_event(ev)) {
49 		if (ev.reset)
50 			data->state = STATE_INACTIVE;
51 		return 0;
52 	}
53 
54 	dev_dbg(&dev->dev,
55 		"iMON decode started at state %d bitno %d (%uus %s)\n",
56 		data->state, data->count, TO_US(ev.duration),
57 		TO_STR(ev.pulse));
58 
59 	for (;;) {
60 		if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2))
61 			return 0;
62 
63 		decrease_duration(&ev, IMON_UNIT);
64 
65 		switch (data->state) {
66 		case STATE_INACTIVE:
67 			if (ev.pulse) {
68 				data->state = STATE_BIT_CHK;
69 				data->bits = 0;
70 				data->count = IMON_BITS;
71 			}
72 			break;
73 		case STATE_BIT_CHK:
74 			if (IMON_CHKBITS & BIT(data->count))
75 				data->last_chk = ev.pulse;
76 			else if (ev.pulse)
77 				goto err_out;
78 			data->state = STATE_BIT_START;
79 			break;
80 		case STATE_BIT_START:
81 			data->bits <<= 1;
82 			if (!ev.pulse)
83 				data->bits |= 1;
84 
85 			if (IMON_CHKBITS & BIT(data->count)) {
86 				if (data->last_chk != !(data->bits & 3))
87 					goto err_out;
88 			}
89 
90 			if (!data->count--)
91 				data->state = STATE_FINISHED;
92 			else
93 				data->state = STATE_BIT_CHK;
94 			break;
95 		case STATE_FINISHED:
96 			if (ev.pulse)
97 				goto err_out;
98 			rc_keydown(dev, RC_PROTO_IMON, data->bits, 0);
99 			data->state = STATE_INACTIVE;
100 			break;
101 		}
102 	}
103 
104 err_out:
105 	dev_dbg(&dev->dev,
106 		"iMON decode failed at state %d bitno %d (%uus %s)\n",
107 		data->state, data->count, TO_US(ev.duration),
108 		TO_STR(ev.pulse));
109 
110 	data->state = STATE_INACTIVE;
111 
112 	return -EINVAL;
113 }
114 
115 /**
116  * ir_imon_encode() - Encode a scancode as a stream of raw events
117  *
118  * @protocol:	protocol to encode
119  * @scancode:	scancode to encode
120  * @events:	array of raw ir events to write into
121  * @max:	maximum size of @events
122  *
123  * Returns:	The number of events written.
124  *		-ENOBUFS if there isn't enough space in the array to fit the
125  *		encoding. In this case all @max events will have been written.
126  */
127 static int ir_imon_encode(enum rc_proto protocol, u32 scancode,
128 			  struct ir_raw_event *events, unsigned int max)
129 {
130 	struct ir_raw_event *e = events;
131 	int i, pulse;
132 
133 	if (!max--)
134 		return -ENOBUFS;
135 	init_ir_raw_event_duration(e, 1, IMON_UNIT);
136 
137 	for (i = IMON_BITS; i >= 0; i--) {
138 		if (BIT(i) & IMON_CHKBITS)
139 			pulse = !(scancode & (BIT(i) | BIT(i + 1)));
140 		else
141 			pulse = 0;
142 
143 		if (pulse == e->pulse) {
144 			e->duration += IMON_UNIT;
145 		} else {
146 			if (!max--)
147 				return -ENOBUFS;
148 			init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
149 		}
150 
151 		pulse = !(scancode & BIT(i));
152 
153 		if (pulse == e->pulse) {
154 			e->duration += IMON_UNIT;
155 		} else {
156 			if (!max--)
157 				return -ENOBUFS;
158 			init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
159 		}
160 	}
161 
162 	if (e->pulse)
163 		e++;
164 
165 	return e - events;
166 }
167 
168 static struct ir_raw_handler imon_handler = {
169 	.protocols	= RC_PROTO_BIT_IMON,
170 	.decode		= ir_imon_decode,
171 	.encode		= ir_imon_encode,
172 	.carrier	= 38000,
173 };
174 
175 static int __init ir_imon_decode_init(void)
176 {
177 	ir_raw_handler_register(&imon_handler);
178 
179 	pr_info("IR iMON protocol handler initialized\n");
180 	return 0;
181 }
182 
183 static void __exit ir_imon_decode_exit(void)
184 {
185 	ir_raw_handler_unregister(&imon_handler);
186 }
187 
188 module_init(ir_imon_decode_init);
189 module_exit(ir_imon_decode_exit);
190 
191 MODULE_LICENSE("GPL");
192 MODULE_AUTHOR("Sean Young <sean@mess.org>");
193 MODULE_DESCRIPTION("iMON IR protocol decoder");
194