diff options
Diffstat (limited to 'drivers/input/misc/uinput.c')
-rw-r--r-- | drivers/input/misc/uinput.c | 325 |
1 files changed, 170 insertions, 155 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 948c1cc01bc9..546ed9b4901d 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -92,24 +92,19 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques | |||
92 | { | 92 | { |
93 | /* Mark slot as available */ | 93 | /* Mark slot as available */ |
94 | udev->requests[request->id] = NULL; | 94 | udev->requests[request->id] = NULL; |
95 | wake_up_interruptible(&udev->requests_waitq); | 95 | wake_up(&udev->requests_waitq); |
96 | 96 | ||
97 | complete(&request->done); | 97 | complete(&request->done); |
98 | } | 98 | } |
99 | 99 | ||
100 | static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) | 100 | static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) |
101 | { | 101 | { |
102 | int retval; | ||
103 | |||
104 | /* Tell our userspace app about this new request by queueing an input event */ | 102 | /* Tell our userspace app about this new request by queueing an input event */ |
105 | uinput_dev_event(dev, EV_UINPUT, request->code, request->id); | 103 | uinput_dev_event(dev, EV_UINPUT, request->code, request->id); |
106 | 104 | ||
107 | /* Wait for the request to complete */ | 105 | /* Wait for the request to complete */ |
108 | retval = wait_for_completion_interruptible(&request->done); | 106 | wait_for_completion(&request->done); |
109 | if (!retval) | 107 | return request->retval; |
110 | retval = request->retval; | ||
111 | |||
112 | return retval; | ||
113 | } | 108 | } |
114 | 109 | ||
115 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 110 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) |
@@ -152,67 +147,62 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | |||
152 | return retval; | 147 | return retval; |
153 | } | 148 | } |
154 | 149 | ||
155 | static int uinput_create_device(struct uinput_device *udev) | 150 | static void uinput_destroy_device(struct uinput_device *udev) |
156 | { | 151 | { |
157 | if (!udev->dev->name) { | 152 | const char *name, *phys; |
158 | printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); | 153 | |
159 | return -EINVAL; | 154 | if (udev->dev) { |
155 | name = udev->dev->name; | ||
156 | phys = udev->dev->phys; | ||
157 | if (udev->state == UIST_CREATED) | ||
158 | input_unregister_device(udev->dev); | ||
159 | else | ||
160 | input_free_device(udev->dev); | ||
161 | kfree(name); | ||
162 | kfree(phys); | ||
163 | udev->dev = NULL; | ||
160 | } | 164 | } |
161 | 165 | ||
162 | udev->dev->event = uinput_dev_event; | 166 | udev->state = UIST_NEW_DEVICE; |
163 | udev->dev->upload_effect = uinput_dev_upload_effect; | ||
164 | udev->dev->erase_effect = uinput_dev_erase_effect; | ||
165 | udev->dev->private = udev; | ||
166 | |||
167 | init_waitqueue_head(&udev->waitq); | ||
168 | |||
169 | input_register_device(udev->dev); | ||
170 | |||
171 | set_bit(UIST_CREATED, &udev->state); | ||
172 | |||
173 | return 0; | ||
174 | } | 167 | } |
175 | 168 | ||
176 | static int uinput_destroy_device(struct uinput_device *udev) | 169 | static int uinput_create_device(struct uinput_device *udev) |
177 | { | 170 | { |
178 | if (!test_bit(UIST_CREATED, &udev->state)) { | 171 | int error; |
179 | printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); | 172 | |
173 | if (udev->state != UIST_SETUP_COMPLETE) { | ||
174 | printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); | ||
180 | return -EINVAL; | 175 | return -EINVAL; |
181 | } | 176 | } |
182 | 177 | ||
183 | input_unregister_device(udev->dev); | 178 | error = input_register_device(udev->dev); |
179 | if (error) { | ||
180 | uinput_destroy_device(udev); | ||
181 | return error; | ||
182 | } | ||
184 | 183 | ||
185 | clear_bit(UIST_CREATED, &udev->state); | 184 | udev->state = UIST_CREATED; |
186 | 185 | ||
187 | return 0; | 186 | return 0; |
188 | } | 187 | } |
189 | 188 | ||
190 | static int uinput_open(struct inode *inode, struct file *file) | 189 | static int uinput_open(struct inode *inode, struct file *file) |
191 | { | 190 | { |
192 | struct uinput_device *newdev; | 191 | struct uinput_device *newdev; |
193 | struct input_dev *newinput; | ||
194 | 192 | ||
195 | newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL); | 193 | newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL); |
196 | if (!newdev) | 194 | if (!newdev) |
197 | goto error; | 195 | return -ENOMEM; |
198 | memset(newdev, 0, sizeof(struct uinput_device)); | 196 | |
197 | init_MUTEX(&newdev->sem); | ||
199 | spin_lock_init(&newdev->requests_lock); | 198 | spin_lock_init(&newdev->requests_lock); |
200 | init_waitqueue_head(&newdev->requests_waitq); | 199 | init_waitqueue_head(&newdev->requests_waitq); |
201 | 200 | init_waitqueue_head(&newdev->waitq); | |
202 | newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); | 201 | newdev->state = UIST_NEW_DEVICE; |
203 | if (!newinput) | ||
204 | goto cleanup; | ||
205 | memset(newinput, 0, sizeof(struct input_dev)); | ||
206 | |||
207 | newdev->dev = newinput; | ||
208 | 202 | ||
209 | file->private_data = newdev; | 203 | file->private_data = newdev; |
210 | 204 | ||
211 | return 0; | 205 | return 0; |
212 | cleanup: | ||
213 | kfree(newdev); | ||
214 | error: | ||
215 | return -ENOMEM; | ||
216 | } | 206 | } |
217 | 207 | ||
218 | static int uinput_validate_absbits(struct input_dev *dev) | 208 | static int uinput_validate_absbits(struct input_dev *dev) |
@@ -246,34 +236,55 @@ static int uinput_validate_absbits(struct input_dev *dev) | |||
246 | return retval; | 236 | return retval; |
247 | } | 237 | } |
248 | 238 | ||
249 | static int uinput_alloc_device(struct file *file, const char __user *buffer, size_t count) | 239 | static int uinput_allocate_device(struct uinput_device *udev) |
240 | { | ||
241 | udev->dev = input_allocate_device(); | ||
242 | if (!udev->dev) | ||
243 | return -ENOMEM; | ||
244 | |||
245 | udev->dev->event = uinput_dev_event; | ||
246 | udev->dev->upload_effect = uinput_dev_upload_effect; | ||
247 | udev->dev->erase_effect = uinput_dev_erase_effect; | ||
248 | udev->dev->private = udev; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) | ||
250 | { | 254 | { |
251 | struct uinput_user_dev *user_dev; | 255 | struct uinput_user_dev *user_dev; |
252 | struct input_dev *dev; | 256 | struct input_dev *dev; |
253 | struct uinput_device *udev; | ||
254 | char *name; | 257 | char *name; |
255 | int size; | 258 | int size; |
256 | int retval; | 259 | int retval; |
257 | 260 | ||
258 | retval = count; | 261 | if (count != sizeof(struct uinput_user_dev)) |
262 | return -EINVAL; | ||
263 | |||
264 | if (!udev->dev) { | ||
265 | retval = uinput_allocate_device(udev); | ||
266 | if (retval) | ||
267 | return retval; | ||
268 | } | ||
259 | 269 | ||
260 | udev = file->private_data; | ||
261 | dev = udev->dev; | 270 | dev = udev->dev; |
262 | 271 | ||
263 | user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); | 272 | user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); |
264 | if (!user_dev) { | 273 | if (!user_dev) |
265 | retval = -ENOMEM; | 274 | return -ENOMEM; |
266 | goto exit; | ||
267 | } | ||
268 | 275 | ||
269 | if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { | 276 | if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { |
270 | retval = -EFAULT; | 277 | retval = -EFAULT; |
271 | goto exit; | 278 | goto exit; |
272 | } | 279 | } |
273 | 280 | ||
274 | kfree(dev->name); | ||
275 | |||
276 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; | 281 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; |
282 | if (!size) { | ||
283 | retval = -EINVAL; | ||
284 | goto exit; | ||
285 | } | ||
286 | |||
287 | kfree(dev->name); | ||
277 | dev->name = name = kmalloc(size, GFP_KERNEL); | 288 | dev->name = name = kmalloc(size, GFP_KERNEL); |
278 | if (!name) { | 289 | if (!name) { |
279 | retval = -ENOMEM; | 290 | retval = -ENOMEM; |
@@ -296,32 +307,50 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz | |||
296 | /* check if absmin/absmax/absfuzz/absflat are filled as | 307 | /* check if absmin/absmax/absfuzz/absflat are filled as |
297 | * told in Documentation/input/input-programming.txt */ | 308 | * told in Documentation/input/input-programming.txt */ |
298 | if (test_bit(EV_ABS, dev->evbit)) { | 309 | if (test_bit(EV_ABS, dev->evbit)) { |
299 | int err = uinput_validate_absbits(dev); | 310 | retval = uinput_validate_absbits(dev); |
300 | if (err < 0) { | 311 | if (retval < 0) |
301 | retval = err; | 312 | goto exit; |
302 | kfree(dev->name); | ||
303 | } | ||
304 | } | 313 | } |
305 | 314 | ||
306 | exit: | 315 | udev->state = UIST_SETUP_COMPLETE; |
316 | retval = count; | ||
317 | |||
318 | exit: | ||
307 | kfree(user_dev); | 319 | kfree(user_dev); |
308 | return retval; | 320 | return retval; |
309 | } | 321 | } |
310 | 322 | ||
323 | static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count) | ||
324 | { | ||
325 | struct input_event ev; | ||
326 | |||
327 | if (count != sizeof(struct input_event)) | ||
328 | return -EINVAL; | ||
329 | |||
330 | if (copy_from_user(&ev, buffer, sizeof(struct input_event))) | ||
331 | return -EFAULT; | ||
332 | |||
333 | input_event(udev->dev, ev.type, ev.code, ev.value); | ||
334 | |||
335 | return sizeof(struct input_event); | ||
336 | } | ||
337 | |||
311 | static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 338 | static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
312 | { | 339 | { |
313 | struct uinput_device *udev = file->private_data; | 340 | struct uinput_device *udev = file->private_data; |
341 | int retval; | ||
342 | |||
343 | retval = down_interruptible(&udev->sem); | ||
344 | if (retval) | ||
345 | return retval; | ||
314 | 346 | ||
315 | if (test_bit(UIST_CREATED, &udev->state)) { | 347 | retval = udev->state == UIST_CREATED ? |
316 | struct input_event ev; | 348 | uinput_inject_event(udev, buffer, count) : |
349 | uinput_setup_device(udev, buffer, count); | ||
317 | 350 | ||
318 | if (copy_from_user(&ev, buffer, sizeof(struct input_event))) | 351 | up(&udev->sem); |
319 | return -EFAULT; | ||
320 | input_event(udev->dev, ev.type, ev.code, ev.value); | ||
321 | } else | ||
322 | count = uinput_alloc_device(file, buffer, count); | ||
323 | 352 | ||
324 | return count; | 353 | return retval; |
325 | } | 354 | } |
326 | 355 | ||
327 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 356 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
@@ -329,28 +358,38 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, | |||
329 | struct uinput_device *udev = file->private_data; | 358 | struct uinput_device *udev = file->private_data; |
330 | int retval = 0; | 359 | int retval = 0; |
331 | 360 | ||
332 | if (!test_bit(UIST_CREATED, &udev->state)) | 361 | if (udev->state != UIST_CREATED) |
333 | return -ENODEV; | 362 | return -ENODEV; |
334 | 363 | ||
335 | if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) | 364 | if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) |
336 | return -EAGAIN; | 365 | return -EAGAIN; |
337 | 366 | ||
338 | retval = wait_event_interruptible(udev->waitq, | 367 | retval = wait_event_interruptible(udev->waitq, |
339 | udev->head != udev->tail || !test_bit(UIST_CREATED, &udev->state)); | 368 | udev->head != udev->tail || udev->state != UIST_CREATED); |
340 | if (retval) | 369 | if (retval) |
341 | return retval; | 370 | return retval; |
342 | 371 | ||
343 | if (!test_bit(UIST_CREATED, &udev->state)) | 372 | retval = down_interruptible(&udev->sem); |
344 | return -ENODEV; | 373 | if (retval) |
374 | return retval; | ||
345 | 375 | ||
346 | while ((udev->head != udev->tail) && | 376 | if (udev->state != UIST_CREATED) { |
347 | (retval + sizeof(struct input_event) <= count)) { | 377 | retval = -ENODEV; |
348 | if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) | 378 | goto out; |
349 | return -EFAULT; | 379 | } |
380 | |||
381 | while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) { | ||
382 | if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) { | ||
383 | retval = -EFAULT; | ||
384 | goto out; | ||
385 | } | ||
350 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; | 386 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; |
351 | retval += sizeof(struct input_event); | 387 | retval += sizeof(struct input_event); |
352 | } | 388 | } |
353 | 389 | ||
390 | out: | ||
391 | up(&udev->sem); | ||
392 | |||
354 | return retval; | 393 | return retval; |
355 | } | 394 | } |
356 | 395 | ||
@@ -366,28 +405,30 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) | |||
366 | return 0; | 405 | return 0; |
367 | } | 406 | } |
368 | 407 | ||
369 | static int uinput_burn_device(struct uinput_device *udev) | 408 | static int uinput_release(struct inode *inode, struct file *file) |
370 | { | 409 | { |
371 | if (test_bit(UIST_CREATED, &udev->state)) | 410 | struct uinput_device *udev = file->private_data; |
372 | uinput_destroy_device(udev); | ||
373 | 411 | ||
374 | kfree(udev->dev->name); | 412 | uinput_destroy_device(udev); |
375 | kfree(udev->dev->phys); | ||
376 | kfree(udev->dev); | ||
377 | kfree(udev); | 413 | kfree(udev); |
378 | 414 | ||
379 | return 0; | 415 | return 0; |
380 | } | 416 | } |
381 | 417 | ||
382 | static int uinput_close(struct inode *inode, struct file *file) | 418 | #define uinput_set_bit(_arg, _bit, _max) \ |
419 | ({ \ | ||
420 | int __ret = 0; \ | ||
421 | if (udev->state == UIST_CREATED) \ | ||
422 | __ret = -EINVAL; \ | ||
423 | else if ((_arg) > (_max)) \ | ||
424 | __ret = -EINVAL; \ | ||
425 | else set_bit((_arg), udev->dev->_bit); \ | ||
426 | __ret; \ | ||
427 | }) | ||
428 | |||
429 | static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
383 | { | 430 | { |
384 | uinput_burn_device(file->private_data); | 431 | int retval; |
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
389 | { | ||
390 | int retval = 0; | ||
391 | struct uinput_device *udev; | 432 | struct uinput_device *udev; |
392 | void __user *p = (void __user *)arg; | 433 | void __user *p = (void __user *)arg; |
393 | struct uinput_ff_upload ff_up; | 434 | struct uinput_ff_upload ff_up; |
@@ -398,19 +439,14 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
398 | 439 | ||
399 | udev = file->private_data; | 440 | udev = file->private_data; |
400 | 441 | ||
401 | /* device attributes can not be changed after the device is created */ | 442 | retval = down_interruptible(&udev->sem); |
402 | switch (cmd) { | 443 | if (retval) |
403 | case UI_SET_EVBIT: | 444 | return retval; |
404 | case UI_SET_KEYBIT: | 445 | |
405 | case UI_SET_RELBIT: | 446 | if (!udev->dev) { |
406 | case UI_SET_ABSBIT: | 447 | retval = uinput_allocate_device(udev); |
407 | case UI_SET_MSCBIT: | 448 | if (retval) |
408 | case UI_SET_LEDBIT: | 449 | goto out; |
409 | case UI_SET_SNDBIT: | ||
410 | case UI_SET_FFBIT: | ||
411 | case UI_SET_PHYS: | ||
412 | if (test_bit(UIST_CREATED, &udev->state)) | ||
413 | return -EINVAL; | ||
414 | } | 450 | } |
415 | 451 | ||
416 | switch (cmd) { | 452 | switch (cmd) { |
@@ -419,74 +455,50 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
419 | break; | 455 | break; |
420 | 456 | ||
421 | case UI_DEV_DESTROY: | 457 | case UI_DEV_DESTROY: |
422 | retval = uinput_destroy_device(udev); | 458 | uinput_destroy_device(udev); |
423 | break; | 459 | break; |
424 | 460 | ||
425 | case UI_SET_EVBIT: | 461 | case UI_SET_EVBIT: |
426 | if (arg > EV_MAX) { | 462 | retval = uinput_set_bit(arg, evbit, EV_MAX); |
427 | retval = -EINVAL; | ||
428 | break; | ||
429 | } | ||
430 | set_bit(arg, udev->dev->evbit); | ||
431 | break; | 463 | break; |
432 | 464 | ||
433 | case UI_SET_KEYBIT: | 465 | case UI_SET_KEYBIT: |
434 | if (arg > KEY_MAX) { | 466 | retval = uinput_set_bit(arg, keybit, KEY_MAX); |
435 | retval = -EINVAL; | ||
436 | break; | ||
437 | } | ||
438 | set_bit(arg, udev->dev->keybit); | ||
439 | break; | 467 | break; |
440 | 468 | ||
441 | case UI_SET_RELBIT: | 469 | case UI_SET_RELBIT: |
442 | if (arg > REL_MAX) { | 470 | retval = uinput_set_bit(arg, relbit, REL_MAX); |
443 | retval = -EINVAL; | ||
444 | break; | ||
445 | } | ||
446 | set_bit(arg, udev->dev->relbit); | ||
447 | break; | 471 | break; |
448 | 472 | ||
449 | case UI_SET_ABSBIT: | 473 | case UI_SET_ABSBIT: |
450 | if (arg > ABS_MAX) { | 474 | retval = uinput_set_bit(arg, absbit, ABS_MAX); |
451 | retval = -EINVAL; | ||
452 | break; | ||
453 | } | ||
454 | set_bit(arg, udev->dev->absbit); | ||
455 | break; | 475 | break; |
456 | 476 | ||
457 | case UI_SET_MSCBIT: | 477 | case UI_SET_MSCBIT: |
458 | if (arg > MSC_MAX) { | 478 | retval = uinput_set_bit(arg, mscbit, MSC_MAX); |
459 | retval = -EINVAL; | ||
460 | break; | ||
461 | } | ||
462 | set_bit(arg, udev->dev->mscbit); | ||
463 | break; | 479 | break; |
464 | 480 | ||
465 | case UI_SET_LEDBIT: | 481 | case UI_SET_LEDBIT: |
466 | if (arg > LED_MAX) { | 482 | retval = uinput_set_bit(arg, ledbit, LED_MAX); |
467 | retval = -EINVAL; | ||
468 | break; | ||
469 | } | ||
470 | set_bit(arg, udev->dev->ledbit); | ||
471 | break; | 483 | break; |
472 | 484 | ||
473 | case UI_SET_SNDBIT: | 485 | case UI_SET_SNDBIT: |
474 | if (arg > SND_MAX) { | 486 | retval = uinput_set_bit(arg, sndbit, SND_MAX); |
475 | retval = -EINVAL; | ||
476 | break; | ||
477 | } | ||
478 | set_bit(arg, udev->dev->sndbit); | ||
479 | break; | 487 | break; |
480 | 488 | ||
481 | case UI_SET_FFBIT: | 489 | case UI_SET_FFBIT: |
482 | if (arg > FF_MAX) { | 490 | retval = uinput_set_bit(arg, ffbit, FF_MAX); |
483 | retval = -EINVAL; | 491 | break; |
484 | break; | 492 | |
485 | } | 493 | case UI_SET_SWBIT: |
486 | set_bit(arg, udev->dev->ffbit); | 494 | retval = uinput_set_bit(arg, swbit, SW_MAX); |
487 | break; | 495 | break; |
488 | 496 | ||
489 | case UI_SET_PHYS: | 497 | case UI_SET_PHYS: |
498 | if (udev->state == UIST_CREATED) { | ||
499 | retval = -EINVAL; | ||
500 | goto out; | ||
501 | } | ||
490 | length = strnlen_user(p, 1024); | 502 | length = strnlen_user(p, 1024); |
491 | if (length <= 0) { | 503 | if (length <= 0) { |
492 | retval = -EFAULT; | 504 | retval = -EFAULT; |
@@ -575,23 +587,26 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
575 | default: | 587 | default: |
576 | retval = -EINVAL; | 588 | retval = -EINVAL; |
577 | } | 589 | } |
590 | |||
591 | out: | ||
592 | up(&udev->sem); | ||
578 | return retval; | 593 | return retval; |
579 | } | 594 | } |
580 | 595 | ||
581 | static struct file_operations uinput_fops = { | 596 | static struct file_operations uinput_fops = { |
582 | .owner = THIS_MODULE, | 597 | .owner = THIS_MODULE, |
583 | .open = uinput_open, | 598 | .open = uinput_open, |
584 | .release = uinput_close, | 599 | .release = uinput_release, |
585 | .read = uinput_read, | 600 | .read = uinput_read, |
586 | .write = uinput_write, | 601 | .write = uinput_write, |
587 | .poll = uinput_poll, | 602 | .poll = uinput_poll, |
588 | .ioctl = uinput_ioctl, | 603 | .unlocked_ioctl = uinput_ioctl, |
589 | }; | 604 | }; |
590 | 605 | ||
591 | static struct miscdevice uinput_misc = { | 606 | static struct miscdevice uinput_misc = { |
592 | .fops = &uinput_fops, | 607 | .fops = &uinput_fops, |
593 | .minor = UINPUT_MINOR, | 608 | .minor = UINPUT_MINOR, |
594 | .name = UINPUT_NAME, | 609 | .name = UINPUT_NAME, |
595 | }; | 610 | }; |
596 | 611 | ||
597 | static int __init uinput_init(void) | 612 | static int __init uinput_init(void) |