diff mbox

[2/2] drm: create fake disconnected connector for use when nothing is plugged in.

Message ID 1273021935-15478-3-git-send-email-airlied@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Airlie May 5, 2010, 1:12 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 994d23b..3b880ca 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -499,6 +499,7 @@  void drm_connector_cleanup(struct drm_connector *connector)
 	drm_mode_object_put(dev, &connector->base);
 	list_del(&connector->head);
 	mutex_unlock(&dev->mode_config.mutex);
+	connector->dev = NULL;
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -1560,6 +1561,11 @@  int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				goto out;
 			}
 
+			if (out_id == dev->mode_config.disconnected_connector.base.id) {
+				ret = 0;
+				goto out;
+			}
+
 			obj = drm_mode_object_find(dev, out_id,
 						   DRM_MODE_OBJECT_CONNECTOR);
 			if (!obj) {
@@ -2655,3 +2661,37 @@  out:
 	mutex_unlock(&dev->mode_config.mutex);
 	return ret;
 }
+
+static void drm_connector_disconnected_dpms(struct drm_connector *connector, int mode)
+{
+	return;
+}
+
+static enum drm_connector_status drm_connector_disconnected_detect(struct drm_connector *connector)
+{
+	return connector_status_disconnected;
+}
+
+static int drm_connector_disconnected_fill_modes(struct drm_connector *connector, u32 max_width, u32 max_height)
+{
+	return 0;
+}
+
+static struct drm_connector_funcs drm_disconnected_funcs = {
+	.dpms = drm_connector_disconnected_dpms,
+	.detect = drm_connector_disconnected_detect,
+	.fill_modes = drm_connector_disconnected_fill_modes,
+	.destroy = drm_connector_cleanup,
+};
+
+int drm_mode_add_disconnected_connector(struct drm_device *dev)
+{
+	if (dev->mode_config.disconnected_connector.dev == NULL) {
+		drm_connector_init(dev, &dev->mode_config.disconnected_connector,
+				   &drm_disconnected_funcs,
+				   DRM_MODE_CONNECTOR_Unknown);
+		dev->mode_config.disconnected_connector.status = connector_status_disconnected;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(drm_mode_add_disconnected_connector);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ebb7a0c..665febb 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -819,11 +819,20 @@  static void output_poll_execute(struct slow_work *work)
 	enum drm_connector_status old_status, status;
 	bool repoll = false, changed = false;
 	int ret;
+	bool connected = false;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		/* if this is HPD or polled don't check it - TV out for instance */
-		if (!connector->polled)
+
+		/* skip the special disconnected connector */
+		if (&dev->mode_config.disconnected_connector == connector)
+			continue;
+		/* if this is HPD or polled don't check it -
+		   TV out for instance */
+		if (!connector->polled) {
+			if (connector->status == connector_status_connected)
+				connected = true;
 			continue;
+		}
 		else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
 			repoll = true;
 
@@ -832,8 +841,10 @@  static void output_poll_execute(struct slow_work *work)
 		   skip it */
 		if (old_status == connector_status_connected &&
 		    !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
-		    !(connector->polled & DRM_CONNECTOR_POLL_HPD))
+		    !(connector->polled & DRM_CONNECTOR_POLL_HPD)) {
+			connected = true;
 			continue;
+		}
 
 		status = connector->funcs->detect(connector);
 		if (old_status != status)
@@ -843,6 +854,14 @@  static void output_poll_execute(struct slow_work *work)
 			connected = true;
 	}
 
+	/* if we have the disconnected connector */
+	if (dev->mode_config.disconnected_connector.dev != NULL) {
+		/* if nothing connected at all we need to force disconnected connector to connected */
+		if (!connected)
+			dev->mode_config.disconnected_connector.status = connector_status_connected;
+		else
+			dev->mode_config.disconnected_connector.status = connector_status_disconnected;
+	}
 	if (changed) {
 		/* send a uevent + call fbdev */
 		drm_sysfs_hotplug_event(dev);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d198b82..f7eb3f0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1283,6 +1283,8 @@  bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 	 */
 	if (count == 0) {
 		printk(KERN_INFO "No connectors reported connected with modes\n");
+		/* create fake connector to hang disconnected X operation off */
+		drm_mode_add_disconnected_connector(dev);
 	}
 	drm_setup_crtcs(fb_helper);
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 2e4bf92..5dd3aad 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -625,6 +625,8 @@  struct drm_mode_config {
 	struct drm_property *scaling_mode_property;
 	struct drm_property *dithering_mode_property;
 	struct drm_property *dirty_info_property;
+
+	struct drm_connector disconnected_connector;
 };
 
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
@@ -804,4 +806,6 @@  extern int drm_add_modes_noedid(struct drm_connector *connector,
 				int hdisplay, int vdisplay);
 
 extern bool drm_edid_is_valid(struct edid *edid);
+
+extern int drm_mode_add_disconnected_connector(struct drm_device *dev);
 #endif /* __DRM_CRTC_H__ */