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