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
, (uint8_t *)elem
.out_sg
[d
].iov_base
,
43 elem
.out_sg
[d
].iov_len
);
45 virtqueue_push(vq
, &elem
, len
);
46 virtio_notify(vdev
, vq
);
50 static void virtio_console_handle_input(VirtIODevice
*vdev
, VirtQueue
*vq
)
54 static uint32_t virtio_console_get_features(VirtIODevice
*vdev
, uint32_t f
)
59 static int vcon_can_read(void *opaque
)
61 VirtIOConsole
*s
= (VirtIOConsole
*) opaque
;
63 if (!virtio_queue_ready(s
->ivq
) ||
64 !(s
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
) ||
65 virtio_queue_empty(s
->ivq
))
68 /* current implementations have a page sized buffer.
69 * We fall back to a one byte per read if there is not enough room.
70 * It would be cool to have a function that returns the available byte
71 * instead of checking for a limit */
72 if (virtqueue_avail_bytes(s
->ivq
, TARGET_PAGE_SIZE
, 0))
73 return TARGET_PAGE_SIZE
;
74 if (virtqueue_avail_bytes(s
->ivq
, 1, 0))
79 static void vcon_read(void *opaque
, const uint8_t *buf
, int size
)
81 VirtIOConsole
*s
= (VirtIOConsole
*) opaque
;
82 VirtQueueElement elem
;
85 /* The current kernel implementation has only one outstanding input
86 * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
87 * handle multiple buffers with multiple sg element for input */
88 while (offset
< size
) {
90 if (!virtqueue_pop(s
->ivq
, &elem
))
92 while (offset
< size
&& i
< elem
.in_num
) {
93 int len
= MIN(elem
.in_sg
[i
].iov_len
, size
- offset
);
94 memcpy(elem
.in_sg
[i
].iov_base
, buf
+ offset
, len
);
98 virtqueue_push(s
->ivq
, &elem
, size
);
100 virtio_notify(&s
->vdev
, s
->ivq
);
103 static void vcon_event(void *opaque
, int event
)
105 /* we will ignore any event for the time being */
108 static void virtio_console_save(QEMUFile
*f
, void *opaque
)
110 VirtIOConsole
*s
= opaque
;
112 virtio_save(&s
->vdev
, f
);
115 static int virtio_console_load(QEMUFile
*f
, void *opaque
, int version_id
)
117 VirtIOConsole
*s
= opaque
;
122 virtio_load(&s
->vdev
, f
);
126 VirtIODevice
*virtio_console_init(DeviceState
*dev
)
129 s
= (VirtIOConsole
*)virtio_common_init("virtio-console",
131 0, sizeof(VirtIOConsole
));
132 s
->vdev
.get_features
= virtio_console_get_features
;
134 s
->ivq
= virtio_add_queue(&s
->vdev
, 128, virtio_console_handle_input
);
135 s
->ovq
= virtio_add_queue(&s
->vdev
, 128, virtio_console_handle_output
);
137 s
->chr
= qdev_init_chardev(dev
);
138 qemu_chr_add_handlers(s
->chr
, vcon_can_read
, vcon_read
, vcon_event
, s
);
140 register_savevm("virtio-console", -1, 1, virtio_console_save
, virtio_console_load
, s
);