diff --git a/inputd/build.sh b/inputd/build.sh new file mode 100755 index 0000000..d2e5891 --- /dev/null +++ b/inputd/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gcc -o ppkbd main.c || exit 1 diff --git a/inputd/kmap.h b/inputd/kmap.h new file mode 100644 index 0000000..d805828 --- /dev/null +++ b/inputd/kmap.h @@ -0,0 +1,284 @@ +static const uint8_t el_phys_map[256] = { + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0xff, 0xff, 0xff, 0xff, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0xff, 0xff, 0xff, 0xff, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x51, 0xff, 0xff, 0x54, 0xff, 0x56, 0xff, + 0x58, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x52, 0x53, 0xff, 0x55, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static const int used_keys[] = { + KEY_ESC, + KEY_1, + KEY_LEFTSHIFT, + KEY_BACKSLASH, + KEY_F1, + KEY_2, + KEY_F2, + KEY_3, + KEY_DOLLAR, + KEY_F3, + KEY_4, + KEY_EURO, + KEY_F4, + KEY_5, + KEY_GRAVE, + KEY_F5, + KEY_6, + KEY_F6, + KEY_7, + KEY_MINUS, + KEY_F7, + KEY_8, + KEY_EQUAL, + KEY_F8, + KEY_9, + KEY_F9, + KEY_BACKSPACE, + KEY_DELETE, + KEY_TAB, + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_ENTER, + KEY_LEFTMETA, + KEY_SYSRQ, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_INSERT, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, + KEY_HOME, + KEY_DOT, + KEY_UP, + KEY_SLASH, + KEY_END, + KEY_LEFTCTRL, + KEY_FN, + KEY_LEFTALT, + KEY_SPACE, + KEY_RIGHTALT, + KEY_APOSTROPHE, + KEY_LEFT, + KEY_LEFTBRACE, + KEY_DOWN, + KEY_RIGHTBRACE, + KEY_RIGHT, +}; + +static const char* key_names[] = { + [KEY_ESC] = "ESC", + [KEY_1] = "1", + [KEY_LEFTSHIFT] = "LEFTSHIFT", + [KEY_BACKSLASH] = "BACKSLASH", + [KEY_F1] = "F1", + [KEY_2] = "2", + [KEY_F2] = "F2", + [KEY_3] = "3", + [KEY_DOLLAR] = "DOLLAR", + [KEY_F3] = "F3", + [KEY_4] = "4", + [KEY_EURO] = "EURO", + [KEY_F4] = "F4", + [KEY_5] = "5", + [KEY_GRAVE] = "GRAVE", + [KEY_F5] = "F5", + [KEY_6] = "6", + [KEY_F6] = "F6", + [KEY_7] = "7", + [KEY_MINUS] = "MINUS", + [KEY_F7] = "F7", + [KEY_8] = "8", + [KEY_EQUAL] = "EQUAL", + [KEY_F8] = "F8", + [KEY_9] = "9", + [KEY_F9] = "F9", + [KEY_BACKSPACE] = "BACKSPACE", + [KEY_DELETE] = "DELETE", + [KEY_TAB] = "TAB", + [KEY_Q] = "Q", + [KEY_W] = "W", + [KEY_E] = "E", + [KEY_R] = "R", + [KEY_T] = "T", + [KEY_Y] = "Y", + [KEY_U] = "U", + [KEY_I] = "I", + [KEY_O] = "O", + [KEY_P] = "P", + [KEY_ENTER] = "ENTER", + [KEY_LEFTMETA] = "LEFTMETA", + [KEY_SYSRQ] = "SYSRQ", + [KEY_A] = "A", + [KEY_S] = "S", + [KEY_D] = "D", + [KEY_F] = "F", + [KEY_G] = "G", + [KEY_H] = "H", + [KEY_J] = "J", + [KEY_K] = "K", + [KEY_L] = "L", + [KEY_SEMICOLON] = "SEMICOLON", + [KEY_INSERT] = "INSERT", + [KEY_Z] = "Z", + [KEY_X] = "X", + [KEY_C] = "C", + [KEY_V] = "V", + [KEY_B] = "B", + [KEY_N] = "N", + [KEY_M] = "M", + [KEY_COMMA] = "COMMA", + [KEY_HOME] = "HOME", + [KEY_DOT] = "DOT", + [KEY_UP] = "UP", + [KEY_SLASH] = "SLASH", + [KEY_END] = "END", + [KEY_LEFTCTRL] = "LEFTCTRL", + [KEY_FN] = "FN", + [KEY_LEFTALT] = "LEFTALT", + [KEY_SPACE] = "SPACE", + [KEY_RIGHTALT] = "RIGHTALT", + [KEY_APOSTROPHE] = "APOSTROPHE", + [KEY_LEFT] = "LEFT", + [KEY_LEFTBRACE] = "LEFTBRACE", + [KEY_DOWN] = "DOWN", + [KEY_RIGHTBRACE] = "RIGHTBRACE", + [KEY_RIGHT] = "RIGHT", +}; + +static const int keymap_base[256][2] = { + [0x11] = { KEY_ESC }, + [0x12] = { KEY_1 }, + [0x13] = { KEY_2 }, + [0x14] = { KEY_3 }, + [0x15] = { KEY_4 }, + [0x16] = { KEY_5 }, + [0x17] = { KEY_6 }, + [0x18] = { KEY_7 }, + [0x19] = { KEY_8 }, + [0x1a] = { KEY_9 }, + [0x1c] = { KEY_BACKSPACE }, + [0x21] = { KEY_TAB }, + [0x22] = { KEY_Q }, + [0x23] = { KEY_W }, + [0x24] = { KEY_E }, + [0x25] = { KEY_R }, + [0x26] = { KEY_T }, + [0x27] = { KEY_Y }, + [0x28] = { KEY_U }, + [0x29] = { KEY_I }, + [0x2a] = { KEY_O }, + [0x2b] = { KEY_P }, + [0x2c] = { KEY_ENTER }, + [0x31] = { KEY_LEFTMETA }, + [0x32] = { KEY_A }, + [0x33] = { KEY_S }, + [0x34] = { KEY_D }, + [0x35] = { KEY_F }, + [0x36] = { KEY_G }, + [0x37] = { KEY_H }, + [0x38] = { KEY_J }, + [0x39] = { KEY_K }, + [0x3a] = { KEY_L }, + [0x3b] = { KEY_SEMICOLON }, + [0x41] = { KEY_LEFTSHIFT }, + [0x42] = { KEY_Z }, + [0x43] = { KEY_X }, + [0x44] = { KEY_C }, + [0x45] = { KEY_V }, + [0x46] = { KEY_B }, + [0x47] = { KEY_N }, + [0x48] = { KEY_M }, + [0x49] = { KEY_COMMA }, + [0x4a] = { KEY_DOT }, + [0x4b] = { KEY_SLASH }, + [0x51] = { KEY_LEFTCTRL }, + [0x52] = { KEY_FN }, + [0x53] = { KEY_LEFTALT }, + [0x54] = { KEY_SPACE }, + [0x55] = { KEY_RIGHTALT }, + [0x56] = { KEY_APOSTROPHE }, + [0x57] = { KEY_LEFTBRACE }, + [0x58] = { KEY_RIGHTBRACE }, +}; + +static const int keymap_fn[256][2] = { + [0x12] = { KEY_LEFTSHIFT, KEY_BACKSLASH }, + [0x13] = { KEY_BACKSLASH }, + [0x14] = { KEY_DOLLAR }, + [0x15] = { KEY_EURO }, + [0x16] = { KEY_LEFTSHIFT, KEY_GRAVE }, + [0x17] = { KEY_GRAVE }, + [0x18] = { KEY_MINUS }, + [0x19] = { KEY_EQUAL }, + [0x1a] = { KEY_LEFTSHIFT, KEY_MINUS }, + [0x1c] = { KEY_DELETE }, + [0x31] = { KEY_LEFTSHIFT, KEY_SYSRQ }, + [0x3b] = { KEY_INSERT }, + [0x49] = { KEY_HOME }, + [0x4a] = { KEY_UP }, + [0x4b] = { KEY_END }, + [0x56] = { KEY_LEFT }, + [0x57] = { KEY_DOWN }, + [0x58] = { KEY_RIGHT }, +}; + +static const int keymap_pine[256][2] = { + [0x12] = { KEY_F1 }, + [0x13] = { KEY_F2 }, + [0x14] = { KEY_F3 }, + [0x15] = { KEY_F4 }, + [0x16] = { KEY_F5 }, + [0x17] = { KEY_F6 }, + [0x18] = { KEY_F7 }, + [0x19] = { KEY_F8 }, + [0x1a] = { KEY_F9 }, +}; + diff --git a/inputd/main.c b/inputd/main.c new file mode 100644 index 0000000..1165d1c --- /dev/null +++ b/inputd/main.c @@ -0,0 +1,498 @@ +/* + * Pinephone keyboard userspace input device daemon. + * + * Copyright (C) 2021 Ondřej Jirman + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// {{{ includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG 0 +#define MEGI_PROTO_BUG 1 + +#if DEBUG +#define debug(args...) printf(args) +#else +#define debug(args...) +#endif + +// }}} +// {{{ utils + +static void syscall_error(int is_err, const char* fmt, ...) +{ + va_list ap; + + if (!is_err) + return; + + fprintf(stderr, "ERROR: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); + + exit(1); +} + +static void error(const char* fmt, ...) +{ + va_list ap; + + fprintf(stderr, "ERROR: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} + +bool read_file(const char* path, char* buf, size_t size) +{ + int fd; + ssize_t ret; + + fd = open(path, O_RDONLY); + if (fd < 0) + return false; + + ret = read(fd, buf, size); + close(fd); + if (ret < 0) + return false; + + if (ret < size) { + buf[ret] = 0; + return true; + } else { + buf[size - 1] = 0; + return false; + } +} + +#define KB_ADDR 0x15 + +int read_kb(int fd, uint8_t data[16]) +{ + int ret; + struct i2c_msg msgs[] = { + { KB_ADDR, I2C_M_RD, 16, data }, + }; + + struct i2c_rdwr_ioctl_data msg = { + .msgs = msgs, + .nmsgs = sizeof(msgs) / sizeof(msgs[0]) + }; + + ret = ioctl(fd, I2C_RDWR, &msg); + //syscall_error(ret < 0, "I2C_RDWR failed"); + + return ret == 1 ? 0 : -1; +} + +#if 0 +int write_kb(int fd, uint8_t data[16]) +{ + int ret; + struct i2c_msg msgs[] = { + { KB_ADDR, 0, 16, data }, + }; + + struct i2c_rdwr_ioctl_data msg = { + .msgs = msgs, + .nmsgs = sizeof(msgs) / sizeof(msgs[0]) + }; + + ret = ioctl(fd, I2C_RDWR, &msg); + //syscall_error(ret < 0, "I2C_RDWR failed"); + + return ret == 1 ? 0 : -1; +} +#endif + +static int gpiochip_open(void) +{ + int ret; + char path[256], buf[1024]; + int fd = -1; + + for (int i = 0; i < 8; i++) { + snprintf(path, sizeof path, "/sys/bus/gpio/devices/gpiochip%d/uevent", i); + if (!read_file(path, buf, sizeof buf)) + continue; + + if (!strstr(buf, "OF_FULLNAME=/soc/pinctrl@1f02c00")) + continue; + + snprintf(path, sizeof path, "/dev/gpiochip%d", i); + + int fd = open(path, O_RDWR); + syscall_error(fd < 0, "open(%s) failed"); + + //ret = ioctl(fd, I2C_SLAVE, addr); + //syscall_error(ret < 0, "I2C_SLAVE failed"); + + return fd; + } + + error("Can't find POGO I2C adapter"); + return -1; +} + +static int setup_gpio(void) +{ + int ret; + struct gpio_v2_line_request req = { + .num_lines = 1, + .offsets[0] = 12, + .config.flags = GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_BIAS_PULL_UP | /*GPIO_V2_LINE_FLAG_ACTIVE_HIGH |*/ GPIO_V2_LINE_FLAG_EDGE_FALLING, + .consumer = "ppkbd", + }; + + int fd = gpiochip_open(); + + ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req); + syscall_error(ret < 0, "GPIO_V2_GET_LINE_IOCTL failed"); + + close(fd); + + return req.fd; +} + +static int get_int_value(int lfd) +{ + int ret; + struct gpio_v2_line_values vals = { + .mask = 1, + }; + + ret = ioctl(lfd, GPIO_V2_LINE_GET_VALUES_IOCTL, &vals); + syscall_error(ret < 0, "GPIO_V2_GET_LINE_IOCTL failed"); + + return vals.bits & 0x1; +} + +static int pogo_i2c_open(void) +{ + int ret; + char path[256], buf[1024]; + int fd = -1; + + for (int i = 0; i < 8; i++) { + snprintf(path, sizeof path, "/sys/class/i2c-adapter/i2c-%d/uevent", i); + if (!read_file(path, buf, sizeof buf)) + continue; + + if (!strstr(buf, "OF_FULLNAME=/soc/i2c@1c2b400")) + continue; + + snprintf(path, sizeof path, "/dev/i2c-%d", i); + + int fd = open(path, O_RDWR); + syscall_error(fd < 0, "open(%s) failed"); + + //ret = ioctl(fd, I2C_SLAVE, addr); + //syscall_error(ret < 0, "I2C_SLAVE failed"); + + return fd; + } + + error("Can't find POGO I2C adapter"); + return -1; +} + +#include "kmap.h" + +int open_uinput_dev(void) +{ + int fd, ret; + + fd = open("/dev/uinput", O_WRONLY/* | O_NONBLOCK*/); + syscall_error(fd < 0, "open(/dev/uinput) failed"); + + struct uinput_setup setup = { + .name = "ppkbd", + .id = { + .bustype = BUS_USB, + .vendor = 0x1234, + .product = 0x5678, + }, + }; + + ret = ioctl(fd, UI_SET_EVBIT, EV_KEY); + syscall_error(ret < 0, "UI_SET_EVBIT failed"); + + for (int i = 0; i < sizeof(used_keys) / sizeof(used_keys[0]); i++) { + ret = ioctl(fd, UI_SET_KEYBIT, used_keys[i]); + syscall_error(ret < 0, "UI_SET_KEYBIT failed"); + } + + ret = ioctl(fd, UI_DEV_SETUP, &setup); + syscall_error(ret < 0, "UI_DEV_SETUP failed"); + + ret = ioctl(fd, UI_DEV_CREATE); + syscall_error(ret < 0, "UI_DEV_CREATE failed"); + + //ioctl(fd, UI_DEV_DESTROY); + //close(fd); + + return fd; +} + +void emit_ev(int fd, int type, int code, int val) +{ + struct input_event ev = { + .type = type, + .code = code, + .value = val, + }; + + ssize_t ret = write(fd, &ev, sizeof ev); + syscall_error(ret < 0, "write event failed"); +} + +void print_bitmap(uint8_t* map) +{ + printf("\033[H"); + for (int r = 0; r < 6; r++) { + if (r == 0) { + printf(" C"); + for (int c = 0; c < 12; c++) + printf("%-3d", c + 1); + printf("\n"); + } + + printf("R%d", r + 1); + for (int c = 0; c < 12; c++) + printf(" %s", map[c] & (1u << r) ? "X" : "."); + printf("\n"); + } +} + +int get_index(int* keys, int len, int key) +{ + for (int i = 0; i < len; i++) { + if (keys[i] == key) + return i; + } + return -1; +} + +int compact(int* keys, int len) +{ + int ckeys[len]; + int ci = 0; + + memset(ckeys, 0, len * sizeof(int)); + + for (int i = 0; i < len; i++) + if (keys[i]) + ckeys[ci++] = keys[i]; + + memcpy(keys, ckeys, sizeof ckeys); + return ci; +} + +static int uinput_fd = -1; +static int pressed_keys[128]; // contains currently pressed phys_idxs in press order +static int pressed_count; + +void on_press(uint8_t phys_idx) +{ + int key = keymap_base[phys_idx][0]; +// printf("press %02hhx %s\n", phys_idx, key ? key_names[key] : ""); + + if (key == KEY_FN || key == KEY_LEFTMETA) { + return; + } + + //XXX: make sure fn/pine is the last presssed key prior to this one? + int fn_idx = get_index(pressed_keys, pressed_count, 0x52); + int pine_idx = get_index(pressed_keys, pressed_count, 0x31); + + const int* keys = keymap_base[phys_idx]; + if (fn_idx >= 0) { + keys = keymap_fn[phys_idx]; + } else if (pine_idx >= 0) { + keys = keymap_pine[phys_idx]; + } + + if (keys[0]) { + emit_ev(uinput_fd, EV_KEY, keys[0], 1); + emit_ev(uinput_fd, EV_SYN, SYN_REPORT, 0); + } + + if (keys[1]) { + emit_ev(uinput_fd, EV_KEY, keys[1], 1); + emit_ev(uinput_fd, EV_SYN, SYN_REPORT, 0); + } +} + +void on_release(uint8_t phys_idx) +{ + int key = keymap_base[phys_idx][0]; +// printf("release %02hhx %s\n", phys_idx, key ? key_names[key] : ""); + + if (key == KEY_FN || key == KEY_LEFTMETA) { + return; + } + + int fn_idx = get_index(pressed_keys, pressed_count, 0x52); + int pine_idx = get_index(pressed_keys, pressed_count, 0x31); + + const int* keys = keymap_base[phys_idx]; + if (fn_idx >= 0) { + keys = keymap_fn[phys_idx]; + } else if (pine_idx >= 0) { + keys = keymap_pine[phys_idx]; + } + + if (keys[0]) { + emit_ev(uinput_fd, EV_KEY, keys[0], 0); + emit_ev(uinput_fd, EV_SYN, SYN_REPORT, 0); + } + + if (keys[1]) { + emit_ev(uinput_fd, EV_KEY, keys[1], 0); + emit_ev(uinput_fd, EV_SYN, SYN_REPORT, 0); + } +} + +void update_keys(uint8_t* map) +{ + // physical indices of pressed keys reported over I2C + int keys[128]; + int n_keys = 0; + + for (int c = 0; c < 12; c++) { + for (int r = 0; r < 6; r++) { + if (map[c] != 0xff && map[c] & (1u << r)) { + uint8_t el_idx = (r << 4) | c; + uint8_t phys_idx = el_phys_map[el_idx]; + if (phys_idx != 0xff && n_keys < 128) { +#if MEGI_PROTO_BUG + int key = keymap_base[phys_idx][0]; + if (key == KEY_LEFTCTRL || key == KEY_Z) // ignore these keys on my keyboard + continue; +#endif + + keys[n_keys++] = phys_idx; + } + } + } + } + + // which pressed keys are no longer pressed? + for (int j = 0; j < pressed_count; j++) { + int key = pressed_keys[j]; + + int idx = get_index(keys, n_keys, key); + if (idx < 0) { + pressed_keys[j] = 0; + pressed_count = compact(pressed_keys, 128); + on_release(key); + } + } + + + // which new keys are pressed? + for (int i = 0; i < n_keys; i++) { + int key = keys[i]; + + // if the key was not pressed, handle a new press event + int pressed_idx = get_index(pressed_keys, pressed_count, key); + if (pressed_idx < 0 && pressed_count < 128) { + pressed_keys[pressed_count++] = key; + on_press(key); + } + } +} + +uint64_t time_abs(void) +{ + struct timespec tmp; + int ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &tmp); + if (ret < 0) + return 0; + + return tmp.tv_sec * 1000000000ull + tmp.tv_nsec; +} + +int main(int ac, char* av[]) +{ + int fd, ret; + + fd = pogo_i2c_open(); + uinput_fd = open_uinput_dev(); + + int lfd = setup_gpio(); + + struct pollfd fds[2] = { + { .fd = lfd, .events = POLLIN, }, + }; + + debug("\033[2J"); + + while (1) { + ret = poll(fds, 1, 10000); + syscall_error(ret < 0, "poll failed"); + + if (fds[0].revents & POLLIN) { + struct gpio_v2_line_event ev; + ssize_t len = read(lfd, &ev, sizeof ev); + syscall_error(len != sizeof ev, "Invalid event size"); + + // read keyboard data + uint8_t buf[16]; + ret = read_kb(fd, buf); + if (ret) + continue; + +#if DEBUG + print_bitmap(buf + 4); +#endif + update_keys(buf + 4); + } + } + + return 0; +} diff --git a/inputd/map-to-c.php b/inputd/map-to-c.php index 2e86350..2455de5 100644 --- a/inputd/map-to-c.php +++ b/inputd/map-to-c.php @@ -1,6 +1,25 @@ #!/usr/bin/env php + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + $pmap = file_get_contents("physical-map.txt"); $kmap = file_get_contents("factory-keymap.txt");