diff options
author | philipl <philipl> | 2006-01-09 19:12:26 +0000 |
---|---|---|
committer | philipl <philipl> | 2006-01-09 19:12:26 +0000 |
commit | ee148a2f8ef97557ec2db501295ed8227699d2bf (patch) | |
tree | 9c227732c96ce30145730faabacf6a85bb95779c /src |
Initial release of the vmmouse driver for VMware virtual machines.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 36 | ||||
-rw-r--r-- | src/vmmouse.c | 1173 | ||||
-rw-r--r-- | src/vmmouse_client.c | 337 | ||||
-rw-r--r-- | src/vmmouse_client.h | 73 | ||||
-rw-r--r-- | src/vmmouse_defs.h | 66 | ||||
-rw-r--r-- | src/vmmouse_proto.c | 145 | ||||
-rw-r--r-- | src/vmmouse_proto.h | 121 |
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_ */ |