summaryrefslogtreecommitdiff
path: root/hw/virtio-console.c
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-01-15 20:05:50 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-01-15 20:05:50 +0000
commit970d878c5432d8be41ac1eb4185ed4665fa6ab88 (patch)
tree62e74112d53787350e981c46141fefc8ccf07ee7 /hw/virtio-console.c
parent9ede2fde19eaf65c07c8bed3936e78dc0ed37412 (diff)
downloadqemu-970d878c5432d8be41ac1eb4185ed4665fa6ab88.tar.gz
Add missing files from last commit.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6316 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/virtio-console.c')
-rw-r--r--hw/virtio-console.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
new file mode 100644
index 0000000000..deae76d0de
--- /dev/null
+++ b/hw/virtio-console.c
@@ -0,0 +1,147 @@
+/*
+ * Virtio Console Device
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "virtio.h"
+#include "virtio-console.h"
+
+
+typedef struct VirtIOConsole
+{
+ VirtIODevice vdev;
+ VirtQueue *ivq, *dvq;
+ CharDriverState *chr;
+} VirtIOConsole;
+
+static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
+{
+ return (VirtIOConsole *)vdev;
+}
+
+static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOConsole *s = to_virtio_console(vdev);
+ VirtQueueElement elem;
+
+ while (virtqueue_pop(vq, &elem)) {
+ ssize_t len = 0;
+ int d;
+
+ for (d=0; d < elem.out_num; d++)
+ len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
+ virtqueue_push(vq, &elem, len);
+ virtio_notify(vdev, vq);
+ }
+}
+
+static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+}
+
+static uint32_t virtio_console_get_features(VirtIODevice *vdev)
+{
+ return 0;
+}
+
+static int vcon_can_read(void *opaque)
+{
+ VirtIOConsole *s = (VirtIOConsole *) opaque;
+
+ if (!virtio_queue_ready(s->ivq) ||
+ !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
+ virtio_queue_empty(s->ivq))
+ return 0;
+
+ /* current implementations have a page sized buffer.
+ * We fall back to a one byte per read if there is not enough room.
+ * It would be cool to have a function that returns the available byte
+ * instead of checking for a limit */
+ if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
+ return TARGET_PAGE_SIZE;
+ if (virtqueue_avail_bytes(s->ivq, 1, 0))
+ return 1;
+ return 0;
+}
+
+static void vcon_read(void *opaque, const uint8_t *buf, int size)
+{
+ VirtIOConsole *s = (VirtIOConsole *) opaque;
+ VirtQueueElement elem;
+ int offset = 0;
+
+ /* The current kernel implementation has only one outstanding input
+ * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
+ * handle multiple buffers with multiple sg element for input */
+ while (offset < size) {
+ int i = 0;
+ if (!virtqueue_pop(s->ivq, &elem))
+ break;
+ while (offset < size && i < elem.in_num) {
+ int len = MIN(elem.in_sg[i].iov_len, size - offset);
+ memcpy(elem.in_sg[i].iov_base, buf + offset, len);
+ offset += len;
+ i++;
+ }
+ virtqueue_push(s->ivq, &elem, size);
+ }
+ virtio_notify(&s->vdev, s->ivq);
+}
+
+static void vcon_event(void *opaque, int event)
+{
+ /* we will ignore any event for the time being */
+}
+
+static void virtio_console_save(QEMUFile *f, void *opaque)
+{
+ VirtIOConsole *s = opaque;
+
+ virtio_save(&s->vdev, f);
+}
+
+static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VirtIOConsole *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ virtio_load(&s->vdev, f);
+ return 0;
+}
+
+void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
+{
+ VirtIOConsole *s;
+
+ s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
+ 6900, 0x1003,
+ 0, VIRTIO_ID_CONSOLE,
+ 0x03, 0x80, 0x00,
+ 0, sizeof(VirtIOConsole));
+ if (s == NULL)
+ return NULL;
+
+ s->vdev.get_features = virtio_console_get_features;
+
+ s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
+ s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
+
+ s->chr = chr;
+ qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
+
+ register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
+
+ return &s->vdev;
+}