#define _GNU_SOURCE #include #include #include #include #include #include #include #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)) const char * evdev_guess_protocol(struct device *device, uint64_t scancode, uint32_t keycode) { struct rc_keymap_entry rke; unsigned i; if (!device || device->evdev_fd < 0) return NULL; for (i = 0; ; i++) { memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.index = i; rke.flags = INPUT_KEYMAP_BY_INDEX; if (ioctl(device->evdev_fd, EVIOCGKEYCODE_V2, &rke)) break; if (rke.u.rc.scancode != scancode) continue; if (rke.keycode != keycode) continue; if (rke.u.rc.protocol > ARRAY_SIZE(rc_protocols)) return NULL; return rc_protocols[rke.u.rc.protocol]; } return NULL; } 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; }