android emulator虚拟设备之qemu pipe分析(三),Android高级工程师进阶学习】
作者:互联网
while (address < address_end) {
unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE;
-
unsigned long next = page_end < address_end ? page_end
- address_end;
unsigned long avail = next - address;
int status, wakeBit;
/* Ensure that the corresponding page is properly mapped */
if (is_write) {
char c;
/* Ensure that the page is mapped and readable */
if (__get_user(c, (char __user *)address)) {
PIPE_E(“read fault at address 0x%08x\n”,
(unsigned int)address);
if (!ret)
ret = -EFAULT;
break;
}
} else {
/* Ensure that the page is mapped and writable */
if (__put_user(0, (char __user *)address)) {
PIPE_E(“write fault at address 0x%08x\n”,
(unsigned int)address);
if (!ret)
ret = -EFAULT;
break;
}
}
/* Now, try to transfer the bytes in the current page */
spin_lock_irqsave(&dev->lock, irq_flags);
if (dev->aps == NULL || access_with_param(
dev, CMD_WRITE_BUFFER + cmd_offset, address, avail,
pipe, &status) < 0)
{
writel((unsigned long)pipe,
dev->base + PIPE_REG_CHANNEL);
writel(avail, dev->base + PIPE_REG_SIZE);
writel(address, dev->base + PIPE_REG_ADDRESS);
writel(CMD_WRITE_BUFFER + cmd_offset,
dev->base + PIPE_REG_COMMAND);
status = readl(dev->base + PIPE_REG_STATUS);
}
spin_unlock_irqrestore(&dev->lock, irq_flags);
if (status > 0) { /* Correct transfer */
ret += status;
address += status;
continue;
}
if (status == 0) /* EOF */
break;
/* An error occured. If we already transfered stuff, just
* return with its count. We expect the next call to return
* an error code */
if (ret > 0)
break;
/* If the error is not PIPE_ERROR_AGAIN, or if we are not in
* non-blocking mode, just return the error code.
*/
if (status != PIPE_ERROR_AGAIN ||
(filp->f_flags & O_NONBLOCK) != 0) {
ret = qemu_pipe_error_convert(status);
break;
}
/* We will have to wait until more data/space is available.
* First, mark the pipe as waiting for a specific wake signal.
*/
wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
set_bit(wakeBit, &pipe->flags);
/* Tell the emulator we’re going to wait for a wake event */
spin_lock_irqsave(&dev->lock, irq_flags);
writel((unsigned long)pipe, dev->base + PIPE_REG_CHANNEL);
writel(CMD_WAKE_ON_WRITE + cmd_offset,
dev->base + PIPE_REG_COMMAND);
spin_unlock_irqrestore(&dev->lock, irq_flags);
/* Unlock the pipe, then wait for the wake signal */
mutex_unlock(&pipe->lock);
while (test_bit(wakeBit, &pipe->flags)) {
if (wait_event_interruptible(
pipe->wake_queue,
!test_bit(wakeBit, &pipe->flags))) {
ret = -ERESTARTSYS;
PIPE_W(“rw, wait_event error\n”);
goto out;
}
if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) {
ret = -EIO;
PIPE_W(“rw, pipe already closed\n”);
goto out;
}
}
/* Try to re-acquire the lock */
if (mutex_lock_interruptible(&pipe->lock)) {
ret = -ERESTARTSYS;
goto out;
}
/* Try the transfer again */
continue;
}
mutex_unlock(&pipe->lock);
out:
return ret;
}
static ssize_t qemu_pipe_read(struct file *filp, char __user *buffer,
size_t bufflen, loff_t *ppos)
{
return qemu_pipe_read_write(filp, buffer, bufflen, 0);
}
static ssize_t qemu_pipe_write(struct file *filp,
const char __user *buffer, size_t bufflen,
loff_t *ppos)
{
return qemu_pipe_read_write(filp, (char __user *)buffer, bufflen, 1);
}
qemu_pipe_poll,实现poll,select,epoll接口用的,没什么特殊的,标准实现方式
static unsigned int qemu_pipe_poll(struct file *filp, poll_table *wait)
{
struct qemu_pipe *pipe = filp->private_data;
struct qemu_pipe_dev *dev = pipe->dev;
unsigned long irq_flags;
unsigned int mask = 0;
int status;
mutex_lock(&pipe->lock);
poll_wait(filp, &pipe->wake_queue, wait);
spin_lock_irqsave(&dev->lock, irq_flags);
writel((unsigned long)pipe, dev->base + PIPE_REG_CHANNEL);
writel(CMD_POLL, dev->base + PIPE_REG_COMMAND);
status = readl(dev->base + PIPE_REG_STATUS);
spin_unlock_irqrestore(&dev->lock, irq_flags);
mutex_unlock(&pipe->lock);
if (status & PIPE_POLL_IN)
mask |= POLLIN | POLLRDNORM;
if (status & PIPE_POLL_OUT)
mask |= POLLOUT | POLLWRNORM;
if (status & PIPE_POLL_HUP)
mask |= POLLHUP;
if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
mask |= POLLERR;
return mask;
}
qemu_pipe_interrupt,中断处理函数,循环处理每一个qemu_pipe,看看是否可读 or 可写 or 关闭了,然后唤醒对应的线程
static irqreturn_t qemu_pipe_interrupt(int irq, void *dev_id)
{
struct qemu_pipe_dev *dev = dev_id;
unsigned long irq_flags;
int count = 0;
/* We’re going to read from the emulator a list of (channel,flags)
* pairs corresponding to the wake events that occured on each
* blocked pipe (i.e. channel).
*/
spin_lock_irqsave(&dev->lock, irq_flags);
for (;
标签:__,PIPE,进阶,dev,pipe,emulator,address,channel 来源: https://blog.csdn.net/m0_66144992/article/details/122741809