diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2018-03-17 20:58:05 +0300 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2018-03-17 20:58:05 +0300 |
commit | ba521f1bd202237d2c1dea95e4213169b8c6ba01 (patch) | |
tree | 2a0a1b5e158a2a2311221f05b873cbae6672643d | |
parent | 83fc580dcc2f0f36114477c4ac7adbe5c32329a3 (diff) | |
parent | 3aceaa34d7723c2556555b05ad04a89ce2d66374 (diff) | |
download | linux-ba521f1bd202237d2c1dea95e4213169b8c6ba01.tar.xz |
Merge branch 'psmouse' into next
Merge various PS/2 handling improvements.
-rw-r--r-- | drivers/input/mouse/alps.c | 30 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 40 | ||||
-rw-r--r-- | drivers/input/mouse/lifebook.c | 62 | ||||
-rw-r--r-- | drivers/input/mouse/logips2pp.c | 152 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 189 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 5 | ||||
-rw-r--r-- | drivers/input/mouse/sentelic.c | 11 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 8 | ||||
-rw-r--r-- | drivers/input/mouse/trackpoint.c | 60 | ||||
-rw-r--r-- | drivers/input/serio/libps2.c | 322 | ||||
-rw-r--r-- | include/linux/libps2.h | 38 |
11 files changed, 521 insertions, 396 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index dbe57da8c1a1..f9c7f2452264 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -827,7 +827,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; - int x, y, z, left, right, middle; + int x, y, z; /* * We can use Byte5 to distinguish if the packet is from Touchpad @@ -847,9 +847,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse) x = packet[1] | ((packet[3] & 0x20) << 2); y = packet[2] | ((packet[3] & 0x40) << 1); z = packet[4]; - left = packet[3] & 0x01; - right = packet[3] & 0x02; - middle = packet[3] & 0x04; /* To prevent the cursor jump when finger lifted */ if (x == 0x7F && y == 0x7F && z == 0x7F) @@ -859,9 +856,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse) input_report_rel(dev2, REL_X, (char)x / 4); input_report_rel(dev2, REL_Y, -((char)y / 4)); - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); + psmouse_report_standard_buttons(dev2, packet[3]); input_sync(dev2); return; @@ -871,8 +866,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse) x = packet[1] | ((packet[3] & 0x78) << 4); y = packet[2] | ((packet[4] & 0x78) << 4); z = packet[5]; - left = packet[3] & 0x01; - right = packet[3] & 0x02; if (z > 30) input_report_key(dev, BTN_TOUCH, 1); @@ -888,8 +881,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_FINGER, z > 0); /* v6 touchpad does not have middle button */ - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); + packet[3] &= ~BIT(2); + psmouse_report_standard_buttons(dev2, packet[3]); input_sync(dev); } @@ -1098,7 +1091,7 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; struct input_dev *dev2 = priv->dev2; - int x, y, z, left, right, middle; + int x, y, z; /* It should be a DualPoint when received trackstick packet */ if (!(priv->flags & ALPS_DUALPOINT)) { @@ -1112,16 +1105,10 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) ((packet[3] & 0x20) << 1); z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1); - left = (packet[1] & 0x01); - right = (packet[1] & 0x02) >> 1; - middle = (packet[1] & 0x04) >> 2; - input_report_rel(dev2, REL_X, (char)x); input_report_rel(dev2, REL_Y, -((char)y)); - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); + psmouse_report_standard_buttons(dev2, packet[1]); input_sync(dev2); } @@ -1503,10 +1490,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse, alps_report_buttons(dev, dev2, packet[0] & 1, packet[0] & 2, packet[0] & 4); - input_report_rel(dev, REL_X, - packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, - packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); + psmouse_report_standard_motion(dev, packet); input_sync(dev); } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a4aaa748e987..db47a5e1d114 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -35,7 +35,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) { - if (psmouse_sliced_command(psmouse, c) || + if (ps2_sliced_command(&psmouse->ps2dev, c) || ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); return -1; @@ -107,8 +107,8 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, switch (etd->hw_version) { case 1: - if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) || - psmouse_sliced_command(psmouse, reg) || + if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) || + ps2_sliced_command(&psmouse->ps2dev, reg) || ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { rc = -1; } @@ -162,9 +162,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, switch (etd->hw_version) { case 1: - if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) || - psmouse_sliced_command(psmouse, reg) || - psmouse_sliced_command(psmouse, val) || + if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) || + ps2_sliced_command(&psmouse->ps2dev, reg) || + ps2_sliced_command(&psmouse->ps2dev, val) || ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) { rc = -1; } @@ -279,8 +279,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); - input_report_key(dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + + psmouse_report_standard_buttons(dev, packet[0]); if (etd->fw_version < 0x020000 && (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { @@ -390,8 +390,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); - input_report_key(dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + psmouse_report_standard_buttons(dev, packet[0]); if (etd->reports_pressure) { input_report_abs(dev, ABS_PRESSURE, pres); input_report_abs(dev, ABS_TOOL_WIDTH, width); @@ -434,9 +433,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse, x = packet[4] - (int)((packet[1]^0x80) << 1); y = (int)((packet[2]^0x80) << 1) - packet[5]; - input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02); - input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04); + psmouse_report_standard_buttons(tp_dev, packet[0]); input_report_rel(tp_dev, REL_X, x); input_report_rel(tp_dev, REL_Y, y); @@ -526,12 +523,10 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); /* For clickpads map both buttons to BTN_LEFT */ - if (etd->fw_version & 0x001000) { + if (etd->fw_version & 0x001000) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); - } else { - input_report_key(dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); - } + else + psmouse_report_standard_buttons(dev, packet[0]); input_report_abs(dev, ABS_PRESSURE, pres); input_report_abs(dev, ABS_TOOL_WIDTH, width); @@ -546,13 +541,10 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; /* For clickpads map both buttons to BTN_LEFT */ - if (etd->fw_version & 0x001000) { + if (etd->fw_version & 0x001000) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); - } else { - input_report_key(dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); - input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04); - } + else + psmouse_report_standard_buttons(dev, packet[0]); input_mt_report_pointer_emulation(dev, true); input_sync(dev); diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 13d324cef7df..a5765f747c02 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -17,6 +17,7 @@ #include <linux/libps2.h> #include <linux/dmi.h> #include <linux/slab.h> +#include <linux/types.h> #include "psmouse.h" #include "lifebook.h" @@ -136,7 +137,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) struct lifebook_data *priv = psmouse->private; struct input_dev *dev1 = psmouse->dev; struct input_dev *dev2 = priv ? priv->dev2 : NULL; - unsigned char *packet = psmouse->packet; + u8 *packet = psmouse->packet; bool relative_packet = packet[0] & 0x08; if (relative_packet || !lifebook_use_6byte_proto) { @@ -188,14 +189,10 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) } if (dev2) { - if (relative_packet) { - input_report_rel(dev2, REL_X, - ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); - input_report_rel(dev2, REL_Y, - -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); - } - input_report_key(dev2, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02); + if (relative_packet) + psmouse_report_standard_motion(dev2, packet); + + psmouse_report_standard_buttons(dev2, packet[0]); input_sync(dev2); } @@ -205,10 +202,12 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) static int lifebook_absolute_mode(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param; + u8 param; + int error; - if (psmouse_reset(psmouse)) - return -1; + error = psmouse_reset(psmouse); + if (error) + return error; /* * Enable absolute output -- ps2_command fails always but if @@ -224,15 +223,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) static void lifebook_relative_mode(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param = 0x06; + u8 param = 0x06; ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); } static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) { - static const unsigned char params[] = { 0, 1, 2, 2, 3 }; - unsigned char p; + static const u8 params[] = { 0, 1, 2, 2, 3 }; + u8 p; if (resolution == 0 || resolution > 400) resolution = 400; @@ -257,11 +256,11 @@ static void lifebook_disconnect(struct psmouse *psmouse) int lifebook_detect(struct psmouse *psmouse, bool set_properties) { if (!lifebook_present) - return -1; + return -ENXIO; if (desired_serio_phys && strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys)) - return -1; + return -ENXIO; if (set_properties) { psmouse->vendor = "Fujitsu"; @@ -294,10 +293,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) dev2->id.version = 0x0000; dev2->dev.parent = &psmouse->ps2dev.serio->dev; - dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - dev2->keybit[BIT_WORD(BTN_LEFT)] = - BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); + input_set_capability(dev2, EV_REL, REL_X); + input_set_capability(dev2, EV_REL, REL_Y); + input_set_capability(dev2, EV_KEY, BTN_LEFT); + input_set_capability(dev2, EV_KEY, BTN_RIGHT); error = input_register_device(priv->dev2); if (error) @@ -316,21 +315,26 @@ int lifebook_init(struct psmouse *psmouse) { struct input_dev *dev1 = psmouse->dev; int max_coord = lifebook_use_6byte_proto ? 4096 : 1024; + int error; + + error = lifebook_absolute_mode(psmouse); + if (error) + return error; - if (lifebook_absolute_mode(psmouse)) - return -1; + /* Clear default capabilities */ + bitmap_zero(dev1->evbit, EV_CNT); + bitmap_zero(dev1->relbit, REL_CNT); + bitmap_zero(dev1->keybit, KEY_CNT); - dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); - dev1->relbit[0] = 0; - dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0; - dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(dev1, EV_KEY, BTN_TOUCH); input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); if (!desired_serio_phys) { - if (lifebook_create_relative_device(psmouse)) { + error = lifebook_create_relative_device(psmouse); + if (error) { lifebook_relative_mode(psmouse); - return -1; + return error; } } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index ef9c97f5e3d7..3d5637e6fa5f 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -9,9 +9,11 @@ * the Free Software Foundation. */ +#include <linux/bitops.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/libps2.h> +#include <linux/types.h> #include "psmouse.h" #include "logips2pp.h" @@ -22,12 +24,12 @@ #define PS2PP_KIND_TRACKMAN 4 /* Logitech mouse features */ -#define PS2PP_WHEEL 0x01 -#define PS2PP_HWHEEL 0x02 -#define PS2PP_SIDE_BTN 0x04 -#define PS2PP_EXTRA_BTN 0x08 -#define PS2PP_TASK_BTN 0x10 -#define PS2PP_NAV_BTN 0x20 +#define PS2PP_WHEEL BIT(0) +#define PS2PP_HWHEEL BIT(1) +#define PS2PP_SIDE_BTN BIT(2) +#define PS2PP_EXTRA_BTN BIT(3) +#define PS2PP_TASK_BTN BIT(4) +#define PS2PP_NAV_BTN BIT(5) struct ps2pp_info { u8 model; @@ -42,7 +44,7 @@ struct ps2pp_info { static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; - unsigned char *packet = psmouse->packet; + u8 *packet = psmouse->packet; if (psmouse->pktcnt < 3) return PSMOUSE_GOOD_DATA; @@ -58,28 +60,30 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) case 0x0d: /* Mouse extra info */ - input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 8) - (int) (packet[2] & 7)); - input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + input_report_rel(dev, + packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + -sign_extend32(packet[2], 3)); + input_report_key(dev, BTN_SIDE, packet[2] & BIT(4)); + input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5)); break; case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ - input_report_key(dev, BTN_SIDE, (packet[2]) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); - input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); - input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); + input_report_key(dev, BTN_SIDE, packet[2] & BIT(0)); + input_report_key(dev, BTN_EXTRA, packet[2] & BIT(1)); + input_report_key(dev, BTN_TASK, packet[2] & BIT(2)); + input_report_key(dev, BTN_BACK, packet[2] & BIT(3)); + input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4)); break; case 0x0f: /* TouchPad extra info */ - input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); - packet[0] = packet[2] | 0x08; + input_report_rel(dev, + packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + -sign_extend32(packet[2] >> 4, 3)); + packet[0] = packet[2] | BIT(3); break; default: @@ -88,16 +92,14 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) (packet[1] >> 4) | (packet[0] & 0x30)); break; } + + psmouse_report_standard_buttons(dev, packet[0]); + } else { /* Standard PS/2 motion data */ - input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); + psmouse_report_standard_packet(dev, packet); } - input_report_key(dev, BTN_LEFT, packet[0] & 1); - input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); - input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); - input_sync(dev); return PSMOUSE_FULL_PACKET; @@ -111,13 +113,17 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) * Ugly. */ -static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) +static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command) { - if (psmouse_sliced_command(psmouse, command)) - return -1; + int error; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) - return -1; + error = ps2_sliced_command(&psmouse->ps2dev, command); + if (error) + return error; + + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300); + if (error) + return error; return 0; } @@ -133,7 +139,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + u8 param[4]; ps2pp_cmd(psmouse, param, 0x32); @@ -171,7 +177,7 @@ static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, } PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, - ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); + ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); /* * Support 800 dpi resolution _only_ if the user wants it (there are good @@ -179,11 +185,12 @@ PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, * also good reasons to use it, let the user decide). */ -static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution) +static void ps2pp_set_resolution(struct psmouse *psmouse, + unsigned int resolution) { if (resolution > 400) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param = 3; + u8 param = 3; ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); @@ -196,7 +203,8 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio static void ps2pp_disconnect(struct psmouse *psmouse) { - device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_smartscroll.dattr); } static const struct ps2pp_info *get_model_info(unsigned char model) @@ -269,24 +277,24 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct input_dev *input_dev = psmouse->dev; if (model_info->features & PS2PP_SIDE_BTN) - __set_bit(BTN_SIDE, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_SIDE); if (model_info->features & PS2PP_EXTRA_BTN) - __set_bit(BTN_EXTRA, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_EXTRA); if (model_info->features & PS2PP_TASK_BTN) - __set_bit(BTN_TASK, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_TASK); if (model_info->features & PS2PP_NAV_BTN) { - __set_bit(BTN_FORWARD, input_dev->keybit); - __set_bit(BTN_BACK, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_FORWARD); + input_set_capability(input_dev, EV_KEY, BTN_BACK); } if (model_info->features & PS2PP_WHEEL) - __set_bit(REL_WHEEL, input_dev->relbit); + input_set_capability(input_dev, EV_REL, REL_WHEEL); if (model_info->features & PS2PP_HWHEEL) - __set_bit(REL_HWHEEL, input_dev->relbit); + input_set_capability(input_dev, EV_REL, REL_HWHEEL); switch (model_info->kind) { @@ -318,6 +326,30 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, } } +static int ps2pp_setup_protocol(struct psmouse *psmouse, + const struct ps2pp_info *model_info) +{ + int error; + + psmouse->protocol_handler = ps2pp_process_byte; + psmouse->pktsize = 3; + + if (model_info->kind != PS2PP_KIND_TP3) { + psmouse->set_resolution = ps2pp_set_resolution; + psmouse->disconnect = ps2pp_disconnect; + + error = device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_smartscroll.dattr); + if (error) { + psmouse_err(psmouse, + "failed to create smartscroll sysfs attribute, error: %d\n", + error); + return error; + } + } + + return 0; +} /* * Logitech magic init. Detect whether the mouse is a Logitech one @@ -328,9 +360,9 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, int ps2pp_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - unsigned char model, buttons; const struct ps2pp_info *model_info; + u8 param[4]; + u8 model, buttons; bool use_ps2pp = false; int error; @@ -346,7 +378,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties) buttons = param[1]; if (!model || !buttons) - return -1; + return -ENXIO; model_info = get_model_info(model); if (model_info) { @@ -368,7 +400,8 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties) param[0] = 0; if (!ps2_command(ps2dev, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { + param[0] == 0x06 && param[1] == 0x00 && + param[2] == 0x14) { use_ps2pp = true; } @@ -387,7 +420,9 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties) } } else { - psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model); + psmouse_warn(psmouse, + "Detected unknown Logitech mouse model %d\n", + model); } if (set_properties) { @@ -395,31 +430,18 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties) psmouse->model = model; if (use_ps2pp) { - psmouse->protocol_handler = ps2pp_process_byte; - psmouse->pktsize = 3; - - if (model_info->kind != PS2PP_KIND_TP3) { - psmouse->set_resolution = ps2pp_set_resolution; - psmouse->disconnect = ps2pp_disconnect; - - error = device_create_file(&ps2dev->serio->dev, - &psmouse_attr_smartscroll.dattr); - if (error) { - psmouse_err(psmouse, - "failed to create smartscroll sysfs attribute, error: %d\n", - error); - return -1; - } - } + error = ps2pp_setup_protocol(psmouse, model_info); + if (error) + return error; } if (buttons >= 3) - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); } - return use_ps2pp ? 0 : -1; + return use_ps2pp ? 0 : -ENXIO; } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 8ac9e03c05b4..8900c3166ebf 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define psmouse_fmt(fmt) fmt +#include <linux/bitops.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> @@ -23,6 +24,7 @@ #include <linux/init.h> #include <linux/libps2.h> #include <linux/mutex.h> +#include <linux/types.h> #include "psmouse.h" #include "synaptics.h" @@ -68,6 +70,10 @@ static bool psmouse_smartscroll = true; module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); +static bool psmouse_a4tech_2wheels; +module_param_named(a4tech_workaround, psmouse_a4tech_2wheels, bool, 0644); +MODULE_PARM_DESC(a4tech_workaround, "A4Tech second scroll wheel workaround, 1 = enabled, 0 = disabled (default)."); + static unsigned int psmouse_resetafter = 5; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); @@ -116,13 +122,30 @@ static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; -static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) +void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) { input_report_key(dev, BTN_LEFT, buttons & BIT(0)); input_report_key(dev, BTN_MIDDLE, buttons & BIT(2)); input_report_key(dev, BTN_RIGHT, buttons & BIT(1)); } +void psmouse_report_standard_motion(struct input_dev *dev, u8 *packet) +{ + int x, y; + + x = packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0; + y = packet[2] ? packet[2] - ((packet[0] << 3) & 0x100) : 0; + + input_report_rel(dev, REL_X, x); + input_report_rel(dev, REL_Y, -y); +} + +void psmouse_report_standard_packet(struct input_dev *dev, u8 *packet) +{ + psmouse_report_standard_buttons(dev, packet[0]); + psmouse_report_standard_motion(dev, packet); +} + /* * psmouse_process_byte() analyzes the PS/2 data stream and reports * relevant events to the input module once full packet has arrived. @@ -130,7 +153,8 @@ static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; - unsigned char *packet = psmouse->packet; + u8 *packet = psmouse->packet; + int wheel; if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; @@ -140,39 +164,52 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) switch (psmouse->protocol->type) { case PSMOUSE_IMPS: /* IntelliMouse has scroll wheel */ - input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); + input_report_rel(dev, REL_WHEEL, -(s8) packet[3]); break; case PSMOUSE_IMEX: /* Scroll wheel and buttons on IntelliMouse Explorer */ switch (packet[3] & 0xC0) { case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); + input_report_rel(dev, REL_WHEEL, + -sign_extend32(packet[3], 5)); break; case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); + input_report_rel(dev, REL_HWHEEL, + -sign_extend32(packet[3], 5)); break; case 0x00: case 0xC0: - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); - input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); + wheel = sign_extend32(packet[3], 3); + + /* + * Some A4Tech mice have two scroll wheels, with first + * one reporting +/-1 in the lower nibble, and second + * one reporting +/-2. + */ + if (psmouse_a4tech_2wheels && abs(wheel) > 1) + input_report_rel(dev, REL_HWHEEL, wheel / 2); + else + input_report_rel(dev, REL_WHEEL, -wheel); + + input_report_key(dev, BTN_SIDE, BIT(4)); + input_report_key(dev, BTN_EXTRA, BIT(5)); break; } break; case PSMOUSE_GENPS: /* Report scroll buttons on NetMice */ - input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); + input_report_rel(dev, REL_WHEEL, -(s8) packet[3]); /* Extra buttons on Genius NewNet 3D */ - input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); - input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); + input_report_key(dev, BTN_SIDE, BIT(6)); + input_report_key(dev, BTN_EXTRA, BIT(7)); break; case PSMOUSE_THINKPS: /* Extra button on ThinkingMouse */ - input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1); + input_report_key(dev, BTN_EXTRA, BIT(3)); /* * Without this bit of weirdness moving up gives wildly @@ -186,8 +223,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) * Cortron PS2 Trackball reports SIDE button in the * 4th bit of the first byte. */ - input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1); - packet[0] |= 0x08; + input_report_key(dev, BTN_SIDE, BIT(3)); + packet[0] |= BIT(3); break; default: @@ -195,11 +232,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) } /* Generic PS/2 Mouse */ - psmouse_report_standard_buttons(dev, - packet[0] | psmouse->extra_buttons); - - input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); + packet[0] |= psmouse->extra_buttons; + psmouse_report_standard_packet(dev, packet); input_sync(dev); @@ -255,7 +289,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse) psmouse_notice(psmouse, "issuing reconnect request\n"); serio_reconnect(psmouse->ps2dev.serio); - return -1; + return -EIO; } } psmouse->pktcnt = 0; @@ -306,7 +340,7 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data) * for normal processing or gathering them as command response. */ static irqreturn_t psmouse_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) + u8 data, unsigned int flags) { struct psmouse *psmouse = serio_get_drvdata(serio); @@ -398,40 +432,19 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } /* - * psmouse_sliced_command() sends an extended PS/2 command to the mouse - * using sliced syntax, understood by advanced devices, such as Logitech - * or Synaptics touchpads. The command is encoded as: - * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu - * is the command. - */ -int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) -{ - int i; - - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) - return -1; - - for (i = 6; i >= 0; i -= 2) { - unsigned char d = (command >> i) & 3; - if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - - return 0; -} - -/* * psmouse_reset() resets the mouse into power-on state. */ int psmouse_reset(struct psmouse *psmouse) { - unsigned char param[2]; + u8 param[2]; + int error; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)) - return -1; + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT); + if (error) + return error; if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID) - return -1; + return -EIO; return 0; } @@ -441,8 +454,8 @@ int psmouse_reset(struct psmouse *psmouse) */ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) { - static const unsigned char params[] = { 0, 1, 2, 2, 3 }; - unsigned char p; + static const u8 params[] = { 0, 1, 2, 2, 3 }; + u8 p; if (resolution == 0 || resolution > 200) resolution = 200; @@ -457,11 +470,12 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) */ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) { - static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; - unsigned char r; + static const u8 rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; + u8 r; int i = 0; - while (rates[i] > rate) i++; + while (rates[i] > rate) + i++; r = rates[i]; ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); psmouse->rate = r; @@ -533,7 +547,7 @@ bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) static int genius_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + u8 param[4]; param[0] = 3; ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); @@ -543,7 +557,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55) - return -1; + return -ENODEV; if (set_properties) { __set_bit(BTN_MIDDLE, psmouse->dev->keybit); @@ -565,7 +579,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties) static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; + u8 param[2]; param[0] = 200; ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); @@ -576,7 +590,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); if (param[0] != 3) - return -1; + return -ENODEV; if (set_properties) { __set_bit(BTN_MIDDLE, psmouse->dev->keybit); @@ -598,7 +612,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; + u8 param[2]; intellimouse_detect(psmouse, 0); @@ -611,7 +625,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); if (param[0] != 4) - return -1; + return -ENODEV; /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ param[0] = 200; @@ -644,8 +658,8 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) static int thinking_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; + u8 param[2]; + static const u8 seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; int i; param[0] = 10; @@ -659,7 +673,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); if (param[0] != 2) - return -1; + return -ENODEV; if (set_properties) { __set_bit(BTN_MIDDLE, psmouse->dev->keybit); @@ -687,7 +701,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) * We have no way of figuring true number of buttons so let's * assume that the device has 3. */ - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE); } return 0; @@ -942,20 +956,17 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) { struct input_dev *input_dev = psmouse->dev; - memset(input_dev->evbit, 0, sizeof(input_dev->evbit)); - memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - memset(input_dev->relbit, 0, sizeof(input_dev->relbit)); - memset(input_dev->absbit, 0, sizeof(input_dev->absbit)); - memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit)); - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_REL, input_dev->evbit); + bitmap_zero(input_dev->evbit, EV_CNT); + bitmap_zero(input_dev->keybit, KEY_CNT); + bitmap_zero(input_dev->relbit, REL_CNT); + bitmap_zero(input_dev->absbit, ABS_CNT); + bitmap_zero(input_dev->mscbit, MSC_CNT); - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_LEFT); + input_set_capability(input_dev, EV_KEY, BTN_RIGHT); - __set_bit(REL_X, input_dev->relbit); - __set_bit(REL_Y, input_dev->relbit); + input_set_capability(input_dev, EV_REL, REL_X); + input_set_capability(input_dev, EV_REL, REL_Y); __set_bit(INPUT_PROP_POINTER, input_dev->propbit); @@ -1225,7 +1236,8 @@ static int psmouse_extensions(struct psmouse *psmouse, static int psmouse_probe(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; + u8 param[2]; + int error; /* * First, we check if it's a mouse. It should send 0x00 or 0x03 in @@ -1234,20 +1246,22 @@ static int psmouse_probe(struct psmouse *psmouse) * subsequent ID queries, probably due to a firmware bug. */ param[0] = 0xa5; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) - return -1; + error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); + if (error) + return error; if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04 && param[0] != 0xff) - return -1; + return -ENODEV; /* * Then we reset and disable the mouse so that it doesn't generate * events. */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) - psmouse_warn(psmouse, "Failed to reset mouse on %s\n", - ps2dev->serio->phys); + error = ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + if (error) + psmouse_warn(psmouse, "Failed to reset mouse on %s: %d\n", + ps2dev->serio->phys, error); return 0; } @@ -1288,10 +1302,13 @@ int psmouse_activate(struct psmouse *psmouse) */ int psmouse_deactivate(struct psmouse *psmouse) { - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { - psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", - psmouse->ps2dev.serio->phys); - return -1; + int error; + + error = ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE); + if (error) { + psmouse_warn(psmouse, "Failed to deactivate mouse on %s: %d\n", + psmouse->ps2dev.serio->phys, error); + return error; } psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 8cd453808cc7..71ac50082c8b 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -131,7 +131,6 @@ struct psmouse { void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, unsigned long delay); -int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); int psmouse_reset(struct psmouse *psmouse); void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); @@ -140,6 +139,10 @@ int psmouse_activate(struct psmouse *psmouse); int psmouse_deactivate(struct psmouse *psmouse); bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]); +void psmouse_report_standard_buttons(struct input_dev *, u8 buttons); +void psmouse_report_standard_motion(struct input_dev *, u8 *packet); +void psmouse_report_standard_packet(struct input_dev *, u8 *packet); + struct psmouse_attribute { struct device_attribute dattr; void *data; diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 11c32ac8234b..1d6010d463e2 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -710,7 +710,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; unsigned char button_status = 0, lscroll = 0, rscroll = 0; unsigned short abs_x, abs_y, fgrs = 0; - int rel_x, rel_y; if (psmouse->pktcnt < 4) return PSMOUSE_GOOD_DATA; @@ -840,15 +839,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) /* * Standard PS/2 Mouse */ - input_report_key(dev, BTN_LEFT, packet[0] & 1); - input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); - input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); - - rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; - rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; - - input_report_rel(dev, REL_X, rel_x); - input_report_rel(dev, REL_Y, rel_y); + psmouse_report_standard_packet(dev, packet); break; } diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index dcb8e0cfaa1a..0d7c781674ca 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -84,7 +84,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode) u8 param[1]; int error; - error = psmouse_sliced_command(psmouse, mode); + error = ps2_sliced_command(&psmouse->ps2dev, mode); if (error) return error; @@ -190,7 +190,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) { int error; - error = psmouse_sliced_command(psmouse, cmd); + error = ps2_sliced_command(&psmouse->ps2dev, cmd); if (error) return error; @@ -547,7 +547,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static u8 param = 0xc8; int error; - error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL); + error = ps2_sliced_command(&psmouse->ps2dev, SYN_QUE_MODEL); if (error) return error; @@ -614,7 +614,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c) u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ int error; - error = psmouse_sliced_command(parent, c); + error = ps2_sliced_command(&parent->ps2dev, c); if (error) return error; diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index bbd29220dbe9..6590d10f166f 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -33,18 +33,15 @@ static const char * const trackpoint_variants[] = { */ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) { - u8 results[2]; - int tries = 0; + u8 param[2] = { TP_POR }; + int err; - /* Issue POR command, and repeat up to once if 0xFC00 received */ - do { - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR))) - return -1; - } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2); + err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND)); + if (err) + return err; /* Check for success response -- 0xAA00 */ - if (results[0] != 0xAA || results[1] != 0x00) + if (param[0] != 0xAA || param[1] != 0x00) return -ENODEV; return 0; @@ -55,49 +52,39 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) */ static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results) { - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { - return -1; - } + results[0] = loc; - return 0; + return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND)); } static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val) { - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { - return -1; - } + u8 param[3] = { TP_WRITE_MEM, loc, val }; - return 0; + return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND)); } static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask) { + u8 param[3] = { TP_TOGGLE, loc, mask }; + /* Bad things will happen if the loc param isn't in this range */ if (loc < 0x20 || loc >= 0x2F) - return -1; - - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { - return -1; - } + return -EINVAL; - return 0; + return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND)); } static int trackpoint_update_bit(struct ps2dev *ps2dev, u8 loc, u8 mask, u8 value) { - int retval = 0; + int retval; u8 data; - trackpoint_read(ps2dev, loc, &data); + retval = trackpoint_read(ps2dev, loc, &data); + if (retval) + return retval; + if (((data & mask) == mask) != !!value) retval = trackpoint_toggle_bit(ps2dev, loc, mask); @@ -142,9 +129,9 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, return err; *field = value; - trackpoint_write(&psmouse->ps2dev, attr->command, value); + err = trackpoint_write(&psmouse->ps2dev, attr->command, value); - return count; + return err ?: count; } #define TRACKPOINT_INT_ATTR(_name, _command, _default) \ @@ -175,10 +162,11 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, if (*field != value) { *field = value; - trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask); + err = trackpoint_toggle_bit(&psmouse->ps2dev, + attr->command, attr->mask); } - return count; + return err ?: count; } diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 83e9c663aa67..e6a07e68d1ff 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -26,31 +26,79 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); MODULE_DESCRIPTION("PS/2 driver library"); MODULE_LICENSE("GPL"); +static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, + unsigned int timeout, unsigned int max_attempts) + __releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock) +{ + int attempt = 0; + int error; + + lockdep_assert_held(&ps2dev->serio->lock); + + do { + ps2dev->nak = 1; + ps2dev->flags |= PS2_FLAG_ACK; + + serio_continue_rx(ps2dev->serio); + + error = serio_write(ps2dev->serio, byte); + if (error) + dev_dbg(&ps2dev->serio->dev, + "failed to write %#02x: %d\n", byte, error); + else + wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_ACK), + msecs_to_jiffies(timeout)); + + serio_pause_rx(ps2dev->serio); + } while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts); + + ps2dev->flags &= ~PS2_FLAG_ACK; + + if (!error) { + switch (ps2dev->nak) { + case 0: + break; + case PS2_RET_NAK: + error = -EAGAIN; + break; + case PS2_RET_ERR: + error = -EPROTO; + break; + default: + error = -EIO; + break; + } + } + + if (error || attempt > 1) + dev_dbg(&ps2dev->serio->dev, + "%02x - %d (%x), attempt %d\n", + byte, error, ps2dev->nak, attempt); + + return error; +} + /* * ps2_sendbyte() sends a byte to the device and waits for acknowledge. - * It doesn't handle retransmission, though it could - because if there - * is a need for retransmissions device has to be replaced anyway. + * It doesn't handle retransmission, the caller is expected to handle + * it when needed. * * ps2_sendbyte() can only be called from a process context. */ -int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) +int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) { + int retval; + serio_pause_rx(ps2dev->serio); - ps2dev->nak = 1; - ps2dev->flags |= PS2_FLAG_ACK; - serio_continue_rx(ps2dev->serio); - if (serio_write(ps2dev->serio, byte) == 0) - wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_ACK), - msecs_to_jiffies(timeout)); + retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1); + dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak); - serio_pause_rx(ps2dev->serio); - ps2dev->flags &= ~PS2_FLAG_ACK; serio_continue_rx(ps2dev->serio); - return -ps2dev->nak; + return retval; } EXPORT_SYMBOL(ps2_sendbyte); @@ -75,7 +123,7 @@ EXPORT_SYMBOL(ps2_end_command); * and discards them. */ -void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) +void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) { if (maxbytes > sizeof(ps2dev->cmdbuf)) { WARN_ON(1); @@ -102,9 +150,9 @@ EXPORT_SYMBOL(ps2_drain); * known keyboard IDs. */ -int ps2_is_keyboard_id(char id_byte) +bool ps2_is_keyboard_id(u8 id_byte) { - static const char keyboard_ids[] = { + static const u8 keyboard_ids[] = { 0xab, /* Regular keyboards */ 0xac, /* NCD Sun keyboard */ 0x2b, /* Trust keyboard, translated */ @@ -123,49 +171,50 @@ EXPORT_SYMBOL(ps2_is_keyboard_id); * completion. */ -static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) +static int ps2_adjust_timeout(struct ps2dev *ps2dev, + unsigned int command, unsigned int timeout) { switch (command) { - case PS2_CMD_RESET_BAT: - /* - * Device has sent the first response byte after - * reset command, reset is thus done, so we can - * shorten the timeout. - * The next byte will come soon (keyboard) or not - * at all (mouse). - */ - if (timeout > msecs_to_jiffies(100)) - timeout = msecs_to_jiffies(100); - break; + case PS2_CMD_RESET_BAT: + /* + * Device has sent the first response byte after + * reset command, reset is thus done, so we can + * shorten the timeout. + * The next byte will come soon (keyboard) or not + * at all (mouse). + */ + if (timeout > msecs_to_jiffies(100)) + timeout = msecs_to_jiffies(100); + break; - case PS2_CMD_GETID: - /* - * Microsoft Natural Elite keyboard responds to - * the GET ID command as it were a mouse, with - * a single byte. Fail the command so atkbd will - * use alternative probe to detect it. - */ - if (ps2dev->cmdbuf[1] == 0xaa) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = 0; - serio_continue_rx(ps2dev->serio); - timeout = 0; - } - - /* - * If device behind the port is not a keyboard there - * won't be 2nd byte of ID response. - */ - if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = ps2dev->cmdcnt = 0; - serio_continue_rx(ps2dev->serio); - timeout = 0; - } - break; + case PS2_CMD_GETID: + /* + * Microsoft Natural Elite keyboard responds to + * the GET ID command as it were a mouse, with + * a single byte. Fail the command so atkbd will + * use alternative probe to detect it. + */ + if (ps2dev->cmdbuf[1] == 0xaa) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } - default: - break; + /* + * If device behind the port is not a keyboard there + * won't be 2nd byte of ID response. + */ + if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = ps2dev->cmdcnt = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } + break; + + default: + break; } return timeout; @@ -178,50 +227,60 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) * ps2_command() can only be called from a process context */ -int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) { - int timeout; - int send = (command >> 12) & 0xf; - int receive = (command >> 8) & 0xf; - int rc = -1; + unsigned int timeout; + unsigned int send = (command >> 12) & 0xf; + unsigned int receive = (command >> 8) & 0xf; + int rc; int i; + u8 send_param[16]; if (receive > sizeof(ps2dev->cmdbuf)) { WARN_ON(1); - return -1; + return -EINVAL; } if (send && !param) { WARN_ON(1); - return -1; + return -EINVAL; } + memcpy(send_param, param, send); + serio_pause_rx(ps2dev->serio); + ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; if (receive && param) for (i = 0; i < receive; i++) ps2dev->cmdbuf[(receive - 1) - i] = param[i]; - serio_continue_rx(ps2dev->serio); + + /* Signal that we are sending the command byte */ + ps2dev->flags |= PS2_FLAG_ACK_CMD; /* * Some devices (Synaptics) peform the reset before * ACKing the reset command, and so it can take a long * time before the ACK arrives. */ - if (ps2_sendbyte(ps2dev, command & 0xff, - command == PS2_CMD_RESET_BAT ? 1000 : 200)) { - serio_pause_rx(ps2dev->serio); + timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200; + + rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2); + if (rc) goto out_reset_flags; - } + + /* Now we are sending command parameters, if any */ + ps2dev->flags &= ~PS2_FLAG_ACK_CMD; for (i = 0; i < send; i++) { - if (ps2_sendbyte(ps2dev, param[i], 200)) { - serio_pause_rx(ps2dev->serio); + rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2); + if (rc) goto out_reset_flags; - } } + serio_continue_rx(ps2dev->serio); + /* * The reset command takes a long time to execute. */ @@ -243,8 +302,11 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) for (i = 0; i < receive; i++) param[i] = ps2dev->cmdbuf[(receive - 1) - i]; - if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) + if (ps2dev->cmdcnt && + (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) { + rc = -EPROTO; goto out_reset_flags; + } rc = 0; @@ -252,11 +314,21 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) ps2dev->flags = 0; serio_continue_rx(ps2dev->serio); - return rc; + dev_dbg(&ps2dev->serio->dev, + "%02x [%*ph] - %x/%08lx [%*ph]\n", + command & 0xff, send, send_param, + ps2dev->nak, ps2dev->flags, + receive, param ?: send_param); + + /* + * ps_command() handles resends itself, so do not leak -EAGAIN + * to the callers. + */ + return rc != -EAGAIN ? rc : -EPROTO; } EXPORT_SYMBOL(__ps2_command); -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) { int rc; @@ -269,6 +341,39 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) EXPORT_SYMBOL(ps2_command); /* + * ps2_sliced_command() sends an extended PS/2 command to the mouse + * using sliced syntax, understood by advanced devices, such as Logitech + * or Synaptics touchpads. The command is encoded as: + * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu + * is the command. + */ + +int ps2_sliced_command(struct ps2dev *ps2dev, u8 command) +{ + int i; + int retval; + + ps2_begin_command(ps2dev); + + retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11); + if (retval) + goto out; + + for (i = 6; i >= 0; i -= 2) { + u8 d = (command >> i) & 3; + retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES); + if (retval) + break; + } + +out: + dev_dbg(&ps2dev->serio->dev, "%02x - %d\n", command, retval); + ps2_end_command(ps2dev); + return retval; +} +EXPORT_SYMBOL(ps2_sliced_command); + +/* * ps2_init() initializes ps2dev structure */ @@ -286,42 +391,53 @@ EXPORT_SYMBOL(ps2_init); * to properly process ACK/NAK of a command from a PS/2 device. */ -int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) +bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data) { switch (data) { - case PS2_RET_ACK: - ps2dev->nak = 0; + case PS2_RET_ACK: + ps2dev->nak = 0; + break; + + case PS2_RET_NAK: + ps2dev->flags |= PS2_FLAG_NAK; + ps2dev->nak = PS2_RET_NAK; + break; + + case PS2_RET_ERR: + if (ps2dev->flags & PS2_FLAG_NAK) { + ps2dev->flags &= ~PS2_FLAG_NAK; + ps2dev->nak = PS2_RET_ERR; break; + } - case PS2_RET_NAK: - ps2dev->flags |= PS2_FLAG_NAK; - ps2dev->nak = PS2_RET_NAK; + /* + * Workaround for mice which don't ACK the Get ID command. + * These are valid mouse IDs that we recognize. + */ + case 0x00: + case 0x03: + case 0x04: + if (ps2dev->flags & PS2_FLAG_WAITID) { + ps2dev->nak = 0; break; - - case PS2_RET_ERR: - if (ps2dev->flags & PS2_FLAG_NAK) { - ps2dev->flags &= ~PS2_FLAG_NAK; - ps2dev->nak = PS2_RET_ERR; - break; - } - + } + /* Fall through */ + default: /* - * Workaround for mice which don't ACK the Get ID command. - * These are valid mouse IDs that we recognize. + * Do not signal errors if we get unexpected reply while + * waiting for an ACK to the initial (first) command byte: + * the device might not be quiesced yet and continue + * delivering data. + * Note that we reset PS2_FLAG_WAITID flag, so the workaround + * for mice not acknowledging the Get ID command only triggers + * on the 1st byte; if device spews data we really want to see + * a real ACK from it. */ - case 0x00: - case 0x03: - case 0x04: - if (ps2dev->flags & PS2_FLAG_WAITID) { - ps2dev->nak = 0; - break; - } - /* Fall through */ - default: - return 0; + dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data); + ps2dev->flags &= ~PS2_FLAG_WAITID; + return ps2dev->flags & PS2_FLAG_ACK_CMD; } - if (!ps2dev->nak) { ps2dev->flags &= ~PS2_FLAG_NAK; if (ps2dev->cmdcnt) @@ -334,7 +450,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) if (data != PS2_RET_ACK) ps2_handle_response(ps2dev, data); - return 1; + return true; } EXPORT_SYMBOL(ps2_handle_ack); @@ -344,7 +460,7 @@ EXPORT_SYMBOL(ps2_handle_ack); * waiting for completion of the command. */ -int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) +bool ps2_handle_response(struct ps2dev *ps2dev, u8 data) { if (ps2dev->cmdcnt) ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; @@ -360,7 +476,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) wake_up(&ps2dev->wait); } - return 1; + return true; } EXPORT_SYMBOL(ps2_handle_response); diff --git a/include/linux/libps2.h b/include/linux/libps2.h index 4ad06e824f76..5f18fe02ae37 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -10,7 +10,13 @@ * the Free Software Foundation. */ +#include <linux/bitops.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/wait.h> +#define PS2_CMD_SETSCALE11 0x00e6 +#define PS2_CMD_SETRES 0x10e8 #define PS2_CMD_GETID 0x02f2 #define PS2_CMD_RESET_BAT 0x02ff @@ -20,11 +26,12 @@ #define PS2_RET_NAK 0xfe #define PS2_RET_ERR 0xfc -#define PS2_FLAG_ACK 1 /* Waiting for ACK/NAK */ -#define PS2_FLAG_CMD 2 /* Waiting for command to finish */ -#define PS2_FLAG_CMD1 4 /* Waiting for the first byte of command response */ -#define PS2_FLAG_WAITID 8 /* Command execiting is GET ID */ -#define PS2_FLAG_NAK 16 /* Last transmission was NAKed */ +#define PS2_FLAG_ACK BIT(0) /* Waiting for ACK/NAK */ +#define PS2_FLAG_CMD BIT(1) /* Waiting for a command to finish */ +#define PS2_FLAG_CMD1 BIT(2) /* Waiting for the first byte of command response */ +#define PS2_FLAG_WAITID BIT(3) /* Command executing is GET ID */ +#define PS2_FLAG_NAK BIT(4) /* Last transmission was NAKed */ +#define PS2_FLAG_ACK_CMD BIT(5) /* Waiting to ACK the command (first) byte */ struct ps2dev { struct serio *serio; @@ -36,21 +43,22 @@ struct ps2dev { wait_queue_head_t wait; unsigned long flags; - unsigned char cmdbuf[8]; - unsigned char cmdcnt; - unsigned char nak; + u8 cmdbuf[8]; + u8 cmdcnt; + u8 nak; }; void ps2_init(struct ps2dev *ps2dev, struct serio *serio); -int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); -void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); +int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout); +void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout); void ps2_begin_command(struct ps2dev *ps2dev); void ps2_end_command(struct ps2dev *ps2dev); -int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); -int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); -int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); +int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command); +int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command); +int ps2_sliced_command(struct ps2dev *ps2dev, u8 command); +bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data); +bool ps2_handle_response(struct ps2dev *ps2dev, u8 data); void ps2_cmd_aborted(struct ps2dev *ps2dev); -int ps2_is_keyboard_id(char id); +bool ps2_is_keyboard_id(u8 id); #endif /* _LIBPS2_H */ |