forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.5 KiB
173 lines
4.5 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* ImgTec IR Decoder setup for NEC protocol. |
|
* |
|
* Copyright 2010-2014 Imagination Technologies Ltd. |
|
*/ |
|
|
|
#include "img-ir-hw.h" |
|
#include <linux/bitrev.h> |
|
#include <linux/log2.h> |
|
|
|
/* Convert NEC data to a scancode */ |
|
static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, |
|
struct img_ir_scancode_req *request) |
|
{ |
|
unsigned int addr, addr_inv, data, data_inv; |
|
/* a repeat code has no data */ |
|
if (!len) |
|
return IMG_IR_REPEATCODE; |
|
if (len != 32) |
|
return -EINVAL; |
|
/* raw encoding: ddDDaaAA */ |
|
addr = (raw >> 0) & 0xff; |
|
addr_inv = (raw >> 8) & 0xff; |
|
data = (raw >> 16) & 0xff; |
|
data_inv = (raw >> 24) & 0xff; |
|
if ((data_inv ^ data) != 0xff) { |
|
/* 32-bit NEC (used by Apple and TiVo remotes) */ |
|
/* scan encoding: as transmitted, MSBit = first received bit */ |
|
request->scancode = bitrev8(addr) << 24 | |
|
bitrev8(addr_inv) << 16 | |
|
bitrev8(data) << 8 | |
|
bitrev8(data_inv); |
|
request->protocol = RC_PROTO_NEC32; |
|
} else if ((addr_inv ^ addr) != 0xff) { |
|
/* Extended NEC */ |
|
/* scan encoding: AAaaDD */ |
|
request->scancode = addr << 16 | |
|
addr_inv << 8 | |
|
data; |
|
request->protocol = RC_PROTO_NECX; |
|
} else { |
|
/* Normal NEC */ |
|
/* scan encoding: AADD */ |
|
request->scancode = addr << 8 | |
|
data; |
|
request->protocol = RC_PROTO_NEC; |
|
} |
|
return IMG_IR_SCANCODE; |
|
} |
|
|
|
/* Convert NEC scancode to NEC data filter */ |
|
static int img_ir_nec_filter(const struct rc_scancode_filter *in, |
|
struct img_ir_filter *out, u64 protocols) |
|
{ |
|
unsigned int addr, addr_inv, data, data_inv; |
|
unsigned int addr_m, addr_inv_m, data_m, data_inv_m; |
|
|
|
data = in->data & 0xff; |
|
data_m = in->mask & 0xff; |
|
|
|
protocols &= RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32; |
|
|
|
/* |
|
* If only one bit is set, we were requested to do an exact |
|
* protocol. This should be the case for wakeup filters; for |
|
* normal filters, guess the protocol from the scancode. |
|
*/ |
|
if (!is_power_of_2(protocols)) { |
|
if ((in->data | in->mask) & 0xff000000) |
|
protocols = RC_PROTO_BIT_NEC32; |
|
else if ((in->data | in->mask) & 0x00ff0000) |
|
protocols = RC_PROTO_BIT_NECX; |
|
else |
|
protocols = RC_PROTO_BIT_NEC; |
|
} |
|
|
|
if (protocols == RC_PROTO_BIT_NEC32) { |
|
/* 32-bit NEC (used by Apple and TiVo remotes) */ |
|
/* scan encoding: as transmitted, MSBit = first received bit */ |
|
addr = bitrev8(in->data >> 24); |
|
addr_m = bitrev8(in->mask >> 24); |
|
addr_inv = bitrev8(in->data >> 16); |
|
addr_inv_m = bitrev8(in->mask >> 16); |
|
data = bitrev8(in->data >> 8); |
|
data_m = bitrev8(in->mask >> 8); |
|
data_inv = bitrev8(in->data >> 0); |
|
data_inv_m = bitrev8(in->mask >> 0); |
|
} else if (protocols == RC_PROTO_BIT_NECX) { |
|
/* Extended NEC */ |
|
/* scan encoding AAaaDD */ |
|
addr = (in->data >> 16) & 0xff; |
|
addr_m = (in->mask >> 16) & 0xff; |
|
addr_inv = (in->data >> 8) & 0xff; |
|
addr_inv_m = (in->mask >> 8) & 0xff; |
|
data_inv = data ^ 0xff; |
|
data_inv_m = data_m; |
|
} else { |
|
/* Normal NEC */ |
|
/* scan encoding: AADD */ |
|
addr = (in->data >> 8) & 0xff; |
|
addr_m = (in->mask >> 8) & 0xff; |
|
addr_inv = addr ^ 0xff; |
|
addr_inv_m = addr_m; |
|
data_inv = data ^ 0xff; |
|
data_inv_m = data_m; |
|
} |
|
|
|
/* raw encoding: ddDDaaAA */ |
|
out->data = data_inv << 24 | |
|
data << 16 | |
|
addr_inv << 8 | |
|
addr; |
|
out->mask = data_inv_m << 24 | |
|
data_m << 16 | |
|
addr_inv_m << 8 | |
|
addr_m; |
|
return 0; |
|
} |
|
|
|
/* |
|
* NEC decoder |
|
* See also http://www.sbprojects.com/knowledge/ir/nec.php |
|
* http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol |
|
*/ |
|
struct img_ir_decoder img_ir_nec = { |
|
.type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32, |
|
.control = { |
|
.decoden = 1, |
|
.code_type = IMG_IR_CODETYPE_PULSEDIST, |
|
}, |
|
/* main timings */ |
|
.unit = 562500, /* 562.5 us */ |
|
.timings = { |
|
/* leader symbol */ |
|
.ldr = { |
|
.pulse = { 16 /* 9ms */ }, |
|
.space = { 8 /* 4.5ms */ }, |
|
}, |
|
/* 0 symbol */ |
|
.s00 = { |
|
.pulse = { 1 /* 562.5 us */ }, |
|
.space = { 1 /* 562.5 us */ }, |
|
}, |
|
/* 1 symbol */ |
|
.s01 = { |
|
.pulse = { 1 /* 562.5 us */ }, |
|
.space = { 3 /* 1687.5 us */ }, |
|
}, |
|
/* free time */ |
|
.ft = { |
|
.minlen = 32, |
|
.maxlen = 32, |
|
.ft_min = 10, /* 5.625 ms */ |
|
}, |
|
}, |
|
/* repeat codes */ |
|
.repeat = 108, /* 108 ms */ |
|
.rtimings = { |
|
/* leader symbol */ |
|
.ldr = { |
|
.space = { 4 /* 2.25 ms */ }, |
|
}, |
|
/* free time */ |
|
.ft = { |
|
.minlen = 0, /* repeat code has no data */ |
|
.maxlen = 0, |
|
}, |
|
}, |
|
/* scancode logic */ |
|
.scancode = img_ir_nec_scancode, |
|
.filter = img_ir_nec_filter, |
|
};
|
|
|