char name[16];
struct input_handle handle;
wait_queue_head_t wait;
- struct evdev_client *grab;
+ int *grab;
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
+ int grab;
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct evdev *evdev;
rcu_read_lock();
- client = rcu_dereference(evdev->grab);
- if (client)
+ list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);
- else
- list_for_each_entry_rcu(client, &evdev->client_list, node)
- evdev_pass_event(client, &event);
rcu_read_unlock();
{
int error;
- if (evdev->grab)
+ if (client->grab)
return -EBUSY;
- error = input_grab_device(&evdev->handle);
- if (error)
- return error;
-
- rcu_assign_pointer(evdev->grab, client);
+ if (!evdev->grab++) {
+ error = input_grab_device(&evdev->handle);
+ if (error)
+ return error;
+ }
+ client->grab = 1;
synchronize_rcu();
return 0;
static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
{
- if (evdev->grab != client)
+ if (!client->grab)
return -EINVAL;
- rcu_assign_pointer(evdev->grab, NULL);
- synchronize_rcu();
- input_release_device(&evdev->handle);
+ if (!--evdev->grab && evdev->exist)
+ input_release_device(&evdev->handle);
+ client->grab = 0;
return 0;
}
struct evdev *evdev = client->evdev;
mutex_lock(&evdev->mutex);
- if (evdev->grab == client)
+ if (client->grab)
evdev_ungrab(evdev, client);
mutex_unlock(&evdev->mutex);