[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freedesktop-xorg-devel
Subject:    [PATCH 8/8] modesetting: Add output hotplug support
From:       Daniel Martin <daniel.martin () secunet ! com>
Date:       2014-11-28 10:20:53
Message-ID: 1417170053-21566-9-git-send-email-daniel.martin () secunet ! com
[Download RAW message or body]

From: Daniel Martin <consume.noise@gmail.com>

When receiving a hotplug uevent, check if we have to add or remove
outputs and act accordingly.

Signed-off-by: Daniel Martin <consume.noise@gmail.com>
---
With this patch we create or destroy outputs as a reaction to uevents.

Due to my limited experience, the solution is either total crap, cause
I'm doing it wrong, or it is that complicated, cause the server never
had disappearing outputs in mind, or a combination of both.

 hw/xfree86/drivers/modesetting/drmmode_display.c | 150 ++++++++++++++++++++++-
 1 file changed, 148 insertions(+), 2 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c \
b/hw/xfree86/drivers/modesetting/drmmode_display.c index 474e5b6..876af68 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -43,6 +43,7 @@
 #include "xf86Crtc.h"
 #include "drmmode_display.h"
 
+#include <xf86RandR12.h>
 #include <cursorstr.h>
 
 #include <X11/extensions/dpmsconst.h>
@@ -785,8 +786,10 @@ drmmode_output_destroy(xf86OutputPtr output)
         free(drmmode_output->props[i].atoms);
     }
     free(drmmode_output->props);
-    for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
-        drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+    if (drmmode_output->mode_output) {
+        for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
+            drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+        }
     }
     free(drmmode_output->mode_encoders);
     drmModeFreeConnector(drmmode_output->mode_output);
@@ -1488,12 +1491,155 @@ drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
 }
 
 #ifdef CONFIG_UDEV_KMS
+static Bool
+drmmode_output_add(drmmode_ptr drmmode, int nth_connector)
+{
+    ScrnInfoPtr scrn = drmmode->scrn;
+    xf86OutputPtr output = drmmode_output_init(scrn, drmmode, nth_connector);
+
+    xf86DrvMsg(scrn->scrnIndex, X_INFO, "Adding output %s\n", output->name);
+
+    if (!output)
+        return FALSE;
+
+    output->randr_output = RROutputCreate(scrn->pScreen, output->name,
+                                          strlen(output->name), output);
+    if (!output->randr_output) {
+        xf86OutputDestroy(output);
+        return FALSE;
+    }
+
+    drmmode_output_create_resources(output);
+    RRPostPendingProperties(output->randr_output);
+
+    return TRUE;
+}
+
+static Bool
+drmmode_output_del(xf86OutputPtr output)
+{
+    ScrnInfoPtr scrn = output->scrn;
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(scrn->pScreen);
+    int i, j;
+
+    output->funcs->dpms(output, DPMSModeOff);
+
+    /* Remove the RROutput from RRCrtc, if any. */
+    if (output->randr_output->crtc) {
+        RRCrtcPtr rr_crtc = output->randr_output->crtc;
+
+        if (rr_crtc->numOutputs < 2) {
+            RRCrtcSet(rr_crtc, NULL, 0, 0, 0, 0, NULL);
+        } else {
+            RROutputPtr *rr_outputs = calloc(rr_crtc->numOutputs,
+                                             sizeof(RROutputPtr));
+            if (!rr_outputs)
+                return FALSE;
+
+            for (i = 0, j = 0; i < rr_crtc->numOutputs; i++) {
+                if (rr_crtc->outputs[i] != output->randr_output) {
+                    rr_outputs[j] = rr_crtc->outputs[i];
+                }
+                j++;
+            }
+
+            RRCrtcSet(rr_crtc, rr_crtc->mode, rr_crtc->x, rr_crtc->y,
+                      rr_crtc->rotation, rr_crtc->numOutputs - 1, rr_outputs);
+            free(rr_outputs);
+        }
+    }
+
+    /* Remove the RROutput from the list of available outputs. */
+    for (i = 0; i < pScrPriv->numOutputs; i++) {
+        if (pScrPriv->outputs[i] == output->randr_output) {
+             memmove(&pScrPriv->outputs[i], &pScrPriv->outputs[i + 1],
+                     ((pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr)));
+             pScrPriv->numOutputs--;
+             break;
+        }
+    }
+
+    xf86DrvMsg(scrn->scrnIndex, X_INFO, "Removing output %s\n", output->name);
+
+    RROutputDestroy(output->randr_output);
+    output->randr_output = NULL;
+
+    xf86OutputDestroy(output);
+
+    return TRUE;
+}
+
 void
 drmmode_output_eval(drmmode_ptr drmmode)
 {
     ScrnInfoPtr scrn = drmmode->scrn;
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    drmModeResPtr mode_res = NULL;
+
+    int old_num_output = xf86_config->num_output;
+    xf86OutputPtr *output_del_list = NULL;
+
+    Bool changed = FALSE;
+    int i, j;
+
+    mode_res = drmModeGetResources(drmmode->fd);
+    if (mode_res) {
+        drmModeFreeResources(drmmode->mode_res);
+        drmmode->mode_res = mode_res;
+    } else
+        return;
+
+    output_del_list = calloc(xf86_config->num_output + 1,
+                             sizeof(*output_del_list));
+    if (!output_del_list)
+        goto out;
+
+    /* Track all currently known outputs in output_del_list. We'll NULL each
+     * entry which we can match with one connector in mode_res->connectors.
+     * Later, every entry not being NULL is an output we have to delete. */
+    memcpy(output_del_list, xf86_config->output,
+           xf86_config->num_output * sizeof(*output_del_list));
+
+    /* Check for outputs we already know or have to add. */
+    for (i = 0; i < mode_res->count_connectors; i++) {
+        Bool found = FALSE;
+
+        for (j = 0; j < old_num_output; j++) {
+            drmmode_output_private_ptr drmmode_output;
+
+            if (output_del_list[j] == NULL)
+                continue;
+
+            drmmode_output = output_del_list[j]->driver_private;
+            if (drmmode_output->output_id == mode_res->connectors[i]) {
+                found = TRUE;
+                break;
+            }
+        }
+
+        if (found)
+            /* Found the output, NULL the entry. */
+            output_del_list[j] = NULL;
+        else
+            changed |= drmmode_output_add(drmmode, i);
+    }
+
+    for (i = 0; i < old_num_output; i++)
+        if (output_del_list[i] != NULL)
+            changed |= drmmode_output_del(output_del_list[i]);
+
+    if (changed) {
+        xf86DisableUnusedFunctions(scrn);
+        drmmode_clones_init(scrn, drmmode);
+
+        xf86RandR12TellChanged(xf86ScrnToScreen(scrn));
+    }
 
     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+
+out:
+    free(output_del_list);
 }
 
 static void
-- 
2.1.3

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic