]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blobdiff - qemu-char.c
apohw: update for actual FPGA design.
[lisovros/qemu_apohw.git] / qemu-char.c
index ac65a1c806893b897e52eb9a2635469ea0c3c3dd..27abcb918633f8f00fc4b784446af5268273d0f8 100644 (file)
 #include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
-#include "block.h"
 #include "hw/usb.h"
 #include "hw/baum.h"
 #include "hw/msmouse.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
 
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <time.h>
 #include <errno.h>
 #include <sys/time.h>
@@ -98,6 +96,7 @@
 #endif
 
 #include "qemu_socket.h"
+#include "ui/qemu-spice.h"
 
 #define READ_BUF_LEN 4096
 
 static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
     QTAILQ_HEAD_INITIALIZER(chardevs);
 
-static void qemu_chr_event(CharDriverState *s, int event)
+void qemu_chr_be_event(CharDriverState *s, int event)
 {
     /* Keep track if the char device is open */
     switch (event) {
@@ -127,7 +126,7 @@ static void qemu_chr_event(CharDriverState *s, int event)
 static void qemu_chr_generic_open_bh(void *opaque)
 {
     CharDriverState *s = opaque;
-    qemu_chr_event(s, CHR_EVENT_OPENED);
+    qemu_chr_be_event(s, CHR_EVENT_OPENED);
     qemu_bh_delete(s->bh);
     s->bh = NULL;
 }
@@ -140,63 +139,66 @@ void qemu_chr_generic_open(CharDriverState *s)
     }
 }
 
-int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
 {
     return s->chr_write(s, buf, len);
 }
 
-int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
 {
     if (!s->chr_ioctl)
         return -ENOTSUP;
     return s->chr_ioctl(s, cmd, arg);
 }
 
-int qemu_chr_can_read(CharDriverState *s)
+int qemu_chr_be_can_write(CharDriverState *s)
 {
     if (!s->chr_can_read)
         return 0;
     return s->chr_can_read(s->handler_opaque);
 }
 
-void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
 {
     s->chr_read(s->handler_opaque, buf, len);
 }
 
-int qemu_chr_get_msgfd(CharDriverState *s)
+int qemu_chr_fe_get_msgfd(CharDriverState *s)
 {
     return s->get_msgfd ? s->get_msgfd(s) : -1;
 }
 
+int qemu_chr_add_client(CharDriverState *s, int fd)
+{
+    return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
+}
+
 void qemu_chr_accept_input(CharDriverState *s)
 {
     if (s->chr_accept_input)
         s->chr_accept_input(s);
 }
 
-void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
 {
     char buf[READ_BUF_LEN];
     va_list ap;
     va_start(ap, fmt);
     vsnprintf(buf, sizeof(buf), fmt, ap);
-    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
+    qemu_chr_fe_write(s, (uint8_t *)buf, strlen(buf));
     va_end(ap);
 }
 
-void qemu_chr_send_event(CharDriverState *s, int event)
-{
-    if (s->chr_send_event)
-        s->chr_send_event(s, event);
-}
-
 void qemu_chr_add_handlers(CharDriverState *s,
                            IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque)
 {
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        /* chr driver being released. */
+        ++s->avail_connections;
+    }
     s->chr_can_read = fd_can_read;
     s->chr_read = fd_read;
     s->chr_event = fd_event;
@@ -216,13 +218,15 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
+static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
-    return chr;
+
+    *_chr= chr;
+    return 0;
 }
 
 /* MUX driver for serial I/O splitting */
@@ -267,7 +271,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                 int64_t ti;
                 int secs;
 
-                ti = qemu_get_clock(rt_clock);
+                ti = qemu_get_clock_ms(rt_clock);
                 if (d->timestamps_start == -1)
                     d->timestamps_start = ti;
                 ti -= d->timestamps_start;
@@ -352,15 +356,10 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
                  break;
             }
         case 's':
-            {
-                DriveInfo *dinfo;
-                QTAILQ_FOREACH(dinfo, &drives, next) {
-                    bdrv_commit(dinfo->bdrv);
-                }
-            }
+            bdrv_commit_all();
             break;
         case 'b':
-            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            qemu_chr_be_event(chr, CHR_EVENT_BREAK);
             break;
         case 'c':
             /* Switch to the next registered device */
@@ -472,8 +471,8 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     CharDriverState *chr;
     MuxDriver *d;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    d = qemu_mallocz(sizeof(MuxDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    d = g_malloc0(sizeof(MuxDriver));
 
     chr->opaque = d;
     d->drv = drv;
@@ -481,6 +480,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     chr->chr_write = mux_chr_write;
     chr->chr_update_read_handler = mux_chr_update_read_handler;
     chr->chr_accept_input = mux_chr_accept_input;
+    /* Frontend guest-open / -close notification is not support with muxes */
+    chr->chr_guest_open = NULL;
+    chr->chr_guest_close = NULL;
 
     /* Muxes are always open on creation */
     qemu_chr_generic_open(chr);
@@ -514,9 +516,10 @@ int send_all(int fd, const void *buf, int len1)
 
 #else
 
-static int unix_write(int fd, const uint8_t *buf, int len1)
+int send_all(int fd, const void *_buf, int len1)
 {
     int ret, len;
+    const uint8_t *buf = _buf;
 
     len = len1;
     while (len > 0) {
@@ -533,13 +536,11 @@ static int unix_write(int fd, const uint8_t *buf, int len1)
     }
     return len1 - len;
 }
-
-int send_all(int fd, const void *buf, int len1)
-{
-    return unix_write(fd, buf, len1);
-}
 #endif /* !_WIN32 */
 
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients;
+
 #ifndef _WIN32
 
 typedef struct {
@@ -547,8 +548,6 @@ typedef struct {
     int max_size;
 } FDCharDriver;
 
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients = 0;
 
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -561,7 +560,7 @@ static int fd_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     FDCharDriver *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -581,11 +580,11 @@ static void fd_chr_read(void *opaque)
     if (size == 0) {
         /* FD has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
         return;
     }
     if (size > 0) {
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -613,8 +612,8 @@ static void fd_chr_close(struct CharDriverState *chr)
         }
     }
 
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
 /* open a character device to a unix fd */
@@ -623,8 +622,8 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     CharDriverState *chr;
     FDCharDriver *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(FDCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(FDCharDriver));
     s->fd_in = fd_in;
     s->fd_out = fd_out;
     chr->opaque = s;
@@ -637,18 +636,21 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
+static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_out;
 
     TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
                       O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
-    if (fd_out < 0)
-        return NULL;
-    return qemu_chr_open_fd(-1, fd_out);
+    if (fd_out < 0) {
+        return -errno;
+    }
+
+    *_chr = qemu_chr_open_fd(-1, fd_out);
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
+static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
@@ -656,7 +658,7 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
 
     if (filename == NULL) {
         fprintf(stderr, "chardev: pipe: no filename given\n");
-        return NULL;
+        return -EINVAL;
     }
 
     snprintf(filename_in, 256, "%s.in", filename);
@@ -668,11 +670,14 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
            close(fd_in);
        if (fd_out >= 0)
            close(fd_out);
-        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
-        if (fd_in < 0)
-            return NULL;
+        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0) {
+            return -errno;
+        }
     }
-    return qemu_chr_open_fd(fd_in, fd_out);
+
+    *_chr = qemu_chr_open_fd(fd_in, fd_out);
+    return 0;
 }
 
 
@@ -689,8 +694,8 @@ static int stdio_read_poll(void *opaque)
     CharDriverState *chr = opaque;
 
     /* try to flush the queue if needed */
-    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
-        qemu_chr_read(chr, term_fifo, 1);
+    if (term_fifo_size != 0 && qemu_chr_be_can_write(chr) > 0) {
+        qemu_chr_be_write(chr, term_fifo, 1);
         term_fifo_size = 0;
     }
     /* see if we can absorb more chars */
@@ -710,12 +715,12 @@ static void stdio_read(void *opaque)
     if (size == 0) {
         /* stdin has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
         return;
     }
     if (size > 0) {
-        if (qemu_chr_can_read(chr) > 0) {
-            qemu_chr_read(chr, buf, 1);
+        if (qemu_chr_be_can_write(chr) > 0) {
+            qemu_chr_be_write(chr, buf, 1);
         } else if (term_fifo_size == 0) {
             term_fifo[term_fifo_size++] = buf[0];
         }
@@ -725,7 +730,7 @@ static void stdio_read(void *opaque)
 /* init terminal so that we can grab keys */
 static struct termios oldtty;
 static int old_fd0_flags;
-static int term_atexit_done;
+static bool stdio_allow_signal;
 
 static void term_exit(void)
 {
@@ -733,32 +738,26 @@ static void term_exit(void)
     fcntl(0, F_SETFL, old_fd0_flags);
 }
 
-static void term_init(QemuOpts *opts)
+static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
 {
     struct termios tty;
 
-    tcgetattr (0, &tty);
-    oldtty = tty;
-    old_fd0_flags = fcntl(0, F_GETFL);
-
-    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+    tty = oldtty;
+    if (!echo) {
+        tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                           |INLCR|IGNCR|ICRNL|IXON);
-    tty.c_oflag |= OPOST;
-    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+        tty.c_oflag |= OPOST;
+        tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+        tty.c_cflag &= ~(CSIZE|PARENB);
+        tty.c_cflag |= CS8;
+        tty.c_cc[VMIN] = 1;
+        tty.c_cc[VTIME] = 0;
+    }
     /* if graphical mode, we allow Ctrl-C handling */
-    if (!qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC))
+    if (!stdio_allow_signal)
         tty.c_lflag &= ~ISIG;
-    tty.c_cflag &= ~(CSIZE|PARENB);
-    tty.c_cflag |= CS8;
-    tty.c_cc[VMIN] = 1;
-    tty.c_cc[VTIME] = 0;
 
     tcsetattr (0, TCSANOW, &tty);
-
-    if (!term_atexit_done++)
-        atexit(term_exit);
-
-    fcntl(0, F_SETFL, O_NONBLOCK);
 }
 
 static void qemu_chr_close_stdio(struct CharDriverState *chr)
