diff options
-rw-r--r-- | .cvsignore | 19 | ||||
-rw-r--r-- | COPYING | 23 | ||||
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | INSTALL | 231 | ||||
-rw-r--r-- | Makefile.am | 22 | ||||
-rw-r--r-- | README | 53 | ||||
-rwxr-xr-x | autogen.sh | 12 | ||||
-rw-r--r-- | configure.ac | 92 | ||||
-rw-r--r-- | man/Makefile.am | 59 | ||||
-rw-r--r-- | man/vmmouse.man | 228 | ||||
-rw-r--r-- | src/Makefile.am | 36 | ||||
-rw-r--r-- | src/vmmouse.c | 1173 | ||||
-rw-r--r-- | src/vmmouse_client.c | 337 | ||||
-rw-r--r-- | src/vmmouse_client.h | 73 | ||||
-rw-r--r-- | src/vmmouse_defs.h | 66 | ||||
-rw-r--r-- | src/vmmouse_proto.c | 145 | ||||
-rw-r--r-- | src/vmmouse_proto.h | 121 |
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 @@ -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. @@ -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 @@ -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_ */ |