diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2011-10-25 10:03:36 +0200 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2011-10-27 19:40:58 +0200 |
commit | 9ca6b5dc8832c177db4a24c5d400c3facc11ffc9 (patch) | |
tree | 6869cba2b7554d7f130a40e9ec304f3927acdd05 /vmwgfx_kms.c | |
parent | afae984948d6f2540ff7a05500e638e4dc02469d (diff) |
vmwgfx: Reinstate the update_layout ioctl v2
We need to redefine a connector as "connected" if it matches a window
in the host preferred GUI layout.
Otherwise "smart" window managers would turn on Xorg outputs that we don't
want to be on.
This reinstates the update_layout and adds the following information to
the modesetting system.
a) Connection status <-> Equivalent to real hardware connection status
b) Preferred mode <-> Equivalent to real hardware reading EDID
c) Host window position <-> Equivalent to a real hardware scanout address
dynamic register.
It should be noted that there is no assumption here about what should be
displayed and where. Only how to access the host windows.
This also bumps minor to signal availability of the new IOCTL.
V2: Ioctl is master only. Minor cleanups
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Diffstat (limited to 'vmwgfx_kms.c')
-rw-r--r-- | vmwgfx_kms.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/vmwgfx_kms.c b/vmwgfx_kms.c index 09b1c85..b7db895 100644 --- a/vmwgfx_kms.c +++ b/vmwgfx_kms.c @@ -1527,6 +1527,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; @@ -1576,17 +1578,19 @@ void vmw_du_connector_restore(struct drm_connector *connector) } enum drm_connector_status - vmw_du_connector_detect(struct drm_connector *connector, bool force) +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); } @@ -1732,3 +1736,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; +} |