vmwgfx: Reinstate the update_layout ioctl
authorThomas Hellstrom <thellstrom@vmware.com>
Tue, 25 Oct 2011 21:35:53 +0000 (23:35 +0200)
committerDave Airlie <airlied@redhat.com>
Wed, 2 Nov 2011 08:30:31 +0000 (08:30 +0000)
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>
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
include/drm/vmwgfx_drm.h

index 13afddc1f034440b054522dfbe85d9640bea2b11..82f5c8b128440dd7526c405f7948fa80dc94a871 100644 (file)
 #define DRM_IOCTL_VMW_PRESENT_READBACK                         \
        DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK,    \
                 struct drm_vmw_present_readback_arg)
+#define DRM_IOCTL_VMW_UPDATE_LAYOUT                            \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT,       \
+                struct drm_vmw_update_layout_arg)
 
 /**
  * The core DRM version of this macro doesn't account for
@@ -165,6 +168,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
        VMW_IOCTL_DEF(VMW_PRESENT_READBACK,
                      vmw_present_readback_ioctl,
                      DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT,
+                     vmw_kms_update_layout_ioctl,
+                     DRM_MASTER | DRM_UNLOCKED),
 };
 
 static struct pci_device_id vmw_pci_id_list[] = {
index 30589d0aecd985fd6b556793f4ad8f278f46ad81..8cca91a93bde092af78c6c7bdcfb0ffceb3f04a6 100644 (file)
@@ -40,9 +40,9 @@
 #include "ttm/ttm_module.h"
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20111008"
+#define VMWGFX_DRIVER_DATE "20111025"
 #define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 2
+#define VMWGFX_DRIVER_MINOR 3
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -633,6 +633,8 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
                     struct drm_vmw_fence_rep __user *user_fence_rep,
                     struct drm_vmw_rect *clips,
                     uint32_t num_clips);
+int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
 
 /**
  * Overlay control - vmwgfx_overlay.c
index 8b14dfd513a10ece2d9c2fe747e490e08205dd9d..f9a0f980c300ff959805394987f9448c5e3e13ef 100644 (file)
@@ -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;
+}
index db0b901f8c3f0f05a76117b92768e7a49a1ba24d..815cf99ce06e2e05394e482b5d3a8a509c88cb04 100644 (file)
@@ -96,6 +96,12 @@ struct vmw_display_unit {
        unsigned pref_height;
        bool pref_active;
        struct drm_display_mode *pref_mode;
+
+       /*
+        * Gui positioning
+        */
+       int gui_x;
+       int gui_y;
 };
 
 #define vmw_crtc_to_du(x) \
@@ -126,8 +132,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
 int vmw_du_connector_set_property(struct drm_connector *connector,
                                  struct drm_property *property,
                                  uint64_t val);
-int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
-                        struct drm_vmw_rect *rects);
+
 
 /*
  * Legacy display unit functions - vmwgfx_ldu.c
index cd7cd8162ed62d4aaba66ea3546c44444dc583db..bcb0912afe7a4a233a171f2d1b4bb7d518c6884e 100644 (file)
@@ -54,7 +54,7 @@
 #define DRM_VMW_FENCE_EVENT          17
 #define DRM_VMW_PRESENT              18
 #define DRM_VMW_PRESENT_READBACK     19
-
+#define DRM_VMW_UPDATE_LAYOUT        20
 
 /*************************************************************************/
 /**
@@ -550,31 +550,6 @@ struct drm_vmw_get_3d_cap_arg {
        uint32_t pad64;
 };
 
-/*************************************************************************/
-/**
- * DRM_VMW_UPDATE_LAYOUT - Update layout
- *
- * Updates the preferred modes and connection status for connectors. The
- * command conisits of one drm_vmw_update_layout_arg pointing out a array
- * of num_outputs drm_vmw_rect's.
- */
-
-/**
- * struct drm_vmw_update_layout_arg
- *
- * @num_outputs: number of active
- * @rects: pointer to array of drm_vmw_rect
- *
- * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
- */
-
-struct drm_vmw_update_layout_arg {
-       uint32_t num_outputs;
-       uint32_t pad64;
-       uint64_t rects;
-};
-
-
 /*************************************************************************/
 /**
  * DRM_VMW_FENCE_WAIT
@@ -788,4 +763,28 @@ struct drm_vmw_present_readback_arg {
         uint64_t clips_ptr;
         uint64_t fence_rep;
 };
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UPDATE_LAYOUT - Update layout
+ *
+ * Updates the preferred modes and connection status for connectors. The
+ * command consists of one drm_vmw_update_layout_arg pointing to an array
+ * of num_outputs drm_vmw_rect's.
+ */
+
+/**
+ * struct drm_vmw_update_layout_arg
+ *
+ * @num_outputs: number of active connectors
+ * @rects: pointer to array of drm_vmw_rect cast to an uint64_t
+ *
+ * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
+ */
+struct drm_vmw_update_layout_arg {
+       uint32_t num_outputs;
+       uint32_t pad64;
+       uint64_t rects;
+};
+
 #endif