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) ...@@ -160,7 +160,7 @@ fw_core_add_descriptor (struct fw_descriptor *desc)
i += (desc->data[i] >> 16) + 1; i += (desc->data[i] >> 16) + 1;
if (i != desc->length) if (i != desc->length)
return -1; return -EINVAL;
down_write(&fw_bus_type.subsys.rwsem); down_write(&fw_bus_type.subsys.rwsem);
......
...@@ -73,9 +73,11 @@ struct client { ...@@ -73,9 +73,11 @@ struct client {
u32 version; u32 version;
struct fw_device *device; struct fw_device *device;
spinlock_t lock; spinlock_t lock;
u32 resource_handle;
struct list_head handler_list; struct list_head handler_list;
struct list_head request_list; struct list_head request_list;
struct list_head transaction_list; struct list_head transaction_list;
struct list_head descriptor_list;
u32 request_serial; u32 request_serial;
struct list_head event_list; struct list_head event_list;
wait_queue_head_t wait; wait_queue_head_t wait;
...@@ -119,6 +121,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file) ...@@ -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->handler_list);
INIT_LIST_HEAD(&client->request_list); INIT_LIST_HEAD(&client->request_list);
INIT_LIST_HEAD(&client->transaction_list); INIT_LIST_HEAD(&client->transaction_list);
INIT_LIST_HEAD(&client->descriptor_list);
spin_lock_init(&client->lock); spin_lock_init(&client->lock);
init_waitqueue_head(&client->wait); init_waitqueue_head(&client->wait);
...@@ -542,6 +545,87 @@ static int ioctl_initiate_bus_reset(struct client *client, void __user *arg) ...@@ -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); 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 static void
iso_callback(struct fw_iso_context *context, u32 cycle, iso_callback(struct fw_iso_context *context, u32 cycle,
size_t header_length, void *header, void *data) size_t header_length, void *header, void *data)
...@@ -731,6 +815,10 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) ...@@ -731,6 +815,10 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
return ioctl_send_response(client, arg); return ioctl_send_response(client, arg);
case FW_CDEV_IOC_INITIATE_BUS_RESET: case FW_CDEV_IOC_INITIATE_BUS_RESET:
return ioctl_initiate_bus_reset(client, arg); 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: case FW_CDEV_IOC_CREATE_ISO_CONTEXT:
return ioctl_create_iso_context(client, arg); return ioctl_create_iso_context(client, arg);
case FW_CDEV_IOC_QUEUE_ISO: case FW_CDEV_IOC_QUEUE_ISO:
...@@ -811,6 +899,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file) ...@@ -811,6 +899,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
struct request *r, *next_r; struct request *r, *next_r;
struct event *e, *next_e; struct event *e, *next_e;
struct response *t, *next_t; struct response *t, *next_t;
struct descriptor *d, *next_d;
unsigned long flags; unsigned long flags;
if (client->buffer.pages) if (client->buffer.pages)
...@@ -835,6 +924,11 @@ static int fw_device_op_release(struct inode *inode, struct file *file) ...@@ -835,6 +924,11 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
kfree(t); 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 /* FIXME: We should wait for the async tasklets to stop
* running before freeing the memory. */ * running before freeing the memory. */
......
...@@ -130,10 +130,13 @@ union fw_cdev_event { ...@@ -130,10 +130,13 @@ union fw_cdev_event {
#define FW_CDEV_IOC_DEALLOCATE _IO('#', 0x03) #define FW_CDEV_IOC_DEALLOCATE _IO('#', 0x03)
#define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x04) #define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x04)
#define FW_CDEV_IOC_INITIATE_BUS_RESET _IO('#', 0x05) #define FW_CDEV_IOC_INITIATE_BUS_RESET _IO('#', 0x05)
#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x06) #define FW_CDEV_IOC_ADD_DESCRIPTOR _IO('#', 0x06)
#define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x07) #define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IO('#', 0x07)
#define FW_CDEV_IOC_START_ISO _IO('#', 0x08)
#define FW_CDEV_IOC_STOP_ISO _IO('#', 0x09) #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 /* FW_CDEV_VERSION History
* *
...@@ -203,6 +206,18 @@ struct fw_cdev_initiate_bus_reset { ...@@ -203,6 +206,18 @@ struct fw_cdev_initiate_bus_reset {
__u32 type; __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_TRANSMIT 0
#define FW_CDEV_ISO_CONTEXT_RECEIVE 1 #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