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 <patrikf@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/207989
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Benson Leung <bleung@chromium.org>

Change-Id: I889d37ef7ffc49f3c073b1c283d5c3327c263b7f
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
This commit is contained in:
Caesar Wang
2015-08-25 18:21:42 +08:00
parent cce63258ec
commit 2f76476339
2 changed files with 101 additions and 0 deletions

View File

@@ -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)
{

View File

@@ -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)