Commit 8905aaafb4b5d9764c5b4b54c7d03eb41bb0a7e9
Committed by
Dmitry Torokhov
1 parent
77edf0c751
Exists in
master
and in
39 other branches
Input: uinput - add devname alias to allow module on-demand load
Recent modprobe and udev versions allow to create device nodes for modules which are not loaded. Only the first access will cause the in-kernel module loader to pull-in the module. Systems which never access the device node will not needlessly load the module, and no longer need init scripts or other facilities to unconditionally load it. Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 3 changed files with 3 additions and 1 deletions Inline Diff
drivers/input/misc/uinput.c
1 | /* | 1 | /* |
2 | * User level driver support for input subsystem | 2 | * User level driver support for input subsystem |
3 | * | 3 | * |
4 | * Heavily based on evdev.c by Vojtech Pavlik | 4 | * Heavily based on evdev.c by Vojtech Pavlik |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | * | 19 | * |
20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | 20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> |
21 | * | 21 | * |
22 | * Changes/Revisions: | 22 | * Changes/Revisions: |
23 | * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) | 23 | * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) |
24 | * - updated ff support for the changes in kernel interface | 24 | * - updated ff support for the changes in kernel interface |
25 | * - added MODULE_VERSION | 25 | * - added MODULE_VERSION |
26 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | 26 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) |
27 | * - added force feedback support | 27 | * - added force feedback support |
28 | * - added UI_SET_PHYS | 28 | * - added UI_SET_PHYS |
29 | * 0.1 20/06/2002 | 29 | * 0.1 20/06/2002 |
30 | * - first public version | 30 | * - first public version |
31 | */ | 31 | */ |
32 | #include <linux/poll.h> | 32 | #include <linux/poll.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/fs.h> | 37 | #include <linux/fs.h> |
38 | #include <linux/miscdevice.h> | 38 | #include <linux/miscdevice.h> |
39 | #include <linux/uinput.h> | 39 | #include <linux/uinput.h> |
40 | #include "../input-compat.h" | 40 | #include "../input-compat.h" |
41 | 41 | ||
42 | static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 42 | static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
43 | { | 43 | { |
44 | struct uinput_device *udev = input_get_drvdata(dev); | 44 | struct uinput_device *udev = input_get_drvdata(dev); |
45 | 45 | ||
46 | udev->buff[udev->head].type = type; | 46 | udev->buff[udev->head].type = type; |
47 | udev->buff[udev->head].code = code; | 47 | udev->buff[udev->head].code = code; |
48 | udev->buff[udev->head].value = value; | 48 | udev->buff[udev->head].value = value; |
49 | do_gettimeofday(&udev->buff[udev->head].time); | 49 | do_gettimeofday(&udev->buff[udev->head].time); |
50 | udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; | 50 | udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; |
51 | 51 | ||
52 | wake_up_interruptible(&udev->waitq); | 52 | wake_up_interruptible(&udev->waitq); |
53 | 53 | ||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ | 57 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ |
58 | 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) |
59 | { | 59 | { |
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 | ||
74 | spin_unlock(&udev->requests_lock); | 74 | spin_unlock(&udev->requests_lock); |
75 | return err; | 75 | return err; |
76 | } | 76 | } |
77 | 77 | ||
78 | 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) |
79 | { | 79 | { |
80 | /* 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. */ |
81 | if (id >= UINPUT_NUM_REQUESTS || id < 0) | 81 | if (id >= UINPUT_NUM_REQUESTS || id < 0) |
82 | return NULL; | 82 | return NULL; |
83 | 83 | ||
84 | return udev->requests[id]; | 84 | return udev->requests[id]; |
85 | } | 85 | } |
86 | 86 | ||
87 | static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) | 87 | static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) |
88 | { | 88 | { |
89 | /* Allocate slot. If none are available right away, wait. */ | 89 | /* Allocate slot. If none are available right away, wait. */ |
90 | return wait_event_interruptible(udev->requests_waitq, | 90 | return wait_event_interruptible(udev->requests_waitq, |
91 | !uinput_request_alloc_id(udev, request)); | 91 | !uinput_request_alloc_id(udev, request)); |
92 | } | 92 | } |
93 | 93 | ||
94 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) | 94 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) |
95 | { | 95 | { |
96 | /* Mark slot as available */ | 96 | /* Mark slot as available */ |
97 | udev->requests[request->id] = NULL; | 97 | udev->requests[request->id] = NULL; |
98 | wake_up(&udev->requests_waitq); | 98 | wake_up(&udev->requests_waitq); |
99 | 99 | ||
100 | complete(&request->done); | 100 | complete(&request->done); |
101 | } | 101 | } |
102 | 102 | ||
103 | static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) | 103 | static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) |
104 | { | 104 | { |
105 | int retval; | 105 | int retval; |
106 | 106 | ||
107 | retval = uinput_request_reserve_slot(udev, request); | 107 | retval = uinput_request_reserve_slot(udev, request); |
108 | if (retval) | 108 | if (retval) |
109 | return retval; | 109 | return retval; |
110 | 110 | ||
111 | retval = mutex_lock_interruptible(&udev->mutex); | 111 | retval = mutex_lock_interruptible(&udev->mutex); |
112 | if (retval) | 112 | if (retval) |
113 | return retval; | 113 | return retval; |
114 | 114 | ||
115 | if (udev->state != UIST_CREATED) { | 115 | if (udev->state != UIST_CREATED) { |
116 | retval = -ENODEV; | 116 | retval = -ENODEV; |
117 | goto out; | 117 | goto out; |
118 | } | 118 | } |
119 | 119 | ||
120 | /* 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 */ |
121 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); | 121 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); |
122 | 122 | ||
123 | out: | 123 | out: |
124 | mutex_unlock(&udev->mutex); | 124 | mutex_unlock(&udev->mutex); |
125 | return retval; | 125 | return retval; |
126 | } | 126 | } |
127 | 127 | ||
128 | /* | 128 | /* |
129 | * Fail all ouitstanding requests so handlers don't wait for the userspace | 129 | * Fail all ouitstanding requests so handlers don't wait for the userspace |
130 | * to finish processing them. | 130 | * to finish processing them. |
131 | */ | 131 | */ |
132 | static void uinput_flush_requests(struct uinput_device *udev) | 132 | static void uinput_flush_requests(struct uinput_device *udev) |
133 | { | 133 | { |
134 | struct uinput_request *request; | 134 | struct uinput_request *request; |
135 | int i; | 135 | int i; |
136 | 136 | ||
137 | spin_lock(&udev->requests_lock); | 137 | spin_lock(&udev->requests_lock); |
138 | 138 | ||
139 | for (i = 0; i < UINPUT_NUM_REQUESTS; i++) { | 139 | for (i = 0; i < UINPUT_NUM_REQUESTS; i++) { |
140 | request = udev->requests[i]; | 140 | request = udev->requests[i]; |
141 | if (request) { | 141 | if (request) { |
142 | request->retval = -ENODEV; | 142 | request->retval = -ENODEV; |
143 | uinput_request_done(udev, request); | 143 | uinput_request_done(udev, request); |
144 | } | 144 | } |
145 | } | 145 | } |
146 | 146 | ||
147 | spin_unlock(&udev->requests_lock); | 147 | spin_unlock(&udev->requests_lock); |
148 | } | 148 | } |
149 | 149 | ||
150 | 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) |
151 | { | 151 | { |
152 | uinput_dev_event(dev, EV_FF, FF_GAIN, gain); | 152 | uinput_dev_event(dev, EV_FF, FF_GAIN, gain); |
153 | } | 153 | } |
154 | 154 | ||
155 | static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) | 155 | static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) |
156 | { | 156 | { |
157 | uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); | 157 | uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); |
158 | } | 158 | } |
159 | 159 | ||
160 | static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) | 160 | static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) |
161 | { | 161 | { |
162 | return uinput_dev_event(dev, EV_FF, effect_id, value); | 162 | return uinput_dev_event(dev, EV_FF, effect_id, value); |
163 | } | 163 | } |
164 | 164 | ||
165 | 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) |
166 | { | 166 | { |
167 | struct uinput_device *udev = input_get_drvdata(dev); | 167 | struct uinput_device *udev = input_get_drvdata(dev); |
168 | struct uinput_request request; | 168 | struct uinput_request request; |
169 | int retval; | 169 | int retval; |
170 | 170 | ||
171 | /* | 171 | /* |
172 | * uinput driver does not currently support periodic effects with | 172 | * uinput driver does not currently support periodic effects with |
173 | * custom waveform since it does not have a way to pass buffer of | 173 | * custom waveform since it does not have a way to pass buffer of |
174 | * samples (custom_data) to userspace. If ever there is a device | 174 | * samples (custom_data) to userspace. If ever there is a device |
175 | * supporting custom waveforms we would need to define an additional | 175 | * supporting custom waveforms we would need to define an additional |
176 | * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. | 176 | * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. |
177 | */ | 177 | */ |
178 | if (effect->type == FF_PERIODIC && | 178 | if (effect->type == FF_PERIODIC && |
179 | effect->u.periodic.waveform == FF_CUSTOM) | 179 | effect->u.periodic.waveform == FF_CUSTOM) |
180 | return -EINVAL; | 180 | return -EINVAL; |
181 | 181 | ||
182 | request.id = -1; | 182 | request.id = -1; |
183 | init_completion(&request.done); | 183 | init_completion(&request.done); |
184 | request.code = UI_FF_UPLOAD; | 184 | request.code = UI_FF_UPLOAD; |
185 | request.u.upload.effect = effect; | 185 | request.u.upload.effect = effect; |
186 | request.u.upload.old = old; | 186 | request.u.upload.old = old; |
187 | 187 | ||
188 | retval = uinput_request_submit(udev, &request); | 188 | retval = uinput_request_submit(udev, &request); |
189 | if (!retval) { | 189 | if (!retval) { |
190 | wait_for_completion(&request.done); | 190 | wait_for_completion(&request.done); |
191 | retval = request.retval; | 191 | retval = request.retval; |
192 | } | 192 | } |
193 | 193 | ||
194 | return retval; | 194 | return retval; |
195 | } | 195 | } |
196 | 196 | ||
197 | 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) |
198 | { | 198 | { |
199 | struct uinput_device *udev = input_get_drvdata(dev); | 199 | struct uinput_device *udev = input_get_drvdata(dev); |
200 | struct uinput_request request; | 200 | struct uinput_request request; |
201 | int retval; | 201 | int retval; |
202 | 202 | ||
203 | if (!test_bit(EV_FF, dev->evbit)) | 203 | if (!test_bit(EV_FF, dev->evbit)) |
204 | return -ENOSYS; | 204 | return -ENOSYS; |
205 | 205 | ||
206 | request.id = -1; | 206 | request.id = -1; |
207 | init_completion(&request.done); | 207 | init_completion(&request.done); |
208 | request.code = UI_FF_ERASE; | 208 | request.code = UI_FF_ERASE; |
209 | request.u.effect_id = effect_id; | 209 | request.u.effect_id = effect_id; |
210 | 210 | ||
211 | retval = uinput_request_submit(udev, &request); | 211 | retval = uinput_request_submit(udev, &request); |
212 | if (!retval) { | 212 | if (!retval) { |
213 | wait_for_completion(&request.done); | 213 | wait_for_completion(&request.done); |
214 | retval = request.retval; | 214 | retval = request.retval; |
215 | } | 215 | } |
216 | 216 | ||
217 | return retval; | 217 | return retval; |
218 | } | 218 | } |
219 | 219 | ||
220 | static void uinput_destroy_device(struct uinput_device *udev) | 220 | static void uinput_destroy_device(struct uinput_device *udev) |
221 | { | 221 | { |
222 | const char *name, *phys; | 222 | const char *name, *phys; |
223 | struct input_dev *dev = udev->dev; | 223 | struct input_dev *dev = udev->dev; |
224 | enum uinput_state old_state = udev->state; | 224 | enum uinput_state old_state = udev->state; |
225 | 225 | ||
226 | udev->state = UIST_NEW_DEVICE; | 226 | udev->state = UIST_NEW_DEVICE; |
227 | 227 | ||
228 | if (dev) { | 228 | if (dev) { |
229 | name = dev->name; | 229 | name = dev->name; |
230 | phys = dev->phys; | 230 | phys = dev->phys; |
231 | if (old_state == UIST_CREATED) { | 231 | if (old_state == UIST_CREATED) { |
232 | uinput_flush_requests(udev); | 232 | uinput_flush_requests(udev); |
233 | input_unregister_device(dev); | 233 | input_unregister_device(dev); |
234 | } else { | 234 | } else { |
235 | input_free_device(dev); | 235 | input_free_device(dev); |
236 | } | 236 | } |
237 | kfree(name); | 237 | kfree(name); |
238 | kfree(phys); | 238 | kfree(phys); |
239 | udev->dev = NULL; | 239 | udev->dev = NULL; |
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
243 | static int uinput_create_device(struct uinput_device *udev) | 243 | static int uinput_create_device(struct uinput_device *udev) |
244 | { | 244 | { |
245 | struct input_dev *dev = udev->dev; | 245 | struct input_dev *dev = udev->dev; |
246 | int error; | 246 | int error; |
247 | 247 | ||
248 | if (udev->state != UIST_SETUP_COMPLETE) { | 248 | if (udev->state != UIST_SETUP_COMPLETE) { |
249 | printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); | 249 | printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); |
250 | return -EINVAL; | 250 | return -EINVAL; |
251 | } | 251 | } |
252 | 252 | ||
253 | if (udev->ff_effects_max) { | 253 | if (udev->ff_effects_max) { |
254 | error = input_ff_create(dev, udev->ff_effects_max); | 254 | error = input_ff_create(dev, udev->ff_effects_max); |
255 | if (error) | 255 | if (error) |
256 | goto fail1; | 256 | goto fail1; |
257 | 257 | ||
258 | dev->ff->upload = uinput_dev_upload_effect; | 258 | dev->ff->upload = uinput_dev_upload_effect; |
259 | dev->ff->erase = uinput_dev_erase_effect; | 259 | dev->ff->erase = uinput_dev_erase_effect; |
260 | dev->ff->playback = uinput_dev_playback; | 260 | dev->ff->playback = uinput_dev_playback; |
261 | dev->ff->set_gain = uinput_dev_set_gain; | 261 | dev->ff->set_gain = uinput_dev_set_gain; |
262 | dev->ff->set_autocenter = uinput_dev_set_autocenter; | 262 | dev->ff->set_autocenter = uinput_dev_set_autocenter; |
263 | } | 263 | } |
264 | 264 | ||
265 | error = input_register_device(udev->dev); | 265 | error = input_register_device(udev->dev); |
266 | if (error) | 266 | if (error) |
267 | goto fail2; | 267 | goto fail2; |
268 | 268 | ||
269 | udev->state = UIST_CREATED; | 269 | udev->state = UIST_CREATED; |
270 | 270 | ||
271 | return 0; | 271 | return 0; |
272 | 272 | ||
273 | fail2: input_ff_destroy(dev); | 273 | fail2: input_ff_destroy(dev); |
274 | fail1: uinput_destroy_device(udev); | 274 | fail1: uinput_destroy_device(udev); |
275 | return error; | 275 | return error; |
276 | } | 276 | } |
277 | 277 | ||
278 | static int uinput_open(struct inode *inode, struct file *file) | 278 | static int uinput_open(struct inode *inode, struct file *file) |
279 | { | 279 | { |
280 | struct uinput_device *newdev; | 280 | struct uinput_device *newdev; |
281 | 281 | ||
282 | newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL); | 282 | newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL); |
283 | if (!newdev) | 283 | if (!newdev) |
284 | return -ENOMEM; | 284 | return -ENOMEM; |
285 | 285 | ||
286 | mutex_init(&newdev->mutex); | 286 | mutex_init(&newdev->mutex); |
287 | spin_lock_init(&newdev->requests_lock); | 287 | spin_lock_init(&newdev->requests_lock); |
288 | init_waitqueue_head(&newdev->requests_waitq); | 288 | init_waitqueue_head(&newdev->requests_waitq); |
289 | init_waitqueue_head(&newdev->waitq); | 289 | init_waitqueue_head(&newdev->waitq); |
290 | newdev->state = UIST_NEW_DEVICE; | 290 | newdev->state = UIST_NEW_DEVICE; |
291 | 291 | ||
292 | file->private_data = newdev; | 292 | file->private_data = newdev; |
293 | nonseekable_open(inode, file); | 293 | nonseekable_open(inode, file); |
294 | 294 | ||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int uinput_validate_absbits(struct input_dev *dev) | 298 | static int uinput_validate_absbits(struct input_dev *dev) |
299 | { | 299 | { |
300 | unsigned int cnt; | 300 | unsigned int cnt; |
301 | int retval = 0; | 301 | int retval = 0; |
302 | 302 | ||
303 | for (cnt = 0; cnt < ABS_CNT; cnt++) { | 303 | for (cnt = 0; cnt < ABS_CNT; cnt++) { |
304 | if (!test_bit(cnt, dev->absbit)) | 304 | if (!test_bit(cnt, dev->absbit)) |
305 | continue; | 305 | continue; |
306 | 306 | ||
307 | if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { | 307 | if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { |
308 | printk(KERN_DEBUG | 308 | printk(KERN_DEBUG |
309 | "%s: invalid abs[%02x] min:%d max:%d\n", | 309 | "%s: invalid abs[%02x] min:%d max:%d\n", |
310 | UINPUT_NAME, cnt, | 310 | UINPUT_NAME, cnt, |
311 | input_abs_get_min(dev, cnt), | 311 | input_abs_get_min(dev, cnt), |
312 | input_abs_get_max(dev, cnt)); | 312 | input_abs_get_max(dev, cnt)); |
313 | retval = -EINVAL; | 313 | retval = -EINVAL; |
314 | break; | 314 | break; |
315 | } | 315 | } |
316 | 316 | ||
317 | if (input_abs_get_flat(dev, cnt) > | 317 | if (input_abs_get_flat(dev, cnt) > |
318 | input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) { | 318 | input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) { |
319 | printk(KERN_DEBUG | 319 | printk(KERN_DEBUG |
320 | "%s: abs_flat #%02x out of range: %d " | 320 | "%s: abs_flat #%02x out of range: %d " |
321 | "(min:%d/max:%d)\n", | 321 | "(min:%d/max:%d)\n", |
322 | UINPUT_NAME, cnt, | 322 | UINPUT_NAME, cnt, |
323 | input_abs_get_flat(dev, cnt), | 323 | input_abs_get_flat(dev, cnt), |
324 | input_abs_get_min(dev, cnt), | 324 | input_abs_get_min(dev, cnt), |
325 | input_abs_get_max(dev, cnt)); | 325 | input_abs_get_max(dev, cnt)); |
326 | retval = -EINVAL; | 326 | retval = -EINVAL; |
327 | break; | 327 | break; |
328 | } | 328 | } |
329 | } | 329 | } |
330 | return retval; | 330 | return retval; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int uinput_allocate_device(struct uinput_device *udev) | 333 | static int uinput_allocate_device(struct uinput_device *udev) |
334 | { | 334 | { |
335 | udev->dev = input_allocate_device(); | 335 | udev->dev = input_allocate_device(); |
336 | if (!udev->dev) | 336 | if (!udev->dev) |
337 | return -ENOMEM; | 337 | return -ENOMEM; |
338 | 338 | ||
339 | udev->dev->event = uinput_dev_event; | 339 | udev->dev->event = uinput_dev_event; |
340 | input_set_drvdata(udev->dev, udev); | 340 | input_set_drvdata(udev->dev, udev); |
341 | 341 | ||
342 | return 0; | 342 | return 0; |
343 | } | 343 | } |
344 | 344 | ||
345 | static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) | 345 | static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) |
346 | { | 346 | { |
347 | struct uinput_user_dev *user_dev; | 347 | struct uinput_user_dev *user_dev; |
348 | struct input_dev *dev; | 348 | struct input_dev *dev; |
349 | char *name; | 349 | char *name; |
350 | int i, size; | 350 | int i, size; |
351 | int retval; | 351 | int retval; |
352 | 352 | ||
353 | if (count != sizeof(struct uinput_user_dev)) | 353 | if (count != sizeof(struct uinput_user_dev)) |
354 | return -EINVAL; | 354 | return -EINVAL; |
355 | 355 | ||
356 | if (!udev->dev) { | 356 | if (!udev->dev) { |
357 | retval = uinput_allocate_device(udev); | 357 | retval = uinput_allocate_device(udev); |
358 | if (retval) | 358 | if (retval) |
359 | return retval; | 359 | return retval; |
360 | } | 360 | } |
361 | 361 | ||
362 | dev = udev->dev; | 362 | dev = udev->dev; |
363 | 363 | ||
364 | user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); | 364 | user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); |
365 | if (!user_dev) | 365 | if (!user_dev) |
366 | return -ENOMEM; | 366 | return -ENOMEM; |
367 | 367 | ||
368 | if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { | 368 | if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { |
369 | retval = -EFAULT; | 369 | retval = -EFAULT; |
370 | goto exit; | 370 | goto exit; |
371 | } | 371 | } |
372 | 372 | ||
373 | udev->ff_effects_max = user_dev->ff_effects_max; | 373 | udev->ff_effects_max = user_dev->ff_effects_max; |
374 | 374 | ||
375 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; | 375 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; |
376 | if (!size) { | 376 | if (!size) { |
377 | retval = -EINVAL; | 377 | retval = -EINVAL; |
378 | goto exit; | 378 | goto exit; |
379 | } | 379 | } |
380 | 380 | ||
381 | kfree(dev->name); | 381 | kfree(dev->name); |
382 | dev->name = name = kmalloc(size, GFP_KERNEL); | 382 | dev->name = name = kmalloc(size, GFP_KERNEL); |
383 | if (!name) { | 383 | if (!name) { |
384 | retval = -ENOMEM; | 384 | retval = -ENOMEM; |
385 | goto exit; | 385 | goto exit; |
386 | } | 386 | } |
387 | strlcpy(name, user_dev->name, size); | 387 | strlcpy(name, user_dev->name, size); |
388 | 388 | ||
389 | dev->id.bustype = user_dev->id.bustype; | 389 | dev->id.bustype = user_dev->id.bustype; |
390 | dev->id.vendor = user_dev->id.vendor; | 390 | dev->id.vendor = user_dev->id.vendor; |
391 | dev->id.product = user_dev->id.product; | 391 | dev->id.product = user_dev->id.product; |
392 | dev->id.version = user_dev->id.version; | 392 | dev->id.version = user_dev->id.version; |
393 | 393 | ||
394 | for (i = 0; i < ABS_CNT; i++) { | 394 | for (i = 0; i < ABS_CNT; i++) { |
395 | input_abs_set_max(dev, i, user_dev->absmax[i]); | 395 | input_abs_set_max(dev, i, user_dev->absmax[i]); |
396 | input_abs_set_min(dev, i, user_dev->absmin[i]); | 396 | input_abs_set_min(dev, i, user_dev->absmin[i]); |
397 | input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); | 397 | input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); |
398 | input_abs_set_flat(dev, i, user_dev->absflat[i]); | 398 | input_abs_set_flat(dev, i, user_dev->absflat[i]); |
399 | } | 399 | } |
400 | 400 | ||
401 | /* check if absmin/absmax/absfuzz/absflat are filled as | 401 | /* check if absmin/absmax/absfuzz/absflat are filled as |
402 | * told in Documentation/input/input-programming.txt */ | 402 | * told in Documentation/input/input-programming.txt */ |
403 | if (test_bit(EV_ABS, dev->evbit)) { | 403 | if (test_bit(EV_ABS, dev->evbit)) { |
404 | retval = uinput_validate_absbits(dev); | 404 | retval = uinput_validate_absbits(dev); |
405 | if (retval < 0) | 405 | if (retval < 0) |
406 | goto exit; | 406 | goto exit; |
407 | } | 407 | } |
408 | 408 | ||
409 | udev->state = UIST_SETUP_COMPLETE; | 409 | udev->state = UIST_SETUP_COMPLETE; |
410 | retval = count; | 410 | retval = count; |
411 | 411 | ||
412 | exit: | 412 | exit: |
413 | kfree(user_dev); | 413 | kfree(user_dev); |
414 | return retval; | 414 | return retval; |
415 | } | 415 | } |
416 | 416 | ||
417 | static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count) | 417 | static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count) |
418 | { | 418 | { |
419 | struct input_event ev; | 419 | struct input_event ev; |
420 | 420 | ||
421 | if (count < input_event_size()) | 421 | if (count < input_event_size()) |
422 | return -EINVAL; | 422 | return -EINVAL; |
423 | 423 | ||
424 | if (input_event_from_user(buffer, &ev)) | 424 | if (input_event_from_user(buffer, &ev)) |
425 | return -EFAULT; | 425 | return -EFAULT; |
426 | 426 | ||
427 | input_event(udev->dev, ev.type, ev.code, ev.value); | 427 | input_event(udev->dev, ev.type, ev.code, ev.value); |
428 | 428 | ||
429 | return input_event_size(); | 429 | return input_event_size(); |
430 | } | 430 | } |
431 | 431 | ||
432 | static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 432 | static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
433 | { | 433 | { |
434 | struct uinput_device *udev = file->private_data; | 434 | struct uinput_device *udev = file->private_data; |
435 | int retval; | 435 | int retval; |
436 | 436 | ||
437 | retval = mutex_lock_interruptible(&udev->mutex); | 437 | retval = mutex_lock_interruptible(&udev->mutex); |
438 | if (retval) | 438 | if (retval) |
439 | return retval; | 439 | return retval; |
440 | 440 | ||
441 | retval = udev->state == UIST_CREATED ? | 441 | retval = udev->state == UIST_CREATED ? |
442 | uinput_inject_event(udev, buffer, count) : | 442 | uinput_inject_event(udev, buffer, count) : |
443 | uinput_setup_device(udev, buffer, count); | 443 | uinput_setup_device(udev, buffer, count); |
444 | 444 | ||
445 | mutex_unlock(&udev->mutex); | 445 | mutex_unlock(&udev->mutex); |
446 | 446 | ||
447 | return retval; | 447 | return retval; |
448 | } | 448 | } |
449 | 449 | ||
450 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 450 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
451 | { | 451 | { |
452 | struct uinput_device *udev = file->private_data; | 452 | struct uinput_device *udev = file->private_data; |
453 | int retval = 0; | 453 | int retval = 0; |
454 | 454 | ||
455 | if (udev->state != UIST_CREATED) | 455 | if (udev->state != UIST_CREATED) |
456 | return -ENODEV; | 456 | return -ENODEV; |
457 | 457 | ||
458 | if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) | 458 | if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) |
459 | return -EAGAIN; | 459 | return -EAGAIN; |
460 | 460 | ||
461 | retval = wait_event_interruptible(udev->waitq, | 461 | retval = wait_event_interruptible(udev->waitq, |
462 | udev->head != udev->tail || udev->state != UIST_CREATED); | 462 | udev->head != udev->tail || udev->state != UIST_CREATED); |
463 | if (retval) | 463 | if (retval) |
464 | return retval; | 464 | return retval; |
465 | 465 | ||
466 | retval = mutex_lock_interruptible(&udev->mutex); | 466 | retval = mutex_lock_interruptible(&udev->mutex); |
467 | if (retval) | 467 | if (retval) |
468 | return retval; | 468 | return retval; |
469 | 469 | ||
470 | if (udev->state != UIST_CREATED) { | 470 | if (udev->state != UIST_CREATED) { |
471 | retval = -ENODEV; | 471 | retval = -ENODEV; |
472 | goto out; | 472 | goto out; |
473 | } | 473 | } |
474 | 474 | ||
475 | while (udev->head != udev->tail && retval + input_event_size() <= count) { | 475 | while (udev->head != udev->tail && retval + input_event_size() <= count) { |
476 | if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { | 476 | if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { |
477 | retval = -EFAULT; | 477 | retval = -EFAULT; |
478 | goto out; | 478 | goto out; |
479 | } | 479 | } |
480 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; | 480 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; |
481 | retval += input_event_size(); | 481 | retval += input_event_size(); |
482 | } | 482 | } |
483 | 483 | ||
484 | out: | 484 | out: |
485 | mutex_unlock(&udev->mutex); | 485 | mutex_unlock(&udev->mutex); |
486 | 486 | ||
487 | return retval; | 487 | return retval; |
488 | } | 488 | } |
489 | 489 | ||
490 | static unsigned int uinput_poll(struct file *file, poll_table *wait) | 490 | static unsigned int uinput_poll(struct file *file, poll_table *wait) |
491 | { | 491 | { |
492 | struct uinput_device *udev = file->private_data; | 492 | struct uinput_device *udev = file->private_data; |
493 | 493 | ||
494 | poll_wait(file, &udev->waitq, wait); | 494 | poll_wait(file, &udev->waitq, wait); |
495 | 495 | ||
496 | if (udev->head != udev->tail) | 496 | if (udev->head != udev->tail) |
497 | return POLLIN | POLLRDNORM; | 497 | return POLLIN | POLLRDNORM; |
498 | 498 | ||
499 | return 0; | 499 | return 0; |
500 | } | 500 | } |
501 | 501 | ||
502 | static int uinput_release(struct inode *inode, struct file *file) | 502 | static int uinput_release(struct inode *inode, struct file *file) |
503 | { | 503 | { |
504 | struct uinput_device *udev = file->private_data; | 504 | struct uinput_device *udev = file->private_data; |
505 | 505 | ||
506 | uinput_destroy_device(udev); | 506 | uinput_destroy_device(udev); |
507 | kfree(udev); | 507 | kfree(udev); |
508 | 508 | ||
509 | return 0; | 509 | return 0; |
510 | } | 510 | } |
511 | 511 | ||
512 | #ifdef CONFIG_COMPAT | 512 | #ifdef CONFIG_COMPAT |
513 | struct uinput_ff_upload_compat { | 513 | struct uinput_ff_upload_compat { |
514 | int request_id; | 514 | int request_id; |
515 | int retval; | 515 | int retval; |
516 | struct ff_effect_compat effect; | 516 | struct ff_effect_compat effect; |
517 | struct ff_effect_compat old; | 517 | struct ff_effect_compat old; |
518 | }; | 518 | }; |
519 | 519 | ||
520 | static int uinput_ff_upload_to_user(char __user *buffer, | 520 | static int uinput_ff_upload_to_user(char __user *buffer, |
521 | const struct uinput_ff_upload *ff_up) | 521 | const struct uinput_ff_upload *ff_up) |
522 | { | 522 | { |
523 | if (INPUT_COMPAT_TEST) { | 523 | if (INPUT_COMPAT_TEST) { |
524 | struct uinput_ff_upload_compat ff_up_compat; | 524 | struct uinput_ff_upload_compat ff_up_compat; |
525 | 525 | ||
526 | ff_up_compat.request_id = ff_up->request_id; | 526 | ff_up_compat.request_id = ff_up->request_id; |
527 | ff_up_compat.retval = ff_up->retval; | 527 | ff_up_compat.retval = ff_up->retval; |
528 | /* | 528 | /* |
529 | * It so happens that the pointer that gives us the trouble | 529 | * It so happens that the pointer that gives us the trouble |
530 | * is the last field in the structure. Since we don't support | 530 | * is the last field in the structure. Since we don't support |
531 | * custom waveforms in uinput anyway we can just copy the whole | 531 | * custom waveforms in uinput anyway we can just copy the whole |
532 | * thing (to the compat size) and ignore the pointer. | 532 | * thing (to the compat size) and ignore the pointer. |
533 | */ | 533 | */ |
534 | memcpy(&ff_up_compat.effect, &ff_up->effect, | 534 | memcpy(&ff_up_compat.effect, &ff_up->effect, |
535 | sizeof(struct ff_effect_compat)); | 535 | sizeof(struct ff_effect_compat)); |
536 | memcpy(&ff_up_compat.old, &ff_up->old, | 536 | memcpy(&ff_up_compat.old, &ff_up->old, |
537 | sizeof(struct ff_effect_compat)); | 537 | sizeof(struct ff_effect_compat)); |
538 | 538 | ||
539 | if (copy_to_user(buffer, &ff_up_compat, | 539 | if (copy_to_user(buffer, &ff_up_compat, |
540 | sizeof(struct uinput_ff_upload_compat))) | 540 | sizeof(struct uinput_ff_upload_compat))) |
541 | return -EFAULT; | 541 | return -EFAULT; |
542 | } else { | 542 | } else { |
543 | if (copy_to_user(buffer, ff_up, | 543 | if (copy_to_user(buffer, ff_up, |
544 | sizeof(struct uinput_ff_upload))) | 544 | sizeof(struct uinput_ff_upload))) |
545 | return -EFAULT; | 545 | return -EFAULT; |
546 | } | 546 | } |
547 | 547 | ||
548 | return 0; | 548 | return 0; |
549 | } | 549 | } |
550 | 550 | ||
551 | static int uinput_ff_upload_from_user(const char __user *buffer, | 551 | static int uinput_ff_upload_from_user(const char __user *buffer, |
552 | struct uinput_ff_upload *ff_up) | 552 | struct uinput_ff_upload *ff_up) |
553 | { | 553 | { |
554 | if (INPUT_COMPAT_TEST) { | 554 | if (INPUT_COMPAT_TEST) { |
555 | struct uinput_ff_upload_compat ff_up_compat; | 555 | struct uinput_ff_upload_compat ff_up_compat; |
556 | 556 | ||
557 | if (copy_from_user(&ff_up_compat, buffer, | 557 | if (copy_from_user(&ff_up_compat, buffer, |
558 | sizeof(struct uinput_ff_upload_compat))) | 558 | sizeof(struct uinput_ff_upload_compat))) |
559 | return -EFAULT; | 559 | return -EFAULT; |
560 | 560 | ||
561 | ff_up->request_id = ff_up_compat.request_id; | 561 | ff_up->request_id = ff_up_compat.request_id; |
562 | ff_up->retval = ff_up_compat.retval; | 562 | ff_up->retval = ff_up_compat.retval; |
563 | memcpy(&ff_up->effect, &ff_up_compat.effect, | 563 | memcpy(&ff_up->effect, &ff_up_compat.effect, |
564 | sizeof(struct ff_effect_compat)); | 564 | sizeof(struct ff_effect_compat)); |
565 | memcpy(&ff_up->old, &ff_up_compat.old, | 565 | memcpy(&ff_up->old, &ff_up_compat.old, |
566 | sizeof(struct ff_effect_compat)); | 566 | sizeof(struct ff_effect_compat)); |
567 | 567 | ||
568 | } else { | 568 | } else { |
569 | if (copy_from_user(ff_up, buffer, | 569 | if (copy_from_user(ff_up, buffer, |
570 | sizeof(struct uinput_ff_upload))) | 570 | sizeof(struct uinput_ff_upload))) |
571 | return -EFAULT; | 571 | return -EFAULT; |
572 | } | 572 | } |
573 | 573 | ||
574 | return 0; | 574 | return 0; |
575 | } | 575 | } |
576 | 576 | ||
577 | #else | 577 | #else |
578 | 578 | ||
579 | static int uinput_ff_upload_to_user(char __user *buffer, | 579 | static int uinput_ff_upload_to_user(char __user *buffer, |
580 | const struct uinput_ff_upload *ff_up) | 580 | const struct uinput_ff_upload *ff_up) |
581 | { | 581 | { |
582 | if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) | 582 | if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) |
583 | return -EFAULT; | 583 | return -EFAULT; |
584 | 584 | ||
585 | return 0; | 585 | return 0; |
586 | } | 586 | } |
587 | 587 | ||
588 | static int uinput_ff_upload_from_user(const char __user *buffer, | 588 | static int uinput_ff_upload_from_user(const char __user *buffer, |
589 | struct uinput_ff_upload *ff_up) | 589 | struct uinput_ff_upload *ff_up) |
590 | { | 590 | { |
591 | if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) | 591 | if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) |
592 | return -EFAULT; | 592 | return -EFAULT; |
593 | 593 | ||
594 | return 0; | 594 | return 0; |
595 | } | 595 | } |
596 | 596 | ||
597 | #endif | 597 | #endif |
598 | 598 | ||
599 | #define uinput_set_bit(_arg, _bit, _max) \ | 599 | #define uinput_set_bit(_arg, _bit, _max) \ |
600 | ({ \ | 600 | ({ \ |
601 | int __ret = 0; \ | 601 | int __ret = 0; \ |
602 | if (udev->state == UIST_CREATED) \ | 602 | if (udev->state == UIST_CREATED) \ |
603 | __ret = -EINVAL; \ | 603 | __ret = -EINVAL; \ |
604 | else if ((_arg) > (_max)) \ | 604 | else if ((_arg) > (_max)) \ |
605 | __ret = -EINVAL; \ | 605 | __ret = -EINVAL; \ |
606 | else set_bit((_arg), udev->dev->_bit); \ | 606 | else set_bit((_arg), udev->dev->_bit); \ |
607 | __ret; \ | 607 | __ret; \ |
608 | }) | 608 | }) |
609 | 609 | ||
610 | static long uinput_ioctl_handler(struct file *file, unsigned int cmd, | 610 | static long uinput_ioctl_handler(struct file *file, unsigned int cmd, |
611 | unsigned long arg, void __user *p) | 611 | unsigned long arg, void __user *p) |
612 | { | 612 | { |
613 | int retval; | 613 | int retval; |
614 | struct uinput_device *udev = file->private_data; | 614 | struct uinput_device *udev = file->private_data; |
615 | struct uinput_ff_upload ff_up; | 615 | struct uinput_ff_upload ff_up; |
616 | struct uinput_ff_erase ff_erase; | 616 | struct uinput_ff_erase ff_erase; |
617 | struct uinput_request *req; | 617 | struct uinput_request *req; |
618 | int length; | 618 | int length; |
619 | char *phys; | 619 | char *phys; |
620 | 620 | ||
621 | retval = mutex_lock_interruptible(&udev->mutex); | 621 | retval = mutex_lock_interruptible(&udev->mutex); |
622 | if (retval) | 622 | if (retval) |
623 | return retval; | 623 | return retval; |
624 | 624 | ||
625 | if (!udev->dev) { | 625 | if (!udev->dev) { |
626 | retval = uinput_allocate_device(udev); | 626 | retval = uinput_allocate_device(udev); |
627 | if (retval) | 627 | if (retval) |
628 | goto out; | 628 | goto out; |
629 | } | 629 | } |
630 | 630 | ||
631 | switch (cmd) { | 631 | switch (cmd) { |
632 | case UI_DEV_CREATE: | 632 | case UI_DEV_CREATE: |
633 | retval = uinput_create_device(udev); | 633 | retval = uinput_create_device(udev); |
634 | break; | 634 | break; |
635 | 635 | ||
636 | case UI_DEV_DESTROY: | 636 | case UI_DEV_DESTROY: |
637 | uinput_destroy_device(udev); | 637 | uinput_destroy_device(udev); |
638 | break; | 638 | break; |
639 | 639 | ||
640 | case UI_SET_EVBIT: | 640 | case UI_SET_EVBIT: |
641 | retval = uinput_set_bit(arg, evbit, EV_MAX); | 641 | retval = uinput_set_bit(arg, evbit, EV_MAX); |
642 | break; | 642 | break; |
643 | 643 | ||
644 | case UI_SET_KEYBIT: | 644 | case UI_SET_KEYBIT: |
645 | retval = uinput_set_bit(arg, keybit, KEY_MAX); | 645 | retval = uinput_set_bit(arg, keybit, KEY_MAX); |
646 | break; | 646 | break; |
647 | 647 | ||
648 | case UI_SET_RELBIT: | 648 | case UI_SET_RELBIT: |
649 | retval = uinput_set_bit(arg, relbit, REL_MAX); | 649 | retval = uinput_set_bit(arg, relbit, REL_MAX); |
650 | break; | 650 | break; |
651 | 651 | ||
652 | case UI_SET_ABSBIT: | 652 | case UI_SET_ABSBIT: |
653 | retval = uinput_set_bit(arg, absbit, ABS_MAX); | 653 | retval = uinput_set_bit(arg, absbit, ABS_MAX); |
654 | break; | 654 | break; |
655 | 655 | ||
656 | case UI_SET_MSCBIT: | 656 | case UI_SET_MSCBIT: |
657 | retval = uinput_set_bit(arg, mscbit, MSC_MAX); | 657 | retval = uinput_set_bit(arg, mscbit, MSC_MAX); |
658 | break; | 658 | break; |
659 | 659 | ||
660 | case UI_SET_LEDBIT: | 660 | case UI_SET_LEDBIT: |
661 | retval = uinput_set_bit(arg, ledbit, LED_MAX); | 661 | retval = uinput_set_bit(arg, ledbit, LED_MAX); |
662 | break; | 662 | break; |
663 | 663 | ||
664 | case UI_SET_SNDBIT: | 664 | case UI_SET_SNDBIT: |
665 | retval = uinput_set_bit(arg, sndbit, SND_MAX); | 665 | retval = uinput_set_bit(arg, sndbit, SND_MAX); |
666 | break; | 666 | break; |
667 | 667 | ||
668 | case UI_SET_FFBIT: | 668 | case UI_SET_FFBIT: |
669 | retval = uinput_set_bit(arg, ffbit, FF_MAX); | 669 | retval = uinput_set_bit(arg, ffbit, FF_MAX); |
670 | break; | 670 | break; |
671 | 671 | ||
672 | case UI_SET_SWBIT: | 672 | case UI_SET_SWBIT: |
673 | retval = uinput_set_bit(arg, swbit, SW_MAX); | 673 | retval = uinput_set_bit(arg, swbit, SW_MAX); |
674 | break; | 674 | break; |
675 | 675 | ||
676 | case UI_SET_PHYS: | 676 | case UI_SET_PHYS: |
677 | if (udev->state == UIST_CREATED) { | 677 | if (udev->state == UIST_CREATED) { |
678 | retval = -EINVAL; | 678 | retval = -EINVAL; |
679 | goto out; | 679 | goto out; |
680 | } | 680 | } |
681 | length = strnlen_user(p, 1024); | 681 | length = strnlen_user(p, 1024); |
682 | if (length <= 0) { | 682 | if (length <= 0) { |
683 | retval = -EFAULT; | 683 | retval = -EFAULT; |
684 | break; | 684 | break; |
685 | } | 685 | } |
686 | kfree(udev->dev->phys); | 686 | kfree(udev->dev->phys); |
687 | udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); | 687 | udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); |
688 | if (!phys) { | 688 | if (!phys) { |
689 | retval = -ENOMEM; | 689 | retval = -ENOMEM; |
690 | break; | 690 | break; |
691 | } | 691 | } |
692 | if (copy_from_user(phys, p, length)) { | 692 | if (copy_from_user(phys, p, length)) { |
693 | udev->dev->phys = NULL; | 693 | udev->dev->phys = NULL; |
694 | kfree(phys); | 694 | kfree(phys); |
695 | retval = -EFAULT; | 695 | retval = -EFAULT; |
696 | break; | 696 | break; |
697 | } | 697 | } |
698 | phys[length - 1] = '\0'; | 698 | phys[length - 1] = '\0'; |
699 | break; | 699 | break; |
700 | 700 | ||
701 | case UI_BEGIN_FF_UPLOAD: | 701 | case UI_BEGIN_FF_UPLOAD: |
702 | retval = uinput_ff_upload_from_user(p, &ff_up); | 702 | retval = uinput_ff_upload_from_user(p, &ff_up); |
703 | if (retval) | 703 | if (retval) |
704 | break; | 704 | break; |
705 | 705 | ||
706 | req = uinput_request_find(udev, ff_up.request_id); | 706 | req = uinput_request_find(udev, ff_up.request_id); |
707 | if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { | 707 | if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { |
708 | retval = -EINVAL; | 708 | retval = -EINVAL; |
709 | break; | 709 | break; |
710 | } | 710 | } |
711 | 711 | ||
712 | ff_up.retval = 0; | 712 | ff_up.retval = 0; |
713 | ff_up.effect = *req->u.upload.effect; | 713 | ff_up.effect = *req->u.upload.effect; |
714 | if (req->u.upload.old) | 714 | if (req->u.upload.old) |
715 | ff_up.old = *req->u.upload.old; | 715 | ff_up.old = *req->u.upload.old; |
716 | else | 716 | else |
717 | memset(&ff_up.old, 0, sizeof(struct ff_effect)); | 717 | memset(&ff_up.old, 0, sizeof(struct ff_effect)); |
718 | 718 | ||
719 | retval = uinput_ff_upload_to_user(p, &ff_up); | 719 | retval = uinput_ff_upload_to_user(p, &ff_up); |
720 | break; | 720 | break; |
721 | 721 | ||
722 | case UI_BEGIN_FF_ERASE: | 722 | case UI_BEGIN_FF_ERASE: |
723 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { | 723 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { |
724 | retval = -EFAULT; | 724 | retval = -EFAULT; |
725 | break; | 725 | break; |
726 | } | 726 | } |
727 | 727 | ||
728 | req = uinput_request_find(udev, ff_erase.request_id); | 728 | req = uinput_request_find(udev, ff_erase.request_id); |
729 | if (!req || req->code != UI_FF_ERASE) { | 729 | if (!req || req->code != UI_FF_ERASE) { |
730 | retval = -EINVAL; | 730 | retval = -EINVAL; |
731 | break; | 731 | break; |
732 | } | 732 | } |
733 | 733 | ||
734 | ff_erase.retval = 0; | 734 | ff_erase.retval = 0; |
735 | ff_erase.effect_id = req->u.effect_id; | 735 | ff_erase.effect_id = req->u.effect_id; |
736 | if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { | 736 | if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { |
737 | retval = -EFAULT; | 737 | retval = -EFAULT; |
738 | break; | 738 | break; |
739 | } | 739 | } |
740 | 740 | ||
741 | break; | 741 | break; |
742 | 742 | ||
743 | case UI_END_FF_UPLOAD: | 743 | case UI_END_FF_UPLOAD: |
744 | retval = uinput_ff_upload_from_user(p, &ff_up); | 744 | retval = uinput_ff_upload_from_user(p, &ff_up); |
745 | if (retval) | 745 | if (retval) |
746 | break; | 746 | break; |
747 | 747 | ||
748 | req = uinput_request_find(udev, ff_up.request_id); | 748 | req = uinput_request_find(udev, ff_up.request_id); |
749 | if (!req || req->code != UI_FF_UPLOAD || | 749 | if (!req || req->code != UI_FF_UPLOAD || |
750 | !req->u.upload.effect) { | 750 | !req->u.upload.effect) { |
751 | retval = -EINVAL; | 751 | retval = -EINVAL; |
752 | break; | 752 | break; |
753 | } | 753 | } |
754 | 754 | ||
755 | req->retval = ff_up.retval; | 755 | req->retval = ff_up.retval; |
756 | uinput_request_done(udev, req); | 756 | uinput_request_done(udev, req); |
757 | break; | 757 | break; |
758 | 758 | ||
759 | case UI_END_FF_ERASE: | 759 | case UI_END_FF_ERASE: |
760 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { | 760 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { |
761 | retval = -EFAULT; | 761 | retval = -EFAULT; |
762 | break; | 762 | break; |
763 | } | 763 | } |
764 | 764 | ||
765 | req = uinput_request_find(udev, ff_erase.request_id); | 765 | req = uinput_request_find(udev, ff_erase.request_id); |
766 | if (!req || req->code != UI_FF_ERASE) { | 766 | if (!req || req->code != UI_FF_ERASE) { |
767 | retval = -EINVAL; | 767 | retval = -EINVAL; |
768 | break; | 768 | break; |
769 | } | 769 | } |
770 | 770 | ||
771 | req->retval = ff_erase.retval; | 771 | req->retval = ff_erase.retval; |
772 | uinput_request_done(udev, req); | 772 | uinput_request_done(udev, req); |
773 | break; | 773 | break; |
774 | 774 | ||
775 | default: | 775 | default: |
776 | retval = -EINVAL; | 776 | retval = -EINVAL; |
777 | } | 777 | } |
778 | 778 | ||
779 | out: | 779 | out: |
780 | mutex_unlock(&udev->mutex); | 780 | mutex_unlock(&udev->mutex); |
781 | return retval; | 781 | return retval; |
782 | } | 782 | } |
783 | 783 | ||
784 | static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 784 | static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
785 | { | 785 | { |
786 | return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); | 786 | return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); |
787 | } | 787 | } |
788 | 788 | ||
789 | #ifdef CONFIG_COMPAT | 789 | #ifdef CONFIG_COMPAT |
790 | static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 790 | static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
791 | { | 791 | { |
792 | return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); | 792 | return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); |
793 | } | 793 | } |
794 | #endif | 794 | #endif |
795 | 795 | ||
796 | static const struct file_operations uinput_fops = { | 796 | static const struct file_operations uinput_fops = { |
797 | .owner = THIS_MODULE, | 797 | .owner = THIS_MODULE, |
798 | .open = uinput_open, | 798 | .open = uinput_open, |
799 | .release = uinput_release, | 799 | .release = uinput_release, |
800 | .read = uinput_read, | 800 | .read = uinput_read, |
801 | .write = uinput_write, | 801 | .write = uinput_write, |
802 | .poll = uinput_poll, | 802 | .poll = uinput_poll, |
803 | .unlocked_ioctl = uinput_ioctl, | 803 | .unlocked_ioctl = uinput_ioctl, |
804 | #ifdef CONFIG_COMPAT | 804 | #ifdef CONFIG_COMPAT |
805 | .compat_ioctl = uinput_compat_ioctl, | 805 | .compat_ioctl = uinput_compat_ioctl, |
806 | #endif | 806 | #endif |
807 | }; | 807 | }; |
808 | 808 | ||
809 | static struct miscdevice uinput_misc = { | 809 | static struct miscdevice uinput_misc = { |
810 | .fops = &uinput_fops, | 810 | .fops = &uinput_fops, |
811 | .minor = UINPUT_MINOR, | 811 | .minor = UINPUT_MINOR, |
812 | .name = UINPUT_NAME, | 812 | .name = UINPUT_NAME, |
813 | }; | 813 | }; |
814 | MODULE_ALIAS_MISCDEV(UINPUT_MINOR); | ||
815 | MODULE_ALIAS("devname:" UINPUT_NAME); | ||
814 | 816 | ||
815 | static int __init uinput_init(void) | 817 | static int __init uinput_init(void) |
816 | { | 818 | { |
817 | return misc_register(&uinput_misc); | 819 | return misc_register(&uinput_misc); |
818 | } | 820 | } |
819 | 821 | ||
820 | static void __exit uinput_exit(void) | 822 | static void __exit uinput_exit(void) |
821 | { | 823 | { |
822 | misc_deregister(&uinput_misc); | 824 | misc_deregister(&uinput_misc); |
823 | } | 825 | } |
824 | 826 | ||
825 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); | 827 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); |
826 | MODULE_DESCRIPTION("User level driver support for input subsystem"); | 828 | MODULE_DESCRIPTION("User level driver support for input subsystem"); |
827 | MODULE_LICENSE("GPL"); | 829 | MODULE_LICENSE("GPL"); |
828 | MODULE_VERSION("0.3"); | 830 | MODULE_VERSION("0.3"); |
829 | 831 | ||
830 | module_init(uinput_init); | 832 | module_init(uinput_init); |
831 | module_exit(uinput_exit); | 833 | module_exit(uinput_exit); |
832 | 834 | ||
833 | 835 |
include/linux/miscdevice.h
1 | #ifndef _LINUX_MISCDEVICE_H | 1 | #ifndef _LINUX_MISCDEVICE_H |
2 | #define _LINUX_MISCDEVICE_H | 2 | #define _LINUX_MISCDEVICE_H |
3 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/major.h> | 4 | #include <linux/major.h> |
5 | 5 | ||
6 | /* | 6 | /* |
7 | * These allocations are managed by device@lanana.org. If you use an | 7 | * These allocations are managed by device@lanana.org. If you use an |
8 | * entry that is not in assigned your entry may well be moved and | 8 | * entry that is not in assigned your entry may well be moved and |
9 | * reassigned, or set dynamic if a fixed value is not justified. | 9 | * reassigned, or set dynamic if a fixed value is not justified. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define PSMOUSE_MINOR 1 | 12 | #define PSMOUSE_MINOR 1 |
13 | #define MS_BUSMOUSE_MINOR 2 | 13 | #define MS_BUSMOUSE_MINOR 2 |
14 | #define ATIXL_BUSMOUSE_MINOR 3 | 14 | #define ATIXL_BUSMOUSE_MINOR 3 |
15 | /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ | 15 | /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ |
16 | #define ATARIMOUSE_MINOR 5 | 16 | #define ATARIMOUSE_MINOR 5 |
17 | #define SUN_MOUSE_MINOR 6 | 17 | #define SUN_MOUSE_MINOR 6 |
18 | #define APOLLO_MOUSE_MINOR 7 | 18 | #define APOLLO_MOUSE_MINOR 7 |
19 | #define PC110PAD_MINOR 9 | 19 | #define PC110PAD_MINOR 9 |
20 | /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ | 20 | /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ |
21 | #define WATCHDOG_MINOR 130 /* Watchdog timer */ | 21 | #define WATCHDOG_MINOR 130 /* Watchdog timer */ |
22 | #define TEMP_MINOR 131 /* Temperature Sensor */ | 22 | #define TEMP_MINOR 131 /* Temperature Sensor */ |
23 | #define RTC_MINOR 135 | 23 | #define RTC_MINOR 135 |
24 | #define EFI_RTC_MINOR 136 /* EFI Time services */ | 24 | #define EFI_RTC_MINOR 136 /* EFI Time services */ |
25 | #define SUN_OPENPROM_MINOR 139 | 25 | #define SUN_OPENPROM_MINOR 139 |
26 | #define DMAPI_MINOR 140 /* DMAPI */ | 26 | #define DMAPI_MINOR 140 /* DMAPI */ |
27 | #define NVRAM_MINOR 144 | 27 | #define NVRAM_MINOR 144 |
28 | #define SGI_MMTIMER 153 | 28 | #define SGI_MMTIMER 153 |
29 | #define STORE_QUEUE_MINOR 155 | 29 | #define STORE_QUEUE_MINOR 155 |
30 | #define I2O_MINOR 166 | 30 | #define I2O_MINOR 166 |
31 | #define MICROCODE_MINOR 184 | 31 | #define MICROCODE_MINOR 184 |
32 | #define TUN_MINOR 200 | 32 | #define TUN_MINOR 200 |
33 | #define MWAVE_MINOR 219 /* ACP/Mwave Modem */ | 33 | #define MWAVE_MINOR 219 /* ACP/Mwave Modem */ |
34 | #define MPT_MINOR 220 | 34 | #define MPT_MINOR 220 |
35 | #define MPT2SAS_MINOR 221 | 35 | #define MPT2SAS_MINOR 221 |
36 | #define UINPUT_MINOR 223 | ||
36 | #define HPET_MINOR 228 | 37 | #define HPET_MINOR 228 |
37 | #define FUSE_MINOR 229 | 38 | #define FUSE_MINOR 229 |
38 | #define KVM_MINOR 232 | 39 | #define KVM_MINOR 232 |
39 | #define BTRFS_MINOR 234 | 40 | #define BTRFS_MINOR 234 |
40 | #define AUTOFS_MINOR 235 | 41 | #define AUTOFS_MINOR 235 |
41 | #define MAPPER_CTRL_MINOR 236 | 42 | #define MAPPER_CTRL_MINOR 236 |
42 | #define MISC_DYNAMIC_MINOR 255 | 43 | #define MISC_DYNAMIC_MINOR 255 |
43 | 44 | ||
44 | struct device; | 45 | struct device; |
45 | 46 | ||
46 | struct miscdevice { | 47 | struct miscdevice { |
47 | int minor; | 48 | int minor; |
48 | const char *name; | 49 | const char *name; |
49 | const struct file_operations *fops; | 50 | const struct file_operations *fops; |
50 | struct list_head list; | 51 | struct list_head list; |
51 | struct device *parent; | 52 | struct device *parent; |
52 | struct device *this_device; | 53 | struct device *this_device; |
53 | const char *nodename; | 54 | const char *nodename; |
54 | mode_t mode; | 55 | mode_t mode; |
55 | }; | 56 | }; |
56 | 57 | ||
57 | extern int misc_register(struct miscdevice * misc); | 58 | extern int misc_register(struct miscdevice * misc); |
58 | extern int misc_deregister(struct miscdevice *misc); | 59 | extern int misc_deregister(struct miscdevice *misc); |
59 | 60 | ||
60 | #define MODULE_ALIAS_MISCDEV(minor) \ | 61 | #define MODULE_ALIAS_MISCDEV(minor) \ |
61 | MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ | 62 | MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ |
62 | "-" __stringify(minor)) | 63 | "-" __stringify(minor)) |
63 | #endif | 64 | #endif |
64 | 65 |
include/linux/uinput.h
1 | #ifndef __UINPUT_H_ | 1 | #ifndef __UINPUT_H_ |
2 | #define __UINPUT_H_ | 2 | #define __UINPUT_H_ |
3 | /* | 3 | /* |
4 | * User level driver support for input subsystem | 4 | * User level driver support for input subsystem |
5 | * | 5 | * |
6 | * Heavily based on evdev.c by Vojtech Pavlik | 6 | * Heavily based on evdev.c by Vojtech Pavlik |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | * | 21 | * |
22 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | 22 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> |
23 | * | 23 | * |
24 | * Changes/Revisions: | 24 | * Changes/Revisions: |
25 | * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) | 25 | * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) |
26 | * - update ff support for the changes in kernel interface | 26 | * - update ff support for the changes in kernel interface |
27 | * - add UINPUT_VERSION | 27 | * - add UINPUT_VERSION |
28 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | 28 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) |
29 | * - added force feedback support | 29 | * - added force feedback support |
30 | * - added UI_SET_PHYS | 30 | * - added UI_SET_PHYS |
31 | * 0.1 20/06/2002 | 31 | * 0.1 20/06/2002 |
32 | * - first public version | 32 | * - first public version |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/input.h> | 35 | #include <linux/input.h> |
36 | 36 | ||
37 | #define UINPUT_VERSION 3 | 37 | #define UINPUT_VERSION 3 |
38 | 38 | ||
39 | #ifdef __KERNEL__ | 39 | #ifdef __KERNEL__ |
40 | #define UINPUT_MINOR 223 | ||
41 | #define UINPUT_NAME "uinput" | 40 | #define UINPUT_NAME "uinput" |
42 | #define UINPUT_BUFFER_SIZE 16 | 41 | #define UINPUT_BUFFER_SIZE 16 |
43 | #define UINPUT_NUM_REQUESTS 16 | 42 | #define UINPUT_NUM_REQUESTS 16 |
44 | 43 | ||
45 | enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; | 44 | enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; |
46 | 45 | ||
47 | struct uinput_request { | 46 | struct uinput_request { |
48 | int id; | 47 | int id; |
49 | int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ | 48 | int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ |
50 | 49 | ||
51 | int retval; | 50 | int retval; |
52 | struct completion done; | 51 | struct completion done; |
53 | 52 | ||
54 | union { | 53 | union { |
55 | int effect_id; | 54 | int effect_id; |
56 | struct { | 55 | struct { |
57 | struct ff_effect *effect; | 56 | struct ff_effect *effect; |
58 | struct ff_effect *old; | 57 | struct ff_effect *old; |
59 | } upload; | 58 | } upload; |
60 | } u; | 59 | } u; |
61 | }; | 60 | }; |
62 | 61 | ||
63 | struct uinput_device { | 62 | struct uinput_device { |
64 | struct input_dev *dev; | 63 | struct input_dev *dev; |
65 | struct mutex mutex; | 64 | struct mutex mutex; |
66 | enum uinput_state state; | 65 | enum uinput_state state; |
67 | wait_queue_head_t waitq; | 66 | wait_queue_head_t waitq; |
68 | unsigned char ready; | 67 | unsigned char ready; |
69 | unsigned char head; | 68 | unsigned char head; |
70 | unsigned char tail; | 69 | unsigned char tail; |
71 | struct input_event buff[UINPUT_BUFFER_SIZE]; | 70 | struct input_event buff[UINPUT_BUFFER_SIZE]; |
72 | int ff_effects_max; | 71 | int ff_effects_max; |
73 | 72 | ||
74 | struct uinput_request *requests[UINPUT_NUM_REQUESTS]; | 73 | struct uinput_request *requests[UINPUT_NUM_REQUESTS]; |
75 | wait_queue_head_t requests_waitq; | 74 | wait_queue_head_t requests_waitq; |
76 | spinlock_t requests_lock; | 75 | spinlock_t requests_lock; |
77 | }; | 76 | }; |
78 | #endif /* __KERNEL__ */ | 77 | #endif /* __KERNEL__ */ |
79 | 78 | ||
80 | struct uinput_ff_upload { | 79 | struct uinput_ff_upload { |
81 | int request_id; | 80 | int request_id; |
82 | int retval; | 81 | int retval; |
83 | struct ff_effect effect; | 82 | struct ff_effect effect; |
84 | struct ff_effect old; | 83 | struct ff_effect old; |
85 | }; | 84 | }; |
86 | 85 | ||
87 | struct uinput_ff_erase { | 86 | struct uinput_ff_erase { |
88 | int request_id; | 87 | int request_id; |
89 | int retval; | 88 | int retval; |
90 | int effect_id; | 89 | int effect_id; |
91 | }; | 90 | }; |
92 | 91 | ||
93 | /* ioctl */ | 92 | /* ioctl */ |
94 | #define UINPUT_IOCTL_BASE 'U' | 93 | #define UINPUT_IOCTL_BASE 'U' |
95 | #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) | 94 | #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) |
96 | #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) | 95 | #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) |
97 | 96 | ||
98 | #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) | 97 | #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) |
99 | #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) | 98 | #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) |
100 | #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) | 99 | #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) |
101 | #define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) | 100 | #define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) |
102 | #define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) | 101 | #define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) |
103 | #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) | 102 | #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) |
104 | #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) | 103 | #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) |
105 | #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) | 104 | #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) |
106 | #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) | 105 | #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) |
107 | #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) | 106 | #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) |
108 | 107 | ||
109 | #define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload) | 108 | #define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload) |
110 | #define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload) | 109 | #define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload) |
111 | #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) | 110 | #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) |
112 | #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) | 111 | #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) |
113 | 112 | ||
114 | /* | 113 | /* |
115 | * To write a force-feedback-capable driver, the upload_effect | 114 | * To write a force-feedback-capable driver, the upload_effect |
116 | * and erase_effect callbacks in input_dev must be implemented. | 115 | * and erase_effect callbacks in input_dev must be implemented. |
117 | * The uinput driver will generate a fake input event when one of | 116 | * The uinput driver will generate a fake input event when one of |
118 | * these callbacks are invoked. The userspace code then uses | 117 | * these callbacks are invoked. The userspace code then uses |
119 | * ioctls to retrieve additional parameters and send the return code. | 118 | * ioctls to retrieve additional parameters and send the return code. |
120 | * The callback blocks until this return code is sent. | 119 | * The callback blocks until this return code is sent. |
121 | * | 120 | * |
122 | * The described callback mechanism is only used if ff_effects_max | 121 | * The described callback mechanism is only used if ff_effects_max |
123 | * is set. | 122 | * is set. |
124 | * | 123 | * |
125 | * To implement upload_effect(): | 124 | * To implement upload_effect(): |
126 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. | 125 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. |
127 | * A request ID will be given in 'value'. | 126 | * A request ID will be given in 'value'. |
128 | * 2. Allocate a uinput_ff_upload struct, fill in request_id with | 127 | * 2. Allocate a uinput_ff_upload struct, fill in request_id with |
129 | * the 'value' from the EV_UINPUT event. | 128 | * the 'value' from the EV_UINPUT event. |
130 | * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the | 129 | * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the |
131 | * uinput_ff_upload struct. It will be filled in with the | 130 | * uinput_ff_upload struct. It will be filled in with the |
132 | * ff_effects passed to upload_effect(). | 131 | * ff_effects passed to upload_effect(). |
133 | * 4. Perform the effect upload, and place a return code back into | 132 | * 4. Perform the effect upload, and place a return code back into |
134 | the uinput_ff_upload struct. | 133 | the uinput_ff_upload struct. |
135 | * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the | 134 | * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the |
136 | * uinput_ff_upload_effect struct. This will complete execution | 135 | * uinput_ff_upload_effect struct. This will complete execution |
137 | * of our upload_effect() handler. | 136 | * of our upload_effect() handler. |
138 | * | 137 | * |
139 | * To implement erase_effect(): | 138 | * To implement erase_effect(): |
140 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. | 139 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. |
141 | * A request ID will be given in 'value'. | 140 | * A request ID will be given in 'value'. |
142 | * 2. Allocate a uinput_ff_erase struct, fill in request_id with | 141 | * 2. Allocate a uinput_ff_erase struct, fill in request_id with |
143 | * the 'value' from the EV_UINPUT event. | 142 | * the 'value' from the EV_UINPUT event. |
144 | * 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the | 143 | * 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the |
145 | * uinput_ff_erase struct. It will be filled in with the | 144 | * uinput_ff_erase struct. It will be filled in with the |
146 | * effect ID passed to erase_effect(). | 145 | * effect ID passed to erase_effect(). |
147 | * 4. Perform the effect erasure, and place a return code back | 146 | * 4. Perform the effect erasure, and place a return code back |
148 | * into the uinput_ff_erase struct. | 147 | * into the uinput_ff_erase struct. |
149 | * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the | 148 | * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the |
150 | * uinput_ff_erase_effect struct. This will complete execution | 149 | * uinput_ff_erase_effect struct. This will complete execution |
151 | * of our erase_effect() handler. | 150 | * of our erase_effect() handler. |
152 | */ | 151 | */ |
153 | 152 | ||
154 | /* | 153 | /* |
155 | * This is the new event type, used only by uinput. | 154 | * This is the new event type, used only by uinput. |
156 | * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' | 155 | * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' |
157 | * is the unique request ID. This number was picked | 156 | * is the unique request ID. This number was picked |
158 | * arbitrarily, above EV_MAX (since the input system | 157 | * arbitrarily, above EV_MAX (since the input system |
159 | * never sees it) but in the range of a 16-bit int. | 158 | * never sees it) but in the range of a 16-bit int. |
160 | */ | 159 | */ |
161 | #define EV_UINPUT 0x0101 | 160 | #define EV_UINPUT 0x0101 |
162 | #define UI_FF_UPLOAD 1 | 161 | #define UI_FF_UPLOAD 1 |
163 | #define UI_FF_ERASE 2 | 162 | #define UI_FF_ERASE 2 |
164 | 163 | ||
165 | #define UINPUT_MAX_NAME_SIZE 80 | 164 | #define UINPUT_MAX_NAME_SIZE 80 |
166 | struct uinput_user_dev { | 165 | struct uinput_user_dev { |
167 | char name[UINPUT_MAX_NAME_SIZE]; | 166 | char name[UINPUT_MAX_NAME_SIZE]; |
168 | struct input_id id; | 167 | struct input_id id; |
169 | int ff_effects_max; | 168 | int ff_effects_max; |
170 | int absmax[ABS_CNT]; | 169 | int absmax[ABS_CNT]; |
171 | int absmin[ABS_CNT]; | 170 | int absmin[ABS_CNT]; |
172 | int absfuzz[ABS_CNT]; | 171 | int absfuzz[ABS_CNT]; |
173 | int absflat[ABS_CNT]; | 172 | int absflat[ABS_CNT]; |
174 | }; | 173 | }; |
175 | #endif /* __UINPUT_H_ */ | 174 | #endif /* __UINPUT_H_ */ |
176 | 175 | ||
177 | 176 |