@@ -769,19 +768,32 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
+static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-        return NULL;
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
+        return -EBUSY;
+    }
+
+    if (stdio_nb_clients == 0) {
+        old_fd0_flags = fcntl(0, F_GETFL);
+        tcgetattr (0, &oldtty);
+        fcntl(0, F_SETFL, O_NONBLOCK);
+        atexit(term_exit);
+    }
+
     chr = qemu_chr_open_fd(0, 1);
     chr->chr_close = qemu_chr_close_stdio;
+    chr->chr_set_echo = qemu_chr_set_echo_stdio;
     qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
     stdio_nb_clients++;
-    term_init(opts);
+    stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
+                                           display_type != DT_NOGRAPHIC);
+    qemu_chr_fe_set_echo(chr, false);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 #ifdef __sun__
@@ -873,7 +885,7 @@ static int pty_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     PtyCharDriver *s = chr->opaque;
 
-    s->read_bytes = qemu_chr_can_read(chr);
+    s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
 }
 
@@ -897,7 +909,7 @@ static void pty_chr_read(void *opaque)
     }
     if (size > 0) {
         pty_chr_state(chr, 1);
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -916,7 +928,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr)
      * timeout to the normal (much longer) poll interval before the
      * timer triggers.
      */
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10);
 }
 
 static void pty_chr_state(CharDriverState *chr, int connected)
@@ -930,7 +942,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
         /* (re-)connect poll interval for idle guests: once per second.
          * We check more frequently in case the guests sends data to
          * the virtual device linked to our pty. */
-        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+        qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000);
     } else {
         if (!s->connected)
             qemu_chr_generic_open(chr);
@@ -964,16 +976,16 @@ static void pty_chr_close(struct CharDriverState *chr)
     close(s->fd);
     qemu_del_timer(s->timer);
     qemu_free_timer(s->timer);
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
     PtyCharDriver *s;
     struct termios tty;
-    int slave_fd, len;
+    int master_fd, slave_fd, len;
 #if defined(__OpenBSD__) || defined(__DragonFly__)
     char pty_name[PATH_MAX];
 #define q_ptsname(x) pty_name
@@ -982,11 +994,8 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 #define q_ptsname(x) ptsname(x)
 #endif
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(PtyCharDriver));
-
-    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
-        return NULL;
+    if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+        return -errno;
     }
 
     /* Set raw attributes on the pty. */
@@ -995,20 +1004,25 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
     tcsetattr(slave_fd, TCSAFLUSH, &tty);
     close(slave_fd);
 
-    len = strlen(q_ptsname(s->fd)) + 5;
-    chr->filename = qemu_malloc(len);
-    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
-    qemu_opt_set(opts, "path", q_ptsname(s->fd));
-    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+    chr = g_malloc0(sizeof(CharDriverState));
 
+    len = strlen(q_ptsname(master_fd)) + 5;
+    chr->filename = g_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd));
+    qemu_opt_set(opts, "path", q_ptsname(master_fd));
+    fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd));
+
+    s = g_malloc0(sizeof(PtyCharDriver));
     chr->opaque = s;
     chr->chr_write = pty_chr_write;
     chr->chr_update_read_handler = pty_chr_update_read_handler;
     chr->chr_close = pty_chr_close;
 
-    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+    s->fd = master_fd;
+    s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 static void tty_serial_init(int fd, int speed,
@@ -1022,9 +1036,6 @@ static void tty_serial_init(int fd, int speed,
            speed, parity, data_bits, stop_bits);
 #endif
     tcgetattr (fd, &tty);
-    if (!term_atexit_done) {
-        oldtty = tty;
-    }
 
 #define check_speed(val) if (speed <= val) { spd = B##val; break; }
     speed = speed * 10 / 11;
@@ -1196,11 +1207,6 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static void tty_exit(void)
-{
-    tcsetattr(0, TCSANOW, &oldtty);
-}
-
 static void qemu_chr_close_tty(CharDriverState *chr)
 {
     FDCharDriver *s = chr->opaque;
@@ -1217,32 +1223,28 @@ static void qemu_chr_close_tty(CharDriverState *chr)
     }
 }
 
-static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
+static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     int fd;
 
-    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+    TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
     if (fd < 0) {
-        return NULL;
+        return -errno;
     }
     tty_serial_init(fd, 115200, 'N', 8, 1);
     chr = qemu_chr_open_fd(fd, fd);
-    if (!chr) {
-        close(fd);
-        return NULL;
-    }
     chr->chr_ioctl = tty_serial_ioctl;
     chr->chr_close = qemu_chr_close_tty;
-    if (!term_atexit_done++)
-        atexit(tty_exit);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 #else  /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
-    return NULL;
+    return -ENOTSUP;
 }
 #endif /* __linux__ || __sun__ */
 
@@ -1352,11 +1354,11 @@ static void pp_close(CharDriverState *chr)
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
     ioctl(fd, PPRELEASE);
     close(fd);
-    qemu_free(drv);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(drv);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1364,19 +1366,20 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
     int fd;
 
     TFR(fd = open(filename, O_RDWR));
-    if (fd < 0)
-        return NULL;
+    if (fd < 0) {
+        return -errno;
+    }
 
     if (ioctl(fd, PPCLAIM) < 0) {
         close(fd);
-        return NULL;
+        return -errno;
     }
 
-    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    drv = g_malloc0(sizeof(ParallelCharDriver));
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
     chr->chr_close = pp_close;
