xenocara/driver/xf86-input-vmmouse/shared/vmmouse_client.c
2017-01-21 18:40:20 +00:00

351 lines
9.6 KiB
C

/*
* Copyright 2002-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).
*/
/*
* vmmouse_client.c --
*
* VMware Virtual Mouse Client
*
* This module provides functions to enable, operate and process
* packets via the VMMouse module hosted in the VMX.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vmmouse_client.h"
#include "vmmouse_proto.h"
/*
*----------------------------------------------------------------------------
*
* VMMouseClientVMCheck --
*
* Checks if we're running in a VM by sending the GETVERSION command.
*
* Returns:
* 0 if we're running natively/the version command failed,
* 1 if we're in a VM.
*
*----------------------------------------------------------------------------
*/
static Bool
VMMouseClientVMCheck(void)
{
VMMouseProtoCmd vmpc;
vmpc.in.vEbx = ~VMMOUSE_PROTO_MAGIC;
vmpc.in.command = VMMOUSE_PROTO_CMD_GETVERSION;
VMMouseProto_SendCmd(&vmpc);
/*
* ebx should contain VMMOUSE_PROTO_MAGIC
* eax should contain version
*/
if (vmpc.out.vEbx != VMMOUSE_PROTO_MAGIC || vmpc.out.vEax == 0xffffffff) {
return FALSE;
}
return TRUE;
}
/*
*----------------------------------------------------------------------
*
* VMMouseClient_Disable --
*
* Tries to disable VMMouse communication mode on the host.
* The caller is responsible for maintaining state (we don't check
* if we're enabled before attempting to disable the VMMouse).
*
* Results:
* TRUE if we successfully disable the VMMouse communication mode,
* FALSE if something went wrong.
*
* Side effects:
* Disables the absolute positioning mode.
*
*----------------------------------------------------------------------
*/
void
VMMouseClient_Disable(void)
{
uint32_t status;
VMMouseProtoCmd vmpc;
VMwareLog(("VMMouseClient_Disable: writing disable command to port\n"));
vmpc.in.vEbx = VMMOUSE_CMD_DISABLE;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
VMMouseProto_SendCmd(&vmpc);
/*
* We should get 0xffff in the flags now.
*/
vmpc.in.vEbx = 0;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
VMMouseProto_SendCmd(&vmpc);
status = vmpc.out.vEax;
if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR) {
VMwareLog(("VMMouseClient_Disable: wrong status returned\n"));
}
}
/*
*----------------------------------------------------------------------
*
* VMMouseClient_Enable --
*
* Public Enable entry point. The driver calls this once it feels
* ready to deal with VMMouse stuff. For now, we just try to enable
* and return the result, but conceivably we could do more.
*
* Results:
* TRUE if the enable succeeds, FALSE otherwise.
*
* Side effects:
* Causes host-side state change.
*
*----------------------------------------------------------------------
*/
Bool
VMMouseClient_Enable(void) {
uint32_t status;
uint32_t data;
VMMouseProtoCmd vmpc;
/*
* First, make sure we're in a VM; i.e. in dualboot configurations we might
* find ourselves running on real hardware.
*/
if (!VMMouseClientVMCheck()) {
return FALSE;
}
VMwareLog(("VMMouseClientVMCheck succeeded, checking VMMOUSE version\n"));
VMwareLog(("VMMouseClient_Enable: READ_ID 0x%08x, VERSION_ID 0x%08x\n",
VMMOUSE_CMD_READ_ID, VMMOUSE_VERSION_ID));
/*
* We probe for the VMMouse backend by sending the ENABLE
* command to the mouse. We should get back the VERSION_ID on
* the data port.
*/
vmpc.in.vEbx = VMMOUSE_CMD_READ_ID;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
VMMouseProto_SendCmd(&vmpc);
/*
* Check whether the VMMOUSE_VERSION_ID is available to read
*/
vmpc.in.vEbx = 0;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
VMMouseProto_SendCmd(&vmpc);
status = vmpc.out.vEax;
if ((status & 0x0000ffff) == 0) {
VMwareLog(("VMMouseClient_Enable: no data on port."));
return FALSE;
}
/*
* Get the VMMOUSE_VERSION_ID then
*/
/* Get just one item */
vmpc.in.vEbx = 1;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_DATA;
VMMouseProto_SendCmd(&vmpc);
data = vmpc.out.vEax;
if (data!= VMMOUSE_VERSION_ID) {
VMwareLog(("VMMouseClient_Enable: data was not VERSION_ID"));
return FALSE;
}
/*
* Restrict access to the VMMouse backdoor handler.
*/
vmpc.in.vEbx = VMMOUSE_RESTRICT_IOPL;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_RESTRICT;
VMMouseProto_SendCmd(&vmpc);
/*
* To quote Jeremy, "Go Go Go!"
*/
VMwareLog(("VMMouseClient_Enable: go go go!\n"));
return TRUE;
}
/*
*----------------------------------------------------------------------
*
* VMMouseClient_GetInput --
*
* Retrieves a 4-word input packet from the VMMouse data port and
* stores it in the specified input structure.
*
* Results:
* The number of packets in the queue, including the retrieved
* packet.
*
* Side effects:
* Could cause host state change.
*
*----------------------------------------------------------------------
*/
unsigned int
VMMouseClient_GetInput (PVMMOUSE_INPUT_DATA pvmmouseInput) {
uint32_t status;
uint16_t numWords;
uint32_t packetInfo;
VMMouseProtoCmd vmpc;
/*
* The status dword has two parts: the high 16 bits are
* for flags, the low 16-bits are the number of DWORDs
* waiting in the data queue. VMMOUSE_ERROR is a special
* case that indicates there's something wrong on the
* host end, e.g. the VMMouse was disabled on the host-side.
*/
vmpc.in.vEbx = 0;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
VMMouseProto_SendCmd(&vmpc);
status = vmpc.out.vEax;
if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
VMwareLog(("VMMouseClient_GetInput: VMMOUSE_ERROR status, abort!\n"));
return VMMOUSE_ERROR;
}
/*
* We don't use the status flags, just get the words
*/
numWords = status & 0x0000ffff;
if ((numWords % 4) != 0) {
VMwareLog(("VMMouseClient_GetInput: invalid status numWords, abort!\n"));
return (0);
}
if (numWords == 0) {
return (0);
}
/*
* The VMMouse uses a 4-dword packet protocol:
* DWORD 0: Button State and per-packet flags
* DWORD 1: X position (absolute or relative)
* DWORD 2: Y position (absolute or relative)
* DWORD 3: Z position (relative)
*/
/* Get 4 items at once */
vmpc.in.vEbx = 4;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_DATA;
VMMouseProto_SendCmd(&vmpc);
packetInfo = vmpc.out.vEax;
pvmmouseInput->Flags = (packetInfo & 0xffff0000) >> 16;
pvmmouseInput->Buttons = (packetInfo & 0x0000ffff);
/* Note that Z is always signed, and X/Y are signed in relative mode. */
pvmmouseInput->X = (int)vmpc.out.vEbx;
pvmmouseInput->Y = (int)vmpc.out.vEcx;
pvmmouseInput->Z = (int)vmpc.out.vEdx;
/*
* Return number of packets (including this one) in queue.
*/
return (numWords >> 2);
}
/*
*----------------------------------------------------------------------------
*
* VMMouseClient_RequestRelative --
*
* Request that the host switch to posting relative packets. It's just
* advisory, so we make no guarantees about if/when the switch will
* happen.
*
* Results:
* None.
*
* Side effects:
* Host may start posting relative packets in the near future.
*
*----------------------------------------------------------------------------
*/
void
VMMouseClient_RequestRelative(void)
{
VMMouseProtoCmd vmpc;
VMwareLog(("VMMouseClient: requesting relative mode\n"));
vmpc.in.vEbx = VMMOUSE_CMD_REQUEST_RELATIVE;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
VMMouseProto_SendCmd(&vmpc);
}
/*
*----------------------------------------------------------------------------
*
* VMMouseClient_RequestAbsolute --
*
* Request that the host switch to posting absolute packets. It's just
* advisory, so we make no guarantees about if/when the switch will
* happen.
*
* Results:
* None.
*
* Side effects:
* Host may start posting absolute packets in the near future.
*
*----------------------------------------------------------------------------
*/
void
VMMouseClient_RequestAbsolute(void)
{
VMMouseProtoCmd vmpc;
VMwareLog(("VMMouseClient: requesting absolute mode\n"));
vmpc.in.vEbx = VMMOUSE_CMD_REQUEST_ABSOLUTE;
vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
VMMouseProto_SendCmd(&vmpc);
}