Browse Source

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:

 - new driver for PhoenixRC Flight Controller Adapter

 - new driver for RAVE SP Power button

 - fixes for autosuspend-related deadlocks in a few unput USB dirvers

 - support for 2nd wheel in ATech PS/2 mouse

 - fix for ALPS trackpoint detection on Thinkpad L570 and Latitude 7370

 - bunch of cleanups in various in PS/2 protocols

 - other assorted changes and fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (35 commits)
  Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad
  Input: stmfts, s6sy761 - update my e-mail
  Input: stmfts - use async probe & suspend/resume to avoid 2s delay
  Input: ALPS - fix TrackStick detection on Thinkpad L570 and Latitude 7370
  Input: xpad - add PDP device id 0x02a4
  Input: alps - report pressure of v3 and v7 trackstick
  Input: pxrc - new driver for PhoenixRC Flight Controller Adapter
  Input: usbtouchscreen - do not rely on input_dev->users
  Input: usbtouchscreen - fix deadlock in autosuspend
  Input: pegasus_notetaker - do not rely on input_dev->users
  Input: pagasus_notetaker - fix deadlock in autosuspend
  Input: synaptics_usb - do not rely on input_dev->users
  Input: synaptics_usb - fix deadlock in autosuspend
  Input: gpio-keys - add support for wakeup event action
  Input: appletouch - use true and false for boolean values
  Input: silead - add Chuwi Hi8 support
  Input: analog - use get_cycles() on PPC
  Input: stmpe-keypad - remove VLA usage
  Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list
  Input: add RAVE SP Powerbutton driver
  ...
Linus Torvalds 7 years ago
parent
commit
5414ab31b1
34 changed files with 1358 additions and 491 deletions
  1. 8 0
      Documentation/devicetree/bindings/input/gpio-keys.txt
  2. 22 0
      Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt
  3. 57 0
      Documentation/input/devices/pxrc.rst
  4. 10 0
      drivers/input/joystick/Kconfig
  5. 1 0
      drivers/input/joystick/Makefile
  6. 1 1
      drivers/input/joystick/analog.c
  7. 303 0
      drivers/input/joystick/pxrc.c
  8. 7 2
      drivers/input/joystick/xpad.c
  9. 131 14
      drivers/input/keyboard/gpio_keys.c
  10. 12 4
      drivers/input/keyboard/stmpe-keypad.c
  11. 9 0
      drivers/input/misc/Kconfig
  12. 1 0
      drivers/input/misc/Makefile
  13. 94 0
      drivers/input/misc/rave-sp-pwrbutton.c
  14. 34 30
      drivers/input/mouse/alps.c
  15. 3 3
      drivers/input/mouse/appletouch.c
  16. 16 24
      drivers/input/mouse/elantech.c
  17. 33 29
      drivers/input/mouse/lifebook.c
  18. 87 65
      drivers/input/mouse/logips2pp.c
  19. 103 86
      drivers/input/mouse/psmouse-base.c
  20. 4 1
      drivers/input/mouse/psmouse.h
  21. 1 10
      drivers/input/mouse/sentelic.c
  22. 52 38
      drivers/input/mouse/synaptics.c
  23. 19 12
      drivers/input/mouse/synaptics_usb.c
  24. 24 36
      drivers/input/mouse/trackpoint.c
  25. 24 0
      drivers/input/serio/i8042-x86ia64io.h
  26. 219 103
      drivers/input/serio/libps2.c
  27. 24 8
      drivers/input/tablet/pegasus_notetaker.c
  28. 1 1
      drivers/input/touchscreen/s6sy761.c
  29. 1 0
      drivers/input/touchscreen/silead.c
  30. 3 1
      drivers/input/touchscreen/stmfts.c
  31. 16 8
      drivers/input/touchscreen/usbtouchscreen.c
  32. 13 0
      include/dt-bindings/input/gpio-keys.h
  33. 2 0
      include/linux/gpio_keys.h
  34. 23 15
      include/linux/libps2.h

+ 8 - 0
Documentation/devicetree/bindings/input/gpio-keys.txt

@@ -26,6 +26,14 @@ Optional subnode-properties:
 	  If not specified defaults to 5.
 	- wakeup-source: Boolean, button can wake-up the system.
 			 (Legacy property supported: "gpio-key,wakeup")
+	- wakeup-event-action: Specifies whether the key should wake the
+	  system when asserted, when deasserted, or both. This property is
+	  only valid for keys that wake up the system (e.g., when the
+	  "wakeup-source" property is also provided).
+	  Supported values are defined in linux-event-codes.h:
+		EV_ACT_ASSERTED		- asserted
+		EV_ACT_DEASSERTED	- deasserted
+		EV_ACT_ANY		- both asserted and deasserted
 	- linux,can-disable: Boolean, indicates that button is connected
 	  to dedicated (not shared) interrupt which can be disabled to
 	  suppress events from the button.

+ 22 - 0
Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt

@@ -0,0 +1,22 @@
+Zodiac Inflight Innovations RAVE Supervisory Processor Power Button Bindings
+
+RAVE SP input device is a "MFD cell" device corresponding to power
+button functionality of RAVE Supervisory Processor. It is expected
+that its Device Tree node is specified as a child of the node
+corresponding to the parent RAVE SP device (as documented in
+Documentation/devicetree/bindings/mfd/zii,rave-sp.txt)
+
+Required properties:
+
+- compatible: Should be "zii,rave-sp-pwrbutton"
+
+Example:
+
+	rave-sp {
+		compatible = "zii,rave-sp-rdu1";
+		current-speed = <38400>;
+
+		pwrbutton {
+			compatible = "zii,rave-sp-pwrbutton";
+		};
+	}

+ 57 - 0
Documentation/input/devices/pxrc.rst

@@ -0,0 +1,57 @@
+=======================================================
+pxrc - PhoenixRC Flight Controller Adapter
+=======================================================
+
+:Author: Marcus Folkesson <marcus.folkesson@gmail.com>
+
+This driver let you use your own RC controller plugged into the
+adapter that comes with PhoenixRC [1]_ or other compatible adapters.
+
+The adapter supports 7 analog channels and 1 digital input switch.
+
+Notes
+=====
+
+Many RC controllers is able to configure which stick goes to which channel.
+This is also configurable in most simulators, so a matching is not necessary.
+
+The driver is generating the following input event for analog channels:
+
++---------+----------------+
+| Channel |      Event     |
++=========+================+
+|     1   |  ABS_X         |
++---------+----------------+
+|     2   |  ABS_Y         |
++---------+----------------+
+|     3   |  ABS_RX        |
++---------+----------------+
+|     4   |  ABS_RY        |
++---------+----------------+
+|     5   |  ABS_RUDDER    |
++---------+----------------+
+|     6   |  ABS_THROTTLE  |
++---------+----------------+
+|     7   |  ABS_MISC      |
++---------+----------------+
+
+The digital input switch is generated as an `BTN_A` event.
+
+Manual Testing
+==============
+
+To test this driver's functionality you may use `input-event` which is part of
+the `input layer utilities` suite [2]_.
+
+For example::
+
+    > modprobe pxrc
+    > input-events <devnr>
+
+To print all input events from input `devnr`.
+
+References
+==========
+
+.. [1] http://www.phoenix-sim.com/
+.. [2] https://www.kraxel.org/cgit/input/

+ 10 - 0
drivers/input/joystick/Kconfig

@@ -351,4 +351,14 @@ config JOYSTICK_PSXPAD_SPI_FF
 
 	  To drive rumble motor a dedicated power supply is required.
 
+config JOYSTICK_PXRC
+	tristate "PhoenixRC Flight Controller Adapter"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use the PhoenixRC Flight Controller Adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pxrc.
+
 endif

+ 1 - 0
drivers/input/joystick/Makefile

@@ -23,6 +23,7 @@ obj-$(CONFIG_JOYSTICK_JOYDUMP)		+= joydump.o
 obj-$(CONFIG_JOYSTICK_MAGELLAN)		+= magellan.o
 obj-$(CONFIG_JOYSTICK_MAPLE)		+= maplecontrol.o
 obj-$(CONFIG_JOYSTICK_PSXPAD_SPI)	+= psxpad-spi.o
+obj-$(CONFIG_JOYSTICK_PXRC)			+= pxrc.o
 obj-$(CONFIG_JOYSTICK_SIDEWINDER)	+= sidewinder.o
 obj-$(CONFIG_JOYSTICK_SPACEBALL)	+= spaceball.o
 obj-$(CONFIG_JOYSTICK_SPACEORB)		+= spaceorb.o

+ 1 - 1
drivers/input/joystick/analog.c

@@ -163,7 +163,7 @@ static unsigned int get_time_pit(void)
 #define GET_TIME(x)	do { x = (unsigned int)rdtsc(); } while (0)
 #define DELTA(x,y)	((y)-(x))
 #define TIME_NAME	"TSC"
-#elif defined(__alpha__) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
+#elif defined(__alpha__) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_PPC) || defined(CONFIG_RISCV)
 #define GET_TIME(x)	do { x = get_cycles(); } while (0)
 #define DELTA(x,y)	((y)-(x))
 #define TIME_NAME	"get_cycles"

+ 303 - 0
drivers/input/joystick/pxrc.c

