linux/drivers/media/rc/ir-sharp-decoder.c
<<
>>
Prefs
   1/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol
   2 *
   3 * Copyright (C) 2013-2014 Imagination Technologies Ltd.
   4 *
   5 * Based on NEC decoder:
   6 * Copyright (C) 2010 by Mauro Carvalho Chehab
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation version 2 of the License.
  11 *
  12 *  This program is distributed in the hope that it will be useful,
  13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *  GNU General Public License for more details.
  16 */
  17
  18#include <linux/bitrev.h>
  19#include <linux/module.h>
  20#include "rc-core-priv.h"
  21
  22#define SHARP_NBITS             15
  23#define SHARP_UNIT              40000  /* ns */
  24#define SHARP_BIT_PULSE         (8    * SHARP_UNIT) /* 320us */
  25#define SHARP_BIT_0_PERIOD      (25   * SHARP_UNIT) /* 1ms (680us space) */
  26#define SHARP_BIT_1_PERIOD      (50   * SHARP_UNIT) /* 2ms (1680ms space) */
  27#define SHARP_ECHO_SPACE        (1000 * SHARP_UNIT) /* 40 ms */
  28#define SHARP_TRAILER_SPACE     (125  * SHARP_UNIT) /* 5 ms (even longer) */
  29
  30enum sharp_state {
  31        STATE_INACTIVE,
  32        STATE_BIT_PULSE,
  33        STATE_BIT_SPACE,
  34        STATE_TRAILER_PULSE,
  35        STATE_ECHO_SPACE,
  36        STATE_TRAILER_SPACE,
  37};
  38
  39/**
  40 * ir_sharp_decode() - Decode one Sharp 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_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
  47{
  48        struct sharp_dec *data = &dev->raw->sharp;
  49        u32 msg, echo, address, command, scancode;
  50
  51        if (!is_timing_event(ev)) {
  52                if (ev.reset)
  53                        data->state = STATE_INACTIVE;
  54                return 0;
  55        }
  56
  57        IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
  58                   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
  59
  60        switch (data->state) {
  61
  62        case STATE_INACTIVE:
  63                if (!ev.pulse)
  64                        break;
  65
  66                if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
  67                               SHARP_BIT_PULSE / 2))
  68                        break;
  69
  70                data->count = 0;
  71                data->pulse_len = ev.duration;
  72                data->state = STATE_BIT_SPACE;
  73                return 0;
  74
  75        case STATE_BIT_PULSE:
  76                if (!ev.pulse)
  77                        break;
  78
  79                if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
  80                               SHARP_BIT_PULSE / 2))
  81                        break;
  82
  83                data->pulse_len = ev.duration;
  84                data->state = STATE_BIT_SPACE;
  85                return 0;
  86
  87        case STATE_BIT_SPACE:
  88                if (ev.pulse)
  89                        break;
  90
  91                data->bits <<= 1;
  92                if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
  93                              SHARP_BIT_PULSE * 2))
  94                        data->bits |= 1;
  95                else if (!eq_margin(data->pulse_len + ev.duration,
  96                                    SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
  97                        break;
  98                data->count++;
  99
 100                if (data->count == SHARP_NBITS ||
 101                    data->count == SHARP_NBITS * 2)
 102                        data->state = STATE_TRAILER_PULSE;
 103                else
 104                        data->state = STATE_BIT_PULSE;
 105
 106                return 0;
 107
 108        case STATE_TRAILER_PULSE:
 109                if (!ev.pulse)
 110                        break;
 111
 112                if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
 113                               SHARP_BIT_PULSE / 2))
 114                        break;
 115
 116                if (data->count == SHARP_NBITS) {
 117                        /* exp,chk bits should be 1,0 */
 118                        if ((data->bits & 0x3) != 0x2 &&
 119                        /* DENON variant, both chk bits 0 */
 120                            (data->bits & 0x3) != 0x0)
 121                                break;
 122                        data->state = STATE_ECHO_SPACE;
 123                } else {
 124                        data->state = STATE_TRAILER_SPACE;
 125                }
 126                return 0;
 127
 128        case STATE_ECHO_SPACE:
 129                if (ev.pulse)
 130                        break;
 131
 132                if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
 133                               SHARP_ECHO_SPACE / 4))
 134                        break;
 135
 136                data->state = STATE_BIT_PULSE;
 137
 138                return 0;
 139
 140        case STATE_TRAILER_SPACE:
 141                if (ev.pulse)
 142                        break;
 143
 144                if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
 145                                SHARP_BIT_PULSE / 2))
 146                        break;
 147
 148                /* Validate - command, ext, chk should be inverted in 2nd */
 149                msg = (data->bits >> 15) & 0x7fff;
 150                echo = data->bits & 0x7fff;
 151                if ((msg ^ echo) != 0x3ff) {
 152                        IR_dprintk(1,
 153                                   "Sharp checksum error: received 0x%04x, 0x%04x\n",
 154                                   msg, echo);
 155                        break;
 156                }
 157
 158                address = bitrev8((msg >> 7) & 0xf8);
 159                command = bitrev8((msg >> 2) & 0xff);
 160
 161                scancode = address << 8 | command;
 162                IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
 163
 164                rc_keydown(dev, RC_TYPE_SHARP, scancode, 0);
 165                data->state = STATE_INACTIVE;
 166                return 0;
 167        }
 168
 169        IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
 170                   data->count, data->state, TO_US(ev.duration),
 171                   TO_STR(ev.pulse));
 172        data->state = STATE_INACTIVE;
 173        return -EINVAL;
 174}
 175
 176static struct ir_raw_handler sharp_handler = {
 177        .protocols      = RC_BIT_SHARP,
 178        .decode         = ir_sharp_decode,
 179};
 180
 181static int __init ir_sharp_decode_init(void)
 182{
 183        ir_raw_handler_register(&sharp_handler);
 184
 185        pr_info("IR Sharp protocol handler initialized\n");
 186        return 0;
 187}
 188
 189static void __exit ir_sharp_decode_exit(void)
 190{
 191        ir_raw_handler_unregister(&sharp_handler);
 192}
 193
 194module_init(ir_sharp_decode_init);
 195module_exit(ir_sharp_decode_exit);
 196
 197MODULE_LICENSE("GPL");
 198MODULE_AUTHOR("James Hogan <james.hogan@imgtec.com>");
 199MODULE_DESCRIPTION("Sharp IR protocol decoder");
 200