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