linux/drivers/media/rc/ir-rc6-decoder.c
<<
>>
Prefs
   1/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol
   2 *
   3 * Copyright (C) 2010 by David H\xC3\xA4rdeman <david@hardeman.nu>
   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#include <linux/module.h>
  17
  18/*
  19 * This decoder currently supports:
  20 * RC6-0-16     (standard toggle bit in header)
  21 * RC6-6A-20    (no toggle bit)
  22 * RC6-6A-24    (no toggle bit)
  23 * RC6-6A-32    (MCE version with toggle bit in body)
  24 */
  25
  26#define RC6_UNIT                444444  /* nanosecs */
  27#define RC6_HEADER_NBITS        4       /* not including toggle bit */
  28#define RC6_0_NBITS             16
  29#define RC6_6A_32_NBITS         32
  30#define RC6_6A_NBITS            128     /* Variable 8..128 */
  31#define RC6_PREFIX_PULSE        (6 * RC6_UNIT)
  32#define RC6_PREFIX_SPACE        (2 * RC6_UNIT)
  33#define RC6_BIT_START           (1 * RC6_UNIT)
  34#define RC6_BIT_END             (1 * RC6_UNIT)
  35#define RC6_TOGGLE_START        (2 * RC6_UNIT)
  36#define RC6_TOGGLE_END          (2 * RC6_UNIT)
  37#define RC6_SUFFIX_SPACE        (6 * RC6_UNIT)
  38#define RC6_MODE_MASK           0x07    /* for the header bits */
  39#define RC6_STARTBIT_MASK       0x08    /* for the header bits */
  40#define RC6_6A_MCE_TOGGLE_MASK  0x8000  /* for the body bits */
  41#define RC6_6A_LCC_MASK         0xffff0000 /* RC6-6A-32 long customer code mask */
  42#define RC6_6A_MCE_CC           0x800f0000 /* MCE customer code */
  43#ifndef CHAR_BIT
  44#define CHAR_BIT 8      /* Normally in <limits.h> */
  45#endif
  46
  47enum rc6_mode {
  48        RC6_MODE_0,
  49        RC6_MODE_6A,
  50        RC6_MODE_UNKNOWN,
  51};
  52
  53enum rc6_state {
  54        STATE_INACTIVE,
  55        STATE_PREFIX_SPACE,
  56        STATE_HEADER_BIT_START,
  57        STATE_HEADER_BIT_END,
  58        STATE_TOGGLE_START,
  59        STATE_TOGGLE_END,
  60        STATE_BODY_BIT_START,
  61        STATE_BODY_BIT_END,
  62        STATE_FINISHED,
  63};
  64
  65static enum rc6_mode rc6_mode(struct rc6_dec *data)
  66{
  67        switch (data->header & RC6_MODE_MASK) {
  68        case 0:
  69                return RC6_MODE_0;
  70        case 6:
  71                if (!data->toggle)
  72                        return RC6_MODE_6A;
  73                /* fall through */
  74        default:
  75                return RC6_MODE_UNKNOWN;
  76        }
  77}
  78
  79/**
  80 * ir_rc6_decode() - Decode one RC6 pulse or space
  81 * @dev:        the struct rc_dev descriptor of the device
  82 * @ev:         the struct ir_raw_event descriptor of the pulse/space
  83 *
  84 * This function returns -EINVAL if the pulse violates the state machine
  85 */
  86static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
  87{
  88        struct rc6_dec *data = &dev->raw->rc6;
  89        u32 scancode;
  90        u8 toggle;
  91
  92        if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
  93                return 0;
  94
  95        if (!is_timing_event(ev)) {
  96                if (ev.reset)
  97                        data->state = STATE_INACTIVE;
  98                return 0;
  99        }
 100
 101        if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
 102                goto out;
 103
 104again:
 105        IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
 106                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 107
 108        if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
 109                return 0;
 110
 111        switch (data->state) {
 112
 113        case STATE_INACTIVE:
 114                if (!ev.pulse)
 115                        break;
 116
 117                /* Note: larger margin on first pulse since each RC6_UNIT
 118                   is quite short and some hardware takes some time to
 119                   adjust to the signal */
 120                if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
 121                        break;
 122
 123                data->state = STATE_PREFIX_SPACE;
 124                data->count = 0;
 125                return 0;
 126
 127        case STATE_PREFIX_SPACE:
 128                if (ev.pulse)
 129                        break;
 130
 131                if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
 132                        break;
 133
 134                data->state = STATE_HEADER_BIT_START;
 135                data->header = 0;
 136                return 0;
 137
 138        case STATE_HEADER_BIT_START:
 139                if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
 140                        break;
 141
 142                data->header <<= 1;
 143                if (ev.pulse)
 144                        data->header |= 1;
 145                data->count++;
 146                data->state = STATE_HEADER_BIT_END;
 147                return 0;
 148
 149        case STATE_HEADER_BIT_END:
 150                if (!is_transition(&ev, &dev->raw->prev_ev))
 151                        break;
 152
 153                if (data->count == RC6_HEADER_NBITS)
 154                        data->state = STATE_TOGGLE_START;
 155                else
 156                        data->state = STATE_HEADER_BIT_START;
 157
 158                decrease_duration(&ev, RC6_BIT_END);
 159                goto again;
 160
 161        case STATE_TOGGLE_START:
 162                if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
 163                        break;
 164
 165                data->toggle = ev.pulse;
 166                data->state = STATE_TOGGLE_END;
 167                return 0;
 168
 169        case STATE_TOGGLE_END:
 170                if (!is_transition(&ev, &dev->raw->prev_ev) ||
 171                    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
 172                        break;
 173
 174                if (!(data->header & RC6_STARTBIT_MASK)) {
 175                        IR_dprintk(1, "RC6 invalid start bit\n");
 176                        break;
 177                }
 178
 179                data->state = STATE_BODY_BIT_START;
 180                decrease_duration(&ev, RC6_TOGGLE_END);
 181                data->count = 0;
 182                data->body = 0;
 183
 184                switch (rc6_mode(data)) {
 185                case RC6_MODE_0:
 186                        data->wanted_bits = RC6_0_NBITS;
 187                        break;
 188                case RC6_MODE_6A:
 189                        data->wanted_bits = RC6_6A_NBITS;
 190                        break;
 191                default:
 192                        IR_dprintk(1, "RC6 unknown mode\n");
 193                        goto out;
 194                }
 195                goto again;
 196
 197        case STATE_BODY_BIT_START:
 198                if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
 199                        /* Discard LSB's that won't fit in data->body */
 200                        if (data->count++ < CHAR_BIT * sizeof data->body) {
 201                                data->body <<= 1;
 202                                if (ev.pulse)
 203                                        data->body |= 1;
 204                        }
 205                        data->state = STATE_BODY_BIT_END;
 206                        return 0;
 207                } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
 208                                geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
 209                        data->state = STATE_FINISHED;
 210                        goto again;
 211                }
 212                break;
 213
 214        case STATE_BODY_BIT_END:
 215                if (!is_transition(&ev, &dev->raw->prev_ev))
 216                        break;
 217
 218                if (data->count == data->wanted_bits)
 219                        data->state = STATE_FINISHED;
 220                else
 221                        data->state = STATE_BODY_BIT_START;
 222
 223                decrease_duration(&ev, RC6_BIT_END);
 224                goto again;
 225
 226        case STATE_FINISHED:
 227                if (ev.pulse)
 228                        break;
 229
 230                switch (rc6_mode(data)) {
 231                case RC6_MODE_0:
 232                        scancode = data->body;
 233                        toggle = data->toggle;
 234                        IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
 235                                   scancode, toggle);
 236                        break;
 237                case RC6_MODE_6A:
 238                        if (data->count > CHAR_BIT * sizeof data->body) {
 239                                IR_dprintk(1, "RC6 too many (%u) data bits\n",
 240                                        data->count);
 241                                goto out;
 242                        }
 243
 244                        scancode = data->body;
 245                        if (data->count == RC6_6A_32_NBITS &&
 246                                        (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
 247                                /* MCE RC */
 248                                toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
 249                                scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
 250                        } else {
 251                                toggle = 0;
 252                        }
 253                        IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
 254                                   scancode, toggle);
 255                        break;
 256                default:
 257                        IR_dprintk(1, "RC6 unknown mode\n");
 258                        goto out;
 259                }
 260
 261                rc_keydown(dev, scancode, toggle);
 262                data->state = STATE_INACTIVE;
 263                return 0;
 264        }
 265
 266out:
 267        IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
 268                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 269        data->state = STATE_INACTIVE;
 270        return -EINVAL;
 271}
 272
 273static struct ir_raw_handler rc6_handler = {
 274        .protocols      = RC_TYPE_RC6,
 275        .decode         = ir_rc6_decode,
 276};
 277
 278static int __init ir_rc6_decode_init(void)
 279{
 280        ir_raw_handler_register(&rc6_handler);
 281
 282        printk(KERN_INFO "IR RC6 protocol handler initialized\n");
 283        return 0;
 284}
 285
 286static void __exit ir_rc6_decode_exit(void)
 287{
 288        ir_raw_handler_unregister(&rc6_handler);
 289}
 290
 291module_init(ir_rc6_decode_init);
 292module_exit(ir_rc6_decode_exit);
 293
 294MODULE_LICENSE("GPL");
 295MODULE_AUTHOR("David H\xC3\xA4rdeman <david@hardeman.nu>");
 296MODULE_DESCRIPTION("RC6 IR protocol decoder");
 297