summaryrefslogtreecommitdiff
path: root/src/udev
diff options
context:
space:
mode:
authorIan Stakenvicius <axs@gentoo.org>2013-07-24 14:00:06 -0400
committerIan Stakenvicius <axs@gentoo.org>2013-07-24 16:27:01 -0400
commit35876baf30ceab34fc16e3fb52763fc0be08f683 (patch)
treeacc96c905d60da830cd4b08b499f50ca4eb901a7 /src/udev
parent87b69cb04556d5dacae2eb1a9f2122ce5f6a4620 (diff)
Switch from external keymaps to internal (hwdb) keymaps
This commit imports the new internal keyboard handling from upstream. This is a combination of many upstream commits, including those that added code, removed old code, and updated the hwdb. Some commits (hwdb ones specifically) were unrelated but brought in anyways to keep the whole hwdb consistent. Each upstream commit included is as follows: 9d7d42bc406a2ac04639674281ce3ff6beeda790 - internal keymap support 0c959b39175b126fdb70ae00de37ca6d9c8ca3a1 - hwdb: keyboard -- add file e8193554925a22b63bef0e77b8397b56d63a91ff - hwdb: keyboard -- update comments c79d894d590fc9df4861738555cc43c477e33376 - hwdb: import data aedc2eddd16e48d468e6ad0aea2caf00c7d37365 - hwdb: keyboard update 97a9313cafccf772ce03f5ebd36fe4d9d8412583 - hwdb: drop non-existant Samsung 900XC3 from keymap ddc77f62244bb41d5c8261517e2e1ff1b763fc94 - switch from udev keymaps to hwdb 0c3815773331b263713f4f7b9d80bc1ca159338e - also remove keymaps-force-release directory 1b6bce89b3383904d0dab619dd38bff673f7286e - keymap: re-add Logitech USB corded/cordless models bf89b99c5a39115112c2eda4c2103e2db54988d2 - 60-keyboard.hwdb: Fix syntax error ce39bb6909578017aa10031638e724e038f0b859 - hwdb: data update, upstream 884c86812c51479496edd50b278383d7bb67baf0 - rules: keyboard - use builtin command All code from each of the above commits is attributed to the original authors. There were some adjustments made in order to support the code differences between upstream and eudev, which was done by myself. Also of note is that the code can still be disabled via the --disable-keymaps configure option, which was removed from upstream. Signed-off-by: Ian Stakenvicius <axs@gentoo.org>
Diffstat (limited to 'src/udev')
-rw-r--r--src/udev/Makefile.am35
-rw-r--r--src/udev/udev-builtin-keyboard.c163
-rw-r--r--src/udev/udev-builtin.c3
-rw-r--r--src/udev/udev.h6
4 files changed, 207 insertions, 0 deletions
diff --git a/src/udev/Makefile.am b/src/udev/Makefile.am
index 2bceb0c698..4a5f5fefa5 100644
--- a/src/udev/Makefile.am
+++ b/src/udev/Makefile.am
@@ -117,6 +117,41 @@ EXTRA_DIST = \
CLEANFILES = \
udev.pc
+if ENABLE_KEYMAP
+AM_CPPFLAGS += \
+ -I $(top_builddir)/src/udev
+
+libudev_core_la_SOURCES += \
+ udev-builtin-keyboard.c
+
+nodist_libudev_core_la_SOURCES = \
+ keyboard-keys-from-name.h \
+ keyboard-keys-to-name.h
+
+keyboard-keys.txt: Makefile
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@
+
+keyboard-keys-from-name.gperf: keyboard-keys.txt Makefile
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print tolower(substr($$1 ,5)) ", " $$1 }' < $< > $@
+
+keyboard-keys-from-name.h: keyboard-keys-from-name.gperf Makefile
+ $(AM_V_GPERF)$(GPERF) -L ANSI-C -t -N keyboard_lookup_key -H hash_key_name -p -C < $< > $@
+
+keyboard-keys-to-name.h: keyboard-keys.txt Makefile
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@
+
+
+BUILT_SOURCES = \
+ $(nodist_libudev_core_la_SOURCES)
+
+CLEANFILES += \
+ keyboard-keys-from-name.gperf \
+ keyboard-keys.txt \
+ $(BUILT_SOURCES)
+
+endif
+
# install udevadm symlink in sbindir
install-exec-hook:
if test "$(bindir)" != "$(sbindir)"; then \
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
new file mode 100644
index 0000000000..ddd853594e
--- /dev/null
+++ b/src/udev/udev-builtin-keyboard.c
@@ -0,0 +1,163 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Kay Sievers <kay@vrfy.org>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/limits.h>
+#include <linux/input.h>
+
+#include "udev.h"
+
+static const struct key *keyboard_lookup_key(const char *str, unsigned int len);
+#include "keyboard-keys-from-name.h"
+#include "keyboard-keys-to-name.h"
+
+static int install_force_release(struct udev_device *dev, const unsigned int *release, unsigned int release_count) {
+ struct udev_device *atkbd;
+ const char *cur;
+ char codes[4096];
+ char *s;
+ size_t l;
+ unsigned int i;
+ int ret;
+
+ atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
+ if (!atkbd)
+ return -ENODEV;
+
+ cur = udev_device_get_sysattr_value(atkbd, "force_release");
+ if (!cur)
+ return -ENODEV;
+
+ s = codes;
+ l = sizeof(codes);
+
+ /* copy current content */
+ l = strpcpy(&s, l, cur);
+
+ /* append new codes */
+ for (i = 0; i < release_count; i++)
+ l = strpcpyf(&s, l, ",%d", release[i]);
+
+ log_debug("keyboard: updating force-release list with '%s'\n", codes);
+ ret = udev_device_set_sysattr_value(atkbd, "force_release", codes);
+ if (ret < 0)
+ log_error("Error writing force-release attribute: %s", strerror(-ret));
+ return ret;
+}
+
+static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
+ struct udev_list_entry *entry;
+ struct {
+ unsigned int scan;
+ unsigned int key;
+ } map[1024];
+ unsigned int map_count = 0;
+ unsigned int release[1024];
+ unsigned int release_count = 0;
+
+ udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
+ const char *key;
+ unsigned int scancode;
+ char *endptr;
+ const char *keycode;
+ const struct key *k;
+
+ key = udev_list_entry_get_name(entry);
+ if (!startswith(key, "KEYBOARD_KEY_"))
+ continue;
+
+ /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
+ scancode = strtol(key + 13, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_error("Error, unable to parse scan code from '%s'\n", key);
+ continue;
+ }
+
+ keycode = udev_list_entry_get_value(entry);
+
+ /* a leading '!' needs a force-release entry */
+ if (keycode[0] == '!') {
+ keycode++;
+
+ release[release_count] = scancode;
+ if (release_count < ELEMENTSOF(release)-1)
+ release_count++;
+
+ if (keycode[0] == '\0')
+ continue;
+ }
+
+ /* translate identifier to key code */
+ k = keyboard_lookup_key(keycode, strlen(keycode));
+ if (!k) {
+ log_error("Error, unknown key identifier '%s'\n", keycode);
+ continue;
+ }
+
+ map[map_count].scan = scancode;
+ map[map_count].key = k->id;
+ if (map_count < ELEMENTSOF(map)-1)
+ map_count++;
+ }
+
+ if (map_count > 0 || release_count > 0) {
+ const char *node;
+ int fd;
+ unsigned int i;
+
+ node = udev_device_get_devnode(dev);
+ if (!node) {
+ log_error("Error, no device node for '%s'\n", udev_device_get_syspath(dev));
+ return EXIT_FAILURE;
+ }
+
+ fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (fd < 0) {
+ log_error("Error, opening device '%s': %m\n", node);
+ return EXIT_FAILURE;
+ }
+
+ /* install list of map codes */
+ for (i = 0; i < map_count; i++) {
+ log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)\n",
+ map[i].scan, map[i].scan, map[i].key, map[i].key);
+ if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0)
+ log_error("Error calling EVIOCSKEYCODE: %m\n");
+ }
+
+ /* install list of force-release codes */
+ if (release_count > 0)
+ install_force_release(dev, release, release_count);
+
+ close(fd);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+const struct udev_builtin udev_builtin_keyboard = {
+ .name = "keyboard",
+ .cmd = builtin_keyboard,
+ .help = "keyboard scan code to key mapping",
+};
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 22deaac1a8..d9cca9dde8 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -39,6 +39,9 @@ static const struct udev_builtin *builtins[] = {
#endif
[UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb,
[UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
+#ifdef ENABLE_KEYMAP
+ [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard,
+#endif
#ifdef HAVE_MODULES
[UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
#endif
diff --git a/src/udev/udev.h b/src/udev/udev.h
index f0256a4d09..80fdd4c0ec 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -145,6 +145,9 @@ enum udev_builtin_cmd {
#endif
UDEV_BUILTIN_HWDB,
UDEV_BUILTIN_INPUT_ID,
+#ifdef ENABLE_KEYMAP
+ UDEV_BUILTIN_KEYBOARD,
+#endif
#ifdef HAVE_MODULES
UDEV_BUILTIN_KMOD,
#endif
@@ -171,6 +174,9 @@ extern const struct udev_builtin udev_builtin_firmware;
#endif
extern const struct udev_builtin udev_builtin_hwdb;
extern const struct udev_builtin udev_builtin_input_id;
+#ifdef ENABLE_KEYMAP
+extern const struct udev_builtin udev_builtin_keyboard;
+#endif
#ifdef HAVE_MODULES
extern const struct udev_builtin udev_builtin_kmod;
#endif