Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Apr 2018 20:21:57 +0000 (13:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Apr 2018 20:21:57 +0000 (13:21 -0700)
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
  ...

34 files changed:
Documentation/devicetree/bindings/input/gpio-keys.txt
Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt [new file with mode: 0644]
Documentation/input/devices/pxrc.rst [new file with mode: 0644]
drivers/input/joystick/Kconfig
drivers/input/joystick/Makefile
drivers/input/joystick/analog.c
drivers/input/joystick/pxrc.c [new file with mode: 0644]
drivers/input/joystick/xpad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/stmpe-keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/rave-sp-pwrbutton.c [new file with mode: 0644]
drivers/input/mouse/alps.c
drivers/input/mouse/appletouch.c
drivers/input/mouse/elantech.c
drivers/input/mouse/lifebook.c
drivers/input/mouse/logips2pp.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics_usb.c
drivers/input/mouse/trackpoint.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/libps2.c
drivers/input/tablet/pegasus_notetaker.c
drivers/input/touchscreen/s6sy761.c
drivers/input/touchscreen/silead.c
drivers/input/touchscreen/stmfts.c
drivers/input/touchscreen/usbtouchscreen.c
include/dt-bindings/input/gpio-keys.h [new file with mode: 0644]
include/linux/gpio_keys.h
include/linux/libps2.h

index a94940481e55ad6de187b3dc1a5c87a57c461fef..996ce84352cbf11627adc17c13d079cc17601de1 100644 (file)
@@ -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.
diff --git a/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt b/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt
new file mode 100644 (file)
index 0000000..43ef770
--- /dev/null
@@ -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";
+               };
+       }
diff --git a/Documentation/input/devices/pxrc.rst b/Documentation/input/devices/pxrc.rst
new file mode 100644 (file)
index 0000000..ca11f64
--- /dev/null
@@ -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/
index f3c2f6ea8b447395fd4fc241735a0b4d8f4a6bd1..9591fc04a8ab203a0b514834c09f40697d0ccc7f 100644 (file)
@@ -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
index 67651efda2e1ab734b6d471af8552b2c3bc3fe74..dd0492ebbed79613374004decee6b87996336794 100644 (file)
@@ -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
index eefac7978f93a7477d5145e48448e253f18b897e..c79dbcb4d146f647f2a96316401405b98112ba41 100644 (file)
@@ -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"
diff --git a/drivers/input/joystick/pxrc.c b/drivers/input/joystick/pxrc.c
new file mode 100644 (file)
index 0000000..07a0dbd
--- /dev/null
@@ -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");
index 9d2688f3f961a822389281e9391cfd1a7214d2f6..06e9650b3b302f12394b9d92572afe872bae6da3 100644 (file)
@@ -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),
index 87e613dc33b804bf60047133f773343550e1a044..052e37675086bf53bc7d471d0434542167c6a88e 100644 (file)
@@ -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)
index 8c6c0b9109c75e22bfdc290d4ecfacb88d911ca9..d69e631cfa0a337290a183789616680cbefbdaab 100644 (file)
 #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;
 
index e9770f5e3f77bcc51f859be939a2aa3d4f8dc222..572b15fa18c22be816704236882255df3e30c967 100644 (file)
@@ -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
index eb9c6c3ec530a7515eb7884a39d8c1544f156ce9..72cde28649e2c0bc4fec14f6898445d2f79880dc 100644 (file)
@@ -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
diff --git a/drivers/input/misc/rave-sp-pwrbutton.c b/drivers/input/misc/rave-sp-pwrbutton.c
new file mode 100644 (file)
index 0000000..bcab3cd
--- /dev/null
@@ -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");
index dbe57da8c1a1ba5c9339cd6ac8596d76665c5d9f..0a67f235ba88a7b6e25877a43b35488a31d8fdf5 100644 (file)
@@ -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;
 }
index 81a695d0b4e04600e60f62949bd07ca01fda8062..032d27983b6c25eadb63163fb858275889597701 100644 (file)
@@ -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)
index a4aaa748e987f7e4db918e290d20d356f9eec21b..db47a5e1d114dcaee65f63df4ee7a51fb0b6aa07 100644 (file)
@@ -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);
index 13d324cef7df5c3af35e4b3aa735e31bf2c4655a..a5765f747c020b30cc6ecff500a94b6aa2c904ad 100644 (file)
@@ -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;
                }
        }
 
index ef9c97f5e3d78b6e1f5ca728bbc1ebf3c352bc73..3d5637e6fa5fac579c3f067245f2a62926309427 100644 (file)
@@ -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"
 
 #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;
 }
 
index 8ac9e03c05b457523b7480bfca1154144ac64da7..8900c3166ebfce0f0f547f0a2b4400b86091c2e8 100644 (file)
@@ -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);
index 8cd453808cc7d8e6bd3026e3aca90fcd73d9758c..71ac50082c8b41a1ceb032779402ef79324828b7 100644 (file)
@@ -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;
index 11c32ac8234b2d1883e9c7349962192b5aabb647..1d6010d463e2cf7b7ee13b93ba8f6f4fb0e7127d 100644 (file)
@@ -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;
        }
 
index a246fc686bb728dbe48b2fc84b90a1734af60c66..60f2c463d1cc7d2805d9a98923ad3934d5ff2294 100644 (file)
@@ -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
index cb7d15d826d0d420ad426c1c491939d11bd65e34..83d2412a64cf4fbed8ede3a961e354c3137d043d 100644 (file)
@@ -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;
 }
index bbd29220dbe99838ba69a48dc3dfb595ec0dae0f..6590d10f166fe0a8e15b0816924f3b09a0c29c7a 100644 (file)
@@ -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;
 }
 
 
index 6cbbdc6e968756a495301f340a2085d3fdf74e65..b353d494ad404888bd2884527fe771937cb1416f 100644 (file)
@@ -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;
 
index 83e9c663aa6727da129d2fe8b0256f73f4581d53..e6a07e68d1ff69d0ae16ac9d862c8816eb39cc05 100644 (file)
@@ -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);
 
index 47de5a81172f65a24a656361afdf244f2f61ff4e..ffd03cfe3131a4a977c6741c67e3c326ca37e99c 100644 (file)
@@ -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;
 }
index 675efa93d4448b556b27bc2e1e0b682273b1d0c3..b63d7fdf0cd20d3c971fca88079e450d188a8199 100644 (file)
@@ -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>
index 646b1e768e6b90ede419d59e1c3f00f7febad9f0..ff7043f74a3d32286a6b8cdbed91f1bc3f0be12f 100644 (file)
@@ -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);
index efdb1a75a163d02c2dfc7bbf14de04569c29f419..704e9904691642750143a92af565afb9a06e8203 100644 (file)
@@ -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,
index aa77d243b78605e09ac0c2adf9e2eff57bdc51fe..c6cf90868503e1c9697bd961ecbbe08495f221bd 100644 (file)
@@ -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;
 }
diff --git a/include/dt-bindings/input/gpio-keys.h b/include/dt-bindings/input/gpio-keys.h
new file mode 100644 (file)
index 0000000..8962df7
--- /dev/null
@@ -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 */
index d06bf77400f16ae861b938696dae9f2b93d797f9..7160df54a6fe3e6fef2c6be9dd67698e185beace 100644 (file)
@@ -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;
index 4ad06e824f76f797250b7cef01ac5932ffa7452b..5f18fe02ae371901a8bd87efce9a521c573d5643 100644 (file)
  * 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
 
 #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 */