linux/drivers/media/rc/img-ir/img-ir-nec.c
<<
>>
Prefs
   1/*
   2 * ImgTec IR Decoder setup for NEC protocol.
   3 *
   4 * Copyright 2010-2014 Imagination Technologies Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by the
   8 * Free Software Foundation; either version 2 of the License, or (at your
   9 * option) any later version.
  10 */
  11
  12#include "img-ir-hw.h"
  13#include <linux/bitrev.h>
  14#include <linux/log2.h>
  15
  16/* Convert NEC data to a scancode */
  17static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
  18                               struct img_ir_scancode_req *request)
  19{
  20        unsigned int addr, addr_inv, data, data_inv;
  21        /* a repeat code has no data */
  22        if (!len)
  23                return IMG_IR_REPEATCODE;
  24        if (len != 32)
  25                return -EINVAL;
  26        /* raw encoding: ddDDaaAA */
  27        addr     = (raw >>  0) & 0xff;
  28        addr_inv = (raw >>  8) & 0xff;
  29        data     = (raw >> 16) & 0xff;
  30        data_inv = (raw >> 24) & 0xff;
  31        if ((data_inv ^ data) != 0xff) {
  32                /* 32-bit NEC (used by Apple and TiVo remotes) */
  33                /* scan encoding: as transmitted, MSBit = first received bit */
  34                request->scancode = bitrev8(addr)     << 24 |
  35                                bitrev8(addr_inv) << 16 |
  36                                bitrev8(data)     <<  8 |
  37                                bitrev8(data_inv);
  38                request->protocol = RC_PROTO_NEC32;
  39        } else if ((addr_inv ^ addr) != 0xff) {
  40                /* Extended NEC */
  41                /* scan encoding: AAaaDD */
  42                request->scancode = addr     << 16 |
  43                                addr_inv <<  8 |
  44                                data;
  45                request->protocol = RC_PROTO_NECX;
  46        } else {
  47                /* Normal NEC */
  48                /* scan encoding: AADD */
  49                request->scancode = addr << 8 |
  50                                data;
  51                request->protocol = RC_PROTO_NEC;
  52        }
  53        return IMG_IR_SCANCODE;
  54}
  55
  56/* Convert NEC scancode to NEC data filter */
  57static int img_ir_nec_filter(const struct rc_scancode_filter *in,
  58                             struct img_ir_filter *out, u64 protocols)
  59{
  60        unsigned int addr, addr_inv, data, data_inv;
  61        unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
  62
  63        data       = in->data & 0xff;
  64        data_m     = in->mask & 0xff;
  65
  66        protocols &= RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32;
  67
  68        /*
  69         * If only one bit is set, we were requested to do an exact
  70         * protocol. This should be the case for wakeup filters; for
  71         * normal filters, guess the protocol from the scancode.
  72         */
  73        if (!is_power_of_2(protocols)) {
  74                if ((in->data | in->mask) & 0xff000000)
  75                        protocols = RC_PROTO_BIT_NEC32;
  76                else if ((in->data | in->mask) & 0x00ff0000)
  77                        protocols = RC_PROTO_BIT_NECX;
  78                else
  79                        protocols = RC_PROTO_BIT_NEC;
  80        }
  81
  82        if (protocols == RC_PROTO_BIT_NEC32) {
  83                /* 32-bit NEC (used by Apple and TiVo remotes) */
  84                /* scan encoding: as transmitted, MSBit = first received bit */
  85                addr       = bitrev8(in->data >> 24);
  86                addr_m     = bitrev8(in->mask >> 24);
  87                addr_inv   = bitrev8(in->data >> 16);
  88                addr_inv_m = bitrev8(in->mask >> 16);
  89                data       = bitrev8(in->data >>  8);
  90                data_m     = bitrev8(in->mask >>  8);
  91                data_inv   = bitrev8(in->data >>  0);
  92                data_inv_m = bitrev8(in->mask >>  0);
  93        } else if (protocols == RC_PROTO_BIT_NECX) {
  94                /* Extended NEC */
  95                /* scan encoding AAaaDD */
  96                addr       = (in->data >> 16) & 0xff;
  97                addr_m     = (in->mask >> 16) & 0xff;
  98                addr_inv   = (in->data >>  8) & 0xff;
  99                addr_inv_m = (in->mask >>  8) & 0xff;
 100                data_inv   = data ^ 0xff;
 101                data_inv_m = data_m;
 102        } else {
 103                /* Normal NEC */
 104                /* scan encoding: AADD */
 105                addr       = (in->data >>  8) & 0xff;
 106                addr_m     = (in->mask >>  8) & 0xff;
 107                addr_inv   = addr ^ 0xff;
 108                addr_inv_m = addr_m;
 109                data_inv   = data ^ 0xff;
 110                data_inv_m = data_m;
 111        }
 112
 113        /* raw encoding: ddDDaaAA */
 114        out->data = data_inv << 24 |
 115                    data     << 16 |
 116                    addr_inv <<  8 |
 117                    addr;
 118        out->mask = data_inv_m << 24 |
 119                    data_m     << 16 |
 120                    addr_inv_m <<  8 |
 121                    addr_m;
 122        return 0;
 123}
 124
 125/*
 126 * NEC decoder
 127 * See also http://www.sbprojects.com/knowledge/ir/nec.php
 128 *        http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol
 129 */
 130struct img_ir_decoder img_ir_nec = {
 131        .type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32,
 132        .control = {
 133                .decoden = 1,
 134                .code_type = IMG_IR_CODETYPE_PULSEDIST,
 135        },
 136        /* main timings */
 137        .unit = 562500, /* 562.5 us */
 138        .timings = {
 139                /* leader symbol */
 140                .ldr = {
 141                        .pulse = { 16   /* 9ms */ },
 142                        .space = { 8    /* 4.5ms */ },
 143                },
 144                /* 0 symbol */
 145                .s00 = {
 146                        .pulse = { 1    /* 562.5 us */ },
 147                        .space = { 1    /* 562.5 us */ },
 148                },
 149                /* 1 symbol */
 150                .s01 = {
 151                        .pulse = { 1    /* 562.5 us */ },
 152                        .space = { 3    /* 1687.5 us */ },
 153                },
 154                /* free time */
 155                .ft = {
 156                        .minlen = 32,
 157                        .maxlen = 32,
 158                        .ft_min = 10,   /* 5.625 ms */
 159                },
 160        },
 161        /* repeat codes */
 162        .repeat = 108,                  /* 108 ms */
 163        .rtimings = {
 164                /* leader symbol */
 165                .ldr = {
 166                        .space = { 4    /* 2.25 ms */ },
 167                },
 168                /* free time */
 169                .ft = {
 170                        .minlen = 0,    /* repeat code has no data */
 171                        .maxlen = 0,
 172                },
 173        },
 174        /* scancode logic */
 175        .scancode = img_ir_nec_scancode,
 176        .filter = img_ir_nec_filter,
 177};
 178