[RFC PATCH] xfree86: Lid status hack

Adam Jackson ajax at redhat.com
Mon Jul 30 12:43:23 PDT 2012


If more than one output is connected, and there's only one ACPI lid
device, proxy the state of the lid into the LVDS / eDP connectivity.
This way we don't suffer from broken lid-status from the firmware in
a way that would result in nothing lighting up.

This is terribly Linux-specific and I don't think we should merge it
as-is, I'm mostly trying to generate some discussion.  There's some
weird corner cases that come out of this since we're still doing the
"poke one thing at a time" model, and we don't explicitly turn _off_
outputs during initial setup, so X and kernel's view of the world
gets out of sync.

I think ideally we'd do this in the DRM, but I was unable to come up
with a clean way to do it there.  Maybe it just needs to be ugly.

Signed-off-by: Adam Jackson <ajax at redhat.com>
---
 hw/xfree86/modes/xf86Crtc.c |   80 ++++++++++++++++++++++++++++++++++++++----
 1 files changed, 72 insertions(+), 8 deletions(-)

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 7d80264..0c9bc8d 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -32,6 +32,11 @@
 #include <stddef.h>
 #include <string.h>
 #include <stdio.h>
+#include <glob.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include "xf86.h"
 #include "xf86DDC.h"
@@ -1521,11 +1526,44 @@ handle_detailed_monrec(struct detailed_monitor_section *det_mon, void *data)
     }
 }
 
+static int
+lvds_lid_status(void)
+{
+    glob_t g = {0, };
+    int ret = XF86OutputStatusConnected;
+#ifdef linux
+    int fd;
+    char buf[80];
+
+    memset(buf, '\0', sizeof(buf));
+
+    if (glob("/proc/acpi/button/lid/*/state", GLOB_NOSORT, NULL, &g) != 0)
+	goto out;
+
+    if (g.gl_pathc != 1)
+	goto out;
+
+    fd = open(g.gl_pathv[0], O_RDONLY);
+    if (fd == -1)
+	goto out;
+
+    read(fd, buf, sizeof(buf)-1);
+    close(fd);
+    if (strstr(buf, "closed"))
+	ret = XF86OutputStatusDisconnected;
+#endif
+
+out:
+    globfree(&g);
+    return ret;
+}
+
 void
 xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
 {
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
     int o;
+    int			num_connected = 0;
 
     /* When canGrow was TRUE in the initial configuration we have to
      * compare against the maximum values so that we don't drop modes.
@@ -1537,6 +1575,40 @@ xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
         maxY = config->maxHeight;
     }
 
+    /* clean the mode list */
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr output = config->output[o];
+	while (output->probed_modes != NULL)
+	    xf86DeleteMode(&output->probed_modes, output->probed_modes);
+    }
+
+    /* scan for connectivity */
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr output = config->output[o];
+	output->status = output->funcs->detect(output);
+
+	if (output->status == XF86OutputStatusConnected)
+	    num_connected++;
+    }
+
+    /*
+     * Hack for LVDS/eDP.  We want to consider these disconnected if the
+     * lid is closed, but only if more than one output is connected (lest
+     * we darken the only available output, since lid status is unreliable)
+     */
+    if (num_connected > 1)
+    {
+	for (o = 0; o < config->num_output; o++)
+	{
+	    xf86OutputPtr output = config->output[o];
+	    if (strstr(output->name, "LVDS") || strstr(output->name, "eDP"))
+		if (output->status == XF86OutputStatusConnected)
+		    output->status = lvds_lid_status();
+	}
+    }
+
     /* Probe the list of modes for each output. */
     for (o = 0; o < config->num_output; o++) {
         xf86OutputPtr output = config->output[o];
@@ -1553,14 +1625,6 @@ xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
         Bool debug_modes = config->debug_modes || xf86Initialising;
         enum det_monrec_source sync_source = sync_default;
 
-        while (output->probed_modes != NULL)
-            xf86DeleteMode(&output->probed_modes, output->probed_modes);
-
-        /*
-         * Check connection status
-         */
-        output->status = (*output->funcs->detect) (output);
-
         if (output->status == XF86OutputStatusDisconnected &&
             !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) {
             xf86OutputSetEDID(output, NULL);
-- 
1.7.7.6



More information about the xorg-devel mailing list