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ärdeman <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        enum rc_type protocol;
  92
  93        if (!is_timing_event(ev)) {
  94                if (ev.reset)
  95                        data->state = STATE_INACTIVE;
  96                return 0;
  97        }
  98
  99        if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
 100                goto out;
 101
 102again:
 103        IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
 104                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 105
 106        if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
 107                return 0;
 108
 109        switch (data->state) {
 110
 111        case STATE_INACTIVE:
 112                if (!ev.pulse)
 113                        break;
 114
 115                /* Note: larger margin on first pulse since each RC6_UNIT
 116                   is quite short and some hardware takes some time to
 117                   adjust to the signal */
 118                if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
 119                        break;
 120
 121                data->state = STATE_PREFIX_SPACE;
 122                data->count = 0;
 123                return 0;
 124
 125        case STATE_PREFIX_SPACE:
 126                if (ev.pulse)
 127                        break;
 128
 129                if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
 130                        break;
 131
 132                data->state = STATE_HEADER_BIT_START;
 133                data->header = 0;
 134                return 0;
 135
 136        case STATE_HEADER_BIT_START:
 137                if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
 138                        break;
 139
 140                data->header <<= 1;
 141                if (ev.pulse)
 142                        data->header |= 1;
 143                data->count++;
 144                data->state = STATE_HEADER_BIT_END;
 145                return 0;
 146
 147        case STATE_HEADER_BIT_END:
 148                if (!is_transition(&ev, &dev->raw->prev_ev))
 149                        break;
 150
 151                if (data->count == RC6_HEADER_NBITS)
 152                        data->state = STATE_TOGGLE_START;
 153                else
 154                        data->state = STATE_HEADER_BIT_START;
 155
 156                decrease_duration(&ev, RC6_BIT_END);
 157                goto again;
 158
 159        case STATE_TOGGLE_START:
 160                if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
 161                        break;
 162
 163                data->toggle = ev.pulse;
 164                data->state = STATE_TOGGLE_END;
 165                return 0;
 166
 167        case STATE_TOGGLE_END:
 168                if (!is_transition(&ev, &dev->raw->prev_ev) ||
 169                    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
 170                        break;
 171
 172                if (!(data->header & RC6_STARTBIT_MASK)) {
 173                        IR_dprintk(1, "RC6 invalid start bit\n");
 174                        break;
 175                }
 176
 177                data->state = STATE_BODY_BIT_START;
 178                decrease_duration(&ev, RC6_TOGGLE_END);
 179                data->count = 0;
 180                data->body = 0;
 181
 182                switch (rc6_mode(data)) {
 183                case RC6_MODE_0:
 184                        data->wanted_bits = RC6_0_NBITS;
 185                        break;
 186                case RC6_MODE_6A:
 187                        data->wanted_bits = RC6_6A_NBITS;
 188                        break;
 189                default:
 190                        IR_dprintk(1, "RC6 unknown mode\n");
 191                        goto out;
 192                }
 193                goto again;
 194
 195        case STATE_BODY_BIT_START:
 196                if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
 197                        /* Discard LSB's that won't fit in data->body */
 198                        if (data->count++ < CHAR_BIT * sizeof data->body) {
 199                                data->body <<= 1;
 200                                if (ev.pulse)
 201                                        data->body |= 1;
 202                        }
 203                        data->state = STATE_BODY_BIT_END;
 204                        return 0;
 205                } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
 206                                geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
 207                        data->state = STATE_FINISHED;
 208                        goto again;
 209                }
 210                break;
 211
 212        case STATE_BODY_BIT_END:
 213                if (!is_transition(&ev, &dev->raw->prev_ev))
 214                        break;
 215
 216                if (data->count == data->wanted_bits)
 217                        data->state = STATE_FINISHED;
 218                else
 219                        data->state = STATE_BODY_BIT_START;
 220
 221                decrease_duration(&ev, RC6_BIT_END);
 222                goto again;
 223
 224        case STATE_FINISHED:
 225                if (ev.pulse)
 226                        break;
 227
 228                switch (rc6_mode(data)) {
 229                case RC6_MODE_0:
 230                        scancode = data->body;
 231                        toggle = data->toggle;
 232                        protocol = RC_TYPE_RC6_0;
 233                        IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
 234                                   scancode, toggle);
 235                        break;
 236
 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                        switch (data->count) {
 246                        case 20:
 247                                protocol = RC_TYPE_RC6_6A_20;
 248                                toggle = 0;
 249                                break;
 250                        case 24:
 251                                protocol = RC_TYPE_RC6_6A_24;
 252                                toggle = 0;
 253                                break;
 254                        case 32:
 255                                if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
 256                                        protocol = RC_TYPE_RC6_MCE;
 257                                        toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
 258                                        scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
 259                                } else {
 260                                        protocol = RC_TYPE_RC6_6A_32;
 261                                        toggle = 0;
 262                                }
 263                                break;
 264                        default:
 265                                IR_dprintk(1, "RC6(6A) unsupported length\n");
 266                                goto out;
 267                        }
 268
 269                        IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
 270                                   protocol, scancode, toggle);
 271                        break;
 272                default:
 273                        IR_dprintk(1, "RC6 unknown mode\n");
 274                        goto out;
 275                }
 276
 277                rc_keydown(dev, protocol, scancode, toggle);
 278                data->state = STATE_INACTIVE;
 279                return 0;
 280        }
 281
 282out:
 283        IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
 284                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 285        data->state = STATE_INACTIVE;
 286        return -EINVAL;
 287}
 288
 289static struct ir_raw_handler rc6_handler = {
 290        .protocols      = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
 291                          RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
 292                          RC_BIT_RC6_MCE,
 293        .decode         = ir_rc6_decode,
 294};
 295
 296static int __init ir_rc6_decode_init(void)
 297{
 298        ir_raw_handler_register(&rc6_handler);
 299
 300        printk(KERN_INFO "IR RC6 protocol handler initialized\n");
 301        return 0;
 302}
 303
 304static void __exit ir_rc6_decode_exit(void)
 305{
 306        ir_raw_handler_unregister(&rc6_handler);
 307}
 308
 309module_init(ir_rc6_decode_init);
 310module_exit(ir_rc6_decode_exit);
 311
 312MODULE_LICENSE("GPL");
 313MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
 314MODULE_DESCRIPTION("RC6 IR protocol decoder");
 315