Re: [Aiptektablet-users] [PATCH 2.6.20 1/1] usb/input updatedaiptek tablet driver
René van Paassen <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Organization | TU Delft - Aerospace Engineering |
| Message-ID | <[email protected]> |
On Thu, 2007-03-08 at 00:02 +0100, Rene van Paassen wrote: > 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]> After feedback from usb list maintainers + some on the aiptek list, I added the following changes to the patch: - Removed product, vendor, product_id and vendor_id files, these are already provided by input core--- - Got rid of accented UTF8 characters - added error checking on input_register_device - got rid of input path search - using del_timer_sync to get rid of potential race on SMP - fixes for relative mode, caught by Mark Vytlacil 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-04-03 23:13:11.000000000 +0200 @@ -4,6 +4,7 @@ * * Copyright (c) 2001 Chris Atenasio <[email protected]> * Copyright (c) 2002-2004 Bryan W. Headley <[email protected]> + * Extra bits 2004 Rene van Paassen <[email protected]> * * based on wacom.c by * Vojtech Pavlik <[email protected]> @@ -45,6 +46,46 @@ * 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 + * v2.2 After feedback from USB maintainers + * - Removed product, vendor, product_id and vendor_id files, + * these are already provided by input core + * - Got rid of accented UTF8 characters + * - added error checking on input_register_device + * - got rid of input path search + * - using del_timer_sync to get rid of potential race on SMP + * - fixes for relative mode, caught by Mark Vytlacil * * NOTE: * This kernel driver is augmented by the "Aiptek" XFree86 input @@ -77,14 +118,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.2 (Apr-03-2007)" +#define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio/Cedric Brun/Rene van Paassen" #define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)" /* @@ -113,7 +155,7 @@ * (returned as Report 3 - absolute coordinates from the mouse) * * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 - * byte0 0 0 0 0 0 0 1 0 + * byte0 0 0 0 0 0 0 1 1 * byte1 X7 X6 X5 X4 X3 X2 X1 X0 * byte2 X15 X14 X13 X12 X11 X10 X9 X8 * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 @@ -135,7 +177,7 @@ * (returned as Report 5 - macrokeys from the mouse) * * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 - * byte0 0 0 0 0 0 1 0 0 + * byte0 0 0 0 0 0 1 0 1 * byte1 0 0 0 BS2 BS Tip IR DV * byte2 0 0 0 0 0 0 1 0 * byte3 0 0 0 K4 K3 K2 K1 K0 @@ -265,9 +307,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 +329,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; @@ -295,7 +343,6 @@ int modelCode; /* Tablet model code (not unique) */ int firmwareCode; /* prom/eeprom version */ char usbPath[64 + 1]; /* device's physical usb path */ - char inputPath[64 + 1]; /* input device path */ }; struct aiptek_settings { @@ -312,9 +359,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 +377,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 +397,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 +513,21 @@ aiptek->inDelay = 0; aiptek->eventCount++; + /* Now remove the inactivity timer, if it is still lurking around. */ + if (aiptek->curSetting.proximityTimeout) { + del_timer_sync(&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) { @@ -452,18 +544,32 @@ * that a non-zero value indicates that one or more * mouse button was pressed.) */ - jitterable = data[5] & 0x07; + jitterable = data[1] & 0x07; - 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; + left = (data[1] & aiptek->curSetting.mouseButtonLeft>>2) != 0 ? 1 : 0; + right = (data[1] & aiptek->curSetting.mouseButtonRight>>2) != 0 ? 1 : 0; + middle = (data[1] & aiptek->curSetting.mouseButtonMiddle>>2) != 0 ? 1 : 0; 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 +579,9 @@ aiptek->curSetting.wheel); aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; } + input_report_key(inputdev, + macroKeyEvents[aiptek->lastMacro], + 0); input_sync(inputdev); } } @@ -490,8 +599,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 +610,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 +629,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 +668,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 +690,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 +707,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 +730,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 +742,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 +760,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 +787,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 +804,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) { + } else { input_report_key(inputdev, - macroKeyEvents[macro - 1], 0); - } - if (macro < 25) { - 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 +845,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 +859,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 +879,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 +994,9 @@ command, data); } kfree(buf); + + msleep(aiptek->curSetting.programmableDelay); + return ret < 0 ? ret : 0; } @@ -972,6 +1097,7 @@ return ret; } } + msleep(160); /* Enable the macro keys */ if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0) @@ -1002,92 +1128,60 @@ */ /*********************************************************************** - * support the 'size' file -- display support + * Add dynamic debugging. */ -static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf) +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, "%dx%d\n", - aiptek->inputdev->absmax[ABS_X] + 1, - aiptek->inputdev->absmax[ABS_Y] + 1); -} - -/* These structs define the sysfs files, param #1 is the name of the - * file, param 2 is the file permissions, param 3 & 4 are to the - * output generator and input parser routines. Absence of a routine is - * permitted -- it only means can't either 'cat' the file, or send data - * to it. - */ -static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); - -/*********************************************************************** - * support routines for the 'product_id' file - */ -static ssize_t show_tabletProductId(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, "0x%04x\n", - aiptek->inputdev->id.product); + return snprintf(buf, PAGE_SIZE, pInt, aiptek->debug); } -static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); - -/*********************************************************************** - * support routines for the 'vendor_id' file - */ -static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf) +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) + if (aiptek == NULL) { return 0; + } - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); + aiptek->debug = (int) simple_strtol(buf, 0, 10); + return count; } -static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); +static DEVICE_ATTR(debug, S_IRUGO | S_IWUGO, show_tabletDebug, + store_tabletDebug); /*********************************************************************** - * support routines for the 'vendor' file + * support the 'size' file -- display support */ -static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); - int retval; if (aiptek == NULL) return 0; - retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer); - return retval; + return snprintf(buf, PAGE_SIZE, "%dx%d\n", + aiptek->inputdev->absmax[ABS_X] + 1, + aiptek->inputdev->absmax[ABS_Y] + 1); } -static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL); - -/*********************************************************************** - * support routines for the 'product' file +/* These structs define the sysfs files, param #1 is the name of the + * file, param 2 is the file permissions, param 3 & 4 are to the + * output generator and input parser routines. Absence of a routine is + * permitted -- it only means can't either 'cat' the file, or send data + * to it. */ -static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct aiptek *aiptek = dev_get_drvdata(dev); - int retval; - - if (aiptek == NULL) - return 0; - - retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product); - return retval; -} +static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); -static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL); /*********************************************************************** * support routines for the 'pointer_mode' file. Note that this file @@ -1103,22 +1197,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 +1222,12 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "stylus") == 0) { + if (strncmp(buf, pStylus, ARRAY_SIZE(pStylus)) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_STYLUS_MODE; - } else if (strcmp(buf, "mouse") == 0) { + } else if (strncmp(buf, pMouse, ARRAY_SIZE(pMouse)) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE; - } else if (strcmp(buf, "either") == 0) { + } else if (strncmp(buf, pEither, ARRAY_SIZE(pEither)) == 0) { aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; } return count; @@ -1157,18 +1251,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 +1272,11 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "absolute") == 0) { - aiptek->newSetting.pointerMode = + if (strncmp(buf, pAbsolute, ARRAY_SIZE(pAbsolute)) == 0) { + aiptek->newSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE; - } else if (strcmp(buf, "relative") == 0) { - aiptek->newSetting.pointerMode = + } else if (strncmp(buf, pRelative, ARRAY_SIZE(pRelative)) == 0) { + aiptek->newSetting.coordinateMode = AIPTEK_COORDINATE_RELATIVE_MODE; } return count; @@ -1206,38 +1300,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 +1341,19 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "mouse") == 0) { + if (strncmp(buf, pMouse, ARRAY_SIZE(pMouse)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE; - } else if (strcmp(buf, "eraser") == 0) { + } else if (strncmp(buf, pEraser, ARRAY_SIZE(pEraser)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE; - } else if (strcmp(buf, "pencil") == 0) { + } else if (strncmp(buf, pPencil, ARRAY_SIZE(pPencil)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE; - } else if (strcmp(buf, "pen") == 0) { + } else if (strncmp(buf, pPen, ARRAY_SIZE(pPen)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; - } else if (strcmp(buf, "brush") == 0) { + } else if (strncmp(buf, pBrush, ARRAY_SIZE(pBrush)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE; - } else if (strcmp(buf, "airbrush") == 0) { + } else if (strncmp(buf, pAirbrush, ARRAY_SIZE(pAirbrush)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE; - } else if (strcmp(buf, "lens") == 0) { + } else if (strncmp(buf, pLens, ARRAY_SIZE(pLens)) == 0) { aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE; } @@ -1282,9 +1376,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 +1392,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "disable") == 0) { + if (strncmp(buf, pDisable, ARRAY_SIZE(pDisable)) == 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 +1418,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 +1434,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "disable") == 0) { + if (strncmp(buf, pDisable, ARRAY_SIZE(pDisable)) == 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 +1459,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,63 +1480,86 @@ show_tabletJitterDelay, store_tabletJitterDelay); /*********************************************************************** - * support routines for the 'delay' file. Note that this file + * support routines for the proximity_timeout file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf) +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, "%d\n", - aiptek->curSetting.programmableDelay); + return snprintf(buf, PAGE_SIZE, pInt, + (aiptek->curSetting.proximityTimeout * 1000) / HZ); } static ssize_t -store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +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.programmableDelay = (int)simple_strtol(buf, NULL, 10); + aiptek->newSetting.proximityTimeout = + ((int) simple_strtol(buf, 0, 10) * HZ) / 1000; return count; } -static DEVICE_ATTR(delay, +static DEVICE_ATTR(proximity_timeout, S_IRUGO | S_IWUGO, - show_tabletProgrammableDelay, store_tabletProgrammableDelay); + show_tabletProximityTimeout, + store_tabletProximityTimeout); /*********************************************************************** - * support routines for the 'input_path' file. Note that this file - * only displays current setting. + * support routines for the 'delay' file. Note that this file + * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_tabletProgrammableDelay(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, "/dev/input/%s\n", - aiptek->features.inputPath); + return snprintf(buf, PAGE_SIZE, pInt, + aiptek->curSetting.programmableDelay); } -static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL); +static ssize_t +store_tabletProgrammableDelay(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.programmableDelay = (int)simple_strtol(buf, 0, 10); + return count; +} + +static DEVICE_ATTR(delay, + S_IRUGO | S_IWUGO, + show_tabletProgrammableDelay, store_tabletProgrammableDelay); /*********************************************************************** * 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 +1622,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 +1644,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "upper") == 0) { + if (strncmp(buf, pUpper, ARRAY_SIZE(pUpper)) == 0) { aiptek->newSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON; - } else if (strcmp(buf, "lower") == 0) { + } else if (strncmp(buf, pLower, ARRAY_SIZE(pLower)) == 0) { aiptek->newSetting.stylusButtonUpper = AIPTEK_STYLUS_LOWER_BUTTON; } @@ -1554,18 +1672,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 +1694,10 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "upper") == 0) { + if (strncmp(buf, pUpper, ARRAY_SIZE(pUpper)) == 0) { aiptek->newSetting.stylusButtonLower = AIPTEK_STYLUS_UPPER_BUTTON; - } else if (strcmp(buf, "lower") == 0) { + } else if (strncmp(buf, pLower, ARRAY_SIZE(pLower)) == 0) { aiptek->newSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON; } @@ -1604,22 +1722,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 +1748,11 @@ if (aiptek == NULL) return 0; - if (strcmp(buf, "left") == 0) { + if (strncmp(buf, pLeft, ARRAY_SIZE(pLeft)) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; - } else if (strcmp(buf, "middle") == 0) { + } else if (strncmp(buf, pMiddle, ARRAY_SIZE(pMiddle)) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON; - } else if (strcmp(buf, "right") == 0) { + } else if (strncmp(buf, pRight, ARRAY_SIZE(pRight)) == 0) { aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON; } return count; @@ -1658,22 +1776,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 +1802,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, ARRAY_SIZE(pLeft)) == 0) { + aiptek->newSetting.mouseButtonMiddle = + AIPTEK_MOUSE_LEFT_BUTTON; + } else if (strncmp(buf, pMiddle, ARRAY_SIZE(pMiddle)) == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON; - } else if (strcmp(buf, "right") == 0) { + } else if (strncmp(buf, pRight, ARRAY_SIZE(pRight)) == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_RIGHT_BUTTON; } @@ -1701,7 +1820,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 +1833,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 +1859,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, ARRAY_SIZE(pLeft)) == 0) { + aiptek->newSetting.mouseButtonRight = + AIPTEK_MOUSE_LEFT_BUTTON; + } else if (strncmp(buf, pMiddle, ARRAY_SIZE(pMiddle)) == 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, ARRAY_SIZE(pRight)) == 0) { + aiptek->newSetting.mouseButtonRight = + AIPTEK_MOUSE_RIGHT_BUTTON; } return count; } @@ -1767,9 +1888,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 +1903,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 +1942,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 +1964,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 +1980,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 +1996,7 @@ if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "%04x\n", + return snprintf(buf, PAGE_SIZE, pHex, aiptek->features.firmwareCode); } @@ -1885,19 +2008,16 @@ */ 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); - device_remove_file(dev, &dev_attr_vendor); - device_remove_file(dev, &dev_attr_product); device_remove_file(dev, &dev_attr_pointer_mode); device_remove_file(dev, &dev_attr_coordinate_mode); device_remove_file(dev, &dev_attr_tool_mode); 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); device_remove_file(dev, &dev_attr_diagnostic); device_remove_file(dev, &dev_attr_odm_code); @@ -1921,18 +2041,15 @@ int ret; if ((ret = device_create_file(dev, &dev_attr_size)) || - (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)) || - (ret = device_create_file(dev, &dev_attr_product)) || + (ret = device_create_file(dev, &dev_attr_debug)) || (ret = device_create_file(dev, &dev_attr_pointer_mode)) || (ret = device_create_file(dev, &dev_attr_coordinate_mode)) || (ret = device_create_file(dev, &dev_attr_tool_mode)) || (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)) || (ret = device_create_file(dev, &dev_attr_diagnostic)) || (ret = device_create_file(dev, &dev_attr_odm_code)) || @@ -1951,6 +2068,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. @@ -1962,8 +2082,7 @@ struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; 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 +2121,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 +2142,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 +2203,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 +2217,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 +2231,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 +2252,14 @@ aiptek->urb->transfer_dma = aiptek->data_dma; aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + /* Register the tablet as an Input Device + */ + i = input_register_device(aiptek->inputdev); + if (i) { + info("aiptek: input_register_device returned err: %d", i); + goto fail2; + } + /* Program the tablet. This sets the tablet up in the mode * specified in newSetting, and also queries the tablet's * physical capacities. @@ -2131,24 +2280,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 +2310,21 @@ 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. */ + + /* 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 +2342,9 @@ { struct aiptek *aiptek = usb_get_intfdata(intf); + /* First remove any timer. */ + del_timer_sync(&aiptek->activityCheck); + /* Disassociate driver's struct with usb interface */ usb_set_intfdata(intf, NULL); @@ -2204,6 +2359,7 @@ AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); kfree(aiptek); + aiptek = NULL; } } ########################################### This message has been scanned by F-Secure Anti-Virus for Microsoft Exchange. For more information, connect to http://www.f-secure.com/ ------------------------------------------------------------------------- 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