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