summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c7
-rw-r--r--drivers/input/joystick/Kconfig10
-rw-r--r--drivers/input/joystick/Makefile1
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/pxrc.c303
-rw-r--r--drivers/input/joystick/xpad.c9
-rw-r--r--drivers/input/keyboard/Kconfig9
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/bf54x-keys.c396
-rw-r--r--drivers/input/keyboard/gpio_keys.c145
-rw-r--r--drivers/input/keyboard/matrix_keypad.c4
-rw-r--r--drivers/input/keyboard/stmpe-keypad.c16
-rw-r--r--drivers/input/misc/Kconfig18
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/bfin_rotary.c294
-rw-r--r--drivers/input/misc/rave-sp-pwrbutton.c94
-rw-r--r--drivers/input/mouse/alps.c64
-rw-r--r--drivers/input/mouse/appletouch.c6
-rw-r--r--drivers/input/mouse/elantech.c40
-rw-r--r--drivers/input/mouse/lifebook.c62
-rw-r--r--drivers/input/mouse/logips2pp.c152
-rw-r--r--drivers/input/mouse/psmouse-base.c189
-rw-r--r--drivers/input/mouse/psmouse.h5
-rw-r--r--drivers/input/mouse/sentelic.c11
-rw-r--r--drivers/input/mouse/synaptics.c91
-rw-r--r--drivers/input/mouse/synaptics_usb.c31
-rw-r--r--drivers/input/mouse/trackpoint.c60
-rw-r--r--drivers/input/serio/gscps2.c11
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h24
-rw-r--r--drivers/input/serio/libps2.c322
-rw-r--r--drivers/input/tablet/pegasus_notetaker.c32
-rw-r--r--drivers/input/touchscreen/mms114.c15
-rw-r--r--drivers/input/touchscreen/s6sy761.c2
-rw-r--r--drivers/input/touchscreen/silead.c1
-rw-r--r--drivers/input/touchscreen/stmfts.c4
-rw-r--r--drivers/input/touchscreen/sur40.c178
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c24
37 files changed, 1425 insertions, 1210 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index c81c79d..46115a3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -31,7 +31,6 @@
enum evdev_clock_type {
EV_CLK_REAL = 0,
EV_CLK_MONO,
- EV_CLK_BOOT,
EV_CLK_MAX
};
@@ -198,12 +197,10 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
case CLOCK_REALTIME:
clk_type = EV_CLK_REAL;
break;
+ case CLOCK_BOOTTIME:
case CLOCK_MONOTONIC:
clk_type = EV_CLK_MONO;
break;
- case CLOCK_BOOTTIME:
- clk_type = EV_CLK_BOOT;
- break;
default:
return -EINVAL;
}
@@ -314,8 +311,6 @@ static void evdev_events(struct input_handle *handle,
ev_time[EV_CLK_MONO] = ktime_get();
ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
- ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
- TK_OFFS_BOOT);
rcu_read_lock();
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index f3c2f6e..9591fc0 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -351,4 +351,14 @@ config JOYSTICK_PSXPAD_SPI_FF
To drive rumble motor a dedicated power supply is required.
+config JOYSTICK_PXRC
+ tristate "PhoenixRC Flight Controller Adapter"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ Say Y here if you want to use the PhoenixRC Flight Controller Adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pxrc.
+
endif
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index 67651ef..dd0492e 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
+obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index c868a87..c79dbcb 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -163,7 +163,7 @@ static unsigned int get_time_pit(void)
#define GET_TIME(x) do { x = (unsigned int)rdtsc(); } while (0)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "TSC"
-#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV) || defined(CONFIG_TILE)
+#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
index 0000000..07a0dbd
--- /dev/null
+++ b/drivers/input/joystick/pxrc.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Phoenix RC Flight Controller Adapter
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <linux/mutex.h>
+#include <linux/input.h>
+
+#define PXRC_VENDOR_ID (0x1781)
+#define PXRC_PRODUCT_ID (0x0898)
+
+static const struct usb_device_id pxrc_table[] = {
+ { USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, pxrc_table);
+
+struct pxrc {
+ struct input_dev *input;
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct urb *urb;
+ struct mutex pm_mutex;
+ bool is_open;
+ __u8 epaddr;
+ char phys[64];
+ unsigned char *data;
+ size_t bsize;
+};
+
+static void pxrc_usb_irq(struct urb *urb)
+{
+ struct pxrc *pxrc = urb->context;
+ int error;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ETIME:
+ /* this urb is timing out */
+ dev_dbg(&pxrc->intf->dev,
+ "%s - urb timed out - was the device unplugged?\n",
+ __func__);
+ return;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EPIPE:
+ /* this urb is terminated, clean up */
+ dev_dbg(&pxrc->intf->dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_dbg(&pxrc->intf->dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
+ goto exit;
+ }
+
+ if (urb->actual_length == 8) {
+ input_report_abs(pxrc->input, ABS_X, pxrc->data[0]);
+ input_report_abs(pxrc->input, ABS_Y, pxrc->data[2]);
+ input_report_abs(pxrc->input, ABS_RX, pxrc->data[3]);
+ input_report_abs(pxrc->input, ABS_RY, pxrc->data[4]);
+ input_report_abs(pxrc->input, ABS_RUDDER, pxrc->data[5]);
+ input_report_abs(pxrc->input, ABS_THROTTLE, pxrc->data[6]);
+ input_report_abs(pxrc->input, ABS_MISC, pxrc->data[7]);
+
+ input_report_key(pxrc->input, BTN_A, pxrc->data[1]);
+ }
+
+exit:
+ /* Resubmit to fetch new fresh URBs */
+ error = usb_submit_urb(urb, GFP_ATOMIC);
+ if (error && error != -EPERM)
+ dev_err(&pxrc->intf->dev,
+ "%s - usb_submit_urb failed with result: %d",
+ __func__, error);
+}
+
+static int pxrc_open(struct input_dev *input)
+{
+ struct pxrc *pxrc = input_get_drvdata(input);
+ int retval;
+
+ mutex_lock(&pxrc->pm_mutex);
+ retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&pxrc->intf->dev,
+ "%s - usb_submit_urb failed, error: %d\n",
+ __func__, retval);
+ retval = -EIO;
+ goto out;
+ }
+
+ pxrc->is_open = true;
+
+out:
+ mutex_unlock(&pxrc->pm_mutex);
+ return retval;
+}
+
+static void pxrc_close(struct input_dev *input)
+{
+ struct pxrc *pxrc = input_get_drvdata(input);
+
+ mutex_lock(&pxrc->pm_mutex);
+ usb_kill_urb(pxrc->urb);
+ pxrc->is_open = false;
+ mutex_unlock(&pxrc->pm_mutex);
+}
+
+static int pxrc_usb_init(struct pxrc *pxrc)
+{
+ struct usb_endpoint_descriptor *epirq;
+ unsigned int pipe;
+ int retval;
+
+ /* Set up the endpoint information */
+ /* This device only has an interrupt endpoint */
+ retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
+ NULL, NULL, &epirq, NULL);
+ if (retval) {
+ dev_err(&pxrc->intf->dev,
+ "Could not find endpoint\n");
+ goto error;
+ }
+
+ pxrc->bsize = usb_endpoint_maxp(epirq);
+ pxrc->epaddr = epirq->bEndpointAddress;
+ pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL);
+ if (!pxrc->data) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ usb_set_intfdata(pxrc->intf, pxrc);
+ usb_make_path(pxrc->udev, pxrc->phys, sizeof(pxrc->phys));
+ strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
+
+ pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pxrc->urb) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ pipe = usb_rcvintpipe(pxrc->udev, pxrc->epaddr),
+ usb_fill_int_urb(pxrc->urb, pxrc->udev, pipe, pxrc->data, pxrc->bsize,
+ pxrc_usb_irq, pxrc, 1);
+
+error:
+ return retval;
+
+
+}
+
+static int pxrc_input_init(struct pxrc *pxrc)
+{
+ pxrc->input = devm_input_allocate_device(&pxrc->intf->dev);
+ if (pxrc->input == NULL) {
+ dev_err(&pxrc->intf->dev, "couldn't allocate input device\n");
+ return -ENOMEM;
+ }
+
+ pxrc->input->name = "PXRC Flight Controller Adapter";
+ pxrc->input->phys = pxrc->phys;
+ usb_to_input_id(pxrc->udev, &pxrc->input->id);
+
+ pxrc->input->open = pxrc_open;
+ pxrc->input->close = pxrc_close;
+
+ input_set_capability(pxrc->input, EV_KEY, BTN_A);
+ input_set_abs_params(pxrc->input, ABS_X, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_Y, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_RX, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_RY, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_RUDDER, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_THROTTLE, 0, 255, 0, 0);
+ input_set_abs_params(pxrc->input, ABS_MISC, 0, 255, 0, 0);
+
+ input_set_drvdata(pxrc->input, pxrc);
+
+ return input_register_device(pxrc->input);
+}
+
+static int pxrc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct pxrc *pxrc;
+ int retval;
+
+ pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
+ if (!pxrc)
+ return -ENOMEM;
+
+ mutex_init(&pxrc->pm_mutex);
+ pxrc->udev = usb_get_dev(interface_to_usbdev(intf));
+ pxrc->intf = intf;
+
+ retval = pxrc_usb_init(pxrc);
+ if (retval)
+ goto error;
+
+ retval = pxrc_input_init(pxrc);
+ if (retval)
+ goto err_free_urb;
+
+ return 0;
+
+err_free_urb:
+ usb_free_urb(pxrc->urb);
+
+error:
+ return retval;
+}
+
+static void pxrc_disconnect(struct usb_interface *intf)
+{
+ struct pxrc *pxrc = usb_get_intfdata(intf);
+
+ usb_free_urb(pxrc->urb);
+ usb_set_intfdata(intf, NULL);
+}
+
+static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct pxrc *pxrc = usb_get_intfdata(intf);
+
+ mutex_lock(&pxrc->pm_mutex);
+ if (pxrc->is_open)
+ usb_kill_urb(pxrc->urb);
+ mutex_unlock(&pxrc->pm_mutex);
+
+ return 0;
+}
+
+static int pxrc_resume(struct usb_interface *intf)
+{
+ struct pxrc *pxrc = usb_get_intfdata(intf);
+ int retval = 0;
+
+ mutex_lock(&pxrc->pm_mutex);
+ if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
+ retval = -EIO;
+
+ mutex_unlock(&pxrc->pm_mutex);
+ return retval;
+}
+
+static int pxrc_pre_reset(struct usb_interface *intf)
+{
+ struct pxrc *pxrc = usb_get_intfdata(intf);
+
+ mutex_lock(&pxrc->pm_mutex);
+ usb_kill_urb(pxrc->urb);
+ return 0;
+}
+
+static int pxrc_post_reset(struct usb_interface *intf)
+{
+ struct pxrc *pxrc = usb_get_intfdata(intf);
+ int retval = 0;
+
+ if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
+ retval = -EIO;
+
+ mutex_unlock(&pxrc->pm_mutex);
+
+ return retval;
+}
+
+static int pxrc_reset_resume(struct usb_interface *intf)
+{
+ return pxrc_resume(intf);
+}
+
+static struct usb_driver pxrc_driver = {
+ .name = "pxrc",
+ .probe = pxrc_probe,
+ .disconnect = pxrc_disconnect,
+ .id_table = pxrc_table,
+ .suspend = pxrc_suspend,
+ .resume = pxrc_resume,
+ .pre_reset = pxrc_pre_reset,
+ .post_reset = pxrc_post_reset,
+ .reset_resume = pxrc_reset_resume,
+};
+
+module_usb_driver(pxrc_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("PhoenixRC Flight Controller Adapter");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 9d2688f..06e9650 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -227,6 +227,7 @@ static const struct xpad_device {
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
+ { 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
@@ -475,7 +476,8 @@ static const u8 xboxone_hori_init[] = {
/*
* This packet is required for some of the PDP pads to start
- * sending input reports. One of those pads is (0x0e6f:0x02ab).
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4).
*/
static const u8 xboxone_pdp_init1[] = {
0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
@@ -483,7 +485,8 @@ static const u8 xboxone_pdp_init1[] = {
/*
* This packet is required for some of the PDP pads to start
- * sending input reports. One of those pads is (0x0e6f:0x02ab).
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4).
*/
static const u8 xboxone_pdp_init2[] = {
0x06, 0x20, 0x00, 0x02, 0x01, 0x00
@@ -521,6 +524,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init1),
XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init2),
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init1),
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init2),
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4c4ab1c..2b469cc 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -157,15 +157,6 @@ config KEYBOARD_QT2160
This driver can also be built as a module. If so, the module
will be called qt2160.
-config KEYBOARD_BFIN
- tristate "Blackfin BF54x keypad support"
- depends on (BF54x && !BF544)
- help
- Say Y here if you want to use the BF54x keypad.
-
- To compile this driver as a module, choose M here: the
- module will be called bf54x-keys.
-
config KEYBOARD_CLPS711X
tristate "CLPS711X Keypad support"
depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST)
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 526e682..8fab920 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
-obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
deleted file mode 100644
index 8a07a42..0000000
--- a/drivers/input/keyboard/bf54x-keys.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * File: drivers/input/keyboard/bf54x-keys.c
- * Based on:
- * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
- *
- * Created:
- * Description: keypad driver for Analog Devices Blackfin BF54x Processors
- *
- *
- * Modified:
- * Copyright 2007-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/pm.h>
-#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-
-#include <asm/portmux.h>
-#include <mach/bf54x_keys.h>
-
-#define DRV_NAME "bf54x-keys"
-#define TIME_SCALE 100 /* 100 ns */
-#define MAX_MULT (0xFF * TIME_SCALE)
-#define MAX_RC 8 /* Max Row/Col */
-
-static const u16 per_rows[] = {
- P_KEY_ROW7,
- P_KEY_ROW6,
- P_KEY_ROW5,
- P_KEY_ROW4,
- P_KEY_ROW3,
- P_KEY_ROW2,
- P_KEY_ROW1,
- P_KEY_ROW0,
- 0
-};
-
-static const u16 per_cols[] = {
- P_KEY_COL7,
- P_KEY_COL6,
- P_KEY_COL5,
- P_KEY_COL4,
- P_KEY_COL3,
- P_KEY_COL2,
- P_KEY_COL1,
- P_KEY_COL0,
- 0
-};
-
-struct bf54x_kpad {
- struct input_dev *input;
- int irq;
- unsigned short lastkey;
- unsigned short *keycode;
- struct timer_list timer;
- unsigned int keyup_test_jiffies;
- unsigned short kpad_msel;
- unsigned short kpad_prescale;
- unsigned short kpad_ctl;
-};
-
-static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
- struct input_dev *input, u16 keyident)
-{
- u16 i;
-
- for (i = 0; i < input->keycodemax; i++)
- if (bf54x_kpad->keycode[i + input->keycodemax] == keyident)
- return bf54x_kpad->keycode[i];
- return -1;
-}
-
-static inline void bfin_keycodecpy(unsigned short *keycode,
- const unsigned int *pdata_kc,
- unsigned short keymapsize)
-{
- unsigned int i;
-
- for (i = 0; i < keymapsize; i++) {
- keycode[i] = pdata_kc[i] & 0xffff;
- keycode[i + keymapsize] = pdata_kc[i] >> 16;
- }
-}
-
-static inline u16 bfin_kpad_get_prescale(u32 timescale)
-{
- u32 sclk = get_sclk();
-
- return ((((sclk / 1000) * timescale) / 1024) - 1);
-}
-
-static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad)
-{
- return (bfin_read_KPAD_STAT() & KPAD_PRESSED);
-}
-
-static inline void bfin_kpad_clear_irq(void)
-{
- bfin_write_KPAD_STAT(0xFFFF);
- bfin_write_KPAD_ROWCOL(0xFFFF);
-}
-
-static void bfin_kpad_timer(struct timer_list *t)
-{
- struct bf54x_kpad *bf54x_kpad = from_timer(bf54x_kpad, t, timer);
-
- if (bfin_kpad_get_keypressed(bf54x_kpad)) {
- /* Try again later */
- mod_timer(&bf54x_kpad->timer,
- jiffies + bf54x_kpad->keyup_test_jiffies);
- return;
- }
-
- input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0);
- input_sync(bf54x_kpad->input);
-
- /* Clear IRQ Status */
-
- bfin_kpad_clear_irq();
- enable_irq(bf54x_kpad->irq);
-}
-
-static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
-{
- struct platform_device *pdev = dev_id;
- struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
- struct input_dev *input = bf54x_kpad->input;
- int key;
- u16 rowcol = bfin_read_KPAD_ROWCOL();
-
- key = bfin_kpad_find_key(bf54x_kpad, input, rowcol);
-
- input_report_key(input, key, 1);
- input_sync(input);
-
- if (bfin_kpad_get_keypressed(bf54x_kpad)) {
- disable_irq_nosync(bf54x_kpad->irq);
- bf54x_kpad->lastkey = key;
- mod_timer(&bf54x_kpad->timer,
- jiffies + bf54x_kpad->keyup_test_jiffies);
- } else {
- input_report_key(input, key, 0);
- input_sync(input);
-
- bfin_kpad_clear_irq();
- }
-
- return IRQ_HANDLED;
-}
-
-static int bfin_kpad_probe(struct platform_device *pdev)
-{
- struct bf54x_kpad *bf54x_kpad;
- struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct input_dev *input;
- int i, error;
-
- if (!pdata->rows || !pdata->cols || !pdata->keymap) {
- dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n");
- return -EINVAL;
- }
-
- if (!pdata->keymapsize ||
- pdata->keymapsize > (pdata->rows * pdata->cols)) {
- dev_err(&pdev->dev, "invalid keymapsize\n");
- return -EINVAL;
- }
-
- bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL);
- if (!bf54x_kpad)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, bf54x_kpad);
-
- /* Allocate memory for keymap followed by private LUT */
- bf54x_kpad->keycode = kmalloc(pdata->keymapsize *
- sizeof(unsigned short) * 2, GFP_KERNEL);
- if (!bf54x_kpad->keycode) {
- error = -ENOMEM;
- goto out;
- }
-
- if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
- !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
- dev_warn(&pdev->dev,
- "invalid platform debounce/columndrive time\n");
- bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
- } else {
- bfin_write_KPAD_MSEL(
- ((pdata->debounce_time / TIME_SCALE)
- & DBON_SCALE) |
- (((pdata->coldrive_time / TIME_SCALE) << 8)
- & COLDRV_SCALE));
-
- }
-
- if (!pdata->keyup_test_interval)
- bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50);
- else
- bf54x_kpad->keyup_test_jiffies =
- msecs_to_jiffies(pdata->keyup_test_interval);
-
- if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
- DRV_NAME)) {
- dev_err(&pdev->dev, "requesting peripherals failed\n");
- error = -EFAULT;
- goto out0;
- }
-
- if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
- DRV_NAME)) {
- dev_err(&pdev->dev, "requesting peripherals failed\n");
- error = -EFAULT;
- goto out1;
- }
-
- bf54x_kpad->irq = platform_get_irq(pdev, 0);
- if (bf54x_kpad->irq < 0) {
- error = -ENODEV;
- goto out2;
- }
-
- error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
- 0, DRV_NAME, pdev);
- if (error) {
- dev_err(&pdev->dev, "unable to claim irq %d\n",
- bf54x_kpad->irq);
- goto out2;
- }
-
- input = input_allocate_device();
- if (!input) {
- error = -ENOMEM;
- goto out3;
- }
-
- bf54x_kpad->input = input;
-
- input->name = pdev->name;
- input->phys = "bf54x-keys/input0";
- input->dev.parent = &pdev->dev;
-
- input->id.bustype = BUS_HOST;
- input->id.vendor = 0x0001;
- input->id.product = 0x0001;
- input->id.version = 0x0100;
-
- input->keycodesize = sizeof(unsigned short);
- input->keycodemax = pdata->keymapsize;
- input->keycode = bf54x_kpad->keycode;
-
- bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize);
-
- /* setup input device */
- __set_bit(EV_KEY, input->evbit);
-
- if (pdata->repeat)
- __set_bit(EV_REP, input->evbit);
-
- for (i = 0; i < input->keycodemax; i++)
- if (bf54x_kpad->keycode[i] <= KEY_MAX)
- __set_bit(bf54x_kpad->keycode[i], input->keybit);
- __clear_bit(KEY_RESERVED, input->keybit);
-
- error = input_register_device(input);
- if (error) {
- dev_err(&pdev->dev, "unable to register input device\n");
- goto out4;
- }
-
- /* Init Keypad Key Up/Release test timer */
-
- timer_setup(&bf54x_kpad->timer, bfin_kpad_timer, 0);
-
- bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
-
- bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) |
- (((pdata->rows - 1) << 10) & KPAD_ROWEN) |
- (2 & KPAD_IRQMODE));
-
- bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN);
-
- device_init_wakeup(&pdev->dev, 1);
-
- return 0;
-
-out4:
- input_free_device(input);
-out3:
- free_irq(bf54x_kpad->irq, pdev);
-out2:
- peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
-out1:
- peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
-out0:
- kfree(bf54x_kpad->keycode);
-out:
- kfree(bf54x_kpad);
-
- return error;
-}
-
-static int bfin_kpad_remove(struct platform_device *pdev)
-{
- struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
-
- del_timer_sync(&bf54x_kpad->timer);
- free_irq(bf54x_kpad->irq, pdev);
-
- input_unregister_device(bf54x_kpad->input);
-
- peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
- peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
-
- kfree(bf54x_kpad->keycode);
- kfree(bf54x_kpad);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int bfin_kpad_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
-
- bf54x_kpad->kpad_msel = bfin_read_KPAD_MSEL();
- bf54x_kpad->kpad_prescale = bfin_read_KPAD_PRESCALE();
- bf54x_kpad->kpad_ctl = bfin_read_KPAD_CTL();
-
- if (device_may_wakeup(&pdev->dev))
- enable_irq_wake(bf54x_kpad->irq);
-
- return 0;
-}
-
-static int bfin_kpad_resume(struct platform_device *pdev)
-{
- struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
-
- bfin_write_KPAD_MSEL(bf54x_kpad->kpad_msel);
- bfin_write_KPAD_PRESCALE(bf54x_kpad->kpad_prescale);
- bfin_write_KPAD_CTL(bf54x_kpad->kpad_ctl);
-
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(bf54x_kpad->irq);
-
- return 0;
-}
-#else
-# define bfin_kpad_suspend NULL
-# define bfin_kpad_resume NULL
-#endif
-
-static struct platform_driver bfin_kpad_device_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .probe = bfin_kpad_probe,
- .remove = bfin_kpad_remove,
- .suspend = bfin_kpad_suspend,
- .resume = bfin_kpad_resume,
-};
-module_platform_driver(bfin_kpad_device_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Keypad driver for BF54x Processors");
-MODULE_ALIAS("platform:bf54x-keys");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 87e613d..052e376 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
+#include <dt-bindings/input/gpio-keys.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
@@ -45,6 +46,7 @@ struct gpio_button_data {
unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
unsigned int irq;
+ unsigned int wakeup_trigger_type;
spinlock_t lock;
bool disabled;
bool key_pressed;
@@ -540,6 +542,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
}
if (bdata->gpiod) {
+ bool active_low = gpiod_is_active_low(bdata->gpiod);
+
if (button->debounce_interval) {
error = gpiod_set_debounce(bdata->gpiod,
button->debounce_interval * 1000);
@@ -568,6 +572,24 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
isr = gpio_keys_gpio_isr;
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+ switch (button->wakeup_event_action) {
+ case EV_ACT_ASSERTED:
+ bdata->wakeup_trigger_type = active_low ?
+ IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+ break;
+ case EV_ACT_DEASSERTED:
+ bdata->wakeup_trigger_type = active_low ?
+ IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
+ break;
+ case EV_ACT_ANY:
+ /* fall through */
+ default:
+ /*
+ * For other cases, we are OK letting suspend/resume
+ * not reconfigure the trigger type.
+ */
+ break;
+ }
} else {
if (!button->irq) {
dev_err(dev, "Found button without gpio or irq\n");
@@ -586,6 +608,11 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
isr = gpio_keys_irq_isr;
irqflags = 0;
+
+ /*
+ * For IRQ buttons, there is no interrupt for release.
+ * So we don't need to reconfigure the trigger type for wakeup.
+ */
}
bdata->code = &ddata->keymap[idx];
@@ -718,6 +745,9 @@ gpio_keys_get_devtree_pdata(struct device *dev)
/* legacy name */
fwnode_property_read_bool(child, "gpio-key,wakeup");
+ fwnode_property_read_u32(child, "wakeup-event-action",
+ &button->wakeup_event_action);
+
button->can_disable =
fwnode_property_read_bool(child, "linux,can-disable");
@@ -845,19 +875,112 @@ static int gpio_keys_probe(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused
+gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata)
+{
+ int error;
+
+ error = enable_irq_wake(bdata->irq);
+ if (error) {
+ dev_err(bdata->input->dev.parent,
+ "failed to configure IRQ %d as wakeup source: %d\n",
+ bdata->irq, error);
+ return error;
+ }
+
+ if (bdata->wakeup_trigger_type) {
+ error = irq_set_irq_type(bdata->irq,
+ bdata->wakeup_trigger_type);
+ if (error) {
+ dev_err(bdata->input->dev.parent,
+ "failed to set wakeup trigger %08x for IRQ %d: %d\n",
+ bdata->wakeup_trigger_type, bdata->irq, error);
+ disable_irq_wake(bdata->irq);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static void __maybe_unused
+gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata)
+{
+ int error;
+
+ /*
+ * The trigger type is always both edges for gpio-based keys and we do
+ * not support changing wakeup trigger for interrupt-based keys.
+ */
+ if (bdata->wakeup_trigger_type) {
+ error = irq_set_irq_type(bdata->irq, IRQ_TYPE_EDGE_BOTH);
+ if (error)
+ dev_warn(bdata->input->dev.parent,
+ "failed to restore interrupt trigger for IRQ %d: %d\n",
+ bdata->irq, error);
+ }
+
+ error = disable_irq_wake(bdata->irq);
+ if (error)
+ dev_warn(bdata->input->dev.parent,
+ "failed to disable IRQ %d as wake source: %d\n",
+ bdata->irq, error);
+}
+
+static int __maybe_unused
+gpio_keys_enable_wakeup(struct gpio_keys_drvdata *ddata)
+{
+ struct gpio_button_data *bdata;
+ int error;
+ int i;
+
+ for (i = 0; i < ddata->pdata->nbuttons; i++) {
+ bdata = &ddata->data[i];
+ if (bdata->button->wakeup) {
+ error = gpio_keys_button_enable_wakeup(bdata);
+ if (error)
+ goto err_out;
+ }
+ bdata->suspended = true;
+ }
+
+ return 0;
+
+err_out:
+ while (i--) {
+ bdata = &ddata->data[i];
+ if (bdata->button->wakeup)
+ gpio_keys_button_disable_wakeup(bdata);
+ bdata->suspended = false;
+ }
+
+ return error;
+}
+
+static void __maybe_unused
+gpio_keys_disable_wakeup(struct gpio_keys_drvdata *ddata)
+{
+ struct gpio_button_data *bdata;
+ int i;
+
+ for (i = 0; i < ddata->pdata->nbuttons; i++) {
+ bdata = &ddata->data[i];
+ bdata->suspended = false;
+ if (irqd_is_wakeup_set(irq_get_irq_data(bdata->irq)))
+ gpio_keys_button_disable_wakeup(bdata);
+ }
+}
+
static int __maybe_unused gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
- int i;
+ int error;
if (device_may_wakeup(dev)) {
- for (i = 0; i < ddata->pdata->nbuttons; i++) {
- struct gpio_button_data *bdata = &ddata->data[i];
- if (bdata->button->wakeup)
- enable_irq_wake(bdata->irq);
- bdata->suspended = true;
- }
+ error = gpio_keys_enable_wakeup(ddata);
+ if (error)
+ return error;
} else {
mutex_lock(&input->mutex);
if (input->users)
@@ -873,15 +996,9 @@ static int __maybe_unused gpio_keys_resume(struct device *dev)
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
int error = 0;
- int i;
if (device_may_wakeup(dev)) {
- for (i = 0; i < ddata->pdata->nbuttons; i++) {
- struct gpio_button_data *bdata = &ddata->data[i];
- if (bdata->button->wakeup)
- disable_irq_wake(bdata->irq);
- bdata->suspended = false;
- }
+ gpio_keys_disable_wakeup(ddata);
} else {
mutex_lock(&input->mutex);
if (input->users)
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 1f316d6..41614c1 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev)
{
struct matrix_keypad *keypad = input_get_drvdata(dev);
+ spin_lock_irq(&keypad->lock);
keypad->stopped = true;
- mb();
+ spin_unlock_irq(&keypad->lock);
+
flush_work(&keypad->work.work);
/*
* matrix_keypad_scan() will leave IRQs enabled;
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index 8c6c0b9..d69e631 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -48,6 +48,14 @@
#define STMPE_KEYPAD_KEYMAP_MAX_SIZE \
(STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
+
+#define STMPE1601_NUM_DATA 5
+#define STMPE2401_NUM_DATA 3
+#define STMPE2403_NUM_DATA 5
+
+/* Make sure it covers all cases above */
+#define MAX_NUM_DATA 5
+
/**
* struct stmpe_keypad_variant - model-specific attributes
* @auto_increment: whether the KPC_DATA_BYTE register address
@@ -74,7 +82,7 @@ struct stmpe_keypad_variant {
static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
[STMPE1601] = {
.auto_increment = true,
- .num_data = 5,
+ .num_data = STMPE1601_NUM_DATA,
.num_normal_data = 3,
.max_cols = 8,
.max_rows = 8,
@@ -84,7 +92,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
[STMPE2401] = {
.auto_increment = false,
.set_pullup = true,
- .num_data = 3,
+ .num_data = STMPE2401_NUM_DATA,
.num_normal_data = 2,
.max_cols = 8,
.max_rows = 12,
@@ -94,7 +102,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
[STMPE2403] = {
.auto_increment = true,
.set_pullup = true,
- .num_data = 5,
+ .num_data = STMPE2403_NUM_DATA,
.num_normal_data = 3,
.max_cols = 8,
.max_rows = 12,
@@ -156,7 +164,7 @@ static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
struct stmpe_keypad *keypad = dev;
struct input_dev *input = keypad->input;
const struct stmpe_keypad_variant *variant = keypad->variant;
- u8 fifo[variant->num_data];
+ u8 fifo[MAX_NUM_DATA];
int ret;
int i;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 62a1312..572b15f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -655,15 +655,6 @@ config INPUT_DM355EVM
To compile this driver as a module, choose M here: the
module will be called dm355evm_keys.
-config INPUT_BFIN_ROTARY
- tristate "Blackfin Rotary support"
- depends on BF54x || BF52x
- help
- Say Y here if you want to use the Blackfin Rotary.
-
- To compile this driver as a module, choose M here: the
- module will be called bfin-rotary.
-
config INPUT_WM831X_ON
tristate "WM831X ON pin"
depends on MFD_WM831X
@@ -841,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
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a8f61af..72cde28 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o
-obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_BMA150) += bma150.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
@@ -60,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/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
deleted file mode 100644
index 799ce3d..0000000
--- a/drivers/input/misc/bfin_rotary.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Rotary counter driver for Analog Devices Blackfin Processors
- *
- * Copyright 2008-2009 Analog Devices Inc.
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/pm.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/platform_data/bfin_rotary.h>
-
-#include <asm/portmux.h>
-
-#define CNT_CONFIG_OFF 0 /* CNT Config Offset */
-#define CNT_IMASK_OFF 4 /* CNT Interrupt Mask Offset */
-#define CNT_STATUS_OFF 8 /* CNT Status Offset */
-#define CNT_COMMAND_OFF 12 /* CNT Command Offset */
-#define CNT_DEBOUNCE_OFF 16 /* CNT Debounce Offset */
-#define CNT_COUNTER_OFF 20 /* CNT Counter Offset */
-#define CNT_MAX_OFF 24 /* CNT Maximum Count Offset */
-#define CNT_MIN_OFF 28 /* CNT Minimum Count Offset */
-
-struct bfin_rot {
- struct input_dev *input;
- void __iomem *base;
- int irq;
- unsigned int up_key;
- unsigned int down_key;
- unsigned int button_key;
- unsigned int rel_code;
-
- unsigned short mode;
- unsigned short debounce;
-
- unsigned short cnt_config;
- unsigned short cnt_imask;
- unsigned short cnt_debounce;
-};
-
-static void report_key_event(struct input_dev *input, int keycode)
-{
- /* simulate a press-n-release */
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
-}
-
-static void report_rotary_event(struct bfin_rot *rotary, int delta)
-{
- struct input_dev *input = rotary->input;
-
- if (rotary->up_key) {
- report_key_event(input,
- delta > 0 ? rotary->up_key : rotary->down_key);
- } else {
- input_report_rel(input, rotary->rel_code, delta);
- input_sync(input);
- }
-}
-
-static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
-{
- struct bfin_rot *rotary = dev_id;
- int delta;
-
- switch (readw(rotary->base + CNT_STATUS_OFF)) {
-
- case ICII:
- break;
-
- case UCII:
- case DCII:
- delta = readl(rotary->base + CNT_COUNTER_OFF);
- if (delta)
- report_rotary_event(rotary, delta);
- break;
-
- case CZMII:
- report_key_event(rotary->input, rotary->button_key);
- break;
-
- default:
- break;
- }
-
- writew(W1LCNT_ZERO, rotary->base + CNT_COMMAND_OFF); /* Clear COUNTER */
- writew(-1, rotary->base + CNT_STATUS_OFF); /* Clear STATUS */
-
- return IRQ_HANDLED;
-}
-
-static int bfin_rotary_open(struct input_dev *input)
-{
- struct bfin_rot *rotary = input_get_drvdata(input);
- unsigned short val;
-
- if (rotary->mode & ROT_DEBE)
- writew(rotary->debounce & DPRESCALE,
- rotary->base + CNT_DEBOUNCE_OFF);
-
- writew(rotary->mode & ~CNTE, rotary->base + CNT_CONFIG_OFF);
-
- val = UCIE | DCIE;
- if (rotary->button_key)
- val |= CZMIE;
- writew(val, rotary->base + CNT_IMASK_OFF);
-
- writew(rotary->mode | CNTE, rotary->base + CNT_CONFIG_OFF);
-
- return 0;
-}
-
-static void bfin_rotary_close(struct input_dev *input)
-{
- struct bfin_rot *rotary = input_get_drvdata(input);
-
- writew(0, rotary->base + CNT_CONFIG_OFF);
- writew(0, rotary->base + CNT_IMASK_OFF);
-}
-
-static void bfin_rotary_free_action(void *data)
-{
- peripheral_free_list(data);
-}
-
-static int bfin_rotary_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- const struct bfin_rotary_platform_data *pdata = dev_get_platdata(dev);
- struct bfin_rot *rotary;
- struct resource *res;
- struct input_dev *input;
- int error;
-
- /* Basic validation */
- if ((pdata->rotary_up_key && !pdata->rotary_down_key) ||
- (!pdata->rotary_up_key && pdata->rotary_down_key)) {
- return -EINVAL;
- }
-
- if (pdata->pin_list) {
- error = peripheral_request_list(pdata->pin_list,
- dev_name(dev));
- if (error) {
- dev_err(dev, "requesting peripherals failed: %d\n",
- error);
- return error;
- }
-
- error = devm_add_action_or_reset(dev, bfin_rotary_free_action,
- pdata->pin_list);
- if (error) {
- dev_err(dev, "setting cleanup action failed: %d\n",
- error);
- return error;
- }
- }
-
- rotary = devm_kzalloc(dev, sizeof(struct bfin_rot), GFP_KERNEL);
- if (!rotary)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rotary->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(rotary->base))
- return PTR_ERR(rotary->base);
-
- input = devm_input_allocate_device(dev);
- if (!input)
- return -ENOMEM;
-
- rotary->input = input;
-
- rotary->up_key = pdata->rotary_up_key;
- rotary->down_key = pdata->rotary_down_key;
- rotary->button_key = pdata->rotary_button_key;
- rotary->rel_code = pdata->rotary_rel_code;
-
- rotary->mode = pdata->mode;
- rotary->debounce = pdata->debounce;
-
- input->name = pdev->name;
- input->phys = "bfin-rotary/input0";
- input->dev.parent = dev;
-
- input_set_drvdata(input, rotary);
-
- input->id.bustype = BUS_HOST;
- input->id.vendor = 0x0001;
- input->id.product = 0x0001;
- input->id.version = 0x0100;
-
- input->open = bfin_rotary_open;
- input->close = bfin_rotary_close;
-
- if (rotary->up_key) {
- __set_bit(EV_KEY, input->evbit);
- __set_bit(rotary->up_key, input->keybit);
- __set_bit(rotary->down_key, input->keybit);
- } else {
- __set_bit(EV_REL, input->evbit);
- __set_bit(rotary->rel_code, input->relbit);
- }
-
- if (rotary->button_key) {
- __set_bit(EV_KEY, input->evbit);
- __set_bit(rotary->button_key, input->keybit);
- }
-
- /* Quiesce the device before requesting irq */
- bfin_rotary_close(input);
-
- rotary->irq = platform_get_irq(pdev, 0);
- if (rotary->irq < 0) {
- dev_err(dev, "No rotary IRQ specified\n");
- return -ENOENT;
- }
-
- error = devm_request_irq(dev, rotary->irq, bfin_rotary_isr,
- 0, dev_name(dev), rotary);
- if (error) {
- dev_err(dev, "unable to claim irq %d; error %d\n",
- rotary->irq, error);
- return error;
- }
-
- error = input_register_device(input);
- if (error) {
- dev_err(dev, "unable to register input device (%d)\n", error);
- return error;
- }
-
- platform_set_drvdata(pdev, rotary);
- device_init_wakeup(dev, 1);
-
- return 0;
-}
-
-static int __maybe_unused bfin_rotary_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
-
- rotary->cnt_config = readw(rotary->base + CNT_CONFIG_OFF);
- rotary->cnt_imask = readw(rotary->base + CNT_IMASK_OFF);
- rotary->cnt_debounce = readw(rotary->base + CNT_DEBOUNCE_OFF);
-
- if (device_may_wakeup(&pdev->dev))
- enable_irq_wake(rotary->irq);
-
- return 0;
-}
-
-static int __maybe_unused bfin_rotary_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
-
- writew(rotary->cnt_debounce, rotary->base + CNT_DEBOUNCE_OFF);
- writew(rotary->cnt_imask, rotary->base + CNT_IMASK_OFF);
- writew(rotary->cnt_config & ~CNTE, rotary->base + CNT_CONFIG_OFF);
-
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(rotary->irq);
-
- if (rotary->cnt_config & CNTE)
- writew(rotary->cnt_config, rotary->base + CNT_CONFIG_OFF);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(bfin_rotary_pm_ops,
- bfin_rotary_suspend, bfin_rotary_resume);
-
-static struct platform_driver bfin_rotary_device_driver = {
- .probe = bfin_rotary_probe,
- .driver = {
- .name = "bfin-rotary",
- .pm = &bfin_rotary_pm_ops,
- },
-};
-module_platform_driver(bfin_rotary_device_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
-MODULE_ALIAS("platform:bfin-rotary");
diff --git a/drivers/input/misc/rave-sp-pwrbutton.c b/drivers/input/misc/rave-sp-pwrbutton.c
new file mode 100644
index 0000000..bcab3cd
--- /dev/null
+++ b/drivers/input/misc/rave-sp-pwrbutton.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Power Button driver for RAVE SP
+//
+// Copyright (C) 2017 Zodiac Inflight Innovations
+//
+//
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/rave-sp.h>
+#include <linux/platform_device.h>
+
+#define RAVE_SP_EVNT_BUTTON_PRESS (RAVE_SP_EVNT_BASE + 0x00)
+
+struct rave_sp_power_button {
+ struct input_dev *idev;
+ struct notifier_block nb;
+};
+
+static int rave_sp_power_button_event(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct rave_sp_power_button *pb =
+ container_of(nb, struct rave_sp_power_button, nb);
+ const u8 event = rave_sp_action_unpack_event(action);
+ const u8 value = rave_sp_action_unpack_value(action);
+ struct input_dev *idev = pb->idev;
+
+ if (event == RAVE_SP_EVNT_BUTTON_PRESS) {
+ input_report_key(idev, KEY_POWER, value);
+ input_sync(idev);
+
+ return NOTIFY_STOP;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int rave_sp_pwrbutton_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rave_sp_power_button *pb;
+ struct input_dev *idev;
+ int error;
+
+ pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
+ if (!pb)
+ return -ENOMEM;
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev)
+ return -ENOMEM;
+
+ idev->name = pdev->name;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ error = input_register_device(idev);
+ if (error)
+ return error;
+
+ pb->idev = idev;
+ pb->nb.notifier_call = rave_sp_power_button_event;
+ pb->nb.priority = 128;
+
+ error = devm_rave_sp_register_event_notifier(dev, &pb->nb);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static const struct of_device_id rave_sp_pwrbutton_of_match[] = {
+ { .compatible = "zii,rave-sp-pwrbutton" },
+ {}
+};
+
+static struct platform_driver rave_sp_pwrbutton_driver = {
+ .probe = rave_sp_pwrbutton_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = rave_sp_pwrbutton_of_match,
+ },
+};
+module_platform_driver(rave_sp_pwrbutton_driver);
+
+MODULE_DEVICE_TABLE(of, rave_sp_pwrbutton_of_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
+MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("RAVE SP Power Button driver");
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index dbe57da..0a67f23 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -139,11 +139,11 @@ static const struct alps_model_info alps_model_data[] = {
};
static const struct alps_protocol_info alps_v3_protocol_data = {
- ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT
+ ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
};
static const struct alps_protocol_info alps_v3_rushmore_data = {
- ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT
+ ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
};
static const struct alps_protocol_info alps_v4_protocol_data = {
@@ -155,7 +155,7 @@ static const struct alps_protocol_info alps_v5_protocol_data = {
};
static const struct alps_protocol_info alps_v7_protocol_data = {
- ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
+ ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
};
static const struct alps_protocol_info alps_v8_protocol_data = {
@@ -583,7 +583,7 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
- z = (packet[4] & 0x7c) >> 2;
+ z = packet[4] & 0x7c;
/*
* The x and y values tend to be quite large, and when used
@@ -595,6 +595,7 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
input_report_rel(dev, REL_X, x);
input_report_rel(dev, REL_Y, -y);
+ input_report_abs(dev, ABS_PRESSURE, z);
/*
* Most ALPS models report the trackstick buttons in the touchpad
@@ -827,7 +828,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
- int x, y, z, left, right, middle;
+ int x, y, z;
/*
* We can use Byte5 to distinguish if the packet is from Touchpad
@@ -847,9 +848,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
x = packet[1] | ((packet[3] & 0x20) << 2);
y = packet[2] | ((packet[3] & 0x40) << 1);
z = packet[4];
- left = packet[3] & 0x01;
- right = packet[3] & 0x02;
- middle = packet[3] & 0x04;
/* To prevent the cursor jump when finger lifted */
if (x == 0x7F && y == 0x7F && z == 0x7F)
@@ -859,9 +857,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
input_report_rel(dev2, REL_X, (char)x / 4);
input_report_rel(dev2, REL_Y, -((char)y / 4));
- input_report_key(dev2, BTN_LEFT, left);
- input_report_key(dev2, BTN_RIGHT, right);
- input_report_key(dev2, BTN_MIDDLE, middle);
+ psmouse_report_standard_buttons(dev2, packet[3]);
input_sync(dev2);
return;
@@ -871,8 +867,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
x = packet[1] | ((packet[3] & 0x78) << 4);
y = packet[2] | ((packet[4] & 0x78) << 4);
z = packet[5];
- left = packet[3] & 0x01;
- right = packet[3] & 0x02;
if (z > 30)
input_report_key(dev, BTN_TOUCH, 1);
@@ -888,8 +882,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
/* v6 touchpad does not have middle button */
- input_report_key(dev, BTN_LEFT, left);
- input_report_key(dev, BTN_RIGHT, right);
+ packet[3] &= ~BIT(2);
+ psmouse_report_standard_buttons(dev2, packet[3]);
input_sync(dev);
}
@@ -1098,7 +1092,7 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev2 = priv->dev2;
- int x, y, z, left, right, middle;
+ int x, y, z;
/* It should be a DualPoint when received trackstick packet */
if (!(priv->flags & ALPS_DUALPOINT)) {
@@ -1112,16 +1106,11 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
((packet[3] & 0x20) << 1);
z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
- left = (packet[1] & 0x01);
- right = (packet[1] & 0x02) >> 1;
- middle = (packet[1] & 0x04) >> 2;
-
input_report_rel(dev2, REL_X, (char)x);
input_report_rel(dev2, REL_Y, -((char)y));
+ input_report_abs(dev2, ABS_PRESSURE, z);
- input_report_key(dev2, BTN_LEFT, left);
- input_report_key(dev2, BTN_RIGHT, right);
- input_report_key(dev2, BTN_MIDDLE, middle);
+ psmouse_report_standard_buttons(dev2, packet[1]);
input_sync(dev2);
}
@@ -1503,10 +1492,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
alps_report_buttons(dev, dev2,
packet[0] & 1, packet[0] & 2, packet[0] & 4);
- input_report_rel(dev, REL_X,
- packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
- input_report_rel(dev, REL_Y,
- packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
+ psmouse_report_standard_motion(dev, packet);
input_sync(dev);
}
@@ -2544,13 +2530,31 @@ static int alps_update_btn_info_ss4_v2(unsigned char otp[][4],
}
static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
- struct alps_data *priv)
+ struct alps_data *priv,
+ struct psmouse *psmouse)
{
bool is_dual = false;
+ int reg_val = 0;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
- if (IS_SS4PLUS_DEV(priv->dev_id))
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
is_dual = (otp[0][0] >> 4) & 0x01;
+ if (!is_dual) {
+ /* For support TrackStick of Thinkpad L/E series */
+ if (alps_exit_command_mode(psmouse) == 0 &&
+ alps_enter_command_mode(psmouse) == 0) {
+ reg_val = alps_command_mode_read_reg(psmouse,
+ 0xD7);
+ }
+ alps_exit_command_mode(psmouse);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+ if (reg_val == 0x0C || reg_val == 0x1D)
+ is_dual = true;
+ }
+ }
+
if (is_dual)
priv->flags |= ALPS_DUALPOINT |
ALPS_DUALPOINT_WITH_PRESSURE;
@@ -2573,7 +2577,7 @@ static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
alps_update_btn_info_ss4_v2(otp, priv);
- alps_update_dual_info_ss4_v2(otp, priv);
+ alps_update_dual_info_ss4_v2(otp, priv, psmouse);
return 0;
}
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 81a695d..032d279 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -587,7 +587,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
/* Perform size detection, if not done already */
if (unlikely(!dev->size_detect_done)) {
atp_detect_size(dev);
- dev->size_detect_done = 1;
+ dev->size_detect_done = true;
goto exit;
}
}
@@ -813,7 +813,7 @@ static int atp_open(struct input_dev *input)
if (usb_submit_urb(dev->urb, GFP_ATOMIC))
return -EIO;
- dev->open = 1;
+ dev->open = true;
return 0;
}
@@ -823,7 +823,7 @@ static void atp_close(struct input_dev *input)
usb_kill_urb(dev->urb);
cancel_work_sync(&dev->work);
- dev->open = 0;
+ dev->open = false;
}
static int atp_handle_geyser(struct atp *dev)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index a4aaa74..db47a5e 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -35,7 +35,7 @@
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
unsigned char *param)
{
- if (psmouse_sliced_command(psmouse, c) ||
+ if (ps2_sliced_command(&psmouse->ps2dev, c) ||
ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c);
return -1;
@@ -107,8 +107,8 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
switch (etd->hw_version) {
case 1:
- if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) ||
- psmouse_sliced_command(psmouse, reg) ||
+ if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) ||
+ ps2_sliced_command(&psmouse->ps2dev, reg) ||
ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
rc = -1;
}
@@ -162,9 +162,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
switch (etd->hw_version) {
case 1:
- if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) ||
- psmouse_sliced_command(psmouse, reg) ||
- psmouse_sliced_command(psmouse, val) ||
+ if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) ||
+ ps2_sliced_command(&psmouse->ps2dev, reg) ||
+ ps2_sliced_command(&psmouse->ps2dev, val) ||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) {
rc = -1;
}
@@ -279,8 +279,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+ psmouse_report_standard_buttons(dev, packet[0]);
if (etd->fw_version < 0x020000 &&
(etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
@@ -390,8 +390,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ psmouse_report_standard_buttons(dev, packet[0]);
if (etd->reports_pressure) {
input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width);
@@ -434,9 +433,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
x = packet[4] - (int)((packet[1]^0x80) << 1);
y = (int)((packet[2]^0x80) << 1) - packet[5];
- input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
- input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
+ psmouse_report_standard_buttons(tp_dev, packet[0]);
input_report_rel(tp_dev, REL_X, x);
input_report_rel(tp_dev, REL_Y, y);
@@ -526,12 +523,10 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->fw_version & 0x001000) {
+ if (etd->fw_version & 0x001000)
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
- } else {
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
- }
+ else
+ psmouse_report_standard_buttons(dev, packet[0]);
input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width);
@@ -546,13 +541,10 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->fw_version & 0x001000) {
+ if (etd->fw_version & 0x001000)
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
- } else {
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
- input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04);
- }
+ else
+ psmouse_report_standard_buttons(dev, packet[0]);
input_mt_report_pointer_emulation(dev, true);
input_sync(dev);
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 13d324c..a5765f7 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -17,6 +17,7 @@
#include <linux/libps2.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/types.h>
#include "psmouse.h"
#include "lifebook.h"
@@ -136,7 +137,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
struct lifebook_data *priv = psmouse->private;
struct input_dev *dev1 = psmouse->dev;
struct input_dev *dev2 = priv ? priv->dev2 : NULL;
- unsigned char *packet = psmouse->packet;
+ u8 *packet = psmouse->packet;
bool relative_packet = packet[0] & 0x08;
if (relative_packet || !lifebook_use_6byte_proto) {
@@ -188,14 +189,10 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
}
if (dev2) {
- if (relative_packet) {
- input_report_rel(dev2, REL_X,
- ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
- input_report_rel(dev2, REL_Y,
- -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
- }
- input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
+ if (relative_packet)
+ psmouse_report_standard_motion(dev2, packet);
+
+ psmouse_report_standard_buttons(dev2, packet[0]);
input_sync(dev2);
}
@@ -205,10 +202,12 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
static int lifebook_absolute_mode(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param;
+ u8 param;
+ int error;
- if (psmouse_reset(psmouse))
- return -1;
+ error = psmouse_reset(psmouse);
+ if (error)
+ return error;
/*
* Enable absolute output -- ps2_command fails always but if
@@ -224,15 +223,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
static void lifebook_relative_mode(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param = 0x06;
+ u8 param = 0x06;
ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
}
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
- static const unsigned char params[] = { 0, 1, 2, 2, 3 };
- unsigned char p;
+ static const u8 params[] = { 0, 1, 2, 2, 3 };
+ u8 p;
if (resolution == 0 || resolution > 400)
resolution = 400;
@@ -257,11 +256,11 @@ static void lifebook_disconnect(struct psmouse *psmouse)
int lifebook_detect(struct psmouse *psmouse, bool set_properties)
{
if (!lifebook_present)
- return -1;
+ return -ENXIO;
if (desired_serio_phys &&
strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
- return -1;
+ return -ENXIO;
if (set_properties) {
psmouse->vendor = "Fujitsu";
@@ -294,10 +293,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
dev2->id.version = 0x0000;
dev2->dev.parent = &psmouse->ps2dev.serio->dev;
- dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- dev2->keybit[BIT_WORD(BTN_LEFT)] =
- BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+ input_set_capability(dev2, EV_REL, REL_X);
+ input_set_capability(dev2, EV_REL, REL_Y);
+ input_set_capability(dev2, EV_KEY, BTN_LEFT);
+ input_set_capability(dev2, EV_KEY, BTN_RIGHT);
error = input_register_device(priv->dev2);
if (error)
@@ -316,21 +315,26 @@ int lifebook_init(struct psmouse *psmouse)
{
struct input_dev *dev1 = psmouse->dev;
int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
+ int error;
+
+ error = lifebook_absolute_mode(psmouse);
+ if (error)
+ return error;
- if (lifebook_absolute_mode(psmouse))
- return -1;
+ /* Clear default capabilities */
+ bitmap_zero(dev1->evbit, EV_CNT);
+ bitmap_zero(dev1->relbit, REL_CNT);
+ bitmap_zero(dev1->keybit, KEY_CNT);
- dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
- dev1->relbit[0] = 0;
- dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
- dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_capability(dev1, EV_KEY, BTN_TOUCH);
input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
if (!desired_serio_phys) {
- if (lifebook_create_relative_device(psmouse)) {
+ error = lifebook_create_relative_device(psmouse);
+ if (error) {
lifebook_relative_mode(psmouse);
- return -1;
+ return error;
}
}
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index ef9c97f..3d5637e 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -9,9 +9,11 @@
* the Free Software Foundation.
*/
+#include <linux/bitops.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/libps2.h>
+#include <linux/types.h>
#include "psmouse.h"
#include "logips2pp.h"
@@ -22,12 +24,12 @@
#define PS2PP_KIND_TRACKMAN 4
/* Logitech mouse features */
-#define PS2PP_WHEEL 0x01
-#define PS2PP_HWHEEL 0x02
-#define PS2PP_SIDE_BTN 0x04
-#define PS2PP_EXTRA_BTN 0x08
-#define PS2PP_TASK_BTN 0x10
-#define PS2PP_NAV_BTN 0x20
+#define PS2PP_WHEEL BIT(0)
+#define PS2PP_HWHEEL BIT(1)
+#define PS2PP_SIDE_BTN BIT(2)
+#define PS2PP_EXTRA_BTN BIT(3)
+#define PS2PP_TASK_BTN BIT(4)
+#define PS2PP_NAV_BTN BIT(5)
struct ps2pp_info {
u8 model;
@@ -42,7 +44,7 @@ struct ps2pp_info {
static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
- unsigned char *packet = psmouse->packet;
+ u8 *packet = psmouse->packet;
if (psmouse->pktcnt < 3)
return PSMOUSE_GOOD_DATA;
@@ -58,28 +60,30 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
case 0x0d: /* Mouse extra info */
- input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
- (int) (packet[2] & 8) - (int) (packet[2] & 7));
- input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
+ input_report_rel(dev,
+ packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
+ -sign_extend32(packet[2], 3));
+ input_report_key(dev, BTN_SIDE, packet[2] & BIT(4));
+ input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
break;
case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
- input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
- input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
- input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
- input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
+ input_report_key(dev, BTN_SIDE, packet[2] & BIT(0));
+ input_report_key(dev, BTN_EXTRA, packet[2] & BIT(1));
+ input_report_key(dev, BTN_TASK, packet[2] & BIT(2));
+ input_report_key(dev, BTN_BACK, packet[2] & BIT(3));
+ input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
break;
case 0x0f: /* TouchPad extra info */
- input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
- (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
- packet[0] = packet[2] | 0x08;
+ input_report_rel(dev,
+ packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
+ -sign_extend32(packet[2] >> 4, 3));
+ packet[0] = packet[2] | BIT(3);
break;
default:
@@ -88,16 +92,14 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
(packet[1] >> 4) | (packet[0] & 0x30));
break;
}
+
+ psmouse_report_standard_buttons(dev, packet[0]);
+
} else {
/* Standard PS/2 motion data */
- input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
- input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+ psmouse_report_standard_packet(dev, packet);
}
- input_report_key(dev, BTN_LEFT, packet[0] & 1);
- input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
- input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
-
input_sync(dev);
return PSMOUSE_FULL_PACKET;
@@ -111,13 +113,17 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
* Ugly.
*/
-static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
+static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
{
- if (psmouse_sliced_command(psmouse, command))
- return -1;
+ int error;
- if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
- return -1;
+ error = ps2_sliced_command(&psmouse->ps2dev, command);
+ if (error)
+ return error;
+
+ error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
+ if (error)
+ return error;
return 0;
}
@@ -133,7 +139,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[4];
+ u8 param[4];
ps2pp_cmd(psmouse, param, 0x32);
@@ -171,7 +177,7 @@ static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
}
PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
- ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
+ ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
/*
* Support 800 dpi resolution _only_ if the user wants it (there are good
@@ -179,11 +185,12 @@ PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
* also good reasons to use it, let the user decide).
*/
-static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+static void ps2pp_set_resolution(struct psmouse *psmouse,
+ unsigned int resolution)
{
if (resolution > 400) {
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param = 3;
+ u8 param = 3;
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
@@ -196,7 +203,8 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
static void ps2pp_disconnect(struct psmouse *psmouse)
{
- device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_smartscroll.dattr);
}
static const struct ps2pp_info *get_model_info(unsigned char model)
@@ -269,24 +277,24 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
struct input_dev *input_dev = psmouse->dev;
if (model_info->features & PS2PP_SIDE_BTN)
- __set_bit(BTN_SIDE, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, BTN_SIDE);
if (model_info->features & PS2PP_EXTRA_BTN)
- __set_bit(BTN_EXTRA, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
if (model_info->features & PS2PP_TASK_BTN)
- __set_bit(BTN_TASK, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, BTN_TASK);
if (model_info->features & PS2PP_NAV_BTN) {
- __set_bit(BTN_FORWARD, input_dev->keybit);
- __set_bit(BTN_BACK, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
+ input_set_capability(input_dev, EV_KEY, BTN_BACK);
}
if (model_info->features & PS2PP_WHEEL)
- __set_bit(REL_WHEEL, input_dev->relbit);
+ input_set_capability(input_dev, EV_REL, REL_WHEEL);
if (model_info->features & PS2PP_HWHEEL)
- __set_bit(REL_HWHEEL, input_dev->relbit);
+ input_set_capability(input_dev, EV_REL, REL_HWHEEL);
switch (model_info->kind) {
@@ -318,6 +326,30 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
}
}
+static int ps2pp_setup_protocol(struct psmouse *psmouse,
+ const struct ps2pp_info *model_info)
+{
+ int error;
+
+ psmouse->protocol_handler = ps2pp_process_byte;
+ psmouse->pktsize = 3;
+
+ if (model_info->kind != PS2PP_KIND_TP3) {
+ psmouse->set_resolution = ps2pp_set_resolution;
+ psmouse->disconnect = ps2pp_disconnect;
+
+ error = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_smartscroll.dattr);
+ if (error) {
+ psmouse_err(psmouse,
+ "failed to create smartscroll sysfs attribute, error: %d\n",
+ error);
+ return error;
+ }
+ }
+
+ return 0;
+}
/*
* Logitech magic init. Detect whether the mouse is a Logitech one
@@ -328,9 +360,9 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[4];
- unsigned char model, buttons;
const struct ps2pp_info *model_info;
+ u8 param[4];
+ u8 model, buttons;
bool use_ps2pp = false;
int error;
@@ -346,7 +378,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
buttons = param[1];
if (!model || !buttons)
- return -1;
+ return -ENXIO;
model_info = get_model_info(model);
if (model_info) {
@@ -368,7 +400,8 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
param[0] = 0;
if (!ps2_command(ps2dev, param, 0x13d1) &&
- param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
+ param[0] == 0x06 && param[1] == 0x00 &&
+ param[2] == 0x14) {
use_ps2pp = true;
}
@@ -387,7 +420,9 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
}
} else {
- psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model);
+ psmouse_warn(psmouse,
+ "Detected unknown Logitech mouse model %d\n",
+ model);
}
if (set_properties) {
@@ -395,31 +430,18 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
psmouse->model = model;
if (use_ps2pp) {
- psmouse->protocol_handler = ps2pp_process_byte;
- psmouse->pktsize = 3;
-
- if (model_info->kind != PS2PP_KIND_TP3) {
- psmouse->set_resolution = ps2pp_set_resolution;
- psmouse->disconnect = ps2pp_disconnect;
-
- error = device_create_file(&ps2dev->serio->dev,
- &psmouse_attr_smartscroll.dattr);
- if (error) {
- psmouse_err(psmouse,
- "failed to create smartscroll sysfs attribute, error: %d\n",
- error);
- return -1;
- }
- }
+ error = ps2pp_setup_protocol(psmouse, model_info);
+ if (error)
+ return error;
}
if (buttons >= 3)
- __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
if (model_info)
ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
}
- return use_ps2pp ? 0 : -1;
+ return use_ps2pp ? 0 : -ENXIO;
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 8ac9e03..8900c31 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define psmouse_fmt(fmt) fmt
+#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -23,6 +24,7 @@
#include <linux/init.h>
#include <linux/libps2.h>
#include <linux/mutex.h>
+#include <linux/types.h>
#include "psmouse.h"
#include "synaptics.h"
@@ -68,6 +70,10 @@ static bool psmouse_smartscroll = true;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
+static bool psmouse_a4tech_2wheels;
+module_param_named(a4tech_workaround, psmouse_a4tech_2wheels, bool, 0644);
+MODULE_PARM_DESC(a4tech_workaround, "A4Tech second scroll wheel workaround, 1 = enabled, 0 = disabled (default).");
+
static unsigned int psmouse_resetafter = 5;
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
@@ -116,13 +122,30 @@ static DEFINE_MUTEX(psmouse_mutex);
static struct workqueue_struct *kpsmoused_wq;
-static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
+void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
{
input_report_key(dev, BTN_LEFT, buttons & BIT(0));
input_report_key(dev, BTN_MIDDLE, buttons & BIT(2));
input_report_key(dev, BTN_RIGHT, buttons & BIT(1));
}
+void psmouse_report_standard_motion(struct input_dev *dev, u8 *packet)
+{
+ int x, y;
+
+ x = packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0;
+ y = packet[2] ? packet[2] - ((packet[0] << 3) & 0x100) : 0;
+
+ input_report_rel(dev, REL_X, x);
+ input_report_rel(dev, REL_Y, -y);
+}
+
+void psmouse_report_standard_packet(struct input_dev *dev, u8 *packet)
+{
+ psmouse_report_standard_buttons(dev, packet[0]);
+ psmouse_report_standard_motion(dev, packet);
+}
+
/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
* relevant events to the input module once full packet has arrived.
@@ -130,7 +153,8 @@ static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
- unsigned char *packet = psmouse->packet;
+ u8 *packet = psmouse->packet;
+ int wheel;
if (psmouse->pktcnt < psmouse->pktsize)
return PSMOUSE_GOOD_DATA;
@@ -140,39 +164,52 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
switch (psmouse->protocol->type) {
case PSMOUSE_IMPS:
/* IntelliMouse has scroll wheel */
- input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
+ input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
break;
case PSMOUSE_IMEX:
/* Scroll wheel and buttons on IntelliMouse Explorer */
switch (packet[3] & 0xC0) {
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
- input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ input_report_rel(dev, REL_WHEEL,
+ -sign_extend32(packet[3], 5));
break;
case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
- input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ input_report_rel(dev, REL_HWHEEL,
+ -sign_extend32(packet[3], 5));
break;
case 0x00:
case 0xC0:
- input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
- input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+ wheel = sign_extend32(packet[3], 3);
+
+ /*
+ * Some A4Tech mice have two scroll wheels, with first
+ * one reporting +/-1 in the lower nibble, and second
+ * one reporting +/-2.
+ */
+ if (psmouse_a4tech_2wheels && abs(wheel) > 1)
+ input_report_rel(dev, REL_HWHEEL, wheel / 2);
+ else
+ input_report_rel(dev, REL_WHEEL, -wheel);
+
+ input_report_key(dev, BTN_SIDE, BIT(4));
+ input_report_key(dev, BTN_EXTRA, BIT(5));
break;
}
break;
case PSMOUSE_GENPS:
/* Report scroll buttons on NetMice */
- input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
+ input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
/* Extra buttons on Genius NewNet 3D */
- input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
+ input_report_key(dev, BTN_SIDE, BIT(6));
+ input_report_key(dev, BTN_EXTRA, BIT(7));
break;
case PSMOUSE_THINKPS:
/* Extra button on ThinkingMouse */
- input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
+ input_report_key(dev, BTN_EXTRA, BIT(3));
/*
* Without this bit of weirdness moving up gives wildly
@@ -186,8 +223,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
* Cortron PS2 Trackball reports SIDE button in the
* 4th bit of the first byte.
*/
- input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
- packet[0] |= 0x08;
+ input_report_key(dev, BTN_SIDE, BIT(3));
+ packet[0] |= BIT(3);
break;
default:
@@ -195,11 +232,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
}
/* Generic PS/2 Mouse */
- psmouse_report_standard_buttons(dev,
- packet[0] | psmouse->extra_buttons);
-
- input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
- input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+ packet[0] |= psmouse->extra_buttons;
+ psmouse_report_standard_packet(dev, packet);
input_sync(dev);
@@ -255,7 +289,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
psmouse_notice(psmouse,
"issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
- return -1;
+ return -EIO;
}
}
psmouse->pktcnt = 0;
@@ -306,7 +340,7 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
* for normal processing or gathering them as command response.
*/
static irqreturn_t psmouse_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags)
+ u8 data, unsigned int flags)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
@@ -398,40 +432,19 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
/*
- * 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);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 8cd4538..71ac500 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -131,7 +131,6 @@ struct psmouse {
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
unsigned long delay);
-int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
@@ -140,6 +139,10 @@ int psmouse_activate(struct psmouse *psmouse);
int psmouse_deactivate(struct psmouse *psmouse);
bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]);
+void psmouse_report_standard_buttons(struct input_dev *, u8 buttons);
+void psmouse_report_standard_motion(struct input_dev *, u8 *packet);
+void psmouse_report_standard_packet(struct input_dev *, u8 *packet);
+
struct psmouse_attribute {
struct device_attribute dattr;
void *data;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 11c32ac..1d6010d 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -710,7 +710,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
unsigned char button_status = 0, lscroll = 0, rscroll = 0;
unsigned short abs_x, abs_y, fgrs = 0;
- int rel_x, rel_y;
if (psmouse->pktcnt < 4)
return PSMOUSE_GOOD_DATA;
@@ -840,15 +839,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
/*
* Standard PS/2 Mouse
*/
- input_report_key(dev, BTN_LEFT, packet[0] & 1);
- input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
- input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
-
- rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
- rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
-
- input_report_rel(dev, REL_X, rel_x);
- input_report_rel(dev, REL_Y, rel_y);
+ psmouse_report_standard_packet(dev, packet);
break;
}
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 3d2e23a..60f2c46 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -84,7 +84,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
u8 param[1];
int error;
- error = psmouse_sliced_command(psmouse, mode);
+ error = ps2_sliced_command(&psmouse->ps2dev, mode);
if (error)
return error;
@@ -173,7 +173,6 @@ static const char * const smbus_pnp_ids[] = {
"LEN0046", /* X250 */
"LEN004a", /* W541 */
"LEN200f", /* T450s */
- "LEN2018", /* T460p */
NULL
};
@@ -190,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;
@@ -547,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;
@@ -614,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;
@@ -1228,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);
@@ -1265,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);
@@ -1277,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
@@ -1296,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,
@@ -1564,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
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
index cb7d15d..83d2412 100644
--- a/drivers/input/mouse/synaptics_usb.c
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -82,6 +82,10 @@ struct synusb {
struct urb *urb;
unsigned char *data;
+ /* serialize access to open/suspend */
+ struct mutex pm_mutex;
+ bool is_open;
+
/* input device related data structures */
struct input_dev *input;
char name[128];
@@ -252,6 +256,7 @@ static int synusb_open(struct input_dev *dev)
return retval;
}
+ mutex_lock(&synusb->pm_mutex);
retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
if (retval) {
dev_err(&synusb->intf->dev,
@@ -262,8 +267,10 @@ static int synusb_open(struct input_dev *dev)
}
synusb->intf->needs_remote_wakeup = 1;
+ synusb->is_open = true;
out:
+ mutex_unlock(&synusb->pm_mutex);
usb_autopm_put_interface(synusb->intf);
return retval;
}
@@ -275,8 +282,11 @@ static void synusb_close(struct input_dev *dev)
autopm_error = usb_autopm_get_interface(synusb->intf);
+ mutex_lock(&synusb->pm_mutex);
usb_kill_urb(synusb->urb);
synusb->intf->needs_remote_wakeup = 0;
+ synusb->is_open = false;
+ mutex_unlock(&synusb->pm_mutex);
if (!autopm_error)
usb_autopm_put_interface(synusb->intf);
@@ -315,6 +325,7 @@ static int synusb_probe(struct usb_interface *intf,
synusb->udev = udev;
synusb->intf = intf;
synusb->input = input_dev;
+ mutex_init(&synusb->pm_mutex);
synusb->flags = id->driver_info;
if (synusb->flags & SYNUSB_COMBO) {
@@ -466,11 +477,10 @@ static void synusb_disconnect(struct usb_interface *intf)
static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
{
struct synusb *synusb = usb_get_intfdata(intf);
- struct input_dev *input_dev = synusb->input;
- mutex_lock(&input_dev->mutex);
+ mutex_lock(&synusb->pm_mutex);
usb_kill_urb(synusb->urb);
- mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&synusb->pm_mutex);
return 0;
}
@@ -478,17 +488,16 @@ static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
static int synusb_resume(struct usb_interface *intf)
{
struct synusb *synusb = usb_get_intfdata(intf);
- struct input_dev *input_dev = synusb->input;
int retval = 0;
- mutex_lock(&input_dev->mutex);
+ mutex_lock(&synusb->pm_mutex);
- if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+ if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
retval = -EIO;
}
- mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&synusb->pm_mutex);
return retval;
}
@@ -496,9 +505,8 @@ static int synusb_resume(struct usb_interface *intf)
static int synusb_pre_reset(struct usb_interface *intf)
{
struct synusb *synusb = usb_get_intfdata(intf);
- struct input_dev *input_dev = synusb->input;
- mutex_lock(&input_dev->mutex);
+ mutex_lock(&synusb->pm_mutex);
usb_kill_urb(synusb->urb);
return 0;
@@ -507,15 +515,14 @@ static int synusb_pre_reset(struct usb_interface *intf)
static int synusb_post_reset(struct usb_interface *intf)
{
struct synusb *synusb = usb_get_intfdata(intf);
- struct input_dev *input_dev = synusb->input;
int retval = 0;
- if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+ if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
retval = -EIO;
}
- mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&synusb->pm_mutex);
return retval;
}
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index bbd2922..6590d10 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -33,18 +33,15 @@ static const char * const trackpoint_variants[] = {
*/
static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
{
- u8 results[2];
- int tries = 0;
+ u8 param[2] = { TP_POR };
+ int err;
- /* Issue POR command, and repeat up to once if 0xFC00 received */
- do {
- if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
- ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR)))
- return -1;
- } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2);
+ err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND));
+ if (err)
+ return err;
/* Check for success response -- 0xAA00 */
- if (results[0] != 0xAA || results[1] != 0x00)
+ if (param[0] != 0xAA || param[1] != 0x00)
return -ENODEV;
return 0;
@@ -55,49 +52,39 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
*/
static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results)
{
- if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
- ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
- return -1;
- }
+ results[0] = loc;
- return 0;
+ return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND));
}
static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
{
- if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
- return -1;
- }
+ u8 param[3] = { TP_WRITE_MEM, loc, val };
- return 0;
+ return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
}
static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
{
+ u8 param[3] = { TP_TOGGLE, loc, mask };
+
/* Bad things will happen if the loc param isn't in this range */
if (loc < 0x20 || loc >= 0x2F)
- return -1;
-
- if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
- ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
- return -1;
- }
+ return -EINVAL;
- return 0;
+ return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
}
static int trackpoint_update_bit(struct ps2dev *ps2dev,
u8 loc, u8 mask, u8 value)
{
- int retval = 0;
+ int retval;
u8 data;
- trackpoint_read(ps2dev, loc, &data);
+ retval = trackpoint_read(ps2dev, loc, &data);
+ if (retval)
+ return retval;
+
if (((data & mask) == mask) != !!value)
retval = trackpoint_toggle_bit(ps2dev, loc, mask);
@@ -142,9 +129,9 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
return err;
*field = value;
- trackpoint_write(&psmouse->ps2dev, attr->command, value);
+ err = trackpoint_write(&psmouse->ps2dev, attr->command, value);
- return count;
+ return err ?: count;
}
#define TRACKPOINT_INT_ATTR(_name, _command, _default) \
@@ -175,10 +162,11 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
if (*field != value) {
*field = value;
- trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
+ err = trackpoint_toggle_bit(&psmouse->ps2dev,
+ attr->command, attr->mask);
}
- return count;
+ return err ?: count;
}
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index aa9f29b..49d8d53 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -91,7 +91,7 @@ struct gscps2port {
struct parisc_device *padev;
struct serio *port;
spinlock_t lock;
- char *addr;
+ char __iomem *addr;
u8 act, append; /* position in buffer[] */
struct {
u8 data;
@@ -114,7 +114,7 @@ struct gscps2port {
* wait_TBE() - wait for Transmit Buffer Empty
*/
-static int wait_TBE(char *addr)
+static int wait_TBE(char __iomem *addr)
{
int timeout = 25000; /* device is expected to react within 250 msec */
while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
@@ -146,14 +146,14 @@ static void gscps2_flush(struct gscps2port *ps2port)
static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
{
unsigned long flags;
- char *addr = ps2port->addr;
+ char __iomem *addr = ps2port->addr;
if (!wait_TBE(addr)) {
printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data);
return 0;
}
- while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+ while (gscps2_readb_status(addr) & GSC_STAT_RBNE)
/* wait */;
spin_lock_irqsave(&ps2port->lock, flags);
@@ -200,13 +200,12 @@ static void gscps2_enable(struct gscps2port *ps2port, int enable)
static void gscps2_reset(struct gscps2port *ps2port)
{
- char *addr = ps2port->addr;
unsigned long flags;
/* reset the interface */
spin_lock_irqsave(&ps2port->lock, flags);
gscps2_flush(ps2port);
- writeb(0xff, addr+GSC_RESET);
+ writeb(0xff, ps2port->addr + GSC_RESET);
gscps2_flush(ps2port);
spin_unlock_irqrestore(&ps2port->lock, flags);
}
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 6cbbdc6..b353d49 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -530,6 +530,20 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
{ }
};
+static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
+ {
+ /*
+ * Sony Vaio VGN-CS series require MUX or the touch sensor
+ * buttons will disturb touchpad operation
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+ },
+ },
+ { }
+};
+
/*
* On some Asus laptops, just running self tests cause problems.
*/
@@ -621,6 +635,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
},
},
{
+ /* 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 = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
@@ -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;
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 83e9c66..e6a07e6 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -26,31 +26,79 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("PS/2 driver library");
MODULE_LICENSE("GPL");
+static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
+ unsigned int timeout, unsigned int max_attempts)
+ __releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock)
+{
+ int attempt = 0;
+ int error;
+
+ lockdep_assert_held(&ps2dev->serio->lock);
+
+ do {
+ ps2dev->nak = 1;
+ ps2dev->flags |= PS2_FLAG_ACK;
+
+ serio_continue_rx(ps2dev->serio);
+
+ error = serio_write(ps2dev->serio, byte);
+ if (error)
+ dev_dbg(&ps2dev->serio->dev,
+ "failed to write %#02x: %d\n", byte, error);
+ else
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_ACK),
+ msecs_to_jiffies(timeout));
+
+ serio_pause_rx(ps2dev->serio);
+ } while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts);
+
+ ps2dev->flags &= ~PS2_FLAG_ACK;
+
+ if (!error) {
+ switch (ps2dev->nak) {
+ case 0:
+ break;
+ case PS2_RET_NAK:
+ error = -EAGAIN;
+ break;
+ case PS2_RET_ERR:
+ error = -EPROTO;
+ break;
+ default:
+ error = -EIO;
+ break;
+ }
+ }
+
+ if (error || attempt > 1)
+ dev_dbg(&ps2dev->serio->dev,
+ "%02x - %d (%x), attempt %d\n",
+ byte, error, ps2dev->nak, attempt);
+
+ return error;
+}
+
/*
* ps2_sendbyte() sends a byte to the device and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because if there
- * is a need for retransmissions device has to be replaced anyway.
+ * It doesn't handle retransmission, the caller is expected to handle
+ * it when needed.
*
* ps2_sendbyte() can only be called from a process context.
*/
-int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
+int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
{
+ int retval;
+
serio_pause_rx(ps2dev->serio);
- ps2dev->nak = 1;
- ps2dev->flags |= PS2_FLAG_ACK;
- serio_continue_rx(ps2dev->serio);
- if (serio_write(ps2dev->serio, byte) == 0)
- wait_event_timeout(ps2dev->wait,
- !(ps2dev->flags & PS2_FLAG_ACK),
- msecs_to_jiffies(timeout));
+ retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1);
+ dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak);
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags &= ~PS2_FLAG_ACK;
serio_continue_rx(ps2dev->serio);
- return -ps2dev->nak;
+ return retval;
}
EXPORT_SYMBOL(ps2_sendbyte);
@@ -75,7 +123,7 @@ EXPORT_SYMBOL(ps2_end_command);
* and discards them.
*/
-void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
{
if (maxbytes > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
@@ -102,9 +150,9 @@ EXPORT_SYMBOL(ps2_drain);
* known keyboard IDs.
*/
-int ps2_is_keyboard_id(char id_byte)
+bool ps2_is_keyboard_id(u8 id_byte)
{
- static const char keyboard_ids[] = {
+ static const u8 keyboard_ids[] = {
0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */
@@ -123,49 +171,50 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
* completion.
*/
-static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+static int ps2_adjust_timeout(struct ps2dev *ps2dev,
+ unsigned int command, unsigned int timeout)
{
switch (command) {
- case PS2_CMD_RESET_BAT:
- /*
- * Device has sent the first response byte after
- * reset command, reset is thus done, so we can
- * shorten the timeout.
- * The next byte will come soon (keyboard) or not
- * at all (mouse).
- */
- if (timeout > msecs_to_jiffies(100))
- timeout = msecs_to_jiffies(100);
- break;
+ case PS2_CMD_RESET_BAT:
+ /*
+ * Device has sent the first response byte after
+ * reset command, reset is thus done, so we can
+ * shorten the timeout.
+ * The next byte will come soon (keyboard) or not
+ * at all (mouse).
+ */
+ if (timeout > msecs_to_jiffies(100))
+ timeout = msecs_to_jiffies(100);
+ break;
- case PS2_CMD_GETID:
- /*
- * Microsoft Natural Elite keyboard responds to
- * the GET ID command as it were a mouse, with
- * a single byte. Fail the command so atkbd will
- * use alternative probe to detect it.
- */
- if (ps2dev->cmdbuf[1] == 0xaa) {
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = 0;
- serio_continue_rx(ps2dev->serio);
- timeout = 0;
- }
-
- /*
- * If device behind the port is not a keyboard there
- * won't be 2nd byte of ID response.
- */
- if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
- timeout = 0;
- }
- break;
+ case PS2_CMD_GETID:
+ /*
+ * Microsoft Natural Elite keyboard responds to
+ * the GET ID command as it were a mouse, with
+ * a single byte. Fail the command so atkbd will
+ * use alternative probe to detect it.
+ */
+ if (ps2dev->cmdbuf[1] == 0xaa) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
- default:
- break;
+ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+ break;
+
+ default:
+ break;
}
return timeout;
@@ -178,50 +227,60 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
* ps2_command() can only be called from a process context
*/
-int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
{
- int timeout;
- int send = (command >> 12) & 0xf;
- int receive = (command >> 8) & 0xf;
- int rc = -1;
+ unsigned int timeout;
+ unsigned int send = (command >> 12) & 0xf;
+ unsigned int receive = (command >> 8) & 0xf;
+ int rc;
int i;
+ u8 send_param[16];
if (receive > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
- return -1;
+ return -EINVAL;
}
if (send && !param) {
WARN_ON(1);
- return -1;
+ return -EINVAL;
}
+ memcpy(send_param, param, send);
+
serio_pause_rx(ps2dev->serio);
+
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
ps2dev->cmdcnt = receive;
if (receive && param)
for (i = 0; i < receive; i++)
ps2dev->cmdbuf[(receive - 1) - i] = param[i];
- serio_continue_rx(ps2dev->serio);
+
+ /* Signal that we are sending the command byte */
+ ps2dev->flags |= PS2_FLAG_ACK_CMD;
/*
* Some devices (Synaptics) peform the reset before
* ACKing the reset command, and so it can take a long
* time before the ACK arrives.
*/
- if (ps2_sendbyte(ps2dev, command & 0xff,
- command == PS2_CMD_RESET_BAT ? 1000 : 200)) {
- serio_pause_rx(ps2dev->serio);
+ timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200;
+
+ rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2);
+ if (rc)
goto out_reset_flags;
- }
+
+ /* Now we are sending command parameters, if any */
+ ps2dev->flags &= ~PS2_FLAG_ACK_CMD;
for (i = 0; i < send; i++) {
- if (ps2_sendbyte(ps2dev, param[i], 200)) {
- serio_pause_rx(ps2dev->serio);
+ rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2);
+ if (rc)
goto out_reset_flags;
- }
}
+ serio_continue_rx(ps2dev->serio);
+
/*
* The reset command takes a long time to execute.
*/
@@ -243,8 +302,11 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
for (i = 0; i < receive; i++)
param[i] = ps2dev->cmdbuf[(receive - 1) - i];
- if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1))
+ if (ps2dev->cmdcnt &&
+ (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
+ rc = -EPROTO;
goto out_reset_flags;
+ }
rc = 0;
@@ -252,11 +314,21 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
- return rc;
+ dev_dbg(&ps2dev->serio->dev,
+ "%02x [%*ph] - %x/%08lx [%*ph]\n",
+ command & 0xff, send, send_param,
+ ps2dev->nak, ps2dev->flags,
+ receive, param ?: send_param);
+
+ /*
+ * ps_command() handles resends itself, so do not leak -EAGAIN
+ * to the callers.
+ */
+ return rc != -EAGAIN ? rc : -EPROTO;
}
EXPORT_SYMBOL(__ps2_command);
-int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
{
int rc;
@@ -269,6 +341,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);
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c
index 47de5a8..ffd03cf 100644
--- a/drivers/input/tablet/pegasus_notetaker.c
+++ b/drivers/input/tablet/pegasus_notetaker.c
@@ -41,6 +41,7 @@
#include <linux/usb/input.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
/* USB HID defines */
#define USB_REQ_GET_REPORT 0x01
@@ -76,6 +77,11 @@ struct pegasus {
struct usb_device *usbdev;
struct usb_interface *intf;
struct urb *irq;
+
+ /* serialize access to open/suspend */
+ struct mutex pm_mutex;
+ bool is_open;
+
char name[128];
char phys[64];
struct work_struct init;
@@ -216,6 +222,7 @@ static int pegasus_open(struct input_dev *dev)
if (error)
return error;
+ mutex_lock(&pegasus->pm_mutex);
pegasus->irq->dev = pegasus->usbdev;
if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) {
error = -EIO;
@@ -226,12 +233,15 @@ static int pegasus_open(struct input_dev *dev)
if (error)
goto err_kill_urb;
+ pegasus->is_open = true;
+ mutex_unlock(&pegasus->pm_mutex);
return 0;
err_kill_urb:
usb_kill_urb(pegasus->irq);
cancel_work_sync(&pegasus->init);
err_autopm_put:
+ mutex_unlock(&pegasus->pm_mutex);
usb_autopm_put_interface(pegasus->intf);
return error;
}
@@ -240,8 +250,12 @@ static void pegasus_close(struct input_dev *dev)
{
struct pegasus *pegasus = input_get_drvdata(dev);
+ mutex_lock(&pegasus->pm_mutex);
usb_kill_urb(pegasus->irq);
cancel_work_sync(&pegasus->init);
+ pegasus->is_open = false;
+ mutex_unlock(&pegasus->pm_mutex);
+
usb_autopm_put_interface(pegasus->intf);
}
@@ -274,6 +288,8 @@ static int pegasus_probe(struct usb_interface *intf,
goto err_free_mem;
}
+ mutex_init(&pegasus->pm_mutex);
+
pegasus->usbdev = dev;
pegasus->dev = input_dev;
pegasus->intf = intf;
@@ -388,10 +404,10 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
- mutex_lock(&pegasus->dev->mutex);
+ mutex_lock(&pegasus->pm_mutex);
usb_kill_urb(pegasus->irq);
cancel_work_sync(&pegasus->init);
- mutex_unlock(&pegasus->dev->mutex);
+ mutex_unlock(&pegasus->pm_mutex);
return 0;
}
@@ -401,10 +417,10 @@ static int pegasus_resume(struct usb_interface *intf)
struct pegasus *pegasus = usb_get_intfdata(intf);
int retval = 0;
- mutex_lock(&pegasus->dev->mutex);
- if (pegasus->dev->users && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
+ mutex_lock(&pegasus->pm_mutex);
+ if (pegasus->is_open && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
retval = -EIO;
- mutex_unlock(&pegasus->dev->mutex);
+ mutex_unlock(&pegasus->pm_mutex);
return retval;
}
@@ -414,14 +430,14 @@ static int pegasus_reset_resume(struct usb_interface *intf)
struct pegasus *pegasus = usb_get_intfdata(intf);
int retval = 0;
- mutex_lock(&pegasus->dev->mutex);
- if (pegasus->dev->users) {
+ mutex_lock(&pegasus->pm_mutex);
+ if (pegasus->is_open) {
retval = pegasus_set_mode(pegasus, PEN_MODE_XY,
NOTETAKER_LED_MOUSE);
if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
retval = -EIO;
}
- mutex_unlock(&pegasus->dev->mutex);
+ mutex_unlock(&pegasus->pm_mutex);
return retval;
}
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index db4f6bb..a5ab774 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -1,11 +1,8 @@
-/*
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+// Melfas MMS114/MMS152 touchscreen device driver
+//
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Joonyoung Shim <jy0922.shim@samsung.com>
#include <linux/module.h>
#include <linux/delay.h>
@@ -624,4 +621,4 @@ module_i2c_driver(mms114_driver);
/* Module information */
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c
index 675efa9..b63d7fd 100644
--- a/drivers/input/touchscreen/s6sy761.c
+++ b/drivers/input/touchscreen/s6sy761.c
@@ -2,7 +2,7 @@
// Samsung S6SY761 Touchscreen device driver
//
// Copyright (c) 2017 Samsung Electronics Co., Ltd.
-// Copyright (c) 2017 Andi Shyti <andi.shyti@samsung.com>
+// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
#include <asm/unaligned.h>
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 646b1e7..ff7043f 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -602,6 +602,7 @@ static const struct acpi_device_id silead_ts_acpi_match[] = {
{ "GSL3675", 0 },
{ "GSL3692", 0 },
{ "MSSL1680", 0 },
+ { "MSSL0001", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index efdb1a7..704e990 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -2,7 +2,7 @@
// STMicroelectronics FTS Touchscreen device driver
//
// Copyright (c) 2017 Samsung Electronics Co., Ltd.
-// Copyright (c) 2017 Andi Shyti <andi.shyti@samsung.com>
+// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -730,6 +730,7 @@ static int stmfts_probe(struct i2c_client *client,
return err;
pm_runtime_enable(&client->dev);
+ device_enable_async_suspend(&client->dev);
return 0;
}
@@ -805,6 +806,7 @@ static struct i2c_driver stmfts_driver = {
.name = STMFTS_DEV_NAME,
.of_match_table = of_match_ptr(stmfts_of_match),
.pm = &stmfts_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = stmfts_probe,
.remove = stmfts_remove,
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index f16f835..894843a 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -38,6 +38,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-sg.h>
@@ -81,7 +82,10 @@ struct sur40_blob {
__le32 area; /* size in pixels/pressure (?) */
- u8 padding[32];
+ u8 padding[24];
+
+ __le32 tag_id; /* valid when type == 0x04 (SUR40_TAG) */
+ __le32 unknown;
} __packed;
@@ -146,6 +150,40 @@ struct sur40_image_header {
#define SUR40_TOUCH 0x02
#define SUR40_TAG 0x04
+/* video controls */
+#define SUR40_BRIGHTNESS_MAX 0xff
+#define SUR40_BRIGHTNESS_MIN 0x00
+#define SUR40_BRIGHTNESS_DEF 0xff
+
+#define SUR40_CONTRAST_MAX 0x0f
+#define SUR40_CONTRAST_MIN 0x00
+#define SUR40_CONTRAST_DEF 0x0a
+
+#define SUR40_GAIN_MAX 0x09
+#define SUR40_GAIN_MIN 0x00
+#define SUR40_GAIN_DEF 0x08
+
+#define SUR40_BACKLIGHT_MAX 0x01
+#define SUR40_BACKLIGHT_MIN 0x00
+#define SUR40_BACKLIGHT_DEF 0x01
+
+#define sur40_str(s) #s
+#define SUR40_PARAM_RANGE(lo, hi) " (range " sur40_str(lo) "-" sur40_str(hi) ")"
+
+/* module parameters */
+static uint brightness = SUR40_BRIGHTNESS_DEF;
+module_param(brightness, uint, 0644);
+MODULE_PARM_DESC(brightness, "set initial brightness"
+ SUR40_PARAM_RANGE(SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX));
+static uint contrast = SUR40_CONTRAST_DEF;
+module_param(contrast, uint, 0644);
+MODULE_PARM_DESC(contrast, "set initial contrast"
+ SUR40_PARAM_RANGE(SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX));
+static uint gain = SUR40_GAIN_DEF;
+module_param(gain, uint, 0644);
+MODULE_PARM_DESC(gain, "set initial gain"
+ SUR40_PARAM_RANGE(SUR40_GAIN_MIN, SUR40_GAIN_MAX));
+
static const struct v4l2_pix_format sur40_pix_format[] = {
{
.pixelformat = V4L2_TCH_FMT_TU08,
@@ -178,6 +216,7 @@ struct sur40_state {
struct video_device vdev;
struct mutex lock;
struct v4l2_pix_format pix_fmt;
+ struct v4l2_ctrl_handler hdl;
struct vb2_queue queue;
struct list_head buf_list;
@@ -187,6 +226,7 @@ struct sur40_state {
struct sur40_data *bulk_in_buffer;
size_t bulk_in_size;
u8 bulk_in_epaddr;
+ u8 vsvideo;
char phys[64];
};
@@ -200,6 +240,11 @@ struct sur40_buffer {
static const struct video_device sur40_video_device;
static const struct vb2_queue sur40_queue;
static void sur40_process_video(struct sur40_state *sur40);
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops sur40_ctrl_ops = {
+ .s_ctrl = sur40_s_ctrl,
+};
/*
* Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT
@@ -220,6 +265,81 @@ static int sur40_command(struct sur40_state *dev,
0x00, index, buffer, size, 1000);
}
+/* poke a byte in the panel register space */
+static int sur40_poke(struct sur40_state *dev, u8 offset, u8 value)
+{
+ int result;
+ u8 index = 0x96; // 0xae for permanent write
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x32, index, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x72, offset, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0xb2, value, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+error:
+ return result;
+}
+
+static int sur40_set_preprocessor(struct sur40_state *dev, u8 value)
+{
+ u8 setting_07[2] = { 0x01, 0x00 };
+ u8 setting_17[2] = { 0x85, 0x80 };
+ int result;
+
+ if (value > 1)
+ return -ERANGE;
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x07, setting_07[value], NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x17, setting_17[value], NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+error:
+ return result;
+}
+
+static void sur40_set_vsvideo(struct sur40_state *handle, u8 value)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ sur40_poke(handle, 0x1c+i, value);
+ handle->vsvideo = value;
+}
+
+static void sur40_set_irlevel(struct sur40_state *handle, u8 value)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ sur40_poke(handle, 0x08+(2*i), value);
+}
+
/* Initialization routine, called from sur40_open */
static int sur40_init(struct sur40_state *dev)
{
@@ -631,6 +751,36 @@ static int sur40_probe(struct usb_interface *interface,
sur40->vdev.queue = &sur40->queue;
video_set_drvdata(&sur40->vdev, sur40);
+ /* initialize the control handler for 4 controls */
+ v4l2_ctrl_handler_init(&sur40->hdl, 4);
+ sur40->v4l2.ctrl_handler = &sur40->hdl;
+ sur40->vsvideo = (SUR40_CONTRAST_DEF << 4) | SUR40_GAIN_DEF;
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX, 1, clamp(brightness,
+ (uint)SUR40_BRIGHTNESS_MIN, (uint)SUR40_BRIGHTNESS_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_CONTRAST,
+ SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX, 1, clamp(contrast,
+ (uint)SUR40_CONTRAST_MIN, (uint)SUR40_CONTRAST_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_GAIN,
+ SUR40_GAIN_MIN, SUR40_GAIN_MAX, 1, clamp(gain,
+ (uint)SUR40_GAIN_MIN, (uint)SUR40_GAIN_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops,
+ V4L2_CID_BACKLIGHT_COMPENSATION, SUR40_BACKLIGHT_MIN,
+ SUR40_BACKLIGHT_MAX, 1, SUR40_BACKLIGHT_DEF);
+
+ v4l2_ctrl_handler_setup(&sur40->hdl);
+
+ if (sur40->hdl.error) {
+ dev_err(&interface->dev,
+ "Unable to register video controls.");
+ v4l2_ctrl_handler_free(&sur40->hdl);
+ goto err_unreg_v4l2;
+ }
+
error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1);
if (error) {
dev_err(&interface->dev,
@@ -663,6 +813,7 @@ static void sur40_disconnect(struct usb_interface *interface)
{
struct sur40_state *sur40 = usb_get_intfdata(interface);
+ v4l2_ctrl_handler_free(&sur40->hdl);
video_unregister_device(&sur40->vdev);
v4l2_device_unregister(&sur40->v4l2);
@@ -856,6 +1007,31 @@ static int sur40_vidioc_g_fmt(struct file *file, void *priv,
return 0;
}
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct sur40_state *sur40 = container_of(ctrl->handler,
+ struct sur40_state, hdl);
+ u8 value = sur40->vsvideo;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sur40_set_irlevel(sur40, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ value = (value & 0x0f) | (ctrl->val << 4);
+ sur40_set_vsvideo(sur40, value);
+ break;
+ case V4L2_CID_GAIN:
+ value = (value & 0xf0) | (ctrl->val);
+ sur40_set_vsvideo(sur40, value);
+ break;
+ case V4L2_CID_BACKLIGHT_COMPENSATION:
+ sur40_set_preprocessor(sur40, ctrl->val);
+ break;
+ }
+ return 0;
+}
+
static int sur40_ioctl_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index aa77d24..c6cf908 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -54,6 +54,7 @@
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
+#include <linux/mutex.h>
static bool swap_xy;
module_param(swap_xy, bool, 0644);
@@ -107,6 +108,8 @@ struct usbtouch_usb {
struct usb_interface *interface;
struct input_dev *input;
struct usbtouch_device_info *type;
+ struct mutex pm_mutex; /* serialize access to open/suspend */
+ bool is_open;
char name[128];
char phys[64];
void *priv;
@@ -1450,6 +1453,7 @@ static int usbtouch_open(struct input_dev *input)
if (r < 0)
goto out;
+ mutex_lock(&usbtouch->pm_mutex);
if (!usbtouch->type->irq_always) {
if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
r = -EIO;
@@ -1458,7 +1462,9 @@ static int usbtouch_open(struct input_dev *input)
}
usbtouch->interface->needs_remote_wakeup = 1;
+ usbtouch->is_open = true;
out_put:
+ mutex_unlock(&usbtouch->pm_mutex);
usb_autopm_put_interface(usbtouch->interface);
out:
return r;
@@ -1469,8 +1475,12 @@ static void usbtouch_close(struct input_dev *input)
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
int r;
+ mutex_lock(&usbtouch->pm_mutex);
if (!usbtouch->type->irq_always)
usb_kill_urb(usbtouch->irq);
+ usbtouch->is_open = false;
+ mutex_unlock(&usbtouch->pm_mutex);
+
r = usb_autopm_get_interface(usbtouch->interface);
usbtouch->interface->needs_remote_wakeup = 0;
if (!r)
@@ -1490,13 +1500,12 @@ static int usbtouch_suspend
static int usbtouch_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- struct input_dev *input = usbtouch->input;
int result = 0;
- mutex_lock(&input->mutex);
- if (input->users || usbtouch->type->irq_always)
+ mutex_lock(&usbtouch->pm_mutex);
+ if (usbtouch->is_open || usbtouch->type->irq_always)
result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&input->mutex);
+ mutex_unlock(&usbtouch->pm_mutex);
return result;
}
@@ -1504,7 +1513,6 @@ static int usbtouch_resume(struct usb_interface *intf)
static int usbtouch_reset_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- struct input_dev *input = usbtouch->input;
int err = 0;
/* reinit the device */
@@ -1519,10 +1527,10 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
}
/* restart IO if needed */
- mutex_lock(&input->mutex);
- if (input->users)
+ mutex_lock(&usbtouch->pm_mutex);
+ if (usbtouch->is_open)
err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&input->mutex);
+ mutex_unlock(&usbtouch->pm_mutex);
return err;
}
OpenPOWER on IntegriCloud