1*4104d13fSDmitry Torokhov /* 2*4104d13fSDmitry Torokhov * Native support for the Aiptek HyperPen USB Tablets 3*4104d13fSDmitry Torokhov * (4000U/5000U/6000U/8000U/12000U) 4*4104d13fSDmitry Torokhov * 5*4104d13fSDmitry Torokhov * Copyright (c) 2001 Chris Atenasio <chris@crud.net> 6*4104d13fSDmitry Torokhov * Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net> 7*4104d13fSDmitry Torokhov * 8*4104d13fSDmitry Torokhov * based on wacom.c by 9*4104d13fSDmitry Torokhov * Vojtech Pavlik <vojtech@suse.cz> 10*4104d13fSDmitry Torokhov * Andreas Bach Aaen <abach@stofanet.dk> 11*4104d13fSDmitry Torokhov * Clifford Wolf <clifford@clifford.at> 12*4104d13fSDmitry Torokhov * Sam Mosel <sam.mosel@computer.org> 13*4104d13fSDmitry Torokhov * James E. Blair <corvus@gnu.org> 14*4104d13fSDmitry Torokhov * Daniel Egger <egger@suse.de> 15*4104d13fSDmitry Torokhov * 16*4104d13fSDmitry Torokhov * Many thanks to Oliver Kuechemann for his support. 17*4104d13fSDmitry Torokhov * 18*4104d13fSDmitry Torokhov * ChangeLog: 19*4104d13fSDmitry Torokhov * v0.1 - Initial release 20*4104d13fSDmitry Torokhov * v0.2 - Hack to get around fake event 28's. (Bryan W. Headley) 21*4104d13fSDmitry Torokhov * v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002) 22*4104d13fSDmitry Torokhov * Released to Linux 2.4.19 and 2.5.x 23*4104d13fSDmitry Torokhov * v0.4 - Rewrote substantial portions of the code to deal with 24*4104d13fSDmitry Torokhov * corrected control sequences, timing, dynamic configuration, 25*4104d13fSDmitry Torokhov * support of 6000U - 12000U, procfs, and macro key support 26*4104d13fSDmitry Torokhov * (Jan-1-2003 - Feb-5-2003, Bryan W. Headley) 27*4104d13fSDmitry Torokhov * v1.0 - Added support for diagnostic messages, count of messages 28*4104d13fSDmitry Torokhov * received from URB - Mar-8-2003, Bryan W. Headley 29*4104d13fSDmitry Torokhov * v1.1 - added support for tablet resolution, changed DV and proximity 30*4104d13fSDmitry Torokhov * some corrections - Jun-22-2003, martin schneebacher 31*4104d13fSDmitry Torokhov * - Added support for the sysfs interface, deprecating the 32*4104d13fSDmitry Torokhov * procfs interface for 2.5.x kernel. Also added support for 33*4104d13fSDmitry Torokhov * Wheel command. Bryan W. Headley July-15-2003. 34*4104d13fSDmitry Torokhov * v1.2 - Reworked jitter timer as a kernel thread. 35*4104d13fSDmitry Torokhov * Bryan W. Headley November-28-2003/Jan-10-2004. 36*4104d13fSDmitry Torokhov * v1.3 - Repaired issue of kernel thread going nuts on single-processor 37*4104d13fSDmitry Torokhov * machines, introduced programmableDelay as a command line 38*4104d13fSDmitry Torokhov * parameter. Feb 7 2004, Bryan W. Headley. 39*4104d13fSDmitry Torokhov * v1.4 - Re-wire jitter so it does not require a thread. Courtesy of 40*4104d13fSDmitry Torokhov * Rene van Paassen. Added reporting of physical pointer device 41*4104d13fSDmitry Torokhov * (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know 42*4104d13fSDmitry Torokhov * for reports 1, 6.) 43*4104d13fSDmitry Torokhov * what physical device reports for reports 1, 6.) Also enabled 44*4104d13fSDmitry Torokhov * MOUSE and LENS tool button modes. Renamed "rubber" to "eraser". 45*4104d13fSDmitry Torokhov * Feb 20, 2004, Bryan W. Headley. 46*4104d13fSDmitry Torokhov * v1.5 - Added previousJitterable, so we don't do jitter delay when the 47*4104d13fSDmitry Torokhov * user is holding a button down for periods of time. 48*4104d13fSDmitry Torokhov * 49*4104d13fSDmitry Torokhov * NOTE: 50*4104d13fSDmitry Torokhov * This kernel driver is augmented by the "Aiptek" XFree86 input 51*4104d13fSDmitry Torokhov * driver for your X server, as well as the Gaiptek GUI Front-end 52*4104d13fSDmitry Torokhov * "Tablet Manager". 53*4104d13fSDmitry Torokhov * These three products are highly interactive with one another, 54*4104d13fSDmitry Torokhov * so therefore it's easier to document them all as one subsystem. 55*4104d13fSDmitry Torokhov * Please visit the project's "home page", located at, 56*4104d13fSDmitry Torokhov * http://aiptektablet.sourceforge.net. 57*4104d13fSDmitry Torokhov * 58*4104d13fSDmitry Torokhov * This program is free software; you can redistribute it and/or modify 59*4104d13fSDmitry Torokhov * it under the terms of the GNU General Public License as published by 60*4104d13fSDmitry Torokhov * the Free Software Foundation; either version 2 of the License, or 61*4104d13fSDmitry Torokhov * (at your option) any later version. 62*4104d13fSDmitry Torokhov * 63*4104d13fSDmitry Torokhov * This program is distributed in the hope that it will be useful, 64*4104d13fSDmitry Torokhov * but WITHOUT ANY WARRANTY; without even the implied warranty of 65*4104d13fSDmitry Torokhov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 66*4104d13fSDmitry Torokhov * GNU General Public License for more details. 67*4104d13fSDmitry Torokhov * 68*4104d13fSDmitry Torokhov * You should have received a copy of the GNU General Public License 69*4104d13fSDmitry Torokhov * along with this program; if not, write to the Free Software 70*4104d13fSDmitry Torokhov * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 71*4104d13fSDmitry Torokhov */ 72*4104d13fSDmitry Torokhov 73*4104d13fSDmitry Torokhov #include <linux/jiffies.h> 74*4104d13fSDmitry Torokhov #include <linux/kernel.h> 75*4104d13fSDmitry Torokhov #include <linux/slab.h> 76*4104d13fSDmitry Torokhov #include <linux/module.h> 77*4104d13fSDmitry Torokhov #include <linux/init.h> 78*4104d13fSDmitry Torokhov #include <linux/usb/input.h> 79*4104d13fSDmitry Torokhov #include <asm/uaccess.h> 80*4104d13fSDmitry Torokhov #include <asm/unaligned.h> 81*4104d13fSDmitry Torokhov 82*4104d13fSDmitry Torokhov /* 83*4104d13fSDmitry Torokhov * Version Information 84*4104d13fSDmitry Torokhov */ 85*4104d13fSDmitry Torokhov #define DRIVER_VERSION "v1.5 (May-15-2004)" 86*4104d13fSDmitry Torokhov #define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio" 87*4104d13fSDmitry Torokhov #define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)" 88*4104d13fSDmitry Torokhov 89*4104d13fSDmitry Torokhov /* 90*4104d13fSDmitry Torokhov * Aiptek status packet: 91*4104d13fSDmitry Torokhov * 92*4104d13fSDmitry Torokhov * (returned as Report 1 - relative coordinates from mouse and stylus) 93*4104d13fSDmitry Torokhov * 94*4104d13fSDmitry Torokhov * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 95*4104d13fSDmitry Torokhov * byte0 0 0 0 0 0 0 0 1 96*4104d13fSDmitry Torokhov * byte1 0 0 0 0 0 BS2 BS Tip 97*4104d13fSDmitry Torokhov * byte2 X7 X6 X5 X4 X3 X2 X1 X0 98*4104d13fSDmitry Torokhov * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 99*4104d13fSDmitry Torokhov * 100*4104d13fSDmitry Torokhov * (returned as Report 2 - absolute coordinates from the stylus) 101*4104d13fSDmitry Torokhov * 102*4104d13fSDmitry Torokhov * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 103*4104d13fSDmitry Torokhov * byte0 0 0 0 0 0 0 1 0 104*4104d13fSDmitry Torokhov * byte1 X7 X6 X5 X4 X3 X2 X1 X0 105*4104d13fSDmitry Torokhov * byte2 X15 X14 X13 X12 X11 X10 X9 X8 106*4104d13fSDmitry Torokhov * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 107*4104d13fSDmitry Torokhov * byte4 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8 108*4104d13fSDmitry Torokhov * byte5 * * * BS2 BS1 Tip IR DV 109*4104d13fSDmitry Torokhov * byte6 P7 P6 P5 P4 P3 P2 P1 P0 110*4104d13fSDmitry Torokhov * byte7 P15 P14 P13 P12 P11 P10 P9 P8 111*4104d13fSDmitry Torokhov * 112*4104d13fSDmitry Torokhov * (returned as Report 3 - absolute coordinates from the mouse) 113*4104d13fSDmitry Torokhov * 114*4104d13fSDmitry Torokhov * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 115*4104d13fSDmitry Torokhov * byte0 0 0 0 0 0 0 1 0 116*4104d13fSDmitry Torokhov * byte1 X7 X6 X5 X4 X3 X2 X1 X0 117*4104d13fSDmitry Torokhov * byte2 X15 X14 X13 X12 X11 X10 X9 X8 118*4104d13fSDmitry Torokhov * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 119*4104d13fSDmitry Torokhov * byte4 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8 120*4104d13fSDmitry Torokhov * byte5 * * * BS2 BS1 Tip IR DV 121*4104d13fSDmitry Torokhov * byte6 P7 P6 P5 P4 P3 P2 P1 P0 122*4104d13fSDmitry Torokhov * byte7 P15 P14 P13 P12 P11 P10 P9 P8 123*4104d13fSDmitry Torokhov * 124*4104d13fSDmitry Torokhov * (returned as Report 4 - macrokeys from the stylus) 125*4104d13fSDmitry Torokhov * 126*4104d13fSDmitry Torokhov * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 127*4104d13fSDmitry Torokhov * byte0 0 0 0 0 0 1 0 0 128*4104d13fSDmitry Torokhov * byte1 0 0 0 BS2 BS Tip IR DV 129*4104d13fSDmitry Torokhov * byte2 0 0 0 0 0 0 1 0 130*4104d13fSDmitry Torokhov * byte3 0 0 0 K4 K3 K2 K1 K0 131*4104d13fSDmitry Torokhov * byte4 P7 P6 P5 P4 P3 P2 P1 P0 132*4104d13fSDmitry Torokhov * byte5 P15 P14 P13 P12 P11 P10 P9 P8 133*4104d13fSDmitry Torokhov * 134*4104d13fSDmitry Torokhov * (returned as Report 5 - macrokeys from the mouse) 135*4104d13fSDmitry Torokhov * 136*4104d13fSDmitry Torokhov * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 137*4104d13fSDmitry Torokhov * byte0 0 0 0 0 0 1 0 0 138*4104d13fSDmitry Torokhov * byte1 0 0 0 BS2 BS Tip IR DV 139*4104d13fSDmitry Torokhov * byte2 0 0 0 0 0 0 1 0 140*4104d13fSDmitry Torokhov * byte3 0 0 0 K4 K3 K2 K1 K0 141*4104d13fSDmitry Torokhov * byte4 P7 P6 P5 P4 P3 P2 P1 P0 142*4104d13fSDmitry Torokhov * byte5 P15 P14 P13 P12 P11 P10 P9 P8 143*4104d13fSDmitry Torokhov * 144*4104d13fSDmitry Torokhov * IR: In Range = Proximity on 145*4104d13fSDmitry Torokhov * DV = Data Valid 146*4104d13fSDmitry Torokhov * BS = Barrel Switch (as in, macro keys) 147*4104d13fSDmitry Torokhov * BS2 also referred to as Tablet Pick 148*4104d13fSDmitry Torokhov * 149*4104d13fSDmitry Torokhov * Command Summary: 150*4104d13fSDmitry Torokhov * 151*4104d13fSDmitry Torokhov * Use report_type CONTROL (3) 152*4104d13fSDmitry Torokhov * Use report_id 2 153*4104d13fSDmitry Torokhov * 154*4104d13fSDmitry Torokhov * Command/Data Description Return Bytes Return Value 155*4104d13fSDmitry Torokhov * 0x10/0x00 SwitchToMouse 0 156*4104d13fSDmitry Torokhov * 0x10/0x01 SwitchToTablet 0 157*4104d13fSDmitry Torokhov * 0x18/0x04 SetResolution 0 158*4104d13fSDmitry Torokhov * 0x12/0xFF AutoGainOn 0 159*4104d13fSDmitry Torokhov * 0x17/0x00 FilterOn 0 160*4104d13fSDmitry Torokhov * 0x01/0x00 GetXExtension 2 MaxX 161*4104d13fSDmitry Torokhov * 0x01/0x01 GetYExtension 2 MaxY 162*4104d13fSDmitry Torokhov * 0x02/0x00 GetModelCode 2 ModelCode = LOBYTE 163*4104d13fSDmitry Torokhov * 0x03/0x00 GetODMCode 2 ODMCode 164*4104d13fSDmitry Torokhov * 0x08/0x00 GetPressureLevels 2 =512 165*4104d13fSDmitry Torokhov * 0x04/0x00 GetFirmwareVersion 2 Firmware Version 166*4104d13fSDmitry Torokhov * 0x11/0x02 EnableMacroKeys 0 167*4104d13fSDmitry Torokhov * 168*4104d13fSDmitry Torokhov * To initialize the tablet: 169*4104d13fSDmitry Torokhov * 170*4104d13fSDmitry Torokhov * (1) Send Resolution500LPI (Command) 171*4104d13fSDmitry Torokhov * (2) Query for Model code (Option Report) 172*4104d13fSDmitry Torokhov * (3) Query for ODM code (Option Report) 173*4104d13fSDmitry Torokhov * (4) Query for firmware (Option Report) 174*4104d13fSDmitry Torokhov * (5) Query for GetXExtension (Option Report) 175*4104d13fSDmitry Torokhov * (6) Query for GetYExtension (Option Report) 176*4104d13fSDmitry Torokhov * (7) Query for GetPressureLevels (Option Report) 177*4104d13fSDmitry Torokhov * (8) SwitchToTablet for Absolute coordinates, or 178*4104d13fSDmitry Torokhov * SwitchToMouse for Relative coordinates (Command) 179*4104d13fSDmitry Torokhov * (9) EnableMacroKeys (Command) 180*4104d13fSDmitry Torokhov * (10) FilterOn (Command) 181*4104d13fSDmitry Torokhov * (11) AutoGainOn (Command) 182*4104d13fSDmitry Torokhov * 183*4104d13fSDmitry Torokhov * (Step 9 can be omitted, but you'll then have no function keys.) 184*4104d13fSDmitry Torokhov */ 185*4104d13fSDmitry Torokhov 186*4104d13fSDmitry Torokhov #define USB_VENDOR_ID_AIPTEK 0x08ca 187*4104d13fSDmitry Torokhov #define USB_REQ_GET_REPORT 0x01 188*4104d13fSDmitry Torokhov #define USB_REQ_SET_REPORT 0x09 189*4104d13fSDmitry Torokhov 190*4104d13fSDmitry Torokhov /* PointerMode codes 191*4104d13fSDmitry Torokhov */ 192*4104d13fSDmitry Torokhov #define AIPTEK_POINTER_ONLY_MOUSE_MODE 0 193*4104d13fSDmitry Torokhov #define AIPTEK_POINTER_ONLY_STYLUS_MODE 1 194*4104d13fSDmitry Torokhov #define AIPTEK_POINTER_EITHER_MODE 2 195*4104d13fSDmitry Torokhov 196*4104d13fSDmitry Torokhov #define AIPTEK_POINTER_ALLOW_MOUSE_MODE(a) \ 197*4104d13fSDmitry Torokhov (a == AIPTEK_POINTER_ONLY_MOUSE_MODE || \ 198*4104d13fSDmitry Torokhov a == AIPTEK_POINTER_EITHER_MODE) 199*4104d13fSDmitry Torokhov #define AIPTEK_POINTER_ALLOW_STYLUS_MODE(a) \ 200*4104d13fSDmitry Torokhov (a == AIPTEK_POINTER_ONLY_STYLUS_MODE || \ 201*4104d13fSDmitry Torokhov a == AIPTEK_POINTER_EITHER_MODE) 202*4104d13fSDmitry Torokhov 203*4104d13fSDmitry Torokhov /* CoordinateMode code 204*4104d13fSDmitry Torokhov */ 205*4104d13fSDmitry Torokhov #define AIPTEK_COORDINATE_RELATIVE_MODE 0 206*4104d13fSDmitry Torokhov #define AIPTEK_COORDINATE_ABSOLUTE_MODE 1 207*4104d13fSDmitry Torokhov 208*4104d13fSDmitry Torokhov /* XTilt and YTilt values 209*4104d13fSDmitry Torokhov */ 210*4104d13fSDmitry Torokhov #define AIPTEK_TILT_MIN (-128) 211*4104d13fSDmitry Torokhov #define AIPTEK_TILT_MAX 127 212*4104d13fSDmitry Torokhov #define AIPTEK_TILT_DISABLE (-10101) 213*4104d13fSDmitry Torokhov 214*4104d13fSDmitry Torokhov /* Wheel values 215*4104d13fSDmitry Torokhov */ 216*4104d13fSDmitry Torokhov #define AIPTEK_WHEEL_MIN 0 217*4104d13fSDmitry Torokhov #define AIPTEK_WHEEL_MAX 1024 218*4104d13fSDmitry Torokhov #define AIPTEK_WHEEL_DISABLE (-10101) 219*4104d13fSDmitry Torokhov 220*4104d13fSDmitry Torokhov /* ToolCode values, which BTW are 0x140 .. 0x14f 221*4104d13fSDmitry Torokhov * We have things set up such that if TOOL_BUTTON_FIRED_BIT is 222*4104d13fSDmitry Torokhov * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx. 223*4104d13fSDmitry Torokhov * 224*4104d13fSDmitry Torokhov * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will 225*4104d13fSDmitry Torokhov * get reset. 226*4104d13fSDmitry Torokhov */ 227*4104d13fSDmitry Torokhov #define TOOL_BUTTON(x) ((x) & 0x14f) 228*4104d13fSDmitry Torokhov #define TOOL_BUTTON_FIRED(x) ((x) & 0x200) 229*4104d13fSDmitry Torokhov #define TOOL_BUTTON_FIRED_BIT 0x200 230*4104d13fSDmitry Torokhov /* toolMode codes 231*4104d13fSDmitry Torokhov */ 232*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN 233*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN 234*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_PENCIL_MODE BTN_TOOL_PENCIL 235*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_BRUSH_MODE BTN_TOOL_BRUSH 236*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE BTN_TOOL_AIRBRUSH 237*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_ERASER_MODE BTN_TOOL_RUBBER 238*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_MOUSE_MODE BTN_TOOL_MOUSE 239*4104d13fSDmitry Torokhov #define AIPTEK_TOOL_BUTTON_LENS_MODE BTN_TOOL_LENS 240*4104d13fSDmitry Torokhov 241*4104d13fSDmitry Torokhov /* Diagnostic message codes 242*4104d13fSDmitry Torokhov */ 243*4104d13fSDmitry Torokhov #define AIPTEK_DIAGNOSTIC_NA 0 244*4104d13fSDmitry Torokhov #define AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE 1 245*4104d13fSDmitry Torokhov #define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2 246*4104d13fSDmitry Torokhov #define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED 3 247*4104d13fSDmitry Torokhov 248*4104d13fSDmitry Torokhov /* Time to wait (in ms) to help mask hand jittering 249*4104d13fSDmitry Torokhov * when pressing the stylus buttons. 250*4104d13fSDmitry Torokhov */ 251*4104d13fSDmitry Torokhov #define AIPTEK_JITTER_DELAY_DEFAULT 50 252*4104d13fSDmitry Torokhov 253*4104d13fSDmitry Torokhov /* Time to wait (in ms) in-between sending the tablet 254*4104d13fSDmitry Torokhov * a command and beginning the process of reading the return 255*4104d13fSDmitry Torokhov * sequence from the tablet. 256*4104d13fSDmitry Torokhov */ 257*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_25 25 258*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_50 50 259*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_100 100 260*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_200 200 261*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_300 300 262*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_400 400 263*4104d13fSDmitry Torokhov #define AIPTEK_PROGRAMMABLE_DELAY_DEFAULT AIPTEK_PROGRAMMABLE_DELAY_400 264*4104d13fSDmitry Torokhov 265*4104d13fSDmitry Torokhov /* Mouse button programming 266*4104d13fSDmitry Torokhov */ 267*4104d13fSDmitry Torokhov #define AIPTEK_MOUSE_LEFT_BUTTON 0x01 268*4104d13fSDmitry Torokhov #define AIPTEK_MOUSE_RIGHT_BUTTON 0x02 269*4104d13fSDmitry Torokhov #define AIPTEK_MOUSE_MIDDLE_BUTTON 0x04 270*4104d13fSDmitry Torokhov 271*4104d13fSDmitry Torokhov /* Stylus button programming 272*4104d13fSDmitry Torokhov */ 273*4104d13fSDmitry Torokhov #define AIPTEK_STYLUS_LOWER_BUTTON 0x08 274*4104d13fSDmitry Torokhov #define AIPTEK_STYLUS_UPPER_BUTTON 0x10 275*4104d13fSDmitry Torokhov 276*4104d13fSDmitry Torokhov /* Length of incoming packet from the tablet 277*4104d13fSDmitry Torokhov */ 278*4104d13fSDmitry Torokhov #define AIPTEK_PACKET_LENGTH 8 279*4104d13fSDmitry Torokhov 280*4104d13fSDmitry Torokhov /* We report in EV_MISC both the proximity and 281*4104d13fSDmitry Torokhov * whether the report came from the stylus, tablet mouse 282*4104d13fSDmitry Torokhov * or "unknown" -- Unknown when the tablet is in relative 283*4104d13fSDmitry Torokhov * mode, because we only get report 1's. 284*4104d13fSDmitry Torokhov */ 285*4104d13fSDmitry Torokhov #define AIPTEK_REPORT_TOOL_UNKNOWN 0x10 286*4104d13fSDmitry Torokhov #define AIPTEK_REPORT_TOOL_STYLUS 0x20 287*4104d13fSDmitry Torokhov #define AIPTEK_REPORT_TOOL_MOUSE 0x40 288*4104d13fSDmitry Torokhov 289*4104d13fSDmitry Torokhov static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT; 290*4104d13fSDmitry Torokhov static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT; 291*4104d13fSDmitry Torokhov 292*4104d13fSDmitry Torokhov struct aiptek_features { 293*4104d13fSDmitry Torokhov int odmCode; /* Tablet manufacturer code */ 294*4104d13fSDmitry Torokhov int modelCode; /* Tablet model code (not unique) */ 295*4104d13fSDmitry Torokhov int firmwareCode; /* prom/eeprom version */ 296*4104d13fSDmitry Torokhov char usbPath[64 + 1]; /* device's physical usb path */ 297*4104d13fSDmitry Torokhov char inputPath[64 + 1]; /* input device path */ 298*4104d13fSDmitry Torokhov }; 299*4104d13fSDmitry Torokhov 300*4104d13fSDmitry Torokhov struct aiptek_settings { 301*4104d13fSDmitry Torokhov int pointerMode; /* stylus-, mouse-only or either */ 302*4104d13fSDmitry Torokhov int coordinateMode; /* absolute/relative coords */ 303*4104d13fSDmitry Torokhov int toolMode; /* pen, pencil, brush, etc. tool */ 304*4104d13fSDmitry Torokhov int xTilt; /* synthetic xTilt amount */ 305*4104d13fSDmitry Torokhov int yTilt; /* synthetic yTilt amount */ 306*4104d13fSDmitry Torokhov int wheel; /* synthetic wheel amount */ 307*4104d13fSDmitry Torokhov int stylusButtonUpper; /* stylus upper btn delivers... */ 308*4104d13fSDmitry Torokhov int stylusButtonLower; /* stylus lower btn delivers... */ 309*4104d13fSDmitry Torokhov int mouseButtonLeft; /* mouse left btn delivers... */ 310*4104d13fSDmitry Torokhov int mouseButtonMiddle; /* mouse middle btn delivers... */ 311*4104d13fSDmitry Torokhov int mouseButtonRight; /* mouse right btn delivers... */ 312*4104d13fSDmitry Torokhov int programmableDelay; /* delay for tablet programming */ 313*4104d13fSDmitry Torokhov int jitterDelay; /* delay for hand jittering */ 314*4104d13fSDmitry Torokhov }; 315*4104d13fSDmitry Torokhov 316*4104d13fSDmitry Torokhov struct aiptek { 317*4104d13fSDmitry Torokhov struct input_dev *inputdev; /* input device struct */ 318*4104d13fSDmitry Torokhov struct usb_device *usbdev; /* usb device struct */ 319*4104d13fSDmitry Torokhov struct urb *urb; /* urb for incoming reports */ 320*4104d13fSDmitry Torokhov dma_addr_t data_dma; /* our dma stuffage */ 321*4104d13fSDmitry Torokhov struct aiptek_features features; /* tablet's array of features */ 322*4104d13fSDmitry Torokhov struct aiptek_settings curSetting; /* tablet's current programmable */ 323*4104d13fSDmitry Torokhov struct aiptek_settings newSetting; /* ... and new param settings */ 324*4104d13fSDmitry Torokhov unsigned int ifnum; /* interface number for IO */ 325*4104d13fSDmitry Torokhov int diagnostic; /* tablet diagnostic codes */ 326*4104d13fSDmitry Torokhov unsigned long eventCount; /* event count */ 327*4104d13fSDmitry Torokhov int inDelay; /* jitter: in jitter delay? */ 328*4104d13fSDmitry Torokhov unsigned long endDelay; /* jitter: time when delay ends */ 329*4104d13fSDmitry Torokhov int previousJitterable; /* jitterable prev value */ 330*4104d13fSDmitry Torokhov unsigned char *data; /* incoming packet data */ 331*4104d13fSDmitry Torokhov }; 332*4104d13fSDmitry Torokhov 333*4104d13fSDmitry Torokhov /* 334*4104d13fSDmitry Torokhov * Permit easy lookup of keyboard events to send, versus 335*4104d13fSDmitry Torokhov * the bitmap which comes from the tablet. This hides the 336*4104d13fSDmitry Torokhov * issue that the F_keys are not sequentially numbered. 337*4104d13fSDmitry Torokhov */ 338*4104d13fSDmitry Torokhov static const int macroKeyEvents[] = { 339*4104d13fSDmitry Torokhov KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, 340*4104d13fSDmitry Torokhov KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, 341*4104d13fSDmitry Torokhov KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, 342*4104d13fSDmitry Torokhov KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, 343*4104d13fSDmitry Torokhov KEY_F24, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO, 344*4104d13fSDmitry Torokhov KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, 0 345*4104d13fSDmitry Torokhov }; 346*4104d13fSDmitry Torokhov 347*4104d13fSDmitry Torokhov /*********************************************************************** 348*4104d13fSDmitry Torokhov * Relative reports deliver values in 2's complement format to 349*4104d13fSDmitry Torokhov * deal with negative offsets. 350*4104d13fSDmitry Torokhov */ 351*4104d13fSDmitry Torokhov static int aiptek_convert_from_2s_complement(unsigned char c) 352*4104d13fSDmitry Torokhov { 353*4104d13fSDmitry Torokhov int ret; 354*4104d13fSDmitry Torokhov unsigned char b = c; 355*4104d13fSDmitry Torokhov int negate = 0; 356*4104d13fSDmitry Torokhov 357*4104d13fSDmitry Torokhov if ((b & 0x80) != 0) { 358*4104d13fSDmitry Torokhov b = ~b; 359*4104d13fSDmitry Torokhov b--; 360*4104d13fSDmitry Torokhov negate = 1; 361*4104d13fSDmitry Torokhov } 362*4104d13fSDmitry Torokhov ret = b; 363*4104d13fSDmitry Torokhov ret = (negate == 1) ? -ret : ret; 364*4104d13fSDmitry Torokhov return ret; 365*4104d13fSDmitry Torokhov } 366*4104d13fSDmitry Torokhov 367*4104d13fSDmitry Torokhov /*********************************************************************** 368*4104d13fSDmitry Torokhov * aiptek_irq can receive one of six potential reports. 369*4104d13fSDmitry Torokhov * The documentation for each is in the body of the function. 370*4104d13fSDmitry Torokhov * 371*4104d13fSDmitry Torokhov * The tablet reports on several attributes per invocation of 372*4104d13fSDmitry Torokhov * aiptek_irq. Because the Linux Input Event system allows the 373*4104d13fSDmitry Torokhov * transmission of ONE attribute per input_report_xxx() call, 374*4104d13fSDmitry Torokhov * collation has to be done on the other end to reconstitute 375*4104d13fSDmitry Torokhov * a complete tablet report. Further, the number of Input Event reports 376*4104d13fSDmitry Torokhov * submitted varies, depending on what USB report type, and circumstance. 377*4104d13fSDmitry Torokhov * To deal with this, EV_MSC is used to indicate an 'end-of-report' 378*4104d13fSDmitry Torokhov * message. This has been an undocumented convention understood by the kernel 379*4104d13fSDmitry Torokhov * tablet driver and clients such as gpm and XFree86's tablet drivers. 380*4104d13fSDmitry Torokhov * 381*4104d13fSDmitry Torokhov * Of the information received from the tablet, the one piece I 382*4104d13fSDmitry Torokhov * cannot transmit is the proximity bit (without resorting to an EV_MSC 383*4104d13fSDmitry Torokhov * convention above.) I therefore have taken over REL_MISC and ABS_MISC 384*4104d13fSDmitry Torokhov * (for relative and absolute reports, respectively) for communicating 385*4104d13fSDmitry Torokhov * Proximity. Why two events? I thought it interesting to know if the 386*4104d13fSDmitry Torokhov * Proximity event occurred while the tablet was in absolute or relative 387*4104d13fSDmitry Torokhov * mode. 388*4104d13fSDmitry Torokhov * 389*4104d13fSDmitry Torokhov * Other tablets use the notion of a certain minimum stylus pressure 390*4104d13fSDmitry Torokhov * to infer proximity. While that could have been done, that is yet 391*4104d13fSDmitry Torokhov * another 'by convention' behavior, the documentation for which 392*4104d13fSDmitry Torokhov * would be spread between two (or more) pieces of software. 393*4104d13fSDmitry Torokhov * 394*4104d13fSDmitry Torokhov * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and 395*4104d13fSDmitry Torokhov * replaced with the input_sync() method (which emits EV_SYN.) 396*4104d13fSDmitry Torokhov */ 397*4104d13fSDmitry Torokhov 398*4104d13fSDmitry Torokhov static void aiptek_irq(struct urb *urb) 399*4104d13fSDmitry Torokhov { 400*4104d13fSDmitry Torokhov struct aiptek *aiptek = urb->context; 401*4104d13fSDmitry Torokhov unsigned char *data = aiptek->data; 402*4104d13fSDmitry Torokhov struct input_dev *inputdev = aiptek->inputdev; 403*4104d13fSDmitry Torokhov int jitterable = 0; 404*4104d13fSDmitry Torokhov int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck; 405*4104d13fSDmitry Torokhov 406*4104d13fSDmitry Torokhov switch (urb->status) { 407*4104d13fSDmitry Torokhov case 0: 408*4104d13fSDmitry Torokhov /* Success */ 409*4104d13fSDmitry Torokhov break; 410*4104d13fSDmitry Torokhov 411*4104d13fSDmitry Torokhov case -ECONNRESET: 412*4104d13fSDmitry Torokhov case -ENOENT: 413*4104d13fSDmitry Torokhov case -ESHUTDOWN: 414*4104d13fSDmitry Torokhov /* This urb is terminated, clean up */ 415*4104d13fSDmitry Torokhov dbg("%s - urb shutting down with status: %d", 416*4104d13fSDmitry Torokhov __FUNCTION__, urb->status); 417*4104d13fSDmitry Torokhov return; 418*4104d13fSDmitry Torokhov 419*4104d13fSDmitry Torokhov default: 420*4104d13fSDmitry Torokhov dbg("%s - nonzero urb status received: %d", 421*4104d13fSDmitry Torokhov __FUNCTION__, urb->status); 422*4104d13fSDmitry Torokhov goto exit; 423*4104d13fSDmitry Torokhov } 424*4104d13fSDmitry Torokhov 425*4104d13fSDmitry Torokhov /* See if we are in a delay loop -- throw out report if true. 426*4104d13fSDmitry Torokhov */ 427*4104d13fSDmitry Torokhov if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) { 428*4104d13fSDmitry Torokhov goto exit; 429*4104d13fSDmitry Torokhov } 430*4104d13fSDmitry Torokhov 431*4104d13fSDmitry Torokhov aiptek->inDelay = 0; 432*4104d13fSDmitry Torokhov aiptek->eventCount++; 433*4104d13fSDmitry Torokhov 434*4104d13fSDmitry Torokhov /* Report 1 delivers relative coordinates with either a stylus 435*4104d13fSDmitry Torokhov * or the mouse. You do not know, however, which input 436*4104d13fSDmitry Torokhov * tool generated the event. 437*4104d13fSDmitry Torokhov */ 438*4104d13fSDmitry Torokhov if (data[0] == 1) { 439*4104d13fSDmitry Torokhov if (aiptek->curSetting.coordinateMode == 440*4104d13fSDmitry Torokhov AIPTEK_COORDINATE_ABSOLUTE_MODE) { 441*4104d13fSDmitry Torokhov aiptek->diagnostic = 442*4104d13fSDmitry Torokhov AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE; 443*4104d13fSDmitry Torokhov } else { 444*4104d13fSDmitry Torokhov x = aiptek_convert_from_2s_complement(data[2]); 445*4104d13fSDmitry Torokhov y = aiptek_convert_from_2s_complement(data[3]); 446*4104d13fSDmitry Torokhov 447*4104d13fSDmitry Torokhov /* jitterable keeps track of whether any button has been pressed. 448*4104d13fSDmitry Torokhov * We're also using it to remap the physical mouse button mask 449*4104d13fSDmitry Torokhov * to pseudo-settings. (We don't specifically care about it's 450*4104d13fSDmitry Torokhov * value after moving/transposing mouse button bitmasks, except 451*4104d13fSDmitry Torokhov * that a non-zero value indicates that one or more 452*4104d13fSDmitry Torokhov * mouse button was pressed.) 453*4104d13fSDmitry Torokhov */ 454*4104d13fSDmitry Torokhov jitterable = data[5] & 0x07; 455*4104d13fSDmitry Torokhov 456*4104d13fSDmitry Torokhov left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; 457*4104d13fSDmitry Torokhov right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; 458*4104d13fSDmitry Torokhov middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; 459*4104d13fSDmitry Torokhov 460*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_LEFT, left); 461*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_MIDDLE, middle); 462*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_RIGHT, right); 463*4104d13fSDmitry Torokhov input_report_rel(inputdev, REL_X, x); 464*4104d13fSDmitry Torokhov input_report_rel(inputdev, REL_Y, y); 465*4104d13fSDmitry Torokhov input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN); 466*4104d13fSDmitry Torokhov 467*4104d13fSDmitry Torokhov /* Wheel support is in the form of a single-event 468*4104d13fSDmitry Torokhov * firing. 469*4104d13fSDmitry Torokhov */ 470*4104d13fSDmitry Torokhov if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) { 471*4104d13fSDmitry Torokhov input_report_rel(inputdev, REL_WHEEL, 472*4104d13fSDmitry Torokhov aiptek->curSetting.wheel); 473*4104d13fSDmitry Torokhov aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; 474*4104d13fSDmitry Torokhov } 475*4104d13fSDmitry Torokhov input_sync(inputdev); 476*4104d13fSDmitry Torokhov } 477*4104d13fSDmitry Torokhov } 478*4104d13fSDmitry Torokhov /* Report 2 is delivered only by the stylus, and delivers 479*4104d13fSDmitry Torokhov * absolute coordinates. 480*4104d13fSDmitry Torokhov */ 481*4104d13fSDmitry Torokhov else if (data[0] == 2) { 482*4104d13fSDmitry Torokhov if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) { 483*4104d13fSDmitry Torokhov aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE; 484*4104d13fSDmitry Torokhov } else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE 485*4104d13fSDmitry Torokhov (aiptek->curSetting.pointerMode)) { 486*4104d13fSDmitry Torokhov aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; 487*4104d13fSDmitry Torokhov } else { 488*4104d13fSDmitry Torokhov x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); 489*4104d13fSDmitry Torokhov y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); 490*4104d13fSDmitry Torokhov z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); 491*4104d13fSDmitry Torokhov 492*4104d13fSDmitry Torokhov p = (data[5] & 0x01) != 0 ? 1 : 0; 493*4104d13fSDmitry Torokhov dv = (data[5] & 0x02) != 0 ? 1 : 0; 494*4104d13fSDmitry Torokhov tip = (data[5] & 0x04) != 0 ? 1 : 0; 495*4104d13fSDmitry Torokhov 496*4104d13fSDmitry Torokhov /* Use jitterable to re-arrange button masks 497*4104d13fSDmitry Torokhov */ 498*4104d13fSDmitry Torokhov jitterable = data[5] & 0x18; 499*4104d13fSDmitry Torokhov 500*4104d13fSDmitry Torokhov bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; 501*4104d13fSDmitry Torokhov pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; 502*4104d13fSDmitry Torokhov 503*4104d13fSDmitry Torokhov /* dv indicates 'data valid' (e.g., the tablet is in sync 504*4104d13fSDmitry Torokhov * and has delivered a "correct" report) We will ignore 505*4104d13fSDmitry Torokhov * all 'bad' reports... 506*4104d13fSDmitry Torokhov */ 507*4104d13fSDmitry Torokhov if (dv != 0) { 508*4104d13fSDmitry Torokhov /* If we've not already sent a tool_button_?? code, do 509*4104d13fSDmitry Torokhov * so now. Then set FIRED_BIT so it won't be resent unless 510*4104d13fSDmitry Torokhov * the user forces FIRED_BIT off. 511*4104d13fSDmitry Torokhov */ 512*4104d13fSDmitry Torokhov if (TOOL_BUTTON_FIRED 513*4104d13fSDmitry Torokhov (aiptek->curSetting.toolMode) == 0) { 514*4104d13fSDmitry Torokhov input_report_key(inputdev, 515*4104d13fSDmitry Torokhov TOOL_BUTTON(aiptek->curSetting.toolMode), 516*4104d13fSDmitry Torokhov 1); 517*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; 518*4104d13fSDmitry Torokhov } 519*4104d13fSDmitry Torokhov 520*4104d13fSDmitry Torokhov if (p != 0) { 521*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_X, x); 522*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_Y, y); 523*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_PRESSURE, z); 524*4104d13fSDmitry Torokhov 525*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_TOUCH, tip); 526*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_STYLUS, bs); 527*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_STYLUS2, pck); 528*4104d13fSDmitry Torokhov 529*4104d13fSDmitry Torokhov if (aiptek->curSetting.xTilt != 530*4104d13fSDmitry Torokhov AIPTEK_TILT_DISABLE) { 531*4104d13fSDmitry Torokhov input_report_abs(inputdev, 532*4104d13fSDmitry Torokhov ABS_TILT_X, 533*4104d13fSDmitry Torokhov aiptek->curSetting.xTilt); 534*4104d13fSDmitry Torokhov } 535*4104d13fSDmitry Torokhov if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) { 536*4104d13fSDmitry Torokhov input_report_abs(inputdev, 537*4104d13fSDmitry Torokhov ABS_TILT_Y, 538*4104d13fSDmitry Torokhov aiptek->curSetting.yTilt); 539*4104d13fSDmitry Torokhov } 540*4104d13fSDmitry Torokhov 541*4104d13fSDmitry Torokhov /* Wheel support is in the form of a single-event 542*4104d13fSDmitry Torokhov * firing. 543*4104d13fSDmitry Torokhov */ 544*4104d13fSDmitry Torokhov if (aiptek->curSetting.wheel != 545*4104d13fSDmitry Torokhov AIPTEK_WHEEL_DISABLE) { 546*4104d13fSDmitry Torokhov input_report_abs(inputdev, 547*4104d13fSDmitry Torokhov ABS_WHEEL, 548*4104d13fSDmitry Torokhov aiptek->curSetting.wheel); 549*4104d13fSDmitry Torokhov aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; 550*4104d13fSDmitry Torokhov } 551*4104d13fSDmitry Torokhov } 552*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS); 553*4104d13fSDmitry Torokhov input_sync(inputdev); 554*4104d13fSDmitry Torokhov } 555*4104d13fSDmitry Torokhov } 556*4104d13fSDmitry Torokhov } 557*4104d13fSDmitry Torokhov /* Report 3's come from the mouse in absolute mode. 558*4104d13fSDmitry Torokhov */ 559*4104d13fSDmitry Torokhov else if (data[0] == 3) { 560*4104d13fSDmitry Torokhov if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) { 561*4104d13fSDmitry Torokhov aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE; 562*4104d13fSDmitry Torokhov } else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE 563*4104d13fSDmitry Torokhov (aiptek->curSetting.pointerMode)) { 564*4104d13fSDmitry Torokhov aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; 565*4104d13fSDmitry Torokhov } else { 566*4104d13fSDmitry Torokhov x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); 567*4104d13fSDmitry Torokhov y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); 568*4104d13fSDmitry Torokhov 569*4104d13fSDmitry Torokhov jitterable = data[5] & 0x1c; 570*4104d13fSDmitry Torokhov 571*4104d13fSDmitry Torokhov p = (data[5] & 0x01) != 0 ? 1 : 0; 572*4104d13fSDmitry Torokhov dv = (data[5] & 0x02) != 0 ? 1 : 0; 573*4104d13fSDmitry Torokhov left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; 574*4104d13fSDmitry Torokhov right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; 575*4104d13fSDmitry Torokhov middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; 576*4104d13fSDmitry Torokhov 577*4104d13fSDmitry Torokhov if (dv != 0) { 578*4104d13fSDmitry Torokhov /* If we've not already sent a tool_button_?? code, do 579*4104d13fSDmitry Torokhov * so now. Then set FIRED_BIT so it won't be resent unless 580*4104d13fSDmitry Torokhov * the user forces FIRED_BIT off. 581*4104d13fSDmitry Torokhov */ 582*4104d13fSDmitry Torokhov if (TOOL_BUTTON_FIRED 583*4104d13fSDmitry Torokhov (aiptek->curSetting.toolMode) == 0) { 584*4104d13fSDmitry Torokhov input_report_key(inputdev, 585*4104d13fSDmitry Torokhov TOOL_BUTTON(aiptek->curSetting.toolMode), 586*4104d13fSDmitry Torokhov 1); 587*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; 588*4104d13fSDmitry Torokhov } 589*4104d13fSDmitry Torokhov 590*4104d13fSDmitry Torokhov if (p != 0) { 591*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_X, x); 592*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_Y, y); 593*4104d13fSDmitry Torokhov 594*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_LEFT, left); 595*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_MIDDLE, middle); 596*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_RIGHT, right); 597*4104d13fSDmitry Torokhov 598*4104d13fSDmitry Torokhov /* Wheel support is in the form of a single-event 599*4104d13fSDmitry Torokhov * firing. 600*4104d13fSDmitry Torokhov */ 601*4104d13fSDmitry Torokhov if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) { 602*4104d13fSDmitry Torokhov input_report_abs(inputdev, 603*4104d13fSDmitry Torokhov ABS_WHEEL, 604*4104d13fSDmitry Torokhov aiptek->curSetting.wheel); 605*4104d13fSDmitry Torokhov aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; 606*4104d13fSDmitry Torokhov } 607*4104d13fSDmitry Torokhov } 608*4104d13fSDmitry Torokhov input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); 609*4104d13fSDmitry Torokhov input_sync(inputdev); 610*4104d13fSDmitry Torokhov } 611*4104d13fSDmitry Torokhov } 612*4104d13fSDmitry Torokhov } 613*4104d13fSDmitry Torokhov /* Report 4s come from the macro keys when pressed by stylus 614*4104d13fSDmitry Torokhov */ 615*4104d13fSDmitry Torokhov else if (data[0] == 4) { 616*4104d13fSDmitry Torokhov jitterable = data[1] & 0x18; 617*4104d13fSDmitry Torokhov 618*4104d13fSDmitry Torokhov p = (data[1] & 0x01) != 0 ? 1 : 0; 619*4104d13fSDmitry Torokhov dv = (data[1] & 0x02) != 0 ? 1 : 0; 620*4104d13fSDmitry Torokhov tip = (data[1] & 0x04) != 0 ? 1 : 0; 621*4104d13fSDmitry Torokhov bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; 622*4104d13fSDmitry Torokhov pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; 623*4104d13fSDmitry Torokhov 624*4104d13fSDmitry Torokhov macro = data[3]; 625*4104d13fSDmitry Torokhov z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); 626*4104d13fSDmitry Torokhov 627*4104d13fSDmitry Torokhov if (dv != 0) { 628*4104d13fSDmitry Torokhov /* If we've not already sent a tool_button_?? code, do 629*4104d13fSDmitry Torokhov * so now. Then set FIRED_BIT so it won't be resent unless 630*4104d13fSDmitry Torokhov * the user forces FIRED_BIT off. 631*4104d13fSDmitry Torokhov */ 632*4104d13fSDmitry Torokhov if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { 633*4104d13fSDmitry Torokhov input_report_key(inputdev, 634*4104d13fSDmitry Torokhov TOOL_BUTTON(aiptek->curSetting.toolMode), 635*4104d13fSDmitry Torokhov 1); 636*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; 637*4104d13fSDmitry Torokhov } 638*4104d13fSDmitry Torokhov 639*4104d13fSDmitry Torokhov if (p != 0) { 640*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_TOUCH, tip); 641*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_STYLUS, bs); 642*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_STYLUS2, pck); 643*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_PRESSURE, z); 644*4104d13fSDmitry Torokhov } 645*4104d13fSDmitry Torokhov 646*4104d13fSDmitry Torokhov /* For safety, we're sending key 'break' codes for the 647*4104d13fSDmitry Torokhov * neighboring macro keys. 648*4104d13fSDmitry Torokhov */ 649*4104d13fSDmitry Torokhov if (macro > 0) { 650*4104d13fSDmitry Torokhov input_report_key(inputdev, 651*4104d13fSDmitry Torokhov macroKeyEvents[macro - 1], 0); 652*4104d13fSDmitry Torokhov } 653*4104d13fSDmitry Torokhov if (macro < 25) { 654*4104d13fSDmitry Torokhov input_report_key(inputdev, 655*4104d13fSDmitry Torokhov macroKeyEvents[macro + 1], 0); 656*4104d13fSDmitry Torokhov } 657*4104d13fSDmitry Torokhov input_report_key(inputdev, macroKeyEvents[macro], p); 658*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_MISC, 659*4104d13fSDmitry Torokhov p | AIPTEK_REPORT_TOOL_STYLUS); 660*4104d13fSDmitry Torokhov input_sync(inputdev); 661*4104d13fSDmitry Torokhov } 662*4104d13fSDmitry Torokhov } 663*4104d13fSDmitry Torokhov /* Report 5s come from the macro keys when pressed by mouse 664*4104d13fSDmitry Torokhov */ 665*4104d13fSDmitry Torokhov else if (data[0] == 5) { 666*4104d13fSDmitry Torokhov jitterable = data[1] & 0x1c; 667*4104d13fSDmitry Torokhov 668*4104d13fSDmitry Torokhov p = (data[1] & 0x01) != 0 ? 1 : 0; 669*4104d13fSDmitry Torokhov dv = (data[1] & 0x02) != 0 ? 1 : 0; 670*4104d13fSDmitry Torokhov left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; 671*4104d13fSDmitry Torokhov right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; 672*4104d13fSDmitry Torokhov middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; 673*4104d13fSDmitry Torokhov macro = data[3]; 674*4104d13fSDmitry Torokhov 675*4104d13fSDmitry Torokhov if (dv != 0) { 676*4104d13fSDmitry Torokhov /* If we've not already sent a tool_button_?? code, do 677*4104d13fSDmitry Torokhov * so now. Then set FIRED_BIT so it won't be resent unless 678*4104d13fSDmitry Torokhov * the user forces FIRED_BIT off. 679*4104d13fSDmitry Torokhov */ 680*4104d13fSDmitry Torokhov if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { 681*4104d13fSDmitry Torokhov input_report_key(inputdev, 682*4104d13fSDmitry Torokhov TOOL_BUTTON(aiptek->curSetting.toolMode), 683*4104d13fSDmitry Torokhov 1); 684*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; 685*4104d13fSDmitry Torokhov } 686*4104d13fSDmitry Torokhov 687*4104d13fSDmitry Torokhov if (p != 0) { 688*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_LEFT, left); 689*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_MIDDLE, middle); 690*4104d13fSDmitry Torokhov input_report_key(inputdev, BTN_RIGHT, right); 691*4104d13fSDmitry Torokhov } 692*4104d13fSDmitry Torokhov 693*4104d13fSDmitry Torokhov /* For safety, we're sending key 'break' codes for the 694*4104d13fSDmitry Torokhov * neighboring macro keys. 695*4104d13fSDmitry Torokhov */ 696*4104d13fSDmitry Torokhov if (macro > 0) { 697*4104d13fSDmitry Torokhov input_report_key(inputdev, 698*4104d13fSDmitry Torokhov macroKeyEvents[macro - 1], 0); 699*4104d13fSDmitry Torokhov } 700*4104d13fSDmitry Torokhov if (macro < 25) { 701*4104d13fSDmitry Torokhov input_report_key(inputdev, 702*4104d13fSDmitry Torokhov macroKeyEvents[macro + 1], 0); 703*4104d13fSDmitry Torokhov } 704*4104d13fSDmitry Torokhov 705*4104d13fSDmitry Torokhov input_report_key(inputdev, macroKeyEvents[macro], 1); 706*4104d13fSDmitry Torokhov input_report_rel(inputdev, ABS_MISC, 707*4104d13fSDmitry Torokhov p | AIPTEK_REPORT_TOOL_MOUSE); 708*4104d13fSDmitry Torokhov input_sync(inputdev); 709*4104d13fSDmitry Torokhov } 710*4104d13fSDmitry Torokhov } 711*4104d13fSDmitry Torokhov /* We have no idea which tool can generate a report 6. Theoretically, 712*4104d13fSDmitry Torokhov * neither need to, having been given reports 4 & 5 for such use. 713*4104d13fSDmitry Torokhov * However, report 6 is the 'official-looking' report for macroKeys; 714*4104d13fSDmitry Torokhov * reports 4 & 5 supposively are used to support unnamed, unknown 715*4104d13fSDmitry Torokhov * hat switches (which just so happen to be the macroKeys.) 716*4104d13fSDmitry Torokhov */ 717*4104d13fSDmitry Torokhov else if (data[0] == 6) { 718*4104d13fSDmitry Torokhov macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); 719*4104d13fSDmitry Torokhov if (macro > 0) { 720*4104d13fSDmitry Torokhov input_report_key(inputdev, macroKeyEvents[macro - 1], 721*4104d13fSDmitry Torokhov 0); 722*4104d13fSDmitry Torokhov } 723*4104d13fSDmitry Torokhov if (macro < 25) { 724*4104d13fSDmitry Torokhov input_report_key(inputdev, macroKeyEvents[macro + 1], 725*4104d13fSDmitry Torokhov 0); 726*4104d13fSDmitry Torokhov } 727*4104d13fSDmitry Torokhov 728*4104d13fSDmitry Torokhov /* If we've not already sent a tool_button_?? code, do 729*4104d13fSDmitry Torokhov * so now. Then set FIRED_BIT so it won't be resent unless 730*4104d13fSDmitry Torokhov * the user forces FIRED_BIT off. 731*4104d13fSDmitry Torokhov */ 732*4104d13fSDmitry Torokhov if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { 733*4104d13fSDmitry Torokhov input_report_key(inputdev, 734*4104d13fSDmitry Torokhov TOOL_BUTTON(aiptek->curSetting. 735*4104d13fSDmitry Torokhov toolMode), 1); 736*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; 737*4104d13fSDmitry Torokhov } 738*4104d13fSDmitry Torokhov 739*4104d13fSDmitry Torokhov input_report_key(inputdev, macroKeyEvents[macro], 1); 740*4104d13fSDmitry Torokhov input_report_abs(inputdev, ABS_MISC, 741*4104d13fSDmitry Torokhov 1 | AIPTEK_REPORT_TOOL_UNKNOWN); 742*4104d13fSDmitry Torokhov input_sync(inputdev); 743*4104d13fSDmitry Torokhov } else { 744*4104d13fSDmitry Torokhov dbg("Unknown report %d", data[0]); 745*4104d13fSDmitry Torokhov } 746*4104d13fSDmitry Torokhov 747*4104d13fSDmitry Torokhov /* Jitter may occur when the user presses a button on the stlyus 748*4104d13fSDmitry Torokhov * or the mouse. What we do to prevent that is wait 'x' milliseconds 749*4104d13fSDmitry Torokhov * following a 'jitterable' event, which should give the hand some time 750*4104d13fSDmitry Torokhov * stabilize itself. 751*4104d13fSDmitry Torokhov * 752*4104d13fSDmitry Torokhov * We just introduced aiptek->previousJitterable to carry forth the 753*4104d13fSDmitry Torokhov * notion that jitter occurs when the button state changes from on to off: 754*4104d13fSDmitry Torokhov * a person drawing, holding a button down is not subject to jittering. 755*4104d13fSDmitry Torokhov * With that in mind, changing from upper button depressed to lower button 756*4104d13fSDmitry Torokhov * WILL transition through a jitter delay. 757*4104d13fSDmitry Torokhov */ 758*4104d13fSDmitry Torokhov 759*4104d13fSDmitry Torokhov if (aiptek->previousJitterable != jitterable && 760*4104d13fSDmitry Torokhov aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) { 761*4104d13fSDmitry Torokhov aiptek->endDelay = jiffies + 762*4104d13fSDmitry Torokhov ((aiptek->curSetting.jitterDelay * HZ) / 1000); 763*4104d13fSDmitry Torokhov aiptek->inDelay = 1; 764*4104d13fSDmitry Torokhov } 765*4104d13fSDmitry Torokhov aiptek->previousJitterable = jitterable; 766*4104d13fSDmitry Torokhov 767*4104d13fSDmitry Torokhov exit: 768*4104d13fSDmitry Torokhov retval = usb_submit_urb(urb, GFP_ATOMIC); 769*4104d13fSDmitry Torokhov if (retval != 0) { 770*4104d13fSDmitry Torokhov err("%s - usb_submit_urb failed with result %d", 771*4104d13fSDmitry Torokhov __FUNCTION__, retval); 772*4104d13fSDmitry Torokhov } 773*4104d13fSDmitry Torokhov } 774*4104d13fSDmitry Torokhov 775*4104d13fSDmitry Torokhov /*********************************************************************** 776*4104d13fSDmitry Torokhov * These are the USB id's known so far. We do not identify them to 777*4104d13fSDmitry Torokhov * specific Aiptek model numbers, because there has been overlaps, 778*4104d13fSDmitry Torokhov * use, and reuse of id's in existing models. Certain models have 779*4104d13fSDmitry Torokhov * been known to use more than one ID, indicative perhaps of 780*4104d13fSDmitry Torokhov * manufacturing revisions. In any event, we consider these 781*4104d13fSDmitry Torokhov * IDs to not be model-specific nor unique. 782*4104d13fSDmitry Torokhov */ 783*4104d13fSDmitry Torokhov static const struct usb_device_id aiptek_ids[] = { 784*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)}, 785*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)}, 786*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)}, 787*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)}, 788*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)}, 789*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)}, 790*4104d13fSDmitry Torokhov {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)}, 791*4104d13fSDmitry Torokhov {} 792*4104d13fSDmitry Torokhov }; 793*4104d13fSDmitry Torokhov 794*4104d13fSDmitry Torokhov MODULE_DEVICE_TABLE(usb, aiptek_ids); 795*4104d13fSDmitry Torokhov 796*4104d13fSDmitry Torokhov /*********************************************************************** 797*4104d13fSDmitry Torokhov * Open an instance of the tablet driver. 798*4104d13fSDmitry Torokhov */ 799*4104d13fSDmitry Torokhov static int aiptek_open(struct input_dev *inputdev) 800*4104d13fSDmitry Torokhov { 801*4104d13fSDmitry Torokhov struct aiptek *aiptek = input_get_drvdata(inputdev); 802*4104d13fSDmitry Torokhov 803*4104d13fSDmitry Torokhov aiptek->urb->dev = aiptek->usbdev; 804*4104d13fSDmitry Torokhov if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) 805*4104d13fSDmitry Torokhov return -EIO; 806*4104d13fSDmitry Torokhov 807*4104d13fSDmitry Torokhov return 0; 808*4104d13fSDmitry Torokhov } 809*4104d13fSDmitry Torokhov 810*4104d13fSDmitry Torokhov /*********************************************************************** 811*4104d13fSDmitry Torokhov * Close an instance of the tablet driver. 812*4104d13fSDmitry Torokhov */ 813*4104d13fSDmitry Torokhov static void aiptek_close(struct input_dev *inputdev) 814*4104d13fSDmitry Torokhov { 815*4104d13fSDmitry Torokhov struct aiptek *aiptek = input_get_drvdata(inputdev); 816*4104d13fSDmitry Torokhov 817*4104d13fSDmitry Torokhov usb_kill_urb(aiptek->urb); 818*4104d13fSDmitry Torokhov } 819*4104d13fSDmitry Torokhov 820*4104d13fSDmitry Torokhov /*********************************************************************** 821*4104d13fSDmitry Torokhov * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, 822*4104d13fSDmitry Torokhov * where they were known as usb_set_report and usb_get_report. 823*4104d13fSDmitry Torokhov */ 824*4104d13fSDmitry Torokhov static int 825*4104d13fSDmitry Torokhov aiptek_set_report(struct aiptek *aiptek, 826*4104d13fSDmitry Torokhov unsigned char report_type, 827*4104d13fSDmitry Torokhov unsigned char report_id, void *buffer, int size) 828*4104d13fSDmitry Torokhov { 829*4104d13fSDmitry Torokhov return usb_control_msg(aiptek->usbdev, 830*4104d13fSDmitry Torokhov usb_sndctrlpipe(aiptek->usbdev, 0), 831*4104d13fSDmitry Torokhov USB_REQ_SET_REPORT, 832*4104d13fSDmitry Torokhov USB_TYPE_CLASS | USB_RECIP_INTERFACE | 833*4104d13fSDmitry Torokhov USB_DIR_OUT, (report_type << 8) + report_id, 834*4104d13fSDmitry Torokhov aiptek->ifnum, buffer, size, 5000); 835*4104d13fSDmitry Torokhov } 836*4104d13fSDmitry Torokhov 837*4104d13fSDmitry Torokhov static int 838*4104d13fSDmitry Torokhov aiptek_get_report(struct aiptek *aiptek, 839*4104d13fSDmitry Torokhov unsigned char report_type, 840*4104d13fSDmitry Torokhov unsigned char report_id, void *buffer, int size) 841*4104d13fSDmitry Torokhov { 842*4104d13fSDmitry Torokhov return usb_control_msg(aiptek->usbdev, 843*4104d13fSDmitry Torokhov usb_rcvctrlpipe(aiptek->usbdev, 0), 844*4104d13fSDmitry Torokhov USB_REQ_GET_REPORT, 845*4104d13fSDmitry Torokhov USB_TYPE_CLASS | USB_RECIP_INTERFACE | 846*4104d13fSDmitry Torokhov USB_DIR_IN, (report_type << 8) + report_id, 847*4104d13fSDmitry Torokhov aiptek->ifnum, buffer, size, 5000); 848*4104d13fSDmitry Torokhov } 849*4104d13fSDmitry Torokhov 850*4104d13fSDmitry Torokhov /*********************************************************************** 851*4104d13fSDmitry Torokhov * Send a command to the tablet. 852*4104d13fSDmitry Torokhov */ 853*4104d13fSDmitry Torokhov static int 854*4104d13fSDmitry Torokhov aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data) 855*4104d13fSDmitry Torokhov { 856*4104d13fSDmitry Torokhov const int sizeof_buf = 3 * sizeof(u8); 857*4104d13fSDmitry Torokhov int ret; 858*4104d13fSDmitry Torokhov u8 *buf; 859*4104d13fSDmitry Torokhov 860*4104d13fSDmitry Torokhov buf = kmalloc(sizeof_buf, GFP_KERNEL); 861*4104d13fSDmitry Torokhov if (!buf) 862*4104d13fSDmitry Torokhov return -ENOMEM; 863*4104d13fSDmitry Torokhov 864*4104d13fSDmitry Torokhov buf[0] = 2; 865*4104d13fSDmitry Torokhov buf[1] = command; 866*4104d13fSDmitry Torokhov buf[2] = data; 867*4104d13fSDmitry Torokhov 868*4104d13fSDmitry Torokhov if ((ret = 869*4104d13fSDmitry Torokhov aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { 870*4104d13fSDmitry Torokhov dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x", 871*4104d13fSDmitry Torokhov command, data); 872*4104d13fSDmitry Torokhov } 873*4104d13fSDmitry Torokhov kfree(buf); 874*4104d13fSDmitry Torokhov return ret < 0 ? ret : 0; 875*4104d13fSDmitry Torokhov } 876*4104d13fSDmitry Torokhov 877*4104d13fSDmitry Torokhov /*********************************************************************** 878*4104d13fSDmitry Torokhov * Retrieve information from the tablet. Querying info is defined as first 879*4104d13fSDmitry Torokhov * sending the {command,data} sequence as a command, followed by a wait 880*4104d13fSDmitry Torokhov * (aka, "programmaticDelay") and then a "read" request. 881*4104d13fSDmitry Torokhov */ 882*4104d13fSDmitry Torokhov static int 883*4104d13fSDmitry Torokhov aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) 884*4104d13fSDmitry Torokhov { 885*4104d13fSDmitry Torokhov const int sizeof_buf = 3 * sizeof(u8); 886*4104d13fSDmitry Torokhov int ret; 887*4104d13fSDmitry Torokhov u8 *buf; 888*4104d13fSDmitry Torokhov 889*4104d13fSDmitry Torokhov buf = kmalloc(sizeof_buf, GFP_KERNEL); 890*4104d13fSDmitry Torokhov if (!buf) 891*4104d13fSDmitry Torokhov return -ENOMEM; 892*4104d13fSDmitry Torokhov 893*4104d13fSDmitry Torokhov buf[0] = 2; 894*4104d13fSDmitry Torokhov buf[1] = command; 895*4104d13fSDmitry Torokhov buf[2] = data; 896*4104d13fSDmitry Torokhov 897*4104d13fSDmitry Torokhov if (aiptek_command(aiptek, command, data) != 0) { 898*4104d13fSDmitry Torokhov kfree(buf); 899*4104d13fSDmitry Torokhov return -EIO; 900*4104d13fSDmitry Torokhov } 901*4104d13fSDmitry Torokhov msleep(aiptek->curSetting.programmableDelay); 902*4104d13fSDmitry Torokhov 903*4104d13fSDmitry Torokhov if ((ret = 904*4104d13fSDmitry Torokhov aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { 905*4104d13fSDmitry Torokhov dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x", 906*4104d13fSDmitry Torokhov buf[0], buf[1], buf[2]); 907*4104d13fSDmitry Torokhov ret = -EIO; 908*4104d13fSDmitry Torokhov } else { 909*4104d13fSDmitry Torokhov ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); 910*4104d13fSDmitry Torokhov } 911*4104d13fSDmitry Torokhov kfree(buf); 912*4104d13fSDmitry Torokhov return ret; 913*4104d13fSDmitry Torokhov } 914*4104d13fSDmitry Torokhov 915*4104d13fSDmitry Torokhov /*********************************************************************** 916*4104d13fSDmitry Torokhov * Program the tablet into either absolute or relative mode. 917*4104d13fSDmitry Torokhov * We also get information about the tablet's size. 918*4104d13fSDmitry Torokhov */ 919*4104d13fSDmitry Torokhov static int aiptek_program_tablet(struct aiptek *aiptek) 920*4104d13fSDmitry Torokhov { 921*4104d13fSDmitry Torokhov int ret; 922*4104d13fSDmitry Torokhov /* Execute Resolution500LPI */ 923*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0) 924*4104d13fSDmitry Torokhov return ret; 925*4104d13fSDmitry Torokhov 926*4104d13fSDmitry Torokhov /* Query getModelCode */ 927*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0) 928*4104d13fSDmitry Torokhov return ret; 929*4104d13fSDmitry Torokhov aiptek->features.modelCode = ret & 0xff; 930*4104d13fSDmitry Torokhov 931*4104d13fSDmitry Torokhov /* Query getODMCode */ 932*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0) 933*4104d13fSDmitry Torokhov return ret; 934*4104d13fSDmitry Torokhov aiptek->features.odmCode = ret; 935*4104d13fSDmitry Torokhov 936*4104d13fSDmitry Torokhov /* Query getFirmwareCode */ 937*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0) 938*4104d13fSDmitry Torokhov return ret; 939*4104d13fSDmitry Torokhov aiptek->features.firmwareCode = ret; 940*4104d13fSDmitry Torokhov 941*4104d13fSDmitry Torokhov /* Query getXextension */ 942*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0) 943*4104d13fSDmitry Torokhov return ret; 944*4104d13fSDmitry Torokhov aiptek->inputdev->absmin[ABS_X] = 0; 945*4104d13fSDmitry Torokhov aiptek->inputdev->absmax[ABS_X] = ret - 1; 946*4104d13fSDmitry Torokhov 947*4104d13fSDmitry Torokhov /* Query getYextension */ 948*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0) 949*4104d13fSDmitry Torokhov return ret; 950*4104d13fSDmitry Torokhov aiptek->inputdev->absmin[ABS_Y] = 0; 951*4104d13fSDmitry Torokhov aiptek->inputdev->absmax[ABS_Y] = ret - 1; 952*4104d13fSDmitry Torokhov 953*4104d13fSDmitry Torokhov /* Query getPressureLevels */ 954*4104d13fSDmitry Torokhov if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0) 955*4104d13fSDmitry Torokhov return ret; 956*4104d13fSDmitry Torokhov aiptek->inputdev->absmin[ABS_PRESSURE] = 0; 957*4104d13fSDmitry Torokhov aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1; 958*4104d13fSDmitry Torokhov 959*4104d13fSDmitry Torokhov /* Depending on whether we are in absolute or relative mode, we will 960*4104d13fSDmitry Torokhov * do a switchToTablet(absolute) or switchToMouse(relative) command. 961*4104d13fSDmitry Torokhov */ 962*4104d13fSDmitry Torokhov if (aiptek->curSetting.coordinateMode == 963*4104d13fSDmitry Torokhov AIPTEK_COORDINATE_ABSOLUTE_MODE) { 964*4104d13fSDmitry Torokhov /* Execute switchToTablet */ 965*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) { 966*4104d13fSDmitry Torokhov return ret; 967*4104d13fSDmitry Torokhov } 968*4104d13fSDmitry Torokhov } else { 969*4104d13fSDmitry Torokhov /* Execute switchToMouse */ 970*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) { 971*4104d13fSDmitry Torokhov return ret; 972*4104d13fSDmitry Torokhov } 973*4104d13fSDmitry Torokhov } 974*4104d13fSDmitry Torokhov 975*4104d13fSDmitry Torokhov /* Enable the macro keys */ 976*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0) 977*4104d13fSDmitry Torokhov return ret; 978*4104d13fSDmitry Torokhov #if 0 979*4104d13fSDmitry Torokhov /* Execute FilterOn */ 980*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0) 981*4104d13fSDmitry Torokhov return ret; 982*4104d13fSDmitry Torokhov #endif 983*4104d13fSDmitry Torokhov 984*4104d13fSDmitry Torokhov /* Execute AutoGainOn */ 985*4104d13fSDmitry Torokhov if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0) 986*4104d13fSDmitry Torokhov return ret; 987*4104d13fSDmitry Torokhov 988*4104d13fSDmitry Torokhov /* Reset the eventCount, so we track events from last (re)programming 989*4104d13fSDmitry Torokhov */ 990*4104d13fSDmitry Torokhov aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA; 991*4104d13fSDmitry Torokhov aiptek->eventCount = 0; 992*4104d13fSDmitry Torokhov 993*4104d13fSDmitry Torokhov return 0; 994*4104d13fSDmitry Torokhov } 995*4104d13fSDmitry Torokhov 996*4104d13fSDmitry Torokhov /*********************************************************************** 997*4104d13fSDmitry Torokhov * Sysfs functions. Sysfs prefers that individually-tunable parameters 998*4104d13fSDmitry Torokhov * exist in their separate pseudo-files. Summary data that is immutable 999*4104d13fSDmitry Torokhov * may exist in a singular file so long as you don't define a writeable 1000*4104d13fSDmitry Torokhov * interface. 1001*4104d13fSDmitry Torokhov */ 1002*4104d13fSDmitry Torokhov 1003*4104d13fSDmitry Torokhov /*********************************************************************** 1004*4104d13fSDmitry Torokhov * support the 'size' file -- display support 1005*4104d13fSDmitry Torokhov */ 1006*4104d13fSDmitry Torokhov static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf) 1007*4104d13fSDmitry Torokhov { 1008*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1009*4104d13fSDmitry Torokhov 1010*4104d13fSDmitry Torokhov if (aiptek == NULL) 1011*4104d13fSDmitry Torokhov return 0; 1012*4104d13fSDmitry Torokhov 1013*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%dx%d\n", 1014*4104d13fSDmitry Torokhov aiptek->inputdev->absmax[ABS_X] + 1, 1015*4104d13fSDmitry Torokhov aiptek->inputdev->absmax[ABS_Y] + 1); 1016*4104d13fSDmitry Torokhov } 1017*4104d13fSDmitry Torokhov 1018*4104d13fSDmitry Torokhov /* These structs define the sysfs files, param #1 is the name of the 1019*4104d13fSDmitry Torokhov * file, param 2 is the file permissions, param 3 & 4 are to the 1020*4104d13fSDmitry Torokhov * output generator and input parser routines. Absence of a routine is 1021*4104d13fSDmitry Torokhov * permitted -- it only means can't either 'cat' the file, or send data 1022*4104d13fSDmitry Torokhov * to it. 1023*4104d13fSDmitry Torokhov */ 1024*4104d13fSDmitry Torokhov static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); 1025*4104d13fSDmitry Torokhov 1026*4104d13fSDmitry Torokhov /*********************************************************************** 1027*4104d13fSDmitry Torokhov * support routines for the 'product_id' file 1028*4104d13fSDmitry Torokhov */ 1029*4104d13fSDmitry Torokhov static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf) 1030*4104d13fSDmitry Torokhov { 1031*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1032*4104d13fSDmitry Torokhov 1033*4104d13fSDmitry Torokhov if (aiptek == NULL) 1034*4104d13fSDmitry Torokhov return 0; 1035*4104d13fSDmitry Torokhov 1036*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "0x%04x\n", 1037*4104d13fSDmitry Torokhov aiptek->inputdev->id.product); 1038*4104d13fSDmitry Torokhov } 1039*4104d13fSDmitry Torokhov 1040*4104d13fSDmitry Torokhov static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); 1041*4104d13fSDmitry Torokhov 1042*4104d13fSDmitry Torokhov /*********************************************************************** 1043*4104d13fSDmitry Torokhov * support routines for the 'vendor_id' file 1044*4104d13fSDmitry Torokhov */ 1045*4104d13fSDmitry Torokhov static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf) 1046*4104d13fSDmitry Torokhov { 1047*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1048*4104d13fSDmitry Torokhov 1049*4104d13fSDmitry Torokhov if (aiptek == NULL) 1050*4104d13fSDmitry Torokhov return 0; 1051*4104d13fSDmitry Torokhov 1052*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); 1053*4104d13fSDmitry Torokhov } 1054*4104d13fSDmitry Torokhov 1055*4104d13fSDmitry Torokhov static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); 1056*4104d13fSDmitry Torokhov 1057*4104d13fSDmitry Torokhov /*********************************************************************** 1058*4104d13fSDmitry Torokhov * support routines for the 'vendor' file 1059*4104d13fSDmitry Torokhov */ 1060*4104d13fSDmitry Torokhov static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf) 1061*4104d13fSDmitry Torokhov { 1062*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1063*4104d13fSDmitry Torokhov int retval; 1064*4104d13fSDmitry Torokhov 1065*4104d13fSDmitry Torokhov if (aiptek == NULL) 1066*4104d13fSDmitry Torokhov return 0; 1067*4104d13fSDmitry Torokhov 1068*4104d13fSDmitry Torokhov retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer); 1069*4104d13fSDmitry Torokhov return retval; 1070*4104d13fSDmitry Torokhov } 1071*4104d13fSDmitry Torokhov 1072*4104d13fSDmitry Torokhov static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL); 1073*4104d13fSDmitry Torokhov 1074*4104d13fSDmitry Torokhov /*********************************************************************** 1075*4104d13fSDmitry Torokhov * support routines for the 'product' file 1076*4104d13fSDmitry Torokhov */ 1077*4104d13fSDmitry Torokhov static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf) 1078*4104d13fSDmitry Torokhov { 1079*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1080*4104d13fSDmitry Torokhov int retval; 1081*4104d13fSDmitry Torokhov 1082*4104d13fSDmitry Torokhov if (aiptek == NULL) 1083*4104d13fSDmitry Torokhov return 0; 1084*4104d13fSDmitry Torokhov 1085*4104d13fSDmitry Torokhov retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product); 1086*4104d13fSDmitry Torokhov return retval; 1087*4104d13fSDmitry Torokhov } 1088*4104d13fSDmitry Torokhov 1089*4104d13fSDmitry Torokhov static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL); 1090*4104d13fSDmitry Torokhov 1091*4104d13fSDmitry Torokhov /*********************************************************************** 1092*4104d13fSDmitry Torokhov * support routines for the 'pointer_mode' file. Note that this file 1093*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1094*4104d13fSDmitry Torokhov */ 1095*4104d13fSDmitry Torokhov static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf) 1096*4104d13fSDmitry Torokhov { 1097*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1098*4104d13fSDmitry Torokhov char *s; 1099*4104d13fSDmitry Torokhov 1100*4104d13fSDmitry Torokhov if (aiptek == NULL) 1101*4104d13fSDmitry Torokhov return 0; 1102*4104d13fSDmitry Torokhov 1103*4104d13fSDmitry Torokhov switch (aiptek->curSetting.pointerMode) { 1104*4104d13fSDmitry Torokhov case AIPTEK_POINTER_ONLY_STYLUS_MODE: 1105*4104d13fSDmitry Torokhov s = "stylus"; 1106*4104d13fSDmitry Torokhov break; 1107*4104d13fSDmitry Torokhov 1108*4104d13fSDmitry Torokhov case AIPTEK_POINTER_ONLY_MOUSE_MODE: 1109*4104d13fSDmitry Torokhov s = "mouse"; 1110*4104d13fSDmitry Torokhov break; 1111*4104d13fSDmitry Torokhov 1112*4104d13fSDmitry Torokhov case AIPTEK_POINTER_EITHER_MODE: 1113*4104d13fSDmitry Torokhov s = "either"; 1114*4104d13fSDmitry Torokhov break; 1115*4104d13fSDmitry Torokhov 1116*4104d13fSDmitry Torokhov default: 1117*4104d13fSDmitry Torokhov s = "unknown"; 1118*4104d13fSDmitry Torokhov break; 1119*4104d13fSDmitry Torokhov } 1120*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1121*4104d13fSDmitry Torokhov } 1122*4104d13fSDmitry Torokhov 1123*4104d13fSDmitry Torokhov static ssize_t 1124*4104d13fSDmitry Torokhov store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1125*4104d13fSDmitry Torokhov { 1126*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1127*4104d13fSDmitry Torokhov if (aiptek == NULL) 1128*4104d13fSDmitry Torokhov return 0; 1129*4104d13fSDmitry Torokhov 1130*4104d13fSDmitry Torokhov if (strcmp(buf, "stylus") == 0) { 1131*4104d13fSDmitry Torokhov aiptek->newSetting.pointerMode = 1132*4104d13fSDmitry Torokhov AIPTEK_POINTER_ONLY_STYLUS_MODE; 1133*4104d13fSDmitry Torokhov } else if (strcmp(buf, "mouse") == 0) { 1134*4104d13fSDmitry Torokhov aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE; 1135*4104d13fSDmitry Torokhov } else if (strcmp(buf, "either") == 0) { 1136*4104d13fSDmitry Torokhov aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; 1137*4104d13fSDmitry Torokhov } 1138*4104d13fSDmitry Torokhov return count; 1139*4104d13fSDmitry Torokhov } 1140*4104d13fSDmitry Torokhov 1141*4104d13fSDmitry Torokhov static DEVICE_ATTR(pointer_mode, 1142*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1143*4104d13fSDmitry Torokhov show_tabletPointerMode, store_tabletPointerMode); 1144*4104d13fSDmitry Torokhov 1145*4104d13fSDmitry Torokhov /*********************************************************************** 1146*4104d13fSDmitry Torokhov * support routines for the 'coordinate_mode' file. Note that this file 1147*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1148*4104d13fSDmitry Torokhov */ 1149*4104d13fSDmitry Torokhov static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf) 1150*4104d13fSDmitry Torokhov { 1151*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1152*4104d13fSDmitry Torokhov char *s; 1153*4104d13fSDmitry Torokhov 1154*4104d13fSDmitry Torokhov if (aiptek == NULL) 1155*4104d13fSDmitry Torokhov return 0; 1156*4104d13fSDmitry Torokhov 1157*4104d13fSDmitry Torokhov switch (aiptek->curSetting.coordinateMode) { 1158*4104d13fSDmitry Torokhov case AIPTEK_COORDINATE_ABSOLUTE_MODE: 1159*4104d13fSDmitry Torokhov s = "absolute"; 1160*4104d13fSDmitry Torokhov break; 1161*4104d13fSDmitry Torokhov 1162*4104d13fSDmitry Torokhov case AIPTEK_COORDINATE_RELATIVE_MODE: 1163*4104d13fSDmitry Torokhov s = "relative"; 1164*4104d13fSDmitry Torokhov break; 1165*4104d13fSDmitry Torokhov 1166*4104d13fSDmitry Torokhov default: 1167*4104d13fSDmitry Torokhov s = "unknown"; 1168*4104d13fSDmitry Torokhov break; 1169*4104d13fSDmitry Torokhov } 1170*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1171*4104d13fSDmitry Torokhov } 1172*4104d13fSDmitry Torokhov 1173*4104d13fSDmitry Torokhov static ssize_t 1174*4104d13fSDmitry Torokhov store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1175*4104d13fSDmitry Torokhov { 1176*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1177*4104d13fSDmitry Torokhov if (aiptek == NULL) 1178*4104d13fSDmitry Torokhov return 0; 1179*4104d13fSDmitry Torokhov 1180*4104d13fSDmitry Torokhov if (strcmp(buf, "absolute") == 0) { 1181*4104d13fSDmitry Torokhov aiptek->newSetting.pointerMode = 1182*4104d13fSDmitry Torokhov AIPTEK_COORDINATE_ABSOLUTE_MODE; 1183*4104d13fSDmitry Torokhov } else if (strcmp(buf, "relative") == 0) { 1184*4104d13fSDmitry Torokhov aiptek->newSetting.pointerMode = 1185*4104d13fSDmitry Torokhov AIPTEK_COORDINATE_RELATIVE_MODE; 1186*4104d13fSDmitry Torokhov } 1187*4104d13fSDmitry Torokhov return count; 1188*4104d13fSDmitry Torokhov } 1189*4104d13fSDmitry Torokhov 1190*4104d13fSDmitry Torokhov static DEVICE_ATTR(coordinate_mode, 1191*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1192*4104d13fSDmitry Torokhov show_tabletCoordinateMode, store_tabletCoordinateMode); 1193*4104d13fSDmitry Torokhov 1194*4104d13fSDmitry Torokhov /*********************************************************************** 1195*4104d13fSDmitry Torokhov * support routines for the 'tool_mode' file. Note that this file 1196*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1197*4104d13fSDmitry Torokhov */ 1198*4104d13fSDmitry Torokhov static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf) 1199*4104d13fSDmitry Torokhov { 1200*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1201*4104d13fSDmitry Torokhov char *s; 1202*4104d13fSDmitry Torokhov 1203*4104d13fSDmitry Torokhov if (aiptek == NULL) 1204*4104d13fSDmitry Torokhov return 0; 1205*4104d13fSDmitry Torokhov 1206*4104d13fSDmitry Torokhov switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) { 1207*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_MOUSE_MODE: 1208*4104d13fSDmitry Torokhov s = "mouse"; 1209*4104d13fSDmitry Torokhov break; 1210*4104d13fSDmitry Torokhov 1211*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_ERASER_MODE: 1212*4104d13fSDmitry Torokhov s = "eraser"; 1213*4104d13fSDmitry Torokhov break; 1214*4104d13fSDmitry Torokhov 1215*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_PENCIL_MODE: 1216*4104d13fSDmitry Torokhov s = "pencil"; 1217*4104d13fSDmitry Torokhov break; 1218*4104d13fSDmitry Torokhov 1219*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_PEN_MODE: 1220*4104d13fSDmitry Torokhov s = "pen"; 1221*4104d13fSDmitry Torokhov break; 1222*4104d13fSDmitry Torokhov 1223*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_BRUSH_MODE: 1224*4104d13fSDmitry Torokhov s = "brush"; 1225*4104d13fSDmitry Torokhov break; 1226*4104d13fSDmitry Torokhov 1227*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE: 1228*4104d13fSDmitry Torokhov s = "airbrush"; 1229*4104d13fSDmitry Torokhov break; 1230*4104d13fSDmitry Torokhov 1231*4104d13fSDmitry Torokhov case AIPTEK_TOOL_BUTTON_LENS_MODE: 1232*4104d13fSDmitry Torokhov s = "lens"; 1233*4104d13fSDmitry Torokhov break; 1234*4104d13fSDmitry Torokhov 1235*4104d13fSDmitry Torokhov default: 1236*4104d13fSDmitry Torokhov s = "unknown"; 1237*4104d13fSDmitry Torokhov break; 1238*4104d13fSDmitry Torokhov } 1239*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1240*4104d13fSDmitry Torokhov } 1241*4104d13fSDmitry Torokhov 1242*4104d13fSDmitry Torokhov static ssize_t 1243*4104d13fSDmitry Torokhov store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1244*4104d13fSDmitry Torokhov { 1245*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1246*4104d13fSDmitry Torokhov if (aiptek == NULL) 1247*4104d13fSDmitry Torokhov return 0; 1248*4104d13fSDmitry Torokhov 1249*4104d13fSDmitry Torokhov if (strcmp(buf, "mouse") == 0) { 1250*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE; 1251*4104d13fSDmitry Torokhov } else if (strcmp(buf, "eraser") == 0) { 1252*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE; 1253*4104d13fSDmitry Torokhov } else if (strcmp(buf, "pencil") == 0) { 1254*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE; 1255*4104d13fSDmitry Torokhov } else if (strcmp(buf, "pen") == 0) { 1256*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; 1257*4104d13fSDmitry Torokhov } else if (strcmp(buf, "brush") == 0) { 1258*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE; 1259*4104d13fSDmitry Torokhov } else if (strcmp(buf, "airbrush") == 0) { 1260*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE; 1261*4104d13fSDmitry Torokhov } else if (strcmp(buf, "lens") == 0) { 1262*4104d13fSDmitry Torokhov aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE; 1263*4104d13fSDmitry Torokhov } 1264*4104d13fSDmitry Torokhov 1265*4104d13fSDmitry Torokhov return count; 1266*4104d13fSDmitry Torokhov } 1267*4104d13fSDmitry Torokhov 1268*4104d13fSDmitry Torokhov static DEVICE_ATTR(tool_mode, 1269*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1270*4104d13fSDmitry Torokhov show_tabletToolMode, store_tabletToolMode); 1271*4104d13fSDmitry Torokhov 1272*4104d13fSDmitry Torokhov /*********************************************************************** 1273*4104d13fSDmitry Torokhov * support routines for the 'xtilt' file. Note that this file 1274*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1275*4104d13fSDmitry Torokhov */ 1276*4104d13fSDmitry Torokhov static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf) 1277*4104d13fSDmitry Torokhov { 1278*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1279*4104d13fSDmitry Torokhov 1280*4104d13fSDmitry Torokhov if (aiptek == NULL) 1281*4104d13fSDmitry Torokhov return 0; 1282*4104d13fSDmitry Torokhov 1283*4104d13fSDmitry Torokhov if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) { 1284*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "disable\n"); 1285*4104d13fSDmitry Torokhov } else { 1286*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%d\n", 1287*4104d13fSDmitry Torokhov aiptek->curSetting.xTilt); 1288*4104d13fSDmitry Torokhov } 1289*4104d13fSDmitry Torokhov } 1290*4104d13fSDmitry Torokhov 1291*4104d13fSDmitry Torokhov static ssize_t 1292*4104d13fSDmitry Torokhov store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1293*4104d13fSDmitry Torokhov { 1294*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1295*4104d13fSDmitry Torokhov int x; 1296*4104d13fSDmitry Torokhov 1297*4104d13fSDmitry Torokhov if (aiptek == NULL) 1298*4104d13fSDmitry Torokhov return 0; 1299*4104d13fSDmitry Torokhov 1300*4104d13fSDmitry Torokhov if (strcmp(buf, "disable") == 0) { 1301*4104d13fSDmitry Torokhov aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE; 1302*4104d13fSDmitry Torokhov } else { 1303*4104d13fSDmitry Torokhov x = (int)simple_strtol(buf, NULL, 10); 1304*4104d13fSDmitry Torokhov if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) { 1305*4104d13fSDmitry Torokhov aiptek->newSetting.xTilt = x; 1306*4104d13fSDmitry Torokhov } 1307*4104d13fSDmitry Torokhov } 1308*4104d13fSDmitry Torokhov return count; 1309*4104d13fSDmitry Torokhov } 1310*4104d13fSDmitry Torokhov 1311*4104d13fSDmitry Torokhov static DEVICE_ATTR(xtilt, 1312*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt); 1313*4104d13fSDmitry Torokhov 1314*4104d13fSDmitry Torokhov /*********************************************************************** 1315*4104d13fSDmitry Torokhov * support routines for the 'ytilt' file. Note that this file 1316*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1317*4104d13fSDmitry Torokhov */ 1318*4104d13fSDmitry Torokhov static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf) 1319*4104d13fSDmitry Torokhov { 1320*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1321*4104d13fSDmitry Torokhov 1322*4104d13fSDmitry Torokhov if (aiptek == NULL) 1323*4104d13fSDmitry Torokhov return 0; 1324*4104d13fSDmitry Torokhov 1325*4104d13fSDmitry Torokhov if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) { 1326*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "disable\n"); 1327*4104d13fSDmitry Torokhov } else { 1328*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%d\n", 1329*4104d13fSDmitry Torokhov aiptek->curSetting.yTilt); 1330*4104d13fSDmitry Torokhov } 1331*4104d13fSDmitry Torokhov } 1332*4104d13fSDmitry Torokhov 1333*4104d13fSDmitry Torokhov static ssize_t 1334*4104d13fSDmitry Torokhov store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1335*4104d13fSDmitry Torokhov { 1336*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1337*4104d13fSDmitry Torokhov int y; 1338*4104d13fSDmitry Torokhov 1339*4104d13fSDmitry Torokhov if (aiptek == NULL) 1340*4104d13fSDmitry Torokhov return 0; 1341*4104d13fSDmitry Torokhov 1342*4104d13fSDmitry Torokhov if (strcmp(buf, "disable") == 0) { 1343*4104d13fSDmitry Torokhov aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE; 1344*4104d13fSDmitry Torokhov } else { 1345*4104d13fSDmitry Torokhov y = (int)simple_strtol(buf, NULL, 10); 1346*4104d13fSDmitry Torokhov if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) { 1347*4104d13fSDmitry Torokhov aiptek->newSetting.yTilt = y; 1348*4104d13fSDmitry Torokhov } 1349*4104d13fSDmitry Torokhov } 1350*4104d13fSDmitry Torokhov return count; 1351*4104d13fSDmitry Torokhov } 1352*4104d13fSDmitry Torokhov 1353*4104d13fSDmitry Torokhov static DEVICE_ATTR(ytilt, 1354*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt); 1355*4104d13fSDmitry Torokhov 1356*4104d13fSDmitry Torokhov /*********************************************************************** 1357*4104d13fSDmitry Torokhov * support routines for the 'jitter' file. Note that this file 1358*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1359*4104d13fSDmitry Torokhov */ 1360*4104d13fSDmitry Torokhov static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf) 1361*4104d13fSDmitry Torokhov { 1362*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1363*4104d13fSDmitry Torokhov 1364*4104d13fSDmitry Torokhov if (aiptek == NULL) 1365*4104d13fSDmitry Torokhov return 0; 1366*4104d13fSDmitry Torokhov 1367*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay); 1368*4104d13fSDmitry Torokhov } 1369*4104d13fSDmitry Torokhov 1370*4104d13fSDmitry Torokhov static ssize_t 1371*4104d13fSDmitry Torokhov store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1372*4104d13fSDmitry Torokhov { 1373*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1374*4104d13fSDmitry Torokhov 1375*4104d13fSDmitry Torokhov if (aiptek == NULL) 1376*4104d13fSDmitry Torokhov return 0; 1377*4104d13fSDmitry Torokhov 1378*4104d13fSDmitry Torokhov aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10); 1379*4104d13fSDmitry Torokhov return count; 1380*4104d13fSDmitry Torokhov } 1381*4104d13fSDmitry Torokhov 1382*4104d13fSDmitry Torokhov static DEVICE_ATTR(jitter, 1383*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1384*4104d13fSDmitry Torokhov show_tabletJitterDelay, store_tabletJitterDelay); 1385*4104d13fSDmitry Torokhov 1386*4104d13fSDmitry Torokhov /*********************************************************************** 1387*4104d13fSDmitry Torokhov * support routines for the 'delay' file. Note that this file 1388*4104d13fSDmitry Torokhov * both displays current setting and allows reprogramming. 1389*4104d13fSDmitry Torokhov */ 1390*4104d13fSDmitry Torokhov static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf) 1391*4104d13fSDmitry Torokhov { 1392*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1393*4104d13fSDmitry Torokhov 1394*4104d13fSDmitry Torokhov if (aiptek == NULL) 1395*4104d13fSDmitry Torokhov return 0; 1396*4104d13fSDmitry Torokhov 1397*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%d\n", 1398*4104d13fSDmitry Torokhov aiptek->curSetting.programmableDelay); 1399*4104d13fSDmitry Torokhov } 1400*4104d13fSDmitry Torokhov 1401*4104d13fSDmitry Torokhov static ssize_t 1402*4104d13fSDmitry Torokhov store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1403*4104d13fSDmitry Torokhov { 1404*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1405*4104d13fSDmitry Torokhov 1406*4104d13fSDmitry Torokhov if (aiptek == NULL) 1407*4104d13fSDmitry Torokhov return 0; 1408*4104d13fSDmitry Torokhov 1409*4104d13fSDmitry Torokhov aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10); 1410*4104d13fSDmitry Torokhov return count; 1411*4104d13fSDmitry Torokhov } 1412*4104d13fSDmitry Torokhov 1413*4104d13fSDmitry Torokhov static DEVICE_ATTR(delay, 1414*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1415*4104d13fSDmitry Torokhov show_tabletProgrammableDelay, store_tabletProgrammableDelay); 1416*4104d13fSDmitry Torokhov 1417*4104d13fSDmitry Torokhov /*********************************************************************** 1418*4104d13fSDmitry Torokhov * support routines for the 'input_path' file. Note that this file 1419*4104d13fSDmitry Torokhov * only displays current setting. 1420*4104d13fSDmitry Torokhov */ 1421*4104d13fSDmitry Torokhov static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf) 1422*4104d13fSDmitry Torokhov { 1423*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1424*4104d13fSDmitry Torokhov 1425*4104d13fSDmitry Torokhov if (aiptek == NULL) 1426*4104d13fSDmitry Torokhov return 0; 1427*4104d13fSDmitry Torokhov 1428*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n", 1429*4104d13fSDmitry Torokhov aiptek->features.inputPath); 1430*4104d13fSDmitry Torokhov } 1431*4104d13fSDmitry Torokhov 1432*4104d13fSDmitry Torokhov static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL); 1433*4104d13fSDmitry Torokhov 1434*4104d13fSDmitry Torokhov /*********************************************************************** 1435*4104d13fSDmitry Torokhov * support routines for the 'event_count' file. Note that this file 1436*4104d13fSDmitry Torokhov * only displays current setting. 1437*4104d13fSDmitry Torokhov */ 1438*4104d13fSDmitry Torokhov static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf) 1439*4104d13fSDmitry Torokhov { 1440*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1441*4104d13fSDmitry Torokhov 1442*4104d13fSDmitry Torokhov if (aiptek == NULL) 1443*4104d13fSDmitry Torokhov return 0; 1444*4104d13fSDmitry Torokhov 1445*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount); 1446*4104d13fSDmitry Torokhov } 1447*4104d13fSDmitry Torokhov 1448*4104d13fSDmitry Torokhov static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL); 1449*4104d13fSDmitry Torokhov 1450*4104d13fSDmitry Torokhov /*********************************************************************** 1451*4104d13fSDmitry Torokhov * support routines for the 'diagnostic' file. Note that this file 1452*4104d13fSDmitry Torokhov * only displays current setting. 1453*4104d13fSDmitry Torokhov */ 1454*4104d13fSDmitry Torokhov static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf) 1455*4104d13fSDmitry Torokhov { 1456*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1457*4104d13fSDmitry Torokhov char *retMsg; 1458*4104d13fSDmitry Torokhov 1459*4104d13fSDmitry Torokhov if (aiptek == NULL) 1460*4104d13fSDmitry Torokhov return 0; 1461*4104d13fSDmitry Torokhov 1462*4104d13fSDmitry Torokhov switch (aiptek->diagnostic) { 1463*4104d13fSDmitry Torokhov case AIPTEK_DIAGNOSTIC_NA: 1464*4104d13fSDmitry Torokhov retMsg = "no errors\n"; 1465*4104d13fSDmitry Torokhov break; 1466*4104d13fSDmitry Torokhov 1467*4104d13fSDmitry Torokhov case AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE: 1468*4104d13fSDmitry Torokhov retMsg = "Error: receiving relative reports\n"; 1469*4104d13fSDmitry Torokhov break; 1470*4104d13fSDmitry Torokhov 1471*4104d13fSDmitry Torokhov case AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE: 1472*4104d13fSDmitry Torokhov retMsg = "Error: receiving absolute reports\n"; 1473*4104d13fSDmitry Torokhov break; 1474*4104d13fSDmitry Torokhov 1475*4104d13fSDmitry Torokhov case AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED: 1476*4104d13fSDmitry Torokhov if (aiptek->curSetting.pointerMode == 1477*4104d13fSDmitry Torokhov AIPTEK_POINTER_ONLY_MOUSE_MODE) { 1478*4104d13fSDmitry Torokhov retMsg = "Error: receiving stylus reports\n"; 1479*4104d13fSDmitry Torokhov } else { 1480*4104d13fSDmitry Torokhov retMsg = "Error: receiving mouse reports\n"; 1481*4104d13fSDmitry Torokhov } 1482*4104d13fSDmitry Torokhov break; 1483*4104d13fSDmitry Torokhov 1484*4104d13fSDmitry Torokhov default: 1485*4104d13fSDmitry Torokhov return 0; 1486*4104d13fSDmitry Torokhov } 1487*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, retMsg); 1488*4104d13fSDmitry Torokhov } 1489*4104d13fSDmitry Torokhov 1490*4104d13fSDmitry Torokhov static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL); 1491*4104d13fSDmitry Torokhov 1492*4104d13fSDmitry Torokhov /*********************************************************************** 1493*4104d13fSDmitry Torokhov * support routines for the 'stylus_upper' file. Note that this file 1494*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1495*4104d13fSDmitry Torokhov */ 1496*4104d13fSDmitry Torokhov static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf) 1497*4104d13fSDmitry Torokhov { 1498*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1499*4104d13fSDmitry Torokhov char *s; 1500*4104d13fSDmitry Torokhov 1501*4104d13fSDmitry Torokhov if (aiptek == NULL) 1502*4104d13fSDmitry Torokhov return 0; 1503*4104d13fSDmitry Torokhov 1504*4104d13fSDmitry Torokhov switch (aiptek->curSetting.stylusButtonUpper) { 1505*4104d13fSDmitry Torokhov case AIPTEK_STYLUS_UPPER_BUTTON: 1506*4104d13fSDmitry Torokhov s = "upper"; 1507*4104d13fSDmitry Torokhov break; 1508*4104d13fSDmitry Torokhov 1509*4104d13fSDmitry Torokhov case AIPTEK_STYLUS_LOWER_BUTTON: 1510*4104d13fSDmitry Torokhov s = "lower"; 1511*4104d13fSDmitry Torokhov break; 1512*4104d13fSDmitry Torokhov 1513*4104d13fSDmitry Torokhov default: 1514*4104d13fSDmitry Torokhov s = "unknown"; 1515*4104d13fSDmitry Torokhov break; 1516*4104d13fSDmitry Torokhov } 1517*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1518*4104d13fSDmitry Torokhov } 1519*4104d13fSDmitry Torokhov 1520*4104d13fSDmitry Torokhov static ssize_t 1521*4104d13fSDmitry Torokhov store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1522*4104d13fSDmitry Torokhov { 1523*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1524*4104d13fSDmitry Torokhov 1525*4104d13fSDmitry Torokhov if (aiptek == NULL) 1526*4104d13fSDmitry Torokhov return 0; 1527*4104d13fSDmitry Torokhov 1528*4104d13fSDmitry Torokhov if (strcmp(buf, "upper") == 0) { 1529*4104d13fSDmitry Torokhov aiptek->newSetting.stylusButtonUpper = 1530*4104d13fSDmitry Torokhov AIPTEK_STYLUS_UPPER_BUTTON; 1531*4104d13fSDmitry Torokhov } else if (strcmp(buf, "lower") == 0) { 1532*4104d13fSDmitry Torokhov aiptek->newSetting.stylusButtonUpper = 1533*4104d13fSDmitry Torokhov AIPTEK_STYLUS_LOWER_BUTTON; 1534*4104d13fSDmitry Torokhov } 1535*4104d13fSDmitry Torokhov return count; 1536*4104d13fSDmitry Torokhov } 1537*4104d13fSDmitry Torokhov 1538*4104d13fSDmitry Torokhov static DEVICE_ATTR(stylus_upper, 1539*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1540*4104d13fSDmitry Torokhov show_tabletStylusUpper, store_tabletStylusUpper); 1541*4104d13fSDmitry Torokhov 1542*4104d13fSDmitry Torokhov /*********************************************************************** 1543*4104d13fSDmitry Torokhov * support routines for the 'stylus_lower' file. Note that this file 1544*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1545*4104d13fSDmitry Torokhov */ 1546*4104d13fSDmitry Torokhov static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf) 1547*4104d13fSDmitry Torokhov { 1548*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1549*4104d13fSDmitry Torokhov char *s; 1550*4104d13fSDmitry Torokhov 1551*4104d13fSDmitry Torokhov if (aiptek == NULL) 1552*4104d13fSDmitry Torokhov return 0; 1553*4104d13fSDmitry Torokhov 1554*4104d13fSDmitry Torokhov switch (aiptek->curSetting.stylusButtonLower) { 1555*4104d13fSDmitry Torokhov case AIPTEK_STYLUS_UPPER_BUTTON: 1556*4104d13fSDmitry Torokhov s = "upper"; 1557*4104d13fSDmitry Torokhov break; 1558*4104d13fSDmitry Torokhov 1559*4104d13fSDmitry Torokhov case AIPTEK_STYLUS_LOWER_BUTTON: 1560*4104d13fSDmitry Torokhov s = "lower"; 1561*4104d13fSDmitry Torokhov break; 1562*4104d13fSDmitry Torokhov 1563*4104d13fSDmitry Torokhov default: 1564*4104d13fSDmitry Torokhov s = "unknown"; 1565*4104d13fSDmitry Torokhov break; 1566*4104d13fSDmitry Torokhov } 1567*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1568*4104d13fSDmitry Torokhov } 1569*4104d13fSDmitry Torokhov 1570*4104d13fSDmitry Torokhov static ssize_t 1571*4104d13fSDmitry Torokhov store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1572*4104d13fSDmitry Torokhov { 1573*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1574*4104d13fSDmitry Torokhov 1575*4104d13fSDmitry Torokhov if (aiptek == NULL) 1576*4104d13fSDmitry Torokhov return 0; 1577*4104d13fSDmitry Torokhov 1578*4104d13fSDmitry Torokhov if (strcmp(buf, "upper") == 0) { 1579*4104d13fSDmitry Torokhov aiptek->newSetting.stylusButtonLower = 1580*4104d13fSDmitry Torokhov AIPTEK_STYLUS_UPPER_BUTTON; 1581*4104d13fSDmitry Torokhov } else if (strcmp(buf, "lower") == 0) { 1582*4104d13fSDmitry Torokhov aiptek->newSetting.stylusButtonLower = 1583*4104d13fSDmitry Torokhov AIPTEK_STYLUS_LOWER_BUTTON; 1584*4104d13fSDmitry Torokhov } 1585*4104d13fSDmitry Torokhov return count; 1586*4104d13fSDmitry Torokhov } 1587*4104d13fSDmitry Torokhov 1588*4104d13fSDmitry Torokhov static DEVICE_ATTR(stylus_lower, 1589*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1590*4104d13fSDmitry Torokhov show_tabletStylusLower, store_tabletStylusLower); 1591*4104d13fSDmitry Torokhov 1592*4104d13fSDmitry Torokhov /*********************************************************************** 1593*4104d13fSDmitry Torokhov * support routines for the 'mouse_left' file. Note that this file 1594*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1595*4104d13fSDmitry Torokhov */ 1596*4104d13fSDmitry Torokhov static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf) 1597*4104d13fSDmitry Torokhov { 1598*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1599*4104d13fSDmitry Torokhov char *s; 1600*4104d13fSDmitry Torokhov 1601*4104d13fSDmitry Torokhov if (aiptek == NULL) 1602*4104d13fSDmitry Torokhov return 0; 1603*4104d13fSDmitry Torokhov 1604*4104d13fSDmitry Torokhov switch (aiptek->curSetting.mouseButtonLeft) { 1605*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_LEFT_BUTTON: 1606*4104d13fSDmitry Torokhov s = "left"; 1607*4104d13fSDmitry Torokhov break; 1608*4104d13fSDmitry Torokhov 1609*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_MIDDLE_BUTTON: 1610*4104d13fSDmitry Torokhov s = "middle"; 1611*4104d13fSDmitry Torokhov break; 1612*4104d13fSDmitry Torokhov 1613*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_RIGHT_BUTTON: 1614*4104d13fSDmitry Torokhov s = "right"; 1615*4104d13fSDmitry Torokhov break; 1616*4104d13fSDmitry Torokhov 1617*4104d13fSDmitry Torokhov default: 1618*4104d13fSDmitry Torokhov s = "unknown"; 1619*4104d13fSDmitry Torokhov break; 1620*4104d13fSDmitry Torokhov } 1621*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1622*4104d13fSDmitry Torokhov } 1623*4104d13fSDmitry Torokhov 1624*4104d13fSDmitry Torokhov static ssize_t 1625*4104d13fSDmitry Torokhov store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1626*4104d13fSDmitry Torokhov { 1627*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1628*4104d13fSDmitry Torokhov 1629*4104d13fSDmitry Torokhov if (aiptek == NULL) 1630*4104d13fSDmitry Torokhov return 0; 1631*4104d13fSDmitry Torokhov 1632*4104d13fSDmitry Torokhov if (strcmp(buf, "left") == 0) { 1633*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; 1634*4104d13fSDmitry Torokhov } else if (strcmp(buf, "middle") == 0) { 1635*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON; 1636*4104d13fSDmitry Torokhov } else if (strcmp(buf, "right") == 0) { 1637*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON; 1638*4104d13fSDmitry Torokhov } 1639*4104d13fSDmitry Torokhov return count; 1640*4104d13fSDmitry Torokhov } 1641*4104d13fSDmitry Torokhov 1642*4104d13fSDmitry Torokhov static DEVICE_ATTR(mouse_left, 1643*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1644*4104d13fSDmitry Torokhov show_tabletMouseLeft, store_tabletMouseLeft); 1645*4104d13fSDmitry Torokhov 1646*4104d13fSDmitry Torokhov /*********************************************************************** 1647*4104d13fSDmitry Torokhov * support routines for the 'mouse_middle' file. Note that this file 1648*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1649*4104d13fSDmitry Torokhov */ 1650*4104d13fSDmitry Torokhov static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf) 1651*4104d13fSDmitry Torokhov { 1652*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1653*4104d13fSDmitry Torokhov char *s; 1654*4104d13fSDmitry Torokhov 1655*4104d13fSDmitry Torokhov if (aiptek == NULL) 1656*4104d13fSDmitry Torokhov return 0; 1657*4104d13fSDmitry Torokhov 1658*4104d13fSDmitry Torokhov switch (aiptek->curSetting.mouseButtonMiddle) { 1659*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_LEFT_BUTTON: 1660*4104d13fSDmitry Torokhov s = "left"; 1661*4104d13fSDmitry Torokhov break; 1662*4104d13fSDmitry Torokhov 1663*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_MIDDLE_BUTTON: 1664*4104d13fSDmitry Torokhov s = "middle"; 1665*4104d13fSDmitry Torokhov break; 1666*4104d13fSDmitry Torokhov 1667*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_RIGHT_BUTTON: 1668*4104d13fSDmitry Torokhov s = "right"; 1669*4104d13fSDmitry Torokhov break; 1670*4104d13fSDmitry Torokhov 1671*4104d13fSDmitry Torokhov default: 1672*4104d13fSDmitry Torokhov s = "unknown"; 1673*4104d13fSDmitry Torokhov break; 1674*4104d13fSDmitry Torokhov } 1675*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1676*4104d13fSDmitry Torokhov } 1677*4104d13fSDmitry Torokhov 1678*4104d13fSDmitry Torokhov static ssize_t 1679*4104d13fSDmitry Torokhov store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1680*4104d13fSDmitry Torokhov { 1681*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1682*4104d13fSDmitry Torokhov 1683*4104d13fSDmitry Torokhov if (aiptek == NULL) 1684*4104d13fSDmitry Torokhov return 0; 1685*4104d13fSDmitry Torokhov 1686*4104d13fSDmitry Torokhov if (strcmp(buf, "left") == 0) { 1687*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON; 1688*4104d13fSDmitry Torokhov } else if (strcmp(buf, "middle") == 0) { 1689*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonMiddle = 1690*4104d13fSDmitry Torokhov AIPTEK_MOUSE_MIDDLE_BUTTON; 1691*4104d13fSDmitry Torokhov } else if (strcmp(buf, "right") == 0) { 1692*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonMiddle = 1693*4104d13fSDmitry Torokhov AIPTEK_MOUSE_RIGHT_BUTTON; 1694*4104d13fSDmitry Torokhov } 1695*4104d13fSDmitry Torokhov return count; 1696*4104d13fSDmitry Torokhov } 1697*4104d13fSDmitry Torokhov 1698*4104d13fSDmitry Torokhov static DEVICE_ATTR(mouse_middle, 1699*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1700*4104d13fSDmitry Torokhov show_tabletMouseMiddle, store_tabletMouseMiddle); 1701*4104d13fSDmitry Torokhov 1702*4104d13fSDmitry Torokhov /*********************************************************************** 1703*4104d13fSDmitry Torokhov * support routines for the 'mouse_right' file. Note that this file 1704*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1705*4104d13fSDmitry Torokhov */ 1706*4104d13fSDmitry Torokhov static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf) 1707*4104d13fSDmitry Torokhov { 1708*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1709*4104d13fSDmitry Torokhov char *s; 1710*4104d13fSDmitry Torokhov 1711*4104d13fSDmitry Torokhov if (aiptek == NULL) 1712*4104d13fSDmitry Torokhov return 0; 1713*4104d13fSDmitry Torokhov 1714*4104d13fSDmitry Torokhov switch (aiptek->curSetting.mouseButtonRight) { 1715*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_LEFT_BUTTON: 1716*4104d13fSDmitry Torokhov s = "left"; 1717*4104d13fSDmitry Torokhov break; 1718*4104d13fSDmitry Torokhov 1719*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_MIDDLE_BUTTON: 1720*4104d13fSDmitry Torokhov s = "middle"; 1721*4104d13fSDmitry Torokhov break; 1722*4104d13fSDmitry Torokhov 1723*4104d13fSDmitry Torokhov case AIPTEK_MOUSE_RIGHT_BUTTON: 1724*4104d13fSDmitry Torokhov s = "right"; 1725*4104d13fSDmitry Torokhov break; 1726*4104d13fSDmitry Torokhov 1727*4104d13fSDmitry Torokhov default: 1728*4104d13fSDmitry Torokhov s = "unknown"; 1729*4104d13fSDmitry Torokhov break; 1730*4104d13fSDmitry Torokhov } 1731*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%s\n", s); 1732*4104d13fSDmitry Torokhov } 1733*4104d13fSDmitry Torokhov 1734*4104d13fSDmitry Torokhov static ssize_t 1735*4104d13fSDmitry Torokhov store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1736*4104d13fSDmitry Torokhov { 1737*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1738*4104d13fSDmitry Torokhov 1739*4104d13fSDmitry Torokhov if (aiptek == NULL) 1740*4104d13fSDmitry Torokhov return 0; 1741*4104d13fSDmitry Torokhov 1742*4104d13fSDmitry Torokhov if (strcmp(buf, "left") == 0) { 1743*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON; 1744*4104d13fSDmitry Torokhov } else if (strcmp(buf, "middle") == 0) { 1745*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonRight = 1746*4104d13fSDmitry Torokhov AIPTEK_MOUSE_MIDDLE_BUTTON; 1747*4104d13fSDmitry Torokhov } else if (strcmp(buf, "right") == 0) { 1748*4104d13fSDmitry Torokhov aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; 1749*4104d13fSDmitry Torokhov } 1750*4104d13fSDmitry Torokhov return count; 1751*4104d13fSDmitry Torokhov } 1752*4104d13fSDmitry Torokhov 1753*4104d13fSDmitry Torokhov static DEVICE_ATTR(mouse_right, 1754*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, 1755*4104d13fSDmitry Torokhov show_tabletMouseRight, store_tabletMouseRight); 1756*4104d13fSDmitry Torokhov 1757*4104d13fSDmitry Torokhov /*********************************************************************** 1758*4104d13fSDmitry Torokhov * support routines for the 'wheel' file. Note that this file 1759*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1760*4104d13fSDmitry Torokhov */ 1761*4104d13fSDmitry Torokhov static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf) 1762*4104d13fSDmitry Torokhov { 1763*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1764*4104d13fSDmitry Torokhov 1765*4104d13fSDmitry Torokhov if (aiptek == NULL) 1766*4104d13fSDmitry Torokhov return 0; 1767*4104d13fSDmitry Torokhov 1768*4104d13fSDmitry Torokhov if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { 1769*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "disable\n"); 1770*4104d13fSDmitry Torokhov } else { 1771*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%d\n", 1772*4104d13fSDmitry Torokhov aiptek->curSetting.wheel); 1773*4104d13fSDmitry Torokhov } 1774*4104d13fSDmitry Torokhov } 1775*4104d13fSDmitry Torokhov 1776*4104d13fSDmitry Torokhov static ssize_t 1777*4104d13fSDmitry Torokhov store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1778*4104d13fSDmitry Torokhov { 1779*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1780*4104d13fSDmitry Torokhov 1781*4104d13fSDmitry Torokhov if (aiptek == NULL) 1782*4104d13fSDmitry Torokhov return 0; 1783*4104d13fSDmitry Torokhov 1784*4104d13fSDmitry Torokhov aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); 1785*4104d13fSDmitry Torokhov return count; 1786*4104d13fSDmitry Torokhov } 1787*4104d13fSDmitry Torokhov 1788*4104d13fSDmitry Torokhov static DEVICE_ATTR(wheel, 1789*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel); 1790*4104d13fSDmitry Torokhov 1791*4104d13fSDmitry Torokhov /*********************************************************************** 1792*4104d13fSDmitry Torokhov * support routines for the 'execute' file. Note that this file 1793*4104d13fSDmitry Torokhov * both displays current setting and allows for setting changing. 1794*4104d13fSDmitry Torokhov */ 1795*4104d13fSDmitry Torokhov static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf) 1796*4104d13fSDmitry Torokhov { 1797*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1798*4104d13fSDmitry Torokhov 1799*4104d13fSDmitry Torokhov if (aiptek == NULL) 1800*4104d13fSDmitry Torokhov return 0; 1801*4104d13fSDmitry Torokhov 1802*4104d13fSDmitry Torokhov /* There is nothing useful to display, so a one-line manual 1803*4104d13fSDmitry Torokhov * is in order... 1804*4104d13fSDmitry Torokhov */ 1805*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, 1806*4104d13fSDmitry Torokhov "Write anything to this file to program your tablet.\n"); 1807*4104d13fSDmitry Torokhov } 1808*4104d13fSDmitry Torokhov 1809*4104d13fSDmitry Torokhov static ssize_t 1810*4104d13fSDmitry Torokhov store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1811*4104d13fSDmitry Torokhov { 1812*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1813*4104d13fSDmitry Torokhov 1814*4104d13fSDmitry Torokhov if (aiptek == NULL) 1815*4104d13fSDmitry Torokhov return 0; 1816*4104d13fSDmitry Torokhov 1817*4104d13fSDmitry Torokhov /* We do not care what you write to this file. Merely the action 1818*4104d13fSDmitry Torokhov * of writing to this file triggers a tablet reprogramming. 1819*4104d13fSDmitry Torokhov */ 1820*4104d13fSDmitry Torokhov memcpy(&aiptek->curSetting, &aiptek->newSetting, 1821*4104d13fSDmitry Torokhov sizeof(struct aiptek_settings)); 1822*4104d13fSDmitry Torokhov 1823*4104d13fSDmitry Torokhov if (aiptek_program_tablet(aiptek) < 0) 1824*4104d13fSDmitry Torokhov return -EIO; 1825*4104d13fSDmitry Torokhov 1826*4104d13fSDmitry Torokhov return count; 1827*4104d13fSDmitry Torokhov } 1828*4104d13fSDmitry Torokhov 1829*4104d13fSDmitry Torokhov static DEVICE_ATTR(execute, 1830*4104d13fSDmitry Torokhov S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute); 1831*4104d13fSDmitry Torokhov 1832*4104d13fSDmitry Torokhov /*********************************************************************** 1833*4104d13fSDmitry Torokhov * support routines for the 'odm_code' file. Note that this file 1834*4104d13fSDmitry Torokhov * only displays current setting. 1835*4104d13fSDmitry Torokhov */ 1836*4104d13fSDmitry Torokhov static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf) 1837*4104d13fSDmitry Torokhov { 1838*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1839*4104d13fSDmitry Torokhov 1840*4104d13fSDmitry Torokhov if (aiptek == NULL) 1841*4104d13fSDmitry Torokhov return 0; 1842*4104d13fSDmitry Torokhov 1843*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode); 1844*4104d13fSDmitry Torokhov } 1845*4104d13fSDmitry Torokhov 1846*4104d13fSDmitry Torokhov static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL); 1847*4104d13fSDmitry Torokhov 1848*4104d13fSDmitry Torokhov /*********************************************************************** 1849*4104d13fSDmitry Torokhov * support routines for the 'model_code' file. Note that this file 1850*4104d13fSDmitry Torokhov * only displays current setting. 1851*4104d13fSDmitry Torokhov */ 1852*4104d13fSDmitry Torokhov static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf) 1853*4104d13fSDmitry Torokhov { 1854*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1855*4104d13fSDmitry Torokhov 1856*4104d13fSDmitry Torokhov if (aiptek == NULL) 1857*4104d13fSDmitry Torokhov return 0; 1858*4104d13fSDmitry Torokhov 1859*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode); 1860*4104d13fSDmitry Torokhov } 1861*4104d13fSDmitry Torokhov 1862*4104d13fSDmitry Torokhov static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL); 1863*4104d13fSDmitry Torokhov 1864*4104d13fSDmitry Torokhov /*********************************************************************** 1865*4104d13fSDmitry Torokhov * support routines for the 'firmware_code' file. Note that this file 1866*4104d13fSDmitry Torokhov * only displays current setting. 1867*4104d13fSDmitry Torokhov */ 1868*4104d13fSDmitry Torokhov static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf) 1869*4104d13fSDmitry Torokhov { 1870*4104d13fSDmitry Torokhov struct aiptek *aiptek = dev_get_drvdata(dev); 1871*4104d13fSDmitry Torokhov 1872*4104d13fSDmitry Torokhov if (aiptek == NULL) 1873*4104d13fSDmitry Torokhov return 0; 1874*4104d13fSDmitry Torokhov 1875*4104d13fSDmitry Torokhov return snprintf(buf, PAGE_SIZE, "%04x\n", 1876*4104d13fSDmitry Torokhov aiptek->features.firmwareCode); 1877*4104d13fSDmitry Torokhov } 1878*4104d13fSDmitry Torokhov 1879*4104d13fSDmitry Torokhov static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL); 1880*4104d13fSDmitry Torokhov 1881*4104d13fSDmitry Torokhov /*********************************************************************** 1882*4104d13fSDmitry Torokhov * This routine removes all existing sysfs files managed by this device 1883*4104d13fSDmitry Torokhov * driver. 1884*4104d13fSDmitry Torokhov */ 1885*4104d13fSDmitry Torokhov static void aiptek_delete_files(struct device *dev) 1886*4104d13fSDmitry Torokhov { 1887*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_size); 1888*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_product_id); 1889*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_vendor_id); 1890*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_vendor); 1891*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_product); 1892*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_pointer_mode); 1893*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_coordinate_mode); 1894*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_tool_mode); 1895*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_xtilt); 1896*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_ytilt); 1897*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_jitter); 1898*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_delay); 1899*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_input_path); 1900*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_event_count); 1901*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_diagnostic); 1902*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_odm_code); 1903*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_model_code); 1904*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_firmware_code); 1905*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_stylus_lower); 1906*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_stylus_upper); 1907*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_mouse_left); 1908*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_mouse_middle); 1909*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_mouse_right); 1910*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_wheel); 1911*4104d13fSDmitry Torokhov device_remove_file(dev, &dev_attr_execute); 1912*4104d13fSDmitry Torokhov } 1913*4104d13fSDmitry Torokhov 1914*4104d13fSDmitry Torokhov /*********************************************************************** 1915*4104d13fSDmitry Torokhov * This routine creates the sysfs files managed by this device 1916*4104d13fSDmitry Torokhov * driver. 1917*4104d13fSDmitry Torokhov */ 1918*4104d13fSDmitry Torokhov static int aiptek_add_files(struct device *dev) 1919*4104d13fSDmitry Torokhov { 1920*4104d13fSDmitry Torokhov int ret; 1921*4104d13fSDmitry Torokhov 1922*4104d13fSDmitry Torokhov if ((ret = device_create_file(dev, &dev_attr_size)) || 1923*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_product_id)) || 1924*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_vendor_id)) || 1925*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_vendor)) || 1926*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_product)) || 1927*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_pointer_mode)) || 1928*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_coordinate_mode)) || 1929*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_tool_mode)) || 1930*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_xtilt)) || 1931*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_ytilt)) || 1932*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_jitter)) || 1933*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_delay)) || 1934*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_input_path)) || 1935*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_event_count)) || 1936*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_diagnostic)) || 1937*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_odm_code)) || 1938*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_model_code)) || 1939*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_firmware_code)) || 1940*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_stylus_lower)) || 1941*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_stylus_upper)) || 1942*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_mouse_left)) || 1943*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_mouse_middle)) || 1944*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_mouse_right)) || 1945*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_wheel)) || 1946*4104d13fSDmitry Torokhov (ret = device_create_file(dev, &dev_attr_execute))) { 1947*4104d13fSDmitry Torokhov err("aiptek: killing own sysfs device files\n"); 1948*4104d13fSDmitry Torokhov aiptek_delete_files(dev); 1949*4104d13fSDmitry Torokhov } 1950*4104d13fSDmitry Torokhov return ret; 1951*4104d13fSDmitry Torokhov } 1952*4104d13fSDmitry Torokhov 1953*4104d13fSDmitry Torokhov /*********************************************************************** 1954*4104d13fSDmitry Torokhov * This routine is called when a tablet has been identified. It basically 1955*4104d13fSDmitry Torokhov * sets up the tablet and the driver's internal structures. 1956*4104d13fSDmitry Torokhov */ 1957*4104d13fSDmitry Torokhov static int 1958*4104d13fSDmitry Torokhov aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) 1959*4104d13fSDmitry Torokhov { 1960*4104d13fSDmitry Torokhov struct usb_device *usbdev = interface_to_usbdev(intf); 1961*4104d13fSDmitry Torokhov struct usb_endpoint_descriptor *endpoint; 1962*4104d13fSDmitry Torokhov struct aiptek *aiptek; 1963*4104d13fSDmitry Torokhov struct input_dev *inputdev; 1964*4104d13fSDmitry Torokhov struct input_handle *inputhandle; 1965*4104d13fSDmitry Torokhov struct list_head *node, *next; 1966*4104d13fSDmitry Torokhov int i; 1967*4104d13fSDmitry Torokhov int speeds[] = { 0, 1968*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_50, 1969*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_400, 1970*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_25, 1971*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_100, 1972*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_200, 1973*4104d13fSDmitry Torokhov AIPTEK_PROGRAMMABLE_DELAY_300 1974*4104d13fSDmitry Torokhov }; 1975*4104d13fSDmitry Torokhov int err = -ENOMEM; 1976*4104d13fSDmitry Torokhov 1977*4104d13fSDmitry Torokhov /* programmableDelay is where the command-line specified 1978*4104d13fSDmitry Torokhov * delay is kept. We make it the first element of speeds[], 1979*4104d13fSDmitry Torokhov * so therefore, your override speed is tried first, then the 1980*4104d13fSDmitry Torokhov * remainder. Note that the default value of 400ms will be tried 1981*4104d13fSDmitry Torokhov * if you do not specify any command line parameter. 1982*4104d13fSDmitry Torokhov */ 1983*4104d13fSDmitry Torokhov speeds[0] = programmableDelay; 1984*4104d13fSDmitry Torokhov 1985*4104d13fSDmitry Torokhov aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); 1986*4104d13fSDmitry Torokhov inputdev = input_allocate_device(); 1987*4104d13fSDmitry Torokhov if (!aiptek || !inputdev) 1988*4104d13fSDmitry Torokhov goto fail1; 1989*4104d13fSDmitry Torokhov 1990*4104d13fSDmitry Torokhov aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, 1991*4104d13fSDmitry Torokhov GFP_ATOMIC, &aiptek->data_dma); 1992*4104d13fSDmitry Torokhov if (!aiptek->data) 1993*4104d13fSDmitry Torokhov goto fail1; 1994*4104d13fSDmitry Torokhov 1995*4104d13fSDmitry Torokhov aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); 1996*4104d13fSDmitry Torokhov if (!aiptek->urb) 1997*4104d13fSDmitry Torokhov goto fail2; 1998*4104d13fSDmitry Torokhov 1999*4104d13fSDmitry Torokhov aiptek->inputdev = inputdev; 2000*4104d13fSDmitry Torokhov aiptek->usbdev = usbdev; 2001*4104d13fSDmitry Torokhov aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; 2002*4104d13fSDmitry Torokhov aiptek->inDelay = 0; 2003*4104d13fSDmitry Torokhov aiptek->endDelay = 0; 2004*4104d13fSDmitry Torokhov aiptek->previousJitterable = 0; 2005*4104d13fSDmitry Torokhov 2006*4104d13fSDmitry Torokhov /* Set up the curSettings struct. Said struct contains the current 2007*4104d13fSDmitry Torokhov * programmable parameters. The newSetting struct contains changes 2008*4104d13fSDmitry Torokhov * the user makes to the settings via the sysfs interface. Those 2009*4104d13fSDmitry Torokhov * changes are not "committed" to curSettings until the user 2010*4104d13fSDmitry Torokhov * writes to the sysfs/.../execute file. 2011*4104d13fSDmitry Torokhov */ 2012*4104d13fSDmitry Torokhov aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; 2013*4104d13fSDmitry Torokhov aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE; 2014*4104d13fSDmitry Torokhov aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; 2015*4104d13fSDmitry Torokhov aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE; 2016*4104d13fSDmitry Torokhov aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE; 2017*4104d13fSDmitry Torokhov aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; 2018*4104d13fSDmitry Torokhov aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON; 2019*4104d13fSDmitry Torokhov aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; 2020*4104d13fSDmitry Torokhov aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON; 2021*4104d13fSDmitry Torokhov aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON; 2022*4104d13fSDmitry Torokhov aiptek->curSetting.jitterDelay = jitterDelay; 2023*4104d13fSDmitry Torokhov aiptek->curSetting.programmableDelay = programmableDelay; 2024*4104d13fSDmitry Torokhov 2025*4104d13fSDmitry Torokhov /* Both structs should have equivalent settings 2026*4104d13fSDmitry Torokhov */ 2027*4104d13fSDmitry Torokhov aiptek->newSetting = aiptek->curSetting; 2028*4104d13fSDmitry Torokhov 2029*4104d13fSDmitry Torokhov /* Determine the usb devices' physical path. 2030*4104d13fSDmitry Torokhov * Asketh not why we always pretend we're using "../input0", 2031*4104d13fSDmitry Torokhov * but I suspect this will have to be refactored one 2032*4104d13fSDmitry Torokhov * day if a single USB device can be a keyboard & a mouse 2033*4104d13fSDmitry Torokhov * & a tablet, and the inputX number actually will tell 2034*4104d13fSDmitry Torokhov * us something... 2035*4104d13fSDmitry Torokhov */ 2036*4104d13fSDmitry Torokhov usb_make_path(usbdev, aiptek->features.usbPath, 2037*4104d13fSDmitry Torokhov sizeof(aiptek->features.usbPath)); 2038*4104d13fSDmitry Torokhov strlcat(aiptek->features.usbPath, "/input0", 2039*4104d13fSDmitry Torokhov sizeof(aiptek->features.usbPath)); 2040*4104d13fSDmitry Torokhov 2041*4104d13fSDmitry Torokhov /* Set up client data, pointers to open and close routines 2042*4104d13fSDmitry Torokhov * for the input device. 2043*4104d13fSDmitry Torokhov */ 2044*4104d13fSDmitry Torokhov inputdev->name = "Aiptek"; 2045*4104d13fSDmitry Torokhov inputdev->phys = aiptek->features.usbPath; 2046*4104d13fSDmitry Torokhov usb_to_input_id(usbdev, &inputdev->id); 2047*4104d13fSDmitry Torokhov inputdev->dev.parent = &intf->dev; 2048*4104d13fSDmitry Torokhov 2049*4104d13fSDmitry Torokhov input_set_drvdata(inputdev, aiptek); 2050*4104d13fSDmitry Torokhov 2051*4104d13fSDmitry Torokhov inputdev->open = aiptek_open; 2052*4104d13fSDmitry Torokhov inputdev->close = aiptek_close; 2053*4104d13fSDmitry Torokhov 2054*4104d13fSDmitry Torokhov /* Now program the capacities of the tablet, in terms of being 2055*4104d13fSDmitry Torokhov * an input device. 2056*4104d13fSDmitry Torokhov */ 2057*4104d13fSDmitry Torokhov inputdev->evbit[0] |= BIT(EV_KEY) 2058*4104d13fSDmitry Torokhov | BIT(EV_ABS) 2059*4104d13fSDmitry Torokhov | BIT(EV_REL) 2060*4104d13fSDmitry Torokhov | BIT(EV_MSC); 2061*4104d13fSDmitry Torokhov 2062*4104d13fSDmitry Torokhov inputdev->absbit[0] |= BIT(ABS_MISC); 2063*4104d13fSDmitry Torokhov 2064*4104d13fSDmitry Torokhov inputdev->relbit[0] |= 2065*4104d13fSDmitry Torokhov (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); 2066*4104d13fSDmitry Torokhov 2067*4104d13fSDmitry Torokhov inputdev->keybit[LONG(BTN_LEFT)] |= 2068*4104d13fSDmitry Torokhov (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); 2069*4104d13fSDmitry Torokhov 2070*4104d13fSDmitry Torokhov inputdev->keybit[LONG(BTN_DIGI)] |= 2071*4104d13fSDmitry Torokhov (BIT(BTN_TOOL_PEN) | 2072*4104d13fSDmitry Torokhov BIT(BTN_TOOL_RUBBER) | 2073*4104d13fSDmitry Torokhov BIT(BTN_TOOL_PENCIL) | 2074*4104d13fSDmitry Torokhov BIT(BTN_TOOL_AIRBRUSH) | 2075*4104d13fSDmitry Torokhov BIT(BTN_TOOL_BRUSH) | 2076*4104d13fSDmitry Torokhov BIT(BTN_TOOL_MOUSE) | 2077*4104d13fSDmitry Torokhov BIT(BTN_TOOL_LENS) | 2078*4104d13fSDmitry Torokhov BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); 2079*4104d13fSDmitry Torokhov 2080*4104d13fSDmitry Torokhov inputdev->mscbit[0] = BIT(MSC_SERIAL); 2081*4104d13fSDmitry Torokhov 2082*4104d13fSDmitry Torokhov /* Programming the tablet macro keys needs to be done with a for loop 2083*4104d13fSDmitry Torokhov * as the keycodes are discontiguous. 2084*4104d13fSDmitry Torokhov */ 2085*4104d13fSDmitry Torokhov for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i) 2086*4104d13fSDmitry Torokhov set_bit(macroKeyEvents[i], inputdev->keybit); 2087*4104d13fSDmitry Torokhov 2088*4104d13fSDmitry Torokhov /* 2089*4104d13fSDmitry Torokhov * Program the input device coordinate capacities. We do not yet 2090*4104d13fSDmitry Torokhov * know what maximum X, Y, and Z values are, so we're putting fake 2091*4104d13fSDmitry Torokhov * values in. Later, we'll ask the tablet to put in the correct 2092*4104d13fSDmitry Torokhov * values. 2093*4104d13fSDmitry Torokhov */ 2094*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0); 2095*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0); 2096*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0); 2097*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); 2098*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); 2099*4104d13fSDmitry Torokhov input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); 2100*4104d13fSDmitry Torokhov 2101*4104d13fSDmitry Torokhov endpoint = &intf->altsetting[0].endpoint[0].desc; 2102*4104d13fSDmitry Torokhov 2103*4104d13fSDmitry Torokhov /* Go set up our URB, which is called when the tablet receives 2104*4104d13fSDmitry Torokhov * input. 2105*4104d13fSDmitry Torokhov */ 2106*4104d13fSDmitry Torokhov usb_fill_int_urb(aiptek->urb, 2107*4104d13fSDmitry Torokhov aiptek->usbdev, 2108*4104d13fSDmitry Torokhov usb_rcvintpipe(aiptek->usbdev, 2109*4104d13fSDmitry Torokhov endpoint->bEndpointAddress), 2110*4104d13fSDmitry Torokhov aiptek->data, 8, aiptek_irq, aiptek, 2111*4104d13fSDmitry Torokhov endpoint->bInterval); 2112*4104d13fSDmitry Torokhov 2113*4104d13fSDmitry Torokhov aiptek->urb->transfer_dma = aiptek->data_dma; 2114*4104d13fSDmitry Torokhov aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 2115*4104d13fSDmitry Torokhov 2116*4104d13fSDmitry Torokhov /* Program the tablet. This sets the tablet up in the mode 2117*4104d13fSDmitry Torokhov * specified in newSetting, and also queries the tablet's 2118*4104d13fSDmitry Torokhov * physical capacities. 2119*4104d13fSDmitry Torokhov * 2120*4104d13fSDmitry Torokhov * Sanity check: if a tablet doesn't like the slow programmatic 2121*4104d13fSDmitry Torokhov * delay, we often get sizes of 0x0. Let's use that as an indicator 2122*4104d13fSDmitry Torokhov * to try faster delays, up to 25 ms. If that logic fails, well, you'll 2123*4104d13fSDmitry Torokhov * have to explain to us how your tablet thinks it's 0x0, and yet that's 2124*4104d13fSDmitry Torokhov * not an error :-) 2125*4104d13fSDmitry Torokhov */ 2126*4104d13fSDmitry Torokhov 2127*4104d13fSDmitry Torokhov for (i = 0; i < ARRAY_SIZE(speeds); ++i) { 2128*4104d13fSDmitry Torokhov aiptek->curSetting.programmableDelay = speeds[i]; 2129*4104d13fSDmitry Torokhov (void)aiptek_program_tablet(aiptek); 2130*4104d13fSDmitry Torokhov if (aiptek->inputdev->absmax[ABS_X] > 0) { 2131*4104d13fSDmitry Torokhov info("input: Aiptek using %d ms programming speed\n", 2132*4104d13fSDmitry Torokhov aiptek->curSetting.programmableDelay); 2133*4104d13fSDmitry Torokhov break; 2134*4104d13fSDmitry Torokhov } 2135*4104d13fSDmitry Torokhov } 2136*4104d13fSDmitry Torokhov 2137*4104d13fSDmitry Torokhov /* Register the tablet as an Input Device 2138*4104d13fSDmitry Torokhov */ 2139*4104d13fSDmitry Torokhov err = input_register_device(aiptek->inputdev); 2140*4104d13fSDmitry Torokhov if (err) 2141*4104d13fSDmitry Torokhov goto fail2; 2142*4104d13fSDmitry Torokhov 2143*4104d13fSDmitry Torokhov /* We now will look for the evdev device which is mapped to 2144*4104d13fSDmitry Torokhov * the tablet. The partial name is kept in the link list of 2145*4104d13fSDmitry Torokhov * input_handles associated with this input device. 2146*4104d13fSDmitry Torokhov * What identifies an evdev input_handler is that it begins 2147*4104d13fSDmitry Torokhov * with 'event', continues with a digit, and that in turn 2148*4104d13fSDmitry Torokhov * is mapped to input/eventN. 2149*4104d13fSDmitry Torokhov */ 2150*4104d13fSDmitry Torokhov list_for_each_safe(node, next, &inputdev->h_list) { 2151*4104d13fSDmitry Torokhov inputhandle = to_handle(node); 2152*4104d13fSDmitry Torokhov if (strncmp(inputhandle->name, "event", 5) == 0) { 2153*4104d13fSDmitry Torokhov strcpy(aiptek->features.inputPath, inputhandle->name); 2154*4104d13fSDmitry Torokhov break; 2155*4104d13fSDmitry Torokhov } 2156*4104d13fSDmitry Torokhov } 2157*4104d13fSDmitry Torokhov 2158*4104d13fSDmitry Torokhov /* Associate this driver's struct with the usb interface. 2159*4104d13fSDmitry Torokhov */ 2160*4104d13fSDmitry Torokhov usb_set_intfdata(intf, aiptek); 2161*4104d13fSDmitry Torokhov 2162*4104d13fSDmitry Torokhov /* Set up the sysfs files 2163*4104d13fSDmitry Torokhov */ 2164*4104d13fSDmitry Torokhov aiptek_add_files(&intf->dev); 2165*4104d13fSDmitry Torokhov 2166*4104d13fSDmitry Torokhov /* Make sure the evdev module is loaded. Assuming evdev IS a module :-) 2167*4104d13fSDmitry Torokhov */ 2168*4104d13fSDmitry Torokhov if (request_module("evdev") != 0) 2169*4104d13fSDmitry Torokhov info("aiptek: error loading 'evdev' module"); 2170*4104d13fSDmitry Torokhov 2171*4104d13fSDmitry Torokhov return 0; 2172*4104d13fSDmitry Torokhov 2173*4104d13fSDmitry Torokhov fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, 2174*4104d13fSDmitry Torokhov aiptek->data_dma); 2175*4104d13fSDmitry Torokhov fail1: input_free_device(inputdev); 2176*4104d13fSDmitry Torokhov kfree(aiptek); 2177*4104d13fSDmitry Torokhov return err; 2178*4104d13fSDmitry Torokhov } 2179*4104d13fSDmitry Torokhov 2180*4104d13fSDmitry Torokhov /*********************************************************************** 2181*4104d13fSDmitry Torokhov * Deal with tablet disconnecting from the system. 2182*4104d13fSDmitry Torokhov */ 2183*4104d13fSDmitry Torokhov static void aiptek_disconnect(struct usb_interface *intf) 2184*4104d13fSDmitry Torokhov { 2185*4104d13fSDmitry Torokhov struct aiptek *aiptek = usb_get_intfdata(intf); 2186*4104d13fSDmitry Torokhov 2187*4104d13fSDmitry Torokhov /* Disassociate driver's struct with usb interface 2188*4104d13fSDmitry Torokhov */ 2189*4104d13fSDmitry Torokhov usb_set_intfdata(intf, NULL); 2190*4104d13fSDmitry Torokhov if (aiptek != NULL) { 2191*4104d13fSDmitry Torokhov /* Free & unhook everything from the system. 2192*4104d13fSDmitry Torokhov */ 2193*4104d13fSDmitry Torokhov usb_kill_urb(aiptek->urb); 2194*4104d13fSDmitry Torokhov input_unregister_device(aiptek->inputdev); 2195*4104d13fSDmitry Torokhov aiptek_delete_files(&intf->dev); 2196*4104d13fSDmitry Torokhov usb_free_urb(aiptek->urb); 2197*4104d13fSDmitry Torokhov usb_buffer_free(interface_to_usbdev(intf), 2198*4104d13fSDmitry Torokhov AIPTEK_PACKET_LENGTH, 2199*4104d13fSDmitry Torokhov aiptek->data, aiptek->data_dma); 2200*4104d13fSDmitry Torokhov kfree(aiptek); 2201*4104d13fSDmitry Torokhov } 2202*4104d13fSDmitry Torokhov } 2203*4104d13fSDmitry Torokhov 2204*4104d13fSDmitry Torokhov static struct usb_driver aiptek_driver = { 2205*4104d13fSDmitry Torokhov .name = "aiptek", 2206*4104d13fSDmitry Torokhov .probe = aiptek_probe, 2207*4104d13fSDmitry Torokhov .disconnect = aiptek_disconnect, 2208*4104d13fSDmitry Torokhov .id_table = aiptek_ids, 2209*4104d13fSDmitry Torokhov }; 2210*4104d13fSDmitry Torokhov 2211*4104d13fSDmitry Torokhov static int __init aiptek_init(void) 2212*4104d13fSDmitry Torokhov { 2213*4104d13fSDmitry Torokhov int result = usb_register(&aiptek_driver); 2214*4104d13fSDmitry Torokhov if (result == 0) { 2215*4104d13fSDmitry Torokhov info(DRIVER_VERSION ": " DRIVER_AUTHOR); 2216*4104d13fSDmitry Torokhov info(DRIVER_DESC); 2217*4104d13fSDmitry Torokhov } 2218*4104d13fSDmitry Torokhov return result; 2219*4104d13fSDmitry Torokhov } 2220*4104d13fSDmitry Torokhov 2221*4104d13fSDmitry Torokhov static void __exit aiptek_exit(void) 2222*4104d13fSDmitry Torokhov { 2223*4104d13fSDmitry Torokhov usb_deregister(&aiptek_driver); 2224*4104d13fSDmitry Torokhov } 2225*4104d13fSDmitry Torokhov 2226*4104d13fSDmitry Torokhov MODULE_AUTHOR(DRIVER_AUTHOR); 2227*4104d13fSDmitry Torokhov MODULE_DESCRIPTION(DRIVER_DESC); 2228*4104d13fSDmitry Torokhov MODULE_LICENSE("GPL"); 2229*4104d13fSDmitry Torokhov 2230*4104d13fSDmitry Torokhov module_param(programmableDelay, int, 0); 2231*4104d13fSDmitry Torokhov MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming"); 2232*4104d13fSDmitry Torokhov module_param(jitterDelay, int, 0); 2233*4104d13fSDmitry Torokhov MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay"); 2234*4104d13fSDmitry Torokhov 2235*4104d13fSDmitry Torokhov module_init(aiptek_init); 2236*4104d13fSDmitry Torokhov module_exit(aiptek_exit); 2237