diff options
Diffstat (limited to 'drivers/firewire/core-cdev.c')
| -rw-r--r-- | drivers/firewire/core-cdev.c | 368 |
1 files changed, 182 insertions, 186 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 4eeaed57e219..8be720b278b7 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/firewire.h> | 25 | #include <linux/firewire.h> |
| 26 | #include <linux/firewire-cdev.h> | 26 | #include <linux/firewire-cdev.h> |
| 27 | #include <linux/idr.h> | 27 | #include <linux/idr.h> |
| 28 | #include <linux/irqflags.h> | ||
| 28 | #include <linux/jiffies.h> | 29 | #include <linux/jiffies.h> |
| 29 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 30 | #include <linux/kref.h> | 31 | #include <linux/kref.h> |
| @@ -32,7 +33,6 @@ | |||
| 32 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 33 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
| 34 | #include <linux/poll.h> | 35 | #include <linux/poll.h> |
| 35 | #include <linux/preempt.h> | ||
| 36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
| 37 | #include <linux/spinlock.h> | 37 | #include <linux/spinlock.h> |
| 38 | #include <linux/string.h> | 38 | #include <linux/string.h> |
| @@ -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, | ||
