static const char identification[] = "$Identification: 42 $";
#include <xf86Version.h>
#ifdef LINUX_INPUT
#include <asm/types.h>
#include <linux/input.h>
#ifndef EV_MSC
#define EV_MSC 0x04
#endif
#ifndef MSC_SERIAL
#define MSC_SERIAL 0x00
#endif
#define MAX_EVENTS 50
#ifdef BUS_PCI
#undef BUS_PCI
#endif
#ifdef BUS_ISA
#undef BUS_ISA
#endif
#endif
#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
#define xf86WcmWaitForTablet(fd) xf86WaitForInput((fd), 1000000)
#define xf86WcmFlushTablet(fd) xf86FlushInput((fd))
#define xf86WcmOpenTablet(local) xf86OpenSerial((local)->options)
#define xf86WcmSetSerialSpeed(fd,rate) xf86SetSerialSpeed((fd),(rate))
#define xf86WcmRead(a,b,c) xf86ReadSerial((a),(b),(c))
#define xf86WcmWrite(a,b,c) xf86WriteSerial((a),(char*)(b),(c))
#define xf86WcmClose(a) xf86CloseSerial((a))
#define XCONFIG_PROBED "(==)"
#define XCONFIG_GIVEN "(**)"
#define xf86Verbose 1
#undef PRIVATE
#define PRIVATE(x) XI_PRIVATE(x)
typedef struct _WacomModule WacomModule;
typedef struct _WacomModule4 WacomModule4;
typedef struct _WacomModule3 WacomModule3;
typedef struct _WacomModel WacomModel, *WacomModelPtr;
typedef struct _WacomDeviceRec WacomDeviceRec, *WacomDevicePtr;
typedef struct _WacomDeviceState WacomDeviceState, *WacomDeviceStatePtr;
typedef struct _WacomChannel WacomChannel, *WacomChannelPtr;
typedef struct _WacomCommonRec WacomCommonRec, *WacomCommonPtr;
typedef struct _WacomFilterState WacomFilterState, *WacomFilterStatePtr;
typedef struct _WacomDeviceClass WacomDeviceClass, *WacomDeviceClassPtr;
#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
#define RESET_RELATIVE(ds) do { (ds).relwheel = 0; } while (0)
static int xf86WcmWait(int t);
static int xf86WcmReady(int fd);
static LocalDevicePtr xf86WcmAllocate(char* name, int flag);
static LocalDevicePtr xf86WcmAllocateStylus(void);
static LocalDevicePtr xf86WcmAllocateCursor(void);
static LocalDevicePtr xf86WcmAllocateEraser(void);
static Bool xf86WcmOpen(LocalDevicePtr local);
static int xf86WcmDevOpen(DeviceIntPtr pWcm);
static int xf86WcmInitTablet(WacomCommonPtr common, WacomModelPtr model,
int fd, const char* id, float version);
static void xf86WcmDevReadInput(LocalDevicePtr local);
static void xf86WcmReadPacket(LocalDevicePtr local);
static void xf86WcmEvent(WacomCommonPtr common,
unsigned int channel, const WacomDeviceState* ds);
static int xf86WcmSerialValidate(WacomCommonPtr common, const unsigned char* data);
static Bool serialDetect(LocalDevicePtr pDev);
static Bool serialInit(LocalDevicePtr pDev);
static int serialInitTablet(WacomCommonPtr common, int fd);
static void serialInitIntuos(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialInitIntuos2(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialInitCintiq(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialInitPenPartner(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialInitGraphire(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialInitProtocol4(WacomCommonPtr common, int fd,
const char* id, float version);
static void serialGetResolution(WacomCommonPtr common, int fd);
static int serialGetRanges(WacomCommonPtr common, int fd);
static int serialResetIntuos(WacomCommonPtr common, int fd);
static int serialResetCintiq(WacomCommonPtr common, int fd);
static int serialResetPenPartner(WacomCommonPtr common, int fd);
static int serialResetProtocol4(WacomCommonPtr common, int fd);
static int serialEnableTiltProtocol4(WacomCommonPtr common, int fd);
static int serialEnableSuppressProtocol4(WacomCommonPtr common, int fd);
static int serialSetLinkSpeedIntuos(WacomCommonPtr common, int fd);
static int serialSetLinkSpeedProtocol5(WacomCommonPtr common, int fd);
static int serialStartTablet(WacomCommonPtr common, int fd);
static int serialParseCintiq(WacomCommonPtr common,
const unsigned char* data);
static int serialParseGraphire(WacomCommonPtr common,
const unsigned char* data);
static int serialParseProtocol4(WacomCommonPtr common,
const unsigned char* data);
static int serialParseProtocol5(WacomCommonPtr common,
const unsigned char* data);
static void serialParseP4Common(WacomCommonPtr common,
const unsigned char* data, WacomDeviceState* last,
WacomDeviceState* ds);
#ifdef LINUX_INPUT
static Bool usbDetect(LocalDevicePtr local);
static Bool usbInit(LocalDevicePtr local);
static void usbInitProtocol5(WacomCommonPtr common, int fd, const char* id,
float version);
static void usbInitProtocol4(WacomCommonPtr common, int fd, const char* id,
float version);
static int usbGetRanges(WacomCommonPtr common, int fd);
static int usbParse(WacomCommonPtr common, const unsigned char* data);
static void usbParseEvent(WacomCommonPtr common,
const struct input_event* event);
static void usbParseChannel(WacomCommonPtr common, int channel, int serial);
#endif
static Bool isdv4Detect(LocalDevicePtr);
static Bool isdv4Init(LocalDevicePtr);
static void isdv4InitISDV4(WacomCommonPtr common, int fd, const char* id,
float version);
static int isdv4Parse(WacomCommonPtr common, const unsigned char* data);
static int xf86WcmFilterCoord(WacomCommonPtr common, WacomChannelPtr pChannel,
WacomDeviceStatePtr ds);
static int xf86WcmFilterIntuos(WacomCommonPtr common, WacomChannelPtr pChannel,
WacomDeviceStatePtr ds);
static void xf86WcmSendEvents(LocalDevicePtr local, const WacomDeviceState* ds);
static Bool xf86WcmDevConvert(LocalDevicePtr local, int first, int num,
int v0, int v1, int v2, int v3, int v4, int v5, int *x, int *y);
static Bool xf86WcmDevReverseConvert(LocalDevicePtr local, int x, int y,
int *valuators);
static int xf86WcmDevProc(DeviceIntPtr pWcm, int what);
static void xf86WcmDevControlProc(DeviceIntPtr device, PtrCtrl *ctrl);
static void xf86WcmDevClose(LocalDevicePtr local);
static int xf86WcmDevChangeControl(LocalDevicePtr local, xDeviceCtl* control);
static int xf86WcmDevSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode);
static const char *default_options[] =
{
"BaudRate", "9600",
"StopBits", "1",
"DataBits", "8",
"Parity", "None",
"Vmin", "1",
"Vtime", "10",
"FlowControl", "Xoff",
NULL
};
#if defined(__QNX__) || defined(__QNXNTO__)
#define POSIX_TTY
#endif
#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))
#define mils(res) (res * 100 / 2.54)
#define DEVICE_ID(flags) ((flags) & 0x07)
#define STYLUS_ID 1
#define CURSOR_ID 2
#define ERASER_ID 4
#define ABSOLUTE_FLAG 8
#define KEEP_SHAPE_FLAG 16
#define BAUD_19200_FLAG 32
#define BETA_FLAG 64
#define BUTTONS_ONLY_FLAG 128
#define IsCursor(priv) (DEVICE_ID((priv)->flags) == CURSOR_ID)
#define IsStylus(priv) (DEVICE_ID((priv)->flags) == STYLUS_ID)
#define IsEraser(priv) (DEVICE_ID((priv)->flags) == ERASER_ID)
#define MAX_SAMPLES 4
#define PEN(ds) (((ds->device_id) & 0x07ff) == 0x0022 \
|| ((ds->device_id) & 0x07ff) == 0x0042 \
|| ((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 MOUSE_2D(ds) (((ds->device_id) & 0x07ff) == 0x0007)
#define LENS_CURSOR(ds) (((ds->device_id) & 0x07ff) == 0x0096)
#define INKING_PEN(ds) (((ds->device_id) & 0x07ff) == 0x0012)
#define STYLUS_TOOL(ds) (PEN(ds) || STROKING_PEN(ds) || INKING_PEN(ds) || \
AIRBRUSH(ds))
#define CURSOR_TOOL(ds) (MOUSE_4D(ds) || LENS_CURSOR(ds) || MOUSE_2D(ds))
typedef int (*FILTERFUNC)(WacomDevicePtr pDev, WacomDeviceStatePtr pState);
#define FILTER_PRESSURE_RES 2048
typedef enum { TV_NONE = 0, TV_ABOVE_BELOW = 1, TV_LEFT_RIGHT = 2 } tvMode;
#define CURSOR_SECTION_NAME "wacomcursor"
#define STYLUS_SECTION_NAME "wacomstylus"
#define ERASER_SECTION_NAME "wacomeraser"
#define DEFAULT_SPEED 1.0
#define MAX_ACCEL 7
#define DEFAULT_SUPPRESS 2
#define MAX_SUPPRESS 6
#define BUFFER_SIZE 256
#define XI_STYLUS "STYLUS"
#define XI_CURSOR "CURSOR"
#define XI_ERASER "ERASER"
#define MAX_VALUE 100
#define MAXTRY 3
#define MAX_COORD_RES 1270.0
#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
#define WC_RESET "\r#"
#define WC_RESET_BAUD "\r$"
#define WC_CONFIG "~R\r"
#define WC_COORD "~C\r"
#define WC_MODEL "~#\r"
#define WC_MULTI "MU1\r"
#define WC_UPPER_ORIGIN "OC1\r"
#define WC_SUPPRESS "SU"
#define WC_ALL_MACRO "~M0\r"
#define WC_NO_MACRO1 "~M1\r"
#define WC_RATE "IT0\r"
#define WC_TILT_MODE "FM1\r"
#define WC_NO_INCREMENT "IN0\r"
#define WC_STREAM_MODE "SR\r"
#define WC_PRESSURE_MODE "PH1\r"
#define WC_ZFILTER "ZF1\r"
#define WC_STOP "\nSP\r"
#define WC_START "ST\r"
#define WC_NEW_RESOLUTION "NR"
#define TILT_REQUEST_FLAG 1
#define TILT_ENABLED_FLAG 2
#define RAW_FILTERING_FLAG 4
#define DEVICE_ISDV4 0x000C
#define ROTATE_NONE 0
#define ROTATE_CW 1
#define ROTATE_CCW 2
#define MAX_CHANNELS 2
#define MAX_USB_EVENTS 32
#define HANDLE_TILT(comm) ((comm)->wcmFlags & TILT_ENABLED_FLAG)
#define RAW_FILTERING(comm) ((comm)->wcmFlags & RAW_FILTERING_FLAG)
struct _WacomFilterState
{
int npoints;
int x[3];
int y[3];
int tiltx[3];
int tilty[3];
int statex;
int statey;
};
struct _WacomDeviceState
{
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 abswheel;
int relwheel;
int distance;
int throttle;
int discard_first;
int proximity;
int sample;
};
struct _WacomChannel
{
WacomDeviceState work;
union
{
WacomDeviceState state;
WacomDeviceState states[MAX_SAMPLES];
} valid;
int nSamples;
LocalDevicePtr pDev;
WacomFilterState rawFilter;
};
struct _WacomDeviceRec
{
unsigned int flags;
int topX;
int topY;
int bottomX;
int bottomY;
double factorX;
double factorY;
unsigned int serial;
int screen_no;
int button[16];
WacomCommonPtr common;
int oldX;
int oldY;
int oldZ;
int oldTiltX;
int oldTiltY;
int oldWheel;
int oldRot;
int oldThrottle;
int oldButtons;
int oldProximity;
double speed;
int accel;
int numScreen;
int currentScreen;
double dscaleX;
double dscaleY;
int doffsetX;
int doffsetY;
tvMode twinview;
int tvResolution[4];
int throttleStart;
int throttleLimit;
int throttleValue;
int *pPressCurve;
int nPressCtrl[4];
};
struct _WacomCommonRec
{
char *wcmDevice;
int wcmSuppress;
unsigned char wcmFlags;
int wcmMaxX;
int wcmMaxY;
int wcmMaxZ;
int wcmResolX;
int wcmResolY;
int wcmUserResolX;
int wcmUserResolY;
int wcmUserResolZ;
LocalDevicePtr *wcmDevices;
int wcmNumDevices;
int wcmPktLength;
int wcmProtocolLevel;
float wcmVersion;
int wcmForceDevice;
int wcmRotate;
int wcmThreshold;
int wcmChannelCnt;
WacomChannel wcmChannel[MAX_CHANNELS];
int wcmInitialized;
unsigned int wcmLinkSpeed;
WacomDeviceClassPtr wcmDevCls;
WacomModelPtr wcmModel;
int wcmGimp;
int bufpos;
unsigned char buffer[BUFFER_SIZE];
#ifdef LINUX_INPUT
int wcmEventCnt;
struct input_event wcmEvents[MAX_USB_EVENTS];
#endif
};
struct _WacomModule4
{
InputDriverPtr wcmDrv;
};
struct _WacomModule
{
int debugLevel;
KeySym* keymap;
const char* identification;
WacomModule4 v4;
int (*DevOpen)(DeviceIntPtr pWcm);
void (*DevReadInput)(LocalDevicePtr local);
void (*DevControlProc)(DeviceIntPtr device, PtrCtrl* ctrl);
void (*DevClose)(LocalDevicePtr local);
int (*DevProc)(DeviceIntPtr pWcm, int what);
int (*DevChangeControl)(LocalDevicePtr local, xDeviceCtl* control);
int (*DevSwitchMode)(ClientPtr client, DeviceIntPtr dev, int mode);
Bool (*DevConvert)(LocalDevicePtr local, int first, int num,
int v0, int v1, int v2, int v3, int v4, int v5,
int* x, int* y);
Bool (*DevReverseConvert)(LocalDevicePtr local, int x, int y,
int* valuators);
};
struct _WacomModel
{
const char* name;
void (*Initialize)(WacomCommonPtr common, int fd, const char* id, float version);
void (*GetResolution)(WacomCommonPtr common, int fd);
int (*GetRanges)(WacomCommonPtr common, int fd);
int (*Reset)(WacomCommonPtr common, int fd);
int (*EnableTilt)(WacomCommonPtr common, int fd);
int (*EnableSuppress)(WacomCommonPtr common, int fd);
int (*SetLinkSpeed)(WacomCommonPtr common, int fd);
int (*Start)(WacomCommonPtr common, int fd);
int (*Parse)(WacomCommonPtr common, const unsigned char* data);
int (*FilterRaw)(WacomCommonPtr common, WacomChannelPtr pChannel,
WacomDeviceStatePtr ds);
};
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 * pl_setup_string = WC_UPPER_ORIGIN WC_RATE WC_STREAM_MODE;
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_HEIGHT "HT1\r"
#define WC_V_ID "ID1\r"
#define WC_V_19200 "BA19\r"
#define WC_V_38400 "BA38\r"
#define WC_V_9600 "$\r"
#define WC_RESET_19200 "\r$"
#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
#define ERASER_PROX 4
#define OTHER_PROX 1
static KeySym wacom_map[] =
{
NoSymbol,
NoSymbol,
NoSymbol,
NoSymbol,
NoSymbol,
NoSymbol,
NoSymbol,
NoSymbol,
XK_F1,
XK_F2,
XK_F3,
XK_F4,
XK_F5,
XK_F6,
XK_F7,
XK_F8,
XK_F9,
XK_F10,
XK_F11,
XK_F12,
XK_F13,
XK_F14,
XK_F15,
XK_F16,
XK_F17,
XK_F18,
XK_F19,
XK_F20,
XK_F21,
XK_F22,
XK_F23,
XK_F24,
XK_F25,
XK_F26,
XK_F27,
XK_F28,
XK_F29,
XK_F30,
XK_F31,
XK_F32
};
static KeySymsRec wacom_keysyms = {
wacom_map, 8, 0x27, 1
};
#define XWACOM_PARAM_TOPX 1
#define XWACOM_PARAM_TOPY 2
#define XWACOM_PARAM_BOTTOMX 3
#define XWACOM_PARAM_BOTTOMY 4
#define XWACOM_PARAM_BUTTON1 5
#define XWACOM_PARAM_BUTTON2 6
#define XWACOM_PARAM_BUTTON3 7
#define XWACOM_PARAM_BUTTON4 8
#define XWACOM_PARAM_BUTTON5 9
#define XWACOM_PARAM_DEBUGLEVEL 10
#define XWACOM_PARAM_PRESSCURVE 11
#define XWACOM_PARAM_RAWFILTER 12
#define XWACOM_PARAM_MODE 13
#define XWACOM_PARAM_SPEEDLEVEL 14
#define XWACOM_PARAM_CLICKFORCE 15
#define XWACOM_PARAM_ACCEL 16
#define XWACOM_PARAM_XYDEFAULT 65
#define XWACOM_PARAM_FILEMODEL 100
#define XWACOM_PARAM_FILEOPTION 101
#define XWACOM_PARAM_GIMP 102
WacomModule gWacomModule =
{
0,
wacom_map,
identification,
{ NULL },
xf86WcmDevOpen,
xf86WcmDevReadInput,
xf86WcmDevControlProc,
xf86WcmDevClose,
xf86WcmDevProc,
xf86WcmDevChangeControl,
xf86WcmDevSwitchMode,
xf86WcmDevConvert,
xf86WcmDevReverseConvert,
};
struct _WacomDeviceClass
{
Bool (*Detect)(LocalDevicePtr local);
Bool (*Init)(LocalDevicePtr local);
void (*Read)(LocalDevicePtr local);
};
static WacomDeviceClass gWacomSerialDevice =
{
serialDetect,
serialInit,
xf86WcmReadPacket,
};
static WacomDeviceClass gWacomISDV4Device =
{
isdv4Detect,
isdv4Init,
xf86WcmReadPacket,
};
#ifdef LINUX_INPUT
static WacomDeviceClass gWacomUSBDevice =
{
usbDetect,
usbInit,
xf86WcmReadPacket,
};
static WacomModel usbUnknown =
{
"Unknown USB",
usbInitProtocol5,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
NULL,
};
static WacomModel usbPenPartner =
{
"USB PenPartner",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbGraphire =
{
"USB Graphire",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbGraphire2 =
{
"USB Graphire2",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbGraphire3 =
{
"USB Graphire3",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbCintiq =
{
"USB Cintiq",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbCintiqPartner =
{
"USB CintiqPartner",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
static WacomModel usbIntuos =
{
"USB Intuos",
usbInitProtocol5,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterIntuos,
};
static WacomModel usbIntuos2 =
{
"USB Intuos2",
usbInitProtocol5,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterIntuos,
};
static WacomModel usbVolito =
{
"USB Volito",
usbInitProtocol4,
NULL,
usbGetRanges,
NULL,
NULL,
NULL,
NULL,
NULL,
usbParse,
xf86WcmFilterCoord,
};
#endif
static WacomDeviceClass* wcmDeviceClasses[] =
{
#ifdef LINUX_INPUT
&gWacomUSBDevice,
#endif
&gWacomISDV4Device,
&gWacomSerialDevice,
NULL
};
#ifdef LINUX_INPUT
static Bool usbDetect(LocalDevicePtr local)
{
int version;
int err;
DBG(1, ErrorF("usbDetect\n"));
SYSCALL(err = ioctl(local->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;
}
return 0;
}
static Bool usbInit(LocalDevicePtr local)
{
short sID[4];
char id[BUFFER_SIZE];
WacomModelPtr model = NULL;
WacomDevicePtr priv = (WacomDevicePtr)local->private;
WacomCommonPtr common = priv->common;
DBG(1, ErrorF("initializing USB tablet\n"));
ioctl(local->fd, EVIOCGID, sID);
ioctl(local->fd, EVIOCGNAME(sizeof(id)), id);
if (sID[1] == 0x056A) {
switch (sID[2]) {
case 0x00:
model = &usbPenPartner; break;
case 0x10:
model = &usbGraphire; break;
case 0x11:
case 0x12:
model = &usbGraphire2; break;
case 0x13:
case 0x14:
model = &usbGraphire3; break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
model = &usbIntuos; break;
case 0x03:
model = &usbCintiqPartner; break;
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
model = &usbCintiq; break;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x47:
model = &usbIntuos2; break;
case 0x60:
model = &usbVolito; break;
}
}
if (!model) model = &usbUnknown;
return xf86WcmInitTablet(common,model,local->fd,id,0.0);
}
static void usbInitProtocol5(WacomCommonPtr common, int fd, const char* id,
float version)
{
DBG(2, ErrorF("detected a protocol 5 model (%s)\n",id));
common->wcmResolX = common->wcmResolY = 2540;
common->wcmProtocolLevel = 5;
common->wcmChannelCnt = 2;
common->wcmPktLength = sizeof(struct input_event);
}
static void usbInitProtocol4(WacomCommonPtr common, int fd, const char* id,
float version)
{
DBG(2, ErrorF("detected a protocol 4 model (%s)\n",id));
common->wcmResolX = common->wcmResolY = 1016;
common->wcmProtocolLevel = 4;
common->wcmPktLength = sizeof(struct input_event);
}
#define BIT(x) (1<<(x))
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y))
#define OFF(x) ((x)%BITS_PER_LONG)
#define LONG(x) ((x)/BITS_PER_LONG)
static int usbGetRanges(WacomCommonPtr common, int fd)
{
int nValues[5];
unsigned long ev[NBITS(EV_MAX)];
unsigned long abs[NBITS(ABS_MAX)];
if (ioctl(fd, EVIOCGBIT(0 , sizeof(ev)), ev) < 0) {
ErrorF("WACOM: unable to ioctl event bits.\n");
return !Success;
}
if (ISBITSET(ev,EV_ABS)) {
if (ioctl(fd, EVIOCGBIT(EV_ABS,sizeof(abs)),abs) < 0) {
ErrorF("WACOM: unable to ioctl abs bits.\n");
return !Success;
}
if (common->wcmMaxX == 0) {
if (ioctl(fd, EVIOCGABS(ABS_X), nValues) < 0) {
ErrorF("WACOM: unable to ioctl xmax value.\n");
return !Success;
}
common->wcmMaxX = nValues[2];
}
if (common->wcmMaxY == 0) {
if (ioctl(fd, EVIOCGABS(ABS_Y), nValues) < 0) {
ErrorF("WACOM: unable to ioctl ymax value.\n");
return !Success;
}
common->wcmMaxY = nValues[2];
}
if (ioctl(fd, EVIOCGABS(ABS_PRESSURE), nValues) < 0) {
ErrorF("WACOM: unable to ioctl press max value.\n");
return !Success;
}
common->wcmMaxZ = nValues[2];
}
return Success;
}
static int usbParse(WacomCommonPtr common, const unsigned char* data)
{
usbParseEvent(common,(const struct input_event*)data);
return common->wcmPktLength;
}
static void usbParseEvent(WacomCommonPtr common,
const struct input_event* event)
{
int i, serial, channel;
if (common->wcmEventCnt >= (sizeof(common->wcmEvents)/sizeof(*common->wcmEvents)))
{
DBG(1, ErrorF("usbParse: Exceeded event queue (%d)\n",
common->wcmEventCnt));
common->wcmEventCnt = 0;
return;
}
common->wcmEvents[common->wcmEventCnt++] = *event;
if ((event->type != EV_MSC) || (event->code != MSC_SERIAL)) {
#ifdef EV_SYN
if ((event->type == EV_SYN) && (event->code == SYN_REPORT)) {
usbParseChannel(common,0,0);
common->wcmEventCnt = 0;
}
#endif
return;
}
serial = event->value;
channel = -1;
if (common->wcmChannelCnt == 1) channel = 0;
else {
for (i=0; i<common->wcmChannelCnt; ++i) {
if (common->wcmChannel[i].work.serial_num == serial) {
channel = i;
break;
}
}
if (channel < 0) {
for (i=0; i<common->wcmChannelCnt; ++i) {
if (common->wcmChannel[i].work.proximity == 0) {
memset(&common->wcmChannel[i],0, sizeof(WacomChannel));
channel = i;
break;
}
}
}
if (channel < 0) {
DBG(1, ErrorF("usbParse: Exceeded channel count; ignoring.\n"));
return;
}
}
usbParseChannel(common,channel,serial);
common->wcmEventCnt = 0;
}
static void usbParseChannel(WacomCommonPtr common, int channel, int serial)
{
int i;
WacomDeviceState* ds;
struct input_event* event;
# define MOD_BUTTONS(bit, value) do { \
ds->buttons = (((value) != 0) ? \
(ds->buttons | (bit)) : (ds->buttons & ~(bit))); \
} while (0)
ds = &common->wcmChannel[channel].work;
ds->relwheel = 0;
ds->serial_num = serial;
for (i=0; i<common->wcmEventCnt; ++i)
{
event = common->wcmEvents + i;
DBG(11, ErrorF("usbParseChannel event[%d]->type=%d code=%d value=%d\n",
i, event->type, event->code, event->value));
if (event->type == EV_ABS) {
if (event->code == ABS_X)
ds->x = event->value;
else if (event->code == ABS_Y)
ds->y = event->value;
else if (event->code == ABS_RZ)
ds->rotation = event->value;
else if (event->code == ABS_TILT_X)
ds->tiltx = event->value - 64;
else if (event->code == ABS_TILT_Y)
ds->tilty = event->value - 64;
else if (event->code == ABS_PRESSURE) {
ds->pressure = event->value;
MOD_BUTTONS (1, event->value > common->wcmThreshold ? 1 : 0);
}
else if (event->code == ABS_DISTANCE)
ds->distance = event->value;
else if (event->code == ABS_WHEEL)
ds->abswheel = event->value;
else if (event->code == ABS_THROTTLE)
ds->throttle = event->value;
} else if (event->type == EV_REL) {
if (event->code == REL_WHEEL)
ds->relwheel = event->value;
else {
ErrorF("wacom: rel event recv'd (%d)!\n", event->code);
}
} else if (event->type == EV_KEY) {
if ((event->code == BTN_TOOL_PEN) || (event->code == BTN_TOOL_PENCIL) ||
(event->code == BTN_TOOL_BRUSH) || (event->code == BTN_TOOL_AIRBRUSH)) {
ds->device_type = STYLUS_ID;
ds->proximity = (event->value != 0);
DBG(6, ErrorF("USB stylus detected %x\n", event->code));
} else if (event->code == BTN_TOOL_RUBBER) {
ds->device_type = ERASER_ID;
ds->proximity = (event->value != 0);
if (ds->proximity) ds->proximity = ERASER_PROX;
DBG(6, ErrorF("USB eraser detected %x\n", event->code));
} else if ((event->code == BTN_TOOL_MOUSE) || (event->code == BTN_TOOL_LENS)) {
DBG(6, ErrorF("USB mouse detected %x\n", event->code));
ds->device_type = CURSOR_ID;
ds->proximity = (event->value != 0);
} else if (event->code == BTN_TOUCH) {
} else if ((event->code == BTN_STYLUS) || (event->code == BTN_MIDDLE)) {
MOD_BUTTONS (2, event->value);
} else if ((event->code == BTN_STYLUS2) || (event->code == BTN_RIGHT)) {
MOD_BUTTONS (4, event->value);
} else if (event->code == BTN_LEFT)
MOD_BUTTONS (1, event->value);
else if (event->code == BTN_SIDE)
MOD_BUTTONS (8, event->value);
else if (event->code == BTN_EXTRA)
MOD_BUTTONS (16, event->value);
}
}
xf86WcmEvent(common, channel, ds);
}
#endif
static WacomModel serialIntuos =
{
"Serial Intuos",
serialInitIntuos,
NULL,
serialGetRanges,
serialResetIntuos,
NULL,
NULL,
serialSetLinkSpeedIntuos,
serialStartTablet,
serialParseProtocol5,
xf86WcmFilterIntuos,
};
static WacomModel serialIntuos2 =
{
"Serial Intuos2",
serialInitIntuos2,
NULL,
serialGetRanges,
serialResetIntuos,
NULL,
NULL,
serialSetLinkSpeedProtocol5,
serialStartTablet,
serialParseProtocol5,
xf86WcmFilterIntuos,
};
static WacomModel serialCintiq =
{
"Serial Cintiq",
serialInitCintiq,
serialGetResolution,
serialGetRanges,
serialResetCintiq,
serialEnableTiltProtocol4,
serialEnableSuppressProtocol4,
NULL,
serialStartTablet,
serialParseCintiq,
xf86WcmFilterCoord,
};
static WacomModel serialPenPartner =
{
"Serial PenPartner",
serialInitPenPartner,
NULL,
serialGetRanges,
serialResetPenPartner,
serialEnableTiltProtocol4,
serialEnableSuppressProtocol4,
NULL,
serialStartTablet,
serialParseProtocol4,
xf86WcmFilterCoord,
};
static WacomModel serialGraphire =
{
"Serial Graphire",
serialInitGraphire,
NULL,
NULL,
serialResetPenPartner,
serialEnableTiltProtocol4,
serialEnableSuppressProtocol4,
NULL,
serialStartTablet,
serialParseGraphire,
xf86WcmFilterCoord,
};
static WacomModel serialProtocol4 =
{
"Serial UD",
serialInitProtocol4,
serialGetResolution,
serialGetRanges,
serialResetProtocol4,
serialEnableTiltProtocol4,
serialEnableSuppressProtocol4,
NULL,
serialStartTablet,
serialParseProtocol4,
xf86WcmFilterCoord,
};
static char *
xf86WcmSendRequest(int fd,
char *request,
char *answer,
int maxlen)
{
int len, nr;
int maxtry = MAXTRY;
if (maxlen < 3)
return NULL;
do {
SYSCALL(len = xf86WcmWrite(fd, request, strlen(request)));
if ((len == -1) && (errno != EAGAIN)) {
ErrorF("Wacom xf86WcmWrite error : %s", strerror(errno));
return NULL;
}
maxtry--;
} while ((len == -1) && maxtry);
if (maxtry == 0) {
ErrorF("Wacom unable to xf86WcmWrite request string '%s' after %d tries\n", request, MAXTRY);
return NULL;
}
do {
maxtry = MAXTRY;
do {
if ((nr = xf86WcmWaitForTablet(fd)) > 0) {
SYSCALL(nr = xf86WcmRead(fd, answer, 1));
if ((nr == -1) && (errno != EAGAIN)) {
ErrorF("Wacom xf86WcmRead 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;
}
do {
maxtry = MAXTRY;
do {
if ((nr = xf86WcmWaitForTablet(fd)) > 0) {
SYSCALL(nr = xf86WcmRead(fd, answer+1, 1));
if ((nr == -1) && (errno != EAGAIN)) {
ErrorF("Wacom xf86WcmRead 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]));
len = 2;
maxtry = MAXTRY;
do {
do {
if ((nr = xf86WcmWaitForTablet(fd)) > 0) {
SYSCALL(nr = xf86WcmRead(fd, answer+len, 1));
if ((nr == -1) && (errno != EAGAIN)) {
ErrorF("Wacom xf86WcmRead error : %s\n", strerror(errno));
return NULL;
}
DBG(10, ErrorF("%c err=%d [%d]\n", answer[len], nr, len));
}
else {
if (len == 2) {
DBG(10, ErrorF("timeout remains %d tries\n", maxtry));
maxtry--;
}
}
} while ((nr <= 0) && len == 2 && maxtry);
if (nr > 0) {
len += nr;
if (len >= (maxlen - 1))
return NULL;
}
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 (nr > 0);
if (len <= 3)
return NULL;
answer[len-1] = '\0';
return answer;
}
static Bool serialDetect(LocalDevicePtr pDev)
{
return 1;
}
static Bool serialInit(LocalDevicePtr local)
{
int err;
WacomCommonPtr common = ((WacomDevicePtr)(local->private))->common;
DBG(1, ErrorF("initializing serial tablet\n"));
if (xf86WcmSetSerialSpeed(local->fd, 38400) < 0)
return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(250)) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(75)) return !Success;
if (xf86WcmSetSerialSpeed(local->fd, 19200) < 0) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(250)) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(75)) return !Success;
if (xf86WcmSetSerialSpeed(local->fd, 9600) < 0) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(250)) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_STOP, strlen(WC_STOP)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(30)) return !Success;
xf86WcmFlushTablet(local->fd);
if (serialInitTablet(common,local->fd) == !Success) {
SYSCALL(xf86WcmClose(local->fd));
local->fd = -1;
return !Success;
}
return Success;
}
static int serialInitTablet(WacomCommonPtr common, int fd)
{
int loop, idx;
char id[BUFFER_SIZE];
float version;
WacomModelPtr model = NULL;
if (model != NULL)
{
id[0] = '\0';
version = 0.0F;
}
else
{
DBG(2, ErrorF("reading model\n"));
if (!xf86WcmSendRequest(fd, WC_MODEL, id, sizeof(id))) return !Success;
DBG(2, ErrorF("%s\n", id));
if (xf86Verbose) ErrorF("%s Wacom tablet model : %s\n", XCONFIG_PROBED, id+2);
for(loop=strlen(id); loop>=0 && *(id+loop) != 'V'; loop--);
for(idx=loop; idx<strlen(id) && *(id+idx) != '-'; idx++); *(id+idx) = '\0';
sscanf(id+loop+1, "%f", &version);
if (id[2] == 'G' && id[3] == 'D')
model = &serialIntuos;
else if (id[2] == 'X' && id[3] == 'D')
model = &serialIntuos2;
else if (id[2] == 'P' && id[3] == 'L')
model = &serialCintiq;
else if (id[2] == 'C' && id[3] == 'T')
model = &serialPenPartner;
else if (id[2] == 'E' && id[3] == 'T')
model = &serialGraphire;
else
model = &serialProtocol4;
}
return xf86WcmInitTablet(common,model,fd,id,version);
}
static int serialParseGraphire(WacomCommonPtr common,
const unsigned char* data)
{
int n;
WacomDeviceState* last = &common->wcmChannel[0].valid.state;
WacomDeviceState* ds;
if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;
ds = &common->wcmChannel[0].work;
RESET_RELATIVE(*ds);
ds->pressure = ((data[6]&ZAXIS_BITS) << 2 ) +
((data[3]&ZAXIS_BIT) >> 1) +
((data[3]&PROXIMITY_BIT) >> 6) +
((data[6]&ZAXIS_SIGN_BIT) ? 0 : 0x100);
ds->buttons = (data[3] & 0x38) >> 3;
serialParseP4Common(common,data,last,ds);
if (ds->device_type == CURSOR_ID)
{
ds->relwheel = (data[6] & 0x30) >> 4;
if (data[6] & 0x40) ds->relwheel = -ds->relwheel;
}
xf86WcmEvent(common,0,ds);
return common->wcmPktLength;
}
static int serialParseCintiq(WacomCommonPtr common,
const unsigned char* data)
{
int n;
WacomDeviceState* last = &common->wcmChannel[0].valid.state;
WacomDeviceState* ds;
if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;
ds = &common->wcmChannel[0].work;
RESET_RELATIVE(*ds);
if (common->wcmMaxZ == 255)
{
ds->pressure = ((data[6] & ZAXIS_BITS) << 1 ) |
((data[3] & ZAXIS_BIT) >> 2) |
((data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x80);
}
else
{
ds->pressure = ((data[6]&ZAXIS_BITS) << 2 ) +
((data[3]&ZAXIS_BIT) >> 1) +
((data[3]&PROXIMITY_BIT) >> 6) +
((data[6]&ZAXIS_SIGN_BIT) ? 0 : 0x100);
}
ds->buttons = (data[3] & 0x38) >> 3;
serialParseP4Common(common,data,last,ds);
xf86WcmEvent(common,0,ds);
return common->wcmPktLength;
}
static int serialParseProtocol4(WacomCommonPtr common,
const unsigned char* data)
{
int n;
WacomDeviceState* last = &common->wcmChannel[0].valid.state;
WacomDeviceState* ds;
if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;
ds = &common->wcmChannel[0].work;
RESET_RELATIVE(*ds);
if (common->wcmMaxZ == 255)
ds->pressure = ((data[6] & ZAXIS_BITS) << 1 ) |
((data[3] & ZAXIS_BIT) >> 2) |
((data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x80);
else
ds->pressure = (data[6] & ZAXIS_BITS) |
(data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x40;
ds->buttons = (data[3] & BUTTONS_BITS) >> 3;
serialParseP4Common(common,data,last,ds);
xf86WcmEvent(common,0,ds);
return common->wcmPktLength;
}
static int serialParseProtocol5(WacomCommonPtr common,
const unsigned char* data)
{
int n;
int have_data=0;
int channel;
WacomDeviceState* ds;
if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;
channel = data[0] & 0x01;
ds = &common->wcmChannel[channel].work;
RESET_RELATIVE(*ds);
DBG(7, ErrorF("packet header = 0x%x\n", (unsigned int)data[0]));
if ((data[0] & 0xfc) == 0xc0) {
memset(ds, 0, sizeof(*ds));
ds->proximity = 1;
ds->device_id = (((data[1] & 0x7f) << 5) |
((data[2] & 0x7c) >> 2));
ds->serial_num = (((data[2] & 0x03) << 30) |
((data[3] & 0x7f) << 23) |
((data[4] & 0x7f) << 16) |
((data[5] & 0x7f) << 9) |
((data[6] & 0x7f) << 2) |
((data[7] & 0x60) >> 5));
if ((ds->device_id & 0xf06) != 0x802) ds->discard_first = 1;
if (STYLUS_TOOL(ds))
ds->device_type = STYLUS_ID;
else if (CURSOR_TOOL(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"));
} else if ((data[0] & 0xfe) == 0x80) {
ds->proximity = 0;
have_data = 1;
}
else if (((data[0] & 0xb8) == 0xa0) || ((data[0] & 0xbe) == 0xb4)) {
ds->x = (((data[1] & 0x7f) << 9) | ((data[2] & 0x7f) << 2) |
((data[3] & 0x60) >> 5));
ds->y = (((data[3] & 0x1f) << 11) | ((data[4] & 0x7f) << 4) |
((data[5] & 0x78) >> 3));
if ((data[0] & 0xb8) == 0xa0) {
ds->pressure = (((data[5] & 0x07) << 7) | (data[6] & 0x7f));
ds->buttons = (((data[0]) & 0x06) | (ds->pressure >= common->wcmThreshold));
} else {
ds->abswheel = (((data[5] & 0x07) << 7) | (data[6] & 0x7f));
}
ds->tiltx = (data[7] & TILT_BITS);
ds->tilty = (data[8] & TILT_BITS);
if (data[7] & TILT_SIGN_BIT)
ds->tiltx -= (TILT_BITS + 1);
if (data[8] & TILT_SIGN_BIT)
ds->tilty -= (TILT_BITS + 1);
ds->proximity = (data[0] & PROXIMITY_BIT);
have_data = 1;
}
else if (((data[0] & 0xbe) == 0xa8) || ((data[0] & 0xbe) == 0xb0)) {
ds->x = (((data[1] & 0x7f) << 9) | ((data[2] & 0x7f) << 2) |
((data[3] & 0x60) >> 5));
ds->y = (((data[3] & 0x1f) << 11) | ((data[4] & 0x7f) << 4) |
((data[5] & 0x78) >> 3));
ds->tilty = 0;
if (MOUSE_4D(ds)) {
ds->throttle = (((data[5] & 0x07) << 7) | (data[6] & 0x7f));
if (data[8] & 0x08) ds->throttle = -ds->throttle;
ds->buttons = (((data[8] & 0x70) >> 1) | (data[8] & 0x07));
have_data = !ds->discard_first;
} else if (LENS_CURSOR(ds)) {
ds->buttons = data[8];
have_data = 1;
} else if (MOUSE_2D(ds)) {
ds->buttons = (data[8] & 0x1C) >> 2;
ds->relwheel = -(data[8] & 1) + ((data[8] & 2) >> 1);
have_data = 1;
}
ds->proximity = (data[0] & PROXIMITY_BIT);
}
else if ((data[0] & 0xbe) == 0xaa) {
ds->x = (((data[1] & 0x7f) << 9) | ((data[2] & 0x7f) << 2) |
((data[3] & 0x60) >> 5));
ds->y = (((data[3] & 0x1f) << 11) | ((data[4] & 0x7f) << 4) |
((data[5] & 0x78) >> 3));
ds->rotation = (((data[6] & 0x0f) << 7) | (data[7] & 0x7f));
if (ds->rotation < 900) ds->rotation = -ds->rotation;
else ds->rotation = 1799 - ds->rotation;
ds->proximity = (data[0] & PROXIMITY_BIT);
have_data = 1;
ds->discard_first = 0;
} else {
DBG(10, ErrorF("unknown wacom V packet 0x%x\n", data[0]));
}
if (have_data) {
xf86WcmEvent(common,channel,ds);
} else {
common->wcmChannel[channel].pDev = NULL;
}
return common->wcmPktLength;
}
static void serialInitIntuos(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected an Intuos model\n"));
common->wcmProtocolLevel = 5;
common->wcmVersion = version;
common->wcmMaxZ = 1023;
common->wcmResolX = 2540;
common->wcmResolY = 2540;
common->wcmPktLength = 9;
common->wcmFlags |= TILT_ENABLED_FLAG;
}
static void serialInitIntuos2(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected an Intuos2 model\n"));
common->wcmProtocolLevel = 5;
common->wcmVersion = version;
common->wcmMaxZ = 1023;
common->wcmResolX = 2540;
common->wcmResolY = 2540;
common->wcmPktLength = 9;
common->wcmFlags |= TILT_ENABLED_FLAG;
}
static void serialInitCintiq(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected a Cintiq model\n"));
common->wcmProtocolLevel = 4;
common->wcmPktLength = 7;
common->wcmVersion = version;
if (id[5] == '2') {
if ( id[6] == '5' ) {
common->wcmMaxZ = 255;
} else {
common->wcmMaxZ = 255;
}
} else if (id[5] == '3') {
common->wcmMaxZ = 255;
} else if (id[5] == '4') {
common->wcmMaxZ = 255;
} else if (id[5] == '5') {
if ( id[6] == '5' ) {
common->wcmMaxZ = 511;
} else {
common->wcmMaxZ = 255;
}
} else if (id[5] == '6') {
if ( id[8] == 'S' ) {
common->wcmMaxZ = 255;
} else {
common->wcmMaxZ = 255;
}
} else if (id[5] == '8') {
common->wcmMaxZ = 511;
}
common->wcmResolX = 508;
common->wcmResolY = 508;
}
static void serialInitPenPartner(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected a PenPartner model\n"));
common->wcmProtocolLevel = 4;
common->wcmPktLength = 7;
common->wcmVersion = version;
common->wcmMaxZ = 256;
common->wcmResolX = 1000;
common->wcmResolY = 1000;
}
static void serialInitGraphire(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected a Graphire model\n"));
common->wcmProtocolLevel = 4;
common->wcmPktLength = 7;
common->wcmVersion = version;
common->wcmMaxX = 5103;
common->wcmMaxY = 3711;
common->wcmMaxZ = 512;
common->wcmResolX = 1000;
common->wcmResolY = 1000;
}
static void serialInitProtocol4(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("detected a Protocol4 model\n"));
common->wcmProtocolLevel = 4;
common->wcmPktLength = 7;
common->wcmVersion = version;
if (!common->wcmMaxZ) {
if (version >= (float)1.2) common->wcmMaxZ = 255;
else common->wcmMaxZ = 120;
}
}
static void serialGetResolution(WacomCommonPtr common, int fd)
{
int a, b;
char buffer[BUFFER_SIZE], header[BUFFER_SIZE];
if (!(common->wcmResolX && common->wcmResolY)) {
DBG(2, ErrorF("Requesting resolution from device\n"));
if (xf86WcmSendRequest(fd, WC_CONFIG, buffer, sizeof(buffer)))
{
DBG(2, ErrorF("%s\n", buffer));
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;
}
}
DBG(2, ErrorF("serialGetResolution: ResolX=%d ResolY=%d\n",
common->wcmResolX, common->wcmResolY));
}
static int serialGetRanges(WacomCommonPtr common, int fd)
{
char buffer[BUFFER_SIZE];
if (!(common->wcmMaxX && common->wcmMaxY)) {
DBG(2, ErrorF("Requesting max coordinates\n"));
if (!xf86WcmSendRequest(fd, WC_COORD, buffer, sizeof(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("serialGetRanges: maxX=%d maxY=%d (%g,%g in)\n",
common->wcmMaxX, common->wcmMaxY,
(double)common->wcmMaxX / common->wcmResolX,
(double)common->wcmMaxY / common->wcmResolY));
return Success;
}
static int serialResetIntuos(WacomCommonPtr common, int fd)
{
int err;
SYSCALL(err = xf86WcmWrite(fd, intuos_setup_string, strlen(intuos_setup_string)));
return (err == -1) ? !Success : Success;
}
static int serialResetCintiq(WacomCommonPtr common, int fd)
{
int err;
SYSCALL(err = xf86WcmWrite(fd, WC_RESET, strlen(WC_RESET)));
if (xf86WcmWait(75)) return !Success;
SYSCALL(err = xf86WcmWrite(fd, pl_setup_string, strlen(pl_setup_string)));
if (err == -1) return !Success;
SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
strlen(penpartner_setup_string)));
return (err == -1) ? !Success : Success;
}
static int serialResetPenPartner(WacomCommonPtr common, int fd)
{
int err;
SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
strlen(penpartner_setup_string)));
return (err == -1) ? !Success : Success;
}
static int serialResetProtocol4(WacomCommonPtr common, int fd)
{
int err;
SYSCALL(err = xf86WcmWrite(fd, WC_RESET, strlen(WC_RESET)));
if (xf86WcmWait(75)) return !Success;
SYSCALL(err = xf86WcmWrite(fd, setup_string, strlen(setup_string)));
if (err == -1) return !Success;
SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
strlen(penpartner_setup_string)));
return (err == -1) ? !Success : Success;
}
static int serialEnableTiltProtocol4(WacomCommonPtr common, int fd)
{
return Success;
}
static int serialEnableSuppressProtocol4(WacomCommonPtr common, int fd)
{
char buf[20];
int err;
sprintf(buf, "%s%d\r", WC_SUPPRESS, common->wcmSuppress);
SYSCALL(err = xf86WcmWrite(fd, buf, strlen(buf)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
return Success;
}
static int serialSetLinkSpeedIntuos(WacomCommonPtr common, int fd)
{
if ((common->wcmLinkSpeed == 38400) && (common->wcmVersion < 2.0F)) {
ErrorF("Wacom: 38400 speed not supported with this Intuos "
"firmware (%f)\n", common->wcmVersion);
ErrorF("Switching to 19200\n");
common->wcmLinkSpeed = 19200;
}
return serialSetLinkSpeedProtocol5(common,fd);
}
static int serialSetLinkSpeedProtocol5(WacomCommonPtr common, int fd)
{
int err;
char* speed_init_string;
DBG(1, ErrorF("Switching serial link to %d\n",
common->wcmLinkSpeed));
speed_init_string = (common->wcmLinkSpeed == 38400) ? WC_V_38400 : WC_V_19200;
SYSCALL(err = xf86WcmWrite(fd, speed_init_string, strlen(speed_init_string)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(75)) return !Success;
if (xf86WcmSetSerialSpeed(fd, common->wcmLinkSpeed) < 0) return !Success;
return Success;
}
static int serialStartTablet(WacomCommonPtr common, int fd)
{
int err;
SYSCALL(err = xf86WcmWrite(fd, WC_START, strlen(WC_START)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
return Success;
}
static void serialParseP4Common(WacomCommonPtr common,
const unsigned char* data, WacomDeviceState* last,
WacomDeviceState* ds)
{
int is_stylus = (data[0] & POINTER_BIT);
int cur_type = is_stylus ? ((ds->buttons & 4) ?
ERASER_ID : STYLUS_ID) : CURSOR_ID;
ds->proximity = (data[0] & PROXIMITY_BIT);
ds->x = (((data[0] & 0x3) << 14) + (data[1] << 7) + data[2]);
ds->y = (((data[3] & 0x3) << 14) + (data[4] << 7) + data[5]);
if (!last->proximity && ds->proximity) ds->device_type = cur_type;
else if (!ds->proximity) memset(ds,0,sizeof(*ds));
else if (is_stylus) {
if ((ds->device_type != cur_type) && (ds->device_type == ERASER_ID)) {
WacomDeviceState out = { 0 };
xf86WcmEvent(common,0,&out);
ds->device_type = cur_type;
}
}
DBG(8, ErrorF("serialParseP4Common %s\n",
ds->device_type == CURSOR_ID ? "CURSOR" :
ds->device_type == ERASER_ID ? "ERASER " :
ds->device_type == STYLUS_ID ? "STYLUS" : "NONE"));
if (HANDLE_TILT(common) && is_stylus) {
ds->tiltx = (data[7] & TILT_BITS);
ds->tilty = (data[8] & TILT_BITS);
if (data[7] & TILT_SIGN_BIT) ds->tiltx -= 64;
if (data[8] & TILT_SIGN_BIT) ds->tilty -= 64;
}
}
int xf86WcmSerialValidate(WacomCommonPtr common, const unsigned char* data)
{
int i, bad = 0;
for (i=0; i<common->wcmPktLength; ++i) {
if ( ((i==0) && !(data[i] & HEADER_BIT)) || ((i!=0) && (data[i] & HEADER_BIT))) {
bad = 1;
DBG(6, ErrorF("xf86WcmSerialValidate: bad magic at %d "
"v=%p l=%d\n", i, data, common->wcmPktLength));
if (i!=0 && (data[i] & HEADER_BIT)) return i;
}
}
if (bad) return common->wcmPktLength;
else return 0;
}
static WacomModel isdv4General =
{
"General ISDV4",
isdv4InitISDV4,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
isdv4Parse,
xf86WcmFilterCoord,
};
static Bool isdv4Detect(LocalDevicePtr local)
{
WacomDevicePtr priv = (WacomDevicePtr) local->private;
WacomCommonPtr common = priv->common;
return (common->wcmForceDevice == DEVICE_ISDV4) ? 1 : 0;
}
static Bool isdv4Init(LocalDevicePtr local)
{
int err;
WacomDevicePtr priv = (WacomDevicePtr)local->private;
WacomCommonPtr common = priv->common;
DBG(1, ErrorF("initializing ISDV4 tablet\n"));
DBG(1, ErrorF("resetting tablet\n"));
if (xf86WcmSetSerialSpeed(local->fd, 38400) < 0) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(250)) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(75)) return !Success;
if (xf86WcmSetSerialSpeed(local->fd, 19200) < 0) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(250)) return !Success;
SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
if (err == -1) {
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if (xf86WcmWait(75)) return !Success;
xf86WcmFlushTablet(local->fd);
DBG(2, ErrorF("not reading model -- Wacom TabletPC ISD V4\n"));
return xf86WcmInitTablet(common,&isdv4General,local->fd,"unknown",0.0);
}
static void isdv4InitISDV4(WacomCommonPtr common, int fd,
const char* id, float version)
{
DBG(2, ErrorF("initializing as ISDV4 model\n"));
common->wcmProtocolLevel = 0;
common->wcmMaxZ = 255;
common->wcmResolX = 2570;
common->wcmResolY = 2570;
common->wcmPktLength = 9;
if (common->wcmRotate==ROTATE_NONE) {
common->wcmMaxX = 21136;
common->wcmMaxY = 15900;
} else if (common->wcmRotate==ROTATE_CW || common->wcmRotate==ROTATE_CCW) {
common->wcmMaxX = 15900;
common->wcmMaxY = 21136;
}
}
static int isdv4Parse(WacomCommonPtr common, const unsigned char* data)
{
WacomDeviceState* last = &common->wcmChannel[0].valid.state;
WacomDeviceState* ds;
int n, cur_type, tmp_coord;
if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;
ds = &common->wcmChannel[0].work;
RESET_RELATIVE(*ds);
ds->proximity = (data[0] & 0x20);
ds->x = (((int)data[6] & 0x60) >> 5) | ((int)data[2] << 2) |
((int)data[1] << 9);
ds->y = (((int)data[6] & 0x18) >> 3) | ((int)data[4] << 2) |
((int)data[3] << 9);
if (common->wcmRotate == ROTATE_CW) {
tmp_coord = ds->x;
ds->x = ds->y;
ds->y = common->wcmMaxY - tmp_coord;
} else if (common->wcmRotate == ROTATE_CCW) {
tmp_coord = ds->y;
ds->y = ds->x;
ds->x = common->wcmMaxX - tmp_coord;
}
ds->pressure = ((data[6] & 0x01) << 7) | (data[5] & 0x7F);
ds->buttons = (data[0] & 0x01) ? 1 : 0 ;
ds->buttons |= (data[0] & 0x02) ? 0x04 : 0 ;
ds->buttons |= (data[0] & 0x04) ? 0x02 : 0 ;
cur_type = (data[0] & 0x04) ? ERASER_ID : STYLUS_ID;
if ( common->wcmNumDevices == 1 && cur_type == ERASER_ID ) cur_type = STYLUS_ID;
if (!last->proximity && ds->proximity) ds->device_type = cur_type;
else if (!ds->proximity) memset(ds,0,sizeof(*ds));
else {
if ((ds->device_type != cur_type) && (ds->device_type == ERASER_ID)) {
WacomDeviceState out = { 0 };
xf86WcmEvent(common,0,&out);
ds->device_type = cur_type;
}
}
DBG(8, ErrorF("isdv4Parse %s\n", ds->device_type == ERASER_ID ? "ERASER " :
ds->device_type == STYLUS_ID ? "STYLUS" : "NONE"));
xf86WcmEvent(common,0,ds);
return common->wcmPktLength;
}
static void filterNearestPoint(double x0, double y0, double x1, double y1,
double a, double b, double* x, double* y)
{
double vx, vy, wx, wy, d1, d2, c;
wx = a - x0; wy = b - y0;
vx = x1 - x0; vy = y1 - y0;
d1 = vx * wx + vy * wy;
if (d1 <= 0) {
*x = x0;
*y = y0;
} else {
d2 = vx * vx + vy * vy;
if (d1 >= d2) {
*x = x1;
*y = y1;
} else {
c = d1 / d2;
*x = x0 + c * vx;
*y = y0 + c * vy;
}
}
}
static int filterOnLine(double x0, double y0, double x1, double y1,
double a, double b)
{
double x, y, d;
filterNearestPoint(x0,y0,x1,y1,a,b,&x,&y);
d = (x-a)*(x-a) + (y-b)*(y-b);
return d < 0.00001;
}
static void filterLine(int* pCurve, int nMax, int x0, int y0, int x1, int y1)
{
int dx, dy, ax, ay, sx, sy, x, y, d;
if ((x0 < 0) || (y0 < 0) || (x1 < 0) || (y1 < 0) ||
(x0 > nMax) || (y0 > nMax) || (x1 > nMax) || (y1 > nMax))
return;
dx = x1 - x0; ax = abs(dx) * 2; sx = (dx>0) ? 1 : -1;
dy = y1 - y0; ay = abs(dy) * 2; sy = (dy>0) ? 1 : -1;
x = x0; y = y0;
if (ax > ay) {
d = ay - ax / 2;
while (1) {
pCurve[x] = y;
if (x == x1) break;
if (d >= 0) {
y += sy;
d -= ax;
}
x += sx;
d += ay;
}
} else {
d = ax - ay / 2;
while (1) {
pCurve[x] = y;
if (y == y1) break;
if (d >= 0) {
x += sx;
d -= ay;
}
y += sy;
d += ax;
}
}
}
static void filterCurveToLine(int* pCurve, int nMax, double x0, double y0,
double x1, double y1, double x2, double y2, double x3, double y3)
{
double x01,y01,x32,y32,xm,ym;
double c1,d1,c2,d2,e,f;
if (filterOnLine(x0,y0,x3,y3,x1,y1) && filterOnLine(x0,y0,x3,y3,x2,y2)) {
filterLine(pCurve,nMax,(int)(x0*nMax),(int)(y0*nMax),
(int)(x3*nMax),(int)(y3*nMax));
return;
}
x01 = (x0 + x1) / 2; y01 = (y0 + y1) / 2;
x32 = (x3 + x2) / 2; y32 = (y3 + y2) / 2;
xm = (x1 + x2) / 2; ym = (y1 + y2) / 2;
c1 = (x01 + xm) / 2; d1 = (y01 + ym) / 2;
c2 = (x32 + xm) / 2; d2 = (y32 + ym) / 2;
e = (c1 + c2) / 2; f = (d1 + d2) / 2;
filterCurveToLine(pCurve,nMax,x0,y0,x01,y01,c1,d1,e,f);
filterCurveToLine(pCurve,nMax,e,f,c2,d2,x32,y32,x3,y3);
}
static void filterIntuosCoord(int* coord, int* current, int tilt, int* state)
{
int ts;
int x0_pred;
int x0_pred1;
int x0, x1, x2, x3;
x0 = *current;
x1 = coord[0];
x2 = coord[1];
x3 = coord[2];
coord[0] = x0;
coord[1] = x1;
coord[2] = x2;
ts = tilt >= 0 ? 1 : -1;
if (*state == 0 || *state == 3) {
if (ts * (x0 - 2 * x1 - x2) > 12 && ts * (x0 - 3 * x2 - 2 * x3) > 12) {
*state = 1;
*current = x1;
} else if (*state == 0) {
x0_pred = 7 * x0 + 14 * x1 + 15 * x2 + 16;
x0_pred1 = 4 * x3;
if (x0_pred > x0_pred1) *current = ((CARD32)(x0_pred - x0_pred1)) >> 5;
else *current = 0;
} else {
*current = (x0 + 2 * x1 + x2 + 2) >> 2;
*state = 0;
}
} else if (*state == 1) {
x0_pred = 3 * x0 + 7 * x2 + 4;
x0_pred1 = 2 * x3;
if (x0_pred > x0_pred1)
*current = ((CARD32)(x0_pred - x0_pred1)) >> 3;
else
*current = 0;
*state = 2;
} else {
*current = x1;
*state = 3;
}
}
static void filterIntuosTilt(int* state, int* tilt)
{
int tx;
tx = *tilt + state[0] + state[1] + state[2];
state[2] = state[1];
state[1] = state[0];
state[0] = *tilt;
tx /= MAX_SAMPLES;
if (tx > 63) tx = 63;
else if (tx < -64) tx = -64;
*tilt = tx;
}
static void filterIntuosStylus(WacomFilterStatePtr state, WacomDeviceStatePtr ds)
{
if (!state->npoints) {
++state->npoints;
DBG(2,ErrorF("filterIntuosStylus: first sample NO_FILTER\n"));
state->x[0] = state->x[1] = state->x[2] = ds->x;
state->y[0] = state->y[1] = state->y[2] = ds->y;
state->tiltx[0] = state->tiltx[1] = state->tiltx[2] = ds->tiltx;
state->tilty[0] = state->tilty[1] = state->tilty[2] = ds->tilty;
return;
}
filterIntuosCoord(state->x, &ds->x, ds->tiltx, &state->statex);
filterIntuosCoord(state->y, &ds->y, ds->tilty, &state->statey);
filterIntuosTilt(state->tiltx, &ds->tiltx);
filterIntuosTilt(state->tilty, &ds->tilty);
}
static void xf86WcmSetPressureCurve(WacomDevicePtr pDev, int x0, int y0, int x1, int y1)
{
int i;
if ((x0 < 0) || (x0 > 100) || (y0 < 0) || (y0 > 100) ||
(x1 < 0) || (x1 > 100) || (y1 < 0) || (y1 > 100)) return;
xf86Msg(X_INFO, "xf86WcmSetPressureCurve: setting to %d,%d %d,%d\n",
x0, y0, x1, y1);
if (!pDev->pPressCurve) {
pDev->pPressCurve = (int*) xalloc(sizeof(int) * (FILTER_PRESSURE_RES + 1));
if (!pDev->pPressCurve) {
xf86Msg(X_ERROR, "xf86WcmSetPressureCurve: failed to "
"allocate memory for curve\n");
return;
}
}
for (i=0; i<=FILTER_PRESSURE_RES; ++i) pDev->pPressCurve[i] = i;
filterCurveToLine(pDev->pPressCurve, FILTER_PRESSURE_RES,
0.0, 0.0,
x0/100.0, y0/100.0,
x1/100.0, y1/100.0,
1.0, 1.0);
for (i=0; i<=FILTER_PRESSURE_RES; i+=128)
DBG(6, ErrorF("PRESSCURVE: %d=%d (%d)\n",i,pDev->pPressCurve[i],
pDev->pPressCurve[i] - i));
pDev->nPressCtrl[0] = x0;
pDev->nPressCtrl[1] = y0;
pDev->nPressCtrl[2] = x1;
pDev->nPressCtrl[3] = y1;
}
static int xf86WcmFilterCoord(WacomCommonPtr common, WacomChannelPtr pChannel,
WacomDeviceStatePtr ds)
{
WacomDeviceState* pLast;
int *x, *y;
int filter_x, filter_y;
x = pChannel->rawFilter.x;
y = pChannel->rawFilter.y;
if (!pChannel->rawFilter.npoints) {
++pChannel->rawFilter.npoints;
DBG(2,ErrorF("xf86WcmFilterCoord: first sample NO_FILTER\n"));
x[0] = x[1] = x[2] = ds->x;
y[0] = y[1] = y[2] = ds->y;
return 0;
}
pLast = &pChannel->valid.state;
filter_x = (ds->x + x[0] + x[1] + x[2])/4;
filter_y = (ds->y + y[0] + y[1] + y[2])/4;
x[2] = x[1];
y[2] = y[1];
x[1] = x[0];
y[1] = y[0];
x[0] = ds->x;
y[0] = ds->y;
if (abs(filter_x - pLast->x) > 4)
ds->x = filter_x;
else
ds->x = pLast->x;
if (abs(filter_y - pLast->y) > 4)
ds->y = filter_y;
else
ds->y = pLast->y;
return 0;
}
static int xf86WcmFilterIntuos(WacomCommonPtr common, WacomChannelPtr pChannel,
WacomDeviceStatePtr ds)
{
if (ds->device_type != CURSOR_ID)
filterIntuosStylus(&pChannel->rawFilter, ds);
else
xf86WcmFilterCoord(common, pChannel, ds);
return 0;
}
static Bool
xf86WcmDevConvert(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("xf86WcmDevConvert\n"));
if (first != 0 || num == 1)
return FALSE;
#ifdef PANORAMIX
if (!noPanoramiXExtension && (priv->flags & ABSOLUTE_FLAG) &&
priv->common->wcmGimp) {
int i, totalWidth, leftPadding = 0;
for (i = 0; i < priv->currentScreen; i++)
leftPadding += screenInfo.screens[i]->width;
for (totalWidth = leftPadding; i < priv->numScreen; i++)
totalWidth += screenInfo.screens[i]->width;
v0 -= (priv->bottomX - priv->topX) * leftPadding
/ (double)totalWidth + 0.5;
}
#endif
if (priv->twinview != TV_NONE && (priv->flags & ABSOLUTE_FLAG)) {
v0 -= priv->topX;
v1 -= priv->topY;
if (priv->twinview == TV_LEFT_RIGHT) {
if (v0 > priv->bottomX)
{
v0 -= priv->bottomX;
priv->currentScreen = 1;
if (priv->screen_no == 0) {
priv->currentScreen = 0;
}
} else {
priv->currentScreen = 0;
if (priv->screen_no == 1) {
priv->currentScreen = 1;
}
}
if (priv->currentScreen == 1) {
*x = priv->tvResolution[0] + priv->tvResolution[2]
* v0 / (priv->bottomX - priv->topX);
*y = v1 * priv->tvResolution[3] /
(priv->bottomY - priv->topY) + 0.5;
} else {
*x = priv->tvResolution[0] * v0 /
(priv->bottomX - priv->topX);
*y = v1 * priv->tvResolution[1] /
(priv->bottomY - priv->topY) + 0.5;
}
}
if (priv->twinview == TV_ABOVE_BELOW) {
if (v1 > priv->bottomY) {
v1 -= priv->bottomY;
priv->currentScreen = 1;
if (priv->screen_no == 0) {
priv->currentScreen = 0;
}
} else {
priv->currentScreen = 0;
if (priv->screen_no == 1) {
priv->currentScreen = 1;
}
}
if (priv->currentScreen == 1) {
*x = v0 * priv->tvResolution[2] /
(priv->bottomX - priv->topX) + 0.5;
*y = priv->tvResolution[1] + priv->tvResolution[3] * v1
/ (priv->bottomY - priv->topY);
} else {
*x = v0 * priv->tvResolution[0] /
(priv->bottomX - priv->topX) + 0.5;
*y = priv->tvResolution[1] * v1 /
(priv->bottomY - priv->topY);
}
}
} else {
*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));
return TRUE;
}
static Bool
xf86WcmDevReverseConvert(LocalDevicePtr local,
int x,
int y,
int *valuators)
{
WacomDevicePtr priv = (WacomDevicePtr) local->private;
valuators[0] = x / priv->factorX + 0.5;
valuators[1] = y / priv->factorY + 0.5;
#ifdef PANORAMIX
if (!noPanoramiXExtension && (priv->flags & ABSOLUTE_FLAG) &&
priv->common->wcmGimp) {
int i, totalWidth, leftPadding = 0;
for (i = 0; i < priv->currentScreen; i++)
leftPadding += screenInfo.screens[i]->width;
for (totalWidth = leftPadding; i < priv->numScreen; i++)
totalWidth += screenInfo.screens[i]->width;
valuators[0] += (priv->bottomX - priv->topX)
* leftPadding / (double)totalWidth + 0.5;
}
#endif
if (priv->twinview != TV_NONE && (priv->flags & ABSOLUTE_FLAG)) {
if (priv->twinview == TV_LEFT_RIGHT) {
if (x > priv->tvResolution[0]) {
x -= priv->tvResolution[0];
priv->currentScreen = 1;
if (priv->screen_no == 0) {
priv->currentScreen = 0;
}
} else {
priv->currentScreen = 0;
if (priv->screen_no == 1) {
priv->currentScreen = 1;
}
}
if (priv->currentScreen == 1) {
valuators[0] = x * (priv->bottomX - priv->topX)
/ priv->tvResolution[2] + priv->bottomX - priv->topX + 0.5;
valuators[1] = y * (priv->bottomY - priv->topY) /
priv->tvResolution[3] + 0.5;
} else {
valuators[0] = x * (priv->bottomX - priv->topX)
/ priv->tvResolution[0] + 0.5;
valuators[1] = y * (priv->bottomY - priv->topY) /
priv->tvResolution[1] + 0.5;
}
}
if (priv->twinview == TV_ABOVE_BELOW) {
if (y > priv->tvResolution[1]) {
y -= priv->tvResolution[1];
priv->currentScreen = 1;
if (priv->screen_no == 0) {
priv->currentScreen = 0;
}
} else {
priv->currentScreen = 0;
if (priv->screen_no == 1) {
priv->currentScreen = 1;
}
}
if (priv->currentScreen == 1) {
valuators[0] = x * (priv->bottomX - priv->topX) /
priv->tvResolution[2] + 0.5;
valuators[1] = y *(priv->bottomY - priv->topY) /
priv->tvResolution[3] + priv->bottomY - priv->topY + 0.5;
} else {
valuators[0] = x * (priv->bottomX - priv->topX) /
priv->tvResolution[0] + 0.5;
valuators[1] = y *(priv->bottomY - priv->topY) /
priv->tvResolution[1] + 0.5;
}
}
valuators[0] += priv->topX;
valuators[1] += priv->topY;
}
DBG(6, ErrorF("Wacom converted x=%d y=%d to v0=%d v1=%d\n", x, y,
valuators[0], valuators[1]));
return TRUE;
}
static void
xf86WcmSetScreen(LocalDevicePtr local,
int *v0,
int *v1)
{
WacomDevicePtr priv = (WacomDevicePtr) local->private;
int screenToSet = miPointerCurrentScreen()->myNum;
int i;
int x, y;
int totalWidth = 0, maxHeight = 0, leftPadding = 0;
double sizeX = priv->bottomX - priv->topX;
double sizeY = priv->bottomY - priv->topY;
if (screenInfo.numScreens == 1) {
priv->factorX = screenInfo.screens[0]->width / sizeX;
priv->factorY = screenInfo.screens[0]->height / sizeY;
return;
}
if (!(local->flags & (XI86_ALWAYS_CORE | XI86_CORE_POINTER))) return;
if (!(priv->flags & ABSOLUTE_FLAG)) {
screenToSet = miPointerCurrentScreen()->myNum;
priv->factorX = screenInfo.screens[screenToSet]->width / sizeX;
priv->factorY = screenInfo.screens[screenToSet]->height / sizeY;
priv->currentScreen = screenToSet;
return;
}
for (i = 0; i < priv->numScreen; i++) {
totalWidth += screenInfo.screens[i]->width;
if (maxHeight < screenInfo.screens[i]->height)
maxHeight = screenInfo.screens[i]->height;
}
if (priv->screen_no == -1) {
for (i = 0; i < priv->numScreen; i++) {
if (*v0 * totalWidth <= (leftPadding +
screenInfo.screens[i]->width) * sizeX) {
screenToSet = i;
break;
}
leftPadding += screenInfo.screens[i]->width;
}
}
#ifdef PANORAMIX
else if (!noPanoramiXExtension && priv->common->wcmGimp) {
screenToSet = priv->screen_no;
for (i = 0; i < screenToSet; i++)
leftPadding += screenInfo.screens[i]->width;
*v0 = (sizeX * leftPadding + *v0 * screenInfo.screens[screenToSet]->width) /
(double)totalWidth + 0.5;
*v1 = *v1 * screenInfo.screens[screenToSet]->height / (double)maxHeight + 0.5;
}
if (!noPanoramiXExtension && priv->common->wcmGimp) {
priv->factorX = totalWidth/sizeX;
priv->factorY = maxHeight/sizeY;
x = (*v0 - sizeX * leftPadding / totalWidth) * priv->factorX + 0.5;
y = *v1 * priv->factorY + 0.5;
if (x >= screenInfo.screens[screenToSet]->width)
x = screenInfo.screens[screenToSet]->width - 1;
if (y >= screenInfo.screens[screenToSet]->height)
y = screenInfo.screens[screenToSet]->height - 1;
}
else
#endif
{
if (priv->screen_no == -1)
*v0 = (*v0 * totalWidth - sizeX * leftPadding)
/ screenInfo.screens[screenToSet]->width;
else
screenToSet = priv->screen_no;
priv->factorX = screenInfo.screens[screenToSet]->width / sizeX;
priv->factorY = screenInfo.screens[screenToSet]->height / sizeY;
x = *v0 * priv->factorX + 0.5;
y = *v1 * priv->factorY + 0.5;
}
xf86XInputSetScreen(local, screenToSet, x, y);
DBG(10, ErrorF("xf86WcmSetScreen current=%d ToSet=%d\n",
priv->currentScreen, screenToSet));
priv->currentScreen = screenToSet;
}
static void
xf86WcmSendButtons(LocalDevicePtr local,
int buttons,
int rx,
int ry,
int rz,
int rtx,
int rty,
int rrot,
int rth,
int rwheel)
{
int button, newb;
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, for %s\n",
button, (buttons & mask) != 0, local->name));
newb = button;
if (priv->button[button-1] != button)
newb = priv->button[button-1];
if (newb == 17)
{
newb = 1;
if (buttons & mask)
{
if (IsCursor(priv))
xf86PostButtonEvent(local->dev,
(priv->flags & ABSOLUTE_FLAG), newb, 1,
0, 6, rx, ry, rz, rrot, rth, rwheel);
else
xf86PostButtonEvent(local->dev,
(priv->flags & ABSOLUTE_FLAG), newb, 1,
0, 6, rx, ry, rz, rtx, rty, rwheel);
if (IsCursor(priv))
xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG),
newb, 0, 0, 6, rx, ry, rz, rrot, rth, rwheel);
else
xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG),
newb, 0, 0, 6, rx, ry, rz, rtx, rty, rwheel);
}
}
if (newb <= 17)
{
if (IsCursor(priv))
xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG),
newb, (buttons & mask) != 0,
0, 6, rx, ry, rz, rrot, rth, rwheel);
else
xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG),
newb, (buttons & mask) != 0,
0, 6, rx, ry, rz, rtx, rty, rwheel);
}
}
}
}
static void
xf86WcmSendEvents(LocalDevicePtr local,
const WacomDeviceState *ds)
{
int type = ds->device_type;
int is_button = !!(ds->buttons);
int is_proximity = ds->proximity;
int x = ds->x;
int y = ds->y;
int z = ds->pressure;
int buttons = ds->buttons;
int tx = ds->tiltx;
int ty = ds->tilty;
int rot = ds->rotation;
int throttle = ds->throttle;
int wheel = ds->abswheel;
WacomDevicePtr priv = (WacomDevicePtr) local->private;
WacomCommonPtr common = priv->common;
int rx, ry, rz, rtx, rty, rrot, rth, rw;
int is_core_pointer, is_absolute;
int aboveBelowSwitch = (priv->twinview == TV_ABOVE_BELOW) ?
((y < priv->topY) ? -1 : ((priv->bottomY < y) ? 1 : 0)) : 0;
int leftRightSwitch = (priv->twinview == TV_LEFT_RIGHT) ?
((x < priv->topX) ? -1 : ((priv->bottomX < x) ? 1 : 0)) : 0;
DBG(7, ErrorF("[%s] prox=%s\tx=%d\ty=%d\tz=%d\tbutton=%s\tbuttons=%d\ttx=%d ty=%d\twl=%d rot=%d th=%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, rot, throttle));
is_absolute = (priv->flags & ABSOLUTE_FLAG);
is_core_pointer = xf86IsCorePointer(local->dev);
if ( is_proximity || x || y || z || buttons || tx || ty || wheel )
{
switch ( leftRightSwitch )
{
case -1:
priv->doffsetX = 0;
break;
case 1:
priv->doffsetX = priv->bottomX - priv->topX;
break;
}
switch ( aboveBelowSwitch )
{
case -1:
priv->doffsetY = 0;
break;
case 1:
priv->doffsetY = priv->bottomY - priv->topY;
break;
}
}
x += priv->doffsetX;
y += priv->doffsetY;
if (is_absolute) {
if (priv->twinview == TV_NONE)
{
rx = x > priv->bottomX ? priv->bottomX - priv->topX :
x < priv->topX ? 0 : x - priv->topX;
ry = y > priv->bottomY ? priv->bottomY - priv->topY :
y < priv->topY ? 0 : y - priv->topY;
}
else
{
rx = x;
ry = y;
}
rz = z;
rtx = tx;
rty = ty;
rrot = rot;
rth = throttle;
rw = wheel;
} else {
if (priv->oldProximity)
{
rx = (x - priv->oldX) * priv->factorY / priv->factorX;
ry = y - priv->oldY;
}
else
{
rx = 0;
ry = 0;
}
if (priv->speed != DEFAULT_SPEED ) {
int no_jitter = priv->speed * 3;
double param = priv->speed;
double relacc = (MAX_ACCEL-priv->accel)*(MAX_ACCEL-priv->accel);
if (ABS(rx) > no_jitter)
{
param += priv->accel > 0 ? rx/relacc : 0;
if (param > 20.00)
rx *= param;
}
if (ABS(ry) > no_jitter)
{
param += priv->accel > 0 ? ry/relacc : 0;
if (param > 20.00)
ry *= param;
}
}
rz = z - priv->oldZ;
rtx = tx - priv->oldTiltX;
rty = ty - priv->oldTiltY;
rrot = rot - priv->oldRot;
rth = throttle - priv->oldThrottle;
rw = wheel - priv->oldWheel;
}
xf86WcmSetScreen(local, &rx, &ry);
if (is_proximity) {
if (!priv->oldProximity) {
if (IsCursor(priv))
xf86PostProximityEvent(local->dev, 1, 0, 6, rx, ry, rz, rrot, rth, rw);
else
xf86PostProximityEvent(local->dev, 1, 0, 6, rx, ry, rz, rtx, rty, rw);
}
if(!(priv->flags & BUTTONS_ONLY_FLAG)) {
if (IsCursor(priv))
xf86PostMotionEvent(local->dev, is_absolute, 0, 6, rx, ry, rz, rrot, rth, rw);
else
xf86PostMotionEvent(local->dev, is_absolute, 0, 6, rx, ry, rz, rtx, rty, rw);
}
if ( ds->relwheel )
{
int fakeButton = ds->relwheel > 0 ? 5 : 4;
int i;
for (i=0; i<abs(ds->relwheel); i++)
{
xf86PostButtonEvent(local->dev, is_absolute, fakeButton,
1, 0, 6, rx, ry, rz, rrot, rth, rw);
xf86PostButtonEvent(local->dev, is_absolute, fakeButton,
0, 0, 6, rx, ry, rz, rrot, rth, rw);
}
}
if (priv->oldButtons != buttons) {
xf86WcmSendButtons (local, buttons, rx, ry, rz, rtx, rty, rrot, rth, rw);
}
}
else {
if (priv->oldButtons) {
buttons = 0;
xf86WcmSendButtons (local, buttons, rx, ry, rz, rtx, rty, rrot, rth, rw);
}
if (!is_core_pointer) {
if (common->wcmProtocolLevel == 4 && buttons) {
int macro = z / 2;
DBG(6, ErrorF("macro=%d buttons=%d wacom_map[%d]=%lx\n",
macro, buttons, macro, (unsigned long)wacom_map[macro]));
if (IsCursor(priv))
xf86PostKeyEvent(local->dev,macro+7,1,is_absolute,
0,6,0,0,buttons,rrot,rth,rw);
else
xf86PostKeyEvent(local->dev,macro+7,1,is_absolute,
0,6,0,0,buttons,rtx,rty,rw);
if (IsCursor(priv))
xf86PostKeyEvent(local->dev,macro+7,0,is_absolute,
0,6,0,0,buttons,rrot,rth,rw);
else
xf86PostKeyEvent(local->dev,macro+7,0,is_absolute,
0,6,0,0,buttons,rtx,rty,rw);
}
}
if (priv->oldProximity)
{
if (IsCursor(priv))
xf86PostProximityEvent(local->dev, 0, 0, 6,
rx, ry, rz, rrot, rth, rw);
else
xf86PostProximityEvent(local->dev,0, 0, 6,
rx, ry, rz, rtx, rty, rw);
}
}
priv->oldProximity = is_proximity;
priv->oldButtons = buttons;
priv->oldWheel = wheel;
priv->oldX = x;
priv->oldY = y;
priv->oldZ = z;
priv->oldTiltX = tx;
priv->oldTiltY = ty;
priv->oldRot = rot;
priv->oldThrottle = throttle;
}
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 (ABS(ds1->throttle - ds2->throttle) > suppress) return 0;
if ((1800 + ds1->rotation - ds2->rotation) % 1800 > suppress &&
(1800 + ds2->rotation - ds1->rotation) % 1800 > suppress) return 0;
if (ABS(ds1->abswheel - ds2->abswheel) > suppress ||
(ds2->relwheel) != 0) return 0;
return 1;
}
static void
xf86WcmDevReadInput(LocalDevicePtr local)
{
int loop=0;
# define MAX_READ_LOOPS 10
WacomCommonPtr common = ((WacomDevicePtr)local->private)->common;
for (loop=0; loop < MAX_READ_LOOPS; ++loop)
{
common->wcmDevCls->Read(local);
if (!xf86WcmReady(local->fd)) break;
}
if (loop >= MAX_READ_LOOPS) {
DBG(1,ErrorF("xf86WcmDevReadInput: Can't keep up!!!\n"));
}
else {
if (loop > 1) DBG(10,ErrorF("xf86WcmDevReadInput: Read (%d)\n",loop));
}
}
void xf86WcmReadPacket(LocalDevicePtr local)
{
WacomCommonPtr common = ((WacomDevicePtr)(local->private))->common;
int len, pos, cnt, remaining;
if (!common->wcmModel) return;
remaining = sizeof(common->buffer) - common->bufpos;
DBG(7, ErrorF("xf86WcmDevReadPacket: device=%s fd=%d "
"pos=%d remaining=%d\n",
common->wcmDevice, local->fd,
common->bufpos, remaining));
SYSCALL(len = xf86WcmRead(local->fd,
common->buffer + common->bufpos, remaining));
if (len <= 0)
{
ErrorF("Error reading wacom device : %s\n", strerror(errno));
return;
}
common->bufpos += len;
DBG(10, ErrorF("xf86WcmReadPacket buffer has %d bytes\n", common->bufpos));
pos = 0;
while ((common->bufpos - pos) >= common->wcmPktLength)
{
cnt = common->wcmModel->Parse(common, common->buffer + pos);
if (cnt <= 0)
{
DBG(1,ErrorF("Misbehaving parser returned %d\n",cnt));
break;
}
pos += cnt;
}
if (pos)
{
if (pos < common->bufpos)
{
DBG(7, ErrorF("MOVE %d bytes\n", common->bufpos - pos));
memmove(common->buffer,common->buffer+pos, common->bufpos-pos);
common->bufpos -= pos;
}
else common->bufpos = 0;
}
}
static void
xf86WcmDevControlProc(DeviceIntPtr device,PtrCtrl *ctrl)
{
DBG(2, ErrorF("xf86WcmDevControlProc\n"));
}
static Bool xf86WcmInitDevice(LocalDevicePtr local)
{
WacomCommonPtr common = ((WacomDevicePtr)local->private)->common;
int loop;
DBG(1,ErrorF("xf86WcmInitDevice: "));
if (common->wcmInitialized)
{
DBG(1,ErrorF("already initialized\n"));
return TRUE;
}
DBG(1,ErrorF("initializing\n"));
if ((xf86WcmOpen(local) != Success) || (local->fd < 0))
{
DBG(1,ErrorF("Failed to open device (fd=%d)\n",local->fd));
if (local->fd >= 0)
{
DBG(1,ErrorF("Closing device\n"));
SYSCALL(xf86WcmClose(local->fd));
}
local->fd = -1;
return FALSE;
}
common->wcmInitialized = TRUE;
DBG(1,ErrorF("Marking all devices open\n"));
for (loop=0; loop<common->wcmNumDevices; loop++)
common->wcmDevices[loop]->fd = local->fd;
return TRUE;
}
static void xf86WcmDevClose(LocalDevicePtr local)
{
WacomDevicePtr priv = (WacomDevicePtr)local->private;
WacomCommonPtr common = priv->common;
int loop, 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)
{
DBG(1,ErrorF("Closing device; uninitializing.\n"));
SYSCALL(xf86WcmClose(local->fd));
common->wcmInitialized = FALSE;
}
local->fd = -1;
}
int xf86WcmWait(int t)
{
int err = xf86WaitForInput(-1, ((t) * 1000));
if (err != -1) return Success;
ErrorF("Wacom select error : %s\n", strerror(errno));
return err;
}
int xf86WcmReady(int fd)
{
int n = xf86WaitForInput(fd, 0);
if (n >= 0) return n ? 1 : 0;
ErrorF("Wacom select error : %s\n", strerror(errno));
return 0;
}
static Bool
xf86WcmOpen(LocalDevicePtr local)
{
WacomDevicePtr priv = (WacomDevicePtr)local->private;
WacomCommonPtr common = priv->common;
WacomDeviceClass** ppDevCls;
DBG(1, ErrorF("opening %s\n", common->wcmDevice));
local->fd = xf86WcmOpenTablet(local);
if (local->fd < 0) {
ErrorF("Error opening %s : %s\n", common->wcmDevice, strerror(errno));
return !Success;
}
for (ppDevCls=wcmDeviceClasses; *ppDevCls!=NULL; ++ppDevCls)
{
if ((*ppDevCls)->Detect(local))
{
common->wcmDevCls = *ppDevCls;
break;
}
}
return common->wcmDevCls->Init(local);
}
static void resetSampleCounter(const WacomChannelPtr pChannel)
{
if (!pChannel->valid.state.proximity)
{
pChannel->nSamples = 0;
pChannel->rawFilter.npoints = 0;
pChannel->rawFilter.statex = 0;
pChannel->rawFilter.statey = 0;
}
}
static void transPressureCurve(WacomDevicePtr pDev, WacomDeviceStatePtr pState)
{
if (pDev->pPressCurve)
{
int p = pState->pressure;
p = (p < 0) ? 0 : (p > pDev->common->wcmMaxZ) ? pDev->common->wcmMaxZ : p;
p = (p * FILTER_PRESSURE_RES) / pDev->common->wcmMaxZ;
p = pDev->pPressCurve[p];
pState->pressure = (p * pDev->common->wcmMaxZ) / FILTER_PRESSURE_RES;
}
}
static void commonDispatchDevice(WacomCommonPtr common,
const WacomChannelPtr pChannel)
{
int id, idx;
WacomDevicePtr priv;
LocalDevicePtr pDev = NULL;
LocalDevicePtr pLastDev = pChannel->pDev;
WacomDeviceState* ds = &pChannel->valid.states[0];
WacomDeviceState* pLast = &pChannel->valid.states[1];
DBG(10, ErrorF("commonDispatchEvents\n"));
for (idx=0; idx<common->wcmNumDevices; idx++)
{
priv = common->wcmDevices[idx]->private;
id = DEVICE_ID(priv->flags);
if (id == ds->device_type &&
((!priv->serial) || (ds->serial_num == priv->serial)))
{
if ((priv->topX <= ds->x && priv->bottomX > ds->x &&
priv->topY <= ds->y && priv->bottomY > ds->y))
{
DBG(11, ErrorF("tool id=%d for %s\n",
id, common->wcmDevices[idx]->name));
pDev = common->wcmDevices[idx];
break;
}
else if (priv->oldProximity)
{
pDev = common->wcmDevices[idx];
}
}
}
DBG(11, ErrorF("commonDispatchEvents: %p %p\n", (void *)pDev, (void *)pLastDev));
if (pLastDev && (pLastDev != pDev) && (pLast->serial_num == ds->serial_num))
{
pLast->proximity = 0;
xf86WcmSendEvents(pLastDev, pLast);
}
if (pDev)
{
WacomDeviceState filtered = pChannel->valid.state;
WacomDevicePtr priv = pDev->private;
transPressureCurve(priv,&filtered);
#if 0
int sampleTime, ticks;
sampleTime = GetTimeInMillis();
ticks = ThrottleToRate(ds->throttle);
if (!ticks)
{
priv->throttleLimit = -1;
}
else if ((priv->throttleStart > sampleTime) ||
(priv->throttleLimit == -1))
{
priv->throttleStart = sampleTime;
priv->throttleLimit = sampleTime + ticks;
}
else if (priv->throttleLimit < sampleTime)
{
DBG(6, ErrorF("LIMIT REACHED: s=%d l=%d n=%d v=%d "
"N=%d\n", priv->throttleStart,
priv->throttleLimit, sampleTime,
ds->throttle, sampleTime + ticks));
ds->relwheel = (ds->throttle > 0) ? 1 :
(ds->throttle < 0) ? -1 : 0;
priv->throttleStart = sampleTime;
priv->throttleLimit = sampleTime + ticks;
}
else
priv->throttleLimit = priv->throttleStart + ticks;
#endif
if (ds->distance > 112 && !(priv->flags & ABSOLUTE_FLAG))
{
ds->proximity = 0;
filtered.proximity = 0;
}
xf86WcmSendEvents(pDev, &filtered);
}
else
{
DBG(11, ErrorF("no device matches with id=%d, serial=%d\n",
ds->device_type, ds->serial_num));
}
pChannel->pDev = pDev;
}
void xf86WcmEvent(WacomCommonPtr common, unsigned int channel,
const WacomDeviceState* pState)
{
WacomDeviceState* pLast;
WacomDeviceState ds;
WacomChannelPtr pChannel;
if (channel >= MAX_CHANNELS)
return;
pChannel = common->wcmChannel + channel;
pLast = &pChannel->valid.state;
ds = *pState;
ds.sample = GetTimeInMillis();
DBG(10, ErrorF("xf86WcmEvent: c=%d i=%d t=%d s=0x%X x=%d y=%d b=0x%X "
"p=%d rz=%d tx=%d ty=%d aw=%d rw=%d t=%d df=%d px=%d st=%d\n",
channel,
ds.device_id,
ds.device_type,
ds.serial_num,
ds.x, ds.y, ds.buttons,
ds.pressure, ds.rotation, ds.tiltx,
ds.tilty, ds.abswheel, ds.relwheel, ds.throttle,
ds.discard_first, ds.proximity, ds.sample));
if (RAW_FILTERING(common) && common->wcmModel->FilterRaw)
{
if (common->wcmModel->FilterRaw(common,pChannel,&ds))
{
DBG(10, ErrorF("Raw filtering discarded data.\n"));
resetSampleCounter(pChannel);
return;
}
}
if (xf86WcmSuppress(common->wcmSuppress, pLast, &ds))
{
DBG(10, ErrorF("Suppressing data according to filter\n"));
if (ABS(ds.throttle) < common->wcmSuppress)
{
resetSampleCounter(pChannel);
return;
}
ds = *pLast;
RESET_RELATIVE(ds);
}
memmove(pChannel->valid.states + 1, pChannel->valid.states,
sizeof(WacomDeviceState) * (MAX_SAMPLES - 1));
pChannel->valid.state = ds;
if (pChannel->nSamples < 4) ++pChannel->nSamples;
commonDispatchDevice(common,pChannel);
resetSampleCounter(pChannel);
}
int xf86WcmInitTablet(WacomCommonPtr common, WacomModelPtr model,
int fd, const char* id, float version)
{
model->Initialize(common,fd,id,version);
if (model->GetResolution) model->GetResolution(common,fd);
if (model->GetRanges && (model->GetRanges(common,fd) != Success))
return !Success;
if (common->wcmThreshold <= 0)
{
common->wcmThreshold = common->wcmMaxZ * 3 / 50;
ErrorF("%s Wacom using pressure threshold of %d for button 1\n",
XCONFIG_PROBED, common->wcmThreshold);
}
if (model->Reset && (model->Reset(common,fd) != Success))
{
ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
return !Success;
}
if ((common->wcmFlags & TILT_REQUEST_FLAG) && model->EnableTilt)
if (model->EnableTilt(common,fd) != Success) return !Success;
if ((common->wcmSuppress != 0) && model->EnableSuppress)
if (model->EnableSuppress(common,fd) != Success) return !Success;
if (common->wcmLinkSpeed != 9600) {
if (model->SetLinkSpeed) {
if (model->SetLinkSpeed(common,fd) != Success) return !Success;
else
ErrorF("Tablet does not support setting link "
"speed, or not yet implemented\n");
}
}
if (xf86Verbose)
ErrorF("%s Wacom %s tablet speed=%d maxX=%d maxY=%d maxZ=%d "
"resX=%d resY=%d suppress=%d tilt=%s\n",
XCONFIG_PROBED,
model->name, common->wcmLinkSpeed,
common->wcmMaxX, common->wcmMaxY, common->wcmMaxZ,
common->wcmResolX, common->wcmResolY,
common->wcmSuppress,
HANDLE_TILT(common) ? "enabled" : "disabled");
if (model->Start && (model->Start(common,fd) != Success)) return !Success;
common->wcmModel = model;
return Success;
}
static int
xf86WcmDevOpen(DeviceIntPtr pWcm)
{
LocalDevicePtr local = (LocalDevicePtr)pWcm->public.devicePrivate;
WacomDevicePtr priv = (WacomDevicePtr)PRIVATE(pWcm);
WacomCommonPtr common = priv->common;
double screenRatio, tabletRatio;
int totalWidth = 0, maxHeight = 0;
if (local->fd < 0) {
if (!xf86WcmInitDevice(local) || (local->fd < 0))
{
DBG(1,ErrorF("Failed to initialize device\n"));
return FALSE;
}
}
if (priv->factorX == 0.0) {
if (priv->twinview != TV_NONE && priv->bottomX == 0 &&
priv->bottomY == 0 && priv->topX == 0 && priv->topY == 0)
{
if (IsCursor(priv))
{
priv->topX = 80;
priv->topY = 80;
}
else
{
priv->topX = 50;
priv->topY = 50;
}
priv->bottomX = common->wcmMaxX - priv->topX;
priv->bottomY = common->wcmMaxY - priv->topY;
}
if (priv->bottomX == 0) priv->bottomX = common->wcmMaxX;
if (priv->bottomY == 0) priv->bottomY = common->wcmMaxY;
if (priv->topX > common->wcmMaxX) {
ErrorF("Wacom invalid TopX (%d) reseting to 0\n", priv->topX);
priv->topX = 0;
}
if (priv->topY > common->wcmMaxY) {
ErrorF("Wacom invalid TopY (%d) reseting to 0\n", priv->topY);
priv->topY = 0;
}
if (priv->bottomX < priv->topX) {
ErrorF("Wacom invalid BottomX (%d) reseting to %d\n",
priv->bottomX, common->wcmMaxX);
priv->bottomX = common->wcmMaxX;
}
if (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 >= priv->numScreen ||
priv->screen_no < 0)) {
if (priv->twinview == TV_NONE || priv->screen_no != 1)
{
ErrorF("%s: invalid screen number %d, resetting to 0\n",
local->name, priv->screen_no);
priv->screen_no = 0;
}
}
if (priv->screen_no != -1) {
priv->currentScreen = priv->screen_no;
if (priv->twinview == TV_NONE)
{
totalWidth = screenInfo.screens[priv->currentScreen]->width;
maxHeight = screenInfo.screens[priv->currentScreen]->height;
}
else
{
totalWidth = priv->tvResolution[2*priv->currentScreen];
maxHeight = priv->tvResolution[2*priv->currentScreen+1];
}
}
else
{
int i;
for (i = 0; i < priv->numScreen; i++)
{
totalWidth += screenInfo.screens[i]->width;
if (maxHeight < screenInfo.screens[i]->height)
maxHeight=screenInfo.screens[i]->height;
}
}
if (priv->flags & KEEP_SHAPE_FLAG) {
screenRatio = (double)totalWidth / (double)maxHeight;
tabletRatio = ((double) (common->wcmMaxX - priv->topX))
/ (common->wcmMaxY - priv->topY);
DBG(2, ErrorF("screenRatio = %.3g, tabletRatio = %.3g\n",
screenRatio, tabletRatio));
if (screenRatio > tabletRatio) {
priv->bottomX = common->wcmMaxX;
priv->bottomY = (common->wcmMaxY - priv->topY) *
tabletRatio / screenRatio + priv->topY;
} else {
priv->bottomX = (common->wcmMaxX - priv->topX) *
screenRatio / tabletRatio + priv->topX;
priv->bottomY = common->wcmMaxY;
}
}
if (priv->numScreen == 1)
{
priv->factorX = totalWidth / (double)(priv->bottomX - priv->topX);
priv->factorY = maxHeight / (double)(priv->bottomY - priv->topY);
DBG(2, ErrorF("X factor = %.3g, Y factor = %.3g\n",
priv->factorX, priv->factorY));
}
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);
}
InitValuatorAxisStruct(pWcm, 0, 0,
((priv->bottomX - priv->topX) * priv->dscaleX),
mils(common->wcmResolX),
0, mils(common->wcmResolX));
InitValuatorAxisStruct(pWcm, 1, 0,
((priv->bottomY - priv->topY) * priv->dscaleY),
mils(common->wcmResolY),
0, mils(common->wcmResolY));
InitValuatorAxisStruct(pWcm, 2, 0, common->wcmMaxZ, 1, 1, 1);
if (IsCursor(priv))
{
InitValuatorAxisStruct(pWcm, 3, -900, 899, 1, 1, 1);
InitValuatorAxisStruct(pWcm, 4, -1023, 1023, 1, 1, 1);
}
else
{
InitValuatorAxisStruct(pWcm, 3, -64, 63, 1, 1, 1);
InitValuatorAxisStruct(pWcm, 4, -64, 63, 1, 1, 1);
}
InitValuatorAxisStruct(pWcm, 5, 0, 1023, 1, 1, 1);
return (local->fd != -1);
}
static int
xf86WcmDevProc(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=%p priv=%p type=%s flags=%d what=%d\n",
(void *)pWcm, (void *)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=%p what=INIT\n", (void *)pWcm));
nbaxes = 6;
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,
xf86WcmDevControlProc) == 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 {
xf86MotionHistoryAllocate(local);
}
if (!xf86WcmDevOpen(pWcm))
{
DBG(1, ErrorF("xf86WcmProc try to open pWcm=%p again\n", (void *)pWcm));
if (!xf86WcmDevOpen(pWcm)) {
DBG(1, ErrorF("xf86WcmProc pWcm=%p what=INIT FALSE\n", (void *)pWcm));
return !Success;
}
}
break;
case DEVICE_ON:
DBG(1, ErrorF("xf86WcmProc pWcm=%p what=ON\n", (void *)pWcm));
if ((local->fd < 0) && (!xf86WcmDevOpen(pWcm))) {
pWcm->inited = FALSE;
return !Success;
}
xf86AddEnabledDevice(local);
pWcm->public.on = TRUE;
break;
case DEVICE_OFF:
case DEVICE_CLOSE:
DBG(1, ErrorF("xf86WcmProc pWcm=%p what=%s\n", (void *)pWcm,
(what == DEVICE_CLOSE) ? "CLOSE" : "OFF"));
if (local->fd >= 0) {
xf86RemoveEnabledDevice(local);
xf86WcmDevClose(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=%p priv=%p\n",
what, (void *)pWcm, (void *)priv));
return Success;
}
static int xf86WcmSetParam(LocalDevicePtr local, int param, int value)
{
WacomDevicePtr priv = (WacomDevicePtr)local->private;
char st[32];
switch (param) {
case XWACOM_PARAM_TOPX:
xf86ReplaceIntOption(local->options, "TopX", value);
priv->topX = xf86SetIntOption(local->options, "TopX", 0);
break;
case XWACOM_PARAM_TOPY:
xf86ReplaceIntOption(local->options, "TopY", value);
priv->topY = xf86SetIntOption(local->options, "TopY", 0);
break;
case XWACOM_PARAM_BOTTOMX:
xf86ReplaceIntOption(local->options, "BottomX", value);
priv->bottomX = xf86SetIntOption(local->options, "BottomX", 0);
break;
case XWACOM_PARAM_BOTTOMY:
xf86ReplaceIntOption(local->options, "BottomY", value);
priv->bottomY = xf86SetIntOption(local->options, "BottomY", 0);
break;
case XWACOM_PARAM_BUTTON1:
if ((value < 0) || (value > 18)) return BadValue;
xf86ReplaceIntOption(local->options,"Button1",value);
priv->button[0] = xf86SetIntOption(local->options,"Button1",1);
break;
case XWACOM_PARAM_BUTTON2:
if ((value < 0) || (value > 18)) return BadValue;
xf86ReplaceIntOption(local->options, "Button2", value);
priv->button[1] = xf86SetIntOption(local->options,"Button2",2);
break;
case XWACOM_PARAM_BUTTON3:
if ((value < 0) || (value > 18)) return BadValue;
xf86ReplaceIntOption(local->options, "Button3", value);
priv->button[2] = xf86SetIntOption(local->options,"Button3",3);
break;
case XWACOM_PARAM_BUTTON4:
if ((value < 0) || (value > 18)) return BadValue;
xf86ReplaceIntOption(local->options, "Button4", value);
priv->button[3] = xf86SetIntOption(local->options,"Button4",4);
break;
case XWACOM_PARAM_BUTTON5:
if ((value < 0) || (value > 18)) return BadValue;
xf86ReplaceIntOption(local->options, "Button5", value);
priv->button[4] = xf86SetIntOption(local->options,"Button5",5);
break;
case XWACOM_PARAM_DEBUGLEVEL:
if ((value < 0) || (value > 100)) return BadValue;
xf86ReplaceIntOption(local->options, "DebugLevel", value);
gWacomModule.debugLevel = value;
break;
case XWACOM_PARAM_RAWFILTER:
if ((value < 0) || (value > 1)) return BadValue;
xf86ReplaceIntOption(local->options, "RawFilter", value);
if (value) priv->common->wcmFlags |= RAW_FILTERING_FLAG;
else priv->common->wcmFlags &= ~(RAW_FILTERING_FLAG);
break;
case XWACOM_PARAM_PRESSCURVE: {
char chBuf[64];
int x0 = (value >> 24) & 0xFF;
int y0 = (value >> 16) & 0xFF;
int x1 = (value >> 8) & 0xFF;
int y1 = value & 0xFF;
if ((x0 > 100) || (y0 > 100) || (x1 > 100) || (y1 > 100))
return BadValue;
snprintf(chBuf,sizeof(chBuf),"%d %d %d %d",x0,y0,x1,y1);
xf86ReplaceStrOption(local->options, "PressCurve",chBuf);
xf86WcmSetPressureCurve(priv,x0,y0,x1,y1);
break;
}
case XWACOM_PARAM_MODE:
if ((value < 0) || (value > 1)) return BadValue;
if (value) {
priv->flags |= ABSOLUTE_FLAG;
xf86ReplaceStrOption(local->options, "Mode", "Absolute");
} else {
priv->flags &= ~ABSOLUTE_FLAG;
xf86ReplaceStrOption(local->options, "Mode", "Relative");
}
break;
case XWACOM_PARAM_SPEEDLEVEL:
if ((value < 0) || (value > 10)) return BadValue;
if (value > 5) priv->speed = 2.00*((double)value - 5.00);
else priv->speed = ((double)value + 1.00) / 6.00;
sprintf(st, "%.3f", priv->speed);
xf86AddNewOption(local->options, "Speed", st);
break;
case XWACOM_PARAM_ACCEL:
if ((value < 0) || (value > MAX_ACCEL-1)) return BadValue;
priv->accel = value;
xf86ReplaceIntOption(local->options, "Accel", priv->accel);
break;
case XWACOM_PARAM_CLICKFORCE:
if ((value < 0) || (value > 20)) return BadValue;
priv->common->wcmThreshold =
(int)((double)(value*priv->common->wcmMaxZ)/100.00+0.5);
xf86ReplaceIntOption(local->options, "Threshold",
priv->common->wcmThreshold);
break;
case XWACOM_PARAM_XYDEFAULT:
xf86ReplaceIntOption(local->options, "TopX", 0);
priv->topX = xf86SetIntOption(local->options, "TopX", 0);
xf86ReplaceIntOption(local->options, "TopY", 0);
priv->topY = xf86SetIntOption(local->options, "TopY", 0);
xf86ReplaceIntOption(local->options,
"BottomX", priv->common->wcmMaxX);
priv->bottomX = xf86SetIntOption(local->options,
"BottomX", priv->common->wcmMaxX);
xf86ReplaceIntOption(local->options,
"BottomY", priv->common->wcmMaxY);
priv->bottomY = xf86SetIntOption(local->options,
"BottomY", priv->common->wcmMaxY);
break;
case XWACOM_PARAM_GIMP:
if ((value != 0) && (value != 1)) return BadValue;
priv->common->wcmGimp = value;
break;
default:
DBG(10, ErrorF("xf86WcmSetParam invalid param %d\n",param));
return BadMatch;
}
return Success;
}
static int xf86WcmOptionCommandToFile(LocalDevicePtr local)
{
WacomDevicePtr priv = (WacomDevicePtr)local->private;
char fileName[80] = "/etc/X11/wcm.";
char command[256];
FILE *fp = 0;
int value;
double speed;
char *s;
strcat(fileName, local->name);
fp = fopen(fileName, "w+");
if ( fp ) {
s = xf86FindOptionValue(local->options, "TopX");
if ( s && priv->topX )
fprintf(fp, "xsetwacom set %s TopX %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "TopY");
if ( s && priv->topY )
fprintf(fp, "xsetwacom set %s TopY %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "BottomX");
if ( s && priv->bottomX != priv->common->wcmMaxX )
fprintf(fp, "xsetwacom set %s BottomX %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "BottomY");
if ( s && priv->bottomY != priv->common->wcmMaxY )
fprintf(fp, "xsetwacom set %s BottomY %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Button1");
if ( s && priv->button[0] != 1 )
fprintf(fp, "xsetwacom set %s Button1 %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Button2");
if ( s && priv->button[1] != 2 )
fprintf(fp, "xsetwacom set %s Button2 %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Button3");
if ( s && priv->button[2] != 3 )
fprintf(fp, "xsetwacom set %s Button3 %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Button4");
if ( s && priv->button[3] != 4 )
fprintf(fp, "xsetwacom set %s Button4 %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Button5");
if ( s && priv->button[4] != 5 )
fprintf(fp, "xsetwacom set %s Button5 %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "PressCurve");
if ( s && !IsCursor(priv) )
fprintf(fp, "xsetwacom set %s PressCurve %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Mode");
if ( s && (((priv->flags & ABSOLUTE_FLAG) && IsCursor(priv))
|| (!(priv->flags & ABSOLUTE_FLAG) && !IsCursor(priv))))
fprintf(fp, "xsetwacom set %s Mode %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "RawFilter");
if ( s )
fprintf(fp, "xsetwacom set %s RawFilter %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Accel");
if ( s && priv->accel )
fprintf(fp, "xsetwacom set %s Accel %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Suppress");
if ( s )
fprintf(fp, "xsetwacom set %s Suppress %s\n", local->name, s);
s = xf86FindOptionValue(local->options, "Speed");
if ( s && priv->speed != DEFAULT_SPEED )
{
speed = strtod(s, NULL);
if(speed > 10.00) value = 10;
else if(speed >= 1.00) value = (int)(speed/2.00 + 5.00);
else if(speed < (double)(1.00/6.00)) value = 0;
else value = (int)(speed*6.00 - 0.50);
fprintf(fp, "xsetwacom set %s SpeedLevel %d\n", local->name, value);
}
s = xf86FindOptionValue(local->options, "Threshold");
if ( s )
{
value = atoi(s);
value = (int)((double)value*100.00/(double)priv->common->wcmMaxZ+0.5);
fprintf(fp, "xsetwacom set %s ClickForce %d\n", local->name, value);
}
fprintf(fp, "%s", "default TopX 0\n");
fprintf(fp, "%s", "default TopY 0\n");
fprintf(fp, "default BottomX %d\n", priv->common->wcmMaxX);
fprintf(fp, "default BottomY %d\n", priv->common->wcmMaxY);
if (IsCursor(priv))
sprintf(command, "default Mode Relative\n");
else
sprintf(command, "default Mode Absolute\n");
fprintf(fp, "%s", command);
fprintf(fp, "%s", "default SpeedLevel 5\n");
fprintf(fp, "%s", "default ClickForce 6\n");
fprintf(fp, "%s", "default Accel 0\n");
fclose(fp);
}
return(Success);
}
static int xf86WcmModelToFile(LocalDevicePtr local)
{
FILE *fp = 0;
LocalDevicePtr localDevices = xf86FirstLocalDevice();
WacomDevicePtr priv = NULL, lprv;
char m1[32], m2[32], *m3;
int i = 0, x = 0, y = 0;
fp = fopen("/etc/wacom.dat", "w+");
if ( fp ) {
while(localDevices) {
m3 = xf86FindOptionValue(localDevices->options, "Type");
if (m3 && (strstr(m3, "eraser") || strstr(m3, "stylus")
|| strstr(m3, "cursor")))
lprv = (WacomDevicePtr)localDevices->private;
else
lprv = NULL;
if (lprv && lprv->common) {
sscanf((char*)(lprv->common->wcmModel)->name, "%s %s", m1, m2);
fprintf(fp, "%s %s %s\n", localDevices->name, m2, m3);
if (lprv->twinview != TV_NONE) {
priv = lprv;
}
if( !priv ) priv = lprv;
}
localDevices = localDevices->next;
}
if (priv->twinview == TV_ABOVE_BELOW) {
fprintf(fp, "Screen0 %d %d %d %d\n", priv->tvResolution[0],
priv->tvResolution[1], 0, 0);
fprintf(fp, "Screen1 %d %d %d %d\n", priv->tvResolution[2],
priv->tvResolution[3], 0, priv->tvResolution[1]);
} else if (priv->twinview == TV_LEFT_RIGHT) {
fprintf(fp, "Screen0 %d %d %d %d\n", priv->tvResolution[0],
priv->tvResolution[1], 0, 0);
fprintf(fp, "Screen1 %d %d %d %d\n", priv->tvResolution[2],
priv->tvResolution[3], priv->tvResolution[0], 0);
} else {
for (i = 0; i<screenInfo.numScreens; i++) {
fprintf(fp, "Screen%d %d %d %d %d\n",
i, screenInfo.screens[i]->width,
screenInfo.screens[i]->height, x, y);
x += screenInfo.screens[i]->width;
}
}
fclose(fp);
}
return(Success);
}
static int
xf86WcmDevChangeControl(LocalDevicePtr local,
xDeviceCtl *control)
{
xDeviceResolutionCtl* res = (xDeviceResolutionCtl *)control;
int* r = (int*)(res+1);
int param = r[0], value = r[1];
DBG(10, ErrorF("xf86WcmDevChangeControl firstValuator=%d\n", res->first_valuator));
if (control->control != DEVICE_RESOLUTION || !res->num_valuators)
return BadMatch;
r[0] = 1, r[1] = 1;
switch (res->first_valuator) {
case 0:
{
return xf86WcmOptionCommandToFile(local);
}
case 1:
{
return xf86WcmModelToFile(local);
}
case 4:
{
DBG(10,ErrorF("xf86WcmDevChangeControl: 0x%x, 0x%x\n", param, value));
return xf86WcmSetParam(local,param,value);
}
default:
DBG(10,ErrorF("xf86WcmDevChangeControl invalid "
"firstValuator=%d\n",res->first_valuator));
return BadMatch;
}
}
static int
xf86WcmDevSwitchMode(ClientPtr client,
DeviceIntPtr dev,
int mode)
{
LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate;
WacomDevicePtr priv = (WacomDevicePtr)local->private;
DBG(3, ErrorF("xf86WcmSwitchMode dev=%p mode=%d\n", (void *)dev, mode));
if (mode == Absolute) {
priv->flags |= ABSOLUTE_FLAG;
}
else {
if (mode == Relative) {
priv->flags &= ~ABSOLUTE_FLAG;
}
else {
DBG(1, ErrorF("xf86WcmDevSwitchMode dev=%p invalid mode=%d\n",
(void *)dev, mode));
return BadMatch;
}
}
return Success;
}
static LocalDevicePtr
xf86WcmAllocate(char * name,
int flag)
{
LocalDevicePtr local;
WacomDevicePtr priv;
WacomCommonPtr common;
int i;
priv = (WacomDevicePtr) xalloc(sizeof(WacomDeviceRec));
if (!priv)
return NULL;
common = (WacomCommonPtr) xalloc(sizeof(WacomCommonRec));
if (!common) {
xfree(priv);
return NULL;
}
local = xf86AllocateInput(gWacomModule.v4.wcmDrv, 0);
if (!local) {
xfree(priv);
xfree(common);
return NULL;
}
local->name = name;
local->flags = 0;
local->device_control = gWacomModule.DevProc;
local->read_input = gWacomModule.DevReadInput;
local->control_proc = gWacomModule.DevChangeControl;
local->close_proc = gWacomModule.DevClose;
local->switch_mode = gWacomModule.DevSwitchMode;
local->conversion_proc = gWacomModule.DevConvert;
local->reverse_conversion_proc = gWacomModule.DevReverseConvert;
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;
memset(priv,0,sizeof(*priv));
priv->flags = flag;
priv->oldX = -1;
priv->oldY = -1;
priv->oldZ = -1;
priv->oldTiltX = -1;
priv->oldTiltY = -1;
priv->oldButtons = 0;
priv->oldWheel = 0;
priv->topX = 0;
priv->topY = 0;
priv->bottomX = 0;
priv->bottomY = 0;
priv->factorX = 0.0;
priv->factorY = 0.0;
priv->common = common;
priv->oldProximity = 0;
priv->serial = 0;
priv->screen_no = -1;
priv->speed = DEFAULT_SPEED;
priv->accel = 0;
for (i=0; i<16; i++)
priv->button[i] = i+1;
priv->numScreen = screenInfo.numScreens;
priv->currentScreen = 0;
priv->dscaleX = 1.0;
priv->dscaleY = 1.0;
priv->doffsetX = 0;
priv->doffsetY = 0;
priv->twinview = TV_NONE;
for (i=0; i<4; i++)
priv->tvResolution[i] = 0;
priv->throttleValue = 0;
priv->throttleStart = 0;
priv->throttleLimit = -1;
memset(common,0,sizeof(*common));
memset(common->wcmChannel, 0, sizeof(common->wcmChannel));
common->wcmDevice = "";
common->wcmSuppress = DEFAULT_SUPPRESS;
common->wcmFlags = RAW_FILTERING_FLAG;
common->wcmDevices = (LocalDevicePtr*) xalloc(sizeof(LocalDevicePtr));
common->wcmDevices[0] = local;
common->wcmNumDevices = 1;
common->wcmMaxX = 0;
common->wcmMaxY = 0;
common->wcmMaxZ = 0;
common->wcmResolX = 0;
common->wcmResolY = 0;
common->wcmChannelCnt = 1;
common->wcmProtocolLevel = 4;
common->wcmThreshold = 0;
common->wcmInitialized = FALSE;
common->wcmLinkSpeed = 9600;
common->wcmDevCls = &gWacomSerialDevice;
common->wcmModel = NULL;
common->wcmGimp = 1;
return local;
}
static LocalDevicePtr
xf86WcmAllocateStylus()
{
LocalDevicePtr local = xf86WcmAllocate(XI_STYLUS, STYLUS_ID);
if (local)
local->type_name = "Wacom Stylus";
return local;
}
static LocalDevicePtr
xf86WcmAllocateCursor()
{
LocalDevicePtr local = xf86WcmAllocate(XI_CURSOR, CURSOR_ID);
if (local)
local->type_name = "Wacom Cursor";
return local;
}
static LocalDevicePtr
xf86WcmAllocateEraser()
{
LocalDevicePtr local = xf86WcmAllocate(XI_ERASER, ABSOLUTE_FLAG|ERASER_ID);
if (local)
local->type_name = "Wacom Eraser";
return local;
}
static void
xf86WcmUninit(InputDriverPtr drv,
LocalDevicePtr local,
int flags)
{
WacomDevicePtr priv;
priv = (WacomDevicePtr) local->private;
DBG(1, ErrorF("xf86WcmUninit\n"));
gWacomModule.DevProc(local->dev, DEVICE_OFF);
if (priv->pPressCurve)
xfree(priv->pPressCurve);
xfree (priv);
xf86DeleteInput(local, 0);
}
static Bool xf86WcmMatchDevice(LocalDevicePtr pMatch, LocalDevicePtr pLocal)
{
WacomDevicePtr privMatch = (WacomDevicePtr)pMatch->private;
WacomDevicePtr priv = (WacomDevicePtr)pLocal->private;
WacomCommonPtr common = priv->common;
if ((pLocal != pMatch) && (pMatch->device_control == gWacomModule.DevProc) &&
!strcmp(privMatch->common->wcmDevice, common->wcmDevice)) {
DBG(2, ErrorF("xf86WcmInit wacom port share between"
" %s and %s\n", pLocal->name, pMatch->name));
xfree(common->wcmDevices);
xfree(common);
common = priv->common = privMatch->common;
common->wcmNumDevices++;
common->wcmDevices = (LocalDevicePtr *)xrealloc(
common->wcmDevices,
sizeof(LocalDevicePtr) * common->wcmNumDevices);
common->wcmDevices[common->wcmNumDevices - 1] = pLocal;
return 1;
}
return 0;
}
static InputInfoPtr
xf86WcmInit(InputDriverPtr drv,
IDevPtr dev,
int flags)
{
LocalDevicePtr local = NULL;
LocalDevicePtr fakeLocal = NULL;
WacomDevicePtr priv = NULL;
WacomCommonPtr common = NULL;
char *s, b[10];
int i, oldButton;
LocalDevicePtr localDevices;
gWacomModule.v4.wcmDrv = drv;
fakeLocal = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec));
if (!fakeLocal)
return NULL;
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) {
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);
common->wcmDevice = xf86FindOptionValue(local->options, "Device");
if (!common->wcmDevice) {
xf86Msg (X_ERROR, "%s: No Device specified.\n", dev->identifier);
goto SetupProc_fail;
}
localDevices = xf86FirstLocalDevice();
for (; localDevices != NULL; localDevices = localDevices->next)
{
if (xf86WcmMatchDevice(localDevices,local))
{
common = priv->common;
break;
}
}
xf86ProcessCommonOptions(local, local->options);
xf86Msg(X_CONFIG, "%s serial device is %s\n", dev->identifier,
common->wcmDevice);
gWacomModule.debugLevel = xf86SetIntOption(local->options, "DebugLevel",
gWacomModule.debugLevel);
if (gWacomModule.debugLevel > 0) {
xf86Msg(X_CONFIG, "WACOM: debug level set to %d\n", gWacomModule.debugLevel);
}
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);
if (priv->flags & CURSOR_ID)
priv->flags &= ~ABSOLUTE_FLAG;
else
priv->flags |= ABSOLUTE_FLAG;
}
xf86Msg(X_CONFIG, "%s is in %s mode\n", local->name,
(priv->flags & ABSOLUTE_FLAG) ? "absolute" : "relative");
s = xf86FindOptionValue(local->options, "ForceDevice");
if (s && (xf86NameCmp(s, "ISDV4") == 0)) {
common->wcmForceDevice=DEVICE_ISDV4;
common->wcmDevCls = &gWacomISDV4Device;
xf86Msg(X_CONFIG, "%s: forcing TabletPC ISD V4 protocol\n", dev->identifier);
}
common->wcmRotate=ROTATE_NONE;
s = xf86FindOptionValue(local->options, "Rotate");
if (s) {
if (xf86NameCmp(s, "CW") == 0) {
common->wcmRotate=ROTATE_CW;
} else if (xf86NameCmp(s, "CCW") ==0) {
common->wcmRotate=ROTATE_CCW;
}
}
common->wcmSuppress = xf86SetIntOption(local->options, "Suppress", common->wcmSuppress);
if ((common->wcmSuppress != 0) &&
(common->wcmSuppress > MAX_SUPPRESS ||
common->wcmSuppress < DEFAULT_SUPPRESS))
common->wcmSuppress = DEFAULT_SUPPRESS;
xf86Msg(X_CONFIG, "WACOM: suppress value is %d\n", common->wcmSuppress);
if (xf86SetBoolOption(local->options, "Tilt", (common->wcmFlags & TILT_REQUEST_FLAG))) {
common->wcmFlags |= TILT_REQUEST_FLAG;
}
if (xf86SetBoolOption(local->options, "RawFilter",
(common->wcmFlags & RAW_FILTERING_FLAG)))
{
common->wcmFlags |= RAW_FILTERING_FLAG;
}
#ifdef LINUX_INPUT
if (xf86SetBoolOption(local->options, "USB", (common->wcmDevCls == &gWacomUSBDevice))) {
(void)xf86LoadKernelModule("wacom");
(void)xf86LoadKernelModule("evdev");
common->wcmDevCls = &gWacomUSBDevice;
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
}
s = xf86FindOptionValue(local->options, "PressCurve");
if (s) {
int a,b,c,d;
if ((sscanf(s,"%d,%d,%d,%d",&a,&b,&c,&d) != 4) ||
(a < 0) || (a > 100) || (b < 0) || (b > 100) ||
(c < 0) || (c > 100) || (d < 0) || (d > 100))
xf86Msg(X_CONFIG, "WACOM: PressCurve not valid\n");
else {
xf86WcmSetPressureCurve(priv,a,b,c,d);
xf86Msg(X_CONFIG, "WACOM: PressCurve %d,%d %d,%d\n", a,b,c,d);
}
}
s = xf86FindOptionValue(local->options, "TVResolution");
if (s) {
int a,b,c,d;
if ((sscanf(s,"%dx%d,%dx%d",&a,&b,&c,&d) != 4) ||
(a <= 0) || (b <= 0) || (c <= 0) || (d <= 0))
xf86Msg(X_CONFIG, "WACOM: TVResolution not valid\n");
else {
priv->tvResolution[0] = a;
priv->tvResolution[1] = b;
priv->tvResolution[2] = c;
priv->tvResolution[3] = d;
xf86Msg(X_CONFIG, "WACOM: TVResolution %d,%d %d,%d\n", a,b,c,d);
}
}
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 y = %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 y = %d\n", dev->identifier,
priv->bottomY);
}
priv->serial = xf86SetIntOption(local->options, "Serial", 0);
if (priv->serial != 0) {
xf86Msg(X_CONFIG, "%s: serial number = %u\n", dev->identifier,
priv->serial);
}
common->wcmThreshold = xf86SetIntOption(local->options, "Threshold", common->wcmThreshold);
if (common->wcmThreshold > 0) {
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 != 0) {
xf86Msg(X_CONFIG, "%s: max x = %d\n", dev->identifier,
common->wcmMaxZ);
}
common->wcmUserResolX = xf86SetIntOption(local->options, "ResolutionX", common->wcmUserResolX);
if (common->wcmUserResolX != 0) {
xf86Msg(X_CONFIG, "%s: resol x = %d\n", dev->identifier,
common->wcmUserResolX);
}
common->wcmUserResolY = xf86SetIntOption(local->options, "ResolutionY", common->wcmUserResolY);
if (common->wcmUserResolY != 0) {
xf86Msg(X_CONFIG, "%s: resol y = %d\n", dev->identifier,
common->wcmUserResolY);
}
common->wcmUserResolZ = xf86SetIntOption(local->options, "ResolutionZ", common->wcmUserResolZ);
if (common->wcmUserResolZ != 0) {
xf86Msg(X_CONFIG, "%s: resol z = %d\n", dev->identifier,
common->wcmUserResolZ);
}
if (xf86SetBoolOption(local->options, "ButtonsOnly", 0)) {
priv->flags |= BUTTONS_ONLY_FLAG;
xf86Msg(X_CONFIG, "%s: buttons only\n", dev->identifier);
}
for (i=0; i<16; i++)
{
sprintf(b, "Button%d", i+1);
oldButton = priv->button[i];
priv->button[i] = xf86SetIntOption(local->options, b, priv->button[i]);
if (oldButton != priv->button[i])
{
xf86Msg(X_CONFIG, "%s: button%d assigned to %d\n",
dev->identifier, i+1, priv->button[i]);
}
}
{
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);
}
priv->speed = xf86SetRealOption(local->options, "Speed", DEFAULT_SPEED);
if (priv->speed != DEFAULT_SPEED) {
xf86Msg(X_CONFIG, "%s: speed = %.3f\n", dev->identifier,
priv->speed);
}
priv->accel = xf86SetIntOption(local->options, "Accel", 0);
if (priv->accel)
xf86Msg(X_CONFIG, "%s: Accel = %d\n", dev->identifier, priv->accel);
s = xf86FindOptionValue(local->options, "Twinview");
if (s) xf86Msg(X_CONFIG, "%s: Twinview = %s\n", dev->identifier, s);
if (s && xf86NameCmp(s, "none") == 0) {
priv->twinview = TV_NONE;
priv->dscaleX = 1.0;
priv->dscaleY = 1.0;
priv->doffsetX = 0;
priv->doffsetY = 0;
} else if (s && xf86NameCmp(s, "horizontal") == 0) {
priv->twinview = TV_LEFT_RIGHT;
priv->dscaleX = 2.0;
priv->dscaleY = 1.0;
priv->doffsetX = 0;
priv->doffsetY = 0;
if(!priv->tvResolution[0]) {
priv->tvResolution[0] = screenInfo.screens[0]->width/2;
priv->tvResolution[1] = screenInfo.screens[0]->height;
priv->tvResolution[2] = priv->tvResolution[0];
priv->tvResolution[3] = priv->tvResolution[1];
}
} else if (s && xf86NameCmp(s, "vertical") == 0) {
priv->twinview = TV_ABOVE_BELOW;
priv->dscaleX = 1.0;
priv->dscaleY = 2.0;
priv->doffsetX = 0;
priv->doffsetY = 0;
if(!priv->tvResolution[0]) {
priv->tvResolution[0] = screenInfo.screens[0]->width;
priv->tvResolution[1] = screenInfo.screens[0]->height/2;
priv->tvResolution[2] = priv->tvResolution[0];
priv->tvResolution[3] = priv->tvResolution[1];
}
} else if (s) {
xf86Msg(X_ERROR, "%s: invalid Twinview (should be none, vertical or horizontal). Using none.\n",
dev->identifier);
priv->twinview = TV_NONE;
priv->dscaleX = 1.0;
priv->dscaleY = 1.0;
priv->doffsetX = 0;
priv->doffsetY = 0;
}
local->flags |= XI86_POINTER_CAPABLE | XI86_CONFIGURED;
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,
"wacom",
NULL,
xf86WcmInit,
xf86WcmUninit,
NULL,
0
};
#ifdef XFree86LOADER
static void
xf86WcmUnplug(pointer p)
{
DBG(1, ErrorF("xf86WcmUnplug\n"));
}
static pointer
xf86WcmPlug(pointer module,
pointer options,
int *errmaj,
int *errmin)
{
#if 0
xf86Msg(X_INFO, "Wacom driver level: %s\n", gWacomModule.identification+strlen("$Identification: "));
#endif
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}
};
XF86ModuleData wacomModuleData = {&xf86WcmVersionRec,
xf86WcmPlug,
xf86WcmUnplug};
#endif