This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:
Subject: ir-keytable: show lirc device and make test show lirc scancodes Author: Sean Young <s...@mess.org> Date: Mon Sep 25 09:09:24 2017 +0100 Now you can see what protocol any remote is using the following command. $ ir-keytable -c -p all -t Old keytable cleared Protocols changed to lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp Testing events. Please, press CTRL-C to abort. 2124.576099: lirc protocol(rc5): scancode = 0x1e11 2124.576143: event type EV_MSC(0x04): scancode = 0x1e11 2124.576143: event type EV_SYN(0x00). 2125.601002: lirc protocol(rc6_mce): scancode = 0x800f0410 2125.601051: event type EV_MSC(0x04): scancode = 0x800f0410 2125.601051: event type EV_SYN(0x00). Signed-off-by: Sean Young <s...@mess.org> utils/common/ir-encode.c | 453 +++++++++++++++++++++++++++++++++++++++++++++ utils/common/ir-encode.h | 15 ++ utils/ir-ctl/ir-encode.c | 450 +------------------------------------------- utils/ir-ctl/ir-encode.h | 16 +- utils/keytable/Makefile.am | 2 +- utils/keytable/ir-encode.c | 1 + utils/keytable/ir-encode.h | 1 + utils/keytable/keytable.c | 122 +++++++++++- 8 files changed, 589 insertions(+), 471 deletions(-) --- http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=f0b56a9ed19e29e358161112b081ca1605f2517a diff --git a/utils/common/ir-encode.c b/utils/common/ir-encode.c new file mode 100644 index 000000000000..8f486dacfa3b --- /dev/null +++ b/utils/common/ir-encode.c @@ -0,0 +1,453 @@ +/* + * ir-encode.c - encodes IR scancodes in different protocols + * + * Copyright (C) 2016 Sean Young <s...@mess.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * TODO: XMP protocol and MCE keyboard + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <ctype.h> + +#include <linux/lirc.h> + +#include "ir-encode.h" + +#define NS_TO_US(x) (((x)+500)/1000) + +static int nec_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const int nec_unit = 562500; + int n = 0; + + void add_byte(unsigned bits) + { + int i; + for (i=0; i<8; i++) { + buf[n++] = NS_TO_US(nec_unit); + if (bits & (1 << i)) + buf[n++] = NS_TO_US(nec_unit * 3); + else + buf[n++] = NS_TO_US(nec_unit); + } + } + + buf[n++] = NS_TO_US(nec_unit * 16); + buf[n++] = NS_TO_US(nec_unit * 8); + + switch (proto) { + default: + return 0; + case RC_PROTO_NEC: + add_byte(scancode >> 8); + add_byte(~(scancode >> 8)); + add_byte(scancode); + add_byte(~scancode); + break; + case RC_PROTO_NECX: + add_byte(scancode >> 16); + add_byte(scancode >> 8); + add_byte(scancode); + add_byte(~scancode); + break; + case RC_PROTO_NEC32: + /* + * At the time of writing kernel software nec decoder + * reverses the bit order so it will not match. Hardware + * decoders do not have this issue. + */ + add_byte(scancode >> 24); + add_byte(scancode >> 16); + add_byte(scancode >> 8); + add_byte(scancode); + break; + } + + buf[n++] = NS_TO_US(nec_unit); + + return n; +} + +static int jvc_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const int jvc_unit = 525000; + int i; + + /* swap bytes so address comes first */ + scancode = ((scancode << 8) & 0xff00) | ((scancode >> 8) & 0x00ff); + + *buf++ = NS_TO_US(jvc_unit * 16); + *buf++ = NS_TO_US(jvc_unit * 8); + + for (i=0; i<16; i++) { + *buf++ = NS_TO_US(jvc_unit); + + if (scancode & 1) + *buf++ = NS_TO_US(jvc_unit * 3); + else + *buf++ = NS_TO_US(jvc_unit); + + scancode >>= 1; + } + + *buf = NS_TO_US(jvc_unit); + + return 35; +} + +static int sanyo_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const int sanyo_unit = 562500; + + void add_bits(int bits, int count) + { + int i; + for (i=0; i<count; i++) { + *buf++ = NS_TO_US(sanyo_unit); + + if (bits & (1 << i)) + *buf++ = NS_TO_US(sanyo_unit * 3); + else + *buf++ = NS_TO_US(sanyo_unit); + } + } + + *buf++ = NS_TO_US(sanyo_unit * 16); + *buf++ = NS_TO_US(sanyo_unit * 8); + + add_bits(scancode >> 8, 13); + add_bits(~(scancode >> 8), 13); + add_bits(scancode, 8); + add_bits(~scancode, 8); + + *buf = NS_TO_US(sanyo_unit); + + return 87; +} + +static int sharp_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const int sharp_unit = 40000; + + void add_bits(int bits, int count) + { + int i; + for (i=0; i<count; i++) { + *buf++ = NS_TO_US(sharp_unit * 8); + + if (bits & (1 << i)) + *buf++ = NS_TO_US(sharp_unit * 50); + else + *buf++ = NS_TO_US(sharp_unit * 25); + } + } + + add_bits(scancode >> 8, 5); + add_bits(scancode, 8); + add_bits(1, 2); + + *buf++ = NS_TO_US(sharp_unit * 8); + *buf++ = NS_TO_US(sharp_unit * 1000); + + add_bits(scancode >> 8, 5); + add_bits(~scancode, 8); + add_bits(~1, 2); + *buf++ = NS_TO_US(sharp_unit * 8); + + return (13 + 2) * 4 + 3; +} + +static int sony_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const int sony_unit = 600000; + int n = 0; + + void add_bits(int bits, int count) + { + int i; + for (i=0; i<count; i++) { + if (bits & (1 << i)) + buf[n++] = NS_TO_US(sony_unit * 2); + else + buf[n++] = NS_TO_US(sony_unit); + + buf[n++] = NS_TO_US(sony_unit); + } + } + + buf[n++] = NS_TO_US(sony_unit * 4); + buf[n++] = NS_TO_US(sony_unit); + + switch (proto) { + case RC_PROTO_SONY12: + add_bits(scancode, 7); + add_bits(scancode >> 16, 5); + break; + case RC_PROTO_SONY15: + add_bits(scancode, 7); + add_bits(scancode >> 16, 8); + break; + case RC_PROTO_SONY20: + add_bits(scancode, 7); + add_bits(scancode >> 16, 5); + add_bits(scancode >> 8, 8); + break; + default: + return 0; + } + + /* ignore last space */ + return n - 1; +} + +static int rc5_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const unsigned int rc5_unit = 888888; + unsigned n = 0; + + void advance_space(unsigned length) + { + if (n % 2) + buf[n] += length; + else + buf[++n] = length; + } + + void advance_pulse(unsigned length) + { + if (n % 2) + buf[++n] = length; + else + buf[n] += length; + } + + void add_bits(int bits, int count) + { + while (count--) { + if (bits & (1 << count)) { + advance_space(NS_TO_US(rc5_unit)); + advance_pulse(NS_TO_US(rc5_unit)); + } else { + advance_pulse(NS_TO_US(rc5_unit)); + advance_space(NS_TO_US(rc5_unit)); + } + } + } + + buf[n] = NS_TO_US(rc5_unit); + + switch (proto) { + default: + return 0; + case RC_PROTO_RC5: + add_bits(!(scancode & 0x40), 1); + add_bits(0, 1); + add_bits(scancode >> 8, 5); + add_bits(scancode, 6); + break; + case RC_PROTO_RC5_SZ: + add_bits(!!(scancode & 0x2000), 1); + add_bits(0, 1); + add_bits(scancode >> 6, 6); + add_bits(scancode, 6); + break; + case RC_PROTO_RC5X_20: + add_bits(!(scancode & 0x4000), 1); + add_bits(0, 1); + add_bits(scancode >> 16, 5); + advance_space(NS_TO_US(rc5_unit * 4)); + add_bits(scancode >> 8, 6); + add_bits(scancode, 6); + break; + } + + /* drop any trailing pulse */ + return (n % 2) ? n : n + 1; +} + +static int rc6_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + const unsigned int rc6_unit = 444444; + unsigned n = 0; + + void advance_space(unsigned length) + { + if (n % 2) + buf[n] += length; + else + buf[++n] = length; + } + + void advance_pulse(unsigned length) + { + if (n % 2) + buf[++n] = length; + else + buf[n] += length; + } + + void add_bits(unsigned bits, unsigned count, unsigned length) + { + while (count--) { + if (bits & (1 << count)) { + advance_pulse(length); + advance_space(length); + } else { + advance_space(length); + advance_pulse(length); + } + } + } + + buf[n++] = NS_TO_US(rc6_unit * 6); + buf[n++] = NS_TO_US(rc6_unit * 2); + buf[n] = 0; + + switch (proto) { + default: + return 0; + case RC_PROTO_RC6_0: + add_bits(8, 4, NS_TO_US(rc6_unit)); + add_bits(0, 1, NS_TO_US(rc6_unit * 2)); + add_bits(scancode, 16, NS_TO_US(rc6_unit)); + break; + case RC_PROTO_RC6_6A_20: + add_bits(14, 4, NS_TO_US(rc6_unit)); + add_bits(0, 1, NS_TO_US(rc6_unit * 2)); + add_bits(scancode, 20, NS_TO_US(rc6_unit)); + break; + case RC_PROTO_RC6_6A_24: + add_bits(14, 4, NS_TO_US(rc6_unit)); + add_bits(0, 1, NS_TO_US(rc6_unit * 2)); + add_bits(scancode, 24, NS_TO_US(rc6_unit)); + break; + case RC_PROTO_RC6_6A_32: + case RC_PROTO_RC6_MCE: + add_bits(14, 4, NS_TO_US(rc6_unit)); + add_bits(0, 1, NS_TO_US(rc6_unit * 2)); + add_bits(scancode, 32, NS_TO_US(rc6_unit)); + break; + } + + /* drop any trailing pulse */ + return (n % 2) ? n : n + 1; +} + +static const struct { + char name[10]; + unsigned scancode_mask; + unsigned max_edges; + unsigned carrier; + int (*encode)(enum rc_proto proto, unsigned scancode, unsigned *buf); +} encoders[] = { + [RC_PROTO_RC5] = { "rc5", 0x1f7f, 24, 36000, rc5_encode }, + [RC_PROTO_RC5X_20] = { "rc5x_20", 0x1f7f3f, 40, 36000, rc5_encode }, + [RC_PROTO_RC5_SZ] = { "rc5_sz", 0x2fff, 26, 36000, rc5_encode }, + [RC_PROTO_SONY12] = { "sony12", 0x1f007f, 25, 40000, sony_encode }, + [RC_PROTO_SONY15] = { "sony15", 0xff007f, 31, 40000, sony_encode }, + [RC_PROTO_SONY20] = { "sony20", 0x1fff7f, 41, 40000, sony_encode }, + [RC_PROTO_JVC] = { "jvc", 0xffff, 35, 38000, jvc_encode }, + [RC_PROTO_NEC] = { "nec", 0xffff, 67, 38000, nec_encode }, + [RC_PROTO_NECX] = { "necx", 0xffffff, 67, 38000, nec_encode }, + [RC_PROTO_NEC32] = { "nec32", 0xffffffff, 67, 38000, nec_encode }, + [RC_PROTO_SANYO] = { "sanyo", 0x1fffff, 87, 38000, sanyo_encode }, + [RC_PROTO_RC6_0] = { "rc6_0", 0xffff, 24, 36000, rc6_encode }, + [RC_PROTO_RC6_6A_20] = { "rc6_6a_20", 0xfffff, 52, 36000, rc6_encode }, + [RC_PROTO_RC6_6A_24] = { "rc6_6a_24", 0xffffff, 60, 36000, rc6_encode }, + [RC_PROTO_RC6_6A_32] = { "rc6_6a_32", 0xffffffff, 76, 36000, rc6_encode }, + [RC_PROTO_RC6_MCE] = { "rc6_mce", 0xffff7fff, 76, 36000, rc6_encode }, + [RC_PROTO_SHARP] = { "sharp", 0x1fff, 63, 38000, sharp_encode }, +}; + +static bool str_like(const char *a, const char *b) +{ + while (*a && *b) { + while (*a == ' ' || *a == '-' || *a == '_') + a++; + while (*b == ' ' || *b == '-' || *b == '_') + b++; + + if (*a >= 0x7f || *b >= 0x7f) + return false; + + if (tolower(*a) != tolower(*b)) + return false; + + a++; b++; + } + + return !*a && !*b; +} + +bool protocol_match(const char *name, enum rc_proto *proto) +{ + enum rc_proto p; + + for (p=0; p<ARRAY_SIZE(encoders); p++) { + if (str_like(encoders[p].name, name)) { + *proto = p; + return true; + } + } + + return false; +} + +unsigned protocol_carrier(enum rc_proto proto) +{ + return encoders[proto].carrier; +} + +unsigned protocol_max_size(enum rc_proto proto) +{ + return encoders[proto].max_edges; +} + +unsigned protocol_scancode_mask(enum rc_proto proto) +{ + return encoders[proto].scancode_mask; +} + +bool protocol_scancode_valid(enum rc_proto p, unsigned s) +{ + if (s & ~encoders[p].scancode_mask) + return false; + + if (p == RC_PROTO_NECX) { + return (((s >> 16) ^ ~(s >> 8)) & 0xff) != 0; + } else if (p == RC_PROTO_NEC32) { + return (((s >> 24) ^ ~(s >> 16)) & 0xff) != 0; + } else if (p == RC_PROTO_RC6_MCE) { + return (s & 0xffff0000) == 0x800f0000; + } else if (p == RC_PROTO_RC6_6A_32) { + return (s & 0xffff0000) != 0x800f0000; + } + + return true; +} + +unsigned protocol_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) +{ + return encoders[proto].encode(proto, scancode, buf); +} + +const char* protocol_name(enum rc_proto proto) +{ + if (proto >= ARRAY_SIZE(encoders)) + return NULL; + + return encoders[proto].name; +} diff --git a/utils/common/ir-encode.h b/utils/common/ir-encode.h new file mode 100644 index 000000000000..6e9c623e3548 --- /dev/null +++ b/utils/common/ir-encode.h @@ -0,0 +1,15 @@ + +#ifndef __IR_ENCODE_H__ +#define __IR_ENCODE_H__ + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) + +bool protocol_match(const char *name, enum rc_proto *proto); +unsigned protocol_carrier(enum rc_proto proto); +unsigned protocol_max_size(enum rc_proto proto); +bool protocol_scancode_valid(enum rc_proto proto, unsigned scancode); +unsigned protocol_scancode_mask(enum rc_proto proto); +unsigned protocol_encode(enum rc_proto proto, unsigned scancode, unsigned *buf); +const char *protocol_name(enum rc_proto proto); + +#endif diff --git a/utils/ir-ctl/ir-encode.c b/utils/ir-ctl/ir-encode.c deleted file mode 100644 index 8a12562868a7..000000000000 --- a/utils/ir-ctl/ir-encode.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * ir-encode.c - encodes IR scancodes in different protocols - * - * Copyright (C) 2016 Sean Young <s...@mess.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * TODO: XMP protocol and MCE keyboard - */ - -#include <stdbool.h> -#include <stdint.h> -#include <ctype.h> - -#include <linux/lirc.h> - -#include "ir-encode.h" - -#define NS_TO_US(x) (((x)+500)/1000) - -static int nec_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const int nec_unit = 562500; - int n = 0; - - void add_byte(unsigned bits) - { - int i; - for (i=0; i<8; i++) { - buf[n++] = NS_TO_US(nec_unit); - if (bits & (1 << i)) - buf[n++] = NS_TO_US(nec_unit * 3); - else - buf[n++] = NS_TO_US(nec_unit); - } - } - - buf[n++] = NS_TO_US(nec_unit * 16); - buf[n++] = NS_TO_US(nec_unit * 8); - - switch (proto) { - default: - return 0; - case RC_PROTO_NEC: - add_byte(scancode >> 8); - add_byte(~(scancode >> 8)); - add_byte(scancode); - add_byte(~scancode); - break; - case RC_PROTO_NECX: - add_byte(scancode >> 16); - add_byte(scancode >> 8); - add_byte(scancode); - add_byte(~scancode); - break; - case RC_PROTO_NEC32: - /* - * At the time of writing kernel software nec decoder - * reverses the bit order so it will not match. Hardware - * decoders do not have this issue. - */ - add_byte(scancode >> 24); - add_byte(scancode >> 16); - add_byte(scancode >> 8); - add_byte(scancode); - break; - } - - buf[n++] = NS_TO_US(nec_unit); - - return n; -} - -static int jvc_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const int jvc_unit = 525000; - int i; - - /* swap bytes so address comes first */ - scancode = ((scancode << 8) & 0xff00) | ((scancode >> 8) & 0x00ff); - - *buf++ = NS_TO_US(jvc_unit * 16); - *buf++ = NS_TO_US(jvc_unit * 8); - - for (i=0; i<16; i++) { - *buf++ = NS_TO_US(jvc_unit); - - if (scancode & 1) - *buf++ = NS_TO_US(jvc_unit * 3); - else - *buf++ = NS_TO_US(jvc_unit); - - scancode >>= 1; - } - - *buf = NS_TO_US(jvc_unit); - - return 35; -} - -static int sanyo_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const int sanyo_unit = 562500; - - void add_bits(int bits, int count) - { - int i; - for (i=0; i<count; i++) { - *buf++ = NS_TO_US(sanyo_unit); - - if (bits & (1 << i)) - *buf++ = NS_TO_US(sanyo_unit * 3); - else - *buf++ = NS_TO_US(sanyo_unit); - } - } - - *buf++ = NS_TO_US(sanyo_unit * 16); - *buf++ = NS_TO_US(sanyo_unit * 8); - - add_bits(scancode >> 8, 13); - add_bits(~(scancode >> 8), 13); - add_bits(scancode, 8); - add_bits(~scancode, 8); - - *buf = NS_TO_US(sanyo_unit); - - return 87; -} - -static int sharp_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const int sharp_unit = 40000; - - void add_bits(int bits, int count) - { - int i; - for (i=0; i<count; i++) { - *buf++ = NS_TO_US(sharp_unit * 8); - - if (bits & (1 << i)) - *buf++ = NS_TO_US(sharp_unit * 50); - else - *buf++ = NS_TO_US(sharp_unit * 25); - } - } - - add_bits(scancode >> 8, 5); - add_bits(scancode, 8); - add_bits(1, 2); - - *buf++ = NS_TO_US(sharp_unit * 8); - *buf++ = NS_TO_US(sharp_unit * 1000); - - add_bits(scancode >> 8, 5); - add_bits(~scancode, 8); - add_bits(~1, 2); - *buf++ = NS_TO_US(sharp_unit * 8); - - return (13 + 2) * 4 + 3; -} - -static int sony_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const int sony_unit = 600000; - int n = 0; - - void add_bits(int bits, int count) - { - int i; - for (i=0; i<count; i++) { - if (bits & (1 << i)) - buf[n++] = NS_TO_US(sony_unit * 2); - else - buf[n++] = NS_TO_US(sony_unit); - - buf[n++] = NS_TO_US(sony_unit); - } - } - - buf[n++] = NS_TO_US(sony_unit * 4); - buf[n++] = NS_TO_US(sony_unit); - - switch (proto) { - case RC_PROTO_SONY12: - add_bits(scancode, 7); - add_bits(scancode >> 16, 5); - break; - case RC_PROTO_SONY15: - add_bits(scancode, 7); - add_bits(scancode >> 16, 8); - break; - case RC_PROTO_SONY20: - add_bits(scancode, 7); - add_bits(scancode >> 16, 5); - add_bits(scancode >> 8, 8); - break; - default: - return 0; - } - - /* ignore last space */ - return n - 1; -} - -static int rc5_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const unsigned int rc5_unit = 888888; - unsigned n = 0; - - void advance_space(unsigned length) - { - if (n % 2) - buf[n] += length; - else - buf[++n] = length; - } - - void advance_pulse(unsigned length) - { - if (n % 2) - buf[++n] = length; - else - buf[n] += length; - } - - void add_bits(int bits, int count) - { - while (count--) { - if (bits & (1 << count)) { - advance_space(NS_TO_US(rc5_unit)); - advance_pulse(NS_TO_US(rc5_unit)); - } else { - advance_pulse(NS_TO_US(rc5_unit)); - advance_space(NS_TO_US(rc5_unit)); - } - } - } - - buf[n] = NS_TO_US(rc5_unit); - - switch (proto) { - default: - return 0; - case RC_PROTO_RC5: - add_bits(!(scancode & 0x40), 1); - add_bits(0, 1); - add_bits(scancode >> 8, 5); - add_bits(scancode, 6); - break; - case RC_PROTO_RC5_SZ: - add_bits(!!(scancode & 0x2000), 1); - add_bits(0, 1); - add_bits(scancode >> 6, 6); - add_bits(scancode, 6); - break; - case RC_PROTO_RC5X_20: - add_bits(!(scancode & 0x4000), 1); - add_bits(0, 1); - add_bits(scancode >> 16, 5); - advance_space(NS_TO_US(rc5_unit * 4)); - add_bits(scancode >> 8, 6); - add_bits(scancode, 6); - break; - } - - /* drop any trailing pulse */ - return (n % 2) ? n : n + 1; -} - -static int rc6_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - const unsigned int rc6_unit = 444444; - unsigned n = 0; - - void advance_space(unsigned length) - { - if (n % 2) - buf[n] += length; - else - buf[++n] = length; - } - - void advance_pulse(unsigned length) - { - if (n % 2) - buf[++n] = length; - else - buf[n] += length; - } - - void add_bits(unsigned bits, unsigned count, unsigned length) - { - while (count--) { - if (bits & (1 << count)) { - advance_pulse(length); - advance_space(length); - } else { - advance_space(length); - advance_pulse(length); - } - } - } - - buf[n++] = NS_TO_US(rc6_unit * 6); - buf[n++] = NS_TO_US(rc6_unit * 2); - buf[n] = 0; - - switch (proto) { - default: - return 0; - case RC_PROTO_RC6_0: - add_bits(8, 4, NS_TO_US(rc6_unit)); - add_bits(0, 1, NS_TO_US(rc6_unit * 2)); - add_bits(scancode, 16, NS_TO_US(rc6_unit)); - break; - case RC_PROTO_RC6_6A_20: - add_bits(14, 4, NS_TO_US(rc6_unit)); - add_bits(0, 1, NS_TO_US(rc6_unit * 2)); - add_bits(scancode, 20, NS_TO_US(rc6_unit)); - break; - case RC_PROTO_RC6_6A_24: - add_bits(14, 4, NS_TO_US(rc6_unit)); - add_bits(0, 1, NS_TO_US(rc6_unit * 2)); - add_bits(scancode, 24, NS_TO_US(rc6_unit)); - break; - case RC_PROTO_RC6_6A_32: - case RC_PROTO_RC6_MCE: - add_bits(14, 4, NS_TO_US(rc6_unit)); - add_bits(0, 1, NS_TO_US(rc6_unit * 2)); - add_bits(scancode, 32, NS_TO_US(rc6_unit)); - break; - } - - /* drop any trailing pulse */ - return (n % 2) ? n : n + 1; -} - -static const struct { - char name[10]; - unsigned scancode_mask; - unsigned max_edges; - unsigned carrier; - int (*encode)(enum rc_proto proto, unsigned scancode, unsigned *buf); -} encoders[] = { - [RC_PROTO_RC5] = { "rc5", 0x1f7f, 24, 36000, rc5_encode }, - [RC_PROTO_RC5X_20] = { "rc5x_20", 0x1f7f3f, 40, 36000, rc5_encode }, - [RC_PROTO_RC5_SZ] = { "rc5_sz", 0x2fff, 26, 36000, rc5_encode }, - [RC_PROTO_SONY12] = { "sony12", 0x1f007f, 25, 40000, sony_encode }, - [RC_PROTO_SONY15] = { "sony15", 0xff007f, 31, 40000, sony_encode }, - [RC_PROTO_SONY20] = { "sony20", 0x1fff7f, 41, 40000, sony_encode }, - [RC_PROTO_JVC] = { "jvc", 0xffff, 35, 38000, jvc_encode }, - [RC_PROTO_NEC] = { "nec", 0xffff, 67, 38000, nec_encode }, - [RC_PROTO_NECX] = { "necx", 0xffffff, 67, 38000, nec_encode }, - [RC_PROTO_NEC32] = { "nec32", 0xffffffff, 67, 38000, nec_encode }, - [RC_PROTO_SANYO] = { "sanyo", 0x1fffff, 87, 38000, sanyo_encode }, - [RC_PROTO_RC6_0] = { "rc6_0", 0xffff, 24, 36000, rc6_encode }, - [RC_PROTO_RC6_6A_20] = { "rc6_6a_20", 0xfffff, 52, 36000, rc6_encode }, - [RC_PROTO_RC6_6A_24] = { "rc6_6a_24", 0xffffff, 60, 36000, rc6_encode }, - [RC_PROTO_RC6_6A_32] = { "rc6_6a_32", 0xffffffff, 76, 36000, rc6_encode }, - [RC_PROTO_RC6_MCE] = { "rc6_mce", 0xffff7fff, 76, 36000, rc6_encode }, - [RC_PROTO_SHARP] = { "sharp", 0x1fff, 63, 38000, sharp_encode }, -}; - -static bool str_like(const char *a, const char *b) -{ - while (*a && *b) { - while (*a == ' ' || *a == '-' || *a == '_') - a++; - while (*b == ' ' || *b == '-' || *b == '_') - b++; - - if (*a >= 0x7f || *b >= 0x7f) - return false; - - if (tolower(*a) != tolower(*b)) - return false; - - a++; b++; - } - - return !*a && !*b; -} - -bool protocol_match(const char *name, enum rc_proto *proto) -{ - enum rc_proto p; - - for (p=0; p<ARRAY_SIZE(encoders); p++) { - if (str_like(encoders[p].name, name)) { - *proto = p; - return true; - } - } - - return false; -} - -unsigned protocol_carrier(enum rc_proto proto) -{ - return encoders[proto].carrier; -} - -unsigned protocol_max_size(enum rc_proto proto) -{ - return encoders[proto].max_edges; -} - -unsigned protocol_scancode_mask(enum rc_proto proto) -{ - return encoders[proto].scancode_mask; -} - -bool protocol_scancode_valid(enum rc_proto p, unsigned s) -{ - if (s & ~encoders[p].scancode_mask) - return false; - - if (p == RC_PROTO_NECX) { - return (((s >> 16) ^ ~(s >> 8)) & 0xff) != 0; - } else if (p == RC_PROTO_NEC32) { - return (((s >> 24) ^ ~(s >> 16)) & 0xff) != 0; - } else if (p == RC_PROTO_RC6_MCE) { - return (s & 0xffff0000) == 0x800f0000; - } else if (p == RC_PROTO_RC6_6A_32) { - return (s & 0xffff0000) != 0x800f0000; - } - - return true; -} - -unsigned protocol_encode(enum rc_proto proto, unsigned scancode, unsigned *buf) -{ - return encoders[proto].encode(proto, scancode, buf); -} - -const char* protocol_name(enum rc_proto proto) -{ - return encoders[proto].name; -} diff --git a/utils/ir-ctl/ir-encode.c b/utils/ir-ctl/ir-encode.c new file mode 120000 index 000000000000..d973a0df0b0f --- /dev/null +++ b/utils/ir-ctl/ir-encode.c @@ -0,0 +1 @@ +../common/ir-encode.c \ No newline at end of file diff --git a/utils/ir-ctl/ir-encode.h b/utils/ir-ctl/ir-encode.h deleted file mode 100644 index 6e9c623e3548..000000000000 --- a/utils/ir-ctl/ir-encode.h +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef __IR_ENCODE_H__ -#define __IR_ENCODE_H__ - -#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) - -bool protocol_match(const char *name, enum rc_proto *proto); -unsigned protocol_carrier(enum rc_proto proto); -unsigned protocol_max_size(enum rc_proto proto); -bool protocol_scancode_valid(enum rc_proto proto, unsigned scancode); -unsigned protocol_scancode_mask(enum rc_proto proto); -unsigned protocol_encode(enum rc_proto proto, unsigned scancode, unsigned *buf); -const char *protocol_name(enum rc_proto proto); - -#endif diff --git a/utils/ir-ctl/ir-encode.h b/utils/ir-ctl/ir-encode.h new file mode 120000 index 000000000000..39853214d203 --- /dev/null +++ b/utils/ir-ctl/ir-encode.h @@ -0,0 +1 @@ +../common/ir-encode.h \ No newline at end of file diff --git a/utils/keytable/Makefile.am b/utils/keytable/Makefile.am index 62b90ad5c073..9eec51ae2249 100644 --- a/utils/keytable/Makefile.am +++ b/utils/keytable/Makefile.am @@ -4,7 +4,7 @@ sysconf_DATA = rc_maps.cfg keytablesystem_DATA = $(srcdir)/rc_keymaps/* udevrules_DATA = 70-infrared.rules -ir_keytable_SOURCES = keytable.c parse.h +ir_keytable_SOURCES = keytable.c parse.h ir-encode.c ir_keytable_LDADD = @LIBINTL@ ir_keytable_LDFLAGS = $(ARGP_LIBS) diff --git a/utils/keytable/ir-encode.c b/utils/keytable/ir-encode.c new file mode 120000 index 000000000000..d973a0df0b0f --- /dev/null +++ b/utils/keytable/ir-encode.c @@ -0,0 +1 @@ +../common/ir-encode.c \ No newline at end of file diff --git a/utils/keytable/ir-encode.h b/utils/keytable/ir-encode.h new file mode 120000 index 000000000000..39853214d203 --- /dev/null +++ b/utils/keytable/ir-encode.h @@ -0,0 +1 @@ +../common/ir-encode.h \ No newline at end of file diff --git a/utils/keytable/keytable.c b/utils/keytable/keytable.c index 988e98570c30..712830e8295a 100644 --- a/utils/keytable/keytable.c +++ b/utils/keytable/keytable.c @@ -18,16 +18,20 @@ #include <fcntl.h> #include <stdio.h> #include <unistd.h> +#include <poll.h> #include <stdlib.h> #include <string.h> #include <linux/input.h> +#include <linux/lirc.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <argp.h> +#include <time.h> #include <stdbool.h> +#include "ir-encode.h" #include "parse.h" #ifdef ENABLE_NLS @@ -271,6 +275,7 @@ static int sysfs = 0; struct rc_device { char *sysfs_name; /* Device sysfs node name */ char *input_name; /* Input device file name */ + char *lirc_name; /* Lirc device file name */ char *drv_name; /* Kernel driver that implements it */ char *dev_name; /* Kernel device name */ char *keytable_name; /* Keycode table name */ @@ -1031,15 +1036,33 @@ static int v2_set_protocols(struct rc_device *rc_dev) static int get_attribs(struct rc_device *rc_dev, char *sysfs_name) { struct uevents *uevent; - char *input = "input", *event = "event"; + char *input = "input", *event = "event", *lirc = "lirc"; char *DEV = "/dev/"; - static struct sysfs_names *input_names, *event_names, *attribs, *cur; + static struct sysfs_names *input_names, *event_names, *attribs, *cur, *lirc_names; /* Clean the attributes */ memset(rc_dev, 0, sizeof(*rc_dev)); rc_dev->sysfs_name = sysfs_name; + lirc_names = seek_sysfs_dir(rc_dev->sysfs_name, lirc); + if (lirc_names) { + uevent = read_sysfs_uevents(lirc_names->name); + free_names(lirc_names); + if (uevent) { + while (uevent->next) { + if (!strcmp(uevent->key, "DEVNAME")) { + rc_dev->lirc_name = malloc(strlen(uevent->value) + strlen(DEV) + 1); + strcpy(rc_dev->lirc_name, DEV); + strcat(rc_dev->lirc_name, uevent->value); + break; + } + uevent = uevent->next; + } + free_uevent(uevent); + } + } + input_names = seek_sysfs_dir(rc_dev->sysfs_name, input); if (!input_names) return EINVAL; @@ -1281,16 +1304,100 @@ static char *get_event_name(struct parse_event *event, u_int16_t code) return ""; } -static void test_event(int fd) +static void print_scancodes(const struct lirc_scancode *scancodes, unsigned count) +{ + unsigned i; + + for (i=0; i< count; i++) { + const char *p = protocol_name(scancodes[i].rc_proto); + + printf(_("%llu.%06llu: "), + scancodes[i].timestamp / 1000000000ull, + (scancodes[i].timestamp % 1000000000ull) / 1000ull); + + if (p) + printf(_("lirc protocol(%s): scancode = 0x%llx"), + p, scancodes[i].scancode); + else + printf(_("lirc protocol(%d): scancode = 0x%llx"), + scancodes[i].rc_proto, scancodes[i].scancode); + + if (scancodes[i].flags & LIRC_SCANCODE_FLAG_REPEAT) + printf(_(" repeat")); + if (scancodes[i].flags & LIRC_SCANCODE_FLAG_TOGGLE) + printf(_(" toggle=1")); + + printf("\n"); + } +} + +static void test_event(struct rc_device *rc_dev, int fd) { struct input_event ev[64]; - int rd, i; + struct lirc_scancode sc[64]; + int rd, i, lircfd = -1; + unsigned mode; + + /* LIRC reports time in monotonic, set event to same */ + mode = CLOCK_MONOTONIC; + ioctl(fd, EVIOCSCLOCKID, &mode); + + if (rc_dev->lirc_name) { + lircfd = open(rc_dev->lirc_name, O_RDONLY | O_NONBLOCK); + if (lircfd == -1) { + perror(_("Can't open lirc device")); + return; + } + unsigned features; + if (ioctl(lircfd, LIRC_GET_FEATURES, &features)) { + perror(_("Can't get lirc features")); + return; + } + + if (!(features & LIRC_CAN_REC_SCANCODE)) { + close(lircfd); + lircfd = -1; + } + else { + unsigned mode = LIRC_MODE_SCANCODE; + if (ioctl(lircfd, LIRC_SET_REC_MODE, &mode)) { + perror(_("Can't set lirc scancode mode")); + return; + } + } + } printf (_("Testing events. Please, press CTRL-C to abort.\n")); while (1) { + struct pollfd pollstruct[2] = { + { .fd = fd, .events = POLLIN }, + { .fd = lircfd, .events = POLLIN }, + }; + + if (poll(pollstruct, 2, -1) < 0) { + if (errno == EINTR) + continue; + + perror(_("poll returned error")); + } + + if (lircfd != -1) { + rd = read(lircfd, sc, sizeof(sc)); + + if (rd != -1) { + print_scancodes(sc, rd / sizeof(struct lirc_scancode)); + } else if (errno != EAGAIN) { + perror(_("Error reading lirc scancode")); + return; + } + } + rd = read(fd, ev, sizeof(ev)); if (rd < (int) sizeof(struct input_event)) { + if (errno == EAGAIN) + continue; + perror(_("Error reading event")); return; } @@ -1482,6 +1589,9 @@ static int show_sysfs_attribs(struct rc_device *rc_dev, char *name) fprintf(stderr, _("\tDriver: %s, table: %s\n"), rc_dev->drv_name, rc_dev->keytable_name); + if (rc_dev->lirc_name) + fprintf(stderr, _("\tlirc device: %s\n"), + rc_dev->lirc_name); fprintf(stderr, _("\tSupported protocols: ")); write_sysfs_protocols(rc_dev->supported, stderr, "%s "); fprintf(stderr, "\n\t"); @@ -1615,7 +1725,7 @@ int main(int argc, char *argv[]) if (debug) fprintf(stderr, _("Opening %s\n"), devicename); - fd = open(devicename, O_RDONLY); + fd = open(devicename, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror(devicename); return -1; @@ -1674,7 +1784,7 @@ int main(int argc, char *argv[]) } if (test) - test_event(fd); + test_event(&rc_dev, fd); return 0; } _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits