Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / rc / ir-jvc-decoder.c
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                525000          /* ns */
13 #define JVC_HEADER_PULSE        (16 * JVC_UNIT) /* lack of header -> repeat */
14 #define JVC_HEADER_SPACE        (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         STATE_HEADER_SPACE,
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.reset)
44                         data->state = STATE_INACTIVE;
45                 return 0;
46         }
47
48         if (!geq_margin(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, TO_US(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(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(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(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(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
96                         data->bits |= 1;
97                         decrease_duration(&ev, JVC_BIT_1_SPACE);
98                 } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
99                         decrease_duration(&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(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(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, RC_PROTO_JVC, scancode, 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(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, TO_US(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(&e, max, &ir_jvc_timings, JVC_NBITS, 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(&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(&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");