Commit d870e5ad authored by Zephaniah E. Hull's avatar Zephaniah E. Hull Committed by Vojtech Pavlik

input: Implement input device grabbing so that it is possible to steal

an input device from other handlers and have an exclusive access
to events.
parent 5b29b6f3
...@@ -29,6 +29,7 @@ struct evdev { ...@@ -29,6 +29,7 @@ struct evdev {
char name[16]; char name[16];
struct input_handle handle; struct input_handle handle;
wait_queue_head_t wait; wait_queue_head_t wait;
struct evdev_list *grab;
struct list_head list; struct list_head list;
}; };
...@@ -48,7 +49,8 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned ...@@ -48,7 +49,8 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
struct evdev *evdev = handle->private; struct evdev *evdev = handle->private;
struct evdev_list *list; struct evdev_list *list;
list_for_each_entry(list, &evdev->list, node) { if (evdev->grab) {
list = evdev->grab;
do_gettimeofday(&list->buffer[list->head].time); do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type; list->buffer[list->head].type = type;
...@@ -57,7 +59,17 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned ...@@ -57,7 +59,17 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} } else
list_for_each_entry(list, &evdev->list, node) {
do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type;
list->buffer[list->head].code = code;
list->buffer[list->head].value = value;
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&evdev->wait); wake_up_interruptible(&evdev->wait);
} }
...@@ -88,6 +100,11 @@ static int evdev_release(struct inode * inode, struct file * file) ...@@ -88,6 +100,11 @@ static int evdev_release(struct inode * inode, struct file * file)
{ {
struct evdev_list *list = file->private_data; struct evdev_list *list = file->private_data;
if (list->evdev->grab == list) {
input_release_device(&list->evdev->handle);
list->evdev->grab = NULL;
}
evdev_fasync(-1, file, 0); evdev_fasync(-1, file, 0);
list_del(&list->node); list_del(&list->node);
...@@ -257,6 +274,22 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -257,6 +274,22 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EFAULT; return -EFAULT;
return 0; return 0;
case EVIOCGRAB:
if (arg) {
if (evdev->grab)
return -EBUSY;
if (input_grab_device(&evdev->handle))
return -EBUSY;
evdev->grab = list;
return 0;
} else {
if (evdev->grab != list)
return -EINVAL;
input_release_device(&evdev->handle);
evdev->grab = NULL;
return 0;
}
default: default:
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
......
...@@ -33,6 +33,8 @@ EXPORT_SYMBOL(input_register_device); ...@@ -33,6 +33,8 @@ EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler); EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler); EXPORT_SYMBOL(input_unregister_handler);
EXPORT_SYMBOL(input_grab_device);
EXPORT_SYMBOL(input_release_device);
EXPORT_SYMBOL(input_open_device); EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_accept_process);
...@@ -175,9 +177,12 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in ...@@ -175,9 +177,12 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (type != EV_SYN) if (type != EV_SYN)
dev->sync = 0; dev->sync = 0;
list_for_each_entry(handle, &dev->h_list, d_node) if (dev->grab)
if (handle->open) dev->grab->handler->event(dev->grab, type, code, value);
handle->handler->event(handle, type, code, value); else
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
} }
static void input_repeat_key(unsigned long data) static void input_repeat_key(unsigned long data)
...@@ -201,6 +206,21 @@ int input_accept_process(struct input_handle *handle, struct file *file) ...@@ -201,6 +206,21 @@ int input_accept_process(struct input_handle *handle, struct file *file)
return 0; return 0;
} }
int input_grab_device(struct input_handle *handle)
{
if (handle->dev->grab)
return -EBUSY;
handle->dev->grab = handle;
return 0;
}
void input_release_device(struct input_handle *handle)
{
if (handle->dev->grab == handle)
handle->dev->grab = NULL;
}
int input_open_device(struct input_handle *handle) int input_open_device(struct input_handle *handle)
{ {
if (handle->dev->pm_dev) if (handle->dev->pm_dev)
...@@ -221,6 +241,7 @@ int input_flush_device(struct input_handle* handle, struct file* file) ...@@ -221,6 +241,7 @@ int input_flush_device(struct input_handle* handle, struct file* file)
void input_close_device(struct input_handle *handle) void input_close_device(struct input_handle *handle)
{ {
input_release_device(handle);
if (handle->dev->pm_dev) if (handle->dev->pm_dev)
pm_dev_idle(handle->dev->pm_dev); pm_dev_idle(handle->dev->pm_dev);
if (handle->dev->close) if (handle->dev->close)
......
...@@ -77,6 +77,8 @@ struct input_absinfo { ...@@ -77,6 +77,8 @@ struct input_absinfo {
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
/* /*
* Event types * Event types
*/ */
...@@ -798,6 +800,8 @@ struct input_dev { ...@@ -798,6 +800,8 @@ struct input_dev {
int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
int (*erase_effect)(struct input_dev *dev, int effect_id); int (*erase_effect)(struct input_dev *dev, int effect_id);
struct input_handle *grab;
struct list_head h_list; struct list_head h_list;
struct list_head node; struct list_head node;
}; };
...@@ -888,6 +892,9 @@ void input_unregister_device(struct input_dev *); ...@@ -888,6 +892,9 @@ void input_unregister_device(struct input_dev *);
void input_register_handler(struct input_handler *); void input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *); void input_unregister_handler(struct input_handler *);
int input_grab_device(struct input_handle *);
void input_release_device(struct input_handle *);
int input_open_device(struct input_handle *); int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *); void input_close_device(struct input_handle *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment