On 20 Nov, the Loial Raven wrote:

> I am using XFree86-4.0.1 and have noticed that my tablet is not
> working properly...
 
> Pressure sensitivity is the problem... it seems like gimp is either
> getting a pressure of 0%, 100%, or some value higher that causes
> feedback when using some paint tools. I was thinking it was a problem
> with Xfree, but when i used the xinputev, i found it was giving proper
> values...

 There's a bug in the XInput driver for the USB version (thus I assume
 you're using this one) which maps the pressure to a range between
 0.25 and 1.25 instead of 0 to 1.00. 

 I'll attach you a fixed version. I still have to make some changes and
 remove some crufty code, but this one should work. If you need the 
 module itself feel free to get back to me and request it for i386 and/or
 PPC.

-- 

Servus,
       Daniel
/*
 * Copyright 1995-1999 by Frederic Lepied, France. <[EMAIL PROTECTED]>
 * Copyright 2000 by Daniel Egger, Germany. <[EMAIL PROTECTED]>
 *
 * Modified for Linux USB by MATSUMURA Namihiko.
 * FrņÅņĶic Lepied <[EMAIL PROTECTED]>.
 * Additional changes by Brion Vibber <[EMAIL PROTECTED]>
 * and Aaron Optimizer Digulla <[EMAIL PROTECTED]> 
 *                                                                            
 * 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.
 *
 */

#include <xf86Version.h>

#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>
#include <keysym.h>
#include <mipointer.h>

#ifdef XFree86LOADER
#include <xf86Module.h>
#endif

#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)

static const char *default_options[] =
{
        NULL
};

static InputDriverPtr wcmDrv;

#ifdef size_t
#undef size_t
#endif

#include <asm/types.h>
#include "linux/input.h"
#ifndef O_NDELAY
#ifndef O_NONBLOCK
#define O_NONBLOCK      04000
#endif
#define O_NDELAY        O_NONBLOCK
#endif

#define INI_DEBUG_LEVEL 5
#ifndef INI_DEBUG_LEVEL
#define INI_DEBUG_LEVEL 0
#endif
static int      debug_level = INI_DEBUG_LEVEL;
#define DEBUG 1
#if DEBUG
#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
#else
#define DBG(lvl, f)
#endif

/******************************************************************************
 * WacomDeviceRec flags
 *****************************************************************************/
#define DEVICE_ID(flags) ((flags) & 0x07)

#define STYLUS_ID               (1<<0)
#define CURSOR_ID               (1<<1)
#define ERASER_ID               (1<<2)
#define ABSOLUTE_FLAG           (1<<3)
#define FIRST_TOUCH_FLAG        (1<<4)
#define KEEP_SHAPE_FLAG         (1<<5)

/******************************************************************************
 * 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                   tilt_x;
  int                   tilt_y;
  int                   rotation;
  int                   wheel;
  int                   discard_first;
  int                   proximity;
  WacomFilterState      x_filter;
  WacomFilterState      y_filter;
} WacomDeviceState;

#define PEN(ds)         (((ds->device_id) & 0x07ff) == 0x0022)
#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
{
  unsigned char flags;  /* various flags (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 */

  struct _WacomCommonRec *common;       /* common info pointer */
  
  int oldX;             /* previous X position */
  int oldY;             /* previous Y position */
  int oldPressure;              /* 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 */

} WacomDeviceRec, *WacomDevicePtr;

typedef struct _WacomCommonRec 
{
  char *wcmDevice;      /* device file name */
  int wcmDeviceType;    /* STYLUS/CURSOR/ERASE_ID */
  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 wcmMaxPressure;   /* max pressure */
  int wcmResolX;        /* X resolution in points/inch */
  int wcmResolY;        /* Y resolution in points/inch */
  int wcmResolPressure; /* FIXME: Making sense? */
  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 */
} WacomCommonRec, *WacomCommonPtr;

/******************************************************************************
 * configuration stuff
 *****************************************************************************/
#define CURSOR_SECTION_NAME "wacomcursor"
#define STYLUS_SECTION_NAME "wacomstylus"
#define ERASER_SECTION_NAME "wacomeraser"

/******************************************************************************
 * constant and macros declarations
 *****************************************************************************/
