[PATCH xserver 3/7] modesetting: Compare connector info to identify outputs

Daniel Martin consume.noise at gmail.com
Mon Nov 20 10:02:06 UTC 2017


The output id is unreliable for MST connectors and so is the connector
type id. Both can change during hotplugs of MST connectors. The fun part
comes if they change while we switched to another VT as one output id
may gets re-assigned to another output.

The only reliable way to identify MST connectors is their PATH. Non-MST
connectors can be identified using their type and type id.

Signed-off-by: Daniel Martin <consume.noise at gmail.com>
---
 hw/xfree86/drivers/modesetting/drmmode_display.c | 52 +++++++++++++++++++++---
 1 file changed, 46 insertions(+), 6 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index b6835572a..d8dd4d75f 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -1223,6 +1223,28 @@ koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
     return blob;
 }
 
+#ifdef CONFIG_UDEV_KMS
+
+/* We have to compare the path if available, as the connector_type_id may
+ * increase on replug (i.e. add the laptop back into a docking station). */
+static Bool
+koutput_equals_output(int fd, xf86OutputPtr output,
+        drmModeConnectorPtr koutput, drmModePropertyBlobPtr koutput_path_blob)
+{
+    drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+    if (!drmmode_output->path_blob)
+        return koutput->connector_type == drmmode_output->connector_type &&
+            koutput->connector_type_id == drmmode_output->connector_type_id;
+
+    if (!koutput_path_blob)
+        return FALSE;
+
+    return !strcmp(koutput_path_blob->data, drmmode_output->path_blob->data);
+}
+
+#endif
+
 static void
 drmmode_output_attach_tile(xf86OutputPtr output, drmModeConnectorPtr koutput)
 {
@@ -2343,8 +2365,17 @@ drmmode_handle_uevents(int fd, void *closure)
         changed = TRUE;
     }
 
-    /* find new output ids we don't have outputs for */
+    /* Re-evaluate the outputs, add new ones and update output ids. */
     for (i = 0; i < mode_res->count_connectors; i++) {
+        drmModePropertyBlobPtr path_blob;
+        drmModeConnectorPtr koutput;
+
+        koutput = drmModeGetConnectorCurrent(drmmode->fd,
+                mode_res->connectors[i]);
+        if (!koutput)
+            continue;
+
+        path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
         found = FALSE;
 
         for (j = 0; j < config->num_output; j++) {
@@ -2352,16 +2383,25 @@ drmmode_handle_uevents(int fd, void *closure)
             drmmode_output_private_ptr drmmode_output;
 
             drmmode_output = output->driver_private;
-            if (mode_res->connectors[i] == drmmode_output->output_id) {
+
+            if (koutput_equals_output(drmmode->fd, output,
+                        koutput, path_blob)) {
                 found = TRUE;
+                /* The connector_id might have changed due to MST hotplugging
+                 * or the output_id be -1, as the connector was disconnected
+                 * once. */
+                drmmode_output->output_id = koutput->connector_id;
                 break;
             }
         }
-        if (found)
-            continue;
 
-        changed = TRUE;
-        drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
+        if (!found) {
+            changed = TRUE;
+            drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
+        }
+
+        drmModeFreePropertyBlob(path_blob);
+        drmModeFreeConnector(koutput);
     }
 
     if (changed) {
-- 
2.13.6



More information about the xorg-devel mailing list