[PATCH 4/8] Input: Block suspend while event queue is not empty.

Arve Hjønnevåg
2009-04-15T01:41:28Z

Add an ioctl, EVIOCSSUSPENDBLOCK, to enables a suspend_blocker that will block
suspend while the event queue is not empty. This allows userspace code to
process input events while the device appears to be asleep.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
drivers/input/evdev.c | 21 +++++++++++++++++++++
include/linux/input.h | 3 +++
2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index ed8baa0..3a61425 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -19,6 +19,7 @@
#include <linux/input.h>
#include <linux/major.h>
#include <linux/device.h>
+#include <linux/suspend_block.h>
#include "input-compat.h"

struct evdev {
@@ -43,6 +44,8 @@ struct evdev_client {
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
+ int use_suspend_blocker;
+ struct suspend_blocker suspend_blocker;
};

static struct evdev *evdev_table[EVDEV_MINORS];
@@ -55,6 +58,8 @@ static void evdev_pass_event(struct evdev_client *client,
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
+ if (client->use_suspend_blocker)
+ suspend_block(&client->suspend_blocker);
client->buffer[client->head++] = *event;
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
@@ -236,6 +241,8 @@ static int evdev_release(struct inode *inode, struct file *file)
mutex_unlock(&evdev->mutex);

evdev_detach_client(evdev, client);
+ if (client->use_suspend_blocker)
+ suspend_blocker_destroy(&client->suspend_blocker);
kfree(client);

evdev_close_device(evdev);
@@ -335,6 +342,8 @@ static int evdev_fetch_next_event(struct evdev_client *client,
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= EVDEV_BUFFER_SIZE - 1;
+ if (client->use_suspend_blocker && client->head == client->tail)
+ suspend_unblock(&client->suspend_blocker);
}

spin_unlock_irq(&client->buffer_lock);
@@ -585,6 +594,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
else
return evdev_ungrab(evdev, client);

+ case EVIOCGSUSPENDBLOCK:
+ return put_user(EV_VERSION, ip);
+
+ case EVIOCSSUSPENDBLOCK:
+ spin_lock_irq(&client->buffer_lock);
+ if ((client->use_suspend_blocker = !!p))
+ suspend_blocker_init(&client->suspend_blocker, "evdev");
+ else
+ suspend_blocker_destroy(&client->suspend_blocker);
+ spin_unlock_irq(&client->buffer_lock);
+ return 0;
+
default:

if (_IOC_TYPE(cmd) != 'E')
diff --git a/include/linux/input.h b/include/linux/input.h
index 1249a0c..67e2332 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -81,6 +81,9 @@ struct input_absinfo {

#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */

+#define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) /* get suspend block enable */
+#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) /* set suspend block enable */
+
/*
* Event types
*/
--
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org