diff options
Diffstat (limited to 'drivers/input/misc/uinput.c')
| -rw-r--r-- | drivers/input/misc/uinput.c | 94 |
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. */ | ||
| 57 | static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) | 58 | static 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 | ||
| 77 | static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) | 78 | static 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 | ||
| 102 | static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) | 103 | static 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 | */ | ||
| 132 | static 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 | ||
| 112 | static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) | 150 | static 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 | ||
| 127 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) | 165 | static 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 | ||
| 156 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | 197 | static 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) | |||
| 176 | static void uinput_destroy_device(struct uinput_device *udev) | 220 | static 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 | ||
| 195 | static int uinput_create_device(struct uinput_device *udev) | 243 | static int uinput_create_device(struct uinput_device *udev) |
