diff -Naur xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.c xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.c --- xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.c 2006-04-07 18:20:33.000000000 +0200 +++ xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.c 2008-01-10 00:41:48.000000000 +0100 @@ -4,6 +4,24 @@ * This driver assumes Linux USB/HID support, available for USB devices. * * Version 0.0, 1-Jan-2003, Bryan W. Headley + * + * Version 1.0 10-jan-2008, Rene van Paassen + * * This version is based on the Xorg driver 1.0.1 version, with + * fixes based on the version developed at aiptektablet.sourceforge.net + * fixes include - correction of the button status calculation + * (buttons were never released) + * - use stylus as default, because reading the + * tablet before X start gives no hint as to what device + * it is producing + * - correction of the proximity bit detection + * - although tablet may produce relative (x, y), the z and + * tilt values are always absolute, corrected that + * - relative x and y may be negative sometimes! removed + * clipping there + * - filtering out events only if ALL values are equal to + * the, previous not when only one or more is equal + + * combined filtering with threshold. + * * * Copyright 2003 by Bryan W. Headley. * @@ -203,12 +221,21 @@ AiptekDevicePtr device = (AiptekDevicePtr) local->private; int xSize, ySize; int width, height; + ScreenPtr pScreen = miPointerCurrentScreen(); DBG(6, ErrorF("xf86AiptekConvert\n")); xf86Msg(X_CONFIG, " xf86AiptekConvert(), with: first=%d, num=%d, v0=%d, " "v1=%d, v2=%d, v3=%d,, v4=%d, v5=%d, x=%d, y=%d\n", first, num, v0, v1, v2, v3, v4, v5, *x, *y); + /* Change the screen number if it differs from that which + * the pointer is currently on + */ + if (pScreen->myNum != device->screenNo) + { + device->screenNo = pScreen->myNum; + } + if (first != 0 || num == 1) { return FALSE; @@ -333,46 +360,54 @@ { x = common->currentValues.x; y = common->currentValues.y; - z = r_z; - xTilt = common->currentValues.xTilt; - yTilt = common->currentValues.yTilt; - } - else - { - x = common->currentValues.x - common->previousValues.x; - y = common->currentValues.y - common->previousValues.y; - z = r_z - common->previousValues.z; - xTilt = common->currentValues.xTilt - common->previousValues.xTilt; - yTilt = common->currentValues.yTilt - common->previousValues.yTilt; - } - /* Translate coordinates according to Top and Bottom points. - */ - if (x > device->xBottom) { - x = device->xBottom; - } + /* Translate coordinates according to Top and Bottom points. + */ + if (x > device->xBottom) { + x = device->xBottom; + } - if (y > device->yBottom) { - y = device->yBottom; - } + if (y > device->yBottom) { + y = device->yBottom; + } - if (device->xTop > 0) { - DBG(10, ErrorF("Adjusting x, with xTop=%d\n", device->xTop)); - x -= device->xTop; - } + if (device->xTop > 0) { + DBG(10, ErrorF("Adjusting x, with xTop=%d\n", device->xTop)); + x -= device->xTop; + } + + if (device->yTop > 0) { + DBG(10, ErrorF("Adjusting y, with yTop=%d\n", device->yTop)); + y -= device->yTop; + } + + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } - if (device->yTop > 0) { - DBG(10, ErrorF("Adjusting y, with yTop=%d\n", device->yTop)); - y -= device->yTop; } - - if (x < 0) { - x = 0; - } - if (y < 0) { - y = 0; + else + { + if (common->previousValues.proximity != 0) + { + x = common->currentValues.x - common->previousValues.x; + y = common->currentValues.y - common->previousValues.y; + } + else + { + x = 0; + y = 0; + } } + z = r_z; + xTilt = common->currentValues.xTilt; + yTilt = common->currentValues.yTilt; + + /* Deal with pressure min..max, which differs from threshold. */ if (z < device->zMin) { z = 0; @@ -594,7 +629,7 @@ */ ++eventsInMessage; common->currentValues.proximity = - (event->value > 0 ? 1 : 0); + PROXIMITY(event->value) ? 1 : 0; } break; } @@ -649,7 +684,7 @@ */ ++eventsInMessage; common->currentValues.proximity = - (event->value > 0 ? 1 : 0); + PROXIMITY (event->value) ? 1 : 0; } break; } @@ -711,24 +746,36 @@ case BTN_TOUCH: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_TOUCH; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_TOUCH; + else + common->currentValues.button &= + ~BUTTONS_EVENT_TOUCH; } break; case BTN_STYLUS: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_STYLUS; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_STYLUS; + else + common->currentValues.button &= + ~BUTTONS_EVENT_STYLUS; } break; case BTN_STYLUS2: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_STYLUS2; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_STYLUS2; + else + common->currentValues.button &= + ~BUTTONS_EVENT_STYLUS2; } break; @@ -742,40 +789,60 @@ case BTN_LEFT: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_MOUSE_LEFT; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_LEFT; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_LEFT; } break; case BTN_MIDDLE: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_MOUSE_MIDDLE; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_MIDDLE; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_MIDDLE; } break; case BTN_RIGHT: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_MOUSE_RIGHT; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_RIGHT; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_RIGHT; } break; case BTN_SIDE: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_SIDE_BTN; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_SIDE_BTN; + else + common->currentValues.button &= + ~BUTTONS_EVENT_SIDE_BTN; } break; case BTN_EXTRA: { ++eventsInMessage; - common->currentValues.button |= - (event->value > 0 ? 1 : 0) * BUTTONS_EVENT_EXTRA_BTN; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_EXTRA_BTN; + else + common->currentValues.button &= + ~BUTTONS_EVENT_EXTRA_BTN; } break; @@ -842,45 +909,28 @@ * Also, we only do the comparison IFF a threshold has been set * for that given dimension. */ - if ((device->xThreshold > 1 && - ABS(common->currentValues.x - common->previousValues.x) - <= device->xThreshold) || - (device->yThreshold > 1 && - ABS(common->currentValues.y - common->previousValues.y) - <= device->yThreshold) || - (device->zThreshold > 1 && - ABS(common->currentValues.z - common->previousValues.z) - <= device->zThreshold) || - (device->xTiltThreshold > 1 && - ABS(common->currentValues.xTilt - common->previousValues.xTilt) - <= device->xTiltThreshold) || - (device->yTiltThreshold > 1 && - ABS(common->currentValues.yTilt - common->previousValues.yTilt) - <= device->yTiltThreshold)) + if (ABS(common->currentValues.x - common->previousValues.x) + <= device->xThreshold && + ABS(common->currentValues.y - common->previousValues.y) + <= device->yThreshold && + ABS(common->currentValues.z - common->previousValues.z) + <= device->zThreshold && + ABS(common->currentValues.xTilt - common->previousValues.xTilt) + <= device->xTiltThreshold && + ABS(common->currentValues.yTilt - common->previousValues.yTilt) + <= device->yTiltThreshold && + common->currentValues.proximity == + common->previousValues.proximity && + common->currentValues.button == + common->previousValues.button && + common->currentValues.macroKey == + common->previousValues.macroKey) { DBG(10, ErrorF("Event Filtered Out by Thresholds\n")); continue; } /* - * If this report somehow has exactly the same readings as the - * previous report for all dimensions, throw the report out. - */ - if ((common->currentValues.x == common->previousValues.x) && - (common->currentValues.y == common->previousValues.y) && - (common->currentValues.z == common->previousValues.z) && - (common->currentValues.proximity == - common->previousValues.proximity) && - (common->currentValues.button == - common->previousValues.button) && - (common->currentValues.macroKey == - common->previousValues.macroKey)) - { - DBG(10, ErrorF("Event Filtered Out\n")); - continue; - } - - /* * We have three different methods by which we report pressure, Z. * One is to use linear values from 0 to common->zCapacity. The * other two, SOFT_SMOOTH and HARD_SMOOTH, use different @@ -1809,8 +1859,10 @@ device->common = common; /* Common info pointer */ /* Record of the event currently being read of the queue */ - common->currentValues.eventType = 0; /* Device event is for, e.g., */ - /* STYLUS, RUBBER, CURSOR */ + common->currentValues.eventType = STYLUS_ID; + /* Device event is for, e.g., */ + /* STYLUS, RUBBER, CURSOR */ + /* Starting with stylus as default */ common->currentValues.x = 0; /* X coordinate */ common->currentValues.y = 0; /* Y coordinate */ common->currentValues.z = 0; /* Z (pressure) */ diff -Naur xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.c~ xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.c~ --- xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.c~ 1970-01-01 01:00:00.000000000 +0100 +++ xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.c~ 2008-01-09 23:09:01.000000000 +0100 @@ -0,0 +1,2498 @@ +/* + * xf86Aiptek + * + * This driver assumes Linux USB/HID support, available for USB devices. + * + * Version 0.0, 1-Jan-2003, Bryan W. Headley + * + * Copyright 2003 by Bryan W. Headley. + * + * Lineage: This driver is based on both the xf86HyperPen and xf86Wacom tablet + * drivers. + * + * xf86HyperPen -- modified from xf86Summa (c) 1996 Steven Lang + * (c) 2000 Roland Jansen + * (c) 2000 Christian Herzog (button & 19200 baud support) + * + * xf86Wacom -- (c) 1995-2001 Frederic Lepied + * + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Bryan W. Headley not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Bryan W. Headley makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * BRYAN W. HEADLEY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL BRYAN W. HEADLEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/input/aiptek/xf86Aiptek.c,v 1.1tsi Exp $ */ + +/* + * + * Section "InputDevice" + * Identifier "stylus" + * Driver "aiptek" + * Option "Device" "pathname" {/dev/input/event0} + * Option "Type" "string" {stylus|cursor|eraser} + * Option "Mode" "string" {absolute|relative} + * Option "Cursor" "string" {stylus|puck} + * Option "USB" "bool" {on|off} + * Option "ScreenNo" "int" + * Option "KeepShape" "bool" {on|off} + * + * # The tablet reports top-right as 0 for the given coordinate + * # to bottom-left as num (value dependent on tablet.) + * # If you choose to invert X, Y or both, the bottom-left coordinate + * # is reported as 0. + * Option "InvX" "bool" {on|off} + * Option "InvY" "bool" {on|off} + * + * # XSize/YSize/XOffset/YOffset allow you to specify an active + * # area within yout tablet. + * + * Option "XSize" "int" + * Option "YSize" "int" + * + * Option "XTop" "int" + * Option "YTop" "int" + * Option "XBottom" "int" + * Option "YBottom" "int" + * Option "XOffset" "int" + * Option "YOffset" "int" + * + * Option "XMax" "int" + * Option "YMax" "int" + * Option "ZMax" "int" + * Option "ZMin" "int" + * + * Option "XThreshold" "int" + * Option "YThreshold" "int" + * Option "ZThreshold" "int" + * + * Option "Pressure" "Soft|Hard|Linear" defaults to Linear + * + * Option "alwayscore" "bool" {on|off} + * Option "debuglevel" "int" + * Option "HistorySize" "int" + * EndSection + * + * Commentary: + * 1. Identifier: what you name your input device is not too + * significant. + * but what it infers is that you can have a driver with + * a name of "stylus" (whose type would be 'stylus') and + * another one with identifier "cursor" (whose type would be + * 'cursor') that both would be driver by the same aiptek + * driver. Note though that the identifier keyword has + * no devicetype connotations: you can identify your input + * device as "zzz", + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Aiptek.h" +#include +#include +#include + +static const char identification[] = "$Identification: 0 $"; +static InputDriverPtr aiptekDrv; +static int debug_level = INI_DEBUG_LEVEL; + +_X_EXPORT InputDriverRec AIPTEK = +{ + 1, /* driver version */ + "aiptek", /* driver name */ + NULL, /* identify */ + xf86AiptekInit, /* pre-init */ + xf86AiptekUninit, /* un-init */ + NULL, /* module */ + 0 /* ref count */ +}; + +/* + * Function/Macro keys variables. + * + * This is a list of X keystrokes the macro keys can send. + */ +static KeySym aiptek_map[] = +{ + /* 0x00 .. 0x07 */ + NoSymbol,NoSymbol,NoSymbol,NoSymbol,NoSymbol,NoSymbol,NoSymbol,NoSymbol, + /* 0x08 .. 0x0f */ + XK_F1, XK_F2, XK_F3, XK_F4, XK_F5, XK_F6, XK_F7, XK_F8, + /* 0x10 .. 0x17 */ + XK_F9, XK_F10, XK_F11, XK_F12, XK_F13, XK_F14, XK_F15, XK_F16, + /* 0x18 .. 0x1f */ + XK_F17, XK_F18, XK_F19, XK_F20, XK_F21, XK_F22, XK_F23, XK_F24, + /* 0x20 .. 0x27 */ + XK_F25, XK_F26, XK_F27, XK_F28, XK_F29, XK_F30, XK_F31, XK_F32 +}; + +/* + * This is the map of Linux Event Input system keystrokes sent for + * the macro keys. There are discrepancies in the mappings, so for example, + * if we wanted to implement full macro key-to-string conversion in the + * Linux driver, we'd have to accept 1-to-many keyboard events, several of + * whom would not have the same encoding. For this reason, we're biting + * the bullet now & implementing a simple lookup/translation scheme. + * A simple 'KEY_F1 = XK_F1' layout wouldn't work, because X wants an + * offset into the KeySym array above, and it'll look up that this means + * XK_whatever... + */ + +static int linux_inputDevice_keyMap[] = +{ + KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, + KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, + KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, KEY_F24, + KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO, KEY_FRONT, KEY_COPY, + KEY_OPEN, KEY_PASTE +}; + +/* minKeyCode = 8 because this is the min legal key code */ +static KeySymsRec keysyms = +{ + /* map minKeyCode maxKC width */ + aiptek_map, 8, 0x27, 1 +}; + +static const char *default_options[] = +{ + "BaudRate", "9600", + "StopBits", "1", + "DataBits", "8", + "Parity", "None", + "VMin", "1", + "Vtime", "10", + "FlowControl", "Xoff", + NULL +}; + +/* + * xf86AiptekConvert + * Convert valuators to X and Y. We deal with multiple X screens, adjusting + * for xTop/xBottom/yTop/yBottom (or xSize/ySize). + */ +static Bool +xf86AiptekConvert(LocalDevicePtr local, + int first, + int num, + int v0, + int v1, + int v2, + int v3, + int v4, + int v5, + int* x, + int* y) +{ + AiptekDevicePtr device = (AiptekDevicePtr) local->private; + int xSize, ySize; + int width, height; + ScreenPtr pScreen = miPointerCurrentScreen(); + + DBG(6, ErrorF("xf86AiptekConvert\n")); + xf86Msg(X_CONFIG, " xf86AiptekConvert(), with: first=%d, num=%d, v0=%d, " + "v1=%d, v2=%d, v3=%d,, v4=%d, v5=%d, x=%d, y=%d\n", + first, num, v0, v1, v2, v3, v4, v5, *x, *y); + + /* Change the screen number if it differs from that which + * the pointer is currently on + */ + if (pScreen->myNum != device->screenNo) + { + device->screenNo = pScreen->myNum; + } + + if (first != 0 || num == 1) + { + return FALSE; + } + + xSize = device->xBottom - device->xTop; + ySize = device->yBottom - device->yTop; + + width = screenInfo.screens[device->screenNo]->width; + height = screenInfo.screens[device->screenNo]->height; + + *x = (v0 * width) / xSize; + *y = (v1 * height) / ySize; + + /* Deal with coordinate inversion */ + if ( device->flags & INVX_FLAG) + { + *x = width - *x; + } + if ( device->flags & INVY_FLAG) + { + *y = height - *y; + } + + /* Normalize the adjusted sizes. */ + if (*x < 0) + { + *x = 0; + } + if (*x > width) + { + *x = width; + } + + if (*y < 0) + { + *y = 0; + } + if (*y > height) + { + *y = height; + } + + if (device->screenNo != 0) + { + xf86XInputSetScreen(local, device->screenNo, *x, *y); + } + xf86Msg(X_CONFIG, ": xf86AiptekConvert() exits, with: x=%d, y=%d\n", + *x, *y); + + return TRUE; +} + +/* + * xf86AiptekReverseConvert + * Convert X and Y to valuators. + */ +static Bool +xf86AiptekReverseConvert(LocalDevicePtr local, + int x, + int y, + int* valuators) +{ + AiptekDevicePtr device = (AiptekDevicePtr) local->private; + int xSize, ySize; + + xf86Msg(X_CONFIG, ": xf86AiptekReverseConvert(), with: x=%d, y=%d, " + "valuators[0]=%d, valuators[1]=%d\n", + x, y, valuators[0], valuators[1] ); + + /* + * Adjust by tablet ratio + */ + xSize = device->xBottom - device->xTop; + ySize = device->yBottom - device->yTop; + + valuators[0] = (x*xSize) / screenInfo.screens[device->screenNo]->width; + valuators[1] = (y*ySize) / screenInfo.screens[device->screenNo]->height; + + DBG(6, ErrorF("converted x,y (%d, %d) to (%d, %d)\n", + x, y, valuators[0], valuators[1] )); + + if (device->screenNo != 0) + { + xf86XInputSetScreen(local,device->screenNo,valuators[0], valuators[1]); + } + xf86Msg(X_CONFIG, ": xf86AiptekReverseConvert() exits, with: " + "valuators[0]=%d, valuators[1]=%d\n", + valuators[0], valuators[1] ); + + return TRUE; +} + +/********************************************************************** + * xf86AiptekSendEvents + * Send events according to the device state. + */ +static void +xf86AiptekSendEvents(LocalDevicePtr local, int r_z) +{ + AiptekDevicePtr device = (AiptekDevicePtr) local->private; + AiptekCommonPtr common = device->common; + + int bCorePointer, bAbsolute; + int x, y, z, xTilt, yTilt; + + if ((DEVICE_ID(device->flags) != common->currentValues.eventType)) + { + DBG(7,ErrorF("xf86AiptekSendEvents: not the same device type (%u,%u)\n", + DEVICE_ID(device->flags), common->currentValues.eventType)); + return; + } + + bAbsolute = (device->flags & ABSOLUTE_FLAG); + bCorePointer = xf86IsCorePointer(local->dev); + + /* + * Normalize X and Y coordinates. This includes dealing + * with absolute/relative coordinate mode. + */ + if (bAbsolute) + { + x = common->currentValues.x; + y = common->currentValues.y; + + /* Translate coordinates according to Top and Bottom points. + */ + if (x > device->xBottom) { + x = device->xBottom; + } + + if (y > device->yBottom) { + y = device->yBottom; + } + + if (device->xTop > 0) { + DBG(10, ErrorF("Adjusting x, with xTop=%d\n", device->xTop)); + x -= device->xTop; + } + + if (device->yTop > 0) { + DBG(10, ErrorF("Adjusting y, with yTop=%d\n", device->yTop)); + y -= device->yTop; + } + + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + + } + else + { + if (common->previousValues.proximity != 0) + { + x = common->currentValues.x - common->previousValues.x; + y = common->currentValues.y - common->previousValues.y; + } + else + { + x = 0; + y = 0; + } + } + + z = r_z; + xTilt = common->currentValues.xTilt; + yTilt = common->currentValues.yTilt; + + + /* Deal with pressure min..max, which differs from threshold. */ + if (z < device->zMin) { + z = 0; + } + + if (z > device->zMax) { + z = device->zMax; + } + + /* + * First, handle the macro keys. + */ + if (common->currentValues.macroKey != VALUE_NA) + { + int i; + + /* This is a little silly, but: The Linux Event Input + * system uses a slightly different keymap than does X + * (it also has more keys defined). So, we have to go + * through a translation process. It's made sillier than + * required because X wants an offset to it's KeySym table, + * rather than an event key -- it'll do it's own lookup. + * It DOES support arbitrary ordering of key events, and + * partial keyboard matrices, so that speaks in favor of this + * scheme. + */ + for (i = 0; + i < sizeof(linux_inputDevice_keyMap)/ + sizeof(linux_inputDevice_keyMap[0]); + ++i) + { + if (linux_inputDevice_keyMap[0]==common->currentValues.macroKey) + { + break; + } + } + + /* First available Keycode begins at 8 => macro+7. + * It's pervasive throughout the Xinput drivers, and + * no, I don't know why they purposively waste the first 8 + * positions of the KeySym map... + */ + + /* Keyboard 'make' (press) event */ + xf86PostKeyEvent(local->dev, i+7, TRUE, + bAbsolute, 0, 5, + x, y, common->currentValues.button, xTilt, yTilt); + /* Keyboard 'break' (depress) event */ + xf86PostKeyEvent(local->dev, i+7, FALSE, + bAbsolute, 0, 5, + x, y, common->currentValues.button, xTilt, yTilt); + } + + /* As the coordinates are ready, we can send events to X */ + if (common->currentValues.proximity) + { + if (!common->previousValues.proximity) + { + if (!bCorePointer) + { + xf86PostProximityEvent(local->dev, 1, 0, 5, + x, y, z, xTilt, yTilt); + } + } + + if ((bAbsolute && + (common->previousValues.x != common->currentValues.x || + common->previousValues.y != common->currentValues.y || + common->previousValues.z != common->currentValues.z)) || + (!bAbsolute && + (common->currentValues.x || common->currentValues.y))) + { + if (bAbsolute || common->previousValues.proximity) + { + xf86PostMotionEvent(local->dev, bAbsolute, 0, 5, + x, y, z, xTilt, yTilt); + } + } + + if (common->previousValues.button != common->currentValues.button) + { + int delta; + delta = common->currentValues.button ^ common->previousValues.button; + while(delta) + { + int id; + id = ffs(delta); + delta &= ~(1 << (id-1)); + xf86PostButtonEvent(local->dev, bAbsolute, id, + (common->currentValues.button & (1<<(id-1))), 0, 5, + x, y, z, xTilt, yTilt); + } + } + } + else + { + if (!bCorePointer) + { + if (common->previousValues.proximity) + { + xf86PostProximityEvent(local->dev, 0, 0, 5, x, y, z, + xTilt, yTilt); + } + } + common->previousValues.proximity = 0; + } +} + +/* + *************************************************************************** + * xf86AiptekHIDReadInput -- + * Read the new events from the device, and enqueue them. + */ +static void +xf86AiptekHIDReadInput(LocalDevicePtr local) +{ + AiptekDevicePtr device = (AiptekDevicePtr) local->private; + AiptekCommonPtr common = device->common; + + ssize_t len; + int i; + struct input_event* event; + char eventbuf[sizeof(struct input_event) * MAX_EVENTS]; + int eventsInMessage; + double d_z; + double d_zCapacity; + + SYSCALL(len = read(local->fd, eventbuf, sizeof(eventbuf))); + + if (len <= 0) + { + ErrorF("Error reading Aiptek tablet: %s\n", strerror(errno)); + return; + } + + eventsInMessage = 0; + for (event=(struct input_event *)(eventbuf); + event<(struct input_event *)(eventbuf+len); + ++event) + { + /* + * Unprocessed events: + * ABS_RZ - rotate stylus + * ABS_DISTANCE - unknown + * ABS_THROTTLE - unknown + * ABS_WHEEL - we have no wheel + * REL_WHEEL - we have no wheel + * + * Synthesized events + * ABS_X_TILT - The aiptek tablet does not report these, + * ABS_Y_TILT - but the Linux kernel driver sends synthetic values. + */ + switch (event->type) + { + case EV_ABS: + { + switch (event->code) + { + case ABS_X: + { + ++eventsInMessage; + common->currentValues.x = event->value; + } + break; + + case ABS_Y: + { + ++eventsInMessage; + common->currentValues.y = event->value; + } + break; + + case ABS_PRESSURE: + { + ++eventsInMessage; + common->currentValues.z = event->value; + } + break; + + case ABS_TILT_X: + case ABS_RZ: + { + ++eventsInMessage; + common->currentValues.xTilt = event->value; + } + break; + + case ABS_TILT_Y: + { + ++eventsInMessage; + common->currentValues.yTilt = event->value; + } + break; + + case ABS_DISTANCE: + { + ++eventsInMessage; + common->currentValues.distance = event->value; + } + break; + + case ABS_WHEEL: + case ABS_THROTTLE: + { + ++eventsInMessage; + common->currentValues.wheel = event->value; + } + break; + + case ABS_MISC: + { + /* We have an agreement with the + * Linux Aiptek HID driver to send + * the proximity bit through ABS_MISC. + * We do this solely if proximity is + * being reported through the Stylus tool; + * else, if mouse, we'll get proximity through + * REL_MISC. + */ + ++eventsInMessage; + common->currentValues.proximity = + PROXIMITY(event->value) ? 1 : 0; + } + break; + } + } + break; /* EV_ABS */ + + case EV_REL: + { + switch (event->code) + { + case REL_X: + { + /* Normalize all relative events into absolute + * coordinates. + */ + ++eventsInMessage; + common->currentValues.x = + common->previousValues.x + event->value; + } + break; + + case REL_Y: + { + /* Normalize all relative events into absolute + * coordinates. + */ + ++eventsInMessage; + common->currentValues.y = + common->previousValues.y + event->value; + } + break; + + case REL_WHEEL: + { + /* Normalize all relative events into absolute + * coordinates. + */ + ++eventsInMessage; + common->currentValues.wheel = + common->previousValues.wheel + event->value; + } + + case REL_MISC: + { + /* We have an agreement with the + * Linux Aiptek HID driver to send + * the proximity bit through REL_MISC. + * We do this solely if proximity is + * being reported through the Mouse tool; + * else, if stylus, we'll get proximity through + * ABS_MISC. + */ + ++eventsInMessage; + common->currentValues.proximity = + PROXIMITY (event->value) ? 1 : 0; + } + break; + } + } + break; /* EV_REL */ + + case EV_KEY: + { + switch (event->code) + { + /* + * Events begun with a BTN_TOOL_PEN, PENCIL, + * BRUSH or AIRBRUSH indicate that they are + * destined for the STYLUS device. + * + * This should probably change, and we should + * have devices for each type. We'll address that + * later. + */ + case BTN_TOOL_PEN: + case BTN_TOOL_PENCIL: + case BTN_TOOL_BRUSH: + case BTN_TOOL_AIRBRUSH: + { + ++eventsInMessage; + common->currentValues.eventType = STYLUS_ID; + } + break; + + /* + * Events begun with a BTN_TOOL_RUBBER indicate + * that they are destined for the ERASER device. + */ + case BTN_TOOL_RUBBER: + { + ++eventsInMessage; + common->currentValues.eventType = ERASER_ID; + } + break; + + /* + * A TOOL_LENS would be for a true PUCK/CURSOR. + * Aiptek instead gives us a mouse, that we can pretend + * is a puck. + */ + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + { + ++eventsInMessage; + common->currentValues.eventType = CURSOR_ID; + } + break; + + /* + * Normal button handling: TOUCH, STYLUS and + * STYLUS2 all buttons that we'll report to X + * as normal buttons. + */ + case BTN_TOUCH: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_TOUCH; + else + common->currentValues.button &= + ~BUTTONS_EVENT_TOUCH; + } + break; + + case BTN_STYLUS: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_STYLUS; + else + common->currentValues.button &= + ~BUTTONS_EVENT_STYLUS; + } + break; + + case BTN_STYLUS2: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_STYLUS2; + else + common->currentValues.button &= + ~BUTTONS_EVENT_STYLUS2; + } + break; + + /* + * Normal Mouse button handling: LEFT, RIGHT and + * MIDDLE all buttons that we'll report to X + * as normal buttons. Note that the damned things + * re-use the same bitmasks as the Stylus buttons, + * above. + */ + case BTN_LEFT: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_LEFT; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_LEFT; + } + break; + + case BTN_MIDDLE: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_MIDDLE; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_MIDDLE; + } + break; + + case BTN_RIGHT: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_MOUSE_RIGHT; + else + common->currentValues.button &= + ~BUTTONS_EVENT_MOUSE_RIGHT; + } + break; + + case BTN_SIDE: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_SIDE_BTN; + else + common->currentValues.button &= + ~BUTTONS_EVENT_SIDE_BTN; + } + break; + + case BTN_EXTRA: + { + ++eventsInMessage; + if (event->value) + common->currentValues.button |= + BUTTONS_EVENT_EXTRA_BTN; + else + common->currentValues.button &= + ~BUTTONS_EVENT_EXTRA_BTN; + } + break; + + /* + * Any other EV_KEY event is assumed to be + * the pressing of a macro key from the tablet. + */ + default: + { + ++eventsInMessage; + common->currentValues.macroKey = event->value; + } + break; + } + } + break; /* EV_KEY */ + + } /* switch event->type */ + + /* We have two potential event terminators. EV_MSC was used + * by (unwritten) convention to indicate the end-of-report. + * Problem is, EV_MSC is supposed to actually report data, + * so a new event type, EV_SYN, was created in Linux 2.5.x + * expressively for this purpose. + * + * Theoretically, if EV_SYN is defined, I should only terminate + * the population of device->currentValues struct IFF I receive + * that event. The fact of the matter is, the EV_MSC is assumed + * to be an ugliness that will take some time to be deprecated. + * For the nonce, we'll support both. But, if you have a tablet + * that's actually supplying something interesting with EV_MSC, + * this is obviously some code that requires modifications. + */ +#ifndef EV_SYN + if (event->type != EV_MSC) +#else + if (event->type != EV_MSC && event->type != EV_SYN) +#endif + { + continue; + } + + /* + * We've seen EV_MSCs in the incoming data trail with no + * other message types in-between. We use 'eventsInMessage' + * to count all 'real' messages in-between. If there were none, + * do NOT copy common->currentValues to common->previousValues + * (as this will make the jitter filter useless). Just go and + * read the subsequent events. + */ + if (eventsInMessage == 0) + { + continue; + } + eventsInMessage = 0; + + /* + * This filter throws out reports that do not meet minimum threshold + * requirements for movement along that axis. + * + * Presently, we discard the entire report if any dimension of the + * currentValues struct does not meet it's minimum threshold. + * + * Also, we only do the comparison IFF a threshold has been set + * for that given dimension. + */ + if (ABS(common->currentValues.x - common->previousValues.x) + <= device->xThreshold && + ABS(common->currentValues.y - common->previousValues.y) + <= device->yThreshold && + ABS(common->currentValues.z - common->previousValues.z) + <= device->zThreshold && + ABS(common->currentValues.xTilt - common->previousValues.xTilt) + <= device->xTiltThreshold && + ABS(common->currentValues.yTilt - common->previousValues.yTilt) + <= device->yTiltThreshold && + common->currentValues.proximity == + common->previousValues.proximity && + common->currentValues.button == + common->previousValues.button && + common->currentValues.macroKey == + common->previousValues.macroKey) + { + DBG(10, ErrorF("Event Filtered Out by Thresholds\n")); + continue; + } + + /* + * We have three different methods by which we report pressure, Z. + * One is to use linear values from 0 to common->zCapacity. The + * other two, SOFT_SMOOTH and HARD_SMOOTH, use different + * algorithms to 'smooth out' the values. + */ + d_z = (double)common->currentValues.z; + d_zCapacity = (double)common->zCapacity; + + switch (device->zMode) + { + case VALUE_NA: + case PRESSURE_MODE_LINEAR: + { + /* Leave Z alone. */ + } + break; + + case PRESSURE_MODE_SOFT_SMOOTH: + { + d_z = (d_z * d_z / d_zCapacity)+ 0.5; + } + break; + + case PRESSURE_MODE_HARD_SMOOTH: + { + d_z = (d_zCapacity * sqrt( d_z / d_zCapacity)) + 0.5; + } + break; + } + + /* Dispatch events to all of our configured devices. */ + for (i=0; i < common->numDevices; ++i) + { + AiptekDevicePtr dev = common->deviceArray[i]->private; + int id; + + id = DEVICE_ID (dev->flags); + + /* Find the device the current events are meant for */ + if (id == common->currentValues.eventType) + { + /* We left 'z' alone during smoothing, so send up + * perturbed value outside of the struct + */ + xf86AiptekSendEvents(common->deviceArray[i], (int) d_z); + } + } + + /* + * Copy the values just processed into the previousValues struct, + * so we can check for 'jittering' in the subsequent report. + */ + common->previousValues.eventType = common->currentValues.eventType; + common->previousValues.x = common->currentValues.x; + common->previousValues.y = common->currentValues.y; + common->previousValues.z = common->currentValues.z; + common->previousValues.proximity = common->currentValues.proximity; + common->previousValues.button = common->currentValues.button; + common->previousValues.macroKey = common->currentValues.macroKey; + common->previousValues.xTilt = common->currentValues.xTilt; + common->previousValues.yTilt = common->currentValues.yTilt; + common->previousValues.distance = common->currentValues.distance; + common->previousValues.wheel = common->currentValues.wheel; + + common->currentValues.macroKey = VALUE_NA; + } +} + +/* + *************************************************************************** + * + * xf86AiptekHIDOpen -- + * + *************************************************************************** + */ +static Bool +xf86AiptekHIDOpen(LocalDevicePtr local) +{ + AiptekDevicePtr device = (AiptekDevicePtr)local->private; + AiptekCommonPtr common = device->common; + char name[256] = "Unknown"; + int abs[5]; + unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; + int i, j; + int err = 0; + int version; + + local->fd = xf86OpenSerial(local->options); + if (local->fd == -1) + { + ErrorF("xf86AiptekHIDOpen Error opening %s : %s\n", common->deviceName, strerror(errno)); + return !Success; + } + + ioctl(local->fd, EVIOCGNAME(sizeof(name)), name); + ErrorF("%s HID Device name: \"%s\"\n", XCONFIG_PROBED, name); + + ioctl(local->fd, EVIOCGVERSION, &version); + ErrorF("%s HID Driver Version: %d.%d.%d\n", XCONFIG_PROBED, + version>>16, (version>>8) & 0xff, version & 0xff); + + ErrorF("%s HID Driver knows it has %d devices configured\n", XCONFIG_PROBED, + common->numDevices); + ErrorF("%s HID Driver is using %d as the fd\n", XCONFIG_PROBED, local->fd); + + for (i = 0; i < common->numDevices; ++i) + { + common->deviceArray[i]->read_input = xf86AiptekHIDReadInput; + common->deviceArray[i]->fd = local->fd; + common->deviceArray[i]->flags |= XI86_POINTER_CAPABLE | XI86_CONFIGURED; + } + common->open = xf86AiptekHIDOpen; + + memset(bit, 0, sizeof(bit)); + ioctl(local->fd, EVIOCGBIT(0, EV_MAX), bit[0]); + + for (i = 0; i < EV_MAX; ++i) + { + if (TEST_BIT(i, bit[0])) + { + ioctl(local->fd, EVIOCGBIT(i, KEY_MAX), bit[i]); + for (j = 0; j < KEY_MAX; ++j) + { + if (TEST_BIT(j, bit[i])) + { + if (i == EV_ABS) + { + ioctl(local->fd, EVIOCGABS(j), abs); + switch (j) + { + case ABS_X: + { + ErrorF("From ioctl() xCapacity=%d\n", abs[2]); + common->xCapacity = abs[2]; + } + break; + + case ABS_Y: + { + ErrorF("From ioctl() yCapacity=%d\n", abs[2]); + common->yCapacity = abs[2]; + } + break; + + case ABS_Z: + { + ErrorF("From ioctl() zCapacity=%d\n", abs[2]); + common->zCapacity = abs[2]; + } + break; + } + } + } + } + } + } + + if (err < 0) + { + ErrorF("xf86AiptekHIDOpen ERROR: %d\n", err); + SYSCALL(close(local->fd)); + return !Success; + } + + return Success; +} + +/* + * xf86AiptekControlProc + */ +static void +xf86AiptekControlProc(DeviceIntPtr device, PtrCtrl *ctrl) +{ + DBG(2, ErrorF("xf86AiptekControlProc\n")); +} + +/* +** xf86AiptekOpen + * Open and initialize the tablet, as well as probe for any needed data. + * (This is TTY style open) + */ + +static Bool +xf86AiptekOpen(LocalDevicePtr local) +{ + AiptekDevicePtr device = (AiptekDevicePtr)local->private; + AiptekCommonPtr common = device->common; + int err, version; + + DBG(1, ErrorF("Opening %s\n", common->deviceName)); + + local->fd = xf86OpenSerial(local->options); + if (local->fd < 0) + { + ErrorF("Error opening %s: %s\n", common->deviceName, strerror(errno)); + return !Success; + } + + DBG(1, ErrorF("Testing USB\n")); + + SYSCALL(err = ioctl(local->fd, EVIOCGVERSION, &version)); + if (!err) + { + int j; + + SYSCALL(close(local->fd)); + + for(j=0; jnumDevices; ++j) + { + common->deviceArray[j]->read_input=xf86AiptekHIDReadInput; + } + common->open=xf86AiptekHIDOpen; + + return xf86AiptekHIDOpen(local); + } + + /* We do not support TTY mode, so just exit angry. */ + return !Success; +} + +/* + * xf86AiptekOpenDevice + * Opens and initializes the device driver. + */ +static int +xf86AiptekOpenDevice(DeviceIntPtr pDriver) +{ + LocalDevicePtr local = (LocalDevicePtr)pDriver->public.devicePrivate; + AiptekDevicePtr device = (AiptekDevicePtr)PRIVATE(pDriver); + AiptekCommonPtr common = device->common; + double tabletRatio, screenRatio; + double xFactor, yFactor; + int gap, loop; + + DBG(2, ErrorF("In xf86AiptekOpenDevice, with fd=%d\n", local->fd)); + + if (local->fd < 0) + { + if (common->initNumber > 2 || + device->initNumber == common->initNumber) + { + if (common->open(local) != Success) + { + if (local->fd >= 0) + { + SYSCALL(close(local->fd)); + } + local->fd = -1; + return !Success; + } + else + { + /* Report the file descriptor to all devices */ + for (loop=0; loop < common->numDevices; ++loop) + { + common->deviceArray[loop]->fd = local->fd; + } + } + common->initNumber++; + } + device->initNumber = common->initNumber; + } + + /* + * Check our active area parameters. We support the following + * three sets of mutually exclusive parameter sets: + * 1) xMax/yMax. The origin (0,0) of the active area is the origin + * of the physical tablet. You therefore are describing the + * width and height of that active area. + * 2) xOffset/xSize,yOffset/ySize. The origin (0,0) of the active + * area is defined as (xOffset,yOffset) (which we'll report as + * (0,0)). The size of the active area in width and height are + * expressed in coordinates as xSize/ySize. That is to say, + * if xOffset=5; yOffset=5, and xSize=10; ySize=10, then we will + * have an active area beginning at (5,5) and ending at (15,15). + * Physical coordinate (5,5) is reported as (0,0); (15,15) is + * reported as (10,10). The rest of the tablet is inert, as far as + * drawing area goes, + * 3) xTop/xBottom,yTop/yBottom. The difference between this and + * #2 above is that all four parameters are physical coordinates + * on the tablet. Using the example above, xTop=5; yTop=5, and + * xBottom=15; yBottom=15. It is inferred mathematically that + * the overall active area is 10x10 coordinates. + * + * NOTE: Mutually exclusive means just that: choose the set of + * parameters you like, and use them throughout. If you user xSize, + * yOffset and xBottom, we'll have NO idea what you want, and quite + * frankly you'll have tempted Fate enough that Bad Things(tm) will + * happen to you. Do not complain to us! + */ + if (device->xMax != VALUE_NA || + device->yMax != VALUE_NA) + { + /* Deal with larger-than-tablet and NA values. + */ + if (device->xMax > common->xCapacity || + device->xMax == VALUE_NA) + { + device->xMax = common->xCapacity; + xf86Msg(X_CONFIG, "xMax value invalid; adjusting to %d\n", + device->xMax); + } + if (device->yMax > common->yCapacity || + device->yMax == VALUE_NA) + { + device->yMax = common->yCapacity; + xf86Msg(X_CONFIG,"yMax value invalid; adjusting to %d\n", + device->yMax); + } + + /* + * Internally we use xTop/yTop/xBottom/yBottom + * for everything. It's the easiest for us to work + * with, vis-a-vis filtering. + */ + + device->xTop = 0; + device->yTop = 0; + device->xBottom = device->xMax; + device->yBottom = device->yMax; + } + + /* + * Deal with xOffset/yOffset;xSize/ySize parameters + */ + if (device->xSize != VALUE_NA || + device->ySize != VALUE_NA || + device->xOffset != VALUE_NA || + device->yOffset != VALUE_NA) + { + int message = 0; + /* Simple sanity tests: nothing larger than the + * tablet; nothing negative, except for an NA value. + */ + if (device->xOffset != VALUE_NA && + (device->xOffset > common->xCapacity || + device->xOffset < 0)) + { + message = 1; + device->xOffset = 0; + } + if (device->yOffset != VALUE_NA && + (device->yOffset > common->yCapacity || + device->yOffset < 0)) + { + message = 1; + device->yOffset = 0; + } + if (device->xSize != VALUE_NA && + (device->xSize > common->xCapacity || + device->xSize < 0)) + { + message = 1; + device->xSize = common->xCapacity; + } + if (device->ySize != VALUE_NA && + (device->ySize > common->yCapacity || + device->ySize < 0)) + { + message = 1; + device->ySize = common->yCapacity; + } + + /* + * If one parameter is set but not the other, we'll + * guess at something reasonable for the missing one. + */ + if (device->xOffset == VALUE_NA || + device->xSize == VALUE_NA) + { + if (device->xOffset == VALUE_NA) + { + message = 1; + device->xOffset = 0; + } + else + { + message = 1; + device->xSize = common->xCapacity - device->xOffset; + } + } + if (device->yOffset == VALUE_NA || + device->ySize == VALUE_NA) + { + if (device->yOffset == VALUE_NA) + { + message = 1; + device->yOffset = 0; + } + else + { + message = 1; + device->ySize = common->yCapacity - device->yOffset; + } + } + + /* + * Do not allow the active area to exceed the size of the + * tablet. To do this, we have to consider both parameters. + * Assumption: xOffset/yOffset is always correct; deliver less + * of the tablet than they asked for, if they asked for too much. + */ + if (device->xOffset + device->xSize > common->xCapacity) + { + message = 1; + device->xSize = common->xCapacity - device->xOffset; + } + if (device->yOffset + device->ySize > common->yCapacity) + { + message = 1; + device->ySize = common->yCapacity - device->yOffset; + } + + /* + * 'message' is used to indicate that we've changed some parameter + * during our filtration process. It's conceivable that we may + * have changed parameters several times, so we without commentary + * to the very end. + */ + if (message == 1) + { + xf86Msg(X_CONFIG,"xOffset/yOffset;xSize/ySize values wrong.\n"); + xf86Msg(X_CONFIG,"xOffset adjusted to %d\n", device->xOffset); + xf86Msg(X_CONFIG,"yOffset adjusted to %d\n", device->yOffset); + xf86Msg(X_CONFIG,"xSize adjusted to %d\n", device->xSize); + xf86Msg(X_CONFIG,"ySize adjusted to %d\n", device->ySize); + } + + /* + * Internally we use xTop/yTop/xBottom/yBottom + * for everything. It's the easiest for us to work + * with, vis-a-vis filtering. + */ + device->xTop = device->xOffset; + device->yTop = device->yOffset; + device->xBottom = device->xOffset + device->xSize; + device->yBottom = device->yOffset + device->ySize; + } + + /* + * Third set of parameters. Because everything internally + * is expressed as xTop/yTop, etc., I'll do tests on transformed + * values from the other parameters as need. My last chance to do + * so. + */ + if (device->xTop == VALUE_NA || + device->xTop < 0 || + device->xTop > common->xCapacity) + { + device->xTop = 0; + xf86Msg(X_CONFIG,"xTop invalid; adjusted to %d\n", device->xTop); + } + if (device->yTop == VALUE_NA || + device->yTop < 0 || + device->yTop > common->yCapacity) + { + device->yTop = 0; + xf86Msg(X_CONFIG,"yTop invalid; adjusted to %d\n", device->yTop); + } + if (device->xBottom == VALUE_NA || + device->xBottom < 0 || + device->xBottom > common->xCapacity) + { + device->xBottom = common->xCapacity; + xf86Msg(X_CONFIG,"xBottom invalid; adjusted to %d\n", + device->xBottom); + } + if (device->yBottom == VALUE_NA || + device->yBottom < 0 || + device->yBottom > common->yCapacity) + { + device->yBottom = common->yCapacity; + xf86Msg(X_CONFIG,"yBottom invalid; adjusted to %d\n", + device->yBottom); + } + + /* + * Determine the X screen we're going to be using. + * If NA, or larger than the number of screens we + * have, or negative, we've going for screen 0, e.g., + * 'default' screen. + */ + if ( device->screenNo >= screenInfo.numScreens || + device->screenNo == VALUE_NA || + device->screenNo < 0) + { + device->screenNo = 0; + xf86Msg(X_CONFIG,"ScreenNo invalid; adjusted to %d\n", + device->screenNo); + } + + /* Calculate the ratio according to KeepShape, TopX and TopY */ + + if (device->flags & KEEP_SHAPE_FLAG) + { + int xDiff, yDiff; + + xDiff = common->xCapacity - device->xTop; + yDiff = common->yCapacity - device->yTop; + + tabletRatio = (double) xDiff / (double) yDiff; + screenRatio = (double) screenInfo.screens[device->screenNo]->width / + (double) screenInfo.screens[device->screenNo]->height; + + DBG(2, ErrorF("Screen %d: screenRatio = %.3g, tabletRatio = %.3g\n", + device->screenNo, screenRatio, tabletRatio)); + + if (screenRatio > tabletRatio) + { + gap = (int)((double)common->yCapacity * + (1.0 - tabletRatio/screenRatio)); + device->xBottom = common->xCapacity; + device->yBottom = common->yCapacity - gap; + DBG(2, ErrorF("Screen %d: 'Y' Gap of %d computed\n", + device->screenNo, gap)); + } + else + { + gap = (int)((double)common->xCapacity * + (1.0 - screenRatio/tabletRatio)); + device->xBottom = common->xCapacity - gap; + device->yBottom = common->yCapacity; + DBG(2, ErrorF("Screen %d: 'X' Gap of %d computed\n", + device->screenNo, gap)); + } + } + + xFactor = (double)screenInfo.screens[device->screenNo]->width/ + (double)(device->xBottom - device->xTop); + yFactor = (double)screenInfo.screens[device->screenNo]->height/ + (double)(device->yBottom - device->yTop); + + /* + * Check threshold correctness + */ + if (device->xThreshold > common->xCapacity || + device->xThreshold == VALUE_NA || + device->xThreshold < 0) + { + device->xThreshold = 0; + } + + if (device->yThreshold > common->yCapacity || + device->yThreshold == VALUE_NA || + device->yThreshold < 0) + { + device->yThreshold = 0; + } + + if (device->zThreshold > common->zCapacity || + device->zThreshold == VALUE_NA || + device->zThreshold < 0) + { + device->zThreshold = 0; + } + + /* Create axisStructs for every axis we support. + * NOTE: min_resolution and max_resolution infers to + * me a programmability to increase/decrease resolution. + * We don't support that, so min & max = current_resolution. + */ + InitValuatorAxisStruct(pDriver, /* X resolution */ + 0, /* axis_id */ + 0, /* min value */ + device->xBottom - device->xTop, /* max value */ + LPI2CPM(375), /* resolution */ + LPI2CPM(375), /* min_resolution */ + LPI2CPM(375)); /* max_resolution */ + + InitValuatorAxisStruct(pDriver, /* Y Resolution */ + 1, /* axis_id */ + 0, /* min value */ + device->yBottom - device->yTop, /* max value */ + LPI2CPM(375), /* resolution */ + LPI2CPM(375), /* min_resolution */ + LPI2CPM(375)); /* max_resolution */ + + InitValuatorAxisStruct(pDriver, /* Pressure */ + 2, /* axis_id */ + 0, /* min value */ + 511, /* max value */ + 512, /* resolution */ + 512, /* min_resolution */ + 512); /* max_resolution */ + + InitValuatorAxisStruct(pDriver, /* xTilt */ + 3, /* axis id */ + -128, /* min value */ + 127, /* max value */ + 256, /* resolution */ + 256, /* min_resolution */ + 256); /* max_resolution */ + + InitValuatorAxisStruct(pDriver, /* yTilt */ + 4, /* axis_id */ + -128, /* min value */ + 127, /* max value */ + 256, /* resolution */ + 256, /* min_resolution */ + 256); /* max_resolution */ + + /* + * The sixth axis would be for wheel support. We do not have + * any wheel devices. But if we did, it would be allocated + * here. + */ + return (local->fd != -1); +} + +/* + * xf86AiptekProc + * + * Call dispatcher for this driver. + */ +static int +xf86AiptekProc(DeviceIntPtr pAiptek, int requestCode) +{ + CARD8 map[512+1]; + int numAxes; + int numButtons; + int loop; + LocalDevicePtr local = (LocalDevicePtr)pAiptek->public.devicePrivate; + AiptekDevicePtr device = (AiptekDevicePtr)PRIVATE(pAiptek); + + DBG(2, ErrorF("xf86AiptekProc() type=%s flags=%d request=%d\n", + (DEVICE_ID(device->flags) == STYLUS_ID) ? "stylus" : + (DEVICE_ID(device->flags) == CURSOR_ID) ? "cursor" : "eraser", + device->flags, requestCode)); + + switch (requestCode) + { + case DEVICE_INIT: + { + DBG(1, ErrorF("xf86AiptekProc request=INIT\n")); + numAxes = 5; /* X, Y, Z, xTilt, yTilt */ + numButtons = 5; + + for(loop=1; loop<=numButtons; ++loop) + { + map[loop] = loop; + } + + if (InitButtonClassDeviceStruct(pAiptek,numButtons,map) == FALSE) + { + ErrorF("Unable to init Button Class Device\n"); + return !Success; + } + + if (InitFocusClassDeviceStruct(pAiptek) == FALSE) + { + ErrorF("Unable to init Focus Class Device\n"); + return !Success; + } + + if (InitPtrFeedbackClassDeviceStruct(pAiptek, + xf86AiptekControlProc) == FALSE) + { + ErrorF("Unable to init Pointer Feedback Class Device\n"); + return !Success; + } + + if (InitProximityClassDeviceStruct(pAiptek) == FALSE) + { + ErrorF("Unable to init Proximity Class Device\n"); + return !Success; + } + + if (InitKeyClassDeviceStruct(pAiptek, &keysyms, NULL) ==FALSE) + { + ErrorF("Unable to init Key Class Device\n"); + return !Success; + } + + if (InitValuatorClassDeviceStruct(pAiptek, + numAxes, + xf86GetMotionEvents, + local->history_size, + ((device->flags & ABSOLUTE_FLAG) + ? Absolute : Relative) | OutOfProximity ) == FALSE) + { + ErrorF("Unable to allocate Valuator Class Device\n"); + return !Success; + } + + /* Allocate the motion history buffer if needed */ + xf86MotionHistoryAllocate(local); + + /* Open the device to gather information */ + xf86AiptekOpenDevice(pAiptek); + } + break; + + case DEVICE_ON: + { + DBG(1, ErrorF("xf86AiptekProc request=ON\n")); + + if ((local->fd < 0) && + (!xf86AiptekOpenDevice(pAiptek))) + { + ErrorF("Unable to open aiptek device\n"); + return !Success; + } + ErrorF("Able to open aiptek device\n"); + xf86AddEnabledDevice(local); + pAiptek->public.on = TRUE; + } + break; + + case DEVICE_OFF: + { + DBG(1, ErrorF("xf86AiptekProc request=%s\n", + (requestCode == DEVICE_CLOSE) ? "CLOSE" : "OFF")); + if (local->fd >= 0) + { + xf86AiptekClose(local); + xf86RemoveEnabledDevice(local); + } + pAiptek->public.on = FALSE; + } + break; + + case DEVICE_CLOSE: + { + DBG(1, ErrorF("xf86AiptekProc request=%s\n", + (requestCode == DEVICE_CLOSE) ? "CLOSE" : "OFF")); + xf86AiptekClose(local); + } + break; + + default: + { + ErrorF("xf86AiptekProc - Unsupported mode=%d\n", requestCode); + return !Success; + } + break; + } + DBG(2, ErrorF("xf86AiptekProc Success request=%d\n", requestCode )); + return Success; +} + +/* + * xf86AiptekClose + * Perhaps this will close the device + */ +static void +xf86AiptekClose(LocalDevicePtr local) +{ + if (local->fd >= 0) + { + SYSCALL(close(local->fd)); + } + local->fd = -1; +} + +/* + * xf86AiptekChangeControl + * Allow the user to change the tablet resolution -- we have an issue + * insofar as we don't know how to write to the tablet. And furthermore, + * even if we DID know how to write to the tablet, it doesn't support + * a "change resolution" call. We tried to avoid this by claiming when + * creating axisStructs that minRes = curRes = maxRes. So, we should never + * get dispatched. + */ +static int +xf86AiptekChangeControl(LocalDevicePtr local, xDeviceCtl *control) +{ + xDeviceResolutionCtl *res; + int *resolutions; + + DBG(3, ErrorF("xf86AiptekChangeControl() entered\n")); + + res = (xDeviceResolutionCtl *)control; + + if ((control->control != DEVICE_RESOLUTION) || + (res->num_valuators < 1)) + { + DBG(3, ErrorF("xf86AiptekChangeControl abends\n")); + return (BadMatch); + } + + resolutions = (int *)(res +1); + + DBG(3, ErrorF("xf86AiptekChangeControl changing to res %d\n", + resolutions[0])); + + /* We don't know how to write, yet + * + * sprintf(str, "SU%d\r", resolutions[0]); + * SYSCALL(write(local->fd, str, strlen(str))); + */ + + return(Success); +} + +/* + * xf86AiptekSwitchMode + * Switches the mode. For now just absolute or relative, hopefully + * more on the way. + */ +static int +xf86AiptekSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) +{ + LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; + AiptekDevicePtr device = (AiptekDevicePtr)(local->private); + + DBG(3, ErrorF("xf86AiptekSwitchMode() dev=%p mode=%d\n", dev, mode)); + + switch(mode) + { + case Absolute: + { + device->flags |= ABSOLUTE_FLAG; + } + break; + + case Relative: + { + device->flags &= ~ABSOLUTE_FLAG; + } + break; + + default: + { + DBG(1, ErrorF("xf86AiptekSwitchMode dev=%p invalid mode=%d\n", + dev, mode)); + return BadMatch; + } + break; + } + + return Success; +} + +/* + * xf86AiptekAllocate + * Allocates the device structures for the Aiptek. + */ +static LocalDevicePtr +xf86AiptekAllocate(char* name, + int flag) +{ + LocalDevicePtr local; + LocalDevicePtr* deviceArray; + AiptekDevicePtr device; + AiptekCommonPtr common; + + DBG(3, ErrorF("xf86AiptekAllocate, with %s and %d\n", name, flag)); + + device = (AiptekDevicePtr) xalloc(sizeof(AiptekDeviceRec)); + if (!device) + { + DBG(3, ErrorF("xf86AiptekAllocate failed to allocate 'device'\n")); + return NULL; + } + + common = (AiptekCommonPtr) xalloc(sizeof(AiptekCommonRec)); + if (!common) + { + DBG(3, ErrorF("xf86AiptekAllocate failed to allocate 'common'\n")); + xfree(device); + return NULL; + } + + deviceArray = (LocalDevicePtr*) xalloc(sizeof(LocalDevicePtr)); + if (!deviceArray) + { + DBG(3, ErrorF("xf86AiptekAllocate failed to allocate 'deviceArray'\n")); + xfree(device); + xfree(common); + return NULL; + } + + + local = xf86AllocateInput(aiptekDrv, 0); + if (!local) + { + DBG(3, ErrorF("xf86AiptekAllocate failed at xf86AllocateInput()\n")); + xfree(device); + xfree(common); + xfree(deviceArray); + return NULL; + } + + local->name = name; + local->type_name = "Aiptek"; + local->flags = 0; + local->device_control = xf86AiptekProc; + local->read_input = xf86AiptekHIDReadInput; + local->control_proc = xf86AiptekChangeControl; + local->close_proc = xf86AiptekClose; + local->switch_mode = xf86AiptekSwitchMode; + local->conversion_proc = xf86AiptekConvert; + local->reverse_conversion_proc = xf86AiptekReverseConvert; + + local->fd = VALUE_NA; + local->atom = 0; + local->dev = NULL; + local->private = device; + local->private_flags = 0; + local->history_size = 0; + + device->flags = flag; /* various flags (device type, + * coordinate type */ + device->xSize = VALUE_NA; /* Active Area X */ + device->ySize = VALUE_NA; /* Active Area Y */ + device->xOffset = VALUE_NA; /* Active area offset X */ + device->yOffset = VALUE_NA; /* Active area offset Y */ + device->xMax = VALUE_NA; /* Max allowed X value */ + device->yMax = VALUE_NA; /* Max allowed Y value */ + device->zMin = VALUE_NA; /* Min allowed Z value */ + device->zMax = VALUE_NA; /* Max allowed Z value */ + device->xTop = VALUE_NA; /* Upper Left X coordinate */ + device->yTop = VALUE_NA; /* Upper Left Y coordinate */ + device->xBottom = VALUE_NA; /* Lower Right X coordinate */ + device->yBottom = VALUE_NA; /* Lower Right Y coordinate */ + device->xThreshold = VALUE_NA; /* X delta must be greater than */ + device->yThreshold = VALUE_NA; /* Y delta must be greater than */ + device->zThreshold = VALUE_NA; /* Z delta must be greater than */ + device->xTiltThreshold =VALUE_NA; + device->yTiltThreshold =VALUE_NA; + device->zMode = VALUE_NA; /* Z: linear, soft, hard log */ + + device->initNumber = VALUE_NA; /* avoid re-init devices */ + device->screenNo = VALUE_NA; /* Attached to X screen */ + + device->common = common; /* Common info pointer */ + + /* Record of the event currently being read of the queue */ + common->currentValues.eventType = STYLUS_ID; + /* Device event is for, e.g., */ + /* STYLUS, RUBBER, CURSOR */ + /* Starting with stylus as default */ + common->currentValues.x = 0; /* X coordinate */ + common->currentValues.y = 0; /* Y coordinate */ + common->currentValues.z = 0; /* Z (pressure) */ + common->currentValues.xTilt = 0; /* XTilt */ + common->currentValues.yTilt = 0; /* YTilt */ + common->currentValues.proximity = 0; /* proximity bit */ + common->currentValues.macroKey = VALUE_NA; /* tablet macro key code */ + common->currentValues.button = 0; /* bitmask of buttons pressed */ + common->currentValues.distance = 0; /* currently unsupported */ + common->currentValues.wheel = 0; /* likewise */ + + /* Record of the event previously read off of the queue */ + common->previousValues.eventType = 0; /* Same comments as above */ + common->previousValues.x = 0; + common->previousValues.y = 0; + common->previousValues.z = 0; + common->previousValues.xTilt = 0; + common->previousValues.yTilt = 0; + common->previousValues.proximity = 0; + common->previousValues.macroKey = VALUE_NA; + common->previousValues.button = 0; + common->previousValues.distance = 0; + common->previousValues.wheel = 0; + + common->deviceName = ""; /* device file name */ + common->flags = 0; /* various flags */ + common->deviceArray = deviceArray; /* Array of tablets */ + common->deviceArray[0]= local; /* with local as element */ + common->numDevices = 1; /* number of devices */ + + common->xCapacity = 0; /* tablet's max X value */ + common->yCapacity = 0; /* tablet's max Y value */ + common->zCapacity = 0; /* tablet's max Z value */ + common->open = xf86AiptekOpen; /* Open function */ + + return local; +} + +/* + * xf86AiptekAllocateStylus + */ +static LocalDevicePtr +xf86AiptekAllocateStylus(void) +{ + LocalDevicePtr local = xf86AiptekAllocate(XI_STYLUS, STYLUS_ID); + + if (local) + { + local->type_name = "Stylus"; + } + return local; +} + +/* + * xf86AiptekAllocateCursor + */ +static LocalDevicePtr +xf86AiptekAllocateCursor(void) +{ + LocalDevicePtr local = xf86AiptekAllocate(XI_CURSOR, CURSOR_ID); + + if (local) + { + local->type_name = "Cursor"; + } + return local; +} + +/* + * xf86AiptekAllocateEraser + */ +static LocalDevicePtr +xf86AiptekAllocateEraser(void) +{ + LocalDevicePtr local = xf86AiptekAllocate(XI_ERASER, + ABSOLUTE_FLAG|ERASER_ID); + + if (local) + { + local->type_name = "Eraser"; + } + return local; +} + +/* + * Stylus device association + */ +DeviceAssocRec aiptek_stylus_assoc = +{ + STYLUS_SECTION_NAME, /* config_section_name */ + xf86AiptekAllocateStylus /* device_allocate */ +}; + +/* + * Cursor device association + */ +DeviceAssocRec aiptek_cursor_assoc = +{ + CURSOR_SECTION_NAME, /* config_section_name */ + xf86AiptekAllocateCursor /* device_allocate */ +}; + +/* + * Eraser device association + */ +DeviceAssocRec aiptek_eraser_assoc = +{ + ERASER_SECTION_NAME, /* config_section_name */ + xf86AiptekAllocateEraser /* device_allocate */ +}; + +/* + * xf86AiptekUninit -- + * + * called when the driver is unloaded. + */ +static void +xf86AiptekUninit(InputDriverPtr drv, + LocalDevicePtr local, + int flags) +{ + AiptekDevicePtr device = (AiptekDevicePtr) local->private; + + DBG(1, ErrorF("xf86AiptekUninit\n")); + + xf86AiptekProc(local->dev, DEVICE_OFF); + + if (device->common && device->common->xCapacity != -10101) + { + device->common->xCapacity = -10101; + xfree(device->common); + } + xfree (device); + xf86DeleteInput(local, 0); +} + +/* + * xf86AiptekInit -- + * + * Called when the module subsection is found in XF86Config + */ +static InputInfoPtr +xf86AiptekInit(InputDriverPtr drv, + IDevPtr dev, + int flags) +{ + LocalDevicePtr local = NULL; + LocalDevicePtr fakeLocal = NULL; + AiptekDevicePtr device = NULL; + AiptekCommonPtr common = NULL; + LocalDevicePtr locals; + char* s; + int shared; + + aiptekDrv = drv; + + xf86Msg(X_INFO, "xf86AiptekInit(): begins\n"); + + fakeLocal = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec)); + if (!fakeLocal) + { + return NULL; + } + + fakeLocal->conf_idev = dev; + + /* + * fakeLocal is here so it can have default serial init values. + * Is this something to remove? TODO + */ + xf86CollectInputOptions(fakeLocal, default_options, NULL); + +/* Type */ + s = xf86FindOptionValue(fakeLocal->options, "Type"); + if (s && (xf86NameCmp(s, "stylus") == 0)) + { + local = xf86AiptekAllocateStylus(); + } + else if (s && (xf86NameCmp(s, "cursor") == 0)) + { + local = xf86AiptekAllocateCursor(); + } + else if (s && (xf86NameCmp(s, "eraser") == 0)) + { + local = xf86AiptekAllocateEraser(); + } + else + { + xf86Msg(X_ERROR, "%s: No type or invalid type specified.\n" + "Must be one of 'stylus', 'cursor', or 'eraser'\n", + dev->identifier); + } + + if(!local) + { + xfree(fakeLocal); + return NULL; + } + + device = (AiptekDevicePtr) local->private; + + common = device->common; + + local->options = fakeLocal->options; + local->conf_idev = fakeLocal->conf_idev; + local->name = dev->identifier; + xfree(fakeLocal); + +/* Device */ +/* (mandatory) */ + common->deviceName = xf86FindOptionValue(local->options, "Device"); + if(!common->deviceName) + { + xf86Msg(X_ERROR, "%s: No Device specified.\n", dev->identifier); + goto SetupProc_fail; + } + + /* + * Lookup to see if there is another aiptek device sharing the + * same device. + */ + + shared = 0; + for (locals = xf86FirstLocalDevice(); + locals != NULL; + locals = locals->next) + { + if((local != locals) && + (locals->device_control == xf86AiptekProc) && + (strcmp(((AiptekDevicePtr)locals->private)->common->deviceName, + common->deviceName) == 0)) + { + xf86Msg(X_CONFIG, + "xf86AiptekConfig: device shared between %s and %s\n", + local->name, + locals->name); + + shared = 1; + + xfree(common->deviceArray); + xfree(common); + + common = device->common = + ((AiptekDevicePtr) locals->private)->common; + common->numDevices++; + common->deviceArray = (LocalDevicePtr*)xrealloc(common->deviceArray, + sizeof(LocalDevicePtr)*common->numDevices); + common->deviceArray[common->numDevices-1] = local; + break; + } + else + { + xf86Msg(X_CONFIG, + "xf86AiptekConfig: device not shared btw %s and %s\n", + local->name, locals->name); + } + } + + /* Process the common options */ + xf86ProcessCommonOptions(local, local->options); + + /* If this is the first device using the aiptek driver, let's open + * the interface so as to obtain legit values for xCapacity and yCapacity + * (and then quickly close it). Yes, the word for this is "kludge". + * I am sufficiently ashamed :-) TODO kludge alert! + */ + if ( shared == 0) + { + xf86AiptekHIDOpen(local); + close(local->fd); + local->fd=-1; + } + + /* Optional configuration */ + xf86Msg(X_CONFIG, "%s device is %s\n", dev->identifier, + common->deviceName); + +/* DebugLevel */ + debug_level = xf86SetIntOption(local->options, "DebugLevel", debug_level); + if ( debug_level > 0) + { + xf86Msg(X_CONFIG, "Debug level set to %d\n", debug_level); + } + +/* zMode */ + s = xf86FindOptionValue(local->options, "Pressure"); + if ( s && (xf86NameCmp(s, "hard") == 0)) + { + device->zMode = PRESSURE_MODE_HARD_SMOOTH; + } + else if ( s && (xf86NameCmp(s, "soft") == 0)) + { + device->zMode = PRESSURE_MODE_SOFT_SMOOTH; + } + else if (s && (xf86NameCmp(s, "normal") == 0)) + { + device->zMode = PRESSURE_MODE_LINEAR; + } + else if (s) + { + xf86Msg(X_ERROR, "%s: invalid Mode ('normal', 'soft' or 'hard').\n", + dev->identifier); + } + +/* Mode */ + s = xf86FindOptionValue(local->options, "Mode"); + if (s && (xf86NameCmp(s, "absolute") == 0)) + { + device->flags |= ABSOLUTE_FLAG; + } + else if (s && (xf86NameCmp(s, "relative") == 0)) + { + device->flags &= ~ABSOLUTE_FLAG; + } + else if (s) + { + xf86Msg(X_ERROR, "%s: invalid Mode ('absolute' or 'relative').\n", + dev->identifier); + device->flags |= ABSOLUTE_FLAG; + } + xf86Msg(X_CONFIG, "%s is in %s mode\n", local->name, + (device->flags & ABSOLUTE_FLAG) ? "absolute" : "relative"); + +#ifdef LINUX_INPUT + /* The define-name is accurate; the XFree86 keyword is not. We are + * reading from a Linux kernel "Input" device. The Input device + * layer generally supports mice, joysticks, and keyboards. As + * an extension, the Input device layer also supports HID devices. + * HID is a standard specified by the USB Implementors Forum. Ergo, + * 99.9% of HID devices are USB devices. + * + * This option is misnamed, misunderstood, misanthrope. Maybe. + */ + if (xf86SetBoolOption(local->options, "USB", + (common->open == xf86AiptekHIDOpen))) + { + local->read_input=xf86AiptekHIDReadInput; + common->open=xf86AiptekHIDOpen; + xf86Msg(X_CONFIG, "%s: reading USB link\n", dev->identifier); + } +#else + if (xf86SetBoolOption(local->options, "USB", 0)) + { + ErrorF("The Aiptek USB driver isn't available for your platform.\n"); + goto SetupProc_fail; + } +#endif + +/* ScreenNo */ + device->screenNo = xf86SetIntOption(local->options, "ScreenNo", VALUE_NA); + if (device->screenNo != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: attached to screen number %d\n", + dev->identifier, device->screenNo); + } + +/* KeepShape */ + if (xf86SetBoolOption(local->options, "KeepShape", 0)) + { + device->flags |= KEEP_SHAPE_FLAG; + xf86Msg(X_CONFIG, "%s: keeps shape\n", dev->identifier); + } + +/* XSize */ + device->xSize = xf86SetIntOption(local->options, "XSize", device->xSize); + device->xSize = xf86SetIntOption(local->options, "SizeX", device->xSize); + if (device->xSize != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: XSize/SizeX = %d\n", dev->identifier, + device->xSize); + } + +/* YSize */ + device->ySize = xf86SetIntOption(local->options, "YSize", device->ySize); + device->ySize = xf86SetIntOption(local->options, "SizeY", device->ySize); + if (device->ySize != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: YSize/SizeY = %d\n", dev->identifier, + device->ySize); + } + +/* XOffset */ + device->xOffset = xf86SetIntOption(local->options, "XOffset", + device->xOffset); + device->xOffset = xf86SetIntOption(local->options, "OffsetX", + device->xOffset); + if (device->xOffset != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: XOffset/OffsetX = %d\n", dev->identifier, + device->xOffset); + } + +/* YOffset */ + device->yOffset = xf86SetIntOption(local->options, "YOffset", + device->yOffset); + device->yOffset = xf86SetIntOption(local->options, "OffsetY", + device->yOffset); + if (device->yOffset != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: YOffset/OffsetY = %d\n", dev->identifier, + device->yOffset); + } + +/* XThreshold */ + device->xThreshold = xf86SetIntOption(local->options, "XThreshold", + device->xThreshold); + device->xThreshold = xf86SetIntOption(local->options, "ThresholdX", + device->xThreshold); + if (device->xThreshold != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: XThreshold/ThresholdX = %d\n", + dev->identifier, device->xThreshold); + } + +/* YThreshold */ + device->yThreshold = xf86SetIntOption(local->options, "YThreshold", + device->yThreshold); + device->yThreshold = xf86SetIntOption(local->options, "ThresholdY", + device->yThreshold); + if (device->yThreshold != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: YThreshold/ThresholdY = %d\n", + dev->identifier, device->yThreshold); + } + +/* ZThreshold */ + device->zThreshold = xf86SetIntOption(local->options, "ZThreshold", + device->zThreshold); + device->zThreshold = xf86SetIntOption(local->options, "ThresholdZ", + device->zThreshold); + if (device->zThreshold != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: ZThreshold/ThresholdZ = %d\n", + dev->identifier, device->zThreshold); + } + +/* XTiltThreshold */ + device->xTiltThreshold = xf86SetIntOption(local->options, "XTiltThreshold", + device->xTiltThreshold); + device->xTiltThreshold = xf86SetIntOption(local->options, "ThresholdXTilt", + device->xTiltThreshold); + if (device->xTiltThreshold != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: XTiltThreshold = %d\n", + dev->identifier, device->xTiltThreshold); + } + +/* YTiltThreshold */ + device->yTiltThreshold = xf86SetIntOption(local->options, "YTiltThreshold", + device->yTiltThreshold); + device->yTiltThreshold = xf86SetIntOption(local->options, "ThresholdYTilt", + device->yTiltThreshold); + if (device->yTiltThreshold != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: YTiltThreshold = %d\n", + dev->identifier, device->yTiltThreshold); + } + +/* XMax */ + device->xMax = xf86SetIntOption(local->options, "XMax", device->xMax); + device->xMax = xf86SetIntOption(local->options, "MaxX", device->xMax); + if (device->xMax != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: XMax/MaxX = %d\n", dev->identifier, + device->xMax); + } + +/* YMax */ + device->yMax = xf86SetIntOption(local->options, "YMax", device->yMax); + device->yMax = xf86SetIntOption(local->options, "MaxY", device->yMax); + if (device->yMax != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: YMax/MaxY = %d\n", dev->identifier, + device->yMax); + } + +/* ZMax */ + device->zMax = xf86SetIntOption(local->options, "ZMax", device->zMax); + device->zMax = xf86SetIntOption(local->options, "MaxZ", device->zMax); + if (device->zMax != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: ZMax/MaxZ = %d\n", dev->identifier, + device->zMax); + } + +/* ZMin */ + device->zMin = xf86SetIntOption(local->options, "ZMin", device->zMin); + device->zMin = xf86SetIntOption(local->options, "MinZ", device->zMin); + if (device->zMin != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: ZMin/MinZ = %d\n", dev->identifier, + device->zMin); + } + +/* TopX */ + device->xTop = xf86SetIntOption(local->options, "TopX", device->xTop); + device->xTop = xf86SetIntOption(local->options, "XTop", device->xTop); + if (device->xTop != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: TopX/XTop = %d\n", dev->identifier, + device->xTop); + } + +/* TopY */ + device->yTop = xf86SetIntOption(local->options, "TopY", device->yTop); + device->yTop = xf86SetIntOption(local->options, "YTop", device->yTop); + if (device->yTop != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: TopY/YTop = %d\n", dev->identifier, + device->yTop); + } + +/* BottomX */ + device->xBottom = xf86SetIntOption(local->options, "BottomX", + device->xBottom); + device->xBottom = xf86SetIntOption(local->options, "XBottom", + device->xBottom); + if (device->xBottom != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: BottomX/XBottom = %d\n", dev->identifier, + device->xBottom); + } + +/* BottomY */ + device->yBottom = xf86SetIntOption(local->options, "BottomY", + device->yBottom); + device->yBottom = xf86SetIntOption(local->options, "YBottom", + device->yBottom); + if (device->yBottom != VALUE_NA) + { + xf86Msg(X_CONFIG, "%s: BottomY/YBottom = %d\n", dev->identifier, + device->yBottom); + } + +/* InvX */ + if (xf86SetBoolOption(local->options, "InvX", FALSE)) + { + device->flags |= INVX_FLAG; + xf86Msg(X_CONFIG, "%s: InvX\n", dev->identifier); + } + +/* InvY */ + if (xf86SetBoolOption(local->options, "InvY", FALSE)) + { + device->flags |= INVY_FLAG; + xf86Msg(X_CONFIG, "%s: InvY\n", dev->identifier); + } + +/* BaudRate */ + { + int val; + val = xf86SetIntOption(local->options, "BaudRate", 0); + + switch(val) + { + case 19200: + break; + case 9600: + break; + default: + xf86Msg(X_ERROR, "%s: Illegal BaudRate (9600 or 19200).", + dev->identifier); + break; + } + if (xf86Verbose) + { + xf86Msg(X_CONFIG, "%s: BaudRate %u\n", dev->identifier, + val); + } + } + xf86Msg(X_CONFIG, "%s: xf86AiptekInit() finished\n", dev->identifier); + + /* Mark the device as configured */ + local->flags |= XI86_POINTER_CAPABLE | XI86_CONFIGURED; + + /* return the LocalDevice */ + return (local); + +SetupProc_fail: + if (common) + xfree(common); + if (device) + xfree(device); + if (local) + xfree(local); + return NULL; +} + +/* + *************************************************************************** + * + * Dynamic loading functions + * + *************************************************************************** + */ +#ifdef XFree86LOADER +/* + * xf86AiptekUnplug -- + * + * called when the module subsection is found in XF86Config + */ +static void +xf86AiptekUnplug(pointer p) +{ + DBG(1, ErrorF("xf86AiptekUnplug\n")); +} + +/* + * xf86AiptekPlug -- + * + * called when the module subsection is found in XF86Config + */ +static pointer +xf86AiptekPlug(pointer module, + pointer options, + int* errmaj, + int* errmin) +{ + DBG(1, ErrorF("xf86AiptekPlug\n")); + + xf86AddInputDriver(&AIPTEK, module, 0); + + return module; +} + +static XF86ModuleVersionInfo xf86AiptekVersionRec = +{ + "aiptek", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 1, 0, + ABI_CLASS_XINPUT, + ABI_XINPUT_VERSION, + MOD_CLASS_XINPUT, + {0, 0, 0, 0} /* signature, to be patched into the file by + * a tool + * */ +}; + +_X_EXPORT XF86ModuleData aiptekModuleData = +{ + &xf86AiptekVersionRec, + xf86AiptekPlug, + xf86AiptekUnplug +}; + +#endif /* XFree86LOADER */ + +/* end of xf86Aiptek.c */ diff -Naur xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.h xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.h --- xf86-input-aiptek-1.0.1.orig/src/xf86Aiptek.h 2006-04-07 18:50:50.000000000 +0200 +++ xf86-input-aiptek-1.0.1.mod/src/xf86Aiptek.h 2008-01-09 23:04:56.000000000 +0100 @@ -98,6 +98,12 @@ #define XI_CURSOR "CURSOR" /* X device name for the cursor */ #define XI_ERASER "ERASER" /* X device name for the eraser */ +/*********************************************************************** + * We ship the proximity bit through EV_MISC, ORed with information + * as to whether report came from the stylus or tablet mouse. + */ +#define PROXIMITY(flags) ((flags) & 0x0F) + /* macro from counts/inch to counts/meter */ #define LPI2CPM(res) (res * 1000 / 25.4)