Edit

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

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2017-01-21 18:40:20
    Hash : 145ab603
    Message : Update to xf86-input-vmmouse 13.1.0

  • driver/xf86-input-vmmouse/src/vmmouse.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 */