@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Phoenix RC Flight Controller Adapter
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <linux/mutex.h>
+#include <linux/input.h>
+
+#define PXRC_VENDOR_ID	(0x1781)
+#define PXRC_PRODUCT_ID	(0x0898)
+
+static const struct usb_device_id pxrc_table[] = {
+	{ USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, pxrc_table);
+
+struct pxrc {
+	struct input_dev	*input;
+	struct usb_device	*udev;
+	struct usb_interface	*intf;
+	struct urb		*urb;
+	struct mutex		pm_mutex;
+	bool			is_open;
+	__u8			epaddr;
+	char			phys[64];
+	unsigned char           *data;
+	size_t			bsize;
+};
+
+static void pxrc_usb_irq(struct urb *urb)
+{
+	struct pxrc *pxrc = urb->context;
+	int error;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ETIME:
+		/* this urb is timing out */
+		dev_dbg(&pxrc->intf->dev,
+			"%s - urb timed out - was the device unplugged?\n",
+			__func__);
+		return;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+	case -EPIPE:
+		/* this urb is terminated, clean up */
+		dev_dbg(&pxrc->intf->dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
+		return;
+	default:
+		dev_dbg(&pxrc->intf->dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
+		goto exit;
+	}
+
+	if (urb->actual_length == 8) {
+		input_report_abs(pxrc->input, ABS_X, pxrc->data[0]);
+		input_report_abs(pxrc->input, ABS_Y, pxrc->data[2]);
+		input_report_abs(pxrc->input, ABS_RX, pxrc->data[3]);
+		input_report_abs(pxrc->input, ABS_RY, pxrc->data[4]);
+		input_report_abs(pxrc->input, ABS_RUDDER, pxrc->data[5]);
+		input_report_abs(pxrc->input, ABS_THROTTLE, pxrc->data[6]);
+		input_report_abs(pxrc->input, ABS_MISC, pxrc->data[7]);
+
+		input_report_key(pxrc->input, BTN_A, pxrc->data[1]);
+	}
+
+exit:
+	/* Resubmit to fetch new fresh URBs */
+	error = usb_submit_urb(urb, GFP_ATOMIC);
+	if (error && error != -EPERM)
+		dev_err(&pxrc->intf->dev,
+			"%s - usb_submit_urb failed with result: %d",
+			__func__, error);
+}
+
+static int pxrc_open(struct input_dev *input)
+{
+	struct pxrc *pxrc = input_get_drvdata(input);
+	int retval;
+
+	mutex_lock(&pxrc->pm_mutex);
+	retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
+	if (retval) {
+		dev_err(&pxrc->intf->dev,
+			"%s - usb_submit_urb failed, error: %d\n",
+			__func__, retval);
+		retval = -EIO;
+		goto out;
+	}
+
+	pxrc->is_open = true;
+
+out:
+	mutex_unlock(&pxrc->pm_mutex);
+	return retval;
+}
+
+static void pxrc_close(struct input_dev *input)
+{
+	struct pxrc *pxrc = input_get_drvdata(input);
+
+	mutex_lock(&pxrc->pm_mutex);
+	usb_kill_urb(pxrc->urb);
+	pxrc->is_open = false;
+	mutex_unlock(&pxrc->pm_mutex);
+}
+
+static int pxrc_usb_init(struct pxrc *pxrc)
+{
+	struct usb_endpoint_descriptor *epirq;
+	unsigned int pipe;
+	int retval;
+
+	/* Set up the endpoint information */
+	/* This device only has an interrupt endpoint */
+	retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
+			NULL, NULL, &epirq, NULL);
+	if (retval) {
+		dev_err(&pxrc->intf->dev,
+			"Could not find endpoint\n");
+		goto error;
+	}
+
+	pxrc->bsize = usb_endpoint_maxp(epirq);
+	pxrc->epaddr = epirq->bEndpointAddress;
+	pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL);
+	if (!pxrc->data) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	usb_set_intfdata(pxrc->intf, pxrc);
+	usb_make_path(pxrc->udev, pxrc->phys, sizeof(pxrc->phys));
+	strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
+
+	pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pxrc->urb) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	pipe = usb_rcvintpipe(pxrc->udev, pxrc->epaddr),
+	usb_fill_int_urb(pxrc->urb, pxrc->udev, pipe, pxrc->data, pxrc->bsize,
+						pxrc_usb_irq, pxrc, 1);
+
+error:
+	return retval;
+
+
+}
+
+static int pxrc_input_init(struct pxrc *pxrc)
+{
+	pxrc->input = devm_input_allocate_device(&pxrc->intf->dev);
+	if (pxrc->input == NULL) {
+		dev_err(&pxrc->intf->dev, "couldn't allocate input device\n");
+		return -ENOMEM;
+	}
+
+	pxrc->input->name = "PXRC Flight Controller Adapter";
+	pxrc->input->phys = pxrc->phys;
+	usb_to_input_id(pxrc->udev, &pxrc->input->id);
+
+	pxrc->input->open = pxrc_open;
+	pxrc->input->close = pxrc_close;
+
+	input_set_capability(pxrc->input, EV_KEY, BTN_A);
+	input_set_abs_params(pxrc->input, ABS_X, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_Y, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_RX, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_RY, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_RUDDER, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_THROTTLE, 0, 255, 0, 0);
+	input_set_abs_params(pxrc->input, ABS_MISC, 0, 255, 0, 0);
+
+	input_set_drvdata(pxrc->input, pxrc);
+
+	return input_register_device(pxrc->input);
+}
+
+static int pxrc_probe(struct usb_interface *intf,
+		      const struct usb_device_id *id)
+{
+	struct pxrc *pxrc;
+	int retval;
+
+	pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
+	if (!pxrc)
+		return -ENOMEM;
+
+	mutex_init(&pxrc->pm_mutex);
+	pxrc->udev = usb_get_dev(interface_to_usbdev(intf));
+	pxrc->intf = intf;
+
+	retval = pxrc_usb_init(pxrc);
+	if (retval)
+		goto error;
+
+	retval = pxrc_input_init(pxrc);
+	if (retval)
+		goto err_free_urb;
+
+	return 0;
+
+err_free_urb:
+	usb_free_urb(pxrc->urb);
+
+error:
+	return retval;
+}
+
+static void pxrc_disconnect(struct usb_interface *intf)
+{
+	struct pxrc *pxrc = usb_get_intfdata(intf);
+
+	usb_free_urb(pxrc->urb);
+	usb_set_intfdata(intf, NULL);
+}
+
+static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct pxrc *pxrc = usb_get_intfdata(intf);
+
+	mutex_lock(&pxrc->pm_mutex);
+	if (pxrc->is_open)
+		usb_kill_urb(pxrc->urb);
+	mutex_unlock(&pxrc->pm_mutex);
+
+	return 0;
+}
+
+static int pxrc_resume(struct usb_interface *intf)
+{
+	struct pxrc *pxrc = usb_get_intfdata(intf);
+	int retval = 0;
+
+	mutex_lock(&pxrc->pm_mutex);
+	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
+		retval = -EIO;
+
+	mutex_unlock(&pxrc->pm_mutex);
+	return retval;
+}
+
+static int pxrc_pre_reset(struct usb_interface *intf)
+{
+	struct pxrc *pxrc = usb_get_intfdata(intf);
+
+	mutex_lock(&pxrc->pm_mutex);
+	usb_kill_urb(pxrc->urb);
+	return 0;
+}
+
+static int pxrc_post_reset(struct usb_interface *intf)
+{
+	struct pxrc *pxrc = usb_get_intfdata(intf);
+	int retval = 0;
+
+	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
+		retval = -EIO;
+
+	mutex_unlock(&pxrc->pm_mutex);
+
+	return retval;
+}
+
+static int pxrc_reset_resume(struct usb_interface *intf)
+{
+	return pxrc_resume(intf);
+}
+
+static struct usb_driver pxrc_driver = {
+	.name =		"pxrc",
+	.probe =	pxrc_probe,
+	.disconnect =	pxrc_disconnect,
+	.id_table =	pxrc_table,
+	.suspend	= pxrc_suspend,
+	.resume		= pxrc_resume,
+	.pre_reset	= pxrc_pre_reset,
+	.post_reset	= pxrc_post_reset,
+	.reset_resume	= pxrc_reset_resume,
+};
+
+module_usb_driver(pxrc_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("PhoenixRC Flight Controller Adapter");
+MODULE_LICENSE("GPL v2");

+ 7 - 2
drivers/input/joystick/xpad.c

@@ -227,6 +227,7 @@ static const struct xpad_device {
 	{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
 	{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
 	{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
@@ -475,7 +476,8 @@ static const u8 xboxone_hori_init[] = {
 
 /*
  * This packet is required for some of the PDP pads to start
- * sending input reports. One of those pads is (0x0e6f:0x02ab).
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4).
  */
 static const u8 xboxone_pdp_init1[] = {
 	0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
@@ -483,7 +485,8 @@ static const u8 xboxone_pdp_init1[] = {
 
 /*
  * This packet is required for some of the PDP pads to start
- * sending input reports. One of those pads is (0x0e6f:0x02ab).
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4).
  */
 static const u8 xboxone_pdp_init2[] = {
 	0x06, 0x20, 0x00, 0x02, 0x01, 0x00
@@ -521,6 +524,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
 	XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
 	XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init1),
 	XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init2),
+	XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init1),
+	XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init2),
 	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
 	XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
 	XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),

+ 131 - 14
drivers/input/keyboard/gpio_keys.c

@@ -30,6 +30,7 @@
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
+#include <dt-bindings/input/gpio-keys.h>
 
 struct gpio_button_data {
 	const struct gpio_keys_button *button;
@@ -45,6 +46,7 @@ struct gpio_button_data {
 	unsigned int software_debounce;	/* in msecs, for GPIO-driven buttons */
 
 	unsigned int irq;
+	unsigned int wakeup_trigger_type;
 	spinlock_t lock;
 	bool disabled;
 	bool key_pressed;
@@ -540,6 +542,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 	}
 
 	if (bdata->gpiod) {
+		bool active_low = gpiod_is_active_low(bdata->gpiod);
+
 		if (button->debounce_interval) {
 			error = gpiod_set_debounce(bdata->gpiod,
 					button->debounce_interval * 1000);
@@ -568,6 +572,24 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 		isr = gpio_keys_gpio_isr;
 		irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
 
+		switch (button->wakeup_event_action) {
+		case EV_ACT_ASSERTED:
+			bdata->wakeup_trigger_type = active_low ?
+				IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+			break;
+		case EV_ACT_DEASSERTED:
+			bdata->wakeup_trigger_type = active_low ?
+				IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
+			break;
+		case EV_ACT_ANY:
+			/* fall through */
+		default:
+			/*
+			 * For other cases, we are OK letting suspend/resume
+			 * not reconfigure the trigger type.
+			 */
+			break;
+		}
 	} else {
 		if (!button->irq) {
 			dev_err(dev, "Found button without gpio or irq\n");
@@ -586,6 +608,11 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 
 		isr = gpio_keys_irq_isr;
 		irqflags = 0;
+
+		/*
+		 * For IRQ buttons, there is no interrupt for release.
+		 * So we don't need to reconfigure the trigger type for wakeup.
+		 */
 	}
 
 	bdata->code = &ddata->keymap[idx];
@@ -718,6 +745,9 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 			/* legacy name */
 			fwnode_property_read_bool(child, "gpio-key,wakeup");
 
+		fwnode_property_read_u32(child, "wakeup-event-action",
+					 &button->wakeup_event_action);
+
 		button->can_disable =
 			fwnode_property_read_bool(child, "linux,can-disable");
 
@@ -845,19 +875,112 @@ static int gpio_keys_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static int __maybe_unused
+gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata)
+{
+	int error;
+
+	error = enable_irq_wake(bdata->irq);
+	if (error) {
+		dev_err(bdata->input->dev.parent,
+			"failed to configure IRQ %d as wakeup source: %d\n",
+			bdata->irq, error);
+		return error;
+	}
+
+	if (bdata->wakeup_trigger_type) {
+		error = irq_set_irq_type(bdata->irq,
+					 bdata->wakeup_trigger_type);
+		if (error) {
+			dev_err(bdata->input->dev.parent,
+				"failed to set wakeup trigger %08x for IRQ %d: %d\n",
+				bdata->wakeup_trigger_type, bdata->irq, error);
+			disable_irq_wake(bdata->irq);
+			return error;
+		}
+	}
+
+	return 0;
+}
+
+static void __maybe_unused
+gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata)
+{
+	int error;
+
+	/*
+	 * The trigger type is always both edges for gpio-based keys and we do
+	 * not support changing wakeup trigger for interrupt-based keys.
+	 */
+	if (bdata->wakeup_trigger_type) {
+		error = irq_set_irq_type(bdata->irq, IRQ_TYPE_EDGE_BOTH);
+		if (error)
+			dev_warn(bdata->input->dev.parent,
+				 "failed to restore interrupt trigger for IRQ %d: %d\n",
+				 bdata->irq, error);
+	}
+
+	error = disable_irq_wake(bdata->irq);
+	if (error)
+		dev_warn(bdata->input->dev.parent,
+			 "failed to disable IRQ %d as wake source: %d\n",
+			 bdata->irq, error);
+}
+
+static int __maybe_unused
+gpio_keys_enable_wakeup(struct gpio_keys_drvdata *ddata)
+{
+	struct gpio_button_data *bdata;
+	int error;
+	int i;
+
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
+		bdata = &ddata->data[i];
+		if (bdata->button->wakeup) {
+			error = gpio_keys_button_enable_wakeup(bdata);
+			if (error)
+				goto err_out;
+		}
+		bdata->suspended = true;
+	}
+
+	return 0;
+
+err_out:
+	while (i--) {
+		bdata = &ddata->data[i];
+		if (bdata->button->wakeup)
+			gpio_keys_button_disable_wakeup(bdata);
+		bdata->suspended = false;
+	}
+
+	return error;
+}
+
+static void __maybe_unused
+gpio_keys_disable_wakeup(struct gpio_keys_drvdata *ddata)
+{
+	struct gpio_button_data *bdata;
+	int i;
+
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
+		bdata = &ddata->data[i];
+		bdata->suspended = false;
+		if (irqd_is_wakeup_set(irq_get_irq_data(bdata->irq)))
+			gpio_keys_button_disable_wakeup(bdata);
+	}
+}
+
 static int __maybe_unused gpio_keys_suspend(struct device *dev)
 {
 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
 	struct input_dev *input = ddata->input;
-	int i;
+	int error;
 
 	if (device_may_wakeup(dev)) {
-		for (i = 0; i < ddata->pdata->nbuttons; i++) {
-			struct gpio_button_data *bdata = &ddata->data[i];
-			if (bdata->button->wakeup)
-				enable_irq_wake(bdata->irq);
-			bdata->suspended = true;
-		}
+		error = gpio_keys_enable_wakeup(ddata);
+		if (error)
+			return error;
 	} else {
 		mutex_lock(&input->mutex);
 		if (input->users)
@@ -873,15 +996,9 @@ static int __maybe_unused gpio_keys_resume(struct device *dev)
 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
 	struct input_dev *input = ddata->input;
 	int error = 0;
-	int i;
 
 	if (device_may_wakeup(dev)) {
-		for (i = 0; i < ddata->pdata->nbuttons; i++) {
-			struct gpio_button_data *bdata = &ddata->data[i];
-			if (bdata->button->wakeup)
-				disable_irq_wake(bdata->irq);
-			bdata->suspended = false;
-		}
+		gpio_keys_disable_wakeup(ddata);
 	} else {
 		mutex_lock(&input->mutex);
 		if (input->users)

+ 12 - 4
drivers/input/keyboard/stmpe-keypad.c

@@ -48,6 +48,14 @@
 #define STMPE_KEYPAD_KEYMAP_MAX_SIZE \
 	(STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
 
+
+#define STMPE1601_NUM_DATA	5
+#define STMPE2401_NUM_DATA	3
+#define STMPE2403_NUM_DATA	5
+
+/* Make sure it covers all cases above */
+#define MAX_NUM_DATA		5
+
 /**
  * struct stmpe_keypad_variant - model-specific attributes
  * @auto_increment: whether the KPC_DATA_BYTE register address
@@ -74,7 +82,7 @@ struct stmpe_keypad_variant {
 static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
 	[STMPE1601] = {
 		.auto_increment		= true,
-		.num_data		= 5,
+		.num_data		= STMPE1601_NUM_DATA,
 		.num_normal_data	= 3,
 		.max_cols		= 8,
 		.max_rows		= 8,
@@ -84,7 +92,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
 	[STMPE2401] = {
 		.auto_increment		= false,
 		.set_pullup		= true,
-		.num_data		= 3,
+		.num_data		= STMPE2401_NUM_DATA,
 		.num_normal_data	= 2,
 		.max_cols		= 8,
 		.max_rows		= 12,
@@ -94,7 +102,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
 	[STMPE2403] = {
 		.auto_increment		= true,
 		.set_pullup		= true,
-		.num_data		= 5,
+		.num_data		= STMPE2403_NUM_DATA,
 		.num_normal_data	= 3,
 		.max_cols		= 8,
 		.max_rows		= 12,
@@ -156,7 +164,7 @@ static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
 	struct stmpe_keypad *keypad = dev;
 	struct input_dev *input = keypad->input;
 	const struct stmpe_keypad_variant *variant = keypad->variant;
-	u8 fifo[variant->num_data];
+	u8 fifo[MAX_NUM_DATA];
 	int ret;
 	int i;
 

+ 9 - 0
drivers/input/misc/Kconfig

@@ -832,4 +832,13 @@ config INPUT_HISI_POWERKEY
 	  To compile this driver as a module, choose M here: the
 	  module will be called hisi_powerkey.
 
+config INPUT_RAVE_SP_PWRBUTTON
+	tristate "RAVE SP Power button Driver"
+	depends on RAVE_SP_CORE
+	help
+	  Say Y here if you want to enable power key reporting from RAVE SP
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rave-sp-pwrbutton.
+
 endif

+ 1 - 0
drivers/input/misc/Makefile

@@ -59,6 +59,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
 obj-$(CONFIG_INPUT_PWM_VIBRA)		+= pwm-vibra.o
+obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON)	+= rave-sp-pwrbutton.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)	+= regulator-haptic.o
 obj-$(CONFIG_INPUT_RETU_PWRBUTTON)	+= retu-pwrbutton.o

+ 94 - 0
drivers/input/misc/rave-sp-pwrbutton.c

@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Power Button driver for RAVE SP
+//
+// Copyright (C) 2017 Zodiac Inflight Innovations
+//
+//
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/rave-sp.h>
+#include <linux/platform_device.h>
+
+#define RAVE_SP_EVNT_BUTTON_PRESS	(RAVE_SP_EVNT_BASE + 0x00)
+
+struct rave_sp_power_button {
+	struct input_dev *idev;
+	struct notifier_block nb;
+};
+
+static int rave_sp_power_button_event(struct notifier_block *nb,
+				      unsigned long action, void *data)
+{
+	struct rave_sp_power_button *pb =
+		container_of(nb, struct rave_sp_power_button, nb);
+	const u8 event = rave_sp_action_unpack_event(action);
+	const u8 value = rave_sp_action_unpack_value(action);
+	struct input_dev *idev = pb->idev;
+
+	if (event == RAVE_SP_EVNT_BUTTON_PRESS) {
+		input_report_key(idev, KEY_POWER, value);
+		input_sync(idev);
+
+		return NOTIFY_STOP;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int rave_sp_pwrbutton_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rave_sp_power_button *pb;
+	struct input_dev *idev;
+	int error;
+
+	pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
+	if (!pb)
+		return -ENOMEM;
+
+	idev = devm_input_allocate_device(dev);
+	if (!idev)
+		return -ENOMEM;
+
+	idev->name = pdev->name;
+
+	input_set_capability(idev, EV_KEY, KEY_POWER);
+
+	error = input_register_device(idev);
+	if (error)
+		return error;
+
+	pb->idev = idev;
+	pb->nb.notifier_call = rave_sp_power_button_event;
+	pb->nb.priority = 128;
+
+	error = devm_rave_sp_register_event_notifier(dev, &pb->nb);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static const struct of_device_id rave_sp_pwrbutton_of_match[] = {
+	{ .compatible = "zii,rave-sp-pwrbutton" },
+	{}
+};
+
+static struct platform_driver rave_sp_pwrbutton_driver = {
+	.probe = rave_sp_pwrbutton_probe,
+	.driver	= {
+		.name = KBUILD_MODNAME,
+		.of_match_table = rave_sp_pwrbutton_of_match,
+	},
+};
+module_platform_driver(rave_sp_pwrbutton_driver);
+
+MODULE_DEVICE_TABLE(of, rave_sp_pwrbutton_of_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
+MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("RAVE SP Power Button driver");

+ 34 - 30
drivers/input/mouse/alps.c

@@ -139,11 +139,11 @@ static const struct alps_model_info alps_model_data[] = {
 };
 
 static const struct alps_protocol_info alps_v3_protocol_data = {
-	ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT
+	ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
 };
 
 static const struct alps_protocol_info alps_v3_rushmore_data = {
-	ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT
+	ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
 };
 
 static const struct alps_protocol_info alps_v4_protocol_data = {
@@ -155,7 +155,7 @@ static const struct alps_protocol_info alps_v5_protocol_data = {
 };
 
 static const struct alps_protocol_info alps_v7_protocol_data = {
-	ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
+	ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
 };
 
 static const struct alps_protocol_info alps_v8_protocol_data = {
@@ -583,7 +583,7 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 
 	x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
 	y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
-	z = (packet[4] & 0x7c) >> 2;
+	z = packet[4] & 0x7c;
 
 	/*
 	 * The x and y values tend to be quite large, and when used
@@ -595,6 +595,7 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 
 	input_report_rel(dev, REL_X, x);
 	input_report_rel(dev, REL_Y, -y);
+	input_report_abs(dev, ABS_PRESSURE, z);
 
 	/*
 	 * Most ALPS models report the trackstick buttons in the touchpad
@@ -827,7 +828,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = psmouse->dev;
 	struct input_dev *dev2 = priv->dev2;
-	int x, y, z, left, right, middle;
+	int x, y, z;
 
 	/*
 	 * We can use Byte5 to distinguish if the packet is from Touchpad
@@ -847,9 +848,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
 		x = packet[1] | ((packet[3] & 0x20) << 2);
 		y = packet[2] | ((packet[3] & 0x40) << 1);
 		z = packet[4];
-		left = packet[3] & 0x01;
-		right = packet[3] & 0x02;
-		middle = packet[3] & 0x04;
 
 		/* To prevent the cursor jump when finger lifted */
 		if (x == 0x7F && y == 0x7F && z == 0x7F)
@@ -859,9 +857,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
 		input_report_rel(dev2, REL_X, (char)x / 4);
 		input_report_rel(dev2, REL_Y, -((char)y / 4));
 
-		input_report_key(dev2, BTN_LEFT, left);
-		input_report_key(dev2, BTN_RIGHT, right);
-		input_report_key(dev2, BTN_MIDDLE, middle);
+		psmouse_report_standard_buttons(dev2, packet[3]);
 
 		input_sync(dev2);
 		return;
@@ -871,8 +867,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
 	x = packet[1] | ((packet[3] & 0x78) << 4);
 	y = packet[2] | ((packet[4] & 0x78) << 4);
 	z = packet[5];
-	left = packet[3] & 0x01;
-	right = packet[3] & 0x02;
 
 	if (z > 30)
 		input_report_key(dev, BTN_TOUCH, 1);
@@ -888,8 +882,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
 	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
 	/* v6 touchpad does not have middle button */
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
+	packet[3] &= ~BIT(2);
+	psmouse_report_standard_buttons(dev2, packet[3]);
 
 	input_sync(dev);
 }
@@ -1098,7 +1092,7 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
 	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev2 = priv->dev2;
-	int x, y, z, left, right, middle;
+	int x, y, z;
 
 	/* It should be a DualPoint when received trackstick packet */
 	if (!(priv->flags & ALPS_DUALPOINT)) {
@@ -1112,16 +1106,11 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
 	    ((packet[3] & 0x20) << 1);
 	z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
 
-	left = (packet[1] & 0x01);
-	right = (packet[1] & 0x02) >> 1;
-	middle = (packet[1] & 0x04) >> 2;
-
 	input_report_rel(dev2, REL_X, (char)x);
 	input_report_rel(dev2, REL_Y, -((char)y));
+	input_report_abs(dev2, ABS_PRESSURE, z);
 
-	input_report_key(dev2, BTN_LEFT, left);
-	input_report_key(dev2, BTN_RIGHT, right);
-	input_report_key(dev2, BTN_MIDDLE, middle);
+	psmouse_report_standard_buttons(dev2, packet[1]);
 
 	input_sync(dev2);
 }
@@ -1503,10 +1492,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 		alps_report_buttons(dev, dev2,
 				packet[0] & 1, packet[0] & 2, packet[0] & 4);
 
-	input_report_rel(dev, REL_X,
-		packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
-	input_report_rel(dev, REL_Y,
-		packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
+	psmouse_report_standard_motion(dev, packet);
 
 	input_sync(dev);
 }
@@ -2544,13 +2530,31 @@ static int alps_update_btn_info_ss4_v2(unsigned char otp[][4],
 }
 
 static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
-				       struct alps_data *priv)
+					struct alps_data *priv,
+					struct psmouse *psmouse)
 {
 	bool is_dual = false;
+	int reg_val = 0;
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 
-	if (IS_SS4PLUS_DEV(priv->dev_id))
+	if (IS_SS4PLUS_DEV(priv->dev_id)) {
 		is_dual = (otp[0][0] >> 4) & 0x01;
 
+		if (!is_dual) {
+			/* For support TrackStick of Thinkpad L/E series */
+			if (alps_exit_command_mode(psmouse) == 0 &&
+				alps_enter_command_mode(psmouse) == 0) {
+				reg_val = alps_command_mode_read_reg(psmouse,
+									0xD7);
+			}
+			alps_exit_command_mode(psmouse);
+			ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+			if (reg_val == 0x0C || reg_val == 0x1D)
+				is_dual = true;
+		}
+	}
+
 	if (is_dual)
 		priv->flags |= ALPS_DUALPOINT |
 					ALPS_DUALPOINT_WITH_PRESSURE;
@@ -2573,7 +2577,7 @@ static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
 
 	alps_update_btn_info_ss4_v2(otp, priv);
 
-	alps_update_dual_info_ss4_v2(otp, priv);
+	alps_update_dual_info_ss4_v2(otp, priv, psmouse);
 
 	return 0;
 }

+ 3 - 3
drivers/input/mouse/appletouch.c

@@ -587,7 +587,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
 		/* Perform size detection, if not done already */
 		if (unlikely(!dev->size_detect_done)) {
 			atp_detect_size(dev);
-			dev->size_detect_done = 1;
+			dev->size_detect_done = true;
 			goto exit;
 		}
 	}
@@ -813,7 +813,7 @@ static int atp_open(struct input_dev *input)
 	if (usb_submit_urb(dev->urb, GFP_ATOMIC))
 		return -EIO;
 
-	dev->open = 1;
+	dev->open = true;
 	return 0;
 }
 
@@ -823,7 +823,7 @@ static void atp_close(struct input_dev *input)
 
 	usb_kill_urb(dev->urb);
 	cancel_work_sync(&dev->work);
-	dev->open = 0;
+	dev->open = false;
 }
 
 static int atp_handle_geyser(struct atp *dev)

+ 16 - 24
drivers/input/mouse/elantech.c

@@ -35,7 +35,7 @@
 static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
 				unsigned char *param)
 {
-	if (psmouse_sliced_command(psmouse, c) ||
+	if (ps2_sliced_command(&psmouse->ps2dev, c) ||
 	    ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
 		psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c);
 		return -1;
@@ -107,8 +107,8 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
 
 	switch (etd->hw_version) {
 	case 1:
-		if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) ||
-		    psmouse_sliced_command(psmouse, reg) ||
+		if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) ||
+		    ps2_sliced_command(&psmouse->ps2dev, reg) ||
 		    ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
 			rc = -1;
 		}
@@ -162,9 +162,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
 
 	switch (etd->hw_version) {
 	case 1:
-		if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) ||
-		    psmouse_sliced_command(psmouse, reg) ||
-		    psmouse_sliced_command(psmouse, val) ||
+		if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) ||
+		    ps2_sliced_command(&psmouse->ps2dev, reg) ||
+		    ps2_sliced_command(&psmouse->ps2dev, val) ||
 		    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) {
 			rc = -1;
 		}
