[PATCH v6 RFC 04/10] kdrive: introduce input hot-plugging support for udev and hal backends (#33140)

Laércio de Sousa laerciosousa at sme-mogidascruzes.sp.gov.br
Thu Sep 3 11:00:49 PDT 2015


This patch introduces input hot-plugging support for kdrive-based
applications in multi-seat context. This feature is enabled
by passing -seat option with desired seat name. All keyboard/mouse
devices assigned to that seat will be automatically grabbed
by kdrive.

It supports udev and hal backends for input hot-plugging support.
Another patches may be required for wscons backend.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=33140

Signed-off-by: Laércio de Sousa <laerciosousa at sme-mogidascruzes.sp.gov.br>
---
 hw/kdrive/src/Makefile.am |   8 ++
 hw/kdrive/src/kdrive.c    |  39 +++++++++
 hw/kdrive/src/kinfo.c     |   4 +
 hw/kdrive/src/kinput.c    | 212 +++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 241 insertions(+), 22 deletions(-)

diff --git a/hw/kdrive/src/Makefile.am b/hw/kdrive/src/Makefile.am
index d69f0dd..b7f94b0 100644
--- a/hw/kdrive/src/Makefile.am
+++ b/hw/kdrive/src/Makefile.am
@@ -23,3 +23,11 @@ libkdrive_la_SOURCES =	\
 	kshadow.c	\
 	$(KDRIVE_XV_SOURCES) \
         $(top_srcdir)/mi/miinitext.c
+
+if CONFIG_UDEV
+libkdrive_la_LIBADD = $(top_builddir)/config/libconfig.la
+else
+if CONFIG_HAL
+libkdrive_la_LIBADD = $(top_builddir)/config/libconfig.la
+endif
+endif
diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c
index dddbe6e..8930ace 100644
--- a/hw/kdrive/src/kdrive.c
+++ b/hw/kdrive/src/kdrive.c
@@ -45,6 +45,10 @@
 
 #include <signal.h>
 
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+#include <hotplug.h>
+#endif
+
 typedef struct _kdDepths {
     CARD8 depth;
     CARD8 bpp;
@@ -1125,6 +1129,11 @@ KdInitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
             KdAddScreen(pScreenInfo, screen, argc, argv);
 
     OsRegisterSigWrapper(KdSignalWrapper);
+
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+    if (SeatId) /* Enable input hot-plugging */
+        config_pre_init();
+#endif
 }
 
 void
@@ -1143,3 +1152,33 @@ DPMSSupported(void)
 {
     return FALSE;
 }
+
+/* These stubs can be safely removed once we can
+ * split input and GPU parts in hotplug.h et al. */
+#ifdef CONFIG_UDEV_KMS
+void
+NewGPUDeviceRequest(struct OdevAttributes *attribs)
+{
+}
+
+void
+DeleteGPUDeviceRequest(struct OdevAttributes *attribs)
+{
+}
+#endif
+
+struct xf86_platform_device *
+xf86_find_platform_device_by_devnum(int major, int minor)
+{
+    return NULL;
+}
+
+void
+systemd_logind_release_fd(int _major, int _minor, int fd)
+{
+}
+
+void
+systemd_logind_vtenter(void)
+{
+}
diff --git a/hw/kdrive/src/kinfo.c b/hw/kdrive/src/kinfo.c
index 01ae1e4..f91d575 100644
--- a/hw/kdrive/src/kinfo.c
+++ b/hw/kdrive/src/kinfo.c
@@ -134,6 +134,7 @@ KdFreePointer(KdPointerInfo * pi)
     free(pi->name);
     free(pi->path);
     input_option_free_list(&pi->options);
+    pi->next = NULL;
     free(pi);
 }
 
@@ -145,6 +146,9 @@ KdFreeKeyboard(KdKeyboardInfo * ki)
     free(ki->xkbRules);
     free(ki->xkbModel);
     free(ki->xkbLayout);
+    free(ki->xkbVariant);
+    free(ki->xkbOptions);
+    input_option_free_list(&ki->options);
     ki->next = NULL;
     free(ki);
 }