@@ -1384,14 +1387,15 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 
     qemu_chr_generic_open(chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 #endif /* __linux__ */
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)(long)chr->opaque;
+    int fd = (int)(intptr_t)chr->opaque;
     uint8_t b;
 
     switch(cmd) {
@@ -1426,26 +1430,31 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     int fd;
 
-    fd = open(filename, O_RDWR);
-    if (fd < 0)
-        return NULL;
+    fd = qemu_open(filename, O_RDWR);
+    if (fd < 0) {
+        return -errno;
+    }
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    chr->opaque = (void *)(long)fd;
+    chr = g_malloc0(sizeof(CharDriverState));
+    chr->opaque = (void *)(intptr_t)fd;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 #endif
 
 #else /* _WIN32 */
 
+static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+
 typedef struct {
     int max_size;
     HANDLE hcom, hrecv, hsend;
@@ -1454,6 +1463,14 @@ typedef struct {
     DWORD len;
 } WinCharState;
 
+typedef struct {
+    HANDLE  hStdIn;
+    HANDLE  hInputReadyEvent;
+    HANDLE  hInputDoneEvent;
+    HANDLE  hInputThread;
+    uint8_t win_stdio_buf;
+} WinStdioCharState;
+
 #define NSENDBUF 2048
 #define NRECVBUF 2048
 #define MAXCONNECT 1
@@ -1483,7 +1500,7 @@ static void win_chr_close(CharDriverState *chr)
     else
         qemu_del_polling_cb(win_chr_poll, chr);
 
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
 static int win_chr_init(CharDriverState *chr, const char *filename)
@@ -1591,7 +1608,7 @@ static int win_chr_read_poll(CharDriverState *chr)
 {
     WinCharState *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -1613,7 +1630,7 @@ static void win_chr_readfile(CharDriverState *chr)
     }
 
     if (size > 0) {
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -1646,25 +1663,27 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
+static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
     if (win_chr_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
+        g_free(s);
+        g_free(chr);
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
 static int win_chr_pipe_poll(void *opaque)
@@ -1746,57 +1765,272 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
+static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
     if (win_chr_pipe_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
+        g_free(s);
+        g_free(chr);
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr)
 {
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     s->hcom = fd_out;
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     qemu_chr_generic_open(chr);
-    return chr;
+    *pchr = chr;
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
+static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **chr)
 {
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr);
 }
 
-static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
+static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *file_out = qemu_opt_get(opts, "path");
     HANDLE fd_out;
 
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (fd_out == INVALID_HANDLE_VALUE)
-        return NULL;
+    if (fd_out == INVALID_HANDLE_VALUE) {
+        return -EIO;
+    }
 
-    return qemu_chr_open_win_file(fd_out);
+    return qemu_chr_open_win_file(fd_out, _chr);
+}
+
+static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+    DWORD   dwSize;
+    int     len1;
+
+    len1 = len;
+
+    while (len1 > 0) {
+        if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
+            break;
+        }
+        buf  += dwSize;
+        len1 -= dwSize;
+    }
+
+    return len - len1;
+}
+
+static void win_stdio_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+    INPUT_RECORD       buf[4];
+    int                ret;
+    DWORD              dwSize;
+    int                i;
+
+    ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf),
+                           &dwSize);
+
+    if (!ret) {
+        /* Avoid error storm */
+        qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
+        return;
+    }
+
+    for (i = 0; i < dwSize; i++) {
+        KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
+
+        if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
+            int j;
+            if (kev->uChar.AsciiChar != 0) {
+                for (j = 0; j < kev->wRepeatCount; j++) {
+                    if (qemu_chr_be_can_write(chr)) {
+                        uint8_t c = kev->uChar.AsciiChar;
+                        qemu_chr_be_write(chr, &c, 1);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static DWORD WINAPI win_stdio_thread(LPVOID param)
+{
+    CharDriverState   *chr   = param;
+    WinStdioCharState *stdio = chr->opaque;
+    int                ret;
+    DWORD              dwSize;
+
+    while (1) {
+
+        /* Wait for one byte */
+        ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
+
+        /* Exit in case of error, continue if nothing read */
+        if (!ret) {
+            break;
+        }
+        if (!dwSize) {
+            continue;
+        }
+
+        /* Some terminal emulator returns \r\n for Enter, just pass \n */
+        if (stdio->win_stdio_buf == '\r') {
+            continue;
+        }
+
+        /* Signal the main thread and wait until the byte was eaten */
+        if (!SetEvent(stdio->hInputReadyEvent)) {
+            break;
+        }
+        if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
+            != WAIT_OBJECT_0) {
+            break;
+        }
+    }
+
+    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
+    return 0;
+}
+
+static void win_stdio_thread_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (qemu_chr_be_can_write(chr)) {
+        qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
+    }
+
+    SetEvent(stdio->hInputDoneEvent);
+}
+
+static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
+{
+    WinStdioCharState *stdio  = chr->opaque;
+    DWORD              dwMode = 0;
+
+    GetConsoleMode(stdio->hStdIn, &dwMode);
+
+    if (echo) {
+        SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
+    } else {
+        SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
+    }
+}
+
+static void win_stdio_close(CharDriverState *chr)
+{
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputReadyEvent);
+    }
+    if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputDoneEvent);
+    }
+    if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
+        TerminateThread(stdio->hInputThread, 0);
+    }
+
+    g_free(chr->opaque);
+    g_free(chr);
+    stdio_nb_clients--;
+}
+
+static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState   *chr;
+    WinStdioCharState *stdio;
+    DWORD              dwMode;
+    int                is_console = 0;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS
+        || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
+        return -EIO;
+    }
+
+    chr   = g_malloc0(sizeof(CharDriverState));
+    stdio = g_malloc0(sizeof(WinStdioCharState));
+
+    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "cannot open stdio: invalid handle\n");
+        exit(1);
+    }
+
+    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+
+    chr->opaque    = stdio;
+    chr->chr_write = win_stdio_write;
+    chr->chr_close = win_stdio_close;
+
+    if (stdio_nb_clients == 0) {
+        if (is_console) {
+            if (qemu_add_wait_object(stdio->hStdIn,
+                                     win_stdio_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        } else {
+            DWORD   dwId;
+
+            stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
+                                            chr, 0, &dwId);
+
+            if (stdio->hInputThread == INVALID_HANDLE_VALUE
+                || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+                || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+                fprintf(stderr, "cannot create stdio thread or event\n");
+                exit(1);
+            }
+            if (qemu_add_wait_object(stdio->hInputReadyEvent,
+                                     win_stdio_thread_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        }
+    }
+
+    dwMode |= ENABLE_LINE_INPUT;
+
+    stdio_clients[stdio_nb_clients++] = chr;
+    if (stdio_nb_clients == 1 && is_console) {
+        /* set the terminal in raw mode */
+        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
+        dwMode |= ENABLE_PROCESSED_INPUT;
+    }
+
+    SetConsoleMode(stdio->hStdIn, dwMode);
+
+    chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
+    qemu_chr_fe_set_echo(chr, false);
+
+    *_chr = chr;
+
+    return 0;
 }
 #endif /* !_WIN32 */
 
@@ -1823,15 +2057,15 @@ static int udp_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     NetCharDriver *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
 
     /* If there were any stray characters in the queue process them
      * first
      */
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
         s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
+        s->max_size = qemu_chr_be_can_write(chr);
     }
     return s->max_size;
 }
