From: Dave Airlie <[email protected]>

This allows for dynamic creation of conneectors when the
kernel tells us.

Signed-off-by: Dave Airlie <[email protected]>
---
 src/drmmode_display.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/drmmode_display.h |   2 +
 src/radeon.h          |   3 +-
 src/radeon_kms.c      |   5 ++
 4 files changed, 177 insertions(+), 7 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index dd79db5..fc03842 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1194,11 +1194,66 @@ const char *output_names[] = { "None",
 
 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
 
+static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
+{
+       xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+       int i;
+       for (i = 0; i < xf86_config->num_output; i++) {
+               xf86OutputPtr output = xf86_config->output[i];
+               drmmode_output_private_ptr drmmode_output;
+
+               drmmode_output = output->driver_private;
+               if (drmmode_output->output_id == id)
+                       return output;
+       }
+       return NULL;
+}
+
+static int parse_path_blob(drmModePropertyBlobPtr path_blob, int 
*conn_base_id, char **path)
+{
+       char *conn;
+       char conn_id[5];
+       int id, len;
+       char *blob_data;
+
+       if (!path_blob)
+               return -1;
+
+       blob_data = path_blob->data;
+       /* we only handle MST paths for now */
+       if (strncmp(blob_data, "mst:", 4))
+               return -1;
+
+       conn = strchr(blob_data + 4, '-');
+       if (!conn)
+               return -1;
+       len = conn - (blob_data + 4);
+       if (len + 1 > 5)
+               return -1;
+       memcpy(conn_id, blob_data + 4, len);
+       conn_id[len] = '\0';
+       id = strtoul(conn_id, NULL, 10);
+
+       *conn_base_id = id;
+
+       *path = conn + 1;
+       return 0;
+}
+
 static void
 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
-                   int *num_dvi, int *num_hdmi)
+                   drmModePropertyBlobPtr path_blob, int *num_dvi, int 
*num_hdmi)
 {
-       {
+       xf86OutputPtr output;
+       int conn_id;
+       char *extra_path;
+
+       output = NULL;
+       if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
+               output = find_output(pScrn, conn_id);
+       if (output) {
+               snprintf(name, 32, "%s-%s", output->name, extra_path);
+       } else {
                if (koutput->connector_type >= NUM_OUTPUT_NAMES)
                        snprintf(name, 32, "Unknown%d-%d", 
koutput->connector_type,
                                 koutput->connector_type_id - 1);
@@ -1241,14 +1296,16 @@ drmmode_create_name(ScrnInfoPtr pScrn, 
drmModeConnectorPtr koutput, char *name,
 }
 
 static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr 
mode_res, int num, int *num_dvi, int *num_hdmi)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr 
mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
 {
+       xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
        RADEONInfoPtr info = RADEONPTR(pScrn);
        xf86OutputPtr output;
        drmModeConnectorPtr koutput;
        drmModeEncoderPtr *kencoders = NULL;
        drmmode_output_private_ptr drmmode_output;
        drmModePropertyPtr props;
+       drmModePropertyBlobPtr path_blob = NULL;
        char name[32];
        int i;
        const char *s;
@@ -1257,6 +1314,18 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr 
drmmode, drmModeResPtr mode_r
        if (!koutput)
                return;
 
+       for (i = 0; i < koutput->count_props; i++) {
+               props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+               if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+                       if (!strcmp(props->name, "PATH")) {
+                               path_blob = drmModeGetPropertyBlob(drmmode->fd, 
koutput->prop_values[i]);
+                               drmModeFreeProperty(props);
+                               break;
+                       }
+                       drmModeFreeProperty(props);
+               }
+       }
+
        kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
        if (!kencoders) {
                goto out_free_encoders;
@@ -1269,7 +1338,26 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr 
drmmode, drmModeResPtr mode_r
                }
        }
 
-       drmmode_create_name(pScrn, koutput, name, num_dvi, num_hdmi);
+       drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
+       if (path_blob)
+               drmModeFreePropertyBlob(path_blob);
+
+       if (path_blob && dynamic) {
+               /* See if we have an output with this name already
+                * and hook stuff up.
+                */
+               for (i = 0; i < xf86_config->num_output; i++) {
+                       output = xf86_config->output[i];
+
+                       if (strncmp(output->name, name, 32))
+                               continue;
+
+                       drmmode_output = output->driver_private;
+                       drmmode_output->output_id = mode_res->connectors[num];
+                       drmmode_output->mode_output = koutput;
+                       return;
+               }
+       }
 
        if (xf86IsEntityShared(pScrn->entityList[0])) {
                if ((s = xf86GetOptValString(info->Options, 
OPTION_ZAPHOD_HEADS))) {
@@ -1325,6 +1413,11 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr 
drmmode, drmModeResPtr mode_r
                }
        }
 
+       if (dynamic) {
+               output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), 
output->name, strlen(output->name), output);
+               drmmode_output_create_resources(output);
+       }
+
        return;
 out_free_encoders:
        if (kencoders){
@@ -1756,7 +1849,7 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr 
drmmode, int cpp)
                        drmmode_crtc_init(pScrn, drmmode, mode_res, i);
 
        for (i = 0; i < mode_res->count_connectors; i++)
