Newer
Older
Kristian Høgsberg
committed
enum dma_data_direction direction;
unsigned long size;
Kristian Høgsberg
committed
if (fw_device_is_shutdown(client->device))
return -ENODEV;
Kristian Høgsberg
committed
/* FIXME: We could support multiple buffers, but we don't. */
if (client->buffer.pages != NULL)
return -EBUSY;
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
Kristian Høgsberg
committed
if (vma->vm_start & ~PAGE_MASK)
return -EINVAL;
client->vm_start = vma->vm_start;
Kristian Høgsberg
committed
size = vma->vm_end - vma->vm_start;
page_count = size >> PAGE_SHIFT;
if (size & ~PAGE_MASK)
return -EINVAL;
if (vma->vm_flags & VM_WRITE)
direction = DMA_TO_DEVICE;
else
direction = DMA_FROM_DEVICE;
ret = fw_iso_buffer_init(&client->buffer, client->device->card,
page_count, direction);
if (ret < 0)
return ret;
ret = fw_iso_buffer_map(&client->buffer, vma);
if (ret < 0)
Kristian Høgsberg
committed
fw_iso_buffer_destroy(&client->buffer, client->device->card);
static int shutdown_resource(int id, void *p, void *data)
{
struct client_resource *r = p;
struct client *client = data;
r->release(client, r);
return 0;
}
static int fw_device_op_release(struct inode *inode, struct file *file)
{
struct client *client = file->private_data;
Kristian Høgsberg
committed
struct event *e, *next_e;
unsigned long flags;
mutex_lock(&client->device->client_list_mutex);
list_del(&client->link);
mutex_unlock(&client->device->client_list_mutex);
Kristian Høgsberg
committed
if (client->buffer.pages)
fw_iso_buffer_destroy(&client->buffer, client->device->card);
if (client->iso_context)
fw_iso_context_destroy(client->iso_context);
/* Freeze client->resource_idr and client->event_list */
spin_lock_irqsave(&client->lock, flags);
client->in_shutdown = true;
spin_unlock_irqrestore(&client->lock, flags);
idr_for_each(&client->resource_idr, shutdown_resource, client);
idr_remove_all(&client->resource_idr);
idr_destroy(&client->resource_idr);
Kristian Høgsberg
committed
list_for_each_entry_safe(e, next_e, &client->event_list, link)
kfree(e);
/*
* FIXME: client should be reference-counted. It's extremely unlikely
* but there may still be transactions being completed at this point.
*/
fw_device_put(client->device);
kfree(client);
return 0;
}
static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
{
struct client *client = file->private_data;
Kristian Høgsberg
committed
unsigned int mask = 0;
poll_wait(file, &client->wait, pt);
Kristian Høgsberg
committed
if (fw_device_is_shutdown(client->device))
mask |= POLLHUP | POLLERR;
if (!list_empty(&client->event_list))
Kristian Høgsberg
committed
mask |= POLLIN | POLLRDNORM;
return mask;
const struct file_operations fw_device_ops = {
.owner = THIS_MODULE,
.open = fw_device_op_open,
.read = fw_device_op_read,
.unlocked_ioctl = fw_device_op_ioctl,
.poll = fw_device_op_poll,
.release = fw_device_op_release,
.mmap = fw_device_op_mmap,
#ifdef CONFIG_COMPAT
.compat_ioctl = fw_device_op_compat_ioctl,