@@ -1843,16 +2077,16 @@ static void udp_chr_read(void *opaque)
 
     if (s->max_size == 0)
         return;
-    s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
     s->bufptr = s->bufcnt;
     if (s->bufcnt <= 0)
         return;
 
     s->bufptr = 0;
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
         s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
+        s->max_size = qemu_chr_be_can_write(chr);
     }
 }
 
@@ -1870,25 +2104,27 @@ static void udp_chr_close(CharDriverState *chr)
 {
     NetCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
     int fd = -1;
+    int ret;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(NetCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(NetCharDriver));
 
     fd = inet_dgram_opts(opts);
     if (fd < 0) {
         fprintf(stderr, "inet_dgram_opts failed\n");
+        ret = -errno;
         goto return_err;
     }
 
@@ -1899,16 +2135,17 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_close = udp_chr_close;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
 return_err:
-    if (chr)
-        free(chr);
-    if (s)
-        free(s);
-    if (fd >= 0)
+    g_free(chr);
+    g_free(s);
+    if (fd >= 0) {
         closesocket(fd);
-    return NULL;
+    }
+    return ret;
 }
 
 /***********************************************************/
@@ -1943,7 +2180,7 @@ static int tcp_chr_read_poll(void *opaque)
     TCPCharDriver *s = chr->opaque;
     if (!s->connected)
         return 0;
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -1976,7 +2213,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
             } else {
                 if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
                     /* Handle IAC break commands by sending a serial break */
-                    qemu_chr_event(chr, CHR_EVENT_BREAK);
+                    qemu_chr_be_event(chr, CHR_EVENT_BREAK);
                     s->do_telnetopt++;
                 }
                 s->do_telnetopt++;
@@ -2058,7 +2295,7 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 {
     TCPCharDriver *s = chr->opaque;
-    return recv(s->fd, buf, len, 0);
+    return qemu_recv(s->fd, buf, len, 0);
 }
 #endif
 
@@ -2079,20 +2316,27 @@ static void tcp_chr_read(void *opaque)
         /* connection closed */
         s->connected = 0;
         if (s->listen_fd >= 0) {
-            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+            qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
         s->fd = -1;
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
     } else if (size > 0) {
         if (s->do_telnetopt)
             tcp_chr_process_IAC_bytes(chr, s, buf, &size);
         if (size > 0)
-            qemu_chr_read(chr, buf, size);
+            qemu_chr_be_write(chr, buf, size);
     }
 }
 
+#ifndef _WIN32
+CharDriverState *qemu_chr_open_eventfd(int eventfd)
+{
+    return qemu_chr_open_fd(eventfd, eventfd);
+}
+#endif
+
 static void tcp_chr_connect(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2125,6 +2369,22 @@ static void socket_set_nodelay(int fd)
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 }
 
+static int tcp_chr_add_client(CharDriverState *chr, int fd)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd != -1)
+       return -1;
+
+    socket_set_nonblock(fd);
+    if (s->do_nodelay)
+        socket_set_nodelay(fd);
+    s->fd = fd;
+    qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
+    tcp_chr_connect(chr);
+
+    return 0;
+}
+
 static void tcp_chr_accept(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2157,30 +2417,26 @@ static void tcp_chr_accept(void *opaque)
             break;
         }
     }
-    socket_set_nonblock(fd);
-    if (s->do_nodelay)
-        socket_set_nodelay(fd);
-    s->fd = fd;
-    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
-    tcp_chr_connect(chr);
+    if (tcp_chr_add_client(chr, fd) < 0)
+       close(fd);
 }
 
 static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     if (s->listen_fd >= 0) {
-        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
         closesocket(s->listen_fd);
     }
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
@@ -2190,6 +2446,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     int do_nodelay;
     int is_unix;
     int is_telnet;
+    int ret;
 
     is_listen      = qemu_opt_get_bool(opts, "server", 0);
     is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
