aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
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 1719554fe19..6099365102d 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,