2 * Virtio Console Device
4 * Copyright IBM, Corp. 2008
7 * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
15 #include "qemu-char.h"
17 #include "virtio-console.h"
20 typedef struct VirtIOConsole
27 static VirtIOConsole
*to_virtio_console(VirtIODevice
*vdev
)
29 return (VirtIOConsole
*)vdev
;
32 static void virtio_console_handle_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
34 VirtIOConsole
*s
= to_virtio_console(vdev
);
35 VirtQueueElement elem
;
37 while (virtqueue_pop(vq
, &elem
)) {
41 for (d
=0; d
< elem
.out_num
; d
++)
42 len
+= qemu_chr_write(s
->chr
, elem
.out_sg
[d
].iov_base
,elem
.out_sg
[d
].iov_len
);
43 virtqueue_push(vq
, &elem
, len
);
44 virtio_notify(vdev
, vq
);
48 static void virtio_console_handle_input(VirtIODevice
*vdev
, VirtQueue
*vq
)
52 static uint32_t virtio_console_get_features(VirtIODevice
*vdev
)
57 static int vcon_can_read(void *opaque
)
59 VirtIOConsole
*s
= (VirtIOConsole
*) opaque
;
61 if (!virtio_queue_ready(s
->ivq
) ||
62 !(s
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
) ||
63 virtio_queue_empty(s
->ivq
))
66 /* current implementations have a page sized buffer.
67 * We fall back to a one byte per read if there is not enough room.
68 * It would be cool to have a function that returns the available byte
69 * instead of checking for a limit */
70 if (virtqueue_avail_bytes(s
->ivq
, TARGET_PAGE_SIZE
, 0))
71 return TARGET_PAGE_SIZE
;
72 if (virtqueue_avail_bytes(s
->ivq
, 1, 0))
77 static void vcon_read(void *opaque
, const uint8_t *buf
, int size
)
79 VirtIOConsole
*s
= (VirtIOConsole
*) opaque
;
80 VirtQueueElement elem
;
83 /* The current kernel implementation has only one outstanding input
84 * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
85 * handle multiple buffers with multiple sg element for input */
86 while (offset
< size
) {
88 if (!virtqueue_pop(s
->ivq
, &elem
))
90 while (offset
< size
&& i
< elem
.in_num
) {
91 int len
= MIN(elem
.in_sg
[i
].iov_len
, size
- offset
);
92 memcpy(elem
.in_sg
[i
].iov_base
, buf
+ offset
, len
);
96 virtqueue_push(s
->ivq
, &elem
, size
);
98 virtio_notify(&s
->vdev
, s
->ivq
);
101 static void vcon_event(void *opaque
, int event
)
103 /* we will ignore any event for the time being */
106 static void virtio_console_save(QEMUFile
*f
, void *opaque
)
108 VirtIOConsole
*s
= opaque
;
110 virtio_save(&s
->vdev
, f
);
113 static int virtio_console_load(QEMUFile
*f
, void *opaque
, int version_id
)
115 VirtIOConsole
*s
= opaque
;
120 virtio_load(&s
->vdev
, f
);
124 void *virtio_console_init(PCIBus
*bus
, CharDriverState
*chr
)
128 s
= (VirtIOConsole
*)virtio_init_pci(bus
, "virtio-console",
129 PCI_VENDOR_ID_REDHAT_QUMRANET
,
130 PCI_DEVICE_ID_VIRTIO_CONSOLE
,
131 PCI_VENDOR_ID_REDHAT_QUMRANET
,
133 PCI_CLASS_DISPLAY_OTHER
, 0x00,
134 0, sizeof(VirtIOConsole
));
138 s
->vdev
.get_features
= virtio_console_get_features
;
140 s
->ivq
= virtio_add_queue(&s
->vdev
, 128, virtio_console_handle_input
);
141 s
->dvq
= virtio_add_queue(&s
->vdev
, 128, virtio_console_handle_output
);
144 qemu_chr_add_handlers(chr
, vcon_can_read
, vcon_read
, vcon_event
, s
);
146 register_savevm("virtio-console", -1, 1, virtio_console_save
, virtio_console_load
, s
);