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