Zbigniew Jędrzejewski-Szmek 62fe94
From e202fa31fb2d60084e7b2ab7976a81c138184d40 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Wed, 27 Aug 2014 18:17:27 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal: add input interface
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
The idev-interface provides input drivers for all libsystemd-terminal
Zbigniew Jędrzejewski-Szmek 62fe94
based applications. It is split into 4 main objects:
Zbigniew Jędrzejewski-Szmek 62fe94
    idev_context: The context object tracks global state of the input
Zbigniew Jędrzejewski-Szmek 62fe94
                  interface. This will include data like system-keymaps,
Zbigniew Jędrzejewski-Szmek 62fe94
                  xkb contexts and more.
Zbigniew Jędrzejewski-Szmek 62fe94
    idev_session: A session serves as controller for a set of devices.
Zbigniew Jędrzejewski-Szmek 62fe94
                  Each session on an idev-context is independent of each
Zbigniew Jędrzejewski-Szmek 62fe94
                  other. The session is also the main notification object.
Zbigniew Jędrzejewski-Szmek 62fe94
                  All events raised via idev are reported through the
Zbigniew Jędrzejewski-Szmek 62fe94
                  session interface. Apart of that, the session is a
Zbigniew Jędrzejewski-Szmek 62fe94
                  pretty dumb object that just contains devices.
Zbigniew Jędrzejewski-Szmek 62fe94
    idev_element: Elements provide real hardware in the idev stack. For
Zbigniew Jędrzejewski-Szmek 62fe94
                  each hardware device, one element is added. Elements
Zbigniew Jędrzejewski-Szmek 62fe94
                  have no knowledge of higher-level device types, they
Zbigniew Jędrzejewski-Szmek 62fe94
                  only provide raw input data to the upper levels. For
Zbigniew Jędrzejewski-Szmek 62fe94
                  example, each evdev device is represented by a different
Zbigniew Jędrzejewski-Szmek 62fe94
                  element in an idev session.
Zbigniew Jędrzejewski-Szmek 62fe94
     idev_device: Devices are objects that the application deals with. An
Zbigniew Jędrzejewski-Szmek 62fe94
                  application is usually not interested in elements (and
Zbigniew Jędrzejewski-Szmek 62fe94
                  those are hidden to applications), instead, they want
Zbigniew Jędrzejewski-Szmek 62fe94
                  high-level input devices like keyboard, touchpads, mice
Zbigniew Jędrzejewski-Szmek 62fe94
                  and more. Device are the high-level interface provided
Zbigniew Jędrzejewski-Szmek 62fe94
                  by idev. Each device might be fed by a set of elements.
Zbigniew Jędrzejewski-Szmek 62fe94
                  Elements drive the device. If elements are removed,
Zbigniew Jędrzejewski-Szmek 62fe94
                  devices are destroyed. If elements are added, suitable
Zbigniew Jędrzejewski-Szmek 62fe94
                  devices are created.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Applications should monitor the system for sessions and hardware devices.
Zbigniew Jędrzejewski-Szmek 62fe94
For each session they want to operate on, they create an idev_session
Zbigniew Jędrzejewski-Szmek 62fe94
object and add hardware to that object. The idev interface requires the
Zbigniew Jędrzejewski-Szmek 62fe94
application to monitor the system (preferably via sysview_*, but not
Zbigniew Jędrzejewski-Szmek 62fe94
required) for hardware devices. Whenever hardware is added to the idev
Zbigniew Jędrzejewski-Szmek 62fe94
session, new devices *might* be created. The relationship between hardware
Zbigniew Jędrzejewski-Szmek 62fe94
and high-level idev-devices is hidden in the idev-session and not exposed.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Internally, the idev elements and devices are virtual objects. Each real
Zbigniew Jędrzejewski-Szmek 62fe94
hardware and device type inherits those virtual objects and provides real
Zbigniew Jędrzejewski-Szmek 62fe94
elements and devices. Those types will be added in follow-up commits.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Data flow from hardware to the application is done via idev_*_feed()
Zbigniew Jędrzejewski-Szmek 62fe94
functions. Data flow from applications to hardware is done via
Zbigniew Jędrzejewski-Szmek 62fe94
idev_*_feedback() functions. Feedback is usually used for LEDs, FF and
Zbigniew Jędrzejewski-Szmek 62fe94
similar operations.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 Makefile.am                             |   3 +
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev-internal.h | 165 +++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev.c          | 587 ++++++++++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev.h          | 133 ++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 4 files changed, 888 insertions(+)
Zbigniew Jędrzejewski-Szmek 62fe94
 create mode 100644 src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
 create mode 100644 src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
 create mode 100644 src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/Makefile.am b/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
