diff options
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/mouse/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 22 | ||||
-rw-r--r-- | drivers/input/mouse/byd.c | 337 | ||||
-rw-r--r-- | drivers/input/mouse/byd.h | 18 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa.c | 22 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa.h | 14 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa_gen3.c | 108 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa_gen5.c | 99 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa_gen6.c | 4 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/focaltech.c | 22 | ||||
-rw-r--r-- | drivers/input/mouse/focaltech.h | 8 | ||||
-rw-r--r-- | drivers/input/mouse/logips2pp.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/logips2pp.h | 4 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 784 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 1 |
17 files changed, 976 insertions, 482 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 17f97e5e11e7..096abb4ad5cd 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -48,6 +48,16 @@ config MOUSE_PS2_ALPS If unsure, say Y. +config MOUSE_PS2_BYD + bool "BYD PS/2 mouse protocol extension" if EXPERT + default y + depends on MOUSE_PS2 + help + Say Y here if you have a BYD PS/2 touchpad connected to + your system. + + If unsure, say Y. + config MOUSE_PS2_LOGIPS2PP bool "Logitech PS/2++ mouse protocol extension" if EXPERT default y diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index ee6a6e9563d4..6168b134937b 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -28,6 +28,7 @@ cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o psmouse-objs := psmouse-base.o synaptics.o focaltech.o psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o +psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 41e6cb501e6a..936f07a4e35f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -31,6 +31,7 @@ #define ALPS_CMD_NIBBLE_10 0x01f2 #define ALPS_REG_BASE_RUSHMORE 0xc2c0 +#define ALPS_REG_BASE_V7 0xc2c0 #define ALPS_REG_BASE_PINNACLE 0x0000 static const struct alps_nibble_commands alps_v3_nibble_commands[] = { @@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse) return 0; } -static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) +static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base) { int ret = -EIO, reg_val; @@ -2128,15 +2129,12 @@ error: static int alps_hw_init_v3(struct psmouse *psmouse) { + struct alps_data *priv = psmouse->private; struct ps2dev *ps2dev = &psmouse->ps2dev; int reg_val; unsigned char param[4]; - reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); - if (reg_val == -EIO) - goto error; - - if (reg_val == 0 && + if ((priv->flags & ALPS_DUALPOINT) && alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) goto error; @@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->decode_fields = alps_decode_pinnacle; priv->nibble_commands = alps_v3_nibble_commands; priv->addr_command = PSMOUSE_CMD_RESET_WRAP; + + if (alps_probe_trackstick_v3_v7(psmouse, + ALPS_REG_BASE_PINNACLE) < 0) + priv->flags &= ~ALPS_DUALPOINT; + break; case ALPS_PROTO_V3_RUSHMORE: @@ -2625,8 +2628,8 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->x_bits = 16; priv->y_bits = 12; - if (alps_probe_trackstick_v3(psmouse, - ALPS_REG_BASE_RUSHMORE) < 0) + if (alps_probe_trackstick_v3_v7(psmouse, + ALPS_REG_BASE_RUSHMORE) < 0) priv->flags &= ~ALPS_DUALPOINT; break; @@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse, if (priv->fw_ver[1] != 0xba) priv->flags |= ALPS_BUTTONPAD; + if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0) + priv->flags &= ~ALPS_DUALPOINT; + break; case ALPS_PROTO_V8: diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c new file mode 100644 index 000000000000..9425e0f6c5ce --- /dev/null +++ b/drivers/input/mouse/byd.c @@ -0,0 +1,337 @@ +/* + * BYD TouchPad PS/2 mouse driver + * + * Copyright (C) 2015 Chris Diamand <chris@diamand.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/libps2.h> +#include <linux/serio.h> + +#include "psmouse.h" +#include "byd.h" + +#define PS2_Y_OVERFLOW BIT_MASK(7) +#define PS2_X_OVERFLOW BIT_MASK(6) +#define PS2_Y_SIGN BIT_MASK(5) +#define PS2_X_SIGN BIT_MASK(4) +#define PS2_ALWAYS_1 BIT_MASK(3) +#define PS2_MIDDLE BIT_MASK(2) +#define PS2_RIGHT BIT_MASK(1) +#define PS2_LEFT BIT_MASK(0) + +/* + * The touchpad reports gestures in the last byte of each packet. It can take + * any of the following values: + */ + +/* One-finger scrolling in one of the edge scroll zones. */ +#define BYD_SCROLLUP 0xCA +#define BYD_SCROLLDOWN 0x36 +#define BYD_SCROLLLEFT 0xCB +#define BYD_SCROLLRIGHT 0x35 +/* Two-finger scrolling. */ +#define BYD_2DOWN 0x2B +#define BYD_2UP 0xD5 +#define BYD_2LEFT 0xD6 +#define BYD_2RIGHT 0x2A +/* Pinching in or out. */ +#define BYD_ZOOMOUT 0xD8 +#define BYD_ZOOMIN 0x28 +/* Three-finger swipe. */ +#define BYD_3UP 0xD3 +#define BYD_3DOWN 0x2D +#define BYD_3LEFT 0xD4 +#define BYD_3RIGHT 0x2C +/* Four-finger swipe. */ +#define BYD_4UP 0xCD +#define BYD_4DOWN 0x33 + +int byd_detect(struct psmouse *psmouse, bool set_properties) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[4]; + + param[0] = 0x03; + param[1] = 0x00; + param[2] = 0x00; + param[3] = 0x00; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + return -1; + + if (param[1] != 0x03 || param[2] != 0x64) + return -ENODEV; + + psmouse_dbg(psmouse, "BYD touchpad detected\n"); + + if (set_properties) { + psmouse->vendor = "BYD"; + psmouse->name = "TouchPad"; + } + + return 0; +} + +static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + u8 *pkt = psmouse->packet; + + if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { + psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n", + pkt[0]); + return PSMOUSE_BAD_DATA; + } + + if (psmouse->pktcnt < psmouse->pktsize) + return PSMOUSE_GOOD_DATA; + + /* Otherwise, a full packet has been received */ + switch (pkt[3]) { + case 0: { + /* Standard packet */ + /* Sign-extend if a sign bit is set. */ + unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; + unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; + int dx = signx | (int) pkt[1]; + int dy = signy | (int) pkt[2]; + + input_report_rel(psmouse->dev, REL_X, dx); + input_report_rel(psmouse->dev, REL_Y, -dy); + + input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT); + input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT); + input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE); + break; + } + + case BYD_SCROLLDOWN: + case BYD_2DOWN: + input_report_rel(dev, REL_WHEEL, -1); + break; + + case BYD_SCROLLUP: + case BYD_2UP: + input_report_rel(dev, REL_WHEEL, 1); + break; + + case BYD_SCROLLLEFT: + case BYD_2LEFT: + input_report_rel(dev, REL_HWHEEL, -1); + break; + + case BYD_SCROLLRIGHT: + case BYD_2RIGHT: + input_report_rel(dev, REL_HWHEEL, 1); + break; + + case BYD_ZOOMOUT: + case BYD_ZOOMIN: + case BYD_3UP: + case BYD_3DOWN: + case BYD_3LEFT: + case BYD_3RIGHT: + case BYD_4UP: + case BYD_4DOWN: + break; + + default: + psmouse_warn(psmouse, + "Unrecognized Z: pkt = %02x %02x %02x %02x\n", + psmouse->packet[0], psmouse->packet[1], + psmouse->packet[2], psmouse->packet[3]); + return PSMOUSE_BAD_DATA; + } + + input_sync(dev); + + return PSMOUSE_FULL_PACKET; +} + +/* Send a sequence of bytes, where each is ACKed before the next is sent. */ +static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len) +{ + unsigned int i; + + for (i = 0; i < len; ++i) { + if (ps2_command(&psmouse->ps2dev, NULL, seq[i])) + return -1; + } + return 0; +} + +/* Keep scrolling after fingers are removed. */ +#define SCROLL_INERTIAL 0x01 +#define SCROLL_NO_INERTIAL 0x02 + +/* Clicking can be done by tapping or pressing. */ +#define CLICK_BOTH 0x01 +/* Clicking can only be done by pressing. */ +#define CLICK_PRESS_ONLY 0x02 + +static int byd_enable(struct psmouse *psmouse) +{ + const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 }; + const u8 seq2[] = { + 0xD3, 0x01, + 0xD0, 0x00, + 0xD0, 0x04, + /* Whether clicking is done by tapping or pressing. */ + 0xD4, CLICK_PRESS_ONLY, + 0xD5, 0x01, + 0xD7, 0x03, + /* Vertical and horizontal one-finger scroll zone inertia. */ + 0xD8, SCROLL_INERTIAL, + 0xDA, 0x05, + 0xDB, 0x02, + 0xE4, 0x05, + 0xD6, 0x01, + 0xDE, 0x04, + 0xE3, 0x01, + 0xCF, 0x00, + 0xD2, 0x03, + /* Vertical and horizontal two-finger scrolling inertia. */ + 0xE5, SCROLL_INERTIAL, + 0xD9, 0x02, + 0xD9, 0x07, + 0xDC, 0x03, + 0xDD, 0x03, + 0xDF, 0x03, + 0xE1, 0x03, + 0xD1, 0x00, + 0xCE, 0x00, + 0xCC, 0x00, + 0xE0, 0x00, + 0xE2, 0x01 + }; + u8 param[4]; + + if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1))) + return -1; + + /* Send a 0x01 command, which should return 4 bytes. */ + if (ps2_command(&psmouse->ps2dev, param, 0x0401)) + return -1; + + if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2))) + return -1; + + return 0; +} + +/* + * Send the set of PS/2 commands required to make it identify as an + * intellimouse with 4-byte instead of 3-byte packets. + */ +static int byd_send_intellimouse_sequence(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + u8 param[4]; + int i; + const struct { + u16 command; + u8 arg; + } seq[] = { + { PSMOUSE_CMD_RESET_BAT, 0 }, + { PSMOUSE_CMD_RESET_BAT, 0 }, + { PSMOUSE_CMD_GETID, 0 }, + { PSMOUSE_CMD_SETSCALE11, 0 }, + { PSMOUSE_CMD_SETSCALE11, 0 }, + { PSMOUSE_CMD_SETSCALE11, 0 }, + { PSMOUSE_CMD_GETINFO, 0 }, + { PSMOUSE_CMD_SETRES, 0x03 }, + { PSMOUSE_CMD_SETRATE, 0xC8 }, + { PSMOUSE_CMD_SETRATE, 0x64 }, + { PSMOUSE_CMD_SETRATE, 0x50 }, + { PSMOUSE_CMD_GETID, 0 }, + { PSMOUSE_CMD_SETRATE, 0xC8 }, + { PSMOUSE_CMD_SETRATE, 0xC8 }, + { PSMOUSE_CMD_SETRATE, 0x50 }, + { PSMOUSE_CMD_GETID, 0 }, + { PSMOUSE_CMD_SETRATE, 0x64 }, + { PSMOUSE_CMD_SETRES, 0x03 }, + { PSMOUSE_CMD_ENABLE, 0 } + }; + + memset(param, 0, sizeof(param)); + for (i = 0; i < ARRAY_SIZE(seq); ++i) { + param[0] = seq[i].arg; + if (ps2_command(ps2dev, param, seq[i].command)) + return -1; + } + + return 0; +} + +static int byd_reset_touchpad(struct psmouse *psmouse) +{ + if (byd_send_intellimouse_sequence(psmouse)) + return -EIO; + + if (byd_enable(psmouse)) + return -EIO; + + return 0; +} + +static int byd_reconnect(struct psmouse *psmouse) +{ + int retry = 0, error = 0; + + psmouse_dbg(psmouse, "Reconnect\n"); + do { + psmouse_reset(psmouse); + if (retry) + ssleep(1); + error = byd_detect(psmouse, 0); + } while (error && ++retry < 3); + + if (error) + return error; + + psmouse_dbg(psmouse, "Reconnected after %d attempts\n", retry); + + error = byd_reset_touchpad(psmouse); + if (error) { + psmouse_err(psmouse, "Unable to initialize device\n"); + return error; + } + + return 0; +} + +int byd_init(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + + if (psmouse_reset(psmouse)) + return -EIO; + + if (byd_reset_touchpad(psmouse)) + return -EIO; + + psmouse->reconnect = byd_reconnect; + psmouse->protocol_handler = byd_process_byte; + psmouse->pktsize = 4; + psmouse->resync_time = 0; + + __set_bit(BTN_MIDDLE, dev->keybit); + __set_bit(REL_WHEEL, dev->relbit); + __set_bit(REL_HWHEEL, dev->relbit); + + return 0; +} diff --git a/drivers/input/mouse/byd.h b/drivers/input/mouse/byd.h new file mode 100644 index 000000000000..d6c120cf36cd --- /dev/null +++ b/drivers/input/mouse/byd.h @@ -0,0 +1,18 @@ +#ifndef _BYD_H +#define _BYD_H + +#ifdef CONFIG_MOUSE_PS2_BYD +int byd_detect(struct psmouse *psmouse, bool set_properties); +int byd_init(struct psmouse *psmouse); +#else +static inline int byd_detect(struct psmouse *psmouse, bool set_properties) +{ + return -ENOSYS; +} +static inline int byd_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif /* CONFIG_MOUSE_PS2_BYD */ + +#endif /* _BYD_H */ diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index eb76b61418f3..dc2394292088 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -383,7 +383,7 @@ static int cyapa_open(struct input_dev *input) * when in operational mode. */ error = cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error) { dev_warn(dev, "set active power failed: %d\n", error); goto out; @@ -424,7 +424,8 @@ static void cyapa_close(struct input_dev *input) pm_runtime_set_suspended(dev); if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE); mutex_unlock(&cyapa->state_sync_lock); } @@ -534,7 +535,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) */ if (!input || cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); /* Gen3 always using polling mode for command. */ if (cyapa->gen >= CYAPA_GEN5) enable_irq(cyapa->client->irq); @@ -550,7 +551,7 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) disable_irq(cyapa->client->irq); if (!input || cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_OFF, 0, false); + PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE); } } @@ -617,7 +618,8 @@ static int cyapa_initialize(struct cyapa *cyapa) /* Power down the device until we need it. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE); return 0; } @@ -634,7 +636,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa) /* Avoid command failures when TP was in OFF state. */ if (cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); error = cyapa_detect(cyapa); if (error) @@ -654,7 +656,7 @@ out: /* Reset to power OFF state to save power when no user open. */ if (cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_OFF, 0, false); + PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE); } else if (!error && cyapa->operational) { /* * Make sure only enable runtime PM when device is @@ -1392,7 +1394,7 @@ static int __maybe_unused cyapa_suspend(struct device *dev) power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode : PWR_MODE_OFF; error = cyapa->ops->set_power_mode(cyapa, power_mode, - cyapa->suspend_sleep_time, true); + cyapa->suspend_sleep_time, CYAPA_PM_SUSPEND); if (error) dev_err(dev, "suspend set power mode failed: %d\n", error); @@ -1447,7 +1449,7 @@ static int __maybe_unused cyapa_runtime_suspend(struct device *dev) error = cyapa->ops->set_power_mode(cyapa, cyapa->runtime_suspend_power_mode, cyapa->runtime_suspend_sleep_time, - false); + CYAPA_PM_RUNTIME_SUSPEND); if (error) dev_warn(dev, "runtime suspend failed: %d\n", error); @@ -1460,7 +1462,7 @@ static int __maybe_unused cyapa_runtime_resume(struct device *dev) int error; error = cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_RUNTIME_RESUME); if (error) dev_warn(dev, "runtime resume failed: %d\n", error); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index b812bba8cdd7..ce951fe4516a 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -250,6 +250,15 @@ struct cyapa; typedef bool (*cb_sort)(struct cyapa *, u8 *, int); +enum cyapa_pm_stage { + CYAPA_PM_DEACTIVE, + CYAPA_PM_ACTIVE, + CYAPA_PM_SUSPEND, + CYAPA_PM_RESUME, + CYAPA_PM_RUNTIME_SUSPEND, + CYAPA_PM_RUNTIME_RESUME, +}; + struct cyapa_dev_ops { int (*check_fw)(struct cyapa *, const struct firmware *); int (*bl_enter)(struct cyapa *); @@ -273,7 +282,7 @@ struct cyapa_dev_ops { int (*sort_empty_output_data)(struct cyapa *, u8 *, int *, cb_sort); - int (*set_power_mode)(struct cyapa *, u8, u16, bool); + int (*set_power_mode)(struct cyapa *, u8, u16, enum cyapa_pm_stage); int (*set_proximity)(struct cyapa *, bool); }; @@ -289,6 +298,9 @@ struct cyapa_pip_cmd_states { u8 *resp_data; int *resp_len; + enum cyapa_pm_stage pm_stage; + struct mutex pm_stage_lock; + u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE]; u8 empty_buf[CYAPA_REG_MAP_SIZE]; }; diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 1a9d12ae7538..f9600753eca5 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -269,6 +269,7 @@ static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { { CYAPA_SMBUS_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */ }; +static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa); /* * cyapa_smbus_read_block - perform smbus block read command @@ -950,12 +951,14 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode) * Device power mode can only be set when device is in operational mode. */ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, - u16 always_unused, bool is_suspend_unused) + u16 always_unused, enum cyapa_pm_stage pm_stage) { - int ret; + struct input_dev *input = cyapa->input; u8 power; int tries; - u16 sleep_time; + int sleep_time; + int interval; + int ret; if (cyapa->state != CYAPA_STATE_OP) return 0; @@ -977,7 +980,7 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, if ((ret & PWR_MODE_MASK) == power_mode) return 0; - sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK); + sleep_time = (int)cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK); power = ret; power &= ~PWR_MODE_MASK; power |= power_mode & PWR_MODE_MASK; @@ -995,7 +998,23 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, * doing so before issuing the next command may result in errors * depending on the command's content. */ - msleep(sleep_time); + if (cyapa->operational && input && input->users && + (pm_stage == CYAPA_PM_RUNTIME_SUSPEND || + pm_stage == CYAPA_PM_RUNTIME_RESUME)) { + /* Try to polling in 120Hz, read may fail, just ignore it. */ + interval = 1000 / 120; + while (sleep_time > 0) { + if (sleep_time > interval) + msleep(interval); + else + msleep(sleep_time); + sleep_time -= interval; + cyapa_gen3_try_poll_handler(cyapa); + } + } else { + msleep(sleep_time); + } + return ret; } @@ -1112,7 +1131,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa) * may cause problems, so we set the power mode first here. */ error = cyapa_gen3_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error) dev_err(dev, "%s: set full power mode failed: %d\n", __func__, error); @@ -1168,32 +1187,16 @@ static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa) return false; } -static int cyapa_gen3_irq_handler(struct cyapa *cyapa) +static int cyapa_gen3_event_process(struct cyapa *cyapa, + struct cyapa_reg_data *data) { struct input_dev *input = cyapa->input; - struct device *dev = &cyapa->client->dev; - struct cyapa_reg_data data; int num_fingers; - int ret; int i; - ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); - if (ret != sizeof(data)) { - dev_err(dev, "failed to read report data, (%d)\n", ret); - return -EINVAL; - } - - if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || - (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || - (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { - dev_err(dev, "invalid device state bytes, %02x %02x\n", - data.device_status, data.finger_btn); - return -EINVAL; - } - - num_fingers = (data.finger_btn >> 4) & 0x0f; + num_fingers = (data->finger_btn >> 4) & 0x0f; for (i = 0; i < num_fingers; i++) { - const struct cyapa_touch *touch = &data.touches[i]; + const struct cyapa_touch *touch = &data->touches[i]; /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ int slot = touch->id - 1; @@ -1210,18 +1213,65 @@ static int cyapa_gen3_irq_handler(struct cyapa *cyapa) if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) input_report_key(input, BTN_LEFT, - !!(data.finger_btn & OP_DATA_LEFT_BTN)); + !!(data->finger_btn & OP_DATA_LEFT_BTN)); if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) input_report_key(input, BTN_MIDDLE, - !!(data.finger_btn & OP_DATA_MIDDLE_BTN)); + !!(data->finger_btn & OP_DATA_MIDDLE_BTN)); if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) input_report_key(input, BTN_RIGHT, - !!(data.finger_btn & OP_DATA_RIGHT_BTN)); + !!(data->finger_btn & OP_DATA_RIGHT_BTN)); input_sync(input); return 0; } +static int cyapa_gen3_irq_handler(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + struct cyapa_reg_data data; + int ret; + + ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); + if (ret != sizeof(data)) { + dev_err(dev, "failed to read report data, (%d)\n", ret); + return -EINVAL; + } + + if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || + (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || + (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { + dev_err(dev, "invalid device state bytes: %02x %02x\n", + data.device_status, data.finger_btn); + return -EINVAL; + } + + return cyapa_gen3_event_process(cyapa, &data); +} + +/* + * This function will be called in the cyapa_gen3_set_power_mode function, + * and it's known that it may failed in some situation after the set power + * mode command was sent. So this function is aimed to avoid the knwon + * and unwanted output I2C and data parse error messages. + */ +static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa) +{ + struct cyapa_reg_data data; + int ret; + + ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); + if (ret != sizeof(data)) + return -EINVAL; + + if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || + (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || + (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) + return -EINVAL; + + return cyapa_gen3_event_process(cyapa, &data); + +} + static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; } static int cyapa_gen3_bl_initiate(struct cyapa *cyapa, const struct firmware *fw) { return 0; } diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 118ba977181e..5775d40b3d53 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -342,6 +342,9 @@ u8 pip_bl_read_app_info[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, 0xff, 0xfe, 0xfd, 0x5a }; +static int cyapa_pip_event_process(struct cyapa *cyapa, + struct cyapa_pip_report_data *report_data); + int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa) { struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; @@ -350,6 +353,9 @@ int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa) atomic_set(&pip->cmd_issued, 0); mutex_init(&pip->cmd_lock); + mutex_init(&pip->pm_stage_lock); + pip->pm_stage = CYAPA_PM_DEACTIVE; + pip->resp_sort_func = NULL; pip->in_progress_cmd = PIP_INVALID_CMD; pip->resp_data = NULL; @@ -397,6 +403,38 @@ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) return 0; } +static void cyapa_set_pip_pm_state(struct cyapa *cyapa, + enum cyapa_pm_stage pm_stage) +{ + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; + + mutex_lock(&pip->pm_stage_lock); + pip->pm_stage = pm_stage; + mutex_unlock(&pip->pm_stage_lock); +} + +static void cyapa_reset_pip_pm_state(struct cyapa *cyapa) +{ + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; + + /* Indicates the pip->pm_stage is not valid. */ + mutex_lock(&pip->pm_stage_lock); + pip->pm_stage = CYAPA_PM_DEACTIVE; + mutex_unlock(&pip->pm_stage_lock); +} + +static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa) +{ + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; + enum cyapa_pm_stage pm_stage; + + mutex_lock(&pip->pm_stage_lock); + pm_stage = pip->pm_stage; + mutex_unlock(&pip->pm_stage_lock); + + return pm_stage; +} + /** * This function is aimed to dump all not read data in Gen5 trackpad * before send any command, otherwise, the interrupt line will be blocked. @@ -404,7 +442,9 @@ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) int cyapa_empty_pip_output_data(struct cyapa *cyapa, u8 *buf, int *len, cb_sort func) { + struct input_dev *input = cyapa->input; struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; + enum cyapa_pm_stage pm_stage = cyapa_get_pip_pm_state(cyapa); int length; int report_count; int empty_count; @@ -478,6 +518,12 @@ int cyapa_empty_pip_output_data(struct cyapa *cyapa, *len = length; /* Response found, success. */ return 0; + } else if (cyapa->operational && input && input->users && + (pm_stage == CYAPA_PM_RUNTIME_RESUME || + pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) { + /* Parse the data and report it if it's valid. */ + cyapa_pip_event_process(cyapa, + (struct cyapa_pip_report_data *)pip->empty_buf); } error = -EINVAL; @@ -1566,15 +1612,17 @@ int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time, bool is_suspend) + u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage) { struct device *dev = &cyapa->client->dev; u8 power_state; - int error; + int error = 0; if (cyapa->state != CYAPA_STATE_GEN5_APP) return 0; + cyapa_set_pip_pm_state(cyapa, pm_stage); + if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, @@ -1597,7 +1645,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, power_mode == PWR_MODE_BTN_ONLY || PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { /* Has in correct power mode state, early return. */ - return 0; + goto out; } } @@ -1605,11 +1653,11 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); if (error) { dev_err(dev, "enter deep sleep fail: %d\n", error); - return error; + goto out; } PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); - return 0; + goto out; } /* @@ -1621,7 +1669,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); if (error) { dev_err(dev, "deep sleep wake fail: %d\n", error); - return error; + goto out; } } @@ -1630,7 +1678,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, GEN5_POWER_STATE_ACTIVE); if (error) { dev_err(dev, "change to active fail: %d\n", error); - return error; + goto out; } PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); @@ -1639,7 +1687,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, GEN5_POWER_STATE_BTN_ONLY); if (error) { dev_err(dev, "fail to button only mode: %d\n", error); - return error; + goto out; } PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); @@ -1664,7 +1712,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, if (error) { dev_err(dev, "set power state to 0x%02x failed: %d\n", power_state, error); - return error; + goto out; } /* @@ -1677,14 +1725,16 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, * is suspending which may cause interrupt line unable to be * asserted again. */ - if (is_suspend) + if (pm_stage == CYAPA_PM_SUSPEND) cyapa_gen5_disable_pip_report(cyapa); PIP_DEV_SET_PWR_STATE(cyapa, cyapa_sleep_time_to_pwr_cmd(sleep_time)); } - return 0; +out: + cyapa_reset_pip_pm_state(cyapa); + return error; } int cyapa_pip_resume_scanning(struct cyapa *cyapa) @@ -2513,7 +2563,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen5_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); @@ -2715,7 +2765,6 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) struct device *dev = &cyapa->client->dev; struct cyapa_pip_report_data report_data; unsigned int report_len; - u8 report_id; int ret; if (!cyapa_is_pip_app_mode(cyapa)) { @@ -2752,7 +2801,23 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) return -EINVAL; } - report_id = report_data.report_head[PIP_RESP_REPORT_ID_OFFSET]; + return cyapa_pip_event_process(cyapa, &report_data); +} + +static int cyapa_pip_event_process(struct cyapa *cyapa, + struct cyapa_pip_report_data *report_data) +{ + struct device *dev = &cyapa->client->dev; + unsigned int report_len; + u8 report_id; + + report_len = get_unaligned_le16( + &report_data->report_head[PIP_RESP_LENGTH_OFFSET]); + /* Idle, no data for report. */ + if (report_len == PIP_RESP_LENGTH_SIZE) + return 0; + + report_id = report_data->report_head[PIP_RESP_REPORT_ID_OFFSET]; if (report_id == PIP_WAKEUP_EVENT_REPORT_ID && report_len == PIP_WAKEUP_EVENT_SIZE) { /* @@ -2805,11 +2870,11 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) } if (report_id == PIP_TOUCH_REPORT_ID) - cyapa_pip_report_touches(cyapa, &report_data); + cyapa_pip_report_touches(cyapa, report_data); else if (report_id == PIP_PROXIMITY_REPORT_ID) - cyapa_pip_report_proximity(cyapa, &report_data); + cyapa_pip_report_proximity(cyapa, report_data); else - cyapa_pip_report_buttons(cyapa, &report_data); + cyapa_pip_report_buttons(cyapa, report_data); return 0; } diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index e4eb048d1bf6..016397850b1b 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -425,7 +425,7 @@ static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time, bool is_suspend) + u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage) { struct device *dev = &cyapa->client->dev; struct gen6_interval_setting *interval_setting = @@ -689,7 +689,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen6_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0, false); + PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 537ebb0e193a..78f93cf68840 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, ETP_WMAX_V2, 0, 0); } - input_mt_init_slots(dev, 2, 0); + input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT); 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; diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index 4d5576de81be..c8c6a8cc329d 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) return 0; } -static void focaltech_reset(struct psmouse *psmouse) -{ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - psmouse_reset(psmouse); -} - #ifdef CONFIG_MOUSE_PS2_FOCALTECH /* @@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse) return 0; } +static void focaltech_reset(struct psmouse *psmouse) +{ + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + psmouse_reset(psmouse); +} + static void focaltech_disconnect(struct psmouse *psmouse) { focaltech_reset(psmouse); @@ -456,14 +456,4 @@ fail: kfree(priv); return error; } - -#else /* CONFIG_MOUSE_PS2_FOCALTECH */ - -int focaltech_init(struct psmouse *psmouse) -{ - focaltech_reset(psmouse); - - return 0; -} - #endif /* CONFIG_MOUSE_PS2_FOCALTECH */ diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h index ca61ebff373e..783b28e8e10b 100644 --- a/drivers/input/mouse/focaltech.h +++ b/drivers/input/mouse/focaltech.h @@ -18,6 +18,14 @@ #define _FOCALTECH_H int focaltech_detect(struct psmouse *psmouse, bool set_properties); + +#ifdef CONFIG_MOUSE_PS2_FOCALTECH int focaltech_init(struct psmouse *psmouse); +#else +static inline int focaltech_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif #endif diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 136e222e2a16..422da1cd9e76 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, * that support it. */ -int ps2pp_init(struct psmouse *psmouse, bool set_properties) +int ps2pp_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h index 0c186f0282d9..bf629453e095 100644 --- a/drivers/input/mouse/logips2pp.h +++ b/drivers/input/mouse/logips2pp.h @@ -12,9 +12,9 @@ #define _LOGIPS2PP_H #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP -int ps2pp_init(struct psmouse *psmouse, bool set_properties); +int ps2pp_detect(struct psmouse *psmouse, bool set_properties); #else -inline int ps2pp_init(struct psmouse *psmouse, bool set_properties) +static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index ad18dab0ac47..39d1becd35c9 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -37,6 +37,7 @@ #include "cypress_ps2.h" #include "focaltech.h" #include "vmmouse.h" +#include "byd.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -119,6 +120,7 @@ struct psmouse_protocol { enum psmouse_type type; bool maxproto; bool ignore_parity; /* Protocol should ignore parity errors from KBC */ + bool try_passthru; /* Try protocol also on passthrough ports */ const char *name; const char *alias; int (*detect)(struct psmouse *, bool); @@ -129,7 +131,6 @@ struct psmouse_protocol { * psmouse_process_byte() analyzes the PS/2 data stream and reports * relevant events to the input module once full packet has arrived. */ - psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; @@ -138,22 +139,16 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; -/* - * Full packet accumulated, process it - */ + /* Full packet accumulated, process it */ -/* - * Scroll wheel on IntelliMice, scroll buttons on NetMice - */ - - if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) + switch (psmouse->type) { + case PSMOUSE_IMPS: + /* IntelliMouse has scroll wheel */ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); + break; -/* - * Scroll wheel and buttons on IntelliMouse Explorer - */ - - if (psmouse->type == PSMOUSE_IMEX) { + 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)); @@ -168,39 +163,42 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); break; } - } + break; -/* - * Extra buttons on Genius NewNet 3D - */ + case PSMOUSE_GENPS: + /* Report scroll buttons on NetMice */ + input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); - if (psmouse->type == PSMOUSE_GENPS) { + /* 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); - } + break; -/* - * Extra button on ThinkingMouse - */ - if (psmouse->type == PSMOUSE_THINKPS) { + case PSMOUSE_THINKPS: + /* Extra button on ThinkingMouse */ input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1); - /* Without this bit of weirdness moving up gives wildly high Y changes. */ + + /* + * Without this bit of weirdness moving up gives wildly + * high Y changes. + */ packet[1] |= (packet[0] & 0x40) << 1; - } + break; -/* - * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first - * byte. - */ - if (psmouse->type == PSMOUSE_CORTRON) { + case PSMOUSE_CORTRON: + /* + * 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; - } + break; -/* - * Generic PS/2 Mouse - */ + default: + break; + } + /* Generic 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); @@ -222,7 +220,6 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, /* * __psmouse_set_state() sets new psmouse state and resets all flags. */ - static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { psmouse->state = new_state; @@ -231,13 +228,11 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta psmouse->last = jiffies; } - /* * psmouse_set_state() sets new psmouse state and resets all flags and * counters while holding serio lock so fighting with interrupt handler * is not a concern. */ - void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { serio_pause_rx(psmouse->ps2dev.serio); @@ -249,7 +244,6 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) * psmouse_handle_byte() processes one byte of the input data stream * by calling corresponding protocol handler. */ - static int psmouse_handle_byte(struct psmouse *psmouse) { psmouse_ret_t rc = psmouse->protocol_handler(psmouse); @@ -292,7 +286,6 @@ static int psmouse_handle_byte(struct psmouse *psmouse) * psmouse_interrupt() handles incoming characters, either passing them * for normal processing or gathering them as command response. */ - static irqreturn_t psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { @@ -335,9 +328,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } psmouse->packet[psmouse->pktcnt++] = data; -/* - * Check if this is a new device announcement (0xAA 0x00) - */ + + /* Check if this is a new device announcement (0xAA 0x00) */ if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { if (psmouse->pktcnt == 1) { psmouse->last = jiffies; @@ -351,9 +343,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, serio_reconnect(serio); goto out; } -/* - * Not a new device, try processing first byte normally - */ + + /* Not a new device, try processing first byte normally */ psmouse->pktcnt = 1; if (psmouse_handle_byte(psmouse)) goto out; @@ -361,9 +352,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, psmouse->packet[psmouse->pktcnt++] = data; } -/* - * See if we need to force resync because mouse was idle for too long - */ + /* + * See if we need to force resync because mouse was idle for + * too long. + */ if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt == 1 && psmouse->resync_time && time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { @@ -380,7 +372,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, return IRQ_HANDLED; } - /* * psmouse_sliced_command() sends an extended PS/2 command to the mouse * using sliced syntax, understood by advanced devices, such as Logitech @@ -404,7 +395,6 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) return 0; } - /* * psmouse_reset() resets the mouse into power-on state. */ @@ -424,7 +414,6 @@ int psmouse_reset(struct psmouse *psmouse) /* * Here we set the mouse resolution. */ - void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) { static const unsigned char params[] = { 0, 1, 2, 2, 3 }; @@ -441,7 +430,6 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) /* * Here we set the mouse report rate. */ - static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) { static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; @@ -457,7 +445,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) /* * Here we set the mouse scaling. */ - static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) { ps2_command(&psmouse->ps2dev, NULL, @@ -468,7 +455,6 @@ static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) /* * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. */ - static int psmouse_poll(struct psmouse *psmouse) { return ps2_command(&psmouse->ps2dev, psmouse->packet, @@ -602,7 +588,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) if (param[0] != 4) return -1; -/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ + /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ param[0] = 200; ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); param[0] = 80; @@ -672,10 +658,10 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) if (!psmouse->name) psmouse->name = "Mouse"; -/* - * We have no way of figuring true number of buttons so let's - * assume that the device has 3. - */ + /* + * 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); } @@ -699,284 +685,6 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties) return 0; } -/* - * Apply default settings to the psmouse structure. Most of them will - * be overridden by individual protocol initialization routines. - */ - -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); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - - __set_bit(REL_X, input_dev->relbit); - __set_bit(REL_Y, input_dev->relbit); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - psmouse->set_rate = psmouse_set_rate; - psmouse->set_resolution = psmouse_set_resolution; - psmouse->set_scale = psmouse_set_scale; - psmouse->poll = psmouse_poll; - psmouse->protocol_handler = psmouse_process_byte; - psmouse->pktsize = 3; - psmouse->reconnect = NULL; - psmouse->disconnect = NULL; - psmouse->cleanup = NULL; - psmouse->pt_activate = NULL; - psmouse->pt_deactivate = NULL; -} - -/* - * Apply default settings to the psmouse structure and call specified - * protocol detection or initialization routine. - */ -static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse, - bool set_properties), - struct psmouse *psmouse, bool set_properties) -{ - if (set_properties) - psmouse_apply_defaults(psmouse); - - return detect(psmouse, set_properties); -} - -/* - * psmouse_extensions() probes for any extensions to the basic PS/2 protocol - * the mouse may have. - */ - -static int psmouse_extensions(struct psmouse *psmouse, - unsigned int max_proto, bool set_properties) -{ - bool synaptics_hardware = false; - -/* Always check for focaltech, this is safe as it uses pnp-id matching */ - if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { - if (max_proto > PSMOUSE_IMEX) { - if (!set_properties || focaltech_init(psmouse) == 0) { - if (IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH)) - return PSMOUSE_FOCALTECH; - /* - * Note that we need to also restrict - * psmouse_max_proto so that psmouse_initialize() - * does not try to reset rate and resolution, - * because even that upsets the device. - */ - psmouse_max_proto = PSMOUSE_PS2; - return PSMOUSE_PS2; - } - } - } - -/* - * We always check for lifebook because it does not disturb mouse - * (it only checks DMI information). - */ - if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) { - if (max_proto > PSMOUSE_IMEX) { - if (!set_properties || lifebook_init(psmouse) == 0) - return PSMOUSE_LIFEBOOK; - } - } - - if (psmouse_do_detect(vmmouse_detect, psmouse, set_properties) == 0) { - if (max_proto > PSMOUSE_IMEX) { - if (!set_properties || vmmouse_init(psmouse) == 0) - return PSMOUSE_VMMOUSE; - } - } - -/* - * Try Kensington ThinkingMouse (we try first, because synaptics probe - * upsets the thinkingmouse). - */ - - if (max_proto > PSMOUSE_IMEX && - psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) { - return PSMOUSE_THINKPS; - } - -/* - * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol - * support is disabled in config - we need to know if it is synaptics so we - * can reset it properly after probing for intellimouse. - */ - if (max_proto > PSMOUSE_PS2 && - psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) { - synaptics_hardware = true; - - if (max_proto > PSMOUSE_IMEX) { -/* - * Try activating protocol, but check if support is enabled first, since - * we try detecting Synaptics even when protocol is disabled. - */ - if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && - (!set_properties || synaptics_init(psmouse) == 0)) { - return PSMOUSE_SYNAPTICS; - } - -/* - * Some Synaptics touchpads can emulate extended protocols (like IMPS/2). - * Unfortunately Logitech/Genius probes confuse some firmware versions so - * we'll have to skip them. - */ - max_proto = PSMOUSE_IMEX; - } -/* - * Make sure that touchpad is in relative mode, gestures (taps) are enabled - */ - synaptics_reset(psmouse); - } - -/* - * Try Cypress Trackpad. - * Must try it before Finger Sensing Pad because Finger Sensing Pad probe - * upsets some modules of Cypress Trackpads. - */ - if (max_proto > PSMOUSE_IMEX && - cypress_detect(psmouse, set_properties) == 0) { - if (IS_ENABLED(CONFIG_MOUSE_PS2_CYPRESS)) { - if (cypress_init(psmouse) == 0) - return PSMOUSE_CYPRESS; - - /* - * Finger Sensing Pad probe upsets some modules of - * Cypress Trackpad, must avoid Finger Sensing Pad - * probe if Cypress Trackpad device detected. - */ - return PSMOUSE_PS2; - } - - max_proto = PSMOUSE_IMEX; - } - -/* - * Try ALPS TouchPad - */ - if (max_proto > PSMOUSE_IMEX) { - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - if (psmouse_do_detect(alps_detect, - psmouse, set_properties) == 0) { - if (!set_properties || alps_init(psmouse) == 0) - return PSMOUSE_ALPS; -/* - * Init failed, try basic relative protocols - */ - max_proto = PSMOUSE_IMEX; - } - } - -/* - * Try OLPC HGPK touchpad. - */ - if (max_proto > PSMOUSE_IMEX && - psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) { - if (!set_properties || hgpk_init(psmouse) == 0) - return PSMOUSE_HGPK; -/* - * Init failed, try basic relative protocols - */ - max_proto = PSMOUSE_IMEX; - } - -/* - * Try Elantech touchpad. - */ - if (max_proto > PSMOUSE_IMEX && - psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) { - if (!set_properties || elantech_init(psmouse) == 0) - return PSMOUSE_ELANTECH; -/* - * Init failed, try basic relative protocols - */ - max_proto = PSMOUSE_IMEX; - } - - if (max_proto > PSMOUSE_IMEX) { - if (psmouse_do_detect(genius_detect, - psmouse, set_properties) == 0) - return PSMOUSE_GENPS; - - if (psmouse_do_detect(ps2pp_init, - psmouse, set_properties) == 0) - return PSMOUSE_PS2PP; - - if (psmouse_do_detect(trackpoint_detect, - psmouse, set_properties) == 0) - return PSMOUSE_TRACKPOINT; - - if (psmouse_do_detect(touchkit_ps2_detect, - psmouse, set_properties) == 0) - return PSMOUSE_TOUCHKIT_PS2; - } - -/* - * Try Finger Sensing Pad. We do it here because its probe upsets - * Trackpoint devices (causing TP_READ_ID command to time out). - */ - if (max_proto > PSMOUSE_IMEX) { - if (psmouse_do_detect(fsp_detect, - psmouse, set_properties) == 0) { - if (!set_properties || fsp_init(psmouse) == 0) - return PSMOUSE_FSP; -/* - * Init failed, try basic relative protocols - */ - max_proto = PSMOUSE_IMEX; - } - } - -/* - * Reset to defaults in case the device got confused by extended - * protocol probes. Note that we follow up with full reset because - * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. - */ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - psmouse_reset(psmouse); - - if (max_proto >= PSMOUSE_IMEX && - psmouse_do_detect(im_explorer_detect, - psmouse, set_properties) == 0) { - return PSMOUSE_IMEX; - } - - if (max_proto >= PSMOUSE_IMPS && - psmouse_do_detect(intellimouse_detect, - psmouse, set_properties) == 0) { - return PSMOUSE_IMPS; - } - -/* - * Okay, all failed, we have a standard mouse here. The number of the buttons - * is still a question, though. We assume 3. - */ - psmouse_do_detect(ps2bare_detect, psmouse, set_properties); - - if (synaptics_hardware) { -/* - * We detected Synaptics hardware but it did not respond to IMPS/2 probes. - * We need to reset the touchpad because if there is a track point on the - * pass through port it could get disabled while probing for protocol - * extensions. - */ - psmouse_reset(psmouse); - } - - return PSMOUSE_PS2; -} - static const struct psmouse_protocol psmouse_protocols[] = { { .type = PSMOUSE_PS2, @@ -985,13 +693,14 @@ static const struct psmouse_protocol psmouse_protocols[] = { .maxproto = true, .ignore_parity = true, .detect = ps2bare_detect, + .try_passthru = true, }, #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP { .type = PSMOUSE_PS2PP, .name = "PS2++", .alias = "logitech", - .detect = ps2pp_init, + .detect = ps2pp_detect, }, #endif { @@ -1022,6 +731,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .maxproto = true, .ignore_parity = true, .detect = intellimouse_detect, + .try_passthru = true, }, { .type = PSMOUSE_IMEX, @@ -1030,6 +740,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .maxproto = true, .ignore_parity = true, .detect = im_explorer_detect, + .try_passthru = true, }, #ifdef CONFIG_MOUSE_PS2_SYNAPTICS { @@ -1061,6 +772,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_LIFEBOOK, .name = "LBPS/2", .alias = "lifebook", + .detect = lifebook_detect, .init = lifebook_init, }, #endif @@ -1070,6 +782,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "TPPS/2", .alias = "trackpoint", .detect = trackpoint_detect, + .try_passthru = true, }, #endif #ifdef CONFIG_MOUSE_PS2_TOUCHKIT @@ -1130,6 +843,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { .init = vmmouse_init, }, #endif +#ifdef CONFIG_MOUSE_PS2_BYD + { + .type = PSMOUSE_BYD, + .name = "BydPS/2", + .alias = "byd", + .detect = byd_detect, + .init = byd_init, + }, +#endif { .type = PSMOUSE_AUTO, .name = "auto", @@ -1138,7 +860,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { }, }; -static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) +static const struct psmouse_protocol *__psmouse_protocol_by_type(enum psmouse_type type) { int i; @@ -1146,6 +868,17 @@ static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type if (psmouse_protocols[i].type == type) return &psmouse_protocols[i]; + return NULL; +} + +static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) +{ + const struct psmouse_protocol *proto; + + proto = __psmouse_protocol_by_type(type); + if (proto) + return proto; + WARN_ON(1); return &psmouse_protocols[0]; } @@ -1166,23 +899,292 @@ static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, return NULL; } +/* + * Apply default settings to the psmouse structure. Most of them will + * be overridden by individual protocol initialization routines. + */ +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); + + __set_bit(BTN_LEFT, input_dev->keybit); + __set_bit(BTN_RIGHT, input_dev->keybit); + + __set_bit(REL_X, input_dev->relbit); + __set_bit(REL_Y, input_dev->relbit); + + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + + psmouse->set_rate = psmouse_set_rate; + psmouse->set_resolution = psmouse_set_resolution; + psmouse->set_scale = psmouse_set_scale; + psmouse->poll = psmouse_poll; + psmouse->protocol_handler = psmouse_process_byte; + psmouse->pktsize = 3; + psmouse->reconnect = NULL; + psmouse->disconnect = NULL; + psmouse->cleanup = NULL; + psmouse->pt_activate = NULL; + psmouse->pt_deactivate = NULL; +} + +static bool psmouse_try_protocol(struct psmouse *psmouse, + enum psmouse_type type, + unsigned int *max_proto, + bool set_properties, bool init_allowed) +{ + const struct psmouse_protocol *proto; + + proto = __psmouse_protocol_by_type(type); + if (!proto) + return false; + + if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && + !proto->try_passthru) { + return false; + } + + if (set_properties) + psmouse_apply_defaults(psmouse); + + if (proto->detect(psmouse, set_properties) != 0) + return false; + + if (set_properties && proto->init && init_allowed) { + if (proto->init(psmouse) != 0) { + /* + * We detected device, but init failed. Adjust + * max_proto so we only try standard protocols. + */ + if (*max_proto > PSMOUSE_IMEX) + *max_proto = PSMOUSE_IMEX; + + return false; + } + } + + return true; +} /* - * psmouse_probe() probes for a PS/2 mouse. + * psmouse_extensions() probes for any extensions to the basic PS/2 protocol + * the mouse may have. */ +static int psmouse_extensions(struct psmouse *psmouse, + unsigned int max_proto, bool set_properties) +{ + bool synaptics_hardware = false; + + /* + * Always check for focaltech, this is safe as it uses pnp-id + * matching. + */ + if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH, + &max_proto, set_properties, false)) { + if (max_proto > PSMOUSE_IMEX && + IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) && + (!set_properties || focaltech_init(psmouse) == 0)) { + return PSMOUSE_FOCALTECH; + } + /* + * Restrict psmouse_max_proto so that psmouse_initialize() + * does not try to reset rate and resolution, because even + * that upsets the device. + * This also causes us to basically fall through to basic + * protocol detection, where we fully reset the mouse, + * and set it up as bare PS/2 protocol device. + */ + psmouse_max_proto = max_proto = PSMOUSE_PS2; + } + + /* + * We always check for LifeBook because it does not disturb mouse + * (it only checks DMI information). + */ + if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto, + set_properties, max_proto > PSMOUSE_IMEX)) + return PSMOUSE_LIFEBOOK; + + if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto, + set_properties, max_proto > PSMOUSE_IMEX)) + return PSMOUSE_VMMOUSE; + + /* + * Try Kensington ThinkingMouse (we try first, because Synaptics + * probe upsets the ThinkingMouse). + */ + if (max_proto > PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto, + set_properties, true)) { + return PSMOUSE_THINKPS; + } + + /* + * Try Synaptics TouchPad. Note that probing is done even if + * Synaptics protocol support is disabled in config - we need to + * know if it is Synaptics so we can reset it properly after + * probing for IntelliMouse. + */ + if (max_proto > PSMOUSE_PS2 && + psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto, + set_properties, false)) { + synaptics_hardware = true; + if (max_proto > PSMOUSE_IMEX) { + /* + * Try activating protocol, but check if support is + * enabled first, since we try detecting Synaptics + * even when protocol is disabled. + */ + if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && + (!set_properties || synaptics_init(psmouse) == 0)) { + return PSMOUSE_SYNAPTICS; + } + + /* + * Some Synaptics touchpads can emulate extended + * protocols (like IMPS/2). Unfortunately + * Logitech/Genius probes confuse some firmware + * versions so we'll have to skip them. + */ + max_proto = PSMOUSE_IMEX; + } + + /* + * Make sure that touchpad is in relative mode, gestures + * (taps) are enabled. + */ + synaptics_reset(psmouse); + } + + /* + * Try Cypress Trackpad. We must try it before Finger Sensing Pad + * because Finger Sensing Pad probe upsets some modules of Cypress + * Trackpads. + */ + if (max_proto > PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto, + set_properties, true)) { + return PSMOUSE_CYPRESS; + } + + /* Try ALPS TouchPad */ + if (max_proto > PSMOUSE_IMEX) { + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS, + &max_proto, set_properties, true)) + return PSMOUSE_ALPS; + } + + /* Try OLPC HGPK touchpad */ + if (max_proto > PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto, + set_properties, true)) { + return PSMOUSE_HGPK; + } + + /* Try Elantech touchpad */ + if (max_proto > PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH, + &max_proto, set_properties, true)) { + return PSMOUSE_ELANTECH; + } + + if (max_proto > PSMOUSE_IMEX) { + if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS, + &max_proto, set_properties, true)) + return PSMOUSE_GENPS; + + if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP, + &max_proto, set_properties, true)) + return PSMOUSE_PS2PP; + + if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT, + &max_proto, set_properties, true)) + return PSMOUSE_TRACKPOINT; + + if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2, + &max_proto, set_properties, true)) + return PSMOUSE_TOUCHKIT_PS2; + + if (psmouse_try_protocol(psmouse, PSMOUSE_BYD, + &max_proto, set_properties, true)) + return PSMOUSE_BYD; + } + + /* + * Try Finger Sensing Pad. We do it here because its probe upsets + * Trackpoint devices (causing TP_READ_ID command to time out). + */ + if (max_proto > PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_FSP, + &max_proto, set_properties, true)) { + return PSMOUSE_FSP; + } + + /* + * Reset to defaults in case the device got confused by extended + * protocol probes. Note that we follow up with full reset because + * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. + */ + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + psmouse_reset(psmouse); + + if (max_proto >= PSMOUSE_IMEX && + psmouse_try_protocol(psmouse, PSMOUSE_IMEX, + &max_proto, set_properties, true)) { + return PSMOUSE_IMEX; + } + + if (max_proto >= PSMOUSE_IMPS && + psmouse_try_protocol(psmouse, PSMOUSE_IMPS, + &max_proto, set_properties, true)) { + return PSMOUSE_IMPS; + } + + /* + * Okay, all failed, we have a standard mouse here. The number of + * the buttons is still a question, though. We assume 3. + */ + psmouse_try_protocol(psmouse, PSMOUSE_PS2, + &max_proto, set_properties, true); + + if (synaptics_hardware) { + /* + * We detected Synaptics hardware but it did not respond to + * IMPS/2 probes. We need to reset the touchpad because if + * there is a track point on the pass through port it could + * get disabled while probing for protocol extensions. + */ + psmouse_reset(psmouse); + } + + return PSMOUSE_PS2; +} + +/* + * psmouse_probe() probes for a PS/2 mouse. + */ static int psmouse_probe(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; -/* - * First, we check if it's a mouse. It should send 0x00 or 0x03 - * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. - * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent - * ID queries, probably due to a firmware bug. - */ - + /* + * First, we check if it's a mouse. It should send 0x00 or 0x03 in + * case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. + * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and + * subsequent ID queries, probably due to a firmware bug. + */ param[0] = 0xa5; if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) return -1; @@ -1191,10 +1193,10 @@ static int psmouse_probe(struct psmouse *psmouse) param[0] != 0x04 && param[0] != 0xff) return -1; -/* - * Then we reset and disable the mouse so that it doesn't generate events. - */ - + /* + * 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); @@ -1205,13 +1207,11 @@ static int psmouse_probe(struct psmouse *psmouse) /* * psmouse_initialize() initializes the mouse to a sane state. */ - static void psmouse_initialize(struct psmouse *psmouse) { -/* - * We set the mouse report rate, resolution and scaling. - */ - + /* + * We set the mouse report rate, resolution and scaling. + */ if (psmouse_max_proto != PSMOUSE_PS2) { psmouse->set_rate(psmouse, psmouse->rate); psmouse->set_resolution(psmouse, psmouse->resolution); @@ -1222,7 +1222,6 @@ static void psmouse_initialize(struct psmouse *psmouse) /* * psmouse_activate() enables the mouse so that we get motion reports from it. */ - int psmouse_activate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { @@ -1236,10 +1235,9 @@ int psmouse_activate(struct psmouse *psmouse) } /* - * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion - * reports from it unless we explicitly request it. + * psmouse_deactivate() puts the mouse into poll mode so that we don't get + * motion reports from it unless we explicitly request it. */ - int psmouse_deactivate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { @@ -1252,11 +1250,9 @@ int psmouse_deactivate(struct psmouse *psmouse) return 0; } - /* * psmouse_resync() attempts to re-validate current protocol. */ - static void psmouse_resync(struct work_struct *work) { struct psmouse *parent = NULL, *psmouse = @@ -1276,16 +1272,16 @@ static void psmouse_resync(struct work_struct *work) psmouse_deactivate(parent); } -/* - * Some mice don't ACK commands sent while they are in the middle of - * transmitting motion packet. To avoid delay we use ps2_sendbyte() - * instead of ps2_command() which would wait for 200ms for an ACK - * that may never come. - * As an additional quirk ALPS touchpads may not only forget to ACK - * disable command but will stop reporting taps, so if we see that - * mouse at least once ACKs disable we will do full reconnect if ACK - * is missing. - */ + /* + * Some mice don't ACK commands sent while they are in the middle of + * transmitting motion packet. To avoid delay we use ps2_sendbyte() + * instead of ps2_command() which would wait for 200ms for an ACK + * that may never come. + * As an additional quirk ALPS touchpads may not only forget to ACK + * disable command but will stop reporting taps, so if we see that + * mouse at least once ACKs disable we will do full reconnect if ACK + * is missing. + */ psmouse->num_resyncs++; if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) { @@ -1294,13 +1290,13 @@ static void psmouse_resync(struct work_struct *work) } else psmouse->acks_disable_command = true; -/* - * Poll the mouse. If it was reset the packet will be shorter than - * psmouse->pktsize and ps2_command will fail. We do not expect and - * do not handle scenario when mouse "upgrades" its protocol while - * disconnected since it would require additional delay. If we ever - * see a mouse that does it we'll adjust the code. - */ + /* + * Poll the mouse. If it was reset the packet will be shorter than + * psmouse->pktsize and ps2_command will fail. We do not expect and + * do not handle scenario when mouse "upgrades" its protocol while + * disconnected since it would require additional delay. If we ever + * see a mouse that does it we'll adjust the code. + */ if (!failed) { if (psmouse->poll(psmouse)) failed = true; @@ -1317,11 +1313,12 @@ static void psmouse_resync(struct work_struct *work) psmouse_set_state(psmouse, PSMOUSE_RESYNCING); } } -/* - * Now try to enable mouse. We try to do that even if poll failed and also - * repeat our attempts 5 times, otherwise we may be left out with disabled - * mouse. - */ + + /* + * Now try to enable mouse. We try to do that even if poll failed + * and also repeat our attempts 5 times, otherwise we may be left + * out with disabled mouse. + */ for (i = 0; i < 5; i++) { if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { enabled = true; @@ -1353,7 +1350,6 @@ static void psmouse_resync(struct work_struct *work) /* * psmouse_cleanup() resets the mouse into power-on state. */ - static void psmouse_cleanup(struct serio *serio) { struct psmouse *psmouse = serio_get_drvdata(serio); @@ -1378,15 +1374,15 @@ static void psmouse_cleanup(struct serio *serio) if (psmouse->cleanup) psmouse->cleanup(psmouse); -/* - * Reset the mouse to defaults (bare PS/2 protocol). - */ + /* + * Reset the mouse to defaults (bare PS/2 protocol). + */ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); -/* - * Some boxes, such as HP nx7400, get terribly confused if mouse - * is not fully enabled before suspending/shutting down. - */ + /* + * Some boxes, such as HP nx7400, get terribly confused if mouse + * is not fully enabled before suspending/shutting down. + */ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); if (parent) { @@ -1402,7 +1398,6 @@ static void psmouse_cleanup(struct serio *serio) /* * psmouse_disconnect() closes and frees. */ - static void psmouse_disconnect(struct serio *serio) { struct psmouse *psmouse, *parent = NULL; @@ -1602,7 +1597,6 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; } - static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio_get_drvdata(serio); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index ad5a5a1ea872..e0ca6cda3d16 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -104,6 +104,7 @@ enum psmouse_type { PSMOUSE_CYPRESS, PSMOUSE_FOCALTECH, PSMOUSE_VMMOUSE, + PSMOUSE_BYD, PSMOUSE_AUTO /* This one should always be last */ }; |