android emulator虚拟设备之qemu pipe分析(三)

if (status < 0) {

PIPE_E(“Could not open pipe channel, error=%d\n”, status);

kfree(pipe);

return status;

}

/* All is done, save the pipe into the file’s private data field */

file->private_data = pipe;

return 0;

}

qemu_pipe_read和qemu_pipe_write都是使用qemu_pipe_read_write来实现的,注意access_ok和__get_user/__put_user对于用户空间指针的检测。具体的读写比较简单,就是操作IO寄存器而已,需要注意的是,如果是非阻塞方式,需要进行阻塞等待。

具体的方法就是往PIPE_REG_COMMAND里面写CMD_WAKE_ON_WRITE或者CMD_WAKE_ON_READ,然后调用wait_event_interruptible去等待!test_bit(wakeBit, &pipe->flags)。

当中断来临时,会检查每一个CHANNEL的PIPE_REG_WAKES寄存器,如果可读 or 可写 or 已关闭,中断函数中会清除pipe->flags中的对应的等待标志位,然后wait_event_interruptible等待结束。如果是qemu_pipe被关闭的情况,wait_event_interruptible等待结束之后,检查到错误状态并退出。

/* This function is used for both reading from and writing to a given

* pipe.

*/

static ssize_t qemu_pipe_read_write(struct file *filp, char __user *buffer,

size_t bufflen, int is_write)

{

unsigned long irq_flags;

struct qemu_pipe *pipe = filp->private_data;

struct qemu_pipe_dev *dev = pipe->dev;

const int cmd_offset = is_write ? 0
(CMD_READ_BUFFER - CMD_WRITE_BUFFER);

unsigned long address, address_end;

int ret = 0;

/* If the emulator already closed the pipe, no need to go further */

if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) {

PIPE_W(“(write=%d) already closed!\n”, is_write);

ret = -EIO;

goto out;

}

/* Null reads or writes succeeds */

if (unlikely(bufflen) == 0)

goto out;

/* Check the buffer range for access */

if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ,

buffer, bufflen)) {

ret = -EFAULT;

PIPE_W(“rw access_ok failed\n”);

goto out;

}

/* Serialize access to the pipe */

if (mutex_lock_interruptible(&pipe->lock)) {

PIPE_W(“(write=%d) interrupted!\n”, is_write);

return -ERESTARTSYS;

}

address = (unsigned long)(void *)buffer;

address_end = address + bufflen;

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(&pi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值