diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/firewire/core-cdev.c | 325 |
1 files changed, 152 insertions, 173 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index a4aa477b9b2c..d7de17a0f250 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
| @@ -368,39 +368,56 @@ void fw_device_cdev_remove(struct fw_device *device) | |||
| 368 | for_each_client(device, wake_up_client); | 368 | for_each_client(device, wake_up_client); |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | static int ioctl_get_info(struct client *client, void *buffer) | 371 | union ioctl_arg { |
| 372 | struct fw_cdev_get_info get_info; | ||
| 373 | struct fw_cdev_send_request send_request; | ||
| 374 | struct fw_cdev_allocate allocate; | ||
| 375 | struct fw_cdev_deallocate deallocate; | ||
| 376 | struct fw_cdev_send_response send_response; | ||
| 377 | struct fw_cdev_initiate_bus_reset initiate_bus_reset; | ||
| 378 | struct fw_cdev_add_descriptor add_descriptor; | ||
| 379 | struct fw_cdev_remove_descriptor remove_descriptor; | ||
| 380 | struct fw_cdev_create_iso_context create_iso_context; | ||
| 381 | struct fw_cdev_queue_iso queue_iso; | ||
| 382 | struct fw_cdev_start_iso start_iso; | ||
| 383 | struct fw_cdev_stop_iso stop_iso; | ||
| 384 | struct fw_cdev_get_cycle_timer get_cycle_timer; | ||
| 385 | struct fw_cdev_allocate_iso_resource allocate_iso_resource; | ||
| 386 | struct fw_cdev_send_stream_packet send_stream_packet; | ||
| 387 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; | ||
| 388 | }; | ||
| 389 | |||
| 390 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) | ||
| 372 | { | 391 | { |
| 373 | struct fw_cdev_get_info *get_info = buffer; | 392 | struct fw_cdev_get_info *a = &arg->get_info; |
| 374 | struct fw_cdev_event_bus_reset bus_reset; | 393 | struct fw_cdev_event_bus_reset bus_reset; |
| 375 | unsigned long ret = 0; | 394 | unsigned long ret = 0; |
| 376 | 395 | ||
| 377 | client->version = get_info->version; | 396 | client->version = a->version; |
| 378 | get_info->version = FW_CDEV_VERSION; | 397 | a->version = FW_CDEV_VERSION; |
| 379 | get_info->card = client->device->card->index; | 398 | a->card = client->device->card->index; |
| 380 | 399 | ||
| 381 | down_read(&fw_device_rwsem); | 400 | down_read(&fw_device_rwsem); |
| 382 | 401 | ||
| 383 | if (get_info->rom != 0) { | 402 | if (a->rom != 0) { |
| 384 | void __user *uptr = u64_to_uptr(get_info->rom); | 403 | size_t want = a->rom_length; |
| 385 | size_t want = get_info->rom_length; | ||
| 386 | size_t have = client->device->config_rom_length * 4; | 404 | size_t have = client->device->config_rom_length * 4; |
| 387 | 405 | ||
| 388 | ret = copy_to_user(uptr, client->device->config_rom, | 406 | ret = copy_to_user(u64_to_uptr(a->rom), |
| 389 | min(want, have)); | 407 | client->device->config_rom, min(want, have)); |
| 390 | } | 408 | } |
| 391 | get_info->rom_length = client->device->config_rom_length * 4; | 409 | a->rom_length = client->device->config_rom_length * 4; |
| 392 | 410 | ||
| 393 | up_read(&fw_device_rwsem); | 411 | up_read(&fw_device_rwsem); |
| 394 | 412 | ||
| 395 | if (ret != 0) | 413 | if (ret != 0) |
| 396 | return -EFAULT; | 414 | return -EFAULT; |
| 397 | 415 | ||
| 398 | client->bus_reset_closure = get_info->bus_reset_closure; | 416 | client->bus_reset_closure = a->bus_reset_closure; |
| 399 | if (get_info->bus_reset != 0) { | 417 | if (a->bus_reset != 0) { |
| 400 | void __user *uptr = u64_to_uptr(get_info->bus_reset); | ||
| 401 | |||
| 402 | fill_bus_reset_event(&bus_reset, client); | 418 | fill_bus_reset_event(&bus_reset, client); |
| 403 | if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) | 419 | if (copy_to_user(u64_to_uptr(a->bus_reset), |
| 420 | &bus_reset, sizeof(bus_reset))) | ||
| 404 | return -EFAULT; | 421 | return -EFAULT; |
| 405 | } | 422 | } |
| 406 | 423 | ||
| @@ -571,11 +588,9 @@ static int init_request(struct client *client, | |||
| 571 | return ret; | 588 | return ret; |
| 572 | } | 589 | } |
| 573 | 590 | ||
| 574 | static int ioctl_send_request(struct client *client, void *buffer) | 591 | static int ioctl_send_request(struct client *client, union ioctl_arg *arg) |
| 575 | { | 592 | { |
| 576 | struct fw_cdev_send_request *request = buffer; | 593 | switch (arg->send_request.tcode) { |
| 577 | |||
| 578 | switch (request->tcode) { | ||
| 579 | case TCODE_WRITE_QUADLET_REQUEST: | 594 | case TCODE_WRITE_QUADLET_REQUEST: |
| 580 | case TCODE_WRITE_BLOCK_REQUEST: | 595 | case TCODE_WRITE_BLOCK_REQUEST: |
| 581 | case TCODE_READ_QUADLET_REQUEST: | 596 | case TCODE_READ_QUADLET_REQUEST: |
| @@ -592,7 +607,7 @@ static int ioctl_send_request(struct client *client, void *buffer) | |||
| 592 | return -EINVAL; | 607 | return -EINVAL; |
| 593 | } | 608 | } |
| 594 | 609 | ||
| 595 | return init_request(client, request, client->device->node_id, | 610 | return init_request(client, &arg->send_request, client->device->node_id, |
| 596 | client->device->max_speed); | 611 | client->device->max_speed); |
| 597 | } | 612 | } |
| 598 | 613 | ||
| @@ -683,9 +698,9 @@ static void release_address_handler(struct client *client, | |||
| 683 | kfree(r); | 698 | kfree(r); |
| 684 | } | 699 | } |
| 685 | 700 | ||
| 686 | static int ioctl_allocate(struct client *client, void *buffer) | 701 | static int ioctl_allocate(struct client *client, union ioctl_arg *arg) |
| 687 | { | 702 | { |
| 688 | struct fw_cdev_allocate *request = buffer; | 703 | struct fw_cdev_allocate *a = &arg->allocate; |
| 689 | struct address_handler_resource *r; | 704 | struct address_handler_resource *r; |
| 690 | struct fw_address_region region; | 705 | struct fw_address_region region; |
| 691 | int ret; | 706 | int ret; |
| @@ -694,13 +709,13 @@ static int ioctl_allocate(struct client *client, void *buffer) | |||
| 694 | if (r == NULL) | 709 | if (r == NULL) |
| 695 | return -ENOMEM; | 710 | return -ENOMEM; |
| 696 | 711 | ||
| 697 | region.start = request->offset; | 712 | region.start = a->offset; |
| 698 | region.end = request->offset + request->length; | 713 | region.end = a->offset + a->length; |
| 699 | r->handler.length = request->length; | 714 | r->handler.length = a->length; |
| 700 | r->handler.address_callback = handle_request; | 715 | r->handler.address_callback = handle_request; |
| 701 | r->handler.callback_data = r; | 716 | r->handler.callback_data = r; |
| 702 | r->closure = request->closure; | 717 | r->closure = a->closure; |
| 703 | r->client = client; | 718 | r->client = client; |
| 704 | 719 | ||
| 705 | ret = fw_core_add_address_handler(&r->handler, ®ion); | 720 | ret = fw_core_add_address_handler(&r->handler, ®ion); |
| 706 | if (ret < 0) { | 721 | if (ret < 0) { |
| @@ -714,27 +729,25 @@ static int ioctl_allocate(struct client *client, void *buffer) | |||
| 714 | release_address_handler(client, &r->resource); | 729 | release_address_handler(client, &r->resource); |
| 715 | return ret; | 730 | return ret; |
| 716 | } | 731 | } |
| 717 | request->handle = r->resource.handle; | 732 | a->handle = r->resource.handle; |
| 718 | 733 | ||
| 719 | return 0; | 734 | return 0; |
| 720 | } | 735 | } |
| 721 | 736 | ||
| 722 | static int ioctl_deallocate(struct client *client, void *buffer) | 737 | static int ioctl_deallocate(struct client *client, union ioctl_arg *arg) |
| 723 | { | 738 | { |
| 724 | struct fw_cdev_deallocate *request = buffer; | 739 | return release_client_resource(client, arg->deallocate.handle, |
| 725 | |||
| 726 | return release_client_resource(client, request->handle, | ||
| 727 | release_address_handler, NULL); | 740 | release_address_handler, NULL); |
| 728 | } | 741 | } |
| 729 | 742 | ||
| 730 | static int ioctl_send_response(struct client *client, void *buffer) | 743 | static int ioctl_send_response(struct client *client, union ioctl_arg *arg) |
| 731 | { | 744 | { |
| 732 | struct fw_cdev_send_response *request = buffer; | 745 | struct fw_cdev_send_response *a = &arg->send_response; |
| 733 | struct client_resource *resource; | 746 | struct client_resource *resource; |
| 734 | struct inbound_transaction_resource *r; | 747 | struct inbound_transaction_resource *r; |
| 735 | int ret = 0; | 748 | int ret = 0; |
| 736 | 749 | ||
| 737 | if (release_client_resource(client, request->handle, | 750 | if (release_client_resource(client, a->handle, |
| 738 | release_request, &resource) < 0) | 751 | release_request, &resource) < 0) |
| 739 | return -EINVAL; | 752 | return -EINVAL; |
| 740 | 753 | ||
| @@ -743,28 +756,24 @@ static int ioctl_send_response(struct client *client, void *buffer) | |||
| 743 | if (is_fcp_request(r->request)) | 756 | if (is_fcp_request(r->request)) |
| 744 | goto out; | 757 | goto out; |
| 745 | 758 | ||
| 746 | if (request->length < r->length) | 759 | if (a->length < r->length) |
| 747 | r->length = request->length; | 760 | r->length = a->length; |
| 748 | if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) { | 761 | if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) { |
| 749 | ret = -EFAULT; | 762 | ret = -EFAULT; |
| 750 | kfree(r->request); | 763 | kfree(r->request); |
| 751 | goto out; | 764 | goto out; |
| 752 | } | 765 | } |
| 753 | fw_send_response(client->device->card, r->request, request->rcode); | 766 | fw_send_response(client->device->card, r->request, a->rcode); |
| 754 | out: | 767 | out: |
| 755 | kfree(r); | 768 | kfree(r); |
| 756 | 769 | ||
| 757 | return ret; | 770 | return ret; |
| 758 | } | 771 | } |
| 759 | 772 | ||
| 760 | static int ioctl_initiate_bus_reset(struct client *client, void *buffer) | 773 | static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg) |
| 761 | { | 774 | { |
| 762 | struct fw_cdev_initiate_bus_reset *request = buffer; | 775 | return fw_core_initiate_bus_reset(client->device->card, |
| 763 | int short_reset; | 776 | arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET); |
| 764 | |||
| 765 | short_reset = (request->type == FW_CDEV_SHORT_RESET); | ||
| 766 | |||
| 767 | return fw_core_initiate_bus_reset(client->device->card, short_reset); | ||
| 768 | } | 777 | } |
| 769 | 778 | ||
| 770 | static void release_descriptor(struct client *client, | 779 | static void release_descriptor(struct client *client, |
| @@ -777,9 +786,9 @@ static void release_descriptor(struct client *client, | |||
| 777 | kfree(r); | 786 | kfree(r); |
| 778 | } | 787 | } |
| 779 | 788 | ||
| 780 | static int ioctl_add_descriptor(struct client *client, void *buffer) | 789 | static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg) |
| 781 | { | 790 | { |
| 782 | struct fw_cdev_add_descriptor *request = buffer; | 791 | struct fw_cdev_add_descriptor *a = &arg->add_descriptor; |
| 783 | struct descriptor_resource *r; | 792 | struct descriptor_resource *r; |
| 784 | int ret; | 793 | int ret; |
| 785 | 794 | ||
| @@ -787,22 +796,21 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) | |||
| 787 | if (!client->device->is_local) | 796 | if (!client->device->is_local) |
| 788 | return -ENOSYS; | 797 | return -ENOSYS; |
| 789 | 798 | ||
| 790 | if (request->length > 256) | 799 | if (a->length > 256) |
| 791 | return -EINVAL; | 800 | return -EINVAL; |
| 792 | 801 | ||
| 793 | r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL); | 802 | r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL); |
| 794 | if (r == NULL) | 803 | if (r == NULL) |
| 795 | return -ENOMEM; | 804 | return -ENOMEM; |
| 796 | 805 | ||
| 797 | if (copy_from_user(r->data, | 806 | if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) { |
| 798 | u64_to_uptr(request->data), request->length * 4)) { | ||
| 799 | ret = -EFAULT; | 807 | ret = -EFAULT; |
| 800 | goto failed; | 808 | goto failed; |
| 801 | } | 809 | } |
| 802 | 810 | ||
| 803 | r->descriptor.length = request->length; | 811 | r->descriptor.length = a->length; |
| 804 | r->descriptor.immediate = request->immediate; | 812 | r->descriptor.immediate = a->immediate; |
| 805 | r->descriptor.key = request->key; | 813 | r->descriptor.key = a->key; |
| 806 | r->descriptor.data = r->data; | 814 | r->descriptor.data = r->data; |
| 807 | 815 | ||
| 808 | ret = fw_core_add_descriptor(&r->descriptor); | 816 | ret = fw_core_add_descriptor(&r->descriptor); |
| @@ -815,7 +823,7 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) | |||
| 815 | fw_core_remove_descriptor(&r->descriptor); | 823 | fw_core_remove_descriptor(&r->descriptor); |
| 816 | goto failed; | 824 | goto failed; |
| 817 | } | 825 | } |
| 818 | request->handle = r->resource.handle; | 826 | a->handle = r->resource.handle; |
| 819 | 827 | ||
| 820 | return 0; | 828 | return 0; |
| 821 | failed: | 829 | failed: |
| @@ -824,11 +832,9 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) | |||
| 824 | return ret; | 832 | return ret; |
| 825 | } | 833 | } |
| 826 | 834 | ||
| 827 | static int ioctl_remove_descriptor(struct client *client, void *buffer) | 835 | static int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg) |
| 828 | { | 836 | { |
| 829 | struct fw_cdev_remove_descriptor *request = buffer; | 837 | return release_client_resource(client, arg->remove_descriptor.handle, |
| 830 | |||
| 831 | return release_client_resource(client, request->handle, | ||
| 832 | release_descriptor, NULL); | 838 | release_descriptor, NULL); |
| 833 | } | 839 | } |
| 834 | 840 | ||
| @@ -851,49 +857,44 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, | |||
| 851 | sizeof(e->interrupt) + header_length, NULL, 0); | 857 | sizeof(e->interrupt) + header_length, NULL, 0); |
| 852 | } | 858 | } |
| 853 | 859 | ||
| 854 | static int ioctl_create_iso_context(struct client *client, void *buffer) | 860 | static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) |
| 855 | { | 861 | { |
| 856 | struct fw_cdev_create_iso_context *request = buffer; | 862 | struct fw_cdev_create_iso_context *a = &arg->create_iso_context; |
| 857 | struct fw_iso_context *context; | 863 | struct fw_iso_context *context; |
| 858 | 864 | ||
| 859 | /* We only support one context at this time. */ | 865 | /* We only support one context at this time. */ |
| 860 | if (client->iso_context != NULL) | 866 | if (client->iso_context != NULL) |
| 861 | return -EBUSY; | 867 | return -EBUSY; |
| 862 | 868 | ||
| 863 | if (request->channel > 63) | 869 | if (a->channel > 63) |
| 864 | return -EINVAL; | 870 | return -EINVAL; |
| 865 | 871 | ||
| 866 | switch (request->type) { | 872 | switch (a->type) { |
| 867 | case FW_ISO_CONTEXT_RECEIVE: | 873 | case FW_ISO_CONTEXT_RECEIVE: |
| 868 | if (request->header_size < 4 || (request->header_size & 3)) | 874 | if (a->header_size < 4 || (a->header_size & 3)) |
| 869 | return -EINVAL; | 875 | return -EINVAL; |
| 870 | |||
| 871 | break; | 876 | break; |
| 872 | 877 | ||
| 873 | case FW_ISO_CONTEXT_TRANSMIT: | 878 | case FW_ISO_CONTEXT_TRANSMIT: |
| 874 | if (request->speed > SCODE_3200) | 879 | if (a->speed > SCODE_3200) |
| 875 | return -EINVAL; | 880 | return -EINVAL; |
| 876 | |||
| 877 | break; | 881 | break; |
| 878 | 882 | ||
| 879 | default: | 883 | default: |
| 880 | return -EINVAL; | 884 | return -EINVAL; |
| 881 | } | 885 | } |
| 882 | 886 | ||
| 883 | context = fw_iso_context_create(client->device->card, | 887 | context = fw_iso_context_create(client->device->card, a->type, |
| 884 | request->type, | 888 | a->channel, a->speed, a->header_size, |
| 885 | request->channel, | 889 | iso_callback, client); |
| 886 | request->speed, | ||
| 887 | request->header_size, | ||
| 888 | iso_callback, client); | ||
| 889 | if (IS_ERR(context)) | 890 | if (IS_ERR(context)) |
| 890 | return PTR_ERR(context); | 891 | return PTR_ERR(context); |
| 891 | 892 | ||
| 892 | client->iso_closure = request->closure; | 893 | client->iso_closure = a->closure; |
| 893 | client->iso_context = context; | 894 | client->iso_context = context; |
| 894 | 895 | ||
| 895 | /* We only support one context at this time. */ | 896 | /* We only support one context at this time. */ |
| 896 | request->handle = 0; | 897 | a->handle = 0; |
| 897 | 898 | ||
| 898 | return 0; | 899 | return 0; |
| 899 | } | 900 | } |
| @@ -906,9 +907,9 @@ static int ioctl_create_iso_context(struct client *client, void *buffer) | |||
| 906 | #define GET_SY(v) (((v) >> 20) & 0x0f) | 907 | #define GET_SY(v) (((v) >> 20) & 0x0f) |
| 907 | #define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff) | 908 | #define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff) |
| 908 | 909 | ||
| 909 | static int ioctl_queue_iso(struct client *client, void *buffer) | 910 | static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) |
| 910 | { | 911 | { |
| 911 | struct fw_cdev_queue_iso *request = buffer; | 912 | struct fw_cdev_queue_iso *a = &arg->queue_iso; |
| 912 | struct fw_cdev_iso_packet __user *p, *end, *next; | 913 | struct fw_cdev_iso_packet __user *p, *end, *next; |
| 913 | struct fw_iso_context *ctx = client->iso_context; | 914 | struct fw_iso_context *ctx = client->iso_context; |
| 914 | unsigned long payload, buffer_end, header_length; | 915 | unsigned long payload, buffer_end, header_length; |
| @@ -919,7 +920,7 @@ static int ioctl_queue_iso(struct client *client, void *buffer) | |||
| 919 | u8 header[256]; | 920 | u8 header[256]; |
| 920 | } u; | 921 | } u; |
| 921 | 922 | ||
| 922 | if (ctx == NULL || request->handle != 0) | 923 | if (ctx == NULL || a->handle != 0) |
| 923 | return -EINVAL; | 924 | return -EINVAL; |
| 924 | 925 | ||
| 925 | /* | 926 | /* |
| @@ -929,23 +930,23 @@ static int ioctl_queue_iso(struct client *client, void *buffer) | |||
| 929 | * set them both to 0, which will still let packets with | 930 | * set them both to 0, which will still let packets with |
| 930 | * payload_length == 0 through. In other words, if no packets | 931 | * payload_length == 0 through. In other words, if no packets |
| 931 | * use the indirect payload, the iso buffer need not be mapped | 932 | * use the indirect payload, the iso buffer need not be mapped |
| 932 | * and the request->data pointer is ignored. | 933 | * and the a->data pointer is ignored. |
| 933 | */ | 934 | */ |
| 934 | 935 | ||
| 935 | payload = (unsigned long)request->data - client->vm_start; | 936 | payload = (unsigned long)a->data - client->vm_start; |
| 936 | buffer_end = client->buffer.page_count << PAGE_SHIFT; | 937 | buffer_end = client->buffer.page_count << PAGE_SHIFT; |
| 937 | if (request->data == 0 || client->buffer.pages == NULL || | 938 | if (a->data == 0 || client->buffer.pages == NULL || |
| 938 | payload >= buffer_end) { | 939 | payload >= buffer_end) { |
| 939 | payload = 0; | 940 | payload = 0; |
| 940 | buffer_end = 0; | 941 | buffer_end = 0; |
| 941 | } | 942 | } |
| 942 | 943 | ||
| 943 | p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); | 944 | p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets); |
| 944 | 945 | ||
| 945 | if (!access_ok(VERIFY_READ, p, request->size)) | 946 | if (!access_ok(VERIFY_READ, p, a->size)) |
| 946 | return -EFAULT; | 947 | return -EFAULT; |
| 947 | 948 | ||
| 948 | end = (void __user *)p + request->size; | 949 | end = (void __user *)p + a->size; |
| 949 | count = 0; | 950 | count = 0; |
| 950 | while (p < end) { | 951 | while (p < end) { |
| 951 | if (get_user(control, &p->control)) | 952 | if (get_user(control, &p->control)) |
| @@ -995,45 +996,41 @@ static int ioctl_queue_iso(struct client *client, void *buffer) | |||
| 995 | count++; | 996 | count++; |
| 996 | } | 997 | } |
| 997 | 998 | ||
| 998 | request->size -= uptr_to_u64(p) - request->packets; | 999 | a->size -= uptr_to_u64(p) - a->packets; |
| 999 | request->packets = uptr_to_u64(p); | 1000 | a->packets = uptr_to_u64(p); |
| 1000 | request->data = client->vm_start + payload; | 1001 | a->data = client->vm_start + payload; |
| 1001 | 1002 | ||
| 1002 | return count; | 1003 | return count; |
| 1003 | } | 1004 | } |
| 1004 | 1005 | ||
| 1005 | static int ioctl_start_iso(struct client *client, void *buffer) | 1006 | static int ioctl_start_iso(struct client *client, union ioctl_arg *arg) |
| 1006 | { | 1007 | { |
| 1007 | struct fw_cdev_start_iso *request = buffer; | 1008 | struct fw_cdev_start_iso *a = &arg->start_iso; |
| 1008 | 1009 | ||
| 1009 | if (client->iso_context == NULL || request->handle != 0) | 1010 | if (client->iso_context == NULL || a->handle != 0) |
| 1010 | return -EINVAL; | 1011 | return -EINVAL; |
| 1011 | 1012 | ||
| 1012 | if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { | 1013 | if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE && |
| 1013 | if (request->tags == 0 || request->tags > 15) | 1014 | (a->tags == 0 || a->tags > 15 || a->sync > 15)) |
| 1014 | return -EINVAL; | 1015 | return -EINVAL; |
| 1015 | |||
| 1016 | if (request->sync > 15) | ||
| 1017 | return -EINVAL; | ||
| 1018 | } | ||
| 1019 | 1016 | ||
| 1020 | return fw_iso_context_start(client->iso_context, request->cycle, | 1017 | return fw_iso_context_start(client->iso_context, |
| 1021 | request->sync, request->tags); | 1018 | a->cycle, a->sync, a->tags); |
| 1022 | } | 1019 | } |
| 1023 | 1020 | ||
| 1024 | static int ioctl_stop_iso(struct client *client, void *buffer) | 1021 | static int ioctl_stop_iso(struct client *client, union ioctl_arg *arg) |
| 1025 | { | 1022 | { |
| 1026 | struct fw_cdev_stop_iso *request = buffer; | 1023 | struct fw_cdev_stop_iso *a = &arg->stop_iso; |
| 1027 | 1024 | ||
| 1028 | if (client->iso_context == NULL || request->handle != 0) | 1025 | if (client->iso_context == NULL || a->handle != 0) |
| 1029 | return -EINVAL; | 1026 | return -EINVAL; |
| 1030 | 1027 | ||
| 1031 | return fw_iso_context_stop(client->iso_context); | 1028 | return fw_iso_context_stop(client->iso_context); |
| 1032 | } | 1029 | } |
| 1033 | 1030 | ||
| 1034 | static int ioctl_get_cycle_timer2(struct client *client, void *buffer) | 1031 | static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg) |
| 1035 | { | 1032 | { |
| 1036 | struct fw_cdev_get_cycle_timer2 *request = buffer; | 1033 | struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2; |
| 1037 | struct fw_card *card = client->device->card; | 1034 | struct fw_card *card = client->device->card; |
| 1038 | struct timespec ts = {0, 0}; | 1035 | struct timespec ts = {0, 0}; |
| 1039 | u32 cycle_time; | 1036 | u32 cycle_time; |
| @@ -1043,7 +1040,7 @@ static int ioctl_get_cycle_timer2(struct client *client, void *buffer) | |||
| 1043 | 1040 | ||
| 1044 | cycle_time = card->driver->get_cycle_time(card); | 1041 | cycle_time = card->driver->get_cycle_time(card); |
| 1045 | 1042 | ||
| 1046 | switch (request->clk_id) { | 1043 | switch (a->clk_id) { |
| 1047 | case CLOCK_REALTIME: getnstimeofday(&ts); break; | 1044 | case CLOCK_REALTIME: getnstimeofday(&ts); break; |
| 1048 | case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; | 1045 | case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; |
| 1049 | case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; | 1046 | case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; |
| @@ -1053,24 +1050,23 @@ static int ioctl_get_cycle_timer2(struct client *client, void *buffer) | |||
| 1053 | 1050 | ||
| 1054 | local_irq_enable(); | 1051 | local_irq_enable(); |
| 1055 | 1052 | ||
| 1056 | request->tv_sec = ts.tv_sec; | 1053 | a->tv_sec = ts.tv_sec; |
| 1057 | request->tv_nsec = ts.tv_nsec; | 1054 | a->tv_nsec = ts.tv_nsec; |
| 1058 | request->cycle_timer = cycle_time; | 1055 | a->cycle_timer = cycle_time; |
| 1059 | 1056 | ||
| 1060 | return ret; | 1057 | return ret; |
| 1061 | } | 1058 | } |
| 1062 | 1059 | ||
| 1063 | static int ioctl_get_cycle_timer(struct client *client, void *buffer) | 1060 | static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg) |
| 1064 | { | 1061 | { |
| 1065 | struct fw_cdev_get_cycle_timer *request = buffer; | 1062 | struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer; |
| 1066 | struct fw_cdev_get_cycle_timer2 ct2; | 1063 | struct fw_cdev_get_cycle_timer2 ct2; |
| 1067 | 1064 | ||
| 1068 | ct2.clk_id = CLOCK_REALTIME; | 1065 | ct2.clk_id = CLOCK_REALTIME; |
| 1069 | ioctl_get_cycle_timer2(client, &ct2); | 1066 | ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2); |
| 1070 | 1067 | ||
| 1071 | request->local_time = ct2.tv_sec * USEC_PER_SEC + | 1068 | a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC; |
| 1072 | ct2.tv_nsec / NSEC_PER_USEC; | 1069 | a->cycle_timer = ct2.cycle_timer; |
| 1073 | request->cycle_timer = ct2.cycle_timer; | ||
| 1074 | 1070 | ||
| 1075 | return 0; | 1071 | return 0; |
| 1076 | } | 1072 | } |
| @@ -1242,33 +1238,32 @@ static int init_iso_resource(struct client *client, | |||
| 1242 | return ret; | 1238 | return ret; |
| 1243 | } | 1239 | } |
| 1244 | 1240 | ||
| 1245 | static int ioctl_allocate_iso_resource(struct client *client, void *buffer) | 1241 | static int ioctl_allocate_iso_resource(struct client *client, |
| 1242 | union ioctl_arg *arg) | ||
| 1246 | { | 1243 | { |
| 1247 | struct fw_cdev_allocate_iso_resource *request = buffer; | 1244 | return init_iso_resource(client, |
| 1248 | 1245 | &arg->allocate_iso_resource, ISO_RES_ALLOC); | |
| 1249 | return init_iso_resource(client, request, ISO_RES_ALLOC); | ||
| 1250 | } | 1246 | } |
| 1251 | 1247 | ||
| 1252 | static int ioctl_deallocate_iso_resource(struct client *client, void *buffer) | 1248 | static int ioctl_deallocate_iso_resource(struct client *client, |
| 1249 | union ioctl_arg *arg) | ||
| 1253 | { | 1250 | { |
| 1254 | struct fw_cdev_deallocate *request = buffer; | 1251 | return release_client_resource(client, |
| 1255 | 1252 | arg->deallocate.handle, release_iso_resource, NULL); | |
| 1256 | return release_client_resource(client, request->handle, | ||
| 1257 | release_iso_resource, NULL); | ||
| 1258 | } | 1253 | } |
| 1259 | 1254 | ||
| 1260 | static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer) | 1255 | static int ioctl_allocate_iso_resource_once(struct client *client, |
| 1256 | union ioctl_arg *arg) | ||
| 1261 | { | 1257 | { |
| 1262 | struct fw_cdev_allocate_iso_resource *request = buffer; | 1258 | return init_iso_resource(client, |
| 1263 | 1259 | &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE); | |
| 1264 | return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE); | ||
| 1265 | } | 1260 | } |
| 1266 | 1261 | ||
| 1267 | static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer) | 1262 | static int ioctl_deallocate_iso_resource_once(struct client *client, |
| 1263 | union ioctl_arg *arg) | ||
| 1268 | { | 1264 | { |
| 1269 | struct fw_cdev_allocate_iso_resource *request = buffer; | 1265 | return init_iso_resource(client, |
| 1270 | 1266 | &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE); | |
| 1271 | return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE); | ||
| 1272 | } | 1267 | } |
| 1273 | 1268 | ||
| 1274 | /* | 1269 | /* |
| @@ -1276,16 +1271,17 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe | |||
| 1276 | * limited by the device's link speed, the local node's link speed, | 1271 | * limited by the device's link speed, the local node's link speed, |
| 1277 | * and all PHY port speeds between the two links. | 1272 | * and all PHY port speeds between the two links. |
| 1278 | */ | 1273 | */ |
| 1279 | static int ioctl_get_speed(struct client *client, void *buffer) | 1274 | static int ioctl_get_speed(struct client *client, union ioctl_arg *arg) |
| 1280 | { | 1275 | { |
| 1281 | return client->device->max_speed; | 1276 | return client->device->max_speed; |
| 1282 | } | 1277 | } |
| 1283 | 1278 | ||
| 1284 | static int ioctl_send_broadcast_request(struct client *client, void *buffer) | 1279 | static int ioctl_send_broadcast_request(struct client *client, |
| 1280 | union ioctl_arg *arg) | ||
| 1285 | { | 1281 | { |
| 1286 | struct fw_cdev_send_request *request = buffer; | 1282 | struct fw_cdev_send_request *a = &arg->send_request; |
| 1287 | 1283 | ||
| 1288 | switch (request->tcode) { | 1284 | switch (a->tcode) { |
| 1289 | case TCODE_WRITE_QUADLET_REQUEST: | 1285 | case TCODE_WRITE_QUADLET_REQUEST: |
| 1290 | case TCODE_WRITE_BLOCK_REQUEST: | 1286 | case TCODE_WRITE_BLOCK_REQUEST: |
| 1291 | break; | 1287 | break; |
| @@ -1294,36 +1290,36 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer) | |||
| 1294 | } | 1290 | } |
| 1295 | 1291 | ||
| 1296 | /* Security policy: Only allow accesses to Units Space. */ | 1292 | /* Security policy: Only allow accesses to Units Space. */ |
| 1297 | if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) | 1293 | if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) |
| 1298 | return -EACCES; | 1294 | return -EACCES; |
| 1299 | 1295 | ||
| 1300 | return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); | 1296 | return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100); |
| 1301 | } | 1297 | } |
| 1302 | 1298 | ||
| 1303 | static int ioctl_send_stream_packet(struct client *client, void *buffer) | 1299 | static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg) |
| 1304 | { | 1300 | { |
| 1305 | struct fw_cdev_send_stream_packet *p = buffer; | 1301 | struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet; |
| 1306 | struct fw_cdev_send_request request; | 1302 | struct fw_cdev_send_request request; |
| 1307 | int dest; | 1303 | int dest; |
| 1308 | 1304 | ||
| 1309 | if (p->speed > client->device->card->link_speed || | 1305 | if (a->speed > client->device->card->link_speed || |
| 1310 | p->length > 1024 << p->speed) | 1306 | a->length > 1024 << a->speed) |
| 1311 | return -EIO; | 1307 | return -EIO; |
| 1312 | 1308 | ||
| 1313 | if (p->tag > 3 || p->channel > 63 || p->sy > 15) | 1309 | if (a->tag > 3 || a->channel > 63 || a->sy > 15) |
| 1314 | return -EINVAL; | 1310 | return -EINVAL; |
| 1315 | 1311 | ||
| 1316 | dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy); | 1312 | dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy); |
| 1317 | request.tcode = TCODE_STREAM_DATA; | 1313 | request.tcode = TCODE_STREAM_DATA; |
| 1318 | request.length = p->length; | 1314 | request.length = a->length; |
| 1319 | request.closure = p->closure; | 1315 | request.closure = a->closure; |
| 1320 | request.data = p->data; | 1316 | request.data = a->data; |
| 1321 | request.generation = p->generation; | 1317 | request.generation = a->generation; |
| 1322 | 1318 | ||
| 1323 | return init_request(client, &request, dest, p->speed); | 1319 | return init_request(client, &request, dest, a->speed); |
| 1324 | } | 1320 | } |
| 1325 | 1321 | ||
| 1326 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | 1322 | static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { |
| 1327 | ioctl_get_info, | 1323 | ioctl_get_info, |
| 1328 | ioctl_send_request, | 1324 | ioctl_send_request, |
| 1329 | ioctl_allocate, | 1325 | ioctl_allocate, |
| @@ -1350,24 +1346,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | |||
| 1350 | static int dispatch_ioctl(struct client *client, | 1346 | static int dispatch_ioctl(struct client *client, |
| 1351 | unsigned int cmd, void __user *arg) | 1347 | unsigned int cmd, void __user *arg) |
| 1352 | { | 1348 | { |
| 1353 | char buffer[sizeof(union { | 1349 | union ioctl_arg buffer; |
| 1354 | struct fw_cdev_get_info _00; | ||
| 1355 | struct fw_cdev_send_request _01; | ||
| 1356 | struct fw_cdev_allocate _02; | ||
| 1357 | struct fw_cdev_deallocate _03; | ||
| 1358 | struct fw_cdev_send_response _04; | ||
| 1359 | struct fw_cdev_initiate_bus_reset _05; | ||
| 1360 | struct fw_cdev_add_descriptor _06; | ||
| 1361 | struct fw_cdev_remove_descriptor _07; | ||
| 1362 | struct fw_cdev_create_iso_context _08; | ||
| 1363 | struct fw_cdev_queue_iso _09; | ||
| 1364 | struct fw_cdev_start_iso _0a; | ||
| 1365 | struct fw_cdev_stop_iso _0b; | ||
| 1366 | struct fw_cdev_get_cycle_timer _0c; | ||
| 1367 | struct fw_cdev_allocate_iso_resource _0d; | ||
| 1368 | struct fw_cdev_send_stream_packet _13; | ||
| 1369 | struct fw_cdev_get_cycle_timer2 _14; | ||
| 1370 | })]; | ||
| 1371 | int ret; | 1350 | int ret; |
| 1372 | 1351 | ||
| 1373 | if (_IOC_TYPE(cmd) != '#' || | 1352 | if (_IOC_TYPE(cmd) != '#' || |
| @@ -1376,17 +1355,17 @@ static int dispatch_ioctl(struct client *client, | |||
| 1376 | 1355 | ||
| 1377 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 1356 | if (_IOC_DIR(cmd) & _IOC_WRITE) { |
| 1378 | if (_IOC_SIZE(cmd) > sizeof(buffer) || | 1357 | if (_IOC_SIZE(cmd) > sizeof(buffer) || |
| 1379 | copy_from_user(buffer, arg, _IOC_SIZE(cmd))) | 1358 | copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) |
| 1380 | return -EFAULT; | 1359 | return -EFAULT; |
| 1381 | } | 1360 | } |
| 1382 | 1361 | ||
| 1383 | ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer); | 1362 | ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer); |
| 1384 | if (ret < 0) | 1363 | if (ret < 0) |
| 1385 | return ret; | 1364 | return ret; |
| 1386 | 1365 | ||
| 1387 | if (_IOC_DIR(cmd) & _IOC_READ) { | 1366 | if (_IOC_DIR(cmd) & _IOC_READ) { |
| 1388 | if (_IOC_SIZE(cmd) > sizeof(buffer) || | 1367 | if (_IOC_SIZE(cmd) > sizeof(buffer) || |
| 1389 | copy_to_user(arg, buffer, _IOC_SIZE(cmd))) | 1368 | copy_to_user(arg, &buffer, _IOC_SIZE(cmd))) |
| 1390 | return -EFAULT; | 1369 | return -EFAULT; |
| 1391 | } | 1370 | } |
| 1392 | 1371 | ||
