summaryrefslogtreecommitdiff
path: root/src/udev/udev-builtin-keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev/udev-builtin-keyboard.c')
-rw-r--r--src/udev/udev-builtin-keyboard.c251
1 files changed, 178 insertions, 73 deletions
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index d8ee4cbb61..01f3879f37 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -18,19 +18,15 @@
***/
#include <stdio.h>
-#include <errno.h>
#include <string.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <sys/ioctl.h>
-#include <linux/limits.h>
#include <linux/input.h>
#include "udev.h"
static const struct key *keyboard_lookup_key(const char *str, unsigned len);
#include "keyboard-keys-from-name.h"
-#include "keyboard-keys-to-name.h"
static int install_force_release(struct udev_device *dev, const unsigned *release, unsigned release_count) {
struct udev_device *atkbd;
@@ -41,6 +37,9 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas
unsigned i;
int ret;
+ assert(dev);
+ assert(release);
+
atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
if (!atkbd)
return -ENODEV;
@@ -66,99 +65,205 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas
return ret;
}
-static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev_list_entry *entry;
+static void map_keycode(int fd, const char *devnode, int scancode, const char *keycode)
+{
struct {
unsigned scan;
unsigned key;
- } map[1024];
- unsigned map_count = 0;
+ } map;
+ char *endptr;
+ const struct key *k;
+ unsigned keycode_num;
+
+ /* translate identifier to key code */
+ k = keyboard_lookup_key(keycode, strlen(keycode));
+ if (k) {
+ keycode_num = k->id;
+ } else {
+ /* check if it's a numeric code already */
+ keycode_num = strtoul(keycode, &endptr, 0);
+ if (endptr[0] !='\0') {
+ log_error("Unknown key identifier '%s'", keycode);
+ return;
+ }
+ }
+
+ map.scan = scancode;
+ map.key = keycode_num;
+
+ log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
+ map.scan, map.scan, map.key, map.key);
+
+ if (ioctl(fd, EVIOCSKEYCODE, &map) < 0)
+ log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key);
+}
+
+static inline char* parse_token(const char *current, int32_t *val_out) {
+ char *next;
+ int32_t val;
+
+ if (!current)
+ return NULL;
+
+ val = strtol(current, &next, 0);
+ if (*next && *next != ':')
+ return NULL;
+
+ if (next != current)
+ *val_out = val;
+
+ if (*next)
+ next++;
+
+ return next;
+}
+
+static void override_abs(int fd, const char *devnode,
+ unsigned evcode, const char *value) {
+ struct input_absinfo absinfo;
+ int rc;
+ char *next;
+
+ rc = ioctl(fd, EVIOCGABS(evcode), &absinfo);
+ if (rc < 0) {
+ log_error_errno(errno, "Unable to EVIOCGABS device \"%s\"", devnode);
+ return;
+ }
+
+ next = parse_token(value, &absinfo.minimum);
+ next = parse_token(next, &absinfo.maximum);
+ next = parse_token(next, &absinfo.resolution);
+ next = parse_token(next, &absinfo.fuzz);
+ next = parse_token(next, &absinfo.flat);
+ if (!next) {
+ log_error("Unable to parse EV_ABS override '%s' for '%s'", value, devnode);
+ return;
+ }
+
+ log_debug("keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32" for \"%s\"",
+ evcode,
+ absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat,
+ devnode);
+ rc = ioctl(fd, EVIOCSABS(evcode), &absinfo);
+ if (rc < 0)
+ log_error_errno(errno, "Unable to EVIOCSABS device \"%s\"", devnode);
+}
+
+static void set_trackpoint_sensitivity(struct udev_device *dev, const char *value)
+{
+ struct udev_device *pdev;
+ char val_s[DECIMAL_STR_MAX(int)];
+ int r, val_i;
+
+ assert(dev);
+ assert(value);
+
+ /* The sensitivity sysfs attr belongs to the serio parent device */
+ pdev = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
+ if (!pdev) {
+ log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev));
+ return;
+ }
+
+ r = safe_atoi(value, &val_i);
+ if (r < 0) {
+ log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value, udev_device_get_devnode(dev));
+ return;
+ }
+
+ xsprintf(val_s, "%d", val_i);
+
+ r = udev_device_set_sysattr_value(pdev, "sensitivity", val_s);
+ if (r < 0)
+ log_error_errno(r, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev));
+}
+
+static int open_device(const char *devnode) {
+ int fd;
+
+ fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Error opening device \"%s\": %m", devnode);
+
+ return fd;
+}
+
+static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
+ struct udev_list_entry *entry;
unsigned release[1024];
unsigned release_count = 0;
+ _cleanup_close_ int fd = -1;
+ const char *node;
+
+ node = udev_device_get_devnode(dev);
+ if (!node) {
+ log_error("No device node for \"%s\"", udev_device_get_syspath(dev));
+ return EXIT_FAILURE;
+ }
udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
const char *key;
- unsigned scancode, keycode_num;
char *endptr;
- const char *keycode;
- const struct key *k;
key = udev_list_entry_get_name(entry);
- if (!startswith(key, "KEYBOARD_KEY_"))
- continue;
-
- /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
- scancode = strtoul(key + 13, &endptr, 16);
- if (endptr[0] != '\0') {
- log_error("Error, unable to parse scan code from '%s'", key);
- continue;
- }
+ if (startswith(key, "KEYBOARD_KEY_")) {
+ const char *keycode;
+ unsigned scancode;
+
+ /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
+ scancode = strtoul(key + 13, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_warning("Unable to parse scan code from \"%s\"", key);
+ continue;
+ }
- keycode = udev_list_entry_get_value(entry);
+ keycode = udev_list_entry_get_value(entry);
- /* a leading '!' needs a force-release entry */
- if (keycode[0] == '!') {
- keycode++;
+ /* a leading '!' needs a force-release entry */
+ if (keycode[0] == '!') {
+ keycode++;
- release[release_count] = scancode;
- if (release_count < ELEMENTSOF(release)-1)
- release_count++;
+ release[release_count] = scancode;
+ if (release_count < ELEMENTSOF(release)-1)
+ release_count++;
- if (keycode[0] == '\0')
- continue;
- }
-
- /* translate identifier to key code */
- k = keyboard_lookup_key(keycode, strlen(keycode));
- if (k) {
- keycode_num = k->id;
- } else {
- /* check if it's a numeric code already */
- keycode_num = strtoul(keycode, &endptr, 0);
- if (endptr[0] !='\0') {
- log_error("Error, unknown key identifier '%s'", keycode);
- continue;
+ if (keycode[0] == '\0')
+ continue;
}
- }
- map[map_count].scan = scancode;
- map[map_count].key = keycode_num;
- if (map_count < ELEMENTSOF(map)-1)
- map_count++;
- }
+ if (fd == -1) {
+ fd = open_device(node);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ }
- if (map_count > 0 || release_count > 0) {
- const char *node;
- int fd;
- unsigned i;
+ map_keycode(fd, node, scancode, keycode);
+ } else if (startswith(key, "EVDEV_ABS_")) {
+ unsigned evcode;
- node = udev_device_get_devnode(dev);
- if (!node) {
- log_error("Error, no device node for '%s'", udev_device_get_syspath(dev));
- return EXIT_FAILURE;
- }
+ /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
+ evcode = strtoul(key + 10, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_warning("Unable to parse EV_ABS code from \"%s\"", key);
+ continue;
+ }
- fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0) {
- log_error_errno(errno, "Error, opening device '%s': %m", node);
- return EXIT_FAILURE;
- }
+ if (fd == -1) {
+ fd = open_device(node);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ }
- /* install list of map codes */
- for (i = 0; i < map_count; i++) {
- log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
- map[i].scan, map[i].scan, map[i].key, map[i].key);
- if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0)
- log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key);
+ override_abs(fd, node, evcode, udev_list_entry_get_value(entry));
+ } else if (streq(key, "POINTINGSTICK_SENSITIVITY")) {
+ set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry));
}
-
- /* install list of force-release codes */
- if (release_count > 0)
- install_force_release(dev, release, release_count);
-
- close(fd);
}
+ /* install list of force-release codes */
+ if (release_count > 0)
+ install_force_release(dev, release, release_count);
+
return EXIT_SUCCESS;
}