summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorphilipl <philipl>2006-01-09 19:12:26 +0000
committerphilipl <philipl>2006-01-09 19:12:26 +0000
commitee148a2f8ef97557ec2db501295ed8227699d2bf (patch)
tree9c227732c96ce30145730faabacf6a85bb95779c
Initial release of the vmmouse driver for VMware virtual machines.
-rw-r--r--.cvsignore19
-rw-r--r--COPYING23
-rw-r--r--ChangeLog3
-rw-r--r--INSTALL231
-rw-r--r--Makefile.am22
-rw-r--r--README53
-rwxr-xr-xautogen.sh12
-rw-r--r--configure.ac92
-rw-r--r--man/Makefile.am59
-rw-r--r--man/vmmouse.man228
-rw-r--r--src/Makefile.am36
-rw-r--r--src/vmmouse.c1173
-rw-r--r--src/vmmouse_client.c337
-rw-r--r--src/vmmouse_client.h73
-rw-r--r--src/vmmouse_defs.h66
-rw-r--r--src/vmmouse_proto.c145
-rw-r--r--src/vmmouse_proto.h121
17 files changed, 2693 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..fb1befd
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,19 @@
+Makefile
+Makefile.in
+*.la
+*.lo
+aclocal.m4
+autom4te.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+ltmain.sh
+missing
+stamp-h1
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..901b59f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,23 @@
+Copyright (c) 2006 VMware, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the copyright holder(s) and author(s)
+shall not be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the copyright holder(s) and
+author(s).
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..500ac73
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,3 @@
+2006-01-06 Philip Langdale <plangdale@vmware.com>
+
+ * Initial release.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..62ea076
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,231 @@
+Copyright 1994, 1995, 1996, 1999, 2000, 2001 Free Software Foundation,
+Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for variables by setting
+them in the environment. You can do that on the command line like this:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it cannot guess the host type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the host
+platform (i.e., that on which the generated programs will eventually be
+run) with `--host=TYPE'. In this case, you should also specify the
+build platform with `--build=TYPE', because, in this case, it may not
+be possible to guess the build platform (it sometimes involves
+compiling and running simple test programs, and this can't be done if
+the compiler is a cross compiler).
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..7052905
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,22 @@
+# Copyright 2005 Adam Jackson.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = src man
diff --git a/README b/README
new file mode 100644
index 0000000..1e9e762
--- /dev/null
+++ b/README
@@ -0,0 +1,53 @@
+VMMouse
+-------
+
+The VMMouse driver enables support for the special VMMouse protocol
+that is provided by VMware virtual machines to give absolute pointer
+positioning.
+
+Installing the driver will improve the user experience when using the
+mouse to interact with the guest operating system. In particular, use of
+the driver improves mouse "lag", provides mouse speed and acceleration
+consistent with the user's host operating system, and enables the
+auto-grab/ungrab feature in VMware products without requiring the VMware
+toolbox application.
+
+Using the driver
+----------------
+
+Assuming you have built and installed the driver in the standard way
+for autotools based packages (see INSTALL), or the driver was already
+installed by your distro, using it is simply a matter of changing the
+driver used for the mouse input device from "mouse" to "vmmouse".
+
+The vmmouse driver is capable of falling back to the standard "mouse"
+driver if a VMware virtual machine is not detected. This allows for
+dual-booting of an operating system from a virtual machine to real hardware
+without having to edit xorg.conf every time.
+
+Implementation
+--------------
+
+The following is not necessary reading for anyone who wants to use the
+driver, but should help anyone who wants to understand how it works or
+who wants to write a driver for a different target, whether it's another
+operating system, a linux kernel input driver or even gpm.
+
+The driver is composed of three different layers:
+
+1) The vmmouse protocol layer (vmmouse_proto.[c|h])
+ - This provides the call to read and write the port over which
+ the vmmouse packets are transfered.
+
+2) The vmmouse client layer (vmmouse_client.[c|h])
+ - This builds on top of the protocol layer to provide higher
+ level calls for enabling/disabling the vmmouse mechanism
+ and for reading data.
+ - A new driver for a different target would use this interface.
+
+3) The Xorg vmmouse driver (vmmouse.c)
+ - This is the actual Xorg specific part of the driver.
+ - Note that interrupts indicating the presence of mouse data
+ are still transmitted on the PS/2 port so it is necessary
+ to be set up to receive those interrupts like a standard
+ PS/2 driver, but the actual data on the PS/2 port is ignored.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..904cd67
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..7dd4dea
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,92 @@
+# Copyright 2005 Adam Jackson.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Process this file with autoconf to produce a configure script
+
+AC_PREREQ(2.57)
+AC_INIT([xf86-input-vmmouse],
+ 12.3.0.0,
+ [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+ xf86-input-vmmouse)
+
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_AUX_DIR(.)
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AM_MAINTAINER_MODE
+
+DRIVER_NAME=vmmouse
+AC_SUBST([DRIVER_NAME])
+
+AM_CONFIG_HEADER([config.h])
+
+# Checks for programs.
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_PROG_CC
+
+AH_TOP([#include "xorg-server.h"])
+
+#AC_DEFINE(XFree86LOADER,1,[Stub define for loadable drivers])
+#
+#AC_ARG_ENABLE(XINPUT, AS_HELP_STRING([--enable-xinput],
+# [Build XInput support (default: yes)]),
+# [XINPUT=$enableval],[XINPUT=yes])
+#AM_CONDITIONAL(XINPUT, test "x$XINPUT" = "xyes")
+#if test "x$XINPUT" = "xyes" ; then
+# AC_DEFINE(XINPUT,1,[Enable XInput support])
+#fi
+#
+#AC_ARG_ENABLE(XKB, AS_HELP_STRING([--enable-xkb],
+# [Build XKB support (default: yes)]),
+# [XKB=$enableval],[XKB=yes])
+#AM_CONDITIONAL(XKB, test "x$XKB" = "xyes")
+#if test "x$XKB" = "xyes" ; then
+# AC_DEFINE(XKB,1,[Enable XKB support])
+#fi
+
+AC_ARG_WITH(xorg-module-dir,
+ AC_HELP_STRING([--with-xorg-module-dir=DIR],
+ [Default xorg module directory [[default=$libdir/xorg/modules]]]),
+ [moduledir="$withval"],
+ [moduledir="$libdir/xorg/modules"])
+inputdir=${moduledir}/input
+AC_SUBST(inputdir)
+
+# Checks for extensions
+XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
+XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
+
+# Checks for pkg-config packages
+PKG_CHECK_MODULES(XORG, xorg-server >= 0.99.3 xproto $REQUIRED_MODULES)
+sdkdir=$(pkg-config --variable=sdkdir xorg-server)
+
+CFLAGS="$CFLAGS $XORG_CFLAGS "' -I$(top_srcdir)/src'
+AC_SUBST([CFLAGS])
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+
+XORG_MANPAGE_SECTIONS
+XORG_RELEASE_VERSION
+
+AC_OUTPUT([Makefile src/Makefile man/Makefile])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..bf7ec17
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,59 @@
+# $Id$
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation.
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the copyright holders shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from the copyright holders.
+#
+
+drivermandir = $(DRIVER_MAN_DIR)
+
+driverman_PRE = @DRIVER_NAME@.man
+
+driverman_DATA = $(driverman_PRE:man=@DRIVER_MAN_SUFFIX@)
+
+EXTRA_DIST = @DRIVER_NAME@.man
+
+CLEANFILES = $(driverman_DATA)
+
+SED = sed
+
+# Strings to replace in man pages
+XORGRELSTRING = @PACKAGE_STRING@
+ XORGMANNAME = X Version 11
+
+MAN_SUBSTS = \
+ -e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xservername__|Xorg|g' \
+ -e 's|__xconfigfile__|xorg.conf|g' \
+ -e 's|__projectroot__|$(prefix)|g' \
+ -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \
+ -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
+ -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
+ -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
+ -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+
+SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
+
+.man.$(DRIVER_MAN_SUFFIX):
+ sed $(MAN_SUBSTS) < $< > $@
diff --git a/man/vmmouse.man b/man/vmmouse.man
new file mode 100644
index 0000000..6dcf0f0
--- /dev/null
+++ b/man/vmmouse.man
@@ -0,0 +1,228 @@
+.\" $XFree86: xc/programs/Xserver/hw/xfree86/input/mouse/mouse.man,v 1.5 2002/12/17 20:55:21 dawes Exp $
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH MOUSE __drivermansuffix__ __vendorversion__
+.SH NAME
+mouse \- Mouse input driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qInputDevice\*q"
+.BI " Identifier \*q" idevname \*q
+.B " Driver \*qmouse\*q"
+.BI " Option \*qProtocol\*q \*q" protoname \*q
+.BI " Option \*qDevice\*q \*q" devpath \*q
+\ \ ...
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B mouse
+is an XFree86 input driver for mice. The driver supports most available
+mouse types and interfaces. USB mice are only supported on some OSs,
+and the level of support for PS/2 mice depends on the OS.
+.PP
+The
+.B mouse
+driver functions as a pointer input device, and may be used as the
+X server's core pointer. Multiple mice are supported by multiple
+instances of this driver.
+.SH SUPPORTED HARDWARE
+There is a detailed list of hardware that the
+.B mouse
+driver supports in the
+.I README.mouse
+document. This can be found
+in __projectroot__/lib/X11/doc/, or online at
+http://www.xfree86.org/current/mouse.html.
+.SH CONFIGURATION DETAILS
+Please refer to XF86Config(__filemansuffix__) for general configuration
+details and for options that can be used with all input drivers. This
+section only covers configuration details specific to this driver.
+.PP
+The driver can auto-detect the mouse type on some platforms On some
+platforms this is limited to plug and play serial mice, and on some the
+auto-detection works for any mouse that the OS's kernel driver supports.
+On others, it is always necessary to specify the mouse protocol in the
+config file. The
+.I README.mouse
+document contains some detailed information about this.
+.PP
+The following driver
+.B Options
+are supported:
+.TP 7
+.BI "Option \*qProtocol\*q \*q" string \*q
+Specify the mouse protocol. Valid protocol types include:
+.PP
+.RS 12
+Auto, Microsoft, MouseSystems, MMSeries, Logitech, MouseMan, MMHitTab,
+GlidePoint, IntelliMouse, ThinkingMouse, AceCad, PS/2, ImPS/2,
+ExplorerPS/2, ThinkingMousePS/2, MouseManPlusPS/2, GlidePointPS/2,
+NetMousePS/2, NetScrollPS/2, BusMouse, SysMouse, WSMouse, USB, Xqueue.
+.RE
+.PP
+.RS 7
+Not all protocols are supported on all platforms. The "Auto" platform
+specifies that protocol auto-detection should be attempted. There is no
+default protocol setting, and specifying this option is mandatory.
+.RE
+.TP 7
+.BI "Option \*qDevice\*q \*q" string \*q
+Specifies the device through which the mouse can be accessed. A common
+setting is "/dev/mouse", which is often a symbolic link to the real
+device. This option is mandatory, and there is no default setting.
+.TP 7
+.BI "Option \*qButtons\*q \*q" integer \*q
+Specifies the number of mouse buttons. In cases where the number of buttons
+cannot be auto-detected, the default value is 3.
+.TP 7
+.BI "Option \*qEmulate3Buttons\*q \*q" boolean \*q
+Enable/disable the emulation of the third (middle) mouse button for mice
+which only have two physical buttons. The third button is emulated by
+pressing both buttons simultaneously. Default: off
+.TP 7
+.BI "Option \*qEmulate3Timeout\*q \*q" integer \*q
+Sets the timeout (in milliseconds) that the driver waits before deciding
+if two buttons where pressed "simultaneously" when 3 button emulation is
+enabled. Default: 50.
+.TP 7
+.BI "Option \*qChordMiddle\*q \*q" boolean \*q
+Enable/disable handling of mice that send left+right events when the middle
+button is used. Default: off.
+.TP 7
+.BI "Option \*qEmulateWheel\*q \*q" boolean \*q
+Enable/disable "wheel" emulation. Wheel emulation means emulating button
+press/release events when the mouse is moved while a specific real button
+is pressed. Wheel button events (typically buttons 4 and 5) are
+usually used for scrolling. Wheel emulation is useful for getting wheel-like
+behaviour with trackballs. It can also be useful for mice with 4 or
+more buttons but no wheel. See the description of the
+.BR EmulateWheelButton ,
+.BR EmulateWheelInertia ,
+.BR XAxisMapping ,
+and
+.B YAxisMapping
+options below. Default: off.
+.TP 7
+.BI "Option \*qEmulateWheelButton\*q \*q" integer \*q
+Specifies which button must be held down to enable wheel emulation mode.
+While this button is down, X and/or Y pointer movement will generate button
+press/release events as specified for the
+.B XAxisMapping
+and
+.B YAxisMapping
+settings. Default: 4.
+.TP 7
+.BI "Option \*qEmulateWheelInertia\*q \*q" integer \*q
+Specifies how far (in pixels) the pointer must move to generate button
+press/release events in wheel emulation mode. Default: 50.
+.TP 7
+.BI "Option \*qXAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the X direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative X axis motion and button number
+.I N2
+is mapped to the positive X axis motion. Default: no mapping.
+.TP 7
+.BI "Option \*qYAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the Y direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative Y axis motion and button number
+.I N2
+is mapped to the positive Y axis motion. Default: "4 5".
+.TP 7
+.BI "Option \*qZAxisMapping\*q \*qX\*q"
+.TP 7
+.BI "Option \*qZAxisMapping\*q \*qY\*q"
+.TP 7
+.BI "Option \*qZAxisMapping\*q \*q" "N1 N2" \*q
+.TP 7
+.BI "Option \*qZAxisMapping\*q \*q" "N1 N2 N3 N4" \*q
+Set the mapping for the Z axis (wheel) motion to buttons or another axis
+.RB ( X
+or
+.BR Y ).
+Button number
+.I N1
+is mapped to the negative Z axis motion and button number
+.I N2
+is mapped to the positive Z axis motion. For mice with two wheels,
+four button numbers can be specified, with the negative and positive motion
+of the second wheel mapped respectively to buttons number
+.I N3
+and
+.IR N4 .
+Default: no mapping.
+.TP 7
+.BI "Option \*qFlipXY\*q \*q" boolean \*q
+Enable/disable swapping the X and Y axes. This transformation is applied
+after the
+.BR InvX ,
+.B InvY
+and
+.BR AngleOffset
+transformations. Default: off.
+.TP 7
+.BI "Option \*qInvX\*q \*q" boolean \*q
+Invert the X axis. Default: off.
+.TP 7
+.BI "Option \*qInvY\*q \*q" boolean \*q
+Invert the Y axis. Default: off.
+.TP 7
+.BI "Option \*qAngleOffset\*q \*q" integer \*q
+Specify a clockwise angular offset (in degrees) to apply to the pointer
+motion. This transformation is applied before the
+.BR FlipXY ,
+.B InvX
+and
+.B InvY
+transformations. Default: 0.
+.TP 7
+.BI "Option \*qSampleRate\*q \*q" integer \*q
+Sets the number of motion/button events the mouse sends per second. Setting
+this is only supported for some mice, including some Logitech mice and
+some PS/2 mice on some platforms. Default: whatever the mouse is
+already set to.
+.TP 7
+.BI "Option \*qResolution\*q \*q" integer \*q
+Sets the resolution of the device in counts per inch. Setting this is
+only supported for some mice, including some PS/2 mice on some platforms.
+Default: whatever the mouse is already set to.
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "L1 B2 L3 B4" \*q
+Sets \*qdrag lock buttons\*q that simulate holding a button down, so
+that low dexterity people do not have to hold a buttton down at the
+same time they move a mouse cursor. Button numbers occur in pairs,
+with the lock button number occurring first, followed by the button
+number that is the target of the lock button.
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "M1" \*q
+Sets a \*qmaster drag lock button\*q that acts as a \*qMeta Key\*q
+indicating that the next button pressed is to be
+\*qdrag locked\*q.
+.TP 7
+.BI "Option \*qClearDTR\*q \*q" boolean \*q
+Enable/disable clearing the DTR line on the serial port used by the mouse.
+Some dual-protocol mice require the DTR line to be cleared to operate
+in the non-default protocol. This option is for serial mice only.
+Default: off.
+.TP 7
+.BI "Option \*qClearRTS\*q \*q" boolean \*q
+Enable/disable clearing the RTS line on the serial port used by the mouse.
+Some dual-protocol mice require the RTS line to be cleared to operate
+in the non-default protocol. This option is for serial mice only.
+Default: off.
+.TP 7
+.BI "Option \*qBaudRate\*q \*q" integer \*q
+Set the baud rate to use for communicating with a serial mouse. This
+option should rarely be required because the default is correct for almost
+all situations. Valid values include: 300, 1200, 2400, 4800, 9600, 19200.
+Default: 1200.
+.PP
+There are some other options that may be used to control various parameters
+for serial port communication, but they are not documented here because
+the driver sets them correctly for each mouse protocol type.
+.SH "SEE ALSO"
+XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__),
+README.mouse.
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..9451d8f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,36 @@
+# Copyright 2005 Adam Jackson.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+
+INCLUDES = -I$(srcdir)
+
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c @DRIVER_NAME@_defs.h \
+ @DRIVER_NAME@_client.c @DRIVER_NAME@_client.h \
+ @DRIVER_NAME@_proto.c @DRIVER_NAME@_proto.h
+
diff --git a/src/vmmouse.c b/src/vmmouse.c
new file mode 100644
index 0000000..76f3144
--- /dev/null
+++ b/src/vmmouse.c
@@ -0,0 +1,1173 @@
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ * Copyright 1993 by David Dawes <dawes@xfree86.org>
+ * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+ * Copyright 1994-2002 by The XFree86 Project, Inc.
+ * Copyright 2002 by Paul Elliott
+ * Copyright 2002-2006 by VMware, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the names of copyright holders not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The copyright holders
+ * make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * vmmouse.c --
+ *
+ * This is a modified version of the mouse input driver
+ * provided in Xserver/hw/xfree86/input/mouse/mouse.c
+ *
+ * Although all data is read using the vmmouse protocol, notification
+ * is still done through the PS/2 port, so all the basic code for
+ * interacting with the port is retained.
+ *
+ */
+
+
+/*****************************************************************************
+ * Standard Headers
+ ****************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+
+#include "xf86.h"
+
+#ifdef XINPUT
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "extinit.h"
+#else
+#include "inputstr.h"
+#endif
+
+#include "xf86Xinput.h"
+#include "xf86_OSproc.h"
+#include "xf86OSmouse.h"
+#include "xf86_ansic.h"
+#include "compiler.h"
+
+#include "xisb.h"
+#include "mipointer.h"
+
+/*****************************************************************************
+ * Local Headers
+ ****************************************************************************/
+#include "vmmouse_client.h"
+
+/*
+ * Version constants
+ */
+#define VMMOUSE_MAJOR_VERSION 12
+#define VMMOUSE_MINOR_VERSION 3
+#define VMMOUSE_PATCHLEVEL 0
+
+/*****************************************************************************
+ * static function header
+ ****************************************************************************/
+#ifdef XFree86LOADER
+static const OptionInfoRec *VMMouseAvailableOptions(void *unused);
+#endif
+static InputInfoPtr VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+static void VMMouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+static void MouseCommonOptions(InputInfoPtr pInfo);
+static void GetVMMouseMotionEvent(InputInfoPtr pInfo);
+static void VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw);
+static void VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy);
+static Bool VMMouseDeviceControl(DeviceIntPtr device, int mode);
+static void VMMouseCloseProc(LocalDevicePtr local);
+static int VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control);
+static void VMMouseReadInput(InputInfoPtr pInfo);
+static int VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode);
+static Bool VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y);
+static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+typedef struct {
+ int screenNum;
+ Bool vmmouseAvailable;
+ Bool relative;
+} VMMousePrivRec, *VMMousePrivPtr;
+
+static const char *reqSymbols[] = {
+ "InitPointerDeviceStruct",
+ "LoaderSymbol",
+ "LoadSubModule",
+ "miPointerGetMotionBufferSize",
+ "miPointerGetMotionEvents",
+ "screenInfo",
+ "Xcalloc",
+ "xf86AddEnabledDevice",
+ "xf86AddInputDriver",
+ "xf86AddModuleInfo",
+ "xf86AllocateInput",
+ "xf86BlockSIGIO",
+ "xf86CloseSerial",
+ "xf86CollectInputOptions",
+ "xf86ffs",
+ "xf86FlushInput",
+ "xf86GetAllowMouseOpenFail",
+ "xf86GetMotionEvents",
+ "xf86InitValuatorAxisStruct",
+ "xf86InitValuatorDefaults",
+ "xf86LoaderCheckSymbol",
+ "xf86MotionHistoryAllocate",
+ "xf86Msg",
+ "xf86NameCmp",
+ "xf86OpenSerial",
+ "xf86OSMouseInit",
+ "xf86PostButtonEvent",
+ "xf86PostMotionEvent",
+ "xf86ProcessCommonOptions",
+ "xf86RemoveEnabledDevice",
+ "xf86SetIntOption",
+ "xf86SetStrOption",
+ "xf86sprintf",
+ "xf86sscanf",
+ "xf86UnblockSIGIO",
+ "xf86usleep",
+ "xf86XInputSetScreen",
+ "Xfree",
+ "XisbBlockDuration",
+ "XisbFree",
+ "XisbNew",
+ "XisbRead",
+ "Xstrdup",
+ NULL
+};
+
+InputDriverRec VMMOUSE = {
+ 1,
+ "vmmouse",
+ NULL,
+ VMMousePreInit,
+ VMMouseUnInit,
+ NULL,
+ 0
+};
+
+typedef enum {
+ OPTION_ALWAYS_CORE,
+ OPTION_SEND_CORE_EVENTS,
+ OPTION_CORE_POINTER,
+ OPTION_SEND_DRAG_EVENTS,
+ OPTION_HISTORY_SIZE,
+ OPTION_DEVICE,
+ OPTION_PROTOCOL,
+ OPTION_BUTTONS,
+ OPTION_EMULATE_3_BUTTONS,
+ OPTION_EMULATE_3_TIMEOUT,
+ OPTION_CHORD_MIDDLE,
+ OPTION_FLIP_XY,
+ OPTION_INV_X,
+ OPTION_INV_Y,
+ OPTION_ANGLE_OFFSET,
+ OPTION_Z_AXIS_MAPPING,
+ OPTION_SAMPLE_RATE,
+ OPTION_RESOLUTION,
+ OPTION_EMULATE_WHEEL,
+ OPTION_EMU_WHEEL_BUTTON,
+ OPTION_EMU_WHEEL_INERTIA,
+ OPTION_X_AXIS_MAPPING,
+ OPTION_Y_AXIS_MAPPING,
+ OPTION_AUTO_SOFT,
+ OPTION_DRAGLOCKBUTTONS
+} MouseOpts;
+
+/*
+ * Define the acceptable mouse options
+ * Currently not all of those options are supported
+ *
+ */
+static const OptionInfoRec mouseOptions[] = {
+ { OPTION_ALWAYS_CORE, "AlwaysCore", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SEND_CORE_EVENTS, "SendCoreEvents", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_CORE_POINTER, "CorePointer", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SEND_DRAG_EVENTS, "SendDragEvents", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_HISTORY_SIZE, "HistorySize", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_DEVICE, "Device", OPTV_STRING, {0}, FALSE },
+ { OPTION_PROTOCOL, "Protocol", OPTV_STRING, {0}, FALSE },
+ { OPTION_BUTTONS, "Buttons", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMULATE_3_BUTTONS, "Emulate3Buttons",OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_EMULATE_3_TIMEOUT, "Emulate3Timeout",OPTV_INTEGER, {0}, FALSE },
+ { OPTION_CHORD_MIDDLE, "ChordMiddle", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_FLIP_XY, "FlipXY", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_INV_X, "InvX", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_INV_Y, "InvY", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_ANGLE_OFFSET, "AngleOffset", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_Z_AXIS_MAPPING, "ZAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_SAMPLE_RATE, "SampleRate", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_RESOLUTION, "Resolution", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMULATE_WHEEL, "EmulateWheel", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_EMU_WHEEL_BUTTON, "EmulateWheelButton", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_EMU_WHEEL_INERTIA, "EmulateWheelInertia", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_X_AXIS_MAPPING, "XAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_Y_AXIS_MAPPING, "YAxisMapping", OPTV_STRING, {0}, FALSE },
+ { OPTION_AUTO_SOFT, "AutoSoft", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_DRAGLOCKBUTTONS, "DragLockButtons",OPTV_STRING, {0}, FALSE },
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
+};
+
+static char reverseMap[32] = { 0, 4, 2, 6, 1, 5, 3, 7,
+ 8, 12, 10, 14, 9, 13, 11, 15,
+ 16, 20, 18, 22, 17, 21, 19, 23,
+ 24, 28, 26, 30, 25, 29, 27, 31};
+
+#define reverseBits(map, b) (((b) & ~0x0f) | map[(b) & 0x0f])
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePreInit --
+ * This function collect all the information that is necessary to
+ * determine the configuration of the hardware and to prepare the
+ * device for being used
+ *
+ * Results:
+ * An InputInfoPtr object which points to vmmouse's information,
+ * if the absolute pointing device available
+ * Otherwise, an InputInfoPtr of regular mouse
+ *
+ * Side effects:
+ * VMMouse was initialized with necessary information
+ *
+ *----------------------------------------------------------------------
+ */
+
+static InputInfoPtr
+VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ OSMouseInfoPtr osInfo = NULL;
+
+ /*
+ * let Xserver init the mouse first
+ */
+ osInfo = xf86OSMouseInit(0);
+ if (!osInfo)
+ return FALSE;
+
+ mPriv = xcalloc (1, sizeof (VMMousePrivRec));
+
+
+ if (!mPriv) {
+ return NULL;
+ }
+ /*
+ * try to enable vmmouse here
+ */
+ if (!VMMouseClient_Enable()) {
+ /*
+ * vmmouse failed
+ * Fall back to normal mouse module
+ */
+ InputDriverRec *passthruMouse;
+ xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
+ mPriv->vmmouseAvailable = FALSE;
+ passthruMouse = (InputDriverRec *)LoaderSymbol("MOUSE");
+ xfree(mPriv);
+ if(passthruMouse != NULL){
+ return (passthruMouse->PreInit)(drv, dev, flags);
+ } else {
+ return NULL;
+ }
+
+ } else {
+ /*
+ * vmmouse is available
+ */
+ mPriv->vmmouseAvailable = TRUE;
+ xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n");
+ /*
+ * Disable the absolute pointing device for now
+ * It will be enabled during DEVICE_ON phase
+ */
+ VMMouseClient_Disable();
+ }
+
+ if (!(pInfo = xf86AllocateInput(drv, 0))) {
+ xfree(mPriv);
+ return NULL;
+ }
+
+ /* Settup the pInfo */
+ pInfo->name = dev->identifier;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+ pInfo->device_control = VMMouseDeviceControl;
+ pInfo->read_input = VMMouseReadInput;
+ pInfo->motion_history_proc = xf86GetMotionEvents;
+ pInfo->control_proc = VMMouseControlProc;
+ pInfo->close_proc = VMMouseCloseProc;
+ pInfo->switch_mode = VMMouseSwitchMode;
+ pInfo->conversion_proc = VMMouseConvertProc;
+ pInfo->reverse_conversion_proc = NULL;
+ pInfo->fd = -1;
+ pInfo->dev = NULL;
+ pInfo->private_flags = 0;
+ pInfo->always_core_feedback = 0;
+ pInfo->conf_idev = dev;
+
+ /* Allocate the MouseDevRec and initialise it. */
+ if (!(pMse = xcalloc(sizeof(MouseDevRec), 1))) {
+ xfree(mPriv);
+ return pInfo;
+ }
+
+ pInfo->private = pMse;
+ pMse->Ctrl = MouseCtrl;
+ pMse->PostEvent = VMMousePostEvent;
+ pMse->CommonOptions = MouseCommonOptions;
+ pMse->mousePriv = mPriv;
+
+
+ /* Collect the options, and process the common options. */
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ /* Check if the device can be opened. */
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1) {
+ if (xf86GetAllowMouseOpenFail())
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ else {
+ xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
+ if (pMse->mousePriv)
+ xfree(pMse->mousePriv);
+ xfree(pMse);
+ pInfo->private = NULL;
+ return pInfo;
+ }
+ }
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+
+ /* Process the options */
+ pMse->CommonOptions(pInfo);
+
+ /* set up the current screen num */
+ mPriv->screenNum = xf86SetIntOption(pInfo->options, "ScreenNumber", 0);
+
+ pInfo->flags |= XI86_CONFIGURED;
+ return pInfo;
+}
+
+#ifdef XFree86LOADER
+static const OptionInfoRec *
+VMMouseAvailableOptions(void *unused)
+{
+ return (mouseOptions);
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MouseCtrl --
+ * Alter the control paramters for the mouse.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+
+ pInfo = device->public.devicePrivate;
+ pMse = pInfo->private;
+
+#ifdef EXTMOUSEDEBUG
+ xf86Msg(X_INFO, "VMMOUSE(0): MouseCtrl pMse=%p\n", pMse);
+#endif
+
+ pMse->num = ctrl->num;
+ pMse->den = ctrl->den;
+ pMse->threshold = ctrl->threshold;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseDoPostEvent --
+ * Post the mouse button event and mouse motion event to Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Mouse location and button status was updated
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ int truebuttons;
+ int id, change;
+
+ pMse = pInfo->private;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+
+ /*
+ * The following truebuttons/reverseBits and lastButtons are
+ * used to compare the current buttons and the previous buttons
+ * to find the button changes during two mouse events
+ */
+ truebuttons = buttons;
+
+ buttons = reverseBits(reverseMap, buttons);
+
+ if (dx || dy) {
+ xf86PostMotionEvent(pInfo->dev, !mPriv->relative, 0, 2, dx, dy);
+ }
+
+ if (truebuttons != pMse->lastButtons) {
+ change = buttons ^ reverseBits(reverseMap, pMse->lastButtons);
+ while (change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(pInfo->dev, 0, id,
+ (buttons & (1 << (id - 1))), 0, 0);
+ }
+ pMse->lastButtons = truebuttons;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePostEvent --
+ * Prepare the mouse status according to the Z axis mapping
+ * before we post the event to Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Buttons was updated according to Z axis mapping
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw)
+{
+ MouseDevPtr pMse;
+ int zbutton = 0;
+ VMMousePrivPtr mPriv;
+
+ pMse = pInfo->private;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ /* Map the Z axis movement. */
+ /* XXX Could this go in the conversion_proc? */
+ switch (pMse->negativeZ) {
+ case MSE_NOZMAP: /* do nothing */
+ break;
+ case MSE_MAPTOX:
+ if (dz != 0) {
+ if(mPriv->relative)
+ dx = dz;
+ else
+ dx += dz;
+ dz = 0;
+ }
+ break;
+ case MSE_MAPTOY:
+ if (dz != 0) {
+ if(mPriv->relative)
+ dy = dz;
+ else
+ dy += dz;
+ dz = 0;
+ }
+ break;
+ default: /* buttons */
+ buttons &= ~(pMse->negativeZ | pMse->positiveZ
+ | pMse->negativeW | pMse->positiveW);
+ if (dw < 0 || dz < -1) {
+ zbutton = pMse->negativeW;
+ }
+ else if (dz < 0) {
+ zbutton = pMse->negativeZ;
+ }
+ else if (dw > 0 || dz > 1) {
+ zbutton = pMse->positiveW;
+ }
+ else if (dz > 0) {
+ zbutton = pMse->positiveZ;
+ }
+ buttons |= zbutton;
+ dz = 0;
+ break;
+ }
+
+ VMMouseDoPostEvent(pInfo, buttons, dx, dy);
+
+ /*
+ * If dz has been mapped to a button `down' event, we need to cook up
+ * a corresponding button `up' event.
+ */
+ if (zbutton) {
+ buttons &= ~zbutton;
+ if(mPriv->relative)
+ VMMouseDoPostEvent(pInfo, buttons, 0, 0);
+ else
+ VMMouseDoPostEvent(pInfo, buttons, dx, dy);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FlushButtons --
+ *
+ * FlushButtons -- send button up events for sanity. It is called
+ * during DEVICE_ON in VMMouseDeviceControl
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+FlushButtons(MouseDevPtr pMse)
+{
+
+ /* If no button down is pending xf86PostButtonEvent()
+ * will discard them. So we are on the safe side. */
+
+ int i, blocked;
+
+ pMse->lastButtons = 0;
+
+ blocked = xf86BlockSIGIO ();
+ for (i = 1; i <= 5; i++)
+ xf86PostButtonEvent(pMse->device,0,i,0,0,0);
+ xf86UnblockSIGIO (blocked);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MouseCommonOptions --
+ * Process acceptable mouse options. Currently we only process
+ * "Buttons" and "ZAxisMapping" options.
+ * More options can be added later on
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * The buttons was setup according to the options
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MouseCommonOptions(InputInfoPtr pInfo)
+{
+ MouseDevPtr pMse;
+ MessageType from = X_DEFAULT;
+ char *s;
+ int origButtons;
+
+ pMse = pInfo->private;
+
+ pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
+ from = X_CONFIG;
+ if (!pMse->buttons) {
+ pMse->buttons = MSE_DFLTBUTTONS;
+ from = X_DEFAULT;
+ }
+ origButtons = pMse->buttons;
+
+ /*
+ * "emulate3Buttons" and "Drag Lock" is not supported
+ */
+
+ /*
+ * Process option for ZAxisMapping
+ */
+ s = xf86SetStrOption(pInfo->options, "ZAxisMapping", NULL);
+ if (s) {
+ int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+ char *msg = NULL;
+
+ if (!xf86NameCmp(s, "x")) {
+ pMse->negativeZ = pMse->positiveZ = MSE_MAPTOX;
+ pMse->negativeW = pMse->positiveW = MSE_MAPTOX;
+ msg = xstrdup("X axis");
+ } else if (!xf86NameCmp(s, "y")) {
+ pMse->negativeZ = pMse->positiveZ = MSE_MAPTOY;
+ pMse->negativeW = pMse->positiveW = MSE_MAPTOY;
+ msg = xstrdup("Y axis");
+ } else if (sscanf(s, "%d %d %d %d", &b1, &b2, &b3, &b4) >= 2 &&
+ b1 > 0 && b1 <= MSE_MAXBUTTONS &&
+ b2 > 0 && b2 <= MSE_MAXBUTTONS) {
+ msg = xstrdup("buttons XX and YY");
+ if (msg)
+ sprintf(msg, "buttons %d and %d", b1, b2);
+ pMse->negativeZ = pMse->negativeW = 1 << (b1-1);
+ pMse->positiveZ = pMse->positiveW = 1 << (b2-1);
+ if (b1 > pMse->buttons) pMse->buttons = b1;
+ if (b2 > pMse->buttons) pMse->buttons = b2;
+
+ /*
+ * Option "ZAxisMapping" "N1 N2 N3 N4" not supported
+ */
+ pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
+ } else {
+ pMse->negativeZ = pMse->positiveZ = MSE_NOZMAP;
+ pMse->negativeW = pMse->positiveW = MSE_NOZMAP;
+ }
+ if (msg) {
+ xf86Msg(X_CONFIG, "%s: ZAxisMapping: %s\n", pInfo->name, msg);
+ xfree(msg);
+ } else {
+ xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n",
+ pInfo->name, s);
+ }
+ }
+
+ /*
+ * Emulatewheel is not supported
+ */
+ if (origButtons != pMse->buttons)
+ from = X_CONFIG;
+
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseUnInit --
+ * This function was supposed to be called by Xserver to do Un-Init.
+ * But it was unused now
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseUnInit(InputDriverPtr drv, LocalDevicePtr local, int flags)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseDeviceControl --
+ * This function was called by Xserver during DEVICE_INIT, DEVICE_ON,
+ * DEVICE_OFF and DEVICE_CLOSE phase
+ *
+ * Results:
+ * TRUE, if sucessful
+ * FALSE, if failed
+ *
+ * Side effects:
+ * Absolute pointing device is enabled during DEVICE_ON
+ * Absolute pointing device is disabled during DEVICE_OFF
+ * and DEVICE_CLOSE
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+VMMouseDeviceControl(DeviceIntPtr device, int mode)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ unsigned char map[MSE_MAXBUTTONS + 1];
+ int i;
+
+ pInfo = device->public.devicePrivate;
+ pMse = pInfo->private;
+ pMse->device = device;
+ mPriv = (VMMousePrivPtr)pMse->mousePriv;
+
+ switch (mode){
+ case DEVICE_INIT:
+ device->public.on = FALSE;
+ /*
+ * [KAZU-241097] We don't know exactly how many buttons the
+ * device has, so setup the map with the maximum number.
+ */
+ for (i = 0; i < MSE_MAXBUTTONS; i++)
+ map[i + 1] = i + 1;
+
+ InitPointerDeviceStruct((DevicePtr)device, map,
+ min(pMse->buttons, MSE_MAXBUTTONS),
+ miPointerGetMotionEvents, pMse->Ctrl,
+ miPointerGetMotionBufferSize());
+
+ /* X valuator */
+ xf86InitValuatorAxisStruct(device, 0, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(device, 0);
+ /* Y valuator */
+ xf86InitValuatorAxisStruct(device, 1, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(device, 1);
+ xf86MotionHistoryAllocate(pInfo);
+
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n");
+#ifdef EXTMOUSEDEBUG
+ xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom,
+ pInfo->name);
+#endif
+ break;
+
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n");
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1)
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ else {
+ pMse->buffer = XisbNew(pInfo->fd, 64);
+ if (!pMse->buffer) {
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ } else {
+ VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ if (mPriv != NULL) {
+ /*
+ * enable absolute pointing device here
+ */
+ if (!VMMouseClient_Enable()) {
+ xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n");
+ mPriv->vmmouseAvailable = FALSE;
+ device->public.on = FALSE;
+ return FALSE;
+ } else {
+ mPriv->vmmouseAvailable = TRUE;
+ VMMouseClient_RequestAbsolute();
+ mPriv->relative = FALSE;
+ xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n");
+ }
+ }
+ xf86FlushInput(pInfo->fd);
+ xf86AddEnabledDevice(pInfo);
+ }
+ }
+ pMse->lastButtons = 0;
+ device->public.on = TRUE;
+ FlushButtons(pMse);
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n");
+
+ if (pInfo->fd != -1) {
+ VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv;
+ if( mPriv->vmmouseAvailable ) {
+ VMMouseClient_Disable();
+ mPriv->vmmouseAvailable = FALSE;
+ }
+
+ xf86RemoveEnabledDevice(pInfo);
+ if (pMse->buffer) {
+ XisbFree(pMse->buffer);
+ pMse->buffer = NULL;
+ }
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ device->public.on = FALSE;
+ usleep(300000);
+ break;
+
+ }
+
+ return Success;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseReadInput --
+ * This function was called by Xserver when there is data available
+ * in the input device
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Input data in regular PS/2 fd was cleared
+ * Real mouse data was read from the absolute pointing device
+ * and posted to Xserver
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseReadInput(InputInfoPtr pInfo)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ int c;
+ int len = 0;
+
+ pMse = pInfo->private;
+ mPriv = pMse->mousePriv;
+
+ /*
+ * First read the bytes in input device to clear the regular PS/2 fd so
+ * we don't get called again.
+ */
+ /*
+ * Set blocking to -1 on the first call because we know there is data to
+ * read. Xisb automatically clears it after one successful read so that
+ * succeeding reads are preceeded by a select with a 0 timeout to prevent
+ * read from blocking indefinitely.
+ */
+ XisbBlockDuration(pMse->buffer, -1);
+ while ((c = XisbRead(pMse->buffer)) >= 0) {
+ len++;
+ /*
+ * regular PS packet consists of 3 bytes
+ * We read 3 bytes to drain the PS/2 packet
+ */
+ if(len < 3) continue;
+ len = 0;
+ /*
+ * Now get the real data from absolute pointing device
+ */
+ GetVMMouseMotionEvent(pInfo);
+ }
+ /*
+ * There maybe still vmmouse data available
+ */
+ GetVMMouseMotionEvent(pInfo);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetVMMouseMotionEvent --
+ * Read all the mouse data available from the absolute
+ * pointing device and post it to the Xserver
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Real mouse data was read from the absolute pointing
+ * device and posted to Xserver
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetVMMouseMotionEvent(InputInfoPtr pInfo){
+ MouseDevPtr pMse;
+ int buttons, dx, dy, dz, dw;
+ VMMOUSE_INPUT_DATA vmmouseInput;
+ int ps2Buttons = 0;
+
+ pMse = pInfo->private;
+ while(VMMouseClient_GetInput(&vmmouseInput)){
+ if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON)
+ ps2Buttons |= 0x04; /* Middle*/
+ if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON)
+ ps2Buttons |= 0x02; /* Right*/
+ if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON)
+ ps2Buttons |= 0x01; /* Left*/
+
+ buttons = (ps2Buttons & 0x04) >> 1 | /* Middle */
+ (ps2Buttons & 0x02) >> 1 | /* Right */
+ (ps2Buttons & 0x01) << 2; /* Left */
+
+ dx = vmmouseInput.X;
+ dy = vmmouseInput.Y;
+ dz = (char)vmmouseInput.Z;
+ dw = 0;
+ /* post an event */
+ pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseControlProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n");
+ return (Success);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseCloseProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseCloseProc(LocalDevicePtr local)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseSwitchProc --
+ * This function is unused
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n");
+ return (Success);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseConvertProc --
+ * This function was called by Xserver to convert valuators to X and Y
+ *
+ * Results:
+ * TRUE
+ *
+ * Side effects:
+ * X and Y was converted according to current Screen dimension
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y)
+{
+ MouseDevPtr pMse;
+ VMMousePrivPtr mPriv;
+ double factorX, factorY;
+
+ pMse = pInfo->private;
+ mPriv = pMse->mousePriv;
+
+ if (first != 0 || num != 2)
+ return FALSE;
+
+ if(mPriv->relative) {
+ *x = v0;
+ *y = v1;
+ } else {
+ factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535;
+ factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535;
+
+ *x = v0 * factorX + 0.5;
+ *y = v1 * factorY + 0.5;
+
+ if (mPriv->screenNum != -1) {
+ xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y);
+ }
+ }
+ return TRUE;
+}
+
+
+#ifdef XFree86LOADER
+ModuleInfoRec VMMouseInfo = {
+ 1,
+ "VMMOUSE",
+ NULL,
+ 0,
+ VMMouseAvailableOptions,
+};
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseUnplug --
+ * This function was called by Xserver when unplug
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VMMouseUnplug(pointer p)
+{
+ xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMousePlug --
+ * This function was called when Xserver load vmmouse module. It will
+ * integrate the module infto the XFree86 loader architecutre.
+ *
+ * Results:
+ * TRUE
+ *
+ * Side effects:
+ * Regular mouse module was loaded as a submodule. In case
+ * absolute pointing device is not available, we can always fall back
+ * to the regular mouse module
+ *
+ *----------------------------------------------------------------------
+ */
+
+static pointer
+VMMousePlug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ static Bool Initialised = FALSE;
+ char *name;
+
+ xf86LoaderReqSymLists(reqSymbols, NULL);
+
+ if (!Initialised) {
+ Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+ if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+ xf86AddModuleInfo(&VMMouseInfo, module);
+ }
+
+ xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n");
+ xf86AddInputDriver(&VMMOUSE, module, 0);
+
+ /*
+ * Load the normal mouse module as submodule
+ * If we fail in PreInit later, this allows us to fall back to normal mouse module
+ */
+#ifndef NORMALISE_MODULE_NAME
+ name = xstrdup("mouse");
+#else
+ /* Normalise the module name */
+ name = xf86NormalizeName("mouse");
+#endif
+
+ if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) {
+ LoaderErrorMsg(NULL, name, *errmaj, *errmin);
+ }
+ xfree(name);
+
+ return module;
+}
+
+static XF86ModuleVersionInfo VMMouseVersionRec = {
+ "vmmouse",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ VMMOUSE_MAJOR_VERSION, VMMOUSE_MINOR_VERSION, VMMOUSE_PATCHLEVEL,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0} /* signature, to be patched into the file by a tool */
+};
+
+/*
+ * The variable contains the necessary information to load and initialize the module
+ */
+XF86ModuleData vmmouseModuleData = {
+ &VMMouseVersionRec,
+ VMMousePlug,
+ VMMouseUnplug
+};
+#endif /* XFree86LOADER */
diff --git a/src/vmmouse_client.c b/src/vmmouse_client.c
new file mode 100644
index 0000000..5f27e54
--- /dev/null
+++ b/src/vmmouse_client.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2002-2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmmouse_client.c --
+ *
+ * VMware Virtual Mouse Client
+ *
+ * This module provides functions to enable, operate and process
+ * packets via the VMMouse module hosted in the VMX.
+ *
+ */
+
+#include "vmmouse_client.h"
+#include "vmmouse_proto.h"
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMMouseClientVMCheck --
+ *
+ * Checks if we're running in a VM by sending the GETVERSION command.
+ *
+ * Returns:
+ * 0 if we're running natively/the version command failed,
+ * 1 if we're in a VM.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VMMouseClientVMCheck(void)
+{
+ VMMouseProtoCmd vmpc;
+
+ vmpc.in.vEbx = ~VMMOUSE_PROTO_MAGIC;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_GETVERSION;
+ VMMouseProto_SendCmd(&vmpc);
+
+ /*
+ * ebx should contain VMMOUSE_PROTO_MAGIC
+ * eax should contain version
+ */
+ if (vmpc.out.vEbx != VMMOUSE_PROTO_MAGIC || vmpc.out.vEax == 0xffffffff) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseClient_Disable --
+ *
+ * Tries to disable VMMouse communication mode on the host.
+ * The caller is responsible for maintaining state (we don't check
+ * if we're enabled before attempting to disable the VMMouse).
+ *
+ * Results:
+ * TRUE if we successfully disable the VMMouse communication mode,
+ * FALSE if something went wrong.
+ *
+ * Side effects:
+ * Disables the absolute positioning mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+VMMouseClient_Disable(void)
+{
+ uint32_t status;
+ VMMouseProtoCmd vmpc;
+
+ VMwareLog(("VMMouseClient_Disable: writing disable command to port\n"));
+ vmpc.in.vEbx = VMMOUSE_CMD_DISABLE;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
+ VMMouseProto_SendCmd(&vmpc);
+ /*
+ * We should get 0xffff in the flags now.
+ */
+ vmpc.in.vEbx = 0;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
+ VMMouseProto_SendCmd(&vmpc);
+ status = vmpc.out.vEax;
+ if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR) {
+ VMwareLog(("VMMouseClient_Disable: wrong status returned\n"));
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseClient_Enable --
+ *
+ * Public Enable entry point. The driver calls this once it feels
+ * ready to deal with VMMouse stuff. For now, we just try to enable
+ * and return the result, but conceivably we could do more.
+ *
+ * Results:
+ * TRUE if the enable succeeds, FALSE otherwise.
+ *
+ * Side effects:
+ * Causes host-side state change.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+VMMouseClient_Enable(void) {
+
+ uint32_t status;
+ uint32_t data;
+ VMMouseProtoCmd vmpc;
+
+ /*
+ * First, make sure we're in a VM; i.e. in dualboot configurations we might
+ * find ourselves running on real hardware.
+ */
+
+ if (!VMMouseClientVMCheck()) {
+ return FALSE;
+ }
+
+ VMwareLog(("VMMouseClientVMCheck succeeded, checking VMMOUSE version\n"));
+ VMwareLog(("VMMouseClient_Enable: READ_ID 0x%08x, VERSION_ID 0x%08x\n",
+ VMMOUSE_CMD_READ_ID, VMMOUSE_VERSION_ID));
+
+ /*
+ * We probe for the VMMouse backend by sending the ENABLE
+ * command to the mouse. We should get back the VERSION_ID on
+ * the data port.
+ */
+ vmpc.in.vEbx = VMMOUSE_CMD_READ_ID;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
+ VMMouseProto_SendCmd(&vmpc);
+
+ /*
+ * Check whether the VMMOUSE_VERSION_ID is available to read
+ */
+ vmpc.in.vEbx = 0;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
+ VMMouseProto_SendCmd(&vmpc);
+ status = vmpc.out.vEax;
+ if ((status & 0x0000ffff) == 0) {
+ VMwareLog(("VMMouseClient_Enable: no data on port."));
+ return FALSE;
+ }
+
+ /*
+ * Get the VMMOUSE_VERSION_ID then
+ */
+ /* Get just one item */
+ vmpc.in.vEbx = 1;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_DATA;
+ VMMouseProto_SendCmd(&vmpc);
+ data = vmpc.out.vEax;
+ if (data!= VMMOUSE_VERSION_ID) {
+ VMwareLog(("VMMouseClient_Enable: data was not VERSION_ID"));
+ return FALSE;
+ }
+
+ /*
+ * To quote Jeremy, "Go Go Go!"
+ */
+
+ VMwareLog(("VMMouseClient_Enable: go go go!\n"));
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMMouseClient_GetInput --
+ *
+ * Retrieves a 4-word input packet from the VMMouse data port and
+ * stores it in the specified input structure.
+ *
+ * Results:
+ * The number of packets in the queue, including the retrieved
+ * packet.
+ *
+ * Side effects:
+ * Could cause host state change.
+ *
+ *----------------------------------------------------------------------
+ */
+
+unsigned int
+VMMouseClient_GetInput (PVMMOUSE_INPUT_DATA pvmmouseInput) {
+
+ uint32_t status;
+ uint16_t numWords;
+ uint32_t packetInfo;
+ VMMouseProtoCmd vmpc;
+
+ /*
+ * The status dword has two parts: the high 16 bits are
+ * for flags, the low 16-bits are the number of DWORDs
+ * waiting in the data queue. VMMOUSE_ERROR is a special
+ * case that indicates there's something wrong on the
+ * host end, e.g. the VMMouse was disabled on the host-side.
+ */
+ vmpc.in.vEbx = 0;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS;
+ VMMouseProto_SendCmd(&vmpc);
+ status = vmpc.out.vEax;
+ if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
+ VMwareLog(("VMMouseClient_GetInput: VMMOUSE_ERROR status, abort!\n"));
+ return VMMOUSE_ERROR;
+ }
+
+ /*
+ * We don't use the status flags, just get the words
+ */
+ numWords = status & 0x0000ffff;
+
+ if ((numWords % 4) != 0) {
+ VMwareLog(("VMMouseClient_GetInput: invalid status numWords, abort!\n"));
+ return (0);
+ }
+
+ if (numWords == 0) {
+ return (0);
+ }
+
+ /*
+ * The VMMouse uses a 4-dword packet protocol:
+ * DWORD 0: Button State and per-packet flags
+ * DWORD 1: X position (absolute or relative)
+ * DWORD 2: Y position (absolute or relative)
+ * DWORD 3: Z position (relative)
+ */
+ /* Get 4 items at once */
+ vmpc.in.vEbx = 4;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_DATA;
+ VMMouseProto_SendCmd(&vmpc);
+ packetInfo = vmpc.out.vEax;
+ pvmmouseInput->Flags = (packetInfo & 0xffff0000) >> 16;
+ pvmmouseInput->Buttons = (packetInfo & 0x0000ffff);
+
+ pvmmouseInput->X = vmpc.out.vEbx & 0xffff;
+ pvmmouseInput->Y = vmpc.out.vEcx & 0xffff;
+ pvmmouseInput->Z = (int)vmpc.out.vEdx;
+ /*
+ * Return number of packets (including this one) in queue.
+ */
+ return (numWords >> 2);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMMouseClient_RequestRelative --
+ *
+ * Request that the host switch to posting relative packets. It's just
+ * advisory, so we make no guarantees about if/when the switch will
+ * happen.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Host may start posting relative packets in the near future.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+VMMouseClient_RequestRelative(void)
+{
+ VMMouseProtoCmd vmpc;
+
+ VMwareLog(("VMMouseClient: requesting relative mode\n"));
+ vmpc.in.vEbx = VMMOUSE_CMD_REQUEST_RELATIVE;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
+ VMMouseProto_SendCmd(&vmpc);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMMouseClient_RequestAbsolute --
+ *
+ * Request that the host switch to posting absolute packets. It's just
+ * advisory, so we make no guarantees about if/when the switch will
+ * happen.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Host may start posting absolute packets in the near future.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+VMMouseClient_RequestAbsolute(void)
+{
+ VMMouseProtoCmd vmpc;
+
+ VMwareLog(("VMMouseClient: requesting absolute mode\n"));
+ vmpc.in.vEbx = VMMOUSE_CMD_REQUEST_ABSOLUTE;
+ vmpc.in.command = VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND;
+ VMMouseProto_SendCmd(&vmpc);
+}
diff --git a/src/vmmouse_client.h b/src/vmmouse_client.h
new file mode 100644
index 0000000..b01bf08
--- /dev/null
+++ b/src/vmmouse_client.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmmouse_client.h --
+ *
+ * VMware Virtual Mouse Client
+ *
+ * This module provides functions to enable/disable, operate and
+ * process packets via the VMMouse absolute positioning module
+ * hosted in the VMX.
+ *
+ */
+
+#ifndef _VMMOUSE_CLIENT_H_
+#define _VMMOUSE_CLIENT_H_
+
+#include "xf86_OSproc.h"
+
+/*
+ * VMMouse Input packet data structure
+ */
+typedef struct _VMMOUSE_INPUT_DATA {
+ unsigned short Flags;
+ unsigned short Buttons;
+ int X;
+ int Y;
+ int Z;
+} VMMOUSE_INPUT_DATA, *PVMMOUSE_INPUT_DATA;
+
+/*
+ * Public Functions
+ */
+Bool VMMouseClient_Enable(void);
+void VMMouseClient_Disable(void);
+unsigned int VMMouseClient_GetInput(PVMMOUSE_INPUT_DATA pvmmouseInput);
+void VMMouseClient_RequestRelative(void);
+void VMMouseClient_RequestAbsolute(void);
+
+#ifdef VMX86_DEVEL
+#define VMwareLog(args) ErrorF args
+#else
+#define VMwareLog(args)
+#endif
+
+#include "vmmouse_defs.h"
+
+#endif /* _VMMOUSE_CLIENT_H_ */
+
diff --git a/src/vmmouse_defs.h b/src/vmmouse_defs.h
new file mode 100644
index 0000000..8dc769e
--- /dev/null
+++ b/src/vmmouse_defs.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmmouse_defs.h --
+ *
+ * VMware Virtual Mouse Protocol definitions. These constants
+ * are shared by the host-side VMMouse module and
+ * the guest tools/drivers.
+ *
+ */
+
+#ifndef _VMMOUSE_DEFS_H_
+#define _VMMOUSE_DEFS_H_
+
+/*
+ * Command related defines
+ */
+#define VMMOUSE_CMD_READ_ID 0x45414552
+#define VMMOUSE_CMD_DISABLE 0x000000f5
+#define VMMOUSE_CMD_REQUEST_RELATIVE 0x4c455252
+#define VMMOUSE_CMD_REQUEST_ABSOLUTE 0x53424152
+
+/*
+ * Data related defines
+ */
+#define VMMOUSE_VERSION_ID_STR "JUB4"
+#define VMMOUSE_VERSION_ID 0x3442554a
+
+/*
+ * Device related defines
+ */
+#define VMMOUSE_ERROR 0xffff0000
+
+/*
+ * VMMouse Input button flags
+ */
+#define VMMOUSE_LEFT_BUTTON 0x20
+#define VMMOUSE_RIGHT_BUTTON 0x10
+#define VMMOUSE_MIDDLE_BUTTON 0x08
+
+#endif
diff --git a/src/vmmouse_proto.c b/src/vmmouse_proto.c
new file mode 100644
index 0000000..186c2e8
--- /dev/null
+++ b/src/vmmouse_proto.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 1999-2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmmouse_proto.c --
+ *
+ * The communication protocol between the guest and the vmmouse
+ * virtual device.
+ */
+
+
+#include "vmmouse_proto.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMMouseProtoInOut --
+ *
+ * Send a low-bandwidth basic request (16 bytes) to vmware, and return its
+ * reply (24 bytes).
+ *
+ * Results:
+ * Host-side response returned in cmd IN/OUT parameter.
+ *
+ * Side effects:
+ * Pokes the communication port.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VMMouseProtoInOut(VMMouseProtoCmd *cmd) // IN/OUT
+{
+#ifdef __x86_64__
+ uint64_t dummy;
+
+ __asm__ __volatile__(
+ "pushq %%rax" "\n\t"
+ "movq 40(%%rax), %%rdi" "\n\t"
+ "movq 32(%%rax), %%rsi" "\n\t"
+ "movq 24(%%rax), %%rdx" "\n\t"
+ "movq 16(%%rax), %%rcx" "\n\t"
+ "movq 8(%%rax), %%rbx" "\n\t"
+ "movq (%%rax), %%rax" "\n\t"
+ "inl %%dx, %%eax" "\n\t" /* NB: There is no inq instruction */
+ "xchgq %%rax, (%%rsp)" "\n\t"
+ "movq %%rdi, 40(%%rax)" "\n\t"
+ "movq %%rsi, 32(%%rax)" "\n\t"
+ "movq %%rdx, 24(%%rax)" "\n\t"
+ "movq %%rcx, 16(%%rax)" "\n\t"
+ "movq %%rbx, 8(%%rax)" "\n\t"
+ "popq (%%rax)"
+ : "=a" (dummy)
+ : "0" (cmd)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ : "rbx", "rcx", "rdx", "rsi", "rdi", "memory"
+ );
+#else
+#ifdef __i386__
+ uint32_t dummy;
+
+ __asm__ __volatile__(
+ "pushl %%eax" "\n\t"
+ "movl 20(%%eax), %%edi" "\n\t"
+ "movl 16(%%eax), %%esi" "\n\t"
+ "movl 12(%%eax), %%edx" "\n\t"
+ "movl 8(%%eax), %%ecx" "\n\t"
+ "movl 4(%%eax), %%ebx" "\n\t"
+ "movl (%%eax), %%eax" "\n\t"
+ "inl %%dx, %%eax" "\n\t"
+ "xchgl %%eax, (%%esp)" "\n\t"
+ "movl %%edi, 20(%%eax)" "\n\t"
+ "movl %%esi, 16(%%eax)" "\n\t"
+ "movl %%edx, 12(%%eax)" "\n\t"
+ "movl %%ecx, 8(%%eax)" "\n\t"
+ "movl %%ebx, 4(%%eax)" "\n\t"
+ "popl (%%eax)"
+ : "=a" (dummy)
+ : "0" (cmd)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ : "ebx", "ecx", "edx", "esi", "edi", "memory"
+ );
+#else
+#error "VMMouse is only supported on x86 and x86-64."
+#endif
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMMouseProto_SendCmd --
+ *
+ * Send a request (16 bytes) to vmware, and synchronously return its
+ * reply (24 bytes).
+ *
+ * Result:
+ * None
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMMouseProto_SendCmd(VMMouseProtoCmd *cmd) // IN/OUT
+{
+ cmd->in.magic = VMMOUSE_PROTO_MAGIC;
+ cmd->in.port = VMMOUSE_PROTO_PORT;
+
+ VMMouseProtoInOut(cmd);
+}
diff --git a/src/vmmouse_proto.h b/src/vmmouse_proto.h
new file mode 100644
index 0000000..fa7dff1
--- /dev/null
+++ b/src/vmmouse_proto.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 1999-2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmmouse_proto.h --
+ *
+ * The communication protocol between the guest and the vmmouse
+ * virtual device.
+ */
+
+
+#ifndef _VMMOUSE_PROTO_H_
+#define _VMMOUSE_PROTO_H_
+
+#include <stdint.h>
+#include "xf86_libc.h"
+
+#if !defined __i386__ && !defined __x86_64__
+#error The vmmouse protocol is only supported on x86 architectures.
+#endif
+
+#define VMMOUSE_PROTO_MAGIC 0x564D5868
+#define VMMOUSE_PROTO_PORT 0x5658
+
+#define VMMOUSE_PROTO_CMD_GETVERSION 10
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA 39
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS 40
+#define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND 41
+
+#define DECLARE_REG32_STRUCT(_r) \
+ union { \
+ struct { \
+ uint16_t low; \
+ uint16_t high; \
+ } vE##_r##_; \
+ uint32_t vE##_r; \
+ }
+
+#ifdef VM_X86_64
+
+#define DECLARE_REG64_STRUCT(_r) \
+ union { \
+ DECLARE_REG32_STRUCT(_r); \
+ struct { \
+ uint32_t low; \
+ uint32_t high; \
+ } vR##_r##_; \
+ uint64_t vR##_r; \
+ }
+
+#define DECLARE_REG_STRUCT(x) DECLARE_REG64_STRUCT(x)
+
+#else
+
+#define DECLARE_REG_STRUCT(x) DECLARE_REG32_STRUCT(x)
+
+#endif
+
+typedef union {
+ struct {
+ union {
+ uint32_t magic;
+ DECLARE_REG_STRUCT(ax);
+ };
+ union {
+ size_t size;
+ DECLARE_REG_STRUCT(bx);
+ };
+ union {
+ uint16_t command;
+ DECLARE_REG_STRUCT(cx);
+ };
+ union {
+ uint16_t port;
+ DECLARE_REG_STRUCT(dx);
+ };
+ DECLARE_REG_STRUCT(si);
+ DECLARE_REG_STRUCT(di);
+ } in;
+ struct {
+ DECLARE_REG_STRUCT(ax);
+ DECLARE_REG_STRUCT(bx);
+ DECLARE_REG_STRUCT(cx);
+ DECLARE_REG_STRUCT(dx);
+ DECLARE_REG_STRUCT(si);
+ DECLARE_REG_STRUCT(di);
+ } out;
+} VMMouseProtoCmd;
+
+
+void
+VMMouseProto_SendCmd(VMMouseProtoCmd *cmd); // IN/OUT
+
+
+#undef DECLARE_REG_STRUCT
+
+#endif /* _VMMOUSE_PROTO_H_ */