1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include <linux/input.h>
11 #include "device-util.h"
13 #include "parse-util.h"
14 #include "stdio-util.h"
15 #include "string-util.h"
17 #include "udev-builtin.h"
19 static const struct key_name
*keyboard_lookup_key(const char *str
, GPERF_LEN_TYPE len
);
20 #include "keyboard-keys-from-name.h"
22 static int install_force_release(sd_device
*dev
, const unsigned *release
, unsigned release_count
) {
34 r
= sd_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
, &atkbd
);
38 r
= sd_device_get_sysattr_value(atkbd
, "force_release", &cur
);
45 /* copy current content */
46 l
= strpcpy(&s
, l
, cur
);
48 /* append new codes */
49 for (i
= 0; i
< release_count
; i
++)
50 l
= strpcpyf(&s
, l
, ",%u", release
[i
]);
52 log_debug("keyboard: updating force-release list with '%s'", codes
);
53 r
= sd_device_set_sysattr_value(atkbd
, "force_release", codes
);
55 return log_error_errno(r
, "Error writing force-release attribute: %m");
60 static void map_keycode(int fd
, const char *devnode
, int scancode
, const char *keycode
) {
66 const struct key_name
*k
;
69 /* translate identifier to key code */
70 k
= keyboard_lookup_key(keycode
, strlen(keycode
));
74 /* check if it's a numeric code already */
75 keycode_num
= strtoul(keycode
, &endptr
, 0);
76 if (endptr
[0] !='\0') {
77 log_error("Unknown key identifier '%s'", keycode
);
83 map
.key
= keycode_num
;
85 log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
86 map
.scan
, map
.scan
, map
.key
, map
.key
);
88 if (ioctl(fd
, EVIOCSKEYCODE
, &map
) < 0)
89 log_error_errno(errno
, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode
, map
.scan
, map
.key
);
92 static inline char* parse_token(const char *current
, int32_t *val_out
) {
99 val
= strtol(current
, &next
, 0);
100 if (*next
&& *next
!= ':')
112 static void override_abs(int fd
, const char *devnode
,
113 unsigned evcode
, const char *value
) {
114 struct input_absinfo absinfo
;
118 rc
= ioctl(fd
, EVIOCGABS(evcode
), &absinfo
);
120 log_error_errno(errno
, "Unable to EVIOCGABS device \"%s\"", devnode
);
124 next
= parse_token(value
, &absinfo
.minimum
);
125 next
= parse_token(next
, &absinfo
.maximum
);
126 next
= parse_token(next
, &absinfo
.resolution
);
127 next
= parse_token(next
, &absinfo
.fuzz
);
128 next
= parse_token(next
, &absinfo
.flat
);
130 log_error("Unable to parse EV_ABS override '%s' for '%s'", value
, devnode
);
134 log_debug("keyboard: %x overridden with %"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
" for \"%s\"",
136 absinfo
.minimum
, absinfo
.maximum
, absinfo
.resolution
, absinfo
.fuzz
, absinfo
.flat
,
138 rc
= ioctl(fd
, EVIOCSABS(evcode
), &absinfo
);
140 log_error_errno(errno
, "Unable to EVIOCSABS device \"%s\"", devnode
);
143 static int set_trackpoint_sensitivity(sd_device
*dev
, const char *value
) {
145 char val_s
[DECIMAL_STR_MAX(int)];
152 r
= sd_device_get_devname(dev
, &devnode
);
154 return log_error_errno(r
, "Failed to get devname: %m");
156 /* The sensitivity sysfs attr belongs to the serio parent device */
157 r
= sd_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
, &pdev
);
159 return log_warning_errno(r
, "Failed to get serio parent for '%s': %m", devnode
);
161 r
= safe_atoi(value
, &val_i
);
163 return log_error_errno(r
, "Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s': %m", value
, devnode
);
164 else if (val_i
< 0 || val_i
> 255)
165 return log_error_errno(ERANGE
, "POINTINGSTICK_SENSITIVITY %d outside range [0..255] for '%s'", val_i
, devnode
);
167 xsprintf(val_s
, "%d", val_i
);
169 r
= sd_device_set_sysattr_value(pdev
, "sensitivity", val_s
);
171 return log_error_errno(r
, "Failed to write 'sensitivity' attribute for '%s': %m", devnode
);
176 static int open_device(const char *devnode
) {
179 fd
= open(devnode
, O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
181 return log_error_errno(errno
, "Error opening device \"%s\": %m", devnode
);
186 static int builtin_keyboard(sd_device
*dev
, int argc
, char *argv
[], bool test
) {
187 unsigned release
[1024];
188 unsigned release_count
= 0;
189 _cleanup_close_
int fd
= -1;
190 const char *node
, *key
, *value
;
193 r
= sd_device_get_devname(dev
, &node
);
195 const char *s
= NULL
;
197 (void) sd_device_get_syspath(dev
, &s
);
198 return log_error_errno(r
, "No device node for \"%s\": %m", strnull(s
));
201 FOREACH_DEVICE_PROPERTY(dev
, key
, value
) {
204 if (startswith(key
, "KEYBOARD_KEY_")) {
205 const char *keycode
= value
;
208 /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
209 scancode
= strtoul(key
+ 13, &endptr
, 16);
210 if (endptr
[0] != '\0') {
211 log_warning("Unable to parse scan code from \"%s\"", key
);
215 /* a leading '!' needs a force-release entry */
216 if (keycode
[0] == '!') {
219 release
[release_count
] = scancode
;
220 if (release_count
< ELEMENTSOF(release
)-1)
223 if (keycode
[0] == '\0')
228 fd
= open_device(node
);
233 map_keycode(fd
, node
, scancode
, keycode
);
234 } else if (startswith(key
, "EVDEV_ABS_")) {
237 /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
238 evcode
= strtoul(key
+ 10, &endptr
, 16);
239 if (endptr
[0] != '\0') {
240 log_warning("Unable to parse EV_ABS code from \"%s\"", key
);
245 fd
= open_device(node
);
254 rc
= ioctl(fd
, EVIOCGBIT(0, sizeof(bits
)), &bits
);
256 return log_error_errno(errno
, "Unable to EVIOCGBIT device \"%s\"", node
);
258 has_abs
= !!(bits
& (1 << EV_ABS
));
260 log_warning("EVDEV_ABS override set but no EV_ABS present on device \"%s\"", node
);
266 override_abs(fd
, node
, evcode
, value
);
267 } else if (streq(key
, "POINTINGSTICK_SENSITIVITY"))
268 set_trackpoint_sensitivity(dev
, value
);
271 /* install list of force-release codes */
272 if (release_count
> 0)
273 install_force_release(dev
, release
, release_count
);
278 const struct udev_builtin udev_builtin_keyboard
= {
280 .cmd
= builtin_keyboard
,
281 .help
= "Keyboard scan code to key mapping",