@@ -279,8 +279,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
 	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
 	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
 	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
-	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+	psmouse_report_standard_buttons(dev, packet[0]);
 
 	if (etd->fw_version < 0x020000 &&
 	    (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
@@ -390,8 +390,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
 	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
 	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
 	input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
-	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+	psmouse_report_standard_buttons(dev, packet[0]);
 	if (etd->reports_pressure) {
 		input_report_abs(dev, ABS_PRESSURE, pres);
 		input_report_abs(dev, ABS_TOOL_WIDTH, width);
@@ -434,9 +433,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
 		x = packet[4] - (int)((packet[1]^0x80) << 1);
 		y = (int)((packet[2]^0x80) << 1) - packet[5];
 
-		input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
-		input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
-		input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
+		psmouse_report_standard_buttons(tp_dev, packet[0]);
 
 		input_report_rel(tp_dev, REL_X, x);
 		input_report_rel(tp_dev, REL_Y, y);
@@ -526,12 +523,10 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
 	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
 
 	/* For clickpads map both buttons to BTN_LEFT */
-	if (etd->fw_version & 0x001000) {
+	if (etd->fw_version & 0x001000)
 		input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
-	} else {
-		input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
-	}
+	else
+		psmouse_report_standard_buttons(dev, packet[0]);
 
 	input_report_abs(dev, ABS_PRESSURE, pres);
 	input_report_abs(dev, ABS_TOOL_WIDTH, width);
@@ -546,13 +541,10 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
 	unsigned char *packet = psmouse->packet;
 
 	/* For clickpads map both buttons to BTN_LEFT */
-	if (etd->fw_version & 0x001000) {
+	if (etd->fw_version & 0x001000)
 		input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
-	} else {
-		input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
-		input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04);
-	}
+	else
+		psmouse_report_standard_buttons(dev, packet[0]);
 
 	input_mt_report_pointer_emulation(dev, true);
 	input_sync(dev);

+ 33 - 29
drivers/input/mouse/lifebook.c

@@ -17,6 +17,7 @@
 #include <linux/libps2.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/types.h>
 
 #include "psmouse.h"
 #include "lifebook.h"
@@ -136,7 +137,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 	struct lifebook_data *priv = psmouse->private;
 	struct input_dev *dev1 = psmouse->dev;
 	struct input_dev *dev2 = priv ? priv->dev2 : NULL;
-	unsigned char *packet = psmouse->packet;
+	u8 *packet = psmouse->packet;
 	bool relative_packet = packet[0] & 0x08;
 
 	if (relative_packet || !lifebook_use_6byte_proto) {
@@ -188,14 +189,10 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 	}
 
 	if (dev2) {
-		if (relative_packet) {
-			input_report_rel(dev2, REL_X,
-				((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
-			input_report_rel(dev2, REL_Y,
-				 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
-		}
-		input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
-		input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
+		if (relative_packet)
+			psmouse_report_standard_motion(dev2, packet);
+
+		psmouse_report_standard_buttons(dev2, packet[0]);
 		input_sync(dev2);
 	}
 
@@ -205,10 +202,12 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 static int lifebook_absolute_mode(struct psmouse *psmouse)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param;
+	u8 param;
+	int error;
 
-	if (psmouse_reset(psmouse))
-		return -1;
+	error = psmouse_reset(psmouse);
+	if (error)
+		return error;
 
 	/*
 	 * Enable absolute output -- ps2_command fails always but if
@@ -224,15 +223,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
 static void lifebook_relative_mode(struct psmouse *psmouse)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param = 0x06;
+	u8 param = 0x06;
 
 	ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
 }
 
 static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 {
-	static const unsigned char params[] = { 0, 1, 2, 2, 3 };
-	unsigned char p;
+	static const u8 params[] = { 0, 1, 2, 2, 3 };
+	u8 p;
 
 	if (resolution == 0 || resolution > 400)
 		resolution = 400;
@@ -257,11 +256,11 @@ static void lifebook_disconnect(struct psmouse *psmouse)
 int lifebook_detect(struct psmouse *psmouse, bool set_properties)
 {
 	if (!lifebook_present)
-		return -1;
+		return -ENXIO;
 
 	if (desired_serio_phys &&
 	    strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
-		return -1;
+		return -ENXIO;
 
 	if (set_properties) {
 		psmouse->vendor = "Fujitsu";
@@ -294,10 +293,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
 	dev2->id.version = 0x0000;
 	dev2->dev.parent = &psmouse->ps2dev.serio->dev;
 
-	dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-	dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-	dev2->keybit[BIT_WORD(BTN_LEFT)] =
-				BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+	input_set_capability(dev2, EV_REL, REL_X);
+	input_set_capability(dev2, EV_REL, REL_Y);
+	input_set_capability(dev2, EV_KEY, BTN_LEFT);
+	input_set_capability(dev2, EV_KEY, BTN_RIGHT);
 
 	error = input_register_device(priv->dev2);
 	if (error)
@@ -316,21 +315,26 @@ int lifebook_init(struct psmouse *psmouse)
 {
 	struct input_dev *dev1 = psmouse->dev;
 	int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
+	int error;
+
+	error = lifebook_absolute_mode(psmouse);
+	if (error)
+		return error;
 
-	if (lifebook_absolute_mode(psmouse))
-		return -1;
+	/* Clear default capabilities */
+	bitmap_zero(dev1->evbit, EV_CNT);
+	bitmap_zero(dev1->relbit, REL_CNT);
+	bitmap_zero(dev1->keybit, KEY_CNT);
 
-	dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
-	dev1->relbit[0] = 0;
-	dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
-	dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_capability(dev1, EV_KEY, BTN_TOUCH);
 	input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
 	input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
 
 	if (!desired_serio_phys) {
-		if (lifebook_create_relative_device(psmouse)) {
+		error = lifebook_create_relative_device(psmouse);
+		if (error) {
 			lifebook_relative_mode(psmouse);
-			return -1;
+			return error;
 		}
 	}
 

+ 87 - 65
drivers/input/mouse/logips2pp.c

@@ -9,9 +9,11 @@
  * the Free Software Foundation.
  */
 
+#include <linux/bitops.h>
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/types.h>
 #include "psmouse.h"
 #include "logips2pp.h"
 
@@ -22,12 +24,12 @@
 #define PS2PP_KIND_TRACKMAN	4
 
 /* Logitech mouse features */
-#define PS2PP_WHEEL		0x01
-#define PS2PP_HWHEEL		0x02
-#define PS2PP_SIDE_BTN		0x04
-#define PS2PP_EXTRA_BTN		0x08
-#define PS2PP_TASK_BTN		0x10
-#define PS2PP_NAV_BTN		0x20
+#define PS2PP_WHEEL		BIT(0)
+#define PS2PP_HWHEEL		BIT(1)
+#define PS2PP_SIDE_BTN		BIT(2)
+#define PS2PP_EXTRA_BTN		BIT(3)
+#define PS2PP_TASK_BTN		BIT(4)
+#define PS2PP_NAV_BTN		BIT(5)
 
 struct ps2pp_info {
 	u8 model;
@@ -42,7 +44,7 @@ struct ps2pp_info {
 static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
 {
 	struct input_dev *dev = psmouse->dev;
-	unsigned char *packet = psmouse->packet;
+	u8 *packet = psmouse->packet;
 
 	if (psmouse->pktcnt < 3)
 		return PSMOUSE_GOOD_DATA;
@@ -58,28 +60,30 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
 
 		case 0x0d: /* Mouse extra info */
 
-			input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
-				(int) (packet[2] & 8) - (int) (packet[2] & 7));
-			input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
-			input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
+			input_report_rel(dev,
+				packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
+				-sign_extend32(packet[2], 3));
+			input_report_key(dev, BTN_SIDE,  packet[2] & BIT(4));
+			input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
 
 			break;
 
 		case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
 
-			input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
-			input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
-			input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
-			input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
-			input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
+			input_report_key(dev, BTN_SIDE,    packet[2] & BIT(0));
+			input_report_key(dev, BTN_EXTRA,   packet[2] & BIT(1));
+			input_report_key(dev, BTN_TASK,    packet[2] & BIT(2));
+			input_report_key(dev, BTN_BACK,    packet[2] & BIT(3));
+			input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
 
 			break;
 
 		case 0x0f: /* TouchPad extra info */
 
-			input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
-				(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
-			packet[0] = packet[2] | 0x08;
+			input_report_rel(dev,
+				packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
+				-sign_extend32(packet[2] >> 4, 3));
+			packet[0] = packet[2] | BIT(3);
 			break;
 
 		default:
@@ -88,16 +92,14 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
 				    (packet[1] >> 4) | (packet[0] & 0x30));
 			break;
 		}
+
+		psmouse_report_standard_buttons(dev, packet[0]);
+
 	} else {
 		/* Standard PS/2 motion data */
-		input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
-		input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+		psmouse_report_standard_packet(dev, packet);
 	}
 
-	input_report_key(dev, BTN_LEFT,    packet[0]       & 1);
-	input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
-	input_report_key(dev, BTN_RIGHT,  (packet[0] >> 1) & 1);
-
 	input_sync(dev);
 
 	return PSMOUSE_FULL_PACKET;
@@ -111,13 +113,17 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
  * Ugly.
  */
 
-static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
+static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
 {
-	if (psmouse_sliced_command(psmouse, command))
-		return -1;
+	int error;
 
-	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
-		return -1;
+	error = ps2_sliced_command(&psmouse->ps2dev, command);
+	if (error)
+		return error;
+
+	error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
+	if (error)
+		return error;
 
 	return 0;
 }
@@ -133,7 +139,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
 static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[4];
+	u8 param[4];
 
 	ps2pp_cmd(psmouse, param, 0x32);
 
@@ -171,7 +177,7 @@ static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
 }
 
 PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
-			ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
+		    ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
 
 /*
  * Support 800 dpi resolution _only_ if the user wants it (there are good
@@ -179,11 +185,12 @@ PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
  * also good reasons to use it, let the user decide).
  */
 
-static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+static void ps2pp_set_resolution(struct psmouse *psmouse,
+				 unsigned int resolution)
 {
 	if (resolution > 400) {
 		struct ps2dev *ps2dev = &psmouse->ps2dev;
-		unsigned char param = 3;
+		u8 param = 3;
 
 		ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
 		ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
@@ -196,7 +203,8 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
 
 static void ps2pp_disconnect(struct psmouse *psmouse)
 {
-	device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
+	device_remove_file(&psmouse->ps2dev.serio->dev,
+			   &psmouse_attr_smartscroll.dattr);
 }
 
 static const struct ps2pp_info *get_model_info(unsigned char model)
@@ -269,24 +277,24 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
 	struct input_dev *input_dev = psmouse->dev;
 
 	if (model_info->features & PS2PP_SIDE_BTN)
-		__set_bit(BTN_SIDE, input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, BTN_SIDE);
 
 	if (model_info->features & PS2PP_EXTRA_BTN)
-		__set_bit(BTN_EXTRA, input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
 
 	if (model_info->features & PS2PP_TASK_BTN)
-		__set_bit(BTN_TASK, input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, BTN_TASK);
 
 	if (model_info->features & PS2PP_NAV_BTN) {
-		__set_bit(BTN_FORWARD, input_dev->keybit);
-		__set_bit(BTN_BACK, input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
+		input_set_capability(input_dev, EV_KEY, BTN_BACK);
 	}
 
 	if (model_info->features & PS2PP_WHEEL)
-		__set_bit(REL_WHEEL, input_dev->relbit);
+		input_set_capability(input_dev, EV_REL, REL_WHEEL);
 
 	if (model_info->features & PS2PP_HWHEEL)
-		__set_bit(REL_HWHEEL, input_dev->relbit);
+		input_set_capability(input_dev, EV_REL, REL_HWHEEL);
 
 	switch (model_info->kind) {
 
@@ -318,6 +326,30 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
 	}
 }
 
+static int ps2pp_setup_protocol(struct psmouse *psmouse,
+				const struct ps2pp_info *model_info)
+{
+	int error;
+
+	psmouse->protocol_handler = ps2pp_process_byte;
+	psmouse->pktsize = 3;
+
+	if (model_info->kind != PS2PP_KIND_TP3) {
+		psmouse->set_resolution = ps2pp_set_resolution;
+		psmouse->disconnect = ps2pp_disconnect;
+
+		error = device_create_file(&psmouse->ps2dev.serio->dev,
+					   &psmouse_attr_smartscroll.dattr);
+		if (error) {
+			psmouse_err(psmouse,
+				    "failed to create smartscroll sysfs attribute, error: %d\n",
+				    error);
+			return error;
+		}
+	}
+
+	return 0;
+}
 
 /*
  * Logitech magic init. Detect whether the mouse is a Logitech one
@@ -328,9 +360,9 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
 int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[4];
-	unsigned char model, buttons;
 	const struct ps2pp_info *model_info;
+	u8 param[4];
+	u8 model, buttons;
 	bool use_ps2pp = false;
 	int error;
 
@@ -346,7 +378,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 	buttons = param[1];
 
 	if (!model || !buttons)
-		return -1;
+		return -ENXIO;
 
 	model_info = get_model_info(model);
 	if (model_info) {
@@ -368,7 +400,8 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 
 			param[0] = 0;
 			if (!ps2_command(ps2dev, param, 0x13d1) &&
-			    param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
+			    param[0] == 0x06 && param[1] == 0x00 &&
+			    param[2] == 0x14) {
 				use_ps2pp = true;
 			}
 
@@ -387,7 +420,9 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 		}
 
 	} else {
-		psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model);
+		psmouse_warn(psmouse,
+			     "Detected unknown Logitech mouse model %d\n",
+			     model);
 	}
 
 	if (set_properties) {
@@ -395,31 +430,18 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 		psmouse->model = model;
 
 		if (use_ps2pp) {
-			psmouse->protocol_handler = ps2pp_process_byte;
-			psmouse->pktsize = 3;
-
-			if (model_info->kind != PS2PP_KIND_TP3) {
-				psmouse->set_resolution = ps2pp_set_resolution;
-				psmouse->disconnect = ps2pp_disconnect;
-
-				error = device_create_file(&ps2dev->serio->dev,
-							   &psmouse_attr_smartscroll.dattr);
-				if (error) {
-					psmouse_err(psmouse,
-						    "failed to create smartscroll sysfs attribute, error: %d\n",
-						    error);
-					return -1;
-				}
-			}
+			error = ps2pp_setup_protocol(psmouse, model_info);
+			if (error)
+				return error;
 		}
 
 		if (buttons >= 3)
-			__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+			input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
 
 		if (model_info)
 			ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
 	}
 
-	return use_ps2pp ? 0 : -1;
+	return use_ps2pp ? 0 : -ENXIO;
 }
 

+ 103 - 86
drivers/input/mouse/psmouse-base.c

@@ -14,6 +14,7 @@
 #define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
 #define psmouse_fmt(fmt)	fmt
 
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -23,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/libps2.h>
 #include <linux/mutex.h>
+#include <linux/types.h>
 
 #include "psmouse.h"
 #include "synaptics.h"
@@ -68,6 +70,10 @@ static bool psmouse_smartscroll = true;
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
+static bool psmouse_a4tech_2wheels;
+module_param_named(a4tech_workaround, psmouse_a4tech_2wheels, bool, 0644);
+MODULE_PARM_DESC(a4tech_workaround, "A4Tech second scroll wheel workaround, 1 = enabled, 0 = disabled (default).");
+
 static unsigned int psmouse_resetafter = 5;
 module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
@@ -116,13 +122,30 @@ static DEFINE_MUTEX(psmouse_mutex);
 
 static struct workqueue_struct *kpsmoused_wq;
 
-static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
+void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
 {
 	input_report_key(dev, BTN_LEFT,   buttons & BIT(0));
 	input_report_key(dev, BTN_MIDDLE, buttons & BIT(2));
 	input_report_key(dev, BTN_RIGHT,  buttons & BIT(1));
 }
 
+void psmouse_report_standard_motion(struct input_dev *dev, u8 *packet)
+{
+	int x, y;
+
+	x = packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0;
+	y = packet[2] ? packet[2] - ((packet[0] << 3) & 0x100) : 0;
+
+	input_report_rel(dev, REL_X, x);
+	input_report_rel(dev, REL_Y, -y);
+}
+
+void psmouse_report_standard_packet(struct input_dev *dev, u8 *packet)
+{
+	psmouse_report_standard_buttons(dev, packet[0]);
+	psmouse_report_standard_motion(dev, packet);
+}
+
 /*
  * psmouse_process_byte() analyzes the PS/2 data stream and reports
  * relevant events to the input module once full packet has arrived.
@@ -130,7 +153,8 @@ static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
 psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
 {
 	struct input_dev *dev = psmouse->dev;
-	unsigned char *packet = psmouse->packet;
+	u8 *packet = psmouse->packet;
+	int wheel;
 
 	if (psmouse->pktcnt < psmouse->pktsize)
 		return PSMOUSE_GOOD_DATA;
@@ -140,39 +164,52 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
 	switch (psmouse->protocol->type) {
 	case PSMOUSE_IMPS:
 		/* IntelliMouse has scroll wheel */
-		input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
+		input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
 		break;
 
 	case PSMOUSE_IMEX:
 		/* Scroll wheel and buttons on IntelliMouse Explorer */
 		switch (packet[3] & 0xC0) {
 		case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
-			input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+			input_report_rel(dev, REL_WHEEL,
+					 -sign_extend32(packet[3], 5));
 			break;
 		case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
-			input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+			input_report_rel(dev, REL_HWHEEL,
+					 -sign_extend32(packet[3], 5));
 			break;
 		case 0x00:
 		case 0xC0:
-			input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
-			input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
-			input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+			wheel = sign_extend32(packet[3], 3);
+
+			/*
+			 * Some A4Tech mice have two scroll wheels, with first
+			 * one reporting +/-1 in the lower nibble, and second
+			 * one reporting +/-2.
+			 */
+			if (psmouse_a4tech_2wheels && abs(wheel) > 1)
+				input_report_rel(dev, REL_HWHEEL, wheel / 2);
+			else
+				input_report_rel(dev, REL_WHEEL, -wheel);
+
+			input_report_key(dev, BTN_SIDE,  BIT(4));
+			input_report_key(dev, BTN_EXTRA, BIT(5));
 			break;
 		}
 		break;
 
 	case PSMOUSE_GENPS:
 		/* Report scroll buttons on NetMice */
-		input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
+		input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
 
 		/* Extra buttons on Genius NewNet 3D */
-		input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
-		input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
+		input_report_key(dev, BTN_SIDE,  BIT(6));
+		input_report_key(dev, BTN_EXTRA, BIT(7));
 		break;
 
 	case PSMOUSE_THINKPS:
 		/* Extra button on ThinkingMouse */
-		input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
+		input_report_key(dev, BTN_EXTRA, BIT(3));
 
 		/*
 		 * Without this bit of weirdness moving up gives wildly
@@ -186,8 +223,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
 		 * Cortron PS2 Trackball reports SIDE button in the
 		 * 4th bit of the first byte.
 		 */
-		input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
-		packet[0] |= 0x08;
+		input_report_key(dev, BTN_SIDE, BIT(3));
+		packet[0] |= BIT(3);
 		break;
 
 	default:
@@ -195,11 +232,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
 	}
 
 	/* Generic PS/2 Mouse */
-	psmouse_report_standard_buttons(dev,
-					packet[0] | psmouse->extra_buttons);
-
-	input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
-	input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+	packet[0] |= psmouse->extra_buttons;
+	psmouse_report_standard_packet(dev, packet);
 
 	input_sync(dev);
 
@@ -255,7 +289,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
 				psmouse_notice(psmouse,
 						"issuing reconnect request\n");
 				serio_reconnect(psmouse->ps2dev.serio);
-				return -1;
+				return -EIO;
 			}
 		}
 		psmouse->pktcnt = 0;
@@ -306,7 +340,7 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
  * for normal processing or gathering them as command response.
  */
 static irqreturn_t psmouse_interrupt(struct serio *serio,
-		unsigned char data, unsigned int flags)
+				     u8 data, unsigned int flags)
 {
 	struct psmouse *psmouse = serio_get_drvdata(serio);
 
@@ -397,41 +431,20 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 	return IRQ_HANDLED;
 }
 
-/*
- * psmouse_sliced_command() sends an extended PS/2 command to the mouse
- * using sliced syntax, understood by advanced devices, such as Logitech
- * or Synaptics touchpads. The command is encoded as:
- * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
- * is the command.
- */
-int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
-{
-	int i;
-
-	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
-		return -1;
-
-	for (i = 6; i >= 0; i -= 2) {
-		unsigned char d = (command >> i) & 3;
-		if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
-			return -1;
-	}
-
-	return 0;
-}
-
 /*
  * psmouse_reset() resets the mouse into power-on state.
  */
 int psmouse_reset(struct psmouse *psmouse)
 {
-	unsigned char param[2];
+	u8 param[2];
+	int error;
 
-	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
-		return -1;
+	error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT);
+	if (error)
+		return error;
 
 	if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
-		return -1;
+		return -EIO;
 
 	return 0;
 }
@@ -441,8 +454,8 @@ int psmouse_reset(struct psmouse *psmouse)
  */
 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 {
-	static const unsigned char params[] = { 0, 1, 2, 2, 3 };
-	unsigned char p;
+	static const u8 params[] = { 0, 1, 2, 2, 3 };
+	u8 p;
 
 	if (resolution == 0 || resolution > 200)
 		resolution = 200;
@@ -457,11 +470,12 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
  */
 static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
 {
-	static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
-	unsigned char r;
+	static const u8 rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
+	u8 r;
 	int i = 0;
 
-	while (rates[i] > rate) i++;
+	while (rates[i] > rate)
+		i++;
 	r = rates[i];
 	ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
 	psmouse->rate = r;
@@ -533,7 +547,7 @@ bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
 static int genius_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[4];
+	u8 param[4];
 
 	param[0] = 3;
 	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
@@ -543,7 +557,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 
 	if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55)
-		return -1;
+		return -ENODEV;
 
 	if (set_properties) {
 		__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
@@ -565,7 +579,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
 static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[2];
+	u8 param[2];
 
 	param[0] = 200;
 	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
@@ -576,7 +590,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 
 	if (param[0] != 3)
-		return -1;
+		return -ENODEV;
 
 	if (set_properties) {
 		__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
@@ -598,7 +612,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
 static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[2];
+	u8 param[2];
 
 	intellimouse_detect(psmouse, 0);
 
@@ -611,7 +625,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 
 	if (param[0] != 4)
-		return -1;
+		return -ENODEV;
 
 	/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
 	param[0] = 200;
@@ -644,8 +658,8 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
 static int thinking_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[2];
-	static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
+	u8 param[2];
+	static const u8 seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
 	int i;
 
 	param[0] = 10;
@@ -659,7 +673,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 
 	if (param[0] != 2)
-		return -1;
+		return -ENODEV;
 
 	if (set_properties) {
 		__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
@@ -687,7 +701,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
 		 * We have no way of figuring true number of buttons so let's
 		 * assume that the device has 3.
 		 */
-		__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+		input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
 	}
 
 	return 0;
@@ -942,20 +956,17 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
 {
 	struct input_dev *input_dev = psmouse->dev;
 
-	memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
-	memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
-	memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
-	memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
-	memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
-
-	__set_bit(EV_KEY, input_dev->evbit);
-	__set_bit(EV_REL, input_dev->evbit);
+	bitmap_zero(input_dev->evbit, EV_CNT);
+	bitmap_zero(input_dev->keybit, KEY_CNT);
+	bitmap_zero(input_dev->relbit, REL_CNT);
+	bitmap_zero(input_dev->absbit, ABS_CNT);
+	bitmap_zero(input_dev->mscbit, MSC_CNT);
 
-	__set_bit(BTN_LEFT, input_dev->keybit);
-	__set_bit(BTN_RIGHT, input_dev->keybit);
+	input_set_capability(input_dev, EV_KEY, BTN_LEFT);
+	input_set_capability(input_dev, EV_KEY, BTN_RIGHT);
 
-	__set_bit(REL_X, input_dev->relbit);
-	__set_bit(REL_Y, input_dev->relbit);
+	input_set_capability(input_dev, EV_REL, REL_X);
+	input_set_capability(input_dev, EV_REL, REL_Y);
 
 	__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 
@@ -1225,7 +1236,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
 static int psmouse_probe(struct psmouse *psmouse)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[2];
+	u8 param[2];
+	int error;
 
 	/*
 	 * First, we check if it's a mouse. It should send 0x00 or 0x03 in
@@ -1234,20 +1246,22 @@ static int psmouse_probe(struct psmouse *psmouse)
 	 * subsequent ID queries, probably due to a firmware bug.
 	 */
 	param[0] = 0xa5;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
-		return -1;
+	error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
+	if (error)
+		return error;
 
 	if (param[0] != 0x00 && param[0] != 0x03 &&
 	    param[0] != 0x04 && param[0] != 0xff)
-		return -1;
+		return -ENODEV;
 
 	/*
 	 * Then we reset and disable the mouse so that it doesn't generate
 	 * events.
 	 */
-	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
-		psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
-			     ps2dev->serio->phys);
+	error = ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+	if (error)
+		psmouse_warn(psmouse, "Failed to reset mouse on %s: %d\n",
+			     ps2dev->serio->phys, error);
 
 	return 0;
 }
@@ -1288,10 +1302,13 @@ int psmouse_activate(struct psmouse *psmouse)
  */
 int psmouse_deactivate(struct psmouse *psmouse)
 {
-	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
-		psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
-			     psmouse->ps2dev.serio->phys);
-		return -1;
+	int error;
+
+	error = ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE);
+	if (error) {
+		psmouse_warn(psmouse, "Failed to deactivate mouse on %s: %d\n",
+			     psmouse->ps2dev.serio->phys, error);
+		return error;
 	}
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);

+ 4 - 1
drivers/input/mouse/psmouse.h

@@ -131,7 +131,6 @@ struct psmouse {
 
 void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
 		unsigned long delay);
-int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 int psmouse_reset(struct psmouse *psmouse);
 void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
@@ -140,6 +139,10 @@ int psmouse_activate(struct psmouse *psmouse);
 int psmouse_deactivate(struct psmouse *psmouse);
 bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]);
 
+void psmouse_report_standard_buttons(struct input_dev *, u8 buttons);
+void psmouse_report_standard_motion(struct input_dev *, u8 *packet);
+void psmouse_report_standard_packet(struct input_dev *, u8 *packet);
+
 struct psmouse_attribute {
 	struct device_attribute dattr;
 	void *data;

+ 1 - 10
drivers/input/mouse/sentelic.c

@@ -710,7 +710,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
 	unsigned char *packet = psmouse->packet;
 	unsigned char button_status = 0, lscroll = 0, rscroll = 0;
 	unsigned short abs_x, abs_y, fgrs = 0;
-	int rel_x, rel_y;
 
 	if (psmouse->pktcnt < 4)
 		return PSMOUSE_GOOD_DATA;
@@ -840,15 +839,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
 		/*
 		 * Standard PS/2 Mouse
 		 */
-		input_report_key(dev, BTN_LEFT, packet[0] & 1);
-		input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
-		input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
-
-		rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
-		rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
-
-		input_report_rel(dev, REL_X, rel_x);
-		input_report_rel(dev, REL_Y, rel_y);
+		psmouse_report_standard_packet(dev, packet);
 		break;
 	}
 

+ 52 - 38
drivers/input/mouse/synaptics.c

@@ -84,7 +84,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
 	u8 param[1];
 	int error;
 
-	error = psmouse_sliced_command(psmouse, mode);
+	error = ps2_sliced_command(&psmouse->ps2dev, mode);
 	if (error)
 		return error;
 
@@ -189,7 +189,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
 {
 	int error;
 
-	error = psmouse_sliced_command(psmouse, cmd);
+	error = ps2_sliced_command(&psmouse->ps2dev, cmd);
 	if (error)
 		return error;
 
@@ -546,7 +546,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
 	static u8 param = 0xc8;
 	int error;
 
-	error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL);
+	error = ps2_sliced_command(&psmouse->ps2dev, SYN_QUE_MODEL);
 	if (error)
 		return error;
 
@@ -613,7 +613,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c)
 	u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 	int error;
 
-	error = psmouse_sliced_command(parent, c);
+	error = ps2_sliced_command(&parent->ps2dev, c);
 	if (error)
 		return error;
 
@@ -1227,32 +1227,39 @@ static void set_abs_position_params(struct input_dev *dev,
 	input_abs_set_res(dev, y_code, info->y_res);
 }
 
-static void set_input_params(struct psmouse *psmouse,
-			     struct synaptics_data *priv)
+static int set_input_params(struct psmouse *psmouse,
+			    struct synaptics_data *priv)
 {
 	struct input_dev *dev = psmouse->dev;
 	struct synaptics_device_info *info = &priv->info;
 	int i;
+	int error;
+
+	/* Reset default psmouse capabilities */
+	__clear_bit(EV_REL, dev->evbit);
+	bitmap_zero(dev->relbit, REL_CNT);
+	bitmap_zero(dev->keybit, KEY_CNT);
 
 	/* Things that apply to both modes */
 	__set_bit(INPUT_PROP_POINTER, dev->propbit);
-	__set_bit(EV_KEY, dev->evbit);
-	__set_bit(BTN_LEFT, dev->keybit);
-	__set_bit(BTN_RIGHT, dev->keybit);
 
-	if (SYN_CAP_MIDDLE_BUTTON(info->capabilities))
-		__set_bit(BTN_MIDDLE, dev->keybit);
+	input_set_capability(dev, EV_KEY, BTN_LEFT);
+
+	/* Clickpads report only left button */
+	if (!SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
+		input_set_capability(dev, EV_KEY, BTN_RIGHT);
+		if (SYN_CAP_MIDDLE_BUTTON(info->capabilities))
+			input_set_capability(dev, EV_KEY, BTN_MIDDLE);
+	}
 
 	if (!priv->absolute_mode) {
 		/* Relative mode */
-		__set_bit(EV_REL, dev->evbit);
-		__set_bit(REL_X, dev->relbit);
-		__set_bit(REL_Y, dev->relbit);
-		return;
+		input_set_capability(dev, EV_REL, REL_X);
+		input_set_capability(dev, EV_REL, REL_Y);
+		return 0;
 	}
 
 	/* Absolute mode */
-	__set_bit(EV_ABS, dev->evbit);
 	set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y);
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
@@ -1264,11 +1271,15 @@ static void set_input_params(struct psmouse *psmouse,
 					ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
 		/* Image sensors can report per-contact pressure */
 		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
-		input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK);
+
+		error = input_mt_init_slots(dev, 2,
+					    INPUT_MT_POINTER | INPUT_MT_TRACK);
+		if (error)
+			return error;
 
 		/* Image sensors can signal 4 and 5 finger clicks */
-		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
-		__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_QUADTAP);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_QUINTTAP);
 	} else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) {
 		set_abs_position_params(dev, info,
 					ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
@@ -1276,10 +1287,13 @@ static void set_input_params(struct psmouse *psmouse,
 		 * Profile sensor in CR-48 tracks contacts reasonably well,
 		 * other non-image sensors with AGM use semi-mt.
 		 */
-		input_mt_init_slots(dev, 2,
-				    INPUT_MT_POINTER |
-				    (cr48_profile_sensor ?
-					INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
+		error = input_mt_init_slots(dev, 2,
+					    INPUT_MT_POINTER |
+					     (cr48_profile_sensor ?
+					      INPUT_MT_TRACK :
+					      INPUT_MT_SEMI_MT));
+		if (error)
+			return error;
 
 		/*
 		 * For semi-mt devices we send ABS_X/Y ourselves instead of
@@ -1295,37 +1309,32 @@ static void set_input_params(struct psmouse *psmouse,
 	if (SYN_CAP_PALMDETECT(info->capabilities))
 		input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
 
-	__set_bit(BTN_TOUCH, dev->keybit);
-	__set_bit(BTN_TOOL_FINGER, dev->keybit);
+	input_set_capability(dev, EV_KEY, BTN_TOUCH);
+	input_set_capability(dev, EV_KEY, BTN_TOOL_FINGER);
 
 	if (synaptics_has_multifinger(priv)) {
-		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-		__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_DOUBLETAP);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_TRIPLETAP);
 	}
 
 	if (SYN_CAP_FOUR_BUTTON(info->capabilities) ||
 	    SYN_CAP_MIDDLE_BUTTON(info->capabilities)) {
-		__set_bit(BTN_FORWARD, dev->keybit);
-		__set_bit(BTN_BACK, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_FORWARD);
+		input_set_capability(dev, EV_KEY, BTN_BACK);
 	}
 
 	if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
 		for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++)
-			__set_bit(BTN_0 + i, dev->keybit);
-
-	__clear_bit(EV_REL, dev->evbit);
-	__clear_bit(REL_X, dev->relbit);
-	__clear_bit(REL_Y, dev->relbit);
+			input_set_capability(dev, EV_KEY, BTN_0 + i);
 
 	if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
 		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
 		if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
 		    !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
 			__set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
-		/* Clickpads report only left button */
-		__clear_bit(BTN_RIGHT, dev->keybit);
-		__clear_bit(BTN_MIDDLE, dev->keybit);
 	}
+
+	return 0;
 }
 
 static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
@@ -1563,7 +1572,12 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
 		     info->capabilities, info->ext_cap, info->ext_cap_0c,
 		     info->ext_cap_10, info->board_id, info->firmware_id);
 
-	set_input_params(psmouse, priv);
+	err = set_input_params(psmouse, priv);
+	if (err) {
+		psmouse_err(psmouse,
+			    "failed to set up capabilities: %d\n", err);
+		goto init_fail;
+	}
 
 	/*
 	 * Encode touchpad model so that it can be used to set

+ 19 - 12
drivers/input/mouse/synaptics_usb.c

@@ -82,6 +82,10 @@ struct synusb {
 	struct urb *urb;
 	unsigned char *data;
 
+	/* serialize access to open/suspend */
+	struct mutex pm_mutex;
+	bool is_open;
+
 	/* input device related data structures */
 	struct input_dev *input;
 	char name[128];
@@ -252,6 +256,7 @@ static int synusb_open(struct input_dev *dev)
 		return retval;
 	}
 
+	mutex_lock(&synusb->pm_mutex);
 	retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
 	if (retval) {
 		dev_err(&synusb->intf->dev,
@@ -262,8 +267,10 @@ static int synusb_open(struct input_dev *dev)
 	}
 
 	synusb->intf->needs_remote_wakeup = 1;
+	synusb->is_open = true;
 
 out:
+	mutex_unlock(&synusb->pm_mutex);
 	usb_autopm_put_interface(synusb->intf);
 	return retval;
 }
@@ -275,8 +282,11 @@ static void synusb_close(struct input_dev *dev)
 
 	autopm_error = usb_autopm_get_interface(synusb->intf);
 
+	mutex_lock(&synusb->pm_mutex);
 	usb_kill_urb(synusb->urb);
 	synusb->intf->needs_remote_wakeup = 0;
+	synusb->is_open = false;
+	mutex_unlock(&synusb->pm_mutex);
 
 	if (!autopm_error)
 		usb_autopm_put_interface(synusb->intf);
@@ -315,6 +325,7 @@ static int synusb_probe(struct usb_interface *intf,
 	synusb->udev = udev;
 	synusb->intf = intf;
 	synusb->input = input_dev;
+	mutex_init(&synusb->pm_mutex);
 
 	synusb->flags = id->driver_info;
 	if (synusb->flags & SYNUSB_COMBO) {
@@ -466,11 +477,10 @@ static void synusb_disconnect(struct usb_interface *intf)
 static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct synusb *synusb = usb_get_intfdata(intf);
-	struct input_dev *input_dev = synusb->input;
 
-	mutex_lock(&input_dev->mutex);
+	mutex_lock(&synusb->pm_mutex);
 	usb_kill_urb(synusb->urb);
-	mutex_unlock(&input_dev->mutex);
+	mutex_unlock(&synusb->pm_mutex);
 
 	return 0;
 }
@@ -478,17 +488,16 @@ static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
 static int synusb_resume(struct usb_interface *intf)
 {
 	struct synusb *synusb = usb_get_intfdata(intf);
-	struct input_dev *input_dev = synusb->input;
 	int retval = 0;
 
-	mutex_lock(&input_dev->mutex);
+	mutex_lock(&synusb->pm_mutex);
 
-	if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+	if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
 	    usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
 		retval = -EIO;
 	}
 
-	mutex_unlock(&input_dev->mutex);
+	mutex_unlock(&synusb->pm_mutex);
 
 	return retval;
 }
@@ -496,9 +505,8 @@ static int synusb_resume(struct usb_interface *intf)
 static int synusb_pre_reset(struct usb_interface *intf)
 {
 	struct synusb *synusb = usb_get_intfdata(intf);
-	struct input_dev *input_dev = synusb->input;
 
-	mutex_lock(&input_dev->mutex);
+	mutex_lock(&synusb->pm_mutex);
 	usb_kill_urb(synusb->urb);
 
 	return 0;
@@ -507,15 +515,14 @@ static int synusb_pre_reset(struct usb_interface *intf)
 static int synusb_post_reset(struct usb_interface *intf)
 {
 	struct synusb *synusb = usb_get_intfdata(intf);
-	struct input_dev *input_dev = synusb->input;
 	int retval = 0;
 
-	if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+	if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
 	    usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
 		retval = -EIO;
 	}
 
-	mutex_unlock(&input_dev->mutex);
+	mutex_unlock(&synusb->pm_mutex);
 
 	return retval;
 }

+ 24 - 36
drivers/input/mouse/trackpoint.c

@@ -33,18 +33,15 @@ static const char * const trackpoint_variants[] = {
  */
 static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
 {
-	u8 results[2];
-	int tries = 0;
+	u8 param[2] = { TP_POR };
+	int err;
 
-	/* Issue POR command, and repeat up to once if 0xFC00 received */
-	do {
-		if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
-		    ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR)))
-			return -1;
-	} while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2);
+	err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND));
+	if (err)
+		return err;
 
 	/* Check for success response -- 0xAA00 */
