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 65*0035a1dcSTobias Mueller #define GEYSER4_HF_ANSI_PRODUCT_ID 0x0229 66*0035a1dcSTobias Mueller #define GEYSER4_HF_ISO_PRODUCT_ID 0x022A 67*0035a1dcSTobias Mueller #define GEYSER4_HF_JIS_PRODUCT_ID 0x022B 68*0035a1dcSTobias Mueller 69b5da20f8SDmitry Torokhov #define ATP_DEVICE(prod) \ 70b5da20f8SDmitry Torokhov .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 71b5da20f8SDmitry Torokhov USB_DEVICE_ID_MATCH_INT_CLASS | \ 72b5da20f8SDmitry Torokhov USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ 73b5da20f8SDmitry Torokhov .idVendor = APPLE_VENDOR_ID, \ 74b5da20f8SDmitry Torokhov .idProduct = (prod), \ 75b5da20f8SDmitry Torokhov .bInterfaceClass = 0x03, \ 76b5da20f8SDmitry Torokhov .bInterfaceProtocol = 0x02 77b5da20f8SDmitry Torokhov 78b5da20f8SDmitry Torokhov /* table of devices that work with this driver */ 79b5da20f8SDmitry Torokhov static struct usb_device_id atp_table [] = { 80b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) }, 81b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) }, 82b5da20f8SDmitry Torokhov { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) }, 83b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) }, 84b5da20f8SDmitry Torokhov 85b5da20f8SDmitry Torokhov /* PowerBooks Oct 2005 */ 86b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) }, 87b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, 88b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, 89b5da20f8SDmitry Torokhov 90b5da20f8SDmitry Torokhov /* Core Duo MacBook & MacBook Pro */ 91b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, 92b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, 93b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, 94b5da20f8SDmitry Torokhov 95b5da20f8SDmitry Torokhov /* Core2 Duo MacBook & MacBook Pro */ 96b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) }, 97b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, 98b5da20f8SDmitry Torokhov { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, 99b5da20f8SDmitry Torokhov 100*0035a1dcSTobias Mueller { ATP_DEVICE(GEYSER4_HF_ANSI_PRODUCT_ID) }, 101*0035a1dcSTobias Mueller { ATP_DEVICE(GEYSER4_HF_ISO_PRODUCT_ID) }, 102*0035a1dcSTobias Mueller { ATP_DEVICE(GEYSER4_HF_JIS_PRODUCT_ID) }, 103*0035a1dcSTobias Mueller 104b5da20f8SDmitry Torokhov /* Terminating entry */ 105b5da20f8SDmitry Torokhov { } 106b5da20f8SDmitry Torokhov }; 107b5da20f8SDmitry Torokhov MODULE_DEVICE_TABLE (usb, atp_table); 108b5da20f8SDmitry Torokhov 109b5da20f8SDmitry Torokhov /* 110b5da20f8SDmitry Torokhov * number of sensors. Note that only 16 instead of 26 X (horizontal) 111b5da20f8SDmitry Torokhov * sensors exist on 12" and 15" PowerBooks. All models have 16 Y 112b5da20f8SDmitry Torokhov * (vertical) sensors. 113b5da20f8SDmitry Torokhov */ 114b5da20f8SDmitry Torokhov #define ATP_XSENSORS 26 115b5da20f8SDmitry Torokhov #define ATP_YSENSORS 16 116b5da20f8SDmitry Torokhov 117b5da20f8SDmitry Torokhov /* amount of fuzz this touchpad generates */ 118b5da20f8SDmitry Torokhov #define ATP_FUZZ 16 119b5da20f8SDmitry Torokhov 120b5da20f8SDmitry Torokhov /* maximum pressure this driver will report */ 121b5da20f8SDmitry Torokhov #define ATP_PRESSURE 300 122b5da20f8SDmitry Torokhov /* 123b5da20f8SDmitry Torokhov * multiplication factor for the X and Y coordinates. 124b5da20f8SDmitry Torokhov * We try to keep the touchpad aspect ratio while still doing only simple 125b5da20f8SDmitry Torokhov * arithmetics. 126b5da20f8SDmitry Torokhov * The factors below give coordinates like: 127b5da20f8SDmitry Torokhov * 0 <= x < 960 on 12" and 15" Powerbooks 128b5da20f8SDmitry Torokhov * 0 <= x < 1600 on 17" Powerbooks 129b5da20f8SDmitry Torokhov * 0 <= y < 646 130b5da20f8SDmitry Torokhov */ 131b5da20f8SDmitry Torokhov #define ATP_XFACT 64 132b5da20f8SDmitry Torokhov #define ATP_YFACT 43 133b5da20f8SDmitry Torokhov 134b5da20f8SDmitry Torokhov /* 135b5da20f8SDmitry Torokhov * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is 136b5da20f8SDmitry Torokhov * ignored. 137b5da20f8SDmitry Torokhov */ 138b5da20f8SDmitry Torokhov #define ATP_THRESHOLD 5 139b5da20f8SDmitry Torokhov 1402a3e480dSDmitry Torokhov /* Geyser initialization constants */ 1412a3e480dSDmitry Torokhov #define ATP_GEYSER_MODE_READ_REQUEST_ID 1 1422a3e480dSDmitry Torokhov #define ATP_GEYSER_MODE_WRITE_REQUEST_ID 9 1432a3e480dSDmitry Torokhov #define ATP_GEYSER_MODE_REQUEST_VALUE 0x300 1442a3e480dSDmitry Torokhov #define ATP_GEYSER_MODE_REQUEST_INDEX 0 1452a3e480dSDmitry Torokhov #define ATP_GEYSER_MODE_VENDOR_VALUE 0x04 146b5da20f8SDmitry Torokhov 147b5da20f8SDmitry Torokhov /* Structure to hold all of our device specific stuff */ 148b5da20f8SDmitry Torokhov struct atp { 149b5da20f8SDmitry Torokhov char phys[64]; 150b5da20f8SDmitry Torokhov struct usb_device * udev; /* usb device */ 151b5da20f8SDmitry Torokhov struct urb * urb; /* usb request block */ 152b5da20f8SDmitry Torokhov signed char * data; /* transferred data */ 153b5da20f8SDmitry Torokhov struct input_dev * input; /* input dev */ 1542a3e480dSDmitry Torokhov unsigned char open; /* non-zero if opened */ 1552a3e480dSDmitry Torokhov unsigned char valid; /* are the sensors valid ? */ 1562a3e480dSDmitry Torokhov unsigned char size_detect_done; 1572a3e480dSDmitry Torokhov unsigned char overflowwarn; /* overflow warning printed? */ 158b5da20f8SDmitry Torokhov int x_old; /* last reported x/y, */ 159b5da20f8SDmitry Torokhov int y_old; /* used for smoothing */ 160b5da20f8SDmitry Torokhov /* current value of the sensors */ 161b5da20f8SDmitry Torokhov signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; 162b5da20f8SDmitry Torokhov /* last value of the sensors */ 163b5da20f8SDmitry Torokhov signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; 164b5da20f8SDmitry Torokhov /* accumulated sensors */ 165b5da20f8SDmitry Torokhov int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; 166b5da20f8SDmitry Torokhov int datalen; /* size of an USB urb transfer */ 1675a6eb676SSoeren Sonnenburg int idlecount; /* number of empty packets */ 1685a6eb676SSoeren Sonnenburg struct work_struct work; 169b5da20f8SDmitry Torokhov }; 170b5da20f8SDmitry Torokhov 171b5da20f8SDmitry Torokhov #define dbg_dump(msg, tab) \ 172b5da20f8SDmitry Torokhov if (debug > 1) { \ 173b5da20f8SDmitry Torokhov int i; \ 174b5da20f8SDmitry Torokhov printk("appletouch: %s %lld", msg, (long long)jiffies); \ 175b5da20f8SDmitry Torokhov for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ 176b5da20f8SDmitry Torokhov printk(" %02x", tab[i]); \ 177b5da20f8SDmitry Torokhov printk("\n"); \ 178b5da20f8SDmitry Torokhov } 179b5da20f8SDmitry Torokhov 180b5da20f8SDmitry Torokhov #define dprintk(format, a...) \ 181b5da20f8SDmitry Torokhov do { \ 1822a3e480dSDmitry Torokhov if (debug) printk(KERN_DEBUG format, ##a); \ 183b5da20f8SDmitry Torokhov } while (0) 184b5da20f8SDmitry Torokhov 185b5da20f8SDmitry Torokhov MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); 186b5da20f8SDmitry Torokhov MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); 187b5da20f8SDmitry Torokhov MODULE_LICENSE("GPL"); 188b5da20f8SDmitry Torokhov 189b5da20f8SDmitry Torokhov /* 190b5da20f8SDmitry Torokhov * Make the threshold a module parameter 191b5da20f8SDmitry Torokhov */ 192b5da20f8SDmitry Torokhov static int threshold = ATP_THRESHOLD; 193b5da20f8SDmitry Torokhov module_param(threshold, int, 0644); 194b5da20f8SDmitry Torokhov MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value"); 195b5da20f8SDmitry Torokhov 196b5da20f8SDmitry Torokhov static int debug = 1; 197b5da20f8SDmitry Torokhov module_param(debug, int, 0644); 198b5da20f8SDmitry Torokhov MODULE_PARM_DESC(debug, "Activate debugging output"); 199b5da20f8SDmitry Torokhov 2002a3e480dSDmitry Torokhov static inline int atp_is_fountain(struct atp *dev) 2012a3e480dSDmitry Torokhov { 2022a3e480dSDmitry Torokhov u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); 2032a3e480dSDmitry Torokhov 2042a3e480dSDmitry Torokhov return productId == FOUNTAIN_ANSI_PRODUCT_ID || 2052a3e480dSDmitry Torokhov productId == FOUNTAIN_ISO_PRODUCT_ID || 2062a3e480dSDmitry Torokhov productId == FOUNTAIN_TP_ONLY_PRODUCT_ID; 2072a3e480dSDmitry Torokhov } 2082a3e480dSDmitry Torokhov 209b5da20f8SDmitry Torokhov /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ 210b5da20f8SDmitry Torokhov static inline int atp_is_geyser_2(struct atp *dev) 211b5da20f8SDmitry Torokhov { 212b5da20f8SDmitry Torokhov u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); 213b5da20f8SDmitry Torokhov 214b5da20f8SDmitry Torokhov return (productId == GEYSER_ANSI_PRODUCT_ID) || 215b5da20f8SDmitry Torokhov (productId == GEYSER_ISO_PRODUCT_ID) || 216b5da20f8SDmitry Torokhov (productId == GEYSER_JIS_PRODUCT_ID); 217b5da20f8SDmitry Torokhov } 218b5da20f8SDmitry Torokhov 219b5da20f8SDmitry Torokhov static inline int atp_is_geyser_3(struct atp *dev) 220b5da20f8SDmitry Torokhov { 221b5da20f8SDmitry Torokhov u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); 222b5da20f8SDmitry Torokhov 223b5da20f8SDmitry Torokhov return (productId == GEYSER3_ANSI_PRODUCT_ID) || 224b5da20f8SDmitry Torokhov (productId == GEYSER3_ISO_PRODUCT_ID) || 225b5da20f8SDmitry Torokhov (productId == GEYSER3_JIS_PRODUCT_ID) || 226b5da20f8SDmitry Torokhov (productId == GEYSER4_ANSI_PRODUCT_ID) || 227b5da20f8SDmitry Torokhov (productId == GEYSER4_ISO_PRODUCT_ID) || 228*0035a1dcSTobias Mueller (productId == GEYSER4_JIS_PRODUCT_ID) || 229*0035a1dcSTobias Mueller (productId == GEYSER4_HF_ANSI_PRODUCT_ID) || 230*0035a1dcSTobias Mueller (productId == GEYSER4_HF_ISO_PRODUCT_ID) || 231*0035a1dcSTobias Mueller (productId == GEYSER4_HF_JIS_PRODUCT_ID); 232b5da20f8SDmitry Torokhov } 233b5da20f8SDmitry Torokhov 2345a6eb676SSoeren Sonnenburg /* 2352a3e480dSDmitry Torokhov * By default newer Geyser devices send standard USB HID mouse 2365a6eb676SSoeren Sonnenburg * packets (Report ID 2). This code changes device mode, so it 2375a6eb676SSoeren Sonnenburg * sends raw sensor reports (Report ID 5). 2385a6eb676SSoeren Sonnenburg */ 2392a3e480dSDmitry Torokhov static int atp_geyser_init(struct usb_device *udev) 2405a6eb676SSoeren Sonnenburg { 2415a6eb676SSoeren Sonnenburg char data[8]; 2425a6eb676SSoeren Sonnenburg int size; 2435a6eb676SSoeren Sonnenburg 2445a6eb676SSoeren Sonnenburg size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 2452a3e480dSDmitry Torokhov ATP_GEYSER_MODE_READ_REQUEST_ID, 2465a6eb676SSoeren Sonnenburg USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 2472a3e480dSDmitry Torokhov ATP_GEYSER_MODE_REQUEST_VALUE, 2482a3e480dSDmitry Torokhov ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000); 2495a6eb676SSoeren Sonnenburg 2505a6eb676SSoeren Sonnenburg if (size != 8) { 2515a6eb676SSoeren Sonnenburg err("Could not do mode read request from device" 2522a3e480dSDmitry Torokhov " (Geyser Raw mode)"); 2535a6eb676SSoeren Sonnenburg return -EIO; 2545a6eb676SSoeren Sonnenburg } 2555a6eb676SSoeren Sonnenburg 2565a6eb676SSoeren Sonnenburg /* Apply the mode switch */ 2572a3e480dSDmitry Torokhov data[0] = ATP_GEYSER_MODE_VENDOR_VALUE; 2585a6eb676SSoeren Sonnenburg 2595a6eb676SSoeren Sonnenburg size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 2602a3e480dSDmitry Torokhov ATP_GEYSER_MODE_WRITE_REQUEST_ID, 2615a6eb676SSoeren Sonnenburg USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 2622a3e480dSDmitry Torokhov ATP_GEYSER_MODE_REQUEST_VALUE, 2632a3e480dSDmitry Torokhov ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000); 2645a6eb676SSoeren Sonnenburg 2655a6eb676SSoeren Sonnenburg if (size != 8) { 2665a6eb676SSoeren Sonnenburg err("Could not do mode write request to device" 2672a3e480dSDmitry Torokhov " (Geyser Raw mode)"); 2685a6eb676SSoeren Sonnenburg return -EIO; 2695a6eb676SSoeren Sonnenburg } 2705a6eb676SSoeren Sonnenburg return 0; 2715a6eb676SSoeren Sonnenburg } 2725a6eb676SSoeren Sonnenburg 2732a3e480dSDmitry Torokhov /* 2742a3e480dSDmitry Torokhov * Reinitialise the device. This usually stops stream of empty packets 2752a3e480dSDmitry Torokhov * coming from it. 2762a3e480dSDmitry Torokhov */ 2775a6eb676SSoeren Sonnenburg static void atp_reinit(struct work_struct *work) 2785a6eb676SSoeren Sonnenburg { 2795a6eb676SSoeren Sonnenburg struct atp *dev = container_of(work, struct atp, work); 2805a6eb676SSoeren Sonnenburg struct usb_device *udev = dev->udev; 2812a3e480dSDmitry Torokhov int retval; 2825a6eb676SSoeren Sonnenburg 2835a6eb676SSoeren Sonnenburg dev->idlecount = 0; 2842a3e480dSDmitry Torokhov 2852a3e480dSDmitry Torokhov atp_geyser_init(udev); 2862a3e480dSDmitry Torokhov 2872a3e480dSDmitry Torokhov retval = usb_submit_urb(dev->urb, GFP_ATOMIC); 2882a3e480dSDmitry Torokhov if (retval) { 2892a3e480dSDmitry Torokhov err("%s - usb_submit_urb failed with result %d", 2902a3e480dSDmitry Torokhov __FUNCTION__, retval); 2912a3e480dSDmitry Torokhov } 2925a6eb676SSoeren Sonnenburg } 2935a6eb676SSoeren Sonnenburg 294b5da20f8SDmitry Torokhov static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, 295b5da20f8SDmitry Torokhov int *z, int *fingers) 296b5da20f8SDmitry Torokhov { 297b5da20f8SDmitry Torokhov int i; 298b5da20f8SDmitry Torokhov /* values to calculate mean */ 299b5da20f8SDmitry Torokhov int pcum = 0, psum = 0; 300b5da20f8SDmitry Torokhov int is_increasing = 0; 301b5da20f8SDmitry Torokhov 302b5da20f8SDmitry Torokhov *fingers = 0; 303b5da20f8SDmitry Torokhov 304b5da20f8SDmitry Torokhov for (i = 0; i < nb_sensors; i++) { 305b5da20f8SDmitry Torokhov if (xy_sensors[i] < threshold) { 306b5da20f8SDmitry Torokhov if (is_increasing) 307b5da20f8SDmitry Torokhov is_increasing = 0; 308b5da20f8SDmitry Torokhov 309b5da20f8SDmitry Torokhov continue; 310b5da20f8SDmitry Torokhov } 311b5da20f8SDmitry Torokhov 312b5da20f8SDmitry Torokhov /* 313b5da20f8SDmitry Torokhov * Makes the finger detection more versatile. For example, 314b5da20f8SDmitry Torokhov * two fingers with no gap will be detected. Also, my 315b5da20f8SDmitry Torokhov * tests show it less likely to have intermittent loss 316b5da20f8SDmitry Torokhov * of multiple finger readings while moving around (scrolling). 317b5da20f8SDmitry Torokhov * 318b5da20f8SDmitry Torokhov * Changes the multiple finger detection to counting humps on 319b5da20f8SDmitry Torokhov * sensors (transitions from nonincreasing to increasing) 320b5da20f8SDmitry Torokhov * instead of counting transitions from low sensors (no 321b5da20f8SDmitry Torokhov * finger reading) to high sensors (finger above 322b5da20f8SDmitry Torokhov * sensor) 323b5da20f8SDmitry Torokhov * 324b5da20f8SDmitry Torokhov * - Jason Parekh <jasonparekh@gmail.com> 325b5da20f8SDmitry Torokhov */ 326b5da20f8SDmitry Torokhov if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { 327b5da20f8SDmitry Torokhov (*fingers)++; 328b5da20f8SDmitry Torokhov is_increasing = 1; 329b5da20f8SDmitry Torokhov } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { 330b5da20f8SDmitry Torokhov is_increasing = 0; 331b5da20f8SDmitry Torokhov } 332b5da20f8SDmitry Torokhov 333b5da20f8SDmitry Torokhov /* 334b5da20f8SDmitry Torokhov * Subtracts threshold so a high sensor that just passes the threshold 335b5da20f8SDmitry Torokhov * won't skew the calculated absolute coordinate. Fixes an issue 336b5da20f8SDmitry Torokhov * where slowly moving the mouse would occassionaly jump a number of 337b5da20f8SDmitry Torokhov * pixels (let me restate--slowly moving the mouse makes this issue 338b5da20f8SDmitry Torokhov * most apparent). 339b5da20f8SDmitry Torokhov */ 340b5da20f8SDmitry Torokhov pcum += (xy_sensors[i] - threshold) * i; 341b5da20f8SDmitry Torokhov psum += (xy_sensors[i] - threshold); 342b5da20f8SDmitry Torokhov } 343b5da20f8SDmitry Torokhov 344b5da20f8SDmitry Torokhov if (psum > 0) { 345b5da20f8SDmitry Torokhov *z = psum; 346b5da20f8SDmitry Torokhov return pcum * fact / psum; 347b5da20f8SDmitry Torokhov } 348b5da20f8SDmitry Torokhov 349b5da20f8SDmitry Torokhov return 0; 350b5da20f8SDmitry Torokhov } 351b5da20f8SDmitry Torokhov 352b5da20f8SDmitry Torokhov static inline void atp_report_fingers(struct input_dev *input, int fingers) 353b5da20f8SDmitry Torokhov { 354b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_FINGER, fingers == 1); 355b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2); 356b5da20f8SDmitry Torokhov input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); 357b5da20f8SDmitry Torokhov } 358b5da20f8SDmitry Torokhov 359b5da20f8SDmitry Torokhov static void atp_complete(struct urb* urb) 360b5da20f8SDmitry Torokhov { 361b5da20f8SDmitry Torokhov int x, y, x_z, y_z, x_f, y_f; 362b5da20f8SDmitry Torokhov int retval, i, j; 363cb560737SThomas Rohwer int key; 364b5da20f8SDmitry Torokhov struct atp *dev = urb->context; 365b5da20f8SDmitry Torokhov 366b5da20f8SDmitry Torokhov switch (urb->status) { 367b5da20f8SDmitry Torokhov case 0: 368b5da20f8SDmitry Torokhov /* success */ 369b5da20f8SDmitry Torokhov break; 370b5da20f8SDmitry Torokhov case -EOVERFLOW: 371b5da20f8SDmitry Torokhov if(!dev->overflowwarn) { 3722a3e480dSDmitry Torokhov printk(KERN_WARNING "appletouch: OVERFLOW with data " 373b5da20f8SDmitry Torokhov "length %d, actual length is %d\n", 374b5da20f8SDmitry Torokhov dev->datalen, dev->urb->actual_length); 375b5da20f8SDmitry Torokhov dev->overflowwarn = 1; 376b5da20f8SDmitry Torokhov } 377b5da20f8SDmitry Torokhov case -ECONNRESET: 378b5da20f8SDmitry Torokhov case -ENOENT: 379b5da20f8SDmitry Torokhov case -ESHUTDOWN: 380b5da20f8SDmitry Torokhov /* This urb is terminated, clean up */ 381b5da20f8SDmitry Torokhov dbg("%s - urb shutting down with status: %d", 382b5da20f8SDmitry Torokhov __FUNCTION__, urb->status); 383b5da20f8SDmitry Torokhov return; 384b5da20f8SDmitry Torokhov default: 385b5da20f8SDmitry Torokhov dbg("%s - nonzero urb status received: %d", 386b5da20f8SDmitry Torokhov __FUNCTION__, urb->status); 387b5da20f8SDmitry Torokhov goto exit; 388b5da20f8SDmitry Torokhov } 389b5da20f8SDmitry Torokhov 390b5da20f8SDmitry Torokhov /* drop incomplete datasets */ 391b5da20f8SDmitry Torokhov if (dev->urb->actual_length != dev->datalen) { 392b5da20f8SDmitry Torokhov dprintk("appletouch: incomplete data package" 393b5da20f8SDmitry Torokhov " (first byte: %d, length: %d).\n", 394b5da20f8SDmitry Torokhov dev->data[0], dev->urb->actual_length); 395b5da20f8SDmitry Torokhov goto exit; 396b5da20f8SDmitry Torokhov } 397b5da20f8SDmitry Torokhov 398b5da20f8SDmitry Torokhov /* reorder the sensors values */ 399b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) { 400b5da20f8SDmitry Torokhov memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); 401b5da20f8SDmitry Torokhov 402b5da20f8SDmitry Torokhov /* 403b5da20f8SDmitry Torokhov * The values are laid out like this: 404b5da20f8SDmitry Torokhov * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... 405b5da20f8SDmitry Torokhov * '-' is an unused value. 406b5da20f8SDmitry Torokhov */ 407b5da20f8SDmitry Torokhov 408b5da20f8SDmitry Torokhov /* read X values */ 409b5da20f8SDmitry Torokhov for (i = 0, j = 19; i < 20; i += 2, j += 3) { 410b5da20f8SDmitry Torokhov dev->xy_cur[i] = dev->data[j + 1]; 411b5da20f8SDmitry Torokhov dev->xy_cur[i + 1] = dev->data[j + 2]; 412b5da20f8SDmitry Torokhov } 413b5da20f8SDmitry Torokhov /* read Y values */ 414b5da20f8SDmitry Torokhov for (i = 0, j = 1; i < 9; i += 2, j += 3) { 415b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; 416b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; 417b5da20f8SDmitry Torokhov } 418b5da20f8SDmitry Torokhov } else if (atp_is_geyser_2(dev)) { 419b5da20f8SDmitry Torokhov memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); 420b5da20f8SDmitry Torokhov 421b5da20f8SDmitry Torokhov /* 422b5da20f8SDmitry Torokhov * The values are laid out like this: 423b5da20f8SDmitry Torokhov * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ... 424b5da20f8SDmitry Torokhov * '-' is an unused value. 425b5da20f8SDmitry Torokhov */ 426b5da20f8SDmitry Torokhov 427b5da20f8SDmitry Torokhov /* read X values */ 428b5da20f8SDmitry Torokhov for (i = 0, j = 19; i < 20; i += 2, j += 3) { 429b5da20f8SDmitry Torokhov dev->xy_cur[i] = dev->data[j]; 430b5da20f8SDmitry Torokhov dev->xy_cur[i + 1] = dev->data[j + 1]; 431b5da20f8SDmitry Torokhov } 432b5da20f8SDmitry Torokhov 433b5da20f8SDmitry Torokhov /* read Y values */ 434b5da20f8SDmitry Torokhov for (i = 0, j = 1; i < 9; i += 2, j += 3) { 435b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i] = dev->data[j]; 436b5da20f8SDmitry Torokhov dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1]; 437b5da20f8SDmitry Torokhov } 438b5da20f8SDmitry Torokhov } else { 439b5da20f8SDmitry Torokhov for (i = 0; i < 8; i++) { 440b5da20f8SDmitry Torokhov /* X values */ 441b5da20f8SDmitry Torokhov dev->xy_cur[i ] = dev->data[5 * i + 2]; 442b5da20f8SDmitry Torokhov dev->xy_cur[i + 8] = dev->data[5 * i + 4]; 443b5da20f8SDmitry Torokhov dev->xy_cur[i + 16] = dev->data[5 * i + 42]; 444b5da20f8SDmitry Torokhov if (i < 2) 445b5da20f8SDmitry Torokhov dev->xy_cur[i + 24] = dev->data[5 * i + 44]; 446b5da20f8SDmitry Torokhov 447b5da20f8SDmitry Torokhov /* Y values */ 448b5da20f8SDmitry Torokhov dev->xy_cur[i + 26] = dev->data[5 * i + 1]; 449b5da20f8SDmitry Torokhov dev->xy_cur[i + 34] = dev->data[5 * i + 3]; 450b5da20f8SDmitry Torokhov } 451b5da20f8SDmitry Torokhov } 452b5da20f8SDmitry Torokhov 453b5da20f8SDmitry Torokhov dbg_dump("sample", dev->xy_cur); 454b5da20f8SDmitry Torokhov 455b5da20f8SDmitry Torokhov if (!dev->valid) { 456b5da20f8SDmitry Torokhov /* first sample */ 457b5da20f8SDmitry Torokhov dev->valid = 1; 458b5da20f8SDmitry Torokhov dev->x_old = dev->y_old = -1; 459b5da20f8SDmitry Torokhov memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 460b5da20f8SDmitry Torokhov 4612a3e480dSDmitry Torokhov if (dev->size_detect_done || 4622a3e480dSDmitry Torokhov atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */ 463b5da20f8SDmitry Torokhov goto exit; 464b5da20f8SDmitry Torokhov 465b5da20f8SDmitry Torokhov /* 17" Powerbooks have extra X sensors */ 466b5da20f8SDmitry Torokhov for (i = (atp_is_geyser_2(dev) ? 15 : 16); i < ATP_XSENSORS; i++) { 4672a3e480dSDmitry Torokhov if (!dev->xy_cur[i]) 4682a3e480dSDmitry Torokhov continue; 469b5da20f8SDmitry Torokhov 4702a3e480dSDmitry Torokhov printk(KERN_INFO "appletouch: 17\" model detected.\n"); 471b5da20f8SDmitry Torokhov if (atp_is_geyser_2(dev)) 472b5da20f8SDmitry Torokhov input_set_abs_params(dev->input, ABS_X, 0, 473b5da20f8SDmitry Torokhov (20 - 1) * 474b5da20f8SDmitry Torokhov ATP_XFACT - 1, 475b5da20f8SDmitry Torokhov ATP_FUZZ, 0); 476b5da20f8SDmitry Torokhov else 477b5da20f8SDmitry Torokhov input_set_abs_params(dev->input, ABS_X, 0, 478b5da20f8SDmitry Torokhov (ATP_XSENSORS - 1) * 479b5da20f8SDmitry Torokhov ATP_XFACT - 1, 480b5da20f8SDmitry Torokhov ATP_FUZZ, 0); 481b5da20f8SDmitry Torokhov break; 482b5da20f8SDmitry Torokhov } 483b5da20f8SDmitry Torokhov 4842a3e480dSDmitry Torokhov dev->size_detect_done = 1; 485b5da20f8SDmitry Torokhov goto exit; 486b5da20f8SDmitry Torokhov } 487b5da20f8SDmitry Torokhov 488b5da20f8SDmitry Torokhov for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { 489b5da20f8SDmitry Torokhov /* accumulate the change */ 490b5da20f8SDmitry Torokhov signed char change = dev->xy_old[i] - dev->xy_cur[i]; 491b5da20f8SDmitry Torokhov dev->xy_acc[i] -= change; 492b5da20f8SDmitry Torokhov 493b5da20f8SDmitry Torokhov /* prevent down drifting */ 494b5da20f8SDmitry Torokhov if (dev->xy_acc[i] < 0) 495b5da20f8SDmitry Torokhov dev->xy_acc[i] = 0; 496b5da20f8SDmitry Torokhov } 497b5da20f8SDmitry Torokhov 498b5da20f8SDmitry Torokhov memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 499b5da20f8SDmitry Torokhov 500b5da20f8SDmitry Torokhov dbg_dump("accumulator", dev->xy_acc); 501b5da20f8SDmitry Torokhov 502b5da20f8SDmitry Torokhov x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, 503b5da20f8SDmitry Torokhov ATP_XFACT, &x_z, &x_f); 504b5da20f8SDmitry Torokhov y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, 505b5da20f8SDmitry Torokhov ATP_YFACT, &y_z, &y_f); 506cb560737SThomas Rohwer key = dev->data[dev->datalen - 1] & 1; 507b5da20f8SDmitry Torokhov 508b5da20f8SDmitry Torokhov if (x && y) { 509b5da20f8SDmitry Torokhov if (dev->x_old != -1) { 510b5da20f8SDmitry Torokhov x = (dev->x_old * 3 + x) >> 2; 511b5da20f8SDmitry Torokhov y = (dev->y_old * 3 + y) >> 2; 512b5da20f8SDmitry Torokhov dev->x_old = x; 513b5da20f8SDmitry Torokhov dev->y_old = y; 514b5da20f8SDmitry Torokhov 515b5da20f8SDmitry Torokhov if (debug > 1) 5162a3e480dSDmitry Torokhov printk(KERN_DEBUG "appletouch: X: %3d Y: %3d " 517b5da20f8SDmitry Torokhov "Xz: %3d Yz: %3d\n", 518b5da20f8SDmitry Torokhov x, y, x_z, y_z); 519b5da20f8SDmitry Torokhov 520b5da20f8SDmitry Torokhov input_report_key(dev->input, BTN_TOUCH, 1); 521b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_X, x); 522b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_Y, y); 523b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_PRESSURE, 524b5da20f8SDmitry Torokhov min(ATP_PRESSURE, x_z + y_z)); 525b5da20f8SDmitry Torokhov atp_report_fingers(dev->input, max(x_f, y_f)); 526b5da20f8SDmitry Torokhov } 527b5da20f8SDmitry Torokhov dev->x_old = x; 528b5da20f8SDmitry Torokhov dev->y_old = y; 5295a6eb676SSoeren Sonnenburg 5305a6eb676SSoeren Sonnenburg } else if (!x && !y) { 531b5da20f8SDmitry Torokhov 532b5da20f8SDmitry Torokhov dev->x_old = dev->y_old = -1; 533b5da20f8SDmitry Torokhov input_report_key(dev->input, BTN_TOUCH, 0); 534b5da20f8SDmitry Torokhov input_report_abs(dev->input, ABS_PRESSURE, 0); 535b5da20f8SDmitry Torokhov atp_report_fingers(dev->input, 0); 536b5da20f8SDmitry Torokhov 537b5da20f8SDmitry Torokhov /* reset the accumulator on release */ 538b5da20f8SDmitry Torokhov memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); 539937ad5c1SSoeren Sonnenburg } 5405a6eb676SSoeren Sonnenburg 54146249ea6SAnton Ekblad input_report_key(dev->input, BTN_LEFT, key); 54246249ea6SAnton Ekblad input_sync(dev->input); 54346249ea6SAnton Ekblad 5442a3e480dSDmitry Torokhov /* 5452a3e480dSDmitry Torokhov * Many Geysers will continue to send packets continually after 5462a3e480dSDmitry Torokhov * the first touch unless reinitialised. Do so if it's been 5472a3e480dSDmitry Torokhov * idle for a while in order to avoid waking the kernel up 5482a3e480dSDmitry Torokhov * several hundred times a second. Re-initialization does not 5492a3e480dSDmitry Torokhov * work on Fountain touchpads. 5502a3e480dSDmitry Torokhov */ 5512a3e480dSDmitry Torokhov if (!atp_is_fountain(dev)) { 552937ad5c1SSoeren Sonnenburg if (!x && !y && !key) { 5535a6eb676SSoeren Sonnenburg dev->idlecount++; 5545a6eb676SSoeren Sonnenburg if (dev->idlecount == 10) { 5555a6eb676SSoeren Sonnenburg dev->valid = 0; 5565a6eb676SSoeren Sonnenburg schedule_work(&dev->work); 5572a3e480dSDmitry Torokhov /* Don't resubmit urb here, wait for reinit */ 5582a3e480dSDmitry Torokhov return; 5595a6eb676SSoeren Sonnenburg } 56046249ea6SAnton Ekblad } else 561937ad5c1SSoeren Sonnenburg dev->idlecount = 0; 5622a3e480dSDmitry Torokhov } 563b5da20f8SDmitry Torokhov 564b5da20f8SDmitry Torokhov exit: 565b5da20f8SDmitry Torokhov retval = usb_submit_urb(dev->urb, GFP_ATOMIC); 566b5da20f8SDmitry Torokhov if (retval) { 567b5da20f8SDmitry Torokhov err("%s - usb_submit_urb failed with result %d", 568b5da20f8SDmitry Torokhov __FUNCTION__, retval); 569b5da20f8SDmitry Torokhov } 570b5da20f8SDmitry Torokhov } 571b5da20f8SDmitry Torokhov 572b5da20f8SDmitry Torokhov static int atp_open(struct input_dev *input) 573b5da20f8SDmitry Torokhov { 574b5da20f8SDmitry Torokhov struct atp *dev = input_get_drvdata(input); 575b5da20f8SDmitry Torokhov 576b5da20f8SDmitry Torokhov if (usb_submit_urb(dev->urb, GFP_ATOMIC)) 577b5da20f8SDmitry Torokhov return -EIO; 578b5da20f8SDmitry Torokhov 579b5da20f8SDmitry Torokhov dev->open = 1; 580b5da20f8SDmitry Torokhov return 0; 581b5da20f8SDmitry Torokhov } 582b5da20f8SDmitry Torokhov 583b5da20f8SDmitry Torokhov static void atp_close(struct input_dev *input) 584b5da20f8SDmitry Torokhov { 585b5da20f8SDmitry Torokhov struct atp *dev = input_get_drvdata(input); 586b5da20f8SDmitry Torokhov 587b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 5885a6eb676SSoeren Sonnenburg cancel_work_sync(&dev->work); 589b5da20f8SDmitry Torokhov dev->open = 0; 590b5da20f8SDmitry Torokhov } 591b5da20f8SDmitry Torokhov 592b5da20f8SDmitry Torokhov static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) 593b5da20f8SDmitry Torokhov { 594b5da20f8SDmitry Torokhov struct atp *dev; 595b5da20f8SDmitry Torokhov struct input_dev *input_dev; 596b5da20f8SDmitry Torokhov struct usb_device *udev = interface_to_usbdev(iface); 597b5da20f8SDmitry Torokhov struct usb_host_interface *iface_desc; 598b5da20f8SDmitry Torokhov struct usb_endpoint_descriptor *endpoint; 599b5da20f8SDmitry Torokhov int int_in_endpointAddr = 0; 600b5da20f8SDmitry Torokhov int i, error = -ENOMEM; 601b5da20f8SDmitry Torokhov 602b5da20f8SDmitry Torokhov /* set up the endpoint information */ 603b5da20f8SDmitry Torokhov /* use only the first interrupt-in endpoint */ 604b5da20f8SDmitry Torokhov iface_desc = iface->cur_altsetting; 605b5da20f8SDmitry Torokhov for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { 606b5da20f8SDmitry Torokhov endpoint = &iface_desc->endpoint[i].desc; 607b5da20f8SDmitry Torokhov if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { 608b5da20f8SDmitry Torokhov /* we found an interrupt in endpoint */ 609b5da20f8SDmitry Torokhov int_in_endpointAddr = endpoint->bEndpointAddress; 610b5da20f8SDmitry Torokhov break; 611b5da20f8SDmitry Torokhov } 612b5da20f8SDmitry Torokhov } 613b5da20f8SDmitry Torokhov if (!int_in_endpointAddr) { 614b5da20f8SDmitry Torokhov err("Could not find int-in endpoint"); 615b5da20f8SDmitry Torokhov return -EIO; 616b5da20f8SDmitry Torokhov } 617b5da20f8SDmitry Torokhov 618b5da20f8SDmitry Torokhov /* allocate memory for our device state and initialize it */ 619b5da20f8SDmitry Torokhov dev = kzalloc(sizeof(struct atp), GFP_KERNEL); 620b5da20f8SDmitry Torokhov input_dev = input_allocate_device(); 621b5da20f8SDmitry Torokhov if (!dev || !input_dev) { 622b5da20f8SDmitry Torokhov err("Out of memory"); 623b5da20f8SDmitry Torokhov goto err_free_devs; 624b5da20f8SDmitry Torokhov } 625b5da20f8SDmitry Torokhov 626b5da20f8SDmitry Torokhov dev->udev = udev; 627b5da20f8SDmitry Torokhov dev->input = input_dev; 628b5da20f8SDmitry Torokhov dev->overflowwarn = 0; 629b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) 630b5da20f8SDmitry Torokhov dev->datalen = 64; 631b5da20f8SDmitry Torokhov else if (atp_is_geyser_2(dev)) 632b5da20f8SDmitry Torokhov dev->datalen = 64; 633b5da20f8SDmitry Torokhov else 634b5da20f8SDmitry Torokhov dev->datalen = 81; 635b5da20f8SDmitry Torokhov 6362a3e480dSDmitry Torokhov if (!atp_is_fountain(dev)) { 6375a6eb676SSoeren Sonnenburg /* switch to raw sensor mode */ 6382a3e480dSDmitry Torokhov if (atp_geyser_init(udev)) 639b5da20f8SDmitry Torokhov goto err_free_devs; 640b5da20f8SDmitry Torokhov 6412a3e480dSDmitry Torokhov printk(KERN_INFO "appletouch: Geyser mode initialized.\n"); 642b5da20f8SDmitry Torokhov } 643b5da20f8SDmitry Torokhov 644b5da20f8SDmitry Torokhov dev->urb = usb_alloc_urb(0, GFP_KERNEL); 645b5da20f8SDmitry Torokhov if (!dev->urb) 646b5da20f8SDmitry Torokhov goto err_free_devs; 647b5da20f8SDmitry Torokhov 648b5da20f8SDmitry Torokhov dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, 649b5da20f8SDmitry Torokhov &dev->urb->transfer_dma); 650b5da20f8SDmitry Torokhov if (!dev->data) 651b5da20f8SDmitry Torokhov goto err_free_urb; 652b5da20f8SDmitry Torokhov 653b5da20f8SDmitry Torokhov usb_fill_int_urb(dev->urb, udev, 654b5da20f8SDmitry Torokhov usb_rcvintpipe(udev, int_in_endpointAddr), 655b5da20f8SDmitry Torokhov dev->data, dev->datalen, atp_complete, dev, 1); 656b5da20f8SDmitry Torokhov 657b5da20f8SDmitry Torokhov usb_make_path(udev, dev->phys, sizeof(dev->phys)); 658b5da20f8SDmitry Torokhov strlcat(dev->phys, "/input0", sizeof(dev->phys)); 659b5da20f8SDmitry Torokhov 660b5da20f8SDmitry Torokhov input_dev->name = "appletouch"; 661b5da20f8SDmitry Torokhov input_dev->phys = dev->phys; 662b5da20f8SDmitry Torokhov usb_to_input_id(dev->udev, &input_dev->id); 663b5da20f8SDmitry Torokhov input_dev->dev.parent = &iface->dev; 664b5da20f8SDmitry Torokhov 665b5da20f8SDmitry Torokhov input_set_drvdata(input_dev, dev); 666b5da20f8SDmitry Torokhov 667b5da20f8SDmitry Torokhov input_dev->open = atp_open; 668b5da20f8SDmitry Torokhov input_dev->close = atp_close; 669b5da20f8SDmitry Torokhov 670b5da20f8SDmitry Torokhov set_bit(EV_ABS, input_dev->evbit); 671b5da20f8SDmitry Torokhov 672b5da20f8SDmitry Torokhov if (atp_is_geyser_3(dev)) { 673b5da20f8SDmitry Torokhov /* 674b5da20f8SDmitry Torokhov * MacBook have 20 X sensors, 10 Y sensors 675b5da20f8SDmitry Torokhov */ 676b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 677b5da20f8SDmitry Torokhov ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); 678b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 679b5da20f8SDmitry Torokhov ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); 680b5da20f8SDmitry Torokhov } else if (atp_is_geyser_2(dev)) { 681b5da20f8SDmitry Torokhov /* 682b5da20f8SDmitry Torokhov * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected 683b5da20f8SDmitry Torokhov * later. 684b5da20f8SDmitry Torokhov */ 685b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 686b5da20f8SDmitry Torokhov ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); 687b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 688b5da20f8SDmitry Torokhov ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); 689b5da20f8SDmitry Torokhov } else { 690b5da20f8SDmitry Torokhov /* 691b5da20f8SDmitry Torokhov * 12" and 15" Powerbooks only have 16 x sensors, 692b5da20f8SDmitry Torokhov * 17" models are detected later. 693b5da20f8SDmitry Torokhov */ 694b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 695b5da20f8SDmitry Torokhov (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); 696b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 697b5da20f8SDmitry Torokhov (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); 698b5da20f8SDmitry Torokhov } 699b5da20f8SDmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); 700b5da20f8SDmitry Torokhov 701b5da20f8SDmitry Torokhov set_bit(EV_KEY, input_dev->evbit); 702b5da20f8SDmitry Torokhov set_bit(BTN_TOUCH, input_dev->keybit); 703b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_FINGER, input_dev->keybit); 704b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); 705b5da20f8SDmitry Torokhov set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); 706b5da20f8SDmitry Torokhov set_bit(BTN_LEFT, input_dev->keybit); 707b5da20f8SDmitry Torokhov 708b5da20f8SDmitry Torokhov error = input_register_device(dev->input); 709b5da20f8SDmitry Torokhov if (error) 710b5da20f8SDmitry Torokhov goto err_free_buffer; 711b5da20f8SDmitry Torokhov 712b5da20f8SDmitry Torokhov /* save our data pointer in this interface device */ 713b5da20f8SDmitry Torokhov usb_set_intfdata(iface, dev); 714b5da20f8SDmitry Torokhov 7155a6eb676SSoeren Sonnenburg INIT_WORK(&dev->work, atp_reinit); 7165a6eb676SSoeren Sonnenburg 717b5da20f8SDmitry Torokhov return 0; 718b5da20f8SDmitry Torokhov 719b5da20f8SDmitry Torokhov err_free_buffer: 720b5da20f8SDmitry Torokhov usb_buffer_free(dev->udev, dev->datalen, 721b5da20f8SDmitry Torokhov dev->data, dev->urb->transfer_dma); 722b5da20f8SDmitry Torokhov err_free_urb: 723b5da20f8SDmitry Torokhov usb_free_urb(dev->urb); 724b5da20f8SDmitry Torokhov err_free_devs: 725b5da20f8SDmitry Torokhov usb_set_intfdata(iface, NULL); 726b5da20f8SDmitry Torokhov kfree(dev); 727b5da20f8SDmitry Torokhov input_free_device(input_dev); 728b5da20f8SDmitry Torokhov return error; 729b5da20f8SDmitry Torokhov } 730b5da20f8SDmitry Torokhov 731b5da20f8SDmitry Torokhov static void atp_disconnect(struct usb_interface *iface) 732b5da20f8SDmitry Torokhov { 733b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 734b5da20f8SDmitry Torokhov 735b5da20f8SDmitry Torokhov usb_set_intfdata(iface, NULL); 736b5da20f8SDmitry Torokhov if (dev) { 737b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 738b5da20f8SDmitry Torokhov input_unregister_device(dev->input); 739b5da20f8SDmitry Torokhov usb_buffer_free(dev->udev, dev->datalen, 740b5da20f8SDmitry Torokhov dev->data, dev->urb->transfer_dma); 741b5da20f8SDmitry Torokhov usb_free_urb(dev->urb); 742b5da20f8SDmitry Torokhov kfree(dev); 743b5da20f8SDmitry Torokhov } 744b5da20f8SDmitry Torokhov printk(KERN_INFO "input: appletouch disconnected\n"); 745b5da20f8SDmitry Torokhov } 746b5da20f8SDmitry Torokhov 747b5da20f8SDmitry Torokhov static int atp_suspend(struct usb_interface *iface, pm_message_t message) 748b5da20f8SDmitry Torokhov { 749b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 7505a6eb676SSoeren Sonnenburg 751b5da20f8SDmitry Torokhov usb_kill_urb(dev->urb); 752b5da20f8SDmitry Torokhov dev->valid = 0; 7535a6eb676SSoeren Sonnenburg 754b5da20f8SDmitry Torokhov return 0; 755b5da20f8SDmitry Torokhov } 756b5da20f8SDmitry Torokhov 757b5da20f8SDmitry Torokhov static int atp_resume(struct usb_interface *iface) 758b5da20f8SDmitry Torokhov { 759b5da20f8SDmitry Torokhov struct atp *dev = usb_get_intfdata(iface); 7605a6eb676SSoeren Sonnenburg 761b5da20f8SDmitry Torokhov if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC)) 762b5da20f8SDmitry Torokhov return -EIO; 763b5da20f8SDmitry Torokhov 764b5da20f8SDmitry Torokhov return 0; 765b5da20f8SDmitry Torokhov } 766b5da20f8SDmitry Torokhov 767b5da20f8SDmitry Torokhov static struct usb_driver atp_driver = { 768b5da20f8SDmitry Torokhov .name = "appletouch", 769b5da20f8SDmitry Torokhov .probe = atp_probe, 770b5da20f8SDmitry Torokhov .disconnect = atp_disconnect, 771b5da20f8SDmitry Torokhov .suspend = atp_suspend, 772b5da20f8SDmitry Torokhov .resume = atp_resume, 773b5da20f8SDmitry Torokhov .id_table = atp_table, 774b5da20f8SDmitry Torokhov }; 775b5da20f8SDmitry Torokhov 776b5da20f8SDmitry Torokhov static int __init atp_init(void) 777b5da20f8SDmitry Torokhov { 778b5da20f8SDmitry Torokhov return usb_register(&atp_driver); 779b5da20f8SDmitry Torokhov } 780b5da20f8SDmitry Torokhov 781b5da20f8SDmitry Torokhov static void __exit atp_exit(void) 782b5da20f8SDmitry Torokhov { 783b5da20f8SDmitry Torokhov usb_deregister(&atp_driver); 784b5da20f8SDmitry Torokhov } 785b5da20f8SDmitry Torokhov 786b5da20f8SDmitry Torokhov module_init(atp_init); 787b5da20f8SDmitry Torokhov module_exit(atp_exit); 788