aboutsummaryrefslogtreecommitdiffstats
path: root/utils/keytable/bpf_protocols
diff options
context:
space:
mode:
Diffstat (limited to 'utils/keytable/bpf_protocols')
-rw-r--r--utils/keytable/bpf_protocols/Makefile.am2
-rw-r--r--utils/keytable/bpf_protocols/bitmap.h36
-rw-r--r--utils/keytable/bpf_protocols/raw.c149
3 files changed, 186 insertions, 1 deletions
diff --git a/utils/keytable/bpf_protocols/Makefile.am b/utils/keytable/bpf_protocols/Makefile.am
index bca3bdec..d9facbc9 100644
--- a/utils/keytable/bpf_protocols/Makefile.am
+++ b/utils/keytable/bpf_protocols/Makefile.am
@@ -10,7 +10,7 @@ CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \
%.o: %.c bpf_helpers.h
$(CLANG) $(CLANG_SYS_INCLUDES) -D__linux__ -I$(top_srcdir)/include -target bpf -O2 -c $<
-PROTOCOLS = grundig.o pulse_distance.o pulse_length.o rc_mm.o manchester.o xbox-dvd.o imon_rsc.o
+PROTOCOLS = grundig.o pulse_distance.o pulse_length.o rc_mm.o manchester.o xbox-dvd.o imon_rsc.o raw.o
all: $(PROTOCOLS)
diff --git a/utils/keytable/bpf_protocols/bitmap.h b/utils/keytable/bpf_protocols/bitmap.h
new file mode 100644
index 00000000..e3d731ad
--- /dev/null
+++ b/utils/keytable/bpf_protocols/bitmap.h
@@ -0,0 +1,36 @@
+
+#ifndef __BITMAP_H__
+#define __BITMAP_H__
+
+#include "string.h"
+
+#define BITS_PER_LONG 64
+#define BITS_TO_LONG(n) \
+ (((n) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+
+
+#define DECLARE_BITMAP(name, bits) \
+ unsigned long name[BITS_TO_LONG(bits)]
+
+static void inline bitmap_zero(unsigned long *bitmap, int bits)
+{
+ for (int i = 0; i < BITS_TO_LONG(bits); i++)
+ bitmap[i] = 0;
+}
+
+static void inline bitmap_fill(unsigned long *bitmap, int bits)
+{
+ for (int i = 0; i < BITS_TO_LONG(bits); i++)
+ bitmap[i] = ~0;
+}
+
+#define bitmap_set(b, n) \
+ b[n / BITS_PER_LONG] |= 1 << (n % BITS_PER_LONG)
+
+#define bitmap_clear(b, n) \
+ b[n / BITS_PER_LONG] &= ~(1 << (n % BITS_PER_LONG))
+
+#define bitmap_test(b, n) \
+ (b[n / BITS_PER_LONG] & (1 << (n % BITS_PER_LONG))) != 0
+
+#endif
diff --git a/utils/keytable/bpf_protocols/raw.c b/utils/keytable/bpf_protocols/raw.c
new file mode 100644
index 00000000..a0ee78b4
--- /dev/null
+++ b/utils/keytable/bpf_protocols/raw.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2019 Sean Young <sean@mess.org>
+//
+// This decoder matches pre-defined pulse-space sequences. It does so by
+// iterating through the list There are many optimisation possible, if
+// performance is an issue.
+//
+// First of all iterating through the list of patterns is one-by-one, even
+// though after the first few pulse space sequences, most patterns will be
+// will not be a match. The bitmap datastructure could use a "next clear bit"
+// function.
+//
+// Secondly this can be transformed into a much more efficient state machine,
+// where we pre-compile the patterns much like a regex.
+
+#include <linux/lirc.h>
+#include <linux/bpf.h>
+
+#include "bpf_helpers.h"
+#include "bitmap.h"
+
+#define MAX_PATTERNS 1024
+
+struct decoder_state {
+ int pos;
+ DECLARE_BITMAP(nomatch, MAX_PATTERNS);
+};
+
+struct bpf_map_def SEC("maps") decoder_state_map = {
+ .type = BPF_MAP_TYPE_ARRAY,
+ .key_size = sizeof(unsigned int),
+ .value_size = sizeof(struct decoder_state),
+ .max_entries = 1,
+};
+
+struct raw_pattern {
+ unsigned int scancode;
+ unsigned short raw[0];
+};
+
+// ir-keytable will load the raw patterns here
+struct bpf_map_def SEC("maps") raw_map = {
+ .type = BPF_MAP_TYPE_ARRAY,
+ .key_size = sizeof(unsigned int),
+ .value_size = sizeof(struct raw_pattern), // this is not used
+ .max_entries = MAX_PATTERNS,
+};
+
+
+// These values can be overridden in the rc_keymap toml
+//
+// We abuse elf relocations. We cast the address of these variables to
+// an int, so that the compiler emits a mov immediate for the address
+// but uses it as an int. The bpf loader replaces the relocation with the
+// actual value (either overridden or taken from the data segment).
+int margin = 200;
+int rc_protocol = 68;
+// The following two values are calculated by ir-keytable
+int trail_space = 1000;
+int max_length = 1;
+
+#define BPF_PARAM(x) (int)(&(x))
+
+static inline int eq_margin(unsigned d1, unsigned d2)
+{
+ return ((d1 > (d2 - BPF_PARAM(margin))) && (d1 < (d2 + BPF_PARAM(margin))));
+}
+
+SEC("raw")
+int bpf_decoder(unsigned int *sample)
+{
+ unsigned int key = 0;
+ struct decoder_state *s = bpf_map_lookup_elem(&decoder_state_map, &key);
+ struct raw_pattern *p;
+ unsigned int i;
+
+ // Make verifier happy. Should never come to pass
+ if (!s)
+ return 0;
+
+ switch (*sample & LIRC_MODE2_MASK) {
+ case LIRC_MODE2_SPACE:
+ case LIRC_MODE2_PULSE:
+ case LIRC_MODE2_TIMEOUT:
+ break;
+ default:
+ // not a timing events
+ return 0;
+ }
+
+ int duration = LIRC_VALUE(*sample);
+ int pulse = LIRC_IS_PULSE(*sample);
+ int pos = s->pos;
+
+ if (pos < 0 || pos >= BPF_PARAM(max_length)) {
+ if (!pulse && duration >= BPF_PARAM(trail_space)) {
+ bitmap_zero(s->nomatch, MAX_PATTERNS);
+ s->pos = 0;
+ }
+
+ return 0;
+ }
+
+ if (!pulse && duration >= BPF_PARAM(trail_space)) {
+ for (i = 0; i < MAX_PATTERNS; i++) {
+ key = i;
+ p = bpf_map_lookup_elem(&raw_map, &key);
+ // Make verifier happy. Should never come to pass
+ if (!p)
+ break;
+
+ // Has this pattern already mismatched?
+ if (bitmap_test(s->nomatch, i))
+ continue;
+
+ // Are we at the end of the pattern?
+ if (p->raw[pos] == 0)
+ bpf_rc_keydown(sample, BPF_PARAM(rc_protocol),
+ p->scancode, 0);
+ }
+
+ bitmap_zero(s->nomatch, MAX_PATTERNS);
+ s->pos = 0;
+ } else {
+ for (i = 0; i < MAX_PATTERNS; i++) {
+ key = i;
+ p = bpf_map_lookup_elem(&raw_map, &key);
+ // Make verifier happy. Should never come to pass
+ if (!p)
+ break;
+
+ // Has this pattern already mismatched?
+ if (bitmap_test(s->nomatch, i))
+ continue;
+
+ // If the pattern ended, or does not match
+ if (p->raw[pos] == 0 ||
+ !eq_margin(duration, p->raw[pos]))
+ bitmap_set(s->nomatch, i);
+ }
+
+ s->pos++;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";

Privacy Policy