2020-05-30 07:44:31

by Jia-Ju Bai

[permalink] [raw]
Subject: [PATCH] input: tablet: aiptek: fix possible buffer overflow caused by bad DMA value in aiptek_irq()

The value aiptek->data is stored in DMA memory, and it is assigned to
data. Thus in the code:
macro = get_unaligned_le16(data + 1);
The value of marco can be modified by malicious hardware.
In this case, buffer overflow may occur when the code
"macroKeyEvents[macro - 1]" and "macroKeyEvents[macro]" is executed.

To fix these possible bugs, macro is checked before being used.

Signed-off-by: Jia-Ju Bai <[email protected]>
---
drivers/input/tablet/aiptek.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index e08b0ef078e8..e353e538fb51 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -737,11 +737,11 @@ static void aiptek_irq(struct urb *urb)
*/
else if (data[0] == 6) {
macro = get_unaligned_le16(data + 1);
- if (macro > 0) {
+ if (macro > 0 && macro < 34) {
input_report_key(inputdev, macroKeyEvents[macro - 1],
0);
}
- if (macro < 25) {
+ if (marco > 0 && macro < 25) {
input_report_key(inputdev, macroKeyEvents[macro + 1],
0);
}
@@ -760,7 +760,8 @@ static void aiptek_irq(struct urb *urb)
aiptek->curSetting.toolMode;
}

- input_report_key(inputdev, macroKeyEvents[macro], 1);
+ if (macro > 0 && macro < 33)
+ input_report_key(inputdev, macroKeyEvents[macro], 1);
input_report_abs(inputdev, ABS_MISC,
1 | AIPTEK_REPORT_TOOL_UNKNOWN);
input_sync(inputdev);
--
2.17.1


2020-06-01 02:08:49

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] input: tablet: aiptek: fix possible buffer overflow caused by bad DMA value in aiptek_irq()

Hi Jia-Ju,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on input/next]
[also build test ERROR on v5.7 next-20200529]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url: https://github.com/0day-ci/linux/commits/Jia-Ju-Bai/input-tablet-aiptek-fix-possible-buffer-overflow-caused-by-bad-DMA-value-in-aiptek_irq/20200601-015649
base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: s390-allyesconfig (attached as .config)
compiler: s390-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=s390

If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <[email protected]>

All errors (new ones prefixed by >>, old ones prefixed by <<):

