aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2005-12-21 00:50:23 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2005-12-21 00:50:23 -0500
commite1e02c9f766e5cf20d951d35e6d2bc2683aa87ef (patch)
treee01d10f57fdf1af64ebaab85caa414989e44f50d
parent041387d98460b3947587929ef3a4773b8c48538f (diff)
Input: appletouch - add support for Geyser 2
This patch adds support for the Geyser 2 touchpads used on post Oct 2005 Apple PowerBooks to the appletouch driver. Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Rene Nussbaumer <linux-kernel@killerfox.forkbomb.ch> Acked-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Stelian Pop <stelian@popies.net> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--Documentation/input/appletouch.txt5
-rw-r--r--drivers/usb/input/appletouch.c145
2 files changed, 112 insertions, 38 deletions
diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt
index b48d11d0326d..4f7c633a76d2 100644
--- a/Documentation/input/appletouch.txt
+++ b/Documentation/input/appletouch.txt
@@ -3,7 +3,7 @@ Apple Touchpad Driver (appletouch)
3 Copyright (C) 2005 Stelian Pop <stelian@popies.net> 3 Copyright (C) 2005 Stelian Pop <stelian@popies.net>
4 4
5appletouch is a Linux kernel driver for the USB touchpad found on post 5appletouch is a Linux kernel driver for the USB touchpad found on post
6February 2005 Apple Alu Powerbooks. 6February 2005 and October 2005 Apple Aluminium Powerbooks.
7 7
8This driver is derived from Johannes Berg's appletrackpad driver[1], but it has 8This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
9been improved in some areas: 9been improved in some areas:
@@ -13,7 +13,8 @@ been improved in some areas:
13 13
14Credits go to Johannes Berg for reverse-engineering the touchpad protocol, 14Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
15Frank Arnold for further improvements, and Alex Harper for some additional 15Frank Arnold for further improvements, and Alex Harper for some additional
16information about the inner workings of the touchpad sensors. 16information about the inner workings of the touchpad sensors. Michael
17Hanselmann added support for the October 2005 models.
17 18
18Usage: 19Usage:
19------ 20------
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
index 15840db092a5..6cce8527ba06 100644
--- a/drivers/usb/input/appletouch.c
+++ b/drivers/usb/input/appletouch.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 2005 Stelian Pop (stelian@popies.net) 6 * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
7 * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) 7 * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
8 * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) 8 * Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
9 * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
9 * 10 *
10 * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. 11 * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
11 * 12 *
@@ -38,6 +39,11 @@
38/* Apple has powerbooks which have the keyboard with different Product IDs */ 39/* Apple has powerbooks which have the keyboard with different Product IDs */
39#define APPLE_VENDOR_ID 0x05AC 40#define APPLE_VENDOR_ID 0x05AC
40 41
42/* These names come from Info.plist in AppleUSBTrackpad.kext */
43#define GEYSER_ANSI_PRODUCT_ID 0x0214
44#define GEYSER_ISO_PRODUCT_ID 0x0215
45#define GEYSER_JIS_PRODUCT_ID 0x0216
46
41#define ATP_DEVICE(prod) \ 47#define ATP_DEVICE(prod) \
42 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 48 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
43 USB_DEVICE_ID_MATCH_INT_CLASS | \ 49 USB_DEVICE_ID_MATCH_INT_CLASS | \
@@ -53,13 +59,17 @@ static struct usb_device_id atp_table [] = {
53 { ATP_DEVICE(0x020F) }, 59 { ATP_DEVICE(0x020F) },
54 { ATP_DEVICE(0x030A) }, 60 { ATP_DEVICE(0x030A) },
55 { ATP_DEVICE(0x030B) }, 61 { ATP_DEVICE(0x030B) },
56 { } /* Terminating entry */ 62
63 /* PowerBooks Oct 2005 */
64 { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) },
65 { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
66 { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
67
68 /* Terminating entry */
69 { }
57}; 70};
58MODULE_DEVICE_TABLE (usb, atp_table); 71MODULE_DEVICE_TABLE (usb, atp_table);
59 72
60/* size of a USB urb transfer */
61#define ATP_DATASIZE 81
62
63/* 73/*
64 * number of sensors. Note that only 16 instead of 26 X (horizontal) 74 * number of sensors. Note that only 16 instead of 26 X (horizontal)
65 * sensors exist on 12" and 15" PowerBooks. All models have 16 Y 75 * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
@@ -108,6 +118,8 @@ struct atp {
108 signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; 118 signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
109 /* accumulated sensors */ 119 /* accumulated sensors */
110 int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; 120 int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
121 int overflowwarn; /* overflow warning printed? */
122 int datalen; /* size of an USB urb transfer */
111}; 123};
112 124
113#define dbg_dump(msg, tab) \ 125#define dbg_dump(msg, tab) \
@@ -124,7 +136,7 @@ struct atp {
124 if (debug) printk(format, ##a); \ 136 if (debug) printk(format, ##a); \
125 } while (0) 137 } while (0)
126 138
127MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold"); 139MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann");
128MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); 140MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
129MODULE_LICENSE("GPL"); 141MODULE_LICENSE("GPL");
130 142
@@ -132,6 +144,16 @@ static int debug = 1;
132module_param(debug, int, 0644); 144module_param(debug, int, 0644);
133MODULE_PARM_DESC(debug, "Activate debugging output"); 145MODULE_PARM_DESC(debug, "Activate debugging output");
134 146
147/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
148static inline int atp_is_geyser_2(struct atp *dev)
149{
150 int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct);
151
152 return (productId == GEYSER_ANSI_PRODUCT_ID) ||
153 (productId == GEYSER_ISO_PRODUCT_ID) ||
154 (productId == GEYSER_JIS_PRODUCT_ID);
155}
156
135static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, 157static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
136 int *z, int *fingers) 158 int *z, int *fingers)
137{ 159{
@@ -168,13 +190,20 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
168static void atp_complete(struct urb* urb, struct pt_regs* regs) 190static void atp_complete(struct urb* urb, struct pt_regs* regs)
169{ 191{
170 int x, y, x_z, y_z, x_f, y_f; 192 int x, y, x_z, y_z, x_f, y_f;
171 int retval, i; 193 int retval, i, j;
172 struct atp *dev = urb->context; 194 struct atp *dev = urb->context;
173 195
174 switch (urb->status) { 196 switch (urb->status) {
175 case 0: 197 case 0:
176 /* success */ 198 /* success */
177 break; 199 break;
200 case -EOVERFLOW:
201 if(!dev->overflowwarn) {
202 printk("appletouch: OVERFLOW with data "
203 "length %d, actual length is %d\n",
204 dev->datalen, dev->urb->actual_length);
205 dev->overflowwarn = 1;
206 }
178 case -ECONNRESET: 207 case -ECONNRESET:
179 case -ENOENT: 208 case -ENOENT:
180 case -ESHUTDOWN: 209 case -ESHUTDOWN:
@@ -189,23 +218,45 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
189 } 218 }
190 219
191 /* drop incomplete datasets */ 220 /* drop incomplete datasets */
192 if (dev->urb->actual_length != ATP_DATASIZE) { 221 if (dev->urb->actual_length != dev->datalen) {
193 dprintk("appletouch: incomplete data package.\n"); 222 dprintk("appletouch: incomplete data package.\n");
194 goto exit; 223 goto exit;
195 } 224 }
196 225
197 /* reorder the sensors values */ 226 /* reorder the sensors values */
198 for (i = 0; i < 8; i++) { 227 if (atp_is_geyser_2(dev)) {
199 /* X values */ 228 memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
200 dev->xy_cur[i ] = dev->data[5 * i + 2]; 229
201 dev->xy_cur[i + 8] = dev->data[5 * i + 4]; 230 /*
202 dev->xy_cur[i + 16] = dev->data[5 * i + 42]; 231 * The values are laid out like this:
203 if (i < 2) 232 * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ...
204 dev->xy_cur[i + 24] = dev->data[5 * i + 44]; 233 * '-' is an unused value.
205 234 */
206 /* Y values */ 235
207 dev->xy_cur[i + 26] = dev->data[5 * i + 1]; 236 /* read X values */
208 dev->xy_cur[i + 34] = dev->data[5 * i + 3]; 237 for (i = 0, j = 19; i < 20; i += 2, j += 3) {
238 dev->xy_cur[i] = dev->data[j];
239 dev->xy_cur[i + 1] = dev->data[j + 1];
240 }
241
242 /* read Y values */
243 for (i = 0, j = 1; i < 9; i += 2, j += 3) {
244 dev->xy_cur[ATP_XSENSORS + i] = dev->data[j];
245 dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1];
246 }
247 } else {
248 for (i = 0; i < 8; i++) {
249 /* X values */
250 dev->xy_cur[i ] = dev->data[5 * i + 2];
251 dev->xy_cur[i + 8] = dev->data[5 * i + 4];
252 dev->xy_cur[i + 16] = dev->data[5 * i + 42];
253 if (i < 2)
254 dev->xy_cur[i + 24] = dev->data[5 * i + 44];
255
256 /* Y values */
257 dev->xy_cur[i + 26] = dev->data[5 * i + 1];
258 dev->xy_cur[i + 34] = dev->data[5 * i + 3];
259 }
209 } 260 }
210 261
211 dbg_dump("sample", dev->xy_cur); 262 dbg_dump("sample", dev->xy_cur);
@@ -216,16 +267,24 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
216 dev->x_old = dev->y_old = -1; 267 dev->x_old = dev->y_old = -1;
217 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 268 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
218 269
219 /* 17" Powerbooks have 10 extra X sensors */ 270 /* 17" Powerbooks have extra X sensors */
220 for (i = 16; i < ATP_XSENSORS; i++) 271 for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
221 if (dev->xy_cur[i]) { 272 if (!dev->xy_cur[i]) continue;
222 printk("appletouch: 17\" model detected.\n"); 273
274 printk("appletouch: 17\" model detected.\n");
275 if(atp_is_geyser_2(dev))
276 input_set_abs_params(dev->input, ABS_X, 0,
277 (20 - 1) *
278 ATP_XFACT - 1,
279 ATP_FUZZ, 0);
280 else
223 input_set_abs_params(dev->input, ABS_X, 0, 281 input_set_abs_params(dev->input, ABS_X, 0,
224 (ATP_XSENSORS - 1) * 282 (ATP_XSENSORS - 1) *
225 ATP_XFACT - 1, 283 ATP_XFACT - 1,
226 ATP_FUZZ, 0); 284 ATP_FUZZ, 0);
227 break; 285
228 } 286 break;
287 }
229 288
230 goto exit; 289 goto exit;
231 } 290 }
@@ -282,7 +341,8 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
282 memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); 341 memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
283 } 342 }
284 343
285 input_report_key(dev->input, BTN_LEFT, !!dev->data[80]); 344 input_report_key(dev->input, BTN_LEFT,
345 !!dev->data[dev->datalen - 1]);
286 346
287 input_sync(dev->input); 347 input_sync(dev->input);
288 348
@@ -353,6 +413,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
353 413
354 dev->udev = udev; 414 dev->udev = udev;
355 dev->input = input_dev; 415 dev->input = input_dev;
416 dev->overflowwarn = 0;
417 dev->datalen = (atp_is_geyser_2(dev)?64:81);
356 418
357 dev->urb = usb_alloc_urb(0, GFP_KERNEL); 419 dev->urb = usb_alloc_urb(0, GFP_KERNEL);
358 if (!dev->urb) { 420 if (!dev->urb) {
@@ -360,7 +422,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
360 goto err_free_devs; 422 goto err_free_devs;
361 } 423 }
362 424
363 dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, 425 dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
364 &dev->urb->transfer_dma); 426 &dev->urb->transfer_dma);
365 if (!dev->data) { 427 if (!dev->data) {
366 retval = -ENOMEM; 428 retval = -ENOMEM;
@@ -369,7 +431,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
369 431
370 usb_fill_int_urb(dev->urb, udev, 432 usb_fill_int_urb(dev->urb, udev,
371 usb_rcvintpipe(udev, int_in_endpointAddr), 433 usb_rcvintpipe(udev, int_in_endpointAddr),
372 dev->data, ATP_DATASIZE, atp_complete, dev, 1); 434 dev->data, dev->datalen, atp_complete, dev, 1);
373 435
374 usb_make_path(udev, dev->phys, sizeof(dev->phys)); 436 usb_make_path(udev, dev->phys, sizeof(dev->phys));
375 strlcat(dev->phys, "/input0", sizeof(dev->phys)); 437 strlcat(dev->phys, "/input0", sizeof(dev->phys));
@@ -385,14 +447,25 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
385 447
386 set_bit(EV_ABS, input_dev->evbit); 448 set_bit(EV_ABS, input_dev->evbit);
387 449
388 /* 450 if (atp_is_geyser_2(dev)) {
389 * 12" and 15" Powerbooks only have 16 x sensors, 451 /*
390 * 17" models are detected later. 452 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
391 */ 453 * later.
392 input_set_abs_params(input_dev, ABS_X, 0, 454 */
393 (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); 455 input_set_abs_params(input_dev, ABS_X, 0,
394 input_set_abs_params(input_dev, ABS_Y, 0, 456 ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
395 (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); 457 input_set_abs_params(input_dev, ABS_Y, 0,
458 ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
459 } else {
460 /*
461 * 12" and 15" Powerbooks only have 16 x sensors,
462 * 17" models are detected later.
463 */
464 input_set_abs_params(input_dev, ABS_X, 0,
465 (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
466 input_set_abs_params(input_dev, ABS_Y, 0,
467 (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
468 }
396 input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); 469 input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
397 470
398 set_bit(EV_KEY, input_dev->evbit); 471 set_bit(EV_KEY, input_dev->evbit);
@@ -427,7 +500,7 @@ static void atp_disconnect(struct usb_interface *iface)
427 usb_kill_urb(dev->urb); 500 usb_kill_urb(dev->urb);
428 input_unregister_device(dev->input); 501 input_unregister_device(dev->input);
429 usb_free_urb(dev->urb); 502 usb_free_urb(dev->urb);
430 usb_buffer_free(dev->udev, ATP_DATASIZE, 503 usb_buffer_free(dev->udev, dev->datalen,
431 dev->data, dev->urb->transfer_dma); 504 dev->data, dev->urb->transfer_dma);
432 kfree(dev); 505 kfree(dev);
433 } 506 }