-               drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, 
&num_hdmi);
+               drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, 
&num_hdmi, 0);
 
        /* workout clones */
        drmmode_clones_init(pScrn, drmmode, mode_res);
@@ -1982,6 +2075,75 @@ Bool drmmode_setup_colormap(ScreenPtr pScreen, 
ScrnInfoPtr pScrn)
     return TRUE;
 }
 
+void
+radeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
+{
+       xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+       drmModeResPtr mode_res;
+       int i, j;
+       Bool found;
+       Bool changed = FALSE;
+
+       mode_res = drmModeGetResources(drmmode->fd);
+       if (!mode_res)
+               goto out;
+
+restart_destroy:
+       for (i = 0; i < config->num_output; i++) {
+               xf86OutputPtr output = config->output[i];
+               drmmode_output_private_ptr drmmode_output = 
output->driver_private;
+               found = FALSE;
+               for (j = 0; j < mode_res->count_connectors; j++) {
+                       if (mode_res->connectors[j] == 
drmmode_output->output_id) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               if (found)
+                       continue;
+
+               drmModeFreeConnector(drmmode_output->mode_output);
+               drmmode_output->mode_output = NULL;
+               drmmode_output->output_id = -1;
+
+               changed = TRUE;
+               if (drmmode->delete_dp_12_displays) {
+                       RROutputDestroy(output->randr_output);
+                       xf86OutputDestroy(output);
+                       goto restart_destroy;
+               }
+       }
+
+       /* find new output ids we don't have outputs for */
+       for (i = 0; i < mode_res->count_connectors; i++) {
+               found = FALSE;
+
+               for (j = 0; j < config->num_output; j++) {
+                       xf86OutputPtr output = config->output[j];
+                       drmmode_output_private_ptr drmmode_output;
+
+                       drmmode_output = output->driver_private;
+                       if (mode_res->connectors[i] == 
drmmode_output->output_id) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               if (found)
+                       continue;
+
+               changed = TRUE;
+               drmmode_output_init(scrn, drmmode, mode_res, i, NULL, NULL, 1);
+       }
+
+       if (changed) {
+               RRSetChanged(xf86ScrnToScreen(scrn));
+               RRTellChanged(xf86ScrnToScreen(scrn));
+       }
+
+       drmModeFreeResources(mode_res);
+out:
+       RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+}
 #ifdef HAVE_LIBUDEV
 static void
 drmmode_handle_uevents(int fd, void *closure)
@@ -1993,7 +2155,7 @@ drmmode_handle_uevents(int fd, void *closure)
        if (!dev)
                return;
 
-       RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+       radeon_mode_hotplug(scrn, drmmode);
        udev_device_unref(dev);
 }
 #endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 2e83ed5..c9920e0 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -51,6 +51,8 @@ typedef struct {
 #endif
   drmEventContext event_context;
   int count_crtcs;
+
+  Bool delete_dp_12_displays;
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
diff --git a/src/radeon.h b/src/radeon.h
index 6123cc2..7b904de 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -148,7 +148,8 @@ typedef enum {
     OPTION_ACCELMETHOD,
     OPTION_EXA_VSYNC,
     OPTION_ZAPHOD_HEADS,
-    OPTION_SWAPBUFFERS_WAIT
+    OPTION_SWAPBUFFERS_WAIT,
+    OPTION_DELETE_DP12,
 } RADEONOpts;
 
 
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index c1a4dec..62364d9 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -73,6 +73,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
     { OPTION_EXA_PIXMAPS,    "EXAPixmaps",      OPTV_BOOLEAN,   {0}, FALSE },
     { OPTION_ZAPHOD_HEADS,   "ZaphodHeads",      OPTV_STRING,  {0}, FALSE },
     { OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_DELETE_DP12,    "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, 
FALSE},
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -937,6 +938,10 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
               "SwapBuffers wait for vsync: %sabled\n", info->swapBuffersWait ? 
"en" : "dis");
 
+    if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
+        info->drmmode.delete_dp_12_displays = TRUE;
+    }
+
     if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == 
FALSE) {
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup 
failed\n");
        goto fail;
-- 
1.9.3

_______________________________________________
xorg-driver-ati mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-driver-ati

Reply via email to