-	if (results[0] != 0xAA || results[1] != 0x00)
+	if (param[0] != 0xAA || param[1] != 0x00)
 		return -ENODEV;
 
 	return 0;
@@ -55,49 +52,39 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
  */
 static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results)
 {
-	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
-	    ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
-		return -1;
-	}
+	results[0] = loc;
 
-	return 0;
+	return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND));
 }
 
 static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
 {
-	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
-		return -1;
-	}
+	u8 param[3] = { TP_WRITE_MEM, loc, val };
 
-	return 0;
+	return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
 }
 
 static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
 {
+	u8 param[3] = { TP_TOGGLE, loc, mask };
+
 	/* Bad things will happen if the loc param isn't in this range */
 	if (loc < 0x20 || loc >= 0x2F)
-		return -1;
-
-	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
-	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
-		return -1;
-	}
+		return -EINVAL;
 
-	return 0;
+	return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
 }
 
 static int trackpoint_update_bit(struct ps2dev *ps2dev,
 				 u8 loc, u8 mask, u8 value)
 {
-	int retval = 0;
+	int retval;
 	u8 data;
 
-	trackpoint_read(ps2dev, loc, &data);
+	retval = trackpoint_read(ps2dev, loc, &data);
+	if (retval)
+		return retval;
+
 	if (((data & mask) == mask) != !!value)
 		retval = trackpoint_toggle_bit(ps2dev, loc, mask);
 
@@ -142,9 +129,9 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
 		return err;
 
 	*field = value;
-	trackpoint_write(&psmouse->ps2dev, attr->command, value);
+	err = trackpoint_write(&psmouse->ps2dev, attr->command, value);
 
-	return count;
+	return err ?: count;
 }
 
 #define TRACKPOINT_INT_ATTR(_name, _command, _default)				\
