xenocara/driver/xf86-video-vmware/src/vmwarectrl.c
2006-11-26 20:20:56 +00:00

563 lines
14 KiB
C

/*
* Copyright 2006 by VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
/*
* vmwarectrl.c --
*
* The implementation of the VMWARE_CTRL protocol extension that
* allows X clients to communicate with the driver.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define NEED_REPLIES
#define NEED_EVENTS
#include "dixstruct.h"
#include "extnsionst.h"
#include <X11/X.h>
#include <X11/extensions/panoramiXproto.h>
#include "vmware.h"
#include "vmwarectrlproto.h"
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlQueryVersion --
*
* Implementation of QueryVersion command handler. Initialises and
* sends a reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlQueryVersion(ClientPtr client)
{
xVMwareCtrlQueryVersionReply rep = { 0, };
register int n;
REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION;
rep.minorVersion = VMWARE_CTRL_MINOR_VERSION;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.majorVersion, n);
swapl(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDoSetRes --
*
* Set the custom resolution into the mode list.
*
* This is done by alternately updating one of two dynamic modes. It is
* done this way because the server gets upset if you try to switch
* to a new resolution that has the same index as the current one.
*
* Results:
* TRUE on success, FALSE otherwise.
*
* Side effects:
* One dynamic mode will be updated if successful.
*
*----------------------------------------------------------------------------
*/
static Bool
VMwareCtrlDoSetRes(ScrnInfoPtr pScrn,
CARD32 x,
CARD32 y)
{
DisplayModePtr mode;
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
if (pScrn && pScrn->modes) {
/*
* Don't resize larger than possible but don't
* return an X Error either.
*/
if (x > pVMWARE->initialMode->HDisplay ||
y > pVMWARE->initialMode->VDisplay) {
return TRUE;
}
/*
* Switch the dynamic modes so that we alternate
* which one gets updated on each call.
*/
mode = pVMWARE->dynMode1;
pVMWARE->dynMode1 = pVMWARE->dynMode2;
pVMWARE->dynMode2 = mode;
/*
* Initialise the dynamic mode if it hasn't been used before.
*/
if (!pVMWARE->dynMode1) {
pVMWARE->dynMode1 = VMWAREAddDisplayMode(pScrn, "DynMode", 1, 1);
}
mode = pVMWARE->dynMode1;
mode->HDisplay = x;
mode->VDisplay = y;
return TRUE;
} else {
return FALSE;
}
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlSetRes --
*
* Implementation of SetRes command handler. Initialises and sends a
* reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlSetRes(ClientPtr client)
{
REQUEST(xVMwareCtrlSetResReq);
xVMwareCtrlSetResReply rep = { 0, };
ScrnInfoPtr pScrn;
ExtensionEntry *ext;
register int n;
REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
return BadMatch;
}
pScrn = ext->extPrivate;
if (pScrn->scrnIndex != stuff->screen) {
return BadMatch;
}
if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y)) {
return BadValue;
}
rep.type = X_Reply;
rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2;
rep.sequenceNumber = client->sequence;
rep.screen = stuff->screen;
rep.x = stuff->x;
rep.y = stuff->y;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.screen, n);
swapl(&rep.x, n);
swapl(&rep.y, n);
}
WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDoSetTopology --
*
* Set the custom topology and set a dynamic mode to the bounding box
* of the passed topology.
*
* Results:
* TRUE on success, FALSE otherwise.
*
* Side effects:
* One dynamic mode and the pending xinerama state will be updated if
* successful.
*
*----------------------------------------------------------------------------
*/
static Bool
VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn,
xXineramaScreenInfo *extents,
unsigned long number)
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
if (pVMWARE && pVMWARE->xinerama) {
VMWAREXineramaPtr xineramaState;
short maxX = 0;
short maxY = 0;
size_t i;
for (i = 0; i < number; i++) {
maxX = MAX(maxX, extents[i].x_org + extents[i].width);
maxY = MAX(maxY, extents[i].y_org + extents[i].height);
}
xineramaState = (VMWAREXineramaPtr)xcalloc(number, sizeof(VMWAREXineramaRec));
if (xineramaState) {
memcpy(xineramaState, extents, number * sizeof (VMWAREXineramaRec));
xfree(pVMWARE->xineramaNextState);
pVMWARE->xineramaNextState = xineramaState;
pVMWARE->xineramaNextNumOutputs = number;
return VMwareCtrlDoSetRes(pScrn, maxX, maxY);
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlSetTopology --
*
* Implementation of SetTopology command handler. Initialises and sends a
* reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlSetTopology(ClientPtr client)
{
REQUEST(xVMwareCtrlSetTopologyReq);
xVMwareCtrlSetTopologyReply rep = { 0, };
ScrnInfoPtr pScrn;
ExtensionEntry *ext;
register int n;
xXineramaScreenInfo *extents;
size_t i;
REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq);
if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
return BadMatch;
}
pScrn = ext->extPrivate;
if (pScrn->scrnIndex != stuff->screen) {
return BadMatch;
}
extents = (xXineramaScreenInfo *)(stuff + 1);
if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) {
return BadValue;
}
rep.type = X_Reply;
rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2;
rep.sequenceNumber = client->sequence;
rep.screen = stuff->screen;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.screen, n);
}
WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDispatch --
*
* Dispatcher for VMWARE_CTRL commands. Calls the correct handler for
* each command type.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of individual command handlers.
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlDispatch(ClientPtr client)
{
REQUEST(xReq);
switch(stuff->data) {
case X_VMwareCtrlQueryVersion:
return VMwareCtrlQueryVersion(client);
case X_VMwareCtrlSetRes:
return VMwareCtrlSetRes(client);
case X_VMwareCtrlSetTopology:
return VMwareCtrlSetTopology(client);
}
return BadRequest;
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlQueryVersion --
*
* Wrapper for QueryVersion handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlQueryVersion(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlQueryVersionReq);
REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
swaps(&stuff->length, n);
return VMwareCtrlQueryVersion(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlSetRes --
*
* Wrapper for SetRes handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlSetRes(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlSetResReq);
REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
swaps(&stuff->length, n);
swapl(&stuff->screen, n);
swapl(&stuff->x, n);
swapl(&stuff->y, n);
return VMwareCtrlSetRes(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlSetTopology --
*
* Wrapper for SetTopology handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlSetTopology(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlSetTopologyReq);
REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq);
swaps(&stuff->length, n);
swapl(&stuff->screen, n);
swapl(&stuff->number, n);
/* Each extent is a struct of shorts. */
SwapRestS(stuff);
return VMwareCtrlSetTopology(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlDispatch --
*
* Wrapper for dispatcher that handles input from other-endian clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of individual command handlers.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlDispatch(ClientPtr client)
{
REQUEST(xReq);
switch(stuff->data) {
case X_VMwareCtrlQueryVersion:
return SVMwareCtrlQueryVersion(client);
case X_VMwareCtrlSetRes:
return SVMwareCtrlSetRes(client);
case X_VMwareCtrlSetTopology:
return SVMwareCtrlSetTopology(client);
}
return BadRequest;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlResetProc --
*
* Cleanup handler called when the extension is removed.
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
VMwareCtrlResetProc(ExtensionEntry* extEntry)
{
/* Currently, no cleanup is necessary. */
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrl_ExitInit --
*
* Initialiser for the VMWARE_CTRL protocol extension.
*
* Results:
* None.
*
* Side effects:
* Protocol extension will be registered if successful.
*
*----------------------------------------------------------------------------
*/
void
VMwareCtrl_ExtInit(ScrnInfoPtr pScrn)
{
ExtensionEntry *myext;
if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0,
VMwareCtrlDispatch,
SVMwareCtrlDispatch,
VMwareCtrlResetProc,
StandardMinorOpcode))) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to add VMWARE_CTRL extension\n");
return;
}
/*
* For now, only support one screen as that's all the virtual
* hardware supports.
*/
myext->extPrivate = pScrn;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Initialized VMWARE_CTRL extension version %d.%d\n",
VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION);
}
}