diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2011-10-25 17:35:53 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-11-02 04:30:31 -0400 |
commit | cd2b89e7e8c036903e7fa0c3dceca25e755fe78d (patch) | |
tree | 4ec5275d9650283de7b3be6d2e5eb0cd2e63cde6 /drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |
parent | bc1c4dc390c644106fa5b8d0fb44a473c4ba627c (diff) |
vmwgfx: Reinstate the update_layout ioctl
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.
Based on code originally written by Jakob Bornecrantz
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 66 |
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 8b14dfd513a1..f9a0f980c300 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, | |||
1517 | du->pref_width = rects[du->unit].w; | 1517 | du->pref_width = rects[du->unit].w; |
1518 | du->pref_height = rects[du->unit].h; | 1518 | du->pref_height = rects[du->unit].h; |
1519 | du->pref_active = true; | 1519 | du->pref_active = true; |
1520 | du->gui_x = rects[du->unit].x; | ||
1521 | du->gui_y = rects[du->unit].y; | ||
1520 | } else { | 1522 | } else { |
1521 | du->pref_width = 800; | 1523 | du->pref_width = 800; |
1522 | du->pref_height = 600; | 1524 | du->pref_height = 600; |
@@ -1572,12 +1574,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force) | |||
1572 | uint32_t num_displays; | 1574 | uint32_t num_displays; |
1573 | struct drm_device *dev = connector->dev; | 1575 | struct drm_device *dev = connector->dev; |
1574 | struct vmw_private *dev_priv = vmw_priv(dev); | 1576 | struct vmw_private *dev_priv = vmw_priv(dev); |
1577 | struct vmw_display_unit *du = vmw_connector_to_du(connector); | ||
1575 | 1578 | ||
1576 | mutex_lock(&dev_priv->hw_mutex); | 1579 | mutex_lock(&dev_priv->hw_mutex); |
1577 | num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); | 1580 | num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); |
1578 | mutex_unlock(&dev_priv->hw_mutex); | 1581 | mutex_unlock(&dev_priv->hw_mutex); |
1579 | 1582 | ||
1580 | return ((vmw_connector_to_du(connector)->unit < num_displays) ? | 1583 | return ((vmw_connector_to_du(connector)->unit < num_displays && |
1584 | du->pref_active) ? | ||
1581 | connector_status_connected : connector_status_disconnected); | 1585 | connector_status_connected : connector_status_disconnected); |
1582 | } | 1586 | } |
1583 | 1587 | ||
@@ -1723,3 +1727,63 @@ int vmw_du_connector_set_property(struct drm_connector *connector, | |||
1723 | { | 1727 | { |
1724 | return 0; | 1728 | return 0; |
1725 | } | 1729 | } |
1730 | |||
1731 | |||
1732 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, | ||
1733 | struct drm_file *file_priv) | ||
1734 | { | ||
1735 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1736 | struct drm_vmw_update_layout_arg *arg = | ||
1737 | (struct drm_vmw_update_layout_arg *)data; | ||
1738 | struct vmw_master *vmaster = vmw_master(file_priv->master); | ||
1739 | void __user *user_rects; | ||
1740 | struct drm_vmw_rect *rects; | ||
1741 | unsigned rects_size; | ||
1742 | int ret; | ||
1743 | int i; | ||
1744 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
1745 | |||
1746 | ret = ttm_read_lock(&vmaster->lock, true); | ||
1747 | if (unlikely(ret != 0)) | ||
1748 | return ret; | ||
1749 | |||
1750 | if (!arg->num_outputs) { | ||
1751 | struct drm_vmw_rect def_rect = {0, 0, 800, 600}; | ||
1752 | vmw_du_update_layout(dev_priv, 1, &def_rect); | ||
1753 | goto out_unlock; | ||
1754 | } | ||
1755 | |||
1756 | rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); | ||
1757 | rects = kzalloc(rects_size, GFP_KERNEL); | ||
1758 | if (unlikely(!rects)) { | ||
1759 | ret = -ENOMEM; | ||
1760 | goto out_unlock; | ||
1761 | } | ||
1762 | |||
1763 | user_rects = (void __user *)(unsigned long)arg->rects; | ||
1764 | ret = copy_from_user(rects, user_rects, rects_size); | ||
1765 | if (unlikely(ret != 0)) { | ||
1766 | DRM_ERROR("Failed to get rects.\n"); | ||
1767 | ret = -EFAULT; | ||
1768 | goto out_free; | ||
1769 | } | ||
1770 | |||
1771 | for (i = 0; i < arg->num_outputs; ++i) { | ||
1772 | if (rects->x < 0 || | ||
1773 | rects->y < 0 || | ||
1774 | rects->x + rects->w > mode_config->max_width || | ||
1775 | rects->y + rects->h > mode_config->max_height) { | ||
1776 | DRM_ERROR("Invalid GUI layout.\n"); | ||
1777 | ret = -EINVAL; | ||
1778 | goto out_free; | ||
1779 | } | ||
1780 | } | ||
1781 | |||
1782 | vmw_du_update_layout(dev_priv, arg->num_outputs, rects); | ||
1783 | |||
1784 | out_free: | ||
1785 | kfree(rects); | ||
1786 | out_unlock: | ||
1787 | ttm_read_unlock(&vmaster->lock); | ||
1788 | return ret; | ||
1789 | } | ||