summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/baum.c10
-rw-r--r--hw/baum.h30
-rw-r--r--hw/msmouse.c10
-rw-r--r--hw/msmouse.h7
-rw-r--r--hw/scsi-bus.c4
-rw-r--r--hw/scsi-disk.c36
-rw-r--r--hw/serial.c28
-rw-r--r--hw/serial.h2
-rw-r--r--hw/virtio-console.c28
-rw-r--r--hw/virtio-serial-bus.c19
10 files changed, 81 insertions, 93 deletions
diff --git a/hw/baum.c b/hw/baum.c
index 09dcb9cc74..d8919d54de 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -25,7 +25,6 @@
 #include "char/char.h"
 #include "qemu/timer.h"
 #include "usb.h"
-#include "baum.h"
 #include <brlapi.h>
 #include <brlapi_constants.h>
 #include <brlapi_keycodes.h>
@@ -562,7 +561,7 @@ static void baum_close(struct CharDriverState *chr)
     g_free(baum);
 }
 
-CharDriverState *chr_baum_init(QemuOpts *opts)
+static CharDriverState *chr_baum_init(QemuOpts *opts)
 {
     BaumDriverState *baum;
     CharDriverState *chr;
@@ -625,3 +624,10 @@ fail_handle:
     g_free(baum);
     return NULL;
 }
+
+static void register_types(void)
+{
+    register_char_driver("braille", chr_baum_init);
+}
+
+type_init(register_types);
diff --git a/hw/baum.h b/hw/baum.h
deleted file mode 100644
index 763588422a..0000000000
--- a/hw/baum.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * QEMU Baum
- *
- * Copyright (c) 2008 Samuel Thibault
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef HW_BAUM_H
-#define HW_BAUM_H 1
-
-/* char device */
-CharDriverState *chr_baum_init(QemuOpts *opts);
-
-#endif
diff --git a/hw/msmouse.c b/hw/msmouse.c
index ef47aed4e9..407ec87784 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -25,7 +25,6 @@
 #include "qemu-common.h"
 #include "char/char.h"
 #include "ui/console.h"
-#include "msmouse.h"
 
 #define MSMOUSE_LO6(n) ((n) & 0x3f)
 #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
@@ -64,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
     g_free (chr);
 }
 
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
 {
     CharDriverState *chr;
 
@@ -76,3 +75,10 @@ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
 
     return chr;
 }
+
+static void register_types(void)
+{
+    register_char_driver("msmouse", qemu_chr_open_msmouse);
+}
+
+type_init(register_types);
diff --git a/hw/msmouse.h b/hw/msmouse.h
deleted file mode 100644
index 8cff3a71c3..0000000000
--- a/hw/msmouse.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef HW_MSMOUSE_H
-#define HW_MSMOUSE_H 1
-
-/* msmouse.c */
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
-
-#endif
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index a97f1cdc1c..01e1dec4ca 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1508,6 +1508,10 @@ void scsi_req_unref(SCSIRequest *req)
    will start the next chunk or complete the command.  */
 void scsi_req_continue(SCSIRequest *req)
 {
+    if (req->io_canceled) {
+        trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
+        return;
+    }
     trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
     if (req->cmd.mode == SCSI_XFER_TO_DEV) {
         req->ops->write_data(req);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index d41158693e..4a0673c0bf 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -178,6 +178,9 @@ static void scsi_aio_complete(void *opaque, int ret)
     assert(r->req.aiocb != NULL);
     r->req.aiocb = NULL;
     bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -223,6 +226,10 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
     if (scsi_is_cmd_fua(&r->req.cmd)) {
         bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
         r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
@@ -230,6 +237,8 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
     }
 
     scsi_req_complete(&r->req, GOOD);
+
+done:
     if (!r->req.io_canceled) {
         scsi_req_unref(&r->req);
     }
@@ -243,6 +252,9 @@ static void scsi_dma_complete(void *opaque, int ret)
     assert(r->req.aiocb != NULL);
     r->req.aiocb = NULL;
     bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -274,6 +286,9 @@ static void scsi_read_complete(void * opaque, int ret)
     assert(r->req.aiocb != NULL);
     r->req.aiocb = NULL;
     bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -305,6 +320,9 @@ static void scsi_do_read(void *opaque, int ret)
         r->req.aiocb = NULL;
         bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
+    if (r->req.io_canceled) {
+        goto done;
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -312,10 +330,6 @@ static void scsi_do_read(void *opaque, int ret)
         }
     }
 
-    if (r->req.io_canceled) {
-        return;
-    }
-
     /* The request is used as the AIO opaque value, so add a ref.  */
     scsi_req_ref(&r->req);
 
@@ -423,6 +437,9 @@ static void scsi_write_complete(void * opaque, int ret)
         r->req.aiocb = NULL;
         bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
+    if (r->req.io_canceled) {
+        goto done;
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -1478,13 +1495,17 @@ static void scsi_unmap_complete(void *opaque, int ret)
     uint32_t nb_sectors;
 
     r->req.aiocb = NULL;
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
     }
 
-    if (data->count > 0 && !r->req.io_canceled) {
+    if (data->count > 0) {
         sector_num = ldq_be_p(&data->inbuf[0]);
         nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
         if (!check_lba_range(s, sector_num, nb_sectors)) {
@@ -1501,10 +1522,9 @@ static void scsi_unmap_complete(void *opaque, int ret)
         return;
     }
 
+    scsi_req_complete(&r->req, GOOD);
+
 done:
-    if (data->count == 0) {
-        scsi_req_complete(&r->req, GOOD);
-    }
     if (!r->req.io_canceled) {
         scsi_req_unref(&r->req);
     }
diff --git a/hw/serial.c b/hw/serial.c
index f0ce9b0c15..eb38f2231d 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -256,16 +256,17 @@ static void serial_update_msl(SerialState *s)
         qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
 }
 
-static void serial_xmit(void *opaque)
+static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
 {
     SerialState *s = opaque;
-    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
 
     if (s->tsr_retry <= 0) {
         if (s->fcr & UART_FCR_FE) {
             s->tsr = fifo_get(s,XMIT_FIFO);
             if (!s->xmit_fifo.count)
                 s->lsr |= UART_LSR_THRE;
+        } else if ((s->lsr & UART_LSR_THRE)) {
+            return FALSE;
         } else {
             s->tsr = s->thr;
             s->lsr |= UART_LSR_THRE;
@@ -277,30 +278,25 @@ static void serial_xmit(void *opaque)
         /* in loopback mode, say that we just received a char */
         serial_receive1(s, &s->tsr, 1);
     } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
-        if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
+        if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY &&
+            qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) {
             s->tsr_retry++;
-            qemu_mod_timer(s->transmit_timer,  new_xmit_ts + s->char_transmit_time);
-            return;
-        } else if (s->poll_msl < 0) {
-            /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
-            drop any further failed writes instantly, until we get one that goes through.
-            This is to prevent guests that log to unconnected pipes or pty's from stalling. */
-            s->tsr_retry = -1;
+            return FALSE;
         }
-    }
-    else {
+        s->tsr_retry = 0;
+    } else {
         s->tsr_retry = 0;
     }
 
     s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
-    if (!(s->lsr & UART_LSR_THRE))
-        qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time);
 
     if (s->lsr & UART_LSR_THRE) {
         s->lsr |= UART_LSR_TEMT;
         s->thr_ipending = 1;
         serial_update_irq(s);
     }
+
+    return FALSE;
 }
 
 
