chiark / gitweb /
terminal: add systemd-modeset debugging tool
[elogind.git] / src / libsystemd-terminal / idev.c
index 5e3080797a75d6d4c7c4a0526f2ea5ce5c277452..8592930662affa6b378d42fa24ae2fb53ecba2f6 100644 (file)
 ***/
 
 #include <inttypes.h>
+#include <libudev.h>
+#include <linux/input.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <systemd/sd-bus.h>
 #include <systemd/sd-event.h>
 #include <systemd/sd-login.h>
+#include <xkbcommon/xkbcommon.h>
 #include "hashmap.h"
 #include "idev.h"
 #include "idev-internal.h"
 #include "login-shared.h"
 #include "macro.h"
-#include "set.h"
+#include "udev-util.h"
 #include "util.h"
 
 static void element_open(idev_element *e);
@@ -451,11 +454,11 @@ int idev_session_new(idev_session **out,
                         return r;
         }
 
-        s->element_map = hashmap_new(string_hash_func, string_compare_func);
+        s->element_map = hashmap_new(&string_hash_ops);
         if (!s->element_map)
                 return -ENOMEM;
 
-        s->device_map = hashmap_new(string_hash_func, string_compare_func);
+        s->device_map = hashmap_new(&string_hash_ops);
         if (!s->device_map)
                 return -ENOMEM;
 
@@ -522,6 +525,108 @@ void idev_session_disable(idev_session *s) {
         }
 }
 
+static int add_link(idev_element *e, idev_device *d) {
+        idev_link *l;
+
+        assert(e);
+        assert(d);
+
+        l = new0(idev_link, 1);
+        if (!l)
+                return -ENOMEM;
+
+        l->element = e;
+        l->device = d;
+        LIST_PREPEND(links_by_element, e->links, l);
+        LIST_PREPEND(links_by_device, d->links, l);
+        device_attach(d, l);
+
+        return 0;
+}
+
+static int guess_type(struct udev_device *d) {
+        const char *id_key;
+
+        id_key = udev_device_get_property_value(d, "ID_INPUT_KEY");
+        if (streq_ptr(id_key, "1"))
+                return IDEV_DEVICE_KEYBOARD;
+
+        return IDEV_DEVICE_CNT;
+}
+
+int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
+        idev_element *e;
+        idev_device *d;
+        dev_t devnum;
+        int r, type;
+
+        assert_return(s, -EINVAL);
+        assert_return(ud, -EINVAL);
+
+        devnum = udev_device_get_devnum(ud);
+        if (devnum == 0)
+                return 0;
+
+        e = idev_find_evdev(s, devnum);
+        if (e)
+                return 0;
+
+        r = idev_evdev_new(&e, s, ud);
+        if (r < 0)
+                return r;
+
+        r = session_add_element(s, e);
+        if (r != 0)
+                return r;
+
+        type = guess_type(ud);
+        if (type < 0)
+                return type;
+
+        switch (type) {
+        case IDEV_DEVICE_KEYBOARD:
+                d = idev_find_keyboard(s, e->name);
+                if (d) {
+                        log_debug("idev: %s: keyboard for new evdev element '%s' already available",
+                                  s->name, e->name);
+                        return 0;
+                }
+
+                r = idev_keyboard_new(&d, s, e->name);
+                if (r < 0)
+                        return r;
+
+                r = add_link(e, d);
+                if (r < 0) {
+                        idev_device_free(d);
+                        return r;
+                }
+
+                return session_add_device(s, d);
+        default:
+                /* unknown elements are silently ignored */
+                return 0;
+        }
+}
+
+int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) {
+        idev_element *e;
+        dev_t devnum;
+
+        assert(s);
+        assert(ud);
+
+        devnum = udev_device_get_devnum(ud);
+        if (devnum == 0)
+                return 0;
+
+        e = idev_find_evdev(s, devnum);
+        if (!e)
+                return 0;
+
+        return session_remove_element(s, e);
+}
+
 /*
  * Contexts
  */
@@ -542,11 +647,11 @@ int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus) {
         if (sysbus)
                 c->sysbus = sd_bus_ref(sysbus);
 
-        c->session_map = hashmap_new(string_hash_func, string_compare_func);
+        c->session_map = hashmap_new(&string_hash_ops);
         if (!c->session_map)
                 return -ENOMEM;
 
-        c->data_map = hashmap_new(string_hash_func, string_compare_func);
+        c->data_map = hashmap_new(&string_hash_ops);
         if (!c->data_map)
                 return -ENOMEM;