xref: /OK3568_Linux_fs/external/xserver/debian/patches/02_kbsd-input-devd.diff (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1>From d96e2bd2a2b48ede527ad7071d3e0eeda9861b73 Mon Sep 17 00:00:00 2001
2From: Robert Millan <rmh@debian.org>
3Date: Mon, 24 Feb 2014 23:22:57 +0100
4Subject: [PATCH] Add devd config backend for FreeBSD (and GNU/kFreeBSD)
5
6Based on original code by Baptiste Daroussin, with some fixes made
7by Koop Mast and myself.
8
9Signed-off-by: Robert Millan <rmh@freebsd.org>
10
11v2 - Emilio Pozuelo Monfort <pochu@debian.org>
12
13 - Ported to NotifyFd API.
14---
15 config/Makefile.am              |    4 +
16 config/config-backends.h        |    5 +
17 config/config.c                 |    5 +
18 config/devd.c                   |  387 +++++++++++++++++++++++++++++++++++++++
19 configure.ac                    |   16 ++
20 hw/xfree86/common/xf86Config.c  |    7 +-
21 hw/xfree86/common/xf86Globals.c |    3 +-
22 include/dix-config.h.in         |    3 +
23 8 files changed, 427 insertions(+), 3 deletions(-)
24 create mode 100644 config/devd.c
25
26--- a/config/Makefile.am
27+++ b/config/Makefile.am
28@@ -34,6 +34,10 @@ if CONFIG_WSCONS
29 libconfig_la_SOURCES += wscons.c
30 endif # CONFIG_WSCONS
31
32+if CONFIG_DEVD
33+libconfig_la_SOURCES += devd.c
34+endif
35+
36 endif # !CONFIG_HAL
37
38 endif # !CONFIG_UDEV
39--- a/config/config-backends.h
40+++ b/config/config-backends.h
41@@ -44,3 +44,8 @@ void config_hal_fini(void);
42 int config_wscons_init(void);
43 void config_wscons_fini(void);
44 #endif
45+
46+#ifdef CONFIG_DEVD
47+int config_devd_init(void);
48+void config_devd_fini(void);
49+#endif
50--- a/config/config.c
51+++ b/config/config.c
52@@ -55,6 +55,9 @@ config_init(void)
53 #elif defined(CONFIG_WSCONS)
54     if (!config_wscons_init())
55         ErrorF("[config] failed to initialise wscons\n");
56+#elif defined(CONFIG_DEVD)
57+    if (!config_devd_init())
58+        ErrorF("[config] failed to initialise devd\n");
59 #endif
60 }
61
62@@ -67,6 +70,8 @@ config_fini(void)
63     config_hal_fini();
64 #elif defined(CONFIG_WSCONS)
65     config_wscons_fini();
66+#elif defined(CONFIG_DEVD)
67+    config_devd_fini();
68 #endif
69 }
70
71--- /dev/null
72+++ b/config/devd.c
73@@ -0,0 +1,375 @@
74+/*
75+ * Copyright © 2012 Baptiste Daroussin
76+ * Copyright © 2014 Robert Millan
77+ *
78+ * Permission is hereby granted, free of charge, to any person obtaining a
79+ * copy of this software and associated documentation files (the "Software"),
80+ * to deal in the Software without restriction, including without limitation
81+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
82+ * and/or sell copies of the Software, and to permit persons to whom the
83+ * Software is furnished to do so, subject to the following conditions:
84+ *
85+ * The above copyright notice and this permission notice (including the next
86+ * paragraph) shall be included in all copies or substantial portions of the
87+ * Software.
88+ *
89+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
92+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
94+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
95+ * DEALINGS IN THE SOFTWARE.
96+ *
97+ * Author: Baptiste Daroussin <bapt@FreeBSD.org>
98+ */
99+
100+#ifdef HAVE_DIX_CONFIG_H
101+#include <dix-config.h>
102+#endif
103+
104+#include <sys/types.h>
105+#include <sys/socket.h>
106+#include <sys/sysctl.h>
107+#include <sys/un.h>
108+
109+#include <ctype.h>
110+#include <errno.h>
111+#include <fcntl.h>
112+#include <stdlib.h>
113+#include <stdio.h>
114+#include <stdarg.h>
115+#include <stdbool.h>
116+#include <unistd.h>
117+
118+#include "input.h"
119+#include "inputstr.h"
120+#include "hotplug.h"
121+#include "config-backends.h"
122+#include "os.h"
123+
124+#define DEVD_SOCK_PATH "/var/run/devd.pipe"
125+
126+#define DEVD_EVENT_ADD		'+'
127+#define DEVD_EVENT_REMOVE	'-'
128+
129+static int sock_devd = -1;
130+
131+struct hw_type {
132+    const char *driver;
133+    int flag;
134+    const char *xdriver;
135+};
136+
137+static struct hw_type hw_types[] = {
138+    {"ukbd", ATTR_KEYBOARD, "kbd"},
139+    {"atkbd", ATTR_KEYBOARD, "kbd"},
140+    {"ums", ATTR_POINTER, "mouse"},
141+    {"psm", ATTR_POINTER, "mouse"},
142+    {"uhid", ATTR_POINTER, "mouse"},
143+    {"joy", ATTR_JOYSTICK, NULL},
144+    {"atp", ATTR_TOUCHPAD, NULL},
145+    {"uep", ATTR_TOUCHSCREEN, NULL},
146+    {NULL, -1, NULL},
147+};
148+
149+static bool
150+sysctl_exists(const char *format, ...)
151+{
152+    va_list args;
153+    char *name = NULL;
154+    size_t len;
155+    int ret;
156+
157+    if (format == NULL)
158+        return false;
159+
160+    va_start(args, format);
161+    vasprintf(&name, format, args);
162+    va_end(args);
163+
164+    ret = sysctlbyname(name, NULL, &len, NULL, 0);
165+
166+    if (ret == -1)
167+        len = 0;
168+
169+    free(name);
170+    return (len > 0);
171+}
172+
173+static char *
174+sysctl_get_str(const char *format, ...)
175+{
176+    va_list args;
177+    char *name = NULL;
178+    char *dest = NULL;
179+    size_t len;
180+
181+    if (format == NULL)
182+        return NULL;
183+
184+    va_start(args, format);
185+    vasprintf(&name, format, args);
186+    va_end(args);
187+
188+    if (sysctlbyname(name, NULL, &len, NULL, 0) == 0) {
189+        dest = malloc(len + 1);
190+        if (!dest)
191+            goto unwind;
192+        if (sysctlbyname(name, dest, &len, NULL, 0) == 0)
193+            dest[len] = '\0';
194+        else {
195+            free(dest);
196+            dest = NULL;
197+        }
198+    }
199+
200+ unwind:
201+    free(name);
202+    return dest;
203+}
204+
205+static void
206+device_added(char *devname)
207+{
208+    char path[PATH_MAX];
209+    char *vendor;
210+    char *product = NULL;
211+    char *config_info = NULL;
212+    char *walk;
213+    InputOption *options = NULL;
214+    InputAttributes attrs = { };
215+    DeviceIntPtr dev = NULL;
216+    int i, rc;
217+    int fd;
218+
219+    for (i = 0; hw_types[i].driver != NULL; i++) {
220+        if (strncmp(devname, hw_types[i].driver,
221+                    strlen(hw_types[i].driver)) == 0 &&
222+            isdigit(*(devname + strlen(hw_types[i].driver)))) {
223+            attrs.flags |= hw_types[i].flag;
224+            break;
225+        }
226+    }
227+    if (hw_types[i].driver == NULL) {
228+        LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n",
229+                       devname);
230+        return;
231+    }
232+    if (hw_types[i].xdriver == NULL) {
233+        LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n",
234+                       devname);
235+        return;
236+    }
237+    snprintf(path, sizeof(path), "/dev/%s", devname);
238+
239+    options = input_option_new(NULL, "_source", "server/devd");
240+    if (!options)
241+        return;
242+
243+    vendor =
244+        sysctl_get_str("dev.%s.%s.%%desc", hw_types[i].driver,
245+                       devname + strlen(hw_types[i].driver));
246+    if (vendor == NULL) {
247+        attrs.vendor = strdup("(unnamed)");
248+        attrs.product = strdup("(unnamed)");
249+    }
250+    else {
251+        if ((walk = strchr(vendor, ' ')) != NULL) {
252+            walk[0] = '\0';
253+            walk++;
254+            product = walk;
255+            if ((walk = strchr(product, ',')) != NULL)
256+                walk[0] = '\0';
257+        }
258+
259+        attrs.vendor = strdup(vendor);
260+        if (product)
261+            attrs.product = strdup(product);
262+        else
263+            attrs.product = strdup("(unnamed)");
264+
265+        options = input_option_new(options, "name", xstrdup(attrs.product));
266+
267+        free(vendor);
268+    }
269+    attrs.usb_id = NULL;
270+    attrs.device = strdup(path);
271+    options = input_option_new(options, "driver", hw_types[i].xdriver);
272+    if (attrs.flags & ATTR_KEYBOARD) {
273+        /*
274+         * Don't pass device option if keyboard is attached to console (open fails),
275+         * thus activating special logic in xf86-input-keyboard.
276+         */
277+        fd = open(path, O_RDONLY | O_NONBLOCK | O_EXCL);
278+        if (fd > 0) {
279+            close(fd);
280+            options = input_option_new(options, "device", xstrdup(path));
281+        }
282+    }
283+    else {
284+        options = input_option_new(options, "device", xstrdup(path));
285+    }
286+
287+    if (asprintf(&config_info, "devd:%s", devname) == -1) {
288+        config_info = NULL;
289+        goto unwind;
290+    }
291+
292+    if (device_is_duplicate(config_info)) {
293+        LogMessage(X_WARNING, "config/devd: device %s already added. "
294+                   "Ignoring.\n", attrs.product);
295+        goto unwind;
296+    }
297+
298+    options = input_option_new(options, "config_info", config_info);
299+    LogMessage(X_INFO, "config/devd: adding input device %s (%s)\n",
300+               attrs.product, path);
301+
302+    rc = NewInputDeviceRequest(options, &attrs, &dev);
303+
304+    if (rc != Success)
305+        goto unwind;
306+
307+ unwind:
308+    free(config_info);
309+    input_option_free_list(&options);
310+
311+    free(attrs.usb_id);
312+    free(attrs.product);
313+    free(attrs.device);
314+    free(attrs.vendor);
315+}
316+
317+static void
318+device_removed(char *devname)
319+{
320+    char *value;
321+
322+    if (asprintf(&value, "devd:%s", devname) == -1)
323+        return;
324+
325+    remove_devices("devd", value);
326+
327+    free(value);
328+}
329+
330+static ssize_t
331+socket_getline(int fd, char **out)
332+{
333+    char *buf, *newbuf;
334+    ssize_t ret, cap, sz = 0;
335+    char c;
336+
337+    cap = 1024;
338+    buf = malloc(cap * sizeof(char));
339+    if (!buf)
340+        return -1;
341+
342+    for (;;) {
343+        ret = read(sock_devd, &c, 1);
344+        if (ret < 1) {
345+            if (errno == EINTR)
346+                continue;
347+            free(buf);
348+            return -1;
349+        }
350+
351+        if (c == '\n')
352+            break;
353+
354+        if (sz + 1 >= cap) {
355+            cap *= 2;
356+            newbuf = realloc(buf, cap * sizeof(char));
357+            if (!newbuf) {
358+                free(buf);
359+                return -1;
360+            }
361+            buf = newbuf;
362+        }
363+        buf[sz] = c;
364+        sz++;
365+    }
366+
367+    buf[sz] = '\0';
368+    if (sz >= 0)
369+        *out = buf;
370+    else
371+        free(buf);
372+
373+    return sz;                  /* number of bytes in the line, not counting the line break */
374+}
375+
376+static void
377+socket_handler(int fd, int ready, void *data)
378+{
379+    char *line = NULL;
380+    char *walk;
381+
382+    if (socket_getline(sock_devd, &line) < 0)
383+        return;
384+
385+    walk = strchr(line + 1, ' ');
386+    if (walk != NULL)
387+        walk[0] = '\0';
388+
389+    switch (*line) {
390+    case DEVD_EVENT_ADD:
391+        device_added(line + 1);
392+        break;
393+    case DEVD_EVENT_REMOVE:
394+        device_removed(line + 1);
395+        break;
396+    default:
397+        break;
398+    }
399+    free(line);
400+}
401+
402+int
403+config_devd_init(void)
404+{
405+    struct sockaddr_un devd;
406+    char devicename[1024];
407+    int i, j;
408+
409+    /* first scan the sysctl to determine the hardware if needed */
410+
411+    for (i = 0; hw_types[i].driver != NULL; i++) {
412+        for (j = 0; sysctl_exists("dev.%s.%i.%%desc", hw_types[i].driver, j);
413+             j++) {
414+            snprintf(devicename, sizeof(devicename), "%s%i", hw_types[i].driver,
415+                     j);
416+            device_added(devicename);
417+        }
418+
419+    }
420+    sock_devd = socket(AF_UNIX, SOCK_STREAM, 0);
421+    if (sock_devd < 0) {
422+        ErrorF("config/devd: Fail opening stream socket");
423+        return 0;
424+    }
425+
426+    devd.sun_family = AF_UNIX;
427+    strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path));
428+
429+    if (connect(sock_devd, (struct sockaddr *) &devd, sizeof(devd)) < 0) {
430+        close(sock_devd);
431+        ErrorF("config/devd: Fail to connect to devd");
432+        return 0;
433+    }
434+
435+    SetNotifyFd(sock_devd, socket_handler, X_NOTIFY_READ, NULL);
436+
437+    return 1;
438+}
439+
440+void
441+config_devd_fini(void)
442+{
443+    if (sock_devd < 0)
444+        return;
445+
446+    RemoveNotifyFd(sock_devd);
447+    close(sock_devd);
448+}
449--- a/configure.ac
450+++ b/configure.ac
451@@ -566,6 +566,7 @@ AC_ARG_ENABLE(dpms,           AS_HELP_ST
452 AC_ARG_ENABLE(config-udev,    AS_HELP_STRING([--enable-config-udev], [Build udev support (default: auto)]), [CONFIG_UDEV=$enableval], [CONFIG_UDEV=auto])
453 AC_ARG_ENABLE(config-udev-kms,    AS_HELP_STRING([--enable-config-udev-kms], [Build udev kms support (default: auto)]), [CONFIG_UDEV_KMS=$enableval], [CONFIG_UDEV_KMS=auto])
454 AC_ARG_ENABLE(config-hal,     AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto])
455+AC_ARG_ENABLE(config-devd,    AS_HELP_STRING([--disable-config-devd], [Build devd support (default: auto)]), [CONFIG_DEVD=$enableval], [CONFIG_DEVD=auto])
456 AC_ARG_ENABLE(config-wscons,  AS_HELP_STRING([--enable-config-wscons], [Build wscons config support (default: auto)]), [CONFIG_WSCONS=$enableval], [CONFIG_WSCONS=auto])
457 AC_ARG_ENABLE(xfree86-utils,     AS_HELP_STRING([--enable-xfree86-utils], [Build xfree86 DDX utilities (default: enabled)]), [XF86UTILS=$enableval], [XF86UTILS=yes])
458 AC_ARG_ENABLE(vgahw,          AS_HELP_STRING([--enable-vgahw], [Build Xorg with vga access (default: enabled)]), [VGAHW=$enableval], [VGAHW=yes])
459@@ -950,6 +951,21 @@ if test "x$CONFIG_WSCONS" = xyes; then
460 	AC_DEFINE(CONFIG_WSCONS, 1, [Use wscons for input auto configuration])
461 fi
462
463+if test "x$CONFIG_DEVD" = xauto; then
464+	case $host_os in
465+		freebsd* | kfreebsd*-gnu)
466+			CONFIG_DEVD=yes;
467+			;;
468+		*)
469+			CONFIG_DEVD=no;
470+			;;
471+	esac
472+fi
473+AM_CONDITIONAL(CONFIG_DEVD, [test "x$CONFIG_DEVD" = xyes])
474+if test "x$CONFIG_DEVD" = xyes; then
475+	AC_DEFINE(CONFIG_DEVD, 1, [Use devd for input auto configuration])
476+fi
477+
478
479 AC_MSG_CHECKING([for glibc...])
480 AC_PREPROC_IFELSE([AC_LANG_SOURCE([
481@@ -2429,7 +2445,7 @@ AC_SUBST([prefix])
482
483 AC_CONFIG_COMMANDS([sdksyms], [touch hw/xfree86/sdksyms.dep])
484
485-if test "x$CONFIG_HAL" = xno && test "x$CONFIG_UDEV" = xno; then
486+if test "x$CONFIG_HAL" = xno && test "x$CONFIG_UDEV" = xno && test "x$CONFIG_DEVD" = xno; then
487     AC_MSG_WARN([
488              ***********************************************
489              Neither HAL nor udev backend will be enabled.
490--- a/hw/xfree86/common/xf86Config.c
491+++ b/hw/xfree86/common/xf86Config.c
492@@ -1257,15 +1257,18 @@ checkCoreInputDevices(serverLayoutPtr se
493     }
494
495     if (!xf86Info.forceInputDevices && !(foundPointer && foundKeyboard)) {
496-#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS)
497+#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) || \
498+    defined(CONFIG_DEVD)
499         const char *config_backend;
500
501 #if defined(CONFIG_HAL)
502         config_backend = "HAL";
503 #elif defined(CONFIG_UDEV)
504         config_backend = "udev";
505-#else
506+#elif defined(CONFIG_WSCONS)
507         config_backend = "wscons";
508+#elif defined(CONFIG_DEVD)
509+        config_backend = "devd";
510 #endif
511         xf86Msg(X_INFO, "The server relies on %s to provide the list of "
512                 "input devices.\n\tIf no devices become available, "
513--- a/hw/xfree86/common/xf86Globals.c
514+++ b/hw/xfree86/common/xf86Globals.c
515@@ -117,7 +117,8 @@ xf86InfoRec xf86Info = {
516     .miscModInDevEnabled = TRUE,
517     .miscModInDevAllowNonLocal = FALSE,
518     .pmFlag = TRUE,
519-#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS)
520+#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) || \
521+    defined(CONFIG_DEVD)
522     .forceInputDevices = FALSE,
523     .autoAddDevices = TRUE,
524     .autoEnableDevices = TRUE,
525--- a/include/dix-config.h.in
526+++ b/include/dix-config.h.in
527@@ -433,6 +433,9 @@
528 /* Enable systemd-logind integration */
529 #undef SYSTEMD_LOGIND 1
530
531+/* Support devd for hotplug */
532+#undef CONFIG_DEVD
533+
534 /* Have a monotonic clock from clock_gettime() */
535 #undef MONOTONIC_CLOCK
536
537