diff options
author | Nicolas Boichat <nicolas@boichat.ch> | 2006-04-19 17:36:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 18:04:09 -0400 |
commit | 9effa978f1d51f6d0426ebabcf6cb32336bb3153 (patch) | |
tree | 9f30639c3bda03d031fc75f5b6404abbf19f17cb /drivers/usb/input/appletouch.c | |
parent | 73e487fdb75f8abf230968dbf73a3dc3b16808d3 (diff) |
[PATCH] USB: MacBook Pro touchpad support
Add support for MacBook touchpad in appletouch driver.
Thanks to Alex Harper for the informations.
Use u16 instead of int16_t in atp_is_geyser* functions.
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Stelian Pop <stelian@popies.net>
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/input/appletouch.c')
-rw-r--r-- | drivers/usb/input/appletouch.c | 113 |
1 files changed, 107 insertions, 6 deletions
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index c222ed13deab..4eff8d7a79d4 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Apple USB Touchpad (for post-February 2005 PowerBooks) driver | 2 | * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver |
3 | * | 3 | * |
4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) | 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) |
5 | * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) | 5 | * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) |
@@ -7,6 +7,7 @@ | |||
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 | * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) |
10 | * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) | ||
10 | * | 11 | * |
11 | * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. | 12 | * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. |
12 | * | 13 | * |
@@ -44,6 +45,11 @@ | |||
44 | #define GEYSER_ISO_PRODUCT_ID 0x0215 | 45 | #define GEYSER_ISO_PRODUCT_ID 0x0215 |
45 | #define GEYSER_JIS_PRODUCT_ID 0x0216 | 46 | #define GEYSER_JIS_PRODUCT_ID 0x0216 |
46 | 47 | ||
48 | /* MacBook devices */ | ||
49 | #define GEYSER3_ANSI_PRODUCT_ID 0x0217 | ||
50 | #define GEYSER3_ISO_PRODUCT_ID 0x0218 | ||
51 | #define GEYSER3_JIS_PRODUCT_ID 0x0219 | ||
52 | |||
47 | #define ATP_DEVICE(prod) \ | 53 | #define ATP_DEVICE(prod) \ |
48 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | 54 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ |
49 | USB_DEVICE_ID_MATCH_INT_CLASS | \ | 55 | USB_DEVICE_ID_MATCH_INT_CLASS | \ |
@@ -65,6 +71,10 @@ static struct usb_device_id atp_table [] = { | |||
65 | { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, | 71 | { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, |
66 | { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, | 72 | { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, |
67 | 73 | ||
74 | { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, | ||
75 | { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, | ||
76 | { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, | ||
77 | |||
68 | /* Terminating entry */ | 78 | /* Terminating entry */ |
69 | { } | 79 | { } |
70 | }; | 80 | }; |
@@ -101,6 +111,13 @@ MODULE_DEVICE_TABLE (usb, atp_table); | |||
101 | */ | 111 | */ |
102 | #define ATP_THRESHOLD 5 | 112 | #define ATP_THRESHOLD 5 |
103 | 113 | ||
114 | /* MacBook Pro (Geyser 3) initialization constants */ | ||
115 | #define ATP_GEYSER3_MODE_READ_REQUEST_ID 1 | ||
116 | #define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9 | ||
117 | #define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300 | ||
118 | #define ATP_GEYSER3_MODE_REQUEST_INDEX 0 | ||
119 | #define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04 | ||
120 | |||
104 | /* Structure to hold all of our device specific stuff */ | 121 | /* Structure to hold all of our device specific stuff */ |
105 | struct atp { | 122 | struct atp { |
106 | char phys[64]; | 123 | char phys[64]; |
@@ -147,13 +164,22 @@ MODULE_PARM_DESC(debug, "Activate debugging output"); | |||
147 | /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ | 164 | /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ |
148 | static inline int atp_is_geyser_2(struct atp *dev) | 165 | static inline int atp_is_geyser_2(struct atp *dev) |
149 | { | 166 | { |
150 | int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct); | 167 | u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); |
151 | 168 | ||
152 | return (productId == GEYSER_ANSI_PRODUCT_ID) || | 169 | return (productId == GEYSER_ANSI_PRODUCT_ID) || |
153 | (productId == GEYSER_ISO_PRODUCT_ID) || | 170 | (productId == GEYSER_ISO_PRODUCT_ID) || |
154 | (productId == GEYSER_JIS_PRODUCT_ID); | 171 | (productId == GEYSER_JIS_PRODUCT_ID); |
155 | } | 172 | } |
156 | 173 | ||
174 | static inline int atp_is_geyser_3(struct atp *dev) | ||
175 | { | ||
176 | u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); | ||
177 | |||
178 | return (productId == GEYSER3_ANSI_PRODUCT_ID) || | ||
179 | (productId == GEYSER3_ISO_PRODUCT_ID) || | ||
180 | (productId == GEYSER3_JIS_PRODUCT_ID); | ||
181 | } | ||
182 | |||
157 | static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, | 183 | static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, |
158 | int *z, int *fingers) | 184 | int *z, int *fingers) |
159 | { | 185 | { |
@@ -219,12 +245,33 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) | |||
219 | 245 | ||
220 | /* drop incomplete datasets */ | 246 | /* drop incomplete datasets */ |
221 | if (dev->urb->actual_length != dev->datalen) { | 247 | if (dev->urb->actual_length != dev->datalen) { |
222 | dprintk("appletouch: incomplete data package.\n"); | 248 | dprintk("appletouch: incomplete data package" |
249 | " (first byte: %d, length: %d).\n", | ||
250 | dev->data[0], dev->urb->actual_length); | ||
223 | goto exit; | 251 | goto exit; |
224 | } | 252 | } |
225 | 253 | ||
226 | /* reorder the sensors values */ | 254 | /* reorder the sensors values */ |
227 | if (atp_is_geyser_2(dev)) { | 255 | if (atp_is_geyser_3(dev)) { |
256 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | ||
257 | |||
258 | /* | ||
259 | * The values are laid out like this: | ||
260 | * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... | ||
261 | * '-' is an unused value. | ||
262 | */ | ||
263 | |||
264 | /* read X values */ | ||
265 | for (i = 0, j = 19; i < 20; i += 2, j += 3) { | ||
266 | dev->xy_cur[i] = dev->data[j + 1]; | ||
267 | dev->xy_cur[i + 1] = dev->data[j + 2]; | ||
268 | } | ||
269 | /* read Y values */ | ||
270 | for (i = 0, j = 1; i < 9; i += 2, j += 3) { | ||
271 | dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; | ||
272 | dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; | ||
273 | } | ||
274 | } else if (atp_is_geyser_2(dev)) { | ||
228 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | 275 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); |
229 | 276 | ||
230 | /* | 277 | /* |
@@ -267,6 +314,9 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) | |||
267 | dev->x_old = dev->y_old = -1; | 314 | dev->x_old = dev->y_old = -1; |
268 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); | 315 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); |
269 | 316 | ||
317 | if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */ | ||
318 | goto exit; | ||
319 | |||
270 | /* 17" Powerbooks have extra X sensors */ | 320 | /* 17" Powerbooks have extra X sensors */ |
271 | for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { | 321 | for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { |
272 | if (!dev->xy_cur[i]) continue; | 322 | if (!dev->xy_cur[i]) continue; |
@@ -414,7 +464,50 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id | |||
414 | dev->udev = udev; | 464 | dev->udev = udev; |
415 | dev->input = input_dev; | 465 | dev->input = input_dev; |
416 | dev->overflowwarn = 0; | 466 | dev->overflowwarn = 0; |
417 | dev->datalen = (atp_is_geyser_2(dev)?64:81); | 467 | if (atp_is_geyser_3(dev)) |
468 | dev->datalen = 64; | ||
469 | else if (atp_is_geyser_2(dev)) | ||
470 | dev->datalen = 64; | ||
471 | else | ||
472 | dev->datalen = 81; | ||
473 | |||
474 | if (atp_is_geyser_3(dev)) { | ||
475 | /* | ||
476 | * By default Geyser 3 device sends standard USB HID mouse | ||
477 | * packets (Report ID 2). This code changes device mode, so it | ||
478 | * sends raw sensor reports (Report ID 5). | ||
479 | */ | ||
480 | char data[8]; | ||
481 | int size; | ||
482 | |||
483 | size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
484 | ATP_GEYSER3_MODE_READ_REQUEST_ID, | ||
485 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
486 | ATP_GEYSER3_MODE_REQUEST_VALUE, | ||
487 | ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); | ||
488 | |||
489 | if (size != 8) { | ||
490 | err("Could not do mode read request from device" | ||
491 | " (Geyser 3 mode)"); | ||
492 | goto err_free_devs; | ||
493 | } | ||
494 | |||
495 | /* Apply the mode switch */ | ||
496 | data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE; | ||
497 | |||
498 | size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
499 | ATP_GEYSER3_MODE_WRITE_REQUEST_ID, | ||
500 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
501 | ATP_GEYSER3_MODE_REQUEST_VALUE, | ||
502 | ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); | ||
503 | |||
504 | if (size != 8) { | ||
505 | err("Could not do mode write request to device" | ||
506 | " (Geyser 3 mode)"); | ||
507 | goto err_free_devs; | ||
508 | } | ||
509 | printk("appletouch Geyser 3 inited.\n"); | ||
510 | } | ||
418 | 511 | ||
419 | dev->urb = usb_alloc_urb(0, GFP_KERNEL); | 512 | dev->urb = usb_alloc_urb(0, GFP_KERNEL); |
420 | if (!dev->urb) { | 513 | if (!dev->urb) { |
@@ -447,7 +540,15 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id | |||
447 | 540 | ||
448 | set_bit(EV_ABS, input_dev->evbit); | 541 | set_bit(EV_ABS, input_dev->evbit); |
449 | 542 | ||
450 | if (atp_is_geyser_2(dev)) { | 543 | if (atp_is_geyser_3(dev)) { |
544 | /* | ||
545 | * MacBook have 20 X sensors, 10 Y sensors | ||
546 | */ | ||
547 | input_set_abs_params(input_dev, ABS_X, 0, | ||
548 | ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); | ||
549 | input_set_abs_params(input_dev, ABS_Y, 0, | ||
550 | ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); | ||
551 | } else if (atp_is_geyser_2(dev)) { | ||
451 | /* | 552 | /* |
452 | * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected | 553 | * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected |
453 | * later. | 554 | * later. |