Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols
0003 //
0004 // Copyright (C) 2010 by Mauro Carvalho Chehab
0005 // Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
0006 
0007 /*
0008  * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol
0009  * and 20 bit RC5x protocol.
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 /* us */
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) /* In reality, approx 100 */
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  * ir_rc5_decode() - Decode one RC-5 pulse or space
0035  * @dev:    the struct rc_dev descriptor of the device
0036  * @ev:     the struct ir_raw_event descriptor of the pulse/space
0037  *
0038  * This function returns -EINVAL if the pulse violates the state machine
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             /* RC5X */
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             /* RC5 */
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             /* RC5 StreamZap */
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  * ir_rc5_encode() - Encode a scancode as a stream of raw events
0198  *
0199  * @protocol:   protocol variant to encode
0200  * @scancode:   scancode to encode
0201  * @events: array of raw ir events to write into
0202  * @max:    maximum size of @events
0203  *
0204  * Returns: The number of events written.
0205  *      -ENOBUFS if there isn't enough space in the array to fit the
0206  *      encoding. In this case all @max events will have been written.
0207  *      -EINVAL if the scancode is ambiguous or invalid.
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     /* Detect protocol and convert scancode to raw data */
0217     if (protocol == RC_PROTO_RC5) {
0218         /* decode scancode */
0219         command  = (scancode & 0x003f) >> 0;
0220         commandx = (scancode & 0x0040) >> 6;
0221         system   = (scancode & 0x1f00) >> 8;
0222         /* encode data */
0223         data = !commandx << 12 | system << 6 | command;
0224 
0225         /* First bit is encoded by leader_pulse */
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         /* decode scancode */
0232         xdata    = (scancode & 0x00003f) >> 0;
0233         command  = (scancode & 0x003f00) >> 8;
0234         commandx = !(scancode & 0x004000);
0235         system   = (scancode & 0x1f0000) >> 16;
0236 
0237         /* encode data */
0238         data = commandx << 18 | system << 12 | command << 6 | xdata;
0239 
0240         /* First bit is encoded by leader_pulse */
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         /* RC5-SZ scancode is raw enough for Manchester as it is */
0255         /* First bit is encoded by leader_pulse */
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");