Fix user emulator breakage, based on patch by Riku Voipio
[qemu/mini2440/sniper_sniper_test.git] / hw / virtio-console.c
blobdeae76d0de525130331f9cba100f6ba0e79d2a84
1 /*
2 * Virtio Console Device
4 * Copyright IBM, Corp. 2008
6 * Authors:
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.
14 #include "hw.h"
15 #include "qemu-char.h"
16 #include "virtio.h"
17 #include "virtio-console.h"
20 typedef struct VirtIOConsole
22 VirtIODevice vdev;
23 VirtQueue *ivq, *dvq;
24 CharDriverState *chr;
25 } 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)) {
38 ssize_t len = 0;
39 int d;
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)
54 return 0;
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))
64 return 0;
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))
73 return 1;
74 return 0;
77 static void vcon_read(void *opaque, const uint8_t *buf, int size)
79 VirtIOConsole *s = (VirtIOConsole *) opaque;
80 VirtQueueElement elem;
81 int offset = 0;
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) {
87 int i = 0;
88 if (!virtqueue_pop(s->ivq, &elem))
89 break;
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);
93 offset += len;
94 i++;
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;
117 if (version_id != 1)
118 return -EINVAL;
120 virtio_load(&s->vdev, f);
121 return 0;
124 void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
126 VirtIOConsole *s;
128 s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
129 6900, 0x1003,
130 0, VIRTIO_ID_CONSOLE,
131 0x03, 0x80, 0x00,
132 0, sizeof(VirtIOConsole));
133 if (s == NULL)
134 return NULL;
136 s->vdev.get_features = virtio_console_get_features;
138 s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
139 s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
141 s->chr = chr;
142 qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
144 register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
146 return &s->vdev;