diff options
author | Keith Packard <keithp@keithp.com> | 2014-03-07 22:07:19 -0800 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2014-03-07 22:07:19 -0800 |
commit | 1c61d38528a573caadee2468ee59ea558c822e09 (patch) | |
tree | b979f8069fcddbb617b3fc63910a462a481c4b17 /hw | |
parent | 5350ae1d38f3c69a26421e0866ede0d2ccc3aea4 (diff) | |
parent | bf3543739db18c6cd52908f7c693cb64f43e3f23 (diff) |
Merge remote-tracking branch 'jwrdecoede/for-keith'
Diffstat (limited to 'hw')
-rw-r--r-- | hw/xfree86/common/xf86Events.c | 15 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Init.c | 3 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Module.h | 4 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Xinput.c | 65 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Xinput.h | 8 | ||||
-rw-r--r-- | hw/xfree86/common/xf86platformBus.c | 60 | ||||
-rw-r--r-- | hw/xfree86/common/xf86platformBus.h | 15 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/Makefile.am | 6 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/lnx_init.c | 25 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/lnx_platform.c | 45 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/systemd-logind.c | 532 | ||||
-rw-r--r-- | hw/xfree86/os-support/shared/posix_tty.c | 6 |
12 files changed, 738 insertions, 46 deletions
diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 7b53949fa..06af73903 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -85,6 +85,8 @@ #endif #include "xf86platformBus.h" +#include "systemd-logind.h" + /* * This is a toggling variable: * FALSE = No VT switching keys have been pressed last time around @@ -556,8 +558,11 @@ xf86VTEnter(void) /* Turn screen saver off when switching back */ dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); - for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) - xf86EnableInputDeviceForVTSwitch(pInfo); + /* If we use systemd-logind it will enable input devices for us */ + if (!systemd_logind_controls_session()) + for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) + xf86EnableInputDeviceForVTSwitch(pInfo); + for (ih = InputHandlers; ih; ih = ih->next) { if (ih->is_input) xf86EnableInputHandler(ih); @@ -589,10 +594,14 @@ xf86VTSwitch(void) /* * Since all screens are currently all in the same state it is sufficient * check the first. This might change in future. + * + * VTLeave is always handled here (VT_PROCESS guarantees this is safe), + * if we use systemd_logind xf86VTEnter() gets called by systemd-logind.c + * once it has resumed all drm nodes. */ if (xf86VTOwner()) xf86VTLeave(); - else + else if (!systemd_logind_controls_session()) xf86VTEnter(); } diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c index ff4d38f28..4579ff591 100644 --- a/hw/xfree86/common/xf86Init.c +++ b/hw/xfree86/common/xf86Init.c @@ -54,6 +54,7 @@ #include "site.h" #include "mi.h" #include "dbus-core.h" +#include "systemd-logind.h" #include "compiler.h" @@ -458,6 +459,7 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv) DoShowOptions(); dbus_core_init(); + systemd_logind_init(); /* Do a general bus probe. This will be a PCI probe for x86 platforms */ xf86BusProbe(); @@ -1062,6 +1064,7 @@ ddxGiveUp(enum ExitCode error) if (xorgHWOpenConsole) xf86CloseConsole(); + systemd_logind_fini(); dbus_core_fini(); xf86CloseLog(error); diff --git a/hw/xfree86/common/xf86Module.h b/hw/xfree86/common/xf86Module.h index b6ec19d13..e8c24f26c 100644 --- a/hw/xfree86/common/xf86Module.h +++ b/hw/xfree86/common/xf86Module.h @@ -80,8 +80,8 @@ typedef enum { * mask is 0xFFFF0000. */ #define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4) -#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(15, 0) -#define ABI_XINPUT_VERSION SET_ABI_VERSION(20, 0) +#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(16, 0) +#define ABI_XINPUT_VERSION SET_ABI_VERSION(21, 0) #define ABI_EXTENSION_VERSION SET_ABI_VERSION(8, 0) #define ABI_FONT_VERSION SET_ABI_VERSION(0, 6) diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index f6f2b90dd..7c3e479e5 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -63,6 +63,7 @@ #include "mipointer.h" #include "extinit.h" #include "loaderProcs.h" +#include "systemd-logind.h" #include "exevents.h" /* AddInputDevice */ #include "exglobals.h" @@ -80,6 +81,7 @@ #include <stdarg.h> #include <stdint.h> /* for int64_t */ +#include <unistd.h> #include "mi.h" @@ -103,6 +105,9 @@ static int xf86InputDevicePostInit(DeviceIntPtr dev); +static InputInfoPtr *new_input_devices; +static int new_input_devices_count; + /** * Eval config and modify DeviceVelocityRec accordingly */ @@ -773,6 +778,11 @@ xf86DeleteInput(InputInfoPtr pInp, int flags) /* Else the entry wasn't in the xf86InputDevs list (ignore this). */ } + if (pInp->flags & XI86_SERVER_FD) { + systemd_logind_release_fd(pInp->major, pInp->minor); + close(pInp->fd); + } + free((void *) pInp->driver); free((void *) pInp->name); xf86optionListFree(pInp->options); @@ -816,6 +826,7 @@ xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable) { InputDriverPtr drv = NULL; DeviceIntPtr dev = NULL; + Bool paused; int rval; /* Memory leak for every attached device if we don't @@ -830,6 +841,26 @@ xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable) goto unwind; } + if (drv->capabilities & XI86_DRV_CAP_SERVER_FD) { + int fd = systemd_logind_take_fd(pInfo->major, pInfo->minor, + pInfo->attrs->device, &paused); + if (fd != -1) { + if (paused) { + /* Put on new_input_devices list for delayed probe */ + new_input_devices = xnfrealloc(new_input_devices, + sizeof(pInfo) * (new_input_devices_count + 1)); + new_input_devices[new_input_devices_count] = pInfo; + new_input_devices_count++; + systemd_logind_release_fd(pInfo->major, pInfo->minor); + close(fd); + return BadMatch; + } + pInfo->fd = fd; + pInfo->flags |= XI86_SERVER_FD; + pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd); + } + } + xf86Msg(X_INFO, "Using input driver '%s' for '%s'\n", drv->driverName, pInfo->name); @@ -949,6 +980,12 @@ NewInputDeviceRequest(InputOption *options, InputAttributes * attrs, goto unwind; } } + + if (strcmp(key, "major") == 0) + pInfo->major = atoi(value); + + if (strcmp(key, "minor") == 0) + pInfo->minor = atoi(value); } nt_list_for_each_entry(option, options, list.next) { @@ -1469,4 +1506,32 @@ xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type, QueueTouchEvents(dev, type, touchid, flags, mask); } +void +xf86InputEnableVTProbe(void) +{ + int i, is_auto = 0; + InputOption *option = NULL; + DeviceIntPtr pdev; + + for (i = 0; i < new_input_devices_count; i++) { + InputInfoPtr pInfo = new_input_devices[i]; + + is_auto = 0; + nt_list_for_each_entry(option, pInfo->options, list.next) { + const char *key = input_option_get_key(option); + const char *value = input_option_get_value(option); + + if (strcmp(key, "_source") == 0 && + (strcmp(value, "server/hal") == 0 || + strcmp(value, "server/udev") == 0 || + strcmp(value, "server/wscons") == 0)) + is_auto = 1; + } + xf86NewInputDevice(pInfo, &pdev, + (!is_auto || + (is_auto && xf86Info.autoEnableDevices))); + } + new_input_devices_count = 0; +} + /* end of xf86Xinput.c */ diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h index b6d125128..9fe8c87b6 100644 --- a/hw/xfree86/common/xf86Xinput.h +++ b/hw/xfree86/common/xf86Xinput.h @@ -64,6 +64,10 @@ /* 0x08 is reserved for legacy XI86_SEND_DRAG_EVENTS, do not use for now */ /* server-internal only */ #define XI86_DEVICE_DISABLED 0x10 /* device was disabled before vt switch */ +#define XI86_SERVER_FD 0x20 /* fd is managed by xserver */ + +/* Input device driver capabilities */ +#define XI86_DRV_CAP_SERVER_FD 0x01 /* This holds the input driver entry and module information. */ typedef struct _InputDriverRec { @@ -76,6 +80,7 @@ typedef struct _InputDriverRec { struct _InputInfoRec * pInfo, int flags); void *module; const char **default_options; + int capabilities; } InputDriverRec, *InputDriverPtr; /* This is to input devices what the ScrnInfoRec is to screens. */ @@ -96,6 +101,8 @@ typedef struct _InputInfoRec { int *valuators, int first_valuator, int num_valuators); int fd; + int major; + int minor; DeviceIntPtr dev; void *private; const char *type_name; @@ -172,6 +179,7 @@ extern _X_EXPORT void xf86AddEnabledDevice(InputInfoPtr pInfo); extern _X_EXPORT void xf86RemoveEnabledDevice(InputInfoPtr pInfo); extern _X_EXPORT void xf86DisableDevice(DeviceIntPtr dev, Bool panic); extern _X_EXPORT void xf86EnableDevice(DeviceIntPtr dev); +extern _X_EXPORT void xf86InputEnableVTProbe(void); /* not exported */ int xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL is_auto); diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 5875a9136..4447e19df 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -52,10 +52,10 @@ int platformSlotClaimed; int xf86_num_platform_devices; -static struct xf86_platform_device *xf86_platform_devices; +struct xf86_platform_device *xf86_platform_devices; int -xf86_add_platform_device(struct OdevAttributes *attribs) +xf86_add_platform_device(struct OdevAttributes *attribs, Bool unowned) { xf86_platform_devices = xnfrealloc(xf86_platform_devices, (sizeof(struct xf86_platform_device) @@ -63,6 +63,8 @@ xf86_add_platform_device(struct OdevAttributes *attribs) xf86_platform_devices[xf86_num_platform_devices].attribs = attribs; xf86_platform_devices[xf86_num_platform_devices].pdev = NULL; + xf86_platform_devices[xf86_num_platform_devices].flags = + unowned ? XF86_PDEV_UNOWNED : 0; xf86_num_platform_devices++; return 0; @@ -89,35 +91,55 @@ xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_name) return config_odev_add_attribute(device->attribs, attrib_id, attrib_name); } +Bool +xf86_add_platform_device_int_attrib(int index, int attrib_id, int attrib_value) +{ + return config_odev_add_int_attribute(xf86_platform_devices[index].attribs, attrib_id, attrib_value); +} + char * xf86_get_platform_attrib(int index, int attrib_id) { - struct xf86_platform_device *device = &xf86_platform_devices[index]; - struct OdevAttribute *oa; - - xorg_list_for_each_entry(oa, &device->attribs->list, member) { - if (oa->attrib_id == attrib_id) - return oa->attrib_name; - } - return NULL; + return config_odev_get_attribute(xf86_platform_devices[index].attribs, attrib_id); } char * xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id) { - struct OdevAttribute *oa; + return config_odev_get_attribute(device->attribs, attrib_id); +} - xorg_list_for_each_entry(oa, &device->attribs->list, member) { - if (oa->attrib_id == attrib_id) - return oa->attrib_name; - } - return NULL; +int +xf86_get_platform_int_attrib(int index, int attrib_id, int def) +{ + return config_odev_get_int_attribute(xf86_platform_devices[index].attribs, attrib_id, def); +} + +int +xf86_get_platform_device_int_attrib(struct xf86_platform_device *device, int attrib_id, int def) +{ + return config_odev_get_int_attribute(device->attribs, attrib_id, def); } Bool xf86_get_platform_device_unowned(int index) { - return xf86_platform_devices[index].attribs->unowned; + return (xf86_platform_devices[index].flags & XF86_PDEV_UNOWNED) ? + TRUE : FALSE; +} + +struct xf86_platform_device * +xf86_find_platform_device_by_devnum(int major, int minor) +{ + int i, attr_major, attr_minor; + + for (i = 0; i < xf86_num_platform_devices; i++) { + attr_major = xf86_get_platform_int_attrib(i, ODEV_ATTRIB_MAJOR, 0); + attr_minor = xf86_get_platform_int_attrib(i, ODEV_ATTRIB_MINOR, 0); + if (attr_major == major && attr_minor == minor) + return &xf86_platform_devices[i]; + } + return NULL; } /* @@ -524,10 +546,10 @@ void xf86platformVTProbe(void) int i; for (i = 0; i < xf86_num_platform_devices; i++) { - if (xf86_platform_devices[i].attribs->unowned == FALSE) + if (!(xf86_platform_devices[i].flags & XF86_PDEV_UNOWNED)) continue; - xf86_platform_devices[i].attribs->unowned = FALSE; + xf86_platform_devices[i].flags &= ~XF86_PDEV_UNOWNED; xf86PlatformReprobeDevice(i, xf86_platform_devices[i].attribs); } } diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h index 4e1757854..78b5a5bea 100644 --- a/hw/xfree86/common/xf86platformBus.h +++ b/hw/xfree86/common/xf86platformBus.h @@ -30,23 +30,34 @@ struct xf86_platform_device { struct OdevAttributes *attribs; /* for PCI devices */ struct pci_device *pdev; + int flags; }; +/* xf86_platform_device flags */ +#define XF86_PDEV_UNOWNED 0x01 +#define XF86_PDEV_SERVER_FD 0x02 +#define XF86_PDEV_PAUSED 0x04 + #ifdef XSERVER_PLATFORM_BUS int xf86platformProbe(void); int xf86platformProbeDev(DriverPtr drvp); extern int xf86_num_platform_devices; +extern struct xf86_platform_device *xf86_platform_devices; extern char * xf86_get_platform_attrib(int index, int attrib_id); extern int -xf86_add_platform_device(struct OdevAttributes *attribs); +xf86_get_platform_int_attrib(int index, int attrib_id, int def); +extern int +xf86_add_platform_device(struct OdevAttributes *attribs, Bool unowned); extern int xf86_remove_platform_device(int dev_index); extern Bool xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_str); extern Bool +xf86_add_platform_device_int_attrib(int index, int attrib_id, int attrib_value); +extern Bool xf86_get_platform_device_unowned(int index); extern int @@ -56,6 +67,8 @@ xf86platformRemoveDevice(int index); extern _X_EXPORT char * xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id); +extern _X_EXPORT int +xf86_get_platform_device_int_attrib(struct xf86_platform_device *device, int attrib_id, int def); extern _X_EXPORT Bool xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid); diff --git a/hw/xfree86/os-support/linux/Makefile.am b/hw/xfree86/os-support/linux/Makefile.am index 83e7e0027..1686dc2c1 100644 --- a/hw/xfree86/os-support/linux/Makefile.am +++ b/hw/xfree86/os-support/linux/Makefile.am @@ -21,6 +21,11 @@ APM_SRCS = lnx_apm.c XORG_CFLAGS += -DHAVE_APM endif +if SYSTEMD_LOGIND +LOGIND_SRCS = systemd-logind.c +XORG_CFLAGS += $(DBUS_CFLAGS) +endif + liblinux_la_SOURCES = lnx_init.c lnx_video.c \ lnx_agp.c lnx_kmod.c lnx_bell.c lnx_platform.c \ $(srcdir)/../shared/bios_mmap.c \ @@ -30,6 +35,7 @@ liblinux_la_SOURCES = lnx_init.c lnx_video.c \ $(srcdir)/../shared/sigio.c \ $(ACPI_SRCS) \ $(APM_SRCS) \ + $(LOGIND_SRCS) \ $(PLATFORM_PCI_SUPPORT) AM_CFLAGS = -DUSESTDRES -DHAVE_SYSV_IPC $(DIX_CFLAGS) $(XORG_CFLAGS) $(PLATFORM_DEFINES) diff --git a/hw/xfree86/os-support/linux/lnx_init.c b/hw/xfree86/os-support/linux/lnx_init.c index 46438e655..85709c629 100644 --- a/hw/xfree86/os-support/linux/lnx_init.c +++ b/hw/xfree86/os-support/linux/lnx_init.c @@ -79,20 +79,15 @@ switch_to(int vt, const char *from) void xf86OpenConsole(void) { - int i, fd = -1, ret; + int i, fd = -1, ret, current_vt = -1; struct vt_mode VT; struct vt_stat vts; + struct stat st; MessageType from = X_PROBED; const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; if (serverGeneration == 1) { - - /* when KeepTty check if we're run with euid==0 */ - if (KeepTty && geteuid() != 0) - FatalError("xf86OpenConsole:" - " Server must be suid root for option \"KeepTTY\"\n"); - /* * setup the virtual terminal manager */ @@ -132,6 +127,22 @@ xf86OpenConsole(void) xf86Msg(from, "using VT number %d\n\n", xf86Info.vtno); + /* Some of stdin / stdout / stderr maybe redirected to a file */ + for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { + ret = fstat(i, &st); + if (ret == 0 && S_ISCHR(st.st_mode) && major(st.st_rdev) == 4) { + current_vt = minor(st.st_rdev); + break; + } + } + + if (!KeepTty && current_vt == xf86Info.vtno) { + xf86Msg(X_PROBED, + "controlling tty is VT number %d, auto-enabling KeepTty\n", + current_vt); + KeepTty = TRUE; + } + if (!KeepTty) { pid_t ppid = getppid(); pid_t ppgid; diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c index 1865b31b9..109a9a774 100644 --- a/hw/xfree86/os-support/linux/lnx_platform.c +++ b/hw/xfree86/os-support/linux/lnx_platform.c @@ -18,16 +18,38 @@ #include "xf86Bus.h" #include "hotplug.h" +#include "systemd-logind.h" static Bool get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) { drmSetVersion sv; char *buf; - int fd; + int major, minor, fd; int err = 0; + Bool paused, server_fd = FALSE; + + major = config_odev_get_int_attribute(attribs, ODEV_ATTRIB_MAJOR, 0); + minor = config_odev_get_int_attribute(attribs, ODEV_ATTRIB_MINOR, 0); + + fd = systemd_logind_take_fd(major, minor, path, &paused); + if (fd != -1) { + if (paused) { + LogMessage(X_ERROR, + "Error systemd-logind returned paused fd for drm node\n"); + systemd_logind_release_fd(major, minor); + return FALSE; + } + if (!config_odev_add_int_attribute(attribs, ODEV_ATTRIB_FD, fd)) { + systemd_logind_release_fd(major, minor); + return FALSE; + } + server_fd = TRUE; + } + + if (fd == -1) + fd = open(path, O_RDWR, O_CLOEXEC); - fd = open(path, O_RDWR, O_CLOEXEC); if (fd == -1) return FALSE; @@ -44,16 +66,20 @@ get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) /* for a delayed probe we've already added the device */ if (delayed_index == -1) { - xf86_add_platform_device(attribs); + xf86_add_platform_device(attribs, FALSE); delayed_index = xf86_num_platform_devices - 1; } + if (server_fd) + xf86_platform_devices[delayed_index].flags |= XF86_PDEV_SERVER_FD; + buf = drmGetBusid(fd); xf86_add_platform_device_attrib(delayed_index, ODEV_ATTRIB_BUSID, buf); drmFreeBusid(buf); out: - close(fd); + if (!server_fd) + close(fd); return (err == 0); } @@ -118,17 +144,11 @@ xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs) void xf86PlatformDeviceProbe(struct OdevAttributes *attribs) { - struct OdevAttribute *attrib; int i; char *path = NULL; Bool ret; - xorg_list_for_each_entry(attrib, &attribs->list, member) { - if (attrib->attrib_id == ODEV_ATTRIB_PATH) { - path = attrib->attrib_name; - break; - } - } + path = config_odev_get_attribute(attribs, ODEV_ATTRIB_PATH); if (!path) goto out_free; @@ -148,8 +168,7 @@ xf86PlatformDeviceProbe(struct OdevAttributes *attribs) if (!xf86VTOwner()) { /* if we don't currently own the VT then don't probe the device, just mark it as unowned for later use */ - attribs->unowned = TRUE; - xf86_add_platform_device(attribs); + xf86_add_platform_device(attribs, TRUE); return; } diff --git a/hw/xfree86/os-support/linux/systemd-logind.c b/hw/xfree86/os-support/linux/systemd-logind.c new file mode 100644 index 000000000..abb8e44d9 --- /dev/null +++ b/hw/xfree86/os-support/linux/systemd-logind.c @@ -0,0 +1,532 @@ +/* + * Copyright © 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Hans de Goede <hdegoede@redhat.com> + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <dbus/dbus.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "os.h" +#include "dbus-core.h" +#include "xf86.h" +#include "xf86platformBus.h" +#include "xf86Xinput.h" + +#include "systemd-logind.h" + +#define DBUS_TIMEOUT 500 /* Wait max 0.5 seconds */ + +struct systemd_logind_info { + DBusConnection *conn; + char *session; + Bool active; + Bool vt_active; +}; + +static struct systemd_logind_info logind_info; + +int +systemd_logind_take_fd(int _major, int _minor, const char *path, + Bool *paused_ret) +{ + struct systemd_logind_info *info = &logind_info; + DBusError error; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + dbus_int32_t major = _major; + dbus_int32_t minor = _minor; + dbus_bool_t paused; + int fd = -1; + + if (!info->session || major == 0) + return -1; + + /* logind does not support mouse devs (with evdev we don't need them) */ + if (strstr(path, "mouse")) + return -1; + + dbus_error_init(&error); + + msg = dbus_message_new_method_call("org.freedesktop.login1", info->session, + "org.freedesktop.login1.Session", "TakeDevice"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(info->conn, msg, + DBUS_TIMEOUT, &error); + if (!reply) { + LogMessage(X_ERROR, "systemd-logind: failed to take device %s: %s\n", + path, error.message); + goto cleanup; + } + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_BOOLEAN, &paused, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: TakeDevice %s: %s\n", + path, error.message); + goto cleanup; + } + + *paused_ret = paused; + + LogMessage(X_INFO, "systemd-logind: got fd for %s %u:%u fd %d paused %d\n", + path, major, minor, fd, paused); + +cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + dbus_error_free(&error); + + return fd; +} + +void +systemd_logind_release_fd(int _major, int _minor) +{ + struct systemd_logind_info *info = &logind_info; + DBusError error; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + dbus_int32_t major = _major; + dbus_int32_t minor = _minor; + + if (!info->session || major == 0) + return; + + dbus_error_init(&error); + + msg = dbus_message_new_method_call("org.freedesktop.login1", info->session, + "org.freedesktop.login1.Session", "ReleaseDevice"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(info->conn, msg, + DBUS_TIMEOUT, &error); + if (!reply) + LogMessage(X_ERROR, "systemd-logind: failed to release device: %s\n", + error.message); + +cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + dbus_error_free(&error); +} + +int +systemd_logind_controls_session(void) +{ + return logind_info.session ? 1 : 0; +} + +void +systemd_logind_vtenter(void) +{ + struct systemd_logind_info *info = &logind_info; + InputInfoPtr pInfo; + int i; + + if (!info->session) + return; /* Not using systemd-logind */ + + if (!info->active) + return; /* Session not active */ + + if (info->vt_active) + return; /* Already did vtenter */ + + for (i = 0; i < xf86_num_platform_devices; i++) { + if (xf86_platform_devices[i].flags & XF86_PDEV_PAUSED) + break; + } + if (i != xf86_num_platform_devices) + return; /* Some drm nodes are still paused wait for resume */ + + xf86VTEnter(); + info->vt_active = TRUE; + + /* Activate any input devices which were resumed before the drm nodes */ + for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) + if ((pInfo->flags & XI86_SERVER_FD) && pInfo->fd != -1) + xf86EnableInputDeviceForVTSwitch(pInfo); + + /* Do delayed input probing, this must be done after the above enabling */ + xf86InputEnableVTProbe(); +} + +static InputInfoPtr +systemd_logind_find_info_ptr_by_devnum(int major, int minor) +{ + InputInfoPtr pInfo; + + for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) + if (pInfo->major == major && pInfo->minor == minor && + (pInfo->flags & XI86_SERVER_FD)) + return pInfo; + + return NULL; +} + +static void +systemd_logind_ack_pause(struct systemd_logind_info *info, + dbus_int32_t minor, dbus_int32_t major) +{ + DBusError error; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + + dbus_error_init(&error); + + msg = dbus_message_new_method_call("org.freedesktop.login1", info->session, + "org.freedesktop.login1.Session", "PauseDeviceComplete"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(info->conn, msg, + DBUS_TIMEOUT, &error); + if (!reply) + LogMessage(X_ERROR, "systemd-logind: failed to ack pause: %s\n", + error.message); + +cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + dbus_error_free(&error); +} + +static DBusHandlerResult +message_filter(DBusConnection * connection, DBusMessage * message, void *data) +{ + struct systemd_logind_info *info = data; + struct xf86_platform_device *pdev = NULL; + InputInfoPtr pInfo = NULL; + int ack = 0, pause = 0, fd = -1; + DBusError error; + dbus_int32_t major, minor; + char *pause_str; + + if (strcmp(dbus_message_get_path(message), info->session) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init(&error); + + if (dbus_message_is_signal(message, "org.freedesktop.login1.Session", + "PauseDevice")) { + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, + DBUS_TYPE_STRING, &pause_str, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: PauseDevice: %s\n", + error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (strcmp(pause_str, "pause") == 0) { + pause = 1; + ack = 1; + } + else if (strcmp(pause_str, "force") == 0) { + pause = 1; + } + else if (strcmp(pause_str, "gone") == 0) { + /* Device removal is handled through udev */ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + else { + LogMessage(X_WARNING, "systemd-logind: unknown pause type: %s\n", + pause_str); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } + else if (dbus_message_is_signal(message, "org.freedesktop.login1.Session", + "ResumeDevice")) { + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, + DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: ResumeDevice: %s\n", + error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + LogMessage(X_INFO, "systemd-logind: got %s for %u:%u\n", + pause ? "pause" : "resume", major, minor); + + pdev = xf86_find_platform_device_by_devnum(major, minor); + if (!pdev) + pInfo = systemd_logind_find_info_ptr_by_devnum(major, minor); + if (!pdev && !pInfo) { + LogMessage(X_WARNING, "systemd-logind: could not find dev %u:%u\n", + major, minor); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (pause) { + /* Our VT_PROCESS usage guarantees we've already given up the vt */ + info->active = info->vt_active = FALSE; + /* Note the actual vtleave has already been handled by xf86Events.c */ + if (pdev) + pdev->flags |= XF86_PDEV_PAUSED; + else { + close(pInfo->fd); + pInfo->fd = -1; + pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", -1); + } + if (ack) + systemd_logind_ack_pause(info, major, minor); + } + else { + /* info->vt_active gets set by systemd_logind_vtenter() */ + info->active = TRUE; + + if (pdev) { + pdev->flags &= ~XF86_PDEV_PAUSED; + systemd_logind_vtenter(); + } + else { + pInfo->fd = fd; + pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd); + if (info->vt_active) + xf86EnableInputDeviceForVTSwitch(pInfo); + } + } + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void +connect_hook(DBusConnection *connection, void *data) +{ + struct systemd_logind_info *info = data; + DBusError error; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + dbus_int32_t arg; + char *session = NULL; + + dbus_error_init(&error); + + msg = dbus_message_new_method_call("org.freedesktop.login1", + "/org/freedesktop/login1", "org.freedesktop.login1.Manager", + "GetSessionByPID"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + arg = getpid(); + if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &arg, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(connection, msg, + DBUS_TIMEOUT, &error); + if (!reply) { + LogMessage(X_ERROR, "systemd-logind: failed to get session: %s\n", + error.message); + goto cleanup; + } + dbus_message_unref(msg); + + if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &session, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: GetSessionByPID: %s\n", + error.message); + goto cleanup; + } + session = XNFstrdup(session); + + dbus_message_unref(reply); + reply = NULL; + + + msg = dbus_message_new_method_call("org.freedesktop.login1", + session, "org.freedesktop.login1.Session", "TakeControl"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + arg = FALSE; /* Don't forcibly take over over the session */ + if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg, + DBUS_TYPE_INVALID)) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(connection, msg, + DBUS_TIMEOUT, &error); + if (!reply) { + LogMessage(X_ERROR, "systemd-logind: TakeControl failed: %s\n", + error.message); + goto cleanup; + } + + /* + * HdG: This is not useful with systemd <= 208 since the signal only + * contains invalidated property names there, rather than property, val + * pairs as it should. Instead we just use the first resume / pause now. + */ +#if 0 + snprintf(match, sizeof(match), + "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='%s'", + session); + dbus_bus_add_match(connection, match, &error); + if (dbus_error_is_set(&error)) { + LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n", + error.message); + goto cleanup; + } +#endif + + if (!dbus_connection_add_filter(connection, message_filter, info, NULL)) { + LogMessage(X_ERROR, "systemd-logind: could not add filter: %s\n", + error.message); + goto cleanup; + } + + LogMessage(X_INFO, "systemd-logind: took control of session %s\n", + session); + info->conn = connection; + info->session = session; + info->vt_active = info->active = TRUE; /* The server owns the vt during init */ + session = NULL; + +cleanup: + free(session); + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + dbus_error_free(&error); +} + +static void +systemd_logind_release_control(struct systemd_logind_info *info) +{ + DBusError error; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + + dbus_error_init(&error); + + msg = dbus_message_new_method_call("org.freedesktop.login1", + info->session, "org.freedesktop.login1.Session", "ReleaseControl"); + if (!msg) { + LogMessage(X_ERROR, "systemd-logind: out of memory\n"); + goto cleanup; + } + + reply = dbus_connection_send_with_reply_and_block(info->conn, msg, + DBUS_TIMEOUT, &error); + if (!reply) { + LogMessage(X_ERROR, "systemd-logind: ReleaseControl failed: %s\n", + error.message); + goto cleanup; + } + +cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + dbus_error_free(&error); +} + +static void +disconnect_hook(void *data) +{ + struct systemd_logind_info *info = data; + + free(info->session); + info->session = NULL; + info->conn = NULL; +} + +static struct dbus_core_hook core_hook = { + .connect = connect_hook, + .disconnect = disconnect_hook, + .data = &logind_info, +}; + +int +systemd_logind_init(void) +{ + return dbus_core_add_hook(&core_hook); +} + +void +systemd_logind_fini(void) +{ + if (logind_info.session) + systemd_logind_release_control(&logind_info); + + dbus_core_remove_hook(&core_hook); +} diff --git a/hw/xfree86/os-support/shared/posix_tty.c b/hw/xfree86/os-support/shared/posix_tty.c index 4d08c1e85..6e2af001a 100644 --- a/hw/xfree86/os-support/shared/posix_tty.c +++ b/hw/xfree86/os-support/shared/posix_tty.c @@ -124,7 +124,11 @@ xf86OpenSerial(XF86OptionPtr options) return -1; } - SYSCALL(fd = open(dev, O_RDWR | O_NONBLOCK)); + fd = xf86CheckIntOption(options, "fd", -1); + + if (fd == -1) + SYSCALL(fd = open(dev, O_RDWR | O_NONBLOCK)); + if (fd == -1) { xf86Msg(X_ERROR, "xf86OpenSerial: Cannot open device %s\n\t%s.\n", |