1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol |
3 | * |
4 | * Copyright (C) 2010 by David Härdeman <david@hardeman.nu> |
5 | */ |
6 | |
7 | #include <linux/bitrev.h> |
8 | #include <linux/module.h> |
9 | #include "rc-core-priv.h" |
10 | |
11 | #define JVC_NBITS 16 /* dev(8) + func(8) */ |
12 | #define JVC_UNIT 525 /* us */ |
13 | #define (16 * JVC_UNIT) /* lack of header -> repeat */ |
14 | #define (8 * JVC_UNIT) |
15 | #define JVC_BIT_PULSE (1 * JVC_UNIT) |
16 | #define JVC_BIT_0_SPACE (1 * JVC_UNIT) |
17 | #define JVC_BIT_1_SPACE (3 * JVC_UNIT) |
18 | #define JVC_TRAILER_PULSE (1 * JVC_UNIT) |
19 | #define JVC_TRAILER_SPACE (35 * JVC_UNIT) |
20 | |
21 | enum jvc_state { |
22 | STATE_INACTIVE, |
23 | , |
24 | STATE_BIT_PULSE, |
25 | STATE_BIT_SPACE, |
26 | STATE_TRAILER_PULSE, |
27 | STATE_TRAILER_SPACE, |
28 | STATE_CHECK_REPEAT, |
29 | }; |
30 | |
31 | /** |
32 | * ir_jvc_decode() - Decode one JVC pulse or space |
33 | * @dev: the struct rc_dev descriptor of the device |
34 | * @ev: the struct ir_raw_event descriptor of the pulse/space |
35 | * |
36 | * This function returns -EINVAL if the pulse violates the state machine |
37 | */ |
38 | static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) |
39 | { |
40 | struct jvc_dec *data = &dev->raw->jvc; |
41 | |
42 | if (!is_timing_event(ev)) { |
43 | if (ev.overflow) |
44 | data->state = STATE_INACTIVE; |
45 | return 0; |
46 | } |
47 | |
48 | if (!geq_margin(d1: ev.duration, JVC_UNIT, JVC_UNIT / 2)) |
49 | goto out; |
50 | |
51 | dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n" , |
52 | data->state, ev.duration, TO_STR(ev.pulse)); |
53 | |
54 | again: |
55 | switch (data->state) { |
56 | |
57 | case STATE_INACTIVE: |
58 | if (!ev.pulse) |
59 | break; |
60 | |
61 | if (!eq_margin(d1: ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) |
62 | break; |
63 | |
64 | data->count = 0; |
65 | data->first = true; |
66 | data->toggle = !data->toggle; |
67 | data->state = STATE_HEADER_SPACE; |
68 | return 0; |
69 | |
70 | case STATE_HEADER_SPACE: |
71 | if (ev.pulse) |
72 | break; |
73 | |
74 | if (!eq_margin(d1: ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2)) |
75 | break; |
76 | |
77 | data->state = STATE_BIT_PULSE; |
78 | return 0; |
79 | |
80 | case STATE_BIT_PULSE: |
81 | if (!ev.pulse) |
82 | break; |
83 | |
84 | if (!eq_margin(d1: ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2)) |
85 | break; |
86 | |
87 | data->state = STATE_BIT_SPACE; |
88 | return 0; |
89 | |
90 | case STATE_BIT_SPACE: |
91 | if (ev.pulse) |
92 | break; |
93 | |
94 | data->bits <<= 1; |
95 | if (eq_margin(d1: ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { |
96 | data->bits |= 1; |
97 | decrease_duration(ev: &ev, JVC_BIT_1_SPACE); |
98 | } else if (eq_margin(d1: ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) |
99 | decrease_duration(ev: &ev, JVC_BIT_0_SPACE); |
100 | else |
101 | break; |
102 | data->count++; |
103 | |
104 | if (data->count == JVC_NBITS) |
105 | data->state = STATE_TRAILER_PULSE; |
106 | else |
107 | data->state = STATE_BIT_PULSE; |
108 | return 0; |
109 | |
110 | case STATE_TRAILER_PULSE: |
111 | if (!ev.pulse) |
112 | break; |
113 | |
114 | if (!eq_margin(d1: ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2)) |
115 | break; |
116 | |
117 | data->state = STATE_TRAILER_SPACE; |
118 | return 0; |
119 | |
120 | case STATE_TRAILER_SPACE: |
121 | if (ev.pulse) |
122 | break; |
123 | |
124 | if (!geq_margin(d1: ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2)) |
125 | break; |
126 | |
127 | if (data->first) { |
128 | u32 scancode; |
129 | scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | |
130 | (bitrev8((data->bits >> 0) & 0xff) << 0); |
131 | dev_dbg(&dev->dev, "JVC scancode 0x%04x\n" , scancode); |
132 | rc_keydown(dev, protocol: RC_PROTO_JVC, scancode, toggle: data->toggle); |
133 | data->first = false; |
134 | data->old_bits = data->bits; |
135 | } else if (data->bits == data->old_bits) { |
136 | dev_dbg(&dev->dev, "JVC repeat\n" ); |
137 | rc_repeat(dev); |
138 | } else { |
139 | dev_dbg(&dev->dev, "JVC invalid repeat msg\n" ); |
140 | break; |
141 | } |
142 | |
143 | data->count = 0; |
144 | data->state = STATE_CHECK_REPEAT; |
145 | return 0; |
146 | |
147 | case STATE_CHECK_REPEAT: |
148 | if (!ev.pulse) |
149 | break; |
150 | |
151 | if (eq_margin(d1: ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) |
152 | data->state = STATE_INACTIVE; |
153 | else |
154 | data->state = STATE_BIT_PULSE; |
155 | goto again; |
156 | } |
157 | |
158 | out: |
159 | dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n" , |
160 | data->state, ev.duration, TO_STR(ev.pulse)); |
161 | data->state = STATE_INACTIVE; |
162 | return -EINVAL; |
163 | } |
164 | |
165 | static const struct ir_raw_timings_pd ir_jvc_timings = { |
166 | .header_pulse = JVC_HEADER_PULSE, |
167 | .header_space = JVC_HEADER_SPACE, |
168 | .bit_pulse = JVC_BIT_PULSE, |
169 | .bit_space[0] = JVC_BIT_0_SPACE, |
170 | .bit_space[1] = JVC_BIT_1_SPACE, |
171 | .trailer_pulse = JVC_TRAILER_PULSE, |
172 | .trailer_space = JVC_TRAILER_SPACE, |
173 | .msb_first = 1, |
174 | }; |
175 | |
176 | /** |
177 | * ir_jvc_encode() - Encode a scancode as a stream of raw events |
178 | * |
179 | * @protocol: protocol to encode |
180 | * @scancode: scancode to encode |
181 | * @events: array of raw ir events to write into |
182 | * @max: maximum size of @events |
183 | * |
184 | * Returns: The number of events written. |
185 | * -ENOBUFS if there isn't enough space in the array to fit the |
186 | * encoding. In this case all @max events will have been written. |
187 | */ |
188 | static int ir_jvc_encode(enum rc_proto protocol, u32 scancode, |
189 | struct ir_raw_event *events, unsigned int max) |
190 | { |
191 | struct ir_raw_event *e = events; |
192 | int ret; |
193 | u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) | |
194 | (bitrev8((scancode >> 0) & 0xff) << 0); |
195 | |
196 | ret = ir_raw_gen_pd(ev: &e, max, timings: &ir_jvc_timings, JVC_NBITS, data: raw); |
197 | if (ret < 0) |
198 | return ret; |
199 | |
200 | return e - events; |
201 | } |
202 | |
203 | static struct ir_raw_handler jvc_handler = { |
204 | .protocols = RC_PROTO_BIT_JVC, |
205 | .decode = ir_jvc_decode, |
206 | .encode = ir_jvc_encode, |
207 | .carrier = 38000, |
208 | .min_timeout = JVC_TRAILER_SPACE, |
209 | }; |
210 | |
211 | static int __init ir_jvc_decode_init(void) |
212 | { |
213 | ir_raw_handler_register(ir_raw_handler: &jvc_handler); |
214 | |
215 | printk(KERN_INFO "IR JVC protocol handler initialized\n" ); |
216 | return 0; |
217 | } |
218 | |
219 | static void __exit ir_jvc_decode_exit(void) |
220 | { |
221 | ir_raw_handler_unregister(ir_raw_handler: &jvc_handler); |
222 | } |
223 | |
224 | module_init(ir_jvc_decode_init); |
225 | module_exit(ir_jvc_decode_exit); |
226 | |
227 | MODULE_LICENSE("GPL" ); |
228 | MODULE_AUTHOR("David Härdeman <david@hardeman.nu>" ); |
229 | MODULE_DESCRIPTION("JVC IR protocol decoder" ); |
230 | |