in smu.c [1173:1226]
static ssize_t smu_read_command(struct file *file, struct smu_private *pp,
char __user *buf, size_t count)
{
DECLARE_WAITQUEUE(wait, current);
struct smu_user_reply_hdr hdr;
unsigned long flags;
int size, rc = 0;
if (!pp->busy)
return 0;
if (count < sizeof(struct smu_user_reply_hdr))
return -EOVERFLOW;
spin_lock_irqsave(&pp->lock, flags);
if (pp->cmd.status == 1) {
if (file->f_flags & O_NONBLOCK) {
spin_unlock_irqrestore(&pp->lock, flags);
return -EAGAIN;
}
add_wait_queue(&pp->wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
rc = 0;
if (pp->cmd.status != 1)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
spin_unlock_irqrestore(&pp->lock, flags);
schedule();
spin_lock_irqsave(&pp->lock, flags);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&pp->wait, &wait);
}
spin_unlock_irqrestore(&pp->lock, flags);
if (rc)
return rc;
if (pp->cmd.status != 0)
pp->cmd.reply_len = 0;
size = sizeof(hdr) + pp->cmd.reply_len;
if (count < size)
size = count;
rc = size;
hdr.status = pp->cmd.status;
hdr.reply_len = pp->cmd.reply_len;
if (copy_to_user(buf, &hdr, sizeof(hdr)))
return -EFAULT;
size -= sizeof(hdr);
if (size && copy_to_user(buf + sizeof(hdr), pp->buffer, size))
return -EFAULT;
pp->busy = 0;
return rc;
}