diff options
author | Dave Airlie <airlied@redhat.com> | 2014-05-08 11:49:55 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-05-08 11:49:55 +1000 |
commit | ef8ae235cf128667a410f9ef4579185be553d192 (patch) | |
tree | 3489e9daa01db6c9d1c1c6ee005366b7db442a24 | |
parent | 78726bccb8bbb9688274ce32101f60e283e65179 (diff) |
modesetting: add DP MST supportdp-mst
as per discussions on dri-devel, don't tear down
outputs as this can cause randr errors in apps,
add an option same as nvidia to allow this behaviour.
-rw-r--r-- | src/driver.c | 6 | ||||
-rw-r--r-- | src/drmmode_display.c | 216 | ||||
-rw-r--r-- | src/drmmode_display.h | 1 |
3 files changed, 175 insertions, 48 deletions
diff --git a/src/driver.c b/src/driver.c index 21274a9..fab50a3 100644 --- a/src/driver.c +++ b/src/driver.c @@ -125,12 +125,14 @@ typedef enum OPTION_SW_CURSOR, OPTION_DEVICE_PATH, OPTION_SHADOW_FB, + OPTION_DELETE_DP_12_DISP, } modesettingOpts; static const OptionInfoRec Options[] = { {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE }, {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DELETE_DP_12_DISP, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; @@ -735,6 +737,10 @@ PreInit(ScrnInfoPtr pScrn, int flags) ms->drmmode.sw_cursor = TRUE; } + if (xf86ReturnOptValBool(ms->Options, OPTION_DELETE_DP_12_DISP, FALSE)) { + ms->drmmode.delete_dp_12_displays = TRUE; + } + ret = drmGetCap(ms->fd, DRM_CAP_DUMB_PREFER_SHADOW, &value); if (!ret) { prefer_shadow = !!value; diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 0cf8c13..f248a2e 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -364,6 +364,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, continue; drmmode_output = output->driver_private; + if (drmmode_output->output_id == -1) + continue; output_ids[output_count] = drmmode_output->mode_output->connector_id; output_count++; } @@ -403,10 +405,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, /* go through all the outputs and force DPMS them back on? */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; if (output->crtc != crtc) continue; + if (drmmode_output->output_id == -1) + continue; output->funcs->dpms(output, DPMSModeOn); } } @@ -620,6 +625,10 @@ drmmode_output_detect(xf86OutputPtr output) drmmode_output_private_ptr drmmode_output = output->driver_private; drmmode_ptr drmmode = drmmode_output->drmmode; xf86OutputStatus status; + + if (drmmode_output->output_id == -1) + return XF86OutputStatusDisconnected; + drmModeFreeConnector(drmmode_output->mode_output); drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); @@ -1002,20 +1011,133 @@ static const char * const output_names[] = { "None", "DSI", }; +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 + 1] = '\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, + drmModePropertyBlobPtr path_blob) +{ + int ret; + char *extra_path; + int conn_id; + xf86OutputPtr output; + + ret = parse_path_blob(path_blob, &conn_id, &extra_path); + if (ret == -1) + goto fallback; + + output = find_output(pScrn, conn_id); + if (!output) + goto fallback; + + snprintf(name, 32, "%s-%s", output->name, extra_path); + ErrorF("setting name to %s\n", name); + return; + +fallback: + if (koutput->connector_type >= MS_ARRAY_SIZE(output_names)) + snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1); +#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT + else if (pScrn->is_gpu) + snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); +#endif + else + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); +} + static void -drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int add_randr) +drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int dynamic) { xf86OutputPtr output; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); drmModeConnectorPtr koutput; drmModeEncoderPtr *kencoders = NULL; drmmode_output_private_ptr drmmode_output; drmModePropertyPtr props; char name[32]; int i; + drmModePropertyBlobPtr path_blob = NULL; koutput = drmModeGetConnector(drmmode->fd, mode_res->connectors[num]); 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); + } + } + + drmmode_create_name(pScrn, koutput, name, path_blob); + + 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; + } + } kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); if (!kencoders) { @@ -1029,16 +1151,6 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r } } - /* need to do smart conversion here for compat with non-kms ATI driver */ - if (koutput->connector_type >= MS_ARRAY_SIZE(output_names)) - snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1); -#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT - else if (pScrn->is_gpu) - snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); -#endif - else - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); - output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); if (!output) { goto out_free_encoders; @@ -1081,7 +1193,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r } } - if (add_randr) + if (dynamic) output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); return; out_free_encoders: @@ -1455,7 +1567,9 @@ drmmode_handle_uevents(int fd, void *closure) drmModeResPtr mode_res; xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); int i, j; - ErrorF("got uevent\n"); + Bool found; + Bool changed = FALSE; + dev = udev_monitor_receive_device(drmmode->uevent_monitor); if (!dev) { ErrorF("failed to get monitor device\n"); @@ -1466,69 +1580,75 @@ drmmode_handle_uevents(int fd, void *closure) if (!mode_res) goto out; - ErrorF("got resourecs %d %d enc %d\n", mode_res->count_crtcs, mode_res->count_connectors, mode_res->count_encoders); if (mode_res->count_crtcs != config->num_crtc) { ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc); goto out_free_res; } - if (mode_res->count_connectors != config->num_output) { - Bool found; - /* figure out if we have gotten rid of any connectors - traverse old output list looking for outputs */ + /* figure out if we have gotten rid of any connectors + traverse old output list looking for outputs */ restart_destroy: - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; - drmmode_output_private_ptr drmmode_output; + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + drmmode_output_private_ptr drmmode_output; - 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; - } + 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; + } + 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) { ErrorF("destroying id %d\n", drmmode_output->output_id); 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; + /* 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; + 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; - } + drmmode_output = output->driver_private; + if (mode_res->connectors[i] == drmmode_output->output_id) { + found = TRUE; + break; } - if (found) - continue; + } + if (found) + continue; - ErrorF("adding id %d\n", mode_res->connectors[i]); - drmmode_output_init(scrn, drmmode, mode_res, i, 1); + changed = TRUE; + ErrorF("adding id %d\n", mode_res->connectors[i]); + drmmode_output_init(scrn, drmmode, mode_res, i, 1); - } + } + + if (changed) { RRSetChanged(xf86ScrnToScreen(scrn)); RRTellChanged(xf86ScrnToScreen(scrn)); } + out_free_res: drmModeFreeResources(mode_res); out: RRGetInfo(xf86ScrnToScreen(scrn), TRUE); - udev_device_unref(dev); } #endif diff --git a/src/drmmode_display.h b/src/drmmode_display.h index f90b547..c9996f9 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -70,6 +70,7 @@ typedef struct { #ifdef HAVE_SCREEN_SPECIFIC_PRIVATE_KEYS DevPrivateKeyRec pixmapPrivateKeyRec; #endif + Bool delete_dp_12_displays; } drmmode_rec, *drmmode_ptr; typedef struct { |