xf86-video-intel: src/sna/sna_display.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Jun 9 12:45:23 PDT 2013


 src/sna/sna_display.c |  492 ++++++++++++++++++++++++++++----------------------
 1 file changed, 277 insertions(+), 215 deletions(-)

New commits:
commit 3d760c9b32776bf2f1acde9256388769a9c5a398
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jun 5 12:52:11 2013 +0100

    sna: Streamline connector probing
    
    This is a tidy up in preparation for a more controversial patch. In the
    meantime, take advantage of information that remains static over the
    lifetime of our connectors.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 2a5e1c3..0ea2de5 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -77,27 +77,40 @@ struct sna_crtc {
 };
 
 struct sna_property {
-	drmModePropertyPtr mode_prop;
-	uint64_t value;
+	drmModePropertyPtr kprop;
 	int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
 	Atom *atoms;
 };
 
 struct sna_output {
 	int id;
-	drmModeConnectorPtr mode_output;
 	int encoder_idx;
-	int num_props;
-	struct sna_property *props;
+
+	unsigned int is_panel : 1;
+
+	uint32_t edid_idx;
+	uint32_t edid_blob_id;
+	uint32_t edid_len;
+	void *edid_raw;
 
 	bool has_panel_limits;
 	int panel_hdisplay;
 	int panel_vdisplay;
 
+	uint32_t dpms_id;
 	int dpms_mode;
 	char *backlight_iface;
 	int backlight_active_level;
 	int backlight_max;
+
+	int num_modes;
+	struct drm_mode_modeinfo *modes;
+
+	int num_props;
+	uint32_t *prop_ids;
+	uint64_t *prop_values;
+	struct sna_property *props;
+
 };
 
 static inline struct sna_output *to_sna_output(xf86OutputPtr output)
@@ -107,7 +120,7 @@ static inline struct sna_output *to_sna_output(xf86OutputPtr output)
 
 static inline int to_connector_id(xf86OutputPtr output)
 {
-	return to_sna_output(output)->mode_output->connector_id;
+	return to_sna_output(output)->id;
 }
 
 static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
@@ -648,12 +661,11 @@ done:
 }
 #endif
 
-static void
+static DisplayModePtr
 mode_from_kmode(ScrnInfoPtr scrn,
-		drmModeModeInfoPtr kmode,
-		DisplayModePtr	mode)
+		const struct drm_mode_modeinfo *kmode,
+		DisplayModePtr mode)
 {
-	memset(mode, 0, sizeof(DisplayModeRec));
 	mode->status = MODE_OK;
 
 	mode->Clock = kmode->clock;
@@ -681,7 +693,8 @@ mode_from_kmode(ScrnInfoPtr scrn,
 	if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS)
 		mode->status = MODE_BAD; /* unknown flags => unhandled */
 
-	xf86SetModeCrtc (mode, scrn->adjustFlags);
+	xf86SetModeCrtc(mode, scrn->adjustFlags);
+	return mode;
 }
 
 static void
@@ -773,12 +786,14 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 		if (output->crtc != crtc)
 			continue;
 
-		assert(output->possible_crtcs & (1 << i));
+		assert(output->possible_crtcs & (1 << sna_crtc->pipe) ||
+		       xf86IsEntityShared(crtc->scrn->entityList[0]));
 
 		DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
 		     __FUNCTION__, output->name, i, to_connector_id(output),
 		     sna_crtc->id, sna_crtc->pipe,
-		     output->possible_crtcs, output->possible_clones));
+		     (uint32_t)output->possible_crtcs,
+		     (uint32_t)output->possible_clones));
 		output_ids[output_count] = to_connector_id(output);
 		output_count++;
 	}
@@ -1729,33 +1744,94 @@ is_panel(int type)
 		type == DRM_MODE_CONNECTOR_eDP);
 }
 