index 3a263f8c17..82f474e20e 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2971,6 +2971,9 @@ libsystemd_terminal_la_CFLAGS = \
Zbigniew Jędrzejewski-Szmek 62fe94
 	$(AM_CFLAGS)
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 libsystemd_terminal_la_SOURCES = \
Zbigniew Jędrzejewski-Szmek 62fe94
+	src/libsystemd-terminal/idev.h \
Zbigniew Jędrzejewski-Szmek 62fe94
+	src/libsystemd-terminal/idev-internal.h \
Zbigniew Jędrzejewski-Szmek 62fe94
+	src/libsystemd-terminal/idev.c \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview.h \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview-internal.h \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview.c \
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
new file mode 100644
Zbigniew Jędrzejewski-Szmek 62fe94
index 0000000000..bffefbb9c1
Zbigniew Jędrzejewski-Szmek 62fe94
--- /dev/null
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -0,0 +1,165 @@
Zbigniew Jędrzejewski-Szmek 62fe94
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/***
Zbigniew Jędrzejewski-Szmek 62fe94
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 62fe94
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 62fe94
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 62fe94
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 62fe94
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 62fe94
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 62fe94
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 62fe94
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 62fe94
+***/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#pragma once
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <inttypes.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdbool.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "idev.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "list.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_link                idev_link;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_device_vtable       idev_device_vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_element             idev_element;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_element_vtable      idev_element_vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Element Links
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_link {
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* element-to-device connection */
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_FIELDS(idev_link, links_by_element);
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element *element;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* device-to-element connection */
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_FIELDS(idev_link, links_by_device);
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *device;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_device_vtable {
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*free) (idev_device *d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*attach) (idev_device *d, idev_link *l);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*detach) (idev_device *d, idev_link *l);
Zbigniew Jędrzejewski-Szmek 62fe94
+        int (*feed) (idev_device *d, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_device {
Zbigniew Jędrzejewski-Szmek 62fe94
+        const idev_device_vtable *vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_session *session;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *name;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_HEAD(idev_link, links);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool public : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool enabled : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#define IDEV_DEVICE_INIT(_vtable, _session) ((idev_device){ \
Zbigniew Jędrzejewski-Szmek 62fe94
+                .vtable = (_vtable), \
Zbigniew Jędrzejewski-Szmek 62fe94
+                .session = (_session), \
Zbigniew Jędrzejewski-Szmek 62fe94
+        })
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_find_device(idev_session *s, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_device_add(idev_device *d, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_device_free(idev_device *d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(idev_device*, idev_device_free);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_device_feed(idev_device *d, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_feedback(idev_device *d, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Elements
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_element_vtable {
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*free) (idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*enable) (idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*disable) (idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*open) (idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*close) (idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        void (*feedback) (idev_element *e, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_element {
Zbigniew Jędrzejewski-Szmek 62fe94
+        const idev_element_vtable *vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_session *session;
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned long n_open;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *name;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_HEAD(idev_link, links);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool enabled : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool readable : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool writable : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#define IDEV_ELEMENT_INIT(_vtable, _session) ((idev_element){ \
Zbigniew Jędrzejewski-Szmek 62fe94
+                .vtable = (_vtable), \
Zbigniew Jędrzejewski-Szmek 62fe94
+                .session = (_session), \
Zbigniew Jędrzejewski-Szmek 62fe94
+        })
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_element *idev_find_element(idev_session *s, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_element_add(idev_element *e, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_element *idev_element_free(idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(idev_element*, idev_element_free);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_element_feed(idev_element *e, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_element_feedback(idev_element *e, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Sessions
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_session {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_context *context;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *name;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *path;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        Hashmap *element_map;
Zbigniew Jędrzejewski-Szmek 62fe94
+        Hashmap *device_map;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_event_fn event_fn;
Zbigniew Jędrzejewski-Szmek 62fe94
+        void *userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool custom : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool managed : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool enabled : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_session *idev_find_session(idev_context *c, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Contexts
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_context {
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned long ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_event *event;
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_bus *sysbus;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        Hashmap *session_map;
Zbigniew Jędrzejewski-Szmek 62fe94
+        Hashmap *data_map;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
new file mode 100644
Zbigniew Jędrzejewski-Szmek 62fe94
index 0000000000..5e3080797a
Zbigniew Jędrzejewski-Szmek 62fe94
--- /dev/null
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -0,0 +1,587 @@
Zbigniew Jędrzejewski-Szmek 62fe94
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/***
Zbigniew Jędrzejewski-Szmek 62fe94
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 62fe94
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 62fe94
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 62fe94
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 62fe94
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 62fe94
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 62fe94
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 62fe94
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 62fe94
+***/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <inttypes.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdbool.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-login.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "idev.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "idev-internal.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "login-shared.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "macro.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "set.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_open(idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_close(idev_element *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_find_device(idev_session *s, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(s, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return hashmap_get(s->device_map, name);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_device_add(idev_device *d, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(d, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(d->vtable, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(d->session, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        d->name = strdup(name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!d->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = hashmap_put(d->session->device_map, d->name, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_device_free(idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device tmp;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!d)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(!d->enabled);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(!d->public);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(!d->links);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d->vtable);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d->vtable->free);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                hashmap_remove_value(d->session->device_map, d->name, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        tmp = *d;
Zbigniew Jędrzejewski-Szmek 62fe94
+        d->vtable->free(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(tmp.name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_device_feed(idev_device *d, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data->type < IDEV_DATA_CNT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->vtable->feed)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return d->vtable->feed(d, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        else
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_feedback(idev_device *d, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data->type < IDEV_DATA_CNT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_FOREACH(links_by_device, l, d->links)
Zbigniew Jędrzejewski-Szmek 62fe94
+                idev_element_feedback(l->element, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void device_attach(idev_device *d, idev_link *l) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(l);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->vtable->attach)
Zbigniew Jędrzejewski-Szmek 62fe94
+                d->vtable->attach(d, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
+                element_open(l->element);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void device_detach(idev_device *d, idev_link *l) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(l);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
+                element_close(l->element);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->vtable->detach)
Zbigniew Jędrzejewski-Szmek 62fe94
+                d->vtable->detach(d, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_enable(idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!d->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                d->enabled = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+                LIST_FOREACH(links_by_device, l, d->links)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        element_open(l->element);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_disable(idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (d->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                d->enabled = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                LIST_FOREACH(links_by_device, l, d->links)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        element_close(l->element);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Elements
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_element *idev_find_element(idev_session *s, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(s, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return hashmap_get(s->element_map, name);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_element_add(idev_element *e, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->vtable, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->session, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        e->name = strdup(name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!e->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = hashmap_put(e->session->element_map, e->name, e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_element *idev_element_free(idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element tmp;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!e)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(!e->enabled);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(!e->links);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e->n_open == 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e->vtable);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e->vtable->free);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                hashmap_remove_value(e->session->element_map, e->name, e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        tmp = *e;
Zbigniew Jędrzejewski-Szmek 62fe94
+        e->vtable->free(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(tmp.name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_element_feed(idev_element *e, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, error = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data->type < IDEV_DATA_CNT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_FOREACH(links_by_element, l, e->links) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = idev_device_feed(l->device, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r != 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        error = r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return error;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_element_feedback(idev_element *e, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(data->type < IDEV_DATA_CNT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->vtable->feedback)
Zbigniew Jędrzejewski-Szmek 62fe94
+               e->vtable->feedback(e, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_open(idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->n_open++ == 0 && e->vtable->open)
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->vtable->open(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_close(idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e->n_open > 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (--e->n_open == 0 && e->vtable->close)
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->vtable->close(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_enable(idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!e->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->enabled = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (e->vtable->enable)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        e->vtable->enable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void element_disable(idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->enabled = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (e->vtable->disable)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        e->vtable->disable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Sessions
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_raise(idev_session *s, idev_event *ev) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        return s->event_fn(s, s->userdata, ev);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_raise_device_add(idev_session *s, idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_event event = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                .type = IDEV_EVENT_DEVICE_ADD,
Zbigniew Jędrzejewski-Szmek 62fe94
+                .device_add = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        .device = d,
Zbigniew Jędrzejewski-Szmek 62fe94
+                },
Zbigniew Jędrzejewski-Szmek 62fe94
+        };
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return session_raise(s, &event);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_raise_device_remove(idev_session *s, idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_event event = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                .type = IDEV_EVENT_DEVICE_REMOVE,
Zbigniew Jędrzejewski-Szmek 62fe94
+                .device_remove = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        .device = d,
Zbigniew Jędrzejewski-Szmek 62fe94
+                },
Zbigniew Jędrzejewski-Szmek 62fe94
+        };
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return session_raise(s, &event);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_event event = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                .type = IDEV_EVENT_DEVICE_DATA,
Zbigniew Jędrzejewski-Szmek 62fe94
+                .device_data = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        .device = d,
Zbigniew Jędrzejewski-Szmek 62fe94
+                        .data = *data,
Zbigniew Jędrzejewski-Szmek 62fe94
+                },
Zbigniew Jędrzejewski-Szmek 62fe94
+        };
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return session_raise(s, &event);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_add_device(idev_session *s, idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev: %s: add device '%s'", s->name, d->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        d->public = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = session_raise_device_add(s, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r != 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                d->public = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+error:
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev: %s: error while adding device '%s': %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          s->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_remove_device(idev_session *s, idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, error = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev: %s: remove device '%s'", s->name, d->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        d->public = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = session_raise_device_remove(s, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r != 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                error = r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device_disable(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (error < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev: %s: error while removing device '%s': %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          s->name, d->name, strerror(-error));
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device_free(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return error;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_add_element(idev_session *s, idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev: %s: add element '%s'", s->name, e->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
+                element_enable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int session_remove_element(idev_session *s, idev_element *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, error = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev: %s: remove element '%s'", s->name, e->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        while ((l = e->links)) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                d = l->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+                LIST_REMOVE(links_by_device, d->links, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+                LIST_REMOVE(links_by_element, e->links, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+                device_detach(d, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!d->links) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = session_remove_device(s, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+                        if (r != 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                                error = r;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                l->device = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+                l->element = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+                free(l);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        element_disable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (error < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev: %s: error while removing element '%s': %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          s->name, e->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element_free(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return error;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_session *idev_find_session(idev_context *c, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return hashmap_get(c->session_map, name);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_session_new(idev_session **out,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     idev_context *c,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     unsigned int flags,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     const char *name,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     idev_event_fn event_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     void *userdata) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_(idev_session_freep) idev_session *s = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(event_fn, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return((flags & IDEV_SESSION_CUSTOM) == !session_id_valid(name), -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(!(flags & IDEV_SESSION_CUSTOM) || !(flags & IDEV_SESSION_MANAGED), -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(!(flags & IDEV_SESSION_MANAGED) || c->sysbus, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s = new0(idev_session, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->context = idev_context_ref(c);
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->custom = flags & IDEV_SESSION_CUSTOM;
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->managed = flags & IDEV_SESSION_MANAGED;
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->event_fn = event_fn;
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->userdata = userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->name = strdup(name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->managed) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = sd_bus_path_encode("/org/freedesktop/login1/session", s->name, &s->path);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->element_map = hashmap_new(string_hash_func, string_compare_func);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->element_map)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->device_map = hashmap_new(string_hash_func, string_compare_func);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->device_map)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = hashmap_put(c->session_map, s->name, s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        *out = s;
Zbigniew Jędrzejewski-Szmek 62fe94
+        s = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_session *idev_session_free(idev_session *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element *e;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        while ((e = hashmap_first(s->element_map)))
Zbigniew Jędrzejewski-Szmek 62fe94
+                session_remove_element(s, e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(hashmap_size(s->device_map) == 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                hashmap_remove_value(s->context->session_map, s->name, s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        s->context = idev_context_unref(s->context);
Zbigniew Jędrzejewski-Szmek 62fe94
+        hashmap_free(s->device_map);
Zbigniew Jędrzejewski-Szmek 62fe94
+        hashmap_free(s->element_map);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(s->path);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(s->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+bool idev_session_is_enabled(idev_session *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        return s && s->enabled;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_session_enable(idev_session *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element *e;
Zbigniew Jędrzejewski-Szmek 62fe94
+        Iterator i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                s->enabled = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+                HASHMAP_FOREACH(e, s->element_map, i)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        element_enable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_session_disable(idev_session *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_element *e;
Zbigniew Jędrzejewski-Szmek 62fe94
+        Iterator i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                s->enabled = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                HASHMAP_FOREACH(e, s->element_map, i)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        element_disable(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Contexts
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_(idev_context_unrefp) idev_context *c = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(event, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        c = new0(idev_context, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!c)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->ref = 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->event = sd_event_ref(event);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (sysbus)
Zbigniew Jędrzejewski-Szmek 62fe94
+                c->sysbus = sd_bus_ref(sysbus);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->session_map = hashmap_new(string_hash_func, string_compare_func);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!c->session_map)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->data_map = hashmap_new(string_hash_func, string_compare_func);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!c->data_map)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        *out = c;
Zbigniew Jędrzejewski-Szmek 62fe94
+        c = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void context_cleanup(idev_context *c) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(hashmap_size(c->data_map) == 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(hashmap_size(c->session_map) == 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        hashmap_free(c->data_map);
Zbigniew Jędrzejewski-Szmek 62fe94
+        hashmap_free(c->session_map);
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->sysbus = sd_bus_unref(c->sysbus);
Zbigniew Jędrzejewski-Szmek 62fe94
+        c->event = sd_event_unref(c->event);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(c);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_context *idev_context_ref(idev_context *c) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        ++c->ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return c;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_context *idev_context_unref(idev_context *c) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!c)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (--c->ref == 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                context_cleanup(c);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
new file mode 100644
Zbigniew Jędrzejewski-Szmek 62fe94
index 0000000000..6f618f37af
Zbigniew Jędrzejewski-Szmek 62fe94
--- /dev/null
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -0,0 +1,133 @@
Zbigniew Jędrzejewski-Szmek 62fe94
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/***
Zbigniew Jędrzejewski-Szmek 62fe94
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 62fe94
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 62fe94
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 62fe94
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 62fe94
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 62fe94
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 62fe94
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 62fe94
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 62fe94
+***/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * IDev
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#pragma once
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <inttypes.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdbool.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_data                idev_data;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_event               idev_event;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_device              idev_device;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_session             idev_session;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_context             idev_context;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Types
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_ELEMENT_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_DEVICE_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Data Packets
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_DATA_RESYNC,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_DATA_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_data {
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned int type;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool resync : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Events
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_EVENT_DEVICE_ADD,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_EVENT_DEVICE_REMOVE,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_EVENT_DEVICE_DATA,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_EVENT_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_event {
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned int type;
Zbigniew Jędrzejewski-Szmek 62fe94
+        union {
Zbigniew Jędrzejewski-Szmek 62fe94
+                struct {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        idev_device *device;
Zbigniew Jędrzejewski-Szmek 62fe94
+                } device_add, device_remove;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                struct {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        idev_device *device;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        idev_data data;
Zbigniew Jędrzejewski-Szmek 62fe94
+                } device_data;
Zbigniew Jędrzejewski-Szmek 62fe94
+        };
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef int (*idev_event_fn) (idev_session *s, void *userdata, idev_event *ev);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_enable(idev_device *d);
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_device_disable(idev_device *d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Sessions
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_SESSION_CUSTOM                     = (1 << 0),
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_SESSION_MANAGED                    = (1 << 1),
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_session_new(idev_session **out,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     idev_context *c,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     unsigned int flags,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     const char *name,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     idev_event_fn event_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                     void *userdata);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_session *idev_session_free(idev_session *s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(idev_session*, idev_session_free);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+bool idev_session_is_enabled(idev_session *s);
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_session_enable(idev_session *s);
Zbigniew Jędrzejewski-Szmek 62fe94
+void idev_session_disable(idev_session *s);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Contexts
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_context *idev_context_ref(idev_context *c);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_context *idev_context_unref(idev_context *c);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(idev_context*, idev_context_unref);