at v2.6.14 469 lines 12 kB view raw
1/* 2 * Apple USB Touchpad (for post-February 2005 PowerBooks) 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 * 10 * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 */ 27 28#include <linux/config.h> 29#include <linux/kernel.h> 30#include <linux/errno.h> 31#include <linux/init.h> 32#include <linux/slab.h> 33#include <linux/module.h> 34#include <linux/usb.h> 35#include <linux/input.h> 36#include <linux/usb_input.h> 37 38/* Apple has powerbooks which have the keyboard with different Product IDs */ 39#define APPLE_VENDOR_ID 0x05AC 40 41#define ATP_DEVICE(prod) \ 42 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 43 USB_DEVICE_ID_MATCH_INT_CLASS | \ 44 USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ 45 .idVendor = APPLE_VENDOR_ID, \ 46 .idProduct = (prod), \ 47 .bInterfaceClass = 0x03, \ 48 .bInterfaceProtocol = 0x02 49 50/* table of devices that work with this driver */ 51static struct usb_device_id atp_table [] = { 52 { ATP_DEVICE(0x020E) }, 53 { ATP_DEVICE(0x020F) }, 54 { ATP_DEVICE(0x030A) }, 55 { ATP_DEVICE(0x030B) }, 56 { } /* Terminating entry */ 57}; 58MODULE_DEVICE_TABLE (usb, atp_table); 59 60/* size of a USB urb transfer */ 61#define ATP_DATASIZE 81 62 63/* 64 * 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 66 * (vertical) sensors. 67 */ 68#define ATP_XSENSORS 26 69#define ATP_YSENSORS 16 70 71/* amount of fuzz this touchpad generates */ 72#define ATP_FUZZ 16 73 74/* maximum pressure this driver will report */ 75#define ATP_PRESSURE 300 76/* 77 * multiplication factor for the X and Y coordinates. 78 * We try to keep the touchpad aspect ratio while still doing only simple 79 * arithmetics. 80 * The factors below give coordinates like: 81 * 0 <= x < 960 on 12" and 15" Powerbooks 82 * 0 <= x < 1600 on 17" Powerbooks 83 * 0 <= y < 646 84 */ 85#define ATP_XFACT 64 86#define ATP_YFACT 43 87 88/* 89 * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is 90 * ignored. 91 */ 92#define ATP_THRESHOLD 5 93 94/* Structure to hold all of our device specific stuff */ 95struct atp { 96 struct usb_device * udev; /* usb device */ 97 struct urb * urb; /* usb request block */ 98 signed char * data; /* transferred data */ 99 int open; /* non-zero if opened */ 100 struct input_dev input; /* input dev */ 101 int valid; /* are the sensors valid ? */ 102 int x_old; /* last reported x/y, */ 103 int y_old; /* used for smoothing */ 104 /* current value of the sensors */ 105 signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; 106 /* last value of the sensors */ 107 signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; 108 /* accumulated sensors */ 109 int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; 110}; 111 112#define dbg_dump(msg, tab) \ 113 if (debug > 1) { \ 114 int i; \ 115 printk("appletouch: %s %lld", msg, (long long)jiffies); \ 116 for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ 117 printk(" %02x", tab[i]); \ 118 printk("\n"); \ 119 } 120 121#define dprintk(format, a...) \ 122 do { \ 123 if (debug) printk(format, ##a); \ 124 } while (0) 125 126MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold"); 127MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); 128MODULE_LICENSE("GPL"); 129 130static int debug = 1; 131module_param(debug, int, 0644); 132MODULE_PARM_DESC(debug, "Activate debugging output"); 133 134static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, 135 int *z, int *fingers) 136{ 137 int i; 138 /* values to calculate mean */ 139 int pcum = 0, psum = 0; 140 141 *fingers = 0; 142 143 for (i = 0; i < nb_sensors; i++) { 144 if (xy_sensors[i] < ATP_THRESHOLD) 145 continue; 146 if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD)) 147 (*fingers)++; 148 pcum += xy_sensors[i] * i; 149 psum += xy_sensors[i]; 150 } 151 152 if (psum > 0) { 153 *z = psum; 154 return pcum * fact / psum; 155 } 156 157 return 0; 158} 159 160static inline void atp_report_fingers(struct input_dev *input, int fingers) 161{ 162 input_report_key(input, BTN_TOOL_FINGER, fingers == 1); 163 input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2); 164 input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); 165} 166 167static void atp_complete(struct urb* urb, struct pt_regs* regs) 168{ 169 int x, y, x_z, y_z, x_f, y_f; 170 int retval, i; 171 struct atp *dev = urb->context; 172 173 switch (urb->status) { 174 case 0: 175 /* success */ 176 break; 177 case -ECONNRESET: 178 case -ENOENT: 179 case -ESHUTDOWN: 180 /* This urb is terminated, clean up */ 181 dbg("%s - urb shutting down with status: %d", 182 __FUNCTION__, urb->status); 183 return; 184 default: 185 dbg("%s - nonzero urb status received: %d", 186 __FUNCTION__, urb->status); 187 goto exit; 188 } 189 190 /* drop incomplete datasets */ 191 if (dev->urb->actual_length != ATP_DATASIZE) { 192 dprintk("appletouch: incomplete data package.\n"); 193 goto exit; 194 } 195 196 /* reorder the sensors values */ 197 for (i = 0; i < 8; i++) { 198 /* X values */ 199 dev->xy_cur[i ] = dev->data[5 * i + 2]; 200 dev->xy_cur[i + 8] = dev->data[5 * i + 4]; 201 dev->xy_cur[i + 16] = dev->data[5 * i + 42]; 202 if (i < 2) 203 dev->xy_cur[i + 24] = dev->data[5 * i + 44]; 204 205 /* Y values */ 206 dev->xy_cur[i + 26] = dev->data[5 * i + 1]; 207 dev->xy_cur[i + 34] = dev->data[5 * i + 3]; 208 } 209 210 dbg_dump("sample", dev->xy_cur); 211 212 if (!dev->valid) { 213 /* first sample */ 214 dev->valid = 1; 215 dev->x_old = dev->y_old = -1; 216 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 217 218 /* 17" Powerbooks have 10 extra X sensors */ 219 for (i = 16; i < ATP_XSENSORS; i++) 220 if (dev->xy_cur[i]) { 221 printk("appletouch: 17\" model detected.\n"); 222 input_set_abs_params(&dev->input, ABS_X, 0, 223 (ATP_XSENSORS - 1) * 224 ATP_XFACT - 1, 225 ATP_FUZZ, 0); 226 break; 227 } 228 229 goto exit; 230 } 231 232 for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { 233 /* accumulate the change */ 234 signed char change = dev->xy_old[i] - dev->xy_cur[i]; 235 dev->xy_acc[i] -= change; 236 237 /* prevent down drifting */ 238 if (dev->xy_acc[i] < 0) 239 dev->xy_acc[i] = 0; 240 } 241 242 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); 243 244 dbg_dump("accumulator", dev->xy_acc); 245 246 x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, 247 ATP_XFACT, &x_z, &x_f); 248 y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, 249 ATP_YFACT, &y_z, &y_f); 250 251 if (x && y) { 252 if (dev->x_old != -1) { 253 x = (dev->x_old * 3 + x) >> 2; 254 y = (dev->y_old * 3 + y) >> 2; 255 dev->x_old = x; 256 dev->y_old = y; 257 258 if (debug > 1) 259 printk("appletouch: X: %3d Y: %3d " 260 "Xz: %3d Yz: %3d\n", 261 x, y, x_z, y_z); 262 263 input_report_key(&dev->input, BTN_TOUCH, 1); 264 input_report_abs(&dev->input, ABS_X, x); 265 input_report_abs(&dev->input, ABS_Y, y); 266 input_report_abs(&dev->input, ABS_PRESSURE, 267 min(ATP_PRESSURE, x_z + y_z)); 268 atp_report_fingers(&dev->input, max(x_f, y_f)); 269 } 270 dev->x_old = x; 271 dev->y_old = y; 272 } 273 else if (!x && !y) { 274 275 dev->x_old = dev->y_old = -1; 276 input_report_key(&dev->input, BTN_TOUCH, 0); 277 input_report_abs(&dev->input, ABS_PRESSURE, 0); 278 atp_report_fingers(&dev->input, 0); 279 280 /* reset the accumulator on release */ 281 memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); 282 } 283 284 input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]); 285 286 input_sync(&dev->input); 287 288exit: 289 retval = usb_submit_urb(dev->urb, GFP_ATOMIC); 290 if (retval) { 291 err("%s - usb_submit_urb failed with result %d", 292 __FUNCTION__, retval); 293 } 294} 295 296static int atp_open(struct input_dev *input) 297{ 298 struct atp *dev = input->private; 299 300 if (usb_submit_urb(dev->urb, GFP_ATOMIC)) 301 return -EIO; 302 303 dev->open = 1; 304 return 0; 305} 306 307static void atp_close(struct input_dev *input) 308{ 309 struct atp *dev = input->private; 310 311 usb_kill_urb(dev->urb); 312 dev->open = 0; 313} 314 315static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) 316{ 317 struct atp *dev = NULL; 318 struct usb_host_interface *iface_desc; 319 struct usb_endpoint_descriptor *endpoint; 320 int int_in_endpointAddr = 0; 321 int i, retval = -ENOMEM; 322 323 /* allocate memory for our device state and initialize it */ 324 dev = kmalloc(sizeof(struct atp), GFP_KERNEL); 325 if (dev == NULL) { 326 err("Out of memory"); 327 goto err_kmalloc; 328 } 329 memset(dev, 0, sizeof(struct atp)); 330 331 dev->udev = interface_to_usbdev(iface); 332 333 /* set up the endpoint information */ 334 /* use only the first interrupt-in endpoint */ 335 iface_desc = iface->cur_altsetting; 336 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { 337 endpoint = &iface_desc->endpoint[i].desc; 338 if (!int_in_endpointAddr && 339 (endpoint->bEndpointAddress & USB_DIR_IN) && 340 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 341 == USB_ENDPOINT_XFER_INT)) { 342 /* we found an interrupt in endpoint */ 343 int_in_endpointAddr = endpoint->bEndpointAddress; 344 break; 345 } 346 } 347 if (!int_in_endpointAddr) { 348 retval = -EIO; 349 err("Could not find int-in endpoint"); 350 goto err_endpoint; 351 } 352 353 /* save our data pointer in this interface device */ 354 usb_set_intfdata(iface, dev); 355 356 dev->urb = usb_alloc_urb(0, GFP_KERNEL); 357 if (!dev->urb) { 358 retval = -ENOMEM; 359 goto err_usballoc; 360 } 361 dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, 362 &dev->urb->transfer_dma); 363 if (!dev->data) { 364 retval = -ENOMEM; 365 goto err_usbbufalloc; 366 } 367 usb_fill_int_urb(dev->urb, dev->udev, 368 usb_rcvintpipe(dev->udev, int_in_endpointAddr), 369 dev->data, ATP_DATASIZE, atp_complete, dev, 1); 370 371 init_input_dev(&dev->input); 372 dev->input.name = "appletouch"; 373 dev->input.dev = &iface->dev; 374 dev->input.private = dev; 375 dev->input.open = atp_open; 376 dev->input.close = atp_close; 377 378 usb_to_input_id(dev->udev, &dev->input.id); 379 380 set_bit(EV_ABS, dev->input.evbit); 381 382 /* 383 * 12" and 15" Powerbooks only have 16 x sensors, 384 * 17" models are detected later. 385 */ 386 input_set_abs_params(&dev->input, ABS_X, 0, 387 (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); 388 input_set_abs_params(&dev->input, ABS_Y, 0, 389 (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); 390 input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); 391 392 set_bit(EV_KEY, dev->input.evbit); 393 set_bit(BTN_TOUCH, dev->input.keybit); 394 set_bit(BTN_TOOL_FINGER, dev->input.keybit); 395 set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit); 396 set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit); 397 set_bit(BTN_LEFT, dev->input.keybit); 398 399 input_register_device(&dev->input); 400 401 printk(KERN_INFO "input: appletouch connected\n"); 402 403 return 0; 404 405err_usbbufalloc: 406 usb_free_urb(dev->urb); 407err_usballoc: 408 usb_set_intfdata(iface, NULL); 409err_endpoint: 410 kfree(dev); 411err_kmalloc: 412 return retval; 413} 414 415static void atp_disconnect(struct usb_interface *iface) 416{ 417 struct atp *dev = usb_get_intfdata(iface); 418 419 usb_set_intfdata(iface, NULL); 420 if (dev) { 421 usb_kill_urb(dev->urb); 422 input_unregister_device(&dev->input); 423 usb_free_urb(dev->urb); 424 usb_buffer_free(dev->udev, ATP_DATASIZE, 425 dev->data, dev->urb->transfer_dma); 426 kfree(dev); 427 } 428 printk(KERN_INFO "input: appletouch disconnected\n"); 429} 430 431static int atp_suspend(struct usb_interface *iface, pm_message_t message) 432{ 433 struct atp *dev = usb_get_intfdata(iface); 434 usb_kill_urb(dev->urb); 435 dev->valid = 0; 436 return 0; 437} 438 439static int atp_resume(struct usb_interface *iface) 440{ 441 struct atp *dev = usb_get_intfdata(iface); 442 if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC)) 443 return -EIO; 444 445 return 0; 446} 447 448static struct usb_driver atp_driver = { 449 .owner = THIS_MODULE, 450 .name = "appletouch", 451 .probe = atp_probe, 452 .disconnect = atp_disconnect, 453 .suspend = atp_suspend, 454 .resume = atp_resume, 455 .id_table = atp_table, 456}; 457 458static int __init atp_init(void) 459{ 460 return usb_register(&atp_driver); 461} 462 463static void __exit atp_exit(void) 464{ 465 usb_deregister(&atp_driver); 466} 467 468module_init(atp_init); 469module_exit(atp_exit);