1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* ir-sony-decoder.c - handle Sony 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 SONY_UNIT 600 /* us */ |
12 | #define (4 * SONY_UNIT) |
13 | #define (1 * SONY_UNIT) |
14 | #define SONY_BIT_0_PULSE (1 * SONY_UNIT) |
15 | #define SONY_BIT_1_PULSE (2 * SONY_UNIT) |
16 | #define SONY_BIT_SPACE (1 * SONY_UNIT) |
17 | #define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ |
18 | |
19 | enum sony_state { |
20 | STATE_INACTIVE, |
21 | , |
22 | STATE_BIT_PULSE, |
23 | STATE_BIT_SPACE, |
24 | STATE_FINISHED, |
25 | }; |
26 | |
27 | /** |
28 | * ir_sony_decode() - Decode one Sony pulse or space |
29 | * @dev: the struct rc_dev descriptor of the device |
30 | * @ev: the struct ir_raw_event descriptor of the pulse/space |
31 | * |
32 | * This function returns -EINVAL if the pulse violates the state machine |
33 | */ |
34 | static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) |
35 | { |
36 | struct sony_dec *data = &dev->raw->sony; |
37 | enum rc_proto protocol; |
38 | u32 scancode; |
39 | u8 device, subdevice, function; |
40 | |
41 | if (!is_timing_event(ev)) { |
42 | if (ev.overflow) |
43 | data->state = STATE_INACTIVE; |
44 | return 0; |
45 | } |
46 | |
47 | if (!geq_margin(d1: ev.duration, SONY_UNIT, SONY_UNIT / 2)) |
48 | goto out; |
49 | |
50 | dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n" , |
51 | data->state, ev.duration, TO_STR(ev.pulse)); |
52 | |
53 | switch (data->state) { |
54 | |
55 | case STATE_INACTIVE: |
56 | if (!ev.pulse) |
57 | break; |
58 | |
59 | if (!eq_margin(d1: ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2)) |
60 | break; |
61 | |
62 | data->count = 0; |
63 | data->state = STATE_HEADER_SPACE; |
64 | return 0; |
65 | |
66 | case STATE_HEADER_SPACE: |
67 | if (ev.pulse) |
68 | break; |
69 | |
70 | if (!eq_margin(d1: ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2)) |
71 | break; |
72 | |
73 | data->state = STATE_BIT_PULSE; |
74 | return 0; |
75 | |
76 | case STATE_BIT_PULSE: |
77 | if (!ev.pulse) |
78 | break; |
79 | |
80 | data->bits <<= 1; |
81 | if (eq_margin(d1: ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) |
82 | data->bits |= 1; |
83 | else if (!eq_margin(d1: ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) |
84 | break; |
85 | |
86 | data->count++; |
87 | data->state = STATE_BIT_SPACE; |
88 | return 0; |
89 | |
90 | case STATE_BIT_SPACE: |
91 | if (ev.pulse) |
92 | break; |
93 | |
94 | if (!geq_margin(d1: ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2)) |
95 | break; |
96 | |
97 | decrease_duration(ev: &ev, SONY_BIT_SPACE); |
98 | |
99 | if (!geq_margin(d1: ev.duration, SONY_UNIT, SONY_UNIT / 2)) { |
100 | data->state = STATE_BIT_PULSE; |
101 | return 0; |
102 | } |
103 | |
104 | data->state = STATE_FINISHED; |
105 | fallthrough; |
106 | |
107 | case STATE_FINISHED: |
108 | if (ev.pulse) |
109 | break; |
110 | |
111 | if (!geq_margin(d1: ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2)) |
112 | break; |
113 | |
114 | switch (data->count) { |
115 | case 12: |
116 | if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY12)) |
117 | goto finish_state_machine; |
118 | |
119 | device = bitrev8((data->bits << 3) & 0xF8); |
120 | subdevice = 0; |
121 | function = bitrev8((data->bits >> 4) & 0xFE); |
122 | protocol = RC_PROTO_SONY12; |
123 | break; |
124 | case 15: |
125 | if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY15)) |
126 | goto finish_state_machine; |
127 | |
128 | device = bitrev8((data->bits >> 0) & 0xFF); |
129 | subdevice = 0; |
130 | function = bitrev8((data->bits >> 7) & 0xFE); |
131 | protocol = RC_PROTO_SONY15; |
132 | break; |
133 | case 20: |
134 | if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY20)) |
135 | goto finish_state_machine; |
136 | |
137 | device = bitrev8((data->bits >> 5) & 0xF8); |
138 | subdevice = bitrev8((data->bits >> 0) & 0xFF); |
139 | function = bitrev8((data->bits >> 12) & 0xFE); |
140 | protocol = RC_PROTO_SONY20; |
141 | break; |
142 | default: |
143 | dev_dbg(&dev->dev, "Sony invalid bitcount %u\n" , |
144 | data->count); |
145 | goto out; |
146 | } |
147 | |
148 | scancode = device << 16 | subdevice << 8 | function; |
149 | dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n" , data->count, |
150 | scancode); |
151 | rc_keydown(dev, protocol, scancode, toggle: 0); |
152 | goto finish_state_machine; |
153 | } |
154 | |
155 | out: |
156 | dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n" , |
157 | data->state, ev.duration, TO_STR(ev.pulse)); |
158 | data->state = STATE_INACTIVE; |
159 | return -EINVAL; |
160 | |
161 | finish_state_machine: |
162 | data->state = STATE_INACTIVE; |
163 | return 0; |
164 | } |
165 | |
166 | static const struct ir_raw_timings_pl ir_sony_timings = { |
167 | .header_pulse = SONY_HEADER_PULSE, |
168 | .bit_space = SONY_BIT_SPACE, |
169 | .bit_pulse[0] = SONY_BIT_0_PULSE, |
170 | .bit_pulse[1] = SONY_BIT_1_PULSE, |
171 | .trailer_space = SONY_TRAILER_SPACE + SONY_BIT_SPACE, |
172 | .msb_first = 0, |
173 | }; |
174 | |
175 | /** |
176 | * ir_sony_encode() - Encode a scancode as a stream of raw events |
177 | * |
178 | * @protocol: protocol to encode |
179 | * @scancode: scancode to encode |
180 | * @events: array of raw ir events to write into |
181 | * @max: maximum size of @events |
182 | * |
183 | * Returns: The number of events written. |
184 | * -ENOBUFS if there isn't enough space in the array to fit the |
185 | * encoding. In this case all @max events will have been written. |
186 | */ |
187 | static int ir_sony_encode(enum rc_proto protocol, u32 scancode, |
188 | struct ir_raw_event *events, unsigned int max) |
189 | { |
190 | struct ir_raw_event *e = events; |
191 | u32 raw, len; |
192 | int ret; |
193 | |
194 | if (protocol == RC_PROTO_SONY12) { |
195 | raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9); |
196 | len = 12; |
197 | } else if (protocol == RC_PROTO_SONY15) { |
198 | raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9); |
199 | len = 15; |
200 | } else { |
201 | raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9) | |
202 | ((scancode & 0xff00) << 4); |
203 | len = 20; |
204 | } |
205 | |
206 | ret = ir_raw_gen_pl(ev: &e, max, timings: &ir_sony_timings, n: len, data: raw); |
207 | if (ret < 0) |
208 | return ret; |
209 | |
210 | return e - events; |
211 | } |
212 | |
213 | static struct ir_raw_handler sony_handler = { |
214 | .protocols = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | |
215 | RC_PROTO_BIT_SONY20, |
216 | .decode = ir_sony_decode, |
217 | .encode = ir_sony_encode, |
218 | .carrier = 40000, |
219 | .min_timeout = SONY_TRAILER_SPACE, |
220 | }; |
221 | |
222 | static int __init ir_sony_decode_init(void) |
223 | { |
224 | ir_raw_handler_register(ir_raw_handler: &sony_handler); |
225 | |
226 | printk(KERN_INFO "IR Sony protocol handler initialized\n" ); |
227 | return 0; |
228 | } |
229 | |
230 | static void __exit ir_sony_decode_exit(void) |
231 | { |
232 | ir_raw_handler_unregister(ir_raw_handler: &sony_handler); |
233 | } |
234 | |
235 | module_init(ir_sony_decode_init); |
236 | module_exit(ir_sony_decode_exit); |
237 | |
238 | MODULE_LICENSE("GPL" ); |
239 | MODULE_AUTHOR("David Härdeman <david@hardeman.nu>" ); |
240 | MODULE_DESCRIPTION("Sony IR protocol decoder" ); |
241 | |