linux/drivers/media/rc/ir-jvc-decoder.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol
   3 *
   4 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
   5 */
   6
   7#include <linux/bitrev.h>
   8#include <linux/module.h>
   9#include "rc-core-priv.h"
  10
  11#define JVC_NBITS               16              /* dev(8) + func(8) */
  12#define JVC_UNIT                525             /* us */
  13#define JVC_HEADER_PULSE        (16 * JVC_UNIT) /* lack of header -> repeat */
  14#define JVC_HEADER_SPACE        (8  * JVC_UNIT)
  15#define JVC_BIT_PULSE           (1  * JVC_UNIT)
  16#define JVC_BIT_0_SPACE         (1  * JVC_UNIT)
  17#define JVC_BIT_1_SPACE         (3  * JVC_UNIT)
  18#define JVC_TRAILER_PULSE       (1  * JVC_UNIT)
  19#define JVC_TRAILER_SPACE       (35 * JVC_UNIT)
  20
  21enum jvc_state {
  22        STATE_INACTIVE,
  23        STATE_HEADER_SPACE,
  24        STATE_BIT_PULSE,
  25        STATE_BIT_SPACE,
  26        STATE_TRAILER_PULSE,
  27        STATE_TRAILER_SPACE,
  28        STATE_CHECK_REPEAT,
  29};
  30
  31/**
  32 * ir_jvc_decode() - Decode one JVC pulse or space
  33 * @dev:        the struct rc_dev descriptor of the device
  34 * @ev:   the struct ir_raw_event descriptor of the pulse/space
  35 *
  36 * This function returns -EINVAL if the pulse violates the state machine
  37 */
  38static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
  39{
  40        struct jvc_dec *data = &dev->raw->jvc;
  41
  42        if (!is_timing_event(ev)) {
  43                if (ev.reset)
  44                        data->state = STATE_INACTIVE;
  45                return 0;
  46        }
  47
  48        if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
  49                goto out;
  50
  51        dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n",
  52                data->state, ev.duration, TO_STR(ev.pulse));
  53
  54again:
  55        switch (data->state) {
  56
  57        case STATE_INACTIVE:
  58                if (!ev.pulse)
  59                        break;
  60
  61                if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
  62                        break;
  63
  64                data->count = 0;
  65                data->first = true;
  66                data->toggle = !data->toggle;
  67                data->state = STATE_HEADER_SPACE;
  68                return 0;
  69
  70        case STATE_HEADER_SPACE:
  71                if (ev.pulse)
  72                        break;
  73
  74                if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
  75                        break;
  76
  77                data->state = STATE_BIT_PULSE;
  78                return 0;
  79
  80        case STATE_BIT_PULSE:
  81                if (!ev.pulse)
  82                        break;
  83
  84                if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
  85                        break;
  86
  87                data->state = STATE_BIT_SPACE;
  88                return 0;
  89
  90        case STATE_BIT_SPACE:
  91                if (ev.pulse)
  92                        break;
  93
  94                data->bits <<= 1;
  95                if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
  96                        data->bits |= 1;
  97                        decrease_duration(&ev, JVC_BIT_1_SPACE);
  98                } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
  99                        decrease_duration(&ev, JVC_BIT_0_SPACE);
 100                else
 101                        break;
 102                data->count++;
 103
 104                if (data->count == JVC_NBITS)
 105                        data->state = STATE_TRAILER_PULSE;
 106                else
 107                        data->state = STATE_BIT_PULSE;
 108                return 0;
 109
 110        case STATE_TRAILER_PULSE:
 111                if (!ev.pulse)
 112                        break;
 113
 114                if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
 115                        break;
 116
 117                data->state = STATE_TRAILER_SPACE;
 118                return 0;
 119
 120        case STATE_TRAILER_SPACE:
 121                if (ev.pulse)
 122                        break;
 123
 124                if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
 125                        break;
 126
 127                if (data->first) {
 128                        u32 scancode;
 129                        scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
 130                                   (bitrev8((data->bits >> 0) & 0xff) << 0);
 131                        dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode);
 132                        rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle);
 133                        data->first = false;
 134                        data->old_bits = data->bits;
 135                } else if (data->bits == data->old_bits) {
 136                        dev_dbg(&dev->dev, "JVC repeat\n");
 137                        rc_repeat(dev);
 138                } else {
 139                        dev_dbg(&dev->dev, "JVC invalid repeat msg\n");
 140                        break;
 141                }
 142
 143                data->count = 0;
 144                data->state = STATE_CHECK_REPEAT;
 145                return 0;
 146
 147        case STATE_CHECK_REPEAT:
 148                if (!ev.pulse)
 149                        break;
 150
 151                if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
 152                        data->state = STATE_INACTIVE;
 153  else
 154                        data->state = STATE_BIT_PULSE;
 155                goto again;
 156        }
 157
 158out:
 159        dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n",
 160                data->state, ev.duration, TO_STR(ev.pulse));
 161        data->state = STATE_INACTIVE;
 162        return -EINVAL;
 163}
 164
 165static const struct ir_raw_timings_pd ir_jvc_timings = {
 166        .header_pulse  = JVC_HEADER_PULSE,
 167        .header_space  = JVC_HEADER_SPACE,
 168        .bit_pulse     = JVC_BIT_PULSE,
 169        .bit_space[0]  = JVC_BIT_0_SPACE,
 170        .bit_space[1]  = JVC_BIT_1_SPACE,
 171        .trailer_pulse = JVC_TRAILER_PULSE,
 172        .trailer_space = JVC_TRAILER_SPACE,
 173        .msb_first     = 1,
 174};
 175
 176/**
 177 * ir_jvc_encode() - Encode a scancode as a stream of raw events
 178 *
 179 * @protocol:   protocol to encode
 180 * @scancode:   scancode to encode
 181 * @events:     array of raw ir events to write into
 182 * @max:        maximum size of @events
 183 *
 184 * Returns:     The number of events written.
 185 *              -ENOBUFS if there isn't enough space in the array to fit the
 186 *              encoding. In this case all @max events will have been written.
 187 */
 188static int ir_jvc_encode(enum rc_proto protocol, u32 scancode,
 189                         struct ir_raw_event *events, unsigned int max)
 190{
 191        struct ir_raw_event *e = events;
 192        int ret;
 193        u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) |
 194                  (bitrev8((scancode >> 0) & 0xff) << 0);
 195
 196        ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw);
 197        if (ret < 0)
 198                return ret;
 199
 200        return e - events;
 201}
 202
 203static struct ir_raw_handler jvc_handler = {
 204        .protocols      = RC_PROTO_BIT_JVC,
 205        .decode         = ir_jvc_decode,
 206        .encode         = ir_jvc_encode,
 207        .carrier        = 38000,
 208        .min_timeout    = JVC_TRAILER_SPACE,
 209};
 210
 211static int __init ir_jvc_decode_init(void)
 212{
 213        ir_raw_handler_register(&jvc_handler);
 214
 215        printk(KERN_INFO "IR JVC protocol handler initialized\n");
 216        return 0;
 217}
 218
 219static void __exit ir_jvc_decode_exit(void)
 220{
 221        ir_raw_handler_unregister(&jvc_handler);
 222}
 223
 224module_init(ir_jvc_decode_init);
 225module_exit(ir_jvc_decode_exit);
 226
 227MODULE_LICENSE("GPL");
 228MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
 229MODULE_DESCRIPTION("JVC IR protocol decoder");
 230