LCOV - code coverage report
Current view: top level - udev - udev-builtin-keyboard.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 125 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <fcntl.h>
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <sys/ioctl.h>
       9             : #include <linux/input.h>
      10             : 
      11             : #include "device-util.h"
      12             : #include "fd-util.h"
      13             : #include "parse-util.h"
      14             : #include "stdio-util.h"
      15             : #include "string-util.h"
      16             : #include "strxcpyx.h"
      17             : #include "udev-builtin.h"
      18             : 
      19             : static const struct key_name *keyboard_lookup_key(const char *str, GPERF_LEN_TYPE len);
      20             : #include "keyboard-keys-from-name.h"
      21             : 
      22           0 : static int install_force_release(sd_device *dev, const unsigned *release, unsigned release_count) {
      23             :         sd_device *atkbd;
      24             :         const char *cur;
      25             :         char codes[4096];
      26             :         char *s;
      27             :         size_t l;
      28             :         unsigned i;
      29             :         int r;
      30             : 
      31           0 :         assert(dev);
      32           0 :         assert(release);
      33             : 
      34           0 :         r = sd_device_get_parent_with_subsystem_devtype(dev, "serio", NULL, &atkbd);
      35           0 :         if (r < 0)
      36           0 :                 return log_device_error_errno(dev, r, "Failed to get serio parent: %m");
      37             : 
      38           0 :         r = sd_device_get_sysattr_value(atkbd, "force_release", &cur);
      39           0 :         if (r < 0)
      40           0 :                 return log_device_error_errno(atkbd, r, "Failed to get force-release attribute: %m");
      41             : 
      42           0 :         s = codes;
      43           0 :         l = sizeof(codes);
      44             : 
      45             :         /* copy current content */
      46           0 :         l = strpcpy(&s, l, cur);
      47             : 
      48             :         /* append new codes */
      49           0 :         for (i = 0; i < release_count; i++)
      50           0 :                 l = strpcpyf(&s, l, ",%u", release[i]);
      51             : 
      52           0 :         log_device_debug(atkbd, "keyboard: updating force-release list with '%s'", codes);
      53           0 :         r = sd_device_set_sysattr_value(atkbd, "force_release", codes);
      54           0 :         if (r < 0)
      55           0 :                 return log_device_error_errno(atkbd, r, "Failed to set force-release attribute: %m");
      56             : 
      57           0 :         return 0;
      58             : }
      59             : 
      60           0 : static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode) {
      61             :         struct {
      62             :                 unsigned scan;
      63             :                 unsigned key;
      64             :         } map;
      65             :         char *endptr;
      66             :         const struct key_name *k;
      67             :         unsigned keycode_num;
      68             : 
      69             :         /* translate identifier to key code */
      70           0 :         k = keyboard_lookup_key(keycode, strlen(keycode));
      71           0 :         if (k) {
      72           0 :                 keycode_num = k->id;
      73             :         } else {
      74             :                 /* check if it's a numeric code already */
      75           0 :                 keycode_num = strtoul(keycode, &endptr, 0);
      76           0 :                 if (endptr[0] !='\0')
      77           0 :                         return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Failed to parse key identifier '%s'", keycode);
      78             :         }
      79             : 
      80           0 :         map.scan = scancode;
      81           0 :         map.key = keycode_num;
      82             : 
      83           0 :         log_device_debug(dev, "keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
      84             :                          map.scan, map.scan, map.key, map.key);
      85             : 
      86           0 :         if (ioctl(fd, EVIOCSKEYCODE, &map) < 0)
      87           0 :                 return log_device_error_errno(dev, errno, "Failed to call EVIOCSKEYCODE with scan code 0x%x, and key code %d: %m", map.scan, map.key);
      88             : 
      89           0 :         return 0;
      90             : }
      91             : 
      92           0 : static char* parse_token(const char *current, int32_t *val_out) {
      93             :         char *next;
      94             :         int32_t val;
      95             : 
      96           0 :         if (!current)
      97           0 :                 return NULL;
      98             : 
      99           0 :         val = strtol(current, &next, 0);
     100           0 :         if (*next && *next != ':')
     101           0 :                 return NULL;
     102             : 
     103           0 :         if (next != current)
     104           0 :                 *val_out = val;
     105             : 
     106           0 :         if (*next)
     107           0 :                 next++;
     108             : 
     109           0 :         return next;
     110             : }
     111             : 
     112           0 : static int override_abs(sd_device *dev, int fd, unsigned evcode, const char *value) {
     113             :         struct input_absinfo absinfo;
     114             :         char *next;
     115             :         int r;
     116             : 
     117           0 :         r = ioctl(fd, EVIOCGABS(evcode), &absinfo);
     118           0 :         if (r < 0)
     119           0 :                 return log_device_error_errno(dev, errno, "Failed to call EVIOCGABS");
     120             : 
     121           0 :         next = parse_token(value, &absinfo.minimum);
     122           0 :         next = parse_token(next, &absinfo.maximum);
     123           0 :         next = parse_token(next, &absinfo.resolution);
     124           0 :         next = parse_token(next, &absinfo.fuzz);
     125           0 :         next = parse_token(next, &absinfo.flat);
     126           0 :         if (!next)
     127           0 :                 return log_device_error(dev, "Failed to parse EV_ABS override '%s'", value);
     128             : 
     129           0 :         log_device_debug(dev, "keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32,
     130             :                          evcode, absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat);
     131           0 :         r = ioctl(fd, EVIOCSABS(evcode), &absinfo);
     132           0 :         if (r < 0)
     133           0 :                 return log_device_error_errno(dev, errno, "Failed to call EVIOCSABS");
     134             : 
     135           0 :         return 0;
     136             : }
     137             : 
     138           0 : static int set_trackpoint_sensitivity(sd_device *dev, const char *value) {
     139             :         sd_device *pdev;
     140             :         char val_s[DECIMAL_STR_MAX(int)];
     141             :         int r, val_i;
     142             : 
     143           0 :         assert(dev);
     144           0 :         assert(value);
     145             : 
     146             :         /* The sensitivity sysfs attr belongs to the serio parent device */
     147           0 :         r = sd_device_get_parent_with_subsystem_devtype(dev, "serio", NULL, &pdev);
     148           0 :         if (r < 0)
     149           0 :                 return log_device_error_errno(dev, r, "Failed to get serio parent: %m");
     150             : 
     151           0 :         r = safe_atoi(value, &val_i);
     152           0 :         if (r < 0)
     153           0 :                 return log_device_error_errno(dev, r, "Failed to parse POINTINGSTICK_SENSITIVITY '%s': %m", value);
     154           0 :         else if (val_i < 0 || val_i > 255)
     155           0 :                 return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "POINTINGSTICK_SENSITIVITY %d outside range [0..255]", val_i);
     156             : 
     157           0 :         xsprintf(val_s, "%d", val_i);
     158             : 
     159           0 :         r = sd_device_set_sysattr_value(pdev, "sensitivity", val_s);
     160           0 :         if (r < 0)
     161           0 :                 return log_device_error_errno(dev, r, "Failed to write 'sensitivity' attribute: %m");
     162             : 
     163           0 :         return 0;
     164             : }
     165             : 
     166           0 : static int builtin_keyboard(sd_device *dev, int argc, char *argv[], bool test) {
     167             :         unsigned release[1024];
     168           0 :         unsigned release_count = 0;
     169           0 :         _cleanup_close_ int fd = -1;
     170             :         const char *node, *key, *value;
     171           0 :         int has_abs = -1, r;
     172             : 
     173           0 :         r = sd_device_get_devname(dev, &node);
     174           0 :         if (r < 0)
     175           0 :                 return log_device_error_errno(dev, r, "Failed to get device name: %m");
     176             : 
     177           0 :         FOREACH_DEVICE_PROPERTY(dev, key, value) {
     178             :                 char *endptr;
     179             : 
     180           0 :                 if (startswith(key, "KEYBOARD_KEY_")) {
     181           0 :                         const char *keycode = value;
     182             :                         unsigned scancode;
     183             : 
     184             :                         /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
     185           0 :                         scancode = strtoul(key + 13, &endptr, 16);
     186           0 :                         if (endptr[0] != '\0') {
     187           0 :                                 log_device_warning(dev, "Failed to parse scan code from \"%s\", ignoring", key);
     188           0 :                                 continue;
     189             :                         }
     190             : 
     191             :                         /* a leading '!' needs a force-release entry */
     192           0 :                         if (keycode[0] == '!') {
     193           0 :                                 keycode++;
     194             : 
     195           0 :                                 release[release_count] = scancode;
     196           0 :                                 if (release_count < ELEMENTSOF(release)-1)
     197           0 :                                         release_count++;
     198             : 
     199           0 :                                 if (keycode[0] == '\0')
     200           0 :                                         continue;
     201             :                         }
     202             : 
     203           0 :                         if (fd < 0) {
     204           0 :                                 fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
     205           0 :                                 if (fd < 0)
     206           0 :                                         return log_device_error_errno(dev, errno, "Failed to open device '%s': %m", node);
     207             :                         }
     208             : 
     209           0 :                         (void) map_keycode(dev, fd, scancode, keycode);
     210           0 :                 } else if (startswith(key, "EVDEV_ABS_")) {
     211             :                         unsigned evcode;
     212             : 
     213             :                         /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
     214           0 :                         evcode = strtoul(key + 10, &endptr, 16);
     215           0 :                         if (endptr[0] != '\0') {
     216           0 :                                 log_device_warning(dev, "Failed to parse EV_ABS code from \"%s\", ignoring", key);
     217           0 :                                 continue;
     218             :                         }
     219             : 
     220           0 :                         if (fd < 0) {
     221           0 :                                 fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
     222           0 :                                 if (fd < 0)
     223           0 :                                         return log_device_error_errno(dev, errno, "Failed to open device '%s': %m", node);
     224             :                         }
     225             : 
     226           0 :                         if (has_abs == -1) {
     227             :                                 unsigned long bits;
     228             :                                 int rc;
     229             : 
     230           0 :                                 rc = ioctl(fd, EVIOCGBIT(0, sizeof(bits)), &bits);
     231           0 :                                 if (rc < 0)
     232           0 :                                         return log_device_error_errno(dev, errno, "Failed to set EVIOCGBIT");
     233             : 
     234           0 :                                 has_abs = !!(bits & (1 << EV_ABS));
     235           0 :                                 if (!has_abs)
     236           0 :                                         log_device_warning(dev, "EVDEV_ABS override set but no EV_ABS present on device");
     237             :                         }
     238             : 
     239           0 :                         if (!has_abs)
     240           0 :                                 continue;
     241             : 
     242           0 :                         (void) override_abs(dev, fd, evcode, value);
     243           0 :                 } else if (streq(key, "POINTINGSTICK_SENSITIVITY"))
     244           0 :                         (void) set_trackpoint_sensitivity(dev, value);
     245             :         }
     246             : 
     247             :         /* install list of force-release codes */
     248           0 :         if (release_count > 0)
     249           0 :                 (void) install_force_release(dev, release, release_count);
     250             : 
     251           0 :         return 0;
     252             : }
     253             : 
     254             : const UdevBuiltin udev_builtin_keyboard = {
     255             :         .name = "keyboard",
     256             :         .cmd = builtin_keyboard,
     257             :         .help = "Keyboard scan code to key mapping",
     258             : };

Generated by: LCOV version 1.14