2 This file is part of systemd.
4 Copyright 2013 Kay Sievers <kay@vrfy.org>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/ioctl.h>
24 #include <linux/input.h>
27 #include "parse-util.h"
28 #include "stdio-util.h"
29 #include "string-util.h"
32 static const struct key_name
*keyboard_lookup_key(const char *str
, GPERF_LEN_TYPE len
);
33 #include "keyboard-keys-from-name.h"
35 static int install_force_release(struct udev_device
*dev
, const unsigned *release
, unsigned release_count
) {
36 struct udev_device
*atkbd
;
47 atkbd
= udev_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
);
51 cur
= udev_device_get_sysattr_value(atkbd
, "force_release");
58 /* copy current content */
59 l
= strpcpy(&s
, l
, cur
);
61 /* append new codes */
62 for (i
= 0; i
< release_count
; i
++)
63 l
= strpcpyf(&s
, l
, ",%u", release
[i
]);
65 log_debug("keyboard: updating force-release list with '%s'", codes
);
66 ret
= udev_device_set_sysattr_value(atkbd
, "force_release", codes
);
68 log_error_errno(ret
, "Error writing force-release attribute: %m");
72 static void map_keycode(int fd
, const char *devnode
, int scancode
, const char *keycode
)
79 const struct key_name
*k
;
82 /* translate identifier to key code */
83 k
= keyboard_lookup_key(keycode
, strlen(keycode
));
87 /* check if it's a numeric code already */
88 keycode_num
= strtoul(keycode
, &endptr
, 0);
89 if (endptr
[0] !='\0') {
90 log_error("Unknown key identifier '%s'", keycode
);
96 map
.key
= keycode_num
;
98 log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
99 map
.scan
, map
.scan
, map
.key
, map
.key
);
101 if (ioctl(fd
, EVIOCSKEYCODE
, &map
) < 0)
102 log_error_errno(errno
, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode
, map
.scan
, map
.key
);
105 static inline char* parse_token(const char *current
, int32_t *val_out
) {
112 val
= strtol(current
, &next
, 0);
113 if (*next
&& *next
!= ':')
125 static void override_abs(int fd
, const char *devnode
,
126 unsigned evcode
, const char *value
) {
127 struct input_absinfo absinfo
;
131 rc
= ioctl(fd
, EVIOCGABS(evcode
), &absinfo
);
133 log_error_errno(errno
, "Unable to EVIOCGABS device \"%s\"", devnode
);
137 next
= parse_token(value
, &absinfo
.minimum
);
138 next
= parse_token(next
, &absinfo
.maximum
);
139 next
= parse_token(next
, &absinfo
.resolution
);
140 next
= parse_token(next
, &absinfo
.fuzz
);
141 next
= parse_token(next
, &absinfo
.flat
);
143 log_error("Unable to parse EV_ABS override '%s' for '%s'", value
, devnode
);
147 log_debug("keyboard: %x overridden with %"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
"/%"PRIi32
" for \"%s\"",
149 absinfo
.minimum
, absinfo
.maximum
, absinfo
.resolution
, absinfo
.fuzz
, absinfo
.flat
,
151 rc
= ioctl(fd
, EVIOCSABS(evcode
), &absinfo
);
153 log_error_errno(errno
, "Unable to EVIOCSABS device \"%s\"", devnode
);
156 static void set_trackpoint_sensitivity(struct udev_device
*dev
, const char *value
)
158 struct udev_device
*pdev
;
159 char val_s
[DECIMAL_STR_MAX(int)];
165 /* The sensitivity sysfs attr belongs to the serio parent device */
166 pdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "serio", NULL
);
168 log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev
));
172 r
= safe_atoi(value
, &val_i
);
174 log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value
, udev_device_get_devnode(dev
));
178 xsprintf(val_s
, "%d", val_i
);
180 r
= udev_device_set_sysattr_value(pdev
, "sensitivity", val_s
);
182 log_error_errno(r
, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev
));
185 static int open_device(const char *devnode
) {
188 fd
= open(devnode
, O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
190 return log_error_errno(errno
, "Error opening device \"%s\": %m", devnode
);
195 static int builtin_keyboard(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
196 struct udev_list_entry
*entry
;
197 unsigned release
[1024];
198 unsigned release_count
= 0;
199 _cleanup_close_
int fd
= -1;
202 node
= udev_device_get_devnode(dev
);
204 log_error("No device node for \"%s\"", udev_device_get_syspath(dev
));
208 udev_list_entry_foreach(entry
, udev_device_get_properties_list_entry(dev
)) {
212 key
= udev_list_entry_get_name(entry
);
213 if (startswith(key
, "KEYBOARD_KEY_")) {
217 /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
218 scancode
= strtoul(key
+ 13, &endptr
, 16);
219 if (endptr
[0] != '\0') {
220 log_warning("Unable to parse scan code from \"%s\"", key
);
224 keycode
= udev_list_entry_get_value(entry
);
226 /* a leading '!' needs a force-release entry */
227 if (keycode
[0] == '!') {
230 release
[release_count
] = scancode
;
231 if (release_count
< ELEMENTSOF(release
)-1)
234 if (keycode
[0] == '\0')
239 fd
= open_device(node
);
244 map_keycode(fd
, node
, scancode
, keycode
);
245 } else if (startswith(key
, "EVDEV_ABS_")) {
248 /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
249 evcode
= strtoul(key
+ 10, &endptr
, 16);
250 if (endptr
[0] != '\0') {
251 log_warning("Unable to parse EV_ABS code from \"%s\"", key
);
256 fd
= open_device(node
);
261 override_abs(fd
, node
, evcode
, udev_list_entry_get_value(entry
));
262 } else if (streq(key
, "POINTINGSTICK_SENSITIVITY"))
263 set_trackpoint_sensitivity(dev
, udev_list_entry_get_value(entry
));
266 /* install list of force-release codes */
267 if (release_count
> 0)
268 install_force_release(dev
, release
, release_count
);
273 const struct udev_builtin udev_builtin_keyboard
= {
275 .cmd
= builtin_keyboard
,
276 .help
= "Keyboard scan code to key mapping",