summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2014-03-07 22:07:19 -0800
committerKeith Packard <keithp@keithp.com>2014-03-07 22:07:19 -0800
commit1c61d38528a573caadee2468ee59ea558c822e09 (patch)
treeb979f8069fcddbb617b3fc63910a462a481c4b17 /hw
parent5350ae1d38f3c69a26421e0866ede0d2ccc3aea4 (diff)
parentbf3543739db18c6cd52908f7c693cb64f43e3f23 (diff)
Merge remote-tracking branch 'jwrdecoede/for-keith'
Diffstat (limited to 'hw')
-rw-r--r--hw/xfree86/common/xf86Events.c15
-rw-r--r--hw/xfree86/common/xf86Init.c3
-rw-r--r--hw/xfree86/common/xf86Module.h4
-rw-r--r--hw/xfree86/common/xf86Xinput.c65
-rw-r--r--hw/xfree86/common/xf86Xinput.h8
-rw-r--r--hw/xfree86/common/xf86platformBus.c60
-rw-r--r--hw/xfree86/common/xf86platformBus.h15
-rw-r--r--hw/xfree86/os-support/linux/Makefile.am6
-rw-r--r--hw/xfree86/os-support/linux/lnx_init.c25
-rw-r--r--hw/xfree86/os-support/linux/lnx_platform.c45
-rw-r--r--hw/xfree86/os-support/linux/systemd-logind.c532
-rw-r--r--hw/xfree86/os-support/shared/posix_tty.c6
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",