+static int
+find_property(struct sna *sna, struct sna_output *output, const char *name)
+{
+	struct drm_mode_get_property prop;
+	int i;
+
+	VG_CLEAR(prop);
+	for (i = 0; i < output->num_props; i++) {
+		prop.prop_id = output->prop_ids[i];
+		prop.count_values = 0;
+		prop.count_enum_blobs = 0;
+		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
+			continue;
+
+		if (strcmp(prop.name, name) == 0)
+			return i;
+	}
+
+	return -1;
+}
+
+static int
+find_property_id(struct sna *sna, struct sna_output *output, const char *name)
+{
+	int idx = find_property(sna, output, name);
+	return idx != -1 ? output->prop_ids[idx] : 0;
+}
+
 static xf86OutputStatus
 sna_output_detect(xf86OutputPtr output)
 {
-	/* go to the hw and retrieve a new output struct */
 	struct sna *sna = to_sna(output->scrn);
 	struct sna_output *sna_output = output->driver_private;
-	xf86OutputStatus status;
+	struct drm_mode_get_connector conn;
+
+	DBG(("%s(%s)\n", __FUNCTION__, output->name));
+
+	VG_CLEAR(conn);
+	conn.connector_id = sna_output->id;
+	sna_output->num_modes = conn.count_modes = 0; /* reprobe */
+	conn.count_encoders = 0;
+	conn.count_props = sna_output->num_props;
+	conn.props_ptr = (uintptr_t)sna_output->prop_ids;
+	conn.prop_values_ptr = (uintptr_t)sna_output->prop_values;
+
+	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
+		return XF86OutputStatusUnknown;
+	DBG(("%s(%s): num modes %d -> %d, num props %d -> %d\n",
+	     __FUNCTION__, output->name,
+	     sna_output->num_modes, conn.count_modes,
+	     sna_output->num_props, conn.count_props));
+
+	assert(conn.count_props == sna_output->num_props);
+
+	while (conn.count_modes && conn.count_modes != sna_output->num_modes) {
+		struct drm_mode_modeinfo *new_modes;
+		int old_count;
+
+		old_count = sna_output->num_modes;
+		new_modes = realloc(sna_output->modes,
+				    sizeof(*sna_output->modes)*conn.count_modes);
+		if (new_modes == NULL)
+			break;
 
-	DBG(("%s\n", __FUNCTION__));
+		sna_output->modes = new_modes;
+		sna_output->num_modes = conn.count_modes;
+		conn.modes_ptr = (uintptr_t)sna_output->modes;
+		conn.count_encoders = 0;
+		conn.count_props = 0;
+		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) {
+			ErrorF("err = %d\n", errno);
+			sna_output->num_modes = min(old_count, sna_output->num_modes);
+			break;
+		}
+	}
 
-	drmModeFreeConnector(sna_output->mode_output);
-	sna_output->mode_output =
-		drmModeGetConnector(sna->kgem.fd, sna_output->id);
+	DBG(("%s(%s): found %d modes, connection status=%d\n",
+	     __FUNCTION__, output->name, sna_output->num_modes, conn.connection));
 
-	switch (sna_output->mode_output->connection) {
+	switch (conn.connection) {
 	case DRM_MODE_CONNECTED:
-		status = XF86OutputStatusConnected;
-		break;
+		return XF86OutputStatusConnected;
 	case DRM_MODE_DISCONNECTED:
-		status = XF86OutputStatusDisconnected;
-		break;
+		return XF86OutputStatusDisconnected;
 	default:
 	case DRM_MODE_UNKNOWNCONNECTION:
-		status = XF86OutputStatusUnknown;
-		break;
+		return XF86OutputStatusUnknown;
 	}
-	return status;
 }
 
 static Bool
