diff options
-rw-r--r-- | Documentation/input/appletouch.txt | 5 | ||||
-rw-r--r-- | drivers/usb/input/appletouch.c | 145 |
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 | ||
5 | appletouch is a Linux kernel driver for the USB touchpad found on post | 5 | appletouch is a Linux kernel driver for the USB touchpad found on post |
6 | February 2005 Apple Alu Powerbooks. | 6 | February 2005 and October 2005 Apple Aluminium Powerbooks. |
7 | 7 | ||
8 | This driver is derived from Johannes Berg's appletrackpad driver[1], but it has | 8 | This driver is derived from Johannes Berg's appletrackpad driver[1], but it has |
9 | been improved in some areas: | 9 | been improved in some areas: |
@@ -13,7 +13,8 @@ been improved in some areas: | |||
13 | 13 | ||
14 | Credits go to Johannes Berg for reverse-engineering the touchpad protocol, | 14 | Credits go to Johannes Berg for reverse-engineering the touchpad protocol, |
15 | Frank Arnold for further improvements, and Alex Harper for some additional | 15 | Frank Arnold for further improvements, and Alex Harper for some additional |
16 | information about the inner workings of the touchpad sensors. | 16 | information about the inner workings of the touchpad sensors. Michael |
17 | Hanselmann added support for the October 2005 models. | ||
17 | 18 | ||
18 | Usage: | 19 | Usage: |
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 | }; |
58 | MODULE_DEVICE_TABLE (usb, atp_table); | 71 | MODULE_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 | ||
127 | MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold"); | 139 | MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); |
128 | MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); | 140 | MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); |
129 | MODULE_LICENSE("GPL"); | 141 | MODULE_LICENSE("GPL"); |
130 | 142 | ||
@@ -132,6 +144,16 @@ static int debug = 1; | |||
132 | module_param(debug, int, 0644); | 144 | module_param(debug, int, 0644); |
133 | MODULE_PARM_DESC(debug, "Activate debugging output"); | 145 | MODULE_PARM_DESC(debug, "Activate debugging output"); |
134 | 146 | ||
147 | /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ | ||
148 | static 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 | |||
135 | static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, | 157 | static 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) | |||
168 | static void atp_complete(struct urb* urb, struct pt_regs* regs) | 190 | static 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 | } |