aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-03-19 20:02:01 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-03-19 20:02:01 -0400
commit10ce3cc919f50c2043b41ca968b43c26a3672600 (patch)
treeea409366a5208aced495bc0516a08b81fd43222e /drivers/input/mouse
parent24e3e5ae1e4c2a3a32f5b1f96b4e3fd721806acd (diff)
parent5c6a7a62c130afef3d61c1dee153012231ff5cd9 (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/Kconfig17
-rw-r--r--drivers/input/mouse/Makefile1
-rw-r--r--drivers/input/mouse/appletouch.c13
-rw-r--r--drivers/input/mouse/bcm5974.c15
-rw-r--r--drivers/input/mouse/hgpk.c9
-rw-r--r--drivers/input/mouse/psmouse-base.c17
-rw-r--r--drivers/input/mouse/psmouse.h2
-rw-r--r--drivers/input/mouse/sentelic.c12
-rw-r--r--drivers/input/mouse/synaptics_i2c.c19
-rw-r--r--drivers/input/mouse/synaptics_usb.c557
10 files changed, 601 insertions, 61 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9c1e6ee83531..9b8db821d5f0 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -322,4 +322,21 @@ config MOUSE_SYNAPTICS_I2C
322 To compile this driver as a module, choose M here: the 322 To compile this driver as a module, choose M here: the
323 module will be called synaptics_i2c. 323 module will be called synaptics_i2c.
324 324
325config MOUSE_SYNAPTICS_USB
326 tristate "Synaptics USB device support"
327 depends on USB_ARCH_HAS_HCD
328 select USB
329 help
330 Say Y here if you want to use a Synaptics USB touchpad or pointing
331 stick.
332
333 While these devices emulate an USB mouse by default and can be used
334 with standard usbhid driver, this driver, together with its X.Org
335 counterpart, allows you to fully utilize capabilities of the device.
336 More information can be found at:
337 <http://jan-steinhoff.de/linux/synaptics-usb.html>
338
339 To compile this driver as a module, choose M here: the
340 module will be called synaptics_usb.
341
325endif 342endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 570c84a4a654..4718effeb8d9 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
18obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o 18obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
19obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o 19obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
20obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o 20obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
21obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
21obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o 22obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
22 23
23psmouse-objs := psmouse-base.o synaptics.o 24psmouse-objs := psmouse-base.o synaptics.o
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index b77f9991278e..0acbc7d50d05 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -938,15 +938,4 @@ static struct usb_driver atp_driver = {
938 .id_table = atp_table, 938 .id_table = atp_table,
939}; 939};
940 940
941static int __init atp_init(void) 941module_usb_driver(atp_driver);
942{
943 return usb_register(&atp_driver);
944}
945
946static void __exit atp_exit(void)
947{
948 usb_deregister(&atp_driver);
949}
950
951module_init(atp_init);
952module_exit(atp_exit);
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 913e9fa4c810..f9e2758b9f46 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -433,6 +433,7 @@ static void setup_events_to_report(struct input_dev *input_dev,
433 __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); 433 __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
434 __set_bit(BTN_LEFT, input_dev->keybit); 434 __set_bit(BTN_LEFT, input_dev->keybit);
435 435
436 __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
436 if (cfg->caps & HAS_INTEGRATED_BUTTON) 437 if (cfg->caps & HAS_INTEGRATED_BUTTON)
437 __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); 438 __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
438 439
@@ -943,16 +944,4 @@ static struct usb_driver bcm5974_driver = {
943 .supports_autosuspend = 1, 944 .supports_autosuspend = 1,
944}; 945};
945 946
946static int __init bcm5974_init(void) 947module_usb_driver(bcm5974_driver);
947{
948 return usb_register(&bcm5974_driver);
949}
950
951static void __exit bcm5974_exit(void)
952{
953 usb_deregister(&bcm5974_driver);
954}
955
956module_init(bcm5974_init);
957module_exit(bcm5974_exit);
958
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 1c5d521de600..575f880727fe 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -640,7 +640,6 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
640 640
641static int hgpk_force_recalibrate(struct psmouse *psmouse) 641static int hgpk_force_recalibrate(struct psmouse *psmouse)
642{ 642{
643 struct ps2dev *ps2dev = &psmouse->ps2dev;
644 struct hgpk_data *priv = psmouse->private; 643 struct hgpk_data *priv = psmouse->private;
645 int err; 644 int err;
646 645
@@ -669,12 +668,9 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
669 * we don't have a good way to deal with it. The 2s window stuff 668 * we don't have a good way to deal with it. The 2s window stuff
670 * (below) is our best option for now. 669 * (below) is our best option for now.
671 */ 670 */
672 671 if (psmouse_activate(psmouse))
673 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
674 return -1; 672 return -1;
675 673
676 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
677
678 if (tpdebug) 674 if (tpdebug)
679 psmouse_dbg(psmouse, "touchpad reactivated\n"); 675 psmouse_dbg(psmouse, "touchpad reactivated\n");
680 676
@@ -733,8 +729,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
733 } 729 }
734 730
735 /* should be all set, enable the touchpad */ 731 /* should be all set, enable the touchpad */
736 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); 732 psmouse_activate(psmouse);
737 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
738 psmouse_dbg(psmouse, "Touchpad powered up.\n"); 733 psmouse_dbg(psmouse, "Touchpad powered up.\n");
739 } else { 734 } else {
740 psmouse_dbg(psmouse, "Powering off touchpad.\n"); 735 psmouse_dbg(psmouse, "Powering off touchpad.\n");
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index de7e8bc17b1f..22fe2547e169 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -60,7 +60,7 @@ static unsigned int psmouse_rate = 100;
60module_param_named(rate, psmouse_rate, uint, 0644); 60module_param_named(rate, psmouse_rate, uint, 0644);
61MODULE_PARM_DESC(rate, "Report rate, in reports per second."); 61MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
62 62
63static unsigned int psmouse_smartscroll = 1; 63static bool psmouse_smartscroll = 1;
64module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); 64module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
65MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); 65MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
66 66
@@ -1092,28 +1092,33 @@ static void psmouse_initialize(struct psmouse *psmouse)
1092 * psmouse_activate() enables the mouse so that we get motion reports from it. 1092 * psmouse_activate() enables the mouse so that we get motion reports from it.
1093 */ 1093 */
1094 1094
1095static void psmouse_activate(struct psmouse *psmouse) 1095int psmouse_activate(struct psmouse *psmouse)
1096{ 1096{
1097 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) 1097 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
1098 psmouse_warn(psmouse, "Failed to enable mouse on %s\n", 1098 psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
1099 psmouse->ps2dev.serio->phys); 1099 psmouse->ps2dev.serio->phys);
1100 return -1;
1101 }
1100 1102
1101 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); 1103 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
1104 return 0;
1102} 1105}
1103 1106
1104
1105/* 1107/*
1106 * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion 1108 * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
1107 * reports from it unless we explicitly request it. 1109 * reports from it unless we explicitly request it.
1108 */ 1110 */
1109 1111
1110static void psmouse_deactivate(struct psmouse *psmouse) 1112int psmouse_deactivate(struct psmouse *psmouse)
1111{ 1113{
1112 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) 1114 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
1113 psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", 1115 psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
1114 psmouse->ps2dev.serio->phys); 1116 psmouse->ps2dev.serio->phys);
1117 return -1;
1118 }
1115 1119
1116 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); 1120 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1121 return 0;
1117} 1122}
1118 1123
1119 1124
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 6a417092d010..fe1df231ba4c 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -105,6 +105,8 @@ int psmouse_reset(struct psmouse *psmouse);
105void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); 105void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
106void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); 106void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
107psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); 107psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
108int psmouse_activate(struct psmouse *psmouse);
109int psmouse_deactivate(struct psmouse *psmouse);
108 110
109struct psmouse_attribute { 111struct psmouse_attribute {
110 struct device_attribute dattr; 112 struct device_attribute dattr;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index e36847de7617..2a77a52d2e62 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -90,8 +90,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
90 * to do that for writes because sysfs set helper does this for 90 * to do that for writes because sysfs set helper does this for
91 * us. 91 * us.
92 */ 92 */
93 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); 93 psmouse_deactivate(psmouse);
94 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
95 94
96 ps2_begin_command(ps2dev); 95 ps2_begin_command(ps2dev);
97 96
@@ -128,8 +127,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
128 127
129 out: 128 out:
130 ps2_end_command(ps2dev); 129 ps2_end_command(ps2dev);
131 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); 130 psmouse_activate(psmouse);
132 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
133 dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", 131 dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
134 reg_addr, *reg_val, rc); 132 reg_addr, *reg_val, rc);
135 return rc; 133 return rc;
@@ -213,8 +211,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
213 unsigned char param[3]; 211 unsigned char param[3];
214 int rc = -1; 212 int rc = -1;
215 213
216 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); 214 psmouse_deactivate(psmouse);
217 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
218 215
219 ps2_begin_command(ps2dev); 216 ps2_begin_command(ps2dev);
220 217
@@ -239,8 +236,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
239 236
240 out: 237 out:
241 ps2_end_command(ps2dev); 238 ps2_end_command(ps2dev);
242 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); 239 psmouse_activate(psmouse);
243 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
244 dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", 240 dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
245 *reg_val, rc); 241 *reg_val, rc);
246 return rc; 242 return rc;
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 4b755cb5b38c..f14675702c0f 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -185,17 +185,17 @@
185#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) 185#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
186 186
187/* Control touchpad's No Deceleration option */ 187/* Control touchpad's No Deceleration option */
188static int no_decel = 1; 188static bool no_decel = 1;
189module_param(no_decel, bool, 0644); 189module_param(no_decel, bool, 0644);
190MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); 190MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
191 191
192/* Control touchpad's Reduced Reporting option */ 192/* Control touchpad's Reduced Reporting option */
193static int reduce_report; 193static bool reduce_report;
194module_param(reduce_report, bool, 0644); 194module_param(reduce_report, bool, 0644);
195MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); 195MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)");
196 196
197/* Control touchpad's No Filter option */ 197/* Control touchpad's No Filter option */
198static int no_filter; 198static bool no_filter;
199module_param(no_filter, bool, 0644); 199module_param(no_filter, bool, 0644);
200MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); 200MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
201 201
@@ -672,18 +672,7 @@ static struct i2c_driver synaptics_i2c_driver = {
672 .id_table = synaptics_i2c_id_table, 672 .id_table = synaptics_i2c_id_table,
673}; 673};
674 674
675static int __init synaptics_i2c_init(void) 675module_i2c_driver(synaptics_i2c_driver);
676{
677 return i2c_add_driver(&synaptics_i2c_driver);
678}
679
680static void __exit synaptics_i2c_exit(void)
681{
682 i2c_del_driver(&synaptics_i2c_driver);
683}
684
685module_init(synaptics_i2c_init);
686module_exit(synaptics_i2c_exit);
687 676
688MODULE_DESCRIPTION("Synaptics I2C touchpad driver"); 677MODULE_DESCRIPTION("Synaptics I2C touchpad driver");
689MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab"); 678MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab");
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
new file mode 100644
index 000000000000..3c5eaaa5d154
--- /dev/null
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -0,0 +1,557 @@
1/*
2 * USB Synaptics device driver
3 *
4 * Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk)
5 * Copyright (c) 2003 Ron Lee (ron@debian.org)
6 * cPad driver for kernel 2.4
7 *
8 * Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de)
9 * Copyright (c) 2004 Ron Lee (ron@debian.org)
10 * rewritten for kernel 2.6
11 *
12 * cPad display character device part is not included. It can be found at
13 * http://jan-steinhoff.de/linux/synaptics-usb.html
14 *
15 * Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman
16 * drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
17 * drivers/input/mouse/synaptics.c by Peter Osterlund
18 *
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the Free
21 * Software Foundation; either version 2 of the License, or (at your option)
22 * any later version.
23 *
24 * Trademarks are the property of their respective owners.
25 */
26
27/*
28 * There are three different types of Synaptics USB devices: Touchpads,
29 * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported
30 * by this driver, touchstick support has not been tested much yet, and
31 * touchscreens have not been tested at all.
32 *
33 * Up to three alternate settings are possible:
34 * setting 0: one int endpoint for relative movement (used by usbhid.ko)
35 * setting 1: one int endpoint for absolute finger position
36 * setting 2 (cPad only): one int endpoint for absolute finger position and
37 * two bulk endpoints for the display (in/out)
38 * This driver uses setting 1.
39 */
40
41#include <linux/kernel.h>
42#include <linux/init.h>
43#include <linux/slab.h>
44#include <linux/module.h>
45#include <linux/moduleparam.h>
46#include <linux/usb.h>
47#include <linux/input.h>
48#include <linux/usb/input.h>
49
50#define USB_VENDOR_ID_SYNAPTICS 0x06cb
51#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 /* Synaptics USB TouchPad */
52#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 /* Integrated USB TouchPad */
53#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 /* Synaptics cPad */
54#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 /* Synaptics TouchScreen */
55#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 /* Synaptics USB Styk */
56#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 /* Synaptics USB WheelPad */
57#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 /* Composite USB TouchPad */
58#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 /* Wireless TouchPad */
59#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 /* DisplayPad */
60
61#define SYNUSB_TOUCHPAD (1 << 0)
62#define SYNUSB_STICK (1 << 1)
63#define SYNUSB_TOUCHSCREEN (1 << 2)
64#define SYNUSB_AUXDISPLAY (1 << 3) /* For cPad */
65#define SYNUSB_COMBO (1 << 4) /* Composite device (TP + stick) */
66#define SYNUSB_IO_ALWAYS (1 << 5)
67
68#define USB_DEVICE_SYNAPTICS(prod, kind) \
69 USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \
70 USB_DEVICE_ID_SYNAPTICS_##prod), \
71 .driver_info = (kind),
72
73#define SYNUSB_RECV_SIZE 8
74
75#define XMIN_NOMINAL 1472
76#define XMAX_NOMINAL 5472
77#define YMIN_NOMINAL 1408
78#define YMAX_NOMINAL 4448
79
80struct synusb {
81 struct usb_device *udev;
82 struct usb_interface *intf;
83 struct urb *urb;
84 unsigned char *data;
85
86 /* input device related data structures */
87 struct input_dev *input;
88 char name[128];
89 char phys[64];
90
91 /* characteristics of the device */
92 unsigned long flags;
93};
94
95static void synusb_report_buttons(struct synusb *synusb)
96{
97 struct input_dev *input_dev = synusb->input;
98
99 input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04);
100 input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01);
101 input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02);
102}
103
104static void synusb_report_stick(struct synusb *synusb)
105{
106 struct input_dev *input_dev = synusb->input;
107 int x, y;
108 unsigned int pressure;
109
110 pressure = synusb->data[6];
111 x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7;
112 y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7;
113
114 if (pressure > 0) {
115 input_report_rel(input_dev, REL_X, x);
116 input_report_rel(input_dev, REL_Y, -y);
117 }
118
119 input_report_abs(input_dev, ABS_PRESSURE, pressure);
120
121 synusb_report_buttons(synusb);
122
123 input_sync(input_dev);
124}
125
126static void synusb_report_touchpad(struct synusb *synusb)
127{
128 struct input_dev *input_dev = synusb->input;
129 unsigned int num_fingers, tool_width;
130 unsigned int x, y;
131 unsigned int pressure, w;
132
133 pressure = synusb->data[6];
134 x = be16_to_cpup((__be16 *)&synusb->data[2]);
135 y = be16_to_cpup((__be16 *)&synusb->data[4]);
136 w = synusb->data[0] & 0x0f;
137
138 if (pressure > 0) {
139 num_fingers = 1;
140 tool_width = 5;
141 switch (w) {
142 case 0 ... 1:
143 num_fingers = 2 + w;
144 break;
145
146 case 2: /* pen, pretend its a finger */
147 break;
148
149 case 4 ... 15:
150 tool_width = w;
151 break;
152 }
153 } else {
154 num_fingers = 0;
155 tool_width = 0;
156 }
157
158 /*
159 * Post events
160 * BTN_TOUCH has to be first as mousedev relies on it when doing
161 * absolute -> relative conversion
162 */
163
164 if (pressure > 30)
165 input_report_key(input_dev, BTN_TOUCH, 1);
166 if (pressure < 25)
167 input_report_key(input_dev, BTN_TOUCH, 0);
168
169 if (num_fingers > 0) {
170 input_report_abs(input_dev, ABS_X, x);
171 input_report_abs(input_dev, ABS_Y,
172 YMAX_NOMINAL + YMIN_NOMINAL - y);
173 }
174
175 input_report_abs(input_dev, ABS_PRESSURE, pressure);
176 input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width);
177
178 input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1);
179 input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
180 input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
181
182 synusb_report_buttons(synusb);
183 if (synusb->flags & SYNUSB_AUXDISPLAY)
184 input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08);
185
186 input_sync(input_dev);
187}
188
189static void synusb_irq(struct urb *urb)
190{
191 struct synusb *synusb = urb->context;
192 int error;
193
194 /* Check our status in case we need to bail out early. */
195 switch (urb->status) {
196 case 0:
197 usb_mark_last_busy(synusb->udev);
198 break;
199
200 /* Device went away so don't keep trying to read from it. */
201 case -ECONNRESET:
202 case -ENOENT:
203 case -ESHUTDOWN:
204 return;
205
206 default:
207 goto resubmit;
208 break;
209 }
210
211 if (synusb->flags & SYNUSB_STICK)
212 synusb_report_stick(synusb);
213 else
214 synusb_report_touchpad(synusb);
215
216resubmit:
217 error = usb_submit_urb(urb, GFP_ATOMIC);
218 if (error && error != -EPERM)
219 dev_err(&synusb->intf->dev,
220 "%s - usb_submit_urb failed with result: %d",
221 __func__, error);
222}
223
224static struct usb_endpoint_descriptor *
225synusb_get_in_endpoint(struct usb_host_interface *iface)
226{
227
228 struct usb_endpoint_descriptor *endpoint;
229 int i;
230
231 for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
232 endpoint = &iface->endpoint[i].desc;
233
234 if (usb_endpoint_is_int_in(endpoint)) {
235 /* we found our interrupt in endpoint */
236 return endpoint;
237 }
238 }
239
240 return NULL;
241}
242
243static int synusb_open(struct input_dev *dev)
244{
245 struct synusb *synusb = input_get_drvdata(dev);
246 int retval;
247
248 retval = usb_autopm_get_interface(synusb->intf);
249 if (retval) {
250 dev_err(&synusb->intf->dev,
251 "%s - usb_autopm_get_interface failed, error: %d\n",
252 __func__, retval);
253 return retval;
254 }
255
256 retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
257 if (retval) {
258 dev_err(&synusb->intf->dev,
259 "%s - usb_submit_urb failed, error: %d\n",
260 __func__, retval);
261 retval = -EIO;
262 goto out;
263 }
264
265 synusb->intf->needs_remote_wakeup = 1;
266
267out:
268 usb_autopm_put_interface(synusb->intf);
269 return retval;
270}
271
272static void synusb_close(struct input_dev *dev)
273{
274 struct synusb *synusb = input_get_drvdata(dev);
275 int autopm_error;
276
277 autopm_error = usb_autopm_get_interface(synusb->intf);
278
279 usb_kill_urb(synusb->urb);
280 synusb->intf->needs_remote_wakeup = 0;
281
282 if (!autopm_error)
283 usb_autopm_put_interface(synusb->intf);
284}
285
286static int synusb_probe(struct usb_interface *intf,
287 const struct usb_device_id *id)
288{
289 struct usb_device *udev = interface_to_usbdev(intf);
290 struct usb_endpoint_descriptor *ep;
291 struct synusb *synusb;
292 struct input_dev *input_dev;
293 unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber;
294 unsigned int altsetting = min(intf->num_altsetting, 1U);
295 int error;
296
297 error = usb_set_interface(udev, intf_num, altsetting);
298 if (error) {
299 dev_err(&udev->dev,
300 "Can not set alternate setting to %i, error: %i",
301 altsetting, error);
302 return error;
303 }
304
305 ep = synusb_get_in_endpoint(intf->cur_altsetting);
306 if (!ep)
307 return -ENODEV;
308
309 synusb = kzalloc(sizeof(*synusb), GFP_KERNEL);
310 input_dev = input_allocate_device();
311 if (!synusb || !input_dev) {
312 error = -ENOMEM;
313 goto err_free_mem;
314 }
315
316 synusb->udev = udev;
317 synusb->intf = intf;
318 synusb->input = input_dev;
319
320 synusb->flags = id->driver_info;
321 if (synusb->flags & SYNUSB_COMBO) {
322 /*
323 * This is a combo device, we need to set proper
324 * capability, depending on the interface.
325 */
326 synusb->flags |= intf_num == 1 ?
327 SYNUSB_STICK : SYNUSB_TOUCHPAD;
328 }
329
330 synusb->urb = usb_alloc_urb(0, GFP_KERNEL);
331 if (!synusb->urb) {
332 error = -ENOMEM;
333 goto err_free_mem;
334 }
335
336 synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL,
337 &synusb->urb->transfer_dma);
338 if (!synusb->data) {
339 error = -ENOMEM;
340 goto err_free_urb;
341 }
342
343 usb_fill_int_urb(synusb->urb, udev,
344 usb_rcvintpipe(udev, ep->bEndpointAddress),
345 synusb->data, SYNUSB_RECV_SIZE,
346 synusb_irq, synusb,
347 ep->bInterval);
348 synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
349
350 if (udev->manufacturer)
351 strlcpy(synusb->name, udev->manufacturer,
352 sizeof(synusb->name));
353
354 if (udev->product) {
355 if (udev->manufacturer)
356 strlcat(synusb->name, " ", sizeof(synusb->name));
357 strlcat(synusb->name, udev->product, sizeof(synusb->name));
358 }
359
360 if (!strlen(synusb->name))
361 snprintf(synusb->name, sizeof(synusb->name),
362 "USB Synaptics Device %04x:%04x",
363 le16_to_cpu(udev->descriptor.idVendor),
364 le16_to_cpu(udev->descriptor.idProduct));
365
366 if (synusb->flags & SYNUSB_STICK)
367 strlcat(synusb->name, " (Stick) ", sizeof(synusb->name));
368
369 usb_make_path(udev, synusb->phys, sizeof(synusb->phys));
370 strlcat(synusb->phys, "/input0", sizeof(synusb->phys));
371
372 input_dev->name = synusb->name;
373 input_dev->phys = synusb->phys;
374 usb_to_input_id(udev, &input_dev->id);
375 input_dev->dev.parent = &synusb->intf->dev;
376
377 if (!(synusb->flags & SYNUSB_IO_ALWAYS)) {
378 input_dev->open = synusb_open;
379 input_dev->close = synusb_close;
380 }
381
382 input_set_drvdata(input_dev, synusb);
383
384 __set_bit(EV_ABS, input_dev->evbit);
385 __set_bit(EV_KEY, input_dev->evbit);
386
387 if (synusb->flags & SYNUSB_STICK) {
388 __set_bit(EV_REL, input_dev->evbit);
389 __set_bit(REL_X, input_dev->relbit);
390 __set_bit(REL_Y, input_dev->relbit);
391 input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
392 } else {
393 input_set_abs_params(input_dev, ABS_X,
394 XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
395 input_set_abs_params(input_dev, ABS_Y,
396 YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
397 input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
398 input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
399 __set_bit(BTN_TOUCH, input_dev->keybit);
400 __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
401 __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
402 __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
403 }
404
405 __set_bit(BTN_LEFT, input_dev->keybit);
406 __set_bit(BTN_RIGHT, input_dev->keybit);
407 __set_bit(BTN_MIDDLE, input_dev->keybit);
408
409 usb_set_intfdata(intf, synusb);
410
411 if (synusb->flags & SYNUSB_IO_ALWAYS) {
412 error = synusb_open(input_dev);
413 if (error)
414 goto err_free_dma;
415 }
416
417 error = input_register_device(input_dev);
418 if (error) {
419 dev_err(&udev->dev,
420 "Failed to register input device, error %d\n",
421 error);
422 goto err_stop_io;
423 }
424
425 return 0;
426
427err_stop_io:
428 if (synusb->flags & SYNUSB_IO_ALWAYS)
429 synusb_close(synusb->input);
430err_free_dma:
431 usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
432 synusb->urb->transfer_dma);
433err_free_urb:
434 usb_free_urb(synusb->urb);
435err_free_mem:
436 input_free_device(input_dev);
437 kfree(synusb);
438 usb_set_intfdata(intf, NULL);
439
440 return error;
441}
442
443static void synusb_disconnect(struct usb_interface *intf)
444{
445 struct synusb *synusb = usb_get_intfdata(intf);
446 struct usb_device *udev = interface_to_usbdev(intf);
447
448 if (synusb->flags & SYNUSB_IO_ALWAYS)
449 synusb_close(synusb->input);
450
451 input_unregister_device(synusb->input);
452
453 usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
454 synusb->urb->transfer_dma);
455 usb_free_urb(synusb->urb);
456 kfree(synusb);
457
458 usb_set_intfdata(intf, NULL);
459}
460
461static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
462{
463 struct synusb *synusb = usb_get_intfdata(intf);
464 struct input_dev *input_dev = synusb->input;
465
466 mutex_lock(&input_dev->mutex);
467 usb_kill_urb(synusb->urb);
468 mutex_unlock(&input_dev->mutex);
469
470 return 0;
471}
472
473static int synusb_resume(struct usb_interface *intf)
474{
475 struct synusb *synusb = usb_get_intfdata(intf);
476 struct input_dev *input_dev = synusb->input;
477 int retval = 0;
478
479 mutex_lock(&input_dev->mutex);
480
481 if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
482 usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
483 retval = -EIO;
484 }
485
486 mutex_unlock(&input_dev->mutex);
487
488 return retval;
489}
490
491static int synusb_pre_reset(struct usb_interface *intf)
492{
493 struct synusb *synusb = usb_get_intfdata(intf);
494 struct input_dev *input_dev = synusb->input;
495
496 mutex_lock(&input_dev->mutex);
497 usb_kill_urb(synusb->urb);
498
499 return 0;
500}
501
502static int synusb_post_reset(struct usb_interface *intf)
503{
504 struct synusb *synusb = usb_get_intfdata(intf);
505 struct input_dev *input_dev = synusb->input;
506 int retval = 0;
507
508 if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
509 usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
510 retval = -EIO;
511 }
512
513 mutex_unlock(&input_dev->mutex);
514
515 return retval;
516}
517
518static int synusb_reset_resume(struct usb_interface *intf)
519{
520 return synusb_resume(intf);
521}
522
523static struct usb_device_id synusb_idtable[] = {
524 { USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) },
525 { USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) },
526 { USB_DEVICE_SYNAPTICS(CPAD,
527 SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) },
528 { USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) },
529 { USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) },
530 { USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) },
531 { USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) },
532 { USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) },
533 { USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) },
534 { }
535};
536MODULE_DEVICE_TABLE(usb, synusb_idtable);
537
538static struct usb_driver synusb_driver = {
539 .name = "synaptics_usb",
540 .probe = synusb_probe,
541 .disconnect = synusb_disconnect,
542 .id_table = synusb_idtable,
543 .suspend = synusb_suspend,
544 .resume = synusb_resume,
545 .pre_reset = synusb_pre_reset,
546 .post_reset = synusb_post_reset,
547 .reset_resume = synusb_reset_resume,
548 .supports_autosuspend = 1,
549};
550
551module_usb_driver(synusb_driver);
552
553MODULE_AUTHOR("Rob Miller <rob@inpharmatica.co.uk>, "
554 "Ron Lee <ron@debian.org>, "
555 "Jan Steinhoff <cpad@jan-steinhoff.de>");
556MODULE_DESCRIPTION("Synaptics USB device driver");
557MODULE_LICENSE("GPL");