[PATCH 2.6.20 1/1] usb/input updated aiptek tablet driver
"Rene van Paassen" <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello all, This is a patch for the aiptek tablet input driver. It is the result of development work done on this driver at aiptektablet.sourceforce.net A summary of the important changes: - corrected proximity (p) and data valid (dv) flags. - corrected mouse button defines - corrected problems with relative mode - function keys of the tablet now are functional - corrected specification of tablet capabilities; using set_bit() old code was wrong for bits > 32 - code now includes a proximity timeout, for tablets that do not send p=0 (out of proximity) and dv=1 (valid report). Only enable for buggy tablets or people who really quickly jerk the stylus from the tablet. Signed-off-by: René van Paassen <[email protected]> --- linux-2.6.20/drivers/usb/input/aiptek.c.orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/drivers/usb/input/aiptek.c 2007-03-05 22:52:51.000000000 +0100 @@ -4,6 +4,7 @@ * * Copyright (c) 2001 Chris Atenasio <[email protected]> * Copyright (c) 2002-2004 Bryan W. Headley <[email protected]> + * Extra bits 2004 René van Paassen <[email protected]> * * based on wacom.c by * Vojtech Pavlik <[email protected]> @@ -45,6 +46,38 @@ * Feb 20, 2004, Bryan W. Headley. * v1.5 - Added previousJitterable, so we don't do jitter delay when the * user is holding a button down for periods of time. + * v1.6 - Corrected mouse button detection, defines were off (RvP) + * Corrected macro button detection. On my tablet (Medion, is + * reported as Aiptek 12000U, data[3] = 1 is just left of F1, + * 2 = F1, 3 = between F1 and F2, etc. + * added a lastMacro variable, so macro key is reset if you drag + * mouse/stylus from macro into the drawing area. + * v1.7 - switched to strncmp for string comparison, to accept trailing + * returns (RvP) + * v1.8 - Putting a new timer (add_timer, del_timer) in the system. + * The problem is now that the tablet never reports + * "out of proximity" events (at least mine doesn't). So my + * answer is sending those events after a time of inactivity. + * is what the timer is for. + * got bitten by the fact that the ABS_MISC event moved up + * by a long in the bit array. To celebrate the detection of + * this bug, started to neatly use set_bit(), instead of crossing + * fingers and mucking with the bitmaps directly (RvP) + * v1.9 - Moved the inactivity timer removal to correct place, removed + * timeout debugging message, added removal proximity timeout file + * (bugfixes). Added fix by the masc (ms - at - sbox.tugraz.at) + * This fix also fixes the problem of lacking out-of-proximity + * reports (at least with my tablet). So I made the proximity + * timeout conditional. Apparently, for my tablet is it not needed + * (with the fixed detection of proximity and data valid). Kept + * the code in, for now. (nov 19, 2004 RvP) + * v1.9.1 Merged in extant patches, did some constant elimination. BwH. + * v1.9.2 Merged in patches in signatures to show_# and store_# routines. + * v2.0 - Switched to using input_allocate_device and usb_kill_urb. + * Ran the code through "indent -kr -i8", to get Linux kernel + * indenting style + removed superfluous brakets in case + * statements. Apr 19, 2006, RvP + * v2.1 Preparing for merge with kernel RvP * * NOTE: * This kernel driver is augmented by the "Aiptek" XFree86 input @@ -77,14 +110,15 @@ #include <linux/init.h> #include <linux/usb/input.h> #include <linux/sched.h> +#include <linux/timer.h> #include <asm/uaccess.h> #include <asm/unaligned.h> /* * Version Information */ -#define DRIVER_VERSION "v1.5 (May-15-2004)" -#define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio" +#define DRIVER_VERSION "v2.1 (Feb-14-2007)" +#define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio/Cédric Brun/René van Paassen" #define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)" /* @@ -265,9 +299,9 @@ /* Mouse button programming */ -#define AIPTEK_MOUSE_LEFT_BUTTON 0x01 -#define AIPTEK_MOUSE_RIGHT_BUTTON 0x02 -#define AIPTEK_MOUSE_MIDDLE_BUTTON 0x04 +#define AIPTEK_MOUSE_LEFT_BUTTON 0x04 +#define AIPTEK_MOUSE_RIGHT_BUTTON 0x08 +#define AIPTEK_MOUSE_MIDDLE_BUTTON 0x10 /* Stylus button programming */ @@ -287,6 +321,12 @@ #define AIPTEK_REPORT_TOOL_STYLUS 0x20 #define AIPTEK_REPORT_TOOL_MOUSE 0x40 + /* Debug levels - higher means more output. + */ +#define AIPTEK_DEBUG_CONFIG 1 +#define AIPTEK_DEBUG_TRACE 2 +#define AIPTEK_DEBUG_IRQTRACE 5 + static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT; static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT; @@ -312,9 +352,11 @@ int mouseButtonRight; /* mouse right btn delivers... */ int programmableDelay; /* delay for tablet programming */ int jitterDelay; /* delay for hand jittering */ + int proximityTimeout; /* reset proximity after this */ }; struct aiptek { + int debug; /* Debug level; 0 =no debug */ struct input_dev *inputdev; /* input device struct */ struct usb_device *usbdev; /* usb device struct */ struct urb *urb; /* urb for incoming reports */ @@ -328,7 +370,9 @@ int inDelay; /* jitter: in jitter delay? */ unsigned long endDelay; /* jitter: time when delay ends */ int previousJitterable; /* jitterable prev value */ + int lastMacro; /* last macro key, might need resetting */ unsigned char *data; /* incoming packet data */ + struct timer_list activityCheck; /* timer for monitoring prox */ }; /* @@ -346,6 +390,36 @@ }; /*********************************************************************** + * Constants used in the sysfs files. This affords us a small size + * optimization, plus maintains a single point of failure (misspellings.) + */ +static char *pStylus = "stylus"; +static char *pMouse = "mouse"; +static char *pEither = "either"; +static char *pUnknown = "unknown"; +static char *pAbsolute = "absolute"; +static char *pRelative = "relative"; +static char *pEraser = "eraser"; +static char *pPen = "pen"; +static char *pPencil = "pencil"; +static char *pBrush = "brush"; +static char *pAirbrush = "airbrush"; +static char *pLens = "lens"; +static char *pDisable = "disable"; +static char *pUpper = "upper"; +static char *pLower = "lower"; +static char *pLeft = "left"; +static char *pRight = "right"; +static char *pMiddle = "middle"; + +/*********************************************************************** + * Very common printf format strings for the sysfs files. + */ +static char *pString = "%s\n"; +static char *pInt = "%d\n"; +static char *pHex = "0x%04x\n"; + +/*********************************************************************** * Relative reports deliver values in 2's complement format to * deal with negative offsets. */ @@ -432,10 +506,21 @@ aiptek->inDelay = 0; aiptek->eventCount++; + /* Now remove the inactivity timer, if it is still lurking around. */ + if (aiptek->curSetting.proximityTimeout) { + del_timer(&aiptek->activityCheck); + } + /* Report 1 delivers relative coordinates with either a stylus * or the mouse. You do not know, however, which input * tool generated the event. + * Update 070228/RvP My tablet, a Medion / re-branded 12000U, + * reports x=-255 for the stylus, and y=-255 for the mouse in + * this mode, apparently when x resp y should be zero. */ + if (aiptek->debug == AIPTEK_DEBUG_IRQTRACE) { + info("irq(%d): report id = %d\n", __LINE__, data[0]); + } if (data[0] == 1) { if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_ABSOLUTE_MODE) { @@ -461,9 +546,23 @@ input_report_key(inputdev, BTN_LEFT, left); input_report_key(inputdev, BTN_MIDDLE, middle); input_report_key(inputdev, BTN_RIGHT, right); + + /* Stylus or Mouse usage is reported in a peculiar + * way. Report tool usage, and correct displacement */ + if (x == -255) { + input_report_abs + (inputdev, ABS_MISC, + 1 | AIPTEK_REPORT_TOOL_STYLUS); + x = 0; + } + if (y == -255) { + input_report_abs + (inputdev, ABS_MISC, + 1 | AIPTEK_REPORT_TOOL_MOUSE); + y = 0; + } input_report_rel(inputdev, REL_X, x); input_report_rel(inputdev, REL_Y, y); - input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN); /* Wheel support is in the form of a single-event * firing. @@ -473,6 +572,9 @@ aiptek->curSetting.wheel); aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; } + input_report_key(inputdev, + macroKeyEvents[aiptek->lastMacro], + 0); input_sync(inputdev); } } @@ -490,8 +592,8 @@ y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); - p = (data[5] & 0x01) != 0 ? 1 : 0; - dv = (data[5] & 0x02) != 0 ? 1 : 0; + dv = (data[5] & 0x01) != 0 ? 1 : 0; + p = (data[5] & 0x02) != 0 ? 1 : 0; tip = (data[5] & 0x04) != 0 ? 1 : 0; /* Use jitterable to re-arrange button masks @@ -501,6 +603,10 @@ bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; + /* Proximity bit not set when bs or pck set + */ + p |= bs | pck; + /* dv indicates 'data valid' (e.g., the tablet is in sync * and has delivered a "correct" report) We will ignore * all 'bad' reports... @@ -516,18 +622,22 @@ TOOL_BUTTON(aiptek->curSetting.toolMode), 1); aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; + } else { + input_report_key(inputdev, + TOOL_BUTTON(aiptek->curSetting.toolMode), + 0); } if (p != 0) { - input_report_abs(inputdev, ABS_X, x); - input_report_abs(inputdev, ABS_Y, y); - input_report_abs(inputdev, ABS_PRESSURE, z); - input_report_key(inputdev, BTN_TOUCH, tip); input_report_key(inputdev, BTN_STYLUS, bs); input_report_key(inputdev, BTN_STYLUS2, pck); - if (aiptek->curSetting.xTilt != + input_report_abs(inputdev, ABS_X, x); + input_report_abs(inputdev, ABS_Y, y); + input_report_abs(inputdev, ABS_PRESSURE, z); + + if (aiptek->curSetting.xTilt != AIPTEK_TILT_DISABLE) { input_report_abs(inputdev, ABS_TILT_X, @@ -551,6 +661,10 @@ } } input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS); + input_report_key(inputdev, + macroKeyEvents[aiptek-> + lastMacro], + 0); input_sync(inputdev); } } @@ -569,8 +683,8 @@ jitterable = data[5] & 0x1c; - p = (data[5] & 0x01) != 0 ? 1 : 0; - dv = (data[5] & 0x02) != 0 ? 1 : 0; + dv = (data[5] & 0x01) != 0 ? 1 : 0; + p = (data[5] & 0x02) != 0 ? 1 : 0; left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; @@ -586,6 +700,9 @@ TOOL_BUTTON(aiptek->curSetting.toolMode), 1); aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; + } else { + input_report_key(inputdev, + TOOL_BUTTON(aiptek->curSetting.toolMode), 0); } if (p != 0) { @@ -606,7 +723,9 @@ aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; } } - input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); + input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); + input_report_key(inputdev, + macroKeyEvents[aiptek->lastMacro], 0); input_sync(inputdev); } } @@ -616,13 +735,12 @@ else if (data[0] == 4) { jitterable = data[1] & 0x18; - p = (data[1] & 0x01) != 0 ? 1 : 0; - dv = (data[1] & 0x02) != 0 ? 1 : 0; + dv = (data[1] & 0x01) != 0 ? 1 : 0; + p = (data[1] & 0x02) != 0 ? 1 : 0; tip = (data[1] & 0x04) != 0 ? 1 : 0; bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; - - macro = data[3]; + macro = data[3] >> 1; z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); if (dv != 0) { @@ -635,29 +753,25 @@ TOOL_BUTTON(aiptek->curSetting.toolMode), 1); aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; + } else { + input_report_key(inputdev, + TOOL_BUTTON(aiptek->curSetting.toolMode), 0); } - if (p != 0) { - input_report_key(inputdev, BTN_TOUCH, tip); - input_report_key(inputdev, BTN_STYLUS, bs); - input_report_key(inputdev, BTN_STYLUS2, pck); - input_report_abs(inputdev, ABS_PRESSURE, z); - } - - /* For safety, we're sending key 'break' codes for the - * neighboring macro keys. + /* This now expressly resets the key on the + * areas (reported as odd by the tablet) + * between the macro key areas. Only report + * key when tip is pressed. */ - if (macro > 0) { - input_report_key(inputdev, - macroKeyEvents[macro - 1], 0); - } - if (macro < 25) { - input_report_key(inputdev, - macroKeyEvents[macro + 1], 0); - } - input_report_key(inputdev, macroKeyEvents[macro], p); + input_report_key(inputdev, macroKeyEvents[macro], + tip & ~data[3]); input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS); + + /* remember this key. If the user now drags stylus + * into the drawing area it needs to be reset. + */ + aiptek->lastMacro = macro; input_sync(inputdev); } } @@ -666,12 +780,12 @@ else if (data[0] == 5) { jitterable = data[1] & 0x1c; - p = (data[1] & 0x01) != 0 ? 1 : 0; - dv = (data[1] & 0x02) != 0 ? 1 : 0; - left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; + dv = (data[1] & 0x01) != 0 ? 1 : 0; + p = (data[1] & 0x02) != 0 ? 1 : 0; + left = (data[1] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; - macro = data[3]; + macro = data[3] >> 1; if (dv != 0) { /* If we've not already sent a tool_button_?? code, do @@ -683,29 +797,18 @@ TOOL_BUTTON(aiptek->curSetting.toolMode), 1); aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; - } - - if (p != 0) { - input_report_key(inputdev, BTN_LEFT, left); - input_report_key(inputdev, BTN_MIDDLE, middle); - input_report_key(inputdev, BTN_RIGHT, right); - } - - /* For safety, we're sending key 'break' codes for the - * neighboring macro keys. - */ - if (macro > 0) { - input_report_key(inputdev, - macroKeyEvents[macro - 1], 0); - } - if (macro < 25) { + } else { input_report_key(inputdev, - macroKeyEvents[macro + 1], 0); + TOOL_BUTTON(aiptek-> + curSetting. + toolMode), 0); } - input_report_key(inputdev, macroKeyEvents[macro], 1); - input_report_rel(inputdev, ABS_MISC, + input_report_key(inputdev, macroKeyEvents[macro], + left & ~data[3]); + input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); + aiptek->lastMacro = macro; input_sync(inputdev); } } @@ -735,6 +838,10 @@ TOOL_BUTTON(aiptek->curSetting. toolMode), 1); aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; + } else { + input_report_key(inputdev, + TOOL_BUTTON(aiptek->curSetting. + toolMode), 0); } input_report_key(inputdev, macroKeyEvents[macro], 1); @@ -745,10 +852,10 @@ dbg("Unknown report %d", data[0]); } - /* Jitter may occur when the user presses a button on the stlyus + /* Jitter may occur when the user presses a button on the stylus * or the mouse. What we do to prevent that is wait 'x' milliseconds * following a 'jitterable' event, which should give the hand some time - * stabilize itself. + * to stabilize itself. * * We just introduced aiptek->previousJitterable to carry forth the * notion that jitter occurs when the button state changes from on to off: @@ -765,7 +872,15 @@ } aiptek->previousJitterable = jitterable; -exit: + /* set the inactivity timer. Take due account for the jitter delay too. */ + if (aiptek->curSetting.proximityTimeout) { + aiptek->activityCheck.expires = + (aiptek->inDelay ? aiptek->endDelay : jiffies) + + aiptek->curSetting.proximityTimeout; + add_timer(&aiptek->activityCheck); + } + + exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval != 0) { err("%s - usb_submit_urb failed with result %d", @@ -872,6 +987,9 @@ command, data); } kfree(buf); + + msleep(aiptek->curSetting.programmableDelay); + return ret < 0 ? ret : 0; } @@ -972,6 +1090,7 @@ return ret; } } + msleep(160); /* Enable the macro keys */ if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0) @@ -1002,6 +1121,38 @@ */ /*********************************************************************** + * Add dynamic debugging. + */ +static ssize_t show_tabletDebug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aiptek *aiptek = dev_get_drvdata(dev); + + if (aiptek == NULL) { + return 0; + } + + return snprintf(buf, PAGE_SIZE, pInt, aiptek->debug); +} + +static ssize_t +store_tabletDebug(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aiptek *aiptek = dev_get_drvdata(dev); + if (aiptek == NULL) { + return 0; + } + + aiptek->debug = (int) simple_strtol(buf, 0, 10); + return count; +} + +static DEVICE_ATTR(debug, S_IRUGO | S_IWUGO, show_tabletDebug, + store_tabletDebug); + +/*********************************************************************** * support the 'size' file -- display support */ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf) @@ -1034,8 +1185,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", - aiptek->inputdev->id.product); + return snprintf(buf, PAGE_SIZE, pHex, aiptek->inputdev->id.product); } static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); @@ -1050,7 +1200,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); + return snprintf(buf, PAGE_SIZE, pHex, aiptek->inputdev->id.vendor); } static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); @@ -1066,7 +1216,7 @@ if (aiptek == NULL) return 0; - retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer); + retval = snprintf(buf, PAGE_SIZE, pString, aiptek->usbdev->manufacturer); return retval; } @@ -1083,7 +1233,7 @@ if (aiptek == NULL) return 0; - retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product); + retval = snprintf(buf, PAGE_SIZE, pString, aiptek->usbdev->product); return retval; } @@ -1103,22 +1253,22 @@ switch (aiptek->curSetting.pointerMode) { case AIPTEK_POINTER_ONLY_STYLUS_MODE: - s = "stylus"; + s = pStylus; break; case AIPTEK_POINTER_ONLY_MOUSE_MODE: - s = "mouse"; + s = pMouse; break; case AIPTEK_POINTER_EITHER_MODE: - s = "either"; + s = pEither; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1128,12 +1278,12 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "stylus") == 0) { + if (strncmp(buf, pStylus, 6) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_STYLUS_MODE; - } else if (strcmp(buf, "mouse") == 0) { + } else if (strncmp(buf, pMouse, 5) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE; - } else if (strcmp(buf, "either") == 0) { + } else if (strncmp(buf, pEither, 6) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; } return count; @@ -1157,18 +1307,18 @@ switch (aiptek->curSetting.coordinateMode) { case AIPTEK_COORDINATE_ABSOLUTE_MODE: - s = "absolute"; + s = pAbsolute; break; case AIPTEK_COORDINATE_RELATIVE_MODE: - s = "relative"; + s = pRelative; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1178,11 +1328,11 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "absolute") == 0) { - aiptek->newSetting.pointerMode = + if (strncmp(buf, pAbsolute, 8) == 0) { + aiptek->newSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE; - } else if (strcmp(buf, "relative") == 0) { - aiptek->newSetting.pointerMode = + } else if (strncmp(buf, pRelative, 8) == 0) { + aiptek->newSetting.coordinateMode = AIPTEK_COORDINATE_RELATIVE_MODE; } return count; @@ -1206,38 +1356,38 @@ switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) { case AIPTEK_TOOL_BUTTON_MOUSE_MODE: - s = "mouse"; + s = pMouse; break; case AIPTEK_TOOL_BUTTON_ERASER_MODE: - s = "eraser"; + s = pEraser; break; case AIPTEK_TOOL_BUTTON_PENCIL_MODE: - s = "pencil"; + s = pPencil; break; case AIPTEK_TOOL_BUTTON_PEN_MODE: - s = "pen"; + s = pPen; break; case AIPTEK_TOOL_BUTTON_BRUSH_MODE: - s = "brush"; + s = pBrush; break; case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE: - s = "airbrush"; + s = pAirbrush; break; case AIPTEK_TOOL_BUTTON_LENS_MODE: - s = "lens"; + s = pLens; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1247,19 +1397,19 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "mouse") == 0) { + if (strncmp(buf, pMouse, 5) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE; - } else if (strcmp(buf, "eraser") == 0) { + } else if (strncmp(buf, pEraser, 6) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE; - } else if (strcmp(buf, "pencil") == 0) { + } else if (strncmp(buf, pPencil, 6) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE; - } else if (strcmp(buf, "pen") == 0) { + } else if (strncmp(buf, pPen, 3) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; - } else if (strcmp(buf, "brush") == 0) { + } else if (strncmp(buf, pBrush, 5) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE; - } else if (strcmp(buf, "airbrush") == 0) { + } else if (strncmp(buf, pAirbrush, 8) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE; - } else if (strcmp(buf, "lens") == 0) { + } else if (strncmp(buf, pLens, 4) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE; } @@ -1282,9 +1432,9 @@ return 0; if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) { - return snprintf(buf, PAGE_SIZE, "disable\n"); + return snprintf(buf, PAGE_SIZE, pString, pDisable); } else { - return snprintf(buf, PAGE_SIZE, "%d\n", + return snprintf(buf, PAGE_SIZE, pInt, aiptek->curSetting.xTilt); } } @@ -1298,10 +1448,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "disable") == 0) { + if (strncmp(buf, pDisable, 7) == 0) { aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE; } else { - x = (int)simple_strtol(buf, NULL, 10); + x = (int) simple_strtol(buf, 0, 10); if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) { aiptek->newSetting.xTilt = x; } @@ -1324,9 +1474,9 @@ return 0; if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) { - return snprintf(buf, PAGE_SIZE, "disable\n"); + return snprintf(buf, PAGE_SIZE, pString, pDisable); } else { - return snprintf(buf, PAGE_SIZE, "%d\n", + return snprintf(buf, PAGE_SIZE, pInt, aiptek->curSetting.yTilt); } } @@ -1340,10 +1490,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "disable") == 0) { + if (strncmp(buf, pDisable, 7) == 0) { aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE; } else { - y = (int)simple_strtol(buf, NULL, 10); + y = (int) simple_strtol(buf, 0, 10); if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) { aiptek->newSetting.yTilt = y; } @@ -1365,7 +1515,8 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay); + return snprintf(buf, PAGE_SIZE, pInt, + aiptek->curSetting.jitterDelay); } static ssize_t @@ -1385,6 +1536,43 @@ show_tabletJitterDelay, store_tabletJitterDelay); /*********************************************************************** + * support routines for the proximity_timeout file. Note that this file + * both displays current setting and allows reprogramming. + */ +static ssize_t show_tabletProximityTimeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct aiptek *aiptek = dev_get_drvdata(dev); + + if (aiptek == NULL) + return 0; + + return snprintf(buf, PAGE_SIZE, pInt, + (aiptek->curSetting.proximityTimeout * 1000) / HZ); +} + +static ssize_t +store_tabletProximityTimeout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aiptek *aiptek = dev_get_drvdata(dev); + + if (aiptek == NULL) + return 0; + + aiptek->newSetting.proximityTimeout = + ((int) simple_strtol(buf, 0, 10) * HZ) / 1000; + return count; +} + +static DEVICE_ATTR(proximity_timeout, + S_IRUGO | S_IWUGO, + show_tabletProximityTimeout, + store_tabletProximityTimeout); + +/*********************************************************************** * support routines for the 'delay' file. Note that this file * both displays current setting and allows reprogramming. */ @@ -1395,7 +1583,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", + return snprintf(buf, PAGE_SIZE, pInt, aiptek->curSetting.programmableDelay); } @@ -1407,7 +1595,7 @@ if (aiptek == NULL) return 0; - aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10); + aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, 0, 10); return count; } @@ -1436,12 +1624,15 @@ * support routines for the 'event_count' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_tabletEventsReceived(struct device *dev, + struct device_attribute *attr, + char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); - if (aiptek == NULL) + if (aiptek == NULL) { return 0; + } return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount); } @@ -1504,18 +1695,18 @@ switch (aiptek->curSetting.stylusButtonUpper) { case AIPTEK_STYLUS_UPPER_BUTTON: - s = "upper"; + s = pUpper; break; case AIPTEK_STYLUS_LOWER_BUTTON: - s = "lower"; + s = pLower; break; default: - s = "unknown"; - break; + s = pUnknown; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1526,10 +1717,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "upper") == 0) { + if (strncmp(buf, pUpper, 5) == 0) { aiptek->newSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON; - } else if (strcmp(buf, "lower") == 0) { + } else if (strncmp(buf, pLower, 5) == 0) { aiptek->newSetting.stylusButtonUpper = AIPTEK_STYLUS_LOWER_BUTTON; } @@ -1554,18 +1745,18 @@ switch (aiptek->curSetting.stylusButtonLower) { case AIPTEK_STYLUS_UPPER_BUTTON: - s = "upper"; + s = pUpper; break; case AIPTEK_STYLUS_LOWER_BUTTON: - s = "lower"; + s = pLower; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1576,10 +1767,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "upper") == 0) { + if (strncmp(buf, pUpper, 5) == 0) { aiptek->newSetting.stylusButtonLower = AIPTEK_STYLUS_UPPER_BUTTON; - } else if (strcmp(buf, "lower") == 0) { + } else if (strncmp(buf, pLower, 5) == 0) { aiptek->newSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON; } @@ -1604,22 +1795,22 @@ switch (aiptek->curSetting.mouseButtonLeft) { case AIPTEK_MOUSE_LEFT_BUTTON: - s = "left"; + s = pLeft; break; case AIPTEK_MOUSE_MIDDLE_BUTTON: - s = "middle"; + s = pMiddle; break; case AIPTEK_MOUSE_RIGHT_BUTTON: - s = "right"; + s = pRight; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1630,11 +1821,11 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "left") == 0) { + if (strncmp(buf, pLeft, 4) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; - } else if (strcmp(buf, "middle") == 0) { + } else if (strncmp(buf, pMiddle, 6) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON; - } else if (strcmp(buf, "right") == 0) { + } else if (strncmp(buf, pRight, 5) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON; } return count; @@ -1658,22 +1849,22 @@ switch (aiptek->curSetting.mouseButtonMiddle) { case AIPTEK_MOUSE_LEFT_BUTTON: - s = "left"; + s = pLeft; break; case AIPTEK_MOUSE_MIDDLE_BUTTON: - s = "middle"; + s = pMiddle; break; case AIPTEK_MOUSE_RIGHT_BUTTON: - s = "right"; + s = pRight; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1684,12 +1875,13 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "left") == 0) { - aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON; - } else if (strcmp(buf, "middle") == 0) { + if (strncmp(buf, pLeft, 4) == 0) { + aiptek->newSetting.mouseButtonMiddle = + AIPTEK_MOUSE_LEFT_BUTTON; + } else if (strncmp(buf, pMiddle, 6) == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON; - } else if (strcmp(buf, "right") == 0) { + } else if (strncmp(buf, pRight, 5) == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_RIGHT_BUTTON; } @@ -1701,7 +1893,7 @@ show_tabletMouseMiddle, store_tabletMouseMiddle); /*********************************************************************** - * support routines for the 'mouse_right' file. Note that this file + * support routines for the 'mouse_right' File. Note that this file * both displays current setting and allows for setting changing. */ static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf) @@ -1714,22 +1906,22 @@ switch (aiptek->curSetting.mouseButtonRight) { case AIPTEK_MOUSE_LEFT_BUTTON: - s = "left"; + s = pLeft; break; case AIPTEK_MOUSE_MIDDLE_BUTTON: - s = "middle"; + s = pMiddle; break; case AIPTEK_MOUSE_RIGHT_BUTTON: - s = "right"; + s = pRight; break; default: - s = "unknown"; + s = pUnknown; break; } - return snprintf(buf, PAGE_SIZE, "%s\n", s); + return snprintf(buf, PAGE_SIZE, pString, s); } static ssize_t @@ -1740,13 +1932,15 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "left") == 0) { - aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON; - } else if (strcmp(buf, "middle") == 0) { + if (strncmp(buf, pLeft, 4) == 0) { + aiptek->newSetting.mouseButtonRight = + AIPTEK_MOUSE_LEFT_BUTTON; + } else if (strncmp(buf, pMiddle, 6) == 0) { aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_MIDDLE_BUTTON; - } else if (strcmp(buf, "right") == 0) { - aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; + } else if (strncmp(buf, pRight, 5) == 0) { + aiptek->newSetting.mouseButtonRight = + AIPTEK_MOUSE_RIGHT_BUTTON; } return count; } @@ -1767,9 +1961,9 @@ return 0; if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { - return snprintf(buf, PAGE_SIZE, "disable\n"); + return snprintf(buf, PAGE_SIZE, pString, pDisable); } else { - return snprintf(buf, PAGE_SIZE, "%d\n", + return snprintf(buf, PAGE_SIZE, pInt, aiptek->curSetting.wheel); } } @@ -1782,7 +1976,7 @@ if (aiptek == NULL) return 0; - aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); + aiptek->newSetting.wheel = (int) simple_strtol(buf, 0, 10); return count; } @@ -1821,14 +2015,16 @@ memcpy(&aiptek->curSetting, &aiptek->newSetting, sizeof(struct aiptek_settings)); - if (aiptek_program_tablet(aiptek) < 0) + if (aiptek_program_tablet(aiptek) < 0) { return -EIO; + } return count; } static DEVICE_ATTR(execute, - S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute); + S_IRUGO | S_IWUGO, show_tabletExecute, + store_tabletExecute); /*********************************************************************** * support routines for the 'odm_code' file. Note that this file @@ -1841,7 +2037,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode); + return snprintf(buf, PAGE_SIZE, pHex, aiptek->features.odmCode); } static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL); @@ -1857,7 +2053,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode); + return snprintf(buf, PAGE_SIZE, pHex, aiptek->features.modelCode); } static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL); @@ -1873,7 +2069,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "%04x\n", + return snprintf(buf, PAGE_SIZE, pHex, aiptek->features.firmwareCode); } @@ -1885,6 +2081,7 @@ */ static void aiptek_delete_files(struct device *dev) { + device_remove_file(dev, &dev_attr_debug); device_remove_file(dev, &dev_attr_size); device_remove_file(dev, &dev_attr_product_id); device_remove_file(dev, &dev_attr_vendor_id); @@ -1896,6 +2093,7 @@ device_remove_file(dev, &dev_attr_xtilt); device_remove_file(dev, &dev_attr_ytilt); device_remove_file(dev, &dev_attr_jitter); + device_remove_file(dev, &dev_attr_proximity_timeout); device_remove_file(dev, &dev_attr_delay); device_remove_file(dev, &dev_attr_input_path); device_remove_file(dev, &dev_attr_event_count); @@ -1921,6 +2119,7 @@ int ret; if ((ret = device_create_file(dev, &dev_attr_size)) || + (ret = device_create_file(dev, &dev_attr_debug)) || (ret = device_create_file(dev, &dev_attr_product_id)) || (ret = device_create_file(dev, &dev_attr_vendor_id)) || (ret = device_create_file(dev, &dev_attr_vendor)) || @@ -1931,6 +2130,7 @@ (ret = device_create_file(dev, &dev_attr_xtilt)) || (ret = device_create_file(dev, &dev_attr_ytilt)) || (ret = device_create_file(dev, &dev_attr_jitter)) || + (ret = device_create_file(dev, &dev_attr_proximity_timeout)) || (ret = device_create_file(dev, &dev_attr_delay)) || (ret = device_create_file(dev, &dev_attr_input_path)) || (ret = device_create_file(dev, &dev_attr_event_count)) || @@ -1951,6 +2151,9 @@ return ret; } +/* forward declaration */ +static void activity_check(unsigned long data); + /*********************************************************************** * This routine is called when a tablet has been identified. It basically * sets up the tablet and the driver's internal structures. @@ -1964,6 +2167,7 @@ struct input_dev *inputdev; struct input_handle *inputhandle; struct list_head *node, *next; + // char path[64 + 1]; int i; int speeds[] = { 0, AIPTEK_PROGRAMMABLE_DELAY_50, @@ -2002,6 +2206,8 @@ aiptek->inDelay = 0; aiptek->endDelay = 0; aiptek->previousJitterable = 0; + aiptek->lastMacro = 0; + /* Set up the curSettings struct. Said struct contains the current * programmable parameters. The newSetting struct contains changes @@ -2021,10 +2227,58 @@ aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON; aiptek->curSetting.jitterDelay = jitterDelay; aiptek->curSetting.programmableDelay = programmableDelay; + aiptek->curSetting.proximityTimeout = 0; /* Both structs should have equivalent settings */ - aiptek->newSetting = aiptek->curSetting; + memcpy(&aiptek->newSetting, &aiptek->curSetting, + sizeof(struct aiptek_settings)); + + /* Now program the capacities of the tablet, in terms of being + * an input device. + */ + set_bit(EV_KEY, aiptek->inputdev->evbit); + set_bit(EV_ABS, aiptek->inputdev->evbit); + set_bit(EV_REL, aiptek->inputdev->evbit); + set_bit(EV_MSC, aiptek->inputdev->evbit); + + set_bit(ABS_X, aiptek->inputdev->absbit); + set_bit(ABS_Y, aiptek->inputdev->absbit); + set_bit(ABS_PRESSURE, aiptek->inputdev->absbit); + set_bit(ABS_TILT_X, aiptek->inputdev->absbit); + set_bit(ABS_TILT_Y, aiptek->inputdev->absbit); + set_bit(ABS_WHEEL, aiptek->inputdev->absbit); + set_bit(ABS_MISC, aiptek->inputdev->absbit); + + set_bit(REL_X, aiptek->inputdev->relbit); + set_bit(REL_Y, aiptek->inputdev->relbit); + set_bit(REL_WHEEL, aiptek->inputdev->relbit); + set_bit(REL_MISC, aiptek->inputdev->relbit); + + set_bit(BTN_LEFT, aiptek->inputdev->keybit); + set_bit(BTN_RIGHT, aiptek->inputdev->keybit); + set_bit(BTN_MIDDLE, aiptek->inputdev->keybit); + + set_bit(BTN_TOOL_PEN, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_RUBBER, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_PENCIL, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_AIRBRUSH, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_BRUSH, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_MOUSE, aiptek->inputdev->keybit); + set_bit(BTN_TOOL_LENS, aiptek->inputdev->keybit); + set_bit(BTN_TOUCH, aiptek->inputdev->keybit); + set_bit(BTN_STYLUS, aiptek->inputdev->keybit); + set_bit(BTN_STYLUS2, aiptek->inputdev->keybit); + + set_bit(MSC_SERIAL, aiptek->inputdev->mscbit); + + /* Programming the tablet macro keys needs to be done with a for loop + * as the keycodes are discontiguous. + */ + for (i = 0; i < sizeof(macroKeyEvents) / sizeof(macroKeyEvents[0]); + ++i) { + set_bit(macroKeyEvents[i], aiptek->inputdev->keybit); + } /* Determine the usb devices' physical path. * Asketh not why we always pretend we're using "../input0", @@ -2034,7 +2288,7 @@ * us something... */ usb_make_path(usbdev, aiptek->features.usbPath, - sizeof(aiptek->features.usbPath)); + sizeof(aiptek->features.usbPath)); strlcat(aiptek->features.usbPath, "/input0", sizeof(aiptek->features.usbPath)); @@ -2048,43 +2302,10 @@ inputdev->private = aiptek; inputdev->open = aiptek_open; inputdev->close = aiptek_close; + aiptek->usbdev = usbdev; + aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; - /* Now program the capacities of the tablet, in terms of being - * an input device. - */ - inputdev->evbit[0] |= BIT(EV_KEY) - | BIT(EV_ABS) - | BIT(EV_REL) - | BIT(EV_MSC); - - inputdev->absbit[0] |= BIT(ABS_MISC); - - inputdev->relbit[0] |= - (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); - - inputdev->keybit[LONG(BTN_LEFT)] |= - (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); - - inputdev->keybit[LONG(BTN_DIGI)] |= - (BIT(BTN_TOOL_PEN) | - BIT(BTN_TOOL_RUBBER) | - BIT(BTN_TOOL_PENCIL) | - BIT(BTN_TOOL_AIRBRUSH) | - BIT(BTN_TOOL_BRUSH) | - BIT(BTN_TOOL_MOUSE) | - BIT(BTN_TOOL_LENS) | - BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); - - inputdev->mscbit[0] = BIT(MSC_SERIAL); - - /* Programming the tablet macro keys needs to be done with a for loop - * as the keycodes are discontiguous. - */ - for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i) - set_bit(macroKeyEvents[i], inputdev->keybit); - - /* - * Program the input device coordinate capacities. We do not yet + /* Program the input device coordinate capacities. We do not yet * know what maximum X, Y, and Z values are, so we're putting fake * values in. Later, we'll ask the tablet to put in the correct * values. @@ -2095,9 +2316,14 @@ input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); - + input_set_abs_params(inputdev, ABS_MISC, 0, 255, 0, 0); endpoint = &intf->altsetting[0].endpoint[0].desc; + /* inactivity timer. */ + init_timer(&aiptek->activityCheck); + aiptek->activityCheck.function = activity_check; + aiptek->activityCheck.data = (unsigned long) aiptek; + /* Go set up our URB, which is called when the tablet receives * input. */ @@ -2111,6 +2337,29 @@ aiptek->urb->transfer_dma = aiptek->data_dma; aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + /* Register the tablet as an Input Device + */ + input_register_device(aiptek->inputdev); + + /* We now will look for the evdev device which is mapped to + * the tablet. The partial name is kept in the link list of + * input_handles associated with this input device. + * What identifies an evdev input_handler is that it begins + * with 'event', continues with a digit, and that in turn + * is mapped to /{devfs}/input/eventN. + */ + inputdev = aiptek->inputdev; + list_for_each_safe(node, next, &inputdev->h_list) { + inputhandle = to_handle(node); + if (strncmp(inputhandle->name, "event", 5) == 0) { + strcpy(aiptek->features.inputPath, + inputhandle->name); + break; + } + } + + info("input: Aiptek as %s\n", aiptek->features.inputPath); + /* Program the tablet. This sets the tablet up in the mode * specified in newSetting, and also queries the tablet's * physical capacities. @@ -2131,24 +2380,12 @@ break; } } - - /* Register the tablet as an Input Device - */ - input_register_device(aiptek->inputdev); - - /* We now will look for the evdev device which is mapped to - * the tablet. The partial name is kept in the link list of - * input_handles associated with this input device. - * What identifies an evdev input_handler is that it begins - * with 'event', continues with a digit, and that in turn - * is mapped to input/eventN. - */ - list_for_each_safe(node, next, &inputdev->h_list) { - inputhandle = to_handle(node); - if (strncmp(inputhandle->name, "event", 5) == 0) { - strcpy(aiptek->features.inputPath, inputhandle->name); - break; - } + + /* Murphy says that some day someone will have a tablet that fails the + above test. That's you, Frederic Rodrigo */ + if (i == ARRAY_SIZE(speeds)) { + info("input: Aiptek tablet insane?"); + goto fail2; } /* Associate this driver's struct with the usb interface. @@ -2173,6 +2410,23 @@ return -ENOMEM; } +/* Activity checking thread. If a sufficient period of inactivity is detected, + the tablet's proximity is reset. */ +static void activity_check(unsigned long data) +{ + struct aiptek *aiptek = (struct aiptek *) data; + + /* This timer is set *after* handling input for the table, and + cleared *before* handling it. Am guessing that we never run + concurrently the module code. */ + + /* info("aiptek: timeout proximity\n"); */ + + /* apparently over-due. Reset the misc key, no tool, no proximity */ + input_report_abs(aiptek->inputdev, ABS_MISC, 0); + input_sync(aiptek->inputdev); +} + /* Forward declaration */ static void aiptek_disconnect(struct usb_interface *intf); @@ -2190,6 +2444,9 @@ { struct aiptek *aiptek = usb_get_intfdata(intf); + /* First remove any timer. */ + del_timer(&aiptek->activityCheck); + /* Disassociate driver's struct with usb interface */ usb_set_intfdata(intf, NULL); @@ -2204,6 +2461,7 @@ AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); kfree(aiptek); + aiptek = NULL; } } ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel