linux/drivers/media/rc/ir-jvc-decoder.c
<<
>>
Prefs
   1/* ir-jvc-decoder.c - handle JVC IR Pulse/Space 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 <linux/bitrev.h>
  16#include <linux/module.h>
  17#include "rc-core-priv.h"
  18
  19#define JVC_NBITS               16              /* dev(8) + func(8) */
  20#define JVC_UNIT                525000          /* ns */
  21#define JVC_HEADER_PULSE        (16 * JVC_UNIT) /* lack of header -> repeat */
  22#define JVC_HEADER_SPACE        (8  * JVC_UNIT)
  23#define JVC_BIT_PULSE           (1  * JVC_UNIT)
  24#define JVC_BIT_0_SPACE         (1  * JVC_UNIT)
  25#define JVC_BIT_1_SPACE         (3  * JVC_UNIT)
  26#define JVC_TRAILER_PULSE       (1  * JVC_UNIT)
  27#define JVC_TRAILER_SPACE       (35 * JVC_UNIT)
  28
  29enum jvc_state {
  30        STATE_INACTIVE,
  31        STATE_HEADER_SPACE,
  32        STATE_BIT_PULSE,
  33        STATE_BIT_SPACE,
  34        STATE_TRAILER_PULSE,
  35        STATE_TRAILER_SPACE,
  36        STATE_CHECK_REPEAT,
  37};
  38
  39/**
  40 * ir_jvc_decode() - Decode one JVC pulse or space
  41 * @dev:        the struct rc_dev descriptor of the device
  42 * @duration:   the struct ir_raw_event descriptor of the pulse/space
  43 *
  44 * This function returns -EINVAL if the pulse violates the state machine
  45 */
  46static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
  47{
  48        struct jvc_dec *data = &dev->raw->jvc;
  49
  50        if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))
  51                return 0;
  52
  53        if (!is_timing_event(ev)) {
  54                if (ev.reset)
  55                        data->state = STATE_INACTIVE;
  56                return 0;
  57        }
  58
  59        if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
  60                goto out;
  61
  62        IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
  63                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
  64
  65again:
  66        switch (data->state) {
  67
  68        case STATE_INACTIVE:
  69                if (!ev.pulse)
  70                        break;
  71
  72                if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
  73                        break;
  74
  75                data->count = 0;
  76                data->first = true;
  77                data->toggle = !data->toggle;
  78                data->state = STATE_HEADER_SPACE;
  79                return 0;
  80
  81        case STATE_HEADER_SPACE:
  82                if (ev.pulse)
  83                        break;
  84
  85                if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
  86                        break;
  87
  88                data->state = STATE_BIT_PULSE;
  89                return 0;
  90
  91        case STATE_BIT_PULSE:
  92                if (!ev.pulse)
  93                        break;
  94
  95                if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
  96                        break;
  97
  98                data->state = STATE_BIT_SPACE;
  99                return 0;
 100
 101        case STATE_BIT_SPACE:
 102                if (ev.pulse)
 103                        break;
 104
 105                data->bits <<= 1;
 106                if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
 107                        data->bits |= 1;
 108                        decrease_duration(&ev, JVC_BIT_1_SPACE);
 109                } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
 110                        decrease_duration(&ev, JVC_BIT_0_SPACE);
 111                else
 112                        break;
 113                data->count++;
 114
 115                if (data->count == JVC_NBITS)
 116                        data->state = STATE_TRAILER_PULSE;
 117                else
 118                        data->state = STATE_BIT_PULSE;
 119                return 0;
 120
 121        case STATE_TRAILER_PULSE:
 122                if (!ev.pulse)
 123                        break;
 124
 125                if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
 126                        break;
 127
 128                data->state = STATE_TRAILER_SPACE;
 129                return 0;
 130
 131        case STATE_TRAILER_SPACE:
 132                if (ev.pulse)
 133                        break;
 134
 135                if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
 136                        break;
 137
 138                if (data->first) {
 139                        u32 scancode;
 140                        scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
 141                                   (bitrev8((data->bits >> 0) & 0xff) << 0);
 142                        IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
 143                        rc_keydown(dev, scancode, data->toggle);
 144                        data->first = false;
 145                        data->old_bits = data->bits;
 146                } else if (data->bits == data->old_bits) {
 147                        IR_dprintk(1, "JVC repeat\n");
 148                        rc_repeat(dev);
 149                } else {
 150                        IR_dprintk(1, "JVC invalid repeat msg\n");
 151                        break;
 152                }
 153
 154                data->count = 0;
 155                data->state = STATE_CHECK_REPEAT;
 156                return 0;
 157
 158        case STATE_CHECK_REPEAT:
 159                if (!ev.pulse)
 160                        break;
 161
 162                if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
 163                        data->state = STATE_INACTIVE;
 164  else
 165                        data->state = STATE_BIT_PULSE;
 166                goto again;
 167        }
 168
 169out:
 170        IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
 171                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 172        data->state = STATE_INACTIVE;
 173        return -EINVAL;
 174}
 175
 176static struct ir_raw_handler jvc_handler = {
 177        .protocols      = RC_TYPE_JVC,
 178        .decode         = ir_jvc_decode,
 179};
 180
 181static int __init ir_jvc_decode_init(void)
 182{
 183        ir_raw_handler_register(&jvc_handler);
 184
 185        printk(KERN_INFO "IR JVC protocol handler initialized\n");
 186        return 0;
 187}
 188
 189static void __exit ir_jvc_decode_exit(void)
 190{
 191        ir_raw_handler_unregister(&jvc_handler);
 192}
 193
 194module_init(ir_jvc_decode_init);
 195module_exit(ir_jvc_decode_exit);
 196
 197MODULE_LICENSE("GPL");
 198MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
 199MODULE_DESCRIPTION("JVC IR protocol decoder");
 200