diff options
Diffstat (limited to 'rcm-server-evdev.c')
-rw-r--r-- | rcm-server-evdev.c | 127 |
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; +} + |