Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/rc/ir-rc6-decoder.c
15109 views
1
/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol
2
*
3
* Copyright (C) 2010 by David Härdeman <[email protected]>
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation version 2 of the License.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*/
14
15
#include "rc-core-priv.h"
16
17
/*
18
* This decoder currently supports:
19
* RC6-0-16 (standard toggle bit in header)
20
* RC6-6A-24 (no toggle bit)
21
* RC6-6A-32 (MCE version with toggle bit in body)
22
*/
23
24
#define RC6_UNIT 444444 /* us */
25
#define RC6_HEADER_NBITS 4 /* not including toggle bit */
26
#define RC6_0_NBITS 16
27
#define RC6_6A_SMALL_NBITS 24
28
#define RC6_6A_LARGE_NBITS 32
29
#define RC6_PREFIX_PULSE (6 * RC6_UNIT)
30
#define RC6_PREFIX_SPACE (2 * RC6_UNIT)
31
#define RC6_BIT_START (1 * RC6_UNIT)
32
#define RC6_BIT_END (1 * RC6_UNIT)
33
#define RC6_TOGGLE_START (2 * RC6_UNIT)
34
#define RC6_TOGGLE_END (2 * RC6_UNIT)
35
#define RC6_MODE_MASK 0x07 /* for the header bits */
36
#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
37
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
38
39
enum rc6_mode {
40
RC6_MODE_0,
41
RC6_MODE_6A,
42
RC6_MODE_UNKNOWN,
43
};
44
45
enum rc6_state {
46
STATE_INACTIVE,
47
STATE_PREFIX_SPACE,
48
STATE_HEADER_BIT_START,
49
STATE_HEADER_BIT_END,
50
STATE_TOGGLE_START,
51
STATE_TOGGLE_END,
52
STATE_BODY_BIT_START,
53
STATE_BODY_BIT_END,
54
STATE_FINISHED,
55
};
56
57
static enum rc6_mode rc6_mode(struct rc6_dec *data)
58
{
59
switch (data->header & RC6_MODE_MASK) {
60
case 0:
61
return RC6_MODE_0;
62
case 6:
63
if (!data->toggle)
64
return RC6_MODE_6A;
65
/* fall through */
66
default:
67
return RC6_MODE_UNKNOWN;
68
}
69
}
70
71
/**
72
* ir_rc6_decode() - Decode one RC6 pulse or space
73
* @dev: the struct rc_dev descriptor of the device
74
* @ev: the struct ir_raw_event descriptor of the pulse/space
75
*
76
* This function returns -EINVAL if the pulse violates the state machine
77
*/
78
static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
79
{
80
struct rc6_dec *data = &dev->raw->rc6;
81
u32 scancode;
82
u8 toggle;
83
84
if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
85
return 0;
86
87
if (!is_timing_event(ev)) {
88
if (ev.reset)
89
data->state = STATE_INACTIVE;
90
return 0;
91
}
92
93
if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
94
goto out;
95
96
again:
97
IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
98
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
99
100
if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
101
return 0;
102
103
switch (data->state) {
104
105
case STATE_INACTIVE:
106
if (!ev.pulse)
107
break;
108
109
/* Note: larger margin on first pulse since each RC6_UNIT
110
is quite short and some hardware takes some time to
111
adjust to the signal */
112
if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
113
break;
114
115
data->state = STATE_PREFIX_SPACE;
116
data->count = 0;
117
return 0;
118
119
case STATE_PREFIX_SPACE:
120
if (ev.pulse)
121
break;
122
123
if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
124
break;
125
126
data->state = STATE_HEADER_BIT_START;
127
return 0;
128
129
case STATE_HEADER_BIT_START:
130
if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
131
break;
132
133
data->header <<= 1;
134
if (ev.pulse)
135
data->header |= 1;
136
data->count++;
137
data->state = STATE_HEADER_BIT_END;
138
return 0;
139
140
case STATE_HEADER_BIT_END:
141
if (!is_transition(&ev, &dev->raw->prev_ev))
142
break;
143
144
if (data->count == RC6_HEADER_NBITS)
145
data->state = STATE_TOGGLE_START;
146
else
147
data->state = STATE_HEADER_BIT_START;
148
149
decrease_duration(&ev, RC6_BIT_END);
150
goto again;
151
152
case STATE_TOGGLE_START:
153
if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
154
break;
155
156
data->toggle = ev.pulse;
157
data->state = STATE_TOGGLE_END;
158
return 0;
159
160
case STATE_TOGGLE_END:
161
if (!is_transition(&ev, &dev->raw->prev_ev) ||
162
!geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
163
break;
164
165
if (!(data->header & RC6_STARTBIT_MASK)) {
166
IR_dprintk(1, "RC6 invalid start bit\n");
167
break;
168
}
169
170
data->state = STATE_BODY_BIT_START;
171
decrease_duration(&ev, RC6_TOGGLE_END);
172
data->count = 0;
173
174
switch (rc6_mode(data)) {
175
case RC6_MODE_0:
176
data->wanted_bits = RC6_0_NBITS;
177
break;
178
case RC6_MODE_6A:
179
/* This might look weird, but we basically
180
check the value of the first body bit to
181
determine the number of bits in mode 6A */
182
if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
183
geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
184
data->wanted_bits = RC6_6A_LARGE_NBITS;
185
else
186
data->wanted_bits = RC6_6A_SMALL_NBITS;
187
break;
188
default:
189
IR_dprintk(1, "RC6 unknown mode\n");
190
goto out;
191
}
192
goto again;
193
194
case STATE_BODY_BIT_START:
195
if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
196
break;
197
198
data->body <<= 1;
199
if (ev.pulse)
200
data->body |= 1;
201
data->count++;
202
data->state = STATE_BODY_BIT_END;
203
return 0;
204
205
case STATE_BODY_BIT_END:
206
if (!is_transition(&ev, &dev->raw->prev_ev))
207
break;
208
209
if (data->count == data->wanted_bits)
210
data->state = STATE_FINISHED;
211
else
212
data->state = STATE_BODY_BIT_START;
213
214
decrease_duration(&ev, RC6_BIT_END);
215
goto again;
216
217
case STATE_FINISHED:
218
if (ev.pulse)
219
break;
220
221
switch (rc6_mode(data)) {
222
case RC6_MODE_0:
223
scancode = data->body & 0xffff;
224
toggle = data->toggle;
225
IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
226
scancode, toggle);
227
break;
228
case RC6_MODE_6A:
229
if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
230
toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
231
scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
232
} else {
233
toggle = 0;
234
scancode = data->body & 0xffffff;
235
}
236
237
IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
238
scancode, toggle);
239
break;
240
default:
241
IR_dprintk(1, "RC6 unknown mode\n");
242
goto out;
243
}
244
245
rc_keydown(dev, scancode, toggle);
246
data->state = STATE_INACTIVE;
247
return 0;
248
}
249
250
out:
251
IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
252
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
253
data->state = STATE_INACTIVE;
254
return -EINVAL;
255
}
256
257
static struct ir_raw_handler rc6_handler = {
258
.protocols = RC_TYPE_RC6,
259
.decode = ir_rc6_decode,
260
};
261
262
static int __init ir_rc6_decode_init(void)
263
{
264
ir_raw_handler_register(&rc6_handler);
265
266
printk(KERN_INFO "IR RC6 protocol handler initialized\n");
267
return 0;
268
}
269
270
static void __exit ir_rc6_decode_exit(void)
271
{
272
ir_raw_handler_unregister(&rc6_handler);
273
}
274
275
module_init(ir_rc6_decode_init);
276
module_exit(ir_rc6_decode_exit);
277
278
MODULE_LICENSE("GPL");
279
MODULE_AUTHOR("David Härdeman <[email protected]>");
280
MODULE_DESCRIPTION("RC6 IR protocol decoder");
281
282