@@ -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);
@@ -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);
@@ -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);
@@ -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__ */