这里面涉及到几个模块:
virtio-input:virtio-input触摸驱动
virtio-mmio: virtio memory map I/O, 负责host-guest之间的内存映射
virtio-ring: ring buffer,负责virtio的buffer管理
Ring Buffer初始化过程
1,virtio_input_probe函数流程过程中会调用virtinput_init_vqs来申请ring buffer,同时注册回调函数(当中断触发时,调用callback函数)。
2,在virtinput_init_vqs函数运行的过程中,会通过readl/writel的方法从QNX侧获取到需要申请的ring buffer的数量:
num = readl(vm_dev->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
if (num == 0) {
err = -ENOENT;
goto error_new_virtqueue;
}
3,在virtio-ring 模块中申请内存,并且把地址的映射关系返回给virtio-mmio
4,virtio-mmio通过readl/writel将这些buffer的地址信息告诉QNX
中断触发情况下的数据走向
1,QNX侧vdev-virtio-input.so接收到screen的touch事件信息
2,vdev-virtio-input.so将得到的touch事件解析成下面这个结构体数据,并且逐个放到guest os给过来的buffer中:
struct virtio_input_event {
__le16 type;
__le16 code;
__le32 value;
};
3,vdev-virtio-input.so触发中断
4,guest触发中断处理函数,在这里是vm_interrupt
5,vm_interrupt函数调用前面注册的回调函数,这里是virtinput_recv_events
6,virtinput_recv_events,函数从ring buffer中把touch数据都获取到,并注入input子系统中
static void virtinput_recv_events(struct virtqueue *vq)
{
struct virtio_input *vi = vq->vdev->priv;
struct virtio_input_event *event;
unsigned long flags;
unsigned int len;
spin_lock_irqsave(&vi->lock, flags);
if (vi->ready) {
while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
spin_unlock_irqrestore(&vi->lock, flags);
input_event(vi->idev,
le16_to_cpu(event->type),
le16_to_cpu(event->code),
le32_to_cpu(event->value));
spin_lock_irqsave(&vi->lock, flags);
printk(KERN_INFO "packed_ring:%d input: [0x%x][0x%x][0x%x] \n", vi->evt->packed_ring, event->type,event->code,event->value);
virtinput_queue_evtbuf(vi, event);
}
virtqueue_kick(vq);
}
spin_unlock_irqrestore(&vi->lock, flags);
}
补充一张图: