aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/mouse
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/Kconfig4
-rw-r--r--drivers/input/mouse/alps.c422
-rw-r--r--drivers/input/mouse/alps.h8
-rw-r--r--drivers/input/mouse/appletouch.c144
-rw-r--r--drivers/input/mouse/bcm5974.c1
-rw-r--r--drivers/input/mouse/cypress_ps2.c31
-rw-r--r--drivers/input/mouse/elantech.c94
-rw-r--r--drivers/input/mouse/elantech.h1
-rw-r--r--drivers/input/mouse/gpio_mouse.c3
-rw-r--r--drivers/input/mouse/logips2pp.c2
-rw-r--r--drivers/input/mouse/navpoint.c1
-rw-r--r--drivers/input/mouse/pxa930_trkball.c3
-rw-r--r--drivers/input/mouse/sermouse.c1
-rw-r--r--drivers/input/mouse/synaptics.c96
-rw-r--r--drivers/input/mouse/synaptics_usb.c1
-rw-r--r--drivers/input/mouse/vsxxxaa.c1
16 files changed, 687 insertions, 126 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index effa9c5f2c5..366fc7ad5eb 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -17,7 +17,7 @@ config MOUSE_PS2
default y
select SERIO
select SERIO_LIBPS2
- select SERIO_I8042 if X86
+ select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO
select SERIO_GSCPS2 if GSC
help
Say Y here if you have a PS/2 mouse connected to your system. This
@@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP
default y
depends on MOUSE_PS2
help
- Say Y here if you have a Logictech PS/2++ mouse connected to
+ Say Y here if you have a Logitech PS/2++ mouse connected to
your system.
If unsure, say Y.
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7c5d72a6a26..fb15c64ffb9 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
{ PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
};
+static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
+ { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */
+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */
+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */
+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */
+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */
+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */
+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */
+ { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */
+ { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */
+ { PSMOUSE_CMD_SETRES, 0x00 }, /* a */
+ { PSMOUSE_CMD_SETRES, 0x01 }, /* b */
+ { PSMOUSE_CMD_SETRES, 0x02 }, /* c */
+ { PSMOUSE_CMD_SETRES, 0x03 }, /* d */
+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */
+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
+};
+
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
@@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = {
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
+ { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */
{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
@@ -257,6 +277,57 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
}
/*
+ * Process bitmap data for V5 protocols. Return value is null.
+ *
+ * The bitmaps don't have enough data to track fingers, so this function
+ * only generates points representing a bounding box of at most two contacts.
+ * These two points are returned in x1, y1, x2, and y2.
+ */
+static void alps_process_bitmap_dolphin(struct alps_data *priv,
+ struct alps_fields *fields,
+ int *x1, int *y1, int *x2, int *y2)
+{
+ int box_middle_x, box_middle_y;
+ unsigned int x_map, y_map;
+ unsigned char start_bit, end_bit;
+ unsigned char x_msb, x_lsb, y_msb, y_lsb;
+
+ x_map = fields->x_map;
+ y_map = fields->y_map;
+
+ if (!x_map || !y_map)
+ return;
+
+ /* Get Most-significant and Least-significant bit */
+ x_msb = fls(x_map);
+ x_lsb = ffs(x_map);
+ y_msb = fls(y_map);
+ y_lsb = ffs(y_map);
+
+ /* Most-significant bit should never exceed max sensor line number */
+ if (x_msb > priv->x_bits || y_msb > priv->y_bits)
+ return;
+
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ if (fields->fingers > 1) {
+ start_bit = priv->x_bits - x_msb;
+ end_bit = priv->x_bits - x_lsb;
+ box_middle_x = (priv->x_max * (start_bit + end_bit)) /
+ (2 * (priv->x_bits - 1));
+
+ start_bit = y_lsb - 1;
+ end_bit = y_msb - 1;
+ box_middle_y = (priv->y_max * (start_bit + end_bit)) /
+ (2 * (priv->y_bits - 1));
+ *x1 = fields->x;
+ *y1 = fields->y;
+ *x2 = 2 * box_middle_x - *x1;
+ *y2 = 2 * box_middle_y - *y1;
+ }
+}
+
+/*
* Process bitmap data from v3 and v4 protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
@@ -461,7 +532,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
f->ts_middle = !!(p[3] & 0x40);
}
-static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[0] & 0x40);
@@ -482,48 +554,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
alps_decode_buttons_v3(f, p);
}
-static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
- alps_decode_pinnacle(f, p);
+ alps_decode_pinnacle(f, p, psmouse);
f->x_map |= (p[5] & 0x10) << 11;
f->y_map |= (p[5] & 0x20) << 6;
}
-static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
+ u64 palm_data = 0;
+ struct alps_data *priv = psmouse->private;
+
f->first_mp = !!(p[0] & 0x02);
f->is_mp = !!(p[0] & 0x20);
- f->fingers = ((p[0] & 0x6) >> 1 |
+ if (!f->is_mp) {
+ f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+ f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+ f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
+ alps_decode_buttons_v3(f, p);
+ } else {
+ f->fingers = ((p[0] & 0x6) >> 1 |
(p[0] & 0x10) >> 2);
- f->x_map = ((p[2] & 0x60) >> 5) |
- ((p[4] & 0x7f) << 2) |
- ((p[5] & 0x7f) << 9) |
- ((p[3] & 0x07) << 16) |
- ((p[3] & 0x70) << 15) |
- ((p[0] & 0x01) << 22);
- f->y_map = (p[1] & 0x7f) |
- ((p[2] & 0x1f) << 7);
-
- f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
- f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
- f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
+ palm_data = (p[1] & 0x7f) |
+ ((p[2] & 0x7f) << 7) |
+ ((p[4] & 0x7f) << 14) |
+ ((p[5] & 0x7f) << 21) |
+ ((p[3] & 0x07) << 28) |
+ (((u64)p[3] & 0x70) << 27) |
+ (((u64)p[0] & 0x01) << 34);
+
+ /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
+ f->y_map = palm_data & (BIT(priv->y_bits) - 1);
+
+ /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
+ f->x_map = (palm_data >> priv->y_bits) &
+ (BIT(priv->x_bits) - 1);
+ }
}
-static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- int fingers = 0, bmap_fingers;
- struct alps_fields f;
+ int fingers = 0, bmap_fn;
+ struct alps_fields f = {0};
- priv->decode_fields(&f, packet);
+ priv->decode_fields(&f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -540,19 +625,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
*/
if (f.is_mp) {
fingers = f.fingers;
- bmap_fingers = alps_process_bitmap(priv,
- f.x_map, f.y_map,
- &x1, &y1, &x2, &y2);
-
- /*
- * We shouldn't report more than one finger if
- * we don't have two coordinates.
- */
- if (fingers > 1 && bmap_fingers < 2)
- fingers = bmap_fingers;
-
- /* Now process position packet */
- priv->decode_fields(&f, priv->multi_data);
+ if (priv->proto_version == ALPS_PROTO_V3) {
+ bmap_fn = alps_process_bitmap(priv, f.x_map,
+ f.y_map, &x1, &y1,
+ &x2, &y2);
+
+ /*
+ * We shouldn't report more than one finger if
+ * we don't have two coordinates.
+ */
+ if (fingers > 1 && bmap_fn < 2)
+ fingers = bmap_fn;
+
+ /* Now process position packet */
+ priv->decode_fields(&f, priv->multi_data,
+ psmouse);
+ } else {
+ /*
+ * Because Dolphin uses position packet's
+ * coordinate data as Pt1 and uses it to
+ * calculate Pt2, so we need to do position
+ * packet decode first.
+ */
+ priv->decode_fields(&f, priv->multi_data,
+ psmouse);
+
+ /*
+ * Since Dolphin's finger number is reliable,
+ * there is no need to compare with bmap_fn.
+ */
+ alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+ &x2, &y2);
+ }
} else {
priv->multi_packet = 0;
}
@@ -642,7 +746,77 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
return;
}
- alps_process_touchpad_packet_v3(psmouse);
+ alps_process_touchpad_packet_v3_v5(psmouse);
+}
+
+static void alps_process_packet_v6(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
+ int x, y, z, left, right, middle;
+
+ /*
+ * We can use Byte5 to distinguish if the packet is from Touchpad
+ * or Trackpoint.
+ * Touchpad: 0 - 0x7E
+ * Trackpoint: 0x7F
+ */
+ if (packet[5] == 0x7F) {
+ /* It should be a DualPoint when received Trackpoint packet */
+ if (!(priv->flags & ALPS_DUALPOINT))
+ return;
+
+ /* Trackpoint packet */
+ x = packet[1] | ((packet[3] & 0x20) << 2);
+ y = packet[2] | ((packet[3] & 0x40) << 1);
+ z = packet[4];
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+ middle = packet[3] & 0x04;
+
+ /* To prevent the cursor jump when finger lifted */
+ if (x == 0x7F && y == 0x7F && z == 0x7F)
+ x = y = z = 0;
+
+ /* Divide 4 since trackpoint's speed is too fast */
+ input_report_rel(dev2, REL_X, (char)x / 4);
+ input_report_rel(dev2, REL_Y, -((char)y / 4));
+
+ input_report_key(dev2, BTN_LEFT, left);
+ input_report_key(dev2, BTN_RIGHT, right);
+ input_report_key(dev2, BTN_MIDDLE, middle);
+
+ input_sync(dev2);
+ return;
+ }
+
+ /* Touchpad packet */
+ x = packet[1] | ((packet[3] & 0x78) << 4);
+ y = packet[2] | ((packet[4] & 0x78) << 4);
+ z = packet[5];
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+
+ if (z > 30)
+ input_report_key(dev, BTN_TOUCH, 1);
+ if (z < 25)
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+
+ input_report_abs(dev, ABS_PRESSURE, z);
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+
+ /* v6 touchpad does not have middle button */
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+
+ input_sync(dev);
}
static void alps_process_packet_v4(struct psmouse *psmouse)
@@ -897,7 +1071,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
}
/* Bytes 2 - pktsize should have 0 in the highest bit */
- if (priv->proto_version != ALPS_PROTO_V5 &&
+ if ((priv->proto_version < ALPS_PROTO_V5) &&
psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
@@ -1085,6 +1259,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
}
+static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word)
+{
+ int i, nibble;
+
+ /*
+ * b0-b11 are valid bits, send sequence is inverse.
+ * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1
+ */
+ for (i = 0; i <= 8; i += 4) {
+ nibble = (word >> i) & 0xf;
+ if (alps_command_mode_send_nibble(psmouse, nibble))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int alps_monitor_mode_write_reg(struct psmouse *psmouse,
+ u16 addr, u16 value)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ /* 0x0A0 is the command to write the word */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) ||
+ alps_monitor_mode_send_word(psmouse, 0x0A0) ||
+ alps_monitor_mode_send_word(psmouse, addr) ||
+ alps_monitor_mode_send_word(psmouse, value) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ return -1;
+
+ return 0;
+}
+
+static int alps_monitor_mode(struct psmouse *psmouse, bool enable)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ if (enable) {
+ /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO))
+ return -1;
+ } else {
+ /* EC to exit monitor mode */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int alps_absolute_mode_v6(struct psmouse *psmouse)
+{
+ u16 reg_val = 0x181;
+ int ret = -1;
+
+ /* enter monitor mode, to write the register */
+ if (alps_monitor_mode(psmouse, true))
+ return -1;
+
+ ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val);
+
+ if (alps_monitor_mode(psmouse, false))
+ ret = -1;
+
+ return ret;
+}
+
static int alps_get_status(struct psmouse *psmouse, char *param)
{
/* Get status: 0xF5 0xF5 0xF5 0xE9 */
@@ -1189,6 +1437,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
return 0;
}
+static int alps_hw_init_v6(struct psmouse *psmouse)
+{
+ unsigned char param[2] = {0xC8, 0x14};
+
+ /* Enter passthrough mode to let trackpoint enter 6byte raw mode */
+ if (alps_passthrough_mode_v2(psmouse, true))
+ return -1;
+
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(&psmouse->ps2dev, &param[1], PSMOUSE_CMD_SETRATE))
+ return -1;
+
+ if (alps_passthrough_mode_v2(psmouse, false))
+ return -1;
+
+ if (alps_absolute_mode_v6(psmouse)) {
+ psmouse_err(psmouse, "Failed to enable absolute mode\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Enable or disable passthrough mode to the trackstick.
*/
@@ -1519,6 +1793,52 @@ error:
return -1;
}
+static int alps_dolphin_get_device_area(struct psmouse *psmouse,
+ struct alps_data *priv)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4] = {0};
+ int num_x_electrode, num_y_electrode;
+
+ if (alps_enter_command_mode(psmouse))
+ return -1;
+
+ param[0] = 0x0a;
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
+ ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE))
+ return -1;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ /*
+ * Dolphin's sensor line number is not fixed. It can be calculated
+ * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
+ * Further more, we can get device's x_max and y_max by multiplying
+ * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
+ *
+ * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
+ * real sensor line number X = 11 + 8 = 19, and
+ * real sensor line number Y = 8 + 1 = 9.
+ * So, x_max = (19 - 1) * 64 = 1152, and
+ * y_max = (9 - 1) * 64 = 512.
+ */
+ num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
+ num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
+ priv->x_bits = num_x_electrode;
+ priv->y_bits = num_y_electrode;
+ priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+ priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+
+ if (alps_exit_command_mode(psmouse))
+ return -1;
+
+ return 0;
+}
+
static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -1553,6 +1873,8 @@ static void alps_set_defaults(struct alps_data *priv)
priv->hw_init = alps_hw_init_v1_v2;
priv->process_packet = alps_process_packet_v1_v2;
priv->set_abs_params = alps_set_abs_params_st;
+ priv->x_max = 1023;
+ priv->y_max = 767;
break;
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
@@ -1571,19 +1893,27 @@ static void alps_set_defaults(struct alps_data *priv)
break;
case ALPS_PROTO_V5:
priv->hw_init = alps_hw_init_dolphin_v1;
- priv->process_packet = alps_process_packet_v3;
+ priv->process_packet = alps_process_touchpad_packet_v3_v5;
priv->decode_fields = alps_decode_dolphin;
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
priv->byte0 = 0xc8;
- priv->mask0 = 0xc8;
+ priv->mask0 = 0xd8;
priv->flags = 0;
priv->x_max = 1360;
priv->y_max = 660;
priv->x_bits = 23;
priv->y_bits = 12;
break;
+ case ALPS_PROTO_V6:
+ priv->hw_init = alps_hw_init_v6;
+ priv->process_packet = alps_process_packet_v6;
+ priv->set_abs_params = alps_set_abs_params_st;
+ priv->nibble_commands = alps_v6_nibble_commands;
+ priv->x_max = 2047;
+ priv->y_max = 1535;
+ break;
}
}
@@ -1645,11 +1975,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
if (alps_match_table(psmouse, priv, e7, ec) == 0) {
return 0;
} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
- ec[0] == 0x73 && ec[1] == 0x01) {
+ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
priv->proto_version = ALPS_PROTO_V5;
alps_set_defaults(priv);
-
- return 0;
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
+ else
+ return 0;
} else if (ec[0] == 0x88 && ec[1] == 0x08) {
priv->proto_version = ALPS_PROTO_V3;
alps_set_defaults(priv);
@@ -1705,8 +2037,8 @@ static void alps_disconnect(struct psmouse *psmouse)
static void alps_set_abs_params_st(struct alps_data *priv,
struct input_dev *dev1)
{
- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+ input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
}
static void alps_set_abs_params_mt(struct alps_data *priv,
@@ -1792,7 +2124,7 @@ int alps_init(struct psmouse *psmouse)
snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = (priv->flags & ALPS_DUALPOINT) ?
- "DualPoint Stick" : "PS/2 Mouse";
+ "DualPoint Stick" : "ALPS PS/2 Device";
dev2->id.bustype = BUS_I8042;
dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index eee59853b9c..03f88b6940c 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -17,6 +17,11 @@
#define ALPS_PROTO_V3 3
#define ALPS_PROTO_V4 4
#define ALPS_PROTO_V5 5
+#define ALPS_PROTO_V6 6
+
+#define DOLPHIN_COUNT_PER_ELECTRODE 64
+#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
+#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
/**
* struct alps_model_info - touchpad ID table
@@ -145,7 +150,8 @@ struct alps_data {
int (*hw_init)(struct psmouse *psmouse);
void (*process_packet)(struct psmouse *psmouse);
- void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+ void (*decode_fields)(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse);
void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
int prev_fin;
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e42f1fa8cdc..ef234c9b2f2 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -30,7 +30,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
@@ -49,6 +48,7 @@ struct atp_info {
int yfact; /* Y multiplication factor */
int datalen; /* size of USB transfers */
void (*callback)(struct urb *); /* callback function */
+ int fuzz; /* fuzz touchpad generates */
};
static void atp_complete_geyser_1_2(struct urb *urb);
@@ -62,6 +62,7 @@ static const struct atp_info fountain_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 16,
};
static const struct atp_info geyser1_info = {
@@ -72,6 +73,7 @@ static const struct atp_info geyser1_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 16,
};
static const struct atp_info geyser2_info = {
@@ -82,6 +84,7 @@ static const struct atp_info geyser2_info = {
.yfact = 43,
.datalen = 64,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 0,
};
static const struct atp_info geyser3_info = {
@@ -91,6 +94,7 @@ static const struct atp_info geyser3_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
+ .fuzz = 0,
};
static const struct atp_info geyser4_info = {
@@ -100,6 +104,7 @@ static const struct atp_info geyser4_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
+ .fuzz = 0,
};
#define ATP_DEVICE(prod, info) \
@@ -156,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);
#define ATP_XSENSORS 26
#define ATP_YSENSORS 16
-/* amount of fuzz this touchpad generates */
-#define ATP_FUZZ 16
+/*
+ * The largest possible bank of sensors with additional buffer of 4 extra values
+ * on either side, for an array of smoothed sensor values.
+ */
+#define ATP_SMOOTHSIZE 34
/* maximum pressure this driver will report */
#define ATP_PRESSURE 300
@@ -166,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);
* Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
* ignored.
*/
-#define ATP_THRESHOLD 5
+#define ATP_THRESHOLD 5
+
+/*
+ * How far we'll bitshift our sensor values before averaging them. Mitigates
+ * rounding errors.
+ */
+#define ATP_SCALE 12
/* Geyser initialization constants */
#define ATP_GEYSER_MODE_READ_REQUEST_ID 1
@@ -204,11 +218,14 @@ struct atp {
bool valid; /* are the samples valid? */
bool size_detect_done;
bool overflow_warned;
+ int fingers_old; /* last reported finger count */
int x_old; /* last reported x/y, */
int y_old; /* used for smoothing */
signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+ int smooth[ATP_SMOOTHSIZE];
+ int smooth_tmp[ATP_SMOOTHSIZE];
int idlecount; /* number of empty packets */
struct work_struct work;
};
@@ -327,10 +344,17 @@ static void atp_reinit(struct work_struct *work)
retval);
}
-static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
- int *z, int *fingers)
+static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors,
+ int fact, int *z, int *fingers)
{
- int i;
+ int i, pass;
+
+ /*
+ * Use offset to point xy_sensors at the first value in dev->xy_acc
+ * for whichever dimension we're looking at this particular go-round.
+ */
+ int *xy_sensors = dev->xy_acc + offset;
+
/* values to calculate mean */
int pcum = 0, psum = 0;
int is_increasing = 0;
@@ -342,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
if (is_increasing)
is_increasing = 0;
- continue;
- }
-
/*
* Makes the finger detection more versatile. For example,
* two fingers with no gap will be detected. Also, my
@@ -359,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
*
* - Jason Parekh <jasonparekh@gmail.com>
*/
- if (i < 1 ||
+
+ } else if (i < 1 ||
(!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
(*fingers)++;
is_increasing = 1;
} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
is_increasing = 0;
}
+ }
+
+ if (*fingers < 1) /* No need to continue if no fingers are found. */
+ return 0;
+ /*
+ * Use a smoothed version of sensor data for movement calculations, to
+ * combat noise without needing to rely so heavily on a threshold.
+ * This improves tracking.
+ *
+ * The smoothed array is bigger than the original so that the smoothing
+ * doesn't result in edge values being truncated.
+ */
+
+ memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0]));
+ /* Pull base values, scaled up to help avoid truncation errors. */
+ for (i = 0; i < nb_sensors; i++)
+ dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE;
+ memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0]));
+
+ for (pass = 0; pass < 4; pass++) {
+ /* Handle edge. */
+ dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2;
+
+ /* Average values with neighbors. */
+ for (i = 1; i < nb_sensors + 7; i++)
+ dev->smooth_tmp[i] = (dev->smooth[i - 1] +
+ dev->smooth[i] * 2 +
+ dev->smooth[i + 1]) / 4;
+
+ /* Handle other edge. */
+ dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2;
+
+ memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth));
+ }
+
+ for (i = 0; i < nb_sensors + 8; i++) {
/*
- * Subtracts threshold so a high sensor that just passes the
- * threshold won't skew the calculated absolute coordinate.
- * Fixes an issue where slowly moving the mouse would
- * occasionally jump a number of pixels (slowly moving the
- * finger makes this issue most apparent.)
+ * Skip values if they're small enough to be truncated to 0
+ * by scale. Mostly noise.
*/
- pcum += (xy_sensors[i] - threshold) * i;
- psum += (xy_sensors[i] - threshold);
+ if ((dev->smooth[i] >> ATP_SCALE) > 0) {
+ pcum += dev->smooth[i] * i;
+ psum += dev->smooth[i];
+ }
}
if (psum > 0) {
- *z = psum;
+ *z = psum >> ATP_SCALE; /* Scale down pressure output. */
return pcum * fact / psum;
}
@@ -456,7 +513,7 @@ static void atp_detect_size(struct atp *dev)
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
dev->info->xfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
break;
}
}
@@ -472,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
- int key;
+ int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@@ -549,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
- x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+ x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
- y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+ y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
- if (x && y) {
+ fingers = max(x_f, y_f);
+
+ if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
- x = (dev->x_old * 3 + x) >> 2;
- y = (dev->y_old * 3 + y) >> 2;
+ x = (dev->x_old * 7 + x) >> 3;
+ y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@@ -572,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
- atp_report_fingers(dev->input, max(x_f, y_f));
+ atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@@ -580,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
+ dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@@ -588,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
+ if (fingers != dev->fingers_old)
+ dev->x_old = dev->y_old = -1;
+ dev->fingers_old = fingers;
+
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@@ -605,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
- int key;
+ int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@@ -661,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
- x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+ x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
- y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+ y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
+
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
- if (x && y) {
+ fingers = max(x_f, y_f);
+
+ if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
- x = (dev->x_old * 3 + x) >> 2;
- y = (dev->y_old * 3 + y) >> 2;
+ x = (dev->x_old * 7 + x) >> 3;
+ y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@@ -684,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
- atp_report_fingers(dev->input, max(x_f, y_f));
+ atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@@ -692,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
+ dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@@ -700,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
+ if (fingers != dev->fingers_old)
+ dev->x_old = dev->y_old = -1;
+ dev->fingers_old = fingers;
+
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@@ -844,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,
input_set_abs_params(input_dev, ABS_X, 0,
(dev->info->xsensors - 1) * dev->info->xfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
(dev->info->ysensors - 1) * dev->info->yfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index a73f9618b0a..c329cdb0b91 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index f51765fff05..8af34ffe208 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -15,7 +15,6 @@
* the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -410,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
__clear_bit(REL_X, input->relbit);
__clear_bit(REL_Y, input->relbit);
- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
@@ -439,7 +437,7 @@ static int cypress_get_finger_count(unsigned char header_byte)
case 2: return 5;
default:
/* Invalid contact (e.g. palm). Ignore it. */
- return -1;
+ return 0;
}
}
@@ -452,17 +450,10 @@ static int cypress_parse_packet(struct psmouse *psmouse,
{
unsigned char *packet = psmouse->packet;
unsigned char header_byte = packet[0];
- int contact_cnt;
memset(report_data, 0, sizeof(struct cytp_report_data));
- contact_cnt = cypress_get_finger_count(header_byte);
-
- if (contact_cnt < 0) /* e.g. palm detect */
- return -EINVAL;
-
- report_data->contact_cnt = contact_cnt;
-
+ report_data->contact_cnt = cypress_get_finger_count(header_byte);
report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
if (report_data->contact_cnt == 1) {
@@ -535,11 +526,9 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
int slots[CYTP_MAX_MT_SLOTS];
int n;
- if (cypress_parse_packet(psmouse, cytp, &report_data))
- return;
+ cypress_parse_packet(psmouse, cytp, &report_data);
n = report_data.contact_cnt;
-
if (n > CYTP_MAX_MT_SLOTS)
n = CYTP_MAX_MT_SLOTS;
@@ -605,10 +594,6 @@ static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
return PSMOUSE_BAD_DATA;
contact_cnt = cypress_get_finger_count(packet[0]);
-
- if (contact_cnt < 0)
- return PSMOUSE_BAD_DATA;
-
if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
else
@@ -679,15 +664,15 @@ int cypress_init(struct psmouse *psmouse)
{
struct cytp_data *cytp;
- cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
- psmouse->private = (void *)cytp;
- if (cytp == NULL)
+ cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
+ if (!cytp)
return -ENOMEM;
- cypress_reset(psmouse);
-
+ psmouse->private = cytp;
psmouse->pktsize = 8;
+ cypress_reset(psmouse);
+
if (cypress_query_hardware(psmouse)) {
psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
goto err_exit;
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 8551dcaf24d..ee2a04d90d2 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -11,6 +11,7 @@
*/
#include <linux/delay.h>
+#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -472,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+ /* For clickpads map both buttons to BTN_LEFT */
+ if (etd->fw_version & 0x001000) {
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
+ } else {
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ }
+
input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width);
@@ -483,9 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
static void elantech_input_sync_v4(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
+ struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet;
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ /* For clickpads map both buttons to BTN_LEFT */
+ if (etd->fw_version & 0x001000) {
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
+ } else {
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ }
+
input_mt_report_pointer_emulation(dev, true);
input_sync(dev);
}
@@ -830,7 +846,11 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
break;
case 3:
- etd->reg_10 = 0x0b;
+ if (etd->set_hw_resolution)
+ etd->reg_10 = 0x0b;
+ else
+ etd->reg_10 = 0x01;
+
if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
rc = -1;
@@ -984,6 +1004,44 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
}
/*
+ * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
+ * fw_version for this is based on the following fw_version & caps table:
+ *
+ * Laptop-model: fw_version: caps: buttons:
+ * Acer S3 0x461f00 10, 13, 0e clickpad
+ * Acer S7-392 0x581f01 50, 17, 0d clickpad
+ * Acer V5-131 0x461f02 01, 16, 0c clickpad
+ * Acer V5-551 0x461f00 ? clickpad
+ * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
+ * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
+ * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
+ * Asus UX31 0x361f00 20, 15, 0e clickpad
+ * Asus UX32VD 0x361f02 00, 15, 0e clickpad
+ * Avatar AVIU-145A2 0x361f00 ? clickpad
+ * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
+ * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
+ * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
+ * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
+ * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
+ * Samsung NP900X3E-A02 0x575f03 ? clickpad
+ * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
+ * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
+ * Samsung RF710 0x450f00 ? 2 hw buttons
+ * System76 Pangolin 0x250f01 ? 2 hw buttons
+ * (*) + 3 trackpoint buttons
+ */
+static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+ struct elantech_data *etd = psmouse->private;
+
+ if (etd->fw_version & 0x001000) {
+ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
+ __clear_bit(BTN_RIGHT, dev->keybit);
+ }
+}
+
+/*
* Set the appropriate event bits for the input subsystem
*/
static int elantech_set_input_params(struct psmouse *psmouse)
@@ -1026,6 +1084,8 @@ static int elantech_set_input_params(struct psmouse *psmouse)
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
/* fall through */
case 3:
+ if (etd->hw_version == 3)
+ elantech_set_buttonpad_prop(psmouse);
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
if (etd->reports_pressure) {
@@ -1047,9 +1107,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
*/
psmouse_warn(psmouse, "couldn't query resolution data.\n");
}
- /* v4 is clickpad, with only one button. */
- __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
- __clear_bit(BTN_RIGHT, dev->keybit);
+ elantech_set_buttonpad_prop(psmouse);
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
/* For X to recognize me as touchpad. */
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
@@ -1292,6 +1350,23 @@ static int elantech_reconnect(struct psmouse *psmouse)
}
/*
+ * Some hw_version 3 models go into error state when we try to set
+ * bit 3 and/or bit 1 of r10.
+ */
+static const struct dmi_system_id no_hw_res_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+ {
+ /* Gigabyte U2442 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "U2442"),
+ },
+ },
+#endif
+ { }
+};
+
+/*
* determine hardware version and set some properties according to it.
*/
static int elantech_set_properties(struct elantech_data *etd)
@@ -1313,6 +1388,8 @@ static int elantech_set_properties(struct elantech_data *etd)
break;
case 6:
case 7:
+ case 8:
+ case 9:
etd->hw_version = 4;
break;
default:
@@ -1349,6 +1426,9 @@ static int elantech_set_properties(struct elantech_data *etd)
*/
etd->crc_enabled = ((etd->fw_version & 0x4000) == 0x4000);
+ /* Enable real hardware resolution on hw_version 3 ? */
+ etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table);
+
return 0;
}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 036a04abaef..9e0e2a1f340 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -130,6 +130,7 @@ struct elantech_data {
bool jumpy_cursor;
bool reports_pressure;
bool crc_enabled;
+ bool set_hw_resolution;
unsigned char hw_version;
unsigned int fw_version;
unsigned int single_finger_reports;
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
index 6b44413f54e..8c7d94200bd 100644
--- a/drivers/input/mouse/gpio_mouse.c
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -8,7 +8,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input-polldev.h>
@@ -48,7 +47,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
static int gpio_mouse_probe(struct platform_device *pdev)
{
- struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_mouse_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct input_polled_dev *input_poll;
struct input_dev *input;
int pin, i;
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 84de2fc6acc..136e222e2a1 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -220,7 +220,7 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
{ 61, PS2PP_KIND_MX, /* MX700 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
- { 66, PS2PP_KIND_MX, /* MX3100 reciver */
+ { 66, PS2PP_KIND_MX, /* MX3100 receiver */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
{ 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index 0b8d33591de..1ccc88af1f0 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c
index 0ecb9e7945e..9b4d9a59e22 100644
--- a/drivers/input/mouse/pxa930_trkball.c
+++ b/drivers/input/mouse/pxa930_trkball.c
@@ -10,7 +10,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -166,7 +165,7 @@ static int pxa930_trkball_probe(struct platform_device *pdev)
if (!trkball)
return -ENOMEM;
- trkball->pdata = pdev->dev.platform_data;
+ trkball->pdata = dev_get_platdata(&pdev->dev);
if (!trkball->pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
error = -EINVAL;
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index d5928fd0c91..8df526620eb 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -32,7 +32,6 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
-#include <linux/init.h>
#define DRIVER_DESC "Serial mouse driver"
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 26386f9d256..ef9e0b8a9aa 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -117,6 +117,82 @@ void synaptics_reset(struct psmouse *psmouse)
}
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+struct min_max_quirk {
+ const char * const *pnp_ids;
+ int x_min, x_max, y_min, y_max;
+};
+
+static const struct min_max_quirk min_max_pnpid_table[] = {
+ {
+ (const char * const []){"LEN0033", NULL},
+ 1024, 5052, 2258, 4832
+ },
+ {
+ (const char * const []){"LEN0035", "LEN0042", NULL},
+ 1232, 5710, 1156, 4696
+ },
+ {
+ (const char * const []){"LEN0034", "LEN0036", "LEN2002",
+ "LEN2004", NULL},
+ 1024, 5112, 2024, 4832
+ },
+ {
+ (const char * const []){"LEN2001", NULL},
+ 1024, 5022, 2508, 4832
+ },
+ { }
+};
+
+/* This list has been kindly provided by Synaptics. */
+static const char * const topbuttonpad_pnp_ids[] = {
+ "LEN0017",
+ "LEN0018",
+ "LEN0019",
+ "LEN0023",
+ "LEN002A",
+ "LEN002B",
+ "LEN002C",
+ "LEN002D",
+ "LEN002E",
+ "LEN0033", /* Helix */
+ "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */
+ "LEN0035", /* X240 */
+ "LEN0036", /* T440 */
+ "LEN0037",
+ "LEN0038",
+ "LEN0041",
+ "LEN0042", /* Yoga */
+ "LEN0045",
+ "LEN0046",
+ "LEN0047",
+ "LEN0048",
+ "LEN0049",
+ "LEN2000",
+ "LEN2001", /* Edge E431 */
+ "LEN2002", /* Edge E531 */
+ "LEN2003",
+ "LEN2004", /* L440 */
+ "LEN2005",
+ "LEN2006",
+ "LEN2007",
+ "LEN2008",
+ "LEN2009",
+ "LEN200A",
+ "LEN200B",
+ NULL
+};
+
+static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
+{
+ int i;
+
+ if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4))
+ for (i = 0; ids[i]; i++)
+ if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i]))
+ return true;
+
+ return false;
+}
/*****************************************************************************
* Synaptics communications functions
@@ -265,10 +341,12 @@ static int synaptics_identify(struct psmouse *psmouse)
* Read touchpad resolution and maximum reported coordinates
* Resolution is left zero if touchpad does not support the query
*/
+
static int synaptics_resolution(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
unsigned char resp[3];
+ int i;
if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
@@ -280,6 +358,16 @@ static int synaptics_resolution(struct psmouse *psmouse)
}
}
+ for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
+ if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
+ priv->x_min = min_max_pnpid_table[i].x_min;
+ priv->x_max = min_max_pnpid_table[i].x_max;
+ priv->y_min = min_max_pnpid_table[i].y_min;
+ priv->y_max = min_max_pnpid_table[i].y_max;
+ return 0;
+ }
+ }
+
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
@@ -1244,8 +1332,10 @@ static void set_abs_position_params(struct input_dev *dev,
input_abs_set_res(dev, y_code, priv->y_res);
}
-static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
+static void set_input_params(struct psmouse *psmouse,
+ struct synaptics_data *priv)
{
+ struct input_dev *dev = psmouse->dev;
int i;
/* Things that apply to both modes */
@@ -1314,6 +1404,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
+ if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids))
+ __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
/* Clickpads report only left button */
__clear_bit(BTN_RIGHT, dev->keybit);
__clear_bit(BTN_MIDDLE, dev->keybit);
@@ -1538,7 +1630,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
priv->board_id, priv->firmware_id);
- set_input_params(psmouse->dev, priv);
+ set_input_params(psmouse, priv);
/*
* Encode touchpad model so that it can be used to set
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
index 64cf34ea760..e122bda16aa 100644
--- a/drivers/input/mouse/synaptics_usb.c
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -39,7 +39,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index e900d465aaf..38298232124 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -82,7 +82,6 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
-#include <linux/init.h>
#define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"