@@ -1793,70 +1869,52 @@ sna_output_attach_edid(xf86OutputPtr output)
 {
 	struct sna *sna = to_sna(output->scrn);
 	struct sna_output *sna_output = output->driver_private;
-	drmModeConnectorPtr koutput = sna_output->mode_output;
+	struct drm_mode_get_blob blob;
 	void *raw = NULL;
-	int raw_length = 0;
 	xf86MonPtr mon = NULL;
-	int i;
 
-	/* look for an EDID property */
-	for (i = 0; i < koutput->count_props; i++) {
-		struct drm_mode_get_property prop;
-		struct drm_mode_get_blob blob;
-		void *tmp;
+	if (sna_output->edid_idx == -1)
+		return;
 
-		VG_CLEAR(prop);
-		prop.prop_id = koutput->props[i];
-		prop.count_values = 0;
-		prop.count_enum_blobs = 0;
-		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
-			continue;
+	raw = sna_output->edid_raw;
+	blob.length = sna_output->edid_len;
 
-		if (!(prop.flags & DRM_MODE_PROP_BLOB))
-			continue;
+	blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
+	if (blob.blob_id == sna_output->edid_blob_id)
+		goto skip_read;
 
-		if (strcmp(prop.name, "EDID"))
-			continue;
+	blob.data = (uintptr_t)raw;
+	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
+		goto done;
 
-		if (koutput->prop_values[i] == 0)
-			continue;
+	DBG(("%s: retrieving blob id=%d, length=%d\n",
+	     __FUNCTION__, blob.blob_id, blob.length));
 
-		VG_CLEAR(blob);
-		blob.length = 0;
-		blob.data = 0;
-		blob.blob_id = koutput->prop_values[i];
+	if (blob.length > sna_output->edid_len) {
+		raw = realloc(raw, blob.length);
+		if (raw == NULL)
+			goto done;
 
+		VG(memset(raw, 0, blob.length));
+		blob.data = (uintptr_t)raw;
 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
-			continue;
-
-		DBG(("%s: retreiving blob (property %d, id=%d, value=%ld), length=%d\n",
-		     __FUNCTION__, i, koutput->props[i], (long)koutput->prop_values[i],
-		     blob.length));
-
-		tmp = malloc(blob.length);
-		if (tmp == NULL)
-			continue;
-
-		VG(memset(tmp, 0, blob.length));
-		blob.data = (uintptr_t)tmp;
-		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
-			free(tmp);
-			continue;
-		}
-
-		free(raw);
-		raw = tmp;
-		raw_length = blob.length;
+			goto done;
 	}
 
+skip_read:
 	if (raw) {
 		mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
-		if (mon && raw_length > 128)
+		if (mon && blob.length > 128)
 			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
 	}
 
+done:
 	xf86OutputSetEDID(output, mon);
-	free(raw);
+	if (raw) {
+		sna_output->edid_raw = raw;
+		sna_output->edid_len = blob.length;
+		sna_output->edid_blob_id = blob.blob_id;
+	}
 }
 
 static DisplayModePtr