diff --git a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c
index a0c1565..49c8bb6 100644
--- a/hw/kdrive/src/kinput.c
+++ b/hw/kdrive/src/kinput.c
@@ -51,6 +51,10 @@
 #include "inpututils.h"
 #include "optionstr.h"
 
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+#include <hotplug.h>
+#endif
+
 #ifdef KDRIVE_EVDEV
 #define DEV_INPUT_EVENT_PREFIX "/dev/input/event"
 #define DEV_INPUT_EVENT_PREFIX_LEN (sizeof(DEV_INPUT_EVENT_PREFIX) - 1)
@@ -396,7 +400,8 @@ KdPointerProc(DeviceIntPtr pDevice, int onoff)
 #endif
         if (!pi->driver) {
             if (!pi->driverPrivate) {
-                ErrorF("no driver specified for %s\n", pi->name);
+                ErrorF("no driver specified for pointer device \"%s\" (%s)\n",
+                       pi->name ? pi->name : "(unnamed)", pi->path);
                 return BadImplementation;
             }
 
@@ -716,7 +721,8 @@ KdKeyboardProc(DeviceIntPtr pDevice, int onoff)
 #endif
         if (!ki->driver) {
             if (!ki->driverPrivate) {
-                ErrorF("no driver specified!\n");
+                ErrorF("no driver specified for keyboard device \"%s\" (%s)\n",
+                       ki->name ? ki->name : "(unnamed)", ki->path);
                 return BadImplementation;
             }
 
@@ -890,6 +896,8 @@ KdNewKeyboard(void)
     ki->bellDuration = 200;
     ki->next = NULL;
     ki->options = NULL;
+    ki->name = strdup("Generic Keyboard");
+    ki->path = NULL;
     ki->xkbRules = strdup(XKB_DFLT_RULES);
     ki->xkbModel = strdup(XKB_DFLT_MODEL);
     ki->xkbLayout = strdup(XKB_DFLT_LAYOUT);
@@ -1073,18 +1081,52 @@ KdParseKbdOptions(KdKeyboardInfo * ki)
         const char *key = input_option_get_key(option);
         const char *value = input_option_get_value(option);
 
-        if (strcasecmp(key, "XkbRules") == 0)
+        if (
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+            strcasecmp(key, "xkb_rules") == 0 ||
+#endif
+            strcasecmp(key, "XkbRules") == 0)
             ki->xkbRules = strdup(value);
-        else if (strcasecmp(key, "XkbModel") == 0)
+        else if (
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+                 strcasecmp(key, "xkb_model") == 0 ||
+#endif
+                 strcasecmp(key, "XkbModel") == 0)
             ki->xkbModel = strdup(value);
-        else if (strcasecmp(key, "XkbLayout") == 0)
+        else if (
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+                 strcasecmp(key, "xkb_layout") == 0 ||
+#endif
+                 strcasecmp(key, "XkbLayout") == 0)
             ki->xkbLayout = strdup(value);
-        else if (strcasecmp(key, "XkbVariant") == 0)
+        else if (
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+                 strcasecmp(key, "xkb_variant") == 0 ||
+#endif
+                 strcasecmp(key, "XkbVariant") == 0)
             ki->xkbVariant = strdup(value);
-        else if (strcasecmp(key, "XkbOptions") == 0)
+        else if (
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+                 strcasecmp(key, "xkb_options") == 0 ||
+#endif
+                 strcasecmp(key, "XkbOptions") == 0)
             ki->xkbOptions = strdup(value);
-        else if (!strcasecmp(key, "device"))
+        else if (!strcasecmp(key, "device")) {
+            if (ki->path != NULL)
+                free(ki->path);
             ki->path = strdup(value);
+        }
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+        else if (!strcasecmp(key, "path")) {
+            if (ki->path != NULL)
+                free(ki->path);
+            ki->path = strdup(value);
+        }
+        else if (!strcasecmp(key, "name")) {
+            free(ki->name);
+            ki->name = strdup(value);
+        }
+#endif
         else if (!strcasecmp(key, "driver"))
             ki->driver = KdFindKeyboardDriver(value);
         else
@@ -1185,8 +1227,22 @@ KdParsePointerOptions(KdPointerInfo * pi)
             pi->transformCoordinates = TRUE;
         else if (!strcasecmp(key, "rawcoord"))
             pi->transformCoordinates = FALSE;
-        else if (!strcasecmp(key, "device"))
+        else if (!strcasecmp(key, "device")) {
+            if (pi->path != NULL)
+                free(pi->path);
             pi->path = strdup(value);
+        }
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+        else if (!strcasecmp(key, "path")) {
+            if (pi->path != NULL)
+                free(pi->path);
+            pi->path = strdup(value);
+        }
+        else if (!strcasecmp(key, "name")) {
+            free(pi->name);
+            pi->name = strdup(value);
+        }
+#endif
         else if (!strcasecmp(key, "protocol"))
             pi->protocol = strdup(value);
         else if (!strcasecmp(key, "driver"))
@@ -1309,11 +1365,21 @@ KdInitInput(void)
     }
 
     mieqInit();
+
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+    if (SeatId) /* Enable input hot-plugging */
+        config_init();
+#endif
 }
 
 void
 KdCloseInput(void)
 {
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+    if (SeatId) /* Input hot-plugging is enabled */
+        config_fini();
+#endif
+
     mieqFini();
 }
 