drivers/input/tablet/aiptek.c: In function 'aiptek_irq':
>> drivers/input/tablet/aiptek.c:744:7: error: 'marco' undeclared (first use in this function); did you mean 'macro'?
744 | if (marco > 0 && macro < 25) {
| ^~~~~
| macro
drivers/input/tablet/aiptek.c:744:7: note: each undeclared identifier is reported only once for each function it appears in

vim +744 drivers/input/tablet/aiptek.c

377
378 /***********************************************************************
379 * aiptek_irq can receive one of six potential reports.
380 * The documentation for each is in the body of the function.
381 *
382 * The tablet reports on several attributes per invocation of
383 * aiptek_irq. Because the Linux Input Event system allows the
384 * transmission of ONE attribute per input_report_xxx() call,
385 * collation has to be done on the other end to reconstitute
386 * a complete tablet report. Further, the number of Input Event reports
387 * submitted varies, depending on what USB report type, and circumstance.
388 * To deal with this, EV_MSC is used to indicate an 'end-of-report'
389 * message. This has been an undocumented convention understood by the kernel
390 * tablet driver and clients such as gpm and XFree86's tablet drivers.
391 *
392 * Of the information received from the tablet, the one piece I
393 * cannot transmit is the proximity bit (without resorting to an EV_MSC
394 * convention above.) I therefore have taken over REL_MISC and ABS_MISC
395 * (for relative and absolute reports, respectively) for communicating
396 * Proximity. Why two events? I thought it interesting to know if the
397 * Proximity event occurred while the tablet was in absolute or relative
398 * mode.
399 * Update: REL_MISC proved not to be such a good idea. With REL_MISC you
400 * get an event transmitted each time. ABS_MISC works better, since it
401 * can be set and re-set. Thus, only using ABS_MISC from now on.
402 *
403 * Other tablets use the notion of a certain minimum stylus pressure
404 * to infer proximity. While that could have been done, that is yet
405 * another 'by convention' behavior, the documentation for which
406 * would be spread between two (or more) pieces of software.
407 *
408 * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
409 * replaced with the input_sync() method (which emits EV_SYN.)
410 */
411
412 static void aiptek_irq(struct urb *urb)
413 {
414 struct aiptek *aiptek = urb->context;
415 unsigned char *data = aiptek->data;
416 struct input_dev *inputdev = aiptek->inputdev;
417 struct usb_interface *intf = aiptek->intf;
418 int jitterable = 0;
419 int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
420
421 switch (urb->status) {
422 case 0:
423 /* Success */
424 break;
425
426 case -ECONNRESET:
427 case -ENOENT:
428 case -ESHUTDOWN:
429 /* This urb is terminated, clean up */
430 dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
431 __func__, urb->status);
432 return;
433
434 default:
435 dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
436 __func__, urb->status);
437 goto exit;
438 }
439
440 /* See if we are in a delay loop -- throw out report if true.
441 */
442 if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
443 goto exit;
444 }
445
446 aiptek->inDelay = 0;
447 aiptek->eventCount++;
448
449 /* Report 1 delivers relative coordinates with either a stylus
450 * or the mouse. You do not know, however, which input
451 * tool generated the event.
452 */
453 if (data[0] == 1) {
454 if (aiptek->curSetting.coordinateMode ==
455 AIPTEK_COORDINATE_ABSOLUTE_MODE) {
456 aiptek->diagnostic =
457 AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
458 } else {
459 x = (signed char) data[2];
460 y = (signed char) data[3];
461
462 /* jitterable keeps track of whether any button has been pressed.
463 * We're also using it to remap the physical mouse button mask
464 * to pseudo-settings. (We don't specifically care about it's
465 * value after moving/transposing mouse button bitmasks, except
466 * that a non-zero value indicates that one or more
467 * mouse button was pressed.)
468 */
469 jitterable = data[1] & 0x07;
470
471 left = (data[1] & aiptek->curSetting.mouseButtonLeft >> 2) != 0 ? 1 : 0;
472 right = (data[1] & aiptek->curSetting.mouseButtonRight >> 2) != 0 ? 1 : 0;
473 middle = (data[1] & aiptek->curSetting.mouseButtonMiddle >> 2) != 0 ? 1 : 0;
474
475 input_report_key(inputdev, BTN_LEFT, left);
476 input_report_key(inputdev, BTN_MIDDLE, middle);
477 input_report_key(inputdev, BTN_RIGHT, right);
478
479 input_report_abs(inputdev, ABS_MISC,
480 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
481 input_report_rel(inputdev, REL_X, x);
482 input_report_rel(inputdev, REL_Y, y);
483
484 /* Wheel support is in the form of a single-event
485 * firing.
486 */
487 if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
488 input_report_rel(inputdev, REL_WHEEL,
489 aiptek->curSetting.wheel);
490 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
491 }
492 if (aiptek->lastMacro != -1) {
493 input_report_key(inputdev,
494 macroKeyEvents[aiptek->lastMacro], 0);
495 aiptek->lastMacro = -1;
496 }
497 input_sync(inputdev);
498 }
499 }
500 /* Report 2 is delivered only by the stylus, and delivers
501 * absolute coordinates.
502 */
503 else if (data[0] == 2) {
504 if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
505 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
506 } else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
507 (aiptek->curSetting.pointerMode)) {
508 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
509 } else {
510 x = get_unaligned_le16(data + 1);
511 y = get_unaligned_le16(data + 3);
512 z = get_unaligned_le16(data + 6);
513
514 dv = (data[5] & 0x01) != 0 ? 1 : 0;
515 p = (data[5] & 0x02) != 0 ? 1 : 0;
516 tip = (data[5] & 0x04) != 0 ? 1 : 0;
517
518 /* Use jitterable to re-arrange button masks
519 */
520 jitterable = data[5] & 0x18;
521
522 bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
523 pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
524
525 /* dv indicates 'data valid' (e.g., the tablet is in sync
526 * and has delivered a "correct" report) We will ignore
527 * all 'bad' reports...
528 */
529 if (dv != 0) {
530 /* If the selected tool changed, reset the old
531 * tool key, and set the new one.
532 */
533 if (aiptek->previousToolMode !=
534 aiptek->curSetting.toolMode) {
535 input_report_key(inputdev,
536 aiptek->previousToolMode, 0);
537 input_report_key(inputdev,
538 aiptek->curSetting.toolMode,
539 1);
540 aiptek->previousToolMode =
541 aiptek->curSetting.toolMode;
542 }
543
544 if (p != 0) {
545 input_report_abs(inputdev, ABS_X, x);
546 input_report_abs(inputdev, ABS_Y, y);
547 input_report_abs(inputdev, ABS_PRESSURE, z);
548
549 input_report_key(inputdev, BTN_TOUCH, tip);
550 input_report_key(inputdev, BTN_STYLUS, bs);
551 input_report_key(inputdev, BTN_STYLUS2, pck);
552
553 if (aiptek->curSetting.xTilt !=
554 AIPTEK_TILT_DISABLE) {
555 input_report_abs(inputdev,
556 ABS_TILT_X,
557 aiptek->curSetting.xTilt);
558 }
559 if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
560 input_report_abs(inputdev,
561 ABS_TILT_Y,
562 aiptek->curSetting.yTilt);
563 }
564
565 /* Wheel support is in the form of a single-event
566 * firing.
567 */
568 if (aiptek->curSetting.wheel !=
569 AIPTEK_WHEEL_DISABLE) {
570 input_report_abs(inputdev,
571 ABS_WHEEL,
572 aiptek->curSetting.wheel);
573 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
574 }
575 }
576 input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
577 if (aiptek->lastMacro != -1) {
578 input_report_key(inputdev,
579 macroKeyEvents[aiptek->lastMacro], 0);
580 aiptek->lastMacro = -1;
581 }
582 input_sync(inputdev);
583 }
584 }
585 }
586 /* Report 3's come from the mouse in absolute mode.
587 */
588 else if (data[0] == 3) {
589 if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
590 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
591 } else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
592 (aiptek->curSetting.pointerMode)) {
593 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
594 } else {
595 x = get_unaligned_le16(data + 1);
596 y = get_unaligned_le16(data + 3);
597
598 jitterable = data[5] & 0x1c;
599
600 dv = (data[5] & 0x01) != 0 ? 1 : 0;
601 p = (data[5] & 0x02) != 0 ? 1 : 0;
602 left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
603 right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
604 middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
605
606 if (dv != 0) {
607 /* If the selected tool changed, reset the old
608 * tool key, and set the new one.
609 */
610 if (aiptek->previousToolMode !=
611 aiptek->curSetting.toolMode) {
612 input_report_key(inputdev,
613 aiptek->previousToolMode, 0);
614 input_report_key(inputdev,
615 aiptek->curSetting.toolMode,
616 1);
617 aiptek->previousToolMode =
618 aiptek->curSetting.toolMode;
619 }
620
621 if (p != 0) {
622 input_report_abs(inputdev, ABS_X, x);
623 input_report_abs(inputdev, ABS_Y, y);
624
625 input_report_key(inputdev, BTN_LEFT, left);
626 input_report_key(inputdev, BTN_MIDDLE, middle);
627 input_report_key(inputdev, BTN_RIGHT, right);
628
629 /* Wheel support is in the form of a single-event
630 * firing.
631 */
632 if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
633 input_report_abs(inputdev,
634 ABS_WHEEL,
635 aiptek->curSetting.wheel);
636 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
637 }
638 }
639 input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
640 if (aiptek->lastMacro != -1) {
641 input_report_key(inputdev,
642 macroKeyEvents[aiptek->lastMacro], 0);
643 aiptek->lastMacro = -1;
644 }
645 input_sync(inputdev);
646 }
647 }
648 }
649 /* Report 4s come from the macro keys when pressed by stylus
650 */
651 else if (data[0] == 4) {
652 jitterable = data[1] & 0x18;
653
654 dv = (data[1] & 0x01) != 0 ? 1 : 0;
655 p = (data[1] & 0x02) != 0 ? 1 : 0;
656 tip = (data[1] & 0x04) != 0 ? 1 : 0;
657 bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
658 pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
659
660 macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
661 z = get_unaligned_le16(data + 4);
662
663 if (dv) {
664 /* If the selected tool changed, reset the old
665 * tool key, and set the new one.
666 */
667 if (aiptek->previousToolMode !=
668 aiptek->curSetting.toolMode) {
669 input_report_key(inputdev,
670 aiptek->previousToolMode, 0);
671 input_report_key(inputdev,
672 aiptek->curSetting.toolMode,
673 1);
674 aiptek->previousToolMode =
675 aiptek->curSetting.toolMode;
676 }
677 }
678
679 if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
680 input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
681 aiptek->lastMacro = -1;
682 }
683
684 if (macro != -1 && macro != aiptek->lastMacro) {
685 input_report_key(inputdev, macroKeyEvents[macro], 1);
686 aiptek->lastMacro = macro;
687 }
688 input_report_abs(inputdev, ABS_MISC,
689 p | AIPTEK_REPORT_TOOL_STYLUS);
690 input_sync(inputdev);
691 }
692 /* Report 5s come from the macro keys when pressed by mouse
693 */
694 else if (data[0] == 5) {
695 jitterable = data[1] & 0x1c;
696
697 dv = (data[1] & 0x01) != 0 ? 1 : 0;
698 p = (data[1] & 0x02) != 0 ? 1 : 0;
699 left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
700 right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
701 middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
702 macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0;
703
704 if (dv) {
705 /* If the selected tool changed, reset the old
706 * tool key, and set the new one.
707 */
708 if (aiptek->previousToolMode !=
709 aiptek->curSetting.toolMode) {
710 input_report_key(inputdev,
711 aiptek->previousToolMode, 0);
712 input_report_key(inputdev,
713 aiptek->curSetting.toolMode, 1);
714 aiptek->previousToolMode = aiptek->curSetting.toolMode;
715 }
716 }
717
718 if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
719 input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
720 aiptek->lastMacro = -1;
721 }
722
723 if (macro != -1 && macro != aiptek->lastMacro) {
724 input_report_key(inputdev, macroKeyEvents[macro], 1);
725 aiptek->lastMacro = macro;
726 }
727
728 input_report_abs(inputdev, ABS_MISC,
729 p | AIPTEK_REPORT_TOOL_MOUSE);
730 input_sync(inputdev);
731 }
732 /* We have no idea which tool can generate a report 6. Theoretically,
733 * neither need to, having been given reports 4 & 5 for such use.
734 * However, report 6 is the 'official-looking' report for macroKeys;
735 * reports 4 & 5 supposively are used to support unnamed, unknown
736 * hat switches (which just so happen to be the macroKeys.)
737 */
738 else if (data[0] == 6) {
739 macro = get_unaligned_le16(data + 1);
740 if (macro > 0 && macro < 34) {
741 input_report_key(inputdev, macroKeyEvents[macro - 1],
742 0);
743 }
> 744 if (marco > 0 && macro < 25) {
745 input_report_key(inputdev, macroKeyEvents[macro + 1],
746 0);
747 }
748
749 /* If the selected tool changed, reset the old
750 tool key, and set the new one.
751 */
752 if (aiptek->previousToolMode !=
753 aiptek->curSetting.toolMode) {
754 input_report_key(inputdev,
755 aiptek->previousToolMode, 0);
756 input_report_key(inputdev,
757 aiptek->curSetting.toolMode,
758 1);
759 aiptek->previousToolMode =
760 aiptek->curSetting.toolMode;
761 }
762
763 if (macro > 0 && macro < 33)
764 input_report_key(inputdev, macroKeyEvents[macro], 1);
765 input_report_abs(inputdev, ABS_MISC,
766 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
767 input_sync(inputdev);
768 } else {
769 dev_dbg(&intf->dev, "Unknown report %d\n", data[0]);
770 }
771
772 /* Jitter may occur when the user presses a button on the stlyus
773 * or the mouse. What we do to prevent that is wait 'x' milliseconds
774 * following a 'jitterable' event, which should give the hand some time
775 * stabilize itself.
776 *
777 * We just introduced aiptek->previousJitterable to carry forth the
778 * notion that jitter occurs when the button state changes from on to off:
779 * a person drawing, holding a button down is not subject to jittering.
780 * With that in mind, changing from upper button depressed to lower button
781 * WILL transition through a jitter delay.
782 */
783
784 if (aiptek->previousJitterable != jitterable &&
785 aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
786 aiptek->endDelay = jiffies +
787 ((aiptek->curSetting.jitterDelay * HZ) / 1000);
788 aiptek->inDelay = 1;
789 }
790 aiptek->previousJitterable = jitterable;
791
792 exit:
793 retval = usb_submit_urb(urb, GFP_ATOMIC);
794 if (retval != 0) {
795 dev_err(&intf->dev,
796 "%s - usb_submit_urb failed with result %d\n",
797 __func__, retval);
798 }
799 }
800

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (18.90 kB)
.config.gz (56.97 kB)
Download all attachments

