aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/synaptics.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse/synaptics.c')
-rw-r--r--drivers/input/mouse/synaptics.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f4a61252bcc9..ebd7a99efeae 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -24,9 +24,11 @@
24 */ 24 */
25 25
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/dmi.h>
27#include <linux/input.h> 28#include <linux/input.h>
28#include <linux/serio.h> 29#include <linux/serio.h>
29#include <linux/libps2.h> 30#include <linux/libps2.h>
31#include <linux/slab.h>
30#include "psmouse.h" 32#include "psmouse.h"
31#include "synaptics.h" 33#include "synaptics.h"
32 34
@@ -135,7 +137,8 @@ static int synaptics_capability(struct psmouse *psmouse)
135 if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) 137 if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
136 return -1; 138 return -1;
137 priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; 139 priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
138 priv->ext_cap = 0; 140 priv->ext_cap = priv->ext_cap_0c = 0;
141
139 if (!SYN_CAP_VALID(priv->capabilities)) 142 if (!SYN_CAP_VALID(priv->capabilities))
140 return -1; 143 return -1;
141 144
@@ -148,7 +151,7 @@ static int synaptics_capability(struct psmouse *psmouse)
148 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { 151 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
149 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { 152 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
150 printk(KERN_ERR "Synaptics claims to have extended capabilities," 153 printk(KERN_ERR "Synaptics claims to have extended capabilities,"
151 " but I'm not able to read them."); 154 " but I'm not able to read them.\n");
152 } else { 155 } else {
153 priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; 156 priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
154 157
@@ -160,6 +163,16 @@ static int synaptics_capability(struct psmouse *psmouse)
160 priv->ext_cap &= 0xff0fff; 163 priv->ext_cap &= 0xff0fff;
161 } 164 }
162 } 165 }
166
167 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
168 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
169 printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
170 " but I'm not able to read it.\n");
171 } else {
172 priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
173 }
174 }
175
163 return 0; 176 return 0;
164} 177}
165 178
@@ -346,7 +359,15 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
346 hw->left = (buf[0] & 0x01) ? 1 : 0; 359 hw->left = (buf[0] & 0x01) ? 1 : 0;
347 hw->right = (buf[0] & 0x02) ? 1 : 0; 360 hw->right = (buf[0] & 0x02) ? 1 : 0;
348 361
349 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { 362 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
363 /*
364 * Clickpad's button is transmitted as middle button,
365 * however, since it is primary button, we will report
366 * it as BTN_LEFT.
367 */
368 hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
369
370 } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
350 hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; 371 hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
351 if (hw->w == 2) 372 if (hw->w == 2)
352 hw->scroll = (signed char)(buf[1]); 373 hw->scroll = (signed char)(buf[1]);
@@ -591,6 +612,12 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
591 612
592 dev->absres[ABS_X] = priv->x_res; 613 dev->absres[ABS_X] = priv->x_res;
593 dev->absres[ABS_Y] = priv->y_res; 614 dev->absres[ABS_Y] = priv->y_res;
615
616 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
617 /* Clickpads report only left button */
618 __clear_bit(BTN_RIGHT, dev->keybit);
619 __clear_bit(BTN_MIDDLE, dev->keybit);
620 }
594} 621}
595 622
596static void synaptics_disconnect(struct psmouse *psmouse) 623static void synaptics_disconnect(struct psmouse *psmouse)
@@ -629,25 +656,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
629 return 0; 656 return 0;
630} 657}
631 658
632#if defined(__i386__) 659static bool impaired_toshiba_kbc;
633#include <linux/dmi.h> 660
634static const struct dmi_system_id toshiba_dmi_table[] = { 661static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
662#if defined(CONFIG_DMI) && defined(CONFIG_X86)
635 { 663 {
636 .ident = "Toshiba Satellite", 664 /* Toshiba Satellite */
637 .matches = { 665 .matches = {
638 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 666 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
639 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), 667 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
640 }, 668 },
641 }, 669 },
642 { 670 {
643 .ident = "Toshiba Dynabook", 671 /* Toshiba Dynabook */
644 .matches = { 672 .matches = {
645 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 673 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
646 DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), 674 DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
647 }, 675 },
648 }, 676 },
649 { 677 {
650 .ident = "Toshiba Portege M300", 678 /* Toshiba Portege M300 */
651 .matches = { 679 .matches = {
652 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 680 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
653 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), 681 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
@@ -655,7 +683,7 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
655 683
656 }, 684 },
657 { 685 {
658 .ident = "Toshiba Portege M300", 686 /* Toshiba Portege M300 */
659 .matches = { 687 .matches = {
660 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 688 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
661 DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), 689 DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
@@ -664,8 +692,13 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
664 692
665 }, 693 },
666 { } 694 { }
667};
668#endif 695#endif
696};
697
698void __init synaptics_module_init(void)
699{
700 impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
701}
669 702
670int synaptics_init(struct psmouse *psmouse) 703int synaptics_init(struct psmouse *psmouse)
671{ 704{
@@ -689,10 +722,10 @@ int synaptics_init(struct psmouse *psmouse)
689 722
690 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; 723 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
691 724
692 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n", 725 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
693 SYN_ID_MODEL(priv->identity), 726 SYN_ID_MODEL(priv->identity),
694 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), 727 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
695 priv->model_id, priv->capabilities, priv->ext_cap); 728 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
696 729
697 set_input_params(psmouse->dev, priv); 730 set_input_params(psmouse->dev, priv);
698 731
@@ -718,18 +751,16 @@ int synaptics_init(struct psmouse *psmouse)
718 if (SYN_CAP_PASS_THROUGH(priv->capabilities)) 751 if (SYN_CAP_PASS_THROUGH(priv->capabilities))
719 synaptics_pt_create(psmouse); 752 synaptics_pt_create(psmouse);
720 753
721#if defined(__i386__)
722 /* 754 /*
723 * Toshiba's KBC seems to have trouble handling data from 755 * Toshiba's KBC seems to have trouble handling data from
724 * Synaptics as full rate, switch to lower rate which is roughly 756 * Synaptics as full rate, switch to lower rate which is roughly
725 * thye same as rate of standard PS/2 mouse. 757 * thye same as rate of standard PS/2 mouse.
726 */ 758 */
727 if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { 759 if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
728 printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", 760 printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
729 dmi_get_system_info(DMI_PRODUCT_NAME)); 761 dmi_get_system_info(DMI_PRODUCT_NAME));
730 psmouse->rate = 40; 762 psmouse->rate = 40;
731 } 763 }
732#endif
733 764
734 return 0; 765 return 0;
735 766
@@ -738,12 +769,26 @@ int synaptics_init(struct psmouse *psmouse)
738 return -1; 769 return -1;
739} 770}
740 771
772bool synaptics_supported(void)
773{
774 return true;
775}
776
741#else /* CONFIG_MOUSE_PS2_SYNAPTICS */ 777#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
742 778
779void __init synaptics_module_init(void)
780{
781}
782
743int synaptics_init(struct psmouse *psmouse) 783int synaptics_init(struct psmouse *psmouse)
744{ 784{
745 return -ENOSYS; 785 return -ENOSYS;
746} 786}
747 787
788bool synaptics_supported(void)
789{
790 return false;
791}
792
748#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ 793#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
749 794