Skip to content

Commit

Permalink
drm/vmwgfx: Allow userspace to change default layout. Bump minor.
Browse files Browse the repository at this point in the history
The host may change the layout and, since the change is
communicated to the master, the master needs a way to
communicate the change to the kernel driver.

The minor version number is bumped to advertize the
availability of this feature.

Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Jakob Bornecrantz authored and Dave Airlie committed Jun 3, 2010
1 parent 991b7b4 commit d8bd19d
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 9 deletions.
7 changes: 6 additions & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
#define DRM_IOCTL_VMW_FENCE_WAIT \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \
struct drm_vmw_fence_wait_arg)
#define DRM_IOCTL_VMW_UPDATE_LAYOUT \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \
struct drm_vmw_update_layout_arg)


/**
Expand Down Expand Up @@ -135,7 +138,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl,
DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
DRM_AUTH | DRM_UNLOCKED)
DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl,
DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED)
};

static struct pci_device_id vmw_pci_id_list[] = {
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

#define VMWGFX_DRIVER_DATE "20100209"
#define VMWGFX_DRIVER_MAJOR 1
#define VMWGFX_DRIVER_MINOR 1
#define VMWGFX_DRIVER_MINOR 2
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
Expand Down Expand Up @@ -509,6 +509,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
void vmw_kms_write_svga(struct vmw_private *vmw_priv,
unsigned width, unsigned height, unsigned pitch,
unsigned bbp, unsigned depth);
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);

/**
* Overlay control - vmwgfx_overlay.c
Expand Down
45 changes: 45 additions & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -938,3 +938,48 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv)

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;

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_kms_ldu_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");
goto out_free;
}

vmw_kms_ldu_update_layout(dev_priv, arg->num_outputs, rects);

out_free:
kfree(rects);
out_unlock:
ttm_read_unlock(&vmaster->lock);
return ret;
}
4 changes: 3 additions & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);

/*
* Legacy display unit functions - vmwgfx_ldu.h
* Legacy display unit functions - vmwgfx_ldu.c
*/
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv);
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv);
int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects);

#endif
83 changes: 77 additions & 6 deletions drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ struct vmw_legacy_display {
struct vmw_legacy_display_unit {
struct vmw_display_unit base;

unsigned pref_width;
unsigned pref_height;
bool pref_active;
struct drm_display_mode *pref_mode;

struct list_head active;
};

Expand Down Expand Up @@ -332,8 +337,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector)
static enum drm_connector_status
vmw_ldu_connector_detect(struct drm_connector *connector)
{
/* XXX vmwctrl should control connection status */
if (vmw_connector_to_ldu(connector)->base.unit == 0)
if (vmw_connector_to_ldu(connector)->pref_active)
return connector_status_connected;
return connector_status_disconnected;
}
Expand All @@ -344,10 +348,9 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = {
752, 800, 0, 480, 489, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 800x600@60Hz */
{ DRM_MODE("800x600",
DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628,
0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1024x768@60Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1184, 1344, 0, 768, 771, 777, 806, 0,
Expand Down Expand Up @@ -419,10 +422,34 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = {
static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
uint32_t max_width, uint32_t max_height)
{
struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode = NULL;
struct drm_display_mode prefmode = { DRM_MODE("preferred",
DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
};
int i;

/* Add preferred mode */
{
mode = drm_mode_duplicate(dev, &prefmode);
if (!mode)
return 0;
mode->hdisplay = ldu->pref_width;
mode->vdisplay = ldu->pref_height;
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_probed_add(connector, mode);

if (ldu->pref_mode) {
list_del_init(&ldu->pref_mode->head);
drm_mode_destroy(dev, ldu->pref_mode);
}

ldu->pref_mode = mode;
}

for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
vmw_ldu_connector_builtin[i].vdisplay > max_height)
Expand Down Expand Up @@ -482,6 +509,11 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)

INIT_LIST_HEAD(&ldu->active);

ldu->pref_active = (unit == 0);
ldu->pref_width = 800;
ldu->pref_height = 600;
ldu->pref_mode = NULL;

drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
connector->status = vmw_ldu_connector_detect(connector);
Expand Down Expand Up @@ -546,3 +578,42 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)

return 0;
}

int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects)
{
struct drm_device *dev = dev_priv->dev;
struct vmw_legacy_display_unit *ldu;
struct drm_connector *con;
int i;

mutex_lock(&dev->mode_config.mutex);

#if 0
DRM_INFO("%s: new layout ", __func__);
for (i = 0; i < (int)num; i++)
DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y,
rects[i].w, rects[i].h);
DRM_INFO("\n");
#else
(void)i;
#endif

list_for_each_entry(con, &dev->mode_config.connector_list, head) {
ldu = vmw_connector_to_ldu(con);
if (num > ldu->base.unit) {
ldu->pref_width = rects[ldu->base.unit].w;
ldu->pref_height = rects[ldu->base.unit].h;
ldu->pref_active = true;
} else {
ldu->pref_width = 800;
ldu->pref_height = 600;
ldu->pref_active = false;
}
con->status = vmw_ldu_connector_detect(con);
}

mutex_unlock(&dev->mode_config.mutex);

return 0;
}
26 changes: 26 additions & 0 deletions include/drm/vmwgfx_drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#define DRM_VMW_EXECBUF 12
#define DRM_VMW_FIFO_DEBUG 13
#define DRM_VMW_FENCE_WAIT 14
/* guarded by minor version >= 2 */
#define DRM_VMW_UPDATE_LAYOUT 15


/*************************************************************************/
Expand Down Expand Up @@ -585,4 +587,28 @@ struct drm_vmw_stream_arg {
* sure that the stream has been stopped.
*/

/*************************************************************************/
/**
* DRM_VMW_UPDATE_LAYOUT - Update layout
*
* Updates the prefered 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;
};

#endif

0 comments on commit d8bd19d

Please sign in to comment.