in xillybus/xillybus_core.c [1427:1562]
static int xillybus_open(struct inode *inode, struct file *filp)
{
int rc;
unsigned long flags;
struct xilly_endpoint *endpoint;
struct xilly_channel *channel;
int index;
rc = xillybus_find_inode(inode, (void **)&endpoint, &index);
if (rc)
return rc;
if (endpoint->fatal_error)
return -EIO;
channel = endpoint->channels[1 + index];
filp->private_data = channel;
/*
* It gets complicated because:
* 1. We don't want to take a mutex we don't have to
* 2. We don't want to open one direction if the other will fail.
*/
if ((filp->f_mode & FMODE_READ) && (!channel->num_wr_buffers))
return -ENODEV;
if ((filp->f_mode & FMODE_WRITE) && (!channel->num_rd_buffers))
return -ENODEV;
if ((filp->f_mode & FMODE_READ) && (filp->f_flags & O_NONBLOCK) &&
(channel->wr_synchronous || !channel->wr_allow_partial ||
!channel->wr_supports_nonempty)) {
dev_err(endpoint->dev,
"open() failed: O_NONBLOCK not allowed for read on this device\n");
return -ENODEV;
}
if ((filp->f_mode & FMODE_WRITE) && (filp->f_flags & O_NONBLOCK) &&
(channel->rd_synchronous || !channel->rd_allow_partial)) {
dev_err(endpoint->dev,
"open() failed: O_NONBLOCK not allowed for write on this device\n");
return -ENODEV;
}
/*
* Note: open() may block on getting mutexes despite O_NONBLOCK.
* This shouldn't occur normally, since multiple open of the same
* file descriptor is almost always prohibited anyhow
* (*_exclusive_open is normally set in real-life systems).
*/
if (filp->f_mode & FMODE_READ) {
rc = mutex_lock_interruptible(&channel->wr_mutex);
if (rc)
return rc;
}
if (filp->f_mode & FMODE_WRITE) {
rc = mutex_lock_interruptible(&channel->rd_mutex);
if (rc)
goto unlock_wr;
}
if ((filp->f_mode & FMODE_READ) &&
(channel->wr_ref_count != 0) &&
(channel->wr_exclusive_open)) {
rc = -EBUSY;
goto unlock;
}
if ((filp->f_mode & FMODE_WRITE) &&
(channel->rd_ref_count != 0) &&
(channel->rd_exclusive_open)) {
rc = -EBUSY;
goto unlock;
}
if (filp->f_mode & FMODE_READ) {
if (channel->wr_ref_count == 0) { /* First open of file */
/* Move the host to first buffer */
spin_lock_irqsave(&channel->wr_spinlock, flags);
channel->wr_host_buf_idx = 0;
channel->wr_host_buf_pos = 0;
channel->wr_fpga_buf_idx = -1;
channel->wr_empty = 1;
channel->wr_ready = 0;
channel->wr_sleepy = 1;
channel->wr_eof = -1;
channel->wr_hangup = 0;
spin_unlock_irqrestore(&channel->wr_spinlock, flags);
iowrite32(1 | (channel->chan_num << 1) |
(4 << 24) | /* Opcode 4, open channel */
((channel->wr_synchronous & 1) << 23),
channel->endpoint->registers +
fpga_buf_ctrl_reg);
}
channel->wr_ref_count++;
}
if (filp->f_mode & FMODE_WRITE) {
if (channel->rd_ref_count == 0) { /* First open of file */
/* Move the host to first buffer */
spin_lock_irqsave(&channel->rd_spinlock, flags);
channel->rd_host_buf_idx = 0;
channel->rd_host_buf_pos = 0;
channel->rd_leftovers[3] = 0; /* No leftovers. */
channel->rd_fpga_buf_idx = channel->num_rd_buffers - 1;
channel->rd_full = 0;
spin_unlock_irqrestore(&channel->rd_spinlock, flags);
iowrite32((channel->chan_num << 1) |
(4 << 24), /* Opcode 4, open channel */
channel->endpoint->registers +
fpga_buf_ctrl_reg);
}
channel->rd_ref_count++;
}
unlock:
if (filp->f_mode & FMODE_WRITE)
mutex_unlock(&channel->rd_mutex);
unlock_wr:
if (filp->f_mode & FMODE_READ)
mutex_unlock(&channel->wr_mutex);
if (!rc && (!channel->seekable))
return nonseekable_open(inode, filp);
return rc;
}