vmmouse.c revision 0da4cdcc
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   xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n");
811}
812
813
814/*
815 *----------------------------------------------------------------------
816 *
817 * VMMouseDeviceControl --
818 * 	This function was called by Xserver during DEVICE_INIT, DEVICE_ON,
819 *	DEVICE_OFF and DEVICE_CLOSE phase
820 *
821 * Results:
822 * 	TRUE, if sucessful
823 *	FALSE, if failed
824 *
825 * Side effects:
826 * 	Absolute pointing device is enabled during DEVICE_ON
827 *	Absolute pointing device is disabled during DEVICE_OFF
828 *	and DEVICE_CLOSE
829 *
830 *----------------------------------------------------------------------
831 */
832
833static Bool
834VMMouseDeviceControl(DeviceIntPtr device, int mode)
835{
836   InputInfoPtr pInfo;
837   MouseDevPtr pMse;
838   unsigned char map[MSE_MAXBUTTONS + 1];
839   int i;
840#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
841   Atom btn_labels[MSE_MAXBUTTONS] = {0};
842   Atom axes_labels[2] = { 0, 0 };
843#endif
844
845   pInfo = device->public.devicePrivate;
846   pMse = pInfo->private;
847   pMse->device = device;
848
849   switch (mode){
850   case DEVICE_INIT:
851      device->public.on = FALSE;
852      /*
853       * [KAZU-241097] We don't know exactly how many buttons the
854       * device has, so setup the map with the maximum number.
855       */
856      for (i = 0; i < MSE_MAXBUTTONS; i++)
857	 map[i + 1] = i + 1;
858#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
859      btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
860      btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
861      btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
862      btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
863      btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
864      btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
865      btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
866      /* other buttons are unknown */
867
868#ifdef ABS_VALUATOR_AXES
869      axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
870      axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
871#else
872      axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
873      axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
874#endif /* ABS_VALUATOR_AXES */
875#endif
876
877      InitPointerDeviceStruct((DevicePtr)device, map,
878			      min(pMse->buttons, MSE_MAXBUTTONS),
879#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
880				btn_labels,
881#endif
882#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
883				miPointerGetMotionEvents,
884#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
885                                GetMotionHistory,
886#endif
887                                pMse->Ctrl,
888#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
889				miPointerGetMotionBufferSize()
890#else
891                                GetMotionHistorySize(), 2
892#endif
893#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
894				, axes_labels
895#endif
896                                );
897
898      /* X valuator */
899#ifdef ABS_VALUATOR_AXES
900      xf86InitValuatorAxisStruct(device, 0,
901#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
902				axes_labels[0],
903#endif
904				0, 65535, 10000, 0, 10000
905#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
906                                , Absolute
907#endif
908                                );
909#else
910      xf86InitValuatorAxisStruct(device, 0,
911#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
912				axes_labels[0],
913#endif
914				0, -1, 1, 0, 1
915#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
916                                , Relative
917#endif
918                                );
919#endif
920      xf86InitValuatorDefaults(device, 0);
921      /* Y valuator */
922#ifdef ABS_VALUATOR_AXES
923      xf86InitValuatorAxisStruct(device, 1,
924#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
925				axes_labels[1],
926#endif
927				0, 65535, 10000, 0, 10000
928#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
929                                , Absolute
930#endif
931                                );
932#else
933      xf86InitValuatorAxisStruct(device, 1,
934#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
935				axes_labels[1],
936#endif
937				0, -1, 1, 0, 1
938#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
939                                , Relative
940#endif
941                                );
942#endif
943      xf86InitValuatorDefaults(device, 1);
944#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
945      xf86MotionHistoryAllocate(pInfo);
946#endif
947
948      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n");
949#ifdef EXTMOUSEDEBUG
950      xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom,
951	     pInfo->name);
952#endif
953      break;
954
955   case DEVICE_ON:
956      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n");
957      pInfo->fd = xf86OpenSerial(pInfo->options);
958      if (pInfo->fd == -1)
959	 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
960      else {
961	 pMse->buffer = XisbNew(pInfo->fd, 64);
962	 if (!pMse->buffer) {
963	    xf86CloseSerial(pInfo->fd);
964	    pInfo->fd = -1;
965	 } else {
966	    VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
967	    if (mPriv != NULL) {
968	       /*
969		* enable absolute pointing device here
970		*/
971	       if (!VMMouseClient_Enable()) {
972		  xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
973		  mPriv->vmmouseAvailable = FALSE;
974		  device->public.on = FALSE;
975		  return FALSE;
976	       } else {
977		  mPriv->vmmouseAvailable = TRUE;
978		  xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n");
979	       }
980	    }
981	    xf86FlushInput(pInfo->fd);
982	    xf86AddEnabledDevice(pInfo);
983	 }
984      }
985      pMse->lastButtons = 0;
986      device->public.on = TRUE;
987      FlushButtons(pMse);
988      break;
989   case DEVICE_OFF:
990   case DEVICE_CLOSE:
991      xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n");
992
993      if (pInfo->fd != -1) {
994	 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
995	 if( mPriv->vmmouseAvailable ) {
996	    VMMouseClient_Disable();
997            mPriv->vmmouseAvailable = FALSE;
998            mPriv->absoluteRequested = FALSE;
999	 }
1000
1001	 xf86RemoveEnabledDevice(pInfo);
1002	 if (pMse->buffer) {
1003	    XisbFree(pMse->buffer);
1004	    pMse->buffer = NULL;
1005	 }
1006	 xf86CloseSerial(pInfo->fd);
1007	 pInfo->fd = -1;
1008      }
1009      device->public.on = FALSE;
1010      usleep(300000);
1011      break;
1012
1013   }
1014
1015   return Success;
1016}
1017
1018
1019/*
1020 *----------------------------------------------------------------------
1021 *
1022 * VMMouseReadInput --
1023 * 	This function was called by Xserver when there is data available
1024 *	in the input device
1025 *
1026 * Results:
1027 * 	None
1028 *
1029 * Side effects:
1030 * 	Input data in regular PS/2 fd was cleared
1031 *	Real mouse data was read from the absolute pointing device
1032 *	and posted to Xserver
1033 *
1034 *----------------------------------------------------------------------
1035 */
1036
1037static void
1038VMMouseReadInput(InputInfoPtr pInfo)
1039{
1040   MouseDevPtr pMse;
1041   VMMousePrivPtr mPriv;
1042   int c;
1043   int len = 0;
1044
1045   pMse = pInfo->private;
1046   mPriv = pMse->mousePriv;
1047
1048   if (!mPriv->absoluteRequested) {
1049      /*
1050       * We can request for absolute mode, but it depends on
1051       * host whether it will send us absolute or relative
1052       * position.
1053       */
1054      VMMouseClient_RequestAbsolute();
1055      mPriv->absoluteRequested = TRUE;
1056      LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): vmmouse enable absolute mode\n");
1057   }
1058
1059   /*
1060    * First read the bytes in input device to clear the regular PS/2 fd so
1061    * we don't get called again.
1062    */
1063   /*
1064    * Set blocking to -1 on the first call because we know there is data to
1065    * read. Xisb automatically clears it after one successful read so that
1066    * succeeding reads are preceeded by a select with a 0 timeout to prevent
1067    * read from blocking indefinitely.
1068    */
1069   XisbBlockDuration(pMse->buffer, -1);
1070   while ((c = XisbRead(pMse->buffer)) >= 0) {
1071      len++;
1072      /*
1073       * regular PS packet consists of 3 bytes
1074       * We read 3 bytes to drain the PS/2 packet
1075       */
1076      if(len < 3) continue;
1077      len = 0;
1078      /*
1079       * Now get the real data from absolute pointing device
1080       */
1081      GetVMMouseMotionEvent(pInfo);
1082   }
1083   /*
1084    * There maybe still vmmouse data available
1085    */
1086   GetVMMouseMotionEvent(pInfo);
1087}
1088
1089
1090/*
1091 *----------------------------------------------------------------------
1092 *
1093 * GetVMMouseMotionEvent --
1094 * 	Read all the mouse data available from the absolute
1095 * 	pointing device	and post it to the Xserver
1096 *
1097 * Results:
1098 * 	None
1099 *
1100 * Side effects:
1101 *	Real mouse data was read from the absolute pointing
1102 *	device and posted to Xserver
1103 *
1104 *----------------------------------------------------------------------
1105 */
1106
1107static void
1108GetVMMouseMotionEvent(InputInfoPtr pInfo){
1109   MouseDevPtr pMse;
1110   VMMousePrivPtr mPriv;
1111   int buttons, dx, dy, dz, dw;
1112   VMMOUSE_INPUT_DATA  vmmouseInput;
1113   int numPackets;
1114
1115   pMse = pInfo->private;
1116   mPriv = (VMMousePrivPtr)pMse->mousePriv;
1117   while((numPackets = VMMouseClient_GetInput(&vmmouseInput))){
1118      int ps2Buttons = 0;
1119      if (numPackets == VMMOUSE_ERROR) {
1120         VMMouseClient_Disable();
1121         VMMouseClient_Enable();
1122         VMMouseClient_RequestAbsolute();
1123         LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): re-requesting absolute mode after reset\n");
1124         break;
1125      }
1126
1127      if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON)
1128	 ps2Buttons |= 0x04; 			/* Middle*/
1129      if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON)
1130	 ps2Buttons |= 0x02; 			/* Right*/
1131      if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON)
1132	 ps2Buttons |= 0x01; 			/* Left*/
1133
1134      buttons = (ps2Buttons & 0x04) >> 1 |	/* Middle */
1135	 (ps2Buttons & 0x02) >> 1 |       	/* Right */
1136	 (ps2Buttons & 0x01) << 2;       	/* Left */
1137
1138      dx = vmmouseInput.X;
1139      dy = vmmouseInput.Y;
1140      dz = (char)vmmouseInput.Z;
1141      dw = 0;
1142      /*
1143       * Get the per package relative or absolute information.
1144       */
1145      mPriv->isCurrRelative = vmmouseInput.Flags & VMMOUSE_MOVE_RELATIVE;
1146      /* post an event */
1147      pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
1148      mPriv->vmmousePrevInput = vmmouseInput;
1149   }
1150}
1151
1152
1153/*
1154 *----------------------------------------------------------------------
1155 *
1156 * VMMouseControlProc --
1157 *	This function is unused
1158 *
1159 * Results:
1160 * 	None
1161 *
1162 * Side effects:
1163 * 	None
1164 *
1165 *----------------------------------------------------------------------
1166 */
1167
1168static int
1169VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control)
1170{
1171   xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n");
1172   return (Success);
1173}
1174
1175
1176/*
1177 *----------------------------------------------------------------------
1178 *
1179 *  VMMouseCloseProc --
1180 *	This function is unused
1181 *
1182 * Results:
1183 * 	None
1184 *
1185 * Side effects:
1186 * 	None
1187 *
1188 *----------------------------------------------------------------------
1189 */
1190
1191#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1192static void
1193VMMouseCloseProc(InputInfoPtr pInfo)
1194{
1195   xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n");
1196}
1197#endif
1198
1199
1200/*
1201 *----------------------------------------------------------------------
1202 *
1203 *  VMMouseSwitchProc --
1204 *	This function is unused
1205 *
1206 * Results:
1207 * 	None
1208 *
1209 * Side effects:
1210 * 	None
1211 *
1212 *----------------------------------------------------------------------
1213 */
1214
1215static int
1216VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
1217{
1218   xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n");
1219   return (Success);
1220}
1221
1222
1223/*
1224 *----------------------------------------------------------------------
1225 *
1226 * VMMouseConvertProc  --
1227 * 	This function was called by Xserver to convert valuators to X and Y
1228 *
1229 * Results:
1230 * 	TRUE
1231 *
1232 * Side effects:
1233 * 	X and Y was converted according to current Screen dimension
1234 *
1235 *----------------------------------------------------------------------
1236 */
1237
1238#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1239static Bool
1240VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
1241	     int v3, int v4, int v5, int *x, int *y)
1242{
1243   MouseDevPtr pMse;
1244   VMMousePrivPtr mPriv;
1245   double factorX, factorY;
1246
1247   pMse = pInfo->private;
1248   mPriv = pMse->mousePriv;
1249
1250   if (first != 0 || num != 2)
1251      return FALSE;
1252
1253   if(mPriv->isCurrRelative) {
1254      *x = v0;
1255      *y = v1;
1256   } else {
1257      factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535;
1258      factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535;
1259
1260      *x = v0 * factorX + 0.5;
1261      *y = v1 * factorY + 0.5;
1262
1263      if (mPriv->screenNum != -1) {
1264	 xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y);
1265      }
1266   }
1267   return TRUE;
1268}
1269#endif
1270
1271
1272#ifdef XFree86LOADER
1273
1274/*
1275 *----------------------------------------------------------------------
1276 *
1277 * VMMouseUnplug  --
1278 * 	This function was called by Xserver when unplug
1279 *
1280 * Results:
1281 * 	None
1282 *
1283 * Side effects:
1284 * 	None
1285 *
1286 *----------------------------------------------------------------------
1287 */
1288
1289static void
1290VMMouseUnplug(pointer p)
1291{
1292   xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n");
1293}
1294
1295
1296/*
1297 *----------------------------------------------------------------------
1298 *
1299 * VMMousePlug  --
1300 * 	This function was called when Xserver load vmmouse module. It will
1301 * 	integrate the  module infto the XFree86 loader architecutre.
1302 *
1303 * Results:
1304 * 	TRUE
1305 *
1306 * Side effects:
1307 * 	Regular mouse module was loaded as a submodule. In case
1308 * 	absolute pointing device is not available, we can always fall back
1309 *	to the regular mouse module
1310 *
1311 *----------------------------------------------------------------------
1312 */
1313
1314static pointer
1315VMMousePlug(pointer	module,
1316	    pointer	options,
1317	    int		*errmaj,
1318	    int		*errmin)
1319{
1320   static Bool Initialised = FALSE;
1321
1322#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
1323   xf86LoaderReqSymLists(reqSymbols, NULL);
1324#endif
1325
1326   if (!Initialised)
1327      Initialised = TRUE;
1328
1329   xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n");
1330   xf86AddInputDriver(&VMMOUSE, module, 0);
1331
1332#ifndef NO_MOUSE_MODULE
1333{
1334   char *name;
1335   /*
1336    * Load the normal mouse module as submodule
1337    * If we fail in PreInit later, this allows us to fall back to normal mouse module
1338    */
1339#ifndef NORMALISE_MODULE_NAME
1340   name = xstrdup("mouse");
1341#else
1342   /* Normalise the module name */
1343   name = xf86NormalizeName("mouse");
1344#endif
1345
1346   if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) {
1347      LoaderErrorMsg(NULL, name, *errmaj, *errmin);
1348   }
1349   free(name);
1350}
1351#endif
1352
1353   return module;
1354}
1355
1356static XF86ModuleVersionInfo VMMouseVersionRec = {
1357   "vmmouse",
1358   MODULEVENDORSTRING,
1359   MODINFOSTRING1,
1360   MODINFOSTRING2,
1361   XORG_VERSION_CURRENT,
1362   PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
1363   ABI_CLASS_XINPUT,
1364   ABI_XINPUT_VERSION,
1365   MOD_CLASS_XINPUT,
1366   {0, 0, 0, 0}		/* signature, to be patched into the file by a tool */
1367};
1368
1369/*
1370 * The variable contains the necessary information to load and initialize the module
1371 */
1372_X_EXPORT XF86ModuleData vmmouseModuleData = {
1373   &VMMouseVersionRec,
1374   VMMousePlug,
1375   VMMouseUnplug
1376};
1377#endif /* XFree86LOADER */
1378