summaryrefslogtreecommitdiff
path: root/rcm-server-evdev.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2015-07-22 23:39:29 +0200
committerDavid Härdeman <david@hardeman.nu>2015-07-22 23:39:29 +0200
commit10836ae78302aa778553300167f6cdebdf8d884b (patch)
treeebb7a3501b11682de18055b813ed5007cb7ffd5d /rcm-server-evdev.c
parentb51c1c648146e49c25c4d6a2a6f5b9b66ea3190d (diff)
Improve rcm-server integration with evdev generation
Diffstat (limited to 'rcm-server-evdev.c')
-rw-r--r--rcm-server-evdev.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/rcm-server-evdev.c b/rcm-server-evdev.c
new file mode 100644
index 0000000..9423806
--- /dev/null
+++ b/rcm-server-evdev.c
@@ -0,0 +1,127 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <systemd/sd-bus.h>
+#include <errno.h>
+#include <linux/input.h>
+
+#include "utils.h"
+#include "shared.h"
+#include "rcm-server-main.h"
+#include "rcm-server-evdev.h"
+#include "rcm-server-keymap.h"
+
+struct rc_scancode {
+ __u16 protocol;
+ __u16 reserved[3];
+ __u64 scancode;
+};
+
+#define INPUT_KEYMAP_BY_INDEX (1 << 0)
+struct rc_keymap_entry {
+ __u8 flags;
+ __u8 len;
+ __u16 index;
+ __u32 keycode;
+ union {
+ struct rc_scancode rc;
+ __u8 scancode[32];
+ } u;
+ char end[];
+};
+#define RKE_SIZE (sizeof(struct rc_scancode))
+
+static int
+evdev_clear_keymap(struct device *device)
+{
+ struct rc_keymap_entry rke;
+ unsigned count = 0;
+ int r = 0;
+
+ printf("Clearing keymap...");
+ while (true) {
+ memset(&rke, 0, sizeof(rke));
+ rke.len = RKE_SIZE;
+ rke.index = 0;
+ rke.flags = INPUT_KEYMAP_BY_INDEX;
+ if (ioctl(device->evdev_fd, EVIOCGKEYCODE_V2, &rke)) {
+ printf("done (%u entries removed)\n", count);
+ break;
+ }
+
+ /*
+ printf(" Clearing 0x%08llX (0x%02X) to 0x%02X\n",
+ rke.u.rc.scancode, rke.u.rc.protocol, rke.keycode);
+ */
+
+ rke.keycode = KEY_RESERVED;
+ if (ioctl(device->evdev_fd, EVIOCSKEYCODE_V2, &rke)) {
+ r = -errno;
+ printf("failed (%s)\n", strerror(errno));
+ break;
+ }
+ count++;
+ }
+
+ return r;
+}
+
+static void
+set_keycode_new(struct device *device, __u16 protocol, __u64 scancode, __u32 keycode)
+{
+ struct rc_keymap_entry rke;
+
+ memset(&rke, 0, sizeof(rke));
+ rke.len = RKE_SIZE;
+ rke.u.rc.protocol = protocol;
+ rke.u.rc.scancode = scancode;
+ rke.keycode = keycode;
+
+ printf("Setting keycode (new ioctl) 0x%08llX (0x%02X) to 0x%02X\n",
+ rke.u.rc.scancode, rke.u.rc.protocol, rke.keycode);
+
+ if (ioctl(device->evdev_fd, EVIOCSKEYCODE_V2, &rke)) {
+ printf("Unable to call SETKEYCODE2 ioctl\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static int
+evdev_set_keymap(struct device *device, struct keymap *keymap)
+{
+ unsigned i;
+
+ printf("\tSetting up keymap: %s\n", keymap->name);
+
+ for (i = 0; i < keymap->keycode_count; i++)
+ set_keycode_new(device,
+ keymap->keycodes[i].protocol,
+ keymap->keycodes[i].scancode,
+ keymap->keycodes[i].lik->value);
+
+ printf("\tDone: %u entries added\n", i);
+ return 0;
+}
+
+int
+evdev_setup(struct device *device)
+{
+ int r;
+ struct keymap *keymap;
+
+ if (!device || device->evdev_fd < 0)
+ return -EINVAL;
+
+ printf("Performing evdev setup for device %s\n", device->path);
+ r = evdev_clear_keymap(device);
+ if (r < 0)
+ return r;
+
+ list_for_each_entry(keymap, &device->keymaps, list)
+ r = evdev_set_keymap(device, keymap);
+
+ return r;
+}
+