@@ -2176,24 +2242,29 @@ int
 NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
                       DeviceIntPtr *pdev)
 {
-    InputOption *option = NULL;
+    InputOption *option = NULL, *optionsdup = NULL;
     KdPointerInfo *pi = NULL;
     KdKeyboardInfo *ki = NULL;
 
     nt_list_for_each_entry(option, options, list.next) {
         const char *key = input_option_get_key(option);
         const char *value = input_option_get_value(option);
+        optionsdup = input_option_new(optionsdup, key, value);
 
         if (strcmp(key, "type") == 0) {
             if (strcmp(value, "pointer") == 0) {
                 pi = KdNewPointer();
-                if (!pi)
+                if (!pi) {
+                    input_option_free_list(&optionsdup);
                     return BadAlloc;
+                }
             }
             else if (strcmp(value, "keyboard") == 0) {
                 ki = KdNewKeyboard();
-                if (!ki)
+                if (!ki) { 
+                    input_option_free_list(&optionsdup);
                     return BadAlloc;
+                }
             }
             else {
                 ErrorF("unrecognised device type!\n");
@@ -2203,25 +2274,66 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
 #ifdef CONFIG_HAL
         else if (strcmp(key, "_source") == 0 &&
                  strcmp(value, "server/hal") == 0) {
-            ErrorF("Ignoring device from HAL.\n");
-            return BadValue;
+            if (SeatId) {
+                /* Input hot-plugging is enabled */
+                if (attrs->flags & ATTR_POINTER) {
+                    pi = KdNewPointer();
+                    if (!pi) {
+                        input_option_free_list(&optionsdup);
+                        return BadAlloc;
+                    }
+                }
+                else if (attrs->flags & ATTR_KEYBOARD) {
+                    ki = KdNewKeyboard();
+                    if (!ki) {
+                        input_option_free_list(&optionsdup);
+                        return BadAlloc;
+                    }
+                }
+            }
+            else {
+                ErrorF("Ignoring device from HAL.\n");
+                input_option_free_list(&optionsdup);
+                return BadValue;
+            }
         }
 #endif
 #ifdef CONFIG_UDEV
         else if (strcmp(key, "_source") == 0 &&
                  strcmp(value, "server/udev") == 0) {
-            ErrorF("Ignoring device from udev.\n");
-            return BadValue;
+            if (SeatId) {
+                /* Input hot-plugging is enabled */
+                if (attrs->flags & ATTR_POINTER) {
+                    pi = KdNewPointer();
+                    if (!pi) {
+                        input_option_free_list(&optionsdup);
+                        return BadAlloc;
+                    }
+                }
+                else if (attrs->flags & ATTR_KEYBOARD) {
+                    ki = KdNewKeyboard();
+                    if (!ki) {
+                        input_option_free_list(&optionsdup);
+                        return BadAlloc;
+                    }
+                }
+            }
+            else {
+                ErrorF("Ignoring device from udev.\n");
+                input_option_free_list(&optionsdup);
+                return BadValue;
+            }
         }
 #endif
     }
 
     if (pi) {
-        pi->options = options;
+        pi->options = optionsdup;
         KdParsePointerOptions(pi);
 
         if (!pi->driver) {
-            ErrorF("couldn't find driver!\n");
+            ErrorF("couldn't find driver for pointer device \"%s\" (%s)\n",
+                   pi->name ? pi->name : "(unnamed)", pi->path);
             KdFreePointer(pi);
             return BadValue;
         }
@@ -2229,18 +2341,21 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
         if (KdAddPointer(pi) != Success ||
             ActivateDevice(pi->dixdev, TRUE) != Success ||
             EnableDevice(pi->dixdev, TRUE) != TRUE) {
-            ErrorF("couldn't add or enable pointer\n");
+            ErrorF("couldn't add or enable pointer \"%s\" (%s)\n",
+                   pi->name ? pi->name : "(unnamed)", pi->path);
+            KdFreePointer(pi);
             return BadImplementation;
         }
 
         *pdev = pi->dixdev;
     }
     else if (ki) {
-        ki->options = options;
+        ki->options = optionsdup;
         KdParseKbdOptions(ki);
 
         if (!ki->driver) {
-            ErrorF("couldn't find driver!\n");
+            ErrorF("couldn't find driver for keyboard device \"%s\" (%s)\n",
+                   ki->name ? ki->name : "(unnamed)", ki->path);
             KdFreeKeyboard(ki);
             return BadValue;
         }
@@ -2248,7 +2363,9 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
         if (KdAddKeyboard(ki) != Success ||
             ActivateDevice(ki->dixdev, TRUE) != Success ||
             EnableDevice(ki->dixdev, TRUE) != TRUE) {
-            ErrorF("couldn't add or enable keyboard\n");
+            ErrorF("couldn't add or enable keyboard \"%s\" (%s)\n",
+                   ki->name ? ki->name : "(unnamed)", ki->path);
+            KdFreeKeyboard(ki);
             return BadImplementation;
         }
 
@@ -2256,6 +2373,7 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
     }
     else {
         ErrorF("unrecognised device identifier!\n");
+        input_option_free_list(&optionsdup);
         return BadValue;
     }
 
@@ -2265,5 +2383,55 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
 void
 DeleteInputDeviceRequest(DeviceIntPtr pDev)
 {
+#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
+    OsBlockSIGIO();
     RemoveDevice(pDev, TRUE);
+
+    /*
+     * Search for fds that were not unregistered correctly
+     * by RemoveDevice() call and unregister them.
+     * Code taken from KdInputDisable() implementation.
+     */
+    if (kdNumInputFds) {
+        KdKeyboardInfo *ki;
+        KdPointerInfo *pi;
+        int found = 0, i = 0;
+
+        while (i < kdNumInputFds) {
+            found = 0;
+
+            for (ki = kdKeyboards; ki; ki = ki->next) {
+                if (ki == kdInputFds[i].closure) {
+                    found = 1;
+                    break;
+                }
+            }
+
+            if (found) {
+                i++;
+                continue;
+            }
+
+            for (pi = kdPointers; pi; pi = pi->next) {
+                if (pi == kdInputFds[i].closure) {
+                    found = 1;
+                    break;
+                }
+            }
+
+            if (found) {
+                i++;
+                continue;
+            }
+
+            ErrorF("Unregistering fd not claimed by any active device: %d\n",
+                   kdInputFds[i].fd);
+            KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE);
+        }
+    }
+
+    OsReleaseSIGIO();
+#else
+    RemoveDevice(pDev, TRUE);
+#endif
 }
-- 
2.5.0



More information about the xorg-devel mailing list