summaryrefslogtreecommitdiff
path: root/src/xf86Wacom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xf86Wacom.c')
-rw-r--r--src/xf86Wacom.c4070
1 files changed, 4070 insertions, 0 deletions
diff --git a/src/xf86Wacom.c b/src/xf86Wacom.c
new file mode 100644
index 0000000..7924bd4
--- /dev/null
+++ b/src/xf86Wacom.c
@@ -0,0 +1,4070 @@
+/* $XConsortium: xf86Wacom.c /main/20 1996/10/27 11:05:20 kaleb $ */
+/*
+ * Copyright 1995-2002 by Frederic Lepied, France. <Lepied@XFree86.org>
+ *
+ * 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 name of Frederic Lepied not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Frederic Lepied makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL FREDERIC LEPIED 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.
+ *
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/input/wacom/xf86Wacom.c,v 1.26 2001/04/01 14:00:13 tsi Exp $ */
+
+/*
+ * This driver is only able to handle the Wacom IV and Wacom V protocols.
+ *
+ * Wacom V protocol work done by Raph Levien <raph@gtk.org> and
+ * Frédéric Lepied <lepied@xfree86.org>.
+ *
+ * Many thanks to Dave Fleck from Wacom for the help provided to
+ * build this driver.
+ *
+ * Modified for Linux USB by MATSUMURA Namihiko,
+ * Daniel Egger, Germany. <egger@suse.de>,
+ * Frederic Lepied <lepied@xfree86.org>,
+ * Brion Vibber <brion@pobox.com>,
+ * Aaron Optimizer Digulla <digulla@hepe.com>,
+ * Jonathan Layes <jonathan@layes.com>.
+ *
+ */
+
+/*
+ * TO XFREE86 THE MAINTAINERS: don't remove the 3.3 code as I continue to maintain it.
+ * Discuss with me before changing things in this driver!
+ *
+ * Fred
+ */
+
+/*
+ * REVISION HISTORY
+ *
+ * 2002-12-17 26-j0.3.3 - added Intuos2
+ */
+
+static const char identification[] = "$Identification: 26-j0.3.3 $";
+
+#include "xf86Version.h"
+
+#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(3,9,0,0,0)
+#define XFREE86_V4 1
+#endif
+
+#ifdef LINUX_INPUT
+#include <asm/types.h>
+#include <linux/input.h>
+
+/* 2.4.5 module support */
+#ifndef EV_MSC
+#define EV_MSC 0x04
+#endif
+
+#ifndef MSC_SERIAL
+#define MSC_SERIAL 0x00
+#endif
+
+/* max number of input events to read in one read call */
+#define MAX_EVENTS 50
+
+/* keithp - a hack to avoid redefinitions of these in xf86str.h */
+#ifdef BUS_PCI
+#undef BUS_PCI
+#endif
+#ifdef BUS_ISA
+#undef BUS_ISA
+#endif
+#endif
+
+#ifdef XFREE86_V4
+/* post 3.9 headers */
+
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "misc.h"
+#include "xf86.h"
+#define NEED_XF86_TYPES
+#if !defined(DGUX)
+#include "xf86_ansic.h"
+#include "xisb.h"
+#endif
+#include "xf86_OSproc.h"
+#include "xf86Xinput.h"
+#include "exevents.h" /* Needed for InitValuator/Proximity stuff */
+#include "keysym.h"
+#include "mipointer.h"
+
+#ifdef XFree86LOADER
+#include "xf86Module.h"
+#endif
+
+#undef sleep
+#define sleep(t) xf86WaitForInput(-1, 1000 * (t))
+#define wait_for_fd(fd) xf86WaitForInput((fd), 1000000)
+#define tcflush(fd, n) xf86FlushInput((fd))
+#undef read
+#define read(a,b,c) xf86ReadSerial((a),(b),(c))
+#undef write
+#define write(a,b,c) xf86WriteSerial((a),(char*)(b),(c))
+#undef close
+#define close(a) xf86CloseSerial((a))
+#define XCONFIG_PROBED "(==)"
+#define XCONFIG_GIVEN "(**)"
+#define xf86Verbose 1
+#undef PRIVATE
+#define PRIVATE(x) XI_PRIVATE(x)
+
+/*
+ * Be sure to set vmin appropriately for your device's protocol. You want to
+ * read a full packet before returning
+ */
+static const char *default_options[] =
+{
+ "BaudRate", "9600",
+ "StopBits", "1",
+ "DataBits", "8",
+ "Parity", "None",
+ "Vmin", "1",
+ "Vtime", "10",
+ "FlowControl", "Xoff",
+ NULL
+};
+
+static InputDriverPtr wcmDrv;
+
+#else /* pre 3.9 headers */
+
+#include "Xos.h"
+#include <signal.h>
+#include <stdio.h>
+
+#define NEED_EVENTS
+#include "X.h"
+#include "Xproto.h"
+#include "misc.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "XI.h"
+#include "XIproto.h"
+#include "keysym.h"
+
+#if defined(sun) && !defined(i386)
+#define POSIX_TTY
+#include <errno.h>
+#include <termio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "extio.h"
+#else
+#include "compiler.h"
+
+#include "xf86.h"
+#include "xf86Procs.h"
+#include "xf86_OSlib.h"
+#include "xf86_Config.h"
+#include "xf86Xinput.h"
+#include "atKeynames.h"
+#include "xf86Version.h"
+#endif
+
+#if !defined(sun) || defined(i386)
+#include "osdep.h"
+#include "exevents.h"
+
+#include "extnsionst.h"
+#include "extinit.h"
+#endif
+
+#endif /* Pre 3.9 headers */
+
+#if defined(__QNX__) || defined(__QNXNTO__)
+#define POSIX_TTY
+#endif
+
+/******************************************************************************
+ * debugging macro
+ *****************************************************************************/
+#ifdef DBG
+#undef DBG
+#endif
+#ifdef DEBUG
+#undef DEBUG
+#endif
+
+static int debug_level = 0;
+#define DEBUG 1
+#if DEBUG
+#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
+#else
+#define DBG(lvl, f)
+#endif
+
+#define ABS(x) ((x) > 0 ? (x) : -(x))
+
+/******************************************************************************
+ * WacomDeviceRec flags
+ *****************************************************************************/
+#define DEVICE_ID(flags) ((flags) & 0x07)
+
+#define STYLUS_ID 1
+#define CURSOR_ID 2
+#define ERASER_ID 4
+#define ABSOLUTE_FLAG 8
+#define FIRST_TOUCH_FLAG 16
+#define KEEP_SHAPE_FLAG 32
+#define BAUD_19200_FLAG 64
+#define BETA_FLAG 128
+
+/******************************************************************************
+ * WacomCommonRec flags
+ *****************************************************************************/
+#define TILT_FLAG 1
+#define GRAPHIRE_FLAG 2
+
+typedef struct
+{
+ int state;
+ int coord[3];
+ int tilt[3];
+} WacomFilterState;
+
+typedef struct
+{
+ int device_id;
+ int device_type;
+ unsigned int serial_num;
+ int x;
+ int y;
+ int buttons;
+ int pressure;
+ int tiltx;
+ int tilty;
+ int rotation;
+ int wheel;
+ int discard_first;
+ int proximity;
+ WacomFilterState x_filter;
+ WacomFilterState y_filter;
+} WacomDeviceState;
+
+#define PEN(ds) (((ds->device_id) & 0x07ff) == 0x0022 || ((ds->device_id) & 0x07ff) == 0x0052)
+#define STROKING_PEN(ds) (((ds->device_id) & 0x07ff) == 0x0032)
+#define AIRBRUSH(ds) (((ds->device_id) & 0x07ff) == 0x0112)
+#define MOUSE_4D(ds) (((ds->device_id) & 0x07ff) == 0x0094)
+#define LENS_CURSOR(ds) (((ds->device_id) & 0x07ff) == 0x0096)
+#define INKING_PEN(ds) (((ds->device_id) & 0x07ff) == 0x0012)
+
+typedef struct
+{
+ /* configuration fields */
+ unsigned int flags; /* various flags (device type, absolute, first touch...) */
+ int topX; /* X top */
+ int topY; /* Y top */
+ int bottomX; /* X bottom */
+ int bottomY; /* Y bottom */
+ double factorX; /* X factor */
+ double factorY; /* Y factor */
+ unsigned int serial; /* device serial number */
+ int initNumber; /* magic number for the init phasis */
+ int screen_no; /* associated screen */
+
+ struct _WacomCommonRec *common; /* common info pointer */
+
+ /* state fields */
+ int oldX; /* previous X position */
+ int oldY; /* previous Y position */
+ int oldZ; /* previous pressure */
+ int oldTiltX; /* previous tilt in x direction */
+ int oldTiltY; /* previous tilt in y direction */
+ int oldWheel; /* previous wheel value */
+ int oldButtons; /* previous buttons state */
+ int oldProximity; /* previous proximity */
+
+ /* JEJ - throttle */
+ int throttleStart; /* time in ticks for last wheel movement */
+ int throttleLimit; /* time in ticks for next wheel movement */
+ int throttleValue; /* current throttle value */
+
+} WacomDeviceRec, *WacomDevicePtr;
+
+#define MAX_USB_EVENTS 6
+
+typedef struct _WacomCommonRec
+{
+ char *wcmDevice; /* device file name */
+ int wcmSuppress; /* transmit position if increment is superior */
+ unsigned char wcmFlags; /* various flags (handle tilt) */
+ int wcmMaxX; /* max X value */
+ int wcmMaxY; /* max Y value */
+ int wcmMaxZ; /* max Z value */
+ int wcmResolX; /* X resolution in points/inch */
+ int wcmResolY; /* Y resolution in points/inch */
+ int wcmResolZ; /* Z resolution in points/inch */
+ LocalDevicePtr *wcmDevices; /* array of all devices sharing the same port */
+ int wcmNumDevices; /* number of devices */
+ int wcmIndex; /* number of bytes read */
+ int wcmPktLength; /* length of a packet */
+ unsigned char wcmData[9]; /* data read on the device */
+ Bool wcmHasEraser; /* True if an eraser has been configured */
+ Bool wcmStylusSide; /* eraser or stylus ? */
+ Bool wcmStylusProximity; /* the stylus is in proximity ? */
+ int wcmProtocolLevel; /* 4 for Wacom IV, 5 for Wacom V */
+ int wcmThreshold; /* Threshold for counting pressure as a button */
+ WacomDeviceState wcmDevStat[2]; /* device state for each tool */
+ int wcmInitNumber; /* magic number for the init phasis */
+ unsigned int wcmLinkSpeed; /* serial link speed */
+ Bool (*wcmOpen)(LocalDevicePtr /*local*/); /* function used to open the line (serial or USB) */
+ unsigned int wcmLastSerial; /* last device (used by the USB part) */
+ int wcmLastTool; /* last tool (used by USB part) */
+#ifdef LINUX_INPUT
+ struct input_event wcmEvent[MAX_USB_EVENTS]; /* data used by USB driver */
+#endif
+} WacomCommonRec, *WacomCommonPtr;
+
+/******************************************************************************
+ * configuration stuff
+ *****************************************************************************/
+#define CURSOR_SECTION_NAME "wacomcursor"
+#define STYLUS_SECTION_NAME "wacomstylus"
+#define ERASER_SECTION_NAME "wacomeraser"
+
+#ifndef XFREE86_V4
+
+#define PORT 1
+#define DEVICENAME 2
+#define THE_MODE 3
+#define SUPPRESS 4
+#define DEBUG_LEVEL 5
+#define TILT_MODE 6
+#define HISTORY_SIZE 7
+#define ALWAYS_CORE 8
+#define KEEP_SHAPE 9
+#define TOP_X 10
+#define TOP_Y 11
+#define BOTTOM_X 12
+#define BOTTOM_Y 13
+#define SERIAL 14
+#define BAUD_RATE 15
+#define THRESHOLD 16
+#define MAX_X 17
+#define MAX_Y 18
+#define MAX_Z 19
+#define RESOLUTION_X 20
+#define RESOLUTION_Y 21
+#define RESOLUTION_Z 22
+#define USB 23
+#define SCREEN_NO 24
+
+#if !defined(sun) || defined(i386)
+static SymTabRec WcmTab[] = {
+ { ENDSUBSECTION, "endsubsection" },
+ { PORT, "port" },
+ { DEVICENAME, "devicename" },
+ { THE_MODE, "mode" },
+ { SUPPRESS, "suppress" },
+ { DEBUG_LEVEL, "debuglevel" },
+ { TILT_MODE, "tiltmode" },
+ { HISTORY_SIZE, "historysize" },
+ { ALWAYS_CORE, "alwayscore" },
+ { KEEP_SHAPE, "keepshape" },
+ { TOP_X, "topx" },
+ { TOP_Y, "topy" },
+ { BOTTOM_X, "bottomx" },
+ { BOTTOM_Y, "bottomy" },
+ { SERIAL, "serial" },
+ { BAUD_RATE, "baudrate" },
+ { THRESHOLD, "threshold" },
+ { MAX_X, "maxx" },
+ { MAX_Y, "maxy" },
+ { MAX_Z, "maxz" },
+ { RESOLUTION_X, "resolutionx" },
+ { RESOLUTION_Y, "resolutiony" },
+ { RESOLUTION_Z, "resolutionz" },
+ { USB, "usb" },
+ { SCREEN_NO, "screenno" },
+ { -1, "" }
+};
+
+#define RELATIVE 1
+#define ABSOLUTE 2
+
+static SymTabRec ModeTabRec[] = {
+ { RELATIVE, "relative" },
+ { ABSOLUTE, "absolute" },
+ { -1, "" }
+};
+
+#endif
+
+#endif /* Pre 3.9 headers */
+
+/******************************************************************************
+ * constant and macros declarations
+ *****************************************************************************/
+#define DEFAULT_MAXZ 240 /* default value of MaxZ when nothing is configured */
+#define BUFFER_SIZE 256 /* size of reception buffer */
+#define XI_STYLUS "STYLUS" /* X device name for the stylus */
+#define XI_CURSOR "CURSOR" /* X device name for the cursor */
+#define XI_ERASER "ERASER" /* X device name for the eraser */
+#define MAX_VALUE 100 /* number of positions */
+#define MAXTRY 3 /* max number of try to receive magic number */
+#define MAX_COORD_RES 1270.0 /* Resolution of the returned MaxX and MaxY */
+#define INVALID_THRESHOLD 30000 /* Invalid threshold value used to test if the user
+ * configured it or not */
+
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+
+#define WC_RESET "\r#" /* reset to wacom IV command set or wacom V reset */
+#define WC_RESET_BAUD "\r$" /* reset baud rate to default (wacom V) or switch to wacom IIs (wacom IV) */
+#define WC_CONFIG "~R\r" /* request a configuration string */
+#define WC_COORD "~C\r" /* request max coordinates */
+#define WC_MODEL "~#\r" /* request model and ROM version */
+
+#define WC_MULTI "MU1\r" /* multi mode input */
+#define WC_UPPER_ORIGIN "OC1\r" /* origin in upper left */
+#define WC_SUPPRESS "SU" /* suppress mode */
+#define WC_ALL_MACRO "~M0\r" /* enable all macro buttons */
+#define WC_NO_MACRO1 "~M1\r" /* disable macro buttons of group 1 */
+#define WC_RATE "IT0\r" /* max transmit rate (unit of 5 ms) */
+#define WC_TILT_MODE "FM1\r" /* enable extra protocol for tilt management */
+#define WC_NO_INCREMENT "IN0\r" /* do not enable increment mode */
+#define WC_STREAM_MODE "SR\r" /* enable continuous mode */
+#define WC_PRESSURE_MODE "PH1\r" /* enable pressure mode */
+#define WC_ZFILTER "ZF1\r" /* stop sending coordinates */
+#define WC_STOP "\nSP\r" /* stop sending coordinates */
+#define WC_START "ST\r" /* start sending coordinates */
+#define WC_NEW_RESOLUTION "NR" /* change the resolution */
+
+static const char * setup_string = WC_MULTI WC_UPPER_ORIGIN
+ WC_ALL_MACRO WC_NO_MACRO1 WC_RATE WC_NO_INCREMENT WC_STREAM_MODE WC_ZFILTER;
+
+static const char * penpartner_setup_string = WC_PRESSURE_MODE WC_START;
+
+#define WC_V_SINGLE "MT0\r"
+#define WC_V_MULTI "MT1\r"
+#define WC_V_ID "ID1\r"
+#define WC_V_19200 "BA19\r"
+#define WC_V_38400 "BA38\r"
+/* #define WC_V_9600 "BA96\r" */
+#define WC_V_9600 "$\r"
+
+#define WC_RESET_19200 "\r$" /* reset to 9600 baud */
+#define WC_RESET_19200_IV "\r#"
+
+static const char * intuos_setup_string = WC_V_MULTI WC_V_ID WC_RATE WC_START;
+
+#define COMMAND_SET_MASK 0xc0
+#define BAUD_RATE_MASK 0x0a
+#define PARITY_MASK 0x30
+#define DATA_LENGTH_MASK 0x40
+#define STOP_BIT_MASK 0x80
+
+#define HEADER_BIT 0x80
+#define ZAXIS_SIGN_BIT 0x40
+#define ZAXIS_BIT 0x04
+#define ZAXIS_BITS 0x3f
+#define POINTER_BIT 0x20
+#define PROXIMITY_BIT 0x40
+#define BUTTON_FLAG 0x08
+#define BUTTONS_BITS 0x78
+#define TILT_SIGN_BIT 0x40
+#define TILT_BITS 0x3f
+
+/* defines to discriminate second side button and the eraser */
+#define ERASER_PROX 4
+#define OTHER_PROX 1
+
+#define HANDLE_TILT(comm) ((comm)->wcmPktLength == 9)
+
+#define mils(res) (res * 100 / 2.54) /* resolution */
+
+/******************************************************************************
+ * Function/Macro keys variables
+ *****************************************************************************/
+static KeySym wacom_map[] =
+{
+ NoSymbol, /* 0x00 */
+ NoSymbol, /* 0x01 */
+ NoSymbol, /* 0x02 */
+ NoSymbol, /* 0x03 */
+ NoSymbol, /* 0x04 */
+ NoSymbol, /* 0x05 */
+ NoSymbol, /* 0x06 */
+ NoSymbol, /* 0x07 */
+ XK_F1, /* 0x08 */
+ XK_F2, /* 0x09 */
+ XK_F3, /* 0x0a */
+ XK_F4, /* 0x0b */
+ XK_F5, /* 0x0c */
+ XK_F6, /* 0x0d */
+ XK_F7, /* 0x0e */
+ XK_F8, /* 0x0f */
+ XK_F8, /* 0x10 */
+ XK_F10, /* 0x11 */
+ XK_F11, /* 0x12 */
+ XK_F12, /* 0x13 */
+ XK_F13, /* 0x14 */
+ XK_F14, /* 0x15 */
+ XK_F15, /* 0x16 */
+ XK_F16, /* 0x17 */
+ XK_F17, /* 0x18 */
+ XK_F18, /* 0x19 */
+ XK_F19, /* 0x1a */
+ XK_F20, /* 0x1b */
+ XK_F21, /* 0x1c */
+ XK_F22, /* 0x1d */
+ XK_F23, /* 0x1e */
+ XK_F24, /* 0x1f */
+ XK_F25, /* 0x20 */
+ XK_F26, /* 0x21 */
+ XK_F27, /* 0x22 */
+ XK_F28, /* 0x23 */
+ XK_F29, /* 0x24 */
+ XK_F30, /* 0x25 */
+ XK_F31, /* 0x26 */
+ XK_F32 /* 0x27 */
+};
+
+/* minKeyCode = 8 because this is the min legal key code */
+static KeySymsRec wacom_keysyms = {
+ /* map minKeyCode maxKC width */
+ wacom_map, 8, 0x27, 1
+};
+
+/******************************************************************************
+ * external declarations
+ *****************************************************************************/
+
+#ifdef LINUX_INPUT
+static void xf86WcmReadUSBInput(LocalDevicePtr);
+static Bool xf86WcmUSBOpen(LocalDevicePtr);
+#endif
+
+
+#ifndef XFREE86_V4
+
+#if defined(sun) && !defined(i386)
+#define ENQUEUE suneqEnqueue
+#else
+#define ENQUEUE xf86eqEnqueue
+
+extern void xf86eqEnqueue(
+#if NeedFunctionPrototypes
+ xEventPtr /*e*/
+#endif
+);
+#endif
+
+extern void miPointerDeltaCursor(
+#if NeedFunctionPrototypes
+ int /*dx*/,
+ int /*dy*/,
+ unsigned long /*time*/
+#endif
+);
+
+#endif /* pre 3.9 declarations */
+
+#if NeedFunctionPrototypes
+static LocalDevicePtr xf86WcmAllocateStylus(void);
+static LocalDevicePtr xf86WcmAllocateCursor(void);
+static LocalDevicePtr xf86WcmAllocateEraser(void);
+#endif
+
+#ifndef XFREE86_V4
+/*
+ ***************************************************************************
+ *
+ * xf86WcmConfig --
+ * Configure the device.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86WcmConfig(LocalDevicePtr *array,
+ int inx,
+ int max,
+ LexPtr val)
+{
+ LocalDevicePtr dev = array[inx];
+ WacomDevicePtr priv = (WacomDevicePtr)(dev->private);
+ WacomCommonPtr common = priv->common;
+ int token;
+ int mtoken;
+
+ DBG(1, ErrorF("xf86WcmConfig\n"));
+
+ if (xf86GetToken(WcmTab) != PORT) {
+ xf86ConfigError("PORT option must be the first option of a Wacom SubSection");
+ }
+
+ if (xf86GetToken(NULL) != STRING)
+ xf86ConfigError("Option string expected");
+ else {
+ int loop;
+
+ /* try to find another wacom device which share the same port */
+ for(loop=0; loop<max; loop++) {
+ if (loop == inx)
+ continue;
+ if ((array[loop]->device_config == xf86WcmConfig) &&
+ (strcmp(((WacomDevicePtr)array[loop]->private)->common->wcmDevice, val->str) == 0)) {
+ DBG(2, ErrorF("xf86WcmConfig wacom port share between"
+ " %s and %s\n",
+ dev->name, array[loop]->name));
+ ((WacomDevicePtr) array[loop]->private)->common->wcmHasEraser |= common->wcmHasEraser;
+ xfree(common->wcmDevices);
+ xfree(common);
+ common = priv->common = ((WacomDevicePtr) array[loop]->private)->common;
+ common->wcmNumDevices++;
+ common->wcmDevices = (LocalDevicePtr *) xrealloc(common->wcmDevices,
+ sizeof(LocalDevicePtr) * common->wcmNumDevices);
+ common->wcmDevices[common->wcmNumDevices - 1] = dev;
+ break;
+ }
+ }
+ if (loop == max) {
+ common->wcmDevice = strdup(val->str);
+ if (xf86Verbose)
+ ErrorF("%s Wacom port is %s\n", XCONFIG_GIVEN,
+ common->wcmDevice);
+ }
+ }
+
+ while ((token = xf86GetToken(WcmTab)) != ENDSUBSECTION) {
+ switch(token) {
+ case DEVICENAME:
+ if (xf86GetToken(NULL) != STRING)
+ xf86ConfigError("Option string expected");
+ dev->name = strdup(val->str);
+ if (xf86Verbose)
+ ErrorF("%s Wacom X device name is %s\n", XCONFIG_GIVEN,
+ dev->name);
+ break;
+
+ case THE_MODE:
+ mtoken = xf86GetToken(ModeTabRec);
+ if ((mtoken == EOF) || (mtoken == STRING) || (mtoken == NUMBER))
+ xf86ConfigError("Mode type token expected");
+ else {
+ switch (mtoken) {
+ case ABSOLUTE:
+ priv->flags = priv->flags | ABSOLUTE_FLAG;
+ break;
+ case RELATIVE:
+ priv->flags = priv->flags & ~ABSOLUTE_FLAG;
+ break;
+ default:
+ xf86ConfigError("Illegal Mode type");
+ break;
+ }
+ }
+ break;
+
+ case SUPPRESS:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmSuppress = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom suppress value is %d\n", XCONFIG_GIVEN,
+ common->wcmSuppress);
+ break;
+
+ case DEBUG_LEVEL:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ debug_level = val->num;
+ if (xf86Verbose) {
+#if DEBUG
+ ErrorF("%s Wacom debug level sets to %d\n", XCONFIG_GIVEN,
+ debug_level);
+#else
+ ErrorF("%s Wacom debug level not sets to %d because"
+ " debugging is not compiled\n", XCONFIG_GIVEN,
+ debug_level);
+#endif
+ }
+ break;
+
+ case TILT_MODE:
+ common->wcmFlags |= TILT_FLAG;
+ break;
+
+ case HISTORY_SIZE:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ dev->history_size = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom Motion history size is %d\n", XCONFIG_GIVEN,
+ dev->history_size);
+ break;
+
+ case ALWAYS_CORE:
+ xf86AlwaysCore(dev, TRUE);
+ if (xf86Verbose)
+ ErrorF("%s Wacom device always stays core pointer\n",
+ XCONFIG_GIVEN);
+ break;
+
+ case KEEP_SHAPE:
+ priv->flags |= KEEP_SHAPE_FLAG;
+ if (xf86Verbose)
+ ErrorF("%s Wacom keeps shape\n",
+ XCONFIG_GIVEN);
+ break;
+
+ case TOP_X:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->topX = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom top x = %d\n", XCONFIG_GIVEN, priv->topX);
+ break;
+
+ case TOP_Y:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->topY = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom top y = %d\n", XCONFIG_GIVEN, priv->topY);
+ break;
+
+ case BOTTOM_X:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->bottomX = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom bottom x = %d\n", XCONFIG_GIVEN, priv->bottomX);
+ break;
+
+ case BOTTOM_Y:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->bottomY = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom bottom y = %d\n", XCONFIG_GIVEN, priv->bottomY);
+ break;
+
+ case SERIAL:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->serial = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom serial number = %u\n", XCONFIG_GIVEN,
+ priv->serial);
+ break;
+
+ case BAUD_RATE:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ switch(val->num) {
+ case 38400:
+ common->wcmLinkSpeed = 38400;
+ break;
+ case 19200:
+ common->wcmLinkSpeed = 19200;
+ break;
+ case 9600:
+ common->wcmLinkSpeed = 9600;
+ break;
+ default:
+ xf86ConfigError("Illegal speed value");
+ break;
+ }
+ if (xf86Verbose)
+ ErrorF("%s Wacom baud rate of %u\n", XCONFIG_GIVEN,
+ val->num);
+ break;
+
+ case THRESHOLD:
+ if (xf86GetToken(NULL) != STRING)
+ xf86ConfigError("Option string expected");
+
+ common->wcmThreshold = atoi(val->str);
+
+ if (xf86Verbose)
+ ErrorF("%s Wacom pressure threshold for button 1 = %d\n",
+ XCONFIG_GIVEN, common->wcmThreshold);
+ break;
+
+ case MAX_X:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmMaxX = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom max x = %d\n", XCONFIG_GIVEN, common->wcmMaxX);
+ break;
+
+ case MAX_Y:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmMaxY = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom max y = %d\n", XCONFIG_GIVEN, common->wcmMaxY);
+ break;
+
+ case MAX_Z:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmMaxZ = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom max y = %d\n", XCONFIG_GIVEN, common->wcmMaxZ);
+ break;
+
+ case RESOLUTION_X:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmResolX = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom resolution x = %d\n", XCONFIG_GIVEN, common->wcmResolX);
+ break;
+
+ case RESOLUTION_Y:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmResolY = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom resolution y = %d\n", XCONFIG_GIVEN, common->wcmResolY);
+ break;
+
+ case RESOLUTION_Z:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ common->wcmResolZ = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom resolution y = %d\n", XCONFIG_GIVEN, common->wcmResolZ);
+ break;
+
+ case USB:
+#ifdef LINUX_INPUT
+ dev->read_input=xf86WcmReadUSBInput;
+ common->wcmOpen=xf86WcmUSBOpen;
+ ErrorF("%s Wacom reading USB link\n", XCONFIG_GIVEN);
+#else
+ ErrorF("The USB version of the driver isn't available for your platform\n");
+#endif
+ break;
+
+ case SCREEN_NO:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("Option number expected");
+ priv->screen_no = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Wacom attached screen = %d\n", XCONFIG_GIVEN,
+ priv->screen_no);
+ break;
+
+ case EOF:
+ FatalError("Unexpected EOF (missing EndSubSection)");
+ break;
+
+ default:
+ xf86ConfigError("Wacom subsection keyword expected");
+ break;
+ }
+ }
+
+ DBG(1, ErrorF("xf86WcmConfig name=%s\n", common->wcmDevice));
+
+ return Success;
+}
+#endif /* Pre 3.9 stuff */
+
+#if 0
+/*
+ ***************************************************************************
+ *
+ * ascii_to_hexa --
+ *
+ ***************************************************************************
+ */
+/*
+ * transform two ascii hexa representation into an unsigned char
+ * most significant byte is the first one
+ */
+static unsigned char
+ascii_to_hexa(char buf[2])
+{
+ unsigned char uc;
+
+ if (buf[0] >= 'A') {
+ uc = buf[0] - 'A' + 10;
+ }
+ else {
+ uc = buf[0] - '0';
+ }
+ uc = uc << 4;
+ if (buf[1] >= 'A') {
+ uc += buf[1] - 'A' + 10;
+ }
+ else {
+ uc += buf[1] - '0';
+ }
+ return uc;
+}
+#endif
+
+#ifndef XFREE86_V4
+/*
+ ***************************************************************************
+ *
+ * set_serial_speed --
+ *
+ * Set speed of the serial port.
+ *
+ ***************************************************************************
+ */
+static int
+set_serial_speed(int fd,
+ int speed_code)
+{
+ struct termios termios_tty;
+ int err;
+
+#ifdef POSIX_TTY
+ SYSCALL(err = tcgetattr(fd, &termios_tty));
+
+ if (err == -1) {
+ ErrorF("Wacom tcgetattr error : %s\n", strerror(errno));
+ return !Success;
+ }
+ termios_tty.c_iflag = IXOFF;
+ termios_tty.c_oflag = 0;
+ termios_tty.c_cflag = speed_code|CS8|CREAD|CLOCAL;
+ termios_tty.c_lflag = 0;
+
+ termios_tty.c_cc[VINTR] = 0;
+ termios_tty.c_cc[VQUIT] = 0;
+ termios_tty.c_cc[VERASE] = 0;
+ termios_tty.c_cc[VEOF] = 0;
+#ifdef VWERASE
+ termios_tty.c_cc[VWERASE] = 0;
+#endif
+#ifdef VREPRINT
+ termios_tty.c_cc[VREPRINT] = 0;
+#endif
+ termios_tty.c_cc[VKILL] = 0;
+ termios_tty.c_cc[VEOF] = 0;
+ termios_tty.c_cc[VEOL] = 0;
+#ifdef VEOL2
+ termios_tty.c_cc[VEOL2] = 0;
+#endif
+ termios_tty.c_cc[VSUSP] = 0;
+#ifdef VDSUSP
+ termios_tty.c_cc[VDSUSP] = 0;
+#endif
+#ifdef VDISCARD
+ termios_tty.c_cc[VDISCARD] = 0;
+#endif
+#ifdef VLNEXT
+ termios_tty.c_cc[VLNEXT] = 0;
+#endif
+
+ /* minimum 1 character in one read call and timeout to 100 ms */
+ termios_tty.c_cc[VMIN] = 1;
+ termios_tty.c_cc[VTIME] = 10;
+
+ SYSCALL(err = tcsetattr(fd, TCSANOW, &termios_tty));
+ if (err == -1) {
+ ErrorF("Wacom tcsetattr TCSANOW error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+#else
+ Code for OSs without POSIX tty functions
+#endif
+
+ return Success;
+}
+
+/*
+ ***************************************************************************
+ *
+ * wait_for_fd --
+ *
+ * Wait one second that the file descriptor becomes readable.
+ *
+ ***************************************************************************
+ */
+static int
+wait_for_fd(int fd)
+{
+ int err;
+ fd_set readfds;
+ struct timeval timeout;
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ SYSCALL(err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout));
+
+ return err;
+}
+
+/*
+ ***************************************************************************
+ *
+ * flush_input_fd --
+ *
+ * Flush all input pending on the file descriptor.
+ *
+ ***************************************************************************
+ */
+static int
+flush_input_fd(int fd)
+{
+ int err;
+ fd_set readfds;
+ struct timeval timeout;
+ char dummy[1];
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ do {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ SYSCALL(err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout));
+
+ if (err > 0) {
+ SYSCALL(err = read(fd, &dummy, 1));
+ DBG(10, ErrorF("flush_input_fd: read %d bytes\n", err));
+ }
+ } while (err > 0);
+ return err;
+}
+#endif /* Pre 3.9 stuff */
+
+/*
+ ***************************************************************************
+ *
+ * send_request --
+ *
+ ***************************************************************************
+ */
+/*
+ * send a request and wait for the answer.
+ * the answer must begin with the first two chars of the request and must end
+ * with \r. The last character in the answer string (\r) is replaced by a \0.
+ */
+static char *
+send_request(int fd,
+ char *request,
+ char *answer)
+{
+ int len, nr;
+ int maxtry = MAXTRY;
+
+ /* send request string */
+ do {
+ SYSCALL(len = write(fd, request, strlen(request)));
+ if ((len == -1) && (errno != EAGAIN)) {
+ ErrorF("Wacom write error : %s", strerror(errno));
+ return NULL;
+ }
+ maxtry--;
+ } while ((len == -1) && maxtry);
+
+ if (maxtry == 0) {
+ ErrorF("Wacom unable to write request string '%s' after %d tries\n", request, MAXTRY);
+ return NULL;
+ }
+
+ do {
+ maxtry = MAXTRY;
+
+ /* Read the first byte of the answer which must be equal to the first
+ * byte of the request.
+ */
+ do {
+ if ((nr = wait_for_fd(fd)) > 0) {
+ SYSCALL(nr = read(fd, answer, 1));
+ if ((nr == -1) && (errno != EAGAIN)) {
+ ErrorF("Wacom read error : %s\n", strerror(errno));
+ return NULL;
+ }
+ DBG(10, ErrorF("%c err=%d [0]\n", answer[0], nr));
+ }
+ maxtry--;
+ } while ((answer[0] != request[0]) && maxtry);
+
+ if (maxtry == 0) {
+ ErrorF("Wacom unable to read first byte of request '%c%c' answer after %d tries\n",
+ request[0], request[1], MAXTRY);
+ return NULL;
+ }
+
+ /* Read the second byte of the answer which must be equal to the second
+ * byte of the request.
+ */
+ do {
+ maxtry = MAXTRY;
+ do {
+ if ((nr = wait_for_fd(fd)) > 0) {
+ SYSCALL(nr = read(fd, answer+1, 1));
+ if ((nr == -1) && (errno != EAGAIN)) {
+ ErrorF("Wacom read error : %s\n", strerror(errno));
+ return NULL;
+ }
+ DBG(10, ErrorF("%c err=%d [1]\n", answer[1], nr));
+ }
+ maxtry--;
+ } while ((nr <= 0) && maxtry);
+
+ if (maxtry == 0) {
+ ErrorF("Wacom unable to read second byte of request '%c%c' answer after %d tries\n",
+ request[0], request[1], MAXTRY);
+ return NULL;
+ }
+
+ if (answer[1] != request[1])
+ answer[0] = answer[1];
+
+ } while ((answer[0] == request[0]) &&
+ (answer[1] != request[1]));
+
+ } while ((answer[0] != request[0]) &&
+ (answer[1] != request[1]));
+
+ /* Read until carriage return or timeout (to handle broken protocol
+ * implementations which don't end with a <cr>).
+ */
+ len = 2;
+ maxtry = MAXTRY;
+ do {
+ do {
+ if ((nr = wait_for_fd(fd)) > 0) {
+ SYSCALL(nr = read(fd, answer+len, 1));
+ if ((nr == -1) && (errno != EAGAIN)) {
+ ErrorF("Wacom read error : %s\n", strerror(errno));
+ return NULL;
+ }
+ DBG(10, ErrorF("%c err=%d [%d]\n", answer[len], nr, len));
+ }
+ else {
+ DBG(10, ErrorF("timeout remains %d tries\n", maxtry));
+ maxtry--;
+ }
+ } while ((nr <= 0) && maxtry);
+
+ if (nr > 0) {
+ len += nr;
+ }
+
+ if (maxtry == 0) {
+ ErrorF("Wacom unable to read last byte of request '%c%c' answer after %d tries\n",
+ request[0], request[1], MAXTRY);
+ break;
+ }
+ } while (answer[len-1] != '\r');
+
+ if (len <= 3)
+ return NULL;
+
+ answer[len-1] = '\0';
+
+ return answer;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmConvert --
+ * Convert valuators to X and Y.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86WcmConvert(LocalDevicePtr local,
+ int first,
+ int num,
+ int v0,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int v5,
+ int* x,
+ int* y)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+
+ DBG(6, ErrorF("xf86WcmConvert\n"));
+
+ if (first != 0 || num == 1)
+ return FALSE;
+
+#ifdef XFREE86_V4
+ {
+ ScreenPtr pscr;
+
+ if (priv->screen_no != -1) {
+ pscr = screenInfo.screens[priv->screen_no];
+ } else {
+ pscr = miPointerCurrentScreen();
+ }
+
+ if (pscr == NULL)
+ return FALSE;
+
+ priv->factorX = ((double) pscr->width)
+ / (priv->bottomX - priv->topX);
+ priv->factorY = ((double) pscr->height)
+ / (priv->bottomY - priv->topY);
+ }
+#endif
+
+ *x = v0 * priv->factorX + 0.5;
+ *y = v1 * priv->factorY + 0.5;
+
+ DBG(6, ErrorF("Wacom converted v0=%d v1=%d to x=%d y=%d\n",
+ v0, v1, *x, *y));
+#ifdef XFREE86_V4
+ if (priv->screen_no != -1) {
+ xf86XInputSetScreen(local, priv->screen_no, *x, *y);
+ }
+#endif
+ return TRUE;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmReverseConvert --
+ * Convert X and Y to valuators.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86WcmReverseConvert(LocalDevicePtr local,
+ int x,
+ int y,
+ int *valuators)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+
+#ifdef XFREE86_V4
+ priv->factorX = ((double) miPointerCurrentScreen()->width)
+ / (priv->bottomX - priv->topX);
+ priv->factorY = ((double) miPointerCurrentScreen()->height)
+ / (priv->bottomY - priv->topY);
+#endif
+
+ valuators[0] = x / priv->factorX + 0.5;
+ valuators[1] = y / priv->factorY + 0.5;
+
+ DBG(6, ErrorF("Wacom converted x=%d y=%d to v0=%d v1=%d\n", x, y,
+ valuators[0], valuators[1]));
+
+ return TRUE;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmSendButtons --
+ * Send button events by comparing the current button mask with the
+ * previous one.
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmSendButtons(LocalDevicePtr local,
+ int buttons,
+ int rx,
+ int ry,
+ int rz,
+ int rtx,
+ int rty,
+ int rwheel)
+
+{
+ int button;
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+
+ for (button=1; button<=16; button++) {
+ int mask = 1 << (button-1);
+
+ if ((mask & priv->oldButtons) != (mask & buttons)) {
+ DBG(4, ErrorF("xf86WcmSendButtons button=%d state=%d\n",
+ button, (buttons & mask) != 0));
+ xf86PostButtonEvent(local->dev,
+ (priv->flags & ABSOLUTE_FLAG),
+ button, (buttons & mask) != 0,
+ 0, 6, rx, ry, rz, rtx, rty, rwheel);
+ }
+ }
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmSendEvents --
+ * Send events according to the device state.
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmSendEvents(LocalDevicePtr local,
+ int type,
+ unsigned int serial,
+ int is_stylus,
+ int is_button,
+ int is_proximity,
+ int x,
+ int y,
+ int z,
+ int buttons,
+ int tx,
+ int ty,
+ int wheel)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+ WacomCommonPtr common = priv->common;
+ int rx, ry, rz, rtx, rty, rwheel;
+ int is_core_pointer, is_absolute;
+
+ if ((DEVICE_ID(priv->flags) != type) ||
+ ((common->wcmProtocolLevel == 5) &&
+ priv->serial && (serial != priv->serial))) {
+ DBG(7,
+ {if (common->wcmProtocolLevel == 5) {
+ ErrorF("xf86WcmSendEvents not the same device id (%u,%u)\n",
+ serial, priv->serial);
+ } else {
+ ErrorF("xf86WcmSendEvents not the same device type (%u,%u)\n",
+ DEVICE_ID(priv->flags), type);}});
+ return;
+ }
+
+ DBG(7, ErrorF("[%s] prox=%s\tx=%d\ty=%d\tz=%d\tbutton=%s\tbuttons=%d\ttx=%d ty=%d\twl=%d\n",
+ (type == STYLUS_ID) ? "stylus" : (type == CURSOR_ID) ? "cursor" : "eraser",
+ is_proximity ? "true" : "false",
+ x, y, z,
+ is_button ? "true" : "false", buttons,
+ tx, ty, wheel));
+
+ /* Translate coordinates according to Top and Bottom points
+ * if we are outside the zone do as a ProximityOut event.
+ */
+
+ if (x > priv->bottomX) {
+ is_proximity = FALSE;
+ buttons = 0;
+ x = priv->bottomX;
+ }
+
+ if (y > priv->bottomY) {
+ is_proximity = FALSE;
+ buttons = 0;
+ y = priv->bottomY;
+ }
+
+ DBG(10, ErrorF("topX=%d topY=%d\n", priv->topX, priv->topY));
+
+ x = x - priv->topX;
+ y = y - priv->topY;
+
+ if (x < 0) {
+ is_proximity = FALSE;
+ buttons = 0;
+ x = 0;
+ }
+
+ if (y < 0) {
+ is_proximity = FALSE;
+ buttons = 0;
+ y = 0;
+ }
+
+ is_absolute = (priv->flags & ABSOLUTE_FLAG);
+ is_core_pointer = xf86IsCorePointer(local->dev);
+
+ DBG(6, ErrorF("[%s] %s prox=%s\tx=%d\ty=%d\tz=%d\tbutton=%s\tbuttons=%d\n",
+ is_stylus ? "stylus" : "cursor",
+ is_absolute ? "abs" : "rel",
+ is_proximity ? "true" : "false",
+ x, y, z,
+ is_button ? "true" : "false", buttons));
+
+ /* Hardware filtering isn't working on Graphire so we do it here.
+ */
+ if ((common->wcmFlags & GRAPHIRE_FLAG) &&
+ ((is_proximity && priv->oldProximity) ||
+ ((is_proximity == 0) && (priv->oldProximity == 0))) &&
+ (buttons == priv->oldButtons) &&
+ (ABS(x - priv->oldX) <= common->wcmSuppress) &&
+ (ABS(y - priv->oldY) <= common->wcmSuppress) &&
+ (ABS(z - priv->oldZ) < 3) &&
+ (ABS(tx - priv->oldTiltX) < 3) &&
+ (ABS(ty - priv->oldTiltY) < 3)) {
+
+ DBG(10, ErrorF("Graphire filtered\n"));
+
+ return;
+ }
+
+ /* sets rx and ry according to the mode */
+ if (is_absolute) {
+ rx = x;
+ ry = y;
+ rz = z;
+ rtx = tx;
+ rty = ty;
+ rwheel = wheel;
+ } else {
+ rx = x - priv->oldX;
+ ry = y - priv->oldY;
+ rz = z - priv->oldZ;
+ rtx = tx - priv->oldTiltX;
+ rty = ty - priv->oldTiltY;
+ rwheel = wheel - priv->oldWheel;
+ }
+
+ /* coordinates are ready we can send events */
+ if (is_proximity) {
+
+ if (!priv->oldProximity) {
+ xf86PostProximityEvent(local->dev, 1, 0, 6, rx, ry, z, tx, ty, rwheel);
+
+ priv->flags |= FIRST_TOUCH_FLAG;
+ DBG(4, ErrorF("xf86WcmSendEvents FIRST_TOUCH_FLAG set\n"));
+
+ if (common->wcmProtocolLevel == 4) {
+ /* handle the two sides switches in the stylus */
+ if (is_stylus && (buttons == 4)) {
+ priv->oldProximity = ERASER_PROX;
+ }
+ else {
+ priv->oldProximity = OTHER_PROX;
+ }
+ }
+ else {
+ priv->oldProximity = OTHER_PROX;
+ }
+ }
+
+ if (common->wcmProtocolLevel == 4 &&
+ !(common->wcmFlags & GRAPHIRE_FLAG)) {
+ /* The stylus reports button 4 for the second side
+ * switch and button 4/5 for the eraser tip. We know
+ * how to choose when we come in proximity for the
+ * first time. If we are in proximity and button 4 then
+ * we have the eraser else we have the second side
+ * switch.
+ */
+ if (is_stylus) {
+ if (buttons == 4) {
+ buttons = (priv->oldProximity == ERASER_PROX) ? 0 : 3;
+ }
+ else {
+ if (priv->oldProximity == ERASER_PROX && buttons == 5) {
+ buttons = ((DEVICE_ID(priv->flags) == ERASER_ID) ? 1 : 4);
+ }
+ }
+ }
+ else {
+ /* If the button flag is pressed, but the switch state
+ * is zero, this means that cursor button 16 was pressed
+ */
+ if (is_button && buttons == 0) {
+ buttons = 16;
+ }
+ }
+ }
+ DBG(4, ErrorF("xf86WcmSendEvents %s rx=%d ry=%d rz=%d buttons=%d\n",
+ is_stylus ? "stylus" : "cursor", rx, ry, rz, buttons));
+
+ /* Turn button index reported into a bit mask for WACOM IV.
+ * The WACOM V and Graphire models already report buttons
+ * as a bit mask.
+ */
+ if (common->wcmProtocolLevel == 4 &&
+ !(common->wcmFlags & GRAPHIRE_FLAG)) {
+ buttons = 1 << (buttons - 1);
+ }
+
+ if ((priv->oldX != x) ||
+ (priv->oldY != y) ||
+ (priv->oldZ != z) ||
+ (is_stylus && HANDLE_TILT(common) &&
+ (tx != priv->oldTiltX || ty != priv->oldTiltY))) {
+ if (!is_absolute && (priv->flags & FIRST_TOUCH_FLAG)) {
+ priv->flags -= FIRST_TOUCH_FLAG;
+ DBG(4, ErrorF("xf86WcmSendEvents FIRST_TOUCH_FLAG unset\n"));
+ } else {
+ xf86PostMotionEvent(local->dev, is_absolute, 0, 6, rx, ry, rz,
+ rtx, rty, rwheel);
+ }
+ }
+
+ if (priv->oldButtons != buttons) {
+ xf86WcmSendButtons (local, buttons, rx, ry, rz, rtx, rty, rwheel);
+ }
+
+ /* Simulate buttons 4 and 5 for Graphire wheel */
+ if ((((common->wcmProtocolLevel == 4) && (common->wcmFlags & GRAPHIRE_FLAG) && (wheel != 0)) ||
+ ((common->wcmOpen == xf86WcmUSBOpen) && (wheel != priv->oldWheel))) &&
+ !is_stylus) {
+ int fake_button;
+
+ if (common->wcmOpen == xf86WcmUSBOpen) {
+ fake_button = (wheel > priv->oldWheel) ? 5 : 4;
+ } else{
+ fake_button = (wheel > 0) ? 5 : 4;
+ }
+
+ xf86PostButtonEvent(local->dev,
+ (priv->flags & ABSOLUTE_FLAG),
+ fake_button, 1,
+ 0, 6, rx, ry, rz, rtx, rty, rwheel);
+
+ xf86PostButtonEvent(local->dev,
+ (priv->flags & ABSOLUTE_FLAG),
+ fake_button, 0,
+ 0, 6, rx, ry, rz, rtx, rty, rwheel);
+ }
+
+ priv->oldButtons = buttons;
+ priv->oldX = x;
+ priv->oldY = y;
+ priv->oldZ = z;
+ priv->oldTiltX = tx;
+ priv->oldTiltY = ty;
+ priv->oldWheel = wheel;
+ }
+ else { /* !PROXIMITY */
+ /* reports button up when the device has been down and becomes out of proximity */
+ if (priv->oldButtons) {
+ xf86WcmSendButtons (local, 0, rx, ry, rz, rtx, rty, rwheel);
+ priv->oldButtons = 0;
+ }
+ if (!is_core_pointer) {
+ /* macro button management */
+ if (common->wcmProtocolLevel == 4 && buttons) {
+ int macro = z / 2;
+
+ DBG(6, ErrorF("macro=%d buttons=%d wacom_map[%d]=%x\n",
+ macro, buttons, macro, wacom_map[macro]));
+
+ /* First available Keycode begins at 8 => macro+7 */
+ xf86PostKeyEvent(local->dev, macro+7, 1,
+ is_absolute, 0, 6,
+ 0, 0, buttons, rtx, rty, rwheel);
+ xf86PostKeyEvent(local->dev, macro+7, 0,
+ is_absolute, 0, 6,
+ 0, 0, buttons, rtx, rty, rwheel);
+ }
+ if (priv->oldProximity) {
+ xf86PostProximityEvent(local->dev, 0, 0, 6, rx, ry, rz,
+ rtx, rty, rwheel);
+ }
+ }
+ priv->oldProximity = 0;
+ }
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmSuppress --
+ * Determine whether device state has changed enough - return 1
+ * if not.
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmSuppress(int suppress,
+ WacomDeviceState *ds1,
+ WacomDeviceState *ds2)
+{
+ if (ds1->buttons != ds2->buttons) return 0;
+ if (ds1->proximity != ds2->proximity) return 0;
+ if (ABS(ds1->x - ds2->x) >= suppress) return 0;
+ if (ABS(ds1->y - ds2->y) >= suppress) return 0;
+ if (ABS(ds1->pressure - ds2->pressure) >= suppress) return 0;
+ if ((1800 + ds1->rotation - ds2->rotation) % 1800 >= suppress &&
+ (1800 + ds2->rotation - ds1->rotation) % 1800 >= suppress) return 0;
+ if (ABS(ds1->wheel - ds2->wheel) >= suppress) return 0;
+ return 1;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmIntuosFilter --
+ * Correct some hardware defects we've been seeing in Intuos pads,
+ * but also cuts down quite a bit on jitter.
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmIntuosFilter(WacomFilterState *state,
+ int coord,
+ int tilt)
+{
+ int tilt_filtered;
+ int ts;
+ int x0_pred;
+ int x0_pred1;
+ int x0, x1, x2, x3;
+ int x;
+
+ tilt_filtered = tilt + state->tilt[1] + state->tilt[2] + state->tilt[3];
+ state->tilt[2] = state->tilt[1];
+ state->tilt[1] = state->tilt[0];
+ state->tilt[0] = tilt;
+
+ x0 = coord;
+ x1 = state->coord[0];
+ x2 = state->coord[1];
+ x3 = state->coord[2];
+ state->coord[0] = x0;
+ state->coord[1] = x1;
+ state->coord[2] = x2;
+
+ ts = tilt_filtered >= 0 ? 1 : -1;
+
+ if (state->state == 0 || state->state == 3) {
+ x0_pred = 2 * x1 - x2;
+ x0_pred1 = 3 * x2 - 2 * x3;
+ if (ts * (x0 - x0_pred) > 12 &&
+ ts * (x0 - x0_pred1) > 12) {
+ /* detected a jump at x0 */
+ state->state = 1;
+ x = x1;
+ }
+ else if (state->state == 0) {
+ x = (7 * x0 + 14 * x1 + 15 * x2 - 4 * x3 + 16) >> 5;
+ }
+ else { /* state->state == 3 */
+ /* a jump at x3 was detected */
+ x = (x0 + 2 * x1 + x2 + 2) >> 2;
+ state->state = 0;
+ }
+ }
+ else if (state->state == 1) {
+ /* a jump at x1 was detected */
+ x = (3 * x0 + 7 * x2 - 2 * x3 + 4) >> 3;
+ state->state = 2;
+ }
+ else { /* state->state == 2 */
+ /* a jump at x2 was detected */
+ x = x1;
+ state->state = 3;
+ }
+
+ return x;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmReadInput --
+ * Read the new events from the device, and enqueue them.
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmReadInput(LocalDevicePtr local)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+ WacomCommonPtr common = priv->common;
+ int len, loop, idx;
+ int is_stylus = 1, is_button, is_proximity, wheel=0;
+ int is_absolute = (priv->flags & ABSOLUTE_FLAG);
+ int x, y, z, buttons, tx = 0, ty = 0;
+ unsigned char buffer[BUFFER_SIZE];
+ WacomDeviceState *ds;
+ WacomDeviceState old_ds;
+ int have_data;
+
+ DBG(7, ErrorF("xf86WcmReadInput BEGIN device=%s fd=%d\n",
+ common->wcmDevice, local->fd));
+
+ SYSCALL(len = read(local->fd, buffer, sizeof(buffer)));
+
+ if (len <= 0) {
+ ErrorF("Error reading wacom device : %s\n", strerror(errno));
+ return;
+ } else {
+ DBG(10, ErrorF("xf86WcmReadInput read %d bytes\n", len));
+ }
+
+ for(loop=0; loop<len; loop++) {
+
+ /* Format of 7 bytes data packet for Wacom Tablets
+ Byte 1
+ bit 7 Sync bit always 1
+ bit 6 Pointing device detected
+ bit 5 Cursor = 0 / Stylus = 1
+ bit 4 Reserved
+ bit 3 1 if a button on the pointing device has been pressed
+ bit 2 Reserved
+ bit 1 X15
+ bit 0 X14
+
+ Byte 2
+ bit 7 Always 0
+ bits 6-0 = X13 - X7
+
+ Byte 3
+ bit 7 Always 0
+ bits 6-0 = X6 - X0
+
+ Byte 4
+ bit 7 Always 0
+ bit 6 B3
+ bit 5 B2
+ bit 4 B1
+ bit 3 B0
+ bit 2 P0
+ bit 1 Y15
+ bit 0 Y14
+
+ Byte 5
+ bit 7 Always 0
+ bits 6-0 = Y13 - Y7
+
+ Byte 6
+ bit 7 Always 0
+ bits 6-0 = Y6 - Y0
+
+ Byte 7
+ bit 7 Always 0
+ bit 6 Sign of pressure data
+ bit 5 P6
+ bit 4 P5
+ bit 3 P4
+ bit 2 P3
+ bit 1 P2
+ bit 0 P1
+
+ byte 8 and 9 are optional and present only
+ in tilt mode.
+
+ Byte 8
+ bit 7 Always 0
+ bit 6 Sign of tilt X
+ bit 5 Xt6
+ bit 4 Xt5
+ bit 3 Xt4
+ bit 2 Xt3
+ bit 1 Xt2
+ bit 0 Xt1
+
+ Byte 9
+ bit 7 Always 0
+ bit 6 Sign of tilt Y
+ bit 5 Yt6
+ bit 4 Yt5
+ bit 3 Yt4
+ bit 2 Yt3
+ bit 1 Yt2
+ bit 0 Yt1
+
+ */
+
+ if ((common->wcmIndex == 0) && !(buffer[loop] & HEADER_BIT)) { /* magic bit is not OK */
+ DBG(6, ErrorF("xf86WcmReadInput bad magic number 0x%x (pktlength=%d) %d\n",
+ buffer[loop], common->wcmPktLength, loop));
+ continue;
+ }
+ else { /* magic bit at wrong place */
+ if ((common->wcmIndex != 0) && (buffer[loop] & HEADER_BIT)) {
+ DBG(6, ErrorF("xf86WcmReadInput magic number 0x%x detetected at index %d loop=%d\n",
+ (unsigned int) buffer[loop], common->wcmIndex, loop));
+ common->wcmIndex = 0;
+ }
+ }
+
+ common->wcmData[common->wcmIndex++] = buffer[loop];
+
+ if (common->wcmProtocolLevel == 4 &&
+ common->wcmIndex == common->wcmPktLength) {
+ int is_graphire = common->wcmFlags & GRAPHIRE_FLAG;
+
+ /* the packet is OK */
+
+ /* reset char count for next read */
+ common->wcmIndex = 0;
+
+ x = (((common->wcmData[0] & 0x3) << 14) +
+ (common->wcmData[1] << 7) +
+ common->wcmData[2]);
+ y = (((common->wcmData[3] & 0x3) << 14) +
+ (common->wcmData[4] << 7) +
+ common->wcmData[5]);
+
+ /* check which device we have */
+ is_stylus = (common->wcmData[0] & POINTER_BIT);
+
+ z = ((common->wcmData[6] & ZAXIS_BITS) * 2) +
+ ((common->wcmData[3] & ZAXIS_BIT) >> 2);
+
+ if (common->wcmMaxZ == 512) {
+ z = z*4 + ((common->wcmData[0] & ZAXIS_BIT) >> 1);
+
+ if (!(common->wcmData[6] & ZAXIS_SIGN_BIT)) {
+ z += 256;
+ }
+ DBG(10, ErrorF("graphire pressure(%c)=%d\n",
+ (common->wcmData[6] & ZAXIS_SIGN_BIT) ? '-' : '+', z));
+ }
+ else {
+ if (!(common->wcmData[6] & ZAXIS_SIGN_BIT)) {
+ z += (common->wcmMaxZ / 2);
+ }
+ }
+
+ is_proximity = (common->wcmData[0] & PROXIMITY_BIT);
+
+ if (is_graphire) {
+ if (is_stylus) {
+ buttons = ((common->wcmData[3] & 0x30) >> 3) |
+ (z >= common->wcmThreshold ? 1 : 0);
+ }
+ else {
+ buttons = (common->wcmData[3] & 0x38) >> 3;
+
+ wheel = (common->wcmData[6] & 0x30) >> 4;
+
+ if (common->wcmData[6] & 0x40) {
+ wheel = -wheel;
+ }
+ }
+ is_button = (buttons != 0);
+
+ DBG(10, ErrorF("graphire buttons=%d prox=%d wheel=%d\n", buttons, is_proximity, wheel));
+ }
+ else {
+ is_button = (common->wcmData[0] & BUTTON_FLAG);
+ buttons = (common->wcmData[3] & BUTTONS_BITS) >> 3;
+ }
+
+ /* The stylus reports button 4 for the second side
+ * switch and button 4/5 for the eraser tip. We know
+ * how to choose when we come in proximity for the
+ * first time. If we are in proximity and button 4 then
+ * we have the eraser else we have the second side
+ * switch.
+ */
+ if (is_stylus) {
+ if (!common->wcmStylusProximity && is_proximity) {
+ if (is_graphire) {
+ common->wcmStylusSide = !(common->wcmData[3] & 0x40);
+ }
+ else {
+ common->wcmStylusSide = (buttons != 4);
+ }
+ }
+ DBG(8, ErrorF("xf86WcmReadInput %s side\n",
+ common->wcmStylusSide ? "stylus" : "eraser"));
+ common->wcmStylusProximity = is_proximity;
+
+ /* handle tilt values only for stylus */
+ if (HANDLE_TILT(common)) {
+ tx = (common->wcmData[7] & TILT_BITS);
+ ty = (common->wcmData[8] & TILT_BITS);
+ if (common->wcmData[7] & TILT_SIGN_BIT)
+ tx -= (TILT_BITS + 1);
+ if (common->wcmData[8] & TILT_SIGN_BIT)
+ ty -= (TILT_BITS + 1);
+ }
+ }
+
+ for(idx=0; idx<common->wcmNumDevices; idx++) {
+ LocalDevicePtr local_dev = common->wcmDevices[idx];
+ WacomDevicePtr priv = (WacomDevicePtr) local_dev->private;
+ int temp_buttons = buttons;
+ int temp_is_proximity = is_proximity;
+ int curDevice;
+
+ DBG(7, ErrorF("xf86WcmReadInput trying to send to %s\n",
+ local_dev->name));
+
+ /* check for device type (STYLUS, ERASER or CURSOR) */
+
+ if (is_stylus) {
+ /*
+ * The eraser is reported as button 4 and 5 of the stylus.
+ * if we haven't an independent device for the eraser
+ * report the button as button 3 of the stylus.
+ */
+ if (is_proximity) {
+ if (is_graphire) {
+ if (common->wcmData[3] & 0x40) {
+ curDevice = ERASER_ID;
+ }
+ else {
+ curDevice = STYLUS_ID;
+ }
+ }
+ else {
+ if ((buttons & 4) && common->wcmHasEraser &&
+ ((!priv->oldProximity ||
+ (priv->oldProximity == ERASER_PROX)))) {
+ curDevice = ERASER_ID;
+ } else {
+ curDevice = STYLUS_ID;
+ }
+ }
+ } else {
+ /*
+ * When we are out of proximity with the eraser the
+ * button 4 isn't reported so we must check the
+ * previous proximity device.
+ */
+ if (common->wcmHasEraser && (priv->oldProximity == ERASER_PROX)) {
+ curDevice = ERASER_ID;
+ } else {
+ curDevice = STYLUS_ID;
+ }
+ }
+
+ /* We check here to see if we changed between eraser and stylus
+ * without leaving proximity. The most likely cause is that
+ * we were fooled by the second side switch into thinking the
+ * stylus was the eraser. If this happens, we send
+ * a proximity-out for the old device.
+ */
+ if ((DEVICE_ID(priv->flags) == STYLUS_ID ||
+ DEVICE_ID(priv->flags) == ERASER_ID) &&
+ curDevice != DEVICE_ID(priv->flags)) {
+ if (priv->oldProximity) {
+ curDevice = DEVICE_ID(priv->flags);
+ temp_buttons = 0;
+ temp_is_proximity = 0;
+ DBG(10, ErrorF("eraser and stylus mix\n"));
+ } else
+ continue;
+ }
+
+ DBG(10, ErrorF((DEVICE_ID(priv->flags) == ERASER_ID) ?
+ "Eraser\n" :
+ "Stylus\n"));
+ }
+ else {
+ if (DEVICE_ID(priv->flags) != CURSOR_ID)
+ continue;
+ DBG(10, ErrorF("Cursor\n"));
+ curDevice = CURSOR_ID;
+ }
+
+ xf86WcmSendEvents(common->wcmDevices[idx],
+ curDevice, 0,
+ is_stylus,
+ is_button,
+ temp_is_proximity,
+ x, y, z, temp_buttons,
+ tx, ty, wheel);
+ }
+ } /* protocol 4 */
+ else if (common->wcmProtocolLevel == 5 &&
+ common->wcmIndex == common->wcmPktLength) {
+ /* the packet is OK */
+ int x, y;
+
+ /* reset count for read of next packet */
+ common->wcmIndex = 0;
+
+ ds = &common->wcmDevStat[common->wcmData[0] & 0x01];
+ old_ds = *ds;
+ have_data = 0;
+
+ DBG(7, ErrorF("packet header = 0x%x\n",
+ (unsigned int)common->wcmData[0]));
+
+ /* Device ID packet */
+ if ((common->wcmData[0] & 0xfc) == 0xc0) {
+ memset(ds, 0, sizeof(*ds));
+ ds->proximity = 1;
+ ds->device_id = (((common->wcmData[1] & 0x7f) << 5) |
+ ((common->wcmData[2] & 0x7c) >> 2));
+ ds->serial_num = (((common->wcmData[2] & 0x03) << 30) |
+ ((common->wcmData[3] & 0x7f) << 23) |
+ ((common->wcmData[4] & 0x7f) << 16) |
+ ((common->wcmData[5] & 0x7f) << 9) |
+ ((common->wcmData[6] & 0x7f) << 23) |
+ ((common->wcmData[7] & 0x60) >> 5));
+ if ((ds->device_id & 0xf06) != 0x802)
+ ds->discard_first = 1;
+
+ if (PEN(ds) || STROKING_PEN(ds) || INKING_PEN(ds) || AIRBRUSH(ds))
+ ds->device_type = STYLUS_ID;
+ else if (MOUSE_4D(ds) || LENS_CURSOR(ds))
+ ds->device_type = CURSOR_ID;
+ else
+ ds->device_type = ERASER_ID;
+
+ DBG(6, ErrorF("device_id=0x%x serial_num=%u type=%s\n",
+ ds->device_id, ds->serial_num,
+ (ds->device_type == STYLUS_ID) ? "stylus"
+ : (ds->device_type == CURSOR_ID) ? "cursor"
+ : "eraser"));
+ }
+ /* Out of proximity packet */
+ else if ((common->wcmData[0] & 0xfe) == 0x80) {
+ ds->proximity = 0;
+ have_data = 1;
+ }
+ /* General pen packet or eraser packet or airbrush first packet */
+ else if (((common->wcmData[0] & 0xb8) == 0xa0) ||
+ /* airbrush second packet */
+ ((common->wcmData[0] & 0xbe) == 0xb4)) {
+ is_stylus = 1;
+ ds->x = (((common->wcmData[1] & 0x7f) << 9) |
+ ((common->wcmData[2] & 0x7f) << 2) |
+ ((common->wcmData[3] & 0x60) >> 5));
+ ds->y = (((common->wcmData[3] & 0x1f) << 11) |
+ ((common->wcmData[4] & 0x7f) << 4) |
+ ((common->wcmData[5] & 0x78) >> 3));
+ if ((common->wcmData[0] & 0xb8) == 0xa0) {
+ ds->pressure = (((common->wcmData[5] & 0x07) << 7) |
+ (common->wcmData[6] & 0x7f));
+ ds->buttons = (((common->wcmData[0]) & 0x06) |
+ (ds->pressure >= common->wcmThreshold));
+ }
+ else {
+ ds->wheel = (((common->wcmData[5] & 0x07) << 7) |
+ (common->wcmData[6] & 0x7f));
+ }
+ ds->tiltx = (common->wcmData[7] & TILT_BITS);
+ ds->tilty = (common->wcmData[8] & TILT_BITS);
+ if (common->wcmData[7] & TILT_SIGN_BIT)
+ ds->tiltx -= (TILT_BITS + 1);
+ if (common->wcmData[8] & TILT_SIGN_BIT)
+ ds->tilty -= (TILT_BITS + 1);
+ ds->proximity = (common->wcmData[0] & PROXIMITY_BIT);
+ have_data = 1;
+ }
+ /* 4D mouse 1st packet or Lens cursor packet */
+ else if (((common->wcmData[0] & 0xbe) == 0xa8) ||
+ ((common->wcmData[0] & 0xbe) == 0xb0)) {
+ is_stylus = 0;
+ ds->x = (((common->wcmData[1] & 0x7f) << 9) |
+ ((common->wcmData[2] & 0x7f) << 2) |
+ ((common->wcmData[3] & 0x60) >> 5));
+ ds->y = (((common->wcmData[3] & 0x1f) << 11) |
+ ((common->wcmData[4] & 0x7f) << 4) |
+ ((common->wcmData[5] & 0x78) >> 3));
+ ds->tilty = 0;
+ ds->wheel = (((common->wcmData[5] & 0x07) << 7) |
+ (common->wcmData[6] & 0x7f));
+ if (common->wcmData[8] & 0x08) ds->wheel = -ds->wheel;
+ /* 4D mouse */
+ if (MOUSE_4D(ds)) {
+ ds->buttons = (((common->wcmData[8] & 0x70) >> 1) |
+ (common->wcmData[8] & 0x07));
+ have_data = !ds->discard_first;
+ }
+ /* Lens cursor */
+ else {
+ ds->buttons = common->wcmData[8];
+ have_data = 1;
+ }
+ ds->proximity = (common->wcmData[0] & PROXIMITY_BIT);
+ }
+ /* 4D mouse 2nd packet */
+ else if ((common->wcmData[0] & 0xbe) == 0xaa) {
+ is_stylus = 0;
+ ds->x = (((common->wcmData[1] & 0x7f) << 9) |
+ ((common->wcmData[2] & 0x7f) << 2) |
+ ((common->wcmData[3] & 0x60) >> 5));
+ ds->y = (((common->wcmData[3] & 0x1f) << 11) |
+ ((common->wcmData[4] & 0x7f) << 4) |
+ ((common->wcmData[5] & 0x78) >> 3));
+ ds->tilty = 0;
+ ds->rotation = (((common->wcmData[6] & 0x0f) << 7) |
+ (common->wcmData[7] & 0x7f));
+ ds->tiltx = ((900 - ((ds->rotation + 900) % 1800)) >> 1);
+ ds->proximity = (common->wcmData[0] & PROXIMITY_BIT);
+ have_data = 1;
+ ds->discard_first = 0;
+ }
+ else {
+ DBG(10, ErrorF("unknown wacom V packet 0x%x\n",
+ common->wcmData[0]));
+ }
+
+ /* Suppress data */
+ if (have_data &&
+ xf86WcmSuppress(common->wcmSuppress, &old_ds, ds)) {
+ DBG(10, ErrorF("Suppressing data according to filter\n"));
+ *ds = old_ds;
+ have_data = 0;
+ }
+
+ if (have_data) {
+ if (is_absolute) {
+ x = xf86WcmIntuosFilter (&ds->x_filter, ds->x, ds->tiltx);
+ y = xf86WcmIntuosFilter (&ds->y_filter, ds->y, ds->tilty);
+ }
+ else {
+ x = ds->x;
+ y = ds->y;
+ }
+ for(idx=0; idx<common->wcmNumDevices; idx++) {
+ DBG(7, ErrorF("xf86WcmReadInput trying to send to %s\n",
+ common->wcmDevices[idx]->name));
+
+ xf86WcmSendEvents(common->wcmDevices[idx],
+ ds->device_type, ds->serial_num,
+ is_stylus,
+ ds->buttons,
+ ds->proximity,
+ x, y,
+ ds->pressure,
+ ds->buttons,
+ ds->tiltx, ds->tilty,
+ ds->wheel);
+ }
+ }
+ } /* protocol 5 */
+ } /* next data */
+ DBG(7, ErrorF("xf86WcmReadInput END local=0x%x priv=0x%x index=%d\n",
+ local, priv, common->wcmIndex));
+}
+
+#ifdef LINUX_INPUT
+/*
+ ***************************************************************************
+ *
+ * xf86WcmIsUSBLine --
+ * Test if the attached device is a USB one.
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmIsUSBLine(int fd)
+{
+ int version;
+ int err;
+
+ SYSCALL(err = ioctl(fd, EVIOCGVERSION, &version));
+
+ if (!err) {
+ ErrorF("%s Wacom Kernel Input driver version is %d.%d.%d\n", XCONFIG_PROBED,
+ version >> 16, (version >> 8) & 0xff, version & 0xff);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int ThrottleToRate(int x)
+{
+ if (x<0) x=-x;
+
+ /* piece-wise exponential function */
+
+ if (x < 128) return 0; /* infinite */
+ if (x < 256) return 1000; /* 1 second */
+ if (x < 512) return 500; /* 0.5 seconds */
+ if (x < 768) return 250; /* 0.25 seconds */
+ if (x < 896) return 100; /* 0.1 seconds */
+ if (x < 960) return 50; /* 0.05 seconds */
+ if (x < 1024) return 25; /* 0.025 seconds */
+ return 0; /* infinite */
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmReadUSBInput --
+ * Read the new events from the device, and enqueue them.
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmReadUSBInput(LocalDevicePtr local)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) local->private;
+ WacomCommonPtr common = priv->common;
+ int serial = common->wcmLastSerial;
+ int is_proximity = priv->oldProximity;
+ int x = priv->oldX;
+ int y = priv->oldY;
+ int pressure = priv->oldZ;
+ int buttons = priv->oldButtons;
+ int tilt_x = priv->oldTiltX;
+ int tilt_y = priv->oldTiltY;
+ int wheel = priv->oldWheel;
+ int sampleTime, ticks;
+
+ ssize_t len;
+ int idx, loop;
+ struct input_event * event, *readevent;
+ char eventbuf[sizeof(struct input_event) * MAX_EVENTS];
+#define MOD_BUTTONS(bit, value) \
+ { int _b=bit, _v=value; buttons = (((_v) != 0) ? (buttons | _b) : (buttons & ~ _b)); }
+
+ /* get the sample time */
+ sampleTime = GetTimeInMillis();
+
+ /* account for roll overs and initialization */
+ if ((priv->throttleStart > sampleTime) || (!priv->throttleStart))
+ {
+ priv->throttleStart = sampleTime;
+ priv->throttleLimit = -1;
+ }
+
+ SYSCALL(len = read(local->fd, eventbuf, sizeof(eventbuf)));
+
+ DBG(10, ErrorF("xf86WcmReadUSBInput read %d events\n", len/sizeof(struct input_event)));
+
+ if (len <= 0) {
+ ErrorF("Error reading wacom device : %s\n", strerror(errno));
+ return;
+ }
+
+ for (readevent=(struct input_event *)eventbuf;
+ readevent<(struct input_event *)(eventbuf+len); readevent++) {
+ /* sanity check */
+ if (common->wcmIndex >= MAX_USB_EVENTS) {
+ DBG(11, ErrorF("xf86WcmReadUSBInput resetting buffer index\n"));
+ common->wcmIndex = 0;
+ }
+
+ common->wcmEvent[common->wcmIndex++] = *readevent;
+
+ /* MSC_SERIAL is the event terminator */
+ if (!((readevent->type == EV_MSC && readevent->code == MSC_SERIAL) ||
+ (readevent->type == EV_ABS && readevent->code == ABS_MISC))) {
+ continue;
+ }
+
+ for(loop=0; loop<common->wcmIndex; loop++) {
+ event = common->wcmEvent + loop;
+ DBG(11, ErrorF("xf86WcmReadUSBInput event[%d]->type=%d code=%d value=%d\n",
+ loop, event->type, event->code, event->value));
+ switch (event->type) {
+ case EV_ABS:
+ switch (event->code) {
+ case ABS_X:
+ x = event->value;
+ break;
+
+ case ABS_Y:
+ y = event->value;
+ break;
+
+ case ABS_TILT_X:
+ case ABS_RZ:
+ tilt_x = event->value;
+ break;
+
+ case ABS_TILT_Y:
+ tilt_y = event->value;
+ break;
+
+ case ABS_PRESSURE:
+ pressure = event->value;
+ MOD_BUTTONS (1, event->value > common->wcmThreshold ? 1 : 0);
+ break;
+
+ case ABS_DISTANCE:
+ /* This is not sent by the driver */
+ /* JEJ - actually it is, but it's not very useful */
+ break;
+
+ case ABS_MISC:
+ serial = event->value;
+ DBG(10, ErrorF("wacom tool serial id=%d\n", serial));
+ break;
+
+ case ABS_WHEEL:
+ wheel = event->value;
+ break;
+
+ case ABS_THROTTLE:
+ priv->throttleValue = event->value;
+ ticks = ThrottleToRate(event->value);
+ priv->throttleLimit = ticks ? priv->throttleStart + ticks : -1;
+ break;
+ }
+ break; /* EV_ABS */
+
+ case EV_REL:
+ switch (event->code) {
+ case REL_WHEEL:
+ wheel += event->value;
+ break;
+ default:
+ ErrorF("wacom: relative event received (%d)!!!\n", event->code);
+ break;
+ }
+ break; /* EV_REL */
+
+ case EV_KEY:
+ switch (event->code) {
+ case BTN_TOOL_PEN:
+ case BTN_TOOL_PENCIL:
+ case BTN_TOOL_BRUSH:
+ case BTN_TOOL_AIRBRUSH:
+ DBG(10, ErrorF("USB Stylus detected %x\n", event->code));
+ common->wcmLastTool = STYLUS_ID;
+ is_proximity = (event->value != 0);
+ break;
+
+ case BTN_TOOL_RUBBER:
+ DBG(10, ErrorF("USB eraser detected %x\n", event->code));
+ common->wcmLastTool = ERASER_ID;
+ is_proximity = (event->value != 0);
+ break;
+
+ case BTN_TOOL_MOUSE:
+ case BTN_TOOL_LENS:
+ DBG(10, ErrorF("USB mouse detected %x\n", event->code));
+ common->wcmLastTool = CURSOR_ID;
+ is_proximity = (event->value != 0);
+ break;
+
+ case BTN_TOUCH:
+ /* we use the pressure to determine the button 1 */
+ break;
+
+ case BTN_STYLUS:
+ case BTN_MIDDLE:
+ MOD_BUTTONS (2, event->value);
+ break;
+
+ case BTN_STYLUS2:
+ case BTN_RIGHT:
+ MOD_BUTTONS (4, event->value);
+ break;
+
+ case BTN_LEFT:
+ MOD_BUTTONS (1, event->value);
+ break;
+
+ case BTN_SIDE:
+ MOD_BUTTONS (8, event->value);
+ break;
+
+ case BTN_EXTRA:
+ MOD_BUTTONS (16, event->value);
+ break;
+ }
+ break; /* EV_KEY */
+ case EV_MSC:
+ switch (event->code) {
+ case MSC_SERIAL:
+ serial = event->value;
+ DBG(10, ErrorF("wacom tool serial id=%d\n", serial));
+ break;
+ }
+ break; /* EV_MSC */
+ } /* switch event->type */
+
+ /* MSC_SERIAL is the event terminator */
+ if (!(event->type == EV_MSC && event->code == MSC_SERIAL) &&
+ !(event->type == EV_ABS && event->code == ABS_MISC)) {
+ continue;
+ }
+
+ /* handle throttle */
+ if ((priv->throttleLimit >= 0) && (priv->throttleLimit < sampleTime))
+ {
+ DBG(6, ErrorF("LIMIT REACHED: s=%d l=%d n=%d v=%d N=%d\n",
+ priv->throttleStart,
+ priv->throttleLimit,
+ sampleTime,
+ priv->throttleValue,
+ sampleTime + ThrottleToRate(priv->throttleValue)));
+
+ wheel += (priv->throttleValue > 0) ? 1 :
+ (priv->throttleValue < 0) ? -1 : 0;
+
+ priv->throttleStart = sampleTime;
+ priv->throttleLimit = sampleTime + ThrottleToRate(priv->throttleValue);
+ }
+
+ if ((is_proximity == priv->oldProximity) &&
+ (buttons == priv->oldButtons) &&
+ (wheel == priv->oldWheel) &&
+ (ABS(x - priv->oldX) <= common->wcmSuppress) &&
+ (ABS(y - priv->oldY) <= common->wcmSuppress) &&
+ (ABS(pressure - priv->oldZ) < 3) &&
+ (ABS(tilt_x - priv->oldTiltX) < 3) &&
+ (ABS(tilt_y - priv->oldTiltY) < 3)) {
+ DBG(10, ErrorF("filtered %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ x, priv->oldX,
+ y, priv->oldY,
+ pressure, priv->oldZ,
+ is_proximity, priv->oldProximity,
+ buttons, priv->oldButtons,
+ wheel, priv->oldWheel,
+ tilt_x, priv->oldTiltX,
+ tilt_y, priv->oldTiltY));
+ continue;
+ }
+
+ DBG(10, ErrorF("sending event %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ x, priv->oldX,
+ y, priv->oldY,
+ pressure, priv->oldZ,
+ is_proximity, priv->oldProximity,
+ buttons, priv->oldButtons,
+ wheel, priv->oldWheel,
+ tilt_x, priv->oldTiltX,
+ tilt_y, priv->oldTiltY));
+
+ for (idx=0; idx<common->wcmNumDevices; idx++) {
+ WacomDevicePtr dev = common->wcmDevices[idx]->private;
+ int id;
+
+ id = DEVICE_ID (dev->flags);
+
+ /* Find the device the current events are meant for */
+ if (id == common->wcmLastTool) {
+ DBG(11, ErrorF("tool id=%d for %s\n", id, local->name));
+
+ xf86WcmSendEvents(common->wcmDevices[idx],
+ common->wcmLastTool,
+ serial,
+ (common->wcmLastTool == STYLUS_ID || common->wcmLastTool == ERASER_ID),
+ !!(buttons),
+ is_proximity,
+ x, y, pressure, buttons,
+ tilt_x, tilt_y, wheel);
+ }
+ }
+ priv->oldX = x;
+ priv->oldY = y;
+ priv->oldZ = pressure;
+ priv->oldTiltX = tilt_x;
+ priv->oldTiltY = tilt_y;
+ priv->oldProximity = is_proximity;
+ priv->oldButtons = buttons;
+ priv->oldWheel = wheel;
+ common->wcmLastSerial = serial;
+ } /* next event */
+ common->wcmIndex=0;
+ } /* next event group */
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmUSBOpen --
+ *
+ ***************************************************************************
+ */
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+#define OFF(x) ((x)%BITS_PER_LONG)
+#define LONG(x) ((x)/BITS_PER_LONG)
+
+static Bool
+xf86WcmUSBOpen(LocalDevicePtr local)
+{
+ int err = 0;
+ WacomDevicePtr priv = (WacomDevicePtr)local->private;
+ WacomCommonPtr common = priv->common;
+ char name[256] = "Unknown";
+ int abs[5];
+ unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
+ int i, j;
+
+#ifdef XFREE86_V4
+ local->fd = xf86OpenSerial(local->options);
+#else
+ SYSCALL(local->fd = open(common->wcmDevice, O_RDONLY|O_NDELAY, 0));
+#endif
+ if (local->fd == -1) {
+ ErrorF("Error opening %s : %s\n", common->wcmDevice, strerror(errno));
+ return !Success;
+ }
+
+ ioctl(local->fd, EVIOCGNAME(sizeof(name)), name);
+ ErrorF("%s Wacom Kernel Input device name: \"%s\"\n", XCONFIG_PROBED, name);
+
+ memset(bit, 0, sizeof(bit));
+ ioctl(local->fd, EVIOCGBIT(0, EV_MAX), bit[0]);
+
+ for (i = 0; i < EV_MAX; i++)
+ if (test_bit(i, bit[0])) {
+ ioctl(local->fd, EVIOCGBIT(i, KEY_MAX), bit[i]);
+ for (j = 0; j < KEY_MAX; j++)
+ if (test_bit(j, bit[i])) {
+ if (i == EV_ABS) {
+ ioctl(local->fd, EVIOCGABS(j), abs);
+ switch (j) {
+ case ABS_X:
+ if (common->wcmMaxX == 0) {
+ common->wcmMaxX = abs[2];
+ }
+ break;
+
+ case ABS_Y:
+ if (common->wcmMaxY == 0) {
+ common->wcmMaxY = abs[2];
+ }
+ break;
+
+ case ABS_PRESSURE:
+ if (common->wcmMaxZ == DEFAULT_MAXZ) {
+ common->wcmMaxZ = abs[2];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ DBG(2, ErrorF("setup is max X=%d(%d) Y=%d(%d) Z=%d(%d)\n",
+ common->wcmMaxX, common->wcmResolX,
+ common->wcmMaxY, common->wcmResolY,
+ common->wcmMaxZ, common->wcmResolZ));
+
+ /* send the tilt mode command after setup because it must be enabled */
+ /* after multi-mode to take precedence */
+ if (HANDLE_TILT(common)) {
+ /* Unfortunately, the USB driver doesn't allow to send this
+ * command to the tablet. Any other solutions ? */
+ DBG(2, ErrorF("Sending tilt mode order\n"));
+ }
+
+ if (common->wcmSuppress < 0) {
+ int xratio = common->wcmMaxX/screenInfo.screens[0]->width;
+ int yratio = common->wcmMaxY/screenInfo.screens[0]->height;
+
+ common->wcmSuppress = (xratio > yratio) ? yratio : xratio;
+ }
+
+ if (common->wcmSuppress > 100) {
+ common->wcmSuppress = 99;
+ }
+ /* Cannot send WC_SUPPRESS to the table. Will have to do
+ * this manually. */
+
+ priv->topX = 0;
+ priv->bottomX = common->wcmMaxX;
+ priv->topY = 0;
+ priv->bottomY = common->wcmMaxY;
+
+ if (xf86Verbose)
+ ErrorF("%s Wacom tablet maximum X=%d maximum Y=%d "
+ "X resolution=%d Y resolution=%d suppress=%d%s\n",
+ XCONFIG_PROBED, common->wcmMaxX, common->wcmMaxY,
+ common->wcmResolX, common->wcmResolY, common->wcmSuppress,
+ HANDLE_TILT(common) ? " Tilt" : "");
+
+ if (err < 0) {
+ ErrorF("ERROR: %d\n", err);
+ SYSCALL(close(local->fd));
+ return !Success;
+ }
+
+ /* to have the button field handled as a bit field */
+ common->wcmProtocolLevel = 5;
+
+ return Success;
+}
+
+#endif /* LINUX_INPUT */
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmControlProc --
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmControlProc(DeviceIntPtr device,
+ PtrCtrl *ctrl)
+{
+ DBG(2, ErrorF("xf86WcmControlProc\n"));
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmOpen --
+ *
+ ***************************************************************************
+ */
+#ifdef XFREE86_V4
+#define WAIT(t) \
+ err = xf86WaitForInput(-1, ((t) * 1000)); \
+ if (err == -1) { \
+ ErrorF("Wacom select error : %s\n", strerror(errno)); \
+ return !Success; \
+ }
+#else
+#define WAIT(t) \
+ timeout.tv_sec = 0; \
+ timeout.tv_usec = (t) * 1000; \
+ SYSCALL(err = select(0, NULL, NULL, NULL, &timeout)); \
+ if (err == -1) { \
+ ErrorF("Wacom select error : %s\n", strerror(errno)); \
+ return !Success; \
+ }
+#endif
+
+static Bool
+xf86WcmOpen(LocalDevicePtr local)
+{
+#ifndef XFREE86_V4
+ struct timeval timeout;
+#endif
+ char buffer[256];
+ char header[64]; /* This is a small buffer for discarding the unwanted header */
+ int err;
+ WacomDevicePtr priv = (WacomDevicePtr)local->private;
+ WacomCommonPtr common = priv->common;
+ int a, b;
+ int loop, idx;
+ float version = 0.0;
+ int is_a_penpartner = 0;
+
+ DBG(1, ErrorF("opening %s\n", common->wcmDevice));
+
+#ifdef XFREE86_V4
+ local->fd = xf86OpenSerial(local->options);
+#else
+ SYSCALL(local->fd = open(common->wcmDevice, O_RDWR|O_NDELAY, 0));
+#endif
+ if (local->fd < 0) {
+ ErrorF("Error opening %s : %s\n", common->wcmDevice, strerror(errno));
+ return !Success;
+ }
+
+#ifdef LINUX_INPUT
+ DBG(1, ErrorF("testing USB\n"));
+
+ if (xf86WcmIsUSBLine(local->fd)) {
+ int loop;
+
+ SYSCALL(close(local->fd));
+
+ for(loop=0; loop<common->wcmNumDevices; loop++) {
+ common->wcmDevices[loop]->read_input=xf86WcmReadUSBInput;
+ }
+ common->wcmOpen=xf86WcmUSBOpen;
+
+ return xf86WcmUSBOpen(local);
+ }
+#endif
+
+ DBG(1, ErrorF("initializing tablet\n"));
+
+ /* Set the speed of the serial link to 38400 */
+#ifdef XFREE86_V4
+ if (xf86SetSerialSpeed(local->fd, 38400) < 0) {
+ return !Success;
+ }
+#else
+ if (set_serial_speed(local->fd, B38400) == !Success)
+ return !Success;
+#endif
+
+ /* Send reset to the tablet */
+ SYSCALL(err = write(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 250 mSecs */
+ WAIT(250);
+
+ /* Send reset to the tablet */
+ SYSCALL(err = write(local->fd, WC_RESET, strlen(WC_RESET)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 75 mSecs */
+ WAIT(75);
+
+ /* Set the speed of the serial link to 19200 */
+#ifdef XFREE86_V4
+ if (xf86SetSerialSpeed(local->fd, 19200) < 0) {
+ return !Success;
+ }
+#else
+ if (set_serial_speed(local->fd, B19200) == !Success)
+ return !Success;
+#endif
+
+ /* Send reset to the tablet */
+ SYSCALL(err = write(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 250 mSecs */
+ WAIT(250);
+
+ /* Send reset to the tablet */
+ SYSCALL(err = write(local->fd, WC_RESET, strlen(WC_RESET)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 75 mSecs */
+ WAIT(75);
+
+ /* Set the speed of the serial link to 9600 */
+#ifdef XFREE86_V4
+ if (xf86SetSerialSpeed(local->fd, 9600) < 0) {
+ return !Success;
+ }
+#else
+ if (set_serial_speed(local->fd, B9600) == !Success)
+ return !Success;
+#endif
+
+ /* Send reset to the tablet */
+ SYSCALL(err = write(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 250 mSecs */
+ WAIT(250);
+
+ SYSCALL(err = write(local->fd, WC_STOP, strlen(WC_STOP)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 30 mSecs */
+ WAIT(30);
+
+#ifdef XFREE86_V4
+ xf86FlushInput(local->fd);
+#else
+ flush_input_fd(local->fd);
+#endif
+
+ DBG(2, ErrorF("reading model\n"));
+ if (!send_request(local->fd, WC_MODEL, buffer)) {
+ return !Success;
+ }
+ DBG(2, ErrorF("%s\n", buffer));
+
+ if (xf86Verbose) {
+ ErrorF("%s Wacom tablet model : %s\n", XCONFIG_PROBED, buffer+2);
+ }
+
+ /* Answer is in the form ~#Tablet-Model VRom_Version */
+ /* look for the first V from the end of the string */
+ /* this seems to be the better way to find the version of the ROM */
+ for(loop=strlen(buffer); loop>=0 && *(buffer+loop) != 'V'; loop--);
+ for(idx=loop; idx<strlen(buffer) && *(buffer+idx) != '-'; idx++);
+ *(buffer+idx) = '\0';
+
+ /* Extract version numbers */
+ sscanf(buffer+loop+1, "%f", &version);
+
+ if ((buffer[2] == 'G' && buffer[3] == 'D') ||
+ (buffer[2] == 'X' && buffer[3] == 'D')) {
+ DBG(2, ErrorF("detected an Intuos model\n"));
+ common->wcmProtocolLevel = 5;
+ common->wcmMaxZ = 1023; /* max Z value */
+ common->wcmResolX = 2540; /* X resolution in points/inch */
+ common->wcmResolY = 2540; /* Y resolution in points/inch */
+ common->wcmResolZ = 2540; /* Z resolution in points/inch */
+ common->wcmPktLength = 9; /* length of a packet */
+ if (common->wcmThreshold == INVALID_THRESHOLD) {
+ common->wcmThreshold = -480; /* Threshold for counting pressure as a button */
+ if (xf86Verbose) {
+ ErrorF("%s Wacom using pressure threshold of %d for button 1\n",
+ XCONFIG_PROBED, common->wcmThreshold);
+ }
+ }
+ }
+
+ /* Tilt works on ROM 1.4 and above */
+ DBG(2, ErrorF("wacom flags=%d ROM version=%f buffer=%s\n",
+ common->wcmFlags, version, buffer+loop+1));
+ if (common->wcmProtocolLevel == 4 &&
+ (common->wcmFlags & TILT_FLAG) && (version >= (float)1.4)) {
+ common->wcmPktLength = 9;
+ }
+
+ /* Check for a PenPartner or Graphire model which doesn't answer WC_CONFIG
+ * request. The Graphire model is handled like a PenPartner except that
+ * it doesn't answer WC_COORD requests.
+ */
+ if ((buffer[2] == 'C' || buffer[2] == 'E') && buffer[3] == 'T') {
+ if (buffer[2] == 'E') {
+ DBG(2, ErrorF("detected a Graphire model\n"));
+ common->wcmFlags |= GRAPHIRE_FLAG;
+ /* Graphire models don't answer WC_COORD requests */
+ common->wcmMaxX = 5103;
+ common->wcmMaxY = 3711;
+ common->wcmMaxZ = 512;
+ }
+ else {
+ DBG(2, ErrorF("detected a PenPartner model\n"));
+ common->wcmMaxZ = 256;
+ }
+ common->wcmResolX = 1000;
+ common->wcmResolY = 1000;
+ is_a_penpartner = 1;
+ }
+ else if (common->wcmProtocolLevel == 4 && !(common->wcmResolX && common->wcmResolY)) {
+ DBG(2, ErrorF("reading config\n"));
+ if (send_request(local->fd, WC_CONFIG, buffer)) {
+ DBG(2, ErrorF("%s\n", buffer));
+ /* The header string is simply a place to put the unwanted
+ * config header don't use buffer+xx because the header size
+ * varies on different tablets
+ */
+ if (sscanf(buffer, "%[^,],%d,%d,%d,%d", header, &a, &b, &common->wcmResolX, &common->wcmResolY) == 5) {
+ DBG(6, ErrorF("WC_CONFIG Header = %s\n", header));
+ }
+ else {
+ ErrorF("WACOM: unable to parse resolution. Using default.\n");
+ common->wcmResolX = common->wcmResolY = 1270;
+ }
+ }
+ else {
+ ErrorF("WACOM: unable to read resolution. Using default.\n");
+ common->wcmResolX = common->wcmResolY = 1270;
+ }
+ }
+
+ if (!(common->wcmFlags & GRAPHIRE_FLAG) && !(common->wcmMaxX && common->wcmMaxY)) {
+ DBG(2, ErrorF("reading max coordinates\n"));
+ if (!send_request(local->fd, WC_COORD, buffer)) {
+ ErrorF("WACOM: unable to read max coordinates. Use the MaxX and MaxY options.\n");
+ return !Success;
+ }
+ DBG(2, ErrorF("%s\n", buffer));
+ if (sscanf(buffer+2, "%d,%d", &common->wcmMaxX, &common->wcmMaxY) != 2) {
+ ErrorF("WACOM: unable to parse max coordinates. Use the MaxX and MaxY options.\n");
+ return !Success;
+ }
+ }
+
+ DBG(2, ErrorF("setup is max X=%d max Y=%d resol X=%d resol Y=%d\n",
+ common->wcmMaxX, common->wcmMaxY, common->wcmResolX,
+ common->wcmResolY));
+
+ /* We can't change the resolution on PenPartner and Graphire models */
+ if (!is_a_penpartner && common->wcmProtocolLevel == 4) {
+ int resolX = common->wcmResolX, resolY = common->wcmResolY;
+
+ /* Force the resolution.
+ */
+ if (((float)version) >= 1.2) {
+ resolX = resolY = 2540;
+ }
+ sprintf(buffer, "%s%d\r", WC_NEW_RESOLUTION, resolX);
+ SYSCALL(err = write(local->fd, buffer, strlen(buffer)));
+
+ /* Verify the resolution change.
+ */
+ DBG(2, ErrorF("rereading config\n"));
+ if (send_request(local->fd, WC_CONFIG, buffer)) {
+ DBG(2, ErrorF("%s\n", buffer));
+ /* The header string is simply a place to put the unwanted
+ * config header don't use buffer+xx because the header size
+ * varies on different tablets
+ */
+ if (sscanf(buffer, "%[^,],%d,%d,%d,%d", header, &a, &b, &common->wcmResolX, &common->wcmResolY) == 5) {
+ DBG(6, ErrorF("WC_CONFIG Header = %s\n", header));
+ }
+ else {
+ ErrorF("WACOM: unable to reparse resolution. Using previous values.\n");
+ }
+ }
+ else {
+ ErrorF("WACOM: unable to reread resolution. Using previous values.\n");
+ }
+
+ /* The following couple of lines convert the MaxX and MaxY returned by
+ * the Wacom from 1270lpi to the Wacom's active resolution.
+ */
+ common->wcmMaxX = (common->wcmMaxX / MAX_COORD_RES) * common->wcmResolX;
+ common->wcmMaxY = (common->wcmMaxY / MAX_COORD_RES) * common->wcmResolY;
+ }
+
+ DBG(2, ErrorF("setup is max X=%d max Y=%d resol X=%d resol Y=%d\n",
+ common->wcmMaxX, common->wcmMaxY, common->wcmResolX,
+ common->wcmResolY));
+
+ /* Send a setup string to the tablet */
+ if (is_a_penpartner) {
+ SYSCALL(err = write(local->fd, penpartner_setup_string,
+ strlen(penpartner_setup_string)));
+ }
+ else if (common->wcmProtocolLevel == 4) {
+ SYSCALL(err = write(local->fd, WC_RESET, strlen(WC_RESET)));
+ WAIT(75);
+ SYSCALL(err = write(local->fd, setup_string, strlen(setup_string)));
+ }
+ else {
+ SYSCALL(err = write(local->fd, intuos_setup_string,
+ strlen(intuos_setup_string)));
+ }
+
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Send the tilt mode command after setup because it must be enabled */
+ /* after multi-mode to take precedence */
+ if (common->wcmProtocolLevel == 4 && HANDLE_TILT(common)) {
+ DBG(2, ErrorF("Sending tilt mode order\n"));
+
+ SYSCALL(err = write(local->fd, WC_TILT_MODE, strlen(WC_TILT_MODE)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+ }
+
+ if (common->wcmSuppress < 0) {
+ int xratio = common->wcmMaxX/screenInfo.screens[0]->width;
+ int yratio = common->wcmMaxY/screenInfo.screens[0]->height;
+
+ common->wcmSuppress = (xratio > yratio) ? yratio : xratio;
+ }
+
+ if (common->wcmSuppress > 100) {
+ common->wcmSuppress = 99;
+ }
+
+ if (common->wcmProtocolLevel == 4) {
+ char buf[20];
+
+ sprintf(buf, "%s%d\r", WC_SUPPRESS, common->wcmSuppress);
+ SYSCALL(err = write(local->fd, buf, strlen(buf)));
+
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+ }
+
+ if (xf86Verbose)
+ ErrorF("%s Wacom %s tablet maximum X=%d maximum Y=%d "
+ "X resolution=%d Y resolution=%d suppress=%d%s\n",
+ XCONFIG_PROBED, common->wcmProtocolLevel == 4 ? "IV" : "V",
+ common->wcmMaxX, common->wcmMaxY,
+ common->wcmResolX, common->wcmResolY, common->wcmSuppress,
+ HANDLE_TILT(common) ? " Tilt" : "");
+
+ if (err <= 0) {
+ SYSCALL(close(local->fd));
+ return !Success;
+ }
+
+ /* change the serial speed if requested */
+ if (common->wcmLinkSpeed > 9600) {
+ if (common->wcmProtocolLevel == 5) {
+ char *speed_init_string = WC_V_19200;
+#ifndef XFREE86_V4
+ int speed = B19200;
+#endif
+ DBG(1, ErrorF("Switching serial link to %d\n", common->wcmLinkSpeed));
+
+ if (common->wcmLinkSpeed == 38400 && version < 2.0) {
+ ErrorF("Wacom: 38400 speed not supported with this Intuos firmware (%f)\n", version);
+ ErrorF("Switching to 19200\n");
+ common->wcmLinkSpeed = 19200;
+ }
+
+ switch (common->wcmLinkSpeed) {
+ case 38400:
+ speed_init_string = WC_V_38400;
+#ifndef XFREE86_V4
+ speed = B38400;
+#endif
+ break;
+
+ case 19200:
+ speed_init_string = WC_V_19200;
+#ifndef XFREE86_V4
+ speed = B19200;
+#endif
+ break;
+ }
+ /* Switch the tablet to the requested speed */
+ SYSCALL(err = write(local->fd, speed_init_string, strlen(speed_init_string)));
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ /* Wait 75 mSecs */
+ WAIT(75);
+
+ /* Set the speed of the serial link to requested speed */
+#ifdef XFREE86_V4
+ if (xf86SetSerialSpeed(local->fd, common->wcmLinkSpeed) < 0) {
+ return !Success;
+ }
+#else
+ if (set_serial_speed(local->fd, speed) == !Success)
+ return !Success;
+#endif
+ }
+ else {
+ ErrorF("Changing the speed of a wacom IV device is not yet implemented\n");
+ }
+ }
+
+ /* Tell the tablet to start sending coordinates */
+ SYSCALL(err = write(local->fd, WC_START, strlen(WC_START)));
+
+ if (err == -1) {
+ ErrorF("Wacom write error : %s\n", strerror(errno));
+ return !Success;
+ }
+
+ return Success;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmOpenDevice --
+ * Open the physical device and init information structs.
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmOpenDevice(DeviceIntPtr pWcm)
+{
+ LocalDevicePtr local = (LocalDevicePtr)pWcm->public.devicePrivate;
+ WacomDevicePtr priv = (WacomDevicePtr)PRIVATE(pWcm);
+ WacomCommonPtr common = priv->common;
+ double screenRatio, tabletRatio;
+ int gap;
+ int loop;
+ int screen_idx = 0;
+
+ if (local->fd < 0) {
+ if (common->wcmInitNumber > 2 ||
+ priv->initNumber == common->wcmInitNumber) {
+ if (common->wcmOpen(local) != Success) {
+ if (local->fd >= 0) {
+ SYSCALL(close(local->fd));
+ }
+ local->fd = -1;
+ }
+ else {
+ /* report the file descriptor to all devices */
+ for(loop=0; loop<common->wcmNumDevices; loop++) {
+ common->wcmDevices[loop]->fd = local->fd;
+ }
+ }
+ common->wcmInitNumber++;
+ priv->initNumber = common->wcmInitNumber;
+ }
+ else {
+ priv->initNumber = common->wcmInitNumber;
+ }
+ }
+
+ if (local->fd != -1 &&
+ priv->factorX == 0.0) {
+
+ if (priv->bottomX == 0) priv->bottomX = common->wcmMaxX;
+
+ if (priv->bottomY == 0) priv->bottomY = common->wcmMaxY;
+
+ /* Verify Box validity */
+
+ if (priv->topX > common->wcmMaxX ||
+ priv->topX < 0) {
+ ErrorF("Wacom invalid TopX (%d) reseting to 0\n", priv->topX);
+ priv->topX = 0;
+ }
+
+ if (priv->topY > common->wcmMaxY ||
+ priv->topY < 0) {
+ ErrorF("Wacom invalid TopY (%d) reseting to 0\n", priv->topY);
+ priv->topY = 0;
+ }
+
+ if (priv->bottomX > common->wcmMaxX ||
+ priv->bottomX < priv->topX) {
+ ErrorF("Wacom invalid BottomX (%d) reseting to %d\n",
+ priv->bottomX, common->wcmMaxX);
+ priv->bottomX = common->wcmMaxX;
+ }
+
+ if (priv->bottomY > common->wcmMaxY ||
+ priv->bottomY < priv->topY) {
+ ErrorF("Wacom invalid BottomY (%d) reseting to %d\n",
+ priv->bottomY, common->wcmMaxY);
+ priv->bottomY = common->wcmMaxY;
+ }
+
+ if (priv->screen_no != -1 &&
+ (priv->screen_no >= screenInfo.numScreens ||
+ priv->screen_no < 0)) {
+ ErrorF("%s: invalid screen number %d, resetting to 0\n",
+ local->name, priv->screen_no);
+ priv->screen_no = 0;
+ }
+
+ /* Calculate the ratio according to KeepShape, TopX and TopY */
+
+ if (priv->screen_no != -1) {
+ screen_idx = priv->screen_no;
+ }
+
+ if (priv->flags & KEEP_SHAPE_FLAG) {
+ screenRatio = ((double) screenInfo.screens[screen_idx]->width)
+ / screenInfo.screens[screen_idx]->height;
+
+ tabletRatio = ((double) (common->wcmMaxX - priv->topX))
+ / (common->wcmMaxY - priv->topY);
+
+ DBG(2, ErrorF("screenRatio = %.3g, tabletRatio = %.3g\n",
+ screenRatio, tabletRatio));
+
+ if (screenRatio > tabletRatio) {
+ gap = common->wcmMaxY * (1 - tabletRatio/screenRatio);
+ priv->bottomX = common->wcmMaxX;
+ priv->bottomY = common->wcmMaxY - gap;
+ } else {
+ gap = common->wcmMaxX * (1 - screenRatio/tabletRatio);
+ priv->bottomX = common->wcmMaxX - gap;
+ priv->bottomY = common->wcmMaxY;
+ }
+ }
+ priv->factorX = ((double) screenInfo.screens[0]->width)
+ / (priv->bottomX - priv->topX);
+ priv->factorY = ((double) screenInfo.screens[0]->height)
+ / (priv->bottomY - priv->topY);
+
+ if (xf86Verbose)
+ ErrorF("%s Wacom tablet top X=%d top Y=%d "
+ "bottom X=%d bottom Y=%d\n",
+ XCONFIG_PROBED, priv->topX, priv->topY,
+ priv->bottomX, priv->bottomY);
+
+ DBG(2, ErrorF("X factor = %.3g, Y factor = %.3g\n",
+ priv->factorX, priv->factorY));
+ }
+
+ /* Check threshold correctness */
+ DBG(2, ErrorF("Threshold=%d\n", common->wcmThreshold));
+
+ if (common->wcmThreshold > common->wcmMaxZ ||
+ common->wcmThreshold < 0) {
+ if (((common->wcmProtocolLevel == 5) ||
+ (common->wcmFlags & GRAPHIRE_FLAG)) &&
+ xf86Verbose &&
+ common->wcmThreshold != INVALID_THRESHOLD)
+ ErrorF("%s Wacom invalid threshold %d. Reset to %d\n",
+ XCONFIG_PROBED, common->wcmThreshold, common->wcmMaxZ / 3);
+ common->wcmThreshold = common->wcmMaxZ / 3;
+ }
+ DBG(2, ErrorF("New threshold=%d\n", common->wcmThreshold));
+
+ /* Set the real values */
+ InitValuatorAxisStruct(pWcm,
+ 0,
+ 0, /* min val */
+ priv->bottomX - priv->topX, /* max val */
+ mils(common->wcmResolX), /* resolution */
+ 0, /* min_res */
+ mils(common->wcmResolX)); /* max_res */
+ InitValuatorAxisStruct(pWcm,
+ 1,
+ 0, /* min val */
+ priv->bottomY - priv->topY, /* max val */
+ mils(common->wcmResolY), /* resolution */
+ 0, /* min_res */
+ mils(common->wcmResolY)); /* max_res */
+ InitValuatorAxisStruct(pWcm,
+ 2,
+ 0, /* min val */
+ common->wcmMaxZ, /* max val */
+ mils(common->wcmResolZ), /* resolution */
+ 0, /* min_res */
+ mils(common->wcmResolZ)); /* max_res */
+ InitValuatorAxisStruct(pWcm,
+ 3,
+ -64, /* min val */
+ 63, /* max val */
+ 128, /* resolution ??? */
+ 0,
+ 128);
+ InitValuatorAxisStruct(pWcm,
+ 4,
+ -64, /* min val */
+ 63, /* max val */
+ 128, /* resolution ??? */
+ 0,
+ 128);
+ InitValuatorAxisStruct(pWcm,
+ 5,
+ 0, /* min val */
+ 1023, /* max val */
+ 128, /* resolution ??? */
+ 0,
+ 128);
+
+ return (local->fd != -1);
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmClose --
+ *
+ ***************************************************************************
+ */
+static void
+xf86WcmClose(LocalDevicePtr local)
+{
+ WacomDevicePtr priv = (WacomDevicePtr)local->private;
+ WacomCommonPtr common = priv->common;
+ int loop;
+ int num = 0;
+
+ for(loop=0; loop<common->wcmNumDevices; loop++) {
+ if (common->wcmDevices[loop]->fd >= 0) {
+ num++;
+ }
+ }
+ DBG(4, ErrorF("Wacom number of open devices = %d\n", num));
+
+ if (num == 1) {
+ SYSCALL(close(local->fd));
+ }
+
+ local->fd = -1;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmProc --
+ * Handle the initialization, etc. of a wacom
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmProc(DeviceIntPtr pWcm,
+ int what)
+{
+ CARD8 map[(32 << 4) + 1];
+ int nbaxes;
+ int nbbuttons;
+ int loop;
+ LocalDevicePtr local = (LocalDevicePtr)pWcm->public.devicePrivate;
+ WacomDevicePtr priv = (WacomDevicePtr)PRIVATE(pWcm);
+
+ DBG(2, ErrorF("BEGIN xf86WcmProc dev=0x%x priv=0x%x type=%s flags=%d what=%d\n",
+ pWcm, priv, (DEVICE_ID(priv->flags) == STYLUS_ID) ? "stylus" :
+ (DEVICE_ID(priv->flags) == CURSOR_ID) ? "cursor" : "eraser",
+ priv->flags, what));
+
+ switch (what)
+ {
+ case DEVICE_INIT:
+ DBG(1, ErrorF("xf86WcmProc pWcm=0x%x what=INIT\n", pWcm));
+
+ nbaxes = 6; /* X, Y, Pressure, Tilt-X, Tilt-Y, Wheel */
+
+ switch(DEVICE_ID(priv->flags)) {
+ case ERASER_ID:
+ nbbuttons = 1;
+ break;
+ case STYLUS_ID:
+ nbbuttons = 4;
+ break;
+ default:
+ nbbuttons = 16;
+ break;
+ }
+
+ for(loop=1; loop<=nbbuttons; loop++) map[loop] = loop;
+
+ if (InitButtonClassDeviceStruct(pWcm,
+ nbbuttons,
+ map) == FALSE) {
+ ErrorF("unable to allocate Button class device\n");
+ return !Success;
+ }
+
+ if (InitFocusClassDeviceStruct(pWcm) == FALSE) {
+ ErrorF("unable to init Focus class device\n");
+ return !Success;
+ }
+
+ if (InitPtrFeedbackClassDeviceStruct(pWcm,
+ xf86WcmControlProc) == FALSE) {
+ ErrorF("unable to init ptr feedback\n");
+ return !Success;
+ }
+
+ if (InitProximityClassDeviceStruct(pWcm) == FALSE) {
+ ErrorF("unable to init proximity class device\n");
+ return !Success;
+ }
+
+ if (InitKeyClassDeviceStruct(pWcm, &wacom_keysyms, NULL) == FALSE) {
+ ErrorF("unable to init key class device\n");
+ return !Success;
+ }
+
+ if (InitValuatorClassDeviceStruct(pWcm,
+ nbaxes,
+ xf86GetMotionEvents,
+ local->history_size,
+ ((priv->flags & ABSOLUTE_FLAG)
+ ? Absolute : Relative) |
+ OutOfProximity)
+ == FALSE) {
+ ErrorF("unable to allocate Valuator class device\n");
+ return !Success;
+ }
+ else {
+ /* allocate the motion history buffer if needed */
+ xf86MotionHistoryAllocate(local);
+#ifndef XFREE86_V4
+ AssignTypeAndName(pWcm, local->atom, local->name);
+#endif
+ }
+
+ /* open the device to gather informations */
+ xf86WcmOpenDevice(pWcm);
+
+ break;
+
+ case DEVICE_ON:
+ DBG(1, ErrorF("xf86WcmProc pWcm=0x%x what=ON\n", pWcm));
+
+ if ((local->fd < 0) && (!xf86WcmOpenDevice(pWcm))) {
+ return !Success;
+ }
+#ifdef XFREE86_V4
+ xf86AddEnabledDevice(local);
+#else
+ AddEnabledDevice(local->fd);
+#endif
+ pWcm->public.on = TRUE;
+ break;
+
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ DBG(1, ErrorF("xf86WcmProc pWcm=0x%x what=%s\n", pWcm,
+ (what == DEVICE_CLOSE) ? "CLOSE" : "OFF"));
+ if (local->fd >= 0) {
+#ifdef XFREE86_V4
+ xf86RemoveEnabledDevice(local);
+#else
+ RemoveEnabledDevice(local->fd);
+#endif
+ xf86WcmClose(local);
+ }
+ pWcm->public.on = FALSE;
+ break;
+
+ default:
+ ErrorF("wacom unsupported mode=%d\n", what);
+ return !Success;
+ break;
+ }
+ DBG(2, ErrorF("END xf86WcmProc Success what=%d dev=0x%x priv=0x%x\n",
+ what, pWcm, priv));
+ return Success;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmChangeControl --
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmChangeControl(LocalDevicePtr local,
+ xDeviceCtl *control)
+{
+ xDeviceResolutionCtl *res;
+ int *resolutions;
+ char str[10];
+
+ res = (xDeviceResolutionCtl *)control;
+
+ if ((control->control != DEVICE_RESOLUTION) ||
+ (res->num_valuators < 1))
+ return (BadMatch);
+
+ resolutions = (int *)(res +1);
+
+ DBG(3, ErrorF("xf86WcmChangeControl changing to %d (suppressing under)\n",
+ resolutions[0]));
+
+ sprintf(str, "SU%d\r", resolutions[0]);
+ SYSCALL(write(local->fd, str, strlen(str)));
+
+ return(Success);
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmSwitchMode --
+ *
+ ***************************************************************************
+ */
+static int
+xf86WcmSwitchMode(ClientPtr client,
+ DeviceIntPtr dev,
+ int mode)
+{
+ LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate;
+ WacomDevicePtr priv = (WacomDevicePtr)local->private;
+
+ DBG(3, ErrorF("xf86WcmSwitchMode dev=0x%x mode=%d\n", dev, mode));
+
+ if (mode == Absolute) {
+ priv->flags = priv->flags | ABSOLUTE_FLAG;
+ }
+ else {
+ if (mode == Relative) {
+ priv->flags = priv->flags & ~ABSOLUTE_FLAG;
+ }
+ else {
+ DBG(1, ErrorF("xf86WcmSwitchMode dev=0x%x invalid mode=%d\n", dev,
+ mode));
+ return BadMatch;
+ }
+ }
+ return Success;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmAllocate --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+xf86WcmAllocate(char * name,
+ int flag)
+{
+ LocalDevicePtr local;
+ WacomDevicePtr priv;
+ WacomCommonPtr common;
+
+ priv = (WacomDevicePtr) xalloc(sizeof(WacomDeviceRec));
+ if (!priv)
+ return NULL;
+
+ common = (WacomCommonPtr) xalloc(sizeof(WacomCommonRec));
+ if (!common) {
+ xfree(priv);
+ return NULL;
+ }
+
+#ifdef XFREE86_V4
+ local = xf86AllocateInput(wcmDrv, 0);
+#else
+ local = (LocalDevicePtr) xalloc(sizeof(LocalDeviceRec));
+#endif
+ if (!local) {
+ xfree(priv);
+ xfree(common);
+ return NULL;
+ }
+
+ local->name = name;
+ local->flags = 0;
+#ifndef XFREE86_V4
+ local->device_config = xf86WcmConfig;
+#endif
+ local->device_control = xf86WcmProc;
+ local->read_input = xf86WcmReadInput;
+ local->control_proc = xf86WcmChangeControl;
+ local->close_proc = xf86WcmClose;
+ local->switch_mode = xf86WcmSwitchMode;
+ local->conversion_proc = xf86WcmConvert;
+ local->reverse_conversion_proc = xf86WcmReverseConvert;
+ local->fd = -1;
+ local->atom = 0;
+ local->dev = NULL;
+ local->private = priv;
+ local->private_flags = 0;
+ local->history_size = 0;
+ local->old_x = -1;
+ local->old_y = -1;
+
+ priv->flags = flag; /* various flags (device type, absolute, first touch...) */
+ priv->oldX = -1; /* previous X position */
+ priv->oldY = -1; /* previous Y position */
+ priv->oldZ = -1; /* previous pressure */
+ priv->oldTiltX = -1; /* previous tilt in x direction */
+ priv->oldTiltY = -1; /* previous tilt in y direction */
+ priv->oldButtons = 0; /* previous buttons state */
+ priv->oldProximity = 1; /* previous proximity */
+ priv->oldWheel = 0; /* previous wheel */
+ priv->topX = 0; /* X top */
+ priv->topY = 0; /* Y top */
+ priv->bottomX = 0; /* X bottom */
+ priv->bottomY = 0; /* Y bottom */
+ priv->factorX = 0.0; /* X factor */
+ priv->factorY = 0.0; /* Y factor */
+ priv->common = common; /* common info pointer */
+ priv->oldProximity = 0; /* previous proximity */
+ priv->serial = 0; /* serial number */
+ priv->initNumber = 0; /* magic number for the init phasis */
+ priv->screen_no = -1; /* associated screen */
+
+ /* JEJ - throttle sampling code */
+ priv->throttleValue = 0;
+ priv->throttleStart = 0;
+ priv->throttleLimit = -1;
+
+ common->wcmDevice = ""; /* device file name */
+ common->wcmSuppress = -1; /* transmit position if increment is superior */
+ common->wcmFlags = 0; /* various flags */
+ common->wcmDevices = (LocalDevicePtr*) xalloc(sizeof(LocalDevicePtr));
+ common->wcmDevices[0] = local;
+ common->wcmNumDevices = 1; /* number of devices */
+ common->wcmIndex = 0; /* number of bytes read */
+ common->wcmPktLength = 7; /* length of a packet */
+ common->wcmMaxX = 0; /* max X value */
+ common->wcmMaxY = 0; /* max Y value */
+ common->wcmMaxZ = DEFAULT_MAXZ; /* max Z value */
+ common->wcmResolX = 0; /* X resolution in points/inch */
+ common->wcmResolY = 0; /* Y resolution in points/inch */
+ common->wcmResolZ = 1270; /* Z resolution in points/inch */
+ common->wcmHasEraser = (flag & ERASER_ID) ? TRUE : FALSE; /* True if an eraser has been configured */
+ common->wcmStylusSide = TRUE; /* eraser or stylus ? */
+ common->wcmStylusProximity = FALSE; /* a stylus is in proximity ? */
+ common->wcmProtocolLevel = 4; /* protocol level */
+ common->wcmThreshold = INVALID_THRESHOLD; /* button 1 threshold for some tablet models */
+ common->wcmInitNumber = 0; /* magic number for the init phasis */
+ common->wcmLinkSpeed = 9600; /* serial link speed */
+ common->wcmOpen = xf86WcmOpen; /* function used to open the line (serial or USB) */
+ common->wcmLastSerial = 0; /* last device (used by the USB part) */
+ common->wcmLastTool = -1; /* last tool (used by the USB part) */
+ return local;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmAllocateStylus --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+xf86WcmAllocateStylus()
+{
+ LocalDevicePtr local = xf86WcmAllocate(XI_STYLUS, STYLUS_ID);
+
+ if (local)
+ local->type_name = "Wacom Stylus";
+ return local;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmAllocateCursor --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+xf86WcmAllocateCursor()
+{
+ LocalDevicePtr local = xf86WcmAllocate(XI_CURSOR, CURSOR_ID);
+
+ if (local)
+ local->type_name = "Wacom Cursor";
+ return local;
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86WcmAllocateEraser --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+xf86WcmAllocateEraser()
+{
+ LocalDevicePtr local = xf86WcmAllocate(XI_ERASER, ABSOLUTE_FLAG|ERASER_ID);
+
+ if (local)
+ local->type_name = "Wacom Eraser";
+ return local;
+}
+
+/*
+ ***************************************************************************
+ *
+ * Wacom Stylus device association --
+ *
+ ***************************************************************************
+ */
+DeviceAssocRec wacom_stylus_assoc =
+{
+ STYLUS_SECTION_NAME, /* config_section_name */
+ xf86WcmAllocateStylus /* device_allocate */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Wacom Cursor device association --
+ *
+ ***************************************************************************
+ */
+DeviceAssocRec wacom_cursor_assoc =
+{
+ CURSOR_SECTION_NAME, /* config_section_name */
+ xf86WcmAllocateCursor /* device_allocate */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Wacom Eraser device association --
+ *
+ ***************************************************************************
+ */
+DeviceAssocRec wacom_eraser_assoc =
+{
+ ERASER_SECTION_NAME, /* config_section_name */
+ xf86WcmAllocateEraser /* device_allocate */
+};
+
+#ifndef XFREE86_V4
+#ifdef DYNAMIC_MODULE
+/*
+ ***************************************************************************
+ *
+ * entry point of dynamic loading
+ *
+ ***************************************************************************
+ */
+int
+#ifndef DLSYM_BUG
+init_module(unsigned long server_version)
+#else
+init_xf86Wacom(unsigned long server_version)
+#endif
+{
+ xf86AddDeviceAssoc(&wacom_stylus_assoc);
+ xf86AddDeviceAssoc(&wacom_cursor_assoc);
+ xf86AddDeviceAssoc(&wacom_eraser_assoc);
+
+ if (server_version != XF86_VERSION_CURRENT) {
+ ErrorF("Warning: Wacom module compiled for version%s\n", XF86_VERSION);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+#endif /* DYNAMIC_MODULE */
+
+#else /* XFREE86_V4 */
+
+#include "wcm-beta.h"
+
+/*
+ * xf86WcmUninit --
+ *
+ * called when the device is no longer needed.
+ */
+static void
+xf86WcmUninit(InputDriverPtr drv,
+ LocalDevicePtr local,
+ int flags)
+{
+ WacomDevicePtr priv;
+
+ priv = (WacomDevicePtr) local->private;
+
+ DBG(1, ErrorF("xf86WcmUninit\n"));
+
+ if (priv->flags & BETA_FLAG)
+ {
+ wcmBetaDeleteDevice(drv,local,flags);
+ return;
+ }
+
+ xf86WcmProc(local->dev, DEVICE_OFF);
+
+ xfree (priv);
+ xf86DeleteInput(local, 0);
+}
+
+/*
+ * xf86WcmInit --
+ *
+ * called when the module subsection is found in XF86Config
+ */
+static InputInfoPtr
+xf86WcmInit(InputDriverPtr drv,
+ IDevPtr dev,
+ int flags)
+{
+ LocalDevicePtr local = NULL;
+ LocalDevicePtr fakeLocal = NULL;
+ WacomDevicePtr priv = NULL;
+ WacomCommonPtr common = NULL;
+ char *s;
+ LocalDevicePtr localDevices;
+
+ wcmDrv = drv;
+
+ fakeLocal = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec));
+ if (!fakeLocal)
+ return NULL;
+
+ fakeLocal->conf_idev = dev;
+
+ /* Force default serial port options to exist because the serial init
+ * phasis is based on those values.
+ */
+ xf86CollectInputOptions(fakeLocal, default_options, NULL);
+
+ /* Type is mandatory */
+ s = xf86FindOptionValue(fakeLocal->options, "Type");
+
+ /* Beta code jumps out here */
+ if (s && (xf86NameCmp(s, "beta") == 0))
+ {
+ xfree(fakeLocal);
+ return wcmBetaNewDevice(drv,dev,flags);
+ }
+ else if (s && (xf86NameCmp(s, "stylus") == 0)) {
+ local = xf86WcmAllocateStylus();
+ }
+ else if (s && (xf86NameCmp(s, "cursor") == 0)) {
+ local = xf86WcmAllocateCursor();
+ }
+ else if (s && (xf86NameCmp(s, "eraser") == 0)) {
+ local = xf86WcmAllocateEraser();
+ }
+ else {
+ xf86Msg(X_ERROR, "%s: No type or invalid type specified.\n"
+ "Must be one of stylus, cursor or eraser\n",
+ dev->identifier);
+ goto SetupProc_fail;
+ }
+
+ if (!local) {
+ xfree(fakeLocal);
+ return NULL;
+ }
+
+ priv = (WacomDevicePtr) local->private;
+ common = priv->common;
+
+ local->options = fakeLocal->options;
+ local->conf_idev = fakeLocal->conf_idev;
+ local->name = dev->identifier;
+ xfree(fakeLocal);
+
+ /* Serial Device is mandatory */
+ common->wcmDevice = xf86FindOptionValue(local->options, "Device");
+
+ if (!common->wcmDevice) {
+ xf86Msg (X_ERROR, "%s: No Device specified.\n", dev->identifier);
+ goto SetupProc_fail;
+ }
+
+ /* Lookup to see if there is another wacom device sharing
+ * the same serial line.
+ */
+ localDevices = xf86FirstLocalDevice();
+
+ while(localDevices) {
+ if ((local != localDevices) &&
+ (localDevices->device_control == xf86WcmProc) &&
+ (strcmp(((WacomDevicePtr)localDevices->private)->common->wcmDevice,
+ common->wcmDevice) == 0)) {
+ DBG(2, ErrorF("xf86WcmConfig wacom port share between"
+ " %s and %s\n",
+ local->name, localDevices->name));
+ ((WacomDevicePtr) localDevices->private)->common->wcmHasEraser |= common->wcmHasEraser;
+ xfree(common->wcmDevices);
+ xfree(common);
+ common = priv->common = ((WacomDevicePtr) localDevices->private)->common;
+ common->wcmNumDevices++;
+ common->wcmDevices = (LocalDevicePtr *) xrealloc(common->wcmDevices,
+ sizeof(LocalDevicePtr) * common->wcmNumDevices);
+ common->wcmDevices[common->wcmNumDevices - 1] = local;
+ break;
+ }
+ localDevices = localDevices->next;
+ }
+
+ /* Process the common options. */
+ xf86ProcessCommonOptions(local, local->options);
+
+ /* Optional configuration */
+
+ xf86Msg(X_CONFIG, "%s serial device is %s\n", dev->identifier,
+ common->wcmDevice);
+
+ debug_level = xf86SetIntOption(local->options, "DebugLevel", debug_level);
+ if (debug_level > 0) {
+ xf86Msg(X_CONFIG, "WACOM: debug level set to %d\n", debug_level);
+ }
+
+ s = xf86FindOptionValue(local->options, "Mode");
+
+ if (s && (xf86NameCmp(s, "absolute") == 0)) {
+ priv->flags = priv->flags | ABSOLUTE_FLAG;
+ }
+ else if (s && (xf86NameCmp(s, "relative") == 0)) {
+ priv->flags = priv->flags & ~ABSOLUTE_FLAG;
+ }
+ else if (s) {
+ xf86Msg(X_ERROR, "%s: invalid Mode (should be absolute or relative). Using default.\n",
+ dev->identifier);
+ }
+ xf86Msg(X_CONFIG, "%s is in %s mode\n", local->name,
+ (priv->flags & ABSOLUTE_FLAG) ? "absolute" : "relative");
+
+ common->wcmSuppress = xf86SetIntOption(local->options, "Suppress", common->wcmSuppress);
+ if (common->wcmSuppress != -1) {
+ xf86Msg(X_CONFIG, "WACOM: suppress value is %d\n", XCONFIG_GIVEN,
+ common->wcmSuppress);
+ }
+
+ if (xf86SetBoolOption(local->options, "Tilt", (common->wcmFlags & TILT_FLAG))) {
+ common->wcmFlags |= TILT_FLAG;
+ }
+
+#ifdef LINUX_INPUT
+ if (xf86SetBoolOption(local->options, "USB", (common->wcmOpen == xf86WcmUSBOpen))) {
+ local->read_input=xf86WcmReadUSBInput;
+ common->wcmOpen=xf86WcmUSBOpen;
+ xf86Msg(X_CONFIG, "%s: reading USB link\n", dev->identifier);
+ }
+#else
+ if (xf86SetBoolOption(local->options, "USB", 0)) {
+ ErrorF("The USB version of the driver isn't available for your platform\n");
+ }
+#endif
+
+ priv->screen_no = xf86SetIntOption(local->options, "ScreenNo", -1);
+ if (priv->screen_no != -1) {
+ xf86Msg(X_CONFIG, "%s: attached screen number %d\n", dev->identifier,
+ priv->screen_no);
+ }
+
+ if (xf86SetBoolOption(local->options, "KeepShape", 0)) {
+ priv->flags |= KEEP_SHAPE_FLAG;
+ xf86Msg(X_CONFIG, "%s: keeps shape\n", dev->identifier);
+ }
+
+ priv->topX = xf86SetIntOption(local->options, "TopX", 0);
+ if (priv->topX != 0) {
+ xf86Msg(X_CONFIG, "%s: top x = %d\n", dev->identifier, priv->topX);
+ }
+ priv->topY = xf86SetIntOption(local->options, "TopY", 0);
+ if (priv->topY != 0) {
+ xf86Msg(X_CONFIG, "%s: top x = %d\n", dev->identifier, priv->topY);
+ }
+ priv->bottomX = xf86SetIntOption(local->options, "BottomX", 0);
+ if (priv->bottomX != 0) {
+ xf86Msg(X_CONFIG, "%s: bottom x = %d\n", dev->identifier,
+ priv->bottomX);
+ }
+ priv->bottomY = xf86SetIntOption(local->options, "BottomY", 0);
+ if (priv->bottomY != 0) {
+ xf86Msg(X_CONFIG, "%s: bottom x = %d\n", dev->identifier,
+ priv->bottomY);
+ }
+ priv->serial = xf86SetIntOption(local->options, "Serial", 0);
+ if (priv->bottomY != 0) {
+ xf86Msg(X_CONFIG, "%s: serial number = %u\n", dev->identifier,
+ priv->serial);
+ }
+ common->wcmThreshold = xf86SetIntOption(local->options, "Threshold", common->wcmThreshold);
+ if (common->wcmThreshold != INVALID_THRESHOLD) {
+ xf86Msg(X_CONFIG, "%s: threshold = %d\n", dev->identifier,
+ common->wcmThreshold);
+ }
+ common->wcmMaxX = xf86SetIntOption(local->options, "MaxX", common->wcmMaxX);
+ if (common->wcmMaxX != 0) {
+ xf86Msg(X_CONFIG, "%s: max x = %d\n", dev->identifier,
+ common->wcmMaxX);
+ }
+ common->wcmMaxY = xf86SetIntOption(local->options, "MaxY", common->wcmMaxY);
+ if (common->wcmMaxY != 0) {
+ xf86Msg(X_CONFIG, "%s: max x = %d\n", dev->identifier,
+ common->wcmMaxY);
+ }
+ common->wcmMaxZ = xf86SetIntOption(local->options, "MaxZ", common->wcmMaxZ);
+ if (common->wcmMaxZ != DEFAULT_MAXZ) {
+ xf86Msg(X_CONFIG, "%s: max x = %d\n", dev->identifier,
+ common->wcmMaxZ);
+ }
+ common->wcmResolX = xf86SetIntOption(local->options, "ResolutionX", common->wcmResolX);
+ if (common->wcmResolX != 0) {
+ xf86Msg(X_CONFIG, "%s: resol x = %d\n", dev->identifier,
+ common->wcmResolX);
+ }
+ common->wcmResolY = xf86SetIntOption(local->options, "ResolutionY", common->wcmResolY);
+ if (common->wcmResolY != 0) {
+ xf86Msg(X_CONFIG, "%s: resol x = %d\n", dev->identifier,
+ common->wcmResolY);
+ }
+ common->wcmResolZ = xf86SetIntOption(local->options, "ResolutionZ", common->wcmResolZ);
+ if (common->wcmResolZ != 0) {
+ xf86Msg(X_CONFIG, "%s: resol x = %d\n", dev->identifier,
+ common->wcmResolZ);
+ }
+
+ {
+ int val;
+ val = xf86SetIntOption(local->options, "BaudRate", 0);
+
+ switch(val) {
+ case 38400:
+ common->wcmLinkSpeed = 38400;
+ break;
+ case 19200:
+ common->wcmLinkSpeed = 19200;
+ break;
+ case 9600:
+ common->wcmLinkSpeed = 9600;
+ break;
+ default:
+ xf86Msg(X_ERROR, "%s: Illegal speed value (must be 9600 or 19200 or 38400).", dev->identifier);
+ break;
+ }
+ if (xf86Verbose)
+ xf86Msg(X_CONFIG, "%s: serial speed %u\n", dev->identifier,
+ val);
+ }
+ /* mark the device configured */
+ local->flags |= XI86_POINTER_CAPABLE | XI86_CONFIGURED;
+
+ /* return the LocalDevice */
+ return (local);
+
+ SetupProc_fail:
+ if (common)
+ xfree(common);
+ if (priv)
+ xfree(priv);
+ if (local)
+ xfree(local);
+ return NULL;
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec WACOM = {
+ 1, /* driver version */
+ "wacom", /* driver name */
+ NULL, /* identify */
+ xf86WcmInit, /* pre-init */
+ xf86WcmUninit, /* un-init */
+ NULL, /* module */
+ 0 /* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+/*
+ * xf86WcmUnplug --
+ *
+ * called when the module subsection is found in XF86Config
+ */
+static void
+xf86WcmUnplug(pointer p)
+{
+ DBG(1, ErrorF("xf86WcmUnplug\n"));
+}
+
+/*
+ * xf86WcmPlug --
+ *
+ * called when the module subsection is found in XF86Config
+ */
+static pointer
+xf86WcmPlug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ xf86Msg(X_INFO, "Wacom driver level: %s\n", identification+strlen("$Identification: "));
+
+ xf86AddInputDriver(&WACOM, module, 0);
+
+ return module;
+}
+
+static XF86ModuleVersionInfo xf86WcmVersionRec =
+{
+ "wacom",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0} /* signature, to be patched into the file by */
+ /* a tool */
+};
+
+XF86ModuleData wacomModuleData = {&xf86WcmVersionRec,
+ xf86WcmPlug,
+ xf86WcmUnplug};
+
+#endif /* XFree86LOADER */
+#endif /* XFREE86_V4 */
+
+/*
+ * Local variables:
+ * change-log-default-name: "~/xinput.log"
+ * c-file-style: "bsd"
+ * End:
+ */
+/* end of xf86Wacom.c */