|
@@ -25,6 +25,7 @@
|
|
|
#include <linux/firewire.h>
|
|
|
#include <linux/firewire-cdev.h>
|
|
|
#include <linux/idr.h>
|
|
|
+#include <linux/irqflags.h>
|
|
|
#include <linux/jiffies.h>
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/kref.h>
|
|
@@ -32,7 +33,6 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/mutex.h>
|
|
|
#include <linux/poll.h>
|
|
|
-#include <linux/preempt.h>
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/string.h>
|
|
@@ -368,39 +368,56 @@ 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 *buffer)
|
|
|
+union ioctl_arg {
|
|
|
+ struct fw_cdev_get_info get_info;
|
|
|
+ struct fw_cdev_send_request send_request;
|
|
|
+ struct fw_cdev_allocate allocate;
|
|
|
+ struct fw_cdev_deallocate deallocate;
|
|
|
+ struct fw_cdev_send_response send_response;
|
|
|
+ struct fw_cdev_initiate_bus_reset initiate_bus_reset;
|
|
|
+ struct fw_cdev_add_descriptor add_descriptor;
|
|
|
+ struct fw_cdev_remove_descriptor remove_descriptor;
|
|
|
+ struct fw_cdev_create_iso_context create_iso_context;
|
|
|
+ struct fw_cdev_queue_iso queue_iso;
|
|
|
+ struct fw_cdev_start_iso start_iso;
|
|
|
+ struct fw_cdev_stop_iso stop_iso;
|
|
|
+ struct fw_cdev_get_cycle_timer get_cycle_timer;
|
|
|
+ struct fw_cdev_allocate_iso_resource allocate_iso_resource;
|
|
|
+ struct fw_cdev_send_stream_packet send_stream_packet;
|
|
|
+ struct fw_cdev_get_cycle_timer2 get_cycle_timer2;
|
|
|
+};
|
|
|
+
|
|
|
+static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_get_info *get_info = buffer;
|
|
|
+ struct fw_cdev_get_info *a = &arg->get_info;
|
|
|
struct fw_cdev_event_bus_reset bus_reset;
|
|
|
unsigned long ret = 0;
|
|
|
|
|
|
- client->version = get_info->version;
|
|
|
- get_info->version = FW_CDEV_VERSION;
|
|
|
- get_info->card = client->device->card->index;
|
|
|
+ client->version = a->version;
|
|
|
+ a->version = FW_CDEV_VERSION;
|
|
|
+ a->card = client->device->card->index;
|
|
|
|
|
|
down_read(&fw_device_rwsem);
|
|
|
|
|
|
- if (get_info->rom != 0) {
|
|
|
- void __user *uptr = u64_to_uptr(get_info->rom);
|
|
|
- size_t want = get_info->rom_length;
|
|
|
+ if (a->rom != 0) {
|
|
|
+ size_t want = a->rom_length;
|
|
|
size_t have = client->device->config_rom_length * 4;
|
|
|
|
|
|
- ret = copy_to_user(uptr, client->device->config_rom,
|
|
|
- min(want, have));
|
|
|
+ ret = copy_to_user(u64_to_uptr(a->rom),
|
|
|
+ client->device->config_rom, min(want, have));
|
|
|
}
|
|
|
- get_info->rom_length = client->device->config_rom_length * 4;
|
|
|
+ a->rom_length = client->device->config_rom_length * 4;
|
|
|
|
|
|
up_read(&fw_device_rwsem);
|
|
|
|
|
|
if (ret != 0)
|
|
|
return -EFAULT;
|
|
|
|
|
|
- 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 = a->bus_reset_closure;
|
|
|
+ if (a->bus_reset != 0) {
|
|
|
fill_bus_reset_event(&bus_reset, client);
|
|
|
- if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
|
|
|
+ if (copy_to_user(u64_to_uptr(a->bus_reset),
|
|
|
+ &bus_reset, sizeof(bus_reset)))
|
|
|
return -EFAULT;
|
|
|
}
|
|
|
|
|
@@ -571,11 +588,9 @@ static int init_request(struct client *client,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_send_request(struct client *client, void *buffer)
|
|
|
+static int ioctl_send_request(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_send_request *request = buffer;
|
|
|
-
|
|
|
- switch (request->tcode) {
|
|
|
+ switch (arg->send_request.tcode) {
|
|
|
case TCODE_WRITE_QUADLET_REQUEST:
|
|
|
case TCODE_WRITE_BLOCK_REQUEST:
|
|
|
case TCODE_READ_QUADLET_REQUEST:
|
|
@@ -592,7 +607,7 @@ static int ioctl_send_request(struct client *client, void *buffer)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- return init_request(client, request, client->device->node_id,
|
|
|
+ return init_request(client, &arg->send_request, client->device->node_id,
|
|
|
client->device->max_speed);
|
|
|
}
|
|
|
|
|
@@ -683,9 +698,9 @@ static void release_address_handler(struct client *client,
|
|
|
kfree(r);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_allocate(struct client *client, void *buffer)
|
|
|
+static int ioctl_allocate(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_allocate *request = buffer;
|
|
|
+ struct fw_cdev_allocate *a = &arg->allocate;
|
|
|
struct address_handler_resource *r;
|
|
|
struct fw_address_region region;
|
|
|
int ret;
|
|
@@ -694,13 +709,13 @@ static int ioctl_allocate(struct client *client, void *buffer)
|
|
|
if (r == NULL)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- region.start = request->offset;
|
|
|
- region.end = request->offset + request->length;
|
|
|
- r->handler.length = request->length;
|
|
|
+ region.start = a->offset;
|
|
|
+ region.end = a->offset + a->length;
|
|
|
+ r->handler.length = a->length;
|
|
|
r->handler.address_callback = handle_request;
|
|
|
- r->handler.callback_data = r;
|
|
|
- r->closure = request->closure;
|
|
|
- r->client = client;
|
|
|
+ r->handler.callback_data = r;
|
|
|
+ r->closure = a->closure;
|
|
|
+ r->client = client;
|
|
|
|
|
|
ret = fw_core_add_address_handler(&r->handler, ®ion);
|
|
|
if (ret < 0) {
|
|
@@ -714,27 +729,25 @@ static int ioctl_allocate(struct client *client, void *buffer)
|
|
|
release_address_handler(client, &r->resource);
|
|
|
return ret;
|
|
|
}
|
|
|
- request->handle = r->resource.handle;
|
|
|
+ a->handle = r->resource.handle;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_deallocate(struct client *client, void *buffer)
|
|
|
+static int ioctl_deallocate(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_deallocate *request = buffer;
|
|
|
-
|
|
|
- return release_client_resource(client, request->handle,
|
|
|
+ return release_client_resource(client, arg->deallocate.handle,
|
|
|
release_address_handler, NULL);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_send_response(struct client *client, void *buffer)
|
|
|
+static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_send_response *request = buffer;
|
|
|
+ struct fw_cdev_send_response *a = &arg->send_response;
|
|
|
struct client_resource *resource;
|
|
|
struct inbound_transaction_resource *r;
|
|
|
int ret = 0;
|
|
|
|
|
|
- if (release_client_resource(client, request->handle,
|
|
|
+ if (release_client_resource(client, a->handle,
|
|
|
release_request, &resource) < 0)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -743,28 +756,24 @@ static int ioctl_send_response(struct client *client, void *buffer)
|
|
|
if (is_fcp_request(r->request))
|
|
|
goto out;
|
|
|
|
|
|
- if (request->length < r->length)
|
|
|
- r->length = request->length;
|
|
|
- if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
|
|
|
+ if (a->length < r->length)
|
|
|
+ r->length = a->length;
|
|
|
+ if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) {
|
|
|
ret = -EFAULT;
|
|
|
kfree(r->request);
|
|
|
goto out;
|
|
|
}
|
|
|
- fw_send_response(client->device->card, r->request, request->rcode);
|
|
|
+ fw_send_response(client->device->card, r->request, a->rcode);
|
|
|
out:
|
|
|
kfree(r);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
|
|
|
+static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_initiate_bus_reset *request = buffer;
|
|
|
- int short_reset;
|
|
|
-
|
|
|
- short_reset = (request->type == FW_CDEV_SHORT_RESET);
|
|
|
-
|
|
|
- return fw_core_initiate_bus_reset(client->device->card, short_reset);
|
|
|
+ return fw_core_initiate_bus_reset(client->device->card,
|
|
|
+ arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET);
|
|
|
}
|
|
|
|
|
|
static void release_descriptor(struct client *client,
|
|
@@ -777,9 +786,9 @@ static void release_descriptor(struct client *client,
|
|
|
kfree(r);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_add_descriptor(struct client *client, void *buffer)
|
|
|
+static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_add_descriptor *request = buffer;
|
|
|
+ struct fw_cdev_add_descriptor *a = &arg->add_descriptor;
|
|
|
struct descriptor_resource *r;
|
|
|
int ret;
|
|
|
|
|
@@ -787,22 +796,21 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
|
|
|
if (!client->device->is_local)
|
|
|
return -ENOSYS;
|
|
|
|
|
|
- if (request->length > 256)
|
|
|
+ if (a->length > 256)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
|
|
|
+ r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL);
|
|
|
if (r == NULL)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- if (copy_from_user(r->data,
|
|
|
- u64_to_uptr(request->data), request->length * 4)) {
|
|
|
+ if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) {
|
|
|
ret = -EFAULT;
|
|
|
goto failed;
|
|
|
}
|
|
|
|
|
|
- r->descriptor.length = request->length;
|
|
|
- r->descriptor.immediate = request->immediate;
|
|
|
- r->descriptor.key = request->key;
|
|
|
+ r->descriptor.length = a->length;
|
|
|
+ r->descriptor.immediate = a->immediate;
|
|
|
+ r->descriptor.key = a->key;
|
|
|
r->descriptor.data = r->data;
|
|
|
|
|
|
ret = fw_core_add_descriptor(&r->descriptor);
|
|
@@ -815,7 +823,7 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
|
|
|
fw_core_remove_descriptor(&r->descriptor);
|
|
|
goto failed;
|
|
|
}
|
|
|
- request->handle = r->resource.handle;
|
|
|
+ a->handle = r->resource.handle;
|
|
|
|
|
|
return 0;
|
|
|
failed:
|
|
@@ -824,11 +832,9 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_remove_descriptor(struct client *client, void *buffer)
|
|
|
+static int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_remove_descriptor *request = buffer;
|
|
|
-
|
|
|
- return release_client_resource(client, request->handle,
|
|
|
+ return release_client_resource(client, arg->remove_descriptor.handle,
|
|
|
release_descriptor, NULL);
|
|
|
}
|
|
|
|
|
@@ -851,49 +857,44 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
|
|
|
sizeof(e->interrupt) + header_length, NULL, 0);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_create_iso_context(struct client *client, void *buffer)
|
|
|
+static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_create_iso_context *request = buffer;
|
|
|
+ struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
|
|
|
struct fw_iso_context *context;
|
|
|
|
|
|
/* We only support one context at this time. */
|
|
|
if (client->iso_context != NULL)
|
|
|
return -EBUSY;
|
|
|
|
|
|
- if (request->channel > 63)
|
|
|
+ if (a->channel > 63)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- switch (request->type) {
|
|
|
+ switch (a->type) {
|
|
|
case FW_ISO_CONTEXT_RECEIVE:
|
|
|
- if (request->header_size < 4 || (request->header_size & 3))
|
|
|
+ if (a->header_size < 4 || (a->header_size & 3))
|
|
|
return -EINVAL;
|
|
|
-
|
|
|
break;
|
|
|
|
|
|
case FW_ISO_CONTEXT_TRANSMIT:
|
|
|
- if (request->speed > SCODE_3200)
|
|
|
+ if (a->speed > SCODE_3200)
|
|
|
return -EINVAL;
|
|
|
-
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- context = fw_iso_context_create(client->device->card,
|
|
|
- request->type,
|
|
|
- request->channel,
|
|
|
- request->speed,
|
|
|
- request->header_size,
|
|
|
- iso_callback, client);
|
|
|
+ context = fw_iso_context_create(client->device->card, a->type,
|
|
|
+ a->channel, a->speed, a->header_size,
|
|
|
+ iso_callback, client);
|
|
|
if (IS_ERR(context))
|
|
|
return PTR_ERR(context);
|
|
|
|
|
|
- client->iso_closure = request->closure;
|
|
|
+ client->iso_closure = a->closure;
|
|
|
client->iso_context = context;
|
|
|
|
|
|
/* We only support one context at this time. */
|
|
|
- request->handle = 0;
|
|
|
+ a->handle = 0;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -906,9 +907,9 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
|
|
|
#define GET_SY(v) (((v) >> 20) & 0x0f)
|
|
|
#define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff)
|
|
|
|
|
|
-static int ioctl_queue_iso(struct client *client, void *buffer)
|
|
|
+static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_queue_iso *request = buffer;
|
|
|
+ struct fw_cdev_queue_iso *a = &arg->queue_iso;
|
|
|
struct fw_cdev_iso_packet __user *p, *end, *next;
|
|
|
struct fw_iso_context *ctx = client->iso_context;
|
|
|
unsigned long payload, buffer_end, header_length;
|
|
@@ -919,7 +920,7 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
|
|
|
u8 header[256];
|
|
|
} u;
|
|
|
|
|
|
- if (ctx == NULL || request->handle != 0)
|
|
|
+ if (ctx == NULL || a->handle != 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
/*
|
|
@@ -929,23 +930,23 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
|
|
|
* 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 a->data pointer is ignored.
|
|
|
*/
|
|
|
|
|
|
- payload = (unsigned long)request->data - client->vm_start;
|
|
|
+ payload = (unsigned long)a->data - client->vm_start;
|
|
|
buffer_end = client->buffer.page_count << PAGE_SHIFT;
|
|
|
- if (request->data == 0 || client->buffer.pages == NULL ||
|
|
|
+ if (a->data == 0 || client->buffer.pages == NULL ||
|
|
|
payload >= buffer_end) {
|
|
|
payload = 0;
|
|
|
buffer_end = 0;
|
|
|
}
|
|
|
|
|
|
- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
|
|
|
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets);
|
|
|
|
|
|
- if (!access_ok(VERIFY_READ, p, request->size))
|
|
|
+ if (!access_ok(VERIFY_READ, p, a->size))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- end = (void __user *)p + request->size;
|
|
|
+ end = (void __user *)p + a->size;
|
|
|
count = 0;
|
|
|
while (p < end) {
|
|
|
if (get_user(control, &p->control))
|
|
@@ -995,61 +996,78 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
|
|
|
count++;
|
|
|
}
|
|
|
|
|
|
- request->size -= uptr_to_u64(p) - request->packets;
|
|
|
- request->packets = uptr_to_u64(p);
|
|
|
- request->data = client->vm_start + payload;
|
|
|
+ a->size -= uptr_to_u64(p) - a->packets;
|
|
|
+ a->packets = uptr_to_u64(p);
|
|
|
+ a->data = client->vm_start + payload;
|
|
|
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_start_iso(struct client *client, void *buffer)
|
|
|
+static int ioctl_start_iso(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_start_iso *request = buffer;
|
|
|
+ struct fw_cdev_start_iso *a = &arg->start_iso;
|
|
|
|
|
|
- if (client->iso_context == NULL || request->handle != 0)
|
|
|
+ if (client->iso_context == NULL || a->handle != 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
|
|
|
- if (request->tags == 0 || request->tags > 15)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (request->sync > 15)
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE &&
|
|
|
+ (a->tags == 0 || a->tags > 15 || a->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,
|
|
|
+ a->cycle, a->sync, a->tags);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_stop_iso(struct client *client, void *buffer)
|
|
|
+static int ioctl_stop_iso(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_stop_iso *request = buffer;
|
|
|
+ struct fw_cdev_stop_iso *a = &arg->stop_iso;
|
|
|
|
|
|
- if (client->iso_context == NULL || request->handle != 0)
|
|
|
+ if (client->iso_context == NULL || a->handle != 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
return fw_iso_context_stop(client->iso_context);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_get_cycle_timer(struct client *client, void *buffer)
|
|
|
+static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_get_cycle_timer *request = buffer;
|
|
|
+ struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2;
|
|
|
struct fw_card *card = client->device->card;
|
|
|
- unsigned long long bus_time;
|
|
|
- struct timeval tv;
|
|
|
- unsigned long flags;
|
|
|
+ struct timespec ts = {0, 0};
|
|
|
+ u32 cycle_time;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ local_irq_disable();
|
|
|
+
|
|
|
+ cycle_time = card->driver->get_cycle_time(card);
|
|
|
|
|
|
- preempt_disable();
|
|
|
- local_irq_save(flags);
|
|
|
+ switch (a->clk_id) {
|
|
|
+ case CLOCK_REALTIME: getnstimeofday(&ts); break;
|
|
|
+ case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break;
|
|
|
+ case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break;
|
|
|
+ default:
|
|
|
+ ret = -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- bus_time = card->driver->get_bus_time(card);
|
|
|
- do_gettimeofday(&tv);
|
|
|
+ local_irq_enable();
|
|
|
|
|
|
- local_irq_restore(flags);
|
|
|
- preempt_enable();
|
|
|
+ a->tv_sec = ts.tv_sec;
|
|
|
+ a->tv_nsec = ts.tv_nsec;
|
|
|
+ a->cycle_timer = cycle_time;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
|
|
|
+{
|
|
|
+ struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer;
|
|
|
+ struct fw_cdev_get_cycle_timer2 ct2;
|
|
|
+
|
|
|
+ ct2.clk_id = CLOCK_REALTIME;
|
|
|
+ ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2);
|
|
|
+
|
|
|
+ a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC;
|
|
|
+ a->cycle_timer = ct2.cycle_timer;
|
|
|
|
|
|
- request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
|
|
|
- request->cycle_timer = bus_time & 0xffffffff;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1220,33 +1238,32 @@ static int init_iso_resource(struct client *client,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
|
|
|
+static int ioctl_allocate_iso_resource(struct client *client,
|
|
|
+ union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_allocate_iso_resource *request = buffer;
|
|
|
-
|
|
|
- return init_iso_resource(client, request, ISO_RES_ALLOC);
|
|
|
+ return init_iso_resource(client,
|
|
|
+ &arg->allocate_iso_resource, ISO_RES_ALLOC);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
|
|
|
+static int ioctl_deallocate_iso_resource(struct client *client,
|
|
|
+ union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_deallocate *request = buffer;
|
|
|
-
|
|
|
- return release_client_resource(client, request->handle,
|
|
|
- release_iso_resource, NULL);
|
|
|
+ return release_client_resource(client,
|
|
|
+ arg->deallocate.handle, release_iso_resource, NULL);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer)
|
|
|
+static int ioctl_allocate_iso_resource_once(struct client *client,
|
|
|
+ union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_allocate_iso_resource *request = buffer;
|
|
|
-
|
|
|
- return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE);
|
|
|
+ return init_iso_resource(client,
|
|
|
+ &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer)
|
|
|
+static int ioctl_deallocate_iso_resource_once(struct client *client,
|
|
|
+ union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_allocate_iso_resource *request = buffer;
|
|
|
-
|
|
|
- return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
|
|
|
+ return init_iso_resource(client,
|
|
|
+ &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1254,16 +1271,17 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe
|
|
|
* limited by the device's link speed, the local node's link speed,
|
|
|
* and all PHY port speeds between the two links.
|
|
|
*/
|
|
|
-static int ioctl_get_speed(struct client *client, void *buffer)
|
|
|
+static int ioctl_get_speed(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
return client->device->max_speed;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_send_broadcast_request(struct client *client, void *buffer)
|
|
|
+static int ioctl_send_broadcast_request(struct client *client,
|
|
|
+ union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_send_request *request = buffer;
|
|
|
+ struct fw_cdev_send_request *a = &arg->send_request;
|
|
|
|
|
|
- switch (request->tcode) {
|
|
|
+ switch (a->tcode) {
|
|
|
case TCODE_WRITE_QUADLET_REQUEST:
|
|
|
case TCODE_WRITE_BLOCK_REQUEST:
|
|
|
break;
|
|
@@ -1272,36 +1290,36 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
|
|
|
}
|
|
|
|
|
|
/* Security policy: Only allow accesses to Units Space. */
|
|
|
- if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
|
|
|
+ if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
|
|
|
return -EACCES;
|
|
|
|
|
|
- return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
|
|
|
+ return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100);
|
|
|
}
|
|
|
|
|
|
-static int ioctl_send_stream_packet(struct client *client, void *buffer)
|
|
|
+static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg)
|
|
|
{
|
|
|
- struct fw_cdev_send_stream_packet *p = buffer;
|
|
|
+ struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet;
|
|
|
struct fw_cdev_send_request request;
|
|
|
int dest;
|
|
|
|
|
|
- if (p->speed > client->device->card->link_speed ||
|
|
|
- p->length > 1024 << p->speed)
|
|
|
+ if (a->speed > client->device->card->link_speed ||
|
|
|
+ a->length > 1024 << a->speed)
|
|
|
return -EIO;
|
|
|
|
|
|
- if (p->tag > 3 || p->channel > 63 || p->sy > 15)
|
|
|
+ if (a->tag > 3 || a->channel > 63 || a->sy > 15)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
|
|
|
+ dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy);
|
|
|
request.tcode = TCODE_STREAM_DATA;
|
|
|
- request.length = p->length;
|
|
|
- request.closure = p->closure;
|
|
|
- request.data = p->data;
|
|
|
- request.generation = p->generation;
|
|
|
+ request.length = a->length;
|
|
|
+ request.closure = a->closure;
|
|
|
+ request.data = a->data;
|
|
|
+ request.generation = a->generation;
|
|
|
|
|
|
- return init_request(client, &request, dest, p->speed);
|
|
|
+ return init_request(client, &request, dest, a->speed);
|
|
|
}
|
|
|
|
|
|
-static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
|
|
|
+static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
|
|
|
ioctl_get_info,
|
|
|
ioctl_send_request,
|
|
|
ioctl_allocate,
|
|
@@ -1322,47 +1340,35 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
|
|
|
ioctl_get_speed,
|
|
|
ioctl_send_broadcast_request,
|
|
|
ioctl_send_stream_packet,
|
|
|
+ ioctl_get_cycle_timer2,
|
|
|
};
|
|
|
|
|
|
static int dispatch_ioctl(struct client *client,
|
|
|
unsigned int cmd, void __user *arg)
|
|
|
{
|
|
|
- char buffer[sizeof(union {
|
|
|
- struct fw_cdev_get_info _00;
|
|
|
- struct fw_cdev_send_request _01;
|
|
|
- struct fw_cdev_allocate _02;
|
|
|
- struct fw_cdev_deallocate _03;
|
|
|
- struct fw_cdev_send_response _04;
|
|
|
- struct fw_cdev_initiate_bus_reset _05;
|
|
|
- struct fw_cdev_add_descriptor _06;
|
|
|
- struct fw_cdev_remove_descriptor _07;
|
|
|
- struct fw_cdev_create_iso_context _08;
|
|
|
- struct fw_cdev_queue_iso _09;
|
|
|
- struct fw_cdev_start_iso _0a;
|
|
|
- struct fw_cdev_stop_iso _0b;
|
|
|
- struct fw_cdev_get_cycle_timer _0c;
|
|
|
- struct fw_cdev_allocate_iso_resource _0d;
|
|
|
- struct fw_cdev_send_stream_packet _13;
|
|
|
- })];
|
|
|
+ union ioctl_arg buffer;
|
|
|
int ret;
|
|
|
|
|
|
+ if (fw_device_is_shutdown(client->device))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
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)))
|
|
|
+ copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
|
|
|
return -EFAULT;
|
|
|
}
|
|
|
|
|
|
- ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
|
|
|
+ ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
if (_IOC_DIR(cmd) & _IOC_READ) {
|
|
|
if (_IOC_SIZE(cmd) > sizeof(buffer) ||
|
|
|
- copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
|
|
|
+ copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
|
|
|
return -EFAULT;
|
|
|
}
|
|
|
|
|
@@ -1372,24 +1378,14 @@ static int dispatch_ioctl(struct client *client,
|
|
|
static long fw_device_op_ioctl(struct file *file,
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
- struct client *client = file->private_data;
|
|
|
-
|
|
|
- if (fw_device_is_shutdown(client->device))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- return dispatch_ioctl(client, cmd, (void __user *) arg);
|
|
|
+ return dispatch_ioctl(file->private_data, cmd, (void __user *)arg);
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
static long fw_device_op_compat_ioctl(struct file *file,
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
- struct client *client = file->private_data;
|
|
|
-
|
|
|
- if (fw_device_is_shutdown(client->device))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- return dispatch_ioctl(client, cmd, compat_ptr(arg));
|
|
|
+ return dispatch_ioctl(file->private_data, cmd, compat_ptr(arg));
|
|
|
}
|
|
|
#endif
|
|
|
|