0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "rc-core-priv.h"
0013 #include <linux/module.h>
0014
0015 #define RC5_NBITS 14
0016 #define RC5_SZ_NBITS 15
0017 #define RC5X_NBITS 20
0018 #define CHECK_RC5X_NBITS 8
0019 #define RC5_UNIT 889
0020 #define RC5_BIT_START (1 * RC5_UNIT)
0021 #define RC5_BIT_END (1 * RC5_UNIT)
0022 #define RC5X_SPACE (4 * RC5_UNIT)
0023 #define RC5_TRAILER (6 * RC5_UNIT)
0024
0025 enum rc5_state {
0026 STATE_INACTIVE,
0027 STATE_BIT_START,
0028 STATE_BIT_END,
0029 STATE_CHECK_RC5X,
0030 STATE_FINISHED,
0031 };
0032
0033
0034
0035
0036
0037
0038
0039
0040 static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
0041 {
0042 struct rc5_dec *data = &dev->raw->rc5;
0043 u8 toggle;
0044 u32 scancode;
0045 enum rc_proto protocol;
0046
0047 if (!is_timing_event(ev)) {
0048 if (ev.overflow)
0049 data->state = STATE_INACTIVE;
0050 return 0;
0051 }
0052
0053 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
0054 goto out;
0055
0056 again:
0057 dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n",
0058 data->state, ev.duration, TO_STR(ev.pulse));
0059
0060 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
0061 return 0;
0062
0063 switch (data->state) {
0064
0065 case STATE_INACTIVE:
0066 if (!ev.pulse)
0067 break;
0068
0069 data->state = STATE_BIT_START;
0070 data->count = 1;
0071 decrease_duration(&ev, RC5_BIT_START);
0072 goto again;
0073
0074 case STATE_BIT_START:
0075 if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
0076 data->state = STATE_FINISHED;
0077 goto again;
0078 }
0079
0080 if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
0081 break;
0082
0083 data->bits <<= 1;
0084 if (!ev.pulse)
0085 data->bits |= 1;
0086 data->count++;
0087 data->state = STATE_BIT_END;
0088 return 0;
0089
0090 case STATE_BIT_END:
0091 if (data->count == CHECK_RC5X_NBITS)
0092 data->state = STATE_CHECK_RC5X;
0093 else
0094 data->state = STATE_BIT_START;
0095
0096 decrease_duration(&ev, RC5_BIT_END);
0097 goto again;
0098
0099 case STATE_CHECK_RC5X:
0100 if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
0101 data->is_rc5x = true;
0102 decrease_duration(&ev, RC5X_SPACE);
0103 } else
0104 data->is_rc5x = false;
0105 data->state = STATE_BIT_START;
0106 goto again;
0107
0108 case STATE_FINISHED:
0109 if (ev.pulse)
0110 break;
0111
0112 if (data->is_rc5x && data->count == RC5X_NBITS) {
0113
0114 u8 xdata, command, system;
0115 if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5X_20)) {
0116 data->state = STATE_INACTIVE;
0117 return 0;
0118 }
0119 xdata = (data->bits & 0x0003F) >> 0;
0120 command = (data->bits & 0x00FC0) >> 6;
0121 system = (data->bits & 0x1F000) >> 12;
0122 toggle = (data->bits & 0x20000) ? 1 : 0;
0123 command += (data->bits & 0x40000) ? 0 : 0x40;
0124 scancode = system << 16 | command << 8 | xdata;
0125 protocol = RC_PROTO_RC5X_20;
0126
0127 } else if (!data->is_rc5x && data->count == RC5_NBITS) {
0128
0129 u8 command, system;
0130 if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5)) {
0131 data->state = STATE_INACTIVE;
0132 return 0;
0133 }
0134 command = (data->bits & 0x0003F) >> 0;
0135 system = (data->bits & 0x007C0) >> 6;
0136 toggle = (data->bits & 0x00800) ? 1 : 0;
0137 command += (data->bits & 0x01000) ? 0 : 0x40;
0138 scancode = system << 8 | command;
0139 protocol = RC_PROTO_RC5;
0140
0141 } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) {
0142
0143 u8 command, system;
0144 if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5_SZ)) {
0145 data->state = STATE_INACTIVE;
0146 return 0;
0147 }
0148 command = (data->bits & 0x0003F) >> 0;
0149 system = (data->bits & 0x02FC0) >> 6;
0150 toggle = (data->bits & 0x01000) ? 1 : 0;
0151 scancode = system << 6 | command;
0152 protocol = RC_PROTO_RC5_SZ;
0153
0154 } else
0155 break;
0156
0157 dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
0158 scancode, protocol, toggle);
0159
0160 rc_keydown(dev, protocol, scancode, toggle);
0161 data->state = STATE_INACTIVE;
0162 return 0;
0163 }
0164
0165 out:
0166 dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
0167 data->state, data->count, ev.duration, TO_STR(ev.pulse));
0168 data->state = STATE_INACTIVE;
0169 return -EINVAL;
0170 }
0171
0172 static const struct ir_raw_timings_manchester ir_rc5_timings = {
0173 .leader_pulse = RC5_UNIT,
0174 .clock = RC5_UNIT,
0175 .trailer_space = RC5_UNIT * 10,
0176 };
0177
0178 static const struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
0179 {
0180 .leader_pulse = RC5_UNIT,
0181 .clock = RC5_UNIT,
0182 .trailer_space = RC5X_SPACE,
0183 },
0184 {
0185 .clock = RC5_UNIT,
0186 .trailer_space = RC5_UNIT * 10,
0187 },
0188 };
0189
0190 static const struct ir_raw_timings_manchester ir_rc5_sz_timings = {
0191 .leader_pulse = RC5_UNIT,
0192 .clock = RC5_UNIT,
0193 .trailer_space = RC5_UNIT * 10,
0194 };
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 static int ir_rc5_encode(enum rc_proto protocol, u32 scancode,
0210 struct ir_raw_event *events, unsigned int max)
0211 {
0212 int ret;
0213 struct ir_raw_event *e = events;
0214 unsigned int data, xdata, command, commandx, system, pre_space_data;
0215
0216
0217 if (protocol == RC_PROTO_RC5) {
0218
0219 command = (scancode & 0x003f) >> 0;
0220 commandx = (scancode & 0x0040) >> 6;
0221 system = (scancode & 0x1f00) >> 8;
0222
0223 data = !commandx << 12 | system << 6 | command;
0224
0225
0226 ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings,
0227 RC5_NBITS - 1, data);
0228 if (ret < 0)
0229 return ret;
0230 } else if (protocol == RC_PROTO_RC5X_20) {
0231
0232 xdata = (scancode & 0x00003f) >> 0;
0233 command = (scancode & 0x003f00) >> 8;
0234 commandx = !(scancode & 0x004000);
0235 system = (scancode & 0x1f0000) >> 16;
0236
0237
0238 data = commandx << 18 | system << 12 | command << 6 | xdata;
0239
0240
0241 pre_space_data = data >> (RC5X_NBITS - CHECK_RC5X_NBITS);
0242 ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
0243 CHECK_RC5X_NBITS - 1,
0244 pre_space_data);
0245 if (ret < 0)
0246 return ret;
0247 ret = ir_raw_gen_manchester(&e, max - (e - events),
0248 &ir_rc5x_timings[1],
0249 RC5X_NBITS - CHECK_RC5X_NBITS,
0250 data);
0251 if (ret < 0)
0252 return ret;
0253 } else if (protocol == RC_PROTO_RC5_SZ) {
0254
0255
0256 ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
0257 RC5_SZ_NBITS - 1,
0258 scancode & 0x2fff);
0259 if (ret < 0)
0260 return ret;
0261 } else {
0262 return -EINVAL;
0263 }
0264
0265 return e - events;
0266 }
0267
0268 static struct ir_raw_handler rc5_handler = {
0269 .protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 |
0270 RC_PROTO_BIT_RC5_SZ,
0271 .decode = ir_rc5_decode,
0272 .encode = ir_rc5_encode,
0273 .carrier = 36000,
0274 .min_timeout = RC5_TRAILER,
0275 };
0276
0277 static int __init ir_rc5_decode_init(void)
0278 {
0279 ir_raw_handler_register(&rc5_handler);
0280
0281 printk(KERN_INFO "IR RC5(x/sz) protocol handler initialized\n");
0282 return 0;
0283 }
0284
0285 static void __exit ir_rc5_decode_exit(void)
0286 {
0287 ir_raw_handler_unregister(&rc5_handler);
0288 }
0289
0290 module_init(ir_rc5_decode_init);
0291 module_exit(ir_rc5_decode_exit);
0292
0293 MODULE_LICENSE("GPL v2");
0294 MODULE_AUTHOR("Mauro Carvalho Chehab and Jarod Wilson");
0295 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
0296 MODULE_DESCRIPTION("RC5(x/sz) IR protocol decoder");