From ee148a2f8ef97557ec2db501295ed8227699d2bf Mon Sep 17 00:00:00 2001 From: philipl Date: Mon, 9 Jan 2006 19:12:26 +0000 Subject: [PATCH] Initial release of the vmmouse driver for VMware virtual machines. --- .cvsignore | 19 + COPYING | 23 + ChangeLog | 3 + INSTALL | 231 +++++++++ Makefile.am | 22 + README | 53 ++ autogen.sh | 12 + configure.ac | 92 ++++ man/Makefile.am | 59 +++ man/vmmouse.man | 228 ++++++++ src/Makefile.am | 36 ++ src/vmmouse.c | 1173 ++++++++++++++++++++++++++++++++++++++++++ src/vmmouse_client.c | 337 ++++++++++++ src/vmmouse_client.h | 73 +++ src/vmmouse_defs.h | 66 +++ src/vmmouse_proto.c | 145 ++++++ src/vmmouse_proto.h | 121 +++++ 17 files changed, 2693 insertions(+) create mode 100644 .cvsignore create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 man/Makefile.am create mode 100644 man/vmmouse.man create mode 100644 src/Makefile.am create mode 100644 src/vmmouse.c create mode 100644 src/vmmouse_client.c create mode 100644 src/vmmouse_client.h create mode 100644 src/vmmouse_defs.h create mode 100644 src/vmmouse_proto.c create mode 100644 src/vmmouse_proto.h 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 + + * 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 + * 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 +#include + +#include "xf86.h" + +#ifdef XINPUT +#include +#include +#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 +#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_ */