summaryrefslogtreecommitdiff
path: root/drivers/input/input.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 16:18:23 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 16:18:23 -0800
commitee249d30fadec7677364063648f5547e243bf93f (patch)
treedccfb94b0a6372f69062ef05fbbfdd770f0b3ece /drivers/input/input.c
parent61f914256c56a39a96dc14eae9f394d35b934812 (diff)
parent4b4193256c8d3bc3a5397b5cd9494c2ad386317d (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - support for inhibiting input devices at request from userspace. If a device implements open/close methods, it can also put device into low power state. This is needed, for example, to disable keyboard and touchpad on convertibles when they are transitioned into tablet mode - now that ordinary input devices can be configured for polling mode, dedicated input polling device implementation has been removed - GTCO tablet driver has been removed, as it used problematic custom HID parser, devices are EOL, and there is no interest from the manufacturer - a new driver for Dialog DA7280 haptic chips has been introduced - a new driver for power button on Dell Wyse 3020 - support for eKTF2132 in ektf2127 driver - support for SC2721 and SC2730 in sc27xx-vibra driver - enhancements for Atmel touchscreens, AD7846 touchscreens, Elan touchpads, ADP5589, ST1232 touchscreen, TM2 touchkey drivers - fixes and cleanups to allow clean builds with W=1 * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (86 commits) Input: da7280 - fix spelling mistake "sequemce" -> "sequence" Input: cyapa_gen6 - fix out-of-bounds stack access Input: sc27xx - add support for sc2730 and sc2721 dt-bindings: input: Add compatible string for SC2721 and SC2730 dt-bindings: input: Convert sc27xx-vibra.txt to json-schema Input: stmpe - add axis inversion and swapping capability Input: adp5589-keys - do not explicitly control IRQ for wakeup Input: adp5589-keys - do not unconditionally configure as wakeup source Input: ipx4xx-beeper - convert comma to semicolon Input: parkbd - convert comma to semicolon Input: new da7280 haptic driver dt-bindings: input: Add document bindings for DA7280 MAINTAINERS: da7280 updates to the Dialog Semiconductor search terms Input: elantech - fix protocol errors for some trackpoints in SMBus mode Input: elan_i2c - add new trackpoint report type 0x5F Input: elants - document some registers and values Input: atmel_mxt_ts - simplify the return expression of mxt_send_bootloader_cmd() Input: imx_keypad - add COMPILE_TEST support Input: applespi - use new structure for SPI transfer delays Input: synaptics-rmi4 - use new structure for SPI transfer delays ...
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r--drivers/input/input.c118
1 files changed, 112 insertions, 6 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3cfd2c18eebd..ccaeb2426385 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -367,8 +367,13 @@ static int input_get_disposition(struct input_dev *dev,
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
- int disposition = input_get_disposition(dev, type, code, &value);
+ int disposition;
+ /* filter-out events from inhibited devices */
+ if (dev->inhibited)
+ return;
+
+ disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);
@@ -612,10 +617,10 @@ int input_open_device(struct input_handle *handle)
handle->open++;
- if (dev->users++) {
+ if (dev->users++ || dev->inhibited) {
/*
- * Device is already opened, so we can exit immediately and
- * report success.
+ * Device is already opened and/or inhibited,
+ * so we can exit immediately and report success.
*/
goto out;
}
@@ -675,10 +680,9 @@ void input_close_device(struct input_handle *handle)
__input_release_device(handle);
- if (!--dev->users) {
+ if (!dev->inhibited && !--dev->users) {
if (dev->poller)
input_dev_poller_stop(dev->poller);
-
if (dev->close)
dev->close(dev);
}
@@ -1416,12 +1420,49 @@ static ssize_t input_dev_show_properties(struct device *dev,
}
static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);
+static int input_inhibit_device(struct input_dev *dev);
+static int input_uninhibit_device(struct input_dev *dev);
+
+static ssize_t inhibited_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", input_dev->inhibited);
+}
+
+static ssize_t inhibited_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ ssize_t rv;
+ bool inhibited;
+
+ if (strtobool(buf, &inhibited))
+ return -EINVAL;
+
+ if (inhibited)
+ rv = input_inhibit_device(input_dev);
+ else
+ rv = input_uninhibit_device(input_dev);
+
+ if (rv != 0)
+ return rv;
+
+ return len;
+}
+
+static DEVICE_ATTR_RW(inhibited);
+
static struct attribute *input_dev_attrs[] = {
&dev_attr_name.attr,
&dev_attr_phys.attr,
&dev_attr_uniq.attr,
&dev_attr_modalias.attr,
&dev_attr_properties.attr,
+ &dev_attr_inhibited.attr,
NULL
};
@@ -1703,6 +1744,63 @@ void input_reset_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_reset_device);
+static int input_inhibit_device(struct input_dev *dev)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->inhibited)
+ goto out;
+
+ if (dev->users) {
+ if (dev->close)
+ dev->close(dev);
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+ }
+
+ spin_lock_irq(&dev->event_lock);
+ input_dev_release_keys(dev);
+ input_dev_toggle(dev, false);
+ spin_unlock_irq(&dev->event_lock);
+
+ dev->inhibited = true;
+
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static int input_uninhibit_device(struct input_dev *dev)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (!dev->inhibited)
+ goto out;
+
+ if (dev->users) {
+ if (dev->open) {
+ ret = dev->open(dev);
+ if (ret)
+ goto out;
+ }
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+ }
+
+ dev->inhibited = false;
+ spin_lock_irq(&dev->event_lock);
+ input_dev_toggle(dev, true);
+ spin_unlock_irq(&dev->event_lock);
+
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
#ifdef CONFIG_PM_SLEEP
static int input_dev_suspend(struct device *dev)
{
@@ -2127,6 +2225,14 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
}
EXPORT_SYMBOL(input_enable_softrepeat);
+bool input_device_enabled(struct input_dev *dev)
+{
+ lockdep_assert_held(&dev->mutex);
+
+ return !dev->inhibited && dev->users > 0;
+}
+EXPORT_SYMBOL_GPL(input_device_enabled);
+
/**
* input_register_device - register device with input core
* @dev: device to be registered