summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-10-03 14:42:56 -0700
committerKeith Packard <keithp@keithp.com>2010-10-22 08:35:29 -0700
commitb066ddda31e40afa652ae51ffc35025ac3ef6f2a (patch)
tree3470aa78e8b7f1643e3a1d37f91db699eeadf8d3 /src
parenta1c54f69643671ce296c57d132852e9846cc41d3 (diff)
intel: Listen for hotplug uevents (V3)
This connects the kernel uevent indicating monitor hotplugging to the RandR notification events so that X applications can be notified automatically when monitors are connected or disconnected. This also adds a configuration option to disable hotplug events. V2: missed a #ifdef HAVE_UDEV around some udev-specific declarations V3: document Hotplug option in man page Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/intel.h12
-rw-r--r--src/intel_driver.c114
3 files changed, 128 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7d823ce3..abb03c3f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,13 +26,13 @@ SUBDIRS = xvmc render_program legacy
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
-AM_CFLAGS = @CWARNFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \
+AM_CFLAGS = @CWARNFLAGS@ @XORG_CFLAGS@ @UDEV_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \
@PCIACCESS_CFLAGS@ -I$(top_srcdir)/uxa -I$(top_srcdir)/src/render_program
intel_drv_la_LTLIBRARIES = intel_drv.la
intel_drv_la_LDFLAGS = -module -avoid-version
intel_drv_ladir = @moduledir@/drivers
-intel_drv_la_LIBADD = -lm @DRM_LIBS@ -ldrm_intel ../uxa/libuxa.la legacy/liblegacy.la
+intel_drv_la_LIBADD = @UDEV_LIBS@ -lm @DRM_LIBS@ -ldrm_intel ../uxa/libuxa.la legacy/liblegacy.la
intel_drv_la_LIBADD += @PCIACCESS_LIBS@
NULL:=#
diff --git a/src/intel.h b/src/intel.h
index 6b059976..7604eeea 100644
--- a/src/intel.h
+++ b/src/intel.h
@@ -34,6 +34,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#if 0
#define I830DEBUG
#endif
@@ -70,6 +74,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "intel_driver.h"
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
#include "uxa.h"
/* XXX
* The X server gained an *almost* identical implementation in 1.9.
@@ -441,6 +449,10 @@ typedef struct intel_screen_private {
*/
Bool fallback_debug;
unsigned debug_flush;
+#if HAVE_UDEV
+ struct udev_monitor *uevent_monitor;
+ InputHandlerProc uevent_handler;
+#endif
} intel_screen_private;
enum {
diff --git a/src/intel_driver.c b/src/intel_driver.c
index b16913b4..7e4a4a43 100644
--- a/src/intel_driver.c
+++ b/src/intel_driver.c
@@ -107,6 +107,7 @@ typedef enum {
OPTION_DEBUG_FLUSH_BATCHES,
OPTION_DEBUG_FLUSH_CACHES,
OPTION_DEBUG_WAIT,
+ OPTION_HOTPLUG,
} I830Opts;
static OptionInfoRec I830Options[] = {
@@ -125,6 +126,7 @@ static OptionInfoRec I830Options[] = {
{OPTION_DEBUG_FLUSH_BATCHES, "DebugFlushBatches", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEBUG_FLUSH_CACHES, "DebugFlushCaches", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEBUG_WAIT, "DebugWait", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, TRUE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
/* *INDENT-ON* */
@@ -804,6 +806,110 @@ intel_flush_callback(CallbackListPtr *list,
}
}
+#if HAVE_UDEV
+static void
+I830HandleUEvents(int fd, void *closure)
+{
+ ScrnInfoPtr scrn = closure;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct udev_device *dev;
+ const char *hotplug;
+ struct stat s;
+ dev_t udev_devnum;
+
+ dev = udev_monitor_receive_device(intel->uevent_monitor);
+ if (!dev)
+ return;
+
+ udev_devnum = udev_device_get_devnum(dev);
+ fstat(intel->drmSubFD, &s);
+ /*
+ * Check to make sure this event is directed at our
+ * device (by comparing dev_t values), then make
+ * sure it's a hotplug event (HOTPLUG=1)
+ */
+
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+ if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1)
+ RRGetInfo(screenInfo.screens[scrn->scrnIndex], TRUE);
+
+ udev_device_unref(dev);
+}
+
+static void
+I830UeventInit(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct udev *u;
+ struct udev_monitor *mon;
+ Bool hotplug;
+ MessageType from = X_CONFIG;
+
+ if (!xf86GetOptValBool(intel->Options, OPTION_HOTPLUG, &hotplug)) {
+ from = X_DEFAULT;
+ hotplug = TRUE;
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from, "hotplug detection: \"%s\"\n",
+ hotplug ? "enabled" : "disabled");
+ if (!hotplug)
+ return;
+
+ u = udev_new();
+ if (!u)
+ return;
+
+ mon = udev_monitor_new_from_netlink(u, "udev");
+
+ if (!mon) {
+ udev_unref(u);
+ return;
+ }
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(mon,
+ "drm",
+ "drm_minor") < 0 ||
+ udev_monitor_enable_receiving(mon) < 0)
+ {
+ udev_monitor_unref(mon);
+ udev_unref(u);
+ return;
+ }
+
+ intel->uevent_handler =
+ xf86AddGeneralHandler(udev_monitor_get_fd(mon),
+ I830HandleUEvents,
+ scrn);
+ if (!intel->uevent_handler) {
+ udev_monitor_unref(mon);
+ udev_unref(u);
+ return;
+ }
+
+ intel->uevent_monitor = mon;
+}
+
+static void
+I830UeventFini(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (intel->uevent_handler)
+ {
+ struct udev *u = udev_monitor_get_udev(intel->uevent_monitor);
+
+ xf86RemoveGeneralHandler(intel->uevent_handler);
+
+ udev_monitor_unref(intel->uevent_monitor);
+ udev_unref(u);
+ intel->uevent_handler = NULL;
+ intel->uevent_monitor = NULL;
+ }
+}
+#endif /* HAVE_UDEV */
+
static Bool
I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
{
@@ -1010,6 +1116,10 @@ I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
intel->suspended = FALSE;
+#if HAVE_UDEV
+ I830UeventInit(scrn);
+#endif
+
return uxa_resources_init(screen);
}
@@ -1091,6 +1201,10 @@ static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen)
ScrnInfoPtr scrn = xf86Screens[scrnIndex];
intel_screen_private *intel = intel_get_screen_private(scrn);
+#if HAVE_UDEV
+ I830UeventFini(scrn);
+#endif
+
if (scrn->vtSema == TRUE) {
I830LeaveVT(scrnIndex, 0);
}