1 // SPDX-License-Identifier: GPL-2.0
2 // ir-nec-decoder.c - handle NEC IR Pulse/Space protocol
4 // Copyright (C) 2010 by Mauro Carvalho Chehab
6 #include <linux/bitrev.h>
7 #include <linux/module.h>
8 #include "rc-core-priv.h"
11 #define NEC_UNIT 563 /* us */
12 #define NEC_HEADER_PULSE (16 * NEC_UNIT)
13 #define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */
14 #define NEC_HEADER_SPACE (8 * NEC_UNIT)
15 #define NEC_REPEAT_SPACE (4 * NEC_UNIT)
16 #define NEC_BIT_PULSE (1 * NEC_UNIT)
17 #define NEC_BIT_0_SPACE (1 * NEC_UNIT)
18 #define NEC_BIT_1_SPACE (3 * NEC_UNIT)
19 #define NEC_TRAILER_PULSE (1 * NEC_UNIT)
20 #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */
21 #define NECX_REPEAT_BITS 1
33 * ir_nec_decode() - Decode one NEC pulse or space
34 * @dev: the struct rc_dev descriptor of the device
35 * @ev: the struct ir_raw_event descriptor of the pulse/space
37 * This function returns -EINVAL if the pulse violates the state machine
39 static int ir_nec_decode(struct rc_dev
*dev
, struct ir_raw_event ev
)
41 struct nec_dec
*data
= &dev
->raw
->nec
;
43 enum rc_proto rc_proto
;
44 u8 address
, not_address
, command
, not_command
;
46 if (!is_timing_event(ev
)) {
48 data
->state
= STATE_INACTIVE
;
52 dev_dbg(&dev
->dev
, "NEC decode started at state %d (%uus %s)\n",
53 data
->state
, ev
.duration
, TO_STR(ev
.pulse
));
55 switch (data
->state
) {
61 if (eq_margin(ev
.duration
, NEC_HEADER_PULSE
, NEC_UNIT
* 2)) {
62 data
->is_nec_x
= false;
63 data
->necx_repeat
= false;
64 } else if (eq_margin(ev
.duration
, NECX_HEADER_PULSE
, NEC_UNIT
/ 2))
65 data
->is_nec_x
= true;
70 data
->state
= STATE_HEADER_SPACE
;
73 case STATE_HEADER_SPACE
:
77 if (eq_margin(ev
.duration
, NEC_HEADER_SPACE
, NEC_UNIT
)) {
78 data
->state
= STATE_BIT_PULSE
;
80 } else if (eq_margin(ev
.duration
, NEC_REPEAT_SPACE
, NEC_UNIT
/ 2)) {
81 data
->state
= STATE_TRAILER_PULSE
;
91 if (!eq_margin(ev
.duration
, NEC_BIT_PULSE
, NEC_UNIT
/ 2))
94 data
->state
= STATE_BIT_SPACE
;
101 if (data
->necx_repeat
&& data
->count
== NECX_REPEAT_BITS
&&
102 geq_margin(ev
.duration
, NEC_TRAILER_SPACE
, NEC_UNIT
/ 2)) {
103 dev_dbg(&dev
->dev
, "Repeat last key\n");
105 data
->state
= STATE_INACTIVE
;
107 } else if (data
->count
> NECX_REPEAT_BITS
)
108 data
->necx_repeat
= false;
111 if (eq_margin(ev
.duration
, NEC_BIT_1_SPACE
, NEC_UNIT
/ 2))
113 else if (!eq_margin(ev
.duration
, NEC_BIT_0_SPACE
, NEC_UNIT
/ 2))
117 if (data
->count
== NEC_NBITS
)
118 data
->state
= STATE_TRAILER_PULSE
;
120 data
->state
= STATE_BIT_PULSE
;
124 case STATE_TRAILER_PULSE
:
128 if (!eq_margin(ev
.duration
, NEC_TRAILER_PULSE
, NEC_UNIT
/ 2))
131 data
->state
= STATE_TRAILER_SPACE
;
134 case STATE_TRAILER_SPACE
:
138 if (!geq_margin(ev
.duration
, NEC_TRAILER_SPACE
, NEC_UNIT
/ 2))
141 if (data
->count
== NEC_NBITS
) {
142 address
= bitrev8((data
->bits
>> 24) & 0xff);
143 not_address
= bitrev8((data
->bits
>> 16) & 0xff);
144 command
= bitrev8((data
->bits
>> 8) & 0xff);
145 not_command
= bitrev8((data
->bits
>> 0) & 0xff);
147 scancode
= ir_nec_bytes_to_scancode(address
,
154 data
->necx_repeat
= true;
156 rc_keydown(dev
, rc_proto
, scancode
, 0);
161 data
->state
= STATE_INACTIVE
;
165 dev_dbg(&dev
->dev
, "NEC decode failed at count %d state %d (%uus %s)\n",
166 data
->count
, data
->state
, ev
.duration
, TO_STR(ev
.pulse
));
167 data
->state
= STATE_INACTIVE
;
172 * ir_nec_scancode_to_raw() - encode an NEC scancode ready for modulation.
173 * @protocol: specific protocol to use
174 * @scancode: a single NEC scancode.
176 static u32
ir_nec_scancode_to_raw(enum rc_proto protocol
, u32 scancode
)
178 unsigned int addr
, addr_inv
, data
, data_inv
;
180 data
= scancode
& 0xff;
182 if (protocol
== RC_PROTO_NEC32
) {
183 /* 32-bit NEC (used by Apple and TiVo remotes) */
184 /* scan encoding: aaAAddDD */
185 addr_inv
= (scancode
>> 24) & 0xff;
186 addr
= (scancode
>> 16) & 0xff;
187 data_inv
= (scancode
>> 8) & 0xff;
188 } else if (protocol
== RC_PROTO_NECX
) {
190 /* scan encoding AAaaDD */
191 addr
= (scancode
>> 16) & 0xff;
192 addr_inv
= (scancode
>> 8) & 0xff;
193 data_inv
= data
^ 0xff;
196 /* scan encoding: AADD */
197 addr
= (scancode
>> 8) & 0xff;
198 addr_inv
= addr
^ 0xff;
199 data_inv
= data
^ 0xff;
202 /* raw encoding: ddDDaaAA */
203 return data_inv
<< 24 |
209 static const struct ir_raw_timings_pd ir_nec_timings
= {
210 .header_pulse
= NEC_HEADER_PULSE
,
211 .header_space
= NEC_HEADER_SPACE
,
212 .bit_pulse
= NEC_BIT_PULSE
,
213 .bit_space
[0] = NEC_BIT_0_SPACE
,
214 .bit_space
[1] = NEC_BIT_1_SPACE
,
215 .trailer_pulse
= NEC_TRAILER_PULSE
,
216 .trailer_space
= NEC_TRAILER_SPACE
,
221 * ir_nec_encode() - Encode a scancode as a stream of raw events
223 * @protocol: protocol to encode
224 * @scancode: scancode to encode
225 * @events: array of raw ir events to write into
226 * @max: maximum size of @events
228 * Returns: The number of events written.
229 * -ENOBUFS if there isn't enough space in the array to fit the
230 * encoding. In this case all @max events will have been written.
232 static int ir_nec_encode(enum rc_proto protocol
, u32 scancode
,
233 struct ir_raw_event
*events
, unsigned int max
)
235 struct ir_raw_event
*e
= events
;
239 /* Convert a NEC scancode to raw NEC data */
240 raw
= ir_nec_scancode_to_raw(protocol
, scancode
);
242 /* Modulate the raw data using a pulse distance modulation */
243 ret
= ir_raw_gen_pd(&e
, max
, &ir_nec_timings
, NEC_NBITS
, raw
);
250 static struct ir_raw_handler nec_handler
= {
251 .protocols
= RC_PROTO_BIT_NEC
| RC_PROTO_BIT_NECX
|
253 .decode
= ir_nec_decode
,
254 .encode
= ir_nec_encode
,
256 .min_timeout
= NEC_TRAILER_SPACE
,
259 static int __init
ir_nec_decode_init(void)
261 ir_raw_handler_register(&nec_handler
);
263 printk(KERN_INFO
"IR NEC protocol handler initialized\n");
267 static void __exit
ir_nec_decode_exit(void)
269 ir_raw_handler_unregister(&nec_handler
);
272 module_init(ir_nec_decode_init
);
273 module_exit(ir_nec_decode_exit
);
275 MODULE_LICENSE("GPL v2");
276 MODULE_AUTHOR("Mauro Carvalho Chehab");
277 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
278 MODULE_DESCRIPTION("NEC IR protocol decoder");