@@ -1903,7 +1961,6 @@ static DisplayModePtr
 sna_output_get_modes(xf86OutputPtr output)
 {
 	struct sna_output *sna_output = output->driver_private;
-	drmModeConnectorPtr koutput = sna_output->mode_output;
 	DisplayModePtr Modes = NULL;
 	int i;
 
@@ -1911,15 +1968,15 @@ sna_output_get_modes(xf86OutputPtr output)
 
 	sna_output_attach_edid(output);
 
-	/* modes should already be available */
-	for (i = 0; i < koutput->count_modes; i++) {
+	for (i = 0; i < sna_output->num_modes; i++) {
 		DisplayModePtr Mode;
 
 		Mode = calloc(1, sizeof(DisplayModeRec));
-		if (Mode) {
-			mode_from_kmode(output->scrn, &koutput->modes[i], Mode);
-			Modes = xf86ModesAdd(Modes, Mode);
-		}
+		if (Mode)
+			Modes = xf86ModesAdd(Modes,
+					     mode_from_kmode(output->scrn,
+							     &sna_output->modes[i],
+							     Mode));
 	}
 
 	/*
@@ -1929,16 +1986,16 @@ sna_output_get_modes(xf86OutputPtr output)
 	 * If it is incorrect, please fix me.
 	 */
 	sna_output->has_panel_limits = false;
-	if (is_panel(koutput->connector_type)) {
+	if (sna_output->is_panel) {
 		sna_output->panel_hdisplay = sna_output->panel_vdisplay = 0;
-		for (i = 0; i < koutput->count_modes; i++) {
-			drmModeModeInfo *mode_ptr;
-
-			mode_ptr = &koutput->modes[i];
-			if (mode_ptr->hdisplay > sna_output->panel_hdisplay)
-				sna_output->panel_hdisplay = mode_ptr->hdisplay;
-			if (mode_ptr->vdisplay > sna_output->panel_vdisplay)
-				sna_output->panel_vdisplay = mode_ptr->vdisplay;
+		for (i = 0; i < sna_output->num_modes; i++) {
+			struct drm_mode_modeinfo *m;
+
+			m = &sna_output->modes[i];
+			if (m->hdisplay > sna_output->panel_hdisplay)
+				sna_output->panel_hdisplay = m->hdisplay;
+			if (m->vdisplay > sna_output->panel_vdisplay)
+				sna_output->panel_vdisplay = m->vdisplay;
 		}
 		sna_output->has_panel_limits =
 			sna_output->panel_hdisplay &&
@@ -1959,14 +2016,14 @@ sna_output_destroy(xf86OutputPtr output)
 	if (sna_output == NULL)
 		return;
 
+	free(sna_output->edid_raw);
 	for (i = 0; i < sna_output->num_props; i++) {
-		drmModeFreeProperty(sna_output->props[i].mode_prop);
+		drmModeFreeProperty(sna_output->props[i].kprop);
 		free(sna_output->props[i].atoms);
 	}
 	free(sna_output->props);
-
-	drmModeFreeConnector(sna_output->mode_output);
-	sna_output->mode_output = NULL;
+	free(sna_output->prop_ids);
+	free(sna_output->prop_values);
 
 	free(sna_output->backlight_iface);
 
@@ -2000,52 +2057,35 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
 {
 	struct sna *sna = to_sna(output->scrn);
 	struct sna_output *sna_output = output->driver_private;
-	drmModeConnectorPtr koutput = sna_output->mode_output;
-	int i;
 
 	DBG(("%s: dpms=%d\n", __FUNCTION__, dpms));
 
 	if (dpms != DPMSModeOn)
 		kgem_submit(&sna->kgem);
 
-	for (i = 0; i < koutput->count_props; i++) {
-		struct drm_mode_get_property prop;
+	/* Record the value of the backlight before turning
+	 * off the display, and reset if after turning it on.
+	 * Order is important as the kernel may record and also
+	 * reset the backlight across DPMS. Hence we need to
+	 * record the value before the kernel modifies it
+	 * and reapply it afterwards.
+	 */
+	if (dpms == DPMSModeOff)
+		sna_output_dpms_backlight(output,
+					  sna_output->dpms_mode,
+					  dpms);
 
-		VG_CLEAR(prop);
-		prop.prop_id = koutput->props[i];
-		prop.count_values = 0;
-		prop.count_enum_blobs = 0;
-		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
-			continue;
+	drmModeConnectorSetProperty(sna->kgem.fd,
+				    sna_output->id,
+				    sna_output->dpms_id,
+				    dpms);
 
-		if (strcmp(prop.name, "DPMS"))
-			continue;
+	if (dpms != DPMSModeOff)
+		sna_output_dpms_backlight(output,
+					  sna_output->dpms_mode,
+					  dpms);
 
-		/* Record thevalue of the backlight before turning
-		 * off the display, and reset if after turnging it on.
-		 * Order is important as the kernel may record and also
-		 * reset the backlight across DPMS. Hence we need to
-		 * record the value before the kernel modifies it
-		 * and reapply it afterwards.
-		 */
-		if (dpms == DPMSModeOff)
-			sna_output_dpms_backlight(output,
-						  sna_output->dpms_mode,
-						  dpms);
-
-		drmModeConnectorSetProperty(sna->kgem.fd,
-					    sna_output->id,
-					    prop.prop_id,
-					    dpms);
-
-		if (dpms != DPMSModeOff)
-			sna_output_dpms_backlight(output,
-						  sna_output->dpms_mode,
-						  dpms);
-
-		sna_output->dpms_mode = dpms;
-		break;
-	}
+	sna_output->dpms_mode = dpms;
 }
 
 static bool
@@ -2102,71 +2142,60 @@ sna_output_create_resources(xf86OutputPtr output)
 {
 	struct sna *sna = to_sna(output->scrn);
 	struct sna_output *sna_output = output->driver_private;
-	drmModeConnectorPtr mode_output = sna_output->mode_output;
 	int i, j, err;
 
-	sna_output->props = calloc(mode_output->count_props,
-				     sizeof(struct sna_property));
+	sna_output->props = calloc(sna_output->num_props,
+				   sizeof(struct sna_property));
 	if (!sna_output->props)
 		return;
 
-	sna_output->num_props = 0;
-	for (i = j = 0; i < mode_output->count_props; i++) {
-		drmModePropertyPtr drmmode_prop;
+	for (i = 0; i < sna_output->num_props; i++) {
+		struct sna_property *p = &sna_output->props[i];
 
-		drmmode_prop = drmModeGetProperty(sna->kgem.fd,
-						  mode_output->props[i]);
-		if (sna_property_ignore(drmmode_prop)) {
-			drmModeFreeProperty(drmmode_prop);
+		p->kprop = drmModeGetProperty(sna->kgem.fd,
+					      sna_output->prop_ids[i]);
+		if (sna_property_ignore(p->kprop)) {
+			drmModeFreeProperty(p->kprop);
+			p->kprop = NULL;
 			continue;
 		}
 
-		sna_output->props[j].mode_prop = drmmode_prop;
-		sna_output->props[j].value = mode_output->prop_values[i];
-		j++;
-	}
-	sna_output->num_props = j;
-
-	for (i = 0; i < sna_output->num_props; i++) {
-		struct sna_property *p = &sna_output->props[i];
-		drmModePropertyPtr drmmode_prop = p->mode_prop;
-
-		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
+		if (p->kprop->flags & DRM_MODE_PROP_RANGE) {
 			p->num_atoms = 1;
 			p->atoms = calloc(p->num_atoms, sizeof(Atom));
 			if (!p->atoms)
 				continue;
 
 			sna_output_create_ranged_atom(output, &p->atoms[0],
-						      drmmode_prop->name,
-						      drmmode_prop->values[0],
-						      drmmode_prop->values[1],
-						      p->value,
-						      drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE);
-
-		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
-			p->num_atoms = drmmode_prop->count_enums + 1;
+						      p->kprop->name,
+						      p->kprop->values[0],
+						      p->kprop->values[1],
+						      sna_output->prop_values[i],
+						      p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE);
+
+		} else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
+			p->num_atoms = p->kprop->count_enums + 1;
 			p->atoms = calloc(p->num_atoms, sizeof(Atom));
 			if (!p->atoms)
 				continue;
 
-			p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
-			for (j = 1; j <= drmmode_prop->count_enums; j++) {
-				struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
+			p->atoms[0] = MakeAtom(p->kprop->name, strlen(p->kprop->name), TRUE);
+			for (j = 1; j <= p->kprop->count_enums; j++) {
+				struct drm_mode_property_enum *e = &p->kprop->enums[j-1];
 				p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
 			}
 
 			err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
 							FALSE, FALSE,
-							drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
+							p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
 							p->num_atoms - 1, (INT32 *)&p->atoms[1]);
 			if (err != 0) {
 				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 					   "RRConfigureOutputProperty error, %d\n", err);
 			}
 
-			for (j = 0; j < drmmode_prop->count_enums; j++)
-				if (drmmode_prop->enums[j].value == p->value)
+			for (j = 0; j < p->kprop->count_enums; j++)
+				if (p->kprop->enums[j].value == sna_output->prop_values[i])
 					break;
 			/* there's always a matching value */
 			err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
@@ -2184,22 +2213,22 @@ sna_output_create_resources(xf86OutputPtr output)
 		 * backlight_range.
 		 */
 		sna_output_create_ranged_atom(output, &backlight_atom,
-					BACKLIGHT_NAME, 0,
-					sna_output->backlight_max,
-					sna_output->backlight_active_level,
-					FALSE);
+					      BACKLIGHT_NAME, 0,
+					      sna_output->backlight_max,
+					      sna_output->backlight_active_level,
+					      FALSE);
 		sna_output_create_ranged_atom(output,
-					&backlight_deprecated_atom,
-					BACKLIGHT_DEPRECATED_NAME, 0,
-					sna_output->backlight_max,
-					sna_output->backlight_active_level,
-					FALSE);
+					      &backlight_deprecated_atom,
+					      BACKLIGHT_DEPRECATED_NAME, 0,
+					      sna_output->backlight_max,
+					      sna_output->backlight_active_level,
+					      FALSE);
 	}
 }
 
 static Bool
 sna_output_set_property(xf86OutputPtr output, Atom property,
-			    RRPropertyValuePtr value)
+			RRPropertyValuePtr value)
 {
 	struct sna *sna = to_sna(output->scrn);
 	struct sna_output *sna_output = output->driver_private;
@@ -2227,10 +2256,10 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
 	for (i = 0; i < sna_output->num_props; i++) {
 		struct sna_property *p = &sna_output->props[i];
 
-		if (p->atoms[0] != property)
+		if (p->atoms == NULL || p->atoms[0] != property)
 			continue;
 
-		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
+		if (p->kprop->flags & DRM_MODE_PROP_RANGE) {
 			uint32_t val;
 
 			if (value->type != XA_INTEGER || value->format != 32 ||
@@ -2239,9 +2268,9 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
 			val = *(uint32_t *)value->data;
 
 			drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id,
-						    p->mode_prop->prop_id, (uint64_t)val);
+						    p->kprop->prop_id, (uint64_t)val);
 			return TRUE;
-		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
+		} else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
 			Atom	atom;
 			const char	*name;
 			int		j;
@@ -2254,10 +2283,10 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
 				return FALSE;
 
 			/* search for matching name string, then set its value down */
-			for (j = 0; j < p->mode_prop->count_enums; j++) {
-				if (!strcmp(p->mode_prop->enums[j].name, name)) {
+			for (j = 0; j < p->kprop->count_enums; j++) {
+				if (!strcmp(p->kprop->enums[j].name, name)) {
 					drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id,
-								    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
+								    p->kprop->prop_id, p->kprop->enums[j].value);
 					return TRUE;
 				}
 			}
@@ -2317,8 +2346,7 @@ static const xf86OutputFuncsRec sna_output_funcs = {
 	.destroy = sna_output_destroy
 };
 
-static const int subpixel_conv_table[7] = {
-	0,
+static const int subpixel_conv_table[] = {
 	SubPixelUnknown,
 	SubPixelHorizontalRGB,
 	SubPixelHorizontalBGR,
@@ -2410,29 +2438,60 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 {
 	struct sna *sna = to_sna(scrn);
 	xf86OutputPtr output;
-	drmModeConnectorPtr koutput;
+	struct drm_mode_get_connector conn;
 	struct drm_mode_get_encoder enc;
+	struct drm_mode_modeinfo dummy;
 	struct sna_output *sna_output;
 	const char *output_name;
 	char name[32];
 	bool ret = false;
 	int i;
 
-	koutput = drmModeGetConnector(sna->kgem.fd,
-				      mode->kmode->connectors[num]);
-	if (!koutput)
+	VG_CLEAR(conn);
+	VG_CLEAR(enc);
+
+	conn.connector_id = mode->kmode->connectors[num];
+	conn.count_props = 0;
+	conn.count_modes = 1; /* skip detect */
+	conn.modes_ptr = (uintptr_t)&dummy;
+	conn.count_encoders = 1;
+	conn.encoders_ptr = (uintptr_t)&enc.encoder_id;
+
+	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
+		return false;
+
+	if (conn.count_encoders != 1)
 		return false;
 
-	VG_CLEAR(enc);
-	enc.encoder_id = koutput->encoders[0];
 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc))
-		goto cleanup_connector;
+		return false;
+
+	sna_output = calloc(sizeof(struct sna_output), 1);
+	if (!sna_output)
+		return false;
+
+	sna_output->num_props = conn.count_props;
+	sna_output->prop_ids = malloc(sizeof(uint32_t)*conn.count_props);
+	sna_output->prop_values = malloc(sizeof(uint64_t)*conn.count_props);
+
+	conn.count_modes = 1;
+	conn.modes_ptr = (uintptr_t)&dummy;
+
+	conn.count_props = sna_output->num_props;
+	conn.props_ptr = (uintptr_t)sna_output->prop_ids;
+	conn.prop_values_ptr = (uintptr_t)sna_output->prop_values;
+
+	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
+		return false;
+
+	/* statically constructed property list */
+	assert(sna_output->num_props == conn.count_props);
 
-	if (koutput->connector_type < ARRAY_SIZE(output_names))
-		output_name = output_names[koutput->connector_type];
+	if (conn.connector_type < ARRAY_SIZE(output_names))
+		output_name = output_names[conn.connector_type];
 	else
 		output_name = "UNKNOWN";
-	snprintf(name, 32, "%s%d", output_name, koutput->connector_type_id);
+	snprintf(name, 32, "%s%d", output_name, conn.connector_type_id);
 
 	if (xf86IsEntityShared(scrn->entityList[0])) {
 		const char *str;
@@ -2440,7 +2499,7 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 		str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
 		if (str && !sna_zaphod_match(str, name)) {
 			ret = true;
-			goto cleanup_connector;
+			goto cleanup;
 		}
 
 		if ((enc.possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) {
@@ -2449,7 +2508,7 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 					   "%s is an invalid output for screen (pipe) %d\n",
 					   name, scrn->confScreen->device->screen);
 			}
-			goto cleanup_connector;
+			goto cleanup;
 		}
 
 		enc.possible_crtcs = 1;
@@ -2464,20 +2523,20 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 		 * explicitly ignored the output.
 		 */
 		ret = output_ignored(scrn, name);
-		goto cleanup_connector;
+		goto cleanup;
 	}
 
-	sna_output = calloc(sizeof(struct sna_output), 1);
-	if (!sna_output)
-		goto cleanup_output;
-
-	sna_output->id = mode->kmode->connectors[num];
-	sna_output->mode_output = koutput;
+	sna_output->id = conn.connector_id;
+	sna_output->is_panel = is_panel(conn.connector_type);
+	sna_output->edid_idx = find_property(sna, sna_output, "EDID");
+	sna_output->dpms_id = find_property_id(sna, sna_output, "DPMS");
 
-	output->mm_width = koutput->mmWidth;
-	output->mm_height = koutput->mmHeight;
+	output->mm_width = conn.mm_width;
+	output->mm_height = conn.mm_height;
 
-	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
+	if (conn.subpixel >= ARRAY_SIZE(subpixel_conv_table))
+		conn.subpixel = 0;
+	output->subpixel_order = subpixel_conv_table[conn.subpixel];
 	output->driver_private = sna_output;
 
 	for (i = 0; i < mode->kmode->count_encoders; i++) {
@@ -2487,23 +2546,25 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 		}
 	}
 
-	if (is_panel(koutput->connector_type))
+	if (sna_output->is_panel)
 		sna_output_backlight_init(output);
 
 	output->possible_crtcs = enc.possible_crtcs;
 	output->possible_clones = enc.possible_clones;
 	output->interlaceAllowed = TRUE;
 
-	DBG(("%s: created output '%s' %d [%d]  (possible crtc:%x, possible clones:%x)\n",
-	     __FUNCTION__, name, num, to_connector_id(output),
-	     output->possible_crtcs, output->possible_clones));
+	DBG(("%s: created output '%s' %d [%d]  (possible crtc:%x, possible clones:%x), edid=%d, dpms=%d\n",
+	     __FUNCTION__, name, num, sna_output->id,
+	     (uint32_t)output->possible_crtcs,
+	     (uint32_t)output->possible_clones,
+	     sna_output->edid_idx, sna_output->dpms_id));
 
 	return true;
 
-cleanup_output:
-	xf86OutputDestroy(output);
-cleanup_connector:
-	drmModeFreeConnector(koutput);
+cleanup:
+	free(sna_output->prop_ids);
+	free(sna_output->prop_values);
+	free(sna_output);
 	return ret;
 }
 
@@ -2533,7 +2594,8 @@ sna_mode_compute_possible_clones(ScrnInfoPtr scrn)
 		output->possible_clones = clones;
 		DBG(("%s: updated output '%s' %d [%d] (possible crtc:%x, possible clones:%x)\n",
 		     __FUNCTION__, output->name, i, to_connector_id(output),
-		     output->possible_crtcs, output->possible_clones));
+		     (uint32_t)output->possible_crtcs,
+		     (uint32_t)output->possible_clones));
 	}
 }
 


More information about the xorg-commit mailing list