linux/drivers/media/IR/ir-rc5-decoder.c
<<
>>
Prefs
   1/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
   2 *
   3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
   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/*
  16 * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
  17 * There are other variants that use a different number of bits.
  18 * This is currently unsupported.
  19 * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
  20 * the first two bits are start bits, and a third one is a filing bit
  21 */
  22
  23#include "ir-core-priv.h"
  24
  25#define RC5_NBITS               14
  26#define RC5X_NBITS              20
  27#define CHECK_RC5X_NBITS        8
  28#define RC5_UNIT                888888 /* ns */
  29#define RC5_BIT_START           (1 * RC5_UNIT)
  30#define RC5_BIT_END             (1 * RC5_UNIT)
  31#define RC5X_SPACE              (4 * RC5_UNIT)
  32
  33/* Used to register rc5_decoder clients */
  34static LIST_HEAD(decoder_list);
  35static DEFINE_SPINLOCK(decoder_lock);
  36
  37enum rc5_state {
  38        STATE_INACTIVE,
  39        STATE_BIT_START,
  40        STATE_BIT_END,
  41        STATE_CHECK_RC5X,
  42        STATE_FINISHED,
  43};
  44
  45struct decoder_data {
  46        struct list_head        list;
  47        struct ir_input_dev     *ir_dev;
  48        int                     enabled:1;
  49
  50        /* State machine control */
  51        enum rc5_state          state;
  52        u32                     rc5_bits;
  53        struct ir_raw_event     prev_ev;
  54        unsigned                count;
  55        unsigned                wanted_bits;
  56};
  57
  58
  59/**
  60 * get_decoder_data()   - gets decoder data
  61 * @input_dev:  input device
  62 *
  63 * Returns the struct decoder_data that corresponds to a device
  64 */
  65
  66static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
  67{
  68        struct decoder_data *data = NULL;
  69
  70        spin_lock(&decoder_lock);
  71        list_for_each_entry(data, &decoder_list, list) {
  72                if (data->ir_dev == ir_dev)
  73                        break;
  74        }
  75        spin_unlock(&decoder_lock);
  76        return data;
  77}
  78
  79static ssize_t store_enabled(struct device *d,
  80                             struct device_attribute *mattr,
  81                             const char *buf,
  82                             size_t len)
  83{
  84        unsigned long value;
  85        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
  86        struct decoder_data *data = get_decoder_data(ir_dev);
  87
  88        if (!data)
  89                return -EINVAL;
  90
  91        if (strict_strtoul(buf, 10, &value) || value > 1)
  92                return -EINVAL;
  93
  94        data->enabled = value;
  95
  96        return len;
  97}
  98
  99static ssize_t show_enabled(struct device *d,
 100                             struct device_attribute *mattr, char *buf)
 101{
 102        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
 103        struct decoder_data *data = get_decoder_data(ir_dev);
 104
 105        if (!data)
 106                return -EINVAL;
 107
 108        if (data->enabled)
 109                return sprintf(buf, "1\n");
 110        else
 111        return sprintf(buf, "0\n");
 112}
 113
 114static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
 115
 116static struct attribute *decoder_attributes[] = {
 117        &dev_attr_enabled.attr,
 118        NULL
 119};
 120
 121static struct attribute_group decoder_attribute_group = {
 122        .name   = "rc5_decoder",
 123        .attrs  = decoder_attributes,
 124};
 125
 126/**
 127 * ir_rc5_decode() - Decode one RC-5 pulse or space
 128 * @input_dev:  the struct input_dev descriptor of the device
 129 * @ev:         the struct ir_raw_event descriptor of the pulse/space
 130 *
 131 * This function returns -EINVAL if the pulse violates the state machine
 132 */
 133static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 134{
 135        struct decoder_data *data;
 136        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 137        u8 toggle;
 138        u32 scancode;
 139
 140        data = get_decoder_data(ir_dev);
 141        if (!data)
 142                return -EINVAL;
 143
 144        if (!data->enabled)
 145                return 0;
 146
 147        if (IS_RESET(ev)) {
 148                data->state = STATE_INACTIVE;
 149                return 0;
 150        }
 151
 152        if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
 153                goto out;
 154
 155again:
 156        IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
 157                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 158
 159        if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
 160                return 0;
 161
 162        switch (data->state) {
 163
 164        case STATE_INACTIVE:
 165                if (!ev.pulse)
 166                        break;
 167
 168                data->state = STATE_BIT_START;
 169                data->count = 1;
 170                /* We just need enough bits to get to STATE_CHECK_RC5X */
 171                data->wanted_bits = RC5X_NBITS;
 172                decrease_duration(&ev, RC5_BIT_START);
 173                goto again;
 174
 175        case STATE_BIT_START:
 176                if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
 177                        break;
 178
 179                data->rc5_bits <<= 1;
 180                if (!ev.pulse)
 181                        data->rc5_bits |= 1;
 182                data->count++;
 183                data->prev_ev = ev;
 184                data->state = STATE_BIT_END;
 185                return 0;
 186
 187        case STATE_BIT_END:
 188                if (!is_transition(&ev, &data->prev_ev))
 189                        break;
 190
 191                if (data->count == data->wanted_bits)
 192                        data->state = STATE_FINISHED;
 193                else if (data->count == CHECK_RC5X_NBITS)
 194                        data->state = STATE_CHECK_RC5X;
 195                else
 196                        data->state = STATE_BIT_START;
 197
 198                decrease_duration(&ev, RC5_BIT_END);
 199                goto again;
 200
 201        case STATE_CHECK_RC5X:
 202                if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
 203                        /* RC5X */
 204                        data->wanted_bits = RC5X_NBITS;
 205                        decrease_duration(&ev, RC5X_SPACE);
 206                } else {
 207                        /* RC5 */
 208                        data->wanted_bits = RC5_NBITS;
 209                }
 210                data->state = STATE_BIT_START;
 211                goto again;
 212
 213        case STATE_FINISHED:
 214                if (ev.pulse)
 215                        break;
 216
 217                if (data->wanted_bits == RC5X_NBITS) {
 218                        /* RC5X */
 219                        u8 xdata, command, system;
 220                        xdata    = (data->rc5_bits & 0x0003F) >> 0;
 221                        command  = (data->rc5_bits & 0x00FC0) >> 6;
 222                        system   = (data->rc5_bits & 0x1F000) >> 12;
 223                        toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
 224                        command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
 225                        scancode = system << 16 | command << 8 | xdata;
 226
 227                        IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
 228                                   scancode, toggle);
 229
 230                } else {
 231                        /* RC5 */
 232                        u8 command, system;
 233                        command  = (data->rc5_bits & 0x0003F) >> 0;
 234                        system   = (data->rc5_bits & 0x007C0) >> 6;
 235                        toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
 236                        command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
 237                        scancode = system << 8 | command;
 238
 239                        IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
 240                                   scancode, toggle);
 241                }
 242
 243                ir_keydown(input_dev, scancode, toggle);
 244                data->state = STATE_INACTIVE;
 245                return 0;
 246        }
 247
 248out:
 249        IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
 250                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 251        data->state = STATE_INACTIVE;
 252        return -EINVAL;
 253}
 254
 255static int ir_rc5_register(struct input_dev *input_dev)
 256{
 257        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 258        struct decoder_data *data;
 259        int rc;
 260
 261        rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
 262        if (rc < 0)
 263                return rc;
 264
 265        data = kzalloc(sizeof(*data), GFP_KERNEL);
 266        if (!data) {
 267                sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
 268                return -ENOMEM;
 269        }
 270
 271        data->ir_dev = ir_dev;
 272        data->enabled = 1;
 273
 274        spin_lock(&decoder_lock);
 275        list_add_tail(&data->list, &decoder_list);
 276        spin_unlock(&decoder_lock);
 277
 278        return 0;
 279}
 280
 281static int ir_rc5_unregister(struct input_dev *input_dev)
 282{
 283        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 284        static struct decoder_data *data;
 285
 286        data = get_decoder_data(ir_dev);
 287        if (!data)
 288                return 0;
 289
 290        sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
 291
 292        spin_lock(&decoder_lock);
 293        list_del(&data->list);
 294        spin_unlock(&decoder_lock);
 295
 296        return 0;
 297}
 298
 299static struct ir_raw_handler rc5_handler = {
 300        .decode         = ir_rc5_decode,
 301        .raw_register   = ir_rc5_register,
 302        .raw_unregister = ir_rc5_unregister,
 303};
 304
 305static int __init ir_rc5_decode_init(void)
 306{
 307        ir_raw_handler_register(&rc5_handler);
 308
 309        printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
 310        return 0;
 311}
 312
 313static void __exit ir_rc5_decode_exit(void)
 314{
 315        ir_raw_handler_unregister(&rc5_handler);
 316}
 317
 318module_init(ir_rc5_decode_init);
 319module_exit(ir_rc5_decode_exit);
 320
 321MODULE_LICENSE("GPL");
 322MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 323MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
 324MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
 325