#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))

/* defines to discriminate second side button and the eraser */
#define ERASER_PROX     4
#define OTHER_PROX      1

#define HANDLE_TILT(comm) ((comm)->wcmPktLength == 9)
/* Strange GCC syntax: Evaluate 'v' only once */
#define ABS(v)      ({ int _v = (v); _v < 0 ? -_v : _v; })

#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
};

#if NeedFunctionPrototypes
static LocalDevicePtr xf86WcmAllocateStylus(void);
static LocalDevicePtr xf86WcmAllocateCursor(void);
static LocalDevicePtr xf86WcmAllocateEraser(void);
#endif

/*
 ***************************************************************************
 *
 * 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;

    priv->factorX = ((double) miPointerCurrentScreen()->width)
        / (priv->bottomX - priv->topX);
    priv->factorY = ((double) miPointerCurrentScreen()->height)
        / (priv->bottomY - priv->topY);
    
    *x = v0 * priv->factorX;
    *y = v1 * priv->factorY;

    DBG(6, ErrorF("Wacom converted v0=%d v1=%d to x=%d y=%d\n",
                  v0, v1, *x, *y));

    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;

    priv->factorX = ((double) miPointerCurrentScreen()->width)
        / (priv->bottomX - priv->topX);
    priv->factorY = ((double) miPointerCurrentScreen()->height)
        / (priv->bottomY - priv->topY);
    
    valuators[0] = x / priv->factorX;
    valuators[1] = y / priv->factorY;

    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                  rpressure,
                   int                  rtilt_x,
                   int                  rtilt_y,
                   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)) {
            xf86PostButtonEvent(local->dev, 
                                (priv->flags & ABSOLUTE_FLAG),
                                button, (buttons & mask) != 0,
                                0, 6, rx, ry, rpressure, rtilt_x, rtilt_y, 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                   pressure,
                  int                   buttons,
                  int                   tilt_x,
                  int                   tilt_y,
                  int                   wheel)
{
    WacomDevicePtr      priv = (WacomDevicePtr) local->private;
    WacomCommonPtr      common = priv->common;
    int                 rx, ry, rpressure, rtilt_x, rtilt_y, rwheel;
    int                 is_core_pointer, is_absolute;

    if ((DEVICE_ID(priv->flags) != type) ||
        ((common->wcmProtocolLevel == 5) &&
         priv->serial && (serial != priv->serial))) {
        return;
    }
    
    /* 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;
    }

    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);

    /* 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(pressure - priv->oldPressure) < 3) &&
        (ABS(tilt_x - priv->oldTiltX) < 3) &&
        (ABS(tilt_y - priv->oldTiltY) < 3)) {
        return;
    }
                
    /* sets rx and ry according to the mode */
    if (is_absolute) {
        rx = x;
        ry = y;
        rpressure = pressure;
        rtilt_x = tilt_x;
        rtilt_y = tilt_y;
        rwheel = wheel;
    } else {
        rx = x - priv->oldX;
        ry = y - priv->oldY;
        /* rpressure = pressure - priv->oldPressure;  FIXME: Makes sense?
        rtilt_x = tilt_x - priv->oldTiltX;
        rtilt_y = tilt_y - priv->oldTiltY; 
        rwheel = wheel - priv->oldWheel; */
        rpressure = pressure;
        rtilt_x = tilt_x;
        rtilt_y = tilt_y;
        rwheel = wheel;
    }

    /* coordinates are ready we can send events */
    if (is_proximity) {
        if (!priv->oldProximity) {
            xf86PostProximityEvent(local->dev, 1, 0, 6, rx, ry, pressure, tilt_x, 
tilt_y, rwheel);

            priv->flags |= FIRST_TOUCH_FLAG;
                    
            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;
                }
            }
        }
        
        /* 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->oldPressure != pressure) ||
            (is_stylus && HANDLE_TILT(common) &&
             (tilt_x != priv->oldTiltX || tilt_y != priv->oldTiltY))) {
            if (!is_absolute && (priv->flags & FIRST_TOUCH_FLAG)) {
                priv->flags -= FIRST_TOUCH_FLAG;
            } else {
                xf86PostMotionEvent(local->dev, is_absolute, 0, 6, rx, ry, rpressure,
                                    rtilt_x, rtilt_y, rwheel); 
            }
        }

        if (priv->oldButtons != buttons) {
            xf86WcmSendButtons (local, buttons, rx, ry, rpressure, rtilt_x, rtilt_y, 
rwheel);
        }

        /* Simulate buttons 4 and 5 for Graphire wheel */
        if ((common->wcmProtocolLevel == 4) &&
            !is_stylus &&
            (common->wcmFlags & GRAPHIRE_FLAG) &&
            (wheel != 0)) {
            int fake_button = (wheel > 0) ? 5 : 4;

            xf86PostButtonEvent(local->dev,
                                (priv->flags & ABSOLUTE_FLAG),
                                fake_button, 1,
                                0, 6, rx, ry, rpressure, rtilt_x, rtilt_y, rwheel);
            
            xf86PostButtonEvent(local->dev,
                                (priv->flags & ABSOLUTE_FLAG),
                                fake_button, 0,
                                0, 6, rx, ry, rpressure, rtilt_x, rtilt_y, rwheel);
        }
        
        priv->oldButtons = buttons;
        priv->oldX = x;
        priv->oldY = y;
        priv->oldPressure = pressure;
        priv->oldTiltX = tilt_x;
        priv->oldTiltY = tilt_y;
        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, rpressure, rtilt_x, rtilt_y, rwheel);
            priv->oldButtons = 0;
        }
        if (!is_core_pointer) {
            /* macro button management */
            if (common->wcmProtocolLevel == 4 && buttons) {
                int     macro = pressure / 2;

                /* First available Keycode begins at 8 => macro+7 */
                xf86PostKeyEvent(local->dev, macro+7, 1,
                                 is_absolute, 0, 6,
                                 0, 0, buttons, rtilt_x, rtilt_y, rwheel);
                xf86PostKeyEvent(local->dev, macro+7, 0,
                                 is_absolute, 0, 6,
                                 0, 0, buttons, rtilt_x, rtilt_y, rwheel);
            }
            if (priv->oldProximity) {
                xf86PostProximityEvent(local->dev, 0, 0, 6, rx, ry, rpressure,
                                       rtilt_x, rtilt_y, 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;
}

/*
 ***************************************************************************
 *
 * xf86WcmReadInput --
 *      Read the new events from the device, and enqueue them.
 *
 ***************************************************************************
 */
/* Was completely rewritten */
static void
xf86WcmReadInput(LocalDevicePtr         local)
{
    WacomDevicePtr      priv = (WacomDevicePtr) local->private;
    WacomCommonPtr      common = priv->common;

    /* FIXME This is not very good; it would be much better to determine the
     * device and use the last values stored in there. Otherwise, we might
     * run into trouble when the device changes. */
    static int device = 0;
    static int serial = 0;
    static int is_proximity = 0;
    static int x = 0;
    static int y = 0;
    static int pressure = 0;
    static int buttons = 0;
    static int tilt_x = 0;
    static int tilt_y = 0;
    static int wheel = 0;

    ssize_t              len;
    int                  idx;
    struct input_event * event;
    char                 eventbuf[BUFFER_SIZE];
#define MOD_BUTTONS(bit, value) \
    { int _b=bit, _v=value; buttons = (((_v) != 0) ? (buttons | _b) : (buttons & ~ 
_b)); }

    SYSCALL(len = read(local->fd, eventbuf, BUFFER_SIZE));

    if (len <= 0)
    {
        ErrorF("Error reading wacom device : %s\n", strerror(errno));
        return;
    }
    
    for (event=(struct input_event *)eventbuf;
         event<(struct input_event *)(eventbuf+len); event++)
    {
        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:
                tilt_x = event->value;
                break;

            case ABS_TILT_Y:
                tilt_y = event->value;
                break;

            case ABS_PRESSURE:
                pressure = event->value;
                break;

            case ABS_DISTANCE:
                /* This is not sent by the driver */
                break;
            }
            break; /* EV_ABS */

        case EV_REL:
            switch (event->code)
            {
            case REL_WHEEL:
                /* FIXME */
                break;
            }
            break; /* EV_REL */

        case EV_KEY:
            switch (event->code)
            {
            case BTN_TOOL_PEN:
                device = STYLUS_ID;
                is_proximity = (event->value != 0);
                break;

            case BTN_TOOL_RUBBER:
                device = ERASER_ID;
                is_proximity = (event->value != 0);
                break;

            case BTN_TOOL_MOUSE:
                device = CURSOR_ID;
                is_proximity = (event->value != 0);
                break;

            case BTN_TOUCH:
                MOD_BUTTONS (1, event->value);
                break;

            case BTN_STYLUS:
                MOD_BUTTONS (2, event->value);
                break;

            case BTN_STYLUS2:
                MOD_BUTTONS (4, event->value);
                break;

            case BTN_LEFT:
                MOD_BUTTONS (1, event->value);
                break;

            case BTN_RIGHT:
                MOD_BUTTONS (2, event->value);
                break;

            case BTN_MIDDLE:
                MOD_BUTTONS (4, event->value);
                break;
            }
            break; /* EV_KEY */
        } 
    } 

    for (idx=0; idx<common->wcmNumDevices; idx++)
    {
        WacomDevicePtr dev;
        int            id;
        
        dev = common->wcmDevices[idx]->private;
        id  = DEVICE_ID (dev->flags);

        /* Find the device the current events are meant for */
        if (id == device)
        {
            xf86WcmSendEvents(common->wcmDevices[idx],
                        device,
                        serial,
                        (device == STYLUS_ID || device == ERASER_ID),
                        !!(buttons),
                        is_proximity,
                        x, y, pressure, buttons,
                        tilt_x, tilt_y, wheel
                        );
        }
    }
}