@@ -330,7 +326,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
                 s->lsr &= ~UART_LSR_THRE;
                 serial_update_irq(s);
             }
-            serial_xmit(s);
+            serial_xmit(NULL, G_IO_OUT, s);
         }
         break;
     case 1:
@@ -684,8 +680,6 @@ void serial_init_core(SerialState *s)
     s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
 
     s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
-    s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s);
-
     qemu_register_reset(serial_reset, s);
 
     qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
diff --git a/hw/serial.h b/hw/serial.h
index 98ee4241be..e57375d03c 100644
--- a/hw/serial.h
+++ b/hw/serial.h
@@ -72,8 +72,6 @@ struct SerialState {
 
     struct QEMUTimer *fifo_timeout_timer;
     int timeout_ipending;           /* timeout interrupt pending state */
-    struct QEMUTimer *transmit_timer;
-
 
     uint64_t char_transmit_time;    /* time to transmit a char in ticks */
     int poll_msl;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 46072a086f..194de6431e 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -20,6 +20,18 @@ typedef struct VirtConsole {
     CharDriverState *chr;
 } VirtConsole;
 
+/*
+ * Callback function that's called from chardevs when backend becomes
+ * writable.
+ */
+static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
+                                    void *opaque)
+{
+    VirtConsole *vcon = opaque;
+
+    virtio_serial_throttle_port(&vcon->port, false);
+    return FALSE;
+}
 
 /* Callback function that's called when the guest sends us data */
 static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
@@ -35,19 +47,21 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
     ret = qemu_chr_fe_write(vcon->chr, buf, len);
     trace_virtio_console_flush_buf(port->id, len, ret);
 
-    if (ret < 0) {
+    if (ret <= 0) {
+        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
         /*
          * Ideally we'd get a better error code than just -1, but
          * that's what the chardev interface gives us right now.  If
          * we had a finer-grained message, like -EPIPE, we could close
-         * this connection.  Absent such error messages, the most we
-         * can do is to return 0 here.
-         *
-         * This will prevent stray -1 values to go to
-         * virtio-serial-bus.c and cause abort()s in
-         * do_flush_queued_data().
+         * this connection.
          */
         ret = 0;
+        if (!k->is_console) {
+            virtio_serial_throttle_port(port, true);
+            qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked,
+                                  vcon);
+        }
     }
     return ret;
 }
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index aa7d0d7fc7..f76c5058ba 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -172,24 +172,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                   port->elem.out_sg[i].iov_base
                                   + port->iov_offset,
                                   buf_size);
-            if (ret < 0 && ret != -EAGAIN) {
-                /* We don't handle any other type of errors here */
-                abort();
-            }
-            if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
-		/*
-                 * this is a temporary check until chardevs can signal to
-                 * frontends that they are writable again. This prevents
-                 * the console from going into throttled mode (forever)
-                 * if virtio-console is connected to a pty without a
-                 * listener. Otherwise the guest spins forever.
-                 * We can revert this if
-                 * 1: chardevs can notify frondends
-                 * 2: the guest driver does not spin in these cases
-                 */
-                if (!vsc->is_console) {
-                    virtio_serial_throttle_port(port, true);
-                }
+            if (port->throttled) {
                 port->iov_idx = i;
                 if (ret > 0) {
                     port->iov_offset += ret;