@@ -175,10 +162,11 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
 
 	if (*field != value) {
 		*field = value;
-		trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
+		err = trackpoint_toggle_bit(&psmouse->ps2dev,
+					    attr->command, attr->mask);
 	}
 
-	return count;
+	return err ?: count;
 }
 
 

+ 24 - 0
drivers/input/serio/i8042-x86ia64io.h

@@ -530,6 +530,20 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
 	{ }
 };
 
+static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
+	{
+		/*
+		 * Sony Vaio VGN-CS series require MUX or the touch sensor
+		 * buttons will disturb touchpad operation
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+		},
+	},
+	{ }
+};
+
 /*
  * On some Asus laptops, just running self tests cause problems.
  */
@@ -620,6 +634,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "20046"),
 		},
 	},
+	{
+		/* Lenovo ThinkPad L460 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
+		},
+	},
 	{
 		/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
 		.matches = {
@@ -1163,6 +1184,9 @@ static int __init i8042_platform_init(void)
 	if (dmi_check_system(i8042_dmi_nomux_table))
 		i8042_nomux = true;
 
+	if (dmi_check_system(i8042_dmi_forcemux_table))
+		i8042_nomux = false;
+
 	if (dmi_check_system(i8042_dmi_notimeout_table))
 		i8042_notimeout = true;
 

+ 219 - 103
drivers/input/serio/libps2.c

@@ -26,31 +26,79 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
 MODULE_DESCRIPTION("PS/2 driver library");
 MODULE_LICENSE("GPL");
 
+static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
+			   unsigned int timeout, unsigned int max_attempts)
+	__releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock)
+{
+	int attempt = 0;
+	int error;
+
+	lockdep_assert_held(&ps2dev->serio->lock);
+
+	do {
+		ps2dev->nak = 1;
+		ps2dev->flags |= PS2_FLAG_ACK;
+
+		serio_continue_rx(ps2dev->serio);
+
+		error = serio_write(ps2dev->serio, byte);
+		if (error)
+			dev_dbg(&ps2dev->serio->dev,
+				"failed to write %#02x: %d\n", byte, error);
+		else
+			wait_event_timeout(ps2dev->wait,
+					   !(ps2dev->flags & PS2_FLAG_ACK),
+					   msecs_to_jiffies(timeout));
+
+		serio_pause_rx(ps2dev->serio);
+	} while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts);
+
+	ps2dev->flags &= ~PS2_FLAG_ACK;
+
+	if (!error) {
+		switch (ps2dev->nak) {
+		case 0:
+			break;
+		case PS2_RET_NAK:
+			error = -EAGAIN;
+			break;
+		case PS2_RET_ERR:
+			error = -EPROTO;
+			break;
+		default:
+			error = -EIO;
+			break;
+		}
+	}
+
+	if (error || attempt > 1)
+		dev_dbg(&ps2dev->serio->dev,
+			"%02x - %d (%x), attempt %d\n",
+			byte, error, ps2dev->nak, attempt);
+
+	return error;
+}
+
 /*
  * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because if there
- * is a need for retransmissions device has to be replaced anyway.
+ * It doesn't handle retransmission, the caller is expected to handle
+ * it when needed.
  *
  * ps2_sendbyte() can only be called from a process context.
  */
 
-int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
+int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
 {
+	int retval;
+
 	serio_pause_rx(ps2dev->serio);
-	ps2dev->nak = 1;
-	ps2dev->flags |= PS2_FLAG_ACK;
-	serio_continue_rx(ps2dev->serio);
 
-	if (serio_write(ps2dev->serio, byte) == 0)
-		wait_event_timeout(ps2dev->wait,
-				   !(ps2dev->flags & PS2_FLAG_ACK),
-				   msecs_to_jiffies(timeout));
+	retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1);
+	dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak);
 
