1*b5da20f8SDmitry Torokhov /* 2*b5da20f8SDmitry Torokhov * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver 3*b5da20f8SDmitry Torokhov * 4*b5da20f8SDmitry Torokhov * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 5*b5da20f8SDmitry Torokhov * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) 6*b5da20f8SDmitry Torokhov * Copyright (C) 2005 Stelian Pop (stelian@popies.net) 7*b5da20f8SDmitry Torokhov * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) 8*b5da20f8SDmitry Torokhov * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) 9*b5da20f8SDmitry Torokhov * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) 10*b5da20f8SDmitry Torokhov * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) 11*b5da20f8SDmitry Torokhov * 12*b5da20f8SDmitry Torokhov * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. 13*b5da20f8SDmitry Torokhov * 14*b5da20f8SDmitry Torokhov * This program is free software; you can redistribute it and/or modify 15*b5da20f8SDmitry Torokhov * it under the terms of the GNU General Public License as published by 16*b5da20f8SDmitry Torokhov * the Free Software Foundation; either version 2 of the License, or 17*b5da20f8SDmitry Torokhov * (at your option) any later version. 18*b5da20f8SDmitry Torokhov * 19*b5da20f8SDmitry Torokhov * This program is distributed in the hope that it will be useful, 20*b5da20f8SDmitry Torokhov * but WITHOUT ANY WARRANTY; without even the implied warranty of 21*b5da20f8SDmitry Torokhov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22*b5da20f8SDmitry Torokhov * GNU General Public License for more details. 23*b5da20f8SDmitry Torokhov * 24*b5da20f8SDmitry Torokhov * You should have received a copy of the GNU General Public License 25*b5da20f8SDmitry Torokhov * along with this program; if not, write to the Free Software 26*b5da20f8SDmitry Torokhov * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27*b5da20f8SDmitry Torokhov * 28*b5da20f8SDmitry Torokhov */ 29*b5da20f8SDmitry Torokhov 30*b5da20f8SDmitry Torokhov #include <linux/kernel.h> 31*b5da20f8SDmitry Torokhov #include <linux/errno.h> 32*b5da20f8SDmitry Torokhov #include <linux/init.h> 33*b5da20f8SDmitry Torokhov #include <linux/slab.h> 34*b5da20f8SDmitry Torokhov #include <linux/module.h> 35*b5da20f8SDmitry Torokhov #include <linux/usb/input.h> 36*b5da20f8SDmitry Torokhov 37*b5da20f8SDmitry Torokhov /* Apple has powerbooks which have the keyboard with different Product IDs */ 38*b5da20f8SDmitry Torokhov #define APPLE_VENDOR_ID 0x05AC 39*b5da20f8SDmitry Torokhov 40*b5da20f8SDmitry Torokhov /* These names come from Info.plist in AppleUSBTrackpad.kext */ 41*b5da20f8SDmitry Torokhov #define FOUNTAIN_ANSI_PRODUCT_ID 0x020E 42*b5da20f8SDmitry Torokhov #define FOUNTAIN_ISO_PRODUCT_ID 0x020F 43*b5da20f8SDmitry Torokhov 44*b5da20f8SDmitry Torokhov #define FOUNTAIN_TP_ONLY_PRODUCT_ID 0x030A 45*b5da20f8SDmitry Torokhov 46*b5da20f8SDmitry Torokhov #define GEYSER1_TP_ONLY_PRODUCT_ID 0x030B 47*b5da20f8SDmitry Torokhov 48*b5da20f8SDmitry Torokhov #define GEYSER_ANSI_PRODUCT_ID 0x0214 49*b5da20f8SDmitry Torokhov #define GEYSER_ISO_PRODUCT_ID 0x0215 50*b5da20f8SDmitry Torokhov #define GEYSER_JIS_PRODUCT_ID 0x0216 51*b5da20f8SDmitry Torokhov 52*b5da20f8SDmitry Torokhov /* MacBook devices */ 53*b5da20f8SDmitry Torokhov #define GEYSER3_ANSI_PRODUCT_ID 0x0217 54*b5da20f8SDmitry Torokhov #define GEYSER3_ISO_PRODUCT_ID 0x0218 55*b5da20f8SDmitry Torokhov #define GEYSER3_JIS_PRODUCT_ID 0x0219 56*b5da20f8SDmitry Torokhov 57*b5da20f8SDmitry Torokhov /* 58*b5da20f8SDmitry Torokhov * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext 59*b5da20f8SDmitry Torokhov * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables 60*b5da20f8SDmitry Torokhov */ 61*b5da20f8SDmitry Torokhov #define GEYSER4_ANSI_PRODUCT_ID 0x021A 62*b5da20f8SDmitry Torokhov #define GEYSER4_ISO_PRODUCT_ID 0x021B 63*b5da20f8SDmitry Torokhov #define GEYSER4_JIS_PRODUCT_ID 0x021C 64*b5da20f8SDmitry Torokhov 65*b5da20f8SDmitry Torokhov #define ATP_DEVICE(prod) \ 66*b5da20f8SDmitry Torokhov .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 67*b5da20f8SDmitry Torokhov USB_DEVICE_ID_MATCH_INT_CLASS | \ 68*b5da20f8SDmitry Torokhov USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ 69*b5da20f8SDmitry Torokhov .idVendor = APPLE_VENDOR_ID, \ 70*b5da20f8SDmitry Torokhov .idProduct = (prod), \ 71*b5da20f8SDmitry Torokhov .bInterfaceClass = 0x03, \ 72*b5da20f8SDmitry Torokhov .bInterfaceProtocol = 0x02 73*b5da20f8SDmitry Torokhov 74*b5da20f8SDmitry Torokhov /* table of devices that work with this driver */ 75*b5da20f8SDmitry Torokhov static struct usb_device_id atp_table [] = { 76*b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) }, 77*b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) }, 78*b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) }, 79*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) }, 80*b5da20f8SDmitry Torokhov 81*b5da20f8SDmitry Torokhov /* PowerBooks Oct 2005 */ 82*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) }, 83*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, 84*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, 85*b5da20f8SDmitry Torokhov 86*b5da20f8SDmitry Torokhov /* Core Duo MacBook & MacBook Pro */ 87*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, 88*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, 89*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, 90*b5da20f8SDmitry Torokhov 91*b5da20f8SDmitry Torokhov /* Core2 Duo MacBook & MacBook Pro */ 92*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) }, 93*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, 94*b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, 95*b5da20f8SDmitry Torokhov 96*b5da20f8SDmitry Torokhov /* Terminating entry */ 97*b5da20f8SDmitry Torokhov { } 98*b5da20f8SDmitry Torokhov }; 99*b5da20f8SDmitry Torokhov MODULE_DEVICE_TABLE (usb, atp_table); 100*b5da20f8SDmitry Torokhov 101*b5da20f8SDmitry Torokhov /* 102*b5da20f8SDmitry Torokhov * number of sensors. Note that only 16 instead of 26 X (horizontal) 103*b5da20f8SDmitry Torokhov * sensors exist on 12" and 15" PowerBooks. All models have 16 Y 104*b5da20f8SDmitry Torokhov * (vertical) sensors. 105*b5da20f8SDmitry Torokhov */ 106*b5da20f8SDmitry Torokhov #define ATP_XSENSORS 26 107*b5da20f8SDmitry Torokhov #define ATP_YSENSORS 16 108*b5da20f8SDmitry Torokhov 109*b5da20f8SDmitry Torokhov /* amount of fuzz this touchpad generates */ 110*b5da20f8SDmitry Torokhov #define ATP_FUZZ 16 111*b5da20f8SDmitry Torokhov 112*b5da20f8SDmitry Torokhov /* maximum pressure this driver will report */ 113*b5da20f8SDmitry Torokhov #define ATP_PRESSURE 300 114*b5da20f8SDmitry Torokhov /* 115*b5da20f8SDmitry Torokhov * multiplication factor for the X and Y coordinates. 116*b5da20f8SDmitry Torokhov * We try to keep the touchpad aspect ratio while still doing only simple 117*b5da20f8SDmitry Torokhov * arithmetics. 118*b5da20f8SDmitry Torokhov * The factors below give coordinates like: 119*b5da20f8SDmitry Torokhov * 0 <= x < 960 on 12" and 15" Powerbooks 120*b5da20f8SDmitry Torokhov * 0 <= x < 1600 on 17" Powerbooks 121*b5da20f8SDmitry Torokhov * 0 <= y < 646 122*b5da20f8SDmitry Torokhov */ 123*b5da20f8SDmitry Torokhov #define ATP_XFACT 64 124*b5da20f8SDmitry Torokhov #define ATP_YFACT 43 125*b5da20f8SDmitry Torokhov 126*b5da20f8SDmitry Torokhov /* 127*b5da20f8SDmitry Torokhov * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is 128*b5da20f8SDmitry Torokhov * ignored. 129*b5da20f8SDmitry Torokhov */ 130*b5da20f8SDmitry Torokhov #define ATP_THRESHOLD 5 131*b5da20f8SDmitry Torokhov 132*b5da20f8SDmitry Torokhov /* MacBook Pro (Geyser 3 & 4) initialization constants */ 133*b5da20f8SDmitry Torokhov #define ATP_GEYSER3_MODE_READ_REQUEST_ID 1 134*b5da20f8SDmitry Torokhov #define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9 135*b5da20f8SDmitry Torokhov #define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300 136*b5da20f8SDmitry Torokhov #define ATP_GEYSER3_MODE_REQUEST_INDEX 0 137*b5da20f8SDmitry Torokhov #define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04 138*b5da20f8SDmitry Torokhov 139*b5da20f8SDmitry Torokhov /* Structure to hold all of our device specific stuff */ 140*b5da20f8SDmitry Torokhov struct atp { 141*b5da20f8SDmitry Torokhov char phys[64]; 142*b5da20f8SDmitry Torokhov struct usb_device * udev; /* usb device */ 143*b5da20f8SDmitry Torokhov struct urb * urb; /* usb request block */ 144*b5da20f8SDmitry Torokhov signed char * data; /* transferred data */ 145*b5da20f8SDmitry Torokhov int open; /* non-zero if opened */ 146*b5da20f8SDmitry Torokhov struct input_dev *input; /* input dev */ 147*b5da20f8SDmitry Torokhov int valid; /* are the sensors valid ? */ 148*b5da20f8SDmitry Torokhov int x_old; /* last reported x/y, */ 149*b5da20f8SDmitry Torokhov int y_old; /* used for smoothing */ 150*b5da20f8SDmitry Torokhov /* current value of the sensors */ 151*b5da20f8SDmitry Torokhov signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; 152*b5da20f8SDmitry Torokhov /* last value of the sensors */ 153*b5da20f8SDmitry Torokhov signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; 154*b5da20f8SDmitry Torokhov /* accumulated sensors */ 155*b5da20f8SDmitry Torokhov int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; 156*b5da20f8SDmitry Torokhov int overflowwarn; /* overflow warning printed? */ 157*b5da20f8SDmitry Torokhov int datalen; /* size of an USB urb transfer */ 158*b5da20f8SDmitry Torokhov }; 159*b5da20f8SDmitry Torokhov 160*b5da20f8SDmitry Torokhov #define dbg_dump(msg, tab) \ 161*b5da20f8SDmitry Torokhov if (debug > 1) { \ 162*b5da20f8SDmitry Torokhov int i; \ 163*b5da20f8SDmitry Torokhov printk("appletouch: %s %lld", msg, (long long)jiffies); \ 164*b5da20f8SDmitry Torokhov for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ 165*b5da20f8SDmitry Torokhov printk(" %02x", tab[i]); \ 166*b5da20f8SDmitry Torokhov printk("\n"); \ 167*b5da20f8SDmitry Torokhov } 168*b5da20f8SDmitry Torokhov 169*b5da20f8SDmitry Torokhov #define dprintk(format, a...) \ 170*b5da20f8SDmitry Torokhov do { \ 171*b5da20f8SDmitry Torokhov if (debug) printk(format, ##a); \ 172*b5da20f8SDmitry Torokhov } while (0) 173*b5da20f8SDmitry Torokhov 174*b5da20f8SDmitry Torokhov MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); 175*b5da20f8SDmitry Torokhov MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); 176*b5da20f8SDmitry Torokhov MODULE_LICENSE("GPL"); 177*b5da20f8SDmitry Torokhov 178*b5da20f8SDmitry Torokhov /* 179*b5da20f8SDmitry Torokhov * Make the threshold a module parameter 180*b5da20f8SDmitry Torokhov */ 181*b5da20f8SDmitry Torokhov static int threshold = ATP_THRESHOLD; 182*b5da20f8SDmitry Torokhov module_param(threshold, int, 0644); 183*b5da20f8SDmitry Torokhov MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value"); 184*b5da20f8SDmitry Torokhov 185*b5da20f8SDmitry Torokhov static int debug = 1; 186*b5da20f8SDmitry Torokhov module_param(debug, int, 0644); 187*b5da20f8SDmitry Torokhov MODULE_PARM_DESC(debug, "Activate debugging output"); 188*b5da20f8SDmitry Torokhov 189*b5da20f8SDmitry Torokhov /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ 190*b5da20f8SDmitry Torokhov static inline int atp_is_geyser_2(struct atp *dev) 191*b5da20f8SDmitry Torokhov { 192*b5da20f8SDmitry Torokhov u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); 193*b5da20f8SDmitry Torokhov 194*b5da20f8SDmitry Torokhov return (productId == GEYSER_ANSI_PRODUCT_ID) || 195*b5da20f8SDmitry Torokhov (productId == GEYSER_ISO_PRODUCT_ID) || 196*b5da20f8SDmitry Torokhov (productId == GEYSER_JIS_PRODUCT_ID); 197*b5da20f8SDmitry Torokhov } 198*b5da20f8SDmitry Torokhov 199*b5da20f8SDmitry Torokhov static inline int atp_is_geyser_3(struct atp *dev) 200*b5da20f8SDmitry Torokhov { 201*b5da20f8SDmitry Torokhov u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); 202*b5da20f8SDmitry Torokhov 203*b5da20f8SDmitry Torokhov return (productId == GEYSER3_ANSI_PRODUCT_ID) || 204*b5da20f8SDmitry Torokhov (productId == GEYSER3_ISO_PRODUCT_ID) || 205*b5da20f8SDmitry Torokhov (productId == GEYSER3_JIS_PRODUCT_ID) || 206*b5da20f8SDmitry Torokhov (productId == GEYSER4_ANSI_PRODUCT_ID) || 207*b5da20f8SDmitry Torokhov (productId == GEYSER4_ISO_PRODUCT_ID) || 208*b5da20f8SDmitry Torokhov (productId == GEYSER4_JIS_PRODUCT_ID); 209*b5da20f8SDmitry Torokhov } 210*b5da20f8SDmitry Torokhov 211*b5da20f8SDmitry Torokhov static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, 212*b5da20f8SDmitry Torokhov int *z, int *fingers) 213*b5da20f8SDmitry Torokhov { 214*b5da20f8SDmitry Torokhov int i; 215*b5da20f8SDmitry Torokhov /* values to calculate mean */ 216*b5da20f8SDmitry Torokhov int pcum = 0, psum = 0; 217*b5da20f8SDmitry Torokhov int is_increasing = 0; 218*b5da20f8SDmitry Torokhov 219*b5da20f8SDmitry Torokhov *fingers = 0; 220*b5da20f8SDmitry Torokhov 221*b5da20f8SDmitry Torokhov for (i = 0; i < nb_sensors; i++) { 222*b5da20f8SDmitry Torokhov if (xy_sensors[i] < threshold) { 223*b5da20f8SDmitry Torokhov if (is_increasing) 224*b5da20f8SDmitry Torokhov is_increasing = 0; 225*b5da20f8SDmitry Torokhov 226*b5da20f8SDmitry Torokhov continue; 227*b5da20f8SDmitry Torokhov } 228*b5da20f8SDmitry Torokhov 229*b5da20f8SDmitry Torokhov /* 230*b5da20f8SDmitry Torokhov * Makes the finger detection more versatile. For example, 231*b5da20f8SDmitry Torokhov * two fingers with no gap will be detected. Also, my 232*b5da20f8SDmitry Torokhov * tests show it less likely to have intermittent loss 233*b5da20f8SDmitry Torokhov * of multiple finger readings while moving around (scrolling). 234*b5da20f8SDmitry Torokhov * 235*b5da20f8SDmitry Torokhov * Changes the multiple finger detection to counting humps on 236*b5da20f8SDmitry Torokhov * sensors (transitions from nonincreasing to increasing) 237*b5da20f8SDmitry Torokhov * instead of counting transitions from low sensors (no 238*b5da20f8SDmitry Torokhov * finger reading) to high sensors (finger above 239*b5da20f8SDmitry Torokhov * sensor) 240*b5da20f8SDmitry Torokhov * 241*b5da20f8SDmitry Torokhov * - Jason Parekh <jasonparekh@gmail.com> 242*b5da20f8SDmitry Torokhov */ 243*b5da20f8SDmitry Torokhov if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { 244*b5da20f8SDmitry Torokhov (*fingers)++; 245*b5da20f8SDmitry Torokhov is_increasing = 1; 246*b5da20f8SDmitry Torokhov } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { 247*b5da20f8SDmitry Torokhov is_increasing = 0; 248*b5da20f8SDmitry Torokhov } 249*b5da20f8SDmitry Torokhov 250*b5da20f8SDmitry Torokhov /* 251*b5da20f8SDmitry Torokhov * Subtracts threshold so a high sensor that just passes the threshold 252*b5da20f8SDmitry Torokhov * won't skew the calculated absolute coordinate. Fixes an issue 253*b5da20f8SDmitry Torokhov * where slowly moving the mouse would occassionaly jump a number of 254*b5da20f8SDmitry Torokhov * pixels (let me restate--slowly moving the mouse makes this issue 255*b5da20f8SDmitry Torokhov * most apparent). 256*b5da20f8SDmitry Torokhov */ 257*b5da20f8SDmitry Torokhov pcum += (xy_sensors[i] - threshold) * i; 258*b5da20f8SDmitry Torokhov psum += (xy_sensors[i] - threshold); 259*b5da20f8SDmitry Torokhov } 260*b5da20f8SDmitry Torokhov 261*b5da20f8SDmitry Torokhov if (psum > 0) { 262*b5da20f8SDmitry Torokhov *z = psum; 263*b5da20f8SDmitry Torokhov return pcum * fact / psum; 264*b5da20f8SDmitry Torokhov } 265*b5da20f8SDmitry Torokhov 266*b5da20f8SDmitry Torokhov return 0; 267*b5da20f8SDmitry Torokhov } 268*b5da20f8SDmitry Torokhov 269*b5da20f8SDmitry Torokhov static inline void atp_report_fingers(struct input_dev *input, int fingers) 270*b5da20f8SDmitry Torokhov { 271*b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_FINGER, fingers == 1); 272*b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2); 273*b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); 274*b5da20f8SDmitry Torokhov } 275*b5da20f8SDmitry Torokhov 276*b5da20f8SDmitry Torokhov static void atp_complete(struct urb* urb) 277*b5da20f8SDmitry Torokhov { 278*b5da20f8SDmitry Torokhov int x, y, x_z, y_z, x_f, y_f; 279*b5da20f8SDmitry Torokhov int retval, i, j; 280*b5da20f8SDmitry Torokhov struct atp *dev = urb->context; 281*b5da20f8SDmitry Torokhov 282*b5da20f8SDmitry Torokhov switch (urb->status) { 283*b5da20f8SDmitry Torokhov case 0: 284*b5da20f8SDmitry Torokhov /* success */ 285*b5da20f8SDmitry Torokhov break; 286*b5da20f8SDmitry Torokhov case -EOVERFLOW: 287*b5da20f8SDmitry Torokhov if(!dev->overflowwarn) { 288*b5da20f8SDmitry Torokhov printk("appletouch: OVERFLOW with data " 289*b5da20f8SDmitry Torokhov "length %d, actual length is %d\n", 290*b5da20f8SDmitry Torokhov dev->datalen, dev->urb->actual_length); 291*b5da20f8SDmitry Torokhov dev->overflowwarn = 1; 292*b5da20f8SDmitry Torokhov } 293*b5da20f8SDmitry Torokhov case -ECONNRESET: 294*b5da20f8SDmitry Torokhov case -ENOENT: 295*b5da20f8SDmitry Torokhov case -ESHUTDOWN: 296*b5da20f8SDmitry Torokhov /* This urb is terminated, clean up */ 297*b5da20f8SDmitry Torokhov dbg("%s - urb shutting down with status: %d", 298*b5da20f8SDmitry Torokhov __FUNCTION__, urb->status); 299*b5da20f8SDmitry Torokhov return; 300*b5da20f8SDmitry Torokhov default: 301*b5da20f8SDmitry Torokhov dbg("%s - nonzero urb status received: %d", 302*b5da20f8SDmitry Torokhov __FUNCTION__, urb->status); 303*b5da20f8SDmitry Torokhov goto exit; 304*b5da20f8SDmitry Torokhov } 305*b5da20f8SDmitry Torokhov 306*b5da20f8SDmitry Torokhov /* drop incomplete datasets */ 307*b5da20f8SDmitry Torokhov if (dev->urb->actual_length != dev->datalen) { 308*b5da20f8SDmitry Torokhov dprintk("appletouch: incomplete data package" 309*b5da20f8SDmitry Torokhov " (first byte: %d, length: %d).\n", 310*b5da20f8SDmitry Torokhov dev->data[0], dev->urb->actual_length); 311*b5da20f8SDmitry Torokhov goto exit; 312*b5da20f8SDmitry Torokhov } 313*b5da20f8SDmitry Torokhov 314*b5da20f8SDmitry Torokhov /* reorder the sensors values */ 315*b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) { 316*b5da20f8SDmitry Torokhov memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); 317*b5da20f8SDmitry Torokhov 318*b5da20f8SDmitry Torokhov /* 319*b5da20f8SDmitry Torokhov * The values are laid out like this: 320*b5da20f8SDmitry Torokhov * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... 321*b5da20f8SDmitry Torokhov * '-' is an unused value. 322*b5da20f8SDmitry Torokhov */ 323*b5da20f8SDmitry Torokhov 324*b5da20f8SDmitry Torokhov /* read X values */ 325*b5da20f8SDmitry Torokhov for (i = 0, j = 19; i < 20; i += 2, j += 3) { 326*b5da20f8SDmitry Torokhov dev->xy_cur[i] = dev->data[j + 1]; 327*b5da20f8SDmitry Torokhov dev->xy_cur[i + 1] = dev->data[j + 2]; 328*b5da20f8SDmitry Torokhov } 329*b5da20f8SDmitry Torokhov /* read Y values */ 330*b5da20f8SDmitry Torokhov for (i = 0, j = 1; i < 9; i += 2, j += 3) { 331*b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; 332*b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; 333*b5da20f8SDmitry Torokhov } 334*b5da20f8SDmitry Torokhov } else if (atp_is_geyser_2(dev)) { 335*b5da20f8SDmitry Torokhov memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); 336*b5da20f8SDmitry Torokhov 337*b5da20f8SDmitry Torokhov /* 338*b5da20f8SDmitry Torokhov * The values are laid out like this: 339*b5da20f8SDmitry Torokhov * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ... 340*b5da20f8SDmitry Torokhov * '-' is an unused value. 341*b5da20f8SDmitry Torokhov */ 342*b5da20f8SDmitry Torokhov 343*b5da20f8SDmitry Torokhov /* read X values */ 344*b5da20f8SDmitry Torokhov for (i = 0, j = 19; i < 20; i += 2, j += 3) { 345*b5da20f8SDmitry Torokhov dev->xy_cur[i] = dev->data[j]; 346*b5da20f8SDmitry Torokhov dev->xy_cur[i + 1] = dev->data[j + 1]; 347*b5da20f8SDmitry Torokhov } 348*b5da20f8SDmitry Torokhov 349*b5da20f8SDmitry Torokhov /* read Y values */ 350*b5da20f8SDmitry Torokhov for (i = 0, j = 1; i < 9; i += 2, j += 3) { 351*b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i] = dev->data[j]; 352*b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1]; 353*b5da20f8SDmitry Torokhov } 354*b5da20f8SDmitry Torokhov } else { 355*b5da20f8SDmitry Torokhov for (i = 0; i < 8; i++) { 356*b5da20f8SDmitry Torokhov /* X values */ 357*b5da20f8SDmitry Torokhov dev->xy_cur[i ] = dev->data[5 * i + 2]; 358*b5da20f8SDmitry Torokhov dev->xy_cur[i + 8] = dev->data[5 * i + 4]; 359*b5da20f8SDmitry Torokhov dev->xy_cur[i + 16] = dev->data[5 * i + 42]; 360*b5da20f8SDmitry Torokhov if (i < 2) 361*b5da20f8SDmitry Torokhov dev->xy_cur[i + 24] = dev->data[5 * i + 44]; 362*b5da20f8SDmitry Torokhov 363*b5da20f8SDmitry Torokhov /* Y values */ 364*b5da20f8SDmitry Torokhov dev->xy_cur[i + 26] = dev->data[5 * i + 1]; 365*b5da20f8SDmitry Torokhov dev->xy_cur[i + 34] = dev->data[5 * i + 3]; 366*b5da20f8SDmitry Torokhov } 367*b5da20f8SDmitry Torokhov } 368*b5da20f8SDmitry Torokhov 369*b5da20f8SDmitry Torokhov dbg_dump("sample", dev->xy_cur); 370*b5da20f8SDmitry Torokhov 371*b5da20f8SDmitry Torokhov if (!dev->valid) { 372*b5da20f8SDmitry Torokhov /* first sample */ 373*b5da20f8SDmitry Torokhov dev->valid = 1; 374*b5da20f8SDmitry Torokhov dev->x_old = dev->y_old = -1; 375*b5da20f8SDmitry Torokhov memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 376*b5da20f8SDmitry Torokhov 377*b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */ 378*b5da20f8SDmitry Torokhov goto exit; 379*b5da20f8SDmitry Torokhov 380*b5da20f8SDmitry Torokhov /* 17" Powerbooks have extra X sensors */ 381*b5da20f8SDmitry Torokhov for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { 382*b5da20f8SDmitry Torokhov if (!dev->xy_cur[i]) continue; 383*b5da20f8SDmitry Torokhov 384*b5da20f8SDmitry Torokhov printk("appletouch: 17\" model detected.\n"); 385*b5da20f8SDmitry Torokhov if(atp_is_geyser_2(dev)) 386*b5da20f8SDmitry Torokhov input_set_abs_params(dev->input, ABS_X, 0, 387*b5da20f8SDmitry Torokhov (20 - 1) * 388*b5da20f8SDmitry Torokhov ATP_XFACT - 1, 389*b5da20f8SDmitry Torokhov ATP_FUZZ, 0); 390*b5da20f8SDmitry Torokhov else 391*b5da20f8SDmitry Torokhov input_set_abs_params(dev->input, ABS_X, 0, 392*b5da20f8SDmitry Torokhov (ATP_XSENSORS - 1) * 393*b5da20f8SDmitry Torokhov ATP_XFACT - 1, 394*b5da20f8SDmitry Torokhov ATP_FUZZ, 0); 395*b5da20f8SDmitry Torokhov 396*b5da20f8SDmitry Torokhov break; 397*b5da20f8SDmitry Torokhov } 398*b5da20f8SDmitry Torokhov 399*b5da20f8SDmitry Torokhov goto exit; 400*b5da20f8SDmitry Torokhov } 401*b5da20f8SDmitry Torokhov 402*b5da20f8SDmitry Torokhov for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { 403*b5da20f8SDmitry Torokhov /* accumulate the change */ 404*b5da20f8SDmitry Torokhov signed char change = dev->xy_old[i] - dev->xy_cur[i]; 405*b5da20f8SDmitry Torokhov dev->xy_acc[i] -= change; 406*b5da20f8SDmitry Torokhov 407*b5da20f8SDmitry Torokhov /* prevent down drifting */ 408*b5da20f8SDmitry Torokhov if (dev->xy_acc[i] < 0) 409*b5da20f8SDmitry Torokhov dev->xy_acc[i] = 0; 410*b5da20f8SDmitry Torokhov } 411*b5da20f8SDmitry Torokhov 412*b5da20f8SDmitry Torokhov memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 413*b5da20f8SDmitry Torokhov 414*b5da20f8SDmitry Torokhov dbg_dump("accumulator", dev->xy_acc); 415*b5da20f8SDmitry Torokhov 416*b5da20f8SDmitry Torokhov x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, 417*b5da20f8SDmitry Torokhov ATP_XFACT, &x_z, &x_f); 418*b5da20f8SDmitry Torokhov y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, 419*b5da20f8SDmitry Torokhov ATP_YFACT, &y_z, &y_f); 420*b5da20f8SDmitry Torokhov 421*b5da20f8SDmitry Torokhov if (x && y) { 422*b5da20f8SDmitry Torokhov if (dev->x_old != -1) { 423*b5da20f8SDmitry Torokhov x = (dev->x_old * 3 + x) >> 2; 424*b5da20f8SDmitry Torokhov y = (dev->y_old * 3 + y) >> 2; 425*b5da20f8SDmitry Torokhov dev->x_old = x; 426*b5da20f8SDmitry Torokhov dev->y_old = y; 427*b5da20f8SDmitry Torokhov 428*b5da20f8SDmitry Torokhov if (debug > 1) 429*b5da20f8SDmitry Torokhov printk("appletouch: X: %3d Y: %3d " 430*b5da20f8SDmitry Torokhov "Xz: %3d Yz: %3d\n", 431*b5da20f8SDmitry Torokhov x, y, x_z, y_z); 432*b5da20f8SDmitry Torokhov 433*b5da20f8SDmitry Torokhov input_report_key(dev->input, BTN_TOUCH, 1); 434*b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_X, x); 435*b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_Y, y); 436*b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_PRESSURE, 437*b5da20f8SDmitry Torokhov min(ATP_PRESSURE, x_z + y_z)); 438*b5da20f8SDmitry Torokhov atp_report_fingers(dev->input, max(x_f, y_f)); 439*b5da20f8SDmitry Torokhov } 440*b5da20f8SDmitry Torokhov dev->x_old = x; 441*b5da20f8SDmitry Torokhov dev->y_old = y; 442*b5da20f8SDmitry Torokhov } 443*b5da20f8SDmitry Torokhov else if (!x && !y) { 444*b5da20f8SDmitry Torokhov 445*b5da20f8SDmitry Torokhov dev->x_old = dev->y_old = -1; 446*b5da20f8SDmitry Torokhov input_report_key(dev->input, BTN_TOUCH, 0); 447*b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_PRESSURE, 0); 448*b5da20f8SDmitry Torokhov atp_report_fingers(dev->input, 0); 449*b5da20f8SDmitry Torokhov 450*b5da20f8SDmitry Torokhov /* reset the accumulator on release */ 451*b5da20f8SDmitry Torokhov memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); 452*b5da20f8SDmitry Torokhov } 453*b5da20f8SDmitry Torokhov 454*b5da20f8SDmitry Torokhov input_report_key(dev->input, BTN_LEFT, 455*b5da20f8SDmitry Torokhov !!dev->data[dev->datalen - 1]); 456*b5da20f8SDmitry Torokhov 457*b5da20f8SDmitry Torokhov input_sync(dev->input); 458*b5da20f8SDmitry Torokhov 459*b5da20f8SDmitry Torokhov exit: 460*b5da20f8SDmitry Torokhov retval = usb_submit_urb(dev->urb, GFP_ATOMIC); 461*b5da20f8SDmitry Torokhov if (retval) { 462*b5da20f8SDmitry Torokhov err("%s - usb_submit_urb failed with result %d", 463*b5da20f8SDmitry Torokhov __FUNCTION__, retval); 464*b5da20f8SDmitry Torokhov } 465*b5da20f8SDmitry Torokhov } 466*b5da20f8SDmitry Torokhov 467*b5da20f8SDmitry Torokhov static int atp_open(struct input_dev *input) 468*b5da20f8SDmitry Torokhov { 469*b5da20f8SDmitry Torokhov struct atp *dev = input_get_drvdata(input); 470*b5da20f8SDmitry Torokhov 471*b5da20f8SDmitry Torokhov if (usb_submit_urb(dev->urb, GFP_ATOMIC)) 472*b5da20f8SDmitry Torokhov return -EIO; 473*b5da20f8SDmitry Torokhov 474*b5da20f8SDmitry Torokhov dev->open = 1; 475*b5da20f8SDmitry Torokhov return 0; 476*b5da20f8SDmitry Torokhov } 477*b5da20f8SDmitry Torokhov 478*b5da20f8SDmitry Torokhov static void atp_close(struct input_dev *input) 479*b5da20f8SDmitry Torokhov { 480*b5da20f8SDmitry Torokhov struct atp *dev = input_get_drvdata(input); 481*b5da20f8SDmitry Torokhov 482*b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 483*b5da20f8SDmitry Torokhov dev->open = 0; 484*b5da20f8SDmitry Torokhov } 485*b5da20f8SDmitry Torokhov 486*b5da20f8SDmitry Torokhov static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) 487*b5da20f8SDmitry Torokhov { 488*b5da20f8SDmitry Torokhov struct atp *dev; 489*b5da20f8SDmitry Torokhov struct input_dev *input_dev; 490*b5da20f8SDmitry Torokhov struct usb_device *udev = interface_to_usbdev(iface); 491*b5da20f8SDmitry Torokhov struct usb_host_interface *iface_desc; 492*b5da20f8SDmitry Torokhov struct usb_endpoint_descriptor *endpoint; 493*b5da20f8SDmitry Torokhov int int_in_endpointAddr = 0; 494*b5da20f8SDmitry Torokhov int i, error = -ENOMEM; 495*b5da20f8SDmitry Torokhov 496*b5da20f8SDmitry Torokhov /* set up the endpoint information */ 497*b5da20f8SDmitry Torokhov /* use only the first interrupt-in endpoint */ 498*b5da20f8SDmitry Torokhov iface_desc = iface->cur_altsetting; 499*b5da20f8SDmitry Torokhov for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { 500*b5da20f8SDmitry Torokhov endpoint = &iface_desc->endpoint[i].desc; 501*b5da20f8SDmitry Torokhov if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { 502*b5da20f8SDmitry Torokhov /* we found an interrupt in endpoint */ 503*b5da20f8SDmitry Torokhov int_in_endpointAddr = endpoint->bEndpointAddress; 504*b5da20f8SDmitry Torokhov break; 505*b5da20f8SDmitry Torokhov } 506*b5da20f8SDmitry Torokhov } 507*b5da20f8SDmitry Torokhov if (!int_in_endpointAddr) { 508*b5da20f8SDmitry Torokhov err("Could not find int-in endpoint"); 509*b5da20f8SDmitry Torokhov return -EIO; 510*b5da20f8SDmitry Torokhov } 511*b5da20f8SDmitry Torokhov 512*b5da20f8SDmitry Torokhov /* allocate memory for our device state and initialize it */ 513*b5da20f8SDmitry Torokhov dev = kzalloc(sizeof(struct atp), GFP_KERNEL); 514*b5da20f8SDmitry Torokhov input_dev = input_allocate_device(); 515*b5da20f8SDmitry Torokhov if (!dev || !input_dev) { 516*b5da20f8SDmitry Torokhov err("Out of memory"); 517*b5da20f8SDmitry Torokhov goto err_free_devs; 518*b5da20f8SDmitry Torokhov } 519*b5da20f8SDmitry Torokhov 520*b5da20f8SDmitry Torokhov dev->udev = udev; 521*b5da20f8SDmitry Torokhov dev->input = input_dev; 522*b5da20f8SDmitry Torokhov dev->overflowwarn = 0; 523*b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) 524*b5da20f8SDmitry Torokhov dev->datalen = 64; 525*b5da20f8SDmitry Torokhov else if (atp_is_geyser_2(dev)) 526*b5da20f8SDmitry Torokhov dev->datalen = 64; 527*b5da20f8SDmitry Torokhov else 528*b5da20f8SDmitry Torokhov dev->datalen = 81; 529*b5da20f8SDmitry Torokhov 530*b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) { 531*b5da20f8SDmitry Torokhov /* 532*b5da20f8SDmitry Torokhov * By default Geyser 3 device sends standard USB HID mouse 533*b5da20f8SDmitry Torokhov * packets (Report ID 2). This code changes device mode, so it 534*b5da20f8SDmitry Torokhov * sends raw sensor reports (Report ID 5). 535*b5da20f8SDmitry Torokhov */ 536*b5da20f8SDmitry Torokhov char data[8]; 537*b5da20f8SDmitry Torokhov int size; 538*b5da20f8SDmitry Torokhov 539*b5da20f8SDmitry Torokhov size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 540*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_READ_REQUEST_ID, 541*b5da20f8SDmitry Torokhov USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 542*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_REQUEST_VALUE, 543*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); 544*b5da20f8SDmitry Torokhov 545*b5da20f8SDmitry Torokhov if (size != 8) { 546*b5da20f8SDmitry Torokhov err("Could not do mode read request from device" 547*b5da20f8SDmitry Torokhov " (Geyser 3 mode)"); 548*b5da20f8SDmitry Torokhov goto err_free_devs; 549*b5da20f8SDmitry Torokhov } 550*b5da20f8SDmitry Torokhov 551*b5da20f8SDmitry Torokhov /* Apply the mode switch */ 552*b5da20f8SDmitry Torokhov data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE; 553*b5da20f8SDmitry Torokhov 554*b5da20f8SDmitry Torokhov size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 555*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_WRITE_REQUEST_ID, 556*b5da20f8SDmitry Torokhov USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 557*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_REQUEST_VALUE, 558*b5da20f8SDmitry Torokhov ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); 559*b5da20f8SDmitry Torokhov 560*b5da20f8SDmitry Torokhov if (size != 8) { 561*b5da20f8SDmitry Torokhov err("Could not do mode write request to device" 562*b5da20f8SDmitry Torokhov " (Geyser 3 mode)"); 563*b5da20f8SDmitry Torokhov goto err_free_devs; 564*b5da20f8SDmitry Torokhov } 565*b5da20f8SDmitry Torokhov printk("appletouch Geyser 3 inited.\n"); 566*b5da20f8SDmitry Torokhov } 567*b5da20f8SDmitry Torokhov 568*b5da20f8SDmitry Torokhov dev->urb = usb_alloc_urb(0, GFP_KERNEL); 569*b5da20f8SDmitry Torokhov if (!dev->urb) 570*b5da20f8SDmitry Torokhov goto err_free_devs; 571*b5da20f8SDmitry Torokhov 572*b5da20f8SDmitry Torokhov dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, 573*b5da20f8SDmitry Torokhov &dev->urb->transfer_dma); 574*b5da20f8SDmitry Torokhov if (!dev->data) 575*b5da20f8SDmitry Torokhov goto err_free_urb; 576*b5da20f8SDmitry Torokhov 577*b5da20f8SDmitry Torokhov usb_fill_int_urb(dev->urb, udev, 578*b5da20f8SDmitry Torokhov usb_rcvintpipe(udev, int_in_endpointAddr), 579*b5da20f8SDmitry Torokhov dev->data, dev->datalen, atp_complete, dev, 1); 580*b5da20f8SDmitry Torokhov 581*b5da20f8SDmitry Torokhov usb_make_path(udev, dev->phys, sizeof(dev->phys)); 582*b5da20f8SDmitry Torokhov strlcat(dev->phys, "/input0", sizeof(dev->phys)); 583*b5da20f8SDmitry Torokhov 584*b5da20f8SDmitry Torokhov input_dev->name = "appletouch"; 585*b5da20f8SDmitry Torokhov input_dev->phys = dev->phys; 586*b5da20f8SDmitry Torokhov usb_to_input_id(dev->udev, &input_dev->id); 587*b5da20f8SDmitry Torokhov input_dev->dev.parent = &iface->dev; 588*b5da20f8SDmitry Torokhov 589*b5da20f8SDmitry Torokhov input_set_drvdata(input_dev, dev); 590*b5da20f8SDmitry Torokhov 591*b5da20f8SDmitry Torokhov input_dev->open = atp_open; 592*b5da20f8SDmitry Torokhov input_dev->close = atp_close; 593*b5da20f8SDmitry Torokhov 594*b5da20f8SDmitry Torokhov set_bit(EV_ABS, input_dev->evbit); 595*b5da20f8SDmitry Torokhov 596*b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) { 597*b5da20f8SDmitry Torokhov /* 598*b5da20f8SDmitry Torokhov * MacBook have 20 X sensors, 10 Y sensors 599*b5da20f8SDmitry Torokhov */ 600*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 601*b5da20f8SDmitry Torokhov ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); 602*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 603*b5da20f8SDmitry Torokhov ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); 604*b5da20f8SDmitry Torokhov } else if (atp_is_geyser_2(dev)) { 605*b5da20f8SDmitry Torokhov /* 606*b5da20f8SDmitry Torokhov * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected 607*b5da20f8SDmitry Torokhov * later. 608*b5da20f8SDmitry Torokhov */ 609*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 610*b5da20f8SDmitry Torokhov ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); 611*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 612*b5da20f8SDmitry Torokhov ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); 613*b5da20f8SDmitry Torokhov } else { 614*b5da20f8SDmitry Torokhov /* 615*b5da20f8SDmitry Torokhov * 12" and 15" Powerbooks only have 16 x sensors, 616*b5da20f8SDmitry Torokhov * 17" models are detected later. 617*b5da20f8SDmitry Torokhov */ 618*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 619*b5da20f8SDmitry Torokhov (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); 620*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 621*b5da20f8SDmitry Torokhov (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); 622*b5da20f8SDmitry Torokhov } 623*b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); 624*b5da20f8SDmitry Torokhov 625*b5da20f8SDmitry Torokhov set_bit(EV_KEY, input_dev->evbit); 626*b5da20f8SDmitry Torokhov set_bit(BTN_TOUCH, input_dev->keybit); 627*b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_FINGER, input_dev->keybit); 628*b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); 629*b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); 630*b5da20f8SDmitry Torokhov set_bit(BTN_LEFT, input_dev->keybit); 631*b5da20f8SDmitry Torokhov 632*b5da20f8SDmitry Torokhov error = input_register_device(dev->input); 633*b5da20f8SDmitry Torokhov if (error) 634*b5da20f8SDmitry Torokhov goto err_free_buffer; 635*b5da20f8SDmitry Torokhov 636*b5da20f8SDmitry Torokhov /* save our data pointer in this interface device */ 637*b5da20f8SDmitry Torokhov usb_set_intfdata(iface, dev); 638*b5da20f8SDmitry Torokhov 639*b5da20f8SDmitry Torokhov return 0; 640*b5da20f8SDmitry Torokhov 641*b5da20f8SDmitry Torokhov err_free_buffer: 642*b5da20f8SDmitry Torokhov usb_buffer_free(dev->udev, dev->datalen, 643*b5da20f8SDmitry Torokhov dev->data, dev->urb->transfer_dma); 644*b5da20f8SDmitry Torokhov err_free_urb: 645*b5da20f8SDmitry Torokhov usb_free_urb(dev->urb); 646*b5da20f8SDmitry Torokhov err_free_devs: 647*b5da20f8SDmitry Torokhov usb_set_intfdata(iface, NULL); 648*b5da20f8SDmitry Torokhov kfree(dev); 649*b5da20f8SDmitry Torokhov input_free_device(input_dev); 650*b5da20f8SDmitry Torokhov return error; 651*b5da20f8SDmitry Torokhov } 652*b5da20f8SDmitry Torokhov 653*b5da20f8SDmitry Torokhov static void atp_disconnect(struct usb_interface *iface) 654*b5da20f8SDmitry Torokhov { 655*b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 656*b5da20f8SDmitry Torokhov 657*b5da20f8SDmitry Torokhov usb_set_intfdata(iface, NULL); 658*b5da20f8SDmitry Torokhov if (dev) { 659*b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 660*b5da20f8SDmitry Torokhov input_unregister_device(dev->input); 661*b5da20f8SDmitry Torokhov usb_buffer_free(dev->udev, dev->datalen, 662*b5da20f8SDmitry Torokhov dev->data, dev->urb->transfer_dma); 663*b5da20f8SDmitry Torokhov usb_free_urb(dev->urb); 664*b5da20f8SDmitry Torokhov kfree(dev); 665*b5da20f8SDmitry Torokhov } 666*b5da20f8SDmitry Torokhov printk(KERN_INFO "input: appletouch disconnected\n"); 667*b5da20f8SDmitry Torokhov } 668*b5da20f8SDmitry Torokhov 669*b5da20f8SDmitry Torokhov static int atp_suspend(struct usb_interface *iface, pm_message_t message) 670*b5da20f8SDmitry Torokhov { 671*b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 672*b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 673*b5da20f8SDmitry Torokhov dev->valid = 0; 674*b5da20f8SDmitry Torokhov return 0; 675*b5da20f8SDmitry Torokhov } 676*b5da20f8SDmitry Torokhov 677*b5da20f8SDmitry Torokhov static int atp_resume(struct usb_interface *iface) 678*b5da20f8SDmitry Torokhov { 679*b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 680*b5da20f8SDmitry Torokhov if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC)) 681*b5da20f8SDmitry Torokhov return -EIO; 682*b5da20f8SDmitry Torokhov 683*b5da20f8SDmitry Torokhov return 0; 684*b5da20f8SDmitry Torokhov } 685*b5da20f8SDmitry Torokhov 686*b5da20f8SDmitry Torokhov static struct usb_driver atp_driver = { 687*b5da20f8SDmitry Torokhov .name = "appletouch", 688*b5da20f8SDmitry Torokhov .probe = atp_probe, 689*b5da20f8SDmitry Torokhov .disconnect = atp_disconnect, 690*b5da20f8SDmitry Torokhov .suspend = atp_suspend, 691*b5da20f8SDmitry Torokhov .resume = atp_resume, 692*b5da20f8SDmitry Torokhov .id_table = atp_table, 693*b5da20f8SDmitry Torokhov }; 694*b5da20f8SDmitry Torokhov 695*b5da20f8SDmitry Torokhov static int __init atp_init(void) 696*b5da20f8SDmitry Torokhov { 697*b5da20f8SDmitry Torokhov return usb_register(&atp_driver); 698*b5da20f8SDmitry Torokhov } 699*b5da20f8SDmitry Torokhov 700*b5da20f8SDmitry Torokhov static void __exit atp_exit(void) 701*b5da20f8SDmitry Torokhov { 702*b5da20f8SDmitry Torokhov usb_deregister(&atp_driver); 703*b5da20f8SDmitry Torokhov } 704*b5da20f8SDmitry Torokhov 705*b5da20f8SDmitry Torokhov module_init(atp_init); 706*b5da20f8SDmitry Torokhov module_exit(atp_exit); 707