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