From 2f76476339641da23b156e5546c182e67daa93ab Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Tue, 25 Aug 2015 18:21:42 +0800 Subject: [PATCH] ANDROID: input: Add "inhibited" property for input devices Under certain circumstances, we want to disable some input devices from userspace. In particular, when we detect that the lid of a laptop is closed, we want to be able to disable touchpad and touchscreen to avoid bogus input. To facilitate this, we introduce the "inhibited" sysfs property for input devices. Using this property, userspace can tell a driver that the events it can provide are not currently of interest and should be ignored. We provide hooks so that the driver can take additional actions, such as powering down the device. We deliberately keep this limited to input devices for now to keep the implementation as straightforward as possible. (cherry-pick from: https://chromium-review.googlesource.com/207989) verify that touchpad works echo 1 > /sys/bus/i2c/drivers/elan_i2c/4-0015/input/input0/inhibited touchpad stops working echo 0 > /sys/bus/i2c/drivers/elan_i2c/4-0015/input/input0/inhibited touchpad works again Signed-off-by: Patrik Fimml Reviewed-on: https://chromium-review.googlesource.com/207989 Reviewed-by: Dmitry Torokhov Reviewed-by: Benson Leung Change-Id: I889d37ef7ffc49f3c073b1c283d5c3327c263b7f Signed-off-by: Caesar Wang --- drivers/input/input.c | 96 +++++++++++++++++++++++++++++++++++++++++++ include/linux/input.h | 5 +++ 2 files changed, 101 insertions(+) diff --git a/drivers/input/input.c b/drivers/input/input.c index a161021c4526..80481b6fc22c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,6 +367,13 @@ static void input_handle_event(struct input_dev *dev, { int disposition; + /* + * When inhibited, skip all events. For devices that do not implement + * inhibit() themselves. + */ + if (dev->inhibited) + return; + disposition = input_get_disposition(dev, type, code, &value); if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) @@ -1380,12 +1387,50 @@ 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(struct input_dev *dev); +static int input_uninhibit(struct input_dev *dev); + +static ssize_t input_dev_show_inhibited(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 input_dev_store_inhibited(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(input_dev); + else + rv = input_uninhibit(input_dev); + + if (rv != 0) + return rv; + + return len; +} + +static DEVICE_ATTR(inhibited, S_IWUSR | S_IRUGO, input_dev_show_inhibited, + input_dev_store_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 }; @@ -1673,6 +1718,57 @@ void input_reset_device(struct input_dev *dev) } EXPORT_SYMBOL(input_reset_device); +static int input_inhibit(struct input_dev *dev) +{ + int rv = 0; + + mutex_lock(&dev->mutex); + + if (dev->inhibited) + goto out; + + if (dev->inhibit) { + rv = dev->inhibit(dev); + if (rv != 0) + goto out; + } + + input_dev_release_keys(dev); + input_dev_toggle(dev, false); + + dev->inhibited = true; + +out: + mutex_unlock(&dev->mutex); + return rv; +} + +static int input_uninhibit(struct input_dev *dev) +{ + int rv = 0; + + mutex_lock(&dev->mutex); + + if (!dev->inhibited) + goto out; + + input_dev_toggle(dev, true); + + if (dev->uninhibit) { + rv = dev->uninhibit(dev); + if (rv != 0) { + input_dev_toggle(dev, false); + goto out; + } + } + + dev->inhibited = false; + +out: + mutex_unlock(&dev->mutex); + return rv; +} + #ifdef CONFIG_PM static int input_dev_suspend(struct device *dev) { diff --git a/include/linux/input.h b/include/linux/input.h index 82ce323b9986..4770ed61cef0 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -187,6 +187,11 @@ struct input_dev { struct input_value *vals; bool devres_managed; + + int (*inhibit)(struct input_dev *dev); + int (*uninhibit)(struct input_dev *dev); + + bool inhibited; }; #define to_input_dev(d) container_of(d, struct input_dev, dev) -- 2.34.1