aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-30 01:48:32 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-08-22 01:29:54 -0400
commit00ce756ce53acdb82d408346e6a7b734ca9e5bad (patch)
tree020ee9aba5b30c72fdf2e46ee0dcf210afa9427e /drivers/input
parent22ae19c6e3c22b390952e90f452f26adad9b8687 (diff)
Input: uinput - mark failed submission requests as free
If uinput_request_submit() fails after new request ID was allocated we need to mark that request ID as free, otherwise it will always stay occupied and we may run out of available IDs. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/misc/uinput.c78
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 1719554fe194..6099365102db 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -56,10 +56,11 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i
56} 56}
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. */
59static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) 59static bool uinput_request_alloc_id(struct uinput_device *udev,
60 struct uinput_request *request)
60{ 61{
61 int id; 62 int id;
62 int err = -1; 63 bool reserved = false;
63 64
64 spin_lock(&udev->requests_lock); 65 spin_lock(&udev->requests_lock);
65 66
@@ -67,13 +68,13 @@ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_req
67 if (!udev->requests[id]) { 68 if (!udev->requests[id]) {
68 request->id = id; 69 request->id = id;
69 udev->requests[id] = request; 70 udev->requests[id] = request;
70 err = 0; 71 reserved = true;
71 break; 72 break;
72 } 73 }
73 } 74 }
74 75
75 spin_unlock(&udev->requests_lock); 76 spin_unlock(&udev->requests_lock);
76 return err; 77 return reserved;
77} 78}
78 79
79static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) 80static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
@@ -85,11 +86,12 @@ static struct uinput_request *uinput_request_find(struct uinput_device *udev, in
85 return udev->requests[id]; 86 return udev->requests[id];
86} 87}
87 88
88static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) 89static int uinput_request_reserve_slot(struct uinput_device *udev,
90 struct uinput_request *request)
89{ 91{
90 /* Allocate slot. If none are available right away, wait. */ 92 /* Allocate slot. If none are available right away, wait. */
91 return wait_event_interruptible(udev->requests_waitq, 93 return wait_event_interruptible(udev->requests_waitq,
92 !uinput_request_alloc_id(udev, request)); 94 uinput_request_alloc_id(udev, request));
93} 95}
94 96
95static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) 97static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request)
@@ -101,14 +103,11 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques
101 complete(&request->done); 103 complete(&request->done);
102} 104}
103 105
104static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) 106static int uinput_request_send(struct uinput_device *udev,
107 struct uinput_request *request)
105{ 108{
106 int retval; 109 int retval;
107 110
108 retval = uinput_request_reserve_slot(udev, request);
109 if (retval)
110 return retval;
111
112 retval = mutex_lock_interruptible(&udev->mutex); 111 retval = mutex_lock_interruptible(&udev->mutex);
113 if (retval) 112 if (retval)
114 return retval; 113 return retval;
@@ -118,7 +117,12 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque
118 goto out; 117 goto out;
119 } 118 }
120 119
121 /* Tell our userspace app about this new request by queueing an input event */ 120 init_completion(&request->done);
121
122 /*
123 * Tell our userspace application about this new request
124 * by queueing an input event.
125 */
122 uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); 126 uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
123 127
124 out: 128 out:
@@ -126,6 +130,25 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque
126 return retval; 130 return retval;
127} 131}
128 132
133static int uinput_request_submit(struct uinput_device *udev,
134 struct uinput_request *request)
135{
136 int error;
137
138 error = uinput_request_reserve_slot(udev, request);
139 if (error)
140 return error;
141
142 error = uinput_request_send(udev, request);
143 if (error) {
144 uinput_request_done(udev, request);
145 return error;
146 }
147
148 wait_for_completion(&request->done);
149 return request->retval;
150}
151
129/* 152/*
130 * Fail all ouitstanding requests so handlers don't wait for the userspace 153 * Fail all ouitstanding requests so handlers don't wait for the userspace
131 * to finish processing them. 154 * to finish processing them.
@@ -167,7 +190,6 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
167{ 190{
168 struct uinput_device *udev = input_get_drvdata(dev); 191 struct uinput_device *udev = input_get_drvdata(dev);
169 struct uinput_request request; 192 struct uinput_request request;
170 int retval;
171 193
172 /* 194 /*
173 * uinput driver does not currently support periodic effects with 195 * uinput driver does not currently support periodic effects with
@@ -180,42 +202,25 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
180 effect->u.periodic.waveform == FF_CUSTOM) 202 effect->u.periodic.waveform == FF_CUSTOM)
181 return -EINVAL; 203 return -EINVAL;
182 204
183 request.id = -1;
184 init_completion(&request.done);
185 request.code = UI_FF_UPLOAD; 205 request.code = UI_FF_UPLOAD;
186 request.u.upload.effect = effect; 206 request.u.upload.effect = effect;
187 request.u.upload.old = old; 207 request.u.upload.old = old;
188 208
189 retval = uinput_request_submit(udev, &request); 209 return uinput_request_submit(udev, &request);
190 if (!retval) {
191 wait_for_completion(&request.done);
192 retval = request.retval;
193 }
194
195 return retval;
196} 210}
197 211
198static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) 212static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
199{ 213{
200 struct uinput_device *udev = input_get_drvdata(dev); 214 struct uinput_device *udev = input_get_drvdata(dev);
201 struct uinput_request request; 215 struct uinput_request request;
202 int retval;
203 216
204 if (!test_bit(EV_FF, dev->evbit)) 217 if (!test_bit(EV_FF, dev->evbit))
205 return -ENOSYS; 218 return -ENOSYS;
206 219
207 request.id = -1;
208 init_completion(&request.done);
209 request.code = UI_FF_ERASE; 220 request.code = UI_FF_ERASE;
210 request.u.effect_id = effect_id; 221 request.u.effect_id = effect_id;
211 222
212 retval = uinput_request_submit(udev, &request); 223 return uinput_request_submit(udev, &request);
213 if (!retval) {
214 wait_for_completion(&request.done);
215 retval = request.retval;
216 }
217
218 return retval;
219} 224}
220 225
221static void uinput_destroy_device(struct uinput_device *udev) 226static void uinput_destroy_device(struct uinput_device *udev)
@@ -478,20 +483,17 @@ static ssize_t uinput_events_to_user(struct uinput_device *udev,
478{ 483{
479 struct input_event event; 484 struct input_event event;
480 size_t read = 0; 485 size_t read = 0;
481 int error = 0;
482 486
483 while (read + input_event_size() <= count && 487 while (read + input_event_size() <= count &&
484 uinput_fetch_next_event(udev, &event)) { 488 uinput_fetch_next_event(udev, &event)) {
485 489
486 if (input_event_to_user(buffer + read, &event)) { 490 if (input_event_to_user(buffer + read, &event))
487 error = -EFAULT; 491 return -EFAULT;
488 break;
489 }
490 492
491 read += input_event_size(); 493 read += input_event_size();
492 } 494 }
493 495
494 return read ?: error; 496 return read;
495} 497}
496 498
497static ssize_t uinput_read(struct file *file, char __user *buffer, 499static ssize_t uinput_read(struct file *file, char __user *buffer,