From: Adam Jackson ajax@redhat.com
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.
Signed-off-by: Keith Packard keithp@keithp.com --- configure.ac | 5 ++ src/Makefile.am | 4 +- src/intel.h | 11 +++++ src/intel_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index e066b3d..58fa929 100644 --- a/configure.ac +++ b/configure.ac @@ -47,6 +47,11 @@ AC_PROG_LIBTOOL PKG_CHECK_MODULES(GEN4ASM, [intel-gen4asm >= 1.0], [gen4asm=yes], [gen4asm=no]) AM_CONDITIONAL(HAVE_GEN4ASM, test x$gen4asm = xyes)
+PKG_CHECK_MODULES(UDEV, [libudev], [udev=yes], [udev=no]) +if test x"$udev" = xyes; then + AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) +fi + AH_TOP([#include "xorg-server.h"])
# Define a configure option for an alternate module directory diff --git a/src/Makefile.am b/src/Makefile.am index b0a1cf7..ab70207 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 b816aeb..a80b214 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 @@ -47,6 +51,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef _I830_H_ #define _I830_H_
+ #include "xf86_OSproc.h" #include "compiler.h" #include "xf86PciInfo.h" @@ -70,6 +75,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. @@ -435,6 +444,8 @@ typedef struct intel_screen_private { */ Bool fallback_debug; unsigned debug_flush; + struct udev_monitor *uevent_monitor; + InputHandlerProc uevent_handler; } intel_screen_private;
enum { diff --git a/src/intel_driver.c b/src/intel_driver.c index 4391672..63b26a4 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* */ @@ -801,6 +803,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) { @@ -1007,6 +1113,10 @@ I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
intel->suspended = FALSE;
+#if HAVE_UDEV + I830UeventInit(scrn); +#endif + return uxa_resources_init(screen); }
@@ -1088,6 +1198,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); }
From: Adam Jackson ajax@redhat.com
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
Signed-off-by: Keith Packard keithp@keithp.com --- configure.ac | 5 ++ src/Makefile.am | 4 +- src/intel.h | 12 +++++ src/intel_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index e066b3d..58fa929 100644 --- a/configure.ac +++ b/configure.ac @@ -47,6 +47,11 @@ AC_PROG_LIBTOOL PKG_CHECK_MODULES(GEN4ASM, [intel-gen4asm >= 1.0], [gen4asm=yes], [gen4asm=no]) AM_CONDITIONAL(HAVE_GEN4ASM, test x$gen4asm = xyes)
+PKG_CHECK_MODULES(UDEV, [libudev], [udev=yes], [udev=no]) +if test x"$udev" = xyes; then + AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) +fi + AH_TOP([#include "xorg-server.h"])
# Define a configure option for an alternate module directory diff --git a/src/Makefile.am b/src/Makefile.am index b0a1cf7..ab70207 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 b816aeb..1234b94 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. @@ -435,6 +443,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 4391672..63b26a4 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* */ @@ -801,6 +803,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) { @@ -1007,6 +1113,10 @@ I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
intel->suspended = FALSE;
+#if HAVE_UDEV + I830UeventInit(scrn); +#endif + return uxa_resources_init(screen); }
@@ -1088,6 +1198,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); }
Keith Packard wrote:
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.
Are these events actually being generated?
If there is the infrastructure to do so, then it seems that the 600ms delay while polling unconnected monitors could easily be removed.
Or has that already been done, but just not for the older hardware?
//Peter
On Mon, 4 Oct 2010 01:15:08 +0200, Peter Stuge peter@stuge.se wrote:
If there is the infrastructure to do so, then it seems that the 600ms delay while polling unconnected monitors could easily be removed.
Newer hardware generates interrupts for VGA and TV hotplug events; older hardware doesn't.
On Sun, 3 Oct 2010 16:08:16 -0700, Keith Packard keithp@keithp.com wrote:
From: Adam Jackson ajax@redhat.com
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.
The obvious question: why are we doing this in the driver? It looks very generic and can be shared between any of the drm drivers, so should this be a facility provided by the server? It would be a good start to a KMS module... -Chris
On Mon, Oct 4, 2010 at 1:08 AM, Keith Packard keithp@keithp.com wrote:
From: Adam Jackson ajax@redhat.com ... +++ 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* */
The HotPlug option should also be added to the intel man page, right?
Geir Ove
From: Adam Jackson ajax@redhat.com
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 --- configure.ac | 5 ++ man/intel.man | 6 +++ src/Makefile.am | 4 +- src/intel.h | 12 +++++ src/intel_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index e066b3d..58fa929 100644 --- a/configure.ac +++ b/configure.ac @@ -47,6 +47,11 @@ AC_PROG_LIBTOOL PKG_CHECK_MODULES(GEN4ASM, [intel-gen4asm >= 1.0], [gen4asm=yes], [gen4asm=no]) AM_CONDITIONAL(HAVE_GEN4ASM, test x$gen4asm = xyes)
+PKG_CHECK_MODULES(UDEV, [libudev], [udev=yes], [udev=no]) +if test x"$udev" = xyes; then + AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) +fi + AH_TOP([#include "xorg-server.h"])
# Define a configure option for an alternate module directory diff --git a/man/intel.man b/man/intel.man index 31860f2..fa7f7dc 100644 --- a/man/intel.man +++ b/man/intel.man @@ -192,6 +192,12 @@ Enable XvMC driver. Current support MPEG2 MC on 915/945 and G33 series. User should provide absolute path to libIntelXvMC.so in XvMCConfig file. .IP Default: Disabled. +.TP +.BI "Option *qHotplug*q *q" boolean *q +This option controls whether the driver automatically notifies +applications when monitors are connected or disconnected. +.IP +Default: enabled.
.SH OUTPUT CONFIGURATION On 830M and better chipsets, the driver supports runtime configuration of diff --git a/src/Makefile.am b/src/Makefile.am index b0a1cf7..ab70207 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 b816aeb..1234b94 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. @@ -435,6 +443,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 4391672..63b26a4 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* */ @@ -801,6 +803,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) { @@ -1007,6 +1113,10 @@ I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
intel->suspended = FALSE;
+#if HAVE_UDEV + I830UeventInit(scrn); +#endif + return uxa_resources_init(screen); }
@@ -1088,6 +1198,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); }
On Mon, Oct 4, 2010 at 7:43 PM, Keith Packard keithp@keithp.com wrote:
+.BI "Option *qHotplug*q *q" boolean *q ...
- {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, TRUE},
It probably doesn't matter, but it would be nice to be consistent with the captialization. "Hotplug" or "HotPlug".
Geir Ove
dri-devel@lists.freedesktop.org