diff options
Diffstat (limited to 'drivers/firewire/fw-device-cdev.c')
-rw-r--r-- | drivers/firewire/fw-device-cdev.c | 278 |
1 files changed, 123 insertions, 155 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c index fab6dfbcca1b..d2b867f44348 100644 --- a/drivers/firewire/fw-device-cdev.c +++ b/drivers/firewire/fw-device-cdev.c @@ -258,41 +258,35 @@ void fw_device_cdev_remove(struct fw_device *device) for_each_client(device, wake_up_client); } -static int ioctl_get_info(struct client *client, void __user *arg) +static int ioctl_get_info(struct client *client, void *buffer) { - struct fw_cdev_get_info get_info; + struct fw_cdev_get_info *get_info = buffer; struct fw_cdev_event_bus_reset bus_reset; - if (copy_from_user(&get_info, arg, sizeof get_info)) - return -EFAULT; - - client->version = get_info.version; - get_info.version = FW_CDEV_VERSION; + client->version = get_info->version; + get_info->version = FW_CDEV_VERSION; - if (get_info.rom != 0) { - void __user *uptr = u64_to_uptr(get_info.rom); - size_t want = get_info.rom_length; + if (get_info->rom != 0) { + void __user *uptr = u64_to_uptr(get_info->rom); + size_t want = get_info->rom_length; size_t have = client->device->config_rom_length * 4; if (copy_to_user(uptr, client->device->config_rom, min(want, have))) return -EFAULT; } - get_info.rom_length = client->device->config_rom_length * 4; + get_info->rom_length = client->device->config_rom_length * 4; - client->bus_reset_closure = get_info.bus_reset_closure; - if (get_info.bus_reset != 0) { - void __user *uptr = u64_to_uptr(get_info.bus_reset); + client->bus_reset_closure = get_info->bus_reset_closure; + if (get_info->bus_reset != 0) { + void __user *uptr = u64_to_uptr(get_info->bus_reset); fill_bus_reset_event(&bus_reset, client); if (copy_to_user(uptr, &bus_reset, sizeof bus_reset)) return -EFAULT; } - get_info.card = client->device->card->index; - - if (copy_to_user(arg, &get_info, sizeof get_info)) - return -EFAULT; + get_info->card = client->device->card->index; return 0; } @@ -369,30 +363,27 @@ complete_transaction(struct fw_card *card, int rcode, response->response.data, response->response.length); } -static ssize_t ioctl_send_request(struct client *client, void __user *arg) +static ssize_t ioctl_send_request(struct client *client, void *buffer) { struct fw_device *device = client->device; - struct fw_cdev_send_request request; + struct fw_cdev_send_request *request = buffer; struct response *response; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - /* What is the biggest size we'll accept, really? */ - if (request.length > 4096) + if (request->length > 4096) return -EINVAL; - response = kmalloc(sizeof *response + request.length, GFP_KERNEL); + response = kmalloc(sizeof *response + request->length, GFP_KERNEL); if (response == NULL) return -ENOMEM; response->client = client; - response->response.length = request.length; - response->response.closure = request.closure; + response->response.length = request->length; + response->response.closure = request->closure; - if (request.data && + if (request->data && copy_from_user(response->response.data, - u64_to_uptr(request.data), request.length)) { + u64_to_uptr(request->data), request->length)) { kfree(response); return -EFAULT; } @@ -401,16 +392,16 @@ static ssize_t ioctl_send_request(struct client *client, void __user *arg) add_client_resource(client, &response->resource); fw_send_request(device->card, &response->transaction, - request.tcode & 0x1f, + request->tcode & 0x1f, device->node->node_id, - request.generation, + request->generation, device->node->max_speed, - request.offset, - response->response.data, request.length, + request->offset, + response->response.data, request->length, complete_transaction, response); - if (request.data) - return sizeof request + request.length; + if (request->data) + return sizeof request + request->length; else return sizeof request; } @@ -495,25 +486,22 @@ release_address_handler(struct client *client, kfree(handler); } -static int ioctl_allocate(struct client *client, void __user *arg) +static int ioctl_allocate(struct client *client, void *buffer) { - struct fw_cdev_allocate request; + struct fw_cdev_allocate *request = buffer; struct address_handler *handler; struct fw_address_region region; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - handler = kmalloc(sizeof *handler, GFP_KERNEL); if (handler == NULL) return -ENOMEM; - region.start = request.offset; - region.end = request.offset + request.length; - handler->handler.length = request.length; + region.start = request->offset; + region.end = request->offset + request->length; + handler->handler.length = request->length; handler->handler.address_callback = handle_request; handler->handler.callback_data = handler; - handler->closure = request.closure; + handler->closure = request->closure; handler->client = client; if (fw_core_add_address_handler(&handler->handler, ®ion) < 0) { @@ -523,55 +511,44 @@ static int ioctl_allocate(struct client *client, void __user *arg) handler->resource.release = release_address_handler; add_client_resource(client, &handler->resource); - request.handle = handler->resource.handle; - - if (copy_to_user(arg, &request, sizeof request)) - return -EFAULT; + request->handle = handler->resource.handle; return 0; } -static int ioctl_deallocate(struct client *client, void __user *arg) +static int ioctl_deallocate(struct client *client, void *buffer) { - struct fw_cdev_deallocate request; - - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; + struct fw_cdev_deallocate *request = buffer; - return release_client_resource(client, request.handle, NULL); + return release_client_resource(client, request->handle, NULL); } -static int ioctl_send_response(struct client *client, void __user *arg) +static int ioctl_send_response(struct client *client, void *buffer) { - struct fw_cdev_send_response request; + struct fw_cdev_send_response *request = buffer; struct client_resource *resource; struct request *r; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - if (release_client_resource(client, request.handle, &resource) < 0) + if (release_client_resource(client, request->handle, &resource) < 0) return -EINVAL; r = container_of(resource, struct request, resource); - if (request.length < r->length) - r->length = request.length; - if (copy_from_user(r->data, u64_to_uptr(request.data), r->length)) + if (request->length < r->length) + r->length = request->length; + if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) return -EFAULT; - fw_send_response(client->device->card, r->request, request.rcode); + fw_send_response(client->device->card, r->request, request->rcode); kfree(r); return 0; } -static int ioctl_initiate_bus_reset(struct client *client, void __user *arg) +static int ioctl_initiate_bus_reset(struct client *client, void *buffer) { - struct fw_cdev_initiate_bus_reset request; + struct fw_cdev_initiate_bus_reset *request = buffer; int short_reset; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - - short_reset = (request.type == FW_CDEV_SHORT_RESET); + short_reset = (request->type == FW_CDEV_SHORT_RESET); return fw_core_initiate_bus_reset(client->device->card, short_reset); } @@ -592,32 +569,29 @@ static void release_descriptor(struct client *client, kfree(descriptor); } -static int ioctl_add_descriptor(struct client *client, void __user *arg) +static int ioctl_add_descriptor(struct client *client, void *buffer) { - struct fw_cdev_add_descriptor request; + struct fw_cdev_add_descriptor *request = buffer; struct descriptor *descriptor; int retval; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - - if (request.length > 256) + if (request->length > 256) return -EINVAL; descriptor = - kmalloc(sizeof *descriptor + request.length * 4, GFP_KERNEL); + kmalloc(sizeof *descriptor + request->length * 4, GFP_KERNEL); if (descriptor == NULL) return -ENOMEM; if (copy_from_user(descriptor->data, - u64_to_uptr(request.data), request.length * 4)) { + u64_to_uptr(request->data), request->length * 4)) { kfree(descriptor); return -EFAULT; } - descriptor->d.length = request.length; - descriptor->d.immediate = request.immediate; - descriptor->d.key = request.key; + descriptor->d.length = request->length; + descriptor->d.immediate = request->immediate; + descriptor->d.key = request->key; descriptor->d.data = descriptor->data; retval = fw_core_add_descriptor(&descriptor->d); @@ -628,22 +602,16 @@ static int ioctl_add_descriptor(struct client *client, void __user *arg) descriptor->resource.release = release_descriptor; add_client_resource(client, &descriptor->resource); - request.handle = descriptor->resource.handle; - - if (copy_to_user(arg, &request, sizeof request)) - return -EFAULT; + request->handle = descriptor->resource.handle; return 0; } -static int ioctl_remove_descriptor(struct client *client, void __user *arg) +static int ioctl_remove_descriptor(struct client *client, void *buffer) { - struct fw_cdev_remove_descriptor request; + struct fw_cdev_remove_descriptor *request = buffer; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - - return release_client_resource(client, request.handle, NULL); + return release_client_resource(client, request->handle, NULL); } static void @@ -667,25 +635,22 @@ iso_callback(struct fw_iso_context *context, u32 cycle, sizeof interrupt->interrupt + header_length, NULL, 0); } -static int ioctl_create_iso_context(struct client *client, void __user *arg) +static int ioctl_create_iso_context(struct client *client, void *buffer) { - struct fw_cdev_create_iso_context request; + struct fw_cdev_create_iso_context *request = buffer; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; - - if (request.channel > 63) + if (request->channel > 63) return -EINVAL; - switch (request.type) { + switch (request->type) { case FW_ISO_CONTEXT_RECEIVE: - if (request.header_size < 4 || (request.header_size & 3)) + if (request->header_size < 4 || (request->header_size & 3)) return -EINVAL; break; case FW_ISO_CONTEXT_TRANSMIT: - if (request.speed > SCODE_3200) + if (request->speed > SCODE_3200) return -EINVAL; break; @@ -695,10 +660,10 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) } client->iso_context = fw_iso_context_create(client->device->card, - request.type, - request.channel, - request.speed, - request.header_size, + request->type, + request->channel, + request->speed, + request->header_size, iso_callback, client); if (IS_ERR(client->iso_context)) return PTR_ERR(client->iso_context); @@ -706,9 +671,9 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) return 0; } -static int ioctl_queue_iso(struct client *client, void __user *arg) +static int ioctl_queue_iso(struct client *client, void *buffer) { - struct fw_cdev_queue_iso request; + struct fw_cdev_queue_iso *request = buffer; struct fw_cdev_iso_packet __user *p, *end, *next; struct fw_iso_context *ctx = client->iso_context; unsigned long payload, buffer_end, header_length; @@ -720,8 +685,6 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) if (ctx == NULL) return -EINVAL; - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; /* If the user passes a non-NULL data pointer, has mmap()'ed * the iso buffer, and the pointer points inside the buffer, @@ -729,21 +692,21 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) * set them both to 0, which will still let packets with * payload_length == 0 through. In other words, if no packets * use the indirect payload, the iso buffer need not be mapped - * and the request.data pointer is ignored.*/ + * and the request->data pointer is ignored.*/ - payload = (unsigned long)request.data - client->vm_start; + payload = (unsigned long)request->data - client->vm_start; buffer_end = client->buffer.page_count << PAGE_SHIFT; - if (request.data == 0 || client->buffer.pages == NULL || + if (request->data == 0 || client->buffer.pages == NULL || payload >= buffer_end) { payload = 0; buffer_end = 0; } - if (!access_ok(VERIFY_READ, request.packets, request.size)) + if (!access_ok(VERIFY_READ, request->packets, request->size)) return -EFAULT; - p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request.packets); - end = (void __user *)p + request.size; + p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); + end = (void __user *)p + request->size; count = 0; while (p < end) { if (__copy_from_user(&u.packet, p, sizeof *p)) @@ -785,71 +748,76 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) count++; } - request.size -= uptr_to_u64(p) - request.packets; - request.packets = uptr_to_u64(p); - request.data = client->vm_start + payload; - - if (copy_to_user(arg, &request, sizeof request)) - return -EFAULT; + request->size -= uptr_to_u64(p) - request->packets; + request->packets = uptr_to_u64(p); + request->data = client->vm_start + payload; return count; } -static int ioctl_start_iso(struct client *client, void __user *arg) +static int ioctl_start_iso(struct client *client, void *buffer) { - struct fw_cdev_start_iso request; - - if (copy_from_user(&request, arg, sizeof request)) - return -EFAULT; + struct fw_cdev_start_iso *request = buffer; if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { - if (request.tags == 0 || request.tags > 15) + if (request->tags == 0 || request->tags > 15) return -EINVAL; - if (request.sync > 15) + if (request->sync > 15) return -EINVAL; } - return fw_iso_context_start(client->iso_context, - request.cycle, request.sync, request.tags); + return fw_iso_context_start(client->iso_context, request->cycle, + request->sync, request->tags); } -static int ioctl_stop_iso(struct client *client, void __user *arg) +static int ioctl_stop_iso(struct client *client, void *buffer) { return fw_iso_context_stop(client->iso_context); } +static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { + ioctl_get_info, + ioctl_send_request, + ioctl_allocate, + ioctl_deallocate, + ioctl_send_response, + ioctl_initiate_bus_reset, + ioctl_add_descriptor, + ioctl_remove_descriptor, + ioctl_create_iso_context, + ioctl_queue_iso, + ioctl_start_iso, + ioctl_stop_iso, +}; + static int dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) { - switch (cmd) { - case FW_CDEV_IOC_GET_INFO: - return ioctl_get_info(client, arg); - case FW_CDEV_IOC_SEND_REQUEST: - return ioctl_send_request(client, arg); - case FW_CDEV_IOC_ALLOCATE: - return ioctl_allocate(client, arg); - case FW_CDEV_IOC_DEALLOCATE: - return ioctl_deallocate(client, arg); - case FW_CDEV_IOC_SEND_RESPONSE: - return ioctl_send_response(client, arg); - case FW_CDEV_IOC_INITIATE_BUS_RESET: - return ioctl_initiate_bus_reset(client, arg); - case FW_CDEV_IOC_ADD_DESCRIPTOR: - return ioctl_add_descriptor(client, arg); - case FW_CDEV_IOC_REMOVE_DESCRIPTOR: - return ioctl_remove_descriptor(client, arg); - case FW_CDEV_IOC_CREATE_ISO_CONTEXT: - return ioctl_create_iso_context(client, arg); - case FW_CDEV_IOC_QUEUE_ISO: - return ioctl_queue_iso(client, arg); - case FW_CDEV_IOC_START_ISO: - return ioctl_start_iso(client, arg); - case FW_CDEV_IOC_STOP_ISO: - return ioctl_stop_iso(client, arg); - default: + char buffer[256]; + int retval; + + if (_IOC_TYPE(cmd) != '#' || + _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) return -EINVAL; + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + if (_IOC_SIZE(cmd) > sizeof buffer || + copy_from_user(buffer, arg, _IOC_SIZE(cmd))) + return -EFAULT; + } + + retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer); + if (retval < 0) + return retval; + + if (_IOC_DIR(cmd) & _IOC_READ) { + if (_IOC_SIZE(cmd) > sizeof buffer || + copy_to_user(arg, buffer, _IOC_SIZE(cmd))) + return -EFAULT; } + + return 0; } static long |