diff options
| author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-06-30 01:48:14 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-06-30 01:48:14 -0400 |
| commit | 0048e6030d41453c2f5ce0e9aead910d46cfd448 (patch) | |
| tree | f7d6ed2acdc2ee4db3ffba332ba629efc014c1ee /drivers/input | |
| parent | 152c12f568d4fc6e9a7dfd42f2d51347fb41d9b7 (diff) | |
Input: uinput - use completions instead of events and manual
wakeups in force feedback code.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/misc/uinput.c | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 9c3d20073ae3..c3eebf593ab6 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
| @@ -53,24 +53,23 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i | |||
| 53 | return 0; | 53 | return 0; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) | 56 | static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) |
| 57 | { | 57 | { |
| 58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ | 58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ |
| 59 | struct uinput_device *udev = dev->private; | ||
| 60 | int id; | 59 | int id; |
| 61 | int err = -1; | 60 | int err = -1; |
| 62 | 61 | ||
| 63 | down(&udev->requests_sem); | 62 | spin_lock(&udev->requests_lock); |
| 64 | 63 | ||
| 65 | for (id = 0; id < UINPUT_NUM_REQUESTS; id++) | 64 | for (id = 0; id < UINPUT_NUM_REQUESTS; id++) |
| 66 | if (!udev->requests[id]) { | 65 | if (!udev->requests[id]) { |
| 67 | udev->requests[id] = request; | ||
| 68 | request->id = id; | 66 | request->id = id; |
| 67 | udev->requests[id] = request; | ||
| 69 | err = 0; | 68 | err = 0; |
| 70 | break; | 69 | break; |
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | up(&udev->requests_sem); | 72 | spin_unlock(&udev->requests_lock); |
| 74 | return err; | 73 | return err; |
| 75 | } | 74 | } |
| 76 | 75 | ||
| @@ -79,70 +78,78 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in | |||
| 79 | /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ | 78 | /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ |
| 80 | if (id >= UINPUT_NUM_REQUESTS || id < 0) | 79 | if (id >= UINPUT_NUM_REQUESTS || id < 0) |
| 81 | return NULL; | 80 | return NULL; |
| 82 | if (udev->requests[id]->completed) | ||
| 83 | return NULL; | ||
| 84 | return udev->requests[id]; | 81 | return udev->requests[id]; |
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) | 84 | static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) |
| 88 | { | 85 | { |
| 89 | struct uinput_device *udev = dev->private; | 86 | /* Allocate slot. If none are available right away, wait. */ |
| 87 | return wait_event_interruptible(udev->requests_waitq, | ||
| 88 | !uinput_request_alloc_id(udev, request)); | ||
| 89 | } | ||
| 90 | 90 | ||
| 91 | memset(request, 0, sizeof(struct uinput_request)); | 91 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) |
| 92 | request->code = code; | 92 | { |
| 93 | init_waitqueue_head(&request->waitq); | 93 | complete(&request->done); |
| 94 | 94 | ||
| 95 | /* Allocate an ID. If none are available right away, wait. */ | 95 | /* Mark slot as available */ |
| 96 | request->retval = wait_event_interruptible(udev->requests_waitq, | 96 | udev->requests[request->id] = NULL; |
| 97 | !uinput_request_alloc_id(dev, request)); | 97 | wake_up_interruptible(&udev->requests_waitq); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) | 100 | static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) |
| 101 | { | 101 | { |
| 102 | struct uinput_device *udev = dev->private; | ||
| 103 | int retval; | 102 | int retval; |
| 104 | 103 | ||
| 105 | /* Tell our userspace app about this new request by queueing an input event */ | 104 | /* Tell our userspace app about this new request by queueing an input event */ |
| 106 | uinput_dev_event(dev, EV_UINPUT, request->code, request->id); | 105 | uinput_dev_event(dev, EV_UINPUT, request->code, request->id); |
| 107 | 106 | ||
| 108 | /* Wait for the request to complete */ | 107 | /* Wait for the request to complete */ |
| 109 | retval = wait_event_interruptible(request->waitq, request->completed); | 108 | retval = wait_for_completion_interruptible(&request->done); |
| 110 | if (retval) | 109 | if (!retval) |
| 111 | request->retval = retval; | 110 | retval = request->retval; |
| 112 | 111 | ||
| 113 | /* Release this request's ID, let others know it's available */ | 112 | return retval; |
| 114 | udev->requests[request->id] = NULL; | ||
| 115 | wake_up_interruptible(&udev->requests_waitq); | ||
| 116 | } | 113 | } |
| 117 | 114 | ||
| 118 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 115 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) |
| 119 | { | 116 | { |
| 120 | struct uinput_request request; | 117 | struct uinput_request request; |
| 118 | int retval; | ||
| 121 | 119 | ||
| 122 | if (!test_bit(EV_FF, dev->evbit)) | 120 | if (!test_bit(EV_FF, dev->evbit)) |
| 123 | return -ENOSYS; | 121 | return -ENOSYS; |
| 124 | 122 | ||
| 125 | uinput_request_init(dev, &request, UI_FF_UPLOAD); | 123 | request.id = -1; |
| 126 | if (request.retval) | 124 | init_completion(&request.done); |
| 127 | return request.retval; | 125 | request.code = UI_FF_UPLOAD; |
| 128 | request.u.effect = effect; | 126 | request.u.effect = effect; |
| 129 | uinput_request_submit(dev, &request); | 127 | |
| 130 | return request.retval; | 128 | retval = uinput_request_reserve_slot(dev->private, &request); |
| 129 | if (!retval) | ||
| 130 | retval = uinput_request_submit(dev, &request); | ||
| 131 | |||
| 132 | return retval; | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | 135 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) |
| 134 | { | 136 | { |
| 135 | struct uinput_request request; | 137 | struct uinput_request request; |
| 138 | int retval; | ||
| 136 | 139 | ||
| 137 | if (!test_bit(EV_FF, dev->evbit)) | 140 | if (!test_bit(EV_FF, dev->evbit)) |
| 138 | return -ENOSYS; | 141 | return -ENOSYS; |
| 139 | 142 | ||
| 140 | uinput_request_init(dev, &request, UI_FF_ERASE); | 143 | request.id = -1; |
| 141 | if (request.retval) | 144 | init_completion(&request.done); |
| 142 | return request.retval; | 145 | request.code = UI_FF_ERASE; |
| 143 | request.u.effect_id = effect_id; | 146 | request.u.effect_id = effect_id; |
| 144 | uinput_request_submit(dev, &request); | 147 | |
| 145 | return request.retval; | 148 | retval = uinput_request_reserve_slot(dev->private, &request); |
| 149 | if (!retval) | ||
| 150 | retval = uinput_request_submit(dev, &request); | ||
| 151 | |||
| 152 | return retval; | ||
| 146 | } | 153 | } |
| 147 | 154 | ||
| 148 | static int uinput_create_device(struct uinput_device *udev) | 155 | static int uinput_create_device(struct uinput_device *udev) |
| @@ -189,7 +196,7 @@ static int uinput_open(struct inode *inode, struct file *file) | |||
| 189 | if (!newdev) | 196 | if (!newdev) |
| 190 | goto error; | 197 | goto error; |
| 191 | memset(newdev, 0, sizeof(struct uinput_device)); | 198 | memset(newdev, 0, sizeof(struct uinput_device)); |
| 192 | init_MUTEX(&newdev->requests_sem); | 199 | spin_lock_init(&newdev->requests_lock); |
| 193 | init_waitqueue_head(&newdev->requests_waitq); | 200 | init_waitqueue_head(&newdev->requests_waitq); |
| 194 | 201 | ||
| 195 | newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); | 202 | newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); |
| @@ -551,8 +558,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
| 551 | } | 558 | } |
| 552 | req->retval = ff_up.retval; | 559 | req->retval = ff_up.retval; |
| 553 | memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); | 560 | memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); |
| 554 | req->completed = 1; | 561 | uinput_request_done(udev, req); |
| 555 | wake_up_interruptible(&req->waitq); | ||
| 556 | break; | 562 | break; |
| 557 | 563 | ||
| 558 | case UI_END_FF_ERASE: | 564 | case UI_END_FF_ERASE: |
| @@ -566,8 +572,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
| 566 | break; | 572 | break; |
| 567 | } | 573 | } |
| 568 | req->retval = ff_erase.retval; | 574 | req->retval = ff_erase.retval; |
| 569 | req->completed = 1; | 575 | uinput_request_done(udev, req); |
| 570 | wake_up_interruptible(&req->waitq); | ||
| 571 | break; | 576 | break; |
| 572 | 577 | ||
| 573 | default: | 578 | default: |
