aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2005-11-20 00:51:22 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2005-11-20 00:51:22 -0500
commit29506415a0ff0152cc2928f8fcac724fbbf98651 (patch)
treee1da48667c6b0499f2ea882b1d762758241da1e6
parente753b650e10af8a040b1081e72088b826bdef72f (diff)
Input: uinput - convert to dynalloc allocation
Also introduce proper locking when creating/deleting device. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/misc/uinput.c310
-rw-r--r--include/linux/uinput.h12
2 files changed, 169 insertions, 153 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 948c1cc01bc9..713260322137 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -152,67 +152,62 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
152 return retval; 152 return retval;
153} 153}
154 154
155static int uinput_create_device(struct uinput_device *udev) 155static void uinput_destroy_device(struct uinput_device *udev)
156{ 156{
157 if (!udev->dev->name) { 157 const char *name, *phys;
158 printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); 158
159 return -EINVAL; 159 if (udev->dev) {
160 name = udev->dev->name;
161 phys = udev->dev->phys;
162 if (udev->state == UIST_CREATED)
163 input_unregister_device(udev->dev);
164 else
165 input_free_device(udev->dev);
166 kfree(name);
167 kfree(phys);
168 udev->dev = NULL;
160 } 169 }
161 170
162 udev->dev->event = uinput_dev_event; 171 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} 172}
175 173
176static int uinput_destroy_device(struct uinput_device *udev) 174static int uinput_create_device(struct uinput_device *udev)
177{ 175{
178 if (!test_bit(UIST_CREATED, &udev->state)) { 176 int error;
179 printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); 177
178 if (udev->state != UIST_SETUP_COMPLETE) {
179 printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
180 return -EINVAL; 180 return -EINVAL;
181 } 181 }
182 182
183 input_unregister_device(udev->dev); 183 error = input_register_device(udev->dev);
184 if (error) {
185 uinput_destroy_device(udev);
186 return error;
187 }
184 188
185 clear_bit(UIST_CREATED, &udev->state); 189 udev->state = UIST_CREATED;
186 190
187 return 0; 191 return 0;
188} 192}
189 193
190static int uinput_open(struct inode *inode, struct file *file) 194static int uinput_open(struct inode *inode, struct file *file)
191{ 195{
192 struct uinput_device *newdev; 196 struct uinput_device *newdev;
193 struct input_dev *newinput;
194 197
195 newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL); 198 newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);
196 if (!newdev) 199 if (!newdev)
197 goto error; 200 return -ENOMEM;
198 memset(newdev, 0, sizeof(struct uinput_device)); 201
202 init_MUTEX(&newdev->sem);
199 spin_lock_init(&newdev->requests_lock); 203 spin_lock_init(&newdev->requests_lock);
200 init_waitqueue_head(&newdev->requests_waitq); 204 init_waitqueue_head(&newdev->requests_waitq);
201 205 init_waitqueue_head(&newdev->waitq);
202 newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); 206 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 207
209 file->private_data = newdev; 208 file->private_data = newdev;
210 209
211 return 0; 210 return 0;
212cleanup:
213 kfree(newdev);
214error:
215 return -ENOMEM;
216} 211}
217 212
218static int uinput_validate_absbits(struct input_dev *dev) 213static int uinput_validate_absbits(struct input_dev *dev)
@@ -246,34 +241,55 @@ static int uinput_validate_absbits(struct input_dev *dev)
246 return retval; 241 return retval;
247} 242}
248 243
249static int uinput_alloc_device(struct file *file, const char __user *buffer, size_t count) 244static int uinput_allocate_device(struct uinput_device *udev)
245{
246 udev->dev = input_allocate_device();
247 if (!udev->dev)
248 return -ENOMEM;
249
250 udev->dev->event = uinput_dev_event;
251 udev->dev->upload_effect = uinput_dev_upload_effect;
252 udev->dev->erase_effect = uinput_dev_erase_effect;
253 udev->dev->private = udev;
254
255 return 0;
256}
257
258static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count)
250{ 259{
251 struct uinput_user_dev *user_dev; 260 struct uinput_user_dev *user_dev;
252 struct input_dev *dev; 261 struct input_dev *dev;
253 struct uinput_device *udev;
254 char *name; 262 char *name;
255 int size; 263 int size;
256 int retval; 264 int retval;
257 265
258 retval = count; 266 if (count != sizeof(struct uinput_user_dev))
267 return -EINVAL;
268
269 if (!udev->dev) {
270 retval = uinput_allocate_device(udev);
271 if (retval)
272 return retval;
273 }
259 274
260 udev = file->private_data;
261 dev = udev->dev; 275 dev = udev->dev;
262 276
263 user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); 277 user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL);
264 if (!user_dev) { 278 if (!user_dev)
265 retval = -ENOMEM; 279 return -ENOMEM;
266 goto exit;
267 }
268 280
269 if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { 281 if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
270 retval = -EFAULT; 282 retval = -EFAULT;
271 goto exit; 283 goto exit;
272 } 284 }
273 285
274 kfree(dev->name);
275
276 size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; 286 size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
287 if (!size) {
288 retval = -EINVAL;
289 goto exit;
290 }
291
292 kfree(dev->name);
277 dev->name = name = kmalloc(size, GFP_KERNEL); 293 dev->name = name = kmalloc(size, GFP_KERNEL);
278 if (!name) { 294 if (!name) {
279 retval = -ENOMEM; 295 retval = -ENOMEM;
@@ -296,32 +312,50 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
296 /* check if absmin/absmax/absfuzz/absflat are filled as 312 /* check if absmin/absmax/absfuzz/absflat are filled as
297 * told in Documentation/input/input-programming.txt */ 313 * told in Documentation/input/input-programming.txt */
298 if (test_bit(EV_ABS, dev->evbit)) { 314 if (test_bit(EV_ABS, dev->evbit)) {
299 int err = uinput_validate_absbits(dev); 315 retval = uinput_validate_absbits(dev);
300 if (err < 0) { 316 if (retval < 0)
301 retval = err; 317 goto exit;
302 kfree(dev->name);
303 }
304 } 318 }
305 319
306exit: 320 udev->state = UIST_SETUP_COMPLETE;
321 retval = count;
322
323 exit:
307 kfree(user_dev); 324 kfree(user_dev);
308 return retval; 325 return retval;
309} 326}
310 327
328static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count)
329{
330 struct input_event ev;
331
332 if (count != sizeof(struct input_event))
333 return -EINVAL;
334
335 if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
336 return -EFAULT;
337
338 input_event(udev->dev, ev.type, ev.code, ev.value);
339
340 return sizeof(struct input_event);
341}
342
311static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 343static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
312{ 344{
313 struct uinput_device *udev = file->private_data; 345 struct uinput_device *udev = file->private_data;
346 int retval;
314 347
315 if (test_bit(UIST_CREATED, &udev->state)) { 348 retval = down_interruptible(&udev->sem);
316 struct input_event ev; 349 if (retval)
350 return retval;
351
352 retval = udev->state == UIST_CREATED ?
353 uinput_inject_event(udev, buffer, count) :
354 uinput_setup_device(udev, buffer, count);
317 355
318 if (copy_from_user(&ev, buffer, sizeof(struct input_event))) 356 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 357
324 return count; 358 return retval;
325} 359}
326 360
327static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 361static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
@@ -329,28 +363,38 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count,
329 struct uinput_device *udev = file->private_data; 363 struct uinput_device *udev = file->private_data;
330 int retval = 0; 364 int retval = 0;
331 365
332 if (!test_bit(UIST_CREATED, &udev->state)) 366 if (udev->state != UIST_CREATED)
333 return -ENODEV; 367 return -ENODEV;
334 368
335 if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) 369 if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK))
336 return -EAGAIN; 370 return -EAGAIN;
337 371
338 retval = wait_event_interruptible(udev->waitq, 372 retval = wait_event_interruptible(udev->waitq,
339 udev->head != udev->tail || !test_bit(UIST_CREATED, &udev->state)); 373 udev->head != udev->tail || udev->state != UIST_CREATED);
340 if (retval) 374 if (retval)
341 return retval; 375 return retval;
342 376
343 if (!test_bit(UIST_CREATED, &udev->state)) 377 retval = down_interruptible(&udev->sem);
344 return -ENODEV; 378 if (retval)
379 return retval;
380
381 if (udev->state != UIST_CREATED) {
382 retval = -ENODEV;
383 goto out;
384 }
345 385
346 while ((udev->head != udev->tail) && 386 while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) {
347 (retval + sizeof(struct input_event) <= count)) { 387 if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) {
348 if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) 388 retval = -EFAULT;
349 return -EFAULT; 389 goto out;
390 }
350 udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; 391 udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
351 retval += sizeof(struct input_event); 392 retval += sizeof(struct input_event);
352 } 393 }
353 394
395 out:
396 up(&udev->sem);
397
354 return retval; 398 return retval;
355} 399}
356 400
@@ -366,28 +410,30 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait)
366 return 0; 410 return 0;
367} 411}
368 412
369static int uinput_burn_device(struct uinput_device *udev) 413static int uinput_release(struct inode *inode, struct file *file)
370{ 414{
371 if (test_bit(UIST_CREATED, &udev->state)) 415 struct uinput_device *udev = file->private_data;
372 uinput_destroy_device(udev);
373 416
374 kfree(udev->dev->name); 417 uinput_destroy_device(udev);
375 kfree(udev->dev->phys);
376 kfree(udev->dev);
377 kfree(udev); 418 kfree(udev);
378 419
379 return 0; 420 return 0;
380} 421}
381 422
382static int uinput_close(struct inode *inode, struct file *file) 423#define uinput_set_bit(_arg, _bit, _max) \
424({ \
425 int __ret = 0; \
426 if (udev->state == UIST_CREATED) \
427 __ret = -EINVAL; \
428 else if ((_arg) > (_max)) \
429 __ret = -EINVAL; \
430 else set_bit((_arg), udev->dev->_bit); \
431 __ret; \
432})
433
434static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
383{ 435{
384 uinput_burn_device(file->private_data); 436 int retval;
385 return 0;
386}
387
388static 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; 437 struct uinput_device *udev;
392 void __user *p = (void __user *)arg; 438 void __user *p = (void __user *)arg;
393 struct uinput_ff_upload ff_up; 439 struct uinput_ff_upload ff_up;
@@ -398,19 +444,14 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd
398 444
399 udev = file->private_data; 445 udev = file->private_data;
400 446
401 /* device attributes can not be changed after the device is created */ 447 retval = down_interruptible(&udev->sem);
402 switch (cmd) { 448 if (retval)
403 case UI_SET_EVBIT: 449 return retval;
404 case UI_SET_KEYBIT: 450
405 case UI_SET_RELBIT: 451 if (!udev->dev) {
406 case UI_SET_ABSBIT: 452 retval = uinput_allocate_device(udev);
407 case UI_SET_MSCBIT: 453 if (retval)
408 case UI_SET_LEDBIT: 454 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 } 455 }
415 456
416 switch (cmd) { 457 switch (cmd) {
@@ -419,74 +460,46 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd
419 break; 460 break;
420 461
421 case UI_DEV_DESTROY: 462 case UI_DEV_DESTROY:
422 retval = uinput_destroy_device(udev); 463 uinput_destroy_device(udev);
423 break; 464 break;
424 465
425 case UI_SET_EVBIT: 466 case UI_SET_EVBIT:
426 if (arg > EV_MAX) { 467 retval = uinput_set_bit(arg, evbit, EV_MAX);
427 retval = -EINVAL;
428 break;
429 }
430 set_bit(arg, udev->dev->evbit);
431 break; 468 break;
432 469
433 case UI_SET_KEYBIT: 470 case UI_SET_KEYBIT:
434 if (arg > KEY_MAX) { 471 retval = uinput_set_bit(arg, keybit, KEY_MAX);
435 retval = -EINVAL;
436 break;
437 }
438 set_bit(arg, udev->dev->keybit);
439 break; 472 break;
440 473
441 case UI_SET_RELBIT: 474 case UI_SET_RELBIT:
442 if (arg > REL_MAX) { 475 retval = uinput_set_bit(arg, relbit, REL_MAX);
443 retval = -EINVAL;
444 break;
445 }
446 set_bit(arg, udev->dev->relbit);
447 break; 476 break;
448 477
449 case UI_SET_ABSBIT: 478 case UI_SET_ABSBIT:
450 if (arg > ABS_MAX) { 479 retval = uinput_set_bit(arg, absbit, ABS_MAX);
451 retval = -EINVAL;
452 break;
453 }
454 set_bit(arg, udev->dev->absbit);
455 break; 480 break;
456 481
457 case UI_SET_MSCBIT: 482 case UI_SET_MSCBIT:
458 if (arg > MSC_MAX) { 483 retval = uinput_set_bit(arg, mscbit, MSC_MAX);
459 retval = -EINVAL;
460 break;
461 }
462 set_bit(arg, udev->dev->mscbit);
463 break; 484 break;
464 485
465 case UI_SET_LEDBIT: 486 case UI_SET_LEDBIT:
466 if (arg > LED_MAX) { 487 retval = uinput_set_bit(arg, ledbit, LED_MAX);
467 retval = -EINVAL;
468 break;
469 }
470 set_bit(arg, udev->dev->ledbit);
471 break; 488 break;
472 489
473 case UI_SET_SNDBIT: 490 case UI_SET_SNDBIT:
474 if (arg > SND_MAX) { 491 retval = uinput_set_bit(arg, sndbit, SND_MAX);
475 retval = -EINVAL;
476 break;
477 }
478 set_bit(arg, udev->dev->sndbit);
479 break; 492 break;
480 493
481 case UI_SET_FFBIT: 494 case UI_SET_FFBIT:
482 if (arg > FF_MAX) { 495 retval = uinput_set_bit(arg, ffbit, FF_MAX);
483 retval = -EINVAL;
484 break;
485 }
486 set_bit(arg, udev->dev->ffbit);
487 break; 496 break;
488 497
489 case UI_SET_PHYS: 498 case UI_SET_PHYS:
499 if (udev->state == UIST_CREATED) {
500 retval = -EINVAL;
501 goto out;
502 }
490 length = strnlen_user(p, 1024); 503 length = strnlen_user(p, 1024);
491 if (length <= 0) { 504 if (length <= 0) {
492 retval = -EFAULT; 505 retval = -EFAULT;
@@ -575,23 +588,26 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd
575 default: 588 default:
576 retval = -EINVAL; 589 retval = -EINVAL;
577 } 590 }
591
592 out:
593 up(&udev->sem);
578 return retval; 594 return retval;
579} 595}
580 596
581static struct file_operations uinput_fops = { 597static struct file_operations uinput_fops = {
582 .owner = THIS_MODULE, 598 .owner = THIS_MODULE,
583 .open = uinput_open, 599 .open = uinput_open,
584 .release = uinput_close, 600 .release = uinput_release,
585 .read = uinput_read, 601 .read = uinput_read,
586 .write = uinput_write, 602 .write = uinput_write,
587 .poll = uinput_poll, 603 .poll = uinput_poll,
588 .ioctl = uinput_ioctl, 604 .unlocked_ioctl = uinput_ioctl,
589}; 605};
590 606
591static struct miscdevice uinput_misc = { 607static struct miscdevice uinput_misc = {
592 .fops = &uinput_fops, 608 .fops = &uinput_fops,
593 .minor = UINPUT_MINOR, 609 .minor = UINPUT_MINOR,
594 .name = UINPUT_NAME, 610 .name = UINPUT_NAME,
595}; 611};
596 612
597static int __init uinput_init(void) 613static int __init uinput_init(void)
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 84876077027f..6fd1a47acab2 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -34,8 +34,7 @@
34#define UINPUT_BUFFER_SIZE 16 34#define UINPUT_BUFFER_SIZE 16
35#define UINPUT_NUM_REQUESTS 16 35#define UINPUT_NUM_REQUESTS 16
36 36
37/* state flags => bit index for {set|clear|test}_bit ops */ 37enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
38#define UIST_CREATED 0
39 38
40struct uinput_request { 39struct uinput_request {
41 int id; 40 int id;
@@ -52,11 +51,12 @@ struct uinput_request {
52 51
53struct uinput_device { 52struct uinput_device {
54 struct input_dev *dev; 53 struct input_dev *dev;
55 unsigned long state; 54 struct semaphore sem;
55 enum uinput_state state;
56 wait_queue_head_t waitq; 56 wait_queue_head_t waitq;
57 unsigned char ready, 57 unsigned char ready;
58 head, 58 unsigned char head;
59 tail; 59 unsigned char tail;
60 struct input_event buff[UINPUT_BUFFER_SIZE]; 60 struct input_event buff[UINPUT_BUFFER_SIZE];
61 61
62 struct uinput_request *requests[UINPUT_NUM_REQUESTS]; 62 struct uinput_request *requests[UINPUT_NUM_REQUESTS];