Commit 66dea3e5 authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Stefan Richter

firewire: Add ioctls to add and remove config rom descriptors.

Signed-off-by: default avatarKristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (fixed whitespace)
parent da8ecffa
......@@ -160,7 +160,7 @@ fw_core_add_descriptor (struct fw_descriptor *desc)
i += (desc->data[i] >> 16) + 1;
if (i != desc->length)
return -1;
return -EINVAL;
down_write(&fw_bus_type.subsys.rwsem);
......
......@@ -73,9 +73,11 @@ struct client {
u32 version;
struct fw_device *device;
spinlock_t lock;
u32 resource_handle;
struct list_head handler_list;
struct list_head request_list;
struct list_head transaction_list;
struct list_head descriptor_list;
u32 request_serial;
struct list_head event_list;
wait_queue_head_t wait;
......@@ -119,6 +121,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&client->handler_list);
INIT_LIST_HEAD(&client->request_list);
INIT_LIST_HEAD(&client->transaction_list);
INIT_LIST_HEAD(&client->descriptor_list);
spin_lock_init(&client->lock);
init_waitqueue_head(&client->wait);
......@@ -542,6 +545,87 @@ static int ioctl_initiate_bus_reset(struct client *client, void __user *arg)
return fw_core_initiate_bus_reset(client->device->card, short_reset);
}
struct descriptor {
struct fw_descriptor d;
struct list_head link;
u32 handle;
u32 data[0];
};
static int ioctl_add_descriptor(struct client *client, void __user *arg)
{
struct fw_cdev_add_descriptor request;
struct descriptor *descriptor;
unsigned long flags;
int retval;
if (copy_from_user(&request, arg, sizeof request))
return -EFAULT;
if (request.length > 256)
return -EINVAL;
descriptor =
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)) {
kfree(descriptor);
return -EFAULT;
}
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);
if (retval < 0) {
kfree(descriptor);
return retval;
}
spin_lock_irqsave(&client->lock, flags);
list_add_tail(&descriptor->link, &client->descriptor_list);
descriptor->handle = client->resource_handle++;
spin_unlock_irqrestore(&client->lock, flags);
request.handle = descriptor->handle;
if (copy_to_user(arg, &request, sizeof request))
return -EFAULT;
return 0;
}
static int ioctl_remove_descriptor(struct client *client, void __user *arg)
{
struct fw_cdev_remove_descriptor request;
struct descriptor *d;
unsigned long flags;
if (copy_from_user(&request, arg, sizeof request))
return -EFAULT;
spin_lock_irqsave(&client->lock, flags);
list_for_each_entry(d, &client->descriptor_list, link) {
if (d->handle == request.handle) {
list_del(&d->link);
break;
}
}
spin_unlock_irqrestore(&client->lock, flags);
if (&d->link == &client->descriptor_list)
return -EINVAL;
fw_core_remove_descriptor(&d->d);
kfree(d);
return 0;
}
static void
iso_callback(struct fw_iso_context *context, u32 cycle,
size_t header_length, void *header, void *data)
......@@ -731,6 +815,10 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
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:
......@@ -811,6 +899,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
struct request *r, *next_r;
struct event *e, *next_e;
struct response *t, *next_t;
struct descriptor *d, *next_d;
unsigned long flags;
if (client->buffer.pages)
......@@ -835,6 +924,11 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
kfree(t);
}
list_for_each_entry_safe(d, next_d, &client->descriptor_list, link) {
fw_core_remove_descriptor(&d->d);
kfree(d);
}
/* FIXME: We should wait for the async tasklets to stop
* running before freeing the memory. */
......
......@@ -130,10 +130,13 @@ union fw_cdev_event {
#define FW_CDEV_IOC_DEALLOCATE _IO('#', 0x03)
#define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x04)
#define FW_CDEV_IOC_INITIATE_BUS_RESET _IO('#', 0x05)
#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x06)
#define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x07)
#define FW_CDEV_IOC_START_ISO _IO('#', 0x08)
#define FW_CDEV_IOC_STOP_ISO _IO('#', 0x09)
#define FW_CDEV_IOC_ADD_DESCRIPTOR _IO('#', 0x06)
#define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IO('#', 0x07)
#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x08)
#define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x09)
#define FW_CDEV_IOC_START_ISO _IO('#', 0x0a)
#define FW_CDEV_IOC_STOP_ISO _IO('#', 0x0b)
/* FW_CDEV_VERSION History
*
......@@ -203,6 +206,18 @@ struct fw_cdev_initiate_bus_reset {
__u32 type;
};
struct fw_cdev_add_descriptor {
__u32 immediate;
__u32 key;
__u64 data;
__u32 length;
__u32 handle;
};
struct fw_cdev_remove_descriptor {
__u32 handle;
};
#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0
#define FW_CDEV_ISO_CONTEXT_RECEIVE 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment