mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
firewire: Add ioctls to add and remove config rom descriptors.
Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (fixed whitespace)
This commit is contained in:
parent
da8ecffaed
commit
66dea3e5f6
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user