-	serio_pause_rx(ps2dev->serio);
-	ps2dev->flags &= ~PS2_FLAG_ACK;
 	serio_continue_rx(ps2dev->serio);
 
-	return -ps2dev->nak;
+	return retval;
 }
 EXPORT_SYMBOL(ps2_sendbyte);
 
@@ -75,7 +123,7 @@ EXPORT_SYMBOL(ps2_end_command);
  * and discards them.
  */
 
-void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
 {
 	if (maxbytes > sizeof(ps2dev->cmdbuf)) {
 		WARN_ON(1);
@@ -102,9 +150,9 @@ EXPORT_SYMBOL(ps2_drain);
  * known keyboard IDs.
  */
 
-int ps2_is_keyboard_id(char id_byte)
+bool ps2_is_keyboard_id(u8 id_byte)
 {
-	static const char keyboard_ids[] = {
+	static const u8 keyboard_ids[] = {
 		0xab,	/* Regular keyboards		*/
 		0xac,	/* NCD Sun keyboard		*/
 		0x2b,	/* Trust keyboard, translated	*/
@@ -123,49 +171,50 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
  * completion.
  */
 
-static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+static int ps2_adjust_timeout(struct ps2dev *ps2dev,
+			      unsigned int command, unsigned int timeout)
 {
 	switch (command) {
-		case PS2_CMD_RESET_BAT:
-			/*
-			 * Device has sent the first response byte after
-			 * reset command, reset is thus done, so we can
-			 * shorten the timeout.
-			 * The next byte will come soon (keyboard) or not
-			 * at all (mouse).
-			 */
-			if (timeout > msecs_to_jiffies(100))
-				timeout = msecs_to_jiffies(100);
-			break;
+	case PS2_CMD_RESET_BAT:
+		/*
+		 * Device has sent the first response byte after
+		 * reset command, reset is thus done, so we can
+		 * shorten the timeout.
+		 * The next byte will come soon (keyboard) or not
+		 * at all (mouse).
+		 */
+		if (timeout > msecs_to_jiffies(100))
+			timeout = msecs_to_jiffies(100);
+		break;
 
-		case PS2_CMD_GETID:
-			/*
-			 * Microsoft Natural Elite keyboard responds to
-			 * the GET ID command as it were a mouse, with
-			 * a single byte. Fail the command so atkbd will
-			 * use alternative probe to detect it.
-			 */
-			if (ps2dev->cmdbuf[1] == 0xaa) {
-				serio_pause_rx(ps2dev->serio);
-				ps2dev->flags = 0;
-				serio_continue_rx(ps2dev->serio);
-				timeout = 0;
-			}
-
-			/*
-			 * If device behind the port is not a keyboard there
-			 * won't be 2nd byte of ID response.
-			 */
-			if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
-				serio_pause_rx(ps2dev->serio);
-				ps2dev->flags = ps2dev->cmdcnt = 0;
-				serio_continue_rx(ps2dev->serio);
-				timeout = 0;
-			}
-			break;
+	case PS2_CMD_GETID:
+		/*
+		 * Microsoft Natural Elite keyboard responds to
+		 * the GET ID command as it were a mouse, with
+		 * a single byte. Fail the command so atkbd will
+		 * use alternative probe to detect it.
+		 */
+		if (ps2dev->cmdbuf[1] == 0xaa) {
+			serio_pause_rx(ps2dev->serio);
+			ps2dev->flags = 0;
+			serio_continue_rx(ps2dev->serio);
+			timeout = 0;
+		}
 
-		default:
-			break;
+		/*
+		 * If device behind the port is not a keyboard there
+		 * won't be 2nd byte of ID response.
+		 */
+		if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+			serio_pause_rx(ps2dev->serio);
+			ps2dev->flags = ps2dev->cmdcnt = 0;
+			serio_continue_rx(ps2dev->serio);
+			timeout = 0;
+		}
+		break;
+
+	default:
+		break;
 	}
 
 	return timeout;
@@ -178,50 +227,60 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
  * ps2_command() can only be called from a process context
  */
 
-int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
-	int timeout;
-	int send = (command >> 12) & 0xf;
-	int receive = (command >> 8) & 0xf;
-	int rc = -1;
+	unsigned int timeout;
+	unsigned int send = (command >> 12) & 0xf;
+	unsigned int receive = (command >> 8) & 0xf;
+	int rc;
 	int i;
+	u8 send_param[16];
 
 	if (receive > sizeof(ps2dev->cmdbuf)) {
 		WARN_ON(1);
-		return -1;
+		return -EINVAL;
 	}
 
 	if (send && !param) {
 		WARN_ON(1);
-		return -1;
+		return -EINVAL;
 	}
 
+	memcpy(send_param, param, send);
+
 	serio_pause_rx(ps2dev->serio);
+
 	ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
 	ps2dev->cmdcnt = receive;
 	if (receive && param)
 		for (i = 0; i < receive; i++)
 			ps2dev->cmdbuf[(receive - 1) - i] = param[i];
-	serio_continue_rx(ps2dev->serio);
+
+	/* Signal that we are sending the command byte */
+	ps2dev->flags |= PS2_FLAG_ACK_CMD;
 
 	/*
 	 * Some devices (Synaptics) peform the reset before
 	 * ACKing the reset command, and so it can take a long
 	 * time before the ACK arrives.
 	 */
-	if (ps2_sendbyte(ps2dev, command & 0xff,
-			 command == PS2_CMD_RESET_BAT ? 1000 : 200)) {
-		serio_pause_rx(ps2dev->serio);
+	timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200;
+
+	rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2);
+	if (rc)
 		goto out_reset_flags;
-	}
+
+	/* Now we are sending command parameters, if any */
+	ps2dev->flags &= ~PS2_FLAG_ACK_CMD;
 
 	for (i = 0; i < send; i++) {
-		if (ps2_sendbyte(ps2dev, param[i], 200)) {
-			serio_pause_rx(ps2dev->serio);
+		rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2);
+		if (rc)
 			goto out_reset_flags;
-		}
 	}
 
+	serio_continue_rx(ps2dev->serio);
+
 	/*
 	 * The reset command takes a long time to execute.
 	 */
@@ -243,8 +302,11 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 		for (i = 0; i < receive; i++)
 			param[i] = ps2dev->cmdbuf[(receive - 1) - i];
 
-	if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1))
+	if (ps2dev->cmdcnt &&
+	    (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
+		rc = -EPROTO;
 		goto out_reset_flags;
+	}
 
 	rc = 0;
 
@@ -252,11 +314,21 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 	ps2dev->flags = 0;
 	serio_continue_rx(ps2dev->serio);
 
-	return rc;
+	dev_dbg(&ps2dev->serio->dev,
+		"%02x [%*ph] - %x/%08lx [%*ph]\n",
+		command & 0xff, send, send_param,
+		ps2dev->nak, ps2dev->flags,
+		receive, param ?: send_param);
+
+	/*
+	 * ps_command() handles resends itself, so do not leak -EAGAIN
+	 * to the callers.
+	 */
+	return rc != -EAGAIN ? rc : -EPROTO;
 }
 EXPORT_SYMBOL(__ps2_command);
 
