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