2020-06-01 04:01:40

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] input: tablet: aiptek: fix possible buffer overflow caused by bad DMA value in aiptek_irq()

Hi Jia-Ju,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on input/next]
[also build test WARNING on v5.7 next-20200529]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url: https://github.com/0day-ci/linux/commits/Jia-Ju-Bai/input-tablet-aiptek-fix-possible-buffer-overflow-caused-by-bad-DMA-value-in-aiptek_irq/20200601-015649
base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: mips-randconfig-r032-20200531 (attached as .config)
compiler: mipsel-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips

If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <[email protected]>

All warnings (new ones prefixed by >>, old ones prefixed by <<):

In file included from include/asm-generic/div64.h:25,
from arch/mips/include/asm/div64.h:12,
from include/linux/math64.h:6,
from include/linux/jiffies.h:6,
from drivers/input/tablet/aiptek.c:60:
drivers/input/tablet/aiptek.c: In function 'aiptek_irq':
drivers/input/tablet/aiptek.c:744:7: error: 'marco' undeclared (first use in this function); did you mean 'macro'?
744 | if (marco > 0 && macro < 25) {
| ^~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
>> drivers/input/tablet/aiptek.c:744:3: note: in expansion of macro 'if'
744 | if (marco > 0 && macro < 25) {
| ^~
drivers/input/tablet/aiptek.c:744:7: note: each undeclared identifier is reported only once for each function it appears in
744 | if (marco > 0 && macro < 25) {
| ^~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
>> drivers/input/tablet/aiptek.c:744:3: note: in expansion of macro 'if'
744 | if (marco > 0 && macro < 25) {
| ^~

vim +/if +744 drivers/input/tablet/aiptek.c

377
378 /***********************************************************************
379 * aiptek_irq can receive one of six potential reports.
380 * The documentation for each is in the body of the function.
381 *
382 * The tablet reports on several attributes per invocation of
383 * aiptek_irq. Because the Linux Input Event system allows the
384 * transmission of ONE attribute per input_report_xxx() call,
385 * collation has to be done on the other end to reconstitute
386 * a complete tablet report. Further, the number of Input Event reports
387 * submitted varies, depending on what USB report type, and circumstance.
388 * To deal with this, EV_MSC is used to indicate an 'end-of-report'
389 * message. This has been an undocumented convention understood by the kernel
390 * tablet driver and clients such as gpm and XFree86's tablet drivers.
391 *
392 * Of the information received from the tablet, the one piece I
393 * cannot transmit is the proximity bit (without resorting to an EV_MSC
394 * convention above.) I therefore have taken over REL_MISC and ABS_MISC
395 * (for relative and absolute reports, respectively) for communicating
396 * Proximity. Why two events? I thought it interesting to know if the
397 * Proximity event occurred while the tablet was in absolute or relative
398 * mode.
399 * Update: REL_MISC proved not to be such a good idea. With REL_MISC you
400 * get an event transmitted each time. ABS_MISC works better, since it
401 * can be set and re-set. Thus, only using ABS_MISC from now on.
402 *
403 * Other tablets use the notion of a certain minimum stylus pressure
404 * to infer proximity. While that could have been done, that is yet
405 * another 'by convention' behavior, the documentation for which
406 * would be spread between two (or more) pieces of software.
407 *
408 * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
409 * replaced with the input_sync() method (which emits EV_SYN.)
410 */
411
412 static void aiptek_irq(struct urb *urb)
413 {
414 struct aiptek *aiptek = urb->context;
415 unsigned char *data = aiptek->data;
416 struct input_dev *inputdev = aiptek->inputdev;
417 struct usb_interface *intf = aiptek->intf;
418 int jitterable = 0;
419 int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
420
421 switch (urb->status) {
422 case 0:
423 /* Success */
424 break;
425
426 case -ECONNRESET:
427 case -ENOENT:
428 case -ESHUTDOWN:
429 /* This urb is terminated, clean up */
430 dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
431 __func__, urb->status);
432 return;
433
434 default:
435 dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
436 __func__, urb->status);
437 goto exit;
438 }
439
440 /* See if we are in a delay loop -- throw out report if true.
441 */
442 if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
443 goto exit;
444 }
445
446 aiptek->inDelay = 0;
447 aiptek->eventCount++;
448
449 /* Report 1 delivers relative coordinates with either a stylus
450 * or the mouse. You do not know, however, which input
451 * tool generated the event.
452 */
453 if (data[0] == 1) {
454 if (aiptek->curSetting.coordinateMode ==
455 AIPTEK_COORDINATE_ABSOLUTE_MODE) {
456 aiptek->diagnostic =
457 AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
458 } else {
459 x = (signed char) data[2];
460 y = (signed char) data[3];
461
462 /* jitterable keeps track of whether any button has been pressed.
463 * We're also using it to remap the physical mouse button mask
464 * to pseudo-settings. (We don't specifically care about it's
465 * value after moving/transposing mouse button bitmasks, except
466 * that a non-zero value indicates that one or more
467 * mouse button was pressed.)
468 */
469 jitterable = data[1] & 0x07;
470
471 left = (data[1] & aiptek->curSetting.mouseButtonLeft >> 2) != 0 ? 1 : 0;
472 right = (data[1] & aiptek->curSetting.mouseButtonRight >> 2) != 0 ? 1 : 0;
473 middle = (data[1] & aiptek->curSetting.mouseButtonMiddle >> 2) != 0 ? 1 : 0;
474
475 input_report_key(inputdev, BTN_LEFT, left);
476 input_report_key(inputdev, BTN_MIDDLE, middle);
477 input_report_key(inputdev, BTN_RIGHT, right);
478
479 input_report_abs(inputdev, ABS_MISC,
480 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
481 input_report_rel(inputdev, REL_X, x);
482 input_report_rel(inputdev, REL_Y, y);
483
484 /* Wheel support is in the form of a single-event
485 * firing.
486 */
487 if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
488 input_report_rel(inputdev, REL_WHEEL,
489 aiptek->curSetting.wheel);
490 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
491 }
492 if (aiptek->lastMacro != -1) {
493 input_report_key(inputdev,
494 macroKeyEvents[aiptek->lastMacro], 0);
495 aiptek->lastMacro = -1;
496 }
497 input_sync(inputdev);
498 }
499 }
500 /* Report 2 is delivered only by the stylus, and delivers
501 * absolute coordinates.
502 */
503 else if (data[0] == 2) {
504 if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
505 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
506 } else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
507 (aiptek->curSetting.pointerMode)) {
508 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
509 } else {
510 x = get_unaligned_le16(data + 1);
511 y = get_unaligned_le16(data + 3);
512 z = get_unaligned_le16(data + 6);
513
514 dv = (data[5] & 0x01) != 0 ? 1 : 0;
515 p = (data[5] & 0x02) != 0 ? 1 : 0;
516 tip = (data[5] & 0x04) != 0 ? 1 : 0;
517
518 /* Use jitterable to re-arrange button masks
519 */
520 jitterable = data[5] & 0x18;
521
522 bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
523 pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
524
525 /* dv indicates 'data valid' (e.g., the tablet is in sync
526 * and has delivered a "correct" report) We will ignore
527 * all 'bad' reports...
528 */
529 if (dv != 0) {
530 /* If the selected tool changed, reset the old
531 * tool key, and set the new one.
532 */
533 if (aiptek->previousToolMode !=
534 aiptek->curSetting.toolMode) {
535 input_report_key(inputdev,
536 aiptek->previousToolMode, 0);
537 input_report_key(inputdev,
538 aiptek->curSetting.toolMode,
539 1);
540 aiptek->previousToolMode =
541 aiptek->curSetting.toolMode;
542 }
543
544 if (p != 0) {
545 input_report_abs(inputdev, ABS_X, x);
546 input_report_abs(inputdev, ABS_Y, y);
547 input_report_abs(inputdev, ABS_PRESSURE, z);
548
549 input_report_key(inputdev, BTN_TOUCH, tip);
550 input_report_key(inputdev, BTN_STYLUS, bs);
551 input_report_key(inputdev, BTN_STYLUS2, pck);
552
553 if (aiptek->curSetting.xTilt !=
554 AIPTEK_TILT_DISABLE) {
555 input_report_abs(inputdev,
556 ABS_TILT_X,
557 aiptek->curSetting.xTilt);
558 }
559 if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
560 input_report_abs(inputdev,
561 ABS_TILT_Y,
562 aiptek->curSetting.yTilt);
563 }
564
565 /* Wheel support is in the form of a single-event
566 * firing.
567 */
568 if (aiptek->curSetting.wheel !=
569 AIPTEK_WHEEL_DISABLE) {
570 input_report_abs(inputdev,
571 ABS_WHEEL,
572 aiptek->curSetting.wheel);
573 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
574 }
575 }
576 input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
577 if (aiptek->lastMacro != -1) {
578 input_report_key(inputdev,
579 macroKeyEvents[aiptek->lastMacro], 0);
580 aiptek->lastMacro = -1;
581 }
582 input_sync(inputdev);
583 }
584 }
585 }
586 /* Report 3's come from the mouse in absolute mode.
587 */
588 else if (data[0] == 3) {
589 if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
590 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
591 } else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
592 (aiptek->curSetting.pointerMode)) {
593 aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
594 } else {
595 x = get_unaligned_le16(data + 1);
596 y = get_unaligned_le16(data + 3);
597
598 jitterable = data[5] & 0x1c;
599
600 dv = (data[5] & 0x01) != 0 ? 1 : 0;
601 p = (data[5] & 0x02) != 0 ? 1 : 0;
602 left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
603 right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
604 middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
605
606 if (dv != 0) {
607 /* If the selected tool changed, reset the old
608 * tool key, and set the new one.
609 */
610 if (aiptek->previousToolMode !=
611 aiptek->curSetting.toolMode) {
612 input_report_key(inputdev,
613 aiptek->previousToolMode, 0);
614 input_report_key(inputdev,
615 aiptek->curSetting.toolMode,
616 1);
617 aiptek->previousToolMode =
618 aiptek->curSetting.toolMode;
619 }
620
621 if (p != 0) {
622 input_report_abs(inputdev, ABS_X, x);
623 input_report_abs(inputdev, ABS_Y, y);
624
625 input_report_key(inputdev, BTN_LEFT, left);
626 input_report_key(inputdev, BTN_MIDDLE, middle);
627 input_report_key(inputdev, BTN_RIGHT, right);
628
629 /* Wheel support is in the form of a single-event
630 * firing.
631 */
632 if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
633 input_report_abs(inputdev,
634 ABS_WHEEL,
635 aiptek->curSetting.wheel);
636 aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
637 }
638 }
639 input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
640 if (aiptek->lastMacro != -1) {
641 input_report_key(inputdev,
642 macroKeyEvents[aiptek->lastMacro], 0);
643 aiptek->lastMacro = -1;
644 }
645 input_sync(inputdev);
646 }
647 }
648 }
649 /* Report 4s come from the macro keys when pressed by stylus
650 */
651 else if (data[0] == 4) {
652 jitterable = data[1] & 0x18;
653
654 dv = (data[1] & 0x01) != 0 ? 1 : 0;
655 p = (data[1] & 0x02) != 0 ? 1 : 0;
656 tip = (data[1] & 0x04) != 0 ? 1 : 0;
657 bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
658 pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
659
660 macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
661 z = get_unaligned_le16(data + 4);
662
663 if (dv) {
664 /* If the selected tool changed, reset the old
665 * tool key, and set the new one.
666 */
667 if (aiptek->previousToolMode !=
668 aiptek->curSetting.toolMode) {
669 input_report_key(inputdev,
670 aiptek->previousToolMode, 0);
671 input_report_key(inputdev,
672 aiptek->curSetting.toolMode,
673 1);
674 aiptek->previousToolMode =
675 aiptek->curSetting.toolMode;
676 }
677 }
678
679 if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
680 input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
681 aiptek->lastMacro = -1;
682 }
683
684 if (macro != -1 && macro != aiptek->lastMacro) {
685 input_report_key(inputdev, macroKeyEvents[macro], 1);
686 aiptek->lastMacro = macro;
687 }
688 input_report_abs(inputdev, ABS_MISC,
689 p | AIPTEK_REPORT_TOOL_STYLUS);
690 input_sync(inputdev);
691 }
692 /* Report 5s come from the macro keys when pressed by mouse
693 */
694 else if (data[0] == 5) {
695 jitterable = data[1] & 0x1c;
696
697 dv = (data[1] & 0x01) != 0 ? 1 : 0;
698 p = (data[1] & 0x02) != 0 ? 1 : 0;
699 left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
700 right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
701 middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
702 macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0;
703
704 if (dv) {
705 /* If the selected tool changed, reset the old
706 * tool key, and set the new one.
707 */
708 if (aiptek->previousToolMode !=
709 aiptek->curSetting.toolMode) {
710 input_report_key(inputdev,
711 aiptek->previousToolMode, 0);
712 input_report_key(inputdev,
713 aiptek->curSetting.toolMode, 1);
714 aiptek->previousToolMode = aiptek->curSetting.toolMode;
715 }
716 }
717
718 if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
719 input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
720 aiptek->lastMacro = -1;
721 }
722
723 if (macro != -1 && macro != aiptek->lastMacro) {
724 input_report_key(inputdev, macroKeyEvents[macro], 1);
725 aiptek->lastMacro = macro;
726 }
727
728 input_report_abs(inputdev, ABS_MISC,
729 p | AIPTEK_REPORT_TOOL_MOUSE);
730 input_sync(inputdev);
731 }
732 /* We have no idea which tool can generate a report 6. Theoretically,
733 * neither need to, having been given reports 4 & 5 for such use.
734 * However, report 6 is the 'official-looking' report for macroKeys;
735 * reports 4 & 5 supposively are used to support unnamed, unknown
736 * hat switches (which just so happen to be the macroKeys.)
737 */
738 else if (data[0] == 6) {
739 macro = get_unaligned_le16(data + 1);
740 if (macro > 0 && macro < 34) {
741 input_report_key(inputdev, macroKeyEvents[macro - 1],
742 0);
743 }
> 744 if (marco > 0 && macro < 25) {
745 input_report_key(inputdev, macroKeyEvents[macro + 1],
746 0);
747 }
748
749 /* If the selected tool changed, reset the old
750 tool key, and set the new one.
751 */
752 if (aiptek->previousToolMode !=
753 aiptek->curSetting.toolMode) {
754 input_report_key(inputdev,
755 aiptek->previousToolMode, 0);
756 input_report_key(inputdev,
757 aiptek->curSetting.toolMode,
758 1);
759 aiptek->previousToolMode =
760 aiptek->curSetting.toolMode;
761 }
762
763 if (macro > 0 && macro < 33)
764 input_report_key(inputdev, macroKeyEvents[macro], 1);
765 input_report_abs(inputdev, ABS_MISC,
766 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
767 input_sync(inputdev);
768 } else {
769 dev_dbg(&intf->dev, "Unknown report %d\n", data[0]);
770 }
771
772 /* Jitter may occur when the user presses a button on the stlyus
773 * or the mouse. What we do to prevent that is wait 'x' milliseconds
774 * following a 'jitterable' event, which should give the hand some time
775 * stabilize itself.
776 *
777 * We just introduced aiptek->previousJitterable to carry forth the
778 * notion that jitter occurs when the button state changes from on to off:
779 * a person drawing, holding a button down is not subject to jittering.
780 * With that in mind, changing from upper button depressed to lower button
781 * WILL transition through a jitter delay.
782 */
783
784 if (aiptek->previousJitterable != jitterable &&
785 aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
786 aiptek->endDelay = jiffies +
787 ((aiptek->curSetting.jitterDelay * HZ) / 1000);
788 aiptek->inDelay = 1;
789 }
790 aiptek->previousJitterable = jitterable;
791
792 exit:
793 retval = usb_submit_urb(urb, GFP_ATOMIC);
794 if (retval != 0) {
795 dev_err(&intf->dev,
796 "%s - usb_submit_urb failed with result %d\n",
797 __func__, retval);
798 }
799 }
800

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (19.86 kB)
.config.gz (33.20 kB)
Download all attachments