summaryrefslogtreecommitdiffstats
path: root/drivers/input/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-22 23:23:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-22 23:23:41 -0400
commitd32e5f44a5aeb9c1febaf16db45bf888a3f66725 (patch)
tree4ebd5550ea9ed5fc437233f3224fa1c0ea4e372c /drivers/input/misc
parentc0a3a64e723324ae6dda53214061a71de63808c3 (diff)
parent05f5c38576475439f3124a3e6d62db68de83f7be (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input fixes from Dmitry Torokhov: - fixes for two long standing issues (lock up and a crash) in force feedback handling in uinput driver - tweak to firmware update timing in Elan I2C touchpad driver. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: elan_i2c - extend Flash-Write delay Input: uinput - avoid crash when sending FF request to device going away Input: uinput - avoid FF flush when destroying device
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/uinput.c57
1 files changed, 39 insertions, 18 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 022be0e22eba..443151de90c6 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -98,14 +98,15 @@ static int uinput_request_reserve_slot(struct uinput_device *udev,
98 uinput_request_alloc_id(udev, request)); 98 uinput_request_alloc_id(udev, request));
99} 99}
100 100
101static void uinput_request_done(struct uinput_device *udev, 101static void uinput_request_release_slot(struct uinput_device *udev,
102 struct uinput_request *request) 102 unsigned int id)
103{ 103{
104 /* Mark slot as available */ 104 /* Mark slot as available */
105 udev->requests[request->id] = NULL; 105 spin_lock(&udev->requests_lock);
106 wake_up(&udev->requests_waitq); 106 udev->requests[id] = NULL;
107 spin_unlock(&udev->requests_lock);
107 108
108 complete(&request->done); 109 wake_up(&udev->requests_waitq);
109} 110}
110 111
111static int uinput_request_send(struct uinput_device *udev, 112static int uinput_request_send(struct uinput_device *udev,
@@ -138,20 +139,22 @@ static int uinput_request_send(struct uinput_device *udev,
138static int uinput_request_submit(struct uinput_device *udev, 139static int uinput_request_submit(struct uinput_device *udev,
139 struct uinput_request *request) 140 struct uinput_request *request)
140{ 141{
141 int error; 142 int retval;
142 143
143 error = uinput_request_reserve_slot(udev, request); 144 retval = uinput_request_reserve_slot(udev, request);
144 if (error) 145 if (retval)
145 return error; 146 return retval;
146 147
147 error = uinput_request_send(udev, request); 148 retval = uinput_request_send(udev, request);
148 if (error) { 149 if (retval)
149 uinput_request_done(udev, request); 150 goto out;
150 return error;
151 }
152 151
153 wait_for_completion(&request->done); 152 wait_for_completion(&request->done);
154 return request->retval; 153 retval = request->retval;
154
155 out:
156 uinput_request_release_slot(udev, request->id);
157 return retval;
155} 158}
156 159
157/* 160/*
@@ -169,7 +172,7 @@ static void uinput_flush_requests(struct uinput_device *udev)
169 request = udev->requests[i]; 172 request = udev->requests[i];
170 if (request) { 173 if (request) {
171 request->retval = -ENODEV; 174 request->retval = -ENODEV;
172 uinput_request_done(udev, request); 175 complete(&request->done);
173 } 176 }
174 } 177 }
175 178
@@ -230,6 +233,18 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
230 return uinput_request_submit(udev, &request); 233 return uinput_request_submit(udev, &request);
231} 234}
232 235
236static int uinput_dev_flush(struct input_dev *dev, struct file *file)
237{
238 /*
239 * If we are called with file == NULL that means we are tearing
240 * down the device, and therefore we can not handle FF erase
241 * requests: either we are handling UI_DEV_DESTROY (and holding
242 * the udev->mutex), or the file descriptor is closed and there is
243 * nobody on the other side anymore.
244 */
245 return file ? input_ff_flush(dev, file) : 0;
246}
247
233static void uinput_destroy_device(struct uinput_device *udev) 248static void uinput_destroy_device(struct uinput_device *udev)
234{ 249{
235 const char *name, *phys; 250 const char *name, *phys;
@@ -297,6 +312,12 @@ static int uinput_create_device(struct uinput_device *udev)
297 dev->ff->playback = uinput_dev_playback; 312 dev->ff->playback = uinput_dev_playback;
298 dev->ff->set_gain = uinput_dev_set_gain; 313 dev->ff->set_gain = uinput_dev_set_gain;
299 dev->ff->set_autocenter = uinput_dev_set_autocenter; 314 dev->ff->set_autocenter = uinput_dev_set_autocenter;
315 /*
316 * The standard input_ff_flush() implementation does
317 * not quite work for uinput as we can't reasonably
318 * handle FF requests during device teardown.
319 */
320 dev->flush = uinput_dev_flush;
300 } 321 }
301 322
302 error = input_register_device(udev->dev); 323 error = input_register_device(udev->dev);
@@ -939,7 +960,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
939 } 960 }
940 961
941 req->retval = ff_up.retval; 962 req->retval = ff_up.retval;
942 uinput_request_done(udev, req); 963 complete(&req->done);
943 goto out; 964 goto out;
944 965
945 case UI_END_FF_ERASE: 966 case UI_END_FF_ERASE:
@@ -955,7 +976,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
955 } 976 }
956 977
957 req->retval = ff_erase.retval; 978 req->retval = ff_erase.retval;
958 uinput_request_done(udev, req); 979 complete(&req->done);
959 goto out; 980 goto out;
960 } 981 }
961 982