1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Kay Sievers <kay@vrfy.org>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/ioctl.h>
25 #include <linux/input.h>
28 #include "parse-util.h"
29 #include "stdio-util.h"
30 #include "string-util.h"
33 static const struct key_name
*keyboard_lookup_key(const char *str
, GPERF_LEN_TYPE len
);
34 #include "keyboard-keys-from-name.h"
36 static int install_force_release(struct udev_device
*dev
, const unsigned *release
, unsigned release_count
) {
37 struct udev_device
*atkbd
;
48 atkbd
= udev_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
);
52 cur
= udev_device_get_sysattr_value(atkbd
, "force_release");
59 /* copy current content */
60 l
= strpcpy(&s
, l
, cur
);
62 /* append new codes */
63 for (i
= 0; i
< release_count
; i
++)
64 l
= strpcpyf(&s
, l
, ",%u", release
[i
]);
66 log_debug("keyboard: updating force-release list with '%s'", codes
);
67 ret
= udev_device_set_sysattr_value(atkbd
, "force_release", codes
);
69 log_error_errno(ret
, "Error writing force-release attribute: %m");
73 static void map_keycode(int fd
, const char *devnode
, int scancode
, const char *keycode
)
80 const struct key_name
*k
;
83 /* translate identifier to key code */
84 k
= keyboard_lookup_key(keycode
, strlen(keycode
));
88 /* check if it's a numeric code already */
89 keycode_num
= strtoul(keycode
, &endptr
, 0);
90 if (endptr
[0] !='\0') {
91 log_error("Unknown key identifier '%s'", keycode
);
97 map
.key
= keycode_num
;
99 log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
100 map
.scan
, map
.scan
, map
.key
, map
.key
);
102 if (ioctl(fd
, EVIOCSKEYCODE
, &map
) < 0)
103 log_error_errno(errno
, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode
, map
.scan
, map
.key
);
106 static inline char* parse_token(const char *current
, int32_t *val_out
) {
113 val
= strtol(current
, &next
, 0);
114 if (*next
&& *next
!= ':')
126 static void override_abs(int fd
, const char *devnode
,
127 unsigned evcode
, const char *value
) {
128 struct input_absinfo absinfo
;
132 rc
= ioctl(fd
, EVIOCGABS(evcode
), &absinfo
);
134 log_error_errno(errno
, "Unable to EVIOCGABS device \"%s\"", devnode
);
138 next
= parse_token(value
, &absinfo
.minimum
);
139 next
= parse_token(next
, &absinfo
.maximum
);
140 next
= parse_token(next
, &absinfo
.resolution
);
141 next
= parse_token(next
, &absinfo
.fuzz
);
142 next
= parse_token(next
, &absinfo
.flat
);
144 log_error("Unable to parse EV_ABS override '%s' for '%s'", value
, devnode
);
148 log_debug("keyboard: %x overridden with %"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
" for \"%s\"",
150 absinfo
.minimum
, absinfo
.maximum
, absinfo
.resolution
, absinfo
.fuzz
, absinfo
.flat
,
152 rc
= ioctl(fd
, EVIOCSABS(evcode
), &absinfo
);
154 log_error_errno(errno
, "Unable to EVIOCSABS device \"%s\"", devnode
);
157 static void set_trackpoint_sensitivity(struct udev_device
*dev
, const char *value
)
159 struct udev_device
*pdev
;
160 char val_s
[DECIMAL_STR_MAX(int)];
166 /* The sensitivity sysfs attr belongs to the serio parent device */
167 pdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
);
169 log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev
));
173 r
= safe_atoi(value
, &val_i
);
175 log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value
, udev_device_get_devnode(dev
));
177 } else if (val_i
< 0 || val_i
> 255) {
178 log_error("POINTINGSTICK_SENSITIVITY %d outside range [0..255] for '%s' ", val_i
, udev_device_get_devnode(dev
));
182 xsprintf(val_s
, "%d", val_i
);
184 r
= udev_device_set_sysattr_value(pdev
, "sensitivity", val_s
);
186 log_error_errno(r
, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev
));
189 static int open_device(const char *devnode
) {
192 fd
= open(devnode
, O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
194 return log_error_errno(errno
, "Error opening device \"%s\": %m", devnode
);
199 static int builtin_keyboard(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
200 struct udev_list_entry
*entry
;
201 unsigned release
[1024];
202 unsigned release_count
= 0;
203 _cleanup_close_
int fd
= -1;
207 node
= udev_device_get_devnode(dev
);
209 log_error("No device node for \"%s\"", udev_device_get_syspath(dev
));
213 udev_list_entry_foreach(entry
, udev_device_get_properties_list_entry(dev
)) {
217 key
= udev_list_entry_get_name(entry
);
218 if (startswith(key
, "KEYBOARD_KEY_")) {
222 /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
223 scancode
= strtoul(key
+ 13, &endptr
, 16);
224 if (endptr
[0] != '\0') {
225 log_warning("Unable to parse scan code from \"%s\"", key
);
229 keycode
= udev_list_entry_get_value(entry
);
231 /* a leading '!' needs a force-release entry */
232 if (keycode
[0] == '!') {
235 release
[release_count
] = scancode
;
236 if (release_count
< ELEMENTSOF(release
)-1)
239 if (keycode
[0] == '\0')
244 fd
= open_device(node
);
249 map_keycode(fd
, node
, scancode
, keycode
);
250 } else if (startswith(key
, "EVDEV_ABS_")) {
253 /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
254 evcode
= strtoul(key
+ 10, &endptr
, 16);
255 if (endptr
[0] != '\0') {
256 log_warning("Unable to parse EV_ABS code from \"%s\"", key
);
261 fd
= open_device(node
);
270 rc
= ioctl(fd
, EVIOCGBIT(0, sizeof(bits
)), &bits
);
272 log_error_errno(errno
, "Unable to EVIOCGBIT device \"%s\"", node
);
276 has_abs
= !!(bits
& (1 << EV_ABS
));
278 log_warning("EVDEV_ABS override set but no EV_ABS present on device \"%s\"", node
);
284 override_abs(fd
, node
, evcode
, udev_list_entry_get_value(entry
));
285 } else if (streq(key
, "POINTINGSTICK_SENSITIVITY"))
286 set_trackpoint_sensitivity(dev
, udev_list_entry_get_value(entry
));
289 /* install list of force-release codes */
290 if (release_count
> 0)
291 install_force_release(dev
, release
, release_count
);
296 const struct udev_builtin udev_builtin_keyboard
= {
298 .cmd
= builtin_keyboard
,
299 .help
= "Keyboard scan code to key mapping",