-int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
 	int rc;
 
@@ -268,6 +340,39 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 }
 EXPORT_SYMBOL(ps2_command);
 
+/*
+ * ps2_sliced_command() sends an extended PS/2 command to the mouse
+ * using sliced syntax, understood by advanced devices, such as Logitech
+ * or Synaptics touchpads. The command is encoded as:
+ * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ * is the command.
+ */
+
+int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
+{
+	int i;
+	int retval;
+
+	ps2_begin_command(ps2dev);
+
+	retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11);
+	if (retval)
+		goto out;
+
+	for (i = 6; i >= 0; i -= 2) {
+		u8 d = (command >> i) & 3;
+		retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES);
+		if (retval)
+			break;
+	}
+
+out:
+	dev_dbg(&ps2dev->serio->dev, "%02x - %d\n", command, retval);
+	ps2_end_command(ps2dev);
+	return retval;
+}
+EXPORT_SYMBOL(ps2_sliced_command);
+
 /*
  * ps2_init() initializes ps2dev structure
  */
@@ -286,42 +391,53 @@ EXPORT_SYMBOL(ps2_init);
  * to properly process ACK/NAK of a command from a PS/2 device.
  */
 
-int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
+bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 {
 	switch (data) {
-		case PS2_RET_ACK:
-			ps2dev->nak = 0;
+	case PS2_RET_ACK:
+		ps2dev->nak = 0;
+		break;
+
+	case PS2_RET_NAK:
+		ps2dev->flags |= PS2_FLAG_NAK;
+		ps2dev->nak = PS2_RET_NAK;
+		break;
+
+	case PS2_RET_ERR:
+		if (ps2dev->flags & PS2_FLAG_NAK) {
+			ps2dev->flags &= ~PS2_FLAG_NAK;
+			ps2dev->nak = PS2_RET_ERR;
 			break;
+		}
 
-		case PS2_RET_NAK:
-			ps2dev->flags |= PS2_FLAG_NAK;
-			ps2dev->nak = PS2_RET_NAK;
+	/*
+	 * Workaround for mice which don't ACK the Get ID command.
+	 * These are valid mouse IDs that we recognize.
+	 */
+	case 0x00:
+	case 0x03:
+	case 0x04:
+		if (ps2dev->flags & PS2_FLAG_WAITID) {
+			ps2dev->nak = 0;
 			break;
-
-		case PS2_RET_ERR:
-			if (ps2dev->flags & PS2_FLAG_NAK) {
-				ps2dev->flags &= ~PS2_FLAG_NAK;
-				ps2dev->nak = PS2_RET_ERR;
-				break;
-			}
-
+		}
+		/* Fall through */
+	default:
 		/*
-		 * Workaround for mice which don't ACK the Get ID command.
-		 * These are valid mouse IDs that we recognize.
+		 * Do not signal errors if we get unexpected reply while
+		 * waiting for an ACK to the initial (first) command byte:
+		 * the device might not be quiesced yet and continue
+		 * delivering data.
+		 * Note that we reset PS2_FLAG_WAITID flag, so the workaround
+		 * for mice not acknowledging the Get ID command only triggers
+		 * on the 1st byte; if device spews data we really want to see
+		 * a real ACK from it.
 		 */
-		case 0x00:
-		case 0x03:
-		case 0x04:
-			if (ps2dev->flags & PS2_FLAG_WAITID) {
-				ps2dev->nak = 0;
-				break;
-			}
-			/* Fall through */
-		default:
-			return 0;
+		dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
+		ps2dev->flags &= ~PS2_FLAG_WAITID;
+		return ps2dev->flags & PS2_FLAG_ACK_CMD;
 	}
 
-
 	if (!ps2dev->nak) {
 		ps2dev->flags &= ~PS2_FLAG_NAK;
 		if (ps2dev->cmdcnt)
@@ -334,7 +450,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
 	if (data != PS2_RET_ACK)
 		ps2_handle_response(ps2dev, data);
 
-	return 1;
+	return true;
 }
 EXPORT_SYMBOL(ps2_handle_ack);
 
@@ -344,7 +460,7 @@ EXPORT_SYMBOL(ps2_handle_ack);
  * waiting for completion of the command.
  */
 
-int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
+bool ps2_handle_response(struct ps2dev *ps2dev, u8 data)
 {
 	if (ps2dev->cmdcnt)
 		ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
@@ -360,7 +476,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
 		wake_up(&ps2dev->wait);
 	}
 
-	return 1;
+	return true;
 }
 EXPORT_SYMBOL(ps2_handle_response);
 