@@ -2199,8 +2456,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     if (!is_listen)
         is_waitconnect = 0;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(TCPCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(TCPCharDriver));
 
     if (is_unix) {
         if (is_listen) {
@@ -2215,8 +2472,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
             fd = inet_connect_opts(opts);
         }
     }
-    if (fd < 0)
+    if (fd < 0) {
+        ret = -errno;
         goto fail;
+    }
 
     if (!is_waitconnect)
         socket_set_nonblock(fd);
@@ -2232,10 +2491,11 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     chr->chr_write = tcp_chr_write;
     chr->chr_close = tcp_chr_close;
     chr->get_msgfd = tcp_get_msgfd;
+    chr->chr_add_client = tcp_chr_add_client;
 
     if (is_listen) {
         s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         if (is_telnet)
             s->do_telnetopt = 1;
 
@@ -2247,7 +2507,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     }
 
     /* for "info chardev" monitor command */
-    chr->filename = qemu_malloc(256);
+    chr->filename = g_malloc(256);
     if (is_unix) {
         snprintf(chr->filename, 256, "unix:%s%s",
                  qemu_opt_get(opts, "path"),
@@ -2268,14 +2528,80 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
         tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);
     }
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
  fail:
     if (fd >= 0)
         closesocket(fd);
-    qemu_free(s);
-    qemu_free(chr);
-    return NULL;
+    g_free(s);
+    g_free(chr);
+    return ret;
+}
+
+/***********************************************************/
+/* Memory chardev */
+typedef struct {
+    size_t outbuf_size;
+    size_t outbuf_capacity;
+    uint8_t *outbuf;
+} MemoryDriver;
+
+static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MemoryDriver *d = chr->opaque;
+
+    /* TODO: the QString implementation has the same code, we should
+     * introduce a generic way to do this in cutils.c */
+    if (d->outbuf_capacity < d->outbuf_size + len) {
+        /* grow outbuf */
+        d->outbuf_capacity += len;
+        d->outbuf_capacity *= 2;
+        d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity);
+    }
+
+    memcpy(d->outbuf + d->outbuf_size, buf, len);
+    d->outbuf_size += len;
+
+    return len;
+}
+
+void qemu_chr_init_mem(CharDriverState *chr)
+{
+    MemoryDriver *d;
+
+    d = g_malloc(sizeof(*d));
+    d->outbuf_size = 0;
+    d->outbuf_capacity = 4096;
+    d->outbuf = g_malloc0(d->outbuf_capacity);
+
+    memset(chr, 0, sizeof(*chr));
+    chr->opaque = d;
+    chr->chr_write = mem_chr_write;
+}
+
+QString *qemu_chr_mem_to_qs(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
+}
+
+/* NOTE: this driver can not be closed with qemu_chr_delete()! */
+void qemu_chr_close_mem(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+
+    g_free(d->outbuf);
+    g_free(chr->opaque);
+    chr->opaque = NULL;
+    chr->chr_write = NULL;
+}
+
+size_t qemu_chr_mem_osize(const CharDriverState *chr)
+{
+    const MemoryDriver *d = chr->opaque;
+    return d->outbuf_size;
 }
 
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
@@ -2285,7 +2611,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
     const char *p;
     QemuOpts *opts;
 
-    opts = qemu_opts_create(&qemu_chardev_opts, label, 1);
+    opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
     if (NULL == opts)
         return NULL;
 
@@ -2404,7 +2730,7 @@ fail:
 
 static const struct {
     const char *name;
-    CharDriverState *(*open)(QemuOpts *opts);
+    int (*open)(QemuOpts *opts, CharDriverState **chr);
 } backend_table[] = {
     { .name = "null",      .open = qemu_chr_open_null },
     { .name = "socket",    .open = qemu_chr_open_socket },
@@ -2416,6 +2742,7 @@ static const struct {
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
     { .name = "console",   .open = qemu_chr_open_win_con },
     { .name = "serial",    .open = qemu_chr_open_win },
+    { .name = "stdio",     .open = qemu_chr_open_win_stdio },
 #else
     { .name = "file",      .open = qemu_chr_open_file_out },
     { .name = "pipe",      .open = qemu_chr_open_pipe },
@@ -2434,19 +2761,28 @@ static const struct {
     || defined(__FreeBSD_kernel__)
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
+#ifdef CONFIG_SPICE
+    { .name = "spicevmc",     .open = qemu_chr_open_spice },
+#endif
 };
 
-CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s))
 {
     CharDriverState *chr;
     int i;
+    int ret;
 
     if (qemu_opts_id(opts) == NULL) {
         fprintf(stderr, "chardev: no id specified\n");
         return NULL;
     }
 
+    if (qemu_opt_get(opts, "backend") == NULL) {
+        fprintf(stderr, "chardev: \"%s\" missing backend\n",
+                qemu_opts_id(opts));
+        return NULL;
+    }
     for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
         if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
             break;
@@ -2457,32 +2793,35 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
         return NULL;
     }
 