/*
 ***************************************************************************
 *
 * xf86WcmControlProc --
 *
 ***************************************************************************
 */
static void
xf86WcmControlProc(DeviceIntPtr device,
                   PtrCtrl      *ctrl)
{
  DBG(2, ErrorF("xf86WcmControlProc\n"));
}

/*
 ***************************************************************************
 *
 * xf86WcmOpen --
 *
 ***************************************************************************
 */
static Bool
xf86WcmOpen(LocalDevicePtr      local)
{
    struct timeval      timeout;
    char                buffer[256];
    int                 err = 0;
    WacomDevicePtr      priv = (WacomDevicePtr)local->private;
    WacomCommonPtr      common = priv->common;
    int                 loop, idx;
    int                 is_a_penpartner = 0;
    
    SYSCALL(local->fd = open(common->wcmDevice, O_RDONLY|O_NDELAY, 0));
    if (local->fd == -1) {
        ErrorF("Error opening %s : %s\n", common->wcmDevice, strerror(errno));
        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));
  
    /* 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"));
    }
  
    {
        char    buf[20];
      
        if (common->wcmSuppress < 0) {
            common->wcmSuppress = 0;
        } else {
            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;
    }

    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;
    
    if (local->fd < 0) {
        if (common->wcmInitNumber > 2 ||
            priv->initNumber == common->wcmInitNumber) {
            if (xf86WcmOpen(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;
        }
    
        /* Calculate the ratio according to KeepShape, TopX and TopY */

        if (priv->flags & KEEP_SHAPE_FLAG) {
            screenRatio = ((double) screenInfo.screens[0]->width)
                / screenInfo.screens[0]->height;

            tabletRatio = ((double) (common->wcmMaxX - priv->topX))
                / (common->wcmMaxY - priv->topY);

            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);
    }

    if (common->wcmThreshold > ((common->wcmMaxPressure / 2) - 1) ||
        common->wcmThreshold < - (common->wcmMaxPressure / 2)) {
        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->wcmMaxPressure / 
3));
        common->wcmThreshold = - (common->wcmMaxPressure / 3);
    }

    /* 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->wcmMaxPressure, /* max val */
                           mils(common->wcmResolPressure), /* resolution */
                           0, /* min_res */
                           mils(common->wcmResolPressure)); /* 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++;
        }
    }
    
    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);
  
    switch (what)
        {
        case DEVICE_INIT: 
            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);
            }

            /* open the device to gather informations */
            xf86WcmOpenDevice(pWcm);

            break; 
      
        case DEVICE_ON:
            if ((local->fd < 0) && (!xf86WcmOpenDevice(pWcm))) {
                return !Success;
            }
            xf86AddEnabledDevice(local);
            pWcm->public.on = TRUE;
            break;
      
        case DEVICE_OFF:
            if (local->fd >= 0) {
                xf86RemoveEnabledDevice(local);
                xf86WcmClose(local);
            }
            pWcm->public.on = FALSE;
            break;
      
        case DEVICE_CLOSE:
            DBG(1, ErrorF("xf86WcmProc  pWcm=0x%x what=%s\n", pWcm,
                          (what == DEVICE_CLOSE) ? "CLOSE" : "OFF"));
            xf86WcmClose(local);
            break;

        default:
            ErrorF("unsupported mode=%d\n", what);
            return !Success;
            break;
        }
    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]));

    /* throw command in here... */
    return Success;
}

