diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 03:29:25 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 03:29:25 -0400 |
commit | 0fbf87caf70acec0c435233fbc39c7bd0aca3ca6 (patch) | |
tree | 65fa9bdde1f04a1359c3599d351199f834eb01ec | |
parent | 58a007765bb5f16020e6000ecbdc5bcc6e54a147 (diff) |
Input: add semaphore and user count to input_dev structure;
serialize open and close calls and ensure that device's
open and close methods are only called when first user
opens it or last user closes it.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/input.c | 33 | ||||
-rw-r--r-- | include/linux/input.h | 4 |
2 files changed, 32 insertions, 5 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 3385dd03abfc..1885f369e3e2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle) | |||
219 | 219 | ||
220 | int input_open_device(struct input_handle *handle) | 220 | int input_open_device(struct input_handle *handle) |
221 | { | 221 | { |
222 | struct input_dev *dev = handle->dev; | ||
223 | int err; | ||
224 | |||
225 | err = down_interruptible(&dev->sem); | ||
226 | if (err) | ||
227 | return err; | ||
228 | |||
222 | handle->open++; | 229 | handle->open++; |
223 | if (handle->dev->open) | 230 | |
224 | return handle->dev->open(handle->dev); | 231 | if (!dev->users++ && dev->open) |
225 | return 0; | 232 | err = dev->open(dev); |
233 | |||
234 | if (err) | ||
235 | handle->open--; | ||
236 | |||
237 | up(&dev->sem); | ||
238 | |||
239 | return err; | ||
226 | } | 240 | } |
227 | 241 | ||
228 | int input_flush_device(struct input_handle* handle, struct file* file) | 242 | int input_flush_device(struct input_handle* handle, struct file* file) |
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file) | |||
235 | 249 | ||
236 | void input_close_device(struct input_handle *handle) | 250 | void input_close_device(struct input_handle *handle) |
237 | { | 251 | { |
252 | struct input_dev *dev = handle->dev; | ||
253 | |||
238 | input_release_device(handle); | 254 | input_release_device(handle); |
239 | if (handle->dev->close) | 255 | |
240 | handle->dev->close(handle->dev); | 256 | down(&dev->sem); |
257 | |||
258 | if (!--dev->users && dev->close) | ||
259 | dev->close(dev); | ||
241 | handle->open--; | 260 | handle->open--; |
261 | |||
262 | up(&dev->sem); | ||
242 | } | 263 | } |
243 | 264 | ||
244 | static void input_link_handle(struct input_handle *handle) | 265 | static void input_link_handle(struct input_handle *handle) |
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev) | |||
415 | 436 | ||
416 | set_bit(EV_SYN, dev->evbit); | 437 | set_bit(EV_SYN, dev->evbit); |
417 | 438 | ||
439 | init_MUTEX(&dev->sem); | ||
440 | |||
418 | /* | 441 | /* |
419 | * If delay and period are pre-set by the driver, then autorepeating | 442 | * If delay and period are pre-set by the driver, then autorepeating |
420 | * is handled by the driver itself and we don't do it in input.c. | 443 | * is handled by the driver itself and we don't do it in input.c. |
diff --git a/include/linux/input.h b/include/linux/input.h index 72731d7d189e..43e8ecec602b 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
@@ -859,6 +859,10 @@ struct input_dev { | |||
859 | int (*erase_effect)(struct input_dev *dev, int effect_id); | 859 | int (*erase_effect)(struct input_dev *dev, int effect_id); |
860 | 860 | ||
861 | struct input_handle *grab; | 861 | struct input_handle *grab; |
862 | |||
863 | struct semaphore sem; /* serializes open and close operations */ | ||
864 | unsigned int users; | ||
865 | |||
862 | struct device *dev; | 866 | struct device *dev; |
863 | 867 | ||
864 | struct list_head h_list; | 868 | struct list_head h_list; |