xenocara/driver/xf86-input-vmmouse/src/vmmouse.c

1395 lines
35 KiB
C

/*
* 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
#include <stdio.h>
#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 "xf86Priv.h"
#include "compiler.h"
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
#include <xserver-properties.h>
#include "exevents.h"
#endif
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 18
#define LogMessageVerbSigSafe xf86MsgVerb
#endif
#include "xisb.h"
#include "mipointer.h"
#ifndef HAVE_XORG_SERVER_1_5_0
#include <xf86_ansic.h>
#include <xf86_libc.h>
#endif
/*****************************************************************************
* Local Headers
****************************************************************************/
#include "vmmouse_client.h"
/*
* This is the only way I know to turn a #define of an integer constant into
* a constant string.
*/
#define VMW_INNERSTRINGIFY(s) #s
#define VMW_STRING(str) VMW_INNERSTRINGIFY(str)
/*
* So that the file compiles unmodified when dropped into an xfree source tree.
*/
#ifndef XORG_VERSION_CURRENT
#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT
#endif
/*
* Version constants
*/
#define VMMOUSE_DRIVER_VERSION \
(PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL)
#define VMMOUSE_DRIVER_VERSION_STRING \
VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \
"." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL)
/*
* Standard four digit version string expected by VMware Tools installer.
* As the driver's version is only {major, minor, patchlevel},
* The fourth digit may describe the commit number relative to the
* last version tag as output from `git describe`
*/
#ifdef __GNUC__
#ifdef VMW_SUBPATCH
const char vm_mouse_version[] __attribute__((section(".modinfo"),unused)) =
"version=" VMMOUSE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH);
#else
const char vm_mouse_version[] __attribute__((section(".modinfo"),unused)) =
"version=" VMMOUSE_DRIVER_VERSION_STRING ".0";
#endif /*VMW_SUBPATCH*/
#endif
/*****************************************************************************
* static function header
****************************************************************************/
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
static int VMMousePreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
#else
static InputInfoPtr VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags);
static void VMMouseCloseProc(InputInfoPtr pInfo);
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);
#endif
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 int VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control);
static void VMMouseReadInput(InputInfoPtr pInfo);
static int VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode);
static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
/******************************************************************************
* Definitions
*****************************************************************************/
typedef struct {
int screenNum;
Bool vmmouseAvailable;
VMMOUSE_INPUT_DATA vmmousePrevInput;
Bool isCurrRelative;
Bool absoluteRequested;
} VMMousePrivRec, *VMMousePrivPtr;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
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
};
#endif
InputDriverRec VMMOUSE = {
1,
"vmmouse",
NULL,
VMMousePreInit,
VMMouseUnInit,
NULL
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 11
,
0
#endif
};
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])
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 14
static InputOption*
input_option_new(InputOption *list, char *key, char *value)
{
InputOption *new;
new = calloc(1, sizeof(InputOption));
new->key = key;
new->value = value;
new->next = list;
return new;
}
static void
input_option_free_list(InputOption **opts)
{
InputOption *tmp = *opts;
while(*opts)
{
tmp = (*opts)->next;
free((*opts)->key);
free((*opts)->value);
free((*opts));
*opts = tmp;
}
}
#endif
static int
VMMouseInitPassthru(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
{
InputAttributes *attrs = NULL;
InputOption *input_options = NULL;
pointer options;
DeviceIntPtr dev;
int rc;
options = xf86OptionListDuplicate(pInfo->options);
options = xf86ReplaceStrOption(options, "Driver", "mouse");
while(options) {
input_options = input_option_new(input_options,
xf86OptionName(options),
xf86OptionValue(options));
options = xf86NextOption(options);
}
rc = NewInputDeviceRequest(input_options, attrs, &dev);
input_option_free_list(&input_options);
return rc;
}
#else /* if ABI_XINPUT_VERSION < 12 */
static InputInfoPtr
VMMouseInitPassthru(InputDriverPtr drv, IDevPtr dev, int flags)
{
InputDriverRec *passthruMouse;
passthruMouse = (InputDriverRec *)LoaderSymbol("MOUSE");
if(passthruMouse != NULL) {
return (passthruMouse->PreInit)(drv, dev, flags);
} else {
return NULL;
}
}
#endif
/*
*----------------------------------------------------------------------
*
* 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
*
*----------------------------------------------------------------------
*/
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
static int
VMMouseNewPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
static InputInfoPtr
VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
InputInfoPtr pInfo;
#ifndef NO_MOUSE_MODULE
{
OSMouseInfoPtr osInfo = NULL;
/*
* let Xserver init the mouse first
*/
osInfo = xf86OSMouseInit(0);
if (!osInfo)
return FALSE;
}
#endif
/*
* enable hardware access
*/
if (!xorgHWAccess) {
if (xf86EnableIO())
xorgHWAccess = TRUE;
else
return NULL;
}
/*
* try to enable vmmouse here
*/
if (!VMMouseClient_Enable()) {
/*
* vmmouse failed
* Fall back to normal mouse module
*/
xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
return VMMouseInitPassthru(drv, dev, flags);
} else {
/*
* vmmouse is available
*/
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))) {
return NULL;
}
pInfo->name = dev->identifier;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
pInfo->motion_history_proc = xf86GetMotionEvents;
#endif
pInfo->close_proc = VMMouseCloseProc;
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;
pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
/* Collect the options, and process the common options. */
xf86CollectInputOptions(pInfo, NULL, NULL);
xf86ProcessCommonOptions(pInfo, pInfo->options);
if (VMMouseNewPreInit(drv, pInfo, flags) == Success)
pInfo->flags |= XI86_CONFIGURED;
return pInfo;
}
static int
VMMouseNewPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
#else /* if ABI_XINPUT_VERSION >= 12 */
static int
VMMousePreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
#endif
{
MouseDevPtr pMse = NULL;
VMMousePrivPtr mPriv = NULL;
int rc = Success;
/* Enable hardware access. */
if (!xorgHWAccess) {
if (xf86EnableIO())
xorgHWAccess = TRUE;
else {
rc = BadValue;
goto error;
}
}
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
/* For ABI < 12, we need to return the wrapped driver's pInfo (see
* above). ABI 12, we call NIDR and are done */
if (!VMMouseClient_Enable()) {
xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
return VMMouseInitPassthru(drv, pInfo, flags);
} else {
xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n");
VMMouseClient_Disable();
}
#endif
mPriv = calloc (1, sizeof (VMMousePrivRec));
if (!mPriv) {
rc = BadAlloc;
goto error;
}
mPriv->absoluteRequested = FALSE;
mPriv->vmmouseAvailable = TRUE;
/* Settup the pInfo */
pInfo->type_name = XI_MOUSE;
pInfo->device_control = VMMouseDeviceControl;
pInfo->read_input = VMMouseReadInput;
pInfo->control_proc = VMMouseControlProc;
pInfo->switch_mode = VMMouseSwitchMode;
/* Allocate the MouseDevRec and initialise it. */
if (!(pMse = calloc(sizeof(MouseDevRec), 1))) {
rc = BadAlloc;
goto error;
}
pInfo->private = pMse;
pMse->Ctrl = MouseCtrl;
pMse->PostEvent = VMMousePostEvent;
pMse->CommonOptions = MouseCommonOptions;
pMse->mousePriv = mPriv;
/* 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);
rc = BadValue;
goto error;
}
}
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);
return Success;
error:
pInfo->private = NULL;
if (mPriv)
free(mPriv);
if (pMse)
free(pMse);
return rc;
}
/*
*----------------------------------------------------------------------
*
* 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;
Bool mouseMoved = FALSE;
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 (mPriv->isCurrRelative) {
mouseMoved = dx || dy;
} else {
mouseMoved = (dx != mPriv->vmmousePrevInput.X) ||
(dy != mPriv->vmmousePrevInput.Y) ||
(mPriv->vmmousePrevInput.Flags & VMMOUSE_MOVE_RELATIVE);
}
if (mouseMoved) {
#ifdef CALL_CONVERSION_PROC
/*
* Xservers between 1.3.99.0 - 1.4.0.90 do not call conversion_proc, so
* we need to do the conversion from device to screen space.
*/
VMMouseConvertProc(pInfo, 0, 2, dx, dy, 0, 0, 0, 0, &dx, &dy);
#endif
xf86PostMotionEvent(pInfo->dev, !mPriv->isCurrRelative, 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->isCurrRelative)
dx = dz;
else
dx += dz;
dz = 0;
}
break;
case MSE_MAPTOY:
if (dz != 0) {
if(mPriv->isCurrRelative)
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->isCurrRelative)
VMMouseDoPostEvent(pInfo, buttons, 0, 0);
else
VMMouseDoPostEvent(pInfo, buttons, dx, dy);
}
}
/*
*----------------------------------------------------------------------
*
* FlushButtons --
*
* FlushButtons -- reset button states.
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
static void
FlushButtons(MouseDevPtr pMse)
{
pMse->lastButtons = 0;
}
/*
*----------------------------------------------------------------------
*
* 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;
char *s;
pMse = pInfo->private;
pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
if (!pMse->buttons) {
pMse->buttons = MSE_DFLTBUTTONS;
}
/*
* "emulate3Buttons" and "Drag Lock" is not supported
*/
/*
* Process option for ZAxisMapping
*/
s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5");
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);
free(msg);
} else {
xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n",
pInfo->name, s);
}
}
}
/*
*----------------------------------------------------------------------
*
* 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, InputInfoPtr pInfo, int flags)
{
MouseDevPtr pMse = pInfo->private;
xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n");
if (pMse) {
VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
free(mPriv);
}
xf86DeleteInput(pInfo, flags);
}
/*
*----------------------------------------------------------------------
*
* 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;
unsigned char map[MSE_MAXBUTTONS + 1];
int i;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
Atom btn_labels[MSE_MAXBUTTONS] = {0};
Atom axes_labels[2] = { 0, 0 };
#endif
pInfo = device->public.devicePrivate;
pMse = pInfo->private;
pMse->device = device;
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;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
/* other buttons are unknown */
#ifdef ABS_VALUATOR_AXES
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
#else
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
#endif /* ABS_VALUATOR_AXES */
#endif
InitPointerDeviceStruct((DevicePtr)device, map,
min(pMse->buttons, MSE_MAXBUTTONS),
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
btn_labels,
#endif
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
miPointerGetMotionEvents,
#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
GetMotionHistory,
#endif
pMse->Ctrl,
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
miPointerGetMotionBufferSize()
#else
GetMotionHistorySize(), 2
#endif
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
, axes_labels
#endif
);
/* X valuator */
#ifdef ABS_VALUATOR_AXES
xf86InitValuatorAxisStruct(device, 0,
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
axes_labels[0],
#endif
0, 65535, 10000, 0, 10000
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
, Absolute
#endif
);
#else
xf86InitValuatorAxisStruct(device, 0,
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
axes_labels[0],
#endif
0, -1, 1, 0, 1
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
, Relative
#endif
);
#endif
xf86InitValuatorDefaults(device, 0);
/* Y valuator */
#ifdef ABS_VALUATOR_AXES
xf86InitValuatorAxisStruct(device, 1,
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
axes_labels[1],
#endif
0, 65535, 10000, 0, 10000
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
, Absolute
#endif
);
#else
xf86InitValuatorAxisStruct(device, 1,
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
axes_labels[1],
#endif
0, -1, 1, 0, 1
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
, Relative
#endif
);
#endif
xf86InitValuatorDefaults(device, 1);
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
xf86MotionHistoryAllocate(pInfo);
#endif
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;
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;
mPriv->absoluteRequested = 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;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) * 100 + GET_ABI_MINOR(ABI_XINPUT_VERSION) >= 1901
case DEVICE_ABORT:
if (pInfo->fd != -1) {
VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
if( mPriv->vmmouseAvailable )
VMMouseClient_Disable();
break;
}
#endif
}
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;
if (!mPriv->absoluteRequested) {
/*
* We can request for absolute mode, but it depends on
* host whether it will send us absolute or relative
* position.
*/
VMMouseClient_RequestAbsolute();
mPriv->absoluteRequested = TRUE;
LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): vmmouse enable absolute mode\n");
}
/*
* 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;
VMMousePrivPtr mPriv;
int buttons, dx, dy, dz, dw;
VMMOUSE_INPUT_DATA vmmouseInput;
int numPackets;
pMse = pInfo->private;
mPriv = (VMMousePrivPtr)pMse->mousePriv;
while((numPackets = VMMouseClient_GetInput(&vmmouseInput))){
int ps2Buttons = 0;
if (numPackets == VMMOUSE_ERROR) {
VMMouseClient_Disable();
VMMouseClient_Enable();
VMMouseClient_RequestAbsolute();
LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): re-requesting absolute mode after reset\n");
break;
}
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;
/*
* Get the per package relative or absolute information.
*/
mPriv->isCurrRelative = vmmouseInput.Flags & VMMOUSE_MOVE_RELATIVE;
/* post an event */
pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
mPriv->vmmousePrevInput = vmmouseInput;
}
}
/*
*----------------------------------------------------------------------
*
* VMMouseControlProc --
* This function is unused
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
static int
VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control)
{
xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n");
return (Success);
}
/*
*----------------------------------------------------------------------
*
* VMMouseCloseProc --
* This function is unused
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
static void
VMMouseCloseProc(InputInfoPtr pInfo)
{
xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n");
}
#endif
/*
*----------------------------------------------------------------------
*
* 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
*
*----------------------------------------------------------------------
*/
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
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->isCurrRelative) {
*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;
}
#endif
#ifdef XFree86LOADER
/*
*----------------------------------------------------------------------
*
* 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;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
xf86LoaderReqSymLists(reqSymbols, NULL);
#endif
if (!Initialised)
Initialised = TRUE;
xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n");
xf86AddInputDriver(&VMMOUSE, module, 0);
#ifndef NO_MOUSE_MODULE
{
char *name;
/*
* 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);
}
free(name);
}
#endif
return module;
}
static XF86ModuleVersionInfo VMMouseVersionRec = {
"vmmouse",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_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
*/
_X_EXPORT XF86ModuleData vmmouseModuleData = {
&VMMouseVersionRec,
VMMousePlug,
VMMouseUnplug
};
#endif /* XFree86LOADER */