/*
 ***************************************************************************
 *
 * xf86WcmSwitchMode -- We're trying to switch mode (Relative vs. Absolute)
 * here.
 *
 ***************************************************************************
 */
static int
xf86WcmSwitchMode(ClientPtr     client,
                  DeviceIntPtr  dev,
                  int           mode)
{
  LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate;
  WacomDevicePtr priv = (WacomDevicePtr)local->private;

  switch (mode)
    {  
      case Absolute:
        priv->flags = priv->flags | ABSOLUTE_FLAG;
        break;

      case Relative:
        priv->flags = priv->flags & ~ABSOLUTE_FLAG; 
        break;

      default:    
        return BadMatch;
    }
  
  return Success;
}

/*
 ***************************************************************************
 *
 * xf86WcmAllocate --
 *
 ***************************************************************************
 */
static LocalDevicePtr
xf86WcmAllocate(char *  name,
                int     flag)
{
  LocalDevicePtr local = xf86AllocateInput(wcmDrv, 0);
  WacomDevicePtr priv = (WacomDevicePtr) xalloc(sizeof(WacomDeviceRec));
  WacomCommonPtr common = (WacomCommonPtr) xalloc(sizeof(WacomCommonRec));
#if defined(sun) && !defined(i386)
  char                  *dev_name = (char *) getenv("WACOM_DEV");  
#endif

  local->name = name;
  local->flags = 0;
  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->oldPressure = -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 = 0; /* previous proximity */
  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 */
  
  common->wcmDevice = ""; /* device file name */
  common->wcmDeviceType = DEVICE_ID(flag); /* device file name */

#if defined(sun) && !defined(i386)
  if (dev_name)
  {
      common->wcmDevice = (char*) xalloc(strlen(dev_name)+1);
      strcpy(common->wcmDevice, dev_name);
      ErrorF("xf86WcmOpen port changed to '%s'\n", common->wcmDevice);
  }
#endif
  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 */
  /* FIXME: Should get this values from the HID driver */
  common->wcmMaxX = 30480;              /* max X value */
  common->wcmMaxY = 23060;              /* max Y value */
  common->wcmMaxPressure = 1023;        /* max pressure */
  common->wcmResolX = 1270;             /* X resolution in points/inch */
  common->wcmResolY = 1270;             /* Y resolution in points/inch */
  common->wcmResolPressure = 1270;              /* pressure 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 */
  return local;
}

