Index: linux-2.6.24-rc7/drivers/input/evdev.c =================================================================== --- linux-2.6.24-rc7.orig/drivers/input/evdev.c +++ linux-2.6.24-rc7/drivers/input/evdev.c @@ -28,7 +28,7 @@ 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; @@ -39,6 +39,7 @@ 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; @@ -79,12 +80,8 @@ 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(); @@ -135,14 +132,15 @@ { 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; @@ -150,12 +148,12 @@ 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; } @@ -230,7 +228,7 @@ struct evdev *evdev = client->evdev; mutex_lock(&evdev->mutex); - if (evdev->grab == client) + if (client->grab) evdev_ungrab(evdev, client); mutex_unlock(&evdev->mutex);