diff options
author | Dmitry Torokhov | 2011-10-26 21:46:20 -0700 |
---|---|---|
committer | Dmitry Torokhov | 2011-10-26 21:46:20 -0700 |
commit | 6ad390a25a9d1d8606b9b826878f0a30639dc2b3 (patch) | |
tree | 05aff14f02776bc0d59a1f777cb92df6f4456ba9 /drivers/input/mouse | |
parent | d6069dae4700cf5290a75002c46b9be8ea7eef3c (diff) | |
parent | 3f48e7354358519e5b93f7f755ec270b3f8eafa0 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/alps.c | 52 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 734 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.h | 57 | ||||
-rw-r--r-- | drivers/input/mouse/hgpk.c | 84 | ||||
-rw-r--r-- | drivers/input/mouse/hgpk.h | 11 | ||||
-rw-r--r-- | drivers/input/mouse/lifebook.c | 6 | ||||
-rw-r--r-- | drivers/input/mouse/logips2pp.c | 16 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 67 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 25 | ||||
-rw-r--r-- | drivers/input/mouse/pxa930_trkball.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/sentelic.c | 13 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 610 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.h | 27 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics_i2c.c | 4 |
14 files changed, 1363 insertions, 345 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 99d58764ef03..003587c71f43 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -23,13 +23,6 @@ #include "psmouse.h" #include "alps.h" -#undef DEBUG -#ifdef DEBUG -#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif - #define ALPS_OLDPROTO 0x01 /* old style input */ #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ #define ALPS_PASS 0x04 /* device has a pass-through port */ @@ -297,10 +290,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) psmouse->packet[4] | psmouse->packet[5]) & 0x80) || (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { - dbg("refusing packet %x %x %x %x " - "(suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5], psmouse->packet[6]); + psmouse_dbg(psmouse, + "refusing packet %x %x %x %x (suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5], psmouse->packet[6]); return PSMOUSE_BAD_DATA; } @@ -319,13 +312,13 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) * There is also possibility that we got 6-byte ALPS * packet followed by 3-byte packet from trackpoint. We * can not distinguish between these 2 scenarios but - * becase the latter is unlikely to happen in course of + * because the latter is unlikely to happen in course of * normal operation (user would need to press all * buttons on the pad and start moving trackpoint * without touching the pad surface) we assume former. * Even if we are wrong the wost thing that would happen * the cursor would jump but we should not get protocol - * desynchronization. + * de-synchronization. */ alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], @@ -361,10 +354,10 @@ static void alps_flush_packet(unsigned long data) if ((psmouse->packet[3] | psmouse->packet[4] | psmouse->packet[5]) & 0x80) { - dbg("refusing packet %x %x %x " - "(suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5]); + psmouse_dbg(psmouse, + "refusing packet %x %x %x (suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5]); } else { alps_process_packet(psmouse); } @@ -396,16 +389,18 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) } if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { - dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", - psmouse->packet[0], model->mask0, model->byte0); + psmouse_dbg(psmouse, + "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", + psmouse->packet[0], model->mask0, model->byte0); return PSMOUSE_BAD_DATA; } /* Bytes 2 - 6 should have 0 in the highest bit */ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { - dbg("refusing packet[%i] = %x\n", - psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", + psmouse->pktcnt - 1, + psmouse->packet[psmouse->pktcnt - 1]); return PSMOUSE_BAD_DATA; } @@ -439,7 +434,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return NULL; - dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100)) return NULL; @@ -459,7 +455,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return NULL; - dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); if (version) { for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) @@ -527,7 +524,8 @@ static int alps_get_status(struct psmouse *psmouse, char *param) ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return -1; - dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); return 0; } @@ -605,12 +603,12 @@ static int alps_hw_init(struct psmouse *psmouse) } if (alps_tap_mode(psmouse, true)) { - printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); + psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); return -1; } if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); + psmouse_err(psmouse, "Failed to enable absolute mode\n"); return -1; } @@ -621,7 +619,7 @@ static int alps_hw_init(struct psmouse *psmouse) /* ALPS needs stream mode, otherwise it won't report any data */ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { - printk(KERN_ERR "alps.c: Failed to enable stream mode\n"); + psmouse_err(psmouse, "Failed to enable stream mode\n"); return -1; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 32503565faf9..09b93b11a274 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -10,8 +10,6 @@ * Trademarks are the property of their respective owners. */ -#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt - #include <linux/delay.h> #include <linux/slab.h> #include <linux/module.h> @@ -25,13 +23,10 @@ #define elantech_debug(fmt, ...) \ do { \ if (etd->debug) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ + psmouse_printk(KERN_DEBUG, psmouse, \ + fmt, ##__VA_ARGS__); \ } while (0) -static bool force_elantech; -module_param_named(force_elantech, force_elantech, bool, 0644); -MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default)."); - /* * Send a Synaptics style sliced query command */ @@ -40,7 +35,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, { if (psmouse_sliced_command(psmouse, c) || ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_err("synaptics_send_cmd query 0x%02x failed.\n", c); + psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); return -1; } @@ -69,7 +64,7 @@ static int elantech_ps2_command(struct psmouse *psmouse, } while (tries > 0); if (rc) - pr_err("ps2 command 0x%02x failed.\n", command); + psmouse_err(psmouse, "ps2 command 0x%02x failed.\n", command); return rc; } @@ -84,7 +79,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, unsigned char param[3]; int rc = 0; - if (reg < 0x10 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) return -1; if (reg > 0x11 && reg < 0x20) @@ -108,12 +103,24 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, rc = -1; } break; + + case 3 ... 4: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { + rc = -1; + } + break; } if (rc) - pr_err("failed to read register 0x%02x.\n", reg); - else + psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg); + else if (etd->hw_version != 4) *val = param[0]; + else + *val = param[1]; return rc; } @@ -127,7 +134,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, struct elantech_data *etd = psmouse->private; int rc = 0; - if (reg < 0x10 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) return -1; if (reg > 0x11 && reg < 0x20) @@ -154,11 +161,38 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, rc = -1; } break; + + case 3: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, val) || + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { + rc = -1; + } + break; + + case 4: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, val) || + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { + rc = -1; + } + break; } if (rc) - pr_err("failed to write register 0x%02x with value 0x%02x.\n", - reg, val); + psmouse_err(psmouse, + "failed to write register 0x%02x with value 0x%02x.\n", + reg, val); return rc; } @@ -166,13 +200,13 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, /* * Dump a complete mouse movement packet to the syslog */ -static void elantech_packet_dump(unsigned char *packet, int size) +static void elantech_packet_dump(struct psmouse *psmouse) { int i; - printk(KERN_DEBUG pr_fmt("PS/2 packet [")); - for (i = 0; i < size; i++) - printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); + psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet ["); + for (i = 0; i < psmouse->pktsize; i++) + printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]); printk("]\n"); } @@ -223,7 +257,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_abs(dev, ABS_X, ((packet[1] & 0x0c) << 6) | packet[2]); input_report_abs(dev, ABS_Y, - ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3])); + etd->y_max - (((packet[1] & 0x03) << 8) | packet[3])); } input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); @@ -233,7 +267,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); if (etd->fw_version < 0x020000 && - (etd->capabilities & ETP_CAP_HAS_ROCKER)) { + (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { /* rocker up */ input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); /* rocker down */ @@ -273,11 +307,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) struct elantech_data *etd = psmouse->private; struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; - unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0; + unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + unsigned int width = 0, pres = 0; /* byte 0: n1 n0 . . . . R L */ fingers = (packet[0] & 0xc0) >> 6; - input_report_key(dev, BTN_TOUCH, fingers != 0); switch (fingers) { case 3: @@ -290,18 +324,15 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) /* pass through... */ case 1: /* - * byte 1: . . . . . x10 x9 x8 + * byte 1: . . . . x11 x10 x9 x8 * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */ - x1 = ((packet[1] & 0x07) << 8) | packet[2]; + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; /* - * byte 4: . . . . . . y9 y8 + * byte 4: . . . . y11 y10 y9 y8 * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ - y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]); - - input_report_abs(dev, ABS_X, x1); - input_report_abs(dev, ABS_Y, y1); + y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); @@ -314,22 +345,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) * byte 0: . . ay8 ax8 . . . . * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */ - x1 = ((packet[0] & 0x10) << 4) | packet[1]; + x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ - y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]); + y1 = etd->y_max - + ((((packet[0] & 0x20) << 3) | packet[2]) << 2); /* * byte 3: . . by8 bx8 . . . . * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */ - x2 = ((packet[3] & 0x10) << 4) | packet[4]; + x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ - y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]); - /* - * For compatibility with the X Synaptics driver scale up - * one coordinate and report as ordinary mouse movent - */ - input_report_abs(dev, ABS_X, x1 << 2); - input_report_abs(dev, ABS_Y, y1 << 2); + y2 = etd->y_max - + ((((packet[3] & 0x20) << 3) | packet[5]) << 2); /* Unknown so just report sensible values */ pres = 127; @@ -337,6 +364,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) break; } + input_report_key(dev, BTN_TOUCH, fingers != 0); + if (fingers != 0) { + input_report_abs(dev, ABS_X, x1); + input_report_abs(dev, ABS_Y, y1); + } elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); @@ -352,7 +384,208 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_sync(dev); } -static int elantech_check_parity_v1(struct psmouse *psmouse) +/* + * Interpret complete data packets and report absolute mode input events for + * hardware version 3. (12 byte packets for two fingers) + */ +static void elantech_report_absolute_v3(struct psmouse *psmouse, + int packet_type) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + unsigned int width = 0, pres = 0; + + /* byte 0: n1 n0 . . . . R L */ + fingers = (packet[0] & 0xc0) >> 6; + + switch (fingers) { + case 3: + case 1: + /* + * byte 1: . . . . x11 x10 x9 x8 + * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 + */ + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; + /* + * byte 4: . . . . y11 y10 y9 y8 + * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 + */ + y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + break; + + case 2: + if (packet_type == PACKET_V3_HEAD) { + /* + * byte 1: . . . . ax11 ax10 ax9 ax8 + * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 + */ + etd->mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; + /* + * byte 4: . . . . ay11 ay10 ay9 ay8 + * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 + */ + etd->mt[0].y = etd->y_max - + (((packet[4] & 0x0f) << 8) | packet[5]); + /* + * wait for next packet + */ + return; + } + + /* packet_type == PACKET_V3_TAIL */ + x1 = etd->mt[0].x; + y1 = etd->mt[0].y; + x2 = ((packet[1] & 0x0f) << 8) | packet[2]; + y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + break; + } + + pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); + + input_report_key(dev, BTN_TOUCH, fingers != 0); + if (fingers != 0) { + input_report_abs(dev, ABS_X, x1); + input_report_abs(dev, ABS_Y, y1); + } + elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); + 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); + input_report_abs(dev, ABS_PRESSURE, pres); + input_report_abs(dev, ABS_TOOL_WIDTH, width); + + input_sync(dev); +} + +static void elantech_input_sync_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + + 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); +} + +static void process_packet_status_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + unsigned fingers; + int i; + + /* notify finger state change */ + fingers = packet[1] & 0x1f; + for (i = 0; i < ETP_MAX_FINGERS; i++) { + if ((fingers & (1 << i)) == 0) { + input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, false); + } + } + + elantech_input_sync_v4(psmouse); +} + +static void process_packet_head_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + int id = ((packet[3] & 0xe0) >> 5) - 1; + int pres, traces; + + if (id < 0) + return; + + etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2]; + etd->mt[id].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + traces = (packet[0] & 0xf0) >> 4; + + input_mt_slot(dev, id); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); + input_report_abs(dev, ABS_MT_PRESSURE, pres); + input_report_abs(dev, ABS_MT_TOUCH_MAJOR, traces * etd->width); + /* report this for backwards compatibility */ + input_report_abs(dev, ABS_TOOL_WIDTH, traces); + + elantech_input_sync_v4(psmouse); +} + +static void process_packet_motion_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0; + int id, sid; + + id = ((packet[0] & 0xe0) >> 5) - 1; + if (id < 0) + return; + + sid = ((packet[3] & 0xe0) >> 5) - 1; + weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1; + /* + * Motion packets give us the delta of x, y values of specific fingers, + * but in two's complement. Let the compiler do the conversion for us. + * Also _enlarge_ the numbers to int, in case of overflow. + */ + delta_x1 = (signed char)packet[1]; + delta_y1 = (signed char)packet[2]; + delta_x2 = (signed char)packet[4]; + delta_y2 = (signed char)packet[5]; + + etd->mt[id].x += delta_x1 * weight; + etd->mt[id].y -= delta_y1 * weight; + input_mt_slot(dev, id); + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); + + if (sid >= 0) { + etd->mt[sid].x += delta_x2 * weight; + etd->mt[sid].y -= delta_y2 * weight; + input_mt_slot(dev, sid); + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[sid].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[sid].y); + } + + elantech_input_sync_v4(psmouse); +} + +static void elantech_report_absolute_v4(struct psmouse *psmouse, + int packet_type) +{ + switch (packet_type) { + case PACKET_V4_STATUS: + process_packet_status_v4(psmouse); + break; + + case PACKET_V4_HEAD: + process_packet_head_v4(psmouse); + break; + + case PACKET_V4_MOTION: + process_packet_motion_v4(psmouse); + break; + + case PACKET_UNKNOWN: + default: + /* impossible to get here */ + break; + } +} + +static int elantech_packet_check_v1(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; unsigned char *packet = psmouse->packet; @@ -376,31 +609,142 @@ static int elantech_check_parity_v1(struct psmouse *psmouse) etd->parity[packet[3]] == p3; } +static int elantech_debounce_check_v2(struct psmouse *psmouse) +{ + /* + * When we encounter packet that matches this exactly, it means the + * hardware is in debounce status. Just ignore the whole packet. + */ + const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; + unsigned char *packet = psmouse->packet; + + return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); +} + +static int elantech_packet_check_v2(struct psmouse *psmouse) +{ + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + + /* + * V2 hardware has two flavors. Older ones that do not report pressure, + * and newer ones that reports pressure and width. With newer ones, all + * packets (1, 2, 3 finger touch) have the same constant bits. With + * older ones, 1/3 finger touch packets and 2 finger touch packets + * have different constant bits. + * With all three cases, if the constant bits are not exactly what I + * expected, I consider them invalid. + */ + if (etd->reports_pressure) + return (packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x0f) == 0x02; + + if ((packet[0] & 0xc0) == 0x80) + return (packet[0] & 0x0c) == 0x0c && + (packet[3] & 0x0e) == 0x08; + + return (packet[0] & 0x3c) == 0x3c && + (packet[1] & 0xf0) == 0x00 && + (packet[3] & 0x3e) == 0x38 && + (packet[4] & 0xf0) == 0x00; +} + +/* + * We check the constant bits to determine what packet type we get, + * so packet checking is mandatory for v3 and later hardware. + */ +static int elantech_packet_check_v3(struct psmouse *psmouse) +{ + const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; + unsigned char *packet = psmouse->packet; + + /* + * check debounce first, it has the same signature in byte 0 + * and byte 3 as PACKET_V3_HEAD. + */ + if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) + return PACKET_DEBOUNCE; + + if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) + return PACKET_V3_HEAD; + + if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) + return PACKET_V3_TAIL; + + return PACKET_UNKNOWN; +} + +static int elantech_packet_check_v4(struct psmouse *psmouse) +{ + unsigned char *packet = psmouse->packet; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x11) + return PACKET_V4_HEAD; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x12) + return PACKET_V4_MOTION; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x10) + return PACKET_V4_STATUS; + + return PACKET_UNKNOWN; +} + /* * Process byte stream from mouse and handle complete packets */ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; + int packet_type; if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; if (etd->debug > 1) - elantech_packet_dump(psmouse->packet, psmouse->pktsize); + elantech_packet_dump(psmouse); switch (etd->hw_version) { case 1: - if (etd->paritycheck && !elantech_check_parity_v1(psmouse)) + if (etd->paritycheck && !elantech_packet_check_v1(psmouse)) return PSMOUSE_BAD_DATA; elantech_report_absolute_v1(psmouse); break; case 2: - /* We don't know how to check parity in protocol v2 */ + /* ignore debounce */ + if (elantech_debounce_check_v2(psmouse)) + return PSMOUSE_FULL_PACKET; + + if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) + return PSMOUSE_BAD_DATA; + elantech_report_absolute_v2(psmouse); break; + + case 3: + packet_type = elantech_packet_check_v3(psmouse); + /* ignore debounce */ + if (packet_type == PACKET_DEBOUNCE) + return PSMOUSE_FULL_PACKET; + + if (packet_type == PACKET_UNKNOWN) + return PSMOUSE_BAD_DATA; + + elantech_report_absolute_v3(psmouse, packet_type); + break; + + case 4: + packet_type = elantech_packet_check_v4(psmouse); + if (packet_type == PACKET_UNKNOWN) + return PSMOUSE_BAD_DATA; + + elantech_report_absolute_v4(psmouse, packet_type); + break; } return PSMOUSE_FULL_PACKET; @@ -435,15 +779,29 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) elantech_write_reg(psmouse, 0x11, etd->reg_11) || elantech_write_reg(psmouse, 0x21, etd->reg_21)) { rc = -1; - break; } + break; + + case 3: + etd->reg_10 = 0x0b; + if (elantech_write_reg(psmouse, 0x10, etd->reg_10)) + rc = -1; + + break; + + case 4: + etd->reg_07 = 0x01; + if (elantech_write_reg(psmouse, 0x07, etd->reg_07)) + rc = -1; + + goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */ } if (rc == 0) { /* * Read back reg 0x10. For hardware version 1 we must make * sure the absolute mode bit is set. For hardware version 2 - * the touchpad is probably initalising and not ready until + * the touchpad is probably initializing and not ready until * we read back the value we just wrote. */ do { @@ -456,27 +814,115 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) } while (tries > 0); if (rc) { - pr_err("failed to read back register 0x10.\n"); + psmouse_err(psmouse, + "failed to read back register 0x10.\n"); } else if (etd->hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { - pr_err("touchpad refuses to switch to absolute mode.\n"); + psmouse_err(psmouse, + "touchpad refuses to switch to absolute mode.\n"); rc = -1; } } + skip_readback_reg_10: if (rc) - pr_err("failed to initialise registers.\n"); + psmouse_err(psmouse, "failed to initialise registers.\n"); return rc; } +static int elantech_set_range(struct psmouse *psmouse, + unsigned int *x_min, unsigned int *y_min, + unsigned int *x_max, unsigned int *y_max, + unsigned int *width) +{ + struct elantech_data *etd = psmouse->private; + unsigned char param[3]; + unsigned char traces; + + switch (etd->hw_version) { + case 1: + *x_min = ETP_XMIN_V1; + *y_min = ETP_YMIN_V1; + *x_max = ETP_XMAX_V1; + *y_max = ETP_YMAX_V1; + break; + + case 2: + if (etd->fw_version == 0x020800 || + etd->fw_version == 0x020b00 || + etd->fw_version == 0x020030) { + *x_min = ETP_XMIN_V2; + *y_min = ETP_YMIN_V2; + *x_max = ETP_XMAX_V2; + *y_max = ETP_YMAX_V2; + } else { + int i; + int fixed_dpi; + + i = (etd->fw_version > 0x020800 && + etd->fw_version < 0x020900) ? 1 : 2; + + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + fixed_dpi = param[1] & 0x10; + + if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) { + if (synaptics_send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + return -1; + + *x_max = (etd->capabilities[1] - i) * param[1] / 2; + *y_max = (etd->capabilities[2] - i) * param[2] / 2; + } else if (etd->fw_version == 0x040216) { + *x_max = 819; + *y_max = 405; + } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) { + *x_max = 900; + *y_max = 500; + } else { + *x_max = (etd->capabilities[1] - i) * 64; + *y_max = (etd->capabilities[2] - i) * 64; + } + } + break; + + case 3: + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + *x_max = (0x0f & param[0]) << 8 | param[1]; + *y_max = (0xf0 & param[0]) << 4 | param[2]; + break; + + case 4: + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + *x_max = (0x0f & param[0]) << 8 | param[1]; + *y_max = (0xf0 & param[0]) << 4 | param[2]; + traces = etd->capabilities[1]; + if ((traces < 2) || (traces > *x_max)) + return -1; + + *width = *x_max / (traces - 1); + break; + } + + return 0; +} + /* * Set the appropriate event bits for the input subsystem */ -static void elantech_set_input_params(struct psmouse *psmouse) +static int elantech_set_input_params(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; + unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; + + if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) + return -1; __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); @@ -494,30 +940,64 @@ static void elantech_set_input_params(struct psmouse *psmouse) case 1: /* Rocker button */ if (etd->fw_version < 0x020000 && - (etd->capabilities & ETP_CAP_HAS_ROCKER)) { + (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } - input_set_abs_params(dev, ABS_X, ETP_XMIN_V1, ETP_XMAX_V1, 0, 0); - input_set_abs_params(dev, ABS_Y, ETP_YMIN_V1, ETP_YMAX_V1, 0, 0); + 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); break; case 2: __set_bit(BTN_TOOL_QUADTAP, dev->keybit); - input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); - input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); + __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); + /* fall through */ + case 3: + 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) { input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, ETP_PMAX_V2, 0, 0); input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, ETP_WMAX_V2, 0, 0); } - __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); - input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); + break; + + case 4: + __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); + input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); + /* + * range of pressure and width is the same as v2, + * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility. + */ + input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, + ETP_PMAX_V2, 0, 0); + input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, + ETP_WMAX_V2, 0, 0); + /* Multitouch capable pad, up to 5 fingers. */ + input_mt_init_slots(dev, ETP_MAX_FINGERS); + input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); + input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2, + ETP_PMAX_V2, 0, 0); + /* + * The firmware reports how many trace lines the finger spans, + * convert to surface unit as Protocol-B requires. + */ + input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, + ETP_WMAX_V2 * width, 0, 0); break; } + + etd->y_max = y_max; + etd->width = width; + + return 0; } struct elantech_attr_data { @@ -587,6 +1067,7 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse, elantech_show_int_attr, \ elantech_set_int_attr) +ELANTECH_INT_ATTR(reg_07, 0x07); ELANTECH_INT_ATTR(reg_10, 0x10); ELANTECH_INT_ATTR(reg_11, 0x11); ELANTECH_INT_ATTR(reg_20, 0x20); @@ -600,6 +1081,7 @@ ELANTECH_INT_ATTR(debug, 0); ELANTECH_INT_ATTR(paritycheck, 0); static struct attribute *elantech_attrs[] = { + &psmouse_attr_reg_07.dattr.attr, &psmouse_attr_reg_10.dattr.attr, &psmouse_attr_reg_11.dattr.attr, &psmouse_attr_reg_20.dattr.attr, @@ -651,7 +1133,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_debug("sending Elantech magic knock failed.\n"); + psmouse_dbg(psmouse, "sending Elantech magic knock failed.\n"); return -1; } @@ -659,9 +1141,11 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * Report this in case there are Elantech models that use a different * set of magic numbers */ - if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { - pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); + if (param[0] != 0x3c || param[1] != 0x03 || + (param[2] != 0xc8 && param[2] != 0x00)) { + psmouse_dbg(psmouse, + "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", + param[0], param[1], param[2]); return -1; } @@ -671,20 +1155,18 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * to Elantech magic knock and there might be more. */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_debug("failed to query firmware version.\n"); + psmouse_dbg(psmouse, "failed to query firmware version.\n"); return -1; } - pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); + psmouse_dbg(psmouse, + "Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", + param[0], param[1], param[2]); if (!elantech_is_signature_valid(param)) { - if (!force_elantech) { - pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); - return -1; - } - - pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); + psmouse_dbg(psmouse, + "Probably not a real Elantech touchpad. Aborting.\n"); + return -1; } if (set_properties) { @@ -715,7 +1197,8 @@ static int elantech_reconnect(struct psmouse *psmouse) return -1; if (elantech_set_absolute_mode(psmouse)) { - pr_err("failed to put touchpad back into absolute mode.\n"); + psmouse_err(psmouse, + "failed to put touchpad back into absolute mode.\n"); return -1; } @@ -723,6 +1206,48 @@ static int elantech_reconnect(struct psmouse *psmouse) } /* + * determine hardware version and set some properties according to it. + */ +static int elantech_set_properties(struct elantech_data *etd) +{ + int ver = (etd->fw_version & 0x0f0000) >> 16; + + if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) + etd->hw_version = 1; + else if (etd->fw_version < 0x150600) + etd->hw_version = 2; + else if (ver == 5) + etd->hw_version = 3; + else if (ver == 6) + etd->hw_version = 4; + else + return -1; + + /* + * Turn on packet checking by default. + */ + etd->paritycheck = 1; + + /* + * This firmware suffers from misreporting coordinates when + * a touch action starts causing the mouse cursor or scrolled page + * to jump. Enable a workaround. + */ + etd->jumpy_cursor = + (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); + + if (etd->hw_version > 1) { + /* For now show extra debug information */ + etd->debug = 1; + + if (etd->fw_version >= 0x020800) + etd->reports_pressure = true; + } + + return 0; +} + +/* * Initialize the touchpad and create sysfs entries */ int elantech_init(struct psmouse *psmouse) @@ -743,70 +1268,53 @@ int elantech_init(struct psmouse *psmouse) * Do the version query again so we can store the result */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_err("failed to query firmware version.\n"); + psmouse_err(psmouse, "failed to query firmware version.\n"); goto init_fail; } - etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; - /* - * Assume every version greater than this is new EeePC style - * hardware with 6 byte packets - */ - if (etd->fw_version >= 0x020030) { - etd->hw_version = 2; - /* For now show extra debug information */ - etd->debug = 1; - /* Don't know how to do parity checking for version 2 */ - etd->paritycheck = 0; - - if (etd->fw_version >= 0x020800) - etd->reports_pressure = true; - - } else { - etd->hw_version = 1; - etd->paritycheck = 1; - } - - pr_info("assuming hardware version %d, firmware version %d.%d.%d\n", - etd->hw_version, param[0], param[1], param[2]); - - if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { - pr_err("failed to query capabilities.\n"); + if (elantech_set_properties(etd)) { + psmouse_err(psmouse, "unknown hardware version, aborting...\n"); goto init_fail; } - pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); - etd->capabilities = param[0]; + psmouse_info(psmouse, + "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", + etd->hw_version, param[0], param[1], param[2]); - /* - * This firmware suffers from misreporting coordinates when - * a touch action starts causing the mouse cursor or scrolled page - * to jump. Enable a workaround. - */ - if (etd->fw_version == 0x020022 || etd->fw_version == 0x020600) { - pr_info("firmware version 2.0.34/2.6.0 detected, enabling jumpy cursor workaround\n"); - etd->jumpy_cursor = true; + if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, + etd->capabilities)) { + psmouse_err(psmouse, "failed to query capabilities.\n"); + goto init_fail; } + psmouse_info(psmouse, + "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", + etd->capabilities[0], etd->capabilities[1], + etd->capabilities[2]); if (elantech_set_absolute_mode(psmouse)) { - pr_err("failed to put touchpad into absolute mode.\n"); + psmouse_err(psmouse, + "failed to put touchpad into absolute mode.\n"); goto init_fail; } - elantech_set_input_params(psmouse); + if (elantech_set_input_params(psmouse)) { + psmouse_err(psmouse, "failed to query touchpad range.\n"); + goto init_fail; + } error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, &elantech_attr_group); if (error) { - pr_err("failed to create sysfs attributes, error: %d.\n", error); + psmouse_err(psmouse, + "failed to create sysfs attributes, error: %d.\n", + error); goto init_fail; } psmouse->protocol_handler = elantech_process_byte; psmouse->disconnect = elantech_disconnect; psmouse->reconnect = elantech_reconnect; - psmouse->pktsize = etd->hw_version == 2 ? 6 : 4; + psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; return 0; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index fabb2b99615c..9e5f1aabea7e 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -16,14 +16,17 @@ /* * Command values for Synaptics style queries */ +#define ETP_FW_ID_QUERY 0x00 #define ETP_FW_VERSION_QUERY 0x01 #define ETP_CAPABILITIES_QUERY 0x02 +#define ETP_SAMPLE_QUERY 0x03 /* * Command values for register reading or writing */ #define ETP_REGISTER_READ 0x10 #define ETP_REGISTER_WRITE 0x11 +#define ETP_REGISTER_READWRITE 0x00 /* * Hardware version 2 custom PS/2 command value @@ -66,16 +69,13 @@ #define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) /* - * It seems the resolution for hardware version 2 doubled. - * Hence the X and Y ranges are doubled too. - * The bezel around the pad also appears to be smaller + * The resolution for older v2 hardware doubled. + * (newer v2's firmware provides command so we can query) */ -#define ETP_EDGE_FUZZ_V2 8 - -#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) -#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2) -#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) -#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2) +#define ETP_XMIN_V2 0 +#define ETP_XMAX_V2 1152 +#define ETP_YMIN_V2 0 +#define ETP_YMAX_V2 768 #define ETP_PMIN_V2 0 #define ETP_PMAX_V2 255 @@ -83,17 +83,37 @@ #define ETP_WMAX_V2 15 /* - * For two finger touches the coordinate of each finger gets reported - * separately but with reduced resolution. + * v3 hardware has 2 kinds of packet types, + * v4 hardware has 3. + */ +#define PACKET_UNKNOWN 0x01 +#define PACKET_DEBOUNCE 0x02 +#define PACKET_V3_HEAD 0x03 +#define PACKET_V3_TAIL 0x04 +#define PACKET_V4_HEAD 0x05 +#define PACKET_V4_MOTION 0x06 +#define PACKET_V4_STATUS 0x07 + +/* + * track up to 5 fingers for v4 hardware + */ +#define ETP_MAX_FINGERS 5 + +/* + * weight value for v4 hardware */ -#define ETP_2FT_FUZZ 4 +#define ETP_WEIGHT_VALUE 5 -#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ) -#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ) -#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ) -#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ) +/* + * The base position for one finger, v4 hardware + */ +struct finger_pos { + unsigned int x; + unsigned int y; +}; struct elantech_data { + unsigned char reg_07; unsigned char reg_10; unsigned char reg_11; unsigned char reg_20; @@ -104,13 +124,16 @@ struct elantech_data { unsigned char reg_25; unsigned char reg_26; unsigned char debug; - unsigned char capabilities; + unsigned char capabilities[3]; bool paritycheck; bool jumpy_cursor; bool reports_pressure; unsigned char hw_version; unsigned int fw_version; unsigned int single_finger_reports; + unsigned int y_max; + unsigned int width; + struct finger_pos mt[ETP_MAX_FINGERS]; unsigned char parity[256]; }; diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 4d17d9f3320b..0470dd46b566 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -136,10 +136,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) /* discard if too big, or half that but > 4 times the prev delta */ if (avx > recalib_delta || (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { - hgpk_err(psmouse, "detected %dpx jump in x\n", x); + psmouse_warn(psmouse, "detected %dpx jump in x\n", x); priv->xbigj = avx; } else if (approx_half(avx, priv->xbigj)) { - hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x); + psmouse_warn(psmouse, "detected secondary %dpx jump in x\n", x); priv->xbigj = avx; priv->xsaw_secondary++; } else { @@ -151,10 +151,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) if (avy > recalib_delta || (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { - hgpk_err(psmouse, "detected %dpx jump in y\n", y); + psmouse_warn(psmouse, "detected %dpx jump in y\n", y); priv->ybigj = avy; } else if (approx_half(avy, priv->ybigj)) { - hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y); + psmouse_warn(psmouse, "detected secondary %dpx jump in y\n", y); priv->ybigj = avy; priv->ysaw_secondary++; } else { @@ -168,7 +168,7 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) priv->ylast = avy; if (do_recal && jumpy_delay) { - hgpk_err(psmouse, "scheduling recalibration\n"); + psmouse_warn(psmouse, "scheduling recalibration\n"); psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(jumpy_delay)); } @@ -260,8 +260,8 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, * movement, it is probably a case of the user moving the * cursor very slowly across the screen. */ if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { - hgpk_err(psmouse, "packet spew detected (%d,%d)\n", - priv->x_tally, priv->y_tally); + psmouse_warn(psmouse, "packet spew detected (%d,%d)\n", + priv->x_tally, priv->y_tally); priv->spew_flag = RECALIBRATING; psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(spew_delay)); @@ -333,12 +333,12 @@ static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet) } if (!valid) - hgpk_dbg(psmouse, - "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n", - priv->mode, pktcnt, - psmouse->packet[0], psmouse->packet[1], - psmouse->packet[2], psmouse->packet[3], - psmouse->packet[4], psmouse->packet[5]); + psmouse_dbg(psmouse, + "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n", + priv->mode, pktcnt, + psmouse->packet[0], psmouse->packet[1], + psmouse->packet[2], psmouse->packet[3], + psmouse->packet[4], psmouse->packet[5]); return valid; } @@ -361,19 +361,20 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) input_report_abs(idev, ABS_PRESSURE, z); if (tpdebug) - hgpk_dbg(psmouse, "pd=%d fd=%d z=%d", - pt_down, finger_down, z); + psmouse_dbg(psmouse, "pd=%d fd=%d z=%d", + pt_down, finger_down, z); } else { /* * PenTablet mode does not report pressure, so we don't * report it here */ if (tpdebug) - hgpk_dbg(psmouse, "pd=%d ", down); + psmouse_dbg(psmouse, "pd=%d ", down); } if (tpdebug) - hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y); + psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", + left, right, x, y); input_report_key(idev, BTN_TOUCH, down); input_report_key(idev, BTN_LEFT, left); @@ -395,7 +396,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) if (x == priv->abs_x && y == priv->abs_y) { if (++priv->dupe_count > SPEW_WATCH_COUNT) { if (tpdebug) - hgpk_dbg(psmouse, "hard spew detected\n"); + psmouse_dbg(psmouse, "hard spew detected\n"); priv->spew_flag = RECALIBRATING; psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(spew_delay)); @@ -412,7 +413,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) int y_diff = priv->abs_y - y; if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) { if (tpdebug) - hgpk_dbg(psmouse, "discarding\n"); + psmouse_dbg(psmouse, "discarding\n"); goto done; } hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); @@ -437,20 +438,21 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse) int y = ((packet[0] << 3) & 0x100) - packet[2]; if (packet[0] & 0xc0) - hgpk_dbg(psmouse, - "overflow -- 0x%02x 0x%02x 0x%02x\n", - packet[0], packet[1], packet[2]); + psmouse_dbg(psmouse, + "overflow -- 0x%02x 0x%02x 0x%02x\n", + packet[0], packet[1], packet[2]); if (hgpk_discard_decay_hack(psmouse, x, y)) { if (tpdebug) - hgpk_dbg(psmouse, "discarding\n"); + psmouse_dbg(psmouse, "discarding\n"); return; } hgpk_spewing_hack(psmouse, left, right, x, y); if (tpdebug) - hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y); + psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", + left, right, x, y); input_report_key(dev, BTN_LEFT, left); input_report_key(dev, BTN_RIGHT, right); @@ -482,9 +484,8 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) * ugh, got a packet inside our recalibration * window, schedule another recalibration. */ - hgpk_dbg(psmouse, - "packet inside calibration window, " - "queueing another recalibration\n"); + psmouse_dbg(psmouse, + "packet inside calibration window, queueing another recalibration\n"); psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(post_interrupt_delay)); } @@ -628,7 +629,7 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) err = hgpk_select_mode(psmouse); if (err) { - hgpk_err(psmouse, "failed to select mode\n"); + psmouse_err(psmouse, "failed to select mode\n"); return err; } @@ -648,11 +649,11 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) return 0; if (!autorecal) { - hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n"); + psmouse_dbg(psmouse, "recalibration disabled, ignoring\n"); return 0; } - hgpk_dbg(psmouse, "recalibrating touchpad..\n"); + psmouse_dbg(psmouse, "recalibrating touchpad..\n"); /* we don't want to race with the irq handler, nor with resyncs */ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -675,7 +676,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); if (tpdebug) - hgpk_dbg(psmouse, "touchpad reactivated\n"); + psmouse_dbg(psmouse, "touchpad reactivated\n"); /* * If we get packets right away after recalibrating, it's likely @@ -727,16 +728,16 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable) err = hgpk_reset_device(psmouse, false); if (err) { - hgpk_err(psmouse, "Failed to reset device!\n"); + psmouse_err(psmouse, "Failed to reset device!\n"); return err; } /* should be all set, enable the touchpad */ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); - hgpk_dbg(psmouse, "Touchpad powered up.\n"); + psmouse_dbg(psmouse, "Touchpad powered up.\n"); } else { - hgpk_dbg(psmouse, "Powering off touchpad.\n"); + psmouse_dbg(psmouse, "Powering off touchpad.\n"); if (ps2_command(ps2dev, NULL, 0xec) || ps2_command(ps2dev, NULL, 0xec) || @@ -923,7 +924,7 @@ static void hgpk_recalib_work(struct work_struct *work) struct psmouse *psmouse = priv->psmouse; if (hgpk_force_recalibrate(psmouse)) - hgpk_err(psmouse, "recalibration failed!\n"); + psmouse_err(psmouse, "recalibration failed!\n"); } static int hgpk_register(struct psmouse *psmouse) @@ -947,14 +948,15 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); if (err) { - hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); + psmouse_err(psmouse, "Failed creating 'powered' sysfs node\n"); return err; } err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_hgpk_mode.dattr); if (err) { - hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n"); + psmouse_err(psmouse, + "Failed creating 'hgpk_mode' sysfs node\n"); goto err_remove_powered; } @@ -963,8 +965,8 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_recalibrate.dattr); if (err) { - hgpk_err(psmouse, - "Failed creating 'recalibrate' sysfs node\n"); + psmouse_err(psmouse, + "Failed creating 'recalibrate' sysfs node\n"); goto err_remove_mode; } } @@ -1027,13 +1029,13 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse) return -EIO; } - hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]); /* HGPK signature: 0x67, 0x00, 0x<model> */ if (param[0] != 0x67 || param[1] != 0x00) return -ENODEV; - hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]); + psmouse_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]); return param[2]; } diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h index 311c0e87fcbf..dd686771cfe0 100644 --- a/drivers/input/mouse/hgpk.h +++ b/drivers/input/mouse/hgpk.h @@ -46,17 +46,6 @@ struct hgpk_data { int xsaw_secondary, ysaw_secondary; /* jumpiness detection */ }; -#define hgpk_dbg(psmouse, format, arg...) \ - dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_err(psmouse, format, arg...) \ - dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_info(psmouse, format, arg...) \ - dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_warn(psmouse, format, arg...) \ - dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_notice(psmouse, format, arg...) \ - dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) - #ifdef CONFIG_MOUSE_PS2_OLPC void hgpk_module_init(void); int hgpk_detect(struct psmouse *psmouse, bool set_properties); diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 83bcaba96b89..2c4db636de6c 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -169,8 +169,8 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) if (relative_packet) { if (!dev2) - printk(KERN_WARNING "lifebook.c: got relative packet " - "but no relative device set up\n"); + psmouse_warn(psmouse, + "got relative packet but no relative device set up\n"); } else { if (lifebook_use_6byte_proto) { input_report_abs(dev1, ABS_X, @@ -212,7 +212,7 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) /* * Enable absolute output -- ps2_command fails always but if - * you leave this call out the touchsreen will never send + * you leave this call out the touchscreen will never send * absolute coordinates */ param = lifebook_use_6byte_proto ? 0x08 : 0x07; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index c9983aee9082..faac2c3bef74 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -82,11 +82,11 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) packet[0] = packet[2] | 0x08; break; -#ifdef DEBUG default: - printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", - (packet[1] >> 4) | (packet[0] & 0x30)); -#endif + psmouse_dbg(psmouse, + "Received PS2++ packet #%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); + break; } } else { /* Standard PS/2 motion data */ @@ -382,7 +382,7 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) } } else { - printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); + psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model); } if (set_properties) { @@ -400,9 +400,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) error = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); if (error) { - printk(KERN_ERR - "logips2pp.c: failed to create smartscroll " - "sysfs attribute, error: %d\n", error); + psmouse_err(psmouse, + "failed to create smartscroll sysfs attribute, error: %d\n", + error); return -1; } } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 3f74baee102b..9f352fbd7b4f 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -11,6 +11,9 @@ * the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define psmouse_fmt(fmt) fmt + #include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> @@ -251,11 +254,14 @@ static int psmouse_handle_byte(struct psmouse *psmouse) switch (rc) { case PSMOUSE_BAD_DATA: if (psmouse->state == PSMOUSE_ACTIVATED) { - printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse_warn(psmouse, + "%s at %s lost sync at byte %d\n", + psmouse->name, psmouse->phys, + psmouse->pktcnt); if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); + psmouse_notice(psmouse, + "issuing reconnect request\n"); serio_reconnect(psmouse->ps2dev.serio); return -1; } @@ -267,8 +273,9 @@ static int psmouse_handle_byte(struct psmouse *psmouse) psmouse->pktcnt = 0; if (psmouse->out_of_sync_cnt) { psmouse->out_of_sync_cnt = 0; - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", - psmouse->name, psmouse->phys); + psmouse_notice(psmouse, + "%s at %s - driver resynced.\n", + psmouse->name, psmouse->phys); } break; @@ -295,9 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { if (psmouse->state == PSMOUSE_ACTIVATED) - printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", - flags & SERIO_TIMEOUT ? " timeout" : "", - flags & SERIO_PARITY ? " bad parity" : ""); + psmouse_warn(psmouse, + "bad data from KBC -%s%s\n", + flags & SERIO_TIMEOUT ? " timeout" : "", + flags & SERIO_PARITY ? " bad parity" : ""); ps2_cmd_aborted(&psmouse->ps2dev); goto out; } @@ -315,8 +323,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { - printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n", + psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); psmouse_queue_work(psmouse, &psmouse->resync_work, 0); @@ -943,7 +951,8 @@ static int psmouse_probe(struct psmouse *psmouse) */ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) - printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys); + psmouse_warn(psmouse, "Failed to reset mouse on %s\n", + ps2dev->serio->phys); return 0; } @@ -1005,8 +1014,8 @@ static void psmouse_initialize(struct psmouse *psmouse) static void psmouse_activate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) - printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to enable mouse on %s\n", + psmouse->ps2dev.serio->phys); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); } @@ -1020,14 +1029,14 @@ static void psmouse_activate(struct psmouse *psmouse) static void psmouse_deactivate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", + psmouse->ps2dev.serio->phys); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); } /* - * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. + * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. */ static int psmouse_poll(struct psmouse *psmouse) @@ -1115,14 +1124,15 @@ static void psmouse_resync(struct work_struct *work) } if (!enabled) { - printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "failed to re-enable mouse on %s\n", + psmouse->ps2dev.serio->phys); failed = true; } if (failed) { psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); + psmouse_info(psmouse, + "resync failed, issuing reconnect request\n"); serio_reconnect(serio); } else psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); @@ -1155,8 +1165,8 @@ static void psmouse_cleanup(struct serio *serio) * Disable stream mode so cleanup routine can proceed undisturbed. */ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to disable mouse on %s\n", + psmouse->ps2dev.serio->phys); if (psmouse->cleanup) psmouse->cleanup(psmouse); @@ -1400,7 +1410,8 @@ static int psmouse_reconnect(struct serio *serio) int rc = -1; if (!drv || !psmouse) { - printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); + psmouse_dbg(psmouse, + "reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -1427,8 +1438,9 @@ static int psmouse_reconnect(struct serio *serio) goto out; } - /* ok, the device type (and capabilities) match the old one, - * we can continue using it, complete intialization + /* + * OK, the device type (and capabilities) match the old one, + * we can continue using it, complete initialization */ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); @@ -1586,9 +1598,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co while (!list_empty(&serio->children)) { if (++retry > 3) { - printk(KERN_WARNING - "psmouse: failed to destroy children ports, " - "protocol change aborted.\n"); + psmouse_warn(psmouse, + "failed to destroy children ports, protocol change aborted.\n"); input_free_device(new_dev); return -EIO; } @@ -1715,7 +1726,7 @@ static int __init psmouse_init(void) kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); if (!kpsmoused_wq) { - printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); + pr_err("failed to create kpsmoused workqueue\n"); return -ENOMEM; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 593e910bfc7a..9b84b0c4e371 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -150,4 +150,29 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true) +#ifndef psmouse_fmt +#define psmouse_fmt(fmt) KBUILD_BASENAME ": " fmt +#endif + +#define psmouse_dbg(psmouse, format, ...) \ + dev_dbg(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_info(psmouse, format, ...) \ + dev_info(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_warn(psmouse, format, ...) \ + dev_warn(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_err(psmouse, format, ...) \ + dev_err(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_notice(psmouse, format, ...) \ + dev_notice(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_printk(level, psmouse, format, ...) \ + dev_printk(level, \ + &(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) + + #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 6c5d84fcdea1..ee3b0ca9d592 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -183,7 +183,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev) /* held the module in reset, will be enabled in open() */ pxa930_trkball_disable(trkball); - error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED, + error = request_irq(irq, pxa930_trkball_interrupt, 0, pdev->name, trkball); if (error) { dev_err(&pdev->dev, "failed to request irq: %d\n", error); diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 2fc887a51066..c5b12d2e955a 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -607,11 +607,12 @@ static void fsp_packet_debug(unsigned char packet[]) ps2_packet_cnt++; jiffies_msec = jiffies_to_msecs(jiffies); - printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", - jiffies_msec, packet[0], packet[1], packet[2], packet[3]); + psmouse_dbg(psmouse, + "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); if (jiffies_msec - ps2_last_second > 1000) { - printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); + psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt); ps2_packet_cnt = 0; ps2_last_second = jiffies_msec; } @@ -820,9 +821,9 @@ int fsp_init(struct psmouse *psmouse) return -ENODEV; } - printk(KERN_INFO - "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", - ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); + psmouse_info(psmouse, + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); if (!priv) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 5538fc657af1..c080b828e5dc 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -44,6 +44,16 @@ #define YMIN_NOMINAL 1408 #define YMAX_NOMINAL 4448 +/* + * Synaptics touchpads report the y coordinate from bottom to top, which is + * opposite from what userspace expects. + * This function is used to invert y before reporting. + */ +static int synaptics_invert_y(int y) +{ + return YMAX_NOMINAL + YMIN_NOMINAL - y; +} + /***************************************************************************** * Stuff we need even when we do not want native Synaptics support @@ -157,8 +167,8 @@ static int synaptics_capability(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { - printk(KERN_ERR "Synaptics claims to have extended capabilities," - " but I'm not able to read them.\n"); + psmouse_warn(psmouse, + "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; @@ -173,8 +183,8 @@ static int synaptics_capability(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { - printk(KERN_ERR "Synaptics claims to have extended capability 0x0c," - " but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); } else { priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; } @@ -222,8 +232,8 @@ static int synaptics_resolution(struct psmouse *psmouse) 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)) { - printk(KERN_ERR "Synaptics claims to have max coordinates" - " query, but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have max coordinates query, but I'm not able to read it.\n"); } else { priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); @@ -233,8 +243,8 @@ static int synaptics_resolution(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 && SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { - printk(KERN_ERR "Synaptics claims to have min coordinates" - " query, but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have min coordinates query, but I'm not able to read it.\n"); } else { priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); @@ -294,7 +304,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; - if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) + if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) return 0; if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) @@ -377,7 +388,8 @@ static void synaptics_pt_activate(struct psmouse *psmouse) priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; if (synaptics_mode_cmd(psmouse, priv->mode)) - printk(KERN_INFO "synaptics: failed to switch guest protocol\n"); + psmouse_warn(psmouse, + "failed to switch guest protocol\n"); } } @@ -387,7 +399,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) { - printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); + psmouse_err(psmouse, + "not enough memory for pass-through port\n"); return; } @@ -401,7 +414,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) psmouse->pt_activate = synaptics_pt_activate; - printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys); + psmouse_info(psmouse, "serio: %s port at %s\n", + serio->name, psmouse->phys); serio_register_port(serio); } @@ -409,6 +423,44 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ +static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count, + int sgm, int agm) +{ + state->count = count; + state->sgm = sgm; + state->agm = agm; +} + +static void synaptics_parse_agm(const unsigned char buf[], + struct synaptics_data *priv, + struct synaptics_hw_state *hw) +{ + struct synaptics_hw_state *agm = &priv->agm; + int agm_packet_type; + + agm_packet_type = (buf[5] & 0x30) >> 4; + switch (agm_packet_type) { + case 1: + /* Gesture packet: (x, y, z) half resolution */ + agm->w = hw->w; + agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; + agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; + agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + break; + + case 2: + /* AGM-CONTACT packet: (count, sgm, agm) */ + synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]); + break; + + default: + break; + } + + /* Record that at least one AGM has been received since last SGM */ + priv->agm_pending = true; +} + static int synaptics_parse_hw_state(const unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) @@ -442,11 +494,10 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { - /* Gesture packet: (x, y, z) at half resolution */ - priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + hw->w == 2) { + synaptics_parse_agm(buf, priv, hw); return 1; } @@ -502,8 +553,7 @@ static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot, input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); if (active) { input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, - YMAX_NOMINAL + YMIN_NOMINAL - y); + input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y)); } } @@ -526,6 +576,388 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev, } } +static void synaptics_report_buttons(struct psmouse *psmouse, + const struct synaptics_hw_state *hw) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + int i; + + input_report_key(dev, BTN_LEFT, hw->left); + input_report_key(dev, BTN_RIGHT, hw->right); + + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + input_report_key(dev, BTN_MIDDLE, hw->middle); + + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + input_report_key(dev, BTN_FORWARD, hw->up); + input_report_key(dev, BTN_BACK, hw->down); + } + + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); +} + +static void synaptics_report_slot(struct input_dev *dev, int slot, + const struct synaptics_hw_state *hw) +{ + input_mt_slot(dev, slot); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL)); + if (!hw) + return; + + input_report_abs(dev, ABS_MT_POSITION_X, hw->x); + input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y)); + input_report_abs(dev, ABS_MT_PRESSURE, hw->z); +} + +static void synaptics_report_mt_data(struct psmouse *psmouse, + struct synaptics_mt_state *mt_state, + const struct synaptics_hw_state *sgm) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state *old = &priv->mt_state; + + switch (mt_state->count) { + case 0: + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, NULL); + break; + case 1: + if (mt_state->sgm == -1) { + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, NULL); + } else if (mt_state->sgm == 0) { + synaptics_report_slot(dev, 0, sgm); + synaptics_report_slot(dev, 1, NULL); + } else { + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, sgm); + } + break; + default: + /* + * If the finger slot contained in SGM is valid, and either + * hasn't changed, or is new, then report SGM in MTB slot 0. + * Otherwise, empty MTB slot 0. + */ + if (mt_state->sgm != -1 && + (mt_state->sgm == old->sgm || old->sgm == -1)) + synaptics_report_slot(dev, 0, sgm); + else + synaptics_report_slot(dev, 0, NULL); + + /* + * If the finger slot contained in AGM is valid, and either + * hasn't changed, or is new, then report AGM in MTB slot 1. + * Otherwise, empty MTB slot 1. + */ + if (mt_state->agm != -1 && + (mt_state->agm == old->agm || old->agm == -1)) + synaptics_report_slot(dev, 1, agm); + else + synaptics_report_slot(dev, 1, NULL); + break; + } + + /* Don't use active slot count to generate BTN_TOOL events. */ + input_mt_report_pointer_emulation(dev, false); + + /* Send the number of fingers reported by touchpad itself. */ + input_mt_report_finger_count(dev, mt_state->count); + + synaptics_report_buttons(psmouse, sgm); + + input_sync(dev); +} + +/* Handle case where mt_state->count = 0 */ +static void synaptics_image_sensor_0f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + synaptics_mt_state_set(mt_state, 0, -1, -1); + priv->mt_state_lost = false; +} + +/* Handle case where mt_state->count = 1 */ +static void synaptics_image_sensor_1f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state *old = &priv->mt_state; + + /* + * If the last AGM was (0,0,0), and there is only one finger left, + * then we absolutely know that SGM contains slot 0, and all other + * fingers have been removed. + */ + if (priv->agm_pending && agm->z == 0) { + synaptics_mt_state_set(mt_state, 1, 0, -1); + priv->mt_state_lost = false; + return; + } + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 1, 0, -1); + break; + case 1: + /* + * If mt_state_lost, then the previous transition was 3->1, + * and SGM now contains either slot 0 or 1, but we don't know + * which. So, we just assume that the SGM now contains slot 1. + * + * If pending AGM and either: + * (a) the previous SGM slot contains slot 0, or + * (b) there was no SGM slot + * then, the SGM now contains slot 1 + * + * Case (a) happens with very rapid "drum roll" gestures, where + * slot 0 finger is lifted and a new slot 1 finger touches + * within one reporting interval. + * + * Case (b) happens if initially two or more fingers tap + * briefly, and all but one lift before the end of the first + * reporting interval. + * + * (In both these cases, slot 0 will becomes empty, so SGM + * contains slot 1 with the new finger) + * + * Else, if there was no previous SGM, it now contains slot 0. + * + * Otherwise, SGM still contains the same slot. + */ + if (priv->mt_state_lost || + (priv->agm_pending && old->sgm <= 0)) + synaptics_mt_state_set(mt_state, 1, 1, -1); + else if (old->sgm == -1) + synaptics_mt_state_set(mt_state, 1, 0, -1); + break; + case 2: + /* + * If mt_state_lost, we don't know which finger SGM contains. + * + * So, report 1 finger, but with both slots empty. + * We will use slot 1 on subsequent 1->1 + */ + if (priv->mt_state_lost) { + synaptics_mt_state_set(mt_state, 1, -1, -1); + break; + } + /* + * Since the last AGM was NOT (0,0,0), it was the finger in + * slot 0 that has been removed. + * So, SGM now contains previous AGM's slot, and AGM is now + * empty. + */ + synaptics_mt_state_set(mt_state, 1, old->agm, -1); + break; + case 3: + /* + * Since last AGM was not (0,0,0), we don't know which finger + * is left. + * + * So, report 1 finger, but with both slots empty. + * We will use slot 1 on subsequent 1->1 + */ + synaptics_mt_state_set(mt_state, 1, -1, -1); + priv->mt_state_lost = true; + break; + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; + } +} + +/* Handle case where mt_state->count = 2 */ +static void synaptics_image_sensor_2f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_mt_state *old = &priv->mt_state; + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 2, 0, 1); + break; + case 1: + /* + * If previous SGM contained slot 1 or higher, SGM now contains + * slot 0 (the newly touching finger) and AGM contains SGM's + * previous slot. + * + * Otherwise, SGM still contains slot 0 and AGM now contains + * slot 1. + */ + if (old->sgm >= 1) + synaptics_mt_state_set(mt_state, 2, 0, old->sgm); + else + synaptics_mt_state_set(mt_state, 2, 0, 1); + break; + case 2: + /* + * If mt_state_lost, SGM now contains either finger 1 or 2, but + * we don't know which. + * So, we just assume that the SGM contains slot 0 and AGM 1. + */ + if (priv->mt_state_lost) + synaptics_mt_state_set(mt_state, 2, 0, 1); + /* + * Otherwise, use the same mt_state, since it either hasn't + * changed, or was updated by a recently received AGM-CONTACT + * packet. + */ + break; + case 3: + /* + * 3->2 transitions have two unsolvable problems: + * 1) no indication is given which finger was removed + * 2) no way to tell if agm packet was for finger 3 + * before 3->2, or finger 2 after 3->2. + * + * So, report 2 fingers, but empty all slots. + * We will guess slots [0,1] on subsequent 2->2. + */ + synaptics_mt_state_set(mt_state, 2, -1, -1); + priv->mt_state_lost = true; + break; + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; + } +} + +/* Handle case where mt_state->count = 3 */ +static void synaptics_image_sensor_3f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_mt_state *old = &priv->mt_state; + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 3, 0, 2); + break; + case 1: + /* + * If previous SGM contained slot 2 or higher, SGM now contains + * slot 0 (one of the newly touching fingers) and AGM contains + * SGM's previous slot. + * + * Otherwise, SGM now contains slot 0 and AGM contains slot 2. + */ + if (old->sgm >= 2) + synaptics_mt_state_set(mt_state, 3, 0, old->sgm); + else + synaptics_mt_state_set(mt_state, 3, 0, 2); + break; + case 2: + /* + * If the AGM previously contained slot 3 or higher, then the + * newly touching finger is in the lowest available slot. + * + * If SGM was previously 1 or higher, then the new SGM is + * now slot 0 (with a new finger), otherwise, the new finger + * is now in a hidden slot between 0 and AGM's slot. + * + * In all such cases, the SGM now contains slot 0, and the AGM + * continues to contain the same slot as before. + */ + if (old->agm >= 3) { + synaptics_mt_state_set(mt_state, 3, 0, old->agm); + break; + } + + /* + * After some 3->1 and all 3->2 transitions, we lose track + * of which slot is reported by SGM and AGM. + * + * For 2->3 in this state, report 3 fingers, but empty all + * slots, and we will guess (0,2) on a subsequent 0->3. + * + * To userspace, the resulting transition will look like: + * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] + */ + if (priv->mt_state_lost) { + synaptics_mt_state_set(mt_state, 3, -1, -1); + break; + } + + /* + * If the (SGM,AGM) really previously contained slots (0, 1), + * then we cannot know what slot was just reported by the AGM, + * because the 2->3 transition can occur either before or after + * the AGM packet. Thus, this most recent AGM could contain + * either the same old slot 1 or the new slot 2. + * Subsequent AGMs will be reporting slot 2. + * + * To userspace, the resulting transition will look like: + * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] + */ + synaptics_mt_state_set(mt_state, 3, 0, -1); + break; + case 3: + /* + * If, for whatever reason, the previous agm was invalid, + * Assume SGM now contains slot 0, AGM now contains slot 2. + */ + if (old->agm <= 2) + synaptics_mt_state_set(mt_state, 3, 0, 2); + /* + * mt_state either hasn't changed, or was updated by a recently + * received AGM-CONTACT packet. + */ + break; + + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; + } +} + +/* Handle case where mt_state->count = 4, or = 5 */ +static void synaptics_image_sensor_45f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + /* mt_state was updated correctly by AGM-CONTACT packet */ + priv->mt_state_lost = false; +} + +static void synaptics_image_sensor_process(struct psmouse *psmouse, + struct synaptics_hw_state *sgm) +{ + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state mt_state; + + /* Initialize using current mt_state (as updated by last agm) */ + mt_state = agm->mt_state; + + /* + * Update mt_state using the new finger count and current mt_state. + */ + if (sgm->z == 0) + synaptics_image_sensor_0f(priv, &mt_state); + else if (sgm->w >= 4) + synaptics_image_sensor_1f(priv, &mt_state); + else if (sgm->w == 0) + synaptics_image_sensor_2f(priv, &mt_state); + else if (sgm->w == 1 && mt_state.count <= 3) + synaptics_image_sensor_3f(priv, &mt_state); + else + synaptics_image_sensor_45f(priv, &mt_state); + + /* Send resulting input events to user space */ + synaptics_report_mt_data(psmouse, &mt_state, sgm); + + /* Store updated mt_state */ + priv->mt_state = agm->mt_state = mt_state; + priv->agm_pending = false; +} + /* * called for each full received packet from the touchpad */ @@ -536,11 +968,15 @@ static void synaptics_process_packet(struct psmouse *psmouse) struct synaptics_hw_state hw; int num_fingers; int finger_width; - int i; if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) return; + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + synaptics_image_sensor_process(psmouse, &hw); + return; + } + if (hw.scroll) { priv->scroll += hw.scroll; @@ -586,7 +1022,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) } if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) - synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers); + synaptics_report_semi_mt_data(dev, &hw, &priv->agm, + num_fingers); /* Post events * BTN_TOUCH has to be first as mousedev relies on it when doing @@ -597,7 +1034,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (num_fingers > 0) { input_report_abs(dev, ABS_X, hw.x); - input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); + input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y)); } input_report_abs(dev, ABS_PRESSURE, hw.z); @@ -605,35 +1042,25 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - input_report_key(dev, BTN_LEFT, hw.left); - input_report_key(dev, BTN_RIGHT, hw.right); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - input_report_key(dev, BTN_MIDDLE, hw.middle); - - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { - input_report_key(dev, BTN_FORWARD, hw.up); - input_report_key(dev, BTN_BACK, hw.down); - } - - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) - input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); + synaptics_report_buttons(psmouse, &hw); input_sync(dev); } -static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) +static int synaptics_validate_byte(struct psmouse *psmouse, + int idx, unsigned char pkt_type) { static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + const char *packet = psmouse->packet; if (idx < 0 || idx > 4) return 0; @@ -651,7 +1078,7 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; default: - printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); + psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); return 0; } } @@ -661,8 +1088,8 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) int i; for (i = 0; i < 5; i++) - if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) { - printk(KERN_INFO "synaptics: using relaxed packet validation\n"); + if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { + psmouse_info(psmouse, "using relaxed packet validation\n"); return SYN_NEWABS_RELAXED; } @@ -687,46 +1114,56 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } - return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ? + return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ? PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; } /***************************************************************************** * Driver initialization/cleanup functions ****************************************************************************/ -static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) +static void set_abs_position_params(struct input_dev *dev, + struct synaptics_data *priv, int x_code, + int y_code) { - int i; + int x_min = priv->x_min ?: XMIN_NOMINAL; + int x_max = priv->x_max ?: XMAX_NOMINAL; + int y_min = priv->y_min ?: YMIN_NOMINAL; + int y_max = priv->y_max ?: YMAX_NOMINAL; int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? SYN_REDUCED_FILTER_FUZZ : 0; + input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); + input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); + input_abs_set_res(dev, x_code, priv->x_res); + input_abs_set_res(dev, y_code, priv->y_res); +} + +static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) +{ + int i; + __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_ABS, dev->evbit); - input_set_abs_params(dev, ABS_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); - input_set_abs_params(dev, ABS_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); + set_abs_position_params(dev, priv, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + input_mt_init_slots(dev, 2); + set_abs_position_params(dev, priv, ABS_MT_POSITION_X, + ABS_MT_POSITION_Y); + /* Image sensors can report per-contact pressure */ + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + + /* Image sensors can signal 4 and 5 finger clicks */ + __set_bit(BTN_TOOL_QUADTAP, dev->keybit); + __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); + } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { + /* Non-image sensors with AGM use semi-mt */ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); - input_set_abs_params(dev, ABS_MT_POSITION_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); - - input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); + set_abs_position_params(dev, priv, ABS_MT_POSITION_X, + ABS_MT_POSITION_Y); } if (SYN_CAP_PALMDETECT(priv->capabilities)) @@ -759,9 +1196,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - input_abs_set_res(dev, ABS_X, priv->x_res); - input_abs_set_res(dev, ABS_Y, priv->y_res); - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); /* Clickpads report only left button */ @@ -793,21 +1227,21 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; if (retry > 1) - printk(KERN_DEBUG "Synaptics reconnected after %d tries\n", - retry); + psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to query device.\n"); return -1; } if (synaptics_set_absolute_mode(psmouse)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to initialize device.\n"); return -1; } if (synaptics_set_advanced_gesture_mode(psmouse)) { - printk(KERN_ERR "Advanced gesture mode reconnect failed.\n"); + psmouse_err(psmouse, + "Advanced gesture mode reconnect failed.\n"); return -1; } @@ -815,12 +1249,12 @@ static int synaptics_reconnect(struct psmouse *psmouse) old_priv.model_id != priv->model_id || old_priv.capabilities != priv->capabilities || old_priv.ext_cap != priv->ext_cap) { - printk(KERN_ERR "Synaptics hardware appears to be different: " - "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); + psmouse_err(psmouse, + "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", + old_priv.identity, priv->identity, + old_priv.model_id, priv->model_id, + old_priv.capabilities, priv->capabilities, + old_priv.ext_cap, priv->ext_cap); return -1; } @@ -901,7 +1335,8 @@ int synaptics_init(struct psmouse *psmouse) * just fine. */ if (broken_olpc_ec) { - printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n"); + psmouse_info(psmouse, + "OLPC XO detected, not enabling Synaptics protocol.\n"); return -ENODEV; } @@ -912,26 +1347,28 @@ int synaptics_init(struct psmouse *psmouse) psmouse_reset(psmouse); if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to query device.\n"); goto init_fail; } if (synaptics_set_absolute_mode(psmouse)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to initialize device.\n"); goto init_fail; } if (synaptics_set_advanced_gesture_mode(psmouse)) { - printk(KERN_ERR "Advanced gesture mode init failed.\n"); + psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); goto init_fail; } priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", - SYN_ID_MODEL(priv->identity), - SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c); + psmouse_info(psmouse, + "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", + SYN_ID_MODEL(priv->identity), + SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), + priv->model_id, + priv->capabilities, priv->ext_cap, priv->ext_cap_0c); set_input_params(psmouse->dev, priv); @@ -963,8 +1400,9 @@ int synaptics_init(struct psmouse *psmouse) * the same rate as a standard PS/2 mouse). */ if (psmouse->rate >= 80 && impaired_toshiba_kbc) { - printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", - dmi_get_system_info(DMI_PRODUCT_NAME)); + psmouse_info(psmouse, + "Toshiba %s detected, limiting rate to 40pps.\n", + dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index ca040aa80fa7..622aea8dd7e0 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -74,6 +74,8 @@ * 2 0x04 reduced filtering firmware does less filtering on * position data, driver should watch * for noise. + * 2 0x08 image sensor image sensor tracks 5 fingers, but only + * reports 2. * 2 0x20 report min query 0x0f gives min coord reported */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ @@ -82,6 +84,7 @@ #define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) #define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) +#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) @@ -112,9 +115,18 @@ #define SYN_REDUCED_FILTER_FUZZ 8 /* - * A structure to describe the state of the touchpad hardware (buttons and pad) + * A structure to describe which internal touchpad finger slots are being + * reported in raw packets. */ +struct synaptics_mt_state { + int count; /* num fingers being tracked */ + int sgm; /* which slot is reported by sgm pkt */ + int agm; /* which slot is reported by agm pkt*/ +}; +/* + * A structure to describe the state of the touchpad hardware (buttons and pad) + */ struct synaptics_hw_state { int x; int y; @@ -127,6 +139,9 @@ struct synaptics_hw_state { unsigned int down:1; unsigned char ext_buttons; signed char scroll; + + /* As reported in last AGM-CONTACT packets */ + struct synaptics_mt_state mt_state; }; struct synaptics_data { @@ -146,7 +161,15 @@ struct synaptics_data { struct serio *pt_port; /* Pass-through serio port */ - struct synaptics_hw_state mt; /* current gesture packet */ + struct synaptics_mt_state mt_state; /* Current mt finger state */ + bool mt_state_lost; /* mt_state may be incorrect */ + + /* + * Last received Advanced Gesture Mode (AGM) packet. An AGM packet + * contains position data for a second contact, at half resolution. + */ + struct synaptics_hw_state agm; + bool agm_pending; /* new AGM packet received */ }; void synaptics_module_init(void); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index cba3c84d2f21..4b755cb5b38c 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -570,7 +570,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client, "Requesting IRQ: %d\n", touch->client->irq); ret = request_irq(touch->client->irq, synaptics_i2c_irq, - IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_FALLING, DRIVER_NAME, touch); if (ret) { dev_warn(&touch->client->dev, @@ -619,7 +619,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int synaptics_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); |