* [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2
@ 2021-02-10 23:39 Hamza Farooq
2021-02-11 10:36 ` kernel test robot
2021-02-15 22:38 ` Hamza Farooq
0 siblings, 2 replies; 5+ messages in thread
From: Hamza Farooq @ 2021-02-10 23:39 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-kernel, linux-input
Haier Y11C Laptop have FocalTech PS/2 Touchpad, BIOS Device Name is FTE0001.
This device have different protocol than exisiting FocalTech PS/2 Driver.
This commit adds a basic multitouch-capable driver.
Some of the protcol is still unknown (just like the other FocalTech driver)
Device can only be identified with PNP ID.
Signed-off-by: Hamza Farooq <0xA6C4@gmail.com>
---
drivers/input/mouse/Kconfig | 10 ++
drivers/input/mouse/Makefile | 2 +-
drivers/input/mouse/focaltech_v2.c | 265 +++++++++++++++++++++++++++++
drivers/input/mouse/focaltech_v2.h | 56 ++++++
drivers/input/mouse/psmouse-base.c | 32 ++++
drivers/input/mouse/psmouse.h | 1 +
6 files changed, 365 insertions(+), 1 deletion(-)
create mode 100644 drivers/input/mouse/focaltech_v2.c
create mode 100644 drivers/input/mouse/focaltech_v2.h
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 63c9cda55..843509c01 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -184,6 +184,16 @@ config MOUSE_PS2_FOCALTECH
If unsure, say Y.
+config MOUSE_PS2_FOCALTECH_V2
+ bool "FocalTech-v2 PS/2 mouse protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a FocalTech-V2 PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_PS2_VMMOUSE
bool "Virtual mouse (vmmouse)"
depends on MOUSE_PS2 && X86 && HYPERVISOR_GUEST
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index e49f08565..31673ea8d 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o
-psmouse-objs := psmouse-base.o synaptics.o focaltech.o
+psmouse-objs := psmouse-base.o synaptics.o focaltech.o focaltech_v2.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o
diff --git a/drivers/input/mouse/focaltech_v2.c b/drivers/input/mouse/focaltech_v2.c
new file mode 100644
index 000000000..a3c7e81c5
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.c
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+
+#include <linux/device.h>
+#include <linux/libps2.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include "psmouse.h"
+#include "focaltech_v2.h"
+
+static const struct fte_command switch_protocol[] = {
+ {PSMOUSE_CMD_SETRATE, 0xea},
+ {PSMOUSE_CMD_SETRATE, 0xed},
+ {PSMOUSE_CMD_ENABLE, 0x00},
+};
+
+static const char *const focaltech_pnp_ids[] = {
+ "FTE0001",
+ NULL};
+
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties)
+{
+ if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids))
+ return -ENODEV;
+
+ if (set_properties) {
+ psmouse->vendor = "FocalTech";
+ psmouse->name = "Touchpad V2";
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+
+static void focaltech_report_state(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ struct input_dev *dev = psmouse->dev;
+ int i;
+
+ for (i = 0; i < FOCALTECH_MAX_FINGERS; i++) {
+ struct focaltech_finger_state *finger = &state->fingers[i];
+
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, finger->valid);
+ if (finger->valid) {
+ input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, finger->y);
+ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, finger->major);
+ input_report_abs(dev, ABS_MT_TOUCH_MINOR, finger->minor);
+ input_report_abs(dev, ABS_MT_PRESSURE, finger->pressure);
+ }
+ }
+ input_mt_sync_frame(dev);
+ input_report_key(dev, BTN_LEFT, state->left);
+ input_report_key(dev, BTN_RIGHT, state->right);
+ input_mt_report_finger_count(dev, state->fingerCount);
+ input_sync(dev);
+}
+
+static void focaltech_process_packet(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ int i, j;
+
+ if (!priv->isReadNext) {
+ for (i = 0; i < 8; i++)
+ priv->lastDeviceData[i] = packet[i];
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = 0xff;
+ state->fingerCount = (int)(packet[4] & 3) + ((packet[4] & 48) >> 2);
+ if ((state->fingerCount > 2) && (packet[0] != 0xff && packet[1] != 0xff && packet[2] != 0xff && packet[3] != 0xff) && (packet[0] & 48) != 32)
+ priv->isReadNext = true;
+ } else {
+ priv->isReadNext = false;
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = packet[i - 8];
+ }
+ if (!priv->isReadNext) {
+ if (!((priv->lastDeviceData[0] == 0xff) && (priv->lastDeviceData[1] == 0xff) && (priv->lastDeviceData[2] == 0xff) && (priv->lastDeviceData[3] == 0xff))) {
+ if ((priv->lastDeviceData[0] & 1) == 1)
+ state->left = true;
+ else
+ state->left = false;
+ if ((priv->lastDeviceData[0] & 2) == 2)
+ state->right = true;
+ else
+ state->right = false;
+ if ((priv->lastDeviceData[0] & 48) == 16) {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].minor = priv->lastDeviceData[j + 1];
+ state->fingers[i].major = priv->lastDeviceData[j + 2];
+ state->fingers[i].pressure = priv->lastDeviceData[j + 3] * 2;
+ if (state->fingers[i].pressure > MAX_PRESSURE)
+ state->fingers[i].pressure = MAX_PRESSURE;
+ }
+ }
+ } else {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].valid = true;
+ state->fingers[i].x = (priv->lastDeviceData[j + 1] << 4) + ((priv->lastDeviceData[j + 3] & 240) >> 4);
+ state->fingers[i].y = (priv->lastDeviceData[j + 2] << 4) + (priv->lastDeviceData[j + 3] & 15);
+ } else
+ state->fingers[i].valid = false;
+ }
+ }
+ if (state->fingerCount == 0)
+ for (i = 0; i < 4; i++)
+ state->fingers[i].valid = false;
+ }
+ }
+ focaltech_report_state(psmouse);
+}
+
+static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse)
+{
+ if (psmouse->pktcnt >= 8) { /* packet received */
+ focaltech_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+ return PSMOUSE_GOOD_DATA;
+}
+
+static int focaltech_switch_protocol(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(switch_protocol); ++i) {
+ memset(param, 0, sizeof(param));
+ param[0] = switch_protocol[i].data;
+ if (ps2_command(ps2dev, param, switch_protocol[i].command))
+ return -EIO;
+ }
+
+ 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);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int focaltech_reconnect(struct psmouse *psmouse)
+{
+ int error;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void focaltech_set_input_params(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+
+ /*
+ * Undo part of setup done for us by psmouse core since touchpad
+ * is not a relative device.
+ */
+ __clear_bit(EV_REL, dev->evbit);
+ __clear_bit(REL_X, dev->relbit);
+ __clear_bit(REL_Y, dev->relbit);
+
+ /*
+ * Now set up our capabilities.
+ */
+ __set_bit(EV_ABS, dev->evbit);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);
+ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MINOR, 0, MAX_MAJOR, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, MAX_MINOR, 0, 0);
+ input_abs_set_res(dev, ABS_MT_POSITION_X, RESOLUTION);
+ input_abs_set_res(dev, ABS_MT_POSITION_Y, RESOLUTION);
+ input_mt_init_slots(dev, FOCALTECH_MAX_FINGERS, INPUT_MT_POINTER);
+}
+
+static void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+ /* not supported yet */
+}
+
+int focaltech_v2_init(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv;
+ int error;
+
+ psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ goto fail;
+ }
+
+ focaltech_set_input_params(psmouse);
+
+ psmouse->protocol_handler = focaltech_process_byte;
+ psmouse->pktsize = 8;
+ psmouse->disconnect = focaltech_disconnect;
+ psmouse->reconnect = focaltech_reconnect;
+ psmouse->cleanup = focaltech_reset;
+ /* resync is not supported yet */
+ psmouse->resync_time = 0;
+ /*
+ * rate/resolution/scale changes are not supported yet, and
+ * the generic implementations of these functions seem to
+ * confuse some touchpads
+ */
+ psmouse->set_resolution = focaltech_set_resolution;
+ psmouse->set_rate = focaltech_set_rate;
+ psmouse->set_scale = focaltech_set_scale;
+
+ return 0;
+
+fail:
+ focaltech_reset(psmouse);
+ kfree(priv);
+ return error;
+}
+#endif /* CONFIG_MOUSE_PS2_FOCALTECH_V2 */
diff --git a/drivers/input/mouse/focaltech_v2.h b/drivers/input/mouse/focaltech_v2.h
new file mode 100644
index 000000000..49c69b9a2
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+#ifndef _FOCALTECH_V2_H
+#define _FOCALTECH_V2_H
+
+#define FOCALTECH_MAX_FINGERS 4
+#define MAX_X 0x08E0 /* 2272 */
+#define MAX_Y 0x03E0 /* 992 */
+#define RESOLUTION 26 /* 87mm x 38mm */
+#define MAX_MAJOR 10
+#define MAX_MINOR 10
+#define MAX_PRESSURE 127
+
+struct fte_command {
+ int command;
+ unsigned char data;
+};
+
+struct focaltech_finger_state {
+ int x;
+ int y;
+ int major;
+ int minor;
+ int pressure;
+ bool valid;
+};
+
+struct focaltech_hw_state {
+ struct focaltech_finger_state fingers[FOCALTECH_MAX_FINGERS];
+ int fingerCount;
+ bool left;
+ bool right;
+};
+
+struct focaltech_data {
+ bool isReadNext;
+ int lastDeviceData[16];
+ struct focaltech_hw_state state;
+};
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties);
+int focaltech_v2_init(struct psmouse *psmouse);
+#else
+static inline int focaltech_v2_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0b4a3039f..5f720af51 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -34,6 +34,7 @@
#include "sentelic.h"
#include "cypress_ps2.h"
#include "focaltech.h"
+#include "focaltech_v2.h"
#include "vmmouse.h"
#include "byd.h"
@@ -891,6 +892,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.init = focaltech_init,
},
#endif
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+ {
+ .type = PSMOUSE_FOCALTECH_V2,
+ .name = "FocalTechPS/2",
+ .alias = "focaltech-v2",
+ .detect = focaltech_detect,
+ .init = focaltech_init,
+ },
+#endif
#ifdef CONFIG_MOUSE_PS2_VMMOUSE
{
.type = PSMOUSE_VMMOUSE,
@@ -1072,6 +1082,28 @@ static int psmouse_extensions(struct psmouse *psmouse,
psmouse_max_proto = max_proto = PSMOUSE_PS2;
}
+ /*
+ * Always check for focaltech-v2, this is safe as it uses pnp-id
+ * matching.
+ */
+ if (psmouse_do_detect(focaltech_v2_detect,
+ psmouse, false, set_properties)) {
+ if (max_proto > PSMOUSE_IMEX &&
+ IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH_V2) &&
+ (!set_properties || focaltech_v2_init(psmouse) == 0)) {
+ return PSMOUSE_FOCALTECH_V2;
+ }
+ /*
+ * 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).
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 64c3a5d3f..68e06aaac 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -65,6 +65,7 @@ enum psmouse_type {
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_CYPRESS,
PSMOUSE_FOCALTECH,
+ PSMOUSE_FOCALTECH_V2,
PSMOUSE_VMMOUSE,
PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS,
--
2.27.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2
2021-02-10 23:39 [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2 Hamza Farooq
@ 2021-02-11 10:36 ` kernel test robot
2021-02-15 22:38 ` Hamza Farooq
1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2021-02-11 10:36 UTC (permalink / raw)
To: Hamza Farooq, dmitry.torokhov; +Cc: kbuild-all, linux-kernel, linux-input
[-- Attachment #1: Type: text/plain, Size: 11893 bytes --]
Hi Hamza,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on input/next]
[also build test ERROR on linux/master hid/for-next linus/master v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Hamza-Farooq/Input-psmouse-add-support-for-FocalTech-PS-2-Protocol-v2/20210211-074527
base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: parisc-randconfig-r004-20210211 (attached as .config)
compiler: hppa-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/958fb71223bb82ea01edbcbf4970af1d888b1050
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Hamza-Farooq/Input-psmouse-add-support-for-FocalTech-PS-2-Protocol-v2/20210211-074527
git checkout 958fb71223bb82ea01edbcbf4970af1d888b1050
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=parisc
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All error/warnings (new ones prefixed by >>):
In file included from include/linux/build_bug.h:5,
from include/linux/bits.h:22,
from include/linux/bitops.h:5,
from drivers/input/mouse/psmouse-base.c:13:
drivers/input/mouse/psmouse-base.c: In function 'psmouse_extensions':
>> drivers/input/mouse/psmouse-base.c:1089:24: error: 'focaltech_v2_detect' undeclared (first use in this function); did you mean 'focaltech_detect'?
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/input/mouse/psmouse-base.c:1089:2: note: in expansion of macro 'if'
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~
drivers/input/mouse/psmouse-base.c:1089:24: note: each undeclared identifier is reported only once for each function it appears in
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/input/mouse/psmouse-base.c:1089:2: note: in expansion of macro 'if'
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~
--
>> drivers/input/mouse/focaltech_v2.c:27:5: warning: no previous prototype for 'focaltech_v2_detect' [-Wmissing-prototypes]
27 | int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties)
| ^~~~~~~~~~~~~~~~~~~
drivers/input/mouse/focaltech_v2.c:17:33: warning: 'switch_protocol' defined but not used [-Wunused-const-variable=]
17 | static const struct fte_command switch_protocol[] = {
| ^~~~~~~~~~~~~~~
vim +1089 drivers/input/mouse/psmouse-base.c
1052
1053 /*
1054 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
1055 * the mouse may have.
1056 */
1057 static int psmouse_extensions(struct psmouse *psmouse,
1058 unsigned int max_proto, bool set_properties)
1059 {
1060 bool synaptics_hardware = false;
1061 int ret;
1062
1063 /*
1064 * Always check for focaltech, this is safe as it uses pnp-id
1065 * matching.
1066 */
1067 if (psmouse_do_detect(focaltech_detect,
1068 psmouse, false, set_properties)) {
1069 if (max_proto > PSMOUSE_IMEX &&
1070 IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) &&
1071 (!set_properties || focaltech_init(psmouse) == 0)) {
1072 return PSMOUSE_FOCALTECH;
1073 }
1074 /*
1075 * Restrict psmouse_max_proto so that psmouse_initialize()
1076 * does not try to reset rate and resolution, because even
1077 * that upsets the device.
1078 * This also causes us to basically fall through to basic
1079 * protocol detection, where we fully reset the mouse,
1080 * and set it up as bare PS/2 protocol device.
1081 */
1082 psmouse_max_proto = max_proto = PSMOUSE_PS2;
1083 }
1084
1085 /*
1086 * Always check for focaltech-v2, this is safe as it uses pnp-id
1087 * matching.
1088 */
> 1089 if (psmouse_do_detect(focaltech_v2_detect,
1090 psmouse, false, set_properties)) {
1091 if (max_proto > PSMOUSE_IMEX &&
1092 IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH_V2) &&
1093 (!set_properties || focaltech_v2_init(psmouse) == 0)) {
1094 return PSMOUSE_FOCALTECH_V2;
1095 }
1096 /*
1097 * Restrict psmouse_max_proto so that psmouse_initialize()
1098 * does not try to reset rate and resolution, because even
1099 * that upsets the device.
1100 * This also causes us to basically fall through to basic
1101 * protocol detection, where we fully reset the mouse,
1102 * and set it up as bare PS/2 protocol device.
1103 */
1104 psmouse_max_proto = max_proto = PSMOUSE_PS2;
1105 }
1106
1107 /*
1108 * We always check for LifeBook because it does not disturb mouse
1109 * (it only checks DMI information).
1110 */
1111 if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto,
1112 set_properties, max_proto > PSMOUSE_IMEX))
1113 return PSMOUSE_LIFEBOOK;
1114
1115 if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto,
1116 set_properties, max_proto > PSMOUSE_IMEX))
1117 return PSMOUSE_VMMOUSE;
1118
1119 /*
1120 * Try Kensington ThinkingMouse (we try first, because Synaptics
1121 * probe upsets the ThinkingMouse).
1122 */
1123 if (max_proto > PSMOUSE_IMEX &&
1124 psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto,
1125 set_properties, true)) {
1126 return PSMOUSE_THINKPS;
1127 }
1128
1129 /*
1130 * Try Synaptics TouchPad. Note that probing is done even if
1131 * Synaptics protocol support is disabled in config - we need to
1132 * know if it is Synaptics so we can reset it properly after
1133 * probing for IntelliMouse.
1134 */
1135 if (max_proto > PSMOUSE_PS2 &&
1136 psmouse_do_detect(synaptics_detect,
1137 psmouse, false, set_properties)) {
1138 synaptics_hardware = true;
1139
1140 if (max_proto > PSMOUSE_IMEX) {
1141 /*
1142 * Try activating protocol, but check if support is
1143 * enabled first, since we try detecting Synaptics
1144 * even when protocol is disabled.
1145 */
1146 if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) ||
1147 IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) {
1148 if (!set_properties)
1149 return PSMOUSE_SYNAPTICS;
1150
1151 ret = synaptics_init(psmouse);
1152 if (ret >= 0)
1153 return ret;
1154 }
1155
1156 /*
1157 * Some Synaptics touchpads can emulate extended
1158 * protocols (like IMPS/2). Unfortunately
1159 * Logitech/Genius probes confuse some firmware
1160 * versions so we'll have to skip them.
1161 */
1162 max_proto = PSMOUSE_IMEX;
1163 }
1164
1165 /*
1166 * Make sure that touchpad is in relative mode, gestures
1167 * (taps) are enabled.
1168 */
1169 synaptics_reset(psmouse);
1170 }
1171
1172 /*
1173 * Try Cypress Trackpad. We must try it before Finger Sensing Pad
1174 * because Finger Sensing Pad probe upsets some modules of Cypress
1175 * Trackpads.
1176 */
1177 if (max_proto > PSMOUSE_IMEX &&
1178 psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto,
1179 set_properties, true)) {
1180 return PSMOUSE_CYPRESS;
1181 }
1182
1183 /* Try ALPS TouchPad */
1184 if (max_proto > PSMOUSE_IMEX) {
1185 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
1186 if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS,
1187 &max_proto, set_properties, true))
1188 return PSMOUSE_ALPS;
1189 }
1190
1191 /* Try OLPC HGPK touchpad */
1192 if (max_proto > PSMOUSE_IMEX &&
1193 psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto,
1194 set_properties, true)) {
1195 return PSMOUSE_HGPK;
1196 }
1197
1198 /* Try Elantech touchpad */
1199 if (max_proto > PSMOUSE_IMEX &&
1200 psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
1201 &max_proto, set_properties, false)) {
1202 if (!set_properties)
1203 return PSMOUSE_ELANTECH;
1204
1205 ret = elantech_init(psmouse);
1206 if (ret >= 0)
1207 return ret;
1208 }
1209
1210 if (max_proto > PSMOUSE_IMEX) {
1211 if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
1212 &max_proto, set_properties, true))
1213 return PSMOUSE_GENPS;
1214
1215 if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP,
1216 &max_proto, set_properties, true))
1217 return PSMOUSE_PS2PP;
1218
1219 if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT,
1220 &max_proto, set_properties, true))
1221 return PSMOUSE_TRACKPOINT;
1222
1223 if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
1224 &max_proto, set_properties, true))
1225 return PSMOUSE_TOUCHKIT_PS2;
1226 }
1227
1228 /*
1229 * Try Finger Sensing Pad. We do it here because its probe upsets
1230 * Trackpoint devices (causing TP_READ_ID command to time out).
1231 */
1232 if (max_proto > PSMOUSE_IMEX &&
1233 psmouse_try_protocol(psmouse, PSMOUSE_FSP,
1234 &max_proto, set_properties, true)) {
1235 return PSMOUSE_FSP;
1236 }
1237
1238 /*
1239 * Reset to defaults in case the device got confused by extended
1240 * protocol probes. Note that we follow up with full reset because
1241 * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
1242 */
1243 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
1244 psmouse_reset(psmouse);
1245
1246 if (max_proto >= PSMOUSE_IMEX &&
1247 psmouse_try_protocol(psmouse, PSMOUSE_IMEX,
1248 &max_proto, set_properties, true)) {
1249 return PSMOUSE_IMEX;
1250 }
1251
1252 if (max_proto >= PSMOUSE_IMPS &&
1253 psmouse_try_protocol(psmouse, PSMOUSE_IMPS,
1254 &max_proto, set_properties, true)) {
1255 return PSMOUSE_IMPS;
1256 }
1257
1258 /*
1259 * Okay, all failed, we have a standard mouse here. The number of
1260 * the buttons is still a question, though. We assume 3.
1261 */
1262 psmouse_try_protocol(psmouse, PSMOUSE_PS2,
1263 &max_proto, set_properties, true);
1264
1265 if (synaptics_hardware) {
1266 /*
1267 * We detected Synaptics hardware but it did not respond to
1268 * IMPS/2 probes. We need to reset the touchpad because if
1269 * there is a track point on the pass through port it could
1270 * get disabled while probing for protocol extensions.
1271 */
1272 psmouse_reset(psmouse);
1273 }
1274
1275 return PSMOUSE_PS2;
1276 }
1277
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 31953 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2
@ 2021-02-11 10:36 ` kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2021-02-11 10:36 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 12188 bytes --]
Hi Hamza,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on input/next]
[also build test ERROR on linux/master hid/for-next linus/master v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Hamza-Farooq/Input-psmouse-add-support-for-FocalTech-PS-2-Protocol-v2/20210211-074527
base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: parisc-randconfig-r004-20210211 (attached as .config)
compiler: hppa-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/958fb71223bb82ea01edbcbf4970af1d888b1050
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Hamza-Farooq/Input-psmouse-add-support-for-FocalTech-PS-2-Protocol-v2/20210211-074527
git checkout 958fb71223bb82ea01edbcbf4970af1d888b1050
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=parisc
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All error/warnings (new ones prefixed by >>):
In file included from include/linux/build_bug.h:5,
from include/linux/bits.h:22,
from include/linux/bitops.h:5,
from drivers/input/mouse/psmouse-base.c:13:
drivers/input/mouse/psmouse-base.c: In function 'psmouse_extensions':
>> drivers/input/mouse/psmouse-base.c:1089:24: error: 'focaltech_v2_detect' undeclared (first use in this function); did you mean 'focaltech_detect'?
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/input/mouse/psmouse-base.c:1089:2: note: in expansion of macro 'if'
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~
drivers/input/mouse/psmouse-base.c:1089:24: note: each undeclared identifier is reported only once for each function it appears in
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:52: note: in definition of macro '__trace_if_var'
58 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/input/mouse/psmouse-base.c:1089:2: note: in expansion of macro 'if'
1089 | if (psmouse_do_detect(focaltech_v2_detect,
| ^~
--
>> drivers/input/mouse/focaltech_v2.c:27:5: warning: no previous prototype for 'focaltech_v2_detect' [-Wmissing-prototypes]
27 | int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties)
| ^~~~~~~~~~~~~~~~~~~
drivers/input/mouse/focaltech_v2.c:17:33: warning: 'switch_protocol' defined but not used [-Wunused-const-variable=]
17 | static const struct fte_command switch_protocol[] = {
| ^~~~~~~~~~~~~~~
vim +1089 drivers/input/mouse/psmouse-base.c
1052
1053 /*
1054 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
1055 * the mouse may have.
1056 */
1057 static int psmouse_extensions(struct psmouse *psmouse,
1058 unsigned int max_proto, bool set_properties)
1059 {
1060 bool synaptics_hardware = false;
1061 int ret;
1062
1063 /*
1064 * Always check for focaltech, this is safe as it uses pnp-id
1065 * matching.
1066 */
1067 if (psmouse_do_detect(focaltech_detect,
1068 psmouse, false, set_properties)) {
1069 if (max_proto > PSMOUSE_IMEX &&
1070 IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) &&
1071 (!set_properties || focaltech_init(psmouse) == 0)) {
1072 return PSMOUSE_FOCALTECH;
1073 }
1074 /*
1075 * Restrict psmouse_max_proto so that psmouse_initialize()
1076 * does not try to reset rate and resolution, because even
1077 * that upsets the device.
1078 * This also causes us to basically fall through to basic
1079 * protocol detection, where we fully reset the mouse,
1080 * and set it up as bare PS/2 protocol device.
1081 */
1082 psmouse_max_proto = max_proto = PSMOUSE_PS2;
1083 }
1084
1085 /*
1086 * Always check for focaltech-v2, this is safe as it uses pnp-id
1087 * matching.
1088 */
> 1089 if (psmouse_do_detect(focaltech_v2_detect,
1090 psmouse, false, set_properties)) {
1091 if (max_proto > PSMOUSE_IMEX &&
1092 IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH_V2) &&
1093 (!set_properties || focaltech_v2_init(psmouse) == 0)) {
1094 return PSMOUSE_FOCALTECH_V2;
1095 }
1096 /*
1097 * Restrict psmouse_max_proto so that psmouse_initialize()
1098 * does not try to reset rate and resolution, because even
1099 * that upsets the device.
1100 * This also causes us to basically fall through to basic
1101 * protocol detection, where we fully reset the mouse,
1102 * and set it up as bare PS/2 protocol device.
1103 */
1104 psmouse_max_proto = max_proto = PSMOUSE_PS2;
1105 }
1106
1107 /*
1108 * We always check for LifeBook because it does not disturb mouse
1109 * (it only checks DMI information).
1110 */
1111 if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto,
1112 set_properties, max_proto > PSMOUSE_IMEX))
1113 return PSMOUSE_LIFEBOOK;
1114
1115 if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto,
1116 set_properties, max_proto > PSMOUSE_IMEX))
1117 return PSMOUSE_VMMOUSE;
1118
1119 /*
1120 * Try Kensington ThinkingMouse (we try first, because Synaptics
1121 * probe upsets the ThinkingMouse).
1122 */
1123 if (max_proto > PSMOUSE_IMEX &&
1124 psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto,
1125 set_properties, true)) {
1126 return PSMOUSE_THINKPS;
1127 }
1128
1129 /*
1130 * Try Synaptics TouchPad. Note that probing is done even if
1131 * Synaptics protocol support is disabled in config - we need to
1132 * know if it is Synaptics so we can reset it properly after
1133 * probing for IntelliMouse.
1134 */
1135 if (max_proto > PSMOUSE_PS2 &&
1136 psmouse_do_detect(synaptics_detect,
1137 psmouse, false, set_properties)) {
1138 synaptics_hardware = true;
1139
1140 if (max_proto > PSMOUSE_IMEX) {
1141 /*
1142 * Try activating protocol, but check if support is
1143 * enabled first, since we try detecting Synaptics
1144 * even when protocol is disabled.
1145 */
1146 if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) ||
1147 IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) {
1148 if (!set_properties)
1149 return PSMOUSE_SYNAPTICS;
1150
1151 ret = synaptics_init(psmouse);
1152 if (ret >= 0)
1153 return ret;
1154 }
1155
1156 /*
1157 * Some Synaptics touchpads can emulate extended
1158 * protocols (like IMPS/2). Unfortunately
1159 * Logitech/Genius probes confuse some firmware
1160 * versions so we'll have to skip them.
1161 */
1162 max_proto = PSMOUSE_IMEX;
1163 }
1164
1165 /*
1166 * Make sure that touchpad is in relative mode, gestures
1167 * (taps) are enabled.
1168 */
1169 synaptics_reset(psmouse);
1170 }
1171
1172 /*
1173 * Try Cypress Trackpad. We must try it before Finger Sensing Pad
1174 * because Finger Sensing Pad probe upsets some modules of Cypress
1175 * Trackpads.
1176 */
1177 if (max_proto > PSMOUSE_IMEX &&
1178 psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto,
1179 set_properties, true)) {
1180 return PSMOUSE_CYPRESS;
1181 }
1182
1183 /* Try ALPS TouchPad */
1184 if (max_proto > PSMOUSE_IMEX) {
1185 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
1186 if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS,
1187 &max_proto, set_properties, true))
1188 return PSMOUSE_ALPS;
1189 }
1190
1191 /* Try OLPC HGPK touchpad */
1192 if (max_proto > PSMOUSE_IMEX &&
1193 psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto,
1194 set_properties, true)) {
1195 return PSMOUSE_HGPK;
1196 }
1197
1198 /* Try Elantech touchpad */
1199 if (max_proto > PSMOUSE_IMEX &&
1200 psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
1201 &max_proto, set_properties, false)) {
1202 if (!set_properties)
1203 return PSMOUSE_ELANTECH;
1204
1205 ret = elantech_init(psmouse);
1206 if (ret >= 0)
1207 return ret;
1208 }
1209
1210 if (max_proto > PSMOUSE_IMEX) {
1211 if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
1212 &max_proto, set_properties, true))
1213 return PSMOUSE_GENPS;
1214
1215 if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP,
1216 &max_proto, set_properties, true))
1217 return PSMOUSE_PS2PP;
1218
1219 if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT,
1220 &max_proto, set_properties, true))
1221 return PSMOUSE_TRACKPOINT;
1222
1223 if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
1224 &max_proto, set_properties, true))
1225 return PSMOUSE_TOUCHKIT_PS2;
1226 }
1227
1228 /*
1229 * Try Finger Sensing Pad. We do it here because its probe upsets
1230 * Trackpoint devices (causing TP_READ_ID command to time out).
1231 */
1232 if (max_proto > PSMOUSE_IMEX &&
1233 psmouse_try_protocol(psmouse, PSMOUSE_FSP,
1234 &max_proto, set_properties, true)) {
1235 return PSMOUSE_FSP;
1236 }
1237
1238 /*
1239 * Reset to defaults in case the device got confused by extended
1240 * protocol probes. Note that we follow up with full reset because
1241 * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
1242 */
1243 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
1244 psmouse_reset(psmouse);
1245
1246 if (max_proto >= PSMOUSE_IMEX &&
1247 psmouse_try_protocol(psmouse, PSMOUSE_IMEX,
1248 &max_proto, set_properties, true)) {
1249 return PSMOUSE_IMEX;
1250 }
1251
1252 if (max_proto >= PSMOUSE_IMPS &&
1253 psmouse_try_protocol(psmouse, PSMOUSE_IMPS,
1254 &max_proto, set_properties, true)) {
1255 return PSMOUSE_IMPS;
1256 }
1257
1258 /*
1259 * Okay, all failed, we have a standard mouse here. The number of
1260 * the buttons is still a question, though. We assume 3.
1261 */
1262 psmouse_try_protocol(psmouse, PSMOUSE_PS2,
1263 &max_proto, set_properties, true);
1264
1265 if (synaptics_hardware) {
1266 /*
1267 * We detected Synaptics hardware but it did not respond to
1268 * IMPS/2 probes. We need to reset the touchpad because if
1269 * there is a track point on the pass through port it could
1270 * get disabled while probing for protocol extensions.
1271 */
1272 psmouse_reset(psmouse);
1273 }
1274
1275 return PSMOUSE_PS2;
1276 }
1277
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 31953 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] Input: psmouse - add support for FocalTech PS/2 Protocol v2
2021-02-10 23:39 [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2 Hamza Farooq
2021-02-11 10:36 ` kernel test robot
@ 2021-02-15 22:38 ` Hamza Farooq
1 sibling, 0 replies; 5+ messages in thread
From: Hamza Farooq @ 2021-02-15 22:38 UTC (permalink / raw)
Cc: kbuild-all, Hamza Farooq, kernel test robot, Dmitry Torokhov,
Henrik Rydberg, linux-kernel, linux-input
Haier Y11C Laptop have FocalTech PS/2 Touchpad, BIOS Device Name is FTE0001.
This device have different protocol than exisiting FocalTech PS/2 Driver.
This commit adds a basic multitouch-capable driver.
Some of the protcol is still unknown (just like the other FocalTech driver)
Device can only be identified with PNP ID.
Signed-off-by: Hamza Farooq <0xA6C4@gmail.com>
Reported-by: kernel test robot <lkp@intel.com>
---
Changes in v2:
- Fixed compilation issue
drivers/input/mouse/Kconfig | 10 ++
drivers/input/mouse/Makefile | 2 +-
drivers/input/mouse/focaltech_v2.c | 265 +++++++++++++++++++++++++++++
drivers/input/mouse/focaltech_v2.h | 57 +++++++
drivers/input/mouse/psmouse-base.c | 32 ++++
drivers/input/mouse/psmouse.h | 1 +
6 files changed, 366 insertions(+), 1 deletion(-)
create mode 100644 drivers/input/mouse/focaltech_v2.c
create mode 100644 drivers/input/mouse/focaltech_v2.h
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 63c9cda55..843509c01 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -184,6 +184,16 @@ config MOUSE_PS2_FOCALTECH
If unsure, say Y.
+config MOUSE_PS2_FOCALTECH_V2
+ bool "FocalTech-v2 PS/2 mouse protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a FocalTech-V2 PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_PS2_VMMOUSE
bool "Virtual mouse (vmmouse)"
depends on MOUSE_PS2 && X86 && HYPERVISOR_GUEST
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index e49f08565..31673ea8d 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o
-psmouse-objs := psmouse-base.o synaptics.o focaltech.o
+psmouse-objs := psmouse-base.o synaptics.o focaltech.o focaltech_v2.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o
diff --git a/drivers/input/mouse/focaltech_v2.c b/drivers/input/mouse/focaltech_v2.c
new file mode 100644
index 000000000..c07c6fb65
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.c
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+
+#include <linux/device.h>
+#include <linux/libps2.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include "psmouse.h"
+#include "focaltech_v2.h"
+
+static const struct fte_command switch_protocol[] = {
+ {PSMOUSE_CMD_SETRATE, 0xea},
+ {PSMOUSE_CMD_SETRATE, 0xed},
+ {PSMOUSE_CMD_ENABLE, 0x00},
+};
+
+static const char *const focaltech_pnp_ids[] = {
+ "FTE0001",
+ NULL};
+
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties)
+{
+ if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids))
+ return -ENODEV;
+
+ if (set_properties) {
+ psmouse->vendor = "FocalTech";
+ psmouse->name = "Touchpad V2";
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+
+static void focaltech_report_state(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ struct input_dev *dev = psmouse->dev;
+ int i;
+
+ for (i = 0; i < FOCALTECH_MAX_FINGERS; i++) {
+ struct focaltech_finger_state *finger = &state->fingers[i];
+
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, finger->valid);
+ if (finger->valid) {
+ input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, finger->y);
+ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, finger->major);
+ input_report_abs(dev, ABS_MT_TOUCH_MINOR, finger->minor);
+ input_report_abs(dev, ABS_MT_PRESSURE, finger->pressure);
+ }
+ }
+ input_mt_sync_frame(dev);
+ input_report_key(dev, BTN_LEFT, state->left);
+ input_report_key(dev, BTN_RIGHT, state->right);
+ input_mt_report_finger_count(dev, state->fingerCount);
+ input_sync(dev);
+}
+
+static void focaltech_process_packet(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ int i, j;
+
+ if (!priv->isReadNext) {
+ for (i = 0; i < 8; i++)
+ priv->lastDeviceData[i] = packet[i];
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = 0xff;
+ state->fingerCount = (int)(packet[4] & 3) + ((packet[4] & 48) >> 2);
+ if ((state->fingerCount > 2) && (packet[0] != 0xff && packet[1] != 0xff && packet[2] != 0xff && packet[3] != 0xff) && (packet[0] & 48) != 32)
+ priv->isReadNext = true;
+ } else {
+ priv->isReadNext = false;
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = packet[i - 8];
+ }
+ if (!priv->isReadNext) {
+ if (!((priv->lastDeviceData[0] == 0xff) && (priv->lastDeviceData[1] == 0xff) && (priv->lastDeviceData[2] == 0xff) && (priv->lastDeviceData[3] == 0xff))) {
+ if ((priv->lastDeviceData[0] & 1) == 1)
+ state->left = true;
+ else
+ state->left = false;
+ if ((priv->lastDeviceData[0] & 2) == 2)
+ state->right = true;
+ else
+ state->right = false;
+ if ((priv->lastDeviceData[0] & 48) == 16) {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].minor = priv->lastDeviceData[j + 1];
+ state->fingers[i].major = priv->lastDeviceData[j + 2];
+ state->fingers[i].pressure = priv->lastDeviceData[j + 3] * 2;
+ if (state->fingers[i].pressure > MAX_PRESSURE)
+ state->fingers[i].pressure = MAX_PRESSURE;
+ }
+ }
+ } else {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].valid = true;
+ state->fingers[i].x = (priv->lastDeviceData[j + 1] << 4) + ((priv->lastDeviceData[j + 3] & 240) >> 4);
+ state->fingers[i].y = (priv->lastDeviceData[j + 2] << 4) + (priv->lastDeviceData[j + 3] & 15);
+ } else
+ state->fingers[i].valid = false;
+ }
+ }
+ if (state->fingerCount == 0)
+ for (i = 0; i < 4; i++)
+ state->fingers[i].valid = false;
+ }
+ }
+ focaltech_report_state(psmouse);
+}
+
+static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse)
+{
+ if (psmouse->pktcnt >= 8) { /* packet received */
+ focaltech_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+ return PSMOUSE_GOOD_DATA;
+}
+
+static int focaltech_switch_protocol(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(switch_protocol); ++i) {
+ memset(param, 0, sizeof(param));
+ param[0] = switch_protocol[i].data;
+ if (ps2_command(ps2dev, param, switch_protocol[i].command))
+ return -EIO;
+ }
+
+ 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);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int focaltech_reconnect(struct psmouse *psmouse)
+{
+ int error;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void focaltech_set_input_params(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+
+ /*
+ * Undo part of setup done for us by psmouse core since touchpad
+ * is not a relative device.
+ */
+ __clear_bit(EV_REL, dev->evbit);
+ __clear_bit(REL_X, dev->relbit);
+ __clear_bit(REL_Y, dev->relbit);
+
+ /*
+ * Now set up our capabilities.
+ */
+ __set_bit(EV_ABS, dev->evbit);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);
+ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MINOR, 0, MAX_MAJOR, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, MAX_MINOR, 0, 0);
+ input_abs_set_res(dev, ABS_MT_POSITION_X, RESOLUTION);
+ input_abs_set_res(dev, ABS_MT_POSITION_Y, RESOLUTION);
+ input_mt_init_slots(dev, FOCALTECH_MAX_FINGERS, INPUT_MT_POINTER);
+}
+
+static void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+ /* not supported yet */
+}
+
+int focaltech_v2_init(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv;
+ int error;
+
+ psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ goto fail;
+ }
+
+ focaltech_set_input_params(psmouse);
+
+ psmouse->protocol_handler = focaltech_process_byte;
+ psmouse->pktsize = 8;
+ psmouse->disconnect = focaltech_disconnect;
+ psmouse->reconnect = focaltech_reconnect;
+ psmouse->cleanup = focaltech_reset;
+ /* resync is not supported yet */
+ psmouse->resync_time = 0;
+ /*
+ * rate/resolution/scale changes are not supported yet, and
+ * the generic implementations of these functions seem to
+ * confuse some touchpads
+ */
+ psmouse->set_resolution = focaltech_set_resolution;
+ psmouse->set_rate = focaltech_set_rate;
+ psmouse->set_scale = focaltech_set_scale;
+
+ return 0;
+
+fail:
+ focaltech_reset(psmouse);
+ kfree(priv);
+ return error;
+}
+#endif /* CONFIG_MOUSE_PS2_FOCALTECH_V2 */
diff --git a/drivers/input/mouse/focaltech_v2.h b/drivers/input/mouse/focaltech_v2.h
new file mode 100644
index 000000000..2206ab14c
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+#ifndef _FOCALTECH_V2_H
+#define _FOCALTECH_V2_H
+
+#define FOCALTECH_MAX_FINGERS 4
+#define MAX_X 0x08E0 /* 2272 */
+#define MAX_Y 0x03E0 /* 992 */
+#define RESOLUTION 26 /* 87mm x 38mm */
+#define MAX_MAJOR 10
+#define MAX_MINOR 10
+#define MAX_PRESSURE 127
+
+struct fte_command {
+ int command;
+ unsigned char data;
+};
+
+struct focaltech_finger_state {
+ int x;
+ int y;
+ int major;
+ int minor;
+ int pressure;
+ bool valid;
+};
+
+struct focaltech_hw_state {
+ struct focaltech_finger_state fingers[FOCALTECH_MAX_FINGERS];
+ int fingerCount;
+ bool left;
+ bool right;
+};
+
+struct focaltech_data {
+ bool isReadNext;
+ int lastDeviceData[16];
+ struct focaltech_hw_state state;
+};
+
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties);
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+int focaltech_v2_init(struct psmouse *psmouse);
+#else
+static inline int focaltech_v2_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0b4a3039f..5f720af51 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -34,6 +34,7 @@
#include "sentelic.h"
#include "cypress_ps2.h"
#include "focaltech.h"
+#include "focaltech_v2.h"
#include "vmmouse.h"
#include "byd.h"
@@ -891,6 +892,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.init = focaltech_init,
},
#endif
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+ {
+ .type = PSMOUSE_FOCALTECH_V2,
+ .name = "FocalTechPS/2",
+ .alias = "focaltech-v2",
+ .detect = focaltech_detect,
+ .init = focaltech_init,
+ },
+#endif
#ifdef CONFIG_MOUSE_PS2_VMMOUSE
{
.type = PSMOUSE_VMMOUSE,
@@ -1072,6 +1082,28 @@ static int psmouse_extensions(struct psmouse *psmouse,
psmouse_max_proto = max_proto = PSMOUSE_PS2;
}
+ /*
+ * Always check for focaltech-v2, this is safe as it uses pnp-id
+ * matching.
+ */
+ if (psmouse_do_detect(focaltech_v2_detect,
+ psmouse, false, set_properties)) {
+ if (max_proto > PSMOUSE_IMEX &&
+ IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH_V2) &&
+ (!set_properties || focaltech_v2_init(psmouse) == 0)) {
+ return PSMOUSE_FOCALTECH_V2;
+ }
+ /*
+ * 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).
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 64c3a5d3f..68e06aaac 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -65,6 +65,7 @@ enum psmouse_type {
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_CYPRESS,
PSMOUSE_FOCALTECH,
+ PSMOUSE_FOCALTECH_V2,
PSMOUSE_VMMOUSE,
PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS,
--
2.27.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2] Input: psmouse - add support for FocalTech PS/2 Protocol v2
2021-02-11 10:36 ` kernel test robot
(?)
@ 2021-02-15 22:49 ` Hamza Farooq
-1 siblings, 0 replies; 5+ messages in thread
From: Hamza Farooq @ 2021-02-15 22:49 UTC (permalink / raw)
Cc: kbuild-all, Hamza Farooq, kernel test robot, Dmitry Torokhov,
Henrik Rydberg, linux-kernel, linux-input
Haier Y11C Laptop have FocalTech PS/2 Touchpad, BIOS Device Name is FTE0001.
This device have different protocol than exisiting FocalTech PS/2 Driver.
This commit adds a basic multitouch-capable driver.
Some of the protcol is still unknown (just like the other FocalTech driver)
Device can only be identified with PNP ID.
Signed-off-by: Hamza Farooq <0xA6C4@gmail.com>
Reported-by: kernel test robot <lkp@intel.com>
---
Changes in v2:
- Fixed compilation issue
drivers/input/mouse/Kconfig | 10 ++
drivers/input/mouse/Makefile | 2 +-
drivers/input/mouse/focaltech_v2.c | 265 +++++++++++++++++++++++++++++
drivers/input/mouse/focaltech_v2.h | 57 +++++++
drivers/input/mouse/psmouse-base.c | 32 ++++
drivers/input/mouse/psmouse.h | 1 +
6 files changed, 366 insertions(+), 1 deletion(-)
create mode 100644 drivers/input/mouse/focaltech_v2.c
create mode 100644 drivers/input/mouse/focaltech_v2.h
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 63c9cda55..843509c01 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -184,6 +184,16 @@ config MOUSE_PS2_FOCALTECH
If unsure, say Y.
+config MOUSE_PS2_FOCALTECH_V2
+ bool "FocalTech-v2 PS/2 mouse protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a FocalTech-V2 PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_PS2_VMMOUSE
bool "Virtual mouse (vmmouse)"
depends on MOUSE_PS2 && X86 && HYPERVISOR_GUEST
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index e49f08565..31673ea8d 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o
-psmouse-objs := psmouse-base.o synaptics.o focaltech.o
+psmouse-objs := psmouse-base.o synaptics.o focaltech.o focaltech_v2.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o
diff --git a/drivers/input/mouse/focaltech_v2.c b/drivers/input/mouse/focaltech_v2.c
new file mode 100644
index 000000000..c07c6fb65
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.c
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+
+#include <linux/device.h>
+#include <linux/libps2.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include "psmouse.h"
+#include "focaltech_v2.h"
+
+static const struct fte_command switch_protocol[] = {
+ {PSMOUSE_CMD_SETRATE, 0xea},
+ {PSMOUSE_CMD_SETRATE, 0xed},
+ {PSMOUSE_CMD_ENABLE, 0x00},
+};
+
+static const char *const focaltech_pnp_ids[] = {
+ "FTE0001",
+ NULL};
+
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties)
+{
+ if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids))
+ return -ENODEV;
+
+ if (set_properties) {
+ psmouse->vendor = "FocalTech";
+ psmouse->name = "Touchpad V2";
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+
+static void focaltech_report_state(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ struct input_dev *dev = psmouse->dev;
+ int i;
+
+ for (i = 0; i < FOCALTECH_MAX_FINGERS; i++) {
+ struct focaltech_finger_state *finger = &state->fingers[i];
+
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, finger->valid);
+ if (finger->valid) {
+ input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, finger->y);
+ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, finger->major);
+ input_report_abs(dev, ABS_MT_TOUCH_MINOR, finger->minor);
+ input_report_abs(dev, ABS_MT_PRESSURE, finger->pressure);
+ }
+ }
+ input_mt_sync_frame(dev);
+ input_report_key(dev, BTN_LEFT, state->left);
+ input_report_key(dev, BTN_RIGHT, state->right);
+ input_mt_report_finger_count(dev, state->fingerCount);
+ input_sync(dev);
+}
+
+static void focaltech_process_packet(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ int i, j;
+
+ if (!priv->isReadNext) {
+ for (i = 0; i < 8; i++)
+ priv->lastDeviceData[i] = packet[i];
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = 0xff;
+ state->fingerCount = (int)(packet[4] & 3) + ((packet[4] & 48) >> 2);
+ if ((state->fingerCount > 2) && (packet[0] != 0xff && packet[1] != 0xff && packet[2] != 0xff && packet[3] != 0xff) && (packet[0] & 48) != 32)
+ priv->isReadNext = true;
+ } else {
+ priv->isReadNext = false;
+ for (i = 8; i < 16; i++)
+ priv->lastDeviceData[i] = packet[i - 8];
+ }
+ if (!priv->isReadNext) {
+ if (!((priv->lastDeviceData[0] == 0xff) && (priv->lastDeviceData[1] == 0xff) && (priv->lastDeviceData[2] == 0xff) && (priv->lastDeviceData[3] == 0xff))) {
+ if ((priv->lastDeviceData[0] & 1) == 1)
+ state->left = true;
+ else
+ state->left = false;
+ if ((priv->lastDeviceData[0] & 2) == 2)
+ state->right = true;
+ else
+ state->right = false;
+ if ((priv->lastDeviceData[0] & 48) == 16) {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].minor = priv->lastDeviceData[j + 1];
+ state->fingers[i].major = priv->lastDeviceData[j + 2];
+ state->fingers[i].pressure = priv->lastDeviceData[j + 3] * 2;
+ if (state->fingers[i].pressure > MAX_PRESSURE)
+ state->fingers[i].pressure = MAX_PRESSURE;
+ }
+ }
+ } else {
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ if (!((priv->lastDeviceData[j + 1] == 0xff) && (priv->lastDeviceData[j + 2] == 0xff) && (priv->lastDeviceData[j + 3] == 0xff))) {
+ state->fingers[i].valid = true;
+ state->fingers[i].x = (priv->lastDeviceData[j + 1] << 4) + ((priv->lastDeviceData[j + 3] & 240) >> 4);
+ state->fingers[i].y = (priv->lastDeviceData[j + 2] << 4) + (priv->lastDeviceData[j + 3] & 15);
+ } else
+ state->fingers[i].valid = false;
+ }
+ }
+ if (state->fingerCount == 0)
+ for (i = 0; i < 4; i++)
+ state->fingers[i].valid = false;
+ }
+ }
+ focaltech_report_state(psmouse);
+}
+
+static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse)
+{
+ if (psmouse->pktcnt >= 8) { /* packet received */
+ focaltech_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+ return PSMOUSE_GOOD_DATA;
+}
+
+static int focaltech_switch_protocol(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(switch_protocol); ++i) {
+ memset(param, 0, sizeof(param));
+ param[0] = switch_protocol[i].data;
+ if (ps2_command(ps2dev, param, switch_protocol[i].command))
+ return -EIO;
+ }
+
+ 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);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int focaltech_reconnect(struct psmouse *psmouse)
+{
+ int error;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void focaltech_set_input_params(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+
+ /*
+ * Undo part of setup done for us by psmouse core since touchpad
+ * is not a relative device.
+ */
+ __clear_bit(EV_REL, dev->evbit);
+ __clear_bit(REL_X, dev->relbit);
+ __clear_bit(REL_Y, dev->relbit);
+
+ /*
+ * Now set up our capabilities.
+ */
+ __set_bit(EV_ABS, dev->evbit);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);
+ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MINOR, 0, MAX_MAJOR, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, MAX_MINOR, 0, 0);
+ input_abs_set_res(dev, ABS_MT_POSITION_X, RESOLUTION);
+ input_abs_set_res(dev, ABS_MT_POSITION_Y, RESOLUTION);
+ input_mt_init_slots(dev, FOCALTECH_MAX_FINGERS, INPUT_MT_POINTER);
+}
+
+static void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+ /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+ /* not supported yet */
+}
+
+int focaltech_v2_init(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv;
+ int error;
+
+ psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ goto fail;
+ }
+
+ focaltech_set_input_params(psmouse);
+
+ psmouse->protocol_handler = focaltech_process_byte;
+ psmouse->pktsize = 8;
+ psmouse->disconnect = focaltech_disconnect;
+ psmouse->reconnect = focaltech_reconnect;
+ psmouse->cleanup = focaltech_reset;
+ /* resync is not supported yet */
+ psmouse->resync_time = 0;
+ /*
+ * rate/resolution/scale changes are not supported yet, and
+ * the generic implementations of these functions seem to
+ * confuse some touchpads
+ */
+ psmouse->set_resolution = focaltech_set_resolution;
+ psmouse->set_rate = focaltech_set_rate;
+ psmouse->set_scale = focaltech_set_scale;
+
+ return 0;
+
+fail:
+ focaltech_reset(psmouse);
+ kfree(priv);
+ return error;
+}
+#endif /* CONFIG_MOUSE_PS2_FOCALTECH_V2 */
diff --git a/drivers/input/mouse/focaltech_v2.h b/drivers/input/mouse/focaltech_v2.h
new file mode 100644
index 000000000..2206ab14c
--- /dev/null
+++ b/drivers/input/mouse/focaltech_v2.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Focaltech v2 TouchPad PS/2 mouse driver
+ *
+ * Copyright (c) 2021 Hamza Farooq <0xA6C4@gmail.com>
+ */
+
+#ifndef _FOCALTECH_V2_H
+#define _FOCALTECH_V2_H
+
+#define FOCALTECH_MAX_FINGERS 4
+#define MAX_X 0x08E0 /* 2272 */
+#define MAX_Y 0x03E0 /* 992 */
+#define RESOLUTION 26 /* 87mm x 38mm */
+#define MAX_MAJOR 10
+#define MAX_MINOR 10
+#define MAX_PRESSURE 127
+
+struct fte_command {
+ int command;
+ unsigned char data;
+};
+
+struct focaltech_finger_state {
+ int x;
+ int y;
+ int major;
+ int minor;
+ int pressure;
+ bool valid;
+};
+
+struct focaltech_hw_state {
+ struct focaltech_finger_state fingers[FOCALTECH_MAX_FINGERS];
+ int fingerCount;
+ bool left;
+ bool right;
+};
+
+struct focaltech_data {
+ bool isReadNext;
+ int lastDeviceData[16];
+ struct focaltech_hw_state state;
+};
+
+int focaltech_v2_detect(struct psmouse *psmouse, bool set_properties);
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+int focaltech_v2_init(struct psmouse *psmouse);
+#else
+static inline int focaltech_v2_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0b4a3039f..5f720af51 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -34,6 +34,7 @@
#include "sentelic.h"
#include "cypress_ps2.h"
#include "focaltech.h"
+#include "focaltech_v2.h"
#include "vmmouse.h"
#include "byd.h"
@@ -891,6 +892,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.init = focaltech_init,
},
#endif
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH_V2
+ {
+ .type = PSMOUSE_FOCALTECH_V2,
+ .name = "FocalTechPS/2",
+ .alias = "focaltech-v2",
+ .detect = focaltech_detect,
+ .init = focaltech_init,
+ },
+#endif
#ifdef CONFIG_MOUSE_PS2_VMMOUSE
{
.type = PSMOUSE_VMMOUSE,
@@ -1072,6 +1082,28 @@ static int psmouse_extensions(struct psmouse *psmouse,
psmouse_max_proto = max_proto = PSMOUSE_PS2;
}
+ /*
+ * Always check for focaltech-v2, this is safe as it uses pnp-id
+ * matching.
+ */
+ if (psmouse_do_detect(focaltech_v2_detect,
+ psmouse, false, set_properties)) {
+ if (max_proto > PSMOUSE_IMEX &&
+ IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH_V2) &&
+ (!set_properties || focaltech_v2_init(psmouse) == 0)) {
+ return PSMOUSE_FOCALTECH_V2;
+ }
+ /*
+ * 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).
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 64c3a5d3f..68e06aaac 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -65,6 +65,7 @@ enum psmouse_type {
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_CYPRESS,
PSMOUSE_FOCALTECH,
+ PSMOUSE_FOCALTECH_V2,
PSMOUSE_VMMOUSE,
PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS,
--
2.27.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-02-15 22:50 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-10 23:39 [PATCH] Input: psmouse - add support for FocalTech PS/2 Protocol v2 Hamza Farooq
2021-02-11 10:36 ` kernel test robot
2021-02-11 10:36 ` kernel test robot
2021-02-15 22:49 ` [PATCH v2] " Hamza Farooq
2021-02-15 22:38 ` Hamza Farooq
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.