diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2ae522f0d2b2..d87e6755d00c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -26,6 +26,7 @@ #include <linux/major.h> #include <linux/device.h> #include <linux/cdev.h> +#include <linux/wakelock.h> #include "input-compat.h" enum evdev_clock_type { @@ -53,6 +54,9 @@ struct evdev_client { unsigned int tail; unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ + struct wake_lock wake_lock; + bool use_wake_lock; + char name[28]; struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; @@ -200,10 +204,14 @@ static void __pass_event(struct evdev_client *client, client->buffer[client->tail].value = 0; client->packet_head = client->tail; + if (client->use_wake_lock) + wake_unlock(&client->wake_lock); } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; + if (client->use_wake_lock) + wake_lock(&client->wake_lock); kill_fasync(&client->fasync, SIGIO, POLL_IN); } } @@ -417,6 +425,9 @@ static int evdev_release(struct inode *inode, struct file *file) evdev_detach_client(evdev, client); + if (client->use_wake_lock) + wake_lock_destroy(&client->wake_lock); + if (is_vmalloc_addr(client)) vfree(client); else @@ -453,6 +464,8 @@ static int evdev_open(struct inode *inode, struct file *file) client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); + snprintf(client->name, sizeof(client->name), "%s-%d", + dev_name(&evdev->dev), task_tgid_vnr(current)); client->evdev = evdev; evdev_attach_client(evdev, client); @@ -519,6 +532,9 @@ static int evdev_fetch_next_event(struct evdev_client *client, if (have_event) { *event = client->buffer[client->tail++]; client->tail &= client->bufsize - 1; + if (client->use_wake_lock && + client->packet_head == client->tail) + wake_unlock(&client->wake_lock); } spin_unlock_irq(&client->buffer_lock); @@ -841,6 +857,11 @@ static int evdev_handle_mt_request(struct input_dev *dev, return 0; } +/* + * HACK: disable conflicting EVIOCREVOKE until Android userspace stops using + * EVIOCSSUSPENDBLOCK + */ +/* static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, struct file *file) { @@ -851,6 +872,36 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, return 0; } +*/ + +static int evdev_enable_suspend_block(struct evdev *evdev, + struct evdev_client *client) +{ + if (client->use_wake_lock) + return 0; + + spin_lock_irq(&client->buffer_lock); + wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); + client->use_wake_lock = true; + if (client->packet_head != client->tail) + wake_lock(&client->wake_lock); + spin_unlock_irq(&client->buffer_lock); + return 0; +} + +static int evdev_disable_suspend_block(struct evdev *evdev, + struct evdev_client *client) +{ + if (!client->use_wake_lock) + return 0; + + spin_lock_irq(&client->buffer_lock); + client->use_wake_lock = false; + wake_lock_destroy(&client->wake_lock); + spin_unlock_irq(&client->buffer_lock); + + return 0; +} static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) @@ -914,12 +965,17 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, else return evdev_ungrab(evdev, client); + /* + * HACK: disable conflicting EVIOCREVOKE until Android userspace stops + * using EVIOCSSUSPENDBLOCK + */ + /* case EVIOCREVOKE: if (p) return -EINVAL; else return evdev_revoke(evdev, client, file); - + */ case EVIOCSCLOCKID: if (copy_from_user(&i, p, sizeof(unsigned int))) return -EFAULT; @@ -937,6 +993,15 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, case EVIOCSKEYCODE_V2: return evdev_handle_set_keycode_v2(dev, p); + + case EVIOCGSUSPENDBLOCK: + return put_user(client->use_wake_lock, ip); + + case EVIOCSSUSPENDBLOCK: + if (p) + return evdev_enable_suspend_block(evdev, client); + else + return evdev_disable_suspend_block(evdev, client); } size = _IOC_SIZE(cmd); |