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