aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/misc/uinput.c94
1 files changed, 71 insertions, 23 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 46b7caeb2817..c5a49aba418f 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -54,27 +54,28 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i
54 return 0; 54 return 0;
55} 55}
56 56
57/* Atomically allocate an ID for the given request. Returns 0 on success. */
57static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) 58static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
58{ 59{
59 /* Atomically allocate an ID for the given request. Returns 0 on success. */
60 int id; 60 int id;
61 int err = -1; 61 int err = -1;
62 62
63 spin_lock(&udev->requests_lock); 63 spin_lock(&udev->requests_lock);
64 64
65 for (id = 0; id < UINPUT_NUM_REQUESTS; id++) 65 for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
66 if (!udev->requests[id]) { 66 if (!udev->requests[id]) {
67 request->id = id; 67 request->id = id;
68 udev->requests[id] = request; 68 udev->requests[id] = request;
69 err = 0; 69 err = 0;
70 break; 70 break;
71 } 71 }
72 }
72 73
73 spin_unlock(&udev->requests_lock); 74 spin_unlock(&udev->requests_lock);
74 return err; 75 return err;
75} 76}
76 77
77static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) 78static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
78{ 79{
79 /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ 80 /* Find an input request, by ID. Returns NULL if the ID isn't valid. */
80 if (id >= UINPUT_NUM_REQUESTS || id < 0) 81 if (id >= UINPUT_NUM_REQUESTS || id < 0)
@@ -99,14 +100,51 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques
99 complete(&request->done); 100 complete(&request->done);
100} 101}
101 102
102static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) 103static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
103{ 104{
105 int retval;
106
107 retval = uinput_request_reserve_slot(udev, request);
108 if (retval)
109 return retval;
110
111 retval = mutex_lock_interruptible(&udev->mutex);
112 if (retval)
113 return retval;
114
115 if (udev->state != UIST_CREATED) {
116 retval = -ENODEV;
117 goto out;
118 }
119
104 /* Tell our userspace app about this new request by queueing an input event */ 120 /* Tell our userspace app about this new request by queueing an input event */
105 uinput_dev_event(dev, EV_UINPUT, request->code, request->id); 121 uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
122
123 out:
124 mutex_unlock(&udev->mutex);
125 return retval;
126}
127
128/*
129 * Fail all ouitstanding requests so handlers don't wait for the userspace
130 * to finish processing them.
131 */
132static void uinput_flush_requests(struct uinput_device *udev)
133{
134 struct uinput_request *request;
135 int i;
136
137 spin_lock(&udev->requests_lock);
138
139 for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
140 request = udev->requests[i];
141 if (request) {
142 request->retval = -ENODEV;
143 uinput_request_done(udev, request);
144 }
145 }
106 146
107 /* Wait for the request to complete */ 147 spin_unlock(&udev->requests_lock);
108 wait_for_completion(&request->done);
109 return request->retval;
110} 148}
111 149
112static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) 150static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
@@ -126,6 +164,7 @@ static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
126 164
127static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) 165static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
128{ 166{
167 struct uinput_device *udev = input_get_drvdata(dev);
129 struct uinput_request request; 168 struct uinput_request request;
130 int retval; 169 int retval;
131 170
@@ -146,15 +185,18 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
146 request.u.upload.effect = effect; 185 request.u.upload.effect = effect;
147 request.u.upload.old = old; 186 request.u.upload.old = old;
148 187
149 retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); 188 retval = uinput_request_submit(udev, &request);
150 if (!retval) 189 if (!retval) {
151 retval = uinput_request_submit(dev, &request); 190 wait_for_completion(&request.done);
191 retval = request.retval;
192 }
152 193
153 return retval; 194 return retval;
154} 195}
155 196
156static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) 197static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
157{ 198{
199 struct uinput_device *udev = input_get_drvdata(dev);
158 struct uinput_request request; 200 struct uinput_request request;
159 int retval; 201 int retval;
160 202
@@ -166,9 +208,11 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
166 request.code = UI_FF_ERASE; 208 request.code = UI_FF_ERASE;
167 request.u.effect_id = effect_id; 209 request.u.effect_id = effect_id;
168 210
169 retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); 211 retval = uinput_request_submit(udev, &request);
170 if (!retval) 212 if (!retval) {
171 retval = uinput_request_submit(dev, &request); 213 wait_for_completion(&request.done);
214 retval = request.retval;
215 }
172 216
173 return retval; 217 return retval;
174} 218}
@@ -176,20 +220,24 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
176static void uinput_destroy_device(struct uinput_device *udev) 220static void uinput_destroy_device(struct uinput_device *udev)
177{ 221{
178 const char *name, *phys; 222 const char *name, *phys;
223 struct input_dev *dev = udev->dev;
224 enum uinput_state old_state = udev->state;
179 225
180 if (udev->dev) { 226 udev->state = UIST_NEW_DEVICE;
181 name = udev->dev->name; 227
182 phys = udev->dev->phys; 228 if (dev) {
183 if (udev->state == UIST_CREATED) 229 name = dev->name;
184 input_unregister_device(udev->dev); 230 phys = dev->phys;
185 else 231 if (old_state == UIST_CREATED) {
186 input_free_device(udev->dev); 232 uinput_flush_requests(udev);
233 input_unregister_device(dev);
234 } else {
235 input_free_device(dev);
236 }
187 kfree(name); 237 kfree(name);
188 kfree(phys); 238 kfree(phys);
189 udev->dev = NULL; 239 udev->dev = NULL;
190 } 240 }
191
192 udev->state = UIST_NEW_DEVICE;
193} 241}
194 242
195static int uinput_create_device(struct uinput_device *udev) 243static int uinput_create_device(struct uinput_device *udev)