+ 24 - 8
drivers/input/tablet/pegasus_notetaker.c

@@ -41,6 +41,7 @@
 #include <linux/usb/input.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 /* USB HID defines */
 #define USB_REQ_GET_REPORT		0x01
@@ -76,6 +77,11 @@ struct pegasus {
 	struct usb_device *usbdev;
 	struct usb_interface *intf;
 	struct urb *irq;
+
+	/* serialize access to open/suspend */
+	struct mutex pm_mutex;
+	bool is_open;
+
 	char name[128];
 	char phys[64];
 	struct work_struct init;
@@ -216,6 +222,7 @@ static int pegasus_open(struct input_dev *dev)
 	if (error)
 		return error;
 
+	mutex_lock(&pegasus->pm_mutex);
 	pegasus->irq->dev = pegasus->usbdev;
 	if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) {
 		error = -EIO;
@@ -226,12 +233,15 @@ static int pegasus_open(struct input_dev *dev)
 	if (error)
 		goto err_kill_urb;
 
+	pegasus->is_open = true;
+	mutex_unlock(&pegasus->pm_mutex);
 	return 0;
 
 err_kill_urb:
 	usb_kill_urb(pegasus->irq);
 	cancel_work_sync(&pegasus->init);
 err_autopm_put:
+	mutex_unlock(&pegasus->pm_mutex);
 	usb_autopm_put_interface(pegasus->intf);
 	return error;
 }
@@ -240,8 +250,12 @@ static void pegasus_close(struct input_dev *dev)
 {
 	struct pegasus *pegasus = input_get_drvdata(dev);
 
+	mutex_lock(&pegasus->pm_mutex);
 	usb_kill_urb(pegasus->irq);
 	cancel_work_sync(&pegasus->init);
+	pegasus->is_open = false;
+	mutex_unlock(&pegasus->pm_mutex);
+
 	usb_autopm_put_interface(pegasus->intf);
 }
 
@@ -274,6 +288,8 @@ static int pegasus_probe(struct usb_interface *intf,
 		goto err_free_mem;
 	}
 
+	mutex_init(&pegasus->pm_mutex);
+
 	pegasus->usbdev = dev;
 	pegasus->dev = input_dev;
 	pegasus->intf = intf;
@@ -388,10 +404,10 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 
-	mutex_lock(&pegasus->dev->mutex);
+	mutex_lock(&pegasus->pm_mutex);
 	usb_kill_urb(pegasus->irq);
 	cancel_work_sync(&pegasus->init);
-	mutex_unlock(&pegasus->dev->mutex);
+	mutex_unlock(&pegasus->pm_mutex);
 
 	return 0;
 }
@@ -401,10 +417,10 @@ static int pegasus_resume(struct usb_interface *intf)
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 	int retval = 0;
 
-	mutex_lock(&pegasus->dev->mutex);
-	if (pegasus->dev->users && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
+	mutex_lock(&pegasus->pm_mutex);
+	if (pegasus->is_open && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
 		retval = -EIO;
-	mutex_unlock(&pegasus->dev->mutex);
+	mutex_unlock(&pegasus->pm_mutex);
 
 	return retval;
 }
@@ -414,14 +430,14 @@ static int pegasus_reset_resume(struct usb_interface *intf)
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 	int retval = 0;
 
-	mutex_lock(&pegasus->dev->mutex);
-	if (pegasus->dev->users) {
+	mutex_lock(&pegasus->pm_mutex);
+	if (pegasus->is_open) {
 		retval = pegasus_set_mode(pegasus, PEN_MODE_XY,
 					  NOTETAKER_LED_MOUSE);
 		if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
 			retval = -EIO;
 	}
-	mutex_unlock(&pegasus->dev->mutex);
+	mutex_unlock(&pegasus->pm_mutex);
 
 	return retval;
 }

+ 1 - 1
drivers/input/touchscreen/s6sy761.c

@@ -2,7 +2,7 @@
 // Samsung S6SY761 Touchscreen device driver
 //
 // Copyright (c) 2017 Samsung Electronics Co., Ltd.
-// Copyright (c) 2017 Andi Shyti <andi.shyti@samsung.com>
+// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
 
 #include <asm/unaligned.h>
 #include <linux/delay.h>

+ 1 - 0
drivers/input/touchscreen/silead.c

@@ -602,6 +602,7 @@ static const struct acpi_device_id silead_ts_acpi_match[] = {
 	{ "GSL3675", 0 },
 	{ "GSL3692", 0 },
 	{ "MSSL1680", 0 },
+	{ "MSSL0001", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);

+ 3 - 1
drivers/input/touchscreen/stmfts.c

@@ -2,7 +2,7 @@
 // STMicroelectronics FTS Touchscreen device driver
 //
 // Copyright (c) 2017 Samsung Electronics Co., Ltd.
-// Copyright (c) 2017 Andi Shyti <andi.shyti@samsung.com>
+// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -730,6 +730,7 @@ static int stmfts_probe(struct i2c_client *client,
 		return err;
 
 	pm_runtime_enable(&client->dev);
+	device_enable_async_suspend(&client->dev);
 
 	return 0;
 }
@@ -805,6 +806,7 @@ static struct i2c_driver stmfts_driver = {
 		.name = STMFTS_DEV_NAME,
 		.of_match_table = of_match_ptr(stmfts_of_match),
 		.pm = &stmfts_pm_ops,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 	.probe = stmfts_probe,
 	.remove = stmfts_remove,

+ 16 - 8
drivers/input/touchscreen/usbtouchscreen.c

@@ -54,6 +54,7 @@
 #include <linux/usb.h>
 #include <linux/usb/input.h>
 #include <linux/hid.h>
+#include <linux/mutex.h>
 
 static bool swap_xy;
 module_param(swap_xy, bool, 0644);
@@ -107,6 +108,8 @@ struct usbtouch_usb {
 	struct usb_interface *interface;
 	struct input_dev *input;
 	struct usbtouch_device_info *type;
+	struct mutex pm_mutex;  /* serialize access to open/suspend */
+	bool is_open;
 	char name[128];
 	char phys[64];
 	void *priv;
@@ -1450,6 +1453,7 @@ static int usbtouch_open(struct input_dev *input)
 	if (r < 0)
 		goto out;
 
+	mutex_lock(&usbtouch->pm_mutex);
 	if (!usbtouch->type->irq_always) {
 		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
 			r = -EIO;
@@ -1458,7 +1462,9 @@ static int usbtouch_open(struct input_dev *input)
 	}
 
 	usbtouch->interface->needs_remote_wakeup = 1;
+	usbtouch->is_open = true;
 out_put:
+	mutex_unlock(&usbtouch->pm_mutex);
 	usb_autopm_put_interface(usbtouch->interface);
 out:
 	return r;
@@ -1469,8 +1475,12 @@ static void usbtouch_close(struct input_dev *input)
 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
 	int r;
 
+	mutex_lock(&usbtouch->pm_mutex);
 	if (!usbtouch->type->irq_always)
 		usb_kill_urb(usbtouch->irq);
+	usbtouch->is_open = false;
+	mutex_unlock(&usbtouch->pm_mutex);
+
 	r = usb_autopm_get_interface(usbtouch->interface);
 	usbtouch->interface->needs_remote_wakeup = 0;
 	if (!r)
@@ -1490,13 +1500,12 @@ static int usbtouch_suspend
 static int usbtouch_resume(struct usb_interface *intf)
 {
 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
-	struct input_dev *input = usbtouch->input;
 	int result = 0;
 
-	mutex_lock(&input->mutex);
-	if (input->users || usbtouch->type->irq_always)
+	mutex_lock(&usbtouch->pm_mutex);
+	if (usbtouch->is_open || usbtouch->type->irq_always)
 		result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
-	mutex_unlock(&input->mutex);
+	mutex_unlock(&usbtouch->pm_mutex);
 
 	return result;
 }
@@ -1504,7 +1513,6 @@ static int usbtouch_resume(struct usb_interface *intf)
 static int usbtouch_reset_resume(struct usb_interface *intf)
 {
 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
-	struct input_dev *input = usbtouch->input;
 	int err = 0;
 
 	/* reinit the device */
@@ -1519,10 +1527,10 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
 	}
 
 	/* restart IO if needed */
-	mutex_lock(&input->mutex);
-	if (input->users)
+	mutex_lock(&usbtouch->pm_mutex);
+	if (usbtouch->is_open)
 		err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
-	mutex_unlock(&input->mutex);
+	mutex_unlock(&usbtouch->pm_mutex);
 
 	return err;
 }

+ 13 - 0
include/dt-bindings/input/gpio-keys.h

@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for gpio keys bindings.
+ */
+
+#ifndef _DT_BINDINGS_GPIO_KEYS_H
+#define _DT_BINDINGS_GPIO_KEYS_H
+
+#define EV_ACT_ANY		0x00	/* asserted or deasserted */
+#define EV_ACT_ASSERTED		0x01	/* asserted */
+#define EV_ACT_DEASSERTED	0x02	/* deasserted */
+
+#endif /* _DT_BINDINGS_GPIO_KEYS_H */

+ 2 - 0
include/linux/gpio_keys.h

@@ -13,6 +13,7 @@ struct device;
  * @desc:		label that will be attached to button's gpio
  * @type:		input event type (%EV_KEY, %EV_SW, %EV_ABS)
  * @wakeup:		configure the button as a wake-up source
+ * @wakeup_event_action:	event action to trigger wakeup
  * @debounce_interval:	debounce ticks interval in msecs
  * @can_disable:	%true indicates that userspace is allowed to
  *			disable button via sysfs
@@ -26,6 +27,7 @@ struct gpio_keys_button {
 	const char *desc;
 	unsigned int type;
 	int wakeup;
+	int wakeup_event_action;
 	int debounce_interval;
 	bool can_disable;
 	int value;

+ 23 - 15
include/linux/libps2.h

@@ -10,7 +10,13 @@
  * the Free Software Foundation.
  */
 
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/wait.h>
 
+#define PS2_CMD_SETSCALE11	0x00e6
+#define PS2_CMD_SETRES		0x10e8
 #define PS2_CMD_GETID		0x02f2
 #define PS2_CMD_RESET_BAT	0x02ff
 
@@ -20,11 +26,12 @@
 #define PS2_RET_NAK		0xfe
 #define PS2_RET_ERR		0xfc
 
-#define PS2_FLAG_ACK		1	/* Waiting for ACK/NAK */
-#define PS2_FLAG_CMD		2	/* Waiting for command to finish */
-#define PS2_FLAG_CMD1		4	/* Waiting for the first byte of command response */
-#define PS2_FLAG_WAITID		8	/* Command execiting is GET ID */
-#define PS2_FLAG_NAK		16	/* Last transmission was NAKed */
+#define PS2_FLAG_ACK		BIT(0)	/* Waiting for ACK/NAK */
+#define PS2_FLAG_CMD		BIT(1)	/* Waiting for a command to finish */
+#define PS2_FLAG_CMD1		BIT(2)	/* Waiting for the first byte of command response */
+#define PS2_FLAG_WAITID		BIT(3)	/* Command executing is GET ID */
+#define PS2_FLAG_NAK		BIT(4)	/* Last transmission was NAKed */
+#define PS2_FLAG_ACK_CMD	BIT(5)	/* Waiting to ACK the command (first) byte */
 
 struct ps2dev {
 	struct serio *serio;
@@ -36,21 +43,22 @@ struct ps2dev {
 	wait_queue_head_t wait;
 
 	unsigned long flags;
-	unsigned char cmdbuf[8];
-	unsigned char cmdcnt;
-	unsigned char nak;
+	u8 cmdbuf[8];
+	u8 cmdcnt;
+	u8 nak;
 };
 
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
-int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
-void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
+int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout);
+void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout);
 void ps2_begin_command(struct ps2dev *ps2dev);
 void ps2_end_command(struct ps2dev *ps2dev);
-int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
-int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
-int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
-int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
+int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
+int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
+int ps2_sliced_command(struct ps2dev *ps2dev, u8 command);
+bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data);
+bool ps2_handle_response(struct ps2dev *ps2dev, u8 data);
 void ps2_cmd_aborted(struct ps2dev *ps2dev);
-int ps2_is_keyboard_id(char id);
+bool ps2_is_keyboard_id(u8 id);
 
 #endif /* _LIBPS2_H */