-    chr = backend_table[i].open(opts);
-    if (!chr) {
-        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
-                qemu_opt_get(opts, "backend"));
+    ret = backend_table[i].open(opts, &chr);
+    if (ret < 0) {
+        fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n",
+                qemu_opt_get(opts, "backend"), strerror(-ret));
         return NULL;
     }
 
     if (!chr->filename)
-        chr->filename = qemu_strdup(qemu_opt_get(opts, "backend"));
+        chr->filename = g_strdup(qemu_opt_get(opts, "backend"));
     chr->init = init;
     QTAILQ_INSERT_TAIL(&chardevs, chr, next);
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
         CharDriverState *base = chr;
         int len = strlen(qemu_opts_id(opts)) + 6;
-        base->label = qemu_malloc(len);
+        base->label = g_malloc(len);
         snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
         chr = qemu_chr_open_mux(base);
         chr->filename = base->filename;
+        chr->avail_connections = MAX_MUX;
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+    } else {
+        chr->avail_connections = 1;
     }
-    chr->label = qemu_strdup(qemu_opts_id(opts));
+    chr->label = g_strdup(qemu_opts_id(opts));
     return chr;
 }
 
-CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
 {
     const char *p;
     CharDriverState *chr;
@@ -2496,68 +2835,61 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     if (!opts)
         return NULL;
 
-    chr = qemu_chr_open_opts(opts, init);
+    chr = qemu_chr_new_from_opts(opts, init);
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         monitor_init(chr, MONITOR_USE_READLINE);
     }
+    qemu_opts_del(opts);
     return chr;
 }
 
-void qemu_chr_close(CharDriverState *chr)
+void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo)
 {
-    QTAILQ_REMOVE(&chardevs, chr, next);
-    if (chr->chr_close)
-        chr->chr_close(chr);
-    qemu_free(chr->filename);
-    qemu_free(chr->label);
-    qemu_free(chr);
+    if (chr->chr_set_echo) {
+        chr->chr_set_echo(chr, echo);
+    }
 }
 
-static void qemu_chr_qlist_iter(QObject *obj, void *opaque)
+void qemu_chr_fe_open(struct CharDriverState *chr)
 {
-    QDict *chr_dict;
-    Monitor *mon = opaque;
+    if (chr->chr_guest_open) {
+        chr->chr_guest_open(chr);
+    }
+}
 
-    chr_dict = qobject_to_qdict(obj);
-    monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"),
-                                         qdict_get_str(chr_dict, "filename"));
+void qemu_chr_fe_close(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_close) {
+        chr->chr_guest_close(chr);
+    }
 }
 
-void qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
+void qemu_chr_delete(CharDriverState *chr)
 {
-    qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
+    QTAILQ_REMOVE(&chardevs, chr, next);
+    if (chr->chr_close)
+        chr->chr_close(chr);
+    g_free(chr->filename);
+    g_free(chr->label);
+    g_free(chr);
 }
 
-/**
- * qemu_chr_info(): Character devices information
- *
- * Each device is represented by a QDict. The returned QObject is a QList
- * of all devices.
- *
- * The QDict contains the following:
- *
- * - "label": device's label
- * - "filename": device's file
- *
- * Example:
- *
- * [ { "label": "monitor", "filename", "stdio" },
- *   { "label": "serial0", "filename": "vc" } ]
- */
-void qemu_chr_info(Monitor *mon, QObject **ret_data)
+ChardevInfoList *qmp_query_chardev(Error **errp)
 {
-    QList *chr_list;
+    ChardevInfoList *chr_list = NULL;
     CharDriverState *chr;
 
-    chr_list = qlist_new();
-
     QTAILQ_FOREACH(chr, &chardevs, next) {
-        QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }",
-                                          chr->label, chr->filename);
-        qlist_append_obj(chr_list, obj);
+        ChardevInfoList *info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->label = g_strdup(chr->label);
+        info->value->filename = g_strdup(chr->filename);
+
+        info->next = chr_list;
+        chr_list = info;
     }
 
-    *ret_data = QOBJECT(chr_list);
+    return chr_list;
 }
 
 CharDriverState *qemu_chr_find(const char *name)