Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: fix build failure in hiddev_ioctl with gcc 3.2

Fix build failure in hiddev_ioctl with gcc 3.2:
http://bugzilla.kernel.org/show_bug.cgi?id=10121

The trick is to move the handling of ioctls which need to allocate
memory to separate functions.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Jean Delvare and committed by
Jiri Kosina
cf2a299e 80750147

+150 -136
+150 -136
drivers/hid/usbhid/hiddev.c
··· 393 393 /* 394 394 * "ioctl" file op 395 395 */ 396 + static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) 397 + { 398 + struct hid_device *hid = hiddev->hid; 399 + struct hiddev_report_info rinfo; 400 + struct hiddev_usage_ref_multi *uref_multi = NULL; 401 + struct hiddev_usage_ref *uref; 402 + struct hid_report *report; 403 + struct hid_field *field; 404 + int i; 405 + 406 + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 407 + if (!uref_multi) 408 + return -ENOMEM; 409 + uref = &uref_multi->uref; 410 + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { 411 + if (copy_from_user(uref_multi, user_arg, 412 + sizeof(*uref_multi))) 413 + goto fault; 414 + } else { 415 + if (copy_from_user(uref, user_arg, sizeof(*uref))) 416 + goto fault; 417 + } 418 + 419 + switch (cmd) { 420 + case HIDIOCGUCODE: 421 + rinfo.report_type = uref->report_type; 422 + rinfo.report_id = uref->report_id; 423 + if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 424 + goto inval; 425 + 426 + if (uref->field_index >= report->maxfield) 427 + goto inval; 428 + 429 + field = report->field[uref->field_index]; 430 + if (uref->usage_index >= field->maxusage) 431 + goto inval; 432 + 433 + uref->usage_code = field->usage[uref->usage_index].hid; 434 + 435 + if (copy_to_user(user_arg, uref, sizeof(*uref))) 436 + goto fault; 437 + 438 + kfree(uref_multi); 439 + return 0; 440 + 441 + default: 442 + if (cmd != HIDIOCGUSAGE && 443 + cmd != HIDIOCGUSAGES && 444 + uref->report_type == HID_REPORT_TYPE_INPUT) 445 + goto inval; 446 + 447 + if (uref->report_id == HID_REPORT_ID_UNKNOWN) { 448 + field = hiddev_lookup_usage(hid, uref); 449 + if (field == NULL) 450 + goto inval; 451 + } else { 452 + rinfo.report_type = uref->report_type; 453 + rinfo.report_id = uref->report_id; 454 + if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 455 + goto inval; 456 + 457 + if (uref->field_index >= report->maxfield) 458 + goto inval; 459 + 460 + field = report->field[uref->field_index]; 461 + 462 + if (cmd == HIDIOCGCOLLECTIONINDEX) { 463 + if (uref->usage_index >= field->maxusage) 464 + goto inval; 465 + } else if (uref->usage_index >= field->report_count) 466 + goto inval; 467 + 468 + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && 469 + (uref_multi->num_values > HID_MAX_MULTI_USAGES || 470 + uref->usage_index + uref_multi->num_values > field->report_count)) 471 + goto inval; 472 + } 473 + 474 + switch (cmd) { 475 + case HIDIOCGUSAGE: 476 + uref->value = field->value[uref->usage_index]; 477 + if (copy_to_user(user_arg, uref, sizeof(*uref))) 478 + goto fault; 479 + goto goodreturn; 480 + 481 + case HIDIOCSUSAGE: 482 + field->value[uref->usage_index] = uref->value; 483 + goto goodreturn; 484 + 485 + case HIDIOCGCOLLECTIONINDEX: 486 + kfree(uref_multi); 487 + return field->usage[uref->usage_index].collection_index; 488 + case HIDIOCGUSAGES: 489 + for (i = 0; i < uref_multi->num_values; i++) 490 + uref_multi->values[i] = 491 + field->value[uref->usage_index + i]; 492 + if (copy_to_user(user_arg, uref_multi, 493 + sizeof(*uref_multi))) 494 + goto fault; 495 + goto goodreturn; 496 + case HIDIOCSUSAGES: 497 + for (i = 0; i < uref_multi->num_values; i++) 498 + field->value[uref->usage_index + i] = 499 + uref_multi->values[i]; 500 + goto goodreturn; 501 + } 502 + 503 + goodreturn: 504 + kfree(uref_multi); 505 + return 0; 506 + fault: 507 + kfree(uref_multi); 508 + return -EFAULT; 509 + inval: 510 + kfree(uref_multi); 511 + return -EINVAL; 512 + } 513 + } 514 + 515 + static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) 516 + { 517 + struct hid_device *hid = hiddev->hid; 518 + struct usb_device *dev = hid_to_usb_dev(hid); 519 + int idx, len; 520 + char *buf; 521 + 522 + if (get_user(idx, (int __user *)user_arg)) 523 + return -EFAULT; 524 + 525 + if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) 526 + return -ENOMEM; 527 + 528 + if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { 529 + kfree(buf); 530 + return -EINVAL; 531 + } 532 + 533 + if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { 534 + kfree(buf); 535 + return -EFAULT; 536 + } 537 + 538 + kfree(buf); 539 + 540 + return len; 541 + } 542 + 396 543 static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 397 544 { 398 545 struct hiddev_list *list = file->private_data; ··· 549 402 struct hiddev_collection_info cinfo; 550 403 struct hiddev_report_info rinfo; 551 404 struct hiddev_field_info finfo; 552 - struct hiddev_usage_ref_multi *uref_multi = NULL; 553 - struct hiddev_usage_ref *uref; 554 405 struct hiddev_devinfo dinfo; 555 406 struct hid_report *report; 556 407 struct hid_field *field; ··· 615 470 } 616 471 617 472 case HIDIOCGSTRING: 618 - { 619 - int idx, len; 620 - char *buf; 621 - 622 - if (get_user(idx, (int __user *)arg)) 623 - return -EFAULT; 624 - 625 - if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) 626 - return -ENOMEM; 627 - 628 - if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { 629 - kfree(buf); 630 - return -EINVAL; 631 - } 632 - 633 - if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { 634 - kfree(buf); 635 - return -EFAULT; 636 - } 637 - 638 - kfree(buf); 639 - 640 - return len; 641 - } 473 + return hiddev_ioctl_string(hiddev, cmd, user_arg); 642 474 643 475 case HIDIOCINITREPORT: 644 476 usbhid_init_reports(hid); ··· 700 578 return 0; 701 579 702 580 case HIDIOCGUCODE: 703 - uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 704 - if (!uref_multi) 705 - return -ENOMEM; 706 - uref = &uref_multi->uref; 707 - if (copy_from_user(uref, user_arg, sizeof(*uref))) 708 - goto fault; 709 - 710 - rinfo.report_type = uref->report_type; 711 - rinfo.report_id = uref->report_id; 712 - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 713 - goto inval; 714 - 715 - if (uref->field_index >= report->maxfield) 716 - goto inval; 717 - 718 - field = report->field[uref->field_index]; 719 - if (uref->usage_index >= field->maxusage) 720 - goto inval; 721 - 722 - uref->usage_code = field->usage[uref->usage_index].hid; 723 - 724 - if (copy_to_user(user_arg, uref, sizeof(*uref))) 725 - goto fault; 726 - 727 - kfree(uref_multi); 728 - return 0; 729 - 581 + /* fall through */ 730 582 case HIDIOCGUSAGE: 731 583 case HIDIOCSUSAGE: 732 584 case HIDIOCGUSAGES: 733 585 case HIDIOCSUSAGES: 734 586 case HIDIOCGCOLLECTIONINDEX: 735 - uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 736 - if (!uref_multi) 737 - return -ENOMEM; 738 - uref = &uref_multi->uref; 739 - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { 740 - if (copy_from_user(uref_multi, user_arg, 741 - sizeof(*uref_multi))) 742 - goto fault; 743 - } else { 744 - if (copy_from_user(uref, user_arg, sizeof(*uref))) 745 - goto fault; 746 - } 747 - 748 - if (cmd != HIDIOCGUSAGE && 749 - cmd != HIDIOCGUSAGES && 750 - uref->report_type == HID_REPORT_TYPE_INPUT) 751 - goto inval; 752 - 753 - if (uref->report_id == HID_REPORT_ID_UNKNOWN) { 754 - field = hiddev_lookup_usage(hid, uref); 755 - if (field == NULL) 756 - goto inval; 757 - } else { 758 - rinfo.report_type = uref->report_type; 759 - rinfo.report_id = uref->report_id; 760 - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 761 - goto inval; 762 - 763 - if (uref->field_index >= report->maxfield) 764 - goto inval; 765 - 766 - field = report->field[uref->field_index]; 767 - 768 - if (cmd == HIDIOCGCOLLECTIONINDEX) { 769 - if (uref->usage_index >= field->maxusage) 770 - goto inval; 771 - } else if (uref->usage_index >= field->report_count) 772 - goto inval; 773 - 774 - else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && 775 - (uref_multi->num_values > HID_MAX_MULTI_USAGES || 776 - uref->usage_index + uref_multi->num_values > field->report_count)) 777 - goto inval; 778 - } 779 - 780 - switch (cmd) { 781 - case HIDIOCGUSAGE: 782 - uref->value = field->value[uref->usage_index]; 783 - if (copy_to_user(user_arg, uref, sizeof(*uref))) 784 - goto fault; 785 - goto goodreturn; 786 - 787 - case HIDIOCSUSAGE: 788 - field->value[uref->usage_index] = uref->value; 789 - goto goodreturn; 790 - 791 - case HIDIOCGCOLLECTIONINDEX: 792 - kfree(uref_multi); 793 - return field->usage[uref->usage_index].collection_index; 794 - case HIDIOCGUSAGES: 795 - for (i = 0; i < uref_multi->num_values; i++) 796 - uref_multi->values[i] = 797 - field->value[uref->usage_index + i]; 798 - if (copy_to_user(user_arg, uref_multi, 799 - sizeof(*uref_multi))) 800 - goto fault; 801 - goto goodreturn; 802 - case HIDIOCSUSAGES: 803 - for (i = 0; i < uref_multi->num_values; i++) 804 - field->value[uref->usage_index + i] = 805 - uref_multi->values[i]; 806 - goto goodreturn; 807 - } 808 - 809 - goodreturn: 810 - kfree(uref_multi); 811 - return 0; 812 - fault: 813 - kfree(uref_multi); 814 - return -EFAULT; 815 - inval: 816 - kfree(uref_multi); 817 - return -EINVAL; 587 + return hiddev_ioctl_usage(hiddev, cmd, user_arg); 818 588 819 589 case HIDIOCGCOLLECTIONINFO: 820 590 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))