LCOV - code coverage report
Current view: top level - udev - udev-builtin-keyboard.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 125 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 6 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 220 0.0 %

           Branch data     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