1/*
2 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
3 * Copyright 1993 by David Dawes <dawes@xfree86.org>
4 * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
5 * Copyright 1994-2002 by The XFree86 Project, Inc.
6 * Copyright 2002 by Paul Elliott
7 * Copyright 2002-2006 by VMware, Inc.
8 *
9 * Permission to use, copy, modify, distribute, and sell this software and its
10 * documentation for any purpose is hereby granted without fee, provided that
11 * the above copyright notice appear in all copies and that both that
12 * copyright notice and this permission notice appear in supporting
13 * documentation, and that the names of copyright holders not be
14 * used in advertising or publicity pertaining to distribution of the
15 * software without specific, written prior permission.  The copyright holders
16 * make no representations about the suitability of this
17 * software for any purpose.  It is provided "as is" without express or
18 * implied warranty.
19 *
20 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
21 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
24 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
25 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 *
28 */
29
30/*
31 * vmmouse.c --
32 *
33 * 	This is a modified version of the mouse input driver
34 * 	provided in Xserver/hw/xfree86/input/mouse/mouse.c
35 *
36 *      Although all data is read using the vmmouse protocol, notification
37 *      is still done through the PS/2 port, so all the basic code for
38 *      interacting with the port is retained.
39 *
40 */
41
42
43/*****************************************************************************
44 *	Standard Headers
45 ****************************************************************************/
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include <stdio.h>
51#include <X11/X.h>
52#include <X11/Xproto.h>
53
54#include "xf86.h"
55
56#ifdef XINPUT
57#include <X11/extensions/XI.h>
58#include <X11/extensions/XIproto.h>
59#include "extnsionst.h"
60#include "extinit.h"
61#else
62#include "inputstr.h"
63#endif
64
65#include "xf86Xinput.h"
66#include "xf86_OSproc.h"
67#include "xf86OSmouse.h"
68#include "xf86Priv.h"
69#include "compiler.h"
70
71#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
72#include <xserver-properties.h>
73#include "exevents.h"
74#endif
75
76#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 18
77#define LogMessageVerbSigSafe xf86MsgVerb
78#endif
79
80#include "xisb.h"
81#include "mipointer.h"
82
83#ifndef HAVE_XORG_SERVER_1_5_0
84#include <xf86_ansic.h>
85#include <xf86_libc.h>
86#endif
87
88/*****************************************************************************
89 *	Local Headers
90 ****************************************************************************/
91#include "vmmouse_client.h"
92
93/*
94 * This is the only way I know to turn a #define of an integer constant into
95 * a constant string.
96 */
97#define VMW_INNERSTRINGIFY(s) #s
98#define VMW_STRING(str) VMW_INNERSTRINGIFY(str)
99
100/*
101 * So that the file compiles unmodified when dropped into an xfree source tree.
102 */
103#ifndef XORG_VERSION_CURRENT
104#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT
105#endif
106
107/*
108 * Version constants
109 */
110#define VMMOUSE_DRIVER_VERSION \
111   (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL)
112#define VMMOUSE_DRIVER_VERSION_STRING \
113    VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \
114    "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL)
115
116/*
117 * Standard four digit version string expected by VMware Tools installer.
118 * As the driver's version is only  {major, minor, patchlevel},
119 * The fourth digit may describe the commit number relative to the
120 * last version tag as output from `git describe`
121 */
122#ifdef __GNUC__
123#ifdef VMW_SUBPATCH
124const char vm_mouse_version[] __attribute__((section(".modinfo"),unused)) =
125    "version=" VMMOUSE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH);
126#else
127const char vm_mouse_version[] __attribute__((section(".modinfo"),unused)) =
128    "version=" VMMOUSE_DRIVER_VERSION_STRING ".0";
129#endif /*VMW_SUBPATCH*/
130#endif
131
132
133/*****************************************************************************
134 *	static function header
135 ****************************************************************************/
136#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
137static int VMMousePreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
138#else
139static InputInfoPtr VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags);
140static void VMMouseCloseProc(InputInfoPtr pInfo);
141static Bool VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
142			       int v3, int v4, int v5, int *x, int *y);
143#endif
144static void VMMouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
145static void MouseCommonOptions(InputInfoPtr pInfo);
146static void GetVMMouseMotionEvent(InputInfoPtr pInfo);
147static void VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw);
148static void VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy);
149static Bool VMMouseDeviceControl(DeviceIntPtr device, int mode);
150static int  VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control);
151static void VMMouseReadInput(InputInfoPtr pInfo);
152static int  VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode);
153static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
154
155/******************************************************************************
156 *		Definitions
157 *****************************************************************************/
158typedef struct {
159   int                 screenNum;
160   Bool                vmmouseAvailable;
161   VMMOUSE_INPUT_DATA  vmmousePrevInput;
162   Bool                isCurrRelative;
163   Bool                absoluteRequested;
164} VMMousePrivRec, *VMMousePrivPtr;
165
166#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
167static const char *reqSymbols[] = {
168   "InitPointerDeviceStruct",
169   "LoaderSymbol",
170   "LoadSubModule",
171   "miPointerGetMotionBufferSize",
172   "miPointerGetMotionEvents",
173   "screenInfo",
174   "Xcalloc",
175   "xf86AddEnabledDevice",
176   "xf86AddInputDriver",
177   "xf86AddModuleInfo",
178   "xf86AllocateInput",
179   "xf86BlockSIGIO",
180   "xf86CloseSerial",
181   "xf86CollectInputOptions",
182   "xf86ffs",
183   "xf86FlushInput",
184   "xf86GetAllowMouseOpenFail",
185   "xf86GetMotionEvents",
186   "xf86InitValuatorAxisStruct",
187   "xf86InitValuatorDefaults",
188   "xf86LoaderCheckSymbol",
189   "xf86MotionHistoryAllocate",
190   "xf86Msg",
191   "xf86NameCmp",
192   "xf86OpenSerial",
193   "xf86OSMouseInit",
194   "xf86PostButtonEvent",
195   "xf86PostMotionEvent",
196   "xf86ProcessCommonOptions",
197   "xf86RemoveEnabledDevice",
198   "xf86SetIntOption",
199   "xf86SetStrOption",
200   "xf86sprintf",
201   "xf86sscanf",
202   "xf86UnblockSIGIO",
203   "xf86usleep",
204   "xf86XInputSetScreen",
205   "Xfree",
206   "XisbBlockDuration",
207   "XisbFree",
208   "XisbNew",
209   "XisbRead",
210   "Xstrdup",
211   NULL
212};
213#endif
214
215InputDriverRec VMMOUSE = {
216   1,
217   "vmmouse",
218   NULL,
219   VMMousePreInit,
220   VMMouseUnInit,
221   NULL
222#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 11
223       ,
224   0
225#endif
226};
227
228static char reverseMap[32] = { 0,  4,  2,  6,  1,  5,  3,  7,
229			       8, 12, 10, 14,  9, 13, 11, 15,
230			      16, 20, 18, 22, 17, 21, 19, 23,
231			      24, 28, 26, 30, 25, 29, 27, 31};
232
233#define reverseBits(map, b)	(((b) & ~0x0f) | map[(b) & 0x0f])
234
235#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
236#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 14
237
238static InputOption*
239input_option_new(InputOption *list, char *key, char *value)
240{
241   InputOption *new;
242
243   new = calloc(1, sizeof(InputOption));
244   new->key = key;
245   new->value = value;
246   new->next = list;
247   return new;
248}
249
250static void
251input_option_free_list(InputOption **opts)
252{
253   InputOption *tmp = *opts;
254   while(*opts)
255   {
256      tmp = (*opts)->next;
257      free((*opts)->key);
258      free((*opts)->value);
259      free((*opts));
260      *opts = tmp;
261   }
262}
263#endif
264
265static int
266VMMouseInitPassthru(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
267{
268   InputAttributes *attrs = NULL;
269   InputOption *input_options = NULL;
270   pointer options;
271   DeviceIntPtr dev;
272   int rc;
273
274   options = xf86OptionListDuplicate(pInfo->options);
275   options = xf86ReplaceStrOption(options, "Driver", "mouse");
276
277   while(options) {
278      input_options = input_option_new(input_options,
279                                       xf86OptionName(options),
280                                       xf86OptionValue(options));
281      options = xf86NextOption(options);
282   }
283
284   rc = NewInputDeviceRequest(input_options, attrs, &dev);
285
286   input_option_free_list(&input_options);
287
288   return rc;
289}
290
291#else /* if ABI_XINPUT_VERSION < 12 */
292static InputInfoPtr
293VMMouseInitPassthru(InputDriverPtr drv, IDevPtr dev, int flags)
294{
295   InputDriverRec *passthruMouse;
296   passthruMouse = (InputDriverRec *)LoaderSymbol("MOUSE");
297   if(passthruMouse != NULL) {
298      return (passthruMouse->PreInit)(drv, dev, flags);
299   } else {
300      return NULL;
301   }
302}
303#endif
304
305/*
306 *----------------------------------------------------------------------
307 *
308 * VMMousePreInit --
309 *	This function collect all the information that is necessary to
310 *	determine the configuration of the hardware and to prepare the
311 *	device for being used
312 *
313 * Results:
314 * 	An InputInfoPtr object which points to vmmouse's information,
315 *	if the absolute pointing device available
316 *	Otherwise, an InputInfoPtr of regular mouse
317 *
318 * Side effects:
319 * 	VMMouse was initialized with necessary information
320 *
321 *----------------------------------------------------------------------
322 */
323
324#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
325static int
326VMMouseNewPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
327
328static InputInfoPtr
329VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
330{
331   InputInfoPtr pInfo;
332
333#ifndef NO_MOUSE_MODULE
334{
335   OSMouseInfoPtr osInfo = NULL;
336
337   /*
338    * let Xserver init the mouse first
339    */
340   osInfo = xf86OSMouseInit(0);
341   if (!osInfo)
342      return FALSE;
343}
344#endif
345
346   /*
347    * enable hardware access
348    */
349   if (!xorgHWAccess) {
350      if (xf86EnableIO())
351          xorgHWAccess = TRUE;
352      else
353          return NULL;
354   }
355
356   /*
357    * try to enable vmmouse here
358    */
359   if (!VMMouseClient_Enable()) {
360      /*
361       * vmmouse failed
362       * Fall back to normal mouse module
363       */
364      xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
365      return VMMouseInitPassthru(drv, dev, flags);
366   } else {
367      /*
368       * vmmouse is available
369       */
370      xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n");
371      /*
372       * Disable the absolute pointing device for now
373       * It will be enabled during DEVICE_ON phase
374       */
375      VMMouseClient_Disable();
376   }
377
378   if (!(pInfo = xf86AllocateInput(drv, 0))) {
379      return NULL;
380   }
381
382   pInfo->name = dev->identifier;
383#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
384   pInfo->motion_history_proc = xf86GetMotionEvents;
385#endif
386   pInfo->close_proc = VMMouseCloseProc;
387   pInfo->conversion_proc = VMMouseConvertProc;
388   pInfo->reverse_conversion_proc = NULL;
389   pInfo->fd = -1;
390   pInfo->dev = NULL;
391   pInfo->private_flags = 0;
392   pInfo->always_core_feedback = 0;
393   pInfo->conf_idev = dev;
394   pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
395
396   /* Collect the options, and process the common options. */
397   xf86CollectInputOptions(pInfo, NULL, NULL);
398   xf86ProcessCommonOptions(pInfo, pInfo->options);
399
400   if (VMMouseNewPreInit(drv, pInfo, flags) == Success)
401       pInfo->flags |= XI86_CONFIGURED;
402
403   return pInfo;
404}
405
406static int
407VMMouseNewPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
408#else /* if ABI_XINPUT_VERSION >= 12 */
409static int
410VMMousePreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
411#endif
412{
413   MouseDevPtr pMse = NULL;
414   VMMousePrivPtr mPriv = NULL;
415   int rc = Success;
416
417   /* Enable hardware access. */
418   if (!xorgHWAccess) {
419      if (xf86EnableIO())
420          xorgHWAccess = TRUE;
421      else {
422          rc = BadValue;
423          goto error;
424      }
425   }
426
427#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
428   /* For ABI < 12, we need to return the wrapped driver's pInfo (see
429    * above). ABI 12, we call NIDR and are done */
430   if (!VMMouseClient_Enable()) {
431      xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
432      return VMMouseInitPassthru(drv, pInfo, flags);
433   } else {
434      xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n");
435      VMMouseClient_Disable();
436   }
437#endif
438
439   mPriv = calloc (1, sizeof (VMMousePrivRec));
440
441   if (!mPriv) {
442      rc = BadAlloc;
443      goto error;
444   }
445
446   mPriv->absoluteRequested = FALSE;
447   mPriv->vmmouseAvailable = TRUE;
448
449   /* Settup the pInfo */
450   pInfo->type_name = XI_MOUSE;
451   pInfo->device_control = VMMouseDeviceControl;
452   pInfo->read_input = VMMouseReadInput;
453   pInfo->control_proc = VMMouseControlProc;
454   pInfo->switch_mode = VMMouseSwitchMode;
455
456   /* Allocate the MouseDevRec and initialise it. */
457   if (!(pMse = calloc(sizeof(MouseDevRec), 1))) {
458      rc = BadAlloc;
459      goto error;
460   }
461
462   pInfo->private = pMse;
463   pMse->Ctrl = MouseCtrl;
464   pMse->PostEvent = VMMousePostEvent;
465   pMse->CommonOptions = MouseCommonOptions;
466   pMse->mousePriv = mPriv;
467
468
469   /* Check if the device can be opened. */
470   pInfo->fd = xf86OpenSerial(pInfo->options);
471   if (pInfo->fd == -1) {
472      if (xf86GetAllowMouseOpenFail())
473	 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
474      else {
475	 xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
476	 rc = BadValue;
477	 goto error;
478      }
479   }
480   xf86CloseSerial(pInfo->fd);
481   pInfo->fd = -1;
482
483   /* Process the options */
484   pMse->CommonOptions(pInfo);
485
486   /* set up the current screen num */
487   mPriv->screenNum = xf86SetIntOption(pInfo->options, "ScreenNumber", 0);
488
489   return Success;
490
491error:
492   pInfo->private = NULL;
493   if (mPriv)
494      free(mPriv);
495   if (pMse)
496      free(pMse);
497
498   return rc;
499}
500
501
502/*
503 *----------------------------------------------------------------------
504 *
505 * MouseCtrl --
506 *     Alter the control paramters for the mouse.
507 *
508 * Results:
509 * 	None
510 *
511 * Side effects:
512 * 	None
513 *
514 *----------------------------------------------------------------------
515 */
516
517static void
518MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
519{
520    InputInfoPtr pInfo;
521    MouseDevPtr pMse;
522
523    pInfo = device->public.devicePrivate;
524    pMse = pInfo->private;
525
526#ifdef EXTMOUSEDEBUG
527    xf86Msg(X_INFO, "VMMOUSE(0): MouseCtrl pMse=%p\n", pMse);
528#endif
529
530    pMse->num       = ctrl->num;
531    pMse->den       = ctrl->den;
532    pMse->threshold = ctrl->threshold;
533}
534
535
536/*
537 *----------------------------------------------------------------------
538 *
539 * VMMouseDoPostEvent --
540 *	Post the mouse button event and mouse motion event to Xserver
541 *
542 * Results:
543 * 	None
544 *
545 * Side effects:
546 * 	Mouse location and button status was updated
547 *
548 *----------------------------------------------------------------------
549 */
550
551static void
552VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy)
553{
554    MouseDevPtr pMse;
555    VMMousePrivPtr mPriv;
556    int truebuttons;
557    int id, change;
558    Bool mouseMoved = FALSE;
559
560    pMse = pInfo->private;
561    mPriv = (VMMousePrivPtr)pMse->mousePriv;
562
563    /*
564     * The following truebuttons/reverseBits and lastButtons are
565     * used to compare the current buttons and the previous buttons
566     * to find the button changes during two mouse events
567     */
568    truebuttons = buttons;
569
570    buttons = reverseBits(reverseMap, buttons);
571
572    if (mPriv->isCurrRelative) {
573       mouseMoved = dx || dy;
574    } else {
575       mouseMoved = (dx != mPriv->vmmousePrevInput.X) ||
576                    (dy != mPriv->vmmousePrevInput.Y) ||
577                    (mPriv->vmmousePrevInput.Flags & VMMOUSE_MOVE_RELATIVE);
578    }
579    if (mouseMoved) {
580
581#ifdef CALL_CONVERSION_PROC
582        /*
583         * Xservers between 1.3.99.0 - 1.4.0.90 do not call conversion_proc, so
584         * we need to do the conversion from device to screen space.
585         */
586        VMMouseConvertProc(pInfo, 0, 2, dx, dy, 0, 0, 0, 0, &dx, &dy);
587#endif
588        xf86PostMotionEvent(pInfo->dev, !mPriv->isCurrRelative, 0, 2, dx, dy);
589    }
590
591    if (truebuttons != pMse->lastButtons) {
592       change = buttons ^ reverseBits(reverseMap, pMse->lastButtons);
593       while (change) {
594	  id = ffs(change);
595	  change &= ~(1 << (id - 1));
596	  xf86PostButtonEvent(pInfo->dev, 0, id,
597			      (buttons & (1 << (id - 1))), 0, 0);
598       }
599       pMse->lastButtons = truebuttons;
600    }
601}
602
603
604/*
605 *----------------------------------------------------------------------
606 *
607 * VMMousePostEvent --
608 *	Prepare the mouse status according to the Z axis mapping
609 *	before we post the event to Xserver
610 *
611 * Results:
612 * 	None
613 *
614 * Side effects:
615 * 	Buttons was updated according to Z axis mapping
616 *
617 *----------------------------------------------------------------------
618 */
619
620static void
621VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw)
622{
623    MouseDevPtr pMse;
624    int zbutton = 0;
625    VMMousePrivPtr mPriv;
626
627    pMse = pInfo->private;
628    mPriv = (VMMousePrivPtr)pMse->mousePriv;
629    /* Map the Z axis movement. */
630    /* XXX Could this go in the conversion_proc? */
631    switch (pMse->negativeZ) {
632    case MSE_NOZMAP:	/* do nothing */
633	break;
634    case MSE_MAPTOX:
635	if (dz != 0) {
636	   if(mPriv->isCurrRelative)
637	      dx = dz;
638	   else
639	      dx += dz;
640	    dz = 0;
641	}
642	break;
643    case MSE_MAPTOY:
644	if (dz != 0) {
645	   if(mPriv->isCurrRelative)
646	      dy = dz;
647	   else
648	      dy += dz;
649	    dz = 0;
650	}
651	break;
652    default:	/* buttons */
653	buttons &= ~(pMse->negativeZ | pMse->positiveZ
654		   | pMse->negativeW | pMse->positiveW);
655	if (dw < 0 || dz < -1) {
656	    zbutton = pMse->negativeW;
657	}
658	else if (dz < 0) {
659	    zbutton = pMse->negativeZ;
660	}
661	else if (dw > 0 || dz > 1) {
662	    zbutton = pMse->positiveW;
663	}
664	else if (dz > 0) {
665	    zbutton = pMse->positiveZ;
666	}
667	buttons |= zbutton;
668	dz = 0;
669	break;
670    }
671
672    VMMouseDoPostEvent(pInfo, buttons, dx, dy);
673
674    /*
675     * If dz has been mapped to a button `down' event, we need to cook up
676     * a corresponding button `up' event.
677     */
678    if (zbutton) {
679	buttons &= ~zbutton;
680	if(mPriv->isCurrRelative)
681	   VMMouseDoPostEvent(pInfo, buttons, 0, 0);
682	else
683	   VMMouseDoPostEvent(pInfo, buttons, dx, dy);
684    }
685}
686
687
688/*
689 *----------------------------------------------------------------------
690 *
691 * FlushButtons --
692 *
693 * 	FlushButtons -- reset button states.
694 *
695 * Results:
696 * 	None
697 *
698 * Side effects:
699 * 	None
700 *
701 *----------------------------------------------------------------------
702 */
703
704static void
705FlushButtons(MouseDevPtr pMse)
706{
707    pMse->lastButtons = 0;
708}
709
710
711/*
712 *----------------------------------------------------------------------
713 *
714 * MouseCommonOptions --
715 *	Process acceptable mouse options. Currently we only process
716 *	"Buttons" and "ZAxisMapping" options.
717 *	More options can be added later on
718 *
719 * Results:
720 * 	None
721 *
722 * Side effects:
723 * 	The buttons was setup according to the options
724 *
725 *----------------------------------------------------------------------
726 */
727
728static void
729MouseCommonOptions(InputInfoPtr pInfo)
730{
731   MouseDevPtr pMse;
732   char *s;
733
734   pMse = pInfo->private;
735
736   pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
737   if (!pMse->buttons) {
738      pMse->buttons = MSE_DFLTBUTTONS;
739   }
740
741   /*
742    * "emulate3Buttons" and "Drag Lock" is not supported
743    */
744
745   /*
746    * Process option for ZAxisMapping
747    */
748   s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5");
749   if (s) {
750      int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
751      char *msg = NULL;
752
753      if (!xf86NameCmp(s, "x")) {
754	 pMse->negativeZ = pMse->positiveZ = MSE_MAPTOX;
755	 pMse->negativeW = pMse->positiveW = MSE_MAPTOX;
756	 msg = xstrdup("X axis");
757      } else if (!xf86NameCmp(s, "y")) {
758	 pMse->negativeZ = pMse->positiveZ = MSE_MAPTOY;
759	 pMse->negativeW = pMse->positiveW = MSE_MAPTOY;
760	 msg = xstrdup("Y axis");
761      } else if (sscanf(s, "%d %d %d %d", &b1, &b2, &b3, &b4) >= 2 &&
762		 b1 > 0 && b1 <= MSE_MAXBUTTONS &&
763		 b2 > 0 && b2 <= MSE_MAXBUTTONS) {
764	 msg = xstrdup("buttons XX and YY");
765	 if (msg)
766	    sprintf(msg, "buttons %d and %d", b1, b2);
767	 pMse->negativeZ = pMse->negativeW = 1 << (b1-1);
768	 pMse->positiveZ = pMse->positiveW = 1 << (b2-1);
769	 if (b1 > pMse->buttons) pMse->buttons = b1;
770	 if (b2 > pMse->buttons) pMse->buttons = b2;
771
772	 /*
773	  * Option "ZAxisMapping" "N1 N2 N3 N4" not supported
774	  */
775	 pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
776      } else {
777	 pMse->negativeZ = pMse->positiveZ = MSE_NOZMAP;
778	 pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
779      }
780      if (msg) {
781	 xf86Msg(X_CONFIG, "%s: ZAxisMapping: %s\n", pInfo->name, msg);
782	 free(msg);
783      } else {
784	 xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n",
785		 pInfo->name, s);
786      }
787   }
788}
789
790
791/*
792 *----------------------------------------------------------------------
793 *
794 * VMMouseUnInit --
795 * 	This function was supposed to be called by Xserver to do Un-Init.
796 *	But it was unused now
797 *
798 * Results:
799 * 	None
800 *
801 * Side effects:
802 * 	None
803 *
804 *----------------------------------------------------------------------
805 */
806
807static void
808VMMouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
809{
810   MouseDevPtr pMse = pInfo->private;
811
812   xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n");
813
814   if (pMse) {
815       VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
816       free(mPriv);
817   }
818
819   xf86DeleteInput(pInfo, flags);
820}
821
822
823/*
824 *----------------------------------------------------------------------
825 *
826 * VMMouseDeviceControl --
827 * 	This function was called by Xserver during DEVICE_INIT, DEVICE_ON,
828 *	DEVICE_OFF and DEVICE_CLOSE phase
829 *
830 * Results:
831 * 	TRUE, if sucessful
832 *	FALSE, if failed
833 *
834 * Side effects:
835 * 	Absolute pointing device is enabled during DEVICE_ON
836 *	Absolute pointing device is disabled during DEVICE_OFF
837 *	and DEVICE_CLOSE
838 *
839 *----------------------------------------------------------------------
840 */
841
842static Bool
843VMMouseDeviceControl(DeviceIntPtr device, int mode)
844{
845   InputInfoPtr pInfo;
846   MouseDevPtr pMse;
847   unsigned char map[MSE_MAXBUTTONS + 1];
848   int i;
849#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
850   Atom btn_labels[MSE_MAXBUTTONS] = {0};
851   Atom axes_labels[2] = { 0, 0 };
852#endif
853
854   pInfo = device->public.devicePrivate;
855   pMse = pInfo->private;
856   pMse->device = device;
857
858   switch (mode){
859   case DEVICE_INIT:
860      device->public.on = FALSE;
861      /*
862       * [KAZU-241097] We don't know exactly how many buttons the
863       * device has, so setup the map with the maximum number.
864       */
865      for (i = 0; i < MSE_MAXBUTTONS; i++)
866	 map[i + 1] = i + 1;
867#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
868      btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
869      btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
870      btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
871      btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
872      btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
873      btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
874      btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
875      /* other buttons are unknown */
876
877#ifdef ABS_VALUATOR_AXES
878      axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
879      axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
880#else
881      axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
882      axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
883#endif /* ABS_VALUATOR_AXES */
884#endif
885
886      InitPointerDeviceStruct((DevicePtr)device, map,
887			      min(pMse->buttons, MSE_MAXBUTTONS),
888#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
889				btn_labels,
890#endif
891#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
892				miPointerGetMotionEvents,
893#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
894                                GetMotionHistory,
895#endif
896                                pMse->Ctrl,
897#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
898				miPointerGetMotionBufferSize()
899#else
900                                GetMotionHistorySize(), 2
901#endif
902#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
903				, axes_labels
904#endif
905                                );
906
907      /* X valuator */
908#ifdef ABS_VALUATOR_AXES
909      xf86InitValuatorAxisStruct(device, 0,
910#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
911				axes_labels[0],
912#endif
913				0, 65535, 10000, 0, 10000
914#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
915                                , Absolute
916#endif
917                                );
918#else
919      xf86InitValuatorAxisStruct(device, 0,
920#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
921				axes_labels[0],
922#endif
923				0, -1, 1, 0, 1
924#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
925                                , Relative
926#endif
927                                );
928#endif
929      xf86InitValuatorDefaults(device, 0);
930      /* Y valuator */
931#ifdef ABS_VALUATOR_AXES
932      xf86InitValuatorAxisStruct(device, 1,
933#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
934				axes_labels[1],
935#endif
936				0, 65535, 10000, 0, 10000
937#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
938                                , Absolute
939#endif
940                                );
941#else
942      xf86InitValuatorAxisStruct(device, 1,
943#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
944				axes_labels[1],
945#endif
946				0, -1, 1, 0, 1
947#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
948                                , Relative
949#endif
950                                );
951#endif
952      xf86InitValuatorDefaults(device, 1);
953#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
954      xf86MotionHistoryAllocate(pInfo);
955#endif
956
957      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n");
958#ifdef EXTMOUSEDEBUG
959      xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom,
960	     pInfo->name);
961#endif
962      break;
963
964   case DEVICE_ON:
965      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n");
966      pInfo->fd = xf86OpenSerial(pInfo->options);
967      if (pInfo->fd == -1)
968	 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
969      else {
970	 pMse->buffer = XisbNew(pInfo->fd, 64);
971	 if (!pMse->buffer) {
972	    xf86CloseSerial(pInfo->fd);
973	    pInfo->fd = -1;
974	 } else {
975	    VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
976	    if (mPriv != NULL) {
977	       /*
978		* enable absolute pointing device here
979		*/
980	       if (!VMMouseClient_Enable()) {
981		  xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
982		  mPriv->vmmouseAvailable = FALSE;
983		  device->public.on = FALSE;
984		  return FALSE;
985	       } else {
986		  mPriv->vmmouseAvailable = TRUE;
987		  xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n");
988	       }
989	    }
990	    xf86FlushInput(pInfo->fd);
991	    xf86AddEnabledDevice(pInfo);
992	 }
993      }
994      pMse->lastButtons = 0;
995      device->public.on = TRUE;
996      FlushButtons(pMse);
997      break;
998   case DEVICE_OFF:
999   case DEVICE_CLOSE:
1000      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n");
1001
1002      if (pInfo->fd != -1) {
1003	 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
1004	 if( mPriv->vmmouseAvailable ) {
1005	    VMMouseClient_Disable();
1006            mPriv->vmmouseAvailable = FALSE;
1007            mPriv->absoluteRequested = FALSE;
1008	 }
1009
1010	 xf86RemoveEnabledDevice(pInfo);
1011	 if (pMse->buffer) {
1012	    XisbFree(pMse->buffer);
1013	    pMse->buffer = NULL;
1014	 }
1015	 xf86CloseSerial(pInfo->fd);
1016	 pInfo->fd = -1;
1017      }
1018      device->public.on = FALSE;
1019      usleep(300000);
1020      break;
1021
1022#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) * 100 + GET_ABI_MINOR(ABI_XINPUT_VERSION) >= 1901
1023   case  DEVICE_ABORT:
1024      if (pInfo->fd != -1) {
1025	 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
1026	 if( mPriv->vmmouseAvailable )
1027	    VMMouseClient_Disable();
1028         break;
1029      }
1030#endif
1031   }
1032
1033   return Success;
1034}
1035
1036
1037/*
1038 *----------------------------------------------------------------------
1039 *
1040 * VMMouseReadInput --
1041 * 	This function was called by Xserver when there is data available
1042 *	in the input device
1043 *
1044 * Results:
1045 * 	None
1046 *
1047 * Side effects:
1048 * 	Input data in regular PS/2 fd was cleared
1049 *	Real mouse data was read from the absolute pointing device
1050 *	and posted to Xserver
1051 *
1052 *----------------------------------------------------------------------
1053 */
1054
1055static void
1056VMMouseReadInput(InputInfoPtr pInfo)
1057{
1058   MouseDevPtr pMse;
1059   VMMousePrivPtr mPriv;
1060   int c;
1061   int len = 0;
1062
1063   pMse = pInfo->private;
1064   mPriv = pMse->mousePriv;
1065
1066   if (!mPriv->absoluteRequested) {
1067      /*
1068       * We can request for absolute mode, but it depends on
1069       * host whether it will send us absolute or relative
1070       * position.
1071       */
1072      VMMouseClient_RequestAbsolute();
1073      mPriv->absoluteRequested = TRUE;
1074      LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): vmmouse enable absolute mode\n");
1075   }
1076
1077   /*
1078    * First read the bytes in input device to clear the regular PS/2 fd so
1079    * we don't get called again.
1080    */
1081   /*
1082    * Set blocking to -1 on the first call because we know there is data to
1083    * read. Xisb automatically clears it after one successful read so that
1084    * succeeding reads are preceeded by a select with a 0 timeout to prevent
1085    * read from blocking indefinitely.
1086    */
1087   XisbBlockDuration(pMse->buffer, -1);
1088   while ((c = XisbRead(pMse->buffer)) >= 0) {
1089      len++;
1090      /*
1091       * regular PS packet consists of 3 bytes
1092       * We read 3 bytes to drain the PS/2 packet
1093       */
1094      if(len < 3) continue;
1095      len = 0;
1096      /*
1097       * Now get the real data from absolute pointing device
1098       */
1099      GetVMMouseMotionEvent(pInfo);
1100   }
1101   /*
1102    * There maybe still vmmouse data available
1103    */
1104   GetVMMouseMotionEvent(pInfo);
1105}
1106
1107
1108/*
1109 *----------------------------------------------------------------------
1110 *
1111 * GetVMMouseMotionEvent --
1112 * 	Read all the mouse data available from the absolute
1113 * 	pointing device	and post it to the Xserver
1114 *
1115 * Results:
1116 * 	None
1117 *
1118 * Side effects:
1119 *	Real mouse data was read from the absolute pointing
1120 *	device and posted to Xserver
1121 *
1122 *----------------------------------------------------------------------
1123 */
1124
1125static void
1126GetVMMouseMotionEvent(InputInfoPtr pInfo){
1127   MouseDevPtr pMse;
1128   VMMousePrivPtr mPriv;
1129   int buttons, dx, dy, dz, dw;
1130   VMMOUSE_INPUT_DATA  vmmouseInput;
1131   int numPackets;
1132
1133   pMse = pInfo->private;
1134   mPriv = (VMMousePrivPtr)pMse->mousePriv;
1135   while((numPackets = VMMouseClient_GetInput(&vmmouseInput))){
1136      int ps2Buttons = 0;
1137      if (numPackets == VMMOUSE_ERROR) {
1138         VMMouseClient_Disable();
1139         VMMouseClient_Enable();
1140         VMMouseClient_RequestAbsolute();
1141         LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): re-requesting absolute mode after reset\n");
1142         break;
1143      }
1144
1145      if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON)
1146	 ps2Buttons |= 0x04; 			/* Middle*/
1147      if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON)
1148	 ps2Buttons |= 0x02; 			/* Right*/
1149      if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON)
1150	 ps2Buttons |= 0x01; 			/* Left*/
1151
1152      buttons = (ps2Buttons & 0x04) >> 1 |	/* Middle */
1153	 (ps2Buttons & 0x02) >> 1 |       	/* Right */
1154	 (ps2Buttons & 0x01) << 2;       	/* Left */
1155
1156      dx = vmmouseInput.X;
1157      dy = vmmouseInput.Y;
1158      dz = (char)vmmouseInput.Z;
1159      dw = 0;
1160      /*
1161       * Get the per package relative or absolute information.
1162       */
1163      mPriv->isCurrRelative = vmmouseInput.Flags & VMMOUSE_MOVE_RELATIVE;
1164      /* post an event */
1165      pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
1166      mPriv->vmmousePrevInput = vmmouseInput;
1167   }
1168}
1169
1170
1171/*
1172 *----------------------------------------------------------------------
1173 *
1174 * VMMouseControlProc --
1175 *	This function is unused
1176 *
1177 * Results:
1178 * 	None
1179 *
1180 * Side effects:
1181 * 	None
1182 *
1183 *----------------------------------------------------------------------
1184 */
1185
1186static int
1187VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control)
1188{
1189   xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n");
1190   return (Success);
1191}
1192
1193
1194/*
1195 *----------------------------------------------------------------------
1196 *
1197 *  VMMouseCloseProc --
1198 *	This function is unused
1199 *
1200 * Results:
1201 * 	None
1202 *
1203 * Side effects:
1204 * 	None
1205 *
1206 *----------------------------------------------------------------------
1207 */
1208
1209#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1210static void
1211VMMouseCloseProc(InputInfoPtr pInfo)
1212{
1213   xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n");
1214}
1215#endif
1216
1217
1218/*
1219 *----------------------------------------------------------------------
1220 *
1221 *  VMMouseSwitchProc --
1222 *	This function is unused
1223 *
1224 * Results:
1225 * 	None
1226 *
1227 * Side effects:
1228 * 	None
1229 *
1230 *----------------------------------------------------------------------
1231 */
1232
1233static int
1234VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
1235{
1236   xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n");
1237   return (Success);
1238}
1239
1240
1241/*
1242 *----------------------------------------------------------------------
1243 *
1244 * VMMouseConvertProc  --
1245 * 	This function was called by Xserver to convert valuators to X and Y
1246 *
1247 * Results:
1248 * 	TRUE
1249 *
1250 * Side effects:
1251 * 	X and Y was converted according to current Screen dimension
1252 *
1253 *----------------------------------------------------------------------
1254 */
1255
1256#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1257static Bool
1258VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
1259	     int v3, int v4, int v5, int *x, int *y)
1260{
1261   MouseDevPtr pMse;
1262   VMMousePrivPtr mPriv;
1263   double factorX, factorY;
1264
1265   pMse = pInfo->private;
1266   mPriv = pMse->mousePriv;
1267
1268   if (first != 0 || num != 2)
1269      return FALSE;
1270
1271   if(mPriv->isCurrRelative) {
1272      *x = v0;
1273      *y = v1;
1274   } else {
1275      factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535;
1276      factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535;
1277
1278      *x = v0 * factorX + 0.5;
1279      *y = v1 * factorY + 0.5;
1280
1281      if (mPriv->screenNum != -1) {
1282	 xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y);
1283      }
1284   }
1285   return TRUE;
1286}
1287#endif
1288
1289
1290#ifdef XFree86LOADER
1291
1292/*
1293 *----------------------------------------------------------------------
1294 *
1295 * VMMouseUnplug  --
1296 * 	This function was called by Xserver when unplug
1297 *
1298 * Results:
1299 * 	None
1300 *
1301 * Side effects:
1302 * 	None
1303 *
1304 *----------------------------------------------------------------------
1305 */
1306
1307static void
1308VMMouseUnplug(pointer p)
1309{
1310   xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n");
1311}
1312
1313
1314/*
1315 *----------------------------------------------------------------------
1316 *
1317 * VMMousePlug  --
1318 * 	This function was called when Xserver load vmmouse module. It will
1319 * 	integrate the  module infto the XFree86 loader architecutre.
1320 *
1321 * Results:
1322 * 	TRUE
1323 *
1324 * Side effects:
1325 * 	Regular mouse module was loaded as a submodule. In case
1326 * 	absolute pointing device is not available, we can always fall back
1327 *	to the regular mouse module
1328 *
1329 *----------------------------------------------------------------------
1330 */
1331
1332static pointer
1333VMMousePlug(pointer	module,
1334	    pointer	options,
1335	    int		*errmaj,
1336	    int		*errmin)
1337{
1338   static Bool Initialised = FALSE;
1339
1340#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
1341   xf86LoaderReqSymLists(reqSymbols, NULL);
1342#endif
1343
1344   if (!Initialised)
1345      Initialised = TRUE;
1346
1347   xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n");
1348   xf86AddInputDriver(&VMMOUSE, module, 0);
1349
1350#ifndef NO_MOUSE_MODULE
1351{
1352   char *name;
1353   /*
1354    * Load the normal mouse module as submodule
1355    * If we fail in PreInit later, this allows us to fall back to normal mouse module
1356    */
1357#ifndef NORMALISE_MODULE_NAME
1358   name = xstrdup("mouse");
1359#else
1360   /* Normalise the module name */
1361   name = xf86NormalizeName("mouse");
1362#endif
1363
1364   if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) {
1365      LoaderErrorMsg(NULL, name, *errmaj, *errmin);
1366   }
1367   free(name);
1368}
1369#endif
1370
1371   return module;
1372}
1373
1374static XF86ModuleVersionInfo VMMouseVersionRec = {
1375   "vmmouse",
1376   MODULEVENDORSTRING,
1377   MODINFOSTRING1,
1378   MODINFOSTRING2,
1379   XORG_VERSION_CURRENT,
1380   PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
1381   ABI_CLASS_XINPUT,
1382   ABI_XINPUT_VERSION,
1383   MOD_CLASS_XINPUT,
1384   {0, 0, 0, 0}		/* signature, to be patched into the file by a tool */
1385};
1386
1387/*
1388 * The variable contains the necessary information to load and initialize the module
1389 */
1390_X_EXPORT XF86ModuleData vmmouseModuleData = {
1391   &VMMouseVersionRec,
1392   VMMousePlug,
1393   VMMouseUnplug
1394};
1395#endif /* XFree86LOADER */
1396