Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);

+94 −0
Original line number Diff line number Diff line
@@ -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. */

+19 −4
Original line number Diff line number Diff line
@@ -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