summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/virtio-serial-bus.c69
1 files changed, 32 insertions, 37 deletions
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index ad44127154..8d07152c08 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -111,6 +111,30 @@ static size_t write_to_port(VirtIOSerialPort *port,
return offset;
}
+static void flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
+ VirtIODevice *vdev, bool discard)
+{
+ VirtQueueElement elem;
+
+ assert(port || discard);
+
+ while (virtqueue_pop(vq, &elem)) {
+ uint8_t *buf;
+ size_t ret, buf_size;
+
+ if (!discard) {
+ buf_size = iov_size(elem.out_sg, elem.out_num);
+ buf = qemu_malloc(buf_size);
+ ret = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, buf_size);
+
+ port->info->have_data(port, buf, ret);
+ qemu_free(buf);
+ }
+ virtqueue_push(vq, &elem, 0);
+ }
+ virtio_notify(vdev, vq);
+}
+
static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
{
VirtQueueElement elem;
@@ -345,47 +369,18 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOSerial *vser;
- VirtQueueElement elem;
+ VirtIOSerialPort *port;
+ bool discard;
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+ port = find_port_by_vq(vser, vq);
- while (virtqueue_pop(vq, &elem)) {
- VirtIOSerialPort *port;
- uint8_t *buf;
- size_t ret, buf_size;
-
- port = find_port_by_vq(vser, vq);
- if (!port) {
- ret = 0;
- goto next_buf;
- }
-
- if (!port->host_connected) {
- ret = 0;
- goto next_buf;
- }
-
- /*
- * A port may not have any handler registered for consuming the
- * data that the guest sends or it may not have a chardev associated
- * with it. Just ignore the data in that case.
- */
- if (!port->info->have_data) {
- ret = 0;
- goto next_buf;
- }
-
- buf_size = iov_size(elem.out_sg, elem.out_num);
- buf = qemu_malloc(buf_size);
- ret = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, buf_size);
-
- port->info->have_data(port, buf, ret);
- qemu_free(buf);
-
- next_buf:
- virtqueue_push(vq, &elem, 0);
+ discard = false;
+ if (!port || !port->host_connected || !port->info->have_data) {
+ discard = true;
}
- virtio_notify(vdev, vq);
+
+ flush_queued_data(port, vq, vdev, discard);
}
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)