diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/mouse/appletouch.c | 266 |
1 files changed, 197 insertions, 69 deletions
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 1f41ae94f26b..36ebe5c25ee3 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c | |||
@@ -327,11 +327,14 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) | |||
327 | input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); | 327 | input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); |
328 | } | 328 | } |
329 | 329 | ||
330 | static void atp_complete(struct urb *urb) | 330 | /* Check URB status and for correct length of data package */ |
331 | |||
332 | #define ATP_URB_STATUS_SUCCESS 0 | ||
333 | #define ATP_URB_STATUS_ERROR 1 | ||
334 | #define ATP_URB_STATUS_ERROR_FATAL 2 | ||
335 | |||
336 | static int atp_status_check(struct urb *urb) | ||
331 | { | 337 | { |
332 | int x, y, x_z, y_z, x_f, y_f; | ||
333 | int retval, i, j; | ||
334 | int key; | ||
335 | struct atp *dev = urb->context; | 338 | struct atp *dev = urb->context; |
336 | 339 | ||
337 | switch (urb->status) { | 340 | switch (urb->status) { |
@@ -351,11 +354,12 @@ static void atp_complete(struct urb *urb) | |||
351 | /* This urb is terminated, clean up */ | 354 | /* This urb is terminated, clean up */ |
352 | dbg("atp_complete: urb shutting down with status: %d", | 355 | dbg("atp_complete: urb shutting down with status: %d", |
353 | urb->status); | 356 | urb->status); |
354 | return; | 357 | return ATP_URB_STATUS_ERROR_FATAL; |
358 | |||
355 | default: | 359 | default: |
356 | dbg("atp_complete: nonzero urb status received: %d", | 360 | dbg("atp_complete: nonzero urb status received: %d", |
357 | urb->status); | 361 | urb->status); |
358 | goto exit; | 362 | return ATP_URB_STATUS_ERROR; |
359 | } | 363 | } |
360 | 364 | ||
361 | /* drop incomplete datasets */ | 365 | /* drop incomplete datasets */ |
@@ -363,30 +367,33 @@ static void atp_complete(struct urb *urb) | |||
363 | dprintk("appletouch: incomplete data package" | 367 | dprintk("appletouch: incomplete data package" |
364 | " (first byte: %d, length: %d).\n", | 368 | " (first byte: %d, length: %d).\n", |
365 | dev->data[0], dev->urb->actual_length); | 369 | dev->data[0], dev->urb->actual_length); |
366 | goto exit; | 370 | return ATP_URB_STATUS_ERROR; |
367 | } | 371 | } |
368 | 372 | ||
369 | /* reorder the sensors values */ | 373 | return ATP_URB_STATUS_SUCCESS; |
370 | if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { | 374 | } |
371 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | ||
372 | 375 | ||
373 | /* | 376 | /* |
374 | * The values are laid out like this: | 377 | * USB interrupt callback functions |
375 | * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... | 378 | */ |
376 | * '-' is an unused value. | ||
377 | */ | ||
378 | 379 | ||
379 | /* read X values */ | 380 | /* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */ |
380 | for (i = 0, j = 19; i < 20; i += 2, j += 3) { | 381 | |
381 | dev->xy_cur[i] = dev->data[j + 1]; | 382 | static void atp_complete_geyser_1_2(struct urb *urb) |
382 | dev->xy_cur[i + 1] = dev->data[j + 2]; | 383 | { |
383 | } | 384 | int x, y, x_z, y_z, x_f, y_f; |
384 | /* read Y values */ | 385 | int retval, i, j; |
385 | for (i = 0, j = 1; i < 9; i += 2, j += 3) { | 386 | int key; |
386 | dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; | 387 | struct atp *dev = urb->context; |
387 | dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; | 388 | int status = atp_status_check(urb); |
388 | } | 389 | |
389 | } else if (dev->type == ATP_GEYSER2) { | 390 | if (status == ATP_URB_STATUS_ERROR_FATAL) |
391 | return; | ||
392 | else if (status == ATP_URB_STATUS_ERROR) | ||
393 | goto exit; | ||
394 | |||
395 | /* reorder the sensors values */ | ||
396 | if (dev->type == ATP_GEYSER2) { | ||
390 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | 397 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); |
391 | 398 | ||
392 | /* | 399 | /* |
@@ -427,33 +434,146 @@ static void atp_complete(struct urb *urb) | |||
427 | /* first sample */ | 434 | /* first sample */ |
428 | dev->valid = true; | 435 | dev->valid = true; |
429 | dev->x_old = dev->y_old = -1; | 436 | dev->x_old = dev->y_old = -1; |
437 | |||
438 | /* Store first sample */ | ||
430 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); | 439 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); |
431 | 440 | ||
432 | if (dev->size_detect_done || | 441 | /* Perform size detection, if not done already */ |
433 | dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */ | 442 | if (!dev->size_detect_done) { |
443 | |||
444 | /* 17" Powerbooks have extra X sensors */ | ||
445 | for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); | ||
446 | i < ATP_XSENSORS; i++) { | ||
447 | if (!dev->xy_cur[i]) | ||
448 | continue; | ||
449 | |||
450 | printk(KERN_INFO | ||
451 | "appletouch: 17\" model detected.\n"); | ||
452 | |||
453 | if (dev->type == ATP_GEYSER2) | ||
454 | input_set_abs_params(dev->input, ABS_X, | ||
455 | 0, | ||
456 | (20 - 1) * | ||
457 | ATP_XFACT - 1, | ||
458 | ATP_FUZZ, 0); | ||
459 | else | ||
460 | input_set_abs_params(dev->input, ABS_X, | ||
461 | 0, | ||
462 | (26 - 1) * | ||
463 | ATP_XFACT - 1, | ||
464 | ATP_FUZZ, 0); | ||
465 | break; | ||
466 | } | ||
467 | |||
468 | dev->size_detect_done = 1; | ||
434 | goto exit; | 469 | goto exit; |
470 | } | ||
471 | } | ||
435 | 472 | ||
436 | /* 17" Powerbooks have extra X sensors */ | 473 | for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { |
437 | for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); | 474 | /* accumulate the change */ |
438 | i < ATP_XSENSORS; i++) { | 475 | signed char change = dev->xy_old[i] - dev->xy_cur[i]; |
439 | if (!dev->xy_cur[i]) | 476 | dev->xy_acc[i] -= change; |
440 | continue; | 477 | |
441 | 478 | /* prevent down drifting */ | |
442 | printk(KERN_INFO "appletouch: 17\" model detected.\n"); | 479 | if (dev->xy_acc[i] < 0) |
443 | if (dev->type == ATP_GEYSER2) | 480 | dev->xy_acc[i] = 0; |
444 | input_set_abs_params(dev->input, ABS_X, 0, | 481 | } |
445 | (20 - 1) * | 482 | |
446 | ATP_XFACT - 1, | 483 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); |
447 | ATP_FUZZ, 0); | 484 | |
448 | else | 485 | dbg_dump("accumulator", dev->xy_acc); |
449 | input_set_abs_params(dev->input, ABS_X, 0, | 486 | |
450 | (ATP_XSENSORS - 1) * | 487 | x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, |
451 | ATP_XFACT - 1, | 488 | ATP_XFACT, &x_z, &x_f); |
452 | ATP_FUZZ, 0); | 489 | y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, |
453 | break; | 490 | ATP_YFACT, &y_z, &y_f); |
491 | key = dev->data[dev->datalen - 1] & 1; | ||
492 | |||
493 | if (x && y) { | ||
494 | if (dev->x_old != -1) { | ||
495 | x = (dev->x_old * 3 + x) >> 2; | ||
496 | y = (dev->y_old * 3 + y) >> 2; | ||
497 | dev->x_old = x; | ||
498 | dev->y_old = y; | ||
499 | |||
500 | if (debug > 1) | ||
501 | printk(KERN_DEBUG "appletouch: " | ||
502 | "X: %3d Y: %3d Xz: %3d Yz: %3d\n", | ||
503 | x, y, x_z, y_z); | ||
504 | |||
505 | input_report_key(dev->input, BTN_TOUCH, 1); | ||
506 | input_report_abs(dev->input, ABS_X, x); | ||
507 | input_report_abs(dev->input, ABS_Y, y); | ||
508 | input_report_abs(dev->input, ABS_PRESSURE, | ||
509 | min(ATP_PRESSURE, x_z + y_z)); | ||
510 | atp_report_fingers(dev->input, max(x_f, y_f)); | ||
454 | } | 511 | } |
512 | dev->x_old = x; | ||
513 | dev->y_old = y; | ||
514 | |||
515 | } else if (!x && !y) { | ||
516 | |||
517 | dev->x_old = dev->y_old = -1; | ||
518 | input_report_key(dev->input, BTN_TOUCH, 0); | ||
519 | input_report_abs(dev->input, ABS_PRESSURE, 0); | ||
520 | atp_report_fingers(dev->input, 0); | ||
521 | |||
522 | /* reset the accumulator on release */ | ||
523 | memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); | ||
524 | } | ||
525 | |||
526 | input_report_key(dev->input, BTN_LEFT, key); | ||
527 | input_sync(dev->input); | ||
528 | |||
529 | exit: | ||
530 | retval = usb_submit_urb(dev->urb, GFP_ATOMIC); | ||
531 | if (retval) | ||
532 | err("atp_complete: usb_submit_urb failed with result %d", | ||
533 | retval); | ||
534 | } | ||
535 | |||
536 | /* Interrupt function for older touchpads: GEYSER3/GEYSER4 */ | ||
537 | |||
538 | static void atp_complete_geyser_3_4(struct urb *urb) | ||
539 | { | ||
540 | int x, y, x_z, y_z, x_f, y_f; | ||
541 | int retval, i, j; | ||
542 | int key; | ||
543 | struct atp *dev = urb->context; | ||
544 | int status = atp_status_check(urb); | ||
545 | |||
546 | if (status == ATP_URB_STATUS_ERROR_FATAL) | ||
547 | return; | ||
548 | else if (status == ATP_URB_STATUS_ERROR) | ||
549 | goto exit; | ||
550 | |||
551 | /* Reorder the sensors values: | ||
552 | * | ||
553 | * The values are laid out like this: | ||
554 | * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... | ||
555 | * '-' is an unused value. | ||
556 | */ | ||
557 | |||
558 | /* read X values */ | ||
559 | for (i = 0, j = 19; i < 20; i += 2, j += 3) { | ||
560 | dev->xy_cur[i] = dev->data[j + 1]; | ||
561 | dev->xy_cur[i + 1] = dev->data[j + 2]; | ||
562 | } | ||
563 | /* read Y values */ | ||
564 | for (i = 0, j = 1; i < 9; i += 2, j += 3) { | ||
565 | dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; | ||
566 | dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; | ||
567 | } | ||
568 | |||
569 | dbg_dump("sample", dev->xy_cur); | ||
570 | |||
571 | if (!dev->valid) { | ||
572 | /* first sample */ | ||
573 | dev->valid = true; | ||
574 | dev->x_old = dev->y_old = -1; | ||
575 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); | ||
455 | 576 | ||
456 | dev->size_detect_done = 1; | ||
457 | goto exit; | 577 | goto exit; |
458 | } | 578 | } |
459 | 579 | ||
@@ -514,28 +634,26 @@ static void atp_complete(struct urb *urb) | |||
514 | input_sync(dev->input); | 634 | input_sync(dev->input); |
515 | 635 | ||
516 | /* | 636 | /* |
517 | * Many Geysers will continue to send packets continually after | 637 | * Geysers 3/4 will continue to send packets continually after |
518 | * the first touch unless reinitialised. Do so if it's been | 638 | * the first touch unless reinitialised. Do so if it's been |
519 | * idle for a while in order to avoid waking the kernel up | 639 | * idle for a while in order to avoid waking the kernel up |
520 | * several hundred times a second. Re-initialization does not | 640 | * several hundred times a second. |
521 | * work on Fountain touchpads. | ||
522 | */ | 641 | */ |
523 | if (dev->type != ATP_FOUNTAIN) { | 642 | |
524 | /* | 643 | /* |
525 | * Button must not be pressed when entering suspend, | 644 | * Button must not be pressed when entering suspend, |
526 | * otherwise we will never release the button. | 645 | * otherwise we will never release the button. |
527 | */ | 646 | */ |
528 | if (!x && !y && !key) { | 647 | if (!x && !y && !key) { |
529 | dev->idlecount++; | 648 | dev->idlecount++; |
530 | if (dev->idlecount == 10) { | 649 | if (dev->idlecount == 10) { |
531 | dev->valid = false; | 650 | dev->valid = false; |
532 | schedule_work(&dev->work); | 651 | schedule_work(&dev->work); |
533 | /* Don't resubmit urb here, wait for reinit */ | 652 | /* Don't resubmit urb here, wait for reinit */ |
534 | return; | 653 | return; |
535 | } | 654 | } |
536 | } else | 655 | } else |
537 | dev->idlecount = 0; | 656 | dev->idlecount = 0; |
538 | } | ||
539 | 657 | ||
540 | exit: | 658 | exit: |
541 | retval = usb_submit_urb(dev->urb, GFP_ATOMIC); | 659 | retval = usb_submit_urb(dev->urb, GFP_ATOMIC); |
@@ -632,9 +750,19 @@ static int atp_probe(struct usb_interface *iface, | |||
632 | if (!dev->data) | 750 | if (!dev->data) |
633 | goto err_free_urb; | 751 | goto err_free_urb; |
634 | 752 | ||
635 | usb_fill_int_urb(dev->urb, udev, | 753 | /* Select the USB complete (callback) function */ |
636 | usb_rcvintpipe(udev, int_in_endpointAddr), | 754 | if (dev->type == ATP_FOUNTAIN || |
637 | dev->data, dev->datalen, atp_complete, dev, 1); | 755 | dev->type == ATP_GEYSER1 || |
756 | dev->type == ATP_GEYSER2) | ||
757 | usb_fill_int_urb(dev->urb, udev, | ||
758 | usb_rcvintpipe(udev, int_in_endpointAddr), | ||
759 | dev->data, dev->datalen, | ||
760 | atp_complete_geyser_1_2, dev, 1); | ||
761 | else | ||
762 | usb_fill_int_urb(dev->urb, udev, | ||
763 | usb_rcvintpipe(udev, int_in_endpointAddr), | ||
764 | dev->data, dev->datalen, | ||
765 | atp_complete_geyser_3_4, dev, 1); | ||
638 | 766 | ||
639 | error = atp_handle_geyser(dev); | 767 | error = atp_handle_geyser(dev); |
640 | if (error) | 768 | if (error) |