xref: /openbmc/linux/drivers/input/mouse/appletouch.c (revision 0035a1dc8f56f2c92f4246b0c8b5f6d1ee10c76b)
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