/*
 ***************************************************************************
 *
 * xf86WcmAllocateStylus -- initialize new Stylus
 *
 ***************************************************************************
 */
static LocalDevicePtr
xf86WcmAllocateStylus()
{
    LocalDevicePtr local = xf86WcmAllocate(XI_STYLUS, STYLUS_ID);
    local->type_name = "Wacom Stylus";
    return local;
}

/*
 ***************************************************************************
 *
 * xf86WcmAllocateCursor --
 *
 ***************************************************************************
 */
static LocalDevicePtr
xf86WcmAllocateCursor()
{
  LocalDevicePtr local = xf86WcmAllocate(XI_CURSOR, CURSOR_ID);
  local->type_name = "Wacom Cursor";
  return local;
}

/*
 ***************************************************************************
 *
 * xf86WcmAllocateEraser --
 *
 ***************************************************************************
 */
static LocalDevicePtr
xf86WcmAllocateEraser()
{
    LocalDevicePtr local = xf86WcmAllocate(XI_ERASER, ABSOLUTE_FLAG|ERASER_ID);
    local->type_name = "Wacom Eraser";
    return local;
}

/*
 * xf86WcmUninit --
 *
 * called when the driver is unloaded.
 */
static void
xf86WcmUninit(InputDriverPtr    drv,
              LocalDevicePtr    local,
              int flags)
{
  WacomDevicePtr priv = (WacomDevicePtr) local->private;
  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;
  LocalDevicePtr localDevices = NULL;
  
  WacomDevicePtr priv = NULL;
  WacomCommonPtr common = NULL;
  char *s = NULL;

  wcmDrv = drv;

  fakeLocal = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec));
  fakeLocal->conf_idev = dev;

  xf86CollectInputOptions(fakeLocal, default_options, NULL);

  s = xf86FindOptionValue(fakeLocal->options, "Type");

  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)
      priv = (WacomDevicePtr) local->private;
  if (priv)
      common = priv->common;

  if (!local || !priv || !common) {
      goto SetupProc_fail;
  }
  
  local->options = fakeLocal->options;
  local->conf_idev = fakeLocal->conf_idev;
  local->name = dev->identifier;
  xfree(fakeLocal);
  
  common->wcmDevice = xf86FindOptionValue(local->options, "Device");

  if (!common->wcmDevice) {
      xf86Msg (X_ERROR, "%s: No Device specified.\n", dev->identifier);
      goto SetupProc_fail;
  }

  localDevices = xf86FirstLocalDevice();
  
  while(localDevices) 
    {
      if ((local != localDevices) &&
          (localDevices->read_input == xf86WcmReadInput) &&
          (strcmp(((WacomDevicePtr)localDevices->private)->common->wcmDevice,
                  common->wcmDevice) == 0))
         {
           ((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 device is %s\n", dev->identifier,
          common->wcmDevice);

  debug_level = xf86SetIntOption(local->options, "DebugLevel", 0);
  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", 0);
  if (common->wcmSuppress != -1) {
      xf86Msg(X_CONFIG, "WACOM: suppress value is %d\n", XCONFIG_GIVEN,
              common->wcmSuppress);      
  }
 
   /* FIXME: Why using "or" here??? */
  
  if (xf86SetBoolOption(local->options, "Tilt", 0)) 
    {
      common->wcmFlags |= TILT_FLAG;
    }

  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) 
    {
      xf86Msg(X_CONFIG, "%s: top x = %d\n", dev->identifier, priv->topY);
    }
  
  priv->bottomX = xf86SetIntOption(local->options, "BottomX", 0);
  if (priv->bottomX)
    {
      xf86Msg(X_CONFIG, "%s: bottom x = %d\n", dev->identifier,
              priv->bottomX);
    }

  priv->bottomY = xf86SetIntOption(local->options, "BottomY", 0);
  if (priv->bottomY)
    {
      xf86Msg(X_CONFIG, "%s: bottom x = %d\n", dev->identifier,
              priv->bottomY);
    }
  
  priv->serial = xf86SetIntOption(local->options, "Serial", 0);
  if (priv->bottomY)
    {
      xf86Msg(X_CONFIG, "%s: serial number = %u\n", dev->identifier,
              priv->serial);
    }
  
  common->wcmThreshold = 
    xf86SetIntOption(local->options, "Threshold", INVALID_THRESHOLD);
  
  if (common->wcmThreshold != INVALID_THRESHOLD)
    {
      xf86Msg(X_CONFIG, "%s: threshold = %d\n", dev->identifier,
              common->wcmThreshold);
    }

  /* 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 */
    "wacomUSB",                 /* 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)
{
  return;
}

/*
 * xf86WcmPlug --
 *
 * called when the module subsection is found in XF86Config
 */
static pointer
xf86WcmPlug(pointer     module,
            pointer     options,
            int         *errmaj,
            int         *errmin)
{
  xf86AddInputDriver(&WACOM, module, 0);
  return module;
}

static XF86ModuleVersionInfo xf86WcmVersionRec =
{
  "wacomUSB",
  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 wacomUSBModuleData = {&xf86WcmVersionRec,
                                  xf86WcmPlug,
                                  xf86WcmUnplug};

#endif /* XFree86LOADER */

Reply via email to