diff options
42 files changed, 3995 insertions, 1233 deletions
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index d56a01775423..5c17196c8fe9 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt | |||
@@ -177,13 +177,13 @@ virtual console (ALT+Fn) and then back again should also help. | |||
177 | 177 | ||
178 | * I hit SysRq, but nothing seems to happen, what's wrong? | 178 | * I hit SysRq, but nothing seems to happen, what's wrong? |
179 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 179 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
180 | There are some keyboards that send different scancodes for SysRq than the | 180 | There are some keyboards that produce a different keycode for SysRq than the |
181 | pre-defined 0x54. So if SysRq doesn't work out of the box for a certain | 181 | pre-defined value of 99 (see KEY_SYSRQ in include/linux/input.h), or which |
182 | keyboard, run 'showkey -s' to find out the proper scancode sequence. Then | 182 | don't have a SysRq key at all. In these cases, run 'showkey -s' to find an |
183 | use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRq | 183 | appropriate scancode sequence, and use 'setkeycodes <sequence> 99' to map |
184 | code (84 is decimal for 0x54). It's probably best to put this command in a | 184 | this sequence to the usual SysRq code (e.g., 'setkeycodes e05b 99'). It's |
185 | boot script. Oh, and by the way, you exit 'showkey' by not typing anything | 185 | probably best to put this command in a boot script. Oh, and by the way, you |
186 | for ten seconds. | 186 | exit 'showkey' by not typing anything for ten seconds. |
187 | 187 | ||
188 | * I want to add SysRQ key events to a module, how does it work? | 188 | * I want to add SysRQ key events to a module, how does it work? |
189 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 189 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index ada25bb8941e..54109dc9240c 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -24,6 +24,8 @@ | |||
24 | * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) | 24 | * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
28 | |||
27 | #include <linux/consolemap.h> | 29 | #include <linux/consolemap.h> |
28 | #include <linux/module.h> | 30 | #include <linux/module.h> |
29 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
@@ -38,7 +40,6 @@ | |||
38 | #include <linux/kbd_kern.h> | 40 | #include <linux/kbd_kern.h> |
39 | #include <linux/kbd_diacr.h> | 41 | #include <linux/kbd_diacr.h> |
40 | #include <linux/vt_kern.h> | 42 | #include <linux/vt_kern.h> |
41 | #include <linux/sysrq.h> | ||
42 | #include <linux/input.h> | 43 | #include <linux/input.h> |
43 | #include <linux/reboot.h> | 44 | #include <linux/reboot.h> |
44 | #include <linux/notifier.h> | 45 | #include <linux/notifier.h> |
@@ -82,8 +83,7 @@ void compute_shiftstate(void); | |||
82 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | 83 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, |
83 | char up_flag); | 84 | char up_flag); |
84 | static k_handler_fn K_HANDLERS; | 85 | static k_handler_fn K_HANDLERS; |
85 | k_handler_fn *k_handler[16] = { K_HANDLERS }; | 86 | static k_handler_fn *k_handler[16] = { K_HANDLERS }; |
86 | EXPORT_SYMBOL_GPL(k_handler); | ||
87 | 87 | ||
88 | #define FN_HANDLERS\ | 88 | #define FN_HANDLERS\ |
89 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ | 89 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ |
@@ -133,7 +133,7 @@ static struct input_handler kbd_handler; | |||
133 | static DEFINE_SPINLOCK(kbd_event_lock); | 133 | static DEFINE_SPINLOCK(kbd_event_lock); |
134 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ | 134 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
135 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 135 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
136 | static int dead_key_next; | 136 | static bool dead_key_next; |
137 | static int npadch = -1; /* -1 or number assembled on pad */ | 137 | static int npadch = -1; /* -1 or number assembled on pad */ |
138 | static unsigned int diacr; | 138 | static unsigned int diacr; |
139 | static char rep; /* flag telling character repeat */ | 139 | static char rep; /* flag telling character repeat */ |
@@ -147,22 +147,6 @@ static struct ledptr { | |||
147 | unsigned char valid:1; | 147 | unsigned char valid:1; |
148 | } ledptrs[3]; | 148 | } ledptrs[3]; |
149 | 149 | ||
150 | /* Simple translation table for the SysRq keys */ | ||
151 | |||
152 | #ifdef CONFIG_MAGIC_SYSRQ | ||
153 | unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = | ||
154 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | ||
155 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | ||
156 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | ||
157 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | ||
158 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | ||
159 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | ||
160 | "\r\000/"; /* 0x60 - 0x6f */ | ||
161 | static int sysrq_down; | ||
162 | static int sysrq_alt_use; | ||
163 | #endif | ||
164 | static int sysrq_alt; | ||
165 | |||
166 | /* | 150 | /* |
167 | * Notifier list for console keyboard events | 151 | * Notifier list for console keyboard events |
168 | */ | 152 | */ |
@@ -361,8 +345,8 @@ static void to_utf8(struct vc_data *vc, uint c) | |||
361 | /* 110***** 10****** */ | 345 | /* 110***** 10****** */ |
362 | put_queue(vc, 0xc0 | (c >> 6)); | 346 | put_queue(vc, 0xc0 | (c >> 6)); |
363 | put_queue(vc, 0x80 | (c & 0x3f)); | 347 | put_queue(vc, 0x80 | (c & 0x3f)); |
364 | } else if (c < 0x10000) { | 348 | } else if (c < 0x10000) { |
365 | if (c >= 0xD800 && c < 0xE000) | 349 | if (c >= 0xD800 && c < 0xE000) |
366 | return; | 350 | return; |
367 | if (c == 0xFFFF) | 351 | if (c == 0xFFFF) |
368 | return; | 352 | return; |
@@ -370,7 +354,7 @@ static void to_utf8(struct vc_data *vc, uint c) | |||
370 | put_queue(vc, 0xe0 | (c >> 12)); | 354 | put_queue(vc, 0xe0 | (c >> 12)); |
371 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); | 355 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); |
372 | put_queue(vc, 0x80 | (c & 0x3f)); | 356 | put_queue(vc, 0x80 | (c & 0x3f)); |
373 | } else if (c < 0x110000) { | 357 | } else if (c < 0x110000) { |
374 | /* 11110*** 10****** 10****** 10****** */ | 358 | /* 11110*** 10****** 10****** 10****** */ |
375 | put_queue(vc, 0xf0 | (c >> 18)); | 359 | put_queue(vc, 0xf0 | (c >> 18)); |
376 | put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); | 360 | put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); |
@@ -469,6 +453,7 @@ static void fn_enter(struct vc_data *vc) | |||
469 | } | 453 | } |
470 | diacr = 0; | 454 | diacr = 0; |
471 | } | 455 | } |
456 | |||
472 | put_queue(vc, 13); | 457 | put_queue(vc, 13); |
473 | if (vc_kbd_mode(kbd, VC_CRLF)) | 458 | if (vc_kbd_mode(kbd, VC_CRLF)) |
474 | put_queue(vc, 10); | 459 | put_queue(vc, 10); |
@@ -478,6 +463,7 @@ static void fn_caps_toggle(struct vc_data *vc) | |||
478 | { | 463 | { |
479 | if (rep) | 464 | if (rep) |
480 | return; | 465 | return; |
466 | |||
481 | chg_vc_kbd_led(kbd, VC_CAPSLOCK); | 467 | chg_vc_kbd_led(kbd, VC_CAPSLOCK); |
482 | } | 468 | } |
483 | 469 | ||
@@ -485,12 +471,14 @@ static void fn_caps_on(struct vc_data *vc) | |||
485 | { | 471 | { |
486 | if (rep) | 472 | if (rep) |
487 | return; | 473 | return; |
474 | |||
488 | set_vc_kbd_led(kbd, VC_CAPSLOCK); | 475 | set_vc_kbd_led(kbd, VC_CAPSLOCK); |
489 | } | 476 | } |
490 | 477 | ||
491 | static void fn_show_ptregs(struct vc_data *vc) | 478 | static void fn_show_ptregs(struct vc_data *vc) |
492 | { | 479 | { |
493 | struct pt_regs *regs = get_irq_regs(); | 480 | struct pt_regs *regs = get_irq_regs(); |
481 | |||
494 | if (regs) | 482 | if (regs) |
495 | show_regs(regs); | 483 | show_regs(regs); |
496 | } | 484 | } |
@@ -515,7 +503,7 @@ static void fn_hold(struct vc_data *vc) | |||
515 | 503 | ||
516 | static void fn_num(struct vc_data *vc) | 504 | static void fn_num(struct vc_data *vc) |
517 | { | 505 | { |
518 | if (vc_kbd_mode(kbd,VC_APPLIC)) | 506 | if (vc_kbd_mode(kbd, VC_APPLIC)) |
519 | applkey(vc, 'P', 1); | 507 | applkey(vc, 'P', 1); |
520 | else | 508 | else |
521 | fn_bare_num(vc); | 509 | fn_bare_num(vc); |
@@ -610,7 +598,7 @@ static void fn_boot_it(struct vc_data *vc) | |||
610 | 598 | ||
611 | static void fn_compose(struct vc_data *vc) | 599 | static void fn_compose(struct vc_data *vc) |
612 | { | 600 | { |
613 | dead_key_next = 1; | 601 | dead_key_next = true; |
614 | } | 602 | } |
615 | 603 | ||
616 | static void fn_spawn_con(struct vc_data *vc) | 604 | static void fn_spawn_con(struct vc_data *vc) |
@@ -657,7 +645,7 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) | |||
657 | 645 | ||
658 | static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) | 646 | static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) |
659 | { | 647 | { |
660 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); | 648 | pr_err("k_lowercase was called - impossible\n"); |
661 | } | 649 | } |
662 | 650 | ||
663 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) | 651 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) |
@@ -669,7 +657,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) | |||
669 | value = handle_diacr(vc, value); | 657 | value = handle_diacr(vc, value); |
670 | 658 | ||
671 | if (dead_key_next) { | 659 | if (dead_key_next) { |
672 | dead_key_next = 0; | 660 | dead_key_next = false; |
673 | diacr = value; | 661 | diacr = value; |
674 | return; | 662 | return; |
675 | } | 663 | } |
@@ -691,6 +679,7 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) | |||
691 | { | 679 | { |
692 | if (up_flag) | 680 | if (up_flag) |
693 | return; | 681 | return; |
682 | |||
694 | diacr = (diacr ? handle_diacr(vc, value) : value); | 683 | diacr = (diacr ? handle_diacr(vc, value) : value); |
695 | } | 684 | } |
696 | 685 | ||
@@ -710,29 +699,28 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) | |||
710 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) | 699 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) |
711 | { | 700 | { |
712 | static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; | 701 | static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; |
713 | value = ret_diacr[value]; | 702 | |
714 | k_deadunicode(vc, value, up_flag); | 703 | k_deadunicode(vc, ret_diacr[value], up_flag); |
715 | } | 704 | } |
716 | 705 | ||
717 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) | 706 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) |
718 | { | 707 | { |
719 | if (up_flag) | 708 | if (up_flag) |
720 | return; | 709 | return; |
710 | |||
721 | set_console(value); | 711 | set_console(value); |
722 | } | 712 | } |
723 | 713 | ||
724 | static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) | 714 | static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) |
725 | { | 715 | { |
726 | unsigned v; | ||
727 | |||
728 | if (up_flag) | 716 | if (up_flag) |
729 | return; | 717 | return; |
730 | v = value; | 718 | |
731 | if (v < ARRAY_SIZE(func_table)) { | 719 | if ((unsigned)value < ARRAY_SIZE(func_table)) { |
732 | if (func_table[value]) | 720 | if (func_table[value]) |
733 | puts_queue(vc, func_table[value]); | 721 | puts_queue(vc, func_table[value]); |
734 | } else | 722 | } else |
735 | printk(KERN_ERR "k_fn called with value=%d\n", value); | 723 | pr_err("k_fn called with value=%d\n", value); |
736 | } | 724 | } |
737 | 725 | ||
738 | static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) | 726 | static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) |
@@ -741,6 +729,7 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) | |||
741 | 729 | ||
742 | if (up_flag) | 730 | if (up_flag) |
743 | return; | 731 | return; |
732 | |||
744 | applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); | 733 | applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); |
745 | } | 734 | } |
746 | 735 | ||
@@ -758,43 +747,45 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) | |||
758 | return; | 747 | return; |
759 | } | 748 | } |
760 | 749 | ||
761 | if (!vc_kbd_led(kbd, VC_NUMLOCK)) | 750 | if (!vc_kbd_led(kbd, VC_NUMLOCK)) { |
751 | |||
762 | switch (value) { | 752 | switch (value) { |
763 | case KVAL(K_PCOMMA): | 753 | case KVAL(K_PCOMMA): |
764 | case KVAL(K_PDOT): | 754 | case KVAL(K_PDOT): |
765 | k_fn(vc, KVAL(K_REMOVE), 0); | 755 | k_fn(vc, KVAL(K_REMOVE), 0); |
766 | return; | 756 | return; |
767 | case KVAL(K_P0): | 757 | case KVAL(K_P0): |
768 | k_fn(vc, KVAL(K_INSERT), 0); | 758 | k_fn(vc, KVAL(K_INSERT), 0); |
769 | return; | 759 | return; |
770 | case KVAL(K_P1): | 760 | case KVAL(K_P1): |
771 | k_fn(vc, KVAL(K_SELECT), 0); | 761 | k_fn(vc, KVAL(K_SELECT), 0); |
772 | return; | 762 | return; |
773 | case KVAL(K_P2): | 763 | case KVAL(K_P2): |
774 | k_cur(vc, KVAL(K_DOWN), 0); | 764 | k_cur(vc, KVAL(K_DOWN), 0); |
775 | return; | 765 | return; |
776 | case KVAL(K_P3): | 766 | case KVAL(K_P3): |
777 | k_fn(vc, KVAL(K_PGDN), 0); | 767 | k_fn(vc, KVAL(K_PGDN), 0); |
778 | return; | 768 | return; |
779 | case KVAL(K_P4): | 769 | case KVAL(K_P4): |
780 | k_cur(vc, KVAL(K_LEFT), 0); | 770 | k_cur(vc, KVAL(K_LEFT), 0); |
781 | return; | 771 | return; |
782 | case KVAL(K_P6): | 772 | case KVAL(K_P6): |
783 | k_cur(vc, KVAL(K_RIGHT), 0); | 773 | k_cur(vc, KVAL(K_RIGHT), 0); |
784 | return; | 774 | return; |
785 | case KVAL(K_P7): | 775 | case KVAL(K_P7): |
786 | k_fn(vc, KVAL(K_FIND), 0); | 776 | k_fn(vc, KVAL(K_FIND), 0); |
787 | return; | 777 | return; |
788 | case KVAL(K_P8): | 778 | case KVAL(K_P8): |
789 | k_cur(vc, KVAL(K_UP), 0); | 779 | k_cur(vc, KVAL(K_UP), 0); |
790 | return; | 780 | return; |
791 | case KVAL(K_P9): | 781 | case KVAL(K_P9): |
792 | k_fn(vc, KVAL(K_PGUP), 0); | 782 | k_fn(vc, KVAL(K_PGUP), 0); |
793 | return; | 783 | return; |
794 | case KVAL(K_P5): | 784 | case KVAL(K_P5): |
795 | applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); | 785 | applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); |
796 | return; | 786 | return; |
797 | } | 787 | } |
788 | } | ||
798 | 789 | ||
799 | put_queue(vc, pad_chars[value]); | 790 | put_queue(vc, pad_chars[value]); |
800 | if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) | 791 | if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) |
@@ -880,6 +871,7 @@ static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) | |||
880 | { | 871 | { |
881 | if (up_flag || rep) | 872 | if (up_flag || rep) |
882 | return; | 873 | return; |
874 | |||
883 | chg_vc_kbd_lock(kbd, value); | 875 | chg_vc_kbd_lock(kbd, value); |
884 | } | 876 | } |
885 | 877 | ||
@@ -888,6 +880,7 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) | |||
888 | k_shift(vc, value, up_flag); | 880 | k_shift(vc, value, up_flag); |
889 | if (up_flag || rep) | 881 | if (up_flag || rep) |
890 | return; | 882 | return; |
883 | |||
891 | chg_vc_kbd_slock(kbd, value); | 884 | chg_vc_kbd_slock(kbd, value); |
892 | /* try to make Alt, oops, AltGr and such work */ | 885 | /* try to make Alt, oops, AltGr and such work */ |
893 | if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { | 886 | if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { |
@@ -925,12 +918,12 @@ static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) | |||
925 | 918 | ||
926 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) | 919 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) |
927 | { | 920 | { |
928 | static unsigned pressed,committing; | 921 | static unsigned pressed, committing; |
929 | static unsigned long releasestart; | 922 | static unsigned long releasestart; |
930 | 923 | ||
931 | if (kbd->kbdmode != VC_UNICODE) { | 924 | if (kbd->kbdmode != VC_UNICODE) { |
932 | if (!up_flag) | 925 | if (!up_flag) |
933 | printk("keyboard mode must be unicode for braille patterns\n"); | 926 | pr_warning("keyboard mode must be unicode for braille patterns\n"); |
934 | return; | 927 | return; |
935 | } | 928 | } |
936 | 929 | ||
@@ -942,32 +935,28 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) | |||
942 | if (value > 8) | 935 | if (value > 8) |
943 | return; | 936 | return; |
944 | 937 | ||
945 | if (up_flag) { | 938 | if (!up_flag) { |
946 | if (brl_timeout) { | ||
947 | if (!committing || | ||
948 | time_after(jiffies, | ||
949 | releasestart + msecs_to_jiffies(brl_timeout))) { | ||
950 | committing = pressed; | ||
951 | releasestart = jiffies; | ||
952 | } | ||
953 | pressed &= ~(1 << (value - 1)); | ||
954 | if (!pressed) { | ||
955 | if (committing) { | ||
956 | k_brlcommit(vc, committing, 0); | ||
957 | committing = 0; | ||
958 | } | ||
959 | } | ||
960 | } else { | ||
961 | if (committing) { | ||
962 | k_brlcommit(vc, committing, 0); | ||
963 | committing = 0; | ||
964 | } | ||
965 | pressed &= ~(1 << (value - 1)); | ||
966 | } | ||
967 | } else { | ||
968 | pressed |= 1 << (value - 1); | 939 | pressed |= 1 << (value - 1); |
969 | if (!brl_timeout) | 940 | if (!brl_timeout) |
970 | committing = pressed; | 941 | committing = pressed; |
942 | } else if (brl_timeout) { | ||
943 | if (!committing || | ||
944 | time_after(jiffies, | ||
945 | releasestart + msecs_to_jiffies(brl_timeout))) { | ||
946 | committing = pressed; | ||
947 | releasestart = jiffies; | ||
948 | } | ||
949 | pressed &= ~(1 << (value - 1)); | ||
950 | if (!pressed && committing) { | ||
951 | k_brlcommit(vc, committing, 0); | ||
952 | committing = 0; | ||
953 | } | ||
954 | } else { | ||
955 | if (committing) { | ||
956 | k_brlcommit(vc, committing, 0); | ||
957 | committing = 0; | ||
958 | } | ||
959 | pressed &= ~(1 << (value - 1)); | ||
971 | } | 960 | } |
972 | } | 961 | } |
973 | 962 | ||
@@ -988,6 +977,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) | |||
988 | kbd->ledmode = LED_SHOW_IOCTL; | 977 | kbd->ledmode = LED_SHOW_IOCTL; |
989 | } else | 978 | } else |
990 | kbd->ledmode = LED_SHOW_FLAGS; | 979 | kbd->ledmode = LED_SHOW_FLAGS; |
980 | |||
991 | set_leds(); | 981 | set_leds(); |
992 | } | 982 | } |
993 | 983 | ||
@@ -1075,7 +1065,7 @@ static const unsigned short x86_keycodes[256] = | |||
1075 | 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; | 1065 | 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; |
1076 | 1066 | ||
1077 | #ifdef CONFIG_SPARC | 1067 | #ifdef CONFIG_SPARC |
1078 | static int sparc_l1_a_state = 0; | 1068 | static int sparc_l1_a_state; |
1079 | extern void sun_do_break(void); | 1069 | extern void sun_do_break(void); |
1080 | #endif | 1070 | #endif |
1081 | 1071 | ||
@@ -1085,52 +1075,54 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, | |||
1085 | int code; | 1075 | int code; |
1086 | 1076 | ||
1087 | switch (keycode) { | 1077 | switch (keycode) { |
1088 | case KEY_PAUSE: | ||
1089 | put_queue(vc, 0xe1); | ||
1090 | put_queue(vc, 0x1d | up_flag); | ||
1091 | put_queue(vc, 0x45 | up_flag); | ||
1092 | break; | ||
1093 | 1078 | ||
1094 | case KEY_HANGEUL: | 1079 | case KEY_PAUSE: |
1095 | if (!up_flag) | 1080 | put_queue(vc, 0xe1); |
1096 | put_queue(vc, 0xf2); | 1081 | put_queue(vc, 0x1d | up_flag); |
1097 | break; | 1082 | put_queue(vc, 0x45 | up_flag); |
1083 | break; | ||
1098 | 1084 | ||
1099 | case KEY_HANJA: | 1085 | case KEY_HANGEUL: |
1100 | if (!up_flag) | 1086 | if (!up_flag) |
1101 | put_queue(vc, 0xf1); | 1087 | put_queue(vc, 0xf2); |
1102 | break; | 1088 | break; |
1103 | 1089 | ||
1104 | case KEY_SYSRQ: | 1090 | case KEY_HANJA: |
1105 | /* | 1091 | if (!up_flag) |
1106 | * Real AT keyboards (that's what we're trying | 1092 | put_queue(vc, 0xf1); |
1107 | * to emulate here emit 0xe0 0x2a 0xe0 0x37 when | 1093 | break; |
1108 | * pressing PrtSc/SysRq alone, but simply 0x54 | ||
1109 | * when pressing Alt+PrtSc/SysRq. | ||
1110 | */ | ||
1111 | if (sysrq_alt) { | ||
1112 | put_queue(vc, 0x54 | up_flag); | ||
1113 | } else { | ||
1114 | put_queue(vc, 0xe0); | ||
1115 | put_queue(vc, 0x2a | up_flag); | ||
1116 | put_queue(vc, 0xe0); | ||
1117 | put_queue(vc, 0x37 | up_flag); | ||
1118 | } | ||
1119 | break; | ||
1120 | 1094 | ||
1121 | default: | 1095 | case KEY_SYSRQ: |
1122 | if (keycode > 255) | 1096 | /* |
1123 | return -1; | 1097 | * Real AT keyboards (that's what we're trying |
1098 | * to emulate here emit 0xe0 0x2a 0xe0 0x37 when | ||
1099 | * pressing PrtSc/SysRq alone, but simply 0x54 | ||
1100 | * when pressing Alt+PrtSc/SysRq. | ||
1101 | */ | ||
1102 | if (test_bit(KEY_LEFTALT, key_down) || | ||
1103 | test_bit(KEY_RIGHTALT, key_down)) { | ||
1104 | put_queue(vc, 0x54 | up_flag); | ||
1105 | } else { | ||
1106 | put_queue(vc, 0xe0); | ||
1107 | put_queue(vc, 0x2a | up_flag); | ||
1108 | put_queue(vc, 0xe0); | ||
1109 | put_queue(vc, 0x37 | up_flag); | ||
1110 | } | ||
1111 | break; | ||
1124 | 1112 | ||
1125 | code = x86_keycodes[keycode]; | 1113 | default: |
1126 | if (!code) | 1114 | if (keycode > 255) |
1127 | return -1; | 1115 | return -1; |
1128 | 1116 | ||
1129 | if (code & 0x100) | 1117 | code = x86_keycodes[keycode]; |
1130 | put_queue(vc, 0xe0); | 1118 | if (!code) |
1131 | put_queue(vc, (code & 0x7f) | up_flag); | 1119 | return -1; |
1132 | 1120 | ||
1133 | break; | 1121 | if (code & 0x100) |
1122 | put_queue(vc, 0xe0); | ||
1123 | put_queue(vc, (code & 0x7f) | up_flag); | ||
1124 | |||
1125 | break; | ||
1134 | } | 1126 | } |
1135 | 1127 | ||
1136 | return 0; | 1128 | return 0; |
@@ -1153,6 +1145,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u | |||
1153 | static void kbd_rawcode(unsigned char data) | 1145 | static void kbd_rawcode(unsigned char data) |
1154 | { | 1146 | { |
1155 | struct vc_data *vc = vc_cons[fg_console].d; | 1147 | struct vc_data *vc = vc_cons[fg_console].d; |
1148 | |||
1156 | kbd = kbd_table + vc->vc_num; | 1149 | kbd = kbd_table + vc->vc_num; |
1157 | if (kbd->kbdmode == VC_RAW) | 1150 | if (kbd->kbdmode == VC_RAW) |
1158 | put_queue(vc, data); | 1151 | put_queue(vc, data); |
@@ -1162,10 +1155,12 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1162 | { | 1155 | { |
1163 | struct vc_data *vc = vc_cons[fg_console].d; | 1156 | struct vc_data *vc = vc_cons[fg_console].d; |
1164 | unsigned short keysym, *key_map; | 1157 | unsigned short keysym, *key_map; |
1165 | unsigned char type, raw_mode; | 1158 | unsigned char type; |
1159 | bool raw_mode; | ||
1166 | struct tty_struct *tty; | 1160 | struct tty_struct *tty; |
1167 | int shift_final; | 1161 | int shift_final; |
1168 | struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; | 1162 | struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; |
1163 | int rc; | ||
1169 | 1164 | ||
1170 | tty = vc->vc_tty; | 1165 | tty = vc->vc_tty; |
1171 | 1166 | ||
@@ -1176,8 +1171,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1176 | 1171 | ||
1177 | kbd = kbd_table + vc->vc_num; | 1172 | kbd = kbd_table + vc->vc_num; |
1178 | 1173 | ||
1179 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | ||
1180 | sysrq_alt = down ? keycode : 0; | ||
1181 | #ifdef CONFIG_SPARC | 1174 | #ifdef CONFIG_SPARC |
1182 | if (keycode == KEY_STOP) | 1175 | if (keycode == KEY_STOP) |
1183 | sparc_l1_a_state = down; | 1176 | sparc_l1_a_state = down; |
@@ -1185,29 +1178,16 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1185 | 1178 | ||
1186 | rep = (down == 2); | 1179 | rep = (down == 2); |
1187 | 1180 | ||
1188 | if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) | 1181 | raw_mode = (kbd->kbdmode == VC_RAW); |
1182 | if (raw_mode && !hw_raw) | ||
1189 | if (emulate_raw(vc, keycode, !down << 7)) | 1183 | if (emulate_raw(vc, keycode, !down << 7)) |
1190 | if (keycode < BTN_MISC && printk_ratelimit()) | 1184 | if (keycode < BTN_MISC && printk_ratelimit()) |
1191 | printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); | 1185 | pr_warning("can't emulate rawmode for keycode %d\n", |
1186 | keycode); | ||
1192 | 1187 | ||
1193 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ | ||
1194 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { | ||
1195 | if (!sysrq_down) { | ||
1196 | sysrq_down = down; | ||
1197 | sysrq_alt_use = sysrq_alt; | ||
1198 | } | ||
1199 | return; | ||
1200 | } | ||
1201 | if (sysrq_down && !down && keycode == sysrq_alt_use) | ||
1202 | sysrq_down = 0; | ||
1203 | if (sysrq_down && down && !rep) { | ||
1204 | handle_sysrq(kbd_sysrq_xlate[keycode], tty); | ||
1205 | return; | ||
1206 | } | ||
1207 | #endif | ||
1208 | #ifdef CONFIG_SPARC | 1188 | #ifdef CONFIG_SPARC |
1209 | if (keycode == KEY_A && sparc_l1_a_state) { | 1189 | if (keycode == KEY_A && sparc_l1_a_state) { |
1210 | sparc_l1_a_state = 0; | 1190 | sparc_l1_a_state = false; |
1211 | sun_do_break(); | 1191 | sun_do_break(); |
1212 | } | 1192 | } |
1213 | #endif | 1193 | #endif |
@@ -1229,7 +1209,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1229 | put_queue(vc, (keycode >> 7) | 0x80); | 1209 | put_queue(vc, (keycode >> 7) | 0x80); |
1230 | put_queue(vc, keycode | 0x80); | 1210 | put_queue(vc, keycode | 0x80); |
1231 | } | 1211 | } |
1232 | raw_mode = 1; | 1212 | raw_mode = true; |
1233 | } | 1213 | } |
1234 | 1214 | ||
1235 | if (down) | 1215 | if (down) |
@@ -1252,29 +1232,32 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1252 | param.ledstate = kbd->ledflagstate; | 1232 | param.ledstate = kbd->ledflagstate; |
1253 | key_map = key_maps[shift_final]; | 1233 | key_map = key_maps[shift_final]; |
1254 | 1234 | ||
1255 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) { | 1235 | rc = atomic_notifier_call_chain(&keyboard_notifier_list, |
1256 | atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, ¶m); | 1236 | KBD_KEYCODE, ¶m); |
1237 | if (rc == NOTIFY_STOP || !key_map) { | ||
1238 | atomic_notifier_call_chain(&keyboard_notifier_list, | ||
1239 | KBD_UNBOUND_KEYCODE, ¶m); | ||
1257 | compute_shiftstate(); | 1240 | compute_shiftstate(); |
1258 | kbd->slockstate = 0; | 1241 | kbd->slockstate = 0; |
1259 | return; | 1242 | return; |
1260 | } | 1243 | } |
1261 | 1244 | ||
1262 | if (keycode >= NR_KEYS) | 1245 | if (keycode < NR_KEYS) |
1263 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) | ||
1264 | keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1)); | ||
1265 | else | ||
1266 | return; | ||
1267 | else | ||
1268 | keysym = key_map[keycode]; | 1246 | keysym = key_map[keycode]; |
1247 | else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) | ||
1248 | keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1)); | ||
1249 | else | ||
1250 | return; | ||
1269 | 1251 | ||
1270 | type = KTYP(keysym); | 1252 | type = KTYP(keysym); |
1271 | 1253 | ||
1272 | if (type < 0xf0) { | 1254 | if (type < 0xf0) { |
1273 | param.value = keysym; | 1255 | param.value = keysym; |
1274 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, ¶m) == NOTIFY_STOP) | 1256 | rc = atomic_notifier_call_chain(&keyboard_notifier_list, |
1275 | return; | 1257 | KBD_UNICODE, ¶m); |
1276 | if (down && !raw_mode) | 1258 | if (rc != NOTIFY_STOP) |
1277 | to_utf8(vc, keysym); | 1259 | if (down && !raw_mode) |
1260 | to_utf8(vc, keysym); | ||
1278 | return; | 1261 | return; |
1279 | } | 1262 | } |
1280 | 1263 | ||
@@ -1288,9 +1271,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1288 | keysym = key_map[keycode]; | 1271 | keysym = key_map[keycode]; |
1289 | } | 1272 | } |
1290 | } | 1273 | } |
1291 | param.value = keysym; | ||
1292 | 1274 | ||
1293 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, ¶m) == NOTIFY_STOP) | 1275 | param.value = keysym; |
1276 | rc = atomic_notifier_call_chain(&keyboard_notifier_list, | ||
1277 | KBD_KEYSYM, ¶m); | ||
1278 | if (rc == NOTIFY_STOP) | ||
1294 | return; | 1279 | return; |
1295 | 1280 | ||
1296 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) | 1281 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index d4e8b213a462..5d15630a5830 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -1,7 +1,4 @@ | |||
1 | /* -*- linux-c -*- | 1 | /* |
2 | * | ||
3 | * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ | ||
4 | * | ||
5 | * Linux Magic System Request Key Hacks | 2 | * Linux Magic System Request Key Hacks |
6 | * | 3 | * |
7 | * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> | 4 | * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> |
@@ -10,8 +7,13 @@ | |||
10 | * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com> | 7 | * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com> |
11 | * overhauled to use key registration | 8 | * overhauled to use key registration |
12 | * based upon discusions in irc://irc.openprojects.net/#kernelnewbies | 9 | * based upon discusions in irc://irc.openprojects.net/#kernelnewbies |
10 | * | ||
11 | * Copyright (c) 2010 Dmitry Torokhov | ||
12 | * Input handler conversion | ||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
16 | |||
15 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
16 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
17 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
@@ -39,33 +41,34 @@ | |||
39 | #include <linux/hrtimer.h> | 41 | #include <linux/hrtimer.h> |
40 | #include <linux/oom.h> | 42 | #include <linux/oom.h> |
41 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
44 | #include <linux/input.h> | ||
42 | 45 | ||
43 | #include <asm/ptrace.h> | 46 | #include <asm/ptrace.h> |
44 | #include <asm/irq_regs.h> | 47 | #include <asm/irq_regs.h> |
45 | 48 | ||
46 | /* Whether we react on sysrq keys or just ignore them */ | 49 | /* Whether we react on sysrq keys or just ignore them */ |
47 | int __read_mostly __sysrq_enabled = 1; | 50 | static int __read_mostly sysrq_enabled = 1; |
48 | 51 | static bool __read_mostly sysrq_always_enabled; | |
49 | static int __read_mostly sysrq_always_enabled; | ||
50 | 52 | ||
51 | int sysrq_on(void) | 53 | static bool sysrq_on(void) |
52 | { | 54 | { |
53 | return __sysrq_enabled || sysrq_always_enabled; | 55 | return sysrq_enabled || sysrq_always_enabled; |
54 | } | 56 | } |
55 | 57 | ||
56 | /* | 58 | /* |
57 | * A value of 1 means 'all', other nonzero values are an op mask: | 59 | * A value of 1 means 'all', other nonzero values are an op mask: |
58 | */ | 60 | */ |
59 | static inline int sysrq_on_mask(int mask) | 61 | static bool sysrq_on_mask(int mask) |
60 | { | 62 | { |
61 | return sysrq_always_enabled || __sysrq_enabled == 1 || | 63 | return sysrq_always_enabled || |
62 | (__sysrq_enabled & mask); | 64 | sysrq_enabled == 1 || |
65 | (sysrq_enabled & mask); | ||
63 | } | 66 | } |
64 | 67 | ||
65 | static int __init sysrq_always_enabled_setup(char *str) | 68 | static int __init sysrq_always_enabled_setup(char *str) |
66 | { | 69 | { |
67 | sysrq_always_enabled = 1; | 70 | sysrq_always_enabled = true; |
68 | printk(KERN_INFO "debug: sysrq always enabled.\n"); | 71 | pr_info("sysrq always enabled.\n"); |
69 | 72 | ||
70 | return 1; | 73 | return 1; |
71 | } | 74 | } |
@@ -76,6 +79,7 @@ __setup("sysrq_always_enabled", sysrq_always_enabled_setup); | |||
76 | static void sysrq_handle_loglevel(int key, struct tty_struct *tty) | 79 | static void sysrq_handle_loglevel(int key, struct tty_struct *tty) |
77 | { | 80 | { |
78 | int i; | 81 | int i; |
82 | |||
79 | i = key - '0'; | 83 | i = key - '0'; |
80 | console_loglevel = 7; | 84 | console_loglevel = 7; |
81 | printk("Loglevel set to %d\n", i); | 85 | printk("Loglevel set to %d\n", i); |
@@ -101,7 +105,7 @@ static struct sysrq_key_op sysrq_SAK_op = { | |||
101 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, | 105 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, |
102 | }; | 106 | }; |
103 | #else | 107 | #else |
104 | #define sysrq_SAK_op (*(struct sysrq_key_op *)0) | 108 | #define sysrq_SAK_op (*(struct sysrq_key_op *)NULL) |
105 | #endif | 109 | #endif |
106 | 110 | ||
107 | #ifdef CONFIG_VT | 111 | #ifdef CONFIG_VT |
@@ -119,7 +123,7 @@ static struct sysrq_key_op sysrq_unraw_op = { | |||
119 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, | 123 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, |
120 | }; | 124 | }; |
121 | #else | 125 | #else |
122 | #define sysrq_unraw_op (*(struct sysrq_key_op *)0) | 126 | #define sysrq_unraw_op (*(struct sysrq_key_op *)NULL) |
123 | #endif /* CONFIG_VT */ | 127 | #endif /* CONFIG_VT */ |
124 | 128 | ||
125 | static void sysrq_handle_crash(int key, struct tty_struct *tty) | 129 | static void sysrq_handle_crash(int key, struct tty_struct *tty) |
@@ -195,7 +199,7 @@ static struct sysrq_key_op sysrq_showlocks_op = { | |||
195 | .action_msg = "Show Locks Held", | 199 | .action_msg = "Show Locks Held", |
196 | }; | 200 | }; |
197 | #else | 201 | #else |
198 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) | 202 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL) |
199 | #endif | 203 | #endif |
200 | 204 | ||
201 | #ifdef CONFIG_SMP | 205 | #ifdef CONFIG_SMP |
@@ -298,7 +302,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { | |||
298 | .enable_mask = SYSRQ_ENABLE_DUMP, | 302 | .enable_mask = SYSRQ_ENABLE_DUMP, |
299 | }; | 303 | }; |
300 | #else | 304 | #else |
301 | #define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)0) | 305 | #define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL) |
302 | #endif | 306 | #endif |
303 | 307 | ||
304 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) | 308 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) |
@@ -477,6 +481,7 @@ struct sysrq_key_op *__sysrq_get_key_op(int key) | |||
477 | i = sysrq_key_table_key2index(key); | 481 | i = sysrq_key_table_key2index(key); |
478 | if (i != -1) | 482 | if (i != -1) |
479 | op_p = sysrq_key_table[i]; | 483 | op_p = sysrq_key_table[i]; |
484 | |||
480 | return op_p; | 485 | return op_p; |
481 | } | 486 | } |
482 | 487 | ||
@@ -488,11 +493,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) | |||
488 | sysrq_key_table[i] = op_p; | 493 | sysrq_key_table[i] = op_p; |
489 | } | 494 | } |
490 | 495 | ||
491 | /* | 496 | static void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) |
492 | * This is the non-locking version of handle_sysrq. It must/can only be called | ||
493 | * by sysrq key handlers, as they are inside of the lock | ||
494 | */ | ||
495 | void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) | ||
496 | { | 497 | { |
497 | struct sysrq_key_op *op_p; | 498 | struct sysrq_key_op *op_p; |
498 | int orig_log_level; | 499 | int orig_log_level; |
@@ -544,10 +545,6 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) | |||
544 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); | 545 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); |
545 | } | 546 | } |
546 | 547 | ||
547 | /* | ||
548 | * This function is called by the keyboard handler when SysRq is pressed | ||
549 | * and any other keycode arrives. | ||
550 | */ | ||
551 | void handle_sysrq(int key, struct tty_struct *tty) | 548 | void handle_sysrq(int key, struct tty_struct *tty) |
552 | { | 549 | { |
553 | if (sysrq_on()) | 550 | if (sysrq_on()) |
@@ -555,10 +552,177 @@ void handle_sysrq(int key, struct tty_struct *tty) | |||
555 | } | 552 | } |
556 | EXPORT_SYMBOL(handle_sysrq); | 553 | EXPORT_SYMBOL(handle_sysrq); |
557 | 554 | ||
555 | #ifdef CONFIG_INPUT | ||
556 | |||
557 | /* Simple translation table for the SysRq keys */ | ||
558 | static const unsigned char sysrq_xlate[KEY_MAX + 1] = | ||
559 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | ||
560 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | ||
561 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | ||
562 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | ||
563 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | ||
564 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | ||
565 | "\r\000/"; /* 0x60 - 0x6f */ | ||
566 | |||
567 | static bool sysrq_down; | ||
568 | static int sysrq_alt_use; | ||
569 | static int sysrq_alt; | ||
570 | |||
571 | static bool sysrq_filter(struct input_handle *handle, unsigned int type, | ||
572 | unsigned int code, int value) | ||
573 | { | ||
574 | if (type != EV_KEY) | ||
575 | goto out; | ||
576 | |||
577 | switch (code) { | ||
578 | |||
579 | case KEY_LEFTALT: | ||
580 | case KEY_RIGHTALT: | ||
581 | if (value) | ||
582 | sysrq_alt = code; | ||
583 | else if (sysrq_down && code == sysrq_alt_use) | ||
584 | sysrq_down = false; | ||
585 | break; | ||
586 | |||
587 | case KEY_SYSRQ: | ||
588 | if (value == 1 && sysrq_alt) { | ||
589 | sysrq_down = true; | ||
590 | sysrq_alt_use = sysrq_alt; | ||
591 | } | ||
592 | break; | ||
593 | |||
594 | default: | ||
595 | if (sysrq_down && value && value != 2) | ||
596 | __handle_sysrq(sysrq_xlate[code], NULL, 1); | ||
597 | break; | ||
598 | } | ||
599 | |||
600 | out: | ||
601 | return sysrq_down; | ||
602 | } | ||
603 | |||
604 | static int sysrq_connect(struct input_handler *handler, | ||
605 | struct input_dev *dev, | ||
606 | const struct input_device_id *id) | ||
607 | { | ||
608 | struct input_handle *handle; | ||
609 | int error; | ||
610 | |||
611 | sysrq_down = false; | ||
612 | sysrq_alt = 0; | ||
613 | |||
614 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | ||
615 | if (!handle) | ||
616 | return -ENOMEM; | ||
617 | |||
618 | handle->dev = dev; | ||
619 | handle->handler = handler; | ||
620 | handle->name = "sysrq"; | ||
621 | |||
622 | error = input_register_handle(handle); | ||
623 | if (error) { | ||
624 | pr_err("Failed to register input sysrq handler, error %d\n", | ||
625 | error); | ||
626 | goto err_free; | ||
627 | } | ||
628 | |||
629 | error = input_open_device(handle); | ||
630 | if (error) { | ||
631 | pr_err("Failed to open input device, error %d\n", error); | ||
632 | goto err_unregister; | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | |||
637 | err_unregister: | ||
638 | input_unregister_handle(handle); | ||
639 | err_free: | ||
640 | kfree(handle); | ||
641 | return error; | ||
642 | } | ||
643 | |||
644 | static void sysrq_disconnect(struct input_handle *handle) | ||
645 | { | ||
646 | input_close_device(handle); | ||
647 | input_unregister_handle(handle); | ||
648 | kfree(handle); | ||
649 | } | ||
650 | |||
651 | /* | ||
652 | * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all | ||
653 | * keyboards have SysRq ikey predefined and so user may add it to keymap | ||
654 | * later, but we expect all such keyboards to have left alt. | ||
655 | */ | ||
656 | static const struct input_device_id sysrq_ids[] = { | ||
657 | { | ||
658 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | ||
659 | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
660 | .evbit = { BIT_MASK(EV_KEY) }, | ||
661 | .keybit = { BIT_MASK(KEY_LEFTALT) }, | ||
662 | }, | ||
663 | { }, | ||
664 | }; | ||
665 | |||
666 | static struct input_handler sysrq_handler = { | ||
667 | .filter = sysrq_filter, | ||
668 | .connect = sysrq_connect, | ||
669 | .disconnect = sysrq_disconnect, | ||
670 | .name = "sysrq", | ||
671 | .id_table = sysrq_ids, | ||
672 | }; | ||
673 | |||
674 | static bool sysrq_handler_registered; | ||
675 | |||
676 | static inline void sysrq_register_handler(void) | ||
677 | { | ||
678 | int error; | ||
679 | |||
680 | error = input_register_handler(&sysrq_handler); | ||
681 | if (error) | ||
682 | pr_err("Failed to register input handler, error %d", error); | ||
683 | else | ||
684 | sysrq_handler_registered = true; | ||
685 | } | ||
686 | |||
687 | static inline void sysrq_unregister_handler(void) | ||
688 | { | ||
689 | if (sysrq_handler_registered) { | ||
690 | input_unregister_handler(&sysrq_handler); | ||
691 | sysrq_handler_registered = false; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | #else | ||
696 | |||
697 | static inline void sysrq_register_handler(void) | ||
698 | { | ||
699 | } | ||
700 | |||
701 | static inline void sysrq_unregister_handler(void) | ||
702 | { | ||
703 | } | ||
704 | |||
705 | #endif /* CONFIG_INPUT */ | ||
706 | |||
707 | int sysrq_toggle_support(int enable_mask) | ||
708 | { | ||
709 | bool was_enabled = sysrq_on(); | ||
710 | |||
711 | sysrq_enabled = enable_mask; | ||
712 | |||
713 | if (was_enabled != sysrq_on()) { | ||
714 | if (sysrq_on()) | ||
715 | sysrq_register_handler(); | ||
716 | else | ||
717 | sysrq_unregister_handler(); | ||
718 | } | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
558 | static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, | 723 | static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, |
559 | struct sysrq_key_op *remove_op_p) | 724 | struct sysrq_key_op *remove_op_p) |
560 | { | 725 | { |
561 | |||
562 | int retval; | 726 | int retval; |
563 | unsigned long flags; | 727 | unsigned long flags; |
564 | 728 | ||
@@ -599,6 +763,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, | |||
599 | return -EFAULT; | 763 | return -EFAULT; |
600 | __handle_sysrq(c, NULL, 0); | 764 | __handle_sysrq(c, NULL, 0); |
601 | } | 765 | } |
766 | |||
602 | return count; | 767 | return count; |
603 | } | 768 | } |
604 | 769 | ||
@@ -606,10 +771,28 @@ static const struct file_operations proc_sysrq_trigger_operations = { | |||
606 | .write = write_sysrq_trigger, | 771 | .write = write_sysrq_trigger, |
607 | }; | 772 | }; |
608 | 773 | ||
774 | static void sysrq_init_procfs(void) | ||
775 | { | ||
776 | if (!proc_create("sysrq-trigger", S_IWUSR, NULL, | ||
777 | &proc_sysrq_trigger_operations)) | ||
778 | pr_err("Failed to register proc interface\n"); | ||
779 | } | ||
780 | |||
781 | #else | ||
782 | |||
783 | static inline void sysrq_init_procfs(void) | ||
784 | { | ||
785 | } | ||
786 | |||
787 | #endif /* CONFIG_PROC_FS */ | ||
788 | |||
609 | static int __init sysrq_init(void) | 789 | static int __init sysrq_init(void) |
610 | { | 790 | { |
611 | proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations); | 791 | sysrq_init_procfs(); |
792 | |||
793 | if (sysrq_on()) | ||
794 | sysrq_register_handler(); | ||
795 | |||
612 | return 0; | 796 | return 0; |
613 | } | 797 | } |
614 | module_init(sysrq_init); | 798 | module_init(sysrq_init); |
615 | #endif | ||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a8293388d019..d8fa5d724c57 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -73,7 +73,7 @@ config KEYBOARD_ATKBD | |||
73 | default y | 73 | default y |
74 | select SERIO | 74 | select SERIO |
75 | select SERIO_LIBPS2 | 75 | select SERIO_LIBPS2 |
76 | select SERIO_I8042 if X86 | 76 | select SERIO_I8042 if X86 && !X86_MRST |
77 | select SERIO_GSCPS2 if GSC | 77 | select SERIO_GSCPS2 if GSC |
78 | help | 78 | help |
79 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually | 79 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually |
@@ -179,6 +179,22 @@ config KEYBOARD_GPIO | |||
179 | To compile this driver as a module, choose M here: the | 179 | To compile this driver as a module, choose M here: the |
180 | module will be called gpio_keys. | 180 | module will be called gpio_keys. |
181 | 181 | ||
182 | config KEYBOARD_TCA6416 | ||
183 | tristate "TCA6416 Keypad Support" | ||
184 | depends on I2C | ||
185 | help | ||
186 | This driver implements basic keypad functionality | ||
187 | for keys connected through TCA6416 IO expander | ||
188 | |||
189 | Say Y here if your device has keys connected to | ||
190 | TCA6416 IO expander. Your board-specific setup logic | ||
191 | must also provide pin-mask details(of which TCA6416 pins | ||
192 | are used for keypad). | ||
193 | |||
194 | If enabled the complete TCA6416 device will be managed through | ||
195 | this driver. | ||
196 | |||
197 | |||
182 | config KEYBOARD_MATRIX | 198 | config KEYBOARD_MATRIX |
183 | tristate "GPIO driven matrix keypad support" | 199 | tristate "GPIO driven matrix keypad support" |
184 | depends on GENERIC_GPIO | 200 | depends on GENERIC_GPIO |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 9a74127e4d17..4596d0c6f922 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o | |||
14 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o | 14 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o |
15 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o | 15 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o |
16 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o | 16 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o |
17 | obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o | ||
17 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o | 18 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o |
18 | obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o | 19 | obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o |
19 | obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o | 20 | obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o |
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 60ac4684f875..bc696931fed7 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c | |||
@@ -670,8 +670,6 @@ static int __devinit lm8323_probe(struct i2c_client *client, | |||
670 | goto fail1; | 670 | goto fail1; |
671 | } | 671 | } |
672 | 672 | ||
673 | i2c_set_clientdata(client, lm); | ||
674 | |||
675 | lm->client = client; | 673 | lm->client = client; |
676 | lm->idev = idev; | 674 | lm->idev = idev; |
677 | mutex_init(&lm->lock); | 675 | mutex_init(&lm->lock); |
@@ -753,6 +751,8 @@ static int __devinit lm8323_probe(struct i2c_client *client, | |||
753 | goto fail4; | 751 | goto fail4; |
754 | } | 752 | } |
755 | 753 | ||
754 | i2c_set_clientdata(client, lm); | ||
755 | |||
756 | device_init_wakeup(&client->dev, 1); | 756 | device_init_wakeup(&client->dev, 1); |
757 | enable_irq_wake(client->irq); | 757 | enable_irq_wake(client->irq); |
758 | 758 | ||
@@ -778,6 +778,8 @@ static int __devexit lm8323_remove(struct i2c_client *client) | |||
778 | struct lm8323_chip *lm = i2c_get_clientdata(client); | 778 | struct lm8323_chip *lm = i2c_get_clientdata(client); |
779 | int i; | 779 | int i; |
780 | 780 | ||
781 | i2c_set_clientdata(client, NULL); | ||
782 | |||
781 | disable_irq_wake(client->irq); | 783 | disable_irq_wake(client->irq); |
782 | free_irq(client->irq, lm); | 784 | free_irq(client->irq, lm); |
783 | cancel_work_sync(&lm->work); | 785 | cancel_work_sync(&lm->work); |
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c new file mode 100644 index 000000000000..493c93f25e2a --- /dev/null +++ b/drivers/input/keyboard/tca6416-keypad.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * Driver for keys on TCA6416 I2C IO expander | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * | ||
6 | * Author : Sriramakrishnan.A.G. <srk@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/workqueue.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/input.h> | ||
23 | #include <linux/tca6416_keypad.h> | ||
24 | |||
25 | #define TCA6416_INPUT 0 | ||
26 | #define TCA6416_OUTPUT 1 | ||
27 | #define TCA6416_INVERT 2 | ||
28 | #define TCA6416_DIRECTION 3 | ||
29 | |||
30 | static const struct i2c_device_id tca6416_id[] = { | ||
31 | { "tca6416-keys", 16, }, | ||
32 | { } | ||
33 | }; | ||
34 | MODULE_DEVICE_TABLE(i2c, tca6416_id); | ||
35 | |||
36 | struct tca6416_drv_data { | ||
37 | struct input_dev *input; | ||
38 | struct tca6416_button data[0]; | ||
39 | }; | ||
40 | |||
41 | struct tca6416_keypad_chip { | ||
42 | uint16_t reg_output; | ||
43 | uint16_t reg_direction; | ||
44 | uint16_t reg_input; | ||
45 | |||
46 | struct i2c_client *client; | ||
47 | struct input_dev *input; | ||
48 | struct delayed_work dwork; | ||
49 | u16 pinmask; | ||
50 | int irqnum; | ||
51 | bool use_polling; | ||
52 | struct tca6416_button buttons[0]; | ||
53 | }; | ||
54 | |||
55 | static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val) | ||
56 | { | ||
57 | int error; | ||
58 | |||
59 | error = i2c_smbus_write_word_data(chip->client, reg << 1, val); | ||
60 | if (error < 0) { | ||
61 | dev_err(&chip->client->dev, | ||
62 | "%s failed, reg: %d, val: %d, error: %d\n", | ||
63 | __func__, reg, val, error); | ||
64 | return error; | ||
65 | } | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) | ||
71 | { | ||
72 | int retval; | ||
73 | |||
74 | retval = i2c_smbus_read_word_data(chip->client, reg << 1); | ||
75 | if (retval < 0) { | ||
76 | dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n", | ||
77 | __func__, reg, retval); | ||
78 | return retval; | ||
79 | } | ||
80 | |||
81 | *val = (u16)retval; | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static void tca6416_keys_scan(struct tca6416_keypad_chip *chip) | ||
86 | { | ||
87 | struct input_dev *input = chip->input; | ||
88 | u16 reg_val, val; | ||
89 | int error, i, pin_index; | ||
90 | |||
91 | error = tca6416_read_reg(chip, TCA6416_INPUT, ®_val); | ||
92 | if (error) | ||
93 | return; | ||
94 | |||
95 | reg_val &= chip->pinmask; | ||
96 | |||
97 | /* Figure out which lines have changed */ | ||
98 | val = reg_val ^ chip->reg_input; | ||
99 | chip->reg_input = reg_val; | ||
100 | |||
101 | for (i = 0, pin_index = 0; i < 16; i++) { | ||
102 | if (val & (1 << i)) { | ||
103 | struct tca6416_button *button = &chip->buttons[pin_index]; | ||
104 | unsigned int type = button->type ?: EV_KEY; | ||
105 | int state = ((reg_val & (1 << i)) ? 1 : 0) | ||
106 | ^ button->active_low; | ||
107 | |||
108 | input_event(input, type, button->code, !!state); | ||
109 | input_sync(input); | ||
110 | } | ||
111 | |||
112 | if (chip->pinmask & (1 << i)) | ||
113 | pin_index++; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * This is threaded IRQ handler and this can (and will) sleep. | ||
119 | */ | ||
120 | static irqreturn_t tca6416_keys_isr(int irq, void *dev_id) | ||
121 | { | ||
122 | struct tca6416_keypad_chip *chip = dev_id; | ||
123 | |||
124 | tca6416_keys_scan(chip); | ||
125 | |||
126 | return IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | static void tca6416_keys_work_func(struct work_struct *work) | ||
130 | { | ||
131 | struct tca6416_keypad_chip *chip = | ||
132 | container_of(work, struct tca6416_keypad_chip, dwork.work); | ||
133 | |||
134 | tca6416_keys_scan(chip); | ||
135 | schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); | ||
136 | } | ||
137 | |||
138 | static int tca6416_keys_open(struct input_dev *dev) | ||
139 | { | ||
140 | struct tca6416_keypad_chip *chip = input_get_drvdata(dev); | ||
141 | |||
142 | /* Get initial device state in case it has switches */ | ||
143 | tca6416_keys_scan(chip); | ||
144 | |||
145 | if (chip->use_polling) | ||
146 | schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); | ||
147 | else | ||
148 | enable_irq(chip->irqnum); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void tca6416_keys_close(struct input_dev *dev) | ||
154 | { | ||
155 | struct tca6416_keypad_chip *chip = input_get_drvdata(dev); | ||
156 | |||
157 | if (chip->use_polling) | ||
158 | cancel_delayed_work_sync(&chip->dwork); | ||
159 | else | ||
160 | disable_irq(chip->irqnum); | ||
161 | } | ||
162 | |||
163 | static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip) | ||
164 | { | ||
165 | int error; | ||
166 | |||
167 | error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output); | ||
168 | if (error) | ||
169 | return error; | ||
170 | |||
171 | error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); | ||
172 | if (error) | ||
173 | return error; | ||
174 | |||
175 | /* ensure that keypad pins are set to input */ | ||
176 | error = tca6416_write_reg(chip, TCA6416_DIRECTION, | ||
177 | chip->reg_direction | chip->pinmask); | ||
178 | if (error) | ||
179 | return error; | ||
180 | |||
181 | error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); | ||
182 | if (error) | ||
183 | return error; | ||
184 | |||
185 | error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input); | ||
186 | if (error) | ||
187 | return error; | ||
188 | |||
189 | chip->reg_input &= chip->pinmask; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int __devinit tca6416_keypad_probe(struct i2c_client *client, | ||
195 | const struct i2c_device_id *id) | ||
196 | { | ||
197 | struct tca6416_keys_platform_data *pdata; | ||
198 | struct tca6416_keypad_chip *chip; | ||
199 | struct input_dev *input; | ||
200 | int error; | ||
201 | int i; | ||
202 | |||
203 | /* Check functionality */ | ||
204 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { | ||
205 | dev_err(&client->dev, "%s adapter not supported\n", | ||
206 | dev_driver_string(&client->adapter->dev)); | ||
207 | return -ENODEV; | ||
208 | } | ||
209 | |||
210 | pdata = client->dev.platform_data; | ||
211 | if (!pdata) { | ||
212 | dev_dbg(&client->dev, "no platform data\n"); | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | chip = kzalloc(sizeof(struct tca6416_keypad_chip) + | ||
217 | pdata->nbuttons * sizeof(struct tca6416_button), | ||
218 | GFP_KERNEL); | ||
219 | input = input_allocate_device(); | ||
220 | if (!chip || !input) { | ||
221 | error = -ENOMEM; | ||
222 | goto fail1; | ||
223 | } | ||
224 | |||
225 | chip->client = client; | ||
226 | chip->input = input; | ||
227 | chip->pinmask = pdata->pinmask; | ||
228 | chip->use_polling = pdata->use_polling; | ||
229 | |||
230 | INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func); | ||
231 | |||
232 | input->phys = "tca6416-keys/input0"; | ||
233 | input->name = client->name; | ||
234 | input->dev.parent = &client->dev; | ||
235 | |||
236 | input->open = tca6416_keys_open; | ||
237 | input->close = tca6416_keys_close; | ||
238 | |||
239 | input->id.bustype = BUS_HOST; | ||
240 | input->id.vendor = 0x0001; | ||
241 | input->id.product = 0x0001; | ||
242 | input->id.version = 0x0100; | ||
243 | |||
244 | /* Enable auto repeat feature of Linux input subsystem */ | ||
245 | if (pdata->rep) | ||
246 | __set_bit(EV_REP, input->evbit); | ||
247 | |||
248 | for (i = 0; i < pdata->nbuttons; i++) { | ||
249 | unsigned int type; | ||
250 | |||
251 | chip->buttons[i] = pdata->buttons[i]; | ||
252 | type = (pdata->buttons[i].type) ?: EV_KEY; | ||
253 | input_set_capability(input, type, pdata->buttons[i].code); | ||
254 | } | ||
255 | |||
256 | input_set_drvdata(input, chip); | ||
257 | |||
258 | /* | ||
259 | * Initialize cached registers from their original values. | ||
260 | * we can't share this chip with another i2c master. | ||
261 | */ | ||
262 | error = tca6416_setup_registers(chip); | ||
263 | if (error) | ||
264 | goto fail1; | ||
265 | |||
266 | if (!chip->use_polling) { | ||
267 | if (pdata->irq_is_gpio) | ||
268 | chip->irqnum = gpio_to_irq(client->irq); | ||
269 | else | ||
270 | chip->irqnum = client->irq; | ||
271 | |||
272 | error = request_threaded_irq(chip->irqnum, NULL, | ||
273 | tca6416_keys_isr, | ||
274 | IRQF_TRIGGER_FALLING, | ||
275 | "tca6416-keypad", chip); | ||
276 | if (error) { | ||
277 | dev_dbg(&client->dev, | ||
278 | "Unable to claim irq %d; error %d\n", | ||
279 | chip->irqnum, error); | ||
280 | goto fail1; | ||
281 | } | ||
282 | disable_irq(chip->irqnum); | ||
283 | } | ||
284 | |||
285 | error = input_register_device(input); | ||
286 | if (error) { | ||
287 | dev_dbg(&client->dev, | ||
288 | "Unable to register input device, error: %d\n", error); | ||
289 | goto fail2; | ||
290 | } | ||
291 | |||
292 | i2c_set_clientdata(client, chip); | ||
293 | |||
294 | return 0; | ||
295 | |||
296 | fail2: | ||
297 | if (!chip->use_polling) { | ||
298 | free_irq(chip->irqnum, chip); | ||
299 | enable_irq(chip->irqnum); | ||
300 | } | ||
301 | fail1: | ||
302 | input_free_device(input); | ||
303 | kfree(chip); | ||
304 | return error; | ||
305 | } | ||
306 | |||
307 | static int __devexit tca6416_keypad_remove(struct i2c_client *client) | ||
308 | { | ||
309 | struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); | ||
310 | |||
311 | if (!chip->use_polling) { | ||
312 | free_irq(chip->irqnum, chip); | ||
313 | enable_irq(chip->irqnum); | ||
314 | } | ||
315 | |||
316 | input_unregister_device(chip->input); | ||
317 | kfree(chip); | ||
318 | |||
319 | i2c_set_clientdata(client, NULL); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | |||
325 | static struct i2c_driver tca6416_keypad_driver = { | ||
326 | .driver = { | ||
327 | .name = "tca6416-keypad", | ||
328 | }, | ||
329 | .probe = tca6416_keypad_probe, | ||
330 | .remove = __devexit_p(tca6416_keypad_remove), | ||
331 | .id_table = tca6416_id, | ||
332 | }; | ||
333 | |||
334 | static int __init tca6416_keypad_init(void) | ||
335 | { | ||
336 | return i2c_add_driver(&tca6416_keypad_driver); | ||
337 | } | ||
338 | |||
339 | subsys_initcall(tca6416_keypad_init); | ||
340 | |||
341 | static void __exit tca6416_keypad_exit(void) | ||
342 | { | ||
343 | i2c_del_driver(&tca6416_keypad_driver); | ||
344 | } | ||
345 | module_exit(tca6416_keypad_exit); | ||
346 | |||
347 | MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>"); | ||
348 | MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander"); | ||
349 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 40dabd8487b5..4cc82826ea6b 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c | |||
@@ -87,7 +87,6 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev) | |||
87 | info->idev->phys = "88pm860x_on/input0"; | 87 | info->idev->phys = "88pm860x_on/input0"; |
88 | info->idev->id.bustype = BUS_I2C; | 88 | info->idev->id.bustype = BUS_I2C; |
89 | info->idev->dev.parent = &pdev->dev; | 89 | info->idev->dev.parent = &pdev->dev; |
90 | info->irq = irq; | ||
91 | info->idev->evbit[0] = BIT_MASK(EV_KEY); | 90 | info->idev->evbit[0] = BIT_MASK(EV_KEY); |
92 | info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); | 91 | info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); |
93 | 92 | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23140a3bb8e0..48cdabec372a 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY | |||
22 | To compile this driver as a module, choose M here: the module | 22 | To compile this driver as a module, choose M here: the module |
23 | will be called 88pm860x_onkey. | 23 | will be called 88pm860x_onkey. |
24 | 24 | ||
25 | config INPUT_AD714X | ||
26 | tristate "Analog Devices AD714x Capacitance Touch Sensor" | ||
27 | help | ||
28 | Say Y here if you want to support an AD7142/3/7/8/7A touch sensor. | ||
29 | |||
30 | You should select a bus connection too. | ||
31 | |||
32 | To compile this driver as a module, choose M here: the | ||
33 | module will be called ad714x. | ||
34 | |||
35 | config INPUT_AD714X_I2C | ||
36 | tristate "support I2C bus connection" | ||
37 | depends on INPUT_AD714X && I2C | ||
38 | default y | ||
39 | help | ||
40 | Say Y here if you have AD7142/AD7147 hooked to an I2C bus. | ||
41 | |||
42 | To compile this driver as a module, choose M here: the | ||
43 | module will be called ad714x-i2c. | ||
44 | |||
45 | config INPUT_AD714X_SPI | ||
46 | tristate "support SPI bus connection" | ||
47 | depends on INPUT_AD714X && SPI | ||
48 | default y | ||
49 | help | ||
50 | Say Y here if you have AD7142/AD7147 hooked to a SPI bus. | ||
51 | |||
52 | To compile this driver as a module, choose M here: the | ||
53 | module will be called ad714x-spi. | ||
54 | |||
25 | config INPUT_PCSPKR | 55 | config INPUT_PCSPKR |
26 | tristate "PC Speaker support" | 56 | tristate "PC Speaker support" |
27 | depends on PCSPKR_PLATFORM | 57 | depends on PCSPKR_PLATFORM |
@@ -277,6 +307,16 @@ config INPUT_PCF50633_PMU | |||
277 | Say Y to include support for delivering PMU events via input | 307 | Say Y to include support for delivering PMU events via input |
278 | layer on NXP PCF50633. | 308 | layer on NXP PCF50633. |
279 | 309 | ||
310 | config INPUT_PCF8574 | ||
311 | tristate "PCF8574 Keypad input device" | ||
312 | depends on I2C && EXPERIMENTAL | ||
313 | help | ||
314 | Say Y here if you want to support a keypad connetced via I2C | ||
315 | with a PCF8574. | ||
316 | |||
317 | To compile this driver as a module, choose M here: the | ||
318 | module will be called pcf8574_keypad. | ||
319 | |||
280 | config INPUT_GPIO_ROTARY_ENCODER | 320 | config INPUT_GPIO_ROTARY_ENCODER |
281 | tristate "Rotary encoders connected to GPIO pins" | 321 | tristate "Rotary encoders connected to GPIO pins" |
282 | depends on GPIOLIB && GENERIC_GPIO | 322 | depends on GPIOLIB && GENERIC_GPIO |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 7e95a5d474dc..f9f577031e06 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -5,6 +5,9 @@ | |||
5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
6 | 6 | ||
7 | obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o | 7 | obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o |
8 | obj-$(CONFIG_INPUT_AD714X) += ad714x.o | ||
9 | obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o | ||
10 | obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o | ||
8 | obj-$(CONFIG_INPUT_APANEL) += apanel.o | 11 | obj-$(CONFIG_INPUT_APANEL) += apanel.o |
9 | obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o | 12 | obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o |
10 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | 13 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o |
@@ -19,6 +22,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | |||
19 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 22 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
20 | obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o | 23 | obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o |
21 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o | 24 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o |
25 | obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o | ||
22 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | 26 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o |
23 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | 27 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o |
24 | obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | 28 | obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o |
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c new file mode 100644 index 000000000000..e9adbe49f6a4 --- /dev/null +++ b/drivers/input/misc/ad714x-i2c.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * AD714X CapTouch Programmable Controller driver (I2C bus) | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/input.h> /* BUS_I2C */ | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include "ad714x.h" | ||
14 | |||
15 | #ifdef CONFIG_PM | ||
16 | static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message) | ||
17 | { | ||
18 | return ad714x_disable(i2c_get_clientdata(client)); | ||
19 | } | ||
20 | |||
21 | static int ad714x_i2c_resume(struct i2c_client *client) | ||
22 | { | ||
23 | return ad714x_enable(i2c_get_clientdata(client)); | ||
24 | } | ||
25 | #else | ||
26 | # define ad714x_i2c_suspend NULL | ||
27 | # define ad714x_i2c_resume NULL | ||
28 | #endif | ||
29 | |||
30 | static int ad714x_i2c_write(struct device *dev, unsigned short reg, | ||
31 | unsigned short data) | ||
32 | { | ||
33 | struct i2c_client *client = to_i2c_client(dev); | ||
34 | int ret = 0; | ||
35 | u8 *_reg = (u8 *)® | ||
36 | u8 *_data = (u8 *)&data; | ||
37 | |||
38 | u8 tx[4] = { | ||
39 | _reg[1], | ||
40 | _reg[0], | ||
41 | _data[1], | ||
42 | _data[0] | ||
43 | }; | ||
44 | |||
45 | ret = i2c_master_send(client, tx, 4); | ||
46 | if (ret < 0) | ||
47 | dev_err(&client->dev, "I2C write error\n"); | ||
48 | |||
49 | return ret; | ||
50 | } | ||
51 | |||
52 | static int ad714x_i2c_read(struct device *dev, unsigned short reg, | ||
53 | unsigned short *data) | ||
54 | { | ||
55 | struct i2c_client *client = to_i2c_client(dev); | ||
56 | int ret = 0; | ||
57 | u8 *_reg = (u8 *)® | ||
58 | u8 *_data = (u8 *)data; | ||
59 | |||
60 | u8 tx[2] = { | ||
61 | _reg[1], | ||
62 | _reg[0] | ||
63 | }; | ||
64 | u8 rx[2]; | ||
65 | |||
66 | ret = i2c_master_send(client, tx, 2); | ||
67 | if (ret >= 0) | ||
68 | ret = i2c_master_recv(client, rx, 2); | ||
69 | |||
70 | if (unlikely(ret < 0)) { | ||
71 | dev_err(&client->dev, "I2C read error\n"); | ||
72 | } else { | ||
73 | _data[0] = rx[1]; | ||
74 | _data[1] = rx[0]; | ||
75 | } | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | static int __devinit ad714x_i2c_probe(struct i2c_client *client, | ||
81 | const struct i2c_device_id *id) | ||
82 | { | ||
83 | struct ad714x_chip *chip; | ||
84 | |||
85 | chip = ad714x_probe(&client->dev, BUS_I2C, client->irq, | ||
86 | ad714x_i2c_read, ad714x_i2c_write); | ||
87 | if (IS_ERR(chip)) | ||
88 | return PTR_ERR(chip); | ||
89 | |||
90 | i2c_set_clientdata(client, chip); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int __devexit ad714x_i2c_remove(struct i2c_client *client) | ||
96 | { | ||
97 | struct ad714x_chip *chip = i2c_get_clientdata(client); | ||
98 | |||
99 | ad714x_remove(chip); | ||
100 | i2c_set_clientdata(client, NULL); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static const struct i2c_device_id ad714x_id[] = { | ||
106 | { "ad7142_captouch", 0 }, | ||
107 | { "ad7143_captouch", 0 }, | ||
108 | { "ad7147_captouch", 0 }, | ||
109 | { "ad7147a_captouch", 0 }, | ||
110 | { "ad7148_captouch", 0 }, | ||
111 | { } | ||
112 | }; | ||
113 | MODULE_DEVICE_TABLE(i2c, ad714x_id); | ||
114 | |||
115 | static struct i2c_driver ad714x_i2c_driver = { | ||
116 | .driver = { | ||
117 | .name = "ad714x_captouch", | ||
118 | }, | ||
119 | .probe = ad714x_i2c_probe, | ||
120 | .remove = __devexit_p(ad714x_i2c_remove), | ||
121 | .suspend = ad714x_i2c_suspend, | ||
122 | .resume = ad714x_i2c_resume, | ||
123 | .id_table = ad714x_id, | ||
124 | }; | ||
125 | |||
126 | static __init int ad714x_i2c_init(void) | ||
127 | { | ||
128 | return i2c_add_driver(&ad714x_i2c_driver); | ||
129 | } | ||
130 | module_init(ad714x_i2c_init); | ||
131 | |||
132 | static __exit void ad714x_i2c_exit(void) | ||
133 | { | ||
134 | i2c_del_driver(&ad714x_i2c_driver); | ||
135 | } | ||
136 | module_exit(ad714x_i2c_exit); | ||
137 | |||
138 | MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver"); | ||
139 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
140 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c new file mode 100644 index 000000000000..7f8dedfd1bfe --- /dev/null +++ b/drivers/input/misc/ad714x-spi.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * AD714X CapTouch Programmable Controller driver (SPI bus) | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/input.h> /* BUS_I2C */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/spi/spi.h> | ||
12 | #include <linux/types.h> | ||
13 | #include "ad714x.h" | ||
14 | |||
15 | #define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */ | ||
16 | #define AD714x_SPI_READ BIT(10) | ||
17 | |||
18 | #ifdef CONFIG_PM | ||
19 | static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message) | ||
20 | { | ||
21 | return ad714x_disable(spi_get_drvdata(spi)); | ||
22 | } | ||
23 | |||
24 | static int ad714x_spi_resume(struct spi_device *spi) | ||
25 | { | ||
26 | return ad714x_enable(spi_get_drvdata(spi)); | ||
27 | } | ||
28 | #else | ||
29 | # define ad714x_spi_suspend NULL | ||
30 | # define ad714x_spi_resume NULL | ||
31 | #endif | ||
32 | |||
33 | static int ad714x_spi_read(struct device *dev, unsigned short reg, | ||
34 | unsigned short *data) | ||
35 | { | ||
36 | struct spi_device *spi = to_spi_device(dev); | ||
37 | unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg; | ||
38 | |||
39 | return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2); | ||
40 | } | ||
41 | |||
42 | static int ad714x_spi_write(struct device *dev, unsigned short reg, | ||
43 | unsigned short data) | ||
44 | { | ||
45 | struct spi_device *spi = to_spi_device(dev); | ||
46 | unsigned short tx[2] = { | ||
47 | AD714x_SPI_CMD_PREFIX | reg, | ||
48 | data | ||
49 | }; | ||
50 | |||
51 | return spi_write(spi, (u8 *)tx, 4); | ||
52 | } | ||
53 | |||
54 | static int __devinit ad714x_spi_probe(struct spi_device *spi) | ||
55 | { | ||
56 | struct ad714x_chip *chip; | ||
57 | |||
58 | chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq, | ||
59 | ad714x_spi_read, ad714x_spi_write); | ||
60 | if (IS_ERR(chip)) | ||
61 | return PTR_ERR(chip); | ||
62 | |||
63 | spi_set_drvdata(spi, chip); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int __devexit ad714x_spi_remove(struct spi_device *spi) | ||
69 | { | ||
70 | struct ad714x_chip *chip = spi_get_drvdata(spi); | ||
71 | |||
72 | ad714x_remove(chip); | ||
73 | spi_set_drvdata(spi, NULL); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static struct spi_driver ad714x_spi_driver = { | ||
79 | .driver = { | ||
80 | .name = "ad714x_captouch", | ||
81 | .owner = THIS_MODULE, | ||
82 | }, | ||
83 | .probe = ad714x_spi_probe, | ||
84 | .remove = __devexit_p(ad714x_spi_remove), | ||
85 | .suspend = ad714x_spi_suspend, | ||
86 | .resume = ad714x_spi_resume, | ||
87 | }; | ||
88 | |||
89 | static __init int ad714x_spi_init(void) | ||
90 | { | ||
91 | return spi_register_driver(&ad714x_spi_driver); | ||
92 | } | ||
93 | module_init(ad714x_spi_init); | ||
94 | |||
95 | static __exit void ad714x_spi_exit(void) | ||
96 | { | ||
97 | spi_unregister_driver(&ad714x_spi_driver); | ||
98 | } | ||
99 | module_exit(ad714x_spi_exit); | ||
100 | |||
101 | MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver"); | ||
102 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
103 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c new file mode 100644 index 000000000000..0fe27baf5e72 --- /dev/null +++ b/drivers/input/misc/ad714x.c | |||
@@ -0,0 +1,1347 @@ | |||
1 | /* | ||
2 | * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/device.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/input.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/input/ad714x.h> | ||
15 | #include "ad714x.h" | ||
16 | |||
17 | #define AD714X_PWR_CTRL 0x0 | ||
18 | #define AD714X_STG_CAL_EN_REG 0x1 | ||
19 | #define AD714X_AMB_COMP_CTRL0_REG 0x2 | ||
20 | #define AD714X_PARTID_REG 0x17 | ||
21 | #define AD7142_PARTID 0xE620 | ||
22 | #define AD7143_PARTID 0xE630 | ||
23 | #define AD7147_PARTID 0x1470 | ||
24 | #define AD7148_PARTID 0x1480 | ||
25 | #define AD714X_STAGECFG_REG 0x80 | ||
26 | #define AD714X_SYSCFG_REG 0x0 | ||
27 | |||
28 | #define STG_LOW_INT_EN_REG 0x5 | ||
29 | #define STG_HIGH_INT_EN_REG 0x6 | ||
30 | #define STG_COM_INT_EN_REG 0x7 | ||
31 | #define STG_LOW_INT_STA_REG 0x8 | ||
32 | #define STG_HIGH_INT_STA_REG 0x9 | ||
33 | #define STG_COM_INT_STA_REG 0xA | ||
34 | |||
35 | #define CDC_RESULT_S0 0xB | ||
36 | #define CDC_RESULT_S1 0xC | ||
37 | #define CDC_RESULT_S2 0xD | ||
38 | #define CDC_RESULT_S3 0xE | ||
39 | #define CDC_RESULT_S4 0xF | ||
40 | #define CDC_RESULT_S5 0x10 | ||
41 | #define CDC_RESULT_S6 0x11 | ||
42 | #define CDC_RESULT_S7 0x12 | ||
43 | #define CDC_RESULT_S8 0x13 | ||
44 | #define CDC_RESULT_S9 0x14 | ||
45 | #define CDC_RESULT_S10 0x15 | ||
46 | #define CDC_RESULT_S11 0x16 | ||
47 | |||
48 | #define STAGE0_AMBIENT 0xF1 | ||
49 | #define STAGE1_AMBIENT 0x115 | ||
50 | #define STAGE2_AMBIENT 0x139 | ||
51 | #define STAGE3_AMBIENT 0x15D | ||
52 | #define STAGE4_AMBIENT 0x181 | ||
53 | #define STAGE5_AMBIENT 0x1A5 | ||
54 | #define STAGE6_AMBIENT 0x1C9 | ||
55 | #define STAGE7_AMBIENT 0x1ED | ||
56 | #define STAGE8_AMBIENT 0x211 | ||
57 | #define STAGE9_AMBIENT 0x234 | ||
58 | #define STAGE10_AMBIENT 0x259 | ||
59 | #define STAGE11_AMBIENT 0x27D | ||
60 | |||
61 | #define PER_STAGE_REG_NUM 36 | ||
62 | #define STAGE_NUM 12 | ||
63 | #define STAGE_CFGREG_NUM 8 | ||
64 | #define SYS_CFGREG_NUM 8 | ||
65 | |||
66 | /* | ||
67 | * driver information which will be used to maintain the software flow | ||
68 | */ | ||
69 | enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE }; | ||
70 | |||
71 | struct ad714x_slider_drv { | ||
72 | int highest_stage; | ||
73 | int abs_pos; | ||
74 | int flt_pos; | ||
75 | enum ad714x_device_state state; | ||
76 | struct input_dev *input; | ||
77 | }; | ||
78 | |||
79 | struct ad714x_wheel_drv { | ||
80 | int abs_pos; | ||
81 | int flt_pos; | ||
82 | int pre_mean_value; | ||
83 | int pre_highest_stage; | ||
84 | int pre_mean_value_no_offset; | ||
85 | int mean_value; | ||
86 | int mean_value_no_offset; | ||
87 | int pos_offset; | ||
88 | int pos_ratio; | ||
89 | int highest_stage; | ||
90 | enum ad714x_device_state state; | ||
91 | struct input_dev *input; | ||
92 | }; | ||
93 | |||
94 | struct ad714x_touchpad_drv { | ||
95 | int x_highest_stage; | ||
96 | int x_flt_pos; | ||
97 | int x_abs_pos; | ||
98 | int y_highest_stage; | ||
99 | int y_flt_pos; | ||
100 | int y_abs_pos; | ||
101 | int left_ep; | ||
102 | int left_ep_val; | ||
103 | int right_ep; | ||
104 | int right_ep_val; | ||
105 | int top_ep; | ||
106 | int top_ep_val; | ||
107 | int bottom_ep; | ||
108 | int bottom_ep_val; | ||
109 | enum ad714x_device_state state; | ||
110 | struct input_dev *input; | ||
111 | }; | ||
112 | |||
113 | struct ad714x_button_drv { | ||
114 | enum ad714x_device_state state; | ||
115 | /* | ||
116 | * Unlike slider/wheel/touchpad, all buttons point to | ||
117 | * same input_dev instance | ||
118 | */ | ||
119 | struct input_dev *input; | ||
120 | }; | ||
121 | |||
122 | struct ad714x_driver_data { | ||
123 | struct ad714x_slider_drv *slider; | ||
124 | struct ad714x_wheel_drv *wheel; | ||
125 | struct ad714x_touchpad_drv *touchpad; | ||
126 | struct ad714x_button_drv *button; | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * information to integrate all things which will be private data | ||
131 | * of spi/i2c device | ||
132 | */ | ||
133 | struct ad714x_chip { | ||
134 | unsigned short h_state; | ||
135 | unsigned short l_state; | ||
136 | unsigned short c_state; | ||
137 | unsigned short adc_reg[STAGE_NUM]; | ||
138 | unsigned short amb_reg[STAGE_NUM]; | ||
139 | unsigned short sensor_val[STAGE_NUM]; | ||
140 | |||
141 | struct ad714x_platform_data *hw; | ||
142 | struct ad714x_driver_data *sw; | ||
143 | |||
144 | int irq; | ||
145 | struct device *dev; | ||
146 | ad714x_read_t read; | ||
147 | ad714x_write_t write; | ||
148 | |||
149 | struct mutex mutex; | ||
150 | |||
151 | unsigned product; | ||
152 | unsigned version; | ||
153 | }; | ||
154 | |||
155 | static void ad714x_use_com_int(struct ad714x_chip *ad714x, | ||
156 | int start_stage, int end_stage) | ||
157 | { | ||
158 | unsigned short data; | ||
159 | unsigned short mask; | ||
160 | |||
161 | mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); | ||
162 | |||
163 | ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); | ||
164 | data |= 1 << start_stage; | ||
165 | ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); | ||
166 | |||
167 | ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); | ||
168 | data &= ~mask; | ||
169 | ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); | ||
170 | } | ||
171 | |||
172 | static void ad714x_use_thr_int(struct ad714x_chip *ad714x, | ||
173 | int start_stage, int end_stage) | ||
174 | { | ||
175 | unsigned short data; | ||
176 | unsigned short mask; | ||
177 | |||
178 | mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); | ||
179 | |||
180 | ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); | ||
181 | data &= ~(1 << start_stage); | ||
182 | ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); | ||
183 | |||
184 | ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); | ||
185 | data |= mask; | ||
186 | ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); | ||
187 | } | ||
188 | |||
189 | static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x, | ||
190 | int start_stage, int end_stage) | ||
191 | { | ||
192 | int max_res = 0; | ||
193 | int max_idx = 0; | ||
194 | int i; | ||
195 | |||
196 | for (i = start_stage; i <= end_stage; i++) { | ||
197 | if (ad714x->sensor_val[i] > max_res) { | ||
198 | max_res = ad714x->sensor_val[i]; | ||
199 | max_idx = i; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return max_idx; | ||
204 | } | ||
205 | |||
206 | static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x, | ||
207 | int start_stage, int end_stage, | ||
208 | int highest_stage, int max_coord) | ||
209 | { | ||
210 | int a_param, b_param; | ||
211 | |||
212 | if (highest_stage == start_stage) { | ||
213 | a_param = ad714x->sensor_val[start_stage + 1]; | ||
214 | b_param = ad714x->sensor_val[start_stage] + | ||
215 | ad714x->sensor_val[start_stage + 1]; | ||
216 | } else if (highest_stage == end_stage) { | ||
217 | a_param = ad714x->sensor_val[end_stage] * | ||
218 | (end_stage - start_stage) + | ||
219 | ad714x->sensor_val[end_stage - 1] * | ||
220 | (end_stage - start_stage - 1); | ||
221 | b_param = ad714x->sensor_val[end_stage] + | ||
222 | ad714x->sensor_val[end_stage - 1]; | ||
223 | } else { | ||
224 | a_param = ad714x->sensor_val[highest_stage] * | ||
225 | (highest_stage - start_stage) + | ||
226 | ad714x->sensor_val[highest_stage - 1] * | ||
227 | (highest_stage - start_stage - 1) + | ||
228 | ad714x->sensor_val[highest_stage + 1] * | ||
229 | (highest_stage - start_stage + 1); | ||
230 | b_param = ad714x->sensor_val[highest_stage] + | ||
231 | ad714x->sensor_val[highest_stage - 1] + | ||
232 | ad714x->sensor_val[highest_stage + 1]; | ||
233 | } | ||
234 | |||
235 | return (max_coord / (end_stage - start_stage)) * a_param / b_param; | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * One button can connect to multi positive and negative of CDCs | ||
240 | * Multi-buttons can connect to same positive/negative of one CDC | ||
241 | */ | ||
242 | static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx) | ||
243 | { | ||
244 | struct ad714x_button_plat *hw = &ad714x->hw->button[idx]; | ||
245 | struct ad714x_button_drv *sw = &ad714x->sw->button[idx]; | ||
246 | |||
247 | switch (sw->state) { | ||
248 | case IDLE: | ||
249 | if (((ad714x->h_state & hw->h_mask) == hw->h_mask) && | ||
250 | ((ad714x->l_state & hw->l_mask) == hw->l_mask)) { | ||
251 | dev_dbg(ad714x->dev, "button %d touched\n", idx); | ||
252 | input_report_key(sw->input, hw->keycode, 1); | ||
253 | input_sync(sw->input); | ||
254 | sw->state = ACTIVE; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case ACTIVE: | ||
259 | if (((ad714x->h_state & hw->h_mask) != hw->h_mask) || | ||
260 | ((ad714x->l_state & hw->l_mask) != hw->l_mask)) { | ||
261 | dev_dbg(ad714x->dev, "button %d released\n", idx); | ||
262 | input_report_key(sw->input, hw->keycode, 0); | ||
263 | input_sync(sw->input); | ||
264 | sw->state = IDLE; | ||
265 | } | ||
266 | break; | ||
267 | |||
268 | default: | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * The response of a sensor is defined by the absolute number of codes | ||
275 | * between the current CDC value and the ambient value. | ||
276 | */ | ||
277 | static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
278 | { | ||
279 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
280 | int i; | ||
281 | |||
282 | for (i = hw->start_stage; i <= hw->end_stage; i++) { | ||
283 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
284 | &ad714x->adc_reg[i]); | ||
285 | ad714x->read(ad714x->dev, | ||
286 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
287 | &ad714x->amb_reg[i]); | ||
288 | |||
289 | ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] - | ||
290 | ad714x->amb_reg[i]); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
295 | { | ||
296 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
297 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
298 | |||
299 | sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, | ||
300 | hw->end_stage); | ||
301 | |||
302 | dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx, | ||
303 | sw->highest_stage); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * The formulae are very straight forward. It uses the sensor with the | ||
308 | * highest response and the 2 adjacent ones. | ||
309 | * When Sensor 0 has the highest response, only sensor 0 and sensor 1 | ||
310 | * are used in the calculations. Similarly when the last sensor has the | ||
311 | * highest response, only the last sensor and the second last sensors | ||
312 | * are used in the calculations. | ||
313 | * | ||
314 | * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1 | ||
315 | * v += Sensor response(i)*i | ||
316 | * w += Sensor response(i) | ||
317 | * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w) | ||
318 | */ | ||
319 | static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
320 | { | ||
321 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
322 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
323 | |||
324 | sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage, | ||
325 | sw->highest_stage, hw->max_coord); | ||
326 | |||
327 | dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx, | ||
328 | sw->abs_pos); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * To minimise the Impact of the noise on the algorithm, ADI developed a | ||
333 | * routine that filters the CDC results after they have been read by the | ||
334 | * host processor. | ||
335 | * The filter used is an Infinite Input Response(IIR) filter implemented | ||
336 | * in firmware and attenuates the noise on the CDC results after they've | ||
337 | * been read by the host processor. | ||
338 | * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) + | ||
339 | * Latest_CDC_result * Coefficient)/10 | ||
340 | */ | ||
341 | static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
342 | { | ||
343 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
344 | |||
345 | sw->flt_pos = (sw->flt_pos * (10 - 4) + | ||
346 | sw->abs_pos * 4)/10; | ||
347 | |||
348 | dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx, | ||
349 | sw->flt_pos); | ||
350 | } | ||
351 | |||
352 | static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
353 | { | ||
354 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
355 | |||
356 | ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); | ||
357 | } | ||
358 | |||
359 | static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
360 | { | ||
361 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
362 | |||
363 | ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); | ||
364 | } | ||
365 | |||
366 | static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx) | ||
367 | { | ||
368 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
369 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
370 | unsigned short h_state, c_state; | ||
371 | unsigned short mask; | ||
372 | |||
373 | mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); | ||
374 | |||
375 | h_state = ad714x->h_state & mask; | ||
376 | c_state = ad714x->c_state & mask; | ||
377 | |||
378 | switch (sw->state) { | ||
379 | case IDLE: | ||
380 | if (h_state) { | ||
381 | sw->state = JITTER; | ||
382 | /* In End of Conversion interrupt mode, the AD714X | ||
383 | * continuously generates hardware interrupts. | ||
384 | */ | ||
385 | ad714x_slider_use_com_int(ad714x, idx); | ||
386 | dev_dbg(ad714x->dev, "slider %d touched\n", idx); | ||
387 | } | ||
388 | break; | ||
389 | |||
390 | case JITTER: | ||
391 | if (c_state == mask) { | ||
392 | ad714x_slider_cal_sensor_val(ad714x, idx); | ||
393 | ad714x_slider_cal_highest_stage(ad714x, idx); | ||
394 | ad714x_slider_cal_abs_pos(ad714x, idx); | ||
395 | sw->flt_pos = sw->abs_pos; | ||
396 | sw->state = ACTIVE; | ||
397 | } | ||
398 | break; | ||
399 | |||
400 | case ACTIVE: | ||
401 | if (c_state == mask) { | ||
402 | if (h_state) { | ||
403 | ad714x_slider_cal_sensor_val(ad714x, idx); | ||
404 | ad714x_slider_cal_highest_stage(ad714x, idx); | ||
405 | ad714x_slider_cal_abs_pos(ad714x, idx); | ||
406 | ad714x_slider_cal_flt_pos(ad714x, idx); | ||
407 | |||
408 | input_report_abs(sw->input, ABS_X, sw->flt_pos); | ||
409 | input_report_key(sw->input, BTN_TOUCH, 1); | ||
410 | } else { | ||
411 | /* When the user lifts off the sensor, configure | ||
412 | * the AD714X back to threshold interrupt mode. | ||
413 | */ | ||
414 | ad714x_slider_use_thr_int(ad714x, idx); | ||
415 | sw->state = IDLE; | ||
416 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
417 | dev_dbg(ad714x->dev, "slider %d released\n", | ||
418 | idx); | ||
419 | } | ||
420 | input_sync(sw->input); | ||
421 | } | ||
422 | break; | ||
423 | |||
424 | default: | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * When the scroll wheel is activated, we compute the absolute position based | ||
431 | * on the sensor values. To calculate the position, we first determine the | ||
432 | * sensor that has the greatest response among the 8 sensors that constitutes | ||
433 | * the scrollwheel. Then we determined the 2 sensors on either sides of the | ||
434 | * sensor with the highest response and we apply weights to these sensors. | ||
435 | */ | ||
436 | static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
437 | { | ||
438 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
439 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
440 | |||
441 | sw->pre_highest_stage = sw->highest_stage; | ||
442 | sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, | ||
443 | hw->end_stage); | ||
444 | |||
445 | dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx, | ||
446 | sw->highest_stage); | ||
447 | } | ||
448 | |||
449 | static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
450 | { | ||
451 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
452 | int i; | ||
453 | |||
454 | for (i = hw->start_stage; i <= hw->end_stage; i++) { | ||
455 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
456 | &ad714x->adc_reg[i]); | ||
457 | ad714x->read(ad714x->dev, | ||
458 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
459 | &ad714x->amb_reg[i]); | ||
460 | if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) | ||
461 | ad714x->sensor_val[i] = ad714x->adc_reg[i] - | ||
462 | ad714x->amb_reg[i]; | ||
463 | else | ||
464 | ad714x->sensor_val[i] = 0; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | * When the scroll wheel is activated, we compute the absolute position based | ||
470 | * on the sensor values. To calculate the position, we first determine the | ||
471 | * sensor that has the greatest response among the 8 sensors that constitutes | ||
472 | * the scrollwheel. Then we determined the 2 sensors on either sides of the | ||
473 | * sensor with the highest response and we apply weights to these sensors. The | ||
474 | * result of this computation gives us the mean value which defined by the | ||
475 | * following formula: | ||
476 | * For i= second_before_highest_stage to i= second_after_highest_stage | ||
477 | * v += Sensor response(i)*WEIGHT*(i+3) | ||
478 | * w += Sensor response(i) | ||
479 | * Mean_Value=v/w | ||
480 | * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio | ||
481 | */ | ||
482 | |||
483 | #define WEIGHT_FACTOR 30 | ||
484 | /* This constant prevents the "PositionOffset" from reaching a big value */ | ||
485 | #define OFFSET_POSITION_CLAMP 120 | ||
486 | static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
487 | { | ||
488 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
489 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
490 | int stage_num = hw->end_stage - hw->start_stage + 1; | ||
491 | int second_before, first_before, highest, first_after, second_after; | ||
492 | int a_param, b_param; | ||
493 | |||
494 | /* Calculate Mean value */ | ||
495 | |||
496 | second_before = (sw->highest_stage + stage_num - 2) % stage_num; | ||
497 | first_before = (sw->highest_stage + stage_num - 1) % stage_num; | ||
498 | highest = sw->highest_stage; | ||
499 | first_after = (sw->highest_stage + stage_num + 1) % stage_num; | ||
500 | second_after = (sw->highest_stage + stage_num + 2) % stage_num; | ||
501 | |||
502 | if (((sw->highest_stage - hw->start_stage) > 1) && | ||
503 | ((hw->end_stage - sw->highest_stage) > 1)) { | ||
504 | a_param = ad714x->sensor_val[second_before] * | ||
505 | (second_before - hw->start_stage + 3) + | ||
506 | ad714x->sensor_val[first_before] * | ||
507 | (second_before - hw->start_stage + 3) + | ||
508 | ad714x->sensor_val[highest] * | ||
509 | (second_before - hw->start_stage + 3) + | ||
510 | ad714x->sensor_val[first_after] * | ||
511 | (first_after - hw->start_stage + 3) + | ||
512 | ad714x->sensor_val[second_after] * | ||
513 | (second_after - hw->start_stage + 3); | ||
514 | } else { | ||
515 | a_param = ad714x->sensor_val[second_before] * | ||
516 | (second_before - hw->start_stage + 1) + | ||
517 | ad714x->sensor_val[first_before] * | ||
518 | (second_before - hw->start_stage + 2) + | ||
519 | ad714x->sensor_val[highest] * | ||
520 | (second_before - hw->start_stage + 3) + | ||
521 | ad714x->sensor_val[first_after] * | ||
522 | (first_after - hw->start_stage + 4) + | ||
523 | ad714x->sensor_val[second_after] * | ||
524 | (second_after - hw->start_stage + 5); | ||
525 | } | ||
526 | a_param *= WEIGHT_FACTOR; | ||
527 | |||
528 | b_param = ad714x->sensor_val[second_before] + | ||
529 | ad714x->sensor_val[first_before] + | ||
530 | ad714x->sensor_val[highest] + | ||
531 | ad714x->sensor_val[first_after] + | ||
532 | ad714x->sensor_val[second_after]; | ||
533 | |||
534 | sw->pre_mean_value = sw->mean_value; | ||
535 | sw->mean_value = a_param / b_param; | ||
536 | |||
537 | /* Calculate the offset */ | ||
538 | |||
539 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
540 | (sw->highest_stage == hw->start_stage)) | ||
541 | sw->pos_offset = sw->mean_value; | ||
542 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
543 | (sw->highest_stage == hw->end_stage)) | ||
544 | sw->pos_offset = sw->pre_mean_value; | ||
545 | |||
546 | if (sw->pos_offset > OFFSET_POSITION_CLAMP) | ||
547 | sw->pos_offset = OFFSET_POSITION_CLAMP; | ||
548 | |||
549 | /* Calculate the mean value without the offset */ | ||
550 | |||
551 | sw->pre_mean_value_no_offset = sw->mean_value_no_offset; | ||
552 | sw->mean_value_no_offset = sw->mean_value - sw->pos_offset; | ||
553 | if (sw->mean_value_no_offset < 0) | ||
554 | sw->mean_value_no_offset = 0; | ||
555 | |||
556 | /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */ | ||
557 | |||
558 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
559 | (sw->highest_stage == hw->start_stage)) | ||
560 | sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) / | ||
561 | hw->max_coord; | ||
562 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
563 | (sw->highest_stage == hw->end_stage)) | ||
564 | sw->pos_ratio = (sw->mean_value_no_offset * 100) / | ||
565 | hw->max_coord; | ||
566 | sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio; | ||
567 | if (sw->abs_pos > hw->max_coord) | ||
568 | sw->abs_pos = hw->max_coord; | ||
569 | } | ||
570 | |||
571 | static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
572 | { | ||
573 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
574 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
575 | if (((sw->pre_highest_stage == hw->end_stage) && | ||
576 | (sw->highest_stage == hw->start_stage)) || | ||
577 | ((sw->pre_highest_stage == hw->start_stage) && | ||
578 | (sw->highest_stage == hw->end_stage))) | ||
579 | sw->flt_pos = sw->abs_pos; | ||
580 | else | ||
581 | sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100; | ||
582 | |||
583 | if (sw->flt_pos > hw->max_coord) | ||
584 | sw->flt_pos = hw->max_coord; | ||
585 | } | ||
586 | |||
587 | static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
588 | { | ||
589 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
590 | |||
591 | ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); | ||
592 | } | ||
593 | |||
594 | static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
595 | { | ||
596 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
597 | |||
598 | ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); | ||
599 | } | ||
600 | |||
601 | static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx) | ||
602 | { | ||
603 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
604 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
605 | unsigned short h_state, c_state; | ||
606 | unsigned short mask; | ||
607 | |||
608 | mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); | ||
609 | |||
610 | h_state = ad714x->h_state & mask; | ||
611 | c_state = ad714x->c_state & mask; | ||
612 | |||
613 | switch (sw->state) { | ||
614 | case IDLE: | ||
615 | if (h_state) { | ||
616 | sw->state = JITTER; | ||
617 | /* In End of Conversion interrupt mode, the AD714X | ||
618 | * continuously generates hardware interrupts. | ||
619 | */ | ||
620 | ad714x_wheel_use_com_int(ad714x, idx); | ||
621 | dev_dbg(ad714x->dev, "wheel %d touched\n", idx); | ||
622 | } | ||
623 | break; | ||
624 | |||
625 | case JITTER: | ||
626 | if (c_state == mask) { | ||
627 | ad714x_wheel_cal_sensor_val(ad714x, idx); | ||
628 | ad714x_wheel_cal_highest_stage(ad714x, idx); | ||
629 | ad714x_wheel_cal_abs_pos(ad714x, idx); | ||
630 | sw->flt_pos = sw->abs_pos; | ||
631 | sw->state = ACTIVE; | ||
632 | } | ||
633 | break; | ||
634 | |||
635 | case ACTIVE: | ||
636 | if (c_state == mask) { | ||
637 | if (h_state) { | ||
638 | ad714x_wheel_cal_sensor_val(ad714x, idx); | ||
639 | ad714x_wheel_cal_highest_stage(ad714x, idx); | ||
640 | ad714x_wheel_cal_abs_pos(ad714x, idx); | ||
641 | ad714x_wheel_cal_flt_pos(ad714x, idx); | ||
642 | |||
643 | input_report_abs(sw->input, ABS_WHEEL, | ||
644 | sw->abs_pos); | ||
645 | input_report_key(sw->input, BTN_TOUCH, 1); | ||
646 | } else { | ||
647 | /* When the user lifts off the sensor, configure | ||
648 | * the AD714X back to threshold interrupt mode. | ||
649 | */ | ||
650 | ad714x_wheel_use_thr_int(ad714x, idx); | ||
651 | sw->state = IDLE; | ||
652 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
653 | |||
654 | dev_dbg(ad714x->dev, "wheel %d released\n", | ||
655 | idx); | ||
656 | } | ||
657 | input_sync(sw->input); | ||
658 | } | ||
659 | break; | ||
660 | |||
661 | default: | ||
662 | break; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
667 | { | ||
668 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
669 | int i; | ||
670 | |||
671 | for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) { | ||
672 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
673 | &ad714x->adc_reg[i]); | ||
674 | ad714x->read(ad714x->dev, | ||
675 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
676 | &ad714x->amb_reg[i]); | ||
677 | if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) | ||
678 | ad714x->sensor_val[i] = ad714x->adc_reg[i] - | ||
679 | ad714x->amb_reg[i]; | ||
680 | else | ||
681 | ad714x->sensor_val[i] = 0; | ||
682 | } | ||
683 | } | ||
684 | |||
685 | static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
686 | { | ||
687 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
688 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
689 | |||
690 | sw->x_highest_stage = ad714x_cal_highest_stage(ad714x, | ||
691 | hw->x_start_stage, hw->x_end_stage); | ||
692 | sw->y_highest_stage = ad714x_cal_highest_stage(ad714x, | ||
693 | hw->y_start_stage, hw->y_end_stage); | ||
694 | |||
695 | dev_dbg(ad714x->dev, | ||
696 | "touchpad %d x_highest_stage:%d, y_highest_stage:%d\n", | ||
697 | idx, sw->x_highest_stage, sw->y_highest_stage); | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | * If 2 fingers are touching the sensor then 2 peaks can be observed in the | ||
702 | * distribution. | ||
703 | * The arithmetic doesn't support to get absolute coordinates for multi-touch | ||
704 | * yet. | ||
705 | */ | ||
706 | static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx) | ||
707 | { | ||
708 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
709 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
710 | int i; | ||
711 | |||
712 | for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) { | ||
713 | if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) | ||
714 | > (ad714x->sensor_val[i + 1] / 10)) | ||
715 | return 1; | ||
716 | } | ||
717 | |||
718 | for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) { | ||
719 | if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) | ||
720 | > (ad714x->sensor_val[i] / 10)) | ||
721 | return 1; | ||
722 | } | ||
723 | |||
724 | for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) { | ||
725 | if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) | ||
726 | > (ad714x->sensor_val[i + 1] / 10)) | ||
727 | return 1; | ||
728 | } | ||
729 | |||
730 | for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) { | ||
731 | if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) | ||
732 | > (ad714x->sensor_val[i] / 10)) | ||
733 | return 1; | ||
734 | } | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * If only one finger is used to activate the touch pad then only 1 peak will be | ||
741 | * registered in the distribution. This peak and the 2 adjacent sensors will be | ||
742 | * used in the calculation of the absolute position. This will prevent hand | ||
743 | * shadows to affect the absolute position calculation. | ||
744 | */ | ||
745 | static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
746 | { | ||
747 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
748 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
749 | |||
750 | sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage, | ||
751 | hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord); | ||
752 | sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage, | ||
753 | hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord); | ||
754 | |||
755 | dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx, | ||
756 | sw->x_abs_pos, sw->y_abs_pos); | ||
757 | } | ||
758 | |||
759 | static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
760 | { | ||
761 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
762 | |||
763 | sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) + | ||
764 | sw->x_abs_pos * 4)/10; | ||
765 | sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) + | ||
766 | sw->y_abs_pos * 4)/10; | ||
767 | |||
768 | dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n", | ||
769 | idx, sw->x_flt_pos, sw->y_flt_pos); | ||
770 | } | ||
771 | |||
772 | /* | ||
773 | * To prevent distortion from showing in the absolute position, it is | ||
774 | * necessary to detect the end points. When endpoints are detected, the | ||
775 | * driver stops updating the status variables with absolute positions. | ||
776 | * End points are detected on the 4 edges of the touchpad sensor. The | ||
777 | * method to detect them is the same for all 4. | ||
778 | * To detect the end points, the firmware computes the difference in | ||
779 | * percent between the sensor on the edge and the adjacent one. The | ||
780 | * difference is calculated in percent in order to make the end point | ||
781 | * detection independent of the pressure. | ||
782 | */ | ||
783 | |||
784 | #define LEFT_END_POINT_DETECTION_LEVEL 550 | ||
785 | #define RIGHT_END_POINT_DETECTION_LEVEL 750 | ||
786 | #define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL 850 | ||
787 | #define TOP_END_POINT_DETECTION_LEVEL 550 | ||
788 | #define BOTTOM_END_POINT_DETECTION_LEVEL 950 | ||
789 | #define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL 700 | ||
790 | static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx) | ||
791 | { | ||
792 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
793 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
794 | int percent_sensor_diff; | ||
795 | |||
796 | /* left endpoint detect */ | ||
797 | percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] - | ||
798 | ad714x->sensor_val[hw->x_start_stage + 1]) * 100 / | ||
799 | ad714x->sensor_val[hw->x_start_stage + 1]; | ||
800 | if (!sw->left_ep) { | ||
801 | if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL) { | ||
802 | sw->left_ep = 1; | ||
803 | sw->left_ep_val = | ||
804 | ad714x->sensor_val[hw->x_start_stage + 1]; | ||
805 | } | ||
806 | } else { | ||
807 | if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) && | ||
808 | (ad714x->sensor_val[hw->x_start_stage + 1] > | ||
809 | LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val)) | ||
810 | sw->left_ep = 0; | ||
811 | } | ||
812 | |||
813 | /* right endpoint detect */ | ||
814 | percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] - | ||
815 | ad714x->sensor_val[hw->x_end_stage - 1]) * 100 / | ||
816 | ad714x->sensor_val[hw->x_end_stage - 1]; | ||
817 | if (!sw->right_ep) { | ||
818 | if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL) { | ||
819 | sw->right_ep = 1; | ||
820 | sw->right_ep_val = | ||
821 | ad714x->sensor_val[hw->x_end_stage - 1]; | ||
822 | } | ||
823 | } else { | ||
824 | if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) && | ||
825 | (ad714x->sensor_val[hw->x_end_stage - 1] > | ||
826 | LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val)) | ||
827 | sw->right_ep = 0; | ||
828 | } | ||
829 | |||
830 | /* top endpoint detect */ | ||
831 | percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] - | ||
832 | ad714x->sensor_val[hw->y_start_stage + 1]) * 100 / | ||
833 | ad714x->sensor_val[hw->y_start_stage + 1]; | ||
834 | if (!sw->top_ep) { | ||
835 | if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL) { | ||
836 | sw->top_ep = 1; | ||
837 | sw->top_ep_val = | ||
838 | ad714x->sensor_val[hw->y_start_stage + 1]; | ||
839 | } | ||
840 | } else { | ||
841 | if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) && | ||
842 | (ad714x->sensor_val[hw->y_start_stage + 1] > | ||
843 | TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val)) | ||
844 | sw->top_ep = 0; | ||
845 | } | ||
846 | |||
847 | /* bottom endpoint detect */ | ||
848 | percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] - | ||
849 | ad714x->sensor_val[hw->y_end_stage - 1]) * 100 / | ||
850 | ad714x->sensor_val[hw->y_end_stage - 1]; | ||
851 | if (!sw->bottom_ep) { | ||
852 | if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL) { | ||
853 | sw->bottom_ep = 1; | ||
854 | sw->bottom_ep_val = | ||
855 | ad714x->sensor_val[hw->y_end_stage - 1]; | ||
856 | } | ||
857 | } else { | ||
858 | if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) && | ||
859 | (ad714x->sensor_val[hw->y_end_stage - 1] > | ||
860 | TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val)) | ||
861 | sw->bottom_ep = 0; | ||
862 | } | ||
863 | |||
864 | return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep; | ||
865 | } | ||
866 | |||
867 | static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
868 | { | ||
869 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
870 | |||
871 | ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage); | ||
872 | } | ||
873 | |||
874 | static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
875 | { | ||
876 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
877 | |||
878 | ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage); | ||
879 | ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage); | ||
880 | } | ||
881 | |||
882 | static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx) | ||
883 | { | ||
884 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
885 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
886 | unsigned short h_state, c_state; | ||
887 | unsigned short mask; | ||
888 | |||
889 | mask = (((1 << (hw->x_end_stage + 1)) - 1) - | ||
890 | ((1 << hw->x_start_stage) - 1)) + | ||
891 | (((1 << (hw->y_end_stage + 1)) - 1) - | ||
892 | ((1 << hw->y_start_stage) - 1)); | ||
893 | |||
894 | h_state = ad714x->h_state & mask; | ||
895 | c_state = ad714x->c_state & mask; | ||
896 | |||
897 | switch (sw->state) { | ||
898 | case IDLE: | ||
899 | if (h_state) { | ||
900 | sw->state = JITTER; | ||
901 | /* In End of Conversion interrupt mode, the AD714X | ||
902 | * continuously generates hardware interrupts. | ||
903 | */ | ||
904 | touchpad_use_com_int(ad714x, idx); | ||
905 | dev_dbg(ad714x->dev, "touchpad %d touched\n", idx); | ||
906 | } | ||
907 | break; | ||
908 | |||
909 | case JITTER: | ||
910 | if (c_state == mask) { | ||
911 | touchpad_cal_sensor_val(ad714x, idx); | ||
912 | touchpad_cal_highest_stage(ad714x, idx); | ||
913 | if ((!touchpad_check_second_peak(ad714x, idx)) && | ||
914 | (!touchpad_check_endpoint(ad714x, idx))) { | ||
915 | dev_dbg(ad714x->dev, | ||
916 | "touchpad%d, 2 fingers or endpoint\n", | ||
917 | idx); | ||
918 | touchpad_cal_abs_pos(ad714x, idx); | ||
919 | sw->x_flt_pos = sw->x_abs_pos; | ||
920 | sw->y_flt_pos = sw->y_abs_pos; | ||
921 | sw->state = ACTIVE; | ||
922 | } | ||
923 | } | ||
924 | break; | ||
925 | |||
926 | case ACTIVE: | ||
927 | if (c_state == mask) { | ||
928 | if (h_state) { | ||
929 | touchpad_cal_sensor_val(ad714x, idx); | ||
930 | touchpad_cal_highest_stage(ad714x, idx); | ||
931 | if ((!touchpad_check_second_peak(ad714x, idx)) | ||
932 | && (!touchpad_check_endpoint(ad714x, idx))) { | ||
933 | touchpad_cal_abs_pos(ad714x, idx); | ||
934 | touchpad_cal_flt_pos(ad714x, idx); | ||
935 | input_report_abs(sw->input, ABS_X, | ||
936 | sw->x_flt_pos); | ||
937 | input_report_abs(sw->input, ABS_Y, | ||
938 | sw->y_flt_pos); | ||
939 | input_report_key(sw->input, BTN_TOUCH, | ||
940 | 1); | ||
941 | } | ||
942 | } else { | ||
943 | /* When the user lifts off the sensor, configure | ||
944 | * the AD714X back to threshold interrupt mode. | ||
945 | */ | ||
946 | touchpad_use_thr_int(ad714x, idx); | ||
947 | sw->state = IDLE; | ||
948 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
949 | dev_dbg(ad714x->dev, "touchpad %d released\n", | ||
950 | idx); | ||
951 | } | ||
952 | input_sync(sw->input); | ||
953 | } | ||
954 | break; | ||
955 | |||
956 | default: | ||
957 | break; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | static int ad714x_hw_detect(struct ad714x_chip *ad714x) | ||
962 | { | ||
963 | unsigned short data; | ||
964 | |||
965 | ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data); | ||
966 | switch (data & 0xFFF0) { | ||
967 | case AD7142_PARTID: | ||
968 | ad714x->product = 0x7142; | ||
969 | ad714x->version = data & 0xF; | ||
970 | dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n", | ||
971 | ad714x->version); | ||
972 | return 0; | ||
973 | |||
974 | case AD7143_PARTID: | ||
975 | ad714x->product = 0x7143; | ||
976 | ad714x->version = data & 0xF; | ||
977 | dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n", | ||
978 | ad714x->version); | ||
979 | return 0; | ||
980 | |||
981 | case AD7147_PARTID: | ||
982 | ad714x->product = 0x7147; | ||
983 | ad714x->version = data & 0xF; | ||
984 | dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n", | ||
985 | ad714x->version); | ||
986 | return 0; | ||
987 | |||
988 | case AD7148_PARTID: | ||
989 | ad714x->product = 0x7148; | ||
990 | ad714x->version = data & 0xF; | ||
991 | dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n", | ||
992 | ad714x->version); | ||
993 | return 0; | ||
994 | |||
995 | default: | ||
996 | dev_err(ad714x->dev, | ||
997 | "fail to detect AD714X captouch, read ID is %04x\n", | ||
998 | data); | ||
999 | return -ENODEV; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | static void ad714x_hw_init(struct ad714x_chip *ad714x) | ||
1004 | { | ||
1005 | int i, j; | ||
1006 | unsigned short reg_base; | ||
1007 | unsigned short data; | ||
1008 | |||
1009 | /* configuration CDC and interrupts */ | ||
1010 | |||
1011 | for (i = 0; i < STAGE_NUM; i++) { | ||
1012 | reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM; | ||
1013 | for (j = 0; j < STAGE_CFGREG_NUM; j++) | ||
1014 | ad714x->write(ad714x->dev, reg_base + j, | ||
1015 | ad714x->hw->stage_cfg_reg[i][j]); | ||
1016 | } | ||
1017 | |||
1018 | for (i = 0; i < SYS_CFGREG_NUM; i++) | ||
1019 | ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i, | ||
1020 | ad714x->hw->sys_cfg_reg[i]); | ||
1021 | for (i = 0; i < SYS_CFGREG_NUM; i++) | ||
1022 | ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i, | ||
1023 | &data); | ||
1024 | |||
1025 | ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF); | ||
1026 | |||
1027 | /* clear all interrupts */ | ||
1028 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); | ||
1029 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); | ||
1030 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); | ||
1031 | } | ||
1032 | |||
1033 | static irqreturn_t ad714x_interrupt_thread(int irq, void *data) | ||
1034 | { | ||
1035 | struct ad714x_chip *ad714x = data; | ||
1036 | int i; | ||
1037 | |||
1038 | mutex_lock(&ad714x->mutex); | ||
1039 | |||
1040 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state); | ||
1041 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state); | ||
1042 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state); | ||
1043 | |||
1044 | for (i = 0; i < ad714x->hw->button_num; i++) | ||
1045 | ad714x_button_state_machine(ad714x, i); | ||
1046 | for (i = 0; i < ad714x->hw->slider_num; i++) | ||
1047 | ad714x_slider_state_machine(ad714x, i); | ||
1048 | for (i = 0; i < ad714x->hw->wheel_num; i++) | ||
1049 | ad714x_wheel_state_machine(ad714x, i); | ||
1050 | for (i = 0; i < ad714x->hw->touchpad_num; i++) | ||
1051 | ad714x_touchpad_state_machine(ad714x, i); | ||
1052 | |||
1053 | mutex_unlock(&ad714x->mutex); | ||
1054 | |||
1055 | return IRQ_HANDLED; | ||
1056 | } | ||
1057 | |||
1058 | #define MAX_DEVICE_NUM 8 | ||
1059 | struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, | ||
1060 | ad714x_read_t read, ad714x_write_t write) | ||
1061 | { | ||
1062 | int i, alloc_idx; | ||
1063 | int error; | ||
1064 | struct input_dev *input[MAX_DEVICE_NUM]; | ||
1065 | |||
1066 | struct ad714x_platform_data *plat_data = dev->platform_data; | ||
1067 | struct ad714x_chip *ad714x; | ||
1068 | void *drv_mem; | ||
1069 | |||
1070 | struct ad714x_button_drv *bt_drv; | ||
1071 | struct ad714x_slider_drv *sd_drv; | ||
1072 | struct ad714x_wheel_drv *wl_drv; | ||
1073 | struct ad714x_touchpad_drv *tp_drv; | ||
1074 | |||
1075 | |||
1076 | if (irq <= 0) { | ||
1077 | dev_err(dev, "IRQ not configured!\n"); | ||
1078 | error = -EINVAL; | ||
1079 | goto err_out; | ||
1080 | } | ||
1081 | |||
1082 | if (dev->platform_data == NULL) { | ||
1083 | dev_err(dev, "platform data for ad714x doesn't exist\n"); | ||
1084 | error = -EINVAL; | ||
1085 | goto err_out; | ||
1086 | } | ||
1087 | |||
1088 | ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) + | ||
1089 | sizeof(*sd_drv) * plat_data->slider_num + | ||
1090 | sizeof(*wl_drv) * plat_data->wheel_num + | ||
1091 | sizeof(*tp_drv) * plat_data->touchpad_num + | ||
1092 | sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL); | ||
1093 | if (!ad714x) { | ||
1094 | error = -ENOMEM; | ||
1095 | goto err_out; | ||
1096 | } | ||
1097 | |||
1098 | ad714x->hw = plat_data; | ||
1099 | |||
1100 | drv_mem = ad714x + 1; | ||
1101 | ad714x->sw = drv_mem; | ||
1102 | drv_mem += sizeof(*ad714x->sw); | ||
1103 | ad714x->sw->slider = sd_drv = drv_mem; | ||
1104 | drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num; | ||
1105 | ad714x->sw->wheel = wl_drv = drv_mem; | ||
1106 | drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num; | ||
1107 | ad714x->sw->touchpad = tp_drv = drv_mem; | ||
1108 | drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num; | ||
1109 | ad714x->sw->button = bt_drv = drv_mem; | ||
1110 | drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num; | ||
1111 | |||
1112 | ad714x->read = read; | ||
1113 | ad714x->write = write; | ||
1114 | ad714x->irq = irq; | ||
1115 | ad714x->dev = dev; | ||
1116 | |||
1117 | error = ad714x_hw_detect(ad714x); | ||
1118 | if (error) | ||
1119 | goto err_free_mem; | ||
1120 | |||
1121 | /* initilize and request sw/hw resources */ | ||
1122 | |||
1123 | ad714x_hw_init(ad714x); | ||
1124 | mutex_init(&ad714x->mutex); | ||
1125 | |||
1126 | /* | ||
1127 | * Allocate and register AD714X input device | ||
1128 | */ | ||
1129 | alloc_idx = 0; | ||
1130 | |||
1131 | /* a slider uses one input_dev instance */ | ||
1132 | if (ad714x->hw->slider_num > 0) { | ||
1133 | struct ad714x_slider_plat *sd_plat = ad714x->hw->slider; | ||
1134 | |||
1135 | for (i = 0; i < ad714x->hw->slider_num; i++) { | ||
1136 | sd_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1137 | if (!input[alloc_idx]) { | ||
1138 | error = -ENOMEM; | ||
1139 | goto err_free_dev; | ||
1140 | } | ||
1141 | |||
1142 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1143 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1144 | __set_bit(ABS_X, input[alloc_idx]->absbit); | ||
1145 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1146 | input_set_abs_params(input[alloc_idx], | ||
1147 | ABS_X, 0, sd_plat->max_coord, 0, 0); | ||
1148 | |||
1149 | input[alloc_idx]->id.bustype = bus_type; | ||
1150 | input[alloc_idx]->id.product = ad714x->product; | ||
1151 | input[alloc_idx]->id.version = ad714x->version; | ||
1152 | |||
1153 | error = input_register_device(input[alloc_idx]); | ||
1154 | if (error) | ||
1155 | goto err_free_dev; | ||
1156 | |||
1157 | alloc_idx++; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | /* a wheel uses one input_dev instance */ | ||
1162 | if (ad714x->hw->wheel_num > 0) { | ||
1163 | struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel; | ||
1164 | |||
1165 | for (i = 0; i < ad714x->hw->wheel_num; i++) { | ||
1166 | wl_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1167 | if (!input[alloc_idx]) { | ||
1168 | error = -ENOMEM; | ||
1169 | goto err_free_dev; | ||
1170 | } | ||
1171 | |||
1172 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1173 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1174 | __set_bit(ABS_WHEEL, input[alloc_idx]->absbit); | ||
1175 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1176 | input_set_abs_params(input[alloc_idx], | ||
1177 | ABS_WHEEL, 0, wl_plat->max_coord, 0, 0); | ||
1178 | |||
1179 | input[alloc_idx]->id.bustype = bus_type; | ||
1180 | input[alloc_idx]->id.product = ad714x->product; | ||
1181 | input[alloc_idx]->id.version = ad714x->version; | ||
1182 | |||
1183 | error = input_register_device(input[alloc_idx]); | ||
1184 | if (error) | ||
1185 | goto err_free_dev; | ||
1186 | |||
1187 | alloc_idx++; | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | /* a touchpad uses one input_dev instance */ | ||
1192 | if (ad714x->hw->touchpad_num > 0) { | ||
1193 | struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad; | ||
1194 | |||
1195 | for (i = 0; i < ad714x->hw->touchpad_num; i++) { | ||
1196 | tp_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1197 | if (!input[alloc_idx]) { | ||
1198 | error = -ENOMEM; | ||
1199 | goto err_free_dev; | ||
1200 | } | ||
1201 | |||
1202 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1203 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1204 | __set_bit(ABS_X, input[alloc_idx]->absbit); | ||
1205 | __set_bit(ABS_Y, input[alloc_idx]->absbit); | ||
1206 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1207 | input_set_abs_params(input[alloc_idx], | ||
1208 | ABS_X, 0, tp_plat->x_max_coord, 0, 0); | ||
1209 | input_set_abs_params(input[alloc_idx], | ||
1210 | ABS_Y, 0, tp_plat->y_max_coord, 0, 0); | ||
1211 | |||
1212 | input[alloc_idx]->id.bustype = bus_type; | ||
1213 | input[alloc_idx]->id.product = ad714x->product; | ||
1214 | input[alloc_idx]->id.version = ad714x->version; | ||
1215 | |||
1216 | error = input_register_device(input[alloc_idx]); | ||
1217 | if (error) | ||
1218 | goto err_free_dev; | ||
1219 | |||
1220 | alloc_idx++; | ||
1221 | } | ||
1222 | } | ||
1223 | |||
1224 | /* all buttons use one input node */ | ||
1225 | if (ad714x->hw->button_num > 0) { | ||
1226 | struct ad714x_button_plat *bt_plat = ad714x->hw->button; | ||
1227 | |||
1228 | input[alloc_idx] = input_allocate_device(); | ||
1229 | if (!input[alloc_idx]) { | ||
1230 | error = -ENOMEM; | ||
1231 | goto err_free_dev; | ||
1232 | } | ||
1233 | |||
1234 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1235 | for (i = 0; i < ad714x->hw->button_num; i++) { | ||
1236 | bt_drv[i].input = input[alloc_idx]; | ||
1237 | __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit); | ||
1238 | } | ||
1239 | |||
1240 | input[alloc_idx]->id.bustype = bus_type; | ||
1241 | input[alloc_idx]->id.product = ad714x->product; | ||
1242 | input[alloc_idx]->id.version = ad714x->version; | ||
1243 | |||
1244 | error = input_register_device(input[alloc_idx]); | ||
1245 | if (error) | ||
1246 | goto err_free_dev; | ||
1247 | |||
1248 | alloc_idx++; | ||
1249 | } | ||
1250 | |||
1251 | error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread, | ||
1252 | IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x); | ||
1253 | if (error) { | ||
1254 | dev_err(dev, "can't allocate irq %d\n", ad714x->irq); | ||
1255 | goto err_unreg_dev; | ||
1256 | } | ||
1257 | |||
1258 | return ad714x; | ||
1259 | |||
1260 | err_free_dev: | ||
1261 | dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx); | ||
1262 | input_free_device(input[alloc_idx]); | ||
1263 | err_unreg_dev: | ||
1264 | while (--alloc_idx >= 0) | ||
1265 | input_unregister_device(input[alloc_idx]); | ||
1266 | err_free_mem: | ||
1267 | kfree(ad714x); | ||
1268 | err_out: | ||
1269 | return ERR_PTR(error); | ||
1270 | } | ||
1271 | EXPORT_SYMBOL(ad714x_probe); | ||
1272 | |||
1273 | void ad714x_remove(struct ad714x_chip *ad714x) | ||
1274 | { | ||
1275 | struct ad714x_platform_data *hw = ad714x->hw; | ||
1276 | struct ad714x_driver_data *sw = ad714x->sw; | ||
1277 | int i; | ||
1278 | |||
1279 | free_irq(ad714x->irq, ad714x); | ||
1280 | |||
1281 | /* unregister and free all input devices */ | ||
1282 | |||
1283 | for (i = 0; i < hw->slider_num; i++) | ||
1284 | input_unregister_device(sw->slider[i].input); | ||
1285 | |||
1286 | for (i = 0; i < hw->wheel_num; i++) | ||
1287 | input_unregister_device(sw->wheel[i].input); | ||
1288 | |||
1289 | for (i = 0; i < hw->touchpad_num; i++) | ||
1290 | input_unregister_device(sw->touchpad[i].input); | ||
1291 | |||
1292 | if (hw->button_num) | ||
1293 | input_unregister_device(sw->button[0].input); | ||
1294 | |||
1295 | kfree(ad714x); | ||
1296 | } | ||
1297 | EXPORT_SYMBOL(ad714x_remove); | ||
1298 | |||
1299 | #ifdef CONFIG_PM | ||
1300 | int ad714x_disable(struct ad714x_chip *ad714x) | ||
1301 | { | ||
1302 | unsigned short data; | ||
1303 | |||
1304 | dev_dbg(ad714x->dev, "%s enter\n", __func__); | ||
1305 | |||
1306 | mutex_lock(&ad714x->mutex); | ||
1307 | |||
1308 | data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3; | ||
1309 | ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data); | ||
1310 | |||
1311 | mutex_unlock(&ad714x->mutex); | ||
1312 | |||
1313 | return 0; | ||
1314 | } | ||
1315 | EXPORT_SYMBOL(ad714x_disable); | ||
1316 | |||
1317 | int ad714x_enable(struct ad714x_chip *ad714x) | ||
1318 | { | ||
1319 | unsigned short data; | ||
1320 | |||
1321 | dev_dbg(ad714x->dev, "%s enter\n", __func__); | ||
1322 | |||
1323 | mutex_lock(&ad714x->mutex); | ||
1324 | |||
1325 | /* resume to non-shutdown mode */ | ||
1326 | |||
1327 | ad714x->write(ad714x->dev, AD714X_PWR_CTRL, | ||
1328 | ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]); | ||
1329 | |||
1330 | /* make sure the interrupt output line is not low level after resume, | ||
1331 | * otherwise we will get no chance to enter falling-edge irq again | ||
1332 | */ | ||
1333 | |||
1334 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); | ||
1335 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); | ||
1336 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); | ||
1337 | |||
1338 | mutex_unlock(&ad714x->mutex); | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | EXPORT_SYMBOL(ad714x_enable); | ||
1343 | #endif | ||
1344 | |||
1345 | MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver"); | ||
1346 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
1347 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h new file mode 100644 index 000000000000..45c54fb13f07 --- /dev/null +++ b/drivers/input/misc/ad714x.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * AD714X CapTouch Programmable Controller driver (bus interfaces) | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #ifndef _AD714X_H_ | ||
10 | #define _AD714X_H_ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | |||
14 | struct device; | ||
15 | struct ad714x_chip; | ||
16 | |||
17 | typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *); | ||
18 | typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short); | ||
19 | |||
20 | int ad714x_disable(struct ad714x_chip *ad714x); | ||
21 | int ad714x_enable(struct ad714x_chip *ad714x); | ||
22 | struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, | ||
23 | ad714x_read_t read, ad714x_write_t write); | ||
24 | void ad714x_remove(struct ad714x_chip *ad714x); | ||
25 | |||
26 | #endif | ||
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c new file mode 100644 index 000000000000..5c3ac4e0b055 --- /dev/null +++ b/drivers/input/misc/pcf8574_keypad.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander | ||
3 | * | ||
4 | * Copyright 2005-2008 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/input.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/workqueue.h> | ||
16 | |||
17 | #define DRV_NAME "pcf8574_keypad" | ||
18 | |||
19 | static const unsigned char pcf8574_kp_btncode[] = { | ||
20 | [0] = KEY_RESERVED, | ||
21 | [1] = KEY_ENTER, | ||
22 | [2] = KEY_BACKSLASH, | ||
23 | [3] = KEY_0, | ||
24 | [4] = KEY_RIGHTBRACE, | ||
25 | [5] = KEY_C, | ||
26 | [6] = KEY_9, | ||
27 | [7] = KEY_8, | ||
28 | [8] = KEY_7, | ||
29 | [9] = KEY_B, | ||
30 | [10] = KEY_6, | ||
31 | [11] = KEY_5, | ||
32 | [12] = KEY_4, | ||
33 | [13] = KEY_A, | ||
34 | [14] = KEY_3, | ||
35 | [15] = KEY_2, | ||
36 | [16] = KEY_1 | ||
37 | }; | ||
38 | |||
39 | struct kp_data { | ||
40 | unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)]; | ||
41 | struct input_dev *idev; | ||
42 | struct i2c_client *client; | ||
43 | char name[64]; | ||
44 | char phys[32]; | ||
45 | unsigned char laststate; | ||
46 | }; | ||
47 | |||
48 | static short read_state(struct kp_data *lp) | ||
49 | { | ||
50 | unsigned char x, y, a, b; | ||
51 | |||
52 | i2c_smbus_write_byte(lp->client, 240); | ||
53 | x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4)); | ||
54 | |||
55 | i2c_smbus_write_byte(lp->client, 15); | ||
56 | y = 0xF & (~i2c_smbus_read_byte(lp->client)); | ||
57 | |||
58 | for (a = 0; x > 0; a++) | ||
59 | x = x >> 1; | ||
60 | for (b = 0; y > 0; b++) | ||
61 | y = y >> 1; | ||
62 | |||
63 | return ((a - 1) * 4) + b; | ||
64 | } | ||
65 | |||
66 | static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id) | ||
67 | { | ||
68 | struct kp_data *lp = dev_id; | ||
69 | unsigned char nextstate = read_state(lp); | ||
70 | |||
71 | if (lp->laststate != nextstate) { | ||
72 | int key_down = nextstate <= ARRAY_SIZE(lp->btncode); | ||
73 | unsigned short keycode = key_down ? | ||
74 | lp->btncode[nextstate] : lp->btncode[lp->laststate]; | ||
75 | |||
76 | input_report_key(lp->idev, keycode, key_down); | ||
77 | input_sync(lp->idev); | ||
78 | |||
79 | lp->laststate = nextstate; | ||
80 | } | ||
81 | |||
82 | return IRQ_HANDLED; | ||
83 | } | ||
84 | |||
85 | static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
86 | { | ||
87 | int i, ret; | ||
88 | struct input_dev *idev; | ||
89 | struct kp_data *lp; | ||
90 | |||
91 | if (i2c_smbus_write_byte(client, 240) < 0) { | ||
92 | dev_err(&client->dev, "probe: write fail\n"); | ||
93 | return -ENODEV; | ||
94 | } | ||
95 | |||
96 | lp = kzalloc(sizeof(*lp), GFP_KERNEL); | ||
97 | if (!lp) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | idev = input_allocate_device(); | ||
101 | if (!idev) { | ||
102 | dev_err(&client->dev, "Can't allocate input device\n"); | ||
103 | ret = -ENOMEM; | ||
104 | goto fail_allocate; | ||
105 | } | ||
106 | |||
107 | lp->idev = idev; | ||
108 | lp->client = client; | ||
109 | |||
110 | idev->evbit[0] = BIT_MASK(EV_KEY); | ||
111 | idev->keycode = lp->btncode; | ||
112 | idev->keycodesize = sizeof(lp->btncode[0]); | ||
113 | idev->keycodemax = ARRAY_SIZE(lp->btncode); | ||
114 | |||
115 | for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { | ||
116 | lp->btncode[i] = pcf8574_kp_btncode[i]; | ||
117 | __set_bit(lp->btncode[i] & KEY_MAX, idev->keybit); | ||
118 | } | ||
119 | |||
120 | sprintf(lp->name, DRV_NAME); | ||
121 | sprintf(lp->phys, "kp_data/input0"); | ||
122 | |||
123 | idev->name = lp->name; | ||
124 | idev->phys = lp->phys; | ||
125 | idev->id.bustype = BUS_I2C; | ||
126 | idev->id.vendor = 0x0001; | ||
127 | idev->id.product = 0x0001; | ||
128 | idev->id.version = 0x0100; | ||
129 | |||
130 | input_set_drvdata(idev, lp); | ||
131 | |||
132 | ret = input_register_device(idev); | ||
133 | if (ret) { | ||
134 | dev_err(&client->dev, "input_register_device() failed\n"); | ||
135 | goto fail_register; | ||
136 | } | ||
137 | |||
138 | lp->laststate = read_state(lp); | ||
139 | |||
140 | ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler, | ||
141 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
142 | DRV_NAME, lp); | ||
143 | if (ret) { | ||
144 | dev_err(&client->dev, "IRQ %d is not free\n", client->irq); | ||
145 | goto fail_irq; | ||
146 | } | ||
147 | |||
148 | i2c_set_clientdata(client, lp); | ||
149 | return 0; | ||
150 | |||
151 | fail_irq: | ||
152 | input_unregister_device(idev); | ||
153 | fail_register: | ||
154 | input_set_drvdata(idev, NULL); | ||
155 | input_free_device(idev); | ||
156 | fail_allocate: | ||
157 | kfree(lp); | ||
158 | |||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | static int __devexit pcf8574_kp_remove(struct i2c_client *client) | ||
163 | { | ||
164 | struct kp_data *lp = i2c_get_clientdata(client); | ||
165 | |||
166 | free_irq(client->irq, lp); | ||
167 | |||
168 | input_unregister_device(lp->idev); | ||
169 | kfree(lp); | ||
170 | |||
171 | i2c_set_clientdata(client, NULL); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | #ifdef CONFIG_PM | ||
177 | static int pcf8574_kp_resume(struct i2c_client *client) | ||
178 | { | ||
179 | enable_irq(client->irq); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg) | ||
185 | { | ||
186 | disable_irq(client->irq); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | #else | ||
191 | # define pcf8574_kp_resume NULL | ||
192 | # define pcf8574_kp_suspend NULL | ||
193 | #endif | ||
194 | |||
195 | static const struct i2c_device_id pcf8574_kp_id[] = { | ||
196 | { DRV_NAME, 0 }, | ||
197 | { } | ||
198 | }; | ||
199 | MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); | ||
200 | |||
201 | static struct i2c_driver pcf8574_kp_driver = { | ||
202 | .driver = { | ||
203 | .name = DRV_NAME, | ||
204 | .owner = THIS_MODULE, | ||
205 | }, | ||
206 | .probe = pcf8574_kp_probe, | ||
207 | .remove = __devexit_p(pcf8574_kp_remove), | ||
208 | .suspend = pcf8574_kp_suspend, | ||
209 | .resume = pcf8574_kp_resume, | ||
210 | .id_table = pcf8574_kp_id, | ||
211 | }; | ||
212 | |||
213 | static int __init pcf8574_kp_init(void) | ||
214 | { | ||
215 | return i2c_add_driver(&pcf8574_kp_driver); | ||
216 | } | ||
217 | module_init(pcf8574_kp_init); | ||
218 | |||
219 | static void __exit pcf8574_kp_exit(void) | ||
220 | { | ||
221 | i2c_del_driver(&pcf8574_kp_driver); | ||
222 | } | ||
223 | module_exit(pcf8574_kp_exit); | ||
224 | |||
225 | MODULE_AUTHOR("Michael Hennerich"); | ||
226 | MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574"); | ||
227 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 04d5a4a3181f..4dac8b79fcd4 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c | |||
@@ -983,11 +983,11 @@ static int __init copy_keymap(void) | |||
983 | for (key = keymap; key->type != KE_END; key++) | 983 | for (key = keymap; key->type != KE_END; key++) |
984 | length++; | 984 | length++; |
985 | 985 | ||
986 | new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); | 986 | new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), |
987 | GFP_KERNEL); | ||
987 | if (!new_keymap) | 988 | if (!new_keymap) |
988 | return -ENOMEM; | 989 | return -ENOMEM; |
989 | 990 | ||
990 | memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); | ||
991 | keymap = new_keymap; | 991 | keymap = new_keymap; |
992 | 992 | ||
993 | return 0; | 993 | return 0; |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index c714ca2407f8..eeb58c1cac16 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -17,7 +17,7 @@ config MOUSE_PS2 | |||
17 | default y | 17 | default y |
18 | select SERIO | 18 | select SERIO |
19 | select SERIO_LIBPS2 | 19 | select SERIO_LIBPS2 |
20 | select SERIO_I8042 if X86 | 20 | select SERIO_I8042 if X86 && !X86_MRST |
21 | select SERIO_GSCPS2 if GSC | 21 | select SERIO_GSCPS2 if GSC |
22 | help | 22 | help |
23 | Say Y here if you have a PS/2 mouse connected to your system. This | 23 | Say Y here if you have a PS/2 mouse connected to your system. This |
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 112b4ee52ff2..b18862b2a70e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
@@ -10,6 +10,8 @@ | |||
10 | * Trademarks are the property of their respective owners. | 10 | * Trademarks are the property of their respective owners. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt | ||
14 | |||
13 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
14 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
15 | #include <linux/module.h> | 17 | #include <linux/module.h> |
@@ -19,10 +21,10 @@ | |||
19 | #include "psmouse.h" | 21 | #include "psmouse.h" |
20 | #include "elantech.h" | 22 | #include "elantech.h" |
21 | 23 | ||
22 | #define elantech_debug(format, arg...) \ | 24 | #define elantech_debug(fmt, ...) \ |
23 | do { \ | 25 | do { \ |
24 | if (etd->debug) \ | 26 | if (etd->debug) \ |
25 | printk(KERN_DEBUG format, ##arg); \ | 27 | printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ |
26 | } while (0) | 28 | } while (0) |
27 | 29 | ||
28 | static bool force_elantech; | 30 | static bool force_elantech; |
@@ -37,7 +39,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, | |||
37 | { | 39 | { |
38 | if (psmouse_sliced_command(psmouse, c) || | 40 | if (psmouse_sliced_command(psmouse, c) || |
39 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 41 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
40 | pr_err("elantech.c: synaptics_send_cmd query 0x%02x failed.\n", c); | 42 | pr_err("synaptics_send_cmd query 0x%02x failed.\n", c); |
41 | return -1; | 43 | return -1; |
42 | } | 44 | } |
43 | 45 | ||
@@ -60,13 +62,13 @@ static int elantech_ps2_command(struct psmouse *psmouse, | |||
60 | if (rc == 0) | 62 | if (rc == 0) |
61 | break; | 63 | break; |
62 | tries--; | 64 | tries--; |
63 | elantech_debug("elantech.c: retrying ps2 command 0x%02x (%d).\n", | 65 | elantech_debug("retrying ps2 command 0x%02x (%d).\n", |
64 | command, tries); | 66 | command, tries); |
65 | msleep(ETP_PS2_COMMAND_DELAY); | 67 | msleep(ETP_PS2_COMMAND_DELAY); |
66 | } while (tries > 0); | 68 | } while (tries > 0); |
67 | 69 | ||
68 | if (rc) | 70 | if (rc) |
69 | pr_err("elantech.c: ps2 command 0x%02x failed.\n", command); | 71 | pr_err("ps2 command 0x%02x failed.\n", command); |
70 | 72 | ||
71 | return rc; | 73 | return rc; |
72 | } | 74 | } |
@@ -108,7 +110,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, | |||
108 | } | 110 | } |
109 | 111 | ||
110 | if (rc) | 112 | if (rc) |
111 | pr_err("elantech.c: failed to read register 0x%02x.\n", reg); | 113 | pr_err("failed to read register 0x%02x.\n", reg); |
112 | else | 114 | else |
113 | *val = param[0]; | 115 | *val = param[0]; |
114 | 116 | ||
@@ -154,7 +156,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, | |||
154 | } | 156 | } |
155 | 157 | ||
156 | if (rc) | 158 | if (rc) |
157 | pr_err("elantech.c: failed to write register 0x%02x with value 0x%02x.\n", | 159 | pr_err("failed to write register 0x%02x with value 0x%02x.\n", |
158 | reg, val); | 160 | reg, val); |
159 | 161 | ||
160 | return rc; | 162 | return rc; |
@@ -167,7 +169,7 @@ static void elantech_packet_dump(unsigned char *packet, int size) | |||
167 | { | 169 | { |
168 | int i; | 170 | int i; |
169 | 171 | ||
170 | printk(KERN_DEBUG "elantech.c: PS/2 packet ["); | 172 | printk(KERN_DEBUG pr_fmt("PS/2 packet [")); |
171 | for (i = 0; i < size; i++) | 173 | for (i = 0; i < size; i++) |
172 | printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); | 174 | printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); |
173 | printk("]\n"); | 175 | printk("]\n"); |
@@ -203,7 +205,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) | |||
203 | if (etd->jumpy_cursor) { | 205 | if (etd->jumpy_cursor) { |
204 | /* Discard packets that are likely to have bogus coordinates */ | 206 | /* Discard packets that are likely to have bogus coordinates */ |
205 | if (fingers > old_fingers) { | 207 | if (fingers > old_fingers) { |
206 | elantech_debug("elantech.c: discarding packet\n"); | 208 | elantech_debug("discarding packet\n"); |
207 | goto discard_packet_v1; | 209 | goto discard_packet_v1; |
208 | } | 210 | } |
209 | } | 211 | } |
@@ -413,23 +415,21 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) | |||
413 | if (rc == 0) | 415 | if (rc == 0) |
414 | break; | 416 | break; |
415 | tries--; | 417 | tries--; |
416 | elantech_debug("elantech.c: retrying read (%d).\n", | 418 | elantech_debug("retrying read (%d).\n", tries); |
417 | tries); | ||
418 | msleep(ETP_READ_BACK_DELAY); | 419 | msleep(ETP_READ_BACK_DELAY); |
419 | } while (tries > 0); | 420 | } while (tries > 0); |
420 | 421 | ||
421 | if (rc) { | 422 | if (rc) { |
422 | pr_err("elantech.c: failed to read back register 0x10.\n"); | 423 | pr_err("failed to read back register 0x10.\n"); |
423 | } else if (etd->hw_version == 1 && | 424 | } else if (etd->hw_version == 1 && |
424 | !(val & ETP_R10_ABSOLUTE_MODE)) { | 425 | !(val & ETP_R10_ABSOLUTE_MODE)) { |
425 | pr_err("elantech.c: touchpad refuses " | 426 | pr_err("touchpad refuses to switch to absolute mode.\n"); |
426 | "to switch to absolute mode.\n"); | ||
427 | rc = -1; | 427 | rc = -1; |
428 | } | 428 | } |
429 | } | 429 | } |
430 | 430 | ||
431 | if (rc) | 431 | if (rc) |
432 | pr_err("elantech.c: failed to initialise registers.\n"); | 432 | pr_err("failed to initialise registers.\n"); |
433 | 433 | ||
434 | return rc; | 434 | return rc; |
435 | } | 435 | } |
@@ -575,6 +575,24 @@ static struct attribute_group elantech_attr_group = { | |||
575 | .attrs = elantech_attrs, | 575 | .attrs = elantech_attrs, |
576 | }; | 576 | }; |
577 | 577 | ||
578 | static bool elantech_is_signature_valid(const unsigned char *param) | ||
579 | { | ||
580 | static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; | ||
581 | int i; | ||
582 | |||
583 | if (param[0] == 0) | ||
584 | return false; | ||
585 | |||
586 | if (param[1] == 0) | ||
587 | return true; | ||
588 | |||
589 | for (i = 0; i < ARRAY_SIZE(rates); i++) | ||
590 | if (param[2] == rates[i]) | ||
591 | return false; | ||
592 | |||
593 | return true; | ||
594 | } | ||
595 | |||
578 | /* | 596 | /* |
579 | * Use magic knock to detect Elantech touchpad | 597 | * Use magic knock to detect Elantech touchpad |
580 | */ | 598 | */ |
@@ -590,7 +608,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) | |||
590 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | 608 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
591 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | 609 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
592 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 610 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
593 | pr_debug("elantech.c: sending Elantech magic knock failed.\n"); | 611 | pr_debug("sending Elantech magic knock failed.\n"); |
594 | return -1; | 612 | return -1; |
595 | } | 613 | } |
596 | 614 | ||
@@ -599,8 +617,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) | |||
599 | * set of magic numbers | 617 | * set of magic numbers |
600 | */ | 618 | */ |
601 | if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { | 619 | if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { |
602 | pr_debug("elantech.c: " | 620 | pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", |
603 | "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", | ||
604 | param[0], param[1], param[2]); | 621 | param[0], param[1], param[2]); |
605 | return -1; | 622 | return -1; |
606 | } | 623 | } |
@@ -611,20 +628,20 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) | |||
611 | * to Elantech magic knock and there might be more. | 628 | * to Elantech magic knock and there might be more. |
612 | */ | 629 | */ |
613 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { | 630 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { |
614 | pr_debug("elantech.c: failed to query firmware version.\n"); | 631 | pr_debug("failed to query firmware version.\n"); |
615 | return -1; | 632 | return -1; |
616 | } | 633 | } |
617 | 634 | ||
618 | pr_debug("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", | 635 | pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", |
619 | param[0], param[1], param[2]); | 636 | param[0], param[1], param[2]); |
620 | 637 | ||
621 | if (param[0] == 0 || param[1] != 0) { | 638 | if (!elantech_is_signature_valid(param)) { |
622 | if (!force_elantech) { | 639 | if (!force_elantech) { |
623 | pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n"); | 640 | pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); |
624 | return -1; | 641 | return -1; |
625 | } | 642 | } |
626 | 643 | ||
627 | pr_debug("elantech.c: Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); | 644 | pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); |
628 | } | 645 | } |
629 | 646 | ||
630 | if (set_properties) { | 647 | if (set_properties) { |
@@ -655,7 +672,7 @@ static int elantech_reconnect(struct psmouse *psmouse) | |||
655 | return -1; | 672 | return -1; |
656 | 673 | ||
657 | if (elantech_set_absolute_mode(psmouse)) { | 674 | if (elantech_set_absolute_mode(psmouse)) { |
658 | pr_err("elantech.c: failed to put touchpad back into absolute mode.\n"); | 675 | pr_err("failed to put touchpad back into absolute mode.\n"); |
659 | return -1; | 676 | return -1; |
660 | } | 677 | } |
661 | 678 | ||
@@ -683,7 +700,7 @@ int elantech_init(struct psmouse *psmouse) | |||
683 | * Do the version query again so we can store the result | 700 | * Do the version query again so we can store the result |
684 | */ | 701 | */ |
685 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { | 702 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { |
686 | pr_err("elantech.c: failed to query firmware version.\n"); | 703 | pr_err("failed to query firmware version.\n"); |
687 | goto init_fail; | 704 | goto init_fail; |
688 | } | 705 | } |
689 | 706 | ||
@@ -704,14 +721,14 @@ int elantech_init(struct psmouse *psmouse) | |||
704 | etd->paritycheck = 1; | 721 | etd->paritycheck = 1; |
705 | } | 722 | } |
706 | 723 | ||
707 | pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d.%d\n", | 724 | pr_info("assuming hardware version %d, firmware version %d.%d.%d\n", |
708 | etd->hw_version, param[0], param[1], param[2]); | 725 | etd->hw_version, param[0], param[1], param[2]); |
709 | 726 | ||
710 | if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { | 727 | if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { |
711 | pr_err("elantech.c: failed to query capabilities.\n"); | 728 | pr_err("failed to query capabilities.\n"); |
712 | goto init_fail; | 729 | goto init_fail; |
713 | } | 730 | } |
714 | pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", | 731 | pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", |
715 | param[0], param[1], param[2]); | 732 | param[0], param[1], param[2]); |
716 | etd->capabilities = param[0]; | 733 | etd->capabilities = param[0]; |
717 | 734 | ||
@@ -721,13 +738,12 @@ int elantech_init(struct psmouse *psmouse) | |||
721 | * to jump. Enable a workaround. | 738 | * to jump. Enable a workaround. |
722 | */ | 739 | */ |
723 | if (etd->fw_version == 0x020022) { | 740 | if (etd->fw_version == 0x020022) { |
724 | pr_info("elantech.c: firmware version 2.0.34 detected, " | 741 | pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n"); |
725 | "enabling jumpy cursor workaround\n"); | ||
726 | etd->jumpy_cursor = 1; | 742 | etd->jumpy_cursor = 1; |
727 | } | 743 | } |
728 | 744 | ||
729 | if (elantech_set_absolute_mode(psmouse)) { | 745 | if (elantech_set_absolute_mode(psmouse)) { |
730 | pr_err("elantech.c: failed to put touchpad into absolute mode.\n"); | 746 | pr_err("failed to put touchpad into absolute mode.\n"); |
731 | goto init_fail; | 747 | goto init_fail; |
732 | } | 748 | } |
733 | 749 | ||
@@ -736,8 +752,7 @@ int elantech_init(struct psmouse *psmouse) | |||
736 | error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, | 752 | error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, |
737 | &elantech_attr_group); | 753 | &elantech_attr_group); |
738 | if (error) { | 754 | if (error) { |
739 | pr_err("elantech.c: failed to create sysfs attributes, error: %d.\n", | 755 | pr_err("failed to create sysfs attributes, error: %d.\n", error); |
740 | error); | ||
741 | goto init_fail; | 756 | goto init_fail; |
742 | } | 757 | } |
743 | 758 | ||
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 08d66d820d2b..1d2205b24800 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c | |||
@@ -40,8 +40,8 @@ | |||
40 | #include "psmouse.h" | 40 | #include "psmouse.h" |
41 | #include "hgpk.h" | 41 | #include "hgpk.h" |
42 | 42 | ||
43 | static int tpdebug; | 43 | static bool tpdebug; |
44 | module_param(tpdebug, int, 0644); | 44 | module_param(tpdebug, bool, 0644); |
45 | MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); | 45 | MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); |
46 | 46 | ||
47 | static int recalib_delta = 100; | 47 | static int recalib_delta = 100; |
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 543c240a85f2..c9983aee9082 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c | |||
@@ -56,36 +56,36 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) | |||
56 | /* Logitech extended packet */ | 56 | /* Logitech extended packet */ |
57 | switch ((packet[1] >> 4) | (packet[0] & 0x30)) { | 57 | switch ((packet[1] >> 4) | (packet[0] & 0x30)) { |
58 | 58 | ||
59 | case 0x0d: /* Mouse extra info */ | 59 | case 0x0d: /* Mouse extra info */ |
60 | 60 | ||
61 | input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, | 61 | input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, |
62 | (int) (packet[2] & 8) - (int) (packet[2] & 7)); | 62 | (int) (packet[2] & 8) - (int) (packet[2] & 7)); |
63 | input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); | 63 | input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); |
64 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); | 64 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); |
65 | 65 | ||
66 | break; | 66 | break; |
67 | 67 | ||
68 | case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ | 68 | case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ |
69 | 69 | ||
70 | input_report_key(dev, BTN_SIDE, (packet[2]) & 1); | 70 | input_report_key(dev, BTN_SIDE, (packet[2]) & 1); |
71 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); | 71 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); |
72 | input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); | 72 | input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); |
73 | input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); | 73 | input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); |
74 | input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); | 74 | input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); |
75 | 75 | ||
76 | break; | 76 | break; |
77 | 77 | ||
78 | case 0x0f: /* TouchPad extra info */ | 78 | case 0x0f: /* TouchPad extra info */ |
79 | 79 | ||
80 | input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, | 80 | input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, |
81 | (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); | 81 | (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); |
82 | packet[0] = packet[2] | 0x08; | 82 | packet[0] = packet[2] | 0x08; |
83 | break; | 83 | break; |
84 | 84 | ||
85 | #ifdef DEBUG | 85 | #ifdef DEBUG |
86 | default: | 86 | default: |
87 | printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", | 87 | printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", |
88 | (packet[1] >> 4) | (packet[0] & 0x30)); | 88 | (packet[1] >> 4) | (packet[0] & 0x30)); |
89 | #endif | 89 | #endif |
90 | } | 90 | } |
91 | } else { | 91 | } else { |
@@ -250,7 +250,6 @@ static const struct ps2pp_info *get_model_info(unsigned char model) | |||
250 | if (model == ps2pp_list[i].model) | 250 | if (model == ps2pp_list[i].model) |
251 | return &ps2pp_list[i]; | 251 | return &ps2pp_list[i]; |
252 | 252 | ||
253 | printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); | ||
254 | return NULL; | 253 | return NULL; |
255 | } | 254 | } |
256 | 255 | ||
@@ -285,31 +284,32 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, | |||
285 | __set_bit(REL_HWHEEL, input_dev->relbit); | 284 | __set_bit(REL_HWHEEL, input_dev->relbit); |
286 | 285 | ||
287 | switch (model_info->kind) { | 286 | switch (model_info->kind) { |
288 | case PS2PP_KIND_WHEEL: | ||
289 | psmouse->name = "Wheel Mouse"; | ||
290 | break; | ||
291 | |||
292 | case PS2PP_KIND_MX: | ||
293 | psmouse->name = "MX Mouse"; | ||
294 | break; | ||
295 | 287 | ||
296 | case PS2PP_KIND_TP3: | 288 | case PS2PP_KIND_WHEEL: |
297 | psmouse->name = "TouchPad 3"; | 289 | psmouse->name = "Wheel Mouse"; |
298 | break; | 290 | break; |
299 | 291 | ||
300 | case PS2PP_KIND_TRACKMAN: | 292 | case PS2PP_KIND_MX: |
301 | psmouse->name = "TrackMan"; | 293 | psmouse->name = "MX Mouse"; |
302 | break; | 294 | break; |
303 | 295 | ||
304 | default: | 296 | case PS2PP_KIND_TP3: |
305 | /* | 297 | psmouse->name = "TouchPad 3"; |
306 | * Set name to "Mouse" only when using PS2++, | 298 | break; |
307 | * otherwise let other protocols define suitable | 299 | |
308 | * name | 300 | case PS2PP_KIND_TRACKMAN: |
309 | */ | 301 | psmouse->name = "TrackMan"; |
310 | if (using_ps2pp) | 302 | break; |
311 | psmouse->name = "Mouse"; | 303 | |
312 | break; | 304 | default: |
305 | /* | ||
306 | * Set name to "Mouse" only when using PS2++, | ||
307 | * otherwise let other protocols define suitable | ||
308 | * name | ||
309 | */ | ||
310 | if (using_ps2pp) | ||
311 | psmouse->name = "Mouse"; | ||
312 | break; | ||
313 | } | 313 | } |
314 | } | 314 | } |
315 | 315 | ||
@@ -343,7 +343,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) | |||
343 | if (!model || !buttons) | 343 | if (!model || !buttons) |
344 | return -1; | 344 | return -1; |
345 | 345 | ||
346 | if ((model_info = get_model_info(model)) != NULL) { | 346 | model_info = get_model_info(model); |
347 | if (model_info) { | ||
347 | 348 | ||
348 | /* | 349 | /* |
349 | * Do Logitech PS2++ / PS2T++ magic init. | 350 | * Do Logitech PS2++ / PS2T++ magic init. |
@@ -379,6 +380,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) | |||
379 | use_ps2pp = true; | 380 | use_ps2pp = true; |
380 | } | 381 | } |
381 | } | 382 | } |
383 | |||
384 | } else { | ||
385 | printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); | ||
382 | } | 386 | } |
383 | 387 | ||
384 | if (set_properties) { | 388 | if (set_properties) { |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a3c97315a473..979c50215282 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -147,18 +147,18 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) | |||
147 | 147 | ||
148 | if (psmouse->type == PSMOUSE_IMEX) { | 148 | if (psmouse->type == PSMOUSE_IMEX) { |
149 | switch (packet[3] & 0xC0) { | 149 | switch (packet[3] & 0xC0) { |
150 | case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ | 150 | case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ |
151 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); | 151 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); |
152 | break; | 152 | break; |
153 | case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ | 153 | case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ |
154 | input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); | 154 | input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); |
155 | break; | 155 | break; |
156 | case 0x00: | 156 | case 0x00: |
157 | case 0xC0: | 157 | case 0xC0: |
158 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); | 158 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); |
159 | input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); | 159 | input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); |
160 | input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); | 160 | input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); |
161 | break; | 161 | break; |
162 | } | 162 | } |
163 | } | 163 | } |
164 | 164 | ||
@@ -247,31 +247,31 @@ static int psmouse_handle_byte(struct psmouse *psmouse) | |||
247 | psmouse_ret_t rc = psmouse->protocol_handler(psmouse); | 247 | psmouse_ret_t rc = psmouse->protocol_handler(psmouse); |
248 | 248 | ||
249 | switch (rc) { | 249 | switch (rc) { |
250 | case PSMOUSE_BAD_DATA: | 250 | case PSMOUSE_BAD_DATA: |
251 | if (psmouse->state == PSMOUSE_ACTIVATED) { | 251 | if (psmouse->state == PSMOUSE_ACTIVATED) { |
252 | printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", | 252 | printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", |
253 | psmouse->name, psmouse->phys, psmouse->pktcnt); | 253 | psmouse->name, psmouse->phys, psmouse->pktcnt); |
254 | if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { | 254 | if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { |
255 | __psmouse_set_state(psmouse, PSMOUSE_IGNORE); | 255 | __psmouse_set_state(psmouse, PSMOUSE_IGNORE); |
256 | printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); | 256 | printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); |
257 | serio_reconnect(psmouse->ps2dev.serio); | 257 | serio_reconnect(psmouse->ps2dev.serio); |
258 | return -1; | 258 | return -1; |
259 | } | ||
260 | } | ||
261 | psmouse->pktcnt = 0; | ||
262 | break; | ||
263 | |||
264 | case PSMOUSE_FULL_PACKET: | ||
265 | psmouse->pktcnt = 0; | ||
266 | if (psmouse->out_of_sync_cnt) { | ||
267 | psmouse->out_of_sync_cnt = 0; | ||
268 | printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", | ||
269 | psmouse->name, psmouse->phys); | ||
270 | } | 259 | } |
271 | break; | 260 | } |
261 | psmouse->pktcnt = 0; | ||
262 | break; | ||
263 | |||
264 | case PSMOUSE_FULL_PACKET: | ||
265 | psmouse->pktcnt = 0; | ||
266 | if (psmouse->out_of_sync_cnt) { | ||
267 | psmouse->out_of_sync_cnt = 0; | ||
268 | printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", | ||
269 | psmouse->name, psmouse->phys); | ||
270 | } | ||
271 | break; | ||
272 | 272 | ||
273 | case PSMOUSE_GOOD_DATA: | 273 | case PSMOUSE_GOOD_DATA: |
274 | break; | 274 | break; |
275 | } | 275 | } |
276 | return 0; | 276 | return 0; |
277 | } | 277 | } |
@@ -1245,7 +1245,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, | |||
1245 | psmouse->pktsize = 3; | 1245 | psmouse->pktsize = 3; |
1246 | 1246 | ||
1247 | if (proto && (proto->detect || proto->init)) { | 1247 | if (proto && (proto->detect || proto->init)) { |
1248 | if (proto->detect && proto->detect(psmouse, 1) < 0) | 1248 | if (proto->detect && proto->detect(psmouse, true) < 0) |
1249 | return -1; | 1249 | return -1; |
1250 | 1250 | ||
1251 | if (proto->init && proto->init(psmouse) < 0) | 1251 | if (proto->init && proto->init(psmouse) < 0) |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ebd7a99efeae..40cea334ad13 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -36,6 +36,8 @@ | |||
36 | * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, | 36 | * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, |
37 | * section 2.3.2, which says that they should be valid regardless of the | 37 | * section 2.3.2, which says that they should be valid regardless of the |
38 | * actual size of the sensor. | 38 | * actual size of the sensor. |
39 | * Note that newer firmware allows querying device for maximum useable | ||
40 | * coordinates. | ||
39 | */ | 41 | */ |
40 | #define XMIN_NOMINAL 1472 | 42 | #define XMIN_NOMINAL 1472 |
41 | #define XMAX_NOMINAL 5472 | 43 | #define XMAX_NOMINAL 5472 |
@@ -194,23 +196,33 @@ static int synaptics_identify(struct psmouse *psmouse) | |||
194 | } | 196 | } |
195 | 197 | ||
196 | /* | 198 | /* |
197 | * Read touchpad resolution | 199 | * Read touchpad resolution and maximum reported coordinates |
198 | * Resolution is left zero if touchpad does not support the query | 200 | * Resolution is left zero if touchpad does not support the query |
199 | */ | 201 | */ |
200 | static int synaptics_resolution(struct psmouse *psmouse) | 202 | static int synaptics_resolution(struct psmouse *psmouse) |
201 | { | 203 | { |
202 | struct synaptics_data *priv = psmouse->private; | 204 | struct synaptics_data *priv = psmouse->private; |
203 | unsigned char res[3]; | 205 | unsigned char res[3]; |
206 | unsigned char max[3]; | ||
204 | 207 | ||
205 | if (SYN_ID_MAJOR(priv->identity) < 4) | 208 | if (SYN_ID_MAJOR(priv->identity) < 4) |
206 | return 0; | ||
207 | 209 | ||
208 | if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res)) | 210 | if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) { |
209 | return 0; | 211 | if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) { |
212 | priv->x_res = res[0]; /* x resolution in units/mm */ | ||
213 | priv->y_res = res[2]; /* y resolution in units/mm */ | ||
214 | } | ||
215 | } | ||
210 | 216 | ||
211 | if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) { | 217 | if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && |
212 | priv->x_res = res[0]; /* x resolution in units/mm */ | 218 | SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { |
213 | priv->y_res = res[2]; /* y resolution in units/mm */ | 219 | if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) { |
220 | printk(KERN_ERR "Synaptics claims to have dimensions query," | ||
221 | " but I'm not able to read it.\n"); | ||
222 | } else { | ||
223 | priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1); | ||
224 | priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3); | ||
225 | } | ||
214 | } | 226 | } |
215 | 227 | ||
216 | return 0; | 228 | return 0; |
@@ -520,19 +532,20 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha | |||
520 | return 0; | 532 | return 0; |
521 | 533 | ||
522 | switch (pkt_type) { | 534 | switch (pkt_type) { |
523 | case SYN_NEWABS: | ||
524 | case SYN_NEWABS_RELAXED: | ||
525 | return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; | ||
526 | 535 | ||
527 | case SYN_NEWABS_STRICT: | 536 | case SYN_NEWABS: |
528 | return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; | 537 | case SYN_NEWABS_RELAXED: |
538 | return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; | ||
529 | 539 | ||
530 | case SYN_OLDABS: | 540 | case SYN_NEWABS_STRICT: |
531 | return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; | 541 | return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; |
532 | 542 | ||
533 | default: | 543 | case SYN_OLDABS: |
534 | printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); | 544 | return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; |
535 | return 0; | 545 | |
546 | default: | ||
547 | printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); | ||
548 | return 0; | ||
536 | } | 549 | } |
537 | } | 550 | } |
538 | 551 | ||
@@ -578,8 +591,10 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
578 | int i; | 591 | int i; |
579 | 592 | ||
580 | __set_bit(EV_ABS, dev->evbit); | 593 | __set_bit(EV_ABS, dev->evbit); |
581 | input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); | 594 | input_set_abs_params(dev, ABS_X, |
582 | input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); | 595 | XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); |
596 | input_set_abs_params(dev, ABS_Y, | ||
597 | YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); | ||
583 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | 598 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); |
584 | __set_bit(ABS_TOOL_WIDTH, dev->absbit); | 599 | __set_bit(ABS_TOOL_WIDTH, dev->absbit); |
585 | 600 | ||
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index ae37c5d162a4..7d4d5e12c0df 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #define SYN_QUE_RESOLUTION 0x08 | 19 | #define SYN_QUE_RESOLUTION 0x08 |
20 | #define SYN_QUE_EXT_CAPAB 0x09 | 20 | #define SYN_QUE_EXT_CAPAB 0x09 |
21 | #define SYN_QUE_EXT_CAPAB_0C 0x0c | 21 | #define SYN_QUE_EXT_CAPAB_0C 0x0c |
22 | #define SYN_QUE_EXT_DIMENSIONS 0x0d | ||
22 | 23 | ||
23 | /* synatics modes */ | 24 | /* synatics modes */ |
24 | #define SYN_BIT_ABSOLUTE_MODE (1 << 7) | 25 | #define SYN_BIT_ABSOLUTE_MODE (1 << 7) |
@@ -51,6 +52,7 @@ | |||
51 | #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) | 52 | #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) |
52 | #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) | 53 | #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) |
53 | #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) | 54 | #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) |
55 | #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) | ||
54 | 56 | ||
55 | /* synaptics modes query bits */ | 57 | /* synaptics modes query bits */ |
56 | #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) | 58 | #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) |
@@ -101,8 +103,8 @@ struct synaptics_data { | |||
101 | unsigned long int ext_cap; /* Extended Capabilities */ | 103 | unsigned long int ext_cap; /* Extended Capabilities */ |
102 | unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ | 104 | unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ |
103 | unsigned long int identity; /* Identification */ | 105 | unsigned long int identity; /* Identification */ |
104 | int x_res; /* X resolution in units/mm */ | 106 | unsigned int x_res, y_res; /* X/Y resolution in units/mm */ |
105 | int y_res; /* Y resolution in units/mm */ | 107 | unsigned int x_max, y_max; /* Max dimensions (from FW) */ |
106 | 108 | ||
107 | unsigned char pkt_type; /* packet type - old, new, etc */ | 109 | unsigned char pkt_type; /* packet type - old, new, etc */ |
108 | unsigned char mode; /* current mode byte */ | 110 | unsigned char mode; /* current mode byte */ |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index ead0494721d0..6168469ad1a6 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
@@ -660,8 +660,21 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id * | |||
660 | } | 660 | } |
661 | 661 | ||
662 | static struct pnp_device_id pnp_kbd_devids[] = { | 662 | static struct pnp_device_id pnp_kbd_devids[] = { |
663 | { .id = "PNP0300", .driver_data = 0 }, | ||
664 | { .id = "PNP0301", .driver_data = 0 }, | ||
665 | { .id = "PNP0302", .driver_data = 0 }, | ||
663 | { .id = "PNP0303", .driver_data = 0 }, | 666 | { .id = "PNP0303", .driver_data = 0 }, |
667 | { .id = "PNP0304", .driver_data = 0 }, | ||
668 | { .id = "PNP0305", .driver_data = 0 }, | ||
669 | { .id = "PNP0306", .driver_data = 0 }, | ||
670 | { .id = "PNP0309", .driver_data = 0 }, | ||
671 | { .id = "PNP030a", .driver_data = 0 }, | ||
664 | { .id = "PNP030b", .driver_data = 0 }, | 672 | { .id = "PNP030b", .driver_data = 0 }, |
673 | { .id = "PNP0320", .driver_data = 0 }, | ||
674 | { .id = "PNP0343", .driver_data = 0 }, | ||
675 | { .id = "PNP0344", .driver_data = 0 }, | ||
676 | { .id = "PNP0345", .driver_data = 0 }, | ||
677 | { .id = "CPQA0D7", .driver_data = 0 }, | ||
665 | { .id = "", }, | 678 | { .id = "", }, |
666 | }; | 679 | }; |
667 | 680 | ||
@@ -672,6 +685,7 @@ static struct pnp_driver i8042_pnp_kbd_driver = { | |||
672 | }; | 685 | }; |
673 | 686 | ||
674 | static struct pnp_device_id pnp_aux_devids[] = { | 687 | static struct pnp_device_id pnp_aux_devids[] = { |
688 | { .id = "AUI0200", .driver_data = 0 }, | ||
675 | { .id = "FJC6000", .driver_data = 0 }, | 689 | { .id = "FJC6000", .driver_data = 0 }, |
676 | { .id = "FJC6001", .driver_data = 0 }, | 690 | { .id = "FJC6001", .driver_data = 0 }, |
677 | { .id = "PNP0f03", .driver_data = 0 }, | 691 | { .id = "PNP0f03", .driver_data = 0 }, |
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c index 670c61c5a516..37d0539fefa0 100644 --- a/drivers/input/tablet/acecad.c +++ b/drivers/input/tablet/acecad.c | |||
@@ -66,18 +66,18 @@ static void usb_acecad_irq(struct urb *urb) | |||
66 | int prox, status; | 66 | int prox, status; |
67 | 67 | ||
68 | switch (urb->status) { | 68 | switch (urb->status) { |
69 | case 0: | 69 | case 0: |
70 | /* success */ | 70 | /* success */ |
71 | break; | 71 | break; |
72 | case -ECONNRESET: | 72 | case -ECONNRESET: |
73 | case -ENOENT: | 73 | case -ENOENT: |
74 | case -ESHUTDOWN: | 74 | case -ESHUTDOWN: |
75 | /* this urb is terminated, clean up */ | 75 | /* this urb is terminated, clean up */ |
76 | dbg("%s - urb shutting down with status: %d", __func__, urb->status); | 76 | dbg("%s - urb shutting down with status: %d", __func__, urb->status); |
77 | return; | 77 | return; |
78 | default: | 78 | default: |
79 | dbg("%s - nonzero urb status received: %d", __func__, urb->status); | 79 | dbg("%s - nonzero urb status received: %d", __func__, urb->status); |
80 | goto resubmit; | 80 | goto resubmit; |
81 | } | 81 | } |
82 | 82 | ||
83 | prox = (data[0] & 0x04) >> 2; | 83 | prox = (data[0] & 0x04) >> 2; |
@@ -135,7 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ | |||
135 | struct usb_acecad *acecad; | 135 | struct usb_acecad *acecad; |
136 | struct input_dev *input_dev; | 136 | struct input_dev *input_dev; |
137 | int pipe, maxp; | 137 | int pipe, maxp; |
138 | int err = -ENOMEM; | 138 | int err; |
139 | 139 | ||
140 | if (interface->desc.bNumEndpoints != 1) | 140 | if (interface->desc.bNumEndpoints != 1) |
141 | return -ENODEV; | 141 | return -ENODEV; |
@@ -193,40 +193,34 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ | |||
193 | input_dev->close = usb_acecad_close; | 193 | input_dev->close = usb_acecad_close; |
194 | 194 | ||
195 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 195 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
196 | input_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | ||
197 | BIT_MASK(ABS_PRESSURE); | ||
198 | input_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | | ||
199 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | ||
200 | input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) | | 196 | input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) | |
201 | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) | | 197 | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) | |
202 | BIT_MASK(BTN_STYLUS2); | 198 | BIT_MASK(BTN_STYLUS2); |
203 | 199 | ||
204 | switch (id->driver_info) { | 200 | switch (id->driver_info) { |
205 | case 0: | 201 | case 0: |
206 | input_dev->absmax[ABS_X] = 5000; | 202 | input_set_abs_params(input_dev, ABS_X, 0, 5000, 4, 0); |
207 | input_dev->absmax[ABS_Y] = 3750; | 203 | input_set_abs_params(input_dev, ABS_Y, 0, 3750, 4, 0); |
208 | input_dev->absmax[ABS_PRESSURE] = 512; | 204 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 512, 0, 0); |
209 | if (!strlen(acecad->name)) | 205 | if (!strlen(acecad->name)) |
210 | snprintf(acecad->name, sizeof(acecad->name), | 206 | snprintf(acecad->name, sizeof(acecad->name), |
211 | "USB Acecad Flair Tablet %04x:%04x", | 207 | "USB Acecad Flair Tablet %04x:%04x", |
212 | le16_to_cpu(dev->descriptor.idVendor), | 208 | le16_to_cpu(dev->descriptor.idVendor), |
213 | le16_to_cpu(dev->descriptor.idProduct)); | 209 | le16_to_cpu(dev->descriptor.idProduct)); |
214 | break; | 210 | break; |
215 | case 1: | 211 | |
216 | input_dev->absmax[ABS_X] = 3000; | 212 | case 1: |
217 | input_dev->absmax[ABS_Y] = 2250; | 213 | input_set_abs_params(input_dev, ABS_X, 0, 53000, 4, 0); |
218 | input_dev->absmax[ABS_PRESSURE] = 1024; | 214 | input_set_abs_params(input_dev, ABS_Y, 0, 2250, 4, 0); |
219 | if (!strlen(acecad->name)) | 215 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1024, 0, 0); |
220 | snprintf(acecad->name, sizeof(acecad->name), | 216 | if (!strlen(acecad->name)) |
221 | "USB Acecad 302 Tablet %04x:%04x", | 217 | snprintf(acecad->name, sizeof(acecad->name), |
222 | le16_to_cpu(dev->descriptor.idVendor), | 218 | "USB Acecad 302 Tablet %04x:%04x", |
223 | le16_to_cpu(dev->descriptor.idProduct)); | 219 | le16_to_cpu(dev->descriptor.idVendor), |
224 | break; | 220 | le16_to_cpu(dev->descriptor.idProduct)); |
221 | break; | ||
225 | } | 222 | } |
226 | 223 | ||
227 | input_dev->absfuzz[ABS_X] = 4; | ||
228 | input_dev->absfuzz[ABS_Y] = 4; | ||
229 | |||
230 | usb_fill_int_urb(acecad->irq, dev, pipe, | 224 | usb_fill_int_urb(acecad->irq, dev, pipe, |
231 | acecad->data, maxp > 8 ? 8 : maxp, | 225 | acecad->data, maxp > 8 ? 8 : maxp, |
232 | usb_acecad_irq, acecad, endpoint->bInterval); | 226 | usb_acecad_irq, acecad, endpoint->bInterval); |
@@ -252,13 +246,11 @@ static void usb_acecad_disconnect(struct usb_interface *intf) | |||
252 | struct usb_acecad *acecad = usb_get_intfdata(intf); | 246 | struct usb_acecad *acecad = usb_get_intfdata(intf); |
253 | 247 | ||
254 | usb_set_intfdata(intf, NULL); | 248 | usb_set_intfdata(intf, NULL); |
255 | if (acecad) { | 249 | |
256 | usb_kill_urb(acecad->irq); | 250 | input_unregister_device(acecad->input); |
257 | input_unregister_device(acecad->input); | 251 | usb_free_urb(acecad->irq); |
258 | usb_free_urb(acecad->irq); | 252 | usb_buffer_free(acecad->usbdev, 8, acecad->data, acecad->data_dma); |
259 | usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); | 253 | kfree(acecad); |
260 | kfree(acecad); | ||
261 | } | ||
262 | } | 254 | } |
263 | 255 | ||
264 | static struct usb_device_id usb_acecad_id_table [] = { | 256 | static struct usb_device_id usb_acecad_id_table [] = { |
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 6682b17bf844..b9969f120247 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c | |||
@@ -34,10 +34,6 @@ struct kbtab { | |||
34 | struct input_dev *dev; | 34 | struct input_dev *dev; |
35 | struct usb_device *usbdev; | 35 | struct usb_device *usbdev; |
36 | struct urb *irq; | 36 | struct urb *irq; |
37 | int x, y; | ||
38 | int button; | ||
39 | int pressure; | ||
40 | __u32 serial[2]; | ||
41 | char phys[32]; | 37 | char phys[32]; |
42 | }; | 38 | }; |
43 | 39 | ||
@@ -46,6 +42,7 @@ static void kbtab_irq(struct urb *urb) | |||
46 | struct kbtab *kbtab = urb->context; | 42 | struct kbtab *kbtab = urb->context; |
47 | unsigned char *data = kbtab->data; | 43 | unsigned char *data = kbtab->data; |
48 | struct input_dev *dev = kbtab->dev; | 44 | struct input_dev *dev = kbtab->dev; |
45 | int pressure; | ||
49 | int retval; | 46 | int retval; |
50 | 47 | ||
51 | switch (urb->status) { | 48 | switch (urb->status) { |
@@ -63,31 +60,27 @@ static void kbtab_irq(struct urb *urb) | |||
63 | goto exit; | 60 | goto exit; |
64 | } | 61 | } |
65 | 62 | ||
66 | kbtab->x = get_unaligned_le16(&data[1]); | ||
67 | kbtab->y = get_unaligned_le16(&data[3]); | ||
68 | |||
69 | kbtab->pressure = (data[5]); | ||
70 | 63 | ||
71 | input_report_key(dev, BTN_TOOL_PEN, 1); | 64 | input_report_key(dev, BTN_TOOL_PEN, 1); |
72 | 65 | ||
73 | input_report_abs(dev, ABS_X, kbtab->x); | 66 | input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1])); |
74 | input_report_abs(dev, ABS_Y, kbtab->y); | 67 | input_report_abs(dev, ABS_Y, get_unaligned_le16(&data[3])); |
75 | 68 | ||
76 | /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ | 69 | /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ |
77 | input_report_key(dev, BTN_RIGHT, data[0] & 0x02); | 70 | input_report_key(dev, BTN_RIGHT, data[0] & 0x02); |
78 | 71 | ||
79 | if (-1 == kb_pressure_click) { | 72 | pressure = data[5]; |
80 | input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); | 73 | if (kb_pressure_click == -1) |
81 | } else { | 74 | input_report_abs(dev, ABS_PRESSURE, pressure); |
82 | input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); | 75 | else |
83 | }; | 76 | input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0); |
84 | 77 | ||
85 | input_sync(dev); | 78 | input_sync(dev); |
86 | 79 | ||
87 | exit: | 80 | exit: |
88 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 81 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
89 | if (retval) | 82 | if (retval) |
90 | err ("%s - usb_submit_urb failed with result %d", | 83 | err("%s - usb_submit_urb failed with result %d", |
91 | __func__, retval); | 84 | __func__, retval); |
92 | } | 85 | } |
93 | 86 | ||
@@ -153,13 +146,11 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
153 | input_dev->open = kbtab_open; | 146 | input_dev->open = kbtab_open; |
154 | input_dev->close = kbtab_close; | 147 | input_dev->close = kbtab_close; |
155 | 148 | ||
156 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | | 149 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
157 | BIT_MASK(EV_MSC); | 150 | input_dev->keybit[BIT_WORD(BTN_LEFT)] |= |
158 | input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | | 151 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); |
159 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | 152 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= |
160 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | | 153 | BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH); |
161 | BIT_MASK(BTN_TOUCH); | ||
162 | input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); | ||
163 | input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); | 154 | input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); |
164 | input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); | 155 | input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); |
165 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); | 156 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); |
@@ -182,7 +173,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
182 | return 0; | 173 | return 0; |
183 | 174 | ||
184 | fail3: usb_free_urb(kbtab->irq); | 175 | fail3: usb_free_urb(kbtab->irq); |
185 | fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); | 176 | fail2: usb_buffer_free(dev, 8, kbtab->data, kbtab->data_dma); |
186 | fail1: input_free_device(input_dev); | 177 | fail1: input_free_device(input_dev); |
187 | kfree(kbtab); | 178 | kfree(kbtab); |
188 | return error; | 179 | return error; |
@@ -193,13 +184,11 @@ static void kbtab_disconnect(struct usb_interface *intf) | |||
193 | struct kbtab *kbtab = usb_get_intfdata(intf); | 184 | struct kbtab *kbtab = usb_get_intfdata(intf); |
194 | 185 | ||
195 | usb_set_intfdata(intf, NULL); | 186 | usb_set_intfdata(intf, NULL); |
196 | if (kbtab) { | 187 | |
197 | usb_kill_urb(kbtab->irq); | 188 | input_unregister_device(kbtab->dev); |
198 | input_unregister_device(kbtab->dev); | 189 | usb_free_urb(kbtab->irq); |
199 | usb_free_urb(kbtab->irq); | 190 | usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma); |
200 | usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); | 191 | kfree(kbtab); |
201 | kfree(kbtab); | ||
202 | } | ||
203 | } | 192 | } |
204 | 193 | ||
205 | static struct usb_driver kbtab_driver = { | 194 | static struct usb_driver kbtab_driver = { |
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 8fef1b689c69..284dfaab6b8c 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h | |||
@@ -106,44 +106,18 @@ MODULE_LICENSE(DRIVER_LICENSE); | |||
106 | 106 | ||
107 | struct wacom { | 107 | struct wacom { |
108 | dma_addr_t data_dma; | 108 | dma_addr_t data_dma; |
109 | struct input_dev *dev; | ||
110 | struct usb_device *usbdev; | 109 | struct usb_device *usbdev; |
111 | struct usb_interface *intf; | 110 | struct usb_interface *intf; |
112 | struct urb *irq; | 111 | struct urb *irq; |
113 | struct wacom_wac *wacom_wac; | 112 | struct wacom_wac wacom_wac; |
114 | struct mutex lock; | 113 | struct mutex lock; |
115 | unsigned int open:1; | 114 | bool open; |
116 | char phys[32]; | 115 | char phys[32]; |
117 | }; | 116 | }; |
118 | 117 | ||
119 | struct wacom_combo { | ||
120 | struct wacom *wacom; | ||
121 | struct urb *urb; | ||
122 | }; | ||
123 | |||
124 | extern const struct usb_device_id wacom_ids[]; | 118 | extern const struct usb_device_id wacom_ids[]; |
125 | 119 | ||
126 | extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo); | 120 | void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); |
127 | extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data); | 121 | void wacom_setup_input_capabilities(struct input_dev *input_dev, |
128 | extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); | 122 | struct wacom_wac *wacom_wac); |
129 | extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data); | ||
130 | extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value); | ||
131 | extern void wacom_input_sync(void *wcombo); | ||
132 | extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
133 | extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
134 | extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
135 | extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
136 | extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
137 | extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
138 | extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
139 | extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
140 | extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
141 | extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
142 | extern void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
143 | extern void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
144 | extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
145 | extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
146 | extern __u16 wacom_le16_to_cpu(unsigned char *data); | ||
147 | extern __u16 wacom_be16_to_cpu(unsigned char *data); | ||
148 | |||
149 | #endif | 123 | #endif |
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index f46502589e4e..d90f4e00e51d 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -11,8 +11,8 @@ | |||
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "wacom.h" | ||
15 | #include "wacom_wac.h" | 14 | #include "wacom_wac.h" |
15 | #include "wacom.h" | ||
16 | 16 | ||
17 | /* defines to get HID report descriptor */ | 17 | /* defines to get HID report descriptor */ |
18 | #define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01) | 18 | #define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01) |
@@ -70,15 +70,9 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type, | |||
70 | buf, size, 1000); | 70 | buf, size, 1000); |
71 | } | 71 | } |
72 | 72 | ||
73 | static struct input_dev * get_input_dev(struct wacom_combo *wcombo) | ||
74 | { | ||
75 | return wcombo->wacom->dev; | ||
76 | } | ||
77 | |||
78 | static void wacom_sys_irq(struct urb *urb) | 73 | static void wacom_sys_irq(struct urb *urb) |
79 | { | 74 | { |
80 | struct wacom *wacom = urb->context; | 75 | struct wacom *wacom = urb->context; |
81 | struct wacom_combo wcombo; | ||
82 | int retval; | 76 | int retval; |
83 | 77 | ||
84 | switch (urb->status) { | 78 | switch (urb->status) { |
@@ -96,59 +90,16 @@ static void wacom_sys_irq(struct urb *urb) | |||
96 | goto exit; | 90 | goto exit; |
97 | } | 91 | } |
98 | 92 | ||
99 | wcombo.wacom = wacom; | 93 | wacom_wac_irq(&wacom->wacom_wac, urb->actual_length); |
100 | wcombo.urb = urb; | ||
101 | |||
102 | if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo)) | ||
103 | input_sync(get_input_dev(&wcombo)); | ||
104 | 94 | ||
105 | exit: | 95 | exit: |
106 | usb_mark_last_busy(wacom->usbdev); | 96 | usb_mark_last_busy(wacom->usbdev); |
107 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 97 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
108 | if (retval) | 98 | if (retval) |
109 | err ("%s - usb_submit_urb failed with result %d", | 99 | err ("%s - usb_submit_urb failed with result %d", |
110 | __func__, retval); | 100 | __func__, retval); |
111 | } | 101 | } |
112 | 102 | ||
113 | void wacom_report_key(void *wcombo, unsigned int key_type, int key_data) | ||
114 | { | ||
115 | input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data); | ||
116 | } | ||
117 | |||
118 | void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data) | ||
119 | { | ||
120 | input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data); | ||
121 | } | ||
122 | |||
123 | void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data) | ||
124 | { | ||
125 | input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data); | ||
126 | } | ||
127 | |||
128 | void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value) | ||
129 | { | ||
130 | input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value); | ||
131 | } | ||
132 | |||
133 | __u16 wacom_be16_to_cpu(unsigned char *data) | ||
134 | { | ||
135 | __u16 value; | ||
136 | value = be16_to_cpu(*(__be16 *) data); | ||
137 | return value; | ||
138 | } | ||
139 | |||
140 | __u16 wacom_le16_to_cpu(unsigned char *data) | ||
141 | { | ||
142 | __u16 value; | ||
143 | value = le16_to_cpu(*(__le16 *) data); | ||
144 | return value; | ||
145 | } | ||
146 | |||
147 | void wacom_input_sync(void *wcombo) | ||
148 | { | ||
149 | input_sync(get_input_dev((struct wacom_combo *)wcombo)); | ||
150 | } | ||
151 | |||
152 | static int wacom_open(struct input_dev *dev) | 103 | static int wacom_open(struct input_dev *dev) |
153 | { | 104 | { |
154 | struct wacom *wacom = input_get_drvdata(dev); | 105 | struct wacom *wacom = input_get_drvdata(dev); |
@@ -168,7 +119,7 @@ static int wacom_open(struct input_dev *dev) | |||
168 | return -EIO; | 119 | return -EIO; |
169 | } | 120 | } |
170 | 121 | ||
171 | wacom->open = 1; | 122 | wacom->open = true; |
172 | wacom->intf->needs_remote_wakeup = 1; | 123 | wacom->intf->needs_remote_wakeup = 1; |
173 | 124 | ||
174 | mutex_unlock(&wacom->lock); | 125 | mutex_unlock(&wacom->lock); |
@@ -181,128 +132,11 @@ static void wacom_close(struct input_dev *dev) | |||
181 | 132 | ||
182 | mutex_lock(&wacom->lock); | 133 | mutex_lock(&wacom->lock); |
183 | usb_kill_urb(wacom->irq); | 134 | usb_kill_urb(wacom->irq); |
184 | wacom->open = 0; | 135 | wacom->open = false; |
185 | wacom->intf->needs_remote_wakeup = 0; | 136 | wacom->intf->needs_remote_wakeup = 0; |
186 | mutex_unlock(&wacom->lock); | 137 | mutex_unlock(&wacom->lock); |
187 | } | 138 | } |
188 | 139 | ||
189 | void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
190 | { | ||
191 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_1) | | ||
192 | BIT_MASK(BTN_5); | ||
193 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); | ||
194 | } | ||
195 | |||
196 | void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
197 | { | ||
198 | input_dev->evbit[0] |= BIT_MASK(EV_MSC); | ||
199 | input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); | ||
200 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); | ||
201 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | | ||
202 | BIT_MASK(BTN_4); | ||
203 | } | ||
204 | |||
205 | void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
206 | { | ||
207 | input_dev->evbit[0] |= BIT_MASK(EV_REL); | ||
208 | input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); | ||
209 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) | | ||
210 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | ||
211 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | | ||
212 | BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) | | ||
213 | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2); | ||
214 | input_set_abs_params(input_dev, ABS_DISTANCE, | ||
215 | 0, wacom_wac->features.distance_max, 0, 0); | ||
216 | } | ||
217 | |||
218 | void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
219 | { | ||
220 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); | ||
221 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | | ||
222 | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); | ||
223 | input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); | ||
224 | input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); | ||
225 | } | ||
226 | |||
227 | void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
228 | { | ||
229 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | | ||
230 | BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | BIT_MASK(BTN_7); | ||
231 | input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); | ||
232 | } | ||
233 | |||
234 | void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
235 | { | ||
236 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); | ||
237 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); | ||
238 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6); | ||
239 | input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); | ||
240 | } | ||
241 | |||
242 | void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
243 | { | ||
244 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_7) | BIT_MASK(BTN_8); | ||
245 | } | ||
246 | |||
247 | void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
248 | { | ||
249 | input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); | ||
250 | } | ||
251 | |||
252 | void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
253 | { | ||
254 | input_dev->evbit[0] |= BIT_MASK(EV_MSC) | BIT_MASK(EV_REL); | ||
255 | input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); | ||
256 | input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); | ||
257 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) | | ||
258 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) | | ||
259 | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); | ||
260 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | | ||
261 | BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) | | ||
262 | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) | | ||
263 | BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) | | ||
264 | BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2); | ||
265 | input_set_abs_params(input_dev, ABS_DISTANCE, | ||
266 | 0, wacom_wac->features.distance_max, 0, 0); | ||
267 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); | ||
268 | input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0); | ||
269 | input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0); | ||
270 | input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); | ||
271 | input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); | ||
272 | } | ||
273 | |||
274 | void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
275 | { | ||
276 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | | ||
277 | BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_STYLUS2); | ||
278 | } | ||
279 | |||
280 | void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
281 | { | ||
282 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER); | ||
283 | } | ||
284 | |||
285 | void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
286 | { | ||
287 | struct wacom_features *features = &wacom_wac->features; | ||
288 | |||
289 | if (features->device_type == BTN_TOOL_DOUBLETAP || | ||
290 | features->device_type == BTN_TOOL_TRIPLETAP) { | ||
291 | input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0); | ||
292 | input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0); | ||
293 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
298 | { | ||
299 | if (wacom_wac->features.device_type == BTN_TOOL_TRIPLETAP) { | ||
300 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP); | ||
301 | input_dev->evbit[0] |= BIT_MASK(EV_MSC); | ||
302 | input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, | 140 | static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, |
307 | struct wacom_features *features) | 141 | struct wacom_features *features) |
308 | { | 142 | { |
@@ -362,9 +196,9 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi | |||
362 | features->device_type = BTN_TOOL_TRIPLETAP; | 196 | features->device_type = BTN_TOOL_TRIPLETAP; |
363 | } | 197 | } |
364 | features->x_max = | 198 | features->x_max = |
365 | wacom_le16_to_cpu(&report[i + 3]); | 199 | get_unaligned_le16(&report[i + 3]); |
366 | features->x_phy = | 200 | features->x_phy = |
367 | wacom_le16_to_cpu(&report[i + 6]); | 201 | get_unaligned_le16(&report[i + 6]); |
368 | features->unit = report[i + 9]; | 202 | features->unit = report[i + 9]; |
369 | features->unitExpo = report[i + 11]; | 203 | features->unitExpo = report[i + 11]; |
370 | i += 12; | 204 | i += 12; |
@@ -374,7 +208,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi | |||
374 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | 208 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; |
375 | features->device_type = BTN_TOOL_PEN; | 209 | features->device_type = BTN_TOOL_PEN; |
376 | features->x_max = | 210 | features->x_max = |
377 | wacom_le16_to_cpu(&report[i + 3]); | 211 | get_unaligned_le16(&report[i + 3]); |
378 | i += 4; | 212 | i += 4; |
379 | } | 213 | } |
380 | } else if (usage == WCM_DIGITIZER) { | 214 | } else if (usage == WCM_DIGITIZER) { |
@@ -396,15 +230,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi | |||
396 | features->pktlen = WACOM_PKGLEN_TPC2FG; | 230 | features->pktlen = WACOM_PKGLEN_TPC2FG; |
397 | features->device_type = BTN_TOOL_TRIPLETAP; | 231 | features->device_type = BTN_TOOL_TRIPLETAP; |
398 | features->y_max = | 232 | features->y_max = |
399 | wacom_le16_to_cpu(&report[i + 3]); | 233 | get_unaligned_le16(&report[i + 3]); |
400 | features->y_phy = | 234 | features->y_phy = |
401 | wacom_le16_to_cpu(&report[i + 6]); | 235 | get_unaligned_le16(&report[i + 6]); |
402 | i += 7; | 236 | i += 7; |
403 | } else { | 237 | } else { |
404 | features->y_max = | 238 | features->y_max = |
405 | features->x_max; | 239 | features->x_max; |
406 | features->y_phy = | 240 | features->y_phy = |
407 | wacom_le16_to_cpu(&report[i + 3]); | 241 | get_unaligned_le16(&report[i + 3]); |
408 | i += 4; | 242 | i += 4; |
409 | } | 243 | } |
410 | } else if (pen) { | 244 | } else if (pen) { |
@@ -413,7 +247,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi | |||
413 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | 247 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; |
414 | features->device_type = BTN_TOOL_PEN; | 248 | features->device_type = BTN_TOOL_PEN; |
415 | features->y_max = | 249 | features->y_max = |
416 | wacom_le16_to_cpu(&report[i + 3]); | 250 | get_unaligned_le16(&report[i + 3]); |
417 | i += 4; | 251 | i += 4; |
418 | } | 252 | } |
419 | } | 253 | } |
@@ -432,7 +266,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi | |||
432 | case HID_USAGE_UNDEFINED: | 266 | case HID_USAGE_UNDEFINED: |
433 | if (usage == WCM_DESKTOP && finger) /* capacity */ | 267 | if (usage == WCM_DESKTOP && finger) /* capacity */ |
434 | features->pressure_max = | 268 | features->pressure_max = |
435 | wacom_le16_to_cpu(&report[i + 3]); | 269 | get_unaligned_le16(&report[i + 3]); |
436 | i += 4; | 270 | i += 4; |
437 | break; | 271 | break; |
438 | } | 272 | } |
@@ -528,6 +362,81 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | |||
528 | return error; | 362 | return error; |
529 | } | 363 | } |
530 | 364 | ||
365 | struct wacom_usbdev_data { | ||
366 | struct list_head list; | ||
367 | struct kref kref; | ||
368 | struct usb_device *dev; | ||
369 | struct wacom_shared shared; | ||
370 | }; | ||
371 | |||
372 | static LIST_HEAD(wacom_udev_list); | ||
373 | static DEFINE_MUTEX(wacom_udev_list_lock); | ||
374 | |||
375 | static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev) | ||
376 | { | ||
377 | struct wacom_usbdev_data *data; | ||
378 | |||
379 | list_for_each_entry(data, &wacom_udev_list, list) { | ||
380 | if (data->dev == dev) { | ||
381 | kref_get(&data->kref); | ||
382 | return data; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | return NULL; | ||
387 | } | ||
388 | |||
389 | static int wacom_add_shared_data(struct wacom_wac *wacom, | ||
390 | struct usb_device *dev) | ||
391 | { | ||
392 | struct wacom_usbdev_data *data; | ||
393 | int retval = 0; | ||
394 | |||
395 | mutex_lock(&wacom_udev_list_lock); | ||
396 | |||
397 | data = wacom_get_usbdev_data(dev); | ||
398 | if (!data) { | ||
399 | data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL); | ||
400 | if (!data) { | ||
401 | retval = -ENOMEM; | ||
402 | goto out; | ||
403 | } | ||
404 | |||
405 | kref_init(&data->kref); | ||
406 | data->dev = dev; | ||
407 | list_add_tail(&data->list, &wacom_udev_list); | ||
408 | } | ||
409 | |||
410 | wacom->shared = &data->shared; | ||
411 | |||
412 | out: | ||
413 | mutex_unlock(&wacom_udev_list_lock); | ||
414 | return retval; | ||
415 | } | ||
416 | |||
417 | static void wacom_release_shared_data(struct kref *kref) | ||
418 | { | ||
419 | struct wacom_usbdev_data *data = | ||
420 | container_of(kref, struct wacom_usbdev_data, kref); | ||
421 | |||
422 | mutex_lock(&wacom_udev_list_lock); | ||
423 | list_del(&data->list); | ||
424 | mutex_unlock(&wacom_udev_list_lock); | ||
425 | |||
426 | kfree(data); | ||
427 | } | ||
428 | |||
429 | static void wacom_remove_shared_data(struct wacom_wac *wacom) | ||
430 | { | ||
431 | struct wacom_usbdev_data *data; | ||
432 | |||
433 | if (wacom->shared) { | ||
434 | data = container_of(wacom->shared, struct wacom_usbdev_data, shared); | ||
435 | kref_put(&data->kref, wacom_release_shared_data); | ||
436 | wacom->shared = NULL; | ||
437 | } | ||
438 | } | ||
439 | |||
531 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) | 440 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) |
532 | { | 441 | { |
533 | struct usb_device *dev = interface_to_usbdev(intf); | 442 | struct usb_device *dev = interface_to_usbdev(intf); |
@@ -542,13 +451,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
542 | return -EINVAL; | 451 | return -EINVAL; |
543 | 452 | ||
544 | wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); | 453 | wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); |
545 | wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); | ||
546 | input_dev = input_allocate_device(); | 454 | input_dev = input_allocate_device(); |
547 | if (!wacom || !input_dev || !wacom_wac) { | 455 | if (!wacom || !input_dev) { |
548 | error = -ENOMEM; | 456 | error = -ENOMEM; |
549 | goto fail1; | 457 | goto fail1; |
550 | } | 458 | } |
551 | 459 | ||
460 | wacom_wac = &wacom->wacom_wac; | ||
552 | wacom_wac->features = *((struct wacom_features *)id->driver_info); | 461 | wacom_wac->features = *((struct wacom_features *)id->driver_info); |
553 | features = &wacom_wac->features; | 462 | features = &wacom_wac->features; |
554 | if (features->pktlen > WACOM_PKGLEN_MAX) { | 463 | if (features->pktlen > WACOM_PKGLEN_MAX) { |
@@ -570,20 +479,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
570 | } | 479 | } |
571 | 480 | ||
572 | wacom->usbdev = dev; | 481 | wacom->usbdev = dev; |
573 | wacom->dev = input_dev; | ||
574 | wacom->intf = intf; | 482 | wacom->intf = intf; |
575 | mutex_init(&wacom->lock); | 483 | mutex_init(&wacom->lock); |
576 | usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); | 484 | usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); |
577 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); | 485 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); |
578 | 486 | ||
579 | usb_to_input_id(dev, &input_dev->id); | 487 | wacom_wac->input = input_dev; |
580 | |||
581 | input_dev->dev.parent = &intf->dev; | ||
582 | |||
583 | input_set_drvdata(input_dev, wacom); | ||
584 | |||
585 | input_dev->open = wacom_open; | ||
586 | input_dev->close = wacom_close; | ||
587 | 488 | ||
588 | endpoint = &intf->cur_altsetting->endpoint[0].desc; | 489 | endpoint = &intf->cur_altsetting->endpoint[0].desc; |
589 | 490 | ||
@@ -600,20 +501,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
600 | features->device_type == BTN_TOOL_PEN ? | 501 | features->device_type == BTN_TOOL_PEN ? |
601 | " Pen" : " Finger", | 502 | " Pen" : " Finger", |
602 | sizeof(wacom_wac->name)); | 503 | sizeof(wacom_wac->name)); |
504 | |||
505 | error = wacom_add_shared_data(wacom_wac, dev); | ||
506 | if (error) | ||
507 | goto fail3; | ||
603 | } | 508 | } |
604 | 509 | ||
605 | input_dev->name = wacom_wac->name; | 510 | input_dev->name = wacom_wac->name; |
606 | wacom->wacom_wac = wacom_wac; | 511 | input_dev->name = wacom_wac->name; |
607 | 512 | input_dev->dev.parent = &intf->dev; | |
608 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 513 | input_dev->open = wacom_open; |
609 | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH); | 514 | input_dev->close = wacom_close; |
610 | 515 | usb_to_input_id(dev, &input_dev->id); | |
611 | input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0); | 516 | input_set_drvdata(input_dev, wacom); |
612 | input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0); | ||
613 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0); | ||
614 | input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); | ||
615 | 517 | ||
616 | wacom_init_input_dev(input_dev, wacom_wac); | 518 | wacom_setup_input_capabilities(input_dev, wacom_wac); |
617 | 519 | ||
618 | usb_fill_int_urb(wacom->irq, dev, | 520 | usb_fill_int_urb(wacom->irq, dev, |
619 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), | 521 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), |
@@ -622,9 +524,9 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
622 | wacom->irq->transfer_dma = wacom->data_dma; | 524 | wacom->irq->transfer_dma = wacom->data_dma; |
623 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 525 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
624 | 526 | ||
625 | error = input_register_device(wacom->dev); | 527 | error = input_register_device(input_dev); |
626 | if (error) | 528 | if (error) |
627 | goto fail3; | 529 | goto fail4; |
628 | 530 | ||
629 | /* Note that if query fails it is not a hard failure */ | 531 | /* Note that if query fails it is not a hard failure */ |
630 | wacom_query_tablet_data(intf, features); | 532 | wacom_query_tablet_data(intf, features); |
@@ -632,11 +534,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
632 | usb_set_intfdata(intf, wacom); | 534 | usb_set_intfdata(intf, wacom); |
633 | return 0; | 535 | return 0; |
634 | 536 | ||
537 | fail4: wacom_remove_shared_data(wacom_wac); | ||
635 | fail3: usb_free_urb(wacom->irq); | 538 | fail3: usb_free_urb(wacom->irq); |
636 | fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); | 539 | fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); |
637 | fail1: input_free_device(input_dev); | 540 | fail1: input_free_device(input_dev); |
638 | kfree(wacom); | 541 | kfree(wacom); |
639 | kfree(wacom_wac); | ||
640 | return error; | 542 | return error; |
641 | } | 543 | } |
642 | 544 | ||
@@ -647,11 +549,11 @@ static void wacom_disconnect(struct usb_interface *intf) | |||
647 | usb_set_intfdata(intf, NULL); | 549 | usb_set_intfdata(intf, NULL); |
648 | 550 | ||
649 | usb_kill_urb(wacom->irq); | 551 | usb_kill_urb(wacom->irq); |
650 | input_unregister_device(wacom->dev); | 552 | input_unregister_device(wacom->wacom_wac.input); |
651 | usb_free_urb(wacom->irq); | 553 | usb_free_urb(wacom->irq); |
652 | usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, | 554 | usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, |
653 | wacom->wacom_wac->data, wacom->data_dma); | 555 | wacom->wacom_wac.data, wacom->data_dma); |
654 | kfree(wacom->wacom_wac); | 556 | wacom_remove_shared_data(&wacom->wacom_wac); |
655 | kfree(wacom); | 557 | kfree(wacom); |
656 | } | 558 | } |
657 | 559 | ||
@@ -669,7 +571,7 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message) | |||
669 | static int wacom_resume(struct usb_interface *intf) | 571 | static int wacom_resume(struct usb_interface *intf) |
670 | { | 572 | { |
671 | struct wacom *wacom = usb_get_intfdata(intf); | 573 | struct wacom *wacom = usb_get_intfdata(intf); |
672 | struct wacom_features *features = &wacom->wacom_wac->features; | 574 | struct wacom_features *features = &wacom->wacom_wac.features; |
673 | int rv; | 575 | int rv; |
674 | 576 | ||
675 | mutex_lock(&wacom->lock); | 577 | mutex_lock(&wacom->lock); |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 4a852d815c68..847fd0135bcf 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
@@ -11,52 +11,58 @@ | |||
11 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | */ | 13 | */ |
14 | #include "wacom.h" | 14 | |
15 | #include "wacom_wac.h" | 15 | #include "wacom_wac.h" |
16 | #include "wacom.h" | ||
16 | 17 | ||
17 | static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo) | 18 | static int wacom_penpartner_irq(struct wacom_wac *wacom) |
18 | { | 19 | { |
19 | unsigned char *data = wacom->data; | 20 | unsigned char *data = wacom->data; |
21 | struct input_dev *input = wacom->input; | ||
20 | 22 | ||
21 | switch (data[0]) { | 23 | switch (data[0]) { |
22 | case 1: | 24 | case 1: |
23 | if (data[5] & 0x80) { | 25 | if (data[5] & 0x80) { |
24 | wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | 26 | wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; |
25 | wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID; | 27 | wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID; |
26 | wacom_report_key(wcombo, wacom->tool[0], 1); | 28 | input_report_key(input, wacom->tool[0], 1); |
27 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ | 29 | input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ |
28 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); | 30 | input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); |
29 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); | 31 | input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); |
30 | wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127); | 32 | input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127); |
31 | wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127)); | 33 | input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127)); |
32 | wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40)); | 34 | input_report_key(input, BTN_STYLUS, (data[5] & 0x40)); |
33 | } else { | 35 | } else { |
34 | wacom_report_key(wcombo, wacom->tool[0], 0); | 36 | input_report_key(input, wacom->tool[0], 0); |
35 | wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */ | 37 | input_report_abs(input, ABS_MISC, 0); /* report tool id */ |
36 | wacom_report_abs(wcombo, ABS_PRESSURE, -1); | 38 | input_report_abs(input, ABS_PRESSURE, -1); |
37 | wacom_report_key(wcombo, BTN_TOUCH, 0); | 39 | input_report_key(input, BTN_TOUCH, 0); |
38 | } | 40 | } |
39 | break; | 41 | break; |
40 | case 2: | 42 | |
41 | wacom_report_key(wcombo, BTN_TOOL_PEN, 1); | 43 | case 2: |
42 | wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ | 44 | input_report_key(input, BTN_TOOL_PEN, 1); |
43 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); | 45 | input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ |
44 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); | 46 | input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); |
45 | wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127); | 47 | input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); |
46 | wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); | 48 | input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127); |
47 | wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40)); | 49 | input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); |
48 | break; | 50 | input_report_key(input, BTN_STYLUS, (data[5] & 0x40)); |
49 | default: | 51 | break; |
50 | printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]); | 52 | |
51 | return 0; | 53 | default: |
54 | printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]); | ||
55 | return 0; | ||
52 | } | 56 | } |
57 | |||
53 | return 1; | 58 | return 1; |
54 | } | 59 | } |
55 | 60 | ||
56 | static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) | 61 | static int wacom_pl_irq(struct wacom_wac *wacom) |
57 | { | 62 | { |
58 | struct wacom_features *features = &wacom->features; | 63 | struct wacom_features *features = &wacom->features; |
59 | unsigned char *data = wacom->data; | 64 | unsigned char *data = wacom->data; |
65 | struct input_dev *input = wacom->input; | ||
60 | int prox, pressure; | 66 | int prox, pressure; |
61 | 67 | ||
62 | if (data[0] != WACOM_REPORT_PENABLED) { | 68 | if (data[0] != WACOM_REPORT_PENABLED) { |
@@ -90,8 +96,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) | |||
90 | /* was entered with stylus2 pressed */ | 96 | /* was entered with stylus2 pressed */ |
91 | if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { | 97 | if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { |
92 | /* report out proximity for previous tool */ | 98 | /* report out proximity for previous tool */ |
93 | wacom_report_key(wcombo, wacom->tool[1], 0); | 99 | input_report_key(input, wacom->tool[1], 0); |
94 | wacom_input_sync(wcombo); | 100 | input_sync(input); |
95 | wacom->tool[1] = BTN_TOOL_PEN; | 101 | wacom->tool[1] = BTN_TOOL_PEN; |
96 | return 0; | 102 | return 0; |
97 | } | 103 | } |
@@ -101,32 +107,33 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) | |||
101 | wacom->tool[1] = BTN_TOOL_PEN; | 107 | wacom->tool[1] = BTN_TOOL_PEN; |
102 | wacom->id[0] = STYLUS_DEVICE_ID; | 108 | wacom->id[0] = STYLUS_DEVICE_ID; |
103 | } | 109 | } |
104 | wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */ | 110 | input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */ |
105 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ | 111 | input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ |
106 | wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); | 112 | input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); |
107 | wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); | 113 | input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); |
108 | wacom_report_abs(wcombo, ABS_PRESSURE, pressure); | 114 | input_report_abs(input, ABS_PRESSURE, pressure); |
109 | 115 | ||
110 | wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08); | 116 | input_report_key(input, BTN_TOUCH, data[4] & 0x08); |
111 | wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10); | 117 | input_report_key(input, BTN_STYLUS, data[4] & 0x10); |
112 | /* Only allow the stylus2 button to be reported for the pen tool. */ | 118 | /* Only allow the stylus2 button to be reported for the pen tool. */ |
113 | wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); | 119 | input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); |
114 | } else { | 120 | } else { |
115 | /* report proximity-out of a (valid) tool */ | 121 | /* report proximity-out of a (valid) tool */ |
116 | if (wacom->tool[1] != BTN_TOOL_RUBBER) { | 122 | if (wacom->tool[1] != BTN_TOOL_RUBBER) { |
117 | /* Unknown tool selected default to pen tool */ | 123 | /* Unknown tool selected default to pen tool */ |
118 | wacom->tool[1] = BTN_TOOL_PEN; | 124 | wacom->tool[1] = BTN_TOOL_PEN; |
119 | } | 125 | } |
120 | wacom_report_key(wcombo, wacom->tool[1], prox); | 126 | input_report_key(input, wacom->tool[1], prox); |
121 | } | 127 | } |
122 | 128 | ||
123 | wacom->tool[0] = prox; /* Save proximity state */ | 129 | wacom->tool[0] = prox; /* Save proximity state */ |
124 | return 1; | 130 | return 1; |
125 | } | 131 | } |
126 | 132 | ||
127 | static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) | 133 | static int wacom_ptu_irq(struct wacom_wac *wacom) |
128 | { | 134 | { |
129 | unsigned char *data = wacom->data; | 135 | unsigned char *data = wacom->data; |
136 | struct input_dev *input = wacom->input; | ||
130 | 137 | ||
131 | if (data[0] != WACOM_REPORT_PENABLED) { | 138 | if (data[0] != WACOM_REPORT_PENABLED) { |
132 | printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); | 139 | printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); |
@@ -134,40 +141,41 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) | |||
134 | } | 141 | } |
135 | 142 | ||
136 | if (data[1] & 0x04) { | 143 | if (data[1] & 0x04) { |
137 | wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20); | 144 | input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20); |
138 | wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08); | 145 | input_report_key(input, BTN_TOUCH, data[1] & 0x08); |
139 | wacom->id[0] = ERASER_DEVICE_ID; | 146 | wacom->id[0] = ERASER_DEVICE_ID; |
140 | } else { | 147 | } else { |
141 | wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20); | 148 | input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20); |
142 | wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01); | 149 | input_report_key(input, BTN_TOUCH, data[1] & 0x01); |
143 | wacom->id[0] = STYLUS_DEVICE_ID; | 150 | wacom->id[0] = STYLUS_DEVICE_ID; |
144 | } | 151 | } |
145 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ | 152 | input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ |
146 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); | 153 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); |
147 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); | 154 | input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); |
148 | wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); | 155 | input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); |
149 | wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); | 156 | input_report_key(input, BTN_STYLUS, data[1] & 0x02); |
150 | wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10); | 157 | input_report_key(input, BTN_STYLUS2, data[1] & 0x10); |
151 | return 1; | 158 | return 1; |
152 | } | 159 | } |
153 | 160 | ||
154 | static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | 161 | static int wacom_graphire_irq(struct wacom_wac *wacom) |
155 | { | 162 | { |
156 | struct wacom_features *features = &wacom->features; | 163 | struct wacom_features *features = &wacom->features; |
157 | unsigned char *data = wacom->data; | 164 | unsigned char *data = wacom->data; |
158 | int x, y, rw; | 165 | struct input_dev *input = wacom->input; |
159 | static int penData = 0; | 166 | int prox; |
167 | int rw = 0; | ||
168 | int retval = 0; | ||
160 | 169 | ||
161 | if (data[0] != WACOM_REPORT_PENABLED) { | 170 | if (data[0] != WACOM_REPORT_PENABLED) { |
162 | dbg("wacom_graphire_irq: received unknown report #%d", data[0]); | 171 | dbg("wacom_graphire_irq: received unknown report #%d", data[0]); |
163 | return 0; | 172 | goto exit; |
164 | } | 173 | } |
165 | 174 | ||
166 | if (data[1] & 0x80) { | 175 | prox = data[1] & 0x80; |
167 | /* in prox and not a pad data */ | 176 | if (prox || wacom->id[0]) { |
168 | penData = 1; | 177 | if (prox) { |
169 | 178 | switch ((data[1] >> 5) & 3) { | |
170 | switch ((data[1] >> 5) & 3) { | ||
171 | 179 | ||
172 | case 0: /* Pen */ | 180 | case 0: /* Pen */ |
173 | wacom->tool[0] = BTN_TOOL_PEN; | 181 | wacom->tool[0] = BTN_TOOL_PEN; |
@@ -180,128 +188,89 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
180 | break; | 188 | break; |
181 | 189 | ||
182 | case 2: /* Mouse with wheel */ | 190 | case 2: /* Mouse with wheel */ |
183 | wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04); | 191 | input_report_key(input, BTN_MIDDLE, data[1] & 0x04); |
184 | if (features->type == WACOM_G4 || features->type == WACOM_MO) { | ||
185 | rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03); | ||
186 | wacom_report_rel(wcombo, REL_WHEEL, -rw); | ||
187 | } else | ||
188 | wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]); | ||
189 | /* fall through */ | 192 | /* fall through */ |
190 | 193 | ||
191 | case 3: /* Mouse without wheel */ | 194 | case 3: /* Mouse without wheel */ |
192 | wacom->tool[0] = BTN_TOOL_MOUSE; | 195 | wacom->tool[0] = BTN_TOOL_MOUSE; |
193 | wacom->id[0] = CURSOR_DEVICE_ID; | 196 | wacom->id[0] = CURSOR_DEVICE_ID; |
194 | wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); | ||
195 | wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); | ||
196 | if (features->type == WACOM_G4 || features->type == WACOM_MO) | ||
197 | wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); | ||
198 | else | ||
199 | wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); | ||
200 | break; | 197 | break; |
198 | } | ||
201 | } | 199 | } |
202 | x = wacom_le16_to_cpu(&data[2]); | 200 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); |
203 | y = wacom_le16_to_cpu(&data[4]); | 201 | input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); |
204 | wacom_report_abs(wcombo, ABS_X, x); | ||
205 | wacom_report_abs(wcombo, ABS_Y, y); | ||
206 | if (wacom->tool[0] != BTN_TOOL_MOUSE) { | 202 | if (wacom->tool[0] != BTN_TOOL_MOUSE) { |
207 | wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8)); | 203 | input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8)); |
208 | wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01); | 204 | input_report_key(input, BTN_TOUCH, data[1] & 0x01); |
209 | wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); | 205 | input_report_key(input, BTN_STYLUS, data[1] & 0x02); |
210 | wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04); | 206 | input_report_key(input, BTN_STYLUS2, data[1] & 0x04); |
211 | } | ||
212 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ | ||
213 | wacom_report_key(wcombo, wacom->tool[0], 1); | ||
214 | } else if (wacom->id[0]) { | ||
215 | wacom_report_abs(wcombo, ABS_X, 0); | ||
216 | wacom_report_abs(wcombo, ABS_Y, 0); | ||
217 | if (wacom->tool[0] == BTN_TOOL_MOUSE) { | ||
218 | wacom_report_key(wcombo, BTN_LEFT, 0); | ||
219 | wacom_report_key(wcombo, BTN_RIGHT, 0); | ||
220 | wacom_report_abs(wcombo, ABS_DISTANCE, 0); | ||
221 | } else { | 207 | } else { |
222 | wacom_report_abs(wcombo, ABS_PRESSURE, 0); | 208 | input_report_key(input, BTN_LEFT, data[1] & 0x01); |
223 | wacom_report_key(wcombo, BTN_TOUCH, 0); | 209 | input_report_key(input, BTN_RIGHT, data[1] & 0x02); |
224 | wacom_report_key(wcombo, BTN_STYLUS, 0); | 210 | if (features->type == WACOM_G4 || |
225 | wacom_report_key(wcombo, BTN_STYLUS2, 0); | 211 | features->type == WACOM_MO) { |
212 | input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f); | ||
213 | rw = (signed)(data[7] & 0x04) - (data[7] & 0x03); | ||
214 | } else { | ||
215 | input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f); | ||
216 | rw = -(signed)data[6]; | ||
217 | } | ||
218 | input_report_rel(input, REL_WHEEL, rw); | ||
226 | } | 219 | } |
227 | wacom->id[0] = 0; | 220 | |
228 | wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ | 221 | if (!prox) |
229 | wacom_report_key(wcombo, wacom->tool[0], 0); | 222 | wacom->id[0] = 0; |
223 | input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ | ||
224 | input_report_key(input, wacom->tool[0], prox); | ||
225 | input_sync(input); /* sync last event */ | ||
230 | } | 226 | } |
231 | 227 | ||
232 | /* send pad data */ | 228 | /* send pad data */ |
233 | switch (features->type) { | 229 | switch (features->type) { |
234 | case WACOM_G4: | 230 | case WACOM_G4: |
235 | if (data[7] & 0xf8) { | 231 | prox = data[7] & 0xf8; |
236 | if (penData) { | 232 | if (prox || wacom->id[1]) { |
237 | wacom_input_sync(wcombo); /* sync last event */ | ||
238 | if (!wacom->id[0]) | ||
239 | penData = 0; | ||
240 | } | ||
241 | wacom->id[1] = PAD_DEVICE_ID; | 233 | wacom->id[1] = PAD_DEVICE_ID; |
242 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); | 234 | input_report_key(input, BTN_0, (data[7] & 0x40)); |
243 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); | 235 | input_report_key(input, BTN_4, (data[7] & 0x80)); |
244 | rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); | 236 | rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); |
245 | wacom_report_rel(wcombo, REL_WHEEL, rw); | 237 | input_report_rel(input, REL_WHEEL, rw); |
246 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); | 238 | input_report_key(input, BTN_TOOL_FINGER, 0xf0); |
247 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); | 239 | if (!prox) |
248 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | 240 | wacom->id[1] = 0; |
249 | } else if (wacom->id[1]) { | 241 | input_report_abs(input, ABS_MISC, wacom->id[1]); |
250 | if (penData) { | 242 | input_event(input, EV_MSC, MSC_SERIAL, 0xf0); |
251 | wacom_input_sync(wcombo); /* sync last event */ | 243 | retval = 1; |
252 | if (!wacom->id[0]) | ||
253 | penData = 0; | ||
254 | } | ||
255 | wacom->id[1] = 0; | ||
256 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); | ||
257 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); | ||
258 | wacom_report_rel(wcombo, REL_WHEEL, 0); | ||
259 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0); | ||
260 | wacom_report_abs(wcombo, ABS_MISC, 0); | ||
261 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | ||
262 | } | 244 | } |
263 | break; | 245 | break; |
264 | case WACOM_MO: | 246 | |
265 | if ((data[7] & 0xf8) || (data[8] & 0xff)) { | 247 | case WACOM_MO: |
266 | if (penData) { | 248 | prox = (data[7] & 0xf8) || data[8]; |
267 | wacom_input_sync(wcombo); /* sync last event */ | 249 | if (prox || wacom->id[1]) { |
268 | if (!wacom->id[0]) | ||
269 | penData = 0; | ||
270 | } | ||
271 | wacom->id[1] = PAD_DEVICE_ID; | 250 | wacom->id[1] = PAD_DEVICE_ID; |
272 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); | 251 | input_report_key(input, BTN_0, (data[7] & 0x08)); |
273 | wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); | 252 | input_report_key(input, BTN_1, (data[7] & 0x20)); |
274 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); | 253 | input_report_key(input, BTN_4, (data[7] & 0x10)); |
275 | wacom_report_key(wcombo, BTN_5, (data[7] & 0x40)); | 254 | input_report_key(input, BTN_5, (data[7] & 0x40)); |
276 | wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f)); | 255 | input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f)); |
277 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); | 256 | input_report_key(input, BTN_TOOL_FINGER, 0xf0); |
278 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); | 257 | if (!prox) |
279 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | 258 | wacom->id[1] = 0; |
280 | } else if (wacom->id[1]) { | 259 | input_report_abs(input, ABS_MISC, wacom->id[1]); |
281 | if (penData) { | 260 | input_event(input, EV_MSC, MSC_SERIAL, 0xf0); |
282 | wacom_input_sync(wcombo); /* sync last event */ | ||
283 | if (!wacom->id[0]) | ||
284 | penData = 0; | ||
285 | } | ||
286 | wacom->id[1] = 0; | ||
287 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); | ||
288 | wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); | ||
289 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); | ||
290 | wacom_report_key(wcombo, BTN_5, (data[7] & 0x40)); | ||
291 | wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f)); | ||
292 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0); | ||
293 | wacom_report_abs(wcombo, ABS_MISC, 0); | ||
294 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | ||
295 | } | 261 | } |
262 | retval = 1; | ||
296 | break; | 263 | break; |
297 | } | 264 | } |
298 | return 1; | 265 | exit: |
266 | return retval; | ||
299 | } | 267 | } |
300 | 268 | ||
301 | static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) | 269 | static int wacom_intuos_inout(struct wacom_wac *wacom) |
302 | { | 270 | { |
303 | struct wacom_features *features = &wacom->features; | 271 | struct wacom_features *features = &wacom->features; |
304 | unsigned char *data = wacom->data; | 272 | unsigned char *data = wacom->data; |
273 | struct input_dev *input = wacom->input; | ||
305 | int idx = 0; | 274 | int idx = 0; |
306 | 275 | ||
307 | /* tool number */ | 276 | /* tool number */ |
@@ -316,64 +285,73 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) | |||
316 | (data[6] << 4) + (data[7] >> 4); | 285 | (data[6] << 4) + (data[7] >> 4); |
317 | 286 | ||
318 | wacom->id[idx] = (data[2] << 4) | (data[3] >> 4); | 287 | wacom->id[idx] = (data[2] << 4) | (data[3] >> 4); |
288 | |||
319 | switch (wacom->id[idx]) { | 289 | switch (wacom->id[idx]) { |
320 | case 0x812: /* Inking pen */ | 290 | case 0x812: /* Inking pen */ |
321 | case 0x801: /* Intuos3 Inking pen */ | 291 | case 0x801: /* Intuos3 Inking pen */ |
322 | case 0x20802: /* Intuos4 Classic Pen */ | 292 | case 0x20802: /* Intuos4 Classic Pen */ |
323 | case 0x012: | 293 | case 0x012: |
324 | wacom->tool[idx] = BTN_TOOL_PENCIL; | 294 | wacom->tool[idx] = BTN_TOOL_PENCIL; |
325 | break; | 295 | break; |
326 | case 0x822: /* Pen */ | 296 | |
327 | case 0x842: | 297 | case 0x822: /* Pen */ |
328 | case 0x852: | 298 | case 0x842: |
329 | case 0x823: /* Intuos3 Grip Pen */ | 299 | case 0x852: |
330 | case 0x813: /* Intuos3 Classic Pen */ | 300 | case 0x823: /* Intuos3 Grip Pen */ |
331 | case 0x885: /* Intuos3 Marker Pen */ | 301 | case 0x813: /* Intuos3 Classic Pen */ |
332 | case 0x802: /* Intuos4 Grip Pen Eraser */ | 302 | case 0x885: /* Intuos3 Marker Pen */ |
333 | case 0x804: /* Intuos4 Marker Pen */ | 303 | case 0x802: /* Intuos4 Grip Pen Eraser */ |
334 | case 0x40802: /* Intuos4 Classic Pen */ | 304 | case 0x804: /* Intuos4 Marker Pen */ |
335 | case 0x022: | 305 | case 0x40802: /* Intuos4 Classic Pen */ |
336 | wacom->tool[idx] = BTN_TOOL_PEN; | 306 | case 0x022: |
337 | break; | 307 | wacom->tool[idx] = BTN_TOOL_PEN; |
338 | case 0x832: /* Stroke pen */ | 308 | break; |
339 | case 0x032: | 309 | |
340 | wacom->tool[idx] = BTN_TOOL_BRUSH; | 310 | case 0x832: /* Stroke pen */ |
341 | break; | 311 | case 0x032: |
342 | case 0x007: /* Mouse 4D and 2D */ | 312 | wacom->tool[idx] = BTN_TOOL_BRUSH; |
343 | case 0x09c: | 313 | break; |
344 | case 0x094: | 314 | |
345 | case 0x017: /* Intuos3 2D Mouse */ | 315 | case 0x007: /* Mouse 4D and 2D */ |
346 | case 0x806: /* Intuos4 Mouse */ | 316 | case 0x09c: |
347 | wacom->tool[idx] = BTN_TOOL_MOUSE; | 317 | case 0x094: |
348 | break; | 318 | case 0x017: /* Intuos3 2D Mouse */ |
349 | case 0x096: /* Lens cursor */ | 319 | case 0x806: /* Intuos4 Mouse */ |
350 | case 0x097: /* Intuos3 Lens cursor */ | 320 | wacom->tool[idx] = BTN_TOOL_MOUSE; |
351 | case 0x006: /* Intuos4 Lens cursor */ | 321 | break; |
352 | wacom->tool[idx] = BTN_TOOL_LENS; | 322 | |
353 | break; | 323 | case 0x096: /* Lens cursor */ |
354 | case 0x82a: /* Eraser */ | 324 | case 0x097: /* Intuos3 Lens cursor */ |
355 | case 0x85a: | 325 | case 0x006: /* Intuos4 Lens cursor */ |
356 | case 0x91a: | 326 | wacom->tool[idx] = BTN_TOOL_LENS; |
357 | case 0xd1a: | 327 | break; |
358 | case 0x0fa: | 328 | |
359 | case 0x82b: /* Intuos3 Grip Pen Eraser */ | 329 | case 0x82a: /* Eraser */ |
360 | case 0x81b: /* Intuos3 Classic Pen Eraser */ | 330 | case 0x85a: |
361 | case 0x91b: /* Intuos3 Airbrush Eraser */ | 331 | case 0x91a: |
362 | case 0x80c: /* Intuos4 Marker Pen Eraser */ | 332 | case 0xd1a: |
363 | case 0x80a: /* Intuos4 Grip Pen Eraser */ | 333 | case 0x0fa: |
364 | case 0x4080a: /* Intuos4 Classic Pen Eraser */ | 334 | case 0x82b: /* Intuos3 Grip Pen Eraser */ |
365 | case 0x90a: /* Intuos4 Airbrush Eraser */ | 335 | case 0x81b: /* Intuos3 Classic Pen Eraser */ |
366 | wacom->tool[idx] = BTN_TOOL_RUBBER; | 336 | case 0x91b: /* Intuos3 Airbrush Eraser */ |
367 | break; | 337 | case 0x80c: /* Intuos4 Marker Pen Eraser */ |
368 | case 0xd12: | 338 | case 0x80a: /* Intuos4 Grip Pen Eraser */ |
369 | case 0x912: | 339 | case 0x4080a: /* Intuos4 Classic Pen Eraser */ |
370 | case 0x112: | 340 | case 0x90a: /* Intuos4 Airbrush Eraser */ |
371 | case 0x913: /* Intuos3 Airbrush */ | 341 | wacom->tool[idx] = BTN_TOOL_RUBBER; |
372 | case 0x902: /* Intuos4 Airbrush */ | 342 | break; |
373 | wacom->tool[idx] = BTN_TOOL_AIRBRUSH; | 343 | |
374 | break; | 344 | case 0xd12: |
375 | default: /* Unknown tool */ | 345 | case 0x912: |
376 | wacom->tool[idx] = BTN_TOOL_PEN; | 346 | case 0x112: |
347 | case 0x913: /* Intuos3 Airbrush */ | ||
348 | case 0x902: /* Intuos4 Airbrush */ | ||
349 | wacom->tool[idx] = BTN_TOOL_AIRBRUSH; | ||
350 | break; | ||
351 | |||
352 | default: /* Unknown tool */ | ||
353 | wacom->tool[idx] = BTN_TOOL_PEN; | ||
354 | break; | ||
377 | } | 355 | } |
378 | return 1; | 356 | return 1; |
379 | } | 357 | } |
@@ -384,41 +362,42 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) | |||
384 | * Reset all states otherwise we lose the initial states | 362 | * Reset all states otherwise we lose the initial states |
385 | * when in-prox next time | 363 | * when in-prox next time |
386 | */ | 364 | */ |
387 | wacom_report_abs(wcombo, ABS_X, 0); | 365 | input_report_abs(input, ABS_X, 0); |
388 | wacom_report_abs(wcombo, ABS_Y, 0); | 366 | input_report_abs(input, ABS_Y, 0); |
389 | wacom_report_abs(wcombo, ABS_DISTANCE, 0); | 367 | input_report_abs(input, ABS_DISTANCE, 0); |
390 | wacom_report_abs(wcombo, ABS_TILT_X, 0); | 368 | input_report_abs(input, ABS_TILT_X, 0); |
391 | wacom_report_abs(wcombo, ABS_TILT_Y, 0); | 369 | input_report_abs(input, ABS_TILT_Y, 0); |
392 | if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { | 370 | if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { |
393 | wacom_report_key(wcombo, BTN_LEFT, 0); | 371 | input_report_key(input, BTN_LEFT, 0); |
394 | wacom_report_key(wcombo, BTN_MIDDLE, 0); | 372 | input_report_key(input, BTN_MIDDLE, 0); |
395 | wacom_report_key(wcombo, BTN_RIGHT, 0); | 373 | input_report_key(input, BTN_RIGHT, 0); |
396 | wacom_report_key(wcombo, BTN_SIDE, 0); | 374 | input_report_key(input, BTN_SIDE, 0); |
397 | wacom_report_key(wcombo, BTN_EXTRA, 0); | 375 | input_report_key(input, BTN_EXTRA, 0); |
398 | wacom_report_abs(wcombo, ABS_THROTTLE, 0); | 376 | input_report_abs(input, ABS_THROTTLE, 0); |
399 | wacom_report_abs(wcombo, ABS_RZ, 0); | 377 | input_report_abs(input, ABS_RZ, 0); |
400 | } else { | 378 | } else { |
401 | wacom_report_abs(wcombo, ABS_PRESSURE, 0); | 379 | input_report_abs(input, ABS_PRESSURE, 0); |
402 | wacom_report_key(wcombo, BTN_STYLUS, 0); | 380 | input_report_key(input, BTN_STYLUS, 0); |
403 | wacom_report_key(wcombo, BTN_STYLUS2, 0); | 381 | input_report_key(input, BTN_STYLUS2, 0); |
404 | wacom_report_key(wcombo, BTN_TOUCH, 0); | 382 | input_report_key(input, BTN_TOUCH, 0); |
405 | wacom_report_abs(wcombo, ABS_WHEEL, 0); | 383 | input_report_abs(input, ABS_WHEEL, 0); |
406 | if (features->type >= INTUOS3S) | 384 | if (features->type >= INTUOS3S) |
407 | wacom_report_abs(wcombo, ABS_Z, 0); | 385 | input_report_abs(input, ABS_Z, 0); |
408 | } | 386 | } |
409 | wacom_report_key(wcombo, wacom->tool[idx], 0); | 387 | input_report_key(input, wacom->tool[idx], 0); |
410 | wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ | 388 | input_report_abs(input, ABS_MISC, 0); /* reset tool id */ |
411 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); | 389 | input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); |
412 | wacom->id[idx] = 0; | 390 | wacom->id[idx] = 0; |
413 | return 2; | 391 | return 2; |
414 | } | 392 | } |
415 | return 0; | 393 | return 0; |
416 | } | 394 | } |
417 | 395 | ||
418 | static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo) | 396 | static void wacom_intuos_general(struct wacom_wac *wacom) |
419 | { | 397 | { |
420 | struct wacom_features *features = &wacom->features; | 398 | struct wacom_features *features = &wacom->features; |
421 | unsigned char *data = wacom->data; | 399 | unsigned char *data = wacom->data; |
400 | struct input_dev *input = wacom->input; | ||
422 | unsigned int t; | 401 | unsigned int t; |
423 | 402 | ||
424 | /* general pen packet */ | 403 | /* general pen packet */ |
@@ -426,30 +405,30 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo) | |||
426 | t = (data[6] << 2) | ((data[7] >> 6) & 3); | 405 | t = (data[6] << 2) | ((data[7] >> 6) & 3); |
427 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) | 406 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) |
428 | t = (t << 1) | (data[1] & 1); | 407 | t = (t << 1) | (data[1] & 1); |
429 | wacom_report_abs(wcombo, ABS_PRESSURE, t); | 408 | input_report_abs(input, ABS_PRESSURE, t); |
430 | wacom_report_abs(wcombo, ABS_TILT_X, | 409 | input_report_abs(input, ABS_TILT_X, |
431 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); | 410 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); |
432 | wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f); | 411 | input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); |
433 | wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2); | 412 | input_report_key(input, BTN_STYLUS, data[1] & 2); |
434 | wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4); | 413 | input_report_key(input, BTN_STYLUS2, data[1] & 4); |
435 | wacom_report_key(wcombo, BTN_TOUCH, t > 10); | 414 | input_report_key(input, BTN_TOUCH, t > 10); |
436 | } | 415 | } |
437 | 416 | ||
438 | /* airbrush second packet */ | 417 | /* airbrush second packet */ |
439 | if ((data[1] & 0xbc) == 0xb4) { | 418 | if ((data[1] & 0xbc) == 0xb4) { |
440 | wacom_report_abs(wcombo, ABS_WHEEL, | 419 | input_report_abs(input, ABS_WHEEL, |
441 | (data[6] << 2) | ((data[7] >> 6) & 3)); | 420 | (data[6] << 2) | ((data[7] >> 6) & 3)); |
442 | wacom_report_abs(wcombo, ABS_TILT_X, | 421 | input_report_abs(input, ABS_TILT_X, |
443 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); | 422 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); |
444 | wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f); | 423 | input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); |
445 | } | 424 | } |
446 | return; | ||
447 | } | 425 | } |
448 | 426 | ||
449 | static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | 427 | static int wacom_intuos_irq(struct wacom_wac *wacom) |
450 | { | 428 | { |
451 | struct wacom_features *features = &wacom->features; | 429 | struct wacom_features *features = &wacom->features; |
452 | unsigned char *data = wacom->data; | 430 | unsigned char *data = wacom->data; |
431 | struct input_dev *input = wacom->input; | ||
453 | unsigned int t; | 432 | unsigned int t; |
454 | int idx = 0, result; | 433 | int idx = 0, result; |
455 | 434 | ||
@@ -470,61 +449,61 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
470 | wacom->tool[1] = BTN_TOOL_FINGER; | 449 | wacom->tool[1] = BTN_TOOL_FINGER; |
471 | 450 | ||
472 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) { | 451 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) { |
473 | wacom_report_key(wcombo, BTN_0, (data[2] & 0x01)); | 452 | input_report_key(input, BTN_0, (data[2] & 0x01)); |
474 | wacom_report_key(wcombo, BTN_1, (data[3] & 0x01)); | 453 | input_report_key(input, BTN_1, (data[3] & 0x01)); |
475 | wacom_report_key(wcombo, BTN_2, (data[3] & 0x02)); | 454 | input_report_key(input, BTN_2, (data[3] & 0x02)); |
476 | wacom_report_key(wcombo, BTN_3, (data[3] & 0x04)); | 455 | input_report_key(input, BTN_3, (data[3] & 0x04)); |
477 | wacom_report_key(wcombo, BTN_4, (data[3] & 0x08)); | 456 | input_report_key(input, BTN_4, (data[3] & 0x08)); |
478 | wacom_report_key(wcombo, BTN_5, (data[3] & 0x10)); | 457 | input_report_key(input, BTN_5, (data[3] & 0x10)); |
479 | wacom_report_key(wcombo, BTN_6, (data[3] & 0x20)); | 458 | input_report_key(input, BTN_6, (data[3] & 0x20)); |
480 | if (data[1] & 0x80) { | 459 | if (data[1] & 0x80) { |
481 | wacom_report_abs(wcombo, ABS_WHEEL, (data[1] & 0x7f)); | 460 | input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f)); |
482 | } else { | 461 | } else { |
483 | /* Out of proximity, clear wheel value. */ | 462 | /* Out of proximity, clear wheel value. */ |
484 | wacom_report_abs(wcombo, ABS_WHEEL, 0); | 463 | input_report_abs(input, ABS_WHEEL, 0); |
485 | } | 464 | } |
486 | if (features->type != INTUOS4S) { | 465 | if (features->type != INTUOS4S) { |
487 | wacom_report_key(wcombo, BTN_7, (data[3] & 0x40)); | 466 | input_report_key(input, BTN_7, (data[3] & 0x40)); |
488 | wacom_report_key(wcombo, BTN_8, (data[3] & 0x80)); | 467 | input_report_key(input, BTN_8, (data[3] & 0x80)); |
489 | } | 468 | } |
490 | if (data[1] | (data[2] & 0x01) | data[3]) { | 469 | if (data[1] | (data[2] & 0x01) | data[3]) { |
491 | wacom_report_key(wcombo, wacom->tool[1], 1); | 470 | input_report_key(input, wacom->tool[1], 1); |
492 | wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); | 471 | input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); |
493 | } else { | 472 | } else { |
494 | wacom_report_key(wcombo, wacom->tool[1], 0); | 473 | input_report_key(input, wacom->tool[1], 0); |
495 | wacom_report_abs(wcombo, ABS_MISC, 0); | 474 | input_report_abs(input, ABS_MISC, 0); |
496 | } | 475 | } |
497 | } else { | 476 | } else { |
498 | wacom_report_key(wcombo, BTN_0, (data[5] & 0x01)); | 477 | input_report_key(input, BTN_0, (data[5] & 0x01)); |
499 | wacom_report_key(wcombo, BTN_1, (data[5] & 0x02)); | 478 | input_report_key(input, BTN_1, (data[5] & 0x02)); |
500 | wacom_report_key(wcombo, BTN_2, (data[5] & 0x04)); | 479 | input_report_key(input, BTN_2, (data[5] & 0x04)); |
501 | wacom_report_key(wcombo, BTN_3, (data[5] & 0x08)); | 480 | input_report_key(input, BTN_3, (data[5] & 0x08)); |
502 | wacom_report_key(wcombo, BTN_4, (data[6] & 0x01)); | 481 | input_report_key(input, BTN_4, (data[6] & 0x01)); |
503 | wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); | 482 | input_report_key(input, BTN_5, (data[6] & 0x02)); |
504 | wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); | 483 | input_report_key(input, BTN_6, (data[6] & 0x04)); |
505 | wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); | 484 | input_report_key(input, BTN_7, (data[6] & 0x08)); |
506 | wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); | 485 | input_report_key(input, BTN_8, (data[5] & 0x10)); |
507 | wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); | 486 | input_report_key(input, BTN_9, (data[6] & 0x10)); |
508 | wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); | 487 | input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); |
509 | wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); | 488 | input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); |
510 | 489 | ||
511 | if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | | 490 | if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | |
512 | data[2] | (data[3] & 0x1f) | data[4]) { | 491 | data[2] | (data[3] & 0x1f) | data[4]) { |
513 | wacom_report_key(wcombo, wacom->tool[1], 1); | 492 | input_report_key(input, wacom->tool[1], 1); |
514 | wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); | 493 | input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); |
515 | } else { | 494 | } else { |
516 | wacom_report_key(wcombo, wacom->tool[1], 0); | 495 | input_report_key(input, wacom->tool[1], 0); |
517 | wacom_report_abs(wcombo, ABS_MISC, 0); | 496 | input_report_abs(input, ABS_MISC, 0); |
518 | } | 497 | } |
519 | } | 498 | } |
520 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff); | 499 | input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff); |
521 | return 1; | 500 | return 1; |
522 | } | 501 | } |
523 | 502 | ||
524 | /* process in/out prox events */ | 503 | /* process in/out prox events */ |
525 | result = wacom_intuos_inout(wacom, wcombo); | 504 | result = wacom_intuos_inout(wacom); |
526 | if (result) | 505 | if (result) |
527 | return result-1; | 506 | return result - 1; |
528 | 507 | ||
529 | /* don't proceed if we don't know the ID */ | 508 | /* don't proceed if we don't know the ID */ |
530 | if (!wacom->id[idx]) | 509 | if (!wacom->id[idx]) |
@@ -545,17 +524,17 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
545 | return 0; | 524 | return 0; |
546 | 525 | ||
547 | if (features->type >= INTUOS3S) { | 526 | if (features->type >= INTUOS3S) { |
548 | wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); | 527 | input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); |
549 | wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); | 528 | input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); |
550 | wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); | 529 | input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); |
551 | } else { | 530 | } else { |
552 | wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2])); | 531 | input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2])); |
553 | wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4])); | 532 | input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4])); |
554 | wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f)); | 533 | input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f)); |
555 | } | 534 | } |
556 | 535 | ||
557 | /* process general packets */ | 536 | /* process general packets */ |
558 | wacom_intuos_general(wacom, wcombo); | 537 | wacom_intuos_general(wacom); |
559 | 538 | ||
560 | /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */ | 539 | /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */ |
561 | if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) { | 540 | if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) { |
@@ -567,174 +546,191 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
567 | t = (data[6] << 3) | ((data[7] >> 5) & 7); | 546 | t = (data[6] << 3) | ((data[7] >> 5) & 7); |
568 | t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : | 547 | t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : |
569 | ((t-1) / 2 + 450)) : (450 - t / 2) ; | 548 | ((t-1) / 2 + 450)) : (450 - t / 2) ; |
570 | wacom_report_abs(wcombo, ABS_Z, t); | 549 | input_report_abs(input, ABS_Z, t); |
571 | } else { | 550 | } else { |
572 | /* 4D mouse rotation packet */ | 551 | /* 4D mouse rotation packet */ |
573 | t = (data[6] << 3) | ((data[7] >> 5) & 7); | 552 | t = (data[6] << 3) | ((data[7] >> 5) & 7); |
574 | wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ? | 553 | input_report_abs(input, ABS_RZ, (data[7] & 0x20) ? |
575 | ((t - 1) / 2) : -t / 2); | 554 | ((t - 1) / 2) : -t / 2); |
576 | } | 555 | } |
577 | 556 | ||
578 | } else if (!(data[1] & 0x10) && features->type < INTUOS3S) { | 557 | } else if (!(data[1] & 0x10) && features->type < INTUOS3S) { |
579 | /* 4D mouse packet */ | 558 | /* 4D mouse packet */ |
580 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); | 559 | input_report_key(input, BTN_LEFT, data[8] & 0x01); |
581 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); | 560 | input_report_key(input, BTN_MIDDLE, data[8] & 0x02); |
582 | wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04); | 561 | input_report_key(input, BTN_RIGHT, data[8] & 0x04); |
583 | 562 | ||
584 | wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x20); | 563 | input_report_key(input, BTN_SIDE, data[8] & 0x20); |
585 | wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x10); | 564 | input_report_key(input, BTN_EXTRA, data[8] & 0x10); |
586 | t = (data[6] << 2) | ((data[7] >> 6) & 3); | 565 | t = (data[6] << 2) | ((data[7] >> 6) & 3); |
587 | wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); | 566 | input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); |
588 | 567 | ||
589 | } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { | 568 | } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { |
590 | /* I4 mouse */ | 569 | /* I4 mouse */ |
591 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) { | 570 | if (features->type >= INTUOS4S && features->type <= INTUOS4L) { |
592 | wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01); | 571 | input_report_key(input, BTN_LEFT, data[6] & 0x01); |
593 | wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02); | 572 | input_report_key(input, BTN_MIDDLE, data[6] & 0x02); |
594 | wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04); | 573 | input_report_key(input, BTN_RIGHT, data[6] & 0x04); |
595 | wacom_report_rel(wcombo, REL_WHEEL, ((data[7] & 0x80) >> 7) | 574 | input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7) |
596 | - ((data[7] & 0x40) >> 6)); | 575 | - ((data[7] & 0x40) >> 6)); |
597 | wacom_report_key(wcombo, BTN_SIDE, data[6] & 0x08); | 576 | input_report_key(input, BTN_SIDE, data[6] & 0x08); |
598 | wacom_report_key(wcombo, BTN_EXTRA, data[6] & 0x10); | 577 | input_report_key(input, BTN_EXTRA, data[6] & 0x10); |
599 | 578 | ||
600 | wacom_report_abs(wcombo, ABS_TILT_X, | 579 | input_report_abs(input, ABS_TILT_X, |
601 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); | 580 | ((data[7] << 1) & 0x7e) | (data[8] >> 7)); |
602 | wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f); | 581 | input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); |
603 | } else { | 582 | } else { |
604 | /* 2D mouse packet */ | 583 | /* 2D mouse packet */ |
605 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04); | 584 | input_report_key(input, BTN_LEFT, data[8] & 0x04); |
606 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08); | 585 | input_report_key(input, BTN_MIDDLE, data[8] & 0x08); |
607 | wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10); | 586 | input_report_key(input, BTN_RIGHT, data[8] & 0x10); |
608 | wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01) | 587 | input_report_rel(input, REL_WHEEL, (data[8] & 0x01) |
609 | - ((data[8] & 0x02) >> 1)); | 588 | - ((data[8] & 0x02) >> 1)); |
610 | 589 | ||
611 | /* I3 2D mouse side buttons */ | 590 | /* I3 2D mouse side buttons */ |
612 | if (features->type >= INTUOS3S && features->type <= INTUOS3L) { | 591 | if (features->type >= INTUOS3S && features->type <= INTUOS3L) { |
613 | wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); | 592 | input_report_key(input, BTN_SIDE, data[8] & 0x40); |
614 | wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); | 593 | input_report_key(input, BTN_EXTRA, data[8] & 0x20); |
615 | } | 594 | } |
616 | } | 595 | } |
617 | } else if ((features->type < INTUOS3S || features->type == INTUOS3L || | 596 | } else if ((features->type < INTUOS3S || features->type == INTUOS3L || |
618 | features->type == INTUOS4L) && | 597 | features->type == INTUOS4L) && |
619 | wacom->tool[idx] == BTN_TOOL_LENS) { | 598 | wacom->tool[idx] == BTN_TOOL_LENS) { |
620 | /* Lens cursor packets */ | 599 | /* Lens cursor packets */ |
621 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); | 600 | input_report_key(input, BTN_LEFT, data[8] & 0x01); |
622 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); | 601 | input_report_key(input, BTN_MIDDLE, data[8] & 0x02); |
623 | wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04); | 602 | input_report_key(input, BTN_RIGHT, data[8] & 0x04); |
624 | wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x10); | 603 | input_report_key(input, BTN_SIDE, data[8] & 0x10); |
625 | wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x08); | 604 | input_report_key(input, BTN_EXTRA, data[8] & 0x08); |
626 | } | 605 | } |
627 | } | 606 | } |
628 | 607 | ||
629 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ | 608 | input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */ |
630 | wacom_report_key(wcombo, wacom->tool[idx], 1); | 609 | input_report_key(input, wacom->tool[idx], 1); |
631 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); | 610 | input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); |
632 | return 1; | 611 | return 1; |
633 | } | 612 | } |
634 | 613 | ||
635 | 614 | ||
636 | static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx) | 615 | static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) |
637 | { | 616 | { |
638 | wacom_report_abs(wcombo, ABS_X, | 617 | struct input_dev *input = wacom->input; |
639 | (data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8)); | 618 | int finger = idx + 1; |
640 | wacom_report_abs(wcombo, ABS_Y, | 619 | int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff; |
641 | (data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8)); | 620 | int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff; |
642 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); | 621 | |
643 | wacom_report_key(wcombo, wacom->tool[idx], 1); | 622 | /* |
644 | if (idx) | 623 | * Work around input core suppressing "duplicate" events since |
645 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | 624 | * we are abusing ABS_X/ABS_Y to transmit multi-finger data. |
646 | else | 625 | * This should go away once we switch to true multitouch |
647 | wacom_report_key(wcombo, BTN_TOUCH, 1); | 626 | * protocol. |
627 | */ | ||
628 | if (wacom->last_finger != finger) { | ||
629 | if (x == input->abs[ABS_X]) | ||
630 | x++; | ||
631 | |||
632 | if (y == input->abs[ABS_Y]) | ||
633 | y++; | ||
634 | } | ||
635 | |||
636 | input_report_abs(input, ABS_X, x); | ||
637 | input_report_abs(input, ABS_Y, y); | ||
638 | input_report_abs(input, ABS_MISC, wacom->id[0]); | ||
639 | input_report_key(input, wacom->tool[finger], 1); | ||
640 | if (!idx) | ||
641 | input_report_key(input, BTN_TOUCH, 1); | ||
642 | input_event(input, EV_MSC, MSC_SERIAL, finger); | ||
643 | input_sync(wacom->input); | ||
644 | |||
645 | wacom->last_finger = finger; | ||
648 | } | 646 | } |
649 | 647 | ||
650 | static void wacom_tpc_touch_out(struct wacom_wac *wacom, void *wcombo, int idx) | 648 | static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) |
651 | { | 649 | { |
652 | wacom_report_abs(wcombo, ABS_X, 0); | 650 | struct input_dev *input = wacom->input; |
653 | wacom_report_abs(wcombo, ABS_Y, 0); | 651 | int finger = idx + 1; |
654 | wacom_report_abs(wcombo, ABS_MISC, 0); | 652 | |
655 | wacom_report_key(wcombo, wacom->tool[idx], 0); | 653 | input_report_abs(input, ABS_X, 0); |
656 | if (idx) | 654 | input_report_abs(input, ABS_Y, 0); |
657 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | 655 | input_report_abs(input, ABS_MISC, 0); |
658 | else | 656 | input_report_key(input, wacom->tool[finger], 0); |
659 | wacom_report_key(wcombo, BTN_TOUCH, 0); | 657 | if (!idx) |
660 | return; | 658 | input_report_key(input, BTN_TOUCH, 0); |
659 | input_event(input, EV_MSC, MSC_SERIAL, finger); | ||
660 | input_sync(input); | ||
661 | } | 661 | } |
662 | 662 | ||
663 | static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo) | 663 | static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) |
664 | { | 664 | { |
665 | char *data = wacom->data; | 665 | char *data = wacom->data; |
666 | struct urb *urb = ((struct wacom_combo *)wcombo)->urb; | 666 | struct input_dev *input = wacom->input; |
667 | static int firstFinger = 0; | ||
668 | static int secondFinger = 0; | ||
669 | 667 | ||
670 | wacom->tool[0] = BTN_TOOL_DOUBLETAP; | 668 | wacom->tool[1] = BTN_TOOL_DOUBLETAP; |
671 | wacom->id[0] = TOUCH_DEVICE_ID; | 669 | wacom->id[0] = TOUCH_DEVICE_ID; |
672 | wacom->tool[1] = BTN_TOOL_TRIPLETAP; | 670 | wacom->tool[2] = BTN_TOOL_TRIPLETAP; |
671 | |||
672 | if (len != WACOM_PKGLEN_TPC1FG) { | ||
673 | 673 | ||
674 | if (urb->actual_length != WACOM_PKGLEN_TPC1FG) { | ||
675 | switch (data[0]) { | 674 | switch (data[0]) { |
676 | case WACOM_REPORT_TPC1FG: | ||
677 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); | ||
678 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); | ||
679 | wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); | ||
680 | wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6])); | ||
681 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); | ||
682 | wacom_report_key(wcombo, wacom->tool[0], 1); | ||
683 | break; | ||
684 | case WACOM_REPORT_TPC2FG: | ||
685 | /* keep this byte to send proper out-prox event */ | ||
686 | wacom->id[1] = data[1] & 0x03; | ||
687 | |||
688 | if (data[1] & 0x01) { | ||
689 | wacom_tpc_finger_in(wacom, wcombo, data, 0); | ||
690 | firstFinger = 1; | ||
691 | } else if (firstFinger) { | ||
692 | wacom_tpc_touch_out(wacom, wcombo, 0); | ||
693 | } | ||
694 | 675 | ||
695 | if (data[1] & 0x02) { | 676 | case WACOM_REPORT_TPC1FG: |
696 | /* sync first finger data */ | 677 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); |
697 | if (firstFinger) | 678 | input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); |
698 | wacom_input_sync(wcombo); | 679 | input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); |
680 | input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6])); | ||
681 | input_report_abs(input, ABS_MISC, wacom->id[0]); | ||
682 | input_report_key(input, wacom->tool[1], 1); | ||
683 | input_sync(input); | ||
684 | break; | ||
699 | 685 | ||
700 | wacom_tpc_finger_in(wacom, wcombo, data, 1); | 686 | case WACOM_REPORT_TPC2FG: |
701 | secondFinger = 1; | 687 | if (data[1] & 0x01) |
702 | } else if (secondFinger) { | 688 | wacom_tpc_finger_in(wacom, data, 0); |
703 | /* sync first finger data */ | 689 | else if (wacom->id[1] & 0x01) |
704 | if (firstFinger) | 690 | wacom_tpc_touch_out(wacom, 0); |
705 | wacom_input_sync(wcombo); | ||
706 | 691 | ||
707 | wacom_tpc_touch_out(wacom, wcombo, 1); | 692 | if (data[1] & 0x02) |
708 | secondFinger = 0; | 693 | wacom_tpc_finger_in(wacom, data, 1); |
709 | } | 694 | else if (wacom->id[1] & 0x02) |
710 | if (!(data[1] & 0x01)) | 695 | wacom_tpc_touch_out(wacom, 1); |
711 | firstFinger = 0; | 696 | break; |
712 | break; | ||
713 | } | 697 | } |
714 | } else { | 698 | } else { |
715 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); | 699 | input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); |
716 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); | 700 | input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); |
717 | wacom_report_key(wcombo, BTN_TOUCH, 1); | 701 | input_report_key(input, BTN_TOUCH, 1); |
718 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); | 702 | input_report_abs(input, ABS_MISC, wacom->id[1]); |
719 | wacom_report_key(wcombo, wacom->tool[0], 1); | 703 | input_report_key(input, wacom->tool[1], 1); |
704 | input_sync(input); | ||
720 | } | 705 | } |
721 | return; | ||
722 | } | 706 | } |
723 | 707 | ||
724 | static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) | 708 | static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) |
725 | { | 709 | { |
726 | struct wacom_features *features = &wacom->features; | 710 | struct wacom_features *features = &wacom->features; |
727 | char *data = wacom->data; | 711 | char *data = wacom->data; |
728 | int prox = 0, pressure, idx = -1; | 712 | struct input_dev *input = wacom->input; |
729 | static int stylusInProx, touchInProx = 1, touchOut; | 713 | int prox = 0, pressure; |
730 | struct urb *urb = ((struct wacom_combo *)wcombo)->urb; | 714 | int retval = 0; |
731 | 715 | ||
732 | dbg("wacom_tpc_irq: received report #%d", data[0]); | 716 | dbg("wacom_tpc_irq: received report #%d", data[0]); |
733 | 717 | ||
734 | if (urb->actual_length == WACOM_PKGLEN_TPC1FG || /* single touch */ | 718 | if (len == WACOM_PKGLEN_TPC1FG || /* single touch */ |
735 | data[0] == WACOM_REPORT_TPC1FG || /* single touch */ | 719 | data[0] == WACOM_REPORT_TPC1FG || /* single touch */ |
736 | data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ | 720 | data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ |
737 | if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with touch */ | 721 | |
722 | if (wacom->shared->stylus_in_proximity) { | ||
723 | if (wacom->id[1] & 0x01) | ||
724 | wacom_tpc_touch_out(wacom, 0); | ||
725 | |||
726 | if (wacom->id[1] & 0x02) | ||
727 | wacom_tpc_touch_out(wacom, 1); | ||
728 | |||
729 | wacom->id[1] = 0; | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | if (len == WACOM_PKGLEN_TPC1FG) { /* with touch */ | ||
738 | prox = data[0] & 0x01; | 734 | prox = data[0] & 0x01; |
739 | } else { /* with capacity */ | 735 | } else { /* with capacity */ |
740 | if (data[0] == WACOM_REPORT_TPC1FG) | 736 | if (data[0] == WACOM_REPORT_TPC1FG) |
@@ -745,168 +741,264 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) | |||
745 | prox = data[1] & 0x03; | 741 | prox = data[1] & 0x03; |
746 | } | 742 | } |
747 | 743 | ||
748 | if (!stylusInProx) { /* stylus not in prox */ | 744 | if (prox) { |
749 | if (prox) { | 745 | if (!wacom->id[1]) |
750 | if (touchInProx) { | 746 | wacom->last_finger = 1; |
751 | wacom_tpc_touch_in(wacom, wcombo); | 747 | wacom_tpc_touch_in(wacom, len); |
752 | touchOut = 1; | 748 | } else { |
753 | return 1; | 749 | if (data[0] == WACOM_REPORT_TPC2FG) { |
754 | } | ||
755 | } else { | ||
756 | /* 2FGT out-prox */ | 750 | /* 2FGT out-prox */ |
757 | if (data[0] == WACOM_REPORT_TPC2FG) { | 751 | if (wacom->id[1] & 0x01) |
758 | idx = (wacom->id[1] & 0x01) - 1; | 752 | wacom_tpc_touch_out(wacom, 0); |
759 | if (idx == 0) { | 753 | |
760 | wacom_tpc_touch_out(wacom, wcombo, idx); | 754 | if (wacom->id[1] & 0x02) |
761 | /* sync first finger event */ | 755 | wacom_tpc_touch_out(wacom, 1); |
762 | if (wacom->id[1] & 0x02) | 756 | } else |
763 | wacom_input_sync(wcombo); | 757 | /* one finger touch */ |
764 | } | 758 | wacom_tpc_touch_out(wacom, 0); |
765 | idx = (wacom->id[1] & 0x02) - 1; | 759 | |
766 | if (idx == 1) | 760 | wacom->id[0] = 0; |
767 | wacom_tpc_touch_out(wacom, wcombo, idx); | ||
768 | } else /* one finger touch */ | ||
769 | wacom_tpc_touch_out(wacom, wcombo, 0); | ||
770 | touchOut = 0; | ||
771 | touchInProx = 1; | ||
772 | return 1; | ||
773 | } | ||
774 | } else if (touchOut || !prox) { /* force touch out-prox */ | ||
775 | wacom_tpc_touch_out(wacom, wcombo, 0); | ||
776 | touchOut = 0; | ||
777 | touchInProx = 1; | ||
778 | return 1; | ||
779 | } | 761 | } |
762 | /* keep prox bit to send proper out-prox event */ | ||
763 | wacom->id[1] = prox; | ||
780 | } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ | 764 | } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ |
781 | prox = data[1] & 0x20; | 765 | prox = data[1] & 0x20; |
782 | 766 | ||
783 | touchInProx = 0; | 767 | if (!wacom->shared->stylus_in_proximity) { /* first in prox */ |
768 | /* Going into proximity select tool */ | ||
769 | wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
770 | if (wacom->tool[0] == BTN_TOOL_PEN) | ||
771 | wacom->id[0] = STYLUS_DEVICE_ID; | ||
772 | else | ||
773 | wacom->id[0] = ERASER_DEVICE_ID; | ||
784 | 774 | ||
785 | if (prox) { /* in prox */ | 775 | wacom->shared->stylus_in_proximity = true; |
786 | if (!wacom->id[0]) { | 776 | } |
787 | /* Going into proximity select tool */ | 777 | input_report_key(input, BTN_STYLUS, data[1] & 0x02); |
788 | wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | 778 | input_report_key(input, BTN_STYLUS2, data[1] & 0x10); |
789 | if (wacom->tool[0] == BTN_TOOL_PEN) | 779 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); |
790 | wacom->id[0] = STYLUS_DEVICE_ID; | 780 | input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); |
791 | else | 781 | pressure = ((data[7] & 0x01) << 8) | data[6]; |
792 | wacom->id[0] = ERASER_DEVICE_ID; | 782 | if (pressure < 0) |
793 | } | 783 | pressure = features->pressure_max + pressure + 1; |
794 | wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); | 784 | input_report_abs(input, ABS_PRESSURE, pressure); |
795 | wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10); | 785 | input_report_key(input, BTN_TOUCH, data[1] & 0x05); |
796 | wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); | 786 | if (!prox) { /* out-prox */ |
797 | wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); | ||
798 | pressure = ((data[7] & 0x01) << 8) | data[6]; | ||
799 | if (pressure < 0) | ||
800 | pressure = features->pressure_max + pressure + 1; | ||
801 | wacom_report_abs(wcombo, ABS_PRESSURE, pressure); | ||
802 | wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05); | ||
803 | } else { | ||
804 | wacom_report_abs(wcombo, ABS_X, 0); | ||
805 | wacom_report_abs(wcombo, ABS_Y, 0); | ||
806 | wacom_report_abs(wcombo, ABS_PRESSURE, 0); | ||
807 | wacom_report_key(wcombo, BTN_STYLUS, 0); | ||
808 | wacom_report_key(wcombo, BTN_STYLUS2, 0); | ||
809 | wacom_report_key(wcombo, BTN_TOUCH, 0); | ||
810 | wacom->id[0] = 0; | 787 | wacom->id[0] = 0; |
811 | /* pen is out so touch can be enabled now */ | 788 | wacom->shared->stylus_in_proximity = false; |
812 | touchInProx = 1; | ||
813 | } | 789 | } |
814 | wacom_report_key(wcombo, wacom->tool[0], prox); | 790 | input_report_key(input, wacom->tool[0], prox); |
815 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); | 791 | input_report_abs(input, ABS_MISC, wacom->id[0]); |
816 | stylusInProx = prox; | 792 | retval = 1; |
817 | return 1; | ||
818 | } | 793 | } |
819 | return 0; | 794 | return retval; |
820 | } | 795 | } |
821 | 796 | ||
822 | int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) | 797 | void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) |
823 | { | 798 | { |
799 | bool sync; | ||
800 | |||
824 | switch (wacom_wac->features.type) { | 801 | switch (wacom_wac->features.type) { |
825 | case PENPARTNER: | 802 | case PENPARTNER: |
826 | return wacom_penpartner_irq(wacom_wac, wcombo); | 803 | sync = wacom_penpartner_irq(wacom_wac); |
827 | 804 | break; | |
828 | case PL: | 805 | |
829 | return wacom_pl_irq(wacom_wac, wcombo); | 806 | case PL: |
830 | 807 | sync = wacom_pl_irq(wacom_wac); | |
831 | case WACOM_G4: | 808 | break; |
832 | case GRAPHIRE: | 809 | |
833 | case WACOM_MO: | 810 | case WACOM_G4: |
834 | return wacom_graphire_irq(wacom_wac, wcombo); | 811 | case GRAPHIRE: |
835 | 812 | case WACOM_MO: | |
836 | case PTU: | 813 | sync = wacom_graphire_irq(wacom_wac); |
837 | return wacom_ptu_irq(wacom_wac, wcombo); | 814 | break; |
838 | 815 | ||
839 | case INTUOS: | 816 | case PTU: |
840 | case INTUOS3S: | 817 | sync = wacom_ptu_irq(wacom_wac); |
841 | case INTUOS3: | 818 | break; |
842 | case INTUOS3L: | 819 | |
843 | case INTUOS4S: | 820 | case INTUOS: |
844 | case INTUOS4: | 821 | case INTUOS3S: |
845 | case INTUOS4L: | 822 | case INTUOS3: |
846 | case CINTIQ: | 823 | case INTUOS3L: |
847 | case WACOM_BEE: | 824 | case INTUOS4S: |
848 | return wacom_intuos_irq(wacom_wac, wcombo); | 825 | case INTUOS4: |
849 | 826 | case INTUOS4L: | |
850 | case TABLETPC: | 827 | case CINTIQ: |
851 | case TABLETPC2FG: | 828 | case WACOM_BEE: |
852 | return wacom_tpc_irq(wacom_wac, wcombo); | 829 | sync = wacom_intuos_irq(wacom_wac); |
853 | 830 | break; | |
854 | default: | 831 | |
855 | return 0; | 832 | case TABLETPC: |
833 | case TABLETPC2FG: | ||
834 | sync = wacom_tpc_irq(wacom_wac, len); | ||
835 | break; | ||
836 | |||
837 | default: | ||
838 | sync = false; | ||
839 | break; | ||
856 | } | 840 | } |
857 | return 0; | 841 | |
842 | if (sync) | ||
843 | input_sync(wacom_wac->input); | ||
844 | } | ||
845 | |||
846 | static void wacom_setup_intuos(struct wacom_wac *wacom_wac) | ||
847 | { | ||
848 | struct input_dev *input_dev = wacom_wac->input; | ||
849 | |||
850 | input_set_capability(input_dev, EV_MSC, MSC_SERIAL); | ||
851 | input_set_capability(input_dev, EV_REL, REL_WHEEL); | ||
852 | |||
853 | __set_bit(BTN_LEFT, input_dev->keybit); | ||
854 | __set_bit(BTN_RIGHT, input_dev->keybit); | ||
855 | __set_bit(BTN_MIDDLE, input_dev->keybit); | ||
856 | __set_bit(BTN_SIDE, input_dev->keybit); | ||
857 | __set_bit(BTN_EXTRA, input_dev->keybit); | ||
858 | |||
859 | __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); | ||
860 | __set_bit(BTN_TOOL_PEN, input_dev->keybit); | ||
861 | __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); | ||
862 | __set_bit(BTN_TOOL_BRUSH, input_dev->keybit); | ||
863 | __set_bit(BTN_TOOL_PENCIL, input_dev->keybit); | ||
864 | __set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit); | ||
865 | __set_bit(BTN_TOOL_LENS, input_dev->keybit); | ||
866 | __set_bit(BTN_STYLUS, input_dev->keybit); | ||
867 | __set_bit(BTN_STYLUS2, input_dev->keybit); | ||
868 | |||
869 | input_set_abs_params(input_dev, ABS_DISTANCE, | ||
870 | 0, wacom_wac->features.distance_max, 0, 0); | ||
871 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); | ||
872 | input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0); | ||
873 | input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0); | ||
874 | input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); | ||
875 | input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); | ||
858 | } | 876 | } |
859 | 877 | ||
860 | void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 878 | void wacom_setup_input_capabilities(struct input_dev *input_dev, |
879 | struct wacom_wac *wacom_wac) | ||
861 | { | 880 | { |
881 | struct wacom_features *features = &wacom_wac->features; | ||
882 | int i; | ||
883 | |||
884 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
885 | |||
886 | __set_bit(BTN_TOUCH, input_dev->keybit); | ||
887 | |||
888 | input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0); | ||
889 | input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0); | ||
890 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0); | ||
891 | |||
892 | __set_bit(ABS_MISC, input_dev->absbit); | ||
893 | |||
862 | switch (wacom_wac->features.type) { | 894 | switch (wacom_wac->features.type) { |
863 | case WACOM_MO: | 895 | case WACOM_MO: |
864 | input_dev_mo(input_dev, wacom_wac); | 896 | __set_bit(BTN_1, input_dev->keybit); |
865 | case WACOM_G4: | 897 | __set_bit(BTN_5, input_dev->keybit); |
866 | input_dev_g4(input_dev, wacom_wac); | 898 | |
867 | /* fall through */ | 899 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); |
868 | case GRAPHIRE: | 900 | /* fall through */ |
869 | input_dev_g(input_dev, wacom_wac); | 901 | |
870 | break; | 902 | case WACOM_G4: |
871 | case WACOM_BEE: | 903 | input_set_capability(input_dev, EV_MSC, MSC_SERIAL); |
872 | input_dev_bee(input_dev, wacom_wac); | 904 | |
873 | case INTUOS3: | 905 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); |
874 | case INTUOS3L: | 906 | __set_bit(BTN_0, input_dev->keybit); |
875 | case CINTIQ: | 907 | __set_bit(BTN_4, input_dev->keybit); |
876 | input_dev_i3(input_dev, wacom_wac); | 908 | /* fall through */ |
877 | /* fall through */ | 909 | |
878 | case INTUOS3S: | 910 | case GRAPHIRE: |
879 | input_dev_i3s(input_dev, wacom_wac); | 911 | input_set_capability(input_dev, EV_REL, REL_WHEEL); |
880 | /* fall through */ | 912 | |
881 | case INTUOS: | 913 | __set_bit(BTN_LEFT, input_dev->keybit); |
882 | input_dev_i(input_dev, wacom_wac); | 914 | __set_bit(BTN_RIGHT, input_dev->keybit); |
883 | break; | 915 | __set_bit(BTN_MIDDLE, input_dev->keybit); |
884 | case INTUOS4: | 916 | |
885 | case INTUOS4L: | 917 | __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); |
886 | input_dev_i4(input_dev, wacom_wac); | 918 | __set_bit(BTN_TOOL_PEN, input_dev->keybit); |
887 | /* fall through */ | 919 | __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); |
888 | case INTUOS4S: | 920 | __set_bit(BTN_STYLUS, input_dev->keybit); |
889 | input_dev_i4s(input_dev, wacom_wac); | 921 | __set_bit(BTN_STYLUS2, input_dev->keybit); |
890 | input_dev_i(input_dev, wacom_wac); | 922 | break; |
891 | break; | 923 | |
892 | case TABLETPC2FG: | 924 | case WACOM_BEE: |
893 | input_dev_tpc2fg(input_dev, wacom_wac); | 925 | __set_bit(BTN_8, input_dev->keybit); |
894 | /* fall through */ | 926 | __set_bit(BTN_9, input_dev->keybit); |
895 | case TABLETPC: | 927 | /* fall through */ |
896 | input_dev_tpc(input_dev, wacom_wac); | 928 | |
897 | if (wacom_wac->features.device_type != BTN_TOOL_PEN) | 929 | case INTUOS3: |
898 | break; /* no need to process stylus stuff */ | 930 | case INTUOS3L: |
899 | 931 | case CINTIQ: | |
900 | /* fall through */ | 932 | __set_bit(BTN_4, input_dev->keybit); |
901 | case PL: | 933 | __set_bit(BTN_5, input_dev->keybit); |
902 | case PTU: | 934 | __set_bit(BTN_6, input_dev->keybit); |
903 | input_dev_pl(input_dev, wacom_wac); | 935 | __set_bit(BTN_7, input_dev->keybit); |
904 | /* fall through */ | 936 | |
905 | case PENPARTNER: | 937 | input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); |
906 | input_dev_pt(input_dev, wacom_wac); | 938 | /* fall through */ |
907 | break; | 939 | |
940 | case INTUOS3S: | ||
941 | __set_bit(BTN_0, input_dev->keybit); | ||
942 | __set_bit(BTN_1, input_dev->keybit); | ||
943 | __set_bit(BTN_2, input_dev->keybit); | ||
944 | __set_bit(BTN_3, input_dev->keybit); | ||
945 | |||
946 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
947 | |||
948 | input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); | ||
949 | input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); | ||
950 | /* fall through */ | ||
951 | |||
952 | case INTUOS: | ||
953 | wacom_setup_intuos(wacom_wac); | ||
954 | break; | ||
955 | |||
956 | case INTUOS4: | ||
957 | case INTUOS4L: | ||
958 | __set_bit(BTN_7, input_dev->keybit); | ||
959 | __set_bit(BTN_8, input_dev->keybit); | ||
960 | /* fall through */ | ||
961 | |||
962 | case INTUOS4S: | ||
963 | for (i = 0; i < 7; i++) | ||
964 | __set_bit(BTN_0 + i, input_dev->keybit); | ||
965 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
966 | |||
967 | input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); | ||
968 | wacom_setup_intuos(wacom_wac); | ||
969 | break; | ||
970 | |||
971 | case TABLETPC2FG: | ||
972 | if (features->device_type == BTN_TOOL_TRIPLETAP) { | ||
973 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | ||
974 | input_set_capability(input_dev, EV_MSC, MSC_SERIAL); | ||
975 | } | ||
976 | /* fall through */ | ||
977 | |||
978 | case TABLETPC: | ||
979 | if (features->device_type == BTN_TOOL_DOUBLETAP || | ||
980 | features->device_type == BTN_TOOL_TRIPLETAP) { | ||
981 | input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0); | ||
982 | input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0); | ||
983 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
984 | } | ||
985 | |||
986 | if (features->device_type != BTN_TOOL_PEN) | ||
987 | break; /* no need to process stylus stuff */ | ||
988 | |||
989 | /* fall through */ | ||
990 | |||
991 | case PL: | ||
992 | case PTU: | ||
993 | __set_bit(BTN_TOOL_PEN, input_dev->keybit); | ||
994 | __set_bit(BTN_STYLUS, input_dev->keybit); | ||
995 | __set_bit(BTN_STYLUS2, input_dev->keybit); | ||
996 | /* fall through */ | ||
997 | |||
998 | case PENPARTNER: | ||
999 | __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); | ||
1000 | break; | ||
908 | } | 1001 | } |
909 | return; | ||
910 | } | 1002 | } |
911 | 1003 | ||
912 | static const struct wacom_features wacom_features_0x00 = | 1004 | static const struct wacom_features wacom_features_0x00 = |
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index b50cf04e61a8..063f1af3204f 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h | |||
@@ -9,6 +9,8 @@ | |||
9 | #ifndef WACOM_WAC_H | 9 | #ifndef WACOM_WAC_H |
10 | #define WACOM_WAC_H | 10 | #define WACOM_WAC_H |
11 | 11 | ||
12 | #include <linux/types.h> | ||
13 | |||
12 | /* maximum packet length for USB devices */ | 14 | /* maximum packet length for USB devices */ |
13 | #define WACOM_PKGLEN_MAX 32 | 15 | #define WACOM_PKGLEN_MAX 32 |
14 | 16 | ||
@@ -71,13 +73,20 @@ struct wacom_features { | |||
71 | unsigned char unitExpo; | 73 | unsigned char unitExpo; |
72 | }; | 74 | }; |
73 | 75 | ||
76 | struct wacom_shared { | ||
77 | bool stylus_in_proximity; | ||
78 | }; | ||
79 | |||
74 | struct wacom_wac { | 80 | struct wacom_wac { |
75 | char name[64]; | 81 | char name[64]; |
76 | unsigned char *data; | 82 | unsigned char *data; |
77 | int tool[2]; | 83 | int tool[3]; |
78 | int id[2]; | 84 | int id[3]; |
79 | __u32 serial[2]; | 85 | __u32 serial[2]; |
86 | int last_finger; | ||
80 | struct wacom_features features; | 87 | struct wacom_features features; |
88 | struct wacom_shared *shared; | ||
89 | struct input_dev *input; | ||
81 | }; | 90 | }; |
82 | 91 | ||
83 | #endif | 92 | #endif |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6c0f1712f55b..b9f58ca82fd1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -119,6 +119,18 @@ config TOUCHSCREEN_DYNAPRO | |||
119 | To compile this driver as a module, choose M here: the | 119 | To compile this driver as a module, choose M here: the |
120 | module will be called dynapro. | 120 | module will be called dynapro. |
121 | 121 | ||
122 | config TOUCHSCREEN_HAMPSHIRE | ||
123 | tristate "Hampshire serial touchscreen" | ||
124 | select SERIO | ||
125 | help | ||
126 | Say Y here if you have a Hampshire serial touchscreen connected to | ||
127 | your system. | ||
128 | |||
129 | If unsure, say N. | ||
130 | |||
131 | To compile this driver as a module, choose M here: the | ||
132 | module will be called hampshire. | ||
133 | |||
122 | config TOUCHSCREEN_EETI | 134 | config TOUCHSCREEN_EETI |
123 | tristate "EETI touchscreen panel support" | 135 | tristate "EETI touchscreen panel support" |
124 | depends on I2C | 136 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 41145d074dec..8ad36eef90a2 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o | |||
13 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o | 13 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o |
14 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o | 14 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o |
15 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | 15 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o |
16 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o | ||
16 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | 17 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o |
17 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o |
18 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | 19 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o |
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c new file mode 100644 index 000000000000..2da6cc31bb21 --- /dev/null +++ b/drivers/input/touchscreen/hampshire.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * Hampshire serial touchscreen driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Adam Bennett | ||
5 | * Based on the dynapro driver (c) Tias Guns | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * 2010/04/08 Adam Bennett <abennett72@gmail.com> | ||
17 | * Copied dynapro.c and edited for Hampshire 4-byte protocol | ||
18 | */ | ||
19 | |||
20 | #include <linux/errno.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/serio.h> | ||
26 | #include <linux/init.h> | ||
27 | |||
28 | #define DRIVER_DESC "Hampshire serial touchscreen driver" | ||
29 | |||
30 | MODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>"); | ||
31 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | /* | ||
35 | * Definitions & global arrays. | ||
36 | */ | ||
37 | |||
38 | #define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40 | ||
39 | #define HAMPSHIRE_FORMAT_LENGTH 4 | ||
40 | #define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80 | ||
41 | |||
42 | #define HAMPSHIRE_MIN_XC 0 | ||
43 | #define HAMPSHIRE_MAX_XC 0x1000 | ||
44 | #define HAMPSHIRE_MIN_YC 0 | ||
45 | #define HAMPSHIRE_MAX_YC 0x1000 | ||
46 | |||
47 | #define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6)) | ||
48 | #define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9)) | ||
49 | #define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0]) | ||
50 | |||
51 | /* | ||
52 | * Per-touchscreen data. | ||
53 | */ | ||
54 | |||
55 | struct hampshire { | ||
56 | struct input_dev *dev; | ||
57 | struct serio *serio; | ||
58 | int idx; | ||
59 | unsigned char data[HAMPSHIRE_FORMAT_LENGTH]; | ||
60 | char phys[32]; | ||
61 | }; | ||
62 | |||
63 | static void hampshire_process_data(struct hampshire *phampshire) | ||
64 | { | ||
65 | struct input_dev *dev = phampshire->dev; | ||
66 | |||
67 | if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) { | ||
68 | input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data)); | ||
69 | input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data)); | ||
70 | input_report_key(dev, BTN_TOUCH, | ||
71 | HAMPSHIRE_GET_TOUCHED(phampshire->data)); | ||
72 | input_sync(dev); | ||
73 | |||
74 | phampshire->idx = 0; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static irqreturn_t hampshire_interrupt(struct serio *serio, | ||
79 | unsigned char data, unsigned int flags) | ||
80 | { | ||
81 | struct hampshire *phampshire = serio_get_drvdata(serio); | ||
82 | |||
83 | phampshire->data[phampshire->idx] = data; | ||
84 | |||
85 | if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0]) | ||
86 | hampshire_process_data(phampshire); | ||
87 | else | ||
88 | dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", | ||
89 | phampshire->data[0]); | ||
90 | |||
91 | return IRQ_HANDLED; | ||
92 | } | ||
93 | |||
94 | static void hampshire_disconnect(struct serio *serio) | ||
95 | { | ||
96 | struct hampshire *phampshire = serio_get_drvdata(serio); | ||
97 | |||
98 | input_get_device(phampshire->dev); | ||
99 | input_unregister_device(phampshire->dev); | ||
100 | serio_close(serio); | ||
101 | serio_set_drvdata(serio, NULL); | ||
102 | input_put_device(phampshire->dev); | ||
103 | kfree(phampshire); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * hampshire_connect() is the routine that is called when someone adds a | ||
108 | * new serio device that supports hampshire protocol and registers it as | ||
109 | * an input device. This is usually accomplished using inputattach. | ||
110 | */ | ||
111 | |||
112 | static int hampshire_connect(struct serio *serio, struct serio_driver *drv) | ||
113 | { | ||
114 | struct hampshire *phampshire; | ||
115 | struct input_dev *input_dev; | ||
116 | int err; | ||
117 | |||
118 | phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL); | ||
119 | input_dev = input_allocate_device(); | ||
120 | if (!phampshire || !input_dev) { | ||
121 | err = -ENOMEM; | ||
122 | goto fail1; | ||
123 | } | ||
124 | |||
125 | phampshire->serio = serio; | ||
126 | phampshire->dev = input_dev; | ||
127 | snprintf(phampshire->phys, sizeof(phampshire->phys), | ||
128 | "%s/input0", serio->phys); | ||
129 | |||
130 | input_dev->name = "Hampshire Serial TouchScreen"; | ||
131 | input_dev->phys = phampshire->phys; | ||
132 | input_dev->id.bustype = BUS_RS232; | ||
133 | input_dev->id.vendor = SERIO_HAMPSHIRE; | ||
134 | input_dev->id.product = 0; | ||
135 | input_dev->id.version = 0x0001; | ||
136 | input_dev->dev.parent = &serio->dev; | ||
137 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
138 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
139 | input_set_abs_params(phampshire->dev, ABS_X, | ||
140 | HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0); | ||
141 | input_set_abs_params(phampshire->dev, ABS_Y, | ||
142 | HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0); | ||
143 | |||
144 | serio_set_drvdata(serio, phampshire); | ||
145 | |||
146 | err = serio_open(serio, drv); | ||
147 | if (err) | ||
148 | goto fail2; | ||
149 | |||
150 | err = input_register_device(phampshire->dev); | ||
151 | if (err) | ||
152 | goto fail3; | ||
153 | |||
154 | return 0; | ||
155 | |||
156 | fail3: serio_close(serio); | ||
157 | fail2: serio_set_drvdata(serio, NULL); | ||
158 | fail1: input_free_device(input_dev); | ||
159 | kfree(phampshire); | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * The serio driver structure. | ||
165 | */ | ||
166 | |||
167 | static struct serio_device_id hampshire_serio_ids[] = { | ||
168 | { | ||
169 | .type = SERIO_RS232, | ||
170 | .proto = SERIO_HAMPSHIRE, | ||
171 | .id = SERIO_ANY, | ||
172 | .extra = SERIO_ANY, | ||
173 | }, | ||
174 | { 0 } | ||
175 | }; | ||
176 | |||
177 | MODULE_DEVICE_TABLE(serio, hampshire_serio_ids); | ||
178 | |||
179 | static struct serio_driver hampshire_drv = { | ||
180 | .driver = { | ||
181 | .name = "hampshire", | ||
182 | }, | ||
183 | .description = DRIVER_DESC, | ||
184 | .id_table = hampshire_serio_ids, | ||
185 | .interrupt = hampshire_interrupt, | ||
186 | .connect = hampshire_connect, | ||
187 | .disconnect = hampshire_disconnect, | ||
188 | }; | ||
189 | |||
190 | /* | ||
191 | * The functions for inserting/removing us as a module. | ||
192 | */ | ||
193 | |||
194 | static int __init hampshire_init(void) | ||
195 | { | ||
196 | return serio_register_driver(&hampshire_drv); | ||
197 | } | ||
198 | |||
199 | static void __exit hampshire_exit(void) | ||
200 | { | ||
201 | serio_unregister_driver(&hampshire_drv); | ||
202 | } | ||
203 | |||
204 | module_init(hampshire_init); | ||
205 | module_exit(hampshire_exit); | ||
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index be23780e8a3e..769b479fcaa6 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c | |||
@@ -347,6 +347,8 @@ static int __devexit tsc2007_remove(struct i2c_client *client) | |||
347 | struct tsc2007 *ts = i2c_get_clientdata(client); | 347 | struct tsc2007 *ts = i2c_get_clientdata(client); |
348 | struct tsc2007_platform_data *pdata = client->dev.platform_data; | 348 | struct tsc2007_platform_data *pdata = client->dev.platform_data; |
349 | 349 | ||
350 | i2c_set_clientdata(client, NULL); | ||
351 | |||
350 | tsc2007_free_irq(ts); | 352 | tsc2007_free_irq(ts); |
351 | 353 | ||
352 | if (pdata->exit_platform_hw) | 354 | if (pdata->exit_platform_hw) |
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 99330bbdbac7..0b0ae2e17a60 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
@@ -811,12 +811,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch) | |||
811 | 811 | ||
812 | priv = usbtouch->priv; | 812 | priv = usbtouch->priv; |
813 | 813 | ||
814 | priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL); | 814 | priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt), |
815 | GFP_KERNEL); | ||
815 | if (!priv->ack_buf) | 816 | if (!priv->ack_buf) |
816 | goto err_priv; | 817 | goto err_priv; |
817 | 818 | ||
818 | memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt)); | ||
819 | |||
820 | priv->ack = usb_alloc_urb(0, GFP_KERNEL); | 819 | priv->ack = usb_alloc_urb(0, GFP_KERNEL); |
821 | if (!priv->ack) { | 820 | if (!priv->ack) { |
822 | dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__); | 821 | dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__); |
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 5109bf3dd858..cbfef1ea7e30 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c | |||
@@ -200,7 +200,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, | |||
200 | mutex_lock(&wm->codec_mutex); | 200 | mutex_lock(&wm->codec_mutex); |
201 | reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); | 201 | reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); |
202 | 202 | ||
203 | if (status & WM97XX_GPIO_HIGH) | 203 | if (status == WM97XX_GPIO_HIGH) |
204 | reg |= gpio; | 204 | reg |= gpio; |
205 | else | 205 | else |
206 | reg &= ~gpio; | 206 | reg &= ~gpio; |
diff --git a/include/linux/input.h b/include/linux/input.h index 7ed2251b33f1..83524e4f3290 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
@@ -806,6 +806,7 @@ struct input_absinfo { | |||
806 | #define BUS_HOST 0x19 | 806 | #define BUS_HOST 0x19 |
807 | #define BUS_GSC 0x1A | 807 | #define BUS_GSC 0x1A |
808 | #define BUS_ATARI 0x1B | 808 | #define BUS_ATARI 0x1B |
809 | #define BUS_SPI 0x1C | ||
809 | 810 | ||
810 | /* | 811 | /* |
811 | * MT_TOOL types | 812 | * MT_TOOL types |
diff --git a/include/linux/input/ad714x.h b/include/linux/input/ad714x.h new file mode 100644 index 000000000000..0cbe5e81482e --- /dev/null +++ b/include/linux/input/ad714x.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * include/linux/input/ad714x.h | ||
3 | * | ||
4 | * AD714x is very flexible, it can be used as buttons, scrollwheel, | ||
5 | * slider, touchpad at the same time. That depends on the boards. | ||
6 | * The platform_data for the device's "struct device" holds this | ||
7 | * information. | ||
8 | * | ||
9 | * Copyright 2009 Analog Devices Inc. | ||
10 | * | ||
11 | * Licensed under the GPL-2 or later. | ||
12 | */ | ||
13 | |||
14 | #ifndef __LINUX_INPUT_AD714X_H__ | ||
15 | #define __LINUX_INPUT_AD714X_H__ | ||
16 | |||
17 | #define STAGE_NUM 12 | ||
18 | #define STAGE_CFGREG_NUM 8 | ||
19 | #define SYS_CFGREG_NUM 8 | ||
20 | |||
21 | /* board information which need be initialized in arch/mach... */ | ||
22 | struct ad714x_slider_plat { | ||
23 | int start_stage; | ||
24 | int end_stage; | ||
25 | int max_coord; | ||
26 | }; | ||
27 | |||
28 | struct ad714x_wheel_plat { | ||
29 | int start_stage; | ||
30 | int end_stage; | ||
31 | int max_coord; | ||
32 | }; | ||
33 | |||
34 | struct ad714x_touchpad_plat { | ||
35 | int x_start_stage; | ||
36 | int x_end_stage; | ||
37 | int x_max_coord; | ||
38 | |||
39 | int y_start_stage; | ||
40 | int y_end_stage; | ||
41 | int y_max_coord; | ||
42 | }; | ||
43 | |||
44 | struct ad714x_button_plat { | ||
45 | int keycode; | ||
46 | unsigned short l_mask; | ||
47 | unsigned short h_mask; | ||
48 | }; | ||
49 | |||
50 | struct ad714x_platform_data { | ||
51 | int slider_num; | ||
52 | int wheel_num; | ||
53 | int touchpad_num; | ||
54 | int button_num; | ||
55 | struct ad714x_slider_plat *slider; | ||
56 | struct ad714x_wheel_plat *wheel; | ||
57 | struct ad714x_touchpad_plat *touchpad; | ||
58 | struct ad714x_button_plat *button; | ||
59 | unsigned short stage_cfg_reg[STAGE_NUM][STAGE_CFGREG_NUM]; | ||
60 | unsigned short sys_cfg_reg[SYS_CFGREG_NUM]; | ||
61 | }; | ||
62 | |||
63 | #endif | ||
diff --git a/include/linux/serio.h b/include/linux/serio.h index 64b473066b9a..b5552568178d 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h | |||
@@ -196,5 +196,6 @@ static inline void serio_continue_rx(struct serio *serio) | |||
196 | #define SERIO_TOUCHIT213 0x38 | 196 | #define SERIO_TOUCHIT213 0x38 |
197 | #define SERIO_W8001 0x39 | 197 | #define SERIO_W8001 0x39 |
198 | #define SERIO_DYNAPRO 0x3a | 198 | #define SERIO_DYNAPRO 0x3a |
199 | #define SERIO_HAMPSHIRE 0x3b | ||
199 | 200 | ||
200 | #endif | 201 | #endif |
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 99adcdc0d3ca..4496322e28dd 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h | |||
@@ -39,41 +39,34 @@ struct sysrq_key_op { | |||
39 | 39 | ||
40 | #ifdef CONFIG_MAGIC_SYSRQ | 40 | #ifdef CONFIG_MAGIC_SYSRQ |
41 | 41 | ||
42 | extern int sysrq_on(void); | ||
43 | |||
44 | /* | ||
45 | * Do not use this one directly: | ||
46 | */ | ||
47 | extern int __sysrq_enabled; | ||
48 | |||
49 | /* Generic SysRq interface -- you may call it from any device driver, supplying | 42 | /* Generic SysRq interface -- you may call it from any device driver, supplying |
50 | * ASCII code of the key, pointer to registers and kbd/tty structs (if they | 43 | * ASCII code of the key, pointer to registers and kbd/tty structs (if they |
51 | * are available -- else NULL's). | 44 | * are available -- else NULL's). |
52 | */ | 45 | */ |
53 | 46 | ||
54 | void handle_sysrq(int key, struct tty_struct *tty); | 47 | void handle_sysrq(int key, struct tty_struct *tty); |
55 | void __handle_sysrq(int key, struct tty_struct *tty, int check_mask); | ||
56 | int register_sysrq_key(int key, struct sysrq_key_op *op); | 48 | int register_sysrq_key(int key, struct sysrq_key_op *op); |
57 | int unregister_sysrq_key(int key, struct sysrq_key_op *op); | 49 | int unregister_sysrq_key(int key, struct sysrq_key_op *op); |
58 | struct sysrq_key_op *__sysrq_get_key_op(int key); | 50 | struct sysrq_key_op *__sysrq_get_key_op(int key); |
59 | 51 | ||
52 | int sysrq_toggle_support(int enable_mask); | ||
53 | |||
60 | #else | 54 | #else |
61 | 55 | ||
62 | static inline int sysrq_on(void) | 56 | static inline void handle_sysrq(int key, struct tty_struct *tty) |
63 | { | 57 | { |
64 | return 0; | ||
65 | } | 58 | } |
66 | static inline int __reterr(void) | 59 | |
60 | static inline int register_sysrq_key(int key, struct sysrq_key_op *op) | ||
67 | { | 61 | { |
68 | return -EINVAL; | 62 | return -EINVAL; |
69 | } | 63 | } |
70 | static inline void handle_sysrq(int key, struct tty_struct *tty) | 64 | |
65 | static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op) | ||
71 | { | 66 | { |
67 | return -EINVAL; | ||
72 | } | 68 | } |
73 | 69 | ||
74 | #define register_sysrq_key(ig,nore) __reterr() | ||
75 | #define unregister_sysrq_key(ig,nore) __reterr() | ||
76 | |||
77 | #endif | 70 | #endif |
78 | 71 | ||
79 | #endif /* _LINUX_SYSRQ_H */ | 72 | #endif /* _LINUX_SYSRQ_H */ |
diff --git a/include/linux/tca6416_keypad.h b/include/linux/tca6416_keypad.h new file mode 100644 index 000000000000..7bd266f3525c --- /dev/null +++ b/include/linux/tca6416_keypad.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * tca6416 keypad platform support | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * | ||
6 | * Author: Sriramakrishnan <srk@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _TCA6416_KEYS_H | ||
14 | #define _TCA6416_KEYS_H | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | |||
18 | struct tca6416_button { | ||
19 | /* Configuration parameters */ | ||
20 | int code; /* input event code (KEY_*, SW_*) */ | ||
21 | int active_low; | ||
22 | int type; /* input event type (EV_KEY, EV_SW) */ | ||
23 | }; | ||
24 | |||
25 | struct tca6416_keys_platform_data { | ||
26 | struct tca6416_button *buttons; | ||
27 | int nbuttons; | ||
28 | unsigned int rep:1; /* enable input subsystem auto repeat */ | ||
29 | uint16_t pinmask; | ||
30 | uint16_t invert; | ||
31 | int irq_is_gpio; | ||
32 | int use_polling; /* use polling if Interrupt is not connected*/ | ||
33 | }; | ||
34 | #endif | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 90f536d84643..509e6ba5df20 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -163,6 +163,27 @@ static int proc_taint(struct ctl_table *table, int write, | |||
163 | void __user *buffer, size_t *lenp, loff_t *ppos); | 163 | void __user *buffer, size_t *lenp, loff_t *ppos); |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | #ifdef CONFIG_MAGIC_SYSRQ | ||
167 | static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */ | ||
168 | |||
169 | static int sysrq_sysctl_handler(ctl_table *table, int write, | ||
170 | void __user *buffer, size_t *lenp, | ||
171 | loff_t *ppos) | ||
172 | { | ||
173 | int error; | ||
174 | |||
175 | error = proc_dointvec(table, write, buffer, lenp, ppos); | ||
176 | if (error) | ||
177 | return error; | ||
178 | |||
179 | if (write) | ||
180 | sysrq_toggle_support(__sysrq_enabled); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | #endif | ||
186 | |||
166 | static struct ctl_table root_table[]; | 187 | static struct ctl_table root_table[]; |
167 | static struct ctl_table_root sysctl_table_root; | 188 | static struct ctl_table_root sysctl_table_root; |
168 | static struct ctl_table_header root_table_header = { | 189 | static struct ctl_table_header root_table_header = { |
@@ -567,7 +588,7 @@ static struct ctl_table kern_table[] = { | |||
567 | .data = &__sysrq_enabled, | 588 | .data = &__sysrq_enabled, |
568 | .maxlen = sizeof (int), | 589 | .maxlen = sizeof (int), |
569 | .mode = 0644, | 590 | .mode = 0644, |
570 | .proc_handler = proc_dointvec, | 591 | .proc_handler = sysrq_sysctl_handler, |
571 | }, | 592 | }, |
572 | #endif | 593 | #endif |
573 | #ifdef CONFIG_PROC_SYSCTL | 594 | #ifdef CONFIG_PROC_SYSCTL |