|
@@ -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;
|
|
|
+}
|