summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c66
1 files changed, 65 insertions, 1 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8b14dfd513a..f9a0f980c30 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1517,6 +1517,8 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
du->pref_width = rects[du->unit].w;
du->pref_height = rects[du->unit].h;
du->pref_active = true;
+ du->gui_x = rects[du->unit].x;
+ du->gui_y = rects[du->unit].y;
} else {
du->pref_width = 800;
du->pref_height = 600;
@@ -1572,12 +1574,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force)
uint32_t num_displays;
struct drm_device *dev = connector->dev;
struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_display_unit *du = vmw_connector_to_du(connector);
mutex_lock(&dev_priv->hw_mutex);
num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS);
mutex_unlock(&dev_priv->hw_mutex);
- return ((vmw_connector_to_du(connector)->unit < num_displays) ?
+ return ((vmw_connector_to_du(connector)->unit < num_displays &&
+ du->pref_active) ?
connector_status_connected : connector_status_disconnected);
}
@@ -1723,3 +1727,63 @@ int vmw_du_connector_set_property(struct drm_connector *connector,
{
return 0;
}
+
+
+int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct drm_vmw_update_layout_arg *arg =
+ (struct drm_vmw_update_layout_arg *)data;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ void __user *user_rects;
+ struct drm_vmw_rect *rects;
+ unsigned rects_size;
+ int ret;
+ int i;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ return ret;
+
+ if (!arg->num_outputs) {
+ struct drm_vmw_rect def_rect = {0, 0, 800, 600};
+ vmw_du_update_layout(dev_priv, 1, &def_rect);
+ goto out_unlock;
+ }
+
+ rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
+ rects = kzalloc(rects_size, GFP_KERNEL);
+ if (unlikely(!rects)) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ user_rects = (void __user *)(unsigned long)arg->rects;
+ ret = copy_from_user(rects, user_rects, rects_size);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed to get rects.\n");
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ for (i = 0; i < arg->num_outputs; ++i) {
+ if (rects->x < 0 ||
+ rects->y < 0 ||
+ rects->x + rects->w > mode_config->max_width ||
+ rects->y + rects->h > mode_config->max_height) {
+ DRM_ERROR("Invalid GUI layout.\n");
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
+ vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
+
+out_free:
+ kfree(rects);
+out_unlock:
+ ttm_read_unlock(&vmaster->lock);
+ return ret;
+}