From a1d4845f8f9110109a5605a7f8c676b0508975ca Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 6 Apr 2015 18:22:08 +0000 Subject: [PATCH] psmouse: Add support for FocalTech touchpads, thanks to Rafal Ramocki (Closes: #780971) svn path=/dists/sid/linux/; revision=22478 --- debian/changelog | 2 + ...-set-the-firmware-id-for-muxed-ports.patch | 24 + ...d-psmouse_matches_pnp_id-helper-func.patch | 89 +++ ...d-support-for-detecting-focaltech-ps.patch | 155 +++++ ...sable-changing-resolution-rate-scale.patch | 119 ++++ ...sable-palm-detection-in-the-focaltec.patch | 38 ++ ...sure-that-focaltech-reports-consiste.patch | 41 ++ ...move-hardcoded-touchpad-size-from-th.patch | 38 ++ ...pport-for-the-focaltech-ps-2-protoco.patch | 572 ++++++++++++++++++ debian/patches/series | 9 + 10 files changed, 1087 insertions(+) create mode 100644 debian/patches/features/all/psmouse/input-i8042-also-set-the-firmware-id-for-muxed-ports.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-add-psmouse_matches_pnp_id-helper-func.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-add-support-for-detecting-focaltech-ps.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-disable-changing-resolution-rate-scale.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-disable-palm-detection-in-the-focaltec.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-ensure-that-focaltech-reports-consiste.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-remove-hardcoded-touchpad-size-from-th.patch create mode 100644 debian/patches/features/all/psmouse/input-psmouse-support-for-the-focaltech-ps-2-protoco.patch diff --git a/debian/changelog b/debian/changelog index a5b638e44..1ccfbfc32 100644 --- a/debian/changelog +++ b/debian/changelog @@ -190,6 +190,8 @@ linux (3.16.7-ckt9-1) UNRELEASED; urgency=medium * [powerpc/powerpc64,ppc64] Disable THERM_PM72 and enable its replacements WINDFARM_PM72 and WINDFARM_RM31 as modules. Update the udeb config accordingly. Thanks to Milan Kupcevic. (Closes: #781934) + * psmouse: Add support for FocalTech touchpads, thanks to Rafal Ramocki + (Closes: #780971) -- Ian Campbell Wed, 18 Mar 2015 21:07:15 +0000 diff --git a/debian/patches/features/all/psmouse/input-i8042-also-set-the-firmware-id-for-muxed-ports.patch b/debian/patches/features/all/psmouse/input-i8042-also-set-the-firmware-id-for-muxed-ports.patch new file mode 100644 index 000000000..13df66e03 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-i8042-also-set-the-firmware-id-for-muxed-ports.patch @@ -0,0 +1,24 @@ +From: Hans de Goede +Date: Thu, 11 Sep 2014 10:13:13 -0700 +Subject: Input: i8042 - also set the firmware id for MUXed ports +Origin: https://git.kernel.org/linus/266e43c4eb81440e81da6c51bc5d4f9be2b7839c + +So that firmware-id matching can be used with multiplexed aux ports too. + +Signed-off-by: Hans de Goede +Signed-off-by: Dmitry Torokhov +--- + drivers/input/serio/i8042.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/input/serio/i8042.c ++++ b/drivers/input/serio/i8042.c +@@ -1268,6 +1268,8 @@ static int __init i8042_create_aux_port( + } else { + snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); ++ strlcpy(serio->firmware_id, i8042_aux_firmware_id, ++ sizeof(serio->firmware_id)); + } + + port->serio = serio; diff --git a/debian/patches/features/all/psmouse/input-psmouse-add-psmouse_matches_pnp_id-helper-func.patch b/debian/patches/features/all/psmouse/input-psmouse-add-psmouse_matches_pnp_id-helper-func.patch new file mode 100644 index 000000000..acf984ef8 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-add-psmouse_matches_pnp_id-helper-func.patch @@ -0,0 +1,89 @@ +From: Hans de Goede +Date: Thu, 11 Sep 2014 10:14:09 -0700 +Subject: Input: psmouse - add psmouse_matches_pnp_id helper function +Origin: https://git.kernel.org/linus/2c75ada6250990ea859b0b5498cb0b7c2823a9d7 + +The matches_pnp_id function from the synaptics driver is useful for other +drivers too. Make it a generic psmouse helper function. + +Signed-off-by: Hans de Goede +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/psmouse-base.c | 14 ++++++++++++++ + drivers/input/mouse/psmouse.h | 1 + + drivers/input/mouse/synaptics.c | 17 +++-------------- + 3 files changed, 18 insertions(+), 14 deletions(-) + +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -462,6 +462,20 @@ static int psmouse_poll(struct psmouse * + PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); + } + ++/* ++ * psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids. ++ */ ++bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) ++{ ++ int i; ++ ++ if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) ++ for (i = 0; ids[i]; i++) ++ if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) ++ return true; ++ ++ return false; ++} + + /* + * Genius NetMouse magic init. +--- a/drivers/input/mouse/psmouse.h ++++ b/drivers/input/mouse/psmouse.h +@@ -108,6 +108,7 @@ void psmouse_set_resolution(struct psmou + psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); + int psmouse_activate(struct psmouse *psmouse); + int psmouse_deactivate(struct psmouse *psmouse); ++bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]); + + struct psmouse_attribute { + struct device_attribute dattr; +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -188,18 +188,6 @@ static const char * const topbuttonpad_p + NULL + }; + +-static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) +-{ +- int i; +- +- if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) +- for (i = 0; ids[i]; i++) +- if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) +- return true; +- +- return false; +-} +- + /***************************************************************************** + * Synaptics communications functions + ****************************************************************************/ +@@ -365,7 +353,8 @@ static int synaptics_resolution(struct p + } + + for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { +- if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) { ++ if (psmouse_matches_pnp_id(psmouse, ++ min_max_pnpid_table[i].pnp_ids)) { + priv->x_min = min_max_pnpid_table[i].x_min; + priv->x_max = min_max_pnpid_table[i].x_max; + priv->y_min = min_max_pnpid_table[i].y_min; +@@ -1448,7 +1437,7 @@ static void set_input_params(struct psmo + + if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +- if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) ++ if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) + __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); + /* Clickpads report only left button */ + __clear_bit(BTN_RIGHT, dev->keybit); diff --git a/debian/patches/features/all/psmouse/input-psmouse-add-support-for-detecting-focaltech-ps.patch b/debian/patches/features/all/psmouse/input-psmouse-add-support-for-detecting-focaltech-ps.patch new file mode 100644 index 000000000..fa02982a0 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-add-support-for-detecting-focaltech-ps.patch @@ -0,0 +1,155 @@ +From: Hans de Goede +Date: Fri, 12 Sep 2014 17:24:47 -0700 +Subject: [1/6] Input: psmouse - add support for detecting FocalTech PS/2 + touchpads +Origin: https://git.kernel.org/linus/3ace3686f198e656624d7ca2984d053e65f6e09d + +The Asus X450 and X550 laptops use a PS/2 touchpad from a new +manufacturer called FocalTech: + +https://bugzilla.kernel.org/show_bug.cgi?id=77391 +https://bugzilla.redhat.com/show_bug.cgi?id=1110011 + +The protocol for these devices is not known at this time, but even +without knowing the protocol they need some special handling. They get +upset by some of our other PS/2 device probing, and once upset generate +random mouse events making things unusable even with an external mouse. + +This patch adds detection of these devices based on their pnp ids, and +when they are detected, treats them as a bare ps/2 mouse. Doing things +this way they at least work in their ps/2 mouse emulation mode. + +Signed-off-by: Hans de Goede +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/Makefile | 2 +- + drivers/input/mouse/focaltech.c | 52 ++++++++++++++++++++++++++++++++++++++ + drivers/input/mouse/focaltech.h | 22 ++++++++++++++++ + drivers/input/mouse/psmouse-base.c | 16 ++++++++++++ + 4 files changed, 91 insertions(+), 1 deletion(-) + create mode 100644 drivers/input/mouse/focaltech.c + create mode 100644 drivers/input/mouse/focaltech.h + +--- a/drivers/input/mouse/Makefile ++++ b/drivers/input/mouse/Makefile +@@ -23,7 +23,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += syn + obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o + obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o + +-psmouse-objs := psmouse-base.o synaptics.o ++psmouse-objs := psmouse-base.o synaptics.o focaltech.o + + psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o + psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o +--- /dev/null ++++ b/drivers/input/mouse/focaltech.c +@@ -0,0 +1,52 @@ ++/* ++ * Focaltech TouchPad PS/2 mouse driver ++ * ++ * Copyright (c) 2014 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * Red Hat authors: ++ * ++ * Hans de Goede ++ */ ++ ++/* ++ * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with ++ * detection only, to avoid further detection attempts confusing the touchpad ++ * this way it at least works in PS/2 mouse compatibility mode. ++ */ ++ ++#include ++#include ++#include "psmouse.h" ++ ++static const char * const focaltech_pnp_ids[] = { ++ "FLT0101", ++ "FLT0102", ++ "FLT0103", ++ NULL ++}; ++ ++int focaltech_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 = "FocalTech Touchpad in mouse emulation mode"; ++ } ++ ++ return 0; ++} ++ ++int focaltech_init(struct psmouse *psmouse) ++{ ++ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); ++ psmouse_reset(psmouse); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/input/mouse/focaltech.h +@@ -0,0 +1,22 @@ ++/* ++ * Focaltech TouchPad PS/2 mouse driver ++ * ++ * Copyright (c) 2014 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * Red Hat authors: ++ * ++ * Hans de Goede ++ */ ++ ++#ifndef _FOCALTECH_H ++#define _FOCALTECH_H ++ ++int focaltech_detect(struct psmouse *psmouse, bool set_properties); ++int focaltech_init(struct psmouse *psmouse); ++ ++#endif +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -35,6 +35,7 @@ + #include "elantech.h" + #include "sentelic.h" + #include "cypress_ps2.h" ++#include "focaltech.h" + + #define DRIVER_DESC "PS/2 mouse driver" + +@@ -720,6 +721,21 @@ static int psmouse_extensions(struct psm + { + 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 (!set_properties || focaltech_init(psmouse) == 0) { ++ /* ++ * Not supported yet, use bare protocol. ++ * 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). diff --git a/debian/patches/features/all/psmouse/input-psmouse-disable-changing-resolution-rate-scale.patch b/debian/patches/features/all/psmouse/input-psmouse-disable-changing-resolution-rate-scale.patch new file mode 100644 index 000000000..dc896eba9 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-disable-changing-resolution-rate-scale.patch @@ -0,0 +1,119 @@ +From: Mathias Gottschlag +Date: Sat, 7 Mar 2015 13:32:10 -0800 +Subject: [5/6] Input: psmouse - disable changing resolution/rate/scale for + FocalTech +Origin: https://git.kernel.org/linus/4ec212f003d2430b0b2748b8a3008255f39cfe13 + +These PS/2 commands make some touchpads stop responding, so this commit +adds some dummy functions to replace the generic implementation. Because +scale changes were not encapsulated in a method of struct psmouse yet, this +commit adds a method set_scale to psmouse. + +Signed-off-by: Mathias Gottschlag +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/focaltech.c | 25 +++++++++++++++++++++++++ + drivers/input/mouse/psmouse-base.c | 14 +++++++++++++- + drivers/input/mouse/psmouse.h | 6 ++++++ + 3 files changed, 44 insertions(+), 1 deletion(-) + +--- a/drivers/input/mouse/focaltech.c ++++ b/drivers/input/mouse/focaltech.c +@@ -386,6 +386,23 @@ static int focaltech_read_size(struct ps + + return 0; + } ++ ++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_init(struct psmouse *psmouse) + { + struct focaltech_data *priv; +@@ -420,6 +437,14 @@ int focaltech_init(struct psmouse *psmou + 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; + +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -454,6 +454,17 @@ static void psmouse_set_rate(struct psmo + } + + /* ++ * Here we set the mouse scaling. ++ */ ++ ++static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) ++{ ++ ps2_command(&psmouse->ps2dev, NULL, ++ scale == PSMOUSE_SCALE21 ? PSMOUSE_CMD_SETSCALE21 : ++ PSMOUSE_CMD_SETSCALE11); ++} ++ ++/* + * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. + */ + +@@ -687,6 +698,7 @@ static void psmouse_apply_defaults(struc + + 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; +@@ -1158,7 +1170,7 @@ static void psmouse_initialize(struct ps + if (psmouse_max_proto != PSMOUSE_PS2) { + psmouse->set_rate(psmouse, psmouse->rate); + psmouse->set_resolution(psmouse, psmouse->resolution); +- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); ++ psmouse->set_scale(psmouse, PSMOUSE_SCALE11); + } + } + +--- a/drivers/input/mouse/psmouse.h ++++ b/drivers/input/mouse/psmouse.h +@@ -36,6 +36,11 @@ typedef enum { + PSMOUSE_FULL_PACKET + } psmouse_ret_t; + ++enum psmouse_scale { ++ PSMOUSE_SCALE11, ++ PSMOUSE_SCALE21 ++}; ++ + struct psmouse { + void *private; + struct input_dev *dev; +@@ -67,6 +72,7 @@ struct psmouse { + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse); + void (*set_rate)(struct psmouse *psmouse, unsigned int rate); + void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution); ++ void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale); + + int (*reconnect)(struct psmouse *psmouse); + void (*disconnect)(struct psmouse *psmouse); diff --git a/debian/patches/features/all/psmouse/input-psmouse-disable-palm-detection-in-the-focaltec.patch b/debian/patches/features/all/psmouse/input-psmouse-disable-palm-detection-in-the-focaltec.patch new file mode 100644 index 000000000..86820deca --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-disable-palm-detection-in-the-focaltec.patch @@ -0,0 +1,38 @@ +From: Mathias Gottschlag +Date: Sat, 7 Mar 2015 13:38:52 -0800 +Subject: [6/6] Input: psmouse - disable "palm detection" in the focaltech + driver +Origin: https://git.kernel.org/linus/4eb8d6e7e5aa14572bc389e554aad9869188cdcd + +Apparently, the threshold for large contact area seems to be rather low on +some devices, causing the touchpad to frequently freeze during normal +usage. Because we do now know how we are supposed to use the value in +question, this commit just drops the related code completely. + +Signed-off-by: Mathias Gottschlag +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/focaltech.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c +index 891a271..23d2594 100644 +--- a/drivers/input/mouse/focaltech.c ++++ b/drivers/input/mouse/focaltech.c +@@ -185,16 +185,6 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse, + + state->pressed = (packet[0] >> 4) & 1; + +- /* +- * packet[5] contains some kind of tool size in the most +- * significant nibble. 0xff is a special value (latching) that +- * signals a large contact area. +- */ +- if (packet[5] == 0xff) { +- state->fingers[finger].valid = false; +- return; +- } +- + state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; + state->fingers[finger].y = (packet[3] << 8) | packet[4]; + state->fingers[finger].valid = true; diff --git a/debian/patches/features/all/psmouse/input-psmouse-ensure-that-focaltech-reports-consiste.patch b/debian/patches/features/all/psmouse/input-psmouse-ensure-that-focaltech-reports-consiste.patch new file mode 100644 index 000000000..a0b5a7ec0 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-ensure-that-focaltech-reports-consiste.patch @@ -0,0 +1,41 @@ +From: Mathias Gottschlag +Date: Sat, 7 Mar 2015 13:27:08 -0800 +Subject: [4/6] Input: psmouse - ensure that focaltech reports consistent + coordinates +Origin: https://git.kernel.org/linus/679d83ea9390636ded518f533af0cefbade317c7 + +We don't know whether x_max or y_max really hold the maximum possible +coordinates, and we don't know for sure whether we correctly interpret the +coordinates sent by the touchpad, so we clamp the reported values to +prevent confusion in userspace code. + +Signed-off-by: Mathias Gottschlag +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/focaltech.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c +index e8fafe8..c66e0e0 100644 +--- a/drivers/input/mouse/focaltech.c ++++ b/drivers/input/mouse/focaltech.c +@@ -126,9 +126,17 @@ static void focaltech_report_state(struct psmouse *psmouse) + input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); + if (active) { +- input_report_abs(dev, ABS_MT_POSITION_X, finger->x); ++ unsigned int clamped_x, clamped_y; ++ /* ++ * The touchpad might report invalid data, so we clamp ++ * the resulting values so that we do not confuse ++ * userspace. ++ */ ++ clamped_x = clamp(finger->x, 0U, priv->x_max); ++ clamped_y = clamp(finger->y, 0U, priv->y_max); ++ input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); + input_report_abs(dev, ABS_MT_POSITION_Y, +- priv->y_max - finger->y); ++ priv->y_max - clamped_y); + } + } + input_mt_report_pointer_emulation(dev, true); diff --git a/debian/patches/features/all/psmouse/input-psmouse-remove-hardcoded-touchpad-size-from-th.patch b/debian/patches/features/all/psmouse/input-psmouse-remove-hardcoded-touchpad-size-from-th.patch new file mode 100644 index 000000000..55fc46ba8 --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-remove-hardcoded-touchpad-size-from-th.patch @@ -0,0 +1,38 @@ +From: Mathias Gottschlag +Date: Sat, 7 Mar 2015 13:26:31 -0800 +Subject: [3/6] Input: psmouse - remove hardcoded touchpad size from the + focaltech driver +Origin: https://git.kernel.org/linus/3e9845251926723319fb60c9e546fe42d3d11687 + +The size has in most cases already been fetched from the touchpad, the +hardcoded values should have been removed. + +Signed-off-by: Mathias Gottschlag +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/focaltech.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c +index 757f78a..e8fafe8 100644 +--- a/drivers/input/mouse/focaltech.c ++++ b/drivers/input/mouse/focaltech.c +@@ -67,9 +67,6 @@ static void focaltech_reset(struct psmouse *psmouse) + + #define FOC_MAX_FINGERS 5 + +-#define FOC_MAX_X 2431 +-#define FOC_MAX_Y 1663 +- + /* + * Current state of a single finger on the touchpad. + */ +@@ -131,7 +128,7 @@ static void focaltech_report_state(struct psmouse *psmouse) + if (active) { + input_report_abs(dev, ABS_MT_POSITION_X, finger->x); + input_report_abs(dev, ABS_MT_POSITION_Y, +- FOC_MAX_Y - finger->y); ++ priv->y_max - finger->y); + } + } + input_mt_report_pointer_emulation(dev, true); diff --git a/debian/patches/features/all/psmouse/input-psmouse-support-for-the-focaltech-ps-2-protoco.patch b/debian/patches/features/all/psmouse/input-psmouse-support-for-the-focaltech-ps-2-protoco.patch new file mode 100644 index 000000000..5af42e8fb --- /dev/null +++ b/debian/patches/features/all/psmouse/input-psmouse-support-for-the-focaltech-ps-2-protoco.patch @@ -0,0 +1,572 @@ +From: Mathias Gottschlag +Date: Mon, 29 Dec 2014 09:26:35 -0800 +Subject: [2/6] Input: psmouse - support for the FocalTech PS/2 protocol + extensions +Origin: https://git.kernel.org/linus/05be1d079ec0b3691783e4384b1ada82149ff7d2 + +Most of the protocol for these touchpads has been reverse engineered. This +commit adds a basic multitouch-capable driver. + +A lot of the protocol is still unknown. Especially, we don't know how to +identify the device yet apart from the PNP ID. + +The previous workaround for these devices has been left in place in case +the driver is not compiled into the kernel or in case some other device +with the same PNP ID is not recognized by the driver yet still has the same +problems with the device probing code. + +Signed-off-by: Mathias Gottschlag +Reviewed-by: Hans de Goede +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/Kconfig | 10 + + drivers/input/mouse/focaltech.c | 408 ++++++++++++++++++++++++++++++++++++- + drivers/input/mouse/focaltech.h | 2 + + drivers/input/mouse/psmouse-base.c | 32 ++- + drivers/input/mouse/psmouse.h | 1 + + 5 files changed, 436 insertions(+), 17 deletions(-) + +--- a/drivers/input/mouse/Kconfig ++++ b/drivers/input/mouse/Kconfig +@@ -146,6 +146,16 @@ config MOUSE_PS2_OLPC + + If unsure, say N. + ++config MOUSE_PS2_FOCALTECH ++ bool "FocalTech PS/2 mouse protocol extension" if EXPERT ++ default y ++ depends on MOUSE_PS2 ++ help ++ Say Y here if you have a FocalTech PS/2 TouchPad connected to ++ your system. ++ ++ If unsure, say Y. ++ + config MOUSE_SERIAL + tristate "Serial mouse" + select SERIO +--- a/drivers/input/mouse/focaltech.c ++++ b/drivers/input/mouse/focaltech.c +@@ -2,6 +2,7 @@ + * Focaltech TouchPad PS/2 mouse driver + * + * Copyright (c) 2014 Red Hat Inc. ++ * Copyright (c) 2014 Mathias Gottschlag + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -13,15 +14,14 @@ + * Hans de Goede + */ + +-/* +- * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with +- * detection only, to avoid further detection attempts confusing the touchpad +- * this way it at least works in PS/2 mouse compatibility mode. +- */ + + #include + #include ++#include ++#include ++#include + #include "psmouse.h" ++#include "focaltech.h" + + static const char * const focaltech_pnp_ids[] = { + "FLT0101", +@@ -30,6 +30,12 @@ static const char * const focaltech_pnp_ + NULL + }; + ++/* ++ * Even if the kernel is built without support for Focaltech PS/2 touchpads (or ++ * when the real driver fails to recognize the device), we still have to detect ++ * them in order to avoid further detection attempts confusing the touchpad. ++ * This way it at least works in PS/2 mouse compatibility mode. ++ */ + int focaltech_detect(struct psmouse *psmouse, bool set_properties) + { + if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) +@@ -37,16 +43,404 @@ int focaltech_detect(struct psmouse *psm + + if (set_properties) { + psmouse->vendor = "FocalTech"; +- psmouse->name = "FocalTech Touchpad in mouse emulation mode"; ++ psmouse->name = "FocalTech Touchpad"; + } + + return 0; + } + +-int focaltech_init(struct psmouse *psmouse) ++static void focaltech_reset(struct psmouse *psmouse) + { + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + psmouse_reset(psmouse); ++} ++ ++#ifdef CONFIG_MOUSE_PS2_FOCALTECH ++ ++/* ++ * Packet types - the numbers are not consecutive, so we might be missing ++ * something here. ++ */ ++#define FOC_TOUCH 0x3 /* bitmap of active fingers */ ++#define FOC_ABS 0x6 /* absolute position of one finger */ ++#define FOC_REL 0x9 /* relative position of 1-2 fingers */ ++ ++#define FOC_MAX_FINGERS 5 ++ ++#define FOC_MAX_X 2431 ++#define FOC_MAX_Y 1663 ++ ++/* ++ * Current state of a single finger on the touchpad. ++ */ ++struct focaltech_finger_state { ++ /* The touchpad has generated a touch event for the finger */ ++ bool active; ++ ++ /* ++ * The touchpad has sent position data for the finger. The ++ * flag is 0 when the finger is not active, and there is a ++ * time between the first touch event for the finger and the ++ * following absolute position packet for the finger where the ++ * touchpad has declared the finger to be valid, but we do not ++ * have any valid position yet. ++ */ ++ bool valid; ++ ++ /* ++ * Absolute position (from the bottom left corner) of the ++ * finger. ++ */ ++ unsigned int x; ++ unsigned int y; ++}; ++ ++/* ++ * Description of the current state of the touchpad hardware. ++ */ ++struct focaltech_hw_state { ++ /* ++ * The touchpad tracks the positions of the fingers for us, ++ * the array indices correspond to the finger indices returned ++ * in the report packages. ++ */ ++ struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; ++ ++ /* True if the clickpad has been pressed. */ ++ bool pressed; ++}; ++ ++struct focaltech_data { ++ unsigned int x_max, y_max; ++ struct focaltech_hw_state state; ++}; ++ ++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 < FOC_MAX_FINGERS; i++) { ++ struct focaltech_finger_state *finger = &state->fingers[i]; ++ bool active = finger->active && finger->valid; ++ ++ input_mt_slot(dev, i); ++ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); ++ if (active) { ++ input_report_abs(dev, ABS_MT_POSITION_X, finger->x); ++ input_report_abs(dev, ABS_MT_POSITION_Y, ++ FOC_MAX_Y - finger->y); ++ } ++ } ++ input_mt_report_pointer_emulation(dev, true); ++ ++ input_report_key(psmouse->dev, BTN_LEFT, state->pressed); ++ input_sync(psmouse->dev); ++} ++ ++static void focaltech_process_touch_packet(struct psmouse *psmouse, ++ unsigned char *packet) ++{ ++ struct focaltech_data *priv = psmouse->private; ++ struct focaltech_hw_state *state = &priv->state; ++ unsigned char fingers = packet[1]; ++ int i; ++ ++ state->pressed = (packet[0] >> 4) & 1; ++ ++ /* the second byte contains a bitmap of all fingers touching the pad */ ++ for (i = 0; i < FOC_MAX_FINGERS; i++) { ++ state->fingers[i].active = fingers & 0x1; ++ if (!state->fingers[i].active) { ++ /* ++ * Even when the finger becomes active again, we still ++ * will have to wait for the first valid position. ++ */ ++ state->fingers[i].valid = false; ++ } ++ fingers >>= 1; ++ } ++} ++ ++static void focaltech_process_abs_packet(struct psmouse *psmouse, ++ unsigned char *packet) ++{ ++ struct focaltech_data *priv = psmouse->private; ++ struct focaltech_hw_state *state = &priv->state; ++ unsigned int finger; ++ ++ finger = (packet[1] >> 4) - 1; ++ if (finger >= FOC_MAX_FINGERS) { ++ psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", ++ finger); ++ return; ++ } ++ ++ state->pressed = (packet[0] >> 4) & 1; ++ ++ /* ++ * packet[5] contains some kind of tool size in the most ++ * significant nibble. 0xff is a special value (latching) that ++ * signals a large contact area. ++ */ ++ if (packet[5] == 0xff) { ++ state->fingers[finger].valid = false; ++ return; ++ } ++ ++ state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; ++ state->fingers[finger].y = (packet[3] << 8) | packet[4]; ++ state->fingers[finger].valid = true; ++} ++ ++static void focaltech_process_rel_packet(struct psmouse *psmouse, ++ unsigned char *packet) ++{ ++ struct focaltech_data *priv = psmouse->private; ++ struct focaltech_hw_state *state = &priv->state; ++ int finger1, finger2; ++ ++ state->pressed = packet[0] >> 7; ++ finger1 = ((packet[0] >> 4) & 0x7) - 1; ++ if (finger1 < FOC_MAX_FINGERS) { ++ state->fingers[finger1].x += (char)packet[1]; ++ state->fingers[finger1].y += (char)packet[2]; ++ } else { ++ psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", ++ finger1); ++ } ++ ++ /* ++ * If there is an odd number of fingers, the last relative ++ * packet only contains one finger. In this case, the second ++ * finger index in the packet is 0 (we subtract 1 in the lines ++ * above to create array indices, so the finger will overflow ++ * and be above FOC_MAX_FINGERS). ++ */ ++ finger2 = ((packet[3] >> 4) & 0x7) - 1; ++ if (finger2 < FOC_MAX_FINGERS) { ++ state->fingers[finger2].x += (char)packet[4]; ++ state->fingers[finger2].y += (char)packet[5]; ++ } ++} ++ ++static void focaltech_process_packet(struct psmouse *psmouse) ++{ ++ unsigned char *packet = psmouse->packet; ++ ++ switch (packet[0] & 0xf) { ++ case FOC_TOUCH: ++ focaltech_process_touch_packet(psmouse, packet); ++ break; ++ ++ case FOC_ABS: ++ focaltech_process_abs_packet(psmouse, packet); ++ break; ++ ++ case FOC_REL: ++ focaltech_process_rel_packet(psmouse, packet); ++ break; ++ ++ default: ++ psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); ++ break; ++ } ++ ++ focaltech_report_state(psmouse); ++} ++ ++static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) ++{ ++ if (psmouse->pktcnt >= 6) { /* Full packet received */ ++ focaltech_process_packet(psmouse); ++ return PSMOUSE_FULL_PACKET; ++ } ++ ++ /* ++ * We might want to do some validation of the data here, but ++ * we do not know the protocol well enough ++ */ ++ return PSMOUSE_GOOD_DATA; ++} ++ ++static int focaltech_switch_protocol(struct psmouse *psmouse) ++{ ++ struct ps2dev *ps2dev = &psmouse->ps2dev; ++ unsigned char param[3]; ++ ++ param[0] = 0; ++ if (ps2_command(ps2dev, param, 0x10f8)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, 0x10f8)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, 0x10f8)) ++ return -EIO; ++ ++ param[0] = 1; ++ if (ps2_command(ps2dev, param, 0x10f8)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) ++ return -EIO; ++ ++ return 0; ++} ++ ++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; ++ struct focaltech_data *priv = psmouse->private; ++ ++ /* ++ * 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); ++ __clear_bit(BTN_RIGHT, dev->keybit); ++ __clear_bit(BTN_MIDDLE, dev->keybit); ++ ++ /* ++ * Now set up our capabilities. ++ */ ++ __set_bit(EV_ABS, dev->evbit); ++ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); ++ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); ++ input_mt_init_slots(dev, 5, INPUT_MT_POINTER); ++ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); ++} ++ ++static int focaltech_read_register(struct ps2dev *ps2dev, int reg, ++ unsigned char *param) ++{ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) ++ return -EIO; ++ ++ param[0] = 0; ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) ++ return -EIO; ++ ++ param[0] = reg; ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) ++ return -EIO; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int focaltech_read_size(struct psmouse *psmouse) ++{ ++ struct ps2dev *ps2dev = &psmouse->ps2dev; ++ struct focaltech_data *priv = psmouse->private; ++ char param[3]; ++ ++ if (focaltech_read_register(ps2dev, 2, param)) ++ return -EIO; ++ ++ /* not sure whether this is 100% correct */ ++ priv->x_max = (unsigned char)param[1] * 128; ++ priv->y_max = (unsigned char)param[2] * 128; ++ ++ return 0; ++} ++int focaltech_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_read_size(psmouse); ++ if (error) { ++ psmouse_err(psmouse, ++ "Unable to read the size of the touchpad\n"); ++ goto fail; ++ } ++ ++ 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 = 6; ++ psmouse->disconnect = focaltech_disconnect; ++ psmouse->reconnect = focaltech_reconnect; ++ psmouse->cleanup = focaltech_reset; ++ /* resync is not supported yet */ ++ psmouse->resync_time = 0; + + return 0; ++ ++fail: ++ focaltech_reset(psmouse); ++ kfree(priv); ++ return error; + } ++ ++bool focaltech_supported(void) ++{ ++ return true; ++} ++ ++#else /* CONFIG_MOUSE_PS2_FOCALTECH */ ++ ++int focaltech_init(struct psmouse *psmouse) ++{ ++ focaltech_reset(psmouse); ++ ++ return 0; ++} ++ ++bool focaltech_supported(void) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ +--- a/drivers/input/mouse/focaltech.h ++++ b/drivers/input/mouse/focaltech.h +@@ -2,6 +2,7 @@ + * Focaltech TouchPad PS/2 mouse driver + * + * Copyright (c) 2014 Red Hat Inc. ++ * Copyright (c) 2014 Mathias Gottschlag + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -18,5 +19,6 @@ + + int focaltech_detect(struct psmouse *psmouse, bool set_properties); + int focaltech_init(struct psmouse *psmouse); ++bool focaltech_supported(void); + + #endif +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -723,16 +723,19 @@ static int psmouse_extensions(struct psm + + /* Always check for focaltech, this is safe as it uses pnp-id matching */ + if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { +- if (!set_properties || focaltech_init(psmouse) == 0) { +- /* +- * Not supported yet, use bare protocol. +- * 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; ++ if (max_proto > PSMOUSE_IMEX) { ++ if (!set_properties || focaltech_init(psmouse) == 0) { ++ if (focaltech_supported()) ++ 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; ++ } + } + } + +@@ -1061,6 +1064,15 @@ static const struct psmouse_protocol psm + .alias = "cortps", + .detect = cortron_detect, + }, ++#ifdef CONFIG_MOUSE_PS2_FOCALTECH ++ { ++ .type = PSMOUSE_FOCALTECH, ++ .name = "FocalTechPS/2", ++ .alias = "focaltech", ++ .detect = focaltech_detect, ++ .init = focaltech_init, ++ }, ++#endif + { + .type = PSMOUSE_AUTO, + .name = "auto", +--- a/drivers/input/mouse/psmouse.h ++++ b/drivers/input/mouse/psmouse.h +@@ -96,6 +96,7 @@ enum psmouse_type { + PSMOUSE_FSP, + PSMOUSE_SYNAPTICS_RELATIVE, + PSMOUSE_CYPRESS, ++ PSMOUSE_FOCALTECH, + PSMOUSE_AUTO /* This one should always be last */ + }; + diff --git a/debian/patches/series b/debian/patches/series index d01606154..957e1653e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -562,3 +562,12 @@ bugfix/all/ext4-fix-accidental-flag-aliasing-in-ext4_map_blocks.patch bugfix/all/ext4-allocate-entire-range-in-zero-range.patch bugfix/x86/x86-microcode-intel-guard-against-stack-overflow-in-.patch bugfix/all/ipv6-don-t-reduce-hop-limit-for-an-interface.patch + +features/all/psmouse/input-i8042-also-set-the-firmware-id-for-muxed-ports.patch +features/all/psmouse/input-psmouse-add-psmouse_matches_pnp_id-helper-func.patch +features/all/psmouse/input-psmouse-add-support-for-detecting-focaltech-ps.patch +features/all/psmouse/input-psmouse-support-for-the-focaltech-ps-2-protoco.patch +features/all/psmouse/input-psmouse-remove-hardcoded-touchpad-size-from-th.patch +features/all/psmouse/input-psmouse-ensure-that-focaltech-reports-consiste.patch +features/all/psmouse/input-psmouse-disable-changing-resolution-rate-scale.patch +features/all/psmouse/input-psmouse-disable-palm-detection-in-the-focaltec.patch