summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorphilipl <philipl>2006-01-09 19:12:26 +0000
committerphilipl <philipl>2006-01-09 19:12:26 +0000
commitee148a2f8ef97557ec2db501295ed8227699d2bf (patch)
tree9c227732c96ce30145730faabacf6a85bb95779c /src
Initial release of the vmmouse driver for VMware virtual machines.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am36
-rw-r--r--src/vmmouse.c1173
-rw-r--r--src/vmmouse_client.c337
-rw-r--r--src/vmmouse_client.h73
-rw-r--r--src/vmmouse_defs.h66
-rw-r--r--src/vmmouse_proto.c145
-rw-r--r--src/vmmouse_proto.h121
7 files changed, 1951 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..9451d8f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,36 @@
+# Copyright 2005 Adam Jackson.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 (including the next
+# paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON 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.
+
+
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+
+INCLUDES = -I$(srcdir)
+
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c @DRIVER_NAME@_defs.h \
+ @DRIVER_NAME@_client.c @DRIVER_NAME@_client.h \
+ @DRIVER_NAME@_proto.c @DRIVER_NAME@_proto.h
+
diff --git a/src/vmmouse.c b/src/vmmouse.c
new file mode 100644
index 0000000..76f3144
--- /dev/null
+++ b/src/vmmouse.c
@@ -0,0 +1,1173 @@
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ * Copyright 1993 by David Dawes <dawes@xfree86.org>
+ * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+ * Copyright 1994-2002 by The XFree86 Project, Inc.
+ * Copyright 2002 by Paul Elliott
+ * Copyright 2002-2006 by VMware, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the names of copyright holders not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The copyright holders
+ * make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * vmmouse.c --
+ *
+ * This is a modified version of the mouse input driver
+ * provided in Xserver/hw/xfree86/input/mouse/mouse.c
+ *
+ * Although all data is read using the vmmouse protocol, notification
+ * is still done through the PS/2 port, so all the basic code for
+ * interacting with the port is retained.
+ *
+ */
+
+
+/*****************************************************************************
+ * Standard Headers
+ ****************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+
+#include "xf86.h"
+
+#ifdef XINPUT
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "extinit.h"
+#else
+#include "inputstr.h"
+#endif
+
+#include "xf86Xinput.h"
+#include "xf86_OSproc.h"
+#include "xf86OSmouse.h"
+#include "xf86_ansic.h"
+#include "compiler.h"
+
+#include "xisb.h"
+#include "mipointer.h"
+
+/*****************************************************************************
+ * Local Headers
+ ****************************************************************************/
+#include "vmmouse_client.h"
+
+/*
+ * Version constants
+ */
+#define VMMOUSE_MAJOR_VERSION 12
+#define VMMOUSE_MINOR_VERSION 3
+#define VMMOUSE_PATCHLEVEL 0
+
+/*****************************************************************************
+ * static function header
+ ****************************************************************************/
+#ifdef XFree86LOADER
+static const OptionInfoRec *VMMouseAvailableOptions(void *unused);
+#endif
+static InputInfoPtr VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+static void VMMouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+static void MouseCommonOptions(InputInfoPtr pInfo);
+static void GetVMMouseMotionEvent(InputInfoPtr pInfo);
+static void VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw);
+static void VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy);
+static Bool VMMouseDeviceControl(DeviceIntPtr device, int mode);
+static void VMMouseCloseProc(LocalDevicePtr local);
+static int VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control);
+static void VMMouseReadInput(InputInfoPtr pInfo);
+static int VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode);
+static Bool VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y);
+static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+typedef struct {
+ int screenNum;
+ Bool vmmouseAvailable;
+ Bool relative;
+} VMMousePrivRec, *VMMousePrivPtr;
+
+static const char *reqSymbols[] = {
+ "InitPointerDeviceStruct",
+ "LoaderSymbol",
+ "LoadSubModule",
+ "miPointerGetMotionBufferSize",
+ "miPointerGetMotionEvents",
+ "screenInfo",
+ "Xcalloc",
+ "xf86AddEnabledDevice",
+ "xf86AddInputDriver",
+ "xf86AddModuleInfo",
+ "xf86AllocateInput",
+ "xf86BlockSIGIO",
+ "xf86CloseSerial",
+ "xf86CollectInputOptions",
+ "xf86ffs",
+ "xf86FlushInput",
+ "xf86GetAllowMouseOpenFail",
+ "xf86GetMotionEvents",
+ "xf86InitValuatorAxisStruct",
+ "xf86InitValuatorDefaults",
+ "xf86LoaderCheckSymbol",
+ "xf86MotionHistoryAllocate",
+ "xf86Msg",
+ "xf86NameCmp",
+ "xf86OpenSerial",
+ "xf86OSMouseInit",
+ "xf86PostButtonEvent",
+ "xf86PostMotionEvent",
+ "xf86ProcessCommonOptions",
+ "xf86RemoveEnabledDevice",
+ "xf86SetIntOption",
+ "xf86SetStrOption",
+ "xf86sprintf",
+ "xf86sscanf",
+ "xf86UnblockSIGIO",
+ "xf86usleep",
+ "xf86XInputSetScreen",
+ "Xfree",
+ "XisbBlockDuration",
+ "XisbFree",
+ "XisbNew",
+ "XisbRead",
+ "Xstrdup",
+ NULL
+};
+
+InputDriverRec VMMOUSE = {
+ 1,
+ "vmmouse",
+ NULL,
+ VMMousePreInit,
+ VMMouseUnInit,
+ NULL,
+ 0
+};
+
+typedef enum {
+ OPTION_ALWAYS_CORE,
+ OPTION_SEND_CORE_EVENTS,
+ OPTION_CORE_POINTER,
+ OPTION_SEND_DRAG_EVENTS,
+ OPTION_HISTORY_SIZE,
+ OPTION_DEVICE,
+ OPTION_PROTOCOL,
+ OPTION_BUTTONS,
+ OPTION_EMULATE_3_BUTTONS,
+ OPTION_EMULATE_3_TIMEOUT,
+ OPTION_CHORD_MIDDLE,
+ OPTION_FLIP_XY,
+ OPTION_INV_X,
+ OPTION_INV_Y,
+ OPTION_ANGLE_OFFSET,
+ OPTION_Z_AXIS_MAPPING,
+ OPTION_SAMPLE_RATE,
+ OPTION_RESOLUTION,
+ OPTION_EMULATE_WHEEL,
+ OPTION_EMU_WHEEL_BUTTON,
+ OPTION_EMU_WHEEL_INERTIA,
+ OPTION_X_AXIS_MAPPING,
+ OPTION_Y_AXIS_MAPPING,
+ OPTION_AUTO_SOFT,
+ OPTION_DRAGLOCKBUTTONS
+} MouseOpts;
+
+/*
+ * Define the acceptable mouse options
+ * Currently not all of those options are supported
+ *
+ */
+static const OptionInfoRec mouseOptions[] = {
+ { OPTION_ALWAYS_CORE, "AlwaysCore", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SEND_CORE_EVENTS, "SendCoreEvents", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_CORE_POINTER, "CorePointer", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SEND_DRAG_EVENTS, "SendDragEvents", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_HISTORY_SIZE, "HistorySize", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_DEVICE, "Device", OPTV_STRING, {0}, FALSE },
+ { OPTION_PROTOCOL, "Protocol", OPTV_STRING, {0}, FALSE },
+ { OPTION_BUTTONS, "Buttons", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMULATE_3_BUTTONS, "Emulate3Buttons",OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_EMULATE_3_TIMEOUT, "Emulate3Timeout",OPTV_INTEGER, {0}, FALSE },
+ { OPTION_CHORD_MIDDLE, "ChordMiddle", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_FLIP_XY, "FlipXY", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_INV_X, "InvX", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_INV_Y, "InvY", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_ANGLE_OFFSET, "AngleOffset", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_Z_AXIS_MAPPING, "ZAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_SAMPLE_RATE, "SampleRate", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_RESOLUTION, "Resolution", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMULATE_WHEEL, "EmulateWheel", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_EMU_WHEEL_BUTTON, "EmulateWheelButton", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMU_WHEEL_INERTIA, "EmulateWheelInertia", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_X_AXIS_MAPPING, "XAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_Y_AXIS_MAPPING, "YAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_AUTO_SOFT, "AutoSoft", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_DRAGLOCKBUTTONS, "DragLockButtons",OPTV_STRING, {0}, FALSE },
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
+};
+
+static char reverseMap[32] = { 0, 4, 2, 6, 1, 5, 3, 7,
+ 8, 12, 10, 14, 9, 13, 11, 15,
+ 16, 20, 18, 22, 17, 21, 19, 23,
+ 24, 28, 26, 30, 25, 29, 27, 31};
+
+#define reverseBits(map, b) (((b) & ~0x0f) | map[(b) & 0x0f])
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePreInit --
+ * This function collect all the information that is necessary to
+ * determine the configuration of the hardware and to prepare the
+ * device for being used
+ *
+ * Results:
+ * An InputInfoPtr object which points to vmmouse's information,
+ * if the absolute pointing device available
+ * Otherwise, an InputInfoPtr of regular mouse
+ *
+ * Side effects:
+ * VMMouse was initialized with necessary information
+ *
+ *----------------------------------------------------------------------
+ */
+
+static InputInfoPtr
+VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ OSMouseInfoPtr osInfo = NULL;
+
+ /*
+ * let Xserver init the mouse first
+ */
+ osInfo = xf86OSMouseInit(0);
+ if (!osInfo)
+ return FALSE;
+
+ mPriv = xcalloc (1, sizeof (VMMousePrivRec));
+
+
+ if (!mPriv) {
+ return NULL;
+ }
+ /*
+ * try to enable vmmouse here
+ */
+ if (!VMMouseClient_Enable()) {
+ /*
+ * vmmouse failed
+ * Fall back to normal mouse module
+ */
+ InputDriverRec *passthruMouse;
+ xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
+ mPriv->vmmouseAvailable = FALSE;
+ passthruMouse = (InputDriverRec *)LoaderSymbol("MOUSE");
+ xfree(mPriv);
+ if(passthruMouse != NULL){
+ return (passthruMouse->PreInit)(drv, dev, flags);
+ } else {
+ return NULL;
+ }
+
+ } else {
+ /*
+ * vmmouse is available
+ */
+ mPriv->vmmouseAvailable = TRUE;
+ xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n");
+ /*
+ * Disable the absolute pointing device for now
+ * It will be enabled during DEVICE_ON phase
+ */
+ VMMouseClient_Disable();
+ }
+
+ if (!(pInfo = xf86AllocateInput(drv, 0))) {
+ xfree(mPriv);
+ return NULL;
+ }
+
+ /* Settup the pInfo */
+ pInfo->name = dev->identifier;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+ pInfo->device_control = VMMouseDeviceControl;
+ pInfo->read_input = VMMouseReadInput;
+ pInfo->motion_history_proc = xf86GetMotionEvents;
+ pInfo->control_proc = VMMouseControlProc;
+ pInfo->close_proc = VMMouseCloseProc;
+ pInfo->switch_mode = VMMouseSwitchMode;
+ pInfo->conversion_proc = VMMouseConvertProc;
+ pInfo->reverse_conversion_proc = NULL;
+ pInfo->fd = -1;
+ pInfo->dev = NULL;
+ pInfo->private_flags = 0;
+ pInfo->always_core_feedback = 0;
+ pInfo->conf_idev = dev;
+
+ /* Allocate the MouseDevRec and initialise it. */
+ if (!(pMse = xcalloc(sizeof(MouseDevRec), 1))) {
+ xfree(mPriv);
+ return pInfo;
+ }
+
+ pInfo->private = pMse;
+ pMse->Ctrl = MouseCtrl;
+ pMse->PostEvent = VMMousePostEvent;
+ pMse->CommonOptions = MouseCommonOptions;
+ pMse->mousePriv = mPriv;
+
+
+ /* Collect the options, and process the common options. */
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ /* Check if the device can be opened. */
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1) {
+ if (xf86GetAllowMouseOpenFail())
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ else {
+ xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
+ if (pMse->mousePriv)
+ xfree(pMse->mousePriv);
+ xfree(pMse);
+ pInfo->private = NULL;
+ return pInfo;
+ }
+ }
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+
+ /* Process the options */
+ pMse->CommonOptions(pInfo);
+
+ /* set up the current screen num */
+ mPriv->screenNum = xf86SetIntOption(pInfo->options, "ScreenNumber", 0);
+
+ pInfo->flags |= XI86_CONFIGURED;
+ return pInfo;
+}
+
+#ifdef XFree86LOADER
+static const OptionInfoRec *
+VMMouseAvailableOptions(void *unused)
+{
+ return (mouseOptions);
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MouseCtrl --
+ * Alter the control paramters for the mouse.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+
+ pInfo = device->public.devicePrivate;
+ pMse = pInfo->private;
+
+#ifdef EXTMOUSEDEBUG
+ xf86Msg(X_INFO, "VMMOUSE(0): MouseCtrl pMse=%p\n", pMse);
+#endif
+
+ pMse->num = ctrl->num;
+ pMse->den = ctrl->den;
+ pMse->threshold = ctrl->threshold;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseDoPostEvent --
+ * Post the mouse button event and mouse motion event to Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Mouse location and button status was updated
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ int truebuttons;
+ int id, change;
+
+ pMse = pInfo->private;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+
+ /*
+ * The following truebuttons/reverseBits and lastButtons are
+ * used to compare the current buttons and the previous buttons
+ * to find the button changes during two mouse events
+ */
+ truebuttons = buttons;
+
+ buttons = reverseBits(reverseMap, buttons);
+
+ if (dx || dy) {
+ xf86PostMotionEvent(pInfo->dev, !mPriv->relative, 0, 2, dx, dy);
+ }
+
+ if (truebuttons != pMse->lastButtons) {
+ change = buttons ^ reverseBits(reverseMap, pMse->lastButtons);
+ while (change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(pInfo->dev, 0, id,
+ (buttons & (1 << (id - 1))), 0, 0);
+ }
+ pMse->lastButtons = truebuttons;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePostEvent --
+ * Prepare the mouse status according to the Z axis mapping
+ * before we post the event to Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Buttons was updated according to Z axis mapping
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw)
+{
+ MouseDevPtr pMse;
+ int zbutton = 0;
+ VMMousePrivPtr mPriv;
+
+ pMse = pInfo->private;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ /* Map the Z axis movement. */
+ /* XXX Could this go in the conversion_proc? */
+ switch (pMse->negativeZ) {
+ case MSE_NOZMAP: /* do nothing */
+ break;
+ case MSE_MAPTOX:
+ if (dz != 0) {
+ if(mPriv->relative)
+ dx = dz;
+ else
+ dx += dz;
+ dz = 0;
+ }
+ break;
+ case MSE_MAPTOY:
+ if (dz != 0) {
+ if(mPriv->relative)
+ dy = dz;
+ else
+ dy += dz;
+ dz = 0;
+ }
+ break;
+ default: /* buttons */
+ buttons &= ~(pMse->negativeZ | pMse->positiveZ
+ | pMse->negativeW | pMse->positiveW);
+ if (dw < 0 || dz < -1) {
+ zbutton = pMse->negativeW;
+ }
+ else if (dz < 0) {
+ zbutton = pMse->negativeZ;
+ }
+ else if (dw > 0 || dz > 1) {
+ zbutton = pMse->positiveW;
+ }
+ else if (dz > 0) {
+ zbutton = pMse->positiveZ;
+ }
+ buttons |= zbutton;
+ dz = 0;
+ break;
+ }
+
+ VMMouseDoPostEvent(pInfo, buttons, dx, dy);
+
+ /*
+ * If dz has been mapped to a button `down' event, we need to cook up
+ * a corresponding button `up' event.
+ */
+ if (zbutton) {
+ buttons &= ~zbutton;
+ if(mPriv->relative)
+ VMMouseDoPostEvent(pInfo, buttons, 0, 0);
+ else
+ VMMouseDoPostEvent(pInfo, buttons, dx, dy);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FlushButtons --
+ *
+ * FlushButtons -- send button up events for sanity. It is called
+ * during DEVICE_ON in VMMouseDeviceControl
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+FlushButtons(MouseDevPtr pMse)
+{
+
+ /* If no button down is pending xf86PostButtonEvent()
+ * will discard them. So we are on the safe side. */
+
+ int i, blocked;
+
+ pMse->lastButtons = 0;
+
+ blocked = xf86BlockSIGIO ();
+ for (i = 1; i <= 5; i++)
+ xf86PostButtonEvent(pMse->device,0,i,0,0,0);
+ xf86UnblockSIGIO (blocked);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MouseCommonOptions --
+ * Process acceptable mouse options. Currently we only process
+ * "Buttons" and "ZAxisMapping" options.
+ * More options can be added later on
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * The buttons was setup according to the options
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MouseCommonOptions(InputInfoPtr pInfo)
+{
+ MouseDevPtr pMse;
+ MessageType from = X_DEFAULT;
+ char *s;
+ int origButtons;
+
+ pMse = pInfo->private;
+
+ pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
+ from = X_CONFIG;
+ if (!pMse->buttons) {
+ pMse->buttons = MSE_DFLTBUTTONS;
+ from = X_DEFAULT;
+ }
+ origButtons = pMse->buttons;
+
+ /*
+ * "emulate3Buttons" and "Drag Lock" is not supported
+ */
+
+ /*
+ * Process option for ZAxisMapping
+ */
+ s = xf86SetStrOption(pInfo->options, "ZAxisMapping", NULL);
+ if (s) {
+ int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+ char *msg = NULL;
+
+ if (!xf86NameCmp(s, "x")) {
+ pMse->negativeZ = pMse->positiveZ = MSE_MAPTOX;
+ pMse->negativeW = pMse->positiveW = MSE_MAPTOX;
+ msg = xstrdup("X axis");
+ } else if (!xf86NameCmp(s, "y")) {
+ pMse->negativeZ = pMse->positiveZ = MSE_MAPTOY;
+ pMse->negativeW = pMse->positiveW = MSE_MAPTOY;
+ msg = xstrdup("Y axis");
+ } else if (sscanf(s, "%d %d %d %d", &b1, &b2, &b3, &b4) >= 2 &&
+ b1 > 0 && b1 <= MSE_MAXBUTTONS &&
+ b2 > 0 && b2 <= MSE_MAXBUTTONS) {
+ msg = xstrdup("buttons XX and YY");
+ if (msg)
+ sprintf(msg, "buttons %d and %d", b1, b2);
+ pMse->negativeZ = pMse->negativeW = 1 << (b1-1);
+ pMse->positiveZ = pMse->positiveW = 1 << (b2-1);
+ if (b1 > pMse->buttons) pMse->buttons = b1;
+ if (b2 > pMse->buttons) pMse->buttons = b2;
+
+ /*
+ * Option "ZAxisMapping" "N1 N2 N3 N4" not supported
+ */
+ pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
+ } else {
+ pMse->negativeZ = pMse->positiveZ = MSE_NOZMAP;
+ pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
+ }
+ if (msg) {
+ xf86Msg(X_CONFIG, "%s: ZAxisMapping: %s\n", pInfo->name, msg);
+ xfree(msg);
+ } else {
+ xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n",
+ pInfo->name, s);
+ }
+ }
+
+ /*
+ * Emulatewheel is not supported
+ */
+ if (origButtons != pMse->buttons)
+ from = X_CONFIG;
+
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseUnInit --
+ * This function was supposed to be called by Xserver to do Un-Init.
+ * But it was unused now
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseUnInit(InputDriverPtr drv, LocalDevicePtr local, int flags)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseDeviceControl --
+ * This function was called by Xserver during DEVICE_INIT, DEVICE_ON,
+ * DEVICE_OFF and DEVICE_CLOSE phase
+ *
+ * Results:
+ * TRUE, if sucessful
+ * FALSE, if failed
+ *
+ * Side effects:
+ * Absolute pointing device is enabled during DEVICE_ON
+ * Absolute pointing device is disabled during DEVICE_OFF
+ * and DEVICE_CLOSE
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+VMMouseDeviceControl(DeviceIntPtr device, int mode)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ unsigned char map[MSE_MAXBUTTONS + 1];
+ int i;
+
+ pInfo = device->public.devicePrivate;
+ pMse = pInfo->private;
+ pMse->device = device;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+
+ switch (mode){
+ case DEVICE_INIT:
+ device->public.on = FALSE;
+ /*
+ * [KAZU-241097] We don't know exactly how many buttons the
+ * device has, so setup the map with the maximum number.
+ */
+ for (i = 0; i < MSE_MAXBUTTONS; i++)
+ map[i + 1] = i + 1;
+
+ InitPointerDeviceStruct((DevicePtr)device, map,
+ min(pMse->buttons, MSE_MAXBUTTONS),
+ miPointerGetMotionEvents, pMse->Ctrl,
+ miPointerGetMotionBufferSize());
+
+ /* X valuator */
+ xf86InitValuatorAxisStruct(device, 0, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(device, 0);
+ /* Y valuator */
+ xf86InitValuatorAxisStruct(device, 1, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(device, 1);
+ xf86MotionHistoryAllocate(pInfo);
+
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n");
+#ifdef EXTMOUSEDEBUG
+ xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom,
+ pInfo->name);
+#endif
+ break;
+
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n");
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1)
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ else {
+ pMse->buffer = XisbNew(pInfo->fd, 64);
+ if (!pMse->buffer) {
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ } else {
+ VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ if (mPriv != NULL) {
+ /*
+ * enable absolute pointing device here
+ */
+ if (!VMMouseClient_Enable()) {
+ xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
+ mPriv->vmmouseAvailable = FALSE;
+ device->public.on = FALSE;
+ return FALSE;
+ } else {
+ mPriv->vmmouseAvailable = TRUE;
+ VMMouseClient_RequestAbsolute();
+ mPriv->relative = FALSE;
+ xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n");
+ }
+ }
+ xf86FlushInput(pInfo->fd);
+ xf86AddEnabledDevice(pInfo);
+ }
+ }
+ pMse->lastButtons = 0;
+ device->public.on = TRUE;
+ FlushButtons(pMse);
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n");
+
+ if (pInfo->fd != -1) {
+ VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ if( mPriv->vmmouseAvailable ) {
+ VMMouseClient_Disable();
+ mPriv->vmmouseAvailable = FALSE;
+ }
+
+ xf86RemoveEnabledDevice(pInfo);
+ if (pMse->buffer) {
+ XisbFree(pMse->buffer);
+ pMse->buffer = NULL;
+ }
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ device->public.on = FALSE;
+ usleep(300000);
+ break;
+
+ }
+
+ return Success;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseReadInput --
+ * This function was called by Xserver when there is data available
+ * in the input device
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Input data in regular PS/2 fd was cleared
+ * Real mouse data was read from the absolute pointing device
+ * and posted to Xserver
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseReadInput(InputInfoPtr pInfo)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ int c;
+ int len = 0;
+
+ pMse = pInfo->private;
+ mPriv = pMse->mousePriv;
+
+ /*
+ * First read the bytes in input device to clear the regular PS/2 fd so
+ * we don't get called again.
+ */
+ /*
+ * Set blocking to -1 on the first call because we know there is data to
+ * read. Xisb automatically clears it after one successful read so that
+ * succeeding reads are preceeded by a select with a 0 timeout to prevent
+ * read from blocking indefinitely.
+ */
+ XisbBlockDuration(pMse->buffer, -1);
+ while ((c = XisbRead(pMse->buffer)) >= 0) {
+ len++;
+ /*
+ * regular PS packet consists of 3 bytes
+ * We read 3 bytes to drain the PS/2 packet
+ */
+ if(len < 3) continue;
+ len = 0;
+ /*
+ * Now get the real data from absolute pointing device
+ */
+ GetVMMouseMotionEvent(pInfo);
+ }
+ /*
+ * There maybe still vmmouse data available
+ */
+ GetVMMouseMotionEvent(pInfo);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetVMMouseMotionEvent --
+ * Read all the mouse data available from the absolute
+ * pointing device and post it to the Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Real mouse data was read from the absolute pointing
+ * device and posted to Xserver
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetVMMouseMotionEvent(InputInfoPtr pInfo){
+ MouseDevPtr pMse;
+ int buttons, dx, dy, dz, dw;
+ VMMOUSE_INPUT_DATA vmmouseInput;
+ int ps2Buttons = 0;
+
+ pMse = pInfo->private;
+ while(VMMouseClient_GetInput(&vmmouseInput)){
+ if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON)
+ ps2Buttons |= 0x04; /* Middle*/
+ if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON)
+ ps2Buttons |= 0x02; /* Right*/
+ if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON)
+ ps2Buttons |= 0x01; /* Left*/
+
+ buttons = (ps2Buttons & 0x04) >> 1 | /* Middle */
+ (ps2Buttons & 0x02) >> 1 | /* Right */
+ (ps2Buttons & 0x01) << 2; /* Left */
+
+ dx = vmmouseInput.X;
+ dy = vmmouseInput.Y;
+ dz = (char)vmmouseInput.Z;
+ dw = 0;
+ /* post an event */
+ pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseControlProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n");
+ return (Success);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseCloseProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseCloseProc(LocalDevicePtr local)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseSwitchProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n");
+ return (Success);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseConvertProc --
+ * This function was called by Xserver to convert valuators to X and Y
+ *
+ * Results:
+ * TRUE
+ *
+ * Side effects:
+ * X and Y was converted according to current Screen dimension
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ double factorX, factorY;
+
+ pMse = pInfo->private;
+ mPriv = pMse->mousePriv;
+
+ if (first != 0 || num != 2)
+ return FALSE;
+
+ if(mPriv->relative) {
+ *x = v0;
+ *y = v1;
+ } else {
+ factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535;
+ factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535;
+
+ *x = v0 * factorX + 0.5;
+ *y = v1 * factorY + 0.5;
+
+ if (mPriv->screenNum != -1) {
+ xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y);
+ }
+ }
+ return TRUE;
+}
+
+
+#ifdef XFree86LOADER
+ModuleInfoRec VMMouseInfo = {
+ 1,
+ "VMMOUSE",
+ NULL,
+ 0,
+ VMMouseAvailableOptions,
+};
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseUnplug --
+ * This function was called by Xserver when unplug
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseUnplug(pointer p)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePlug --
+ * This function was called when Xserver load vmmouse module. It will
+ * integrate the module infto the XFree86 loader architecutre.
+ *
+ * Results:
+ * TRUE
+ *
+ * Side effects:
+ * Regular mouse module was loaded as a submodule. In case
+ * absolute pointing device is not available, we can always fall back
+ * to the regular mouse module
+ *
+ *----------------------------------------------------------------------
+ */
+
+static pointer
+VMMousePlug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ static Bool Initialised = FALSE;
+ char *name;
+
+ xf86LoaderReqSymLists(reqSymbols, NULL);
+
+ if (!Initialised) {
+ Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+ if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+ xf86AddModuleInfo(&VMMouseInfo, module);
+ }
+
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n");
+ xf86AddInputDriver(&VMMOUSE, module, 0);
+
+ /*
+ * Load the normal mouse module as submodule
+ * If we fail in PreInit later, this allows us to fall back to normal mouse module
+ */
+#ifndef NORMALISE_MODULE_NAME
+ name = xstrdup("mouse");
+#else
+ /* Normalise the module name */
+ name = xf86NormalizeName("mouse");
+#endif
+
+ if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) {
+ LoaderErrorMsg(NULL, name, *errmaj, *errmin);
+ }
+ xfree(name);
+
+ return module;
+}
+
+static XF86ModuleVersionInfo VMMouseVersionRec = {
+ "vmmouse",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ VMMOUSE_MAJOR_VERSION, VMMOUSE_MINOR_VERSION, VMMOUSE_PATCHLEVEL,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0} /* signature, to be patched into the file by a tool */
+};
+
+/*
+ * The variable contains the necessary information to load and initialize the module
+ */
+XF86ModuleData vmmouseModuleData = {
+ &VMMouseVersionRec,
+ VMMousePlug,
+ VMMouseUnplug
+};
+#endif /* XFree86LOADER */
diff --git a/src/vmmouse_client.c b/src/vmmouse_client.c
new file mode 100644
index 0000000..5f27e54
--- /dev/null
+++ b/src/vmmouse_client.c
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ *
+ */
+
+#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;
+ }
+
+ /*
+ * 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);
+
+ pvmmouseInput->X = vmpc.out.vEbx & 0xffff;
+ pvmmouseInput->Y = vmpc.out.vEcx & 0xffff;
+ 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);
+}
diff --git a/src/vmmouse_client.h b/src/vmmouse_client.h
new file mode 100644
index 0000000..b01bf08
--- /dev/null
+++ b/src/vmmouse_client.h
@@ -0,0 +1,73 @@
+/*
+ * 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.h --
+ *
+ * VMware Virtual Mouse Client
+ *
+ * This module provides functions to enable/disable, operate and
+ * process packets via the VMMouse absolute positioning module
+ * hosted in the VMX.
+ *
+ */
+
+#ifndef _VMMOUSE_CLIENT_H_
+#define _VMMOUSE_CLIENT_H_
+
+#include "xf86_OSproc.h"
+
+/*
+ * VMMouse Input packet data structure
+ */
+typedef struct _VMMOUSE_INPUT_DATA {
+ unsigned short Flags;
+ unsigned short Buttons;
+ int X;
+ int Y;
+ int Z;
+} VMMOUSE_INPUT_DATA, *PVMMOUSE_INPUT_DATA;
+
+/*
+ * Public Functions
+ */
+Bool VMMouseClient_Enable(void);
+void VMMouseClient_Disable(void);
+unsigned int VMMouseClient_GetInput(PVMMOUSE_INPUT_DATA pvmmouseInput);
+void VMMouseClient_RequestRelative(void);
+void VMMouseClient_RequestAbsolute(void);
+
+#ifdef VMX86_DEVEL
+#define VMwareLog(args) ErrorF args
+#else
+#define VMwareLog(args)
+#endif
+
+#include "vmmouse_defs.h"
+
+#endif /* _VMMOUSE_CLIENT_H_ */
+
diff --git a/src/vmmouse_defs.h b/src/vmmouse_defs.h
new file mode 100644
index 0000000..8dc769e
--- /dev/null
+++ b/src/vmmouse_defs.h
@@ -0,0 +1,66 @@
+/*
+ * 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_defs.h --
+ *
+ * VMware Virtual Mouse Protocol definitions. These constants
+ * are shared by the host-side VMMouse module and
+ * the guest tools/drivers.
+ *
+ */
+
+#ifndef _VMMOUSE_DEFS_H_
+#define _VMMOUSE_DEFS_H_
+
+/*
+ * Command related defines
+ */
+#define VMMOUSE_CMD_READ_ID 0x45414552
+#define VMMOUSE_CMD_DISABLE 0x000000f5
+#define VMMOUSE_CMD_REQUEST_RELATIVE 0x4c455252
+#define VMMOUSE_CMD_REQUEST_ABSOLUTE 0x53424152
+
+/*
+ * Data related defines
+ */
+#define VMMOUSE_VERSION_ID_STR "JUB4"
+#define VMMOUSE_VERSION_ID 0x3442554a
+
+/*
+ * Device related defines
+ */
+#define VMMOUSE_ERROR 0xffff0000
+
+/*
+ * VMMouse Input button flags
+ */
+#define VMMOUSE_LEFT_BUTTON 0x20
+#define VMMOUSE_RIGHT_BUTTON 0x10
+#define VMMOUSE_MIDDLE_BUTTON 0x08
+
+#endif
diff --git a/src/vmmouse_proto.c b/src/vmmouse_proto.c
new file mode 100644
index 0000000..186c2e8
--- /dev/null
+++ b/src/vmmouse_proto.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 1999-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_proto.c --
+ *
+ * The communication protocol between the guest and the vmmouse
+ * virtual device.
+ */
+
+
+#include "vmmouse_proto.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMMouseProtoInOut --
+ *
+ * Send a low-bandwidth basic request (16 bytes) to vmware, and return its
+ * reply (24 bytes).
+ *
+ * Results:
+ * Host-side response returned in cmd IN/OUT parameter.
+ *
+ * Side effects:
+ * Pokes the communication port.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VMMouseProtoInOut(VMMouseProtoCmd *cmd) // IN/OUT
+{
+#ifdef __x86_64__
+ uint64_t dummy;
+
+ __asm__ __volatile__(
+ "pushq %%rax" "\n\t"
+ "movq 40(%%rax), %%rdi" "\n\t"
+ "movq 32(%%rax), %%rsi" "\n\t"
+ "movq 24(%%rax), %%rdx" "\n\t"
+ "movq 16(%%rax), %%rcx" "\n\t"
+ "movq 8(%%rax), %%rbx" "\n\t"
+ "movq (%%rax), %%rax" "\n\t"
+ "inl %%dx, %%eax" "\n\t" /* NB: There is no inq instruction */
+ "xchgq %%rax, (%%rsp)" "\n\t"
+ "movq %%rdi, 40(%%rax)" "\n\t"
+ "movq %%rsi, 32(%%rax)" "\n\t"
+ "movq %%rdx, 24(%%rax)" "\n\t"
+ "movq %%rcx, 16(%%rax)" "\n\t"
+ "movq %%rbx, 8(%%rax)" "\n\t"
+ "popq (%%rax)"
+ : "=a" (dummy)
+ : "0" (cmd)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ : "rbx", "rcx", "rdx", "rsi", "rdi", "memory"
+ );
+#else
+#ifdef __i386__
+ uint32_t dummy;
+
+ __asm__ __volatile__(
+ "pushl %%eax" "\n\t"
+ "movl 20(%%eax), %%edi" "\n\t"
+ "movl 16(%%eax), %%esi" "\n\t"
+ "movl 12(%%eax), %%edx" "\n\t"
+ "movl 8(%%eax), %%ecx" "\n\t"
+ "movl 4(%%eax), %%ebx" "\n\t"
+ "movl (%%eax), %%eax" "\n\t"
+ "inl %%dx, %%eax" "\n\t"
+ "xchgl %%eax, (%%esp)" "\n\t"
+ "movl %%edi, 20(%%eax)" "\n\t"
+ "movl %%esi, 16(%%eax)" "\n\t"
+ "movl %%edx, 12(%%eax)" "\n\t"
+ "movl %%ecx, 8(%%eax)" "\n\t"
+ "movl %%ebx, 4(%%eax)" "\n\t"
+ "popl (%%eax)"
+ : "=a" (dummy)
+ : "0" (cmd)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ : "ebx", "ecx", "edx", "esi", "edi", "memory"
+ );
+#else
+#error "VMMouse is only supported on x86 and x86-64."
+#endif
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMMouseProto_SendCmd --
+ *
+ * Send a request (16 bytes) to vmware, and synchronously return its
+ * reply (24 bytes).
+ *
+ * Result:
+ * None
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMMouseProto_SendCmd(VMMouseProtoCmd *cmd) // IN/OUT
+{
+ cmd->in.magic = VMMOUSE_PROTO_MAGIC;
+ cmd->in.port = VMMOUSE_PROTO_PORT;
+
+ VMMouseProtoInOut(cmd);
+}
diff --git a/src/vmmouse_proto.h b/src/vmmouse_proto.h
new file mode 100644
index 0000000..fa7dff1
--- /dev/null
+++ b/src/vmmouse_proto.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 1999-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_proto.h --
+ *
+ * The communication protocol between the guest and the vmmouse
+ * virtual device.
+ */
+
+
+#ifndef _VMMOUSE_PROTO_H_
+#define _VMMOUSE_PROTO_H_
+
+#include <stdint.h>
+#include "xf86_libc.h"
+
+#if !defined __i386__ && !defined __x86_64__
+#error The vmmouse protocol is only supported on x86 architectures.
+#endif
+
+#define VMMOUSE_PROTO_MAGIC 0x564D5868
+#define VMMOUSE_PROTO_PORT 0x5658
+
+#define VMMOUSE_PROTO_CMD_GETVERSION 10
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA 39
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS 40
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND 41
+
+#define DECLARE_REG32_STRUCT(_r) \
+ union { \
+ struct { \
+ uint16_t low; \
+ uint16_t high; \
+ } vE##_r##_; \
+ uint32_t vE##_r; \
+ }
+
+#ifdef VM_X86_64
+
+#define DECLARE_REG64_STRUCT(_r) \
+ union { \
+ DECLARE_REG32_STRUCT(_r); \
+ struct { \
+ uint32_t low; \
+ uint32_t high; \
+ } vR##_r##_; \
+ uint64_t vR##_r; \
+ }
+
+#define DECLARE_REG_STRUCT(x) DECLARE_REG64_STRUCT(x)
+
+#else
+
+#define DECLARE_REG_STRUCT(x) DECLARE_REG32_STRUCT(x)
+
+#endif
+
+typedef union {
+ struct {
+ union {
+ uint32_t magic;
+ DECLARE_REG_STRUCT(ax);
+ };
+ union {
+ size_t size;
+ DECLARE_REG_STRUCT(bx);
+ };
+ union {
+ uint16_t command;
+ DECLARE_REG_STRUCT(cx);
+ };
+ union {
+ uint16_t port;
+ DECLARE_REG_STRUCT(dx);
+ };
+ DECLARE_REG_STRUCT(si);
+ DECLARE_REG_STRUCT(di);
+ } in;
+ struct {
+ DECLARE_REG_STRUCT(ax);
+ DECLARE_REG_STRUCT(bx);
+ DECLARE_REG_STRUCT(cx);
+ DECLARE_REG_STRUCT(dx);
+ DECLARE_REG_STRUCT(si);
+ DECLARE_REG_STRUCT(di);
+ } out;
+} VMMouseProtoCmd;
+
+
+void
+VMMouseProto_SendCmd(VMMouseProtoCmd *cmd); // IN/OUT
+
+
+#undef DECLARE_REG_STRUCT
+
+#endif /* _VMMOUSE_PROTO_H_ */