diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 23:23:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 23:23:41 -0400 |
commit | d32e5f44a5aeb9c1febaf16db45bf888a3f66725 (patch) | |
tree | 4ebd5550ea9ed5fc437233f3224fa1c0ea4e372c /drivers/input/misc | |
parent | c0a3a64e723324ae6dda53214061a71de63808c3 (diff) | |
parent | 05f5c38576475439f3124a3e6d62db68de83f7be (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.c | 57 |
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 | ||
101 | static void uinput_request_done(struct uinput_device *udev, | 101 | static 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 | ||
111 | static int uinput_request_send(struct uinput_device *udev, | 112 | static int uinput_request_send(struct uinput_device *udev, |
@@ -138,20 +139,22 @@ static int uinput_request_send(struct uinput_device *udev, | |||
138 | static int uinput_request_submit(struct uinput_device *udev, | 139 | static 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 | ||
236 | static 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 | |||
233 | static void uinput_destroy_device(struct uinput_device *udev) | 248 | static 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 | ||