summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-05-08 08:04:58 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2014-06-11 11:05:27 +0100
commit782c920b01d5144125f2fe954e29fd7b07a1913e (patch)
tree59c363ea30ccf475bb62e1843cd6bbcd430a4d7b /src
parente680e54eab6ffa72e5e1eb6cc0e3fe4b235b06a1 (diff)
sna: Create a stable output name based on MST topology
In order to provide persistent names for MST devices, which may change topology dynamically, the kernel exports a PATH blob. We can then use this path to generate the output name, and so reuse existing XID when a monitor is plugged back in. Based on the patch for -modesetting by Dave Airlie. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/sna/sna_display.c110
1 files changed, 105 insertions, 5 deletions
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 36084d0b..12f1e8d2 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -2592,6 +2592,8 @@ sna_output_destroy(xf86OutputPtr output)
free(sna_output->edid_raw);
for (i = 0; i < sna_output->num_props; i++) {
+ if (output->randr_output)
+ RRDeleteOutputProperty(output->randr_output, sna_output->props[i].atoms[0]);
drmModeFreeProperty(sna_output->props[i].kprop);
free(sna_output->props[i].atoms);
}
@@ -3122,6 +3124,66 @@ sna_mode_compute_possible_outputs(struct sna *sna)
}
}
+static int name_from_path(struct sna *sna,
+ struct sna_output *sna_output,
+ char *name)
+{
+ struct drm_mode_get_blob blob;
+ char buf[32], *path = buf;
+ int id;
+
+ id = find_property(sna, sna_output, "PATH");
+ DBG(("%s: found? PATH=%d\n", __FUNCTION__, id));
+ if (id == -1)
+ return 0;
+
+ VG_CLEAR(blob);
+ blob.blob_id = sna_output->prop_values[id];
+ blob.length = sizeof(buf)-1;
+ blob.data = (uintptr_t)path;
+ VG(memset(path, 0, blob.length));
+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
+ return 0;
+
+ if (blob.length >= sizeof(buf)) {
+ path = alloca(blob.length + 1);
+ blob.data = (uintptr_t)path;
+ VG(memset(path, 0, blob.length));
+ DBG(("%s: reading %d bytes for path blob\n", __FUNCTION__, blob.length));
+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
+ return 0;
+ }
+
+ path[blob.length] = '\0'; /* paranoia */
+ DBG(("%s: PATH='%s'\n", __FUNCTION__, path));
+
+ /* we only handle MST paths for now */
+ if (strncmp(path, "mst:", 4) == 0) {
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ char tmp[5], *c;
+ int n;
+
+ c = strchr(path + 4, '-');
+ if (c == NULL)
+ return 0;
+
+ id = c - (path + 4);
+ if (id + 1> 5)
+ return 0;
+
+ memcpy(tmp, path + 4, id);
+ tmp[id] = '\0';
+ id = strtoul(tmp, NULL, 0);
+
+ for (n = 0; n < sna->mode.num_real_output; n++) {
+ if (to_sna_output(config->output[n])->id == id)
+ return snprintf(name, 32, "%s-%s", config->output[n]->name, c + 1);
+ }
+ }
+
+ return 0;
+}
+
static int
sna_output_add(struct sna *sna, int id, int serial)
{
@@ -3135,7 +3197,7 @@ sna_output_add(struct sna *sna, int id, int serial)
unsigned possible_encoders, attached_encoders, possible_crtcs;
const char *output_name;
char name[32];
- int len, i;
+ int path, len, i;
DBG(("%s(%d): serial=%d\n", __FUNCTION__, id, serial));
@@ -3251,6 +3313,39 @@ sna_output_add(struct sna *sna, int id, int serial)
VG(VALGRIND_MAKE_MEM_DEFINED(sna_output->prop_ids, sizeof(uint32_t)*sna_output->num_props));
VG(VALGRIND_MAKE_MEM_DEFINED(sna_output->prop_values, sizeof(uint64_t)*sna_output->num_props));
+ /* Construct name from topology, and recheck if output is acceptable */
+ path = name_from_path(sna, sna_output, name);
+ if (path) {
+ const char *str;
+
+ if (output_ignored(scrn, name)) {
+ len = 0;
+ goto skip;
+ }
+
+ if (serial) {
+ for (i = 0; i < sna->mode.num_real_output; i++) {
+ output = config->output[i];
+ if (strcmp(output->name, name) == 0) {
+ assert(output->scrn == scrn);
+ assert(output->funcs == &sna_output_funcs);
+ assert(to_sna_output(output)->id == 0);
+ sna_output_destroy(output);
+ goto reset;
+ }
+ }
+ }
+
+ str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
+ if (str && !sna_zaphod_match(str, name)) {
+ DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
+ len = 0;
+ goto skip;
+ }
+
+ len = path;
+ }
+
output = calloc(1, sizeof(*output) + len + 1);
if (!output)
goto cleanup;
@@ -3279,6 +3374,7 @@ sna_output_add(struct sna *sna, int id, int serial)
output->use_screen_monitor = config->num_output != 1;
xf86OutputUseScreenMonitor(output, !output->use_screen_monitor);
+reset:
sna_output->id = compat_conn.conn.connector_id;
sna_output->is_panel = is_panel(compat_conn.conn.connector_type);
sna_output->edid_idx = find_property(sna, sna_output, "EDID");
@@ -3312,9 +3408,11 @@ sna_output_add(struct sna *sna, int id, int serial)
output->interlaceAllowed = TRUE;
if (serial) {
- output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);
- if (output->randr_output == NULL)
- goto cleanup;
+ if (output->randr_output == NULL) {
+ output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);
+ if (output->randr_output == NULL)
+ goto cleanup;
+ }
sna_output_create_resources(output);
RRPostPendingProperties(output->randr_output);
@@ -3337,10 +3435,12 @@ sna_output_add(struct sna *sna, int id, int serial)
return 1;
cleanup:
+ len = -1;
+skip:
free(sna_output->prop_ids);
free(sna_output->prop_values);
free(sna_output);
- return -1;
+ return len;
}
static void sna_output_del(xf86OutputPtr output)