All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
@ 2016-12-12 22:42 Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 01/54] gtk: avoid oob array access Marc-André Lureau
                   ` (55 more replies)
  0 siblings, 56 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Hi,

This is a followup of the series "char: fixes and improvements", where
I started to refactor a bit the code to allow qom-ification. Paolo
quickly reviewed some of those patches already.

qemu-char.c is quite a large file (~130k, 5000 loc) with may chardev
and a lot of #ifdef. It doesn't use qemu Object. Using Object
hopefully brings cleaner, more consitent code base. It helps to split
the various backends in different files. Eventually, we could also
allow or switch to -object-add interface.

Note: this series has been tested with Linux and cross-building with
mingw. It mostly breaks on other platforms, help welcome for
testing. I'd also like to write more chardev backend tests to ensure
no regression (test-char.c is quite limited for now)

Comments and testing welcome!

Marc-André Lureau (54):
  gtk: avoid oob array access
  char: use a const CharDriver
  char: use a static array for backends
  char: move callbacks in CharDriver
  char: fold single-user functions in caller
  char: introduce generic qemu_chr_get_kind()
  char: use a feature bit for replay
  char: allocate CharDriverState as a single object
  bt: use qemu_chr_alloc()
  char: rename CharDriverState Chardev
  char: rename TCPChardev and NetChardev
  spice-char: improve error reporting
  char: use error_report()
  gtk: overwrite the console.c char driver
  chardev: qom-ify
  spice-qemu-char: convert to finalize
  baum: convert to finalize
  msmouse: convert to finalize
  mux: convert to finalize
  char-udp: convert to finalize
  char-socket: convert to finalize
  char-pty: convert to finalize
  char-ringbuf: convert to finalize
  char-parallel: convert parallel to finalize
  char-stdio: convert to finalize
  char-win-stdio: convert to finalize
  char-win: do not override chr_free
  char-win: convert to finalize
  char-fd: convert to finalize
  char: remove chr_free
  char: get rid of CharDriver
  char: remove class kind field
  char: move to chardev/
  char: create chardev-obj-y
  char: make null_chr_write() the default method
  char: move null chardev to its own file
  char: move mux to its own file
  char: move ringbuf/memory to its own file
  char: rename and move to header CHR_READ_BUF_LEN
  char: remove unused READ_RETRIES
  char: move QIOChannel-related in char-io.h
  char: move fd chardev in its own file
  char: move win chardev base class in its own file
  char: move win-stdio into its own file
  char: move socket chardev to itw own file
  char: move udp chardev in its own file
  char: move file chardev in its own file
  char: move stdio in its own file
  char: move console in its own file
  char: move pipe chardev in its own file
  char: move pty chardev in its own file
  char: move serial chardev to itw own file
  char: move parallel chardev in its own file
  char: headers clean-up

 backends/baum.c                   |   97 +-
 backends/msmouse.c                |   72 +-
 backends/rng-egd.c                |    4 +-
 backends/testdev.c                |   48 +-
 chardev/char-console.c            |   30 +
 chardev/char-fd.c                 |  147 ++
 chardev/char-file.c               |  115 +
 chardev/char-io.c                 |  168 ++
 chardev/char-mux.c                |  332 +++
 chardev/char-null.c               |   31 +
 chardev/char-parallel.c           |  292 +++
 chardev/char-pipe.c               |  167 ++
 chardev/char-pty.c                |  277 +++
 chardev/char-ringbuf.c            |  225 ++
 chardev/char-serial.c             |  294 +++
 chardev/char-socket.c             |  995 ++++++++
 chardev/char-stdio.c              |  140 ++
 chardev/char-udp.c                |  211 ++
 chardev/char-win-stdio.c          |  243 ++
 chardev/char-win.c                |  245 ++
 chardev/char.c                    | 1311 ++++++++++
 gdbstub.c                         |   39 +-
 hw/arm/fsl-imx25.c                |    2 +-
 hw/arm/fsl-imx31.c                |    2 +-
 hw/arm/fsl-imx6.c                 |    2 +-
 hw/arm/nseries.c                  |    2 +-
 hw/arm/omap2.c                    |    2 +-
 hw/arm/pxa2xx.c                   |    2 +-
 hw/arm/virt.c                     |    2 +-
 hw/bt/hci-csr.c                   |   63 +-
 hw/char/escc.c                    |    2 +-
 hw/char/exynos4210_uart.c         |    2 +-
 hw/char/imx_serial.c              |    2 +-
 hw/char/mcf_uart.c                |    4 +-
 hw/char/omap_uart.c               |    6 +-
 hw/char/parallel.c                |    2 +-
 hw/char/serial-isa.c              |    2 +-
 hw/char/serial.c                  |    4 +-
 hw/char/sh_serial.c               |    2 +-
 hw/char/spapr_vty.c               |    2 +-
 hw/char/virtio-console.c          |    2 +-
 hw/core/qdev-properties-system.c  |    4 +-
 hw/display/milkymist-tmu2.c       |    2 +-
 hw/display/sm501.c                |    2 +-
 hw/isa/isa-bus.c                  |    2 +-
 hw/isa/pc87312.c                  |    2 +-
 hw/mips/mips_malta.c              |    4 +-
 hw/misc/ivshmem.c                 |    2 +-
 hw/misc/milkymist-pfpu.c          |    2 +-
 hw/usb/ccid-card-passthru.c       |    2 +-
 hw/usb/dev-serial.c               |    6 +-
 hw/usb/redirect.c                 |    4 +-
 monitor.c                         |    6 +-
 net/colo-compare.c                |    4 +-
 net/filter-mirror.c               |    4 +-
 net/slirp.c                       |    2 +-
 net/vhost-user.c                  |   10 +-
 qemu-char.c                       | 4956 -------------------------------------
 qmp.c                             |    2 +-
 qtest.c                           |    2 +-
 replay/replay-char.c              |    8 +-
 spice-qemu-char.c                 |  221 +-
 stubs/get-next-serial.c           |    2 +-
 stubs/monitor-init.c              |    2 +-
 stubs/replay.c                    |    4 +-
 tests/test-char.c                 |   10 +-
 tests/vhost-user-test.c           |    4 +-
 ui/console.c                      |  104 +-
 ui/gtk.c                          |   82 +-
 vl.c                              |   12 +-
 xen-common-stub.c                 |    2 +-
 xen-common.c                      |    4 +-
 Makefile                          |    3 +-
 Makefile.objs                     |    4 +-
 Makefile.target                   |    3 +
 chardev/Makefile.objs             |   17 +
 tests/Makefile.include            |    6 +-
 MAINTAINERS                       |    2 +-
 chardev/char-fd.h                 |   21 +
 chardev/char-io.h                 |   24 +
 chardev/char-mux.h                |   40 +
 chardev/char-parallel.h           |    9 +
 chardev/char-serial.h             |   12 +
 chardev/char-win-stdio.h          |    6 +
 chardev/char-win.h                |   30 +
 hw/lm32/lm32.h                    |    4 +-
 hw/lm32/milkymist-hw.h            |    2 +-
 include/hw/arm/exynos4210.h       |    2 +-
 include/hw/arm/omap.h             |    6 +-
 include/hw/bt.h                   |    4 +-
 include/hw/char/cadence_uart.h    |    2 +-
 include/hw/char/escc.h            |    2 +-
 include/hw/char/pl011.h           |    4 +-
 include/hw/char/serial.h          |    4 +-
 include/hw/char/xilinx_uartlite.h |    2 +-
 include/hw/cris/etraxfs.h         |    2 +-
 include/hw/devices.h              |    2 +-
 include/hw/i386/pc.h              |    2 +-
 include/hw/m68k/mcf.h             |    4 +-
 include/hw/ppc/spapr_vio.h        |    2 +-
 include/hw/qdev-properties.h      |    2 +-
 include/hw/sh4/sh.h               |    2 +-
 include/hw/sparc/grlib.h          |    2 +-
 include/hw/xen/xen.h              |    2 +-
 include/monitor/monitor.h         |    2 +-
 include/qemu/typedefs.h           |    2 +-
 include/sysemu/char.h             |  153 +-
 include/sysemu/replay.h           |    4 +-
 include/sysemu/sysemu.h           |    4 +-
 include/ui/console.h              |    2 +
 include/ui/gtk.h                  |    2 +-
 include/ui/qemu-spice.h           |    2 +-
 112 files changed, 6008 insertions(+), 5455 deletions(-)
 create mode 100644 chardev/char-console.c
 create mode 100644 chardev/char-fd.c
 create mode 100644 chardev/char-file.c
 create mode 100644 chardev/char-io.c
 create mode 100644 chardev/char-mux.c
 create mode 100644 chardev/char-null.c
 create mode 100644 chardev/char-parallel.c
 create mode 100644 chardev/char-pipe.c
 create mode 100644 chardev/char-pty.c
 create mode 100644 chardev/char-ringbuf.c
 create mode 100644 chardev/char-serial.c
 create mode 100644 chardev/char-socket.c
 create mode 100644 chardev/char-stdio.c
 create mode 100644 chardev/char-udp.c
 create mode 100644 chardev/char-win-stdio.c
 create mode 100644 chardev/char-win.c
 create mode 100644 chardev/char.c
 delete mode 100644 qemu-char.c
 create mode 100644 chardev/Makefile.objs
 create mode 100644 chardev/char-fd.h
 create mode 100644 chardev/char-io.h
 create mode 100644 chardev/char-mux.h
 create mode 100644 chardev/char-parallel.h
 create mode 100644 chardev/char-serial.h
 create mode 100644 chardev/char-win-stdio.h
 create mode 100644 chardev/char-win.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 01/54] gtk: avoid oob array access
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 02/54] char: use a const CharDriver Marc-André Lureau
                   ` (54 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

When too many consoles are created, vcs[] may be write out-of-bounds.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 ui/gtk.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ui/gtk.c b/ui/gtk.c
index e81642876a..67c52179ee 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1696,6 +1696,11 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
     ChardevCommon *common = qapi_ChardevVC_base(vc);
     CharDriverState *chr;
 
+    if (nb_vcs == MAX_VCS) {
+        error_setg(errp, "Maximum number of consoles reached");
+        return NULL;
+    }
+
     chr = qemu_chr_alloc(common, errp);
     if (!chr) {
         return NULL;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 02/54] char: use a const CharDriver
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 01/54] gtk: avoid oob array access Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-13 23:11   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 03/54] char: use a static array for backends Marc-André Lureau
                   ` (53 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

No need to allocate & copy fileds, let's use static const struct
instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |   8 +++-
 backends/msmouse.c    |   7 +++-
 backends/testdev.c    |   7 +++-
 qemu-char.c           | 100 ++++++++++++++++++++++++--------------------------
 spice-qemu-char.c     |  14 +++++--
 ui/console.c          |   9 +++--
 include/sysemu/char.h |  19 +++++-----
 7 files changed, 90 insertions(+), 74 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index b92369d840..a790622867 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -686,8 +686,12 @@ fail_handle:
 
 static void register_types(void)
 {
-    register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL,
-                         chr_baum_init);
+    static const CharDriver driver = {
+        .kind = CHARDEV_BACKEND_KIND_BRAILLE,
+        .parse = NULL, .create = chr_baum_init
+    };
+
+    register_char_driver(&driver);
 }
 
 type_init(register_types);
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 733ca80f48..567000860c 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -179,8 +179,11 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
 
 static void register_types(void)
 {
-    register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL,
-                         qemu_chr_open_msmouse);
+    static const CharDriver driver = {
+        .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
+        .parse = NULL, .create = qemu_chr_open_msmouse
+    };
+    register_char_driver(&driver);
 }
 
 type_init(register_types);
diff --git a/backends/testdev.c b/backends/testdev.c
index 60156e320e..9bd86238d2 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -130,8 +130,11 @@ static CharDriverState *chr_testdev_init(const char *id,
 
 static void register_types(void)
 {
-    register_char_driver("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL,
-                         chr_testdev_init);
+    static const CharDriver driver = {
+        .kind = CHARDEV_BACKEND_KIND_TESTDEV,
+        .parse = NULL, .create = chr_testdev_init
+    };
+    register_char_driver(&driver);
 }
 
 type_init(register_types);
diff --git a/qemu-char.c b/qemu-char.c
index 2c9940cea4..309709cb6d 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -4094,27 +4094,11 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
-typedef struct CharDriver {
-    const char *name;
-    ChardevBackendKind kind;
-    CharDriverParse *parse;
-    CharDriverCreate *create;
-} CharDriver;
-
 static GSList *backends;
 
-void register_char_driver(const char *name, ChardevBackendKind kind,
-                          CharDriverParse *parse, CharDriverCreate *create)
+void register_char_driver(const CharDriver *driver)
 {
-    CharDriver *s;
-
-    s = g_malloc0(sizeof(*s));
-    s->name = g_strdup(name);
-    s->kind = kind;
-    s->parse = parse;
-    s->create = create;
-
-    backends = g_slist_append(backends, s);
+    backends = g_slist_append(backends, (void *)driver);
 }
 
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
@@ -4139,7 +4123,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         fprintf(stderr, "Available chardev backend types:\n");
         for (i = backends; i; i = i->next) {
             cd = i->data;
-            fprintf(stderr, "%s\n", cd->name);
+            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
         }
         exit(!is_help_option(qemu_opt_get(opts, "backend")));
     }
@@ -4152,7 +4136,8 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     for (i = backends; i; i = i->next) {
         cd = i->data;
 
-        if (strcmp(cd->name, qemu_opt_get(opts, "backend")) == 0) {
+        if (strcmp(ChardevBackendKind_lookup[cd->kind],
+                   qemu_opt_get(opts, "backend")) == 0) {
             break;
         }
     }
@@ -4371,7 +4356,7 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
         ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
         c = i->data;
         info->value = g_malloc0(sizeof(*info->value));
-        info->value->name = g_strdup(c->name);
+        info->value->name = g_strdup(ChardevBackendKind_lookup[c->kind]);
 
         info->next = backend_list;
         backend_list = info;
@@ -4907,45 +4892,56 @@ void qemu_chr_cleanup(void)
 
 static void register_types(void)
 {
-    register_char_driver("null", CHARDEV_BACKEND_KIND_NULL, NULL,
-                         qemu_chr_open_null);
-    register_char_driver("socket", CHARDEV_BACKEND_KIND_SOCKET,
-                         qemu_chr_parse_socket, qmp_chardev_open_socket);
-    register_char_driver("udp", CHARDEV_BACKEND_KIND_UDP, qemu_chr_parse_udp,
-                         qmp_chardev_open_udp);
-    register_char_driver("ringbuf", CHARDEV_BACKEND_KIND_RINGBUF,
-                         qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf);
-    register_char_driver("file", CHARDEV_BACKEND_KIND_FILE,
-                         qemu_chr_parse_file_out, qmp_chardev_open_file);
-    register_char_driver("stdio", CHARDEV_BACKEND_KIND_STDIO,
-                         qemu_chr_parse_stdio, qemu_chr_open_stdio);
+    int i;
+    static const CharDriver drivers[] = {
+        { .kind = CHARDEV_BACKEND_KIND_NULL, .parse = NULL,
+          .create = qemu_chr_open_null },
+        { .kind = CHARDEV_BACKEND_KIND_SOCKET,
+          .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket },
+        { .kind = CHARDEV_BACKEND_KIND_UDP, .parse = qemu_chr_parse_udp,
+          .create = qmp_chardev_open_udp },
+        { .kind = CHARDEV_BACKEND_KIND_RINGBUF,
+          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf },
+        { .kind = CHARDEV_BACKEND_KIND_FILE,
+          .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file },
+        { .kind = CHARDEV_BACKEND_KIND_STDIO,
+          .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
 #if defined HAVE_CHARDEV_SERIAL
-    register_char_driver("serial", CHARDEV_BACKEND_KIND_SERIAL,
-                         qemu_chr_parse_serial, qmp_chardev_open_serial);
-    register_char_driver("tty", CHARDEV_BACKEND_KIND_SERIAL,
-                         qemu_chr_parse_serial, qmp_chardev_open_serial);
+        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
+          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
+        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
+          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
-    register_char_driver("parallel", CHARDEV_BACKEND_KIND_PARALLEL,
-                         qemu_chr_parse_parallel, qmp_chardev_open_parallel);
-    register_char_driver("parport", CHARDEV_BACKEND_KIND_PARALLEL,
-                         qemu_chr_parse_parallel, qmp_chardev_open_parallel);
+        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
+          .parse = qemu_chr_parse_parallel,
+          .create = qmp_chardev_open_parallel },
+        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
+          .parse = qemu_chr_parse_parallel,
+          .create = qmp_chardev_open_parallel },
 #endif
 #ifdef HAVE_CHARDEV_PTY
-    register_char_driver("pty", CHARDEV_BACKEND_KIND_PTY, NULL,
-                         qemu_chr_open_pty);
+        { .kind = CHARDEV_BACKEND_KIND_PTY,
+          .parse = NULL, .create = qemu_chr_open_pty },
 #endif
 #ifdef _WIN32
-    register_char_driver("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL,
-                         qemu_chr_open_win_con);
+        { .kind = CHARDEV_BACKEND_KIND_CONSOLE, .parse = NULL,
+          .create = qemu_chr_open_win_con },
 #endif
-    register_char_driver("pipe", CHARDEV_BACKEND_KIND_PIPE,
-                         qemu_chr_parse_pipe, qemu_chr_open_pipe);
-    register_char_driver("mux", CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux,
-                         qemu_chr_open_mux);
-    /* Bug-compatibility: */
-    register_char_driver("memory", CHARDEV_BACKEND_KIND_MEMORY,
-                         qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf);
+        { .kind = CHARDEV_BACKEND_KIND_PIPE,
+          .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe },
+        { .kind = CHARDEV_BACKEND_KIND_MUX, .parse = qemu_chr_parse_mux,
+          .create = qemu_chr_open_mux },
+        /* Bug-compatibility: */
+        { .kind = CHARDEV_BACKEND_KIND_MEMORY,
+          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf },
+    };
+
+
+    for (i = 0; i < ARRAY_SIZE(drivers); i++) {
+        register_char_driver(&drivers[i]);
+    }
+
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
      * is specified
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 276c4aef68..8e9151db5c 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -389,10 +389,16 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
 
 static void register_types(void)
 {
-    register_char_driver("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
-                         qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc);
-    register_char_driver("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
-                         qemu_chr_parse_spice_port, qemu_chr_open_spice_port);
+    static const CharDriver vmc_driver = {
+        .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
+        .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc
+    };
+    static const CharDriver port_driver = {
+        .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
+        .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port
+    };
+    register_char_driver(&vmc_driver);
+    register_char_driver(&port_driver);
 }
 
 type_init(register_types);
diff --git a/ui/console.c b/ui/console.c
index ed888e55ea..764501b363 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2180,12 +2180,15 @@ static const TypeInfo qemu_console_info = {
     .class_size = sizeof(QemuConsoleClass),
 };
 
-
 static void register_types(void)
 {
+    static const CharDriver vc_driver = {
+        .kind = CHARDEV_BACKEND_KIND_VC,
+        .parse = qemu_chr_parse_vc, .create = vc_init
+    };
+
     type_register_static(&qemu_console_info);
-    register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc,
-                         vc_init);
+    register_char_driver(&vc_driver);
 }
 
 type_init(register_types);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 0a149428cf..144514c962 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -473,15 +473,16 @@ void qemu_chr_set_feature(CharDriverState *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
-typedef void CharDriverParse(QemuOpts *opts, ChardevBackend *backend,
-                             Error **errp);
-typedef CharDriverState *CharDriverCreate(const char *id,
-                                          ChardevBackend *backend,
-                                          ChardevReturn *ret, bool *be_opened,
-                                          Error **errp);
-
-void register_char_driver(const char *name, ChardevBackendKind kind,
-                          CharDriverParse *parse, CharDriverCreate *create);
+typedef struct CharDriver {
+    ChardevBackendKind kind;
+    void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
+    CharDriverState *(*create)(const char *id,
+                               ChardevBackend *backend,
+                               ChardevReturn *ret, bool *be_opened,
+                               Error **errp);
+} CharDriver;
+
+void register_char_driver(const CharDriver *driver);
 
 extern int term_escape_char;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 03/54] char: use a static array for backends
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 01/54] gtk: avoid oob array access Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 02/54] char: use a const CharDriver Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-14 14:52   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver Marc-André Lureau
                   ` (52 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Number and kinds of backends is known at compile-time, use a fixed-sized
static array to simplify iterations & lookups.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c           | 101 ++++++++++++++++++++++++++++----------------------
 include/sysemu/char.h |   1 +
 2 files changed, 58 insertions(+), 44 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 309709cb6d..7934d9da7c 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -4094,20 +4094,20 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
-static GSList *backends;
+static const CharDriver *backends[CHARDEV_BACKEND_KIND__MAX];
 
 void register_char_driver(const CharDriver *driver)
 {
-    backends = g_slist_append(backends, (void *)driver);
+    backends[driver->kind] = driver;
 }
 
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                         Error **errp)
 {
     Error *local_err = NULL;
-    CharDriver *cd;
+    const CharDriver *cd;
     CharDriverState *chr;
-    GSList *i;
+    int i;
     ChardevReturn *ret = NULL;
     ChardevBackend *backend;
     const char *id = qemu_opts_id(opts);
@@ -4121,9 +4121,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
 
     if (is_help_option(qemu_opt_get(opts, "backend"))) {
         fprintf(stderr, "Available chardev backend types:\n");
-        for (i = backends; i; i = i->next) {
-            cd = i->data;
-            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
+        for (i = 0; i < ARRAY_SIZE(backends); i++) {
+            cd = backends[i];
+            if (cd) {
+                fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
+                if (cd->alias) {
+                    fprintf(stderr, "%s\n", cd->alias);
+                }
+            }
         }
         exit(!is_help_option(qemu_opt_get(opts, "backend")));
     }
@@ -4133,15 +4138,20 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         goto err;
     }
 
-    for (i = backends; i; i = i->next) {
-        cd = i->data;
+    cd = NULL;
+    for (i = 0; i < ARRAY_SIZE(backends); i++) {
+        const char *name = qemu_opt_get(opts, "backend");
+        cd = backends[i];
 
-        if (strcmp(ChardevBackendKind_lookup[cd->kind],
-                   qemu_opt_get(opts, "backend")) == 0) {
+        if (!cd) {
+            continue;
+        }
+        if (g_str_equal(ChardevBackendKind_lookup[cd->kind], name) ||
+            (cd->alias && g_str_equal(cd->alias, name))) {
             break;
         }
     }
-    if (i == NULL) {
+    if (cd == NULL) {
         error_setg(errp, "chardev: backend \"%s\" not found",
                    qemu_opt_get(opts, "backend"));
         goto err;
@@ -4346,20 +4356,35 @@ ChardevInfoList *qmp_query_chardev(Error **errp)
     return chr_list;
 }
 
+static ChardevBackendInfoList *
+qmp_prepend_backend(ChardevBackendInfoList *list, const CharDriver *c,
+                    const char *name)
+{
+    ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
+    info->value = g_malloc0(sizeof(*info->value));
+    info->value->name = g_strdup(name);
+    info->next = list;
+    return info;
+
+}
+
 ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
 {
     ChardevBackendInfoList *backend_list = NULL;
-    CharDriver *c = NULL;
-    GSList *i = NULL;
+    const CharDriver *c;
+    int i;
 
-    for (i = backends; i; i = i->next) {
-        ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
-        c = i->data;
-        info->value = g_malloc0(sizeof(*info->value));
-        info->value->name = g_strdup(ChardevBackendKind_lookup[c->kind]);
+    for (i = 0; i < ARRAY_SIZE(backends); i++) {
+        c = backends[i];
+        if (!c) {
+            continue;
+        }
 
-        info->next = backend_list;
-        backend_list = info;
+        backend_list = qmp_prepend_backend(backend_list, c,
+                                           ChardevBackendKind_lookup[c->kind]);
+        if (c->alias) {
+            backend_list = qmp_prepend_backend(backend_list, c, c->alias);
+        }
     }
 
     return backend_list;
@@ -4815,9 +4840,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
 {
     ChardevReturn *ret = g_new0(ChardevReturn, 1);
     CharDriverState *chr = NULL;
+    const CharDriver *cd;
     Error *local_err = NULL;
-    GSList *i;
-    CharDriver *cd;
     bool be_opened = true;
 
     chr = qemu_chr_find(id);
@@ -4826,22 +4850,16 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         goto out_error;
     }
 
-    for (i = backends; i; i = i->next) {
-        cd = i->data;
-
-        if (cd->kind == backend->type) {
-            chr = cd->create(id, backend, ret, &be_opened, &local_err);
-            if (local_err) {
-                error_propagate(errp, local_err);
-                goto out_error;
-            }
-            break;
-        }
+    cd = (int)backend->type >= 0 && backend->type < ARRAY_SIZE(backends) ?
+        backends[backend->type] : NULL;
+    if (cd == NULL) {
+        error_setg(errp, "chardev backend not available");
+        goto out_error;
     }
 
-    if (chr == NULL) {
-        assert(!i);
-        error_setg(errp, "chardev backend not available");
+    chr = cd->create(id, backend, ret, &be_opened, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         goto out_error;
     }
 
@@ -4907,16 +4925,11 @@ static void register_types(void)
         { .kind = CHARDEV_BACKEND_KIND_STDIO,
           .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
 #if defined HAVE_CHARDEV_SERIAL
-        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
-          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
-        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
+        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
           .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
-        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
-          .parse = qemu_chr_parse_parallel,
-          .create = qmp_chardev_open_parallel },
-        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
+        { .kind = CHARDEV_BACKEND_KIND_PARALLEL, .alias = "parport",
           .parse = qemu_chr_parse_parallel,
           .create = qmp_chardev_open_parallel },
 #endif
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 144514c962..c8750ede21 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -474,6 +474,7 @@ void qemu_chr_set_feature(CharDriverState *chr,
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
 typedef struct CharDriver {
+    const char *alias;
     ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
     CharDriverState *(*create)(const char *id,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (2 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 03/54] char: use a static array for backends Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-14 16:02   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller Marc-André Lureau
                   ` (51 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This makes the code more declarative, and avoids to duplicate the
information on all instances.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |  13 +-
 backends/msmouse.c    |  13 +-
 backends/testdev.c    |  10 +-
 gdbstub.c             |   7 +-
 hw/bt/hci-csr.c       |   8 +-
 qemu-char.c           | 427 +++++++++++++++++++++++++++++++-------------------
 spice-qemu-char.c     |  36 +++--
 ui/console.c          |  26 +--
 ui/gtk.c              |  11 +-
 include/sysemu/char.h |  46 +++---
 10 files changed, 370 insertions(+), 227 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index a790622867..ef6178993a 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -637,7 +637,8 @@ static void baum_free(struct CharDriverState *chr)
     g_free(baum);
 }
 
-static CharDriverState *chr_baum_init(const char *id,
+static CharDriverState *chr_baum_init(const CharDriver *driver,
+                                      const char *id,
                                       ChardevBackend *backend,
                                       ChardevReturn *ret,
                                       bool *be_opened,
@@ -648,7 +649,7 @@ static CharDriverState *chr_baum_init(const char *id,
     CharDriverState *chr;
     brlapi_handle_t *handle;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -656,9 +657,6 @@ static CharDriverState *chr_baum_init(const char *id,
     baum->chr = chr;
 
     chr->opaque = baum;
-    chr->chr_write = baum_write;
-    chr->chr_accept_input = baum_accept_input;
-    chr->chr_free = baum_free;
 
     handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
@@ -688,7 +686,10 @@ static void register_types(void)
 {
     static const CharDriver driver = {
         .kind = CHARDEV_BACKEND_KIND_BRAILLE,
-        .parse = NULL, .create = chr_baum_init
+        .parse = NULL, .create = chr_baum_init,
+        .chr_write = baum_write,
+        .chr_accept_input = baum_accept_input,
+        .chr_free = baum_free,
     };
 
     register_char_driver(&driver);
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 567000860c..a2f9f7a235 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -148,7 +148,8 @@ static QemuInputHandler msmouse_handler = {
     .sync  = msmouse_input_sync,
 };
 
-static CharDriverState *qemu_chr_open_msmouse(const char *id,
+static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
+                                              const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
                                               bool *be_opened,
@@ -158,13 +159,10 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
     MouseState *mouse;
     CharDriverState *chr;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    chr->chr_write = msmouse_chr_write;
-    chr->chr_free = msmouse_chr_free;
-    chr->chr_accept_input = msmouse_chr_accept_input;
     *be_opened = false;
 
     mouse = g_new0(MouseState, 1);
@@ -181,7 +179,10 @@ static void register_types(void)
 {
     static const CharDriver driver = {
         .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
-        .parse = NULL, .create = qemu_chr_open_msmouse
+        .parse = NULL, .create = qemu_chr_open_msmouse,
+        .chr_write = msmouse_chr_write,
+        .chr_accept_input = msmouse_chr_accept_input,
+        .chr_free = msmouse_chr_free,
     };
     register_char_driver(&driver);
 }
diff --git a/backends/testdev.c b/backends/testdev.c
index 9bd86238d2..92aefe9f8a 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -109,7 +109,8 @@ static void testdev_free(struct CharDriverState *chr)
     g_free(testdev);
 }
 
-static CharDriverState *chr_testdev_init(const char *id,
+static CharDriverState *chr_testdev_init(const CharDriver *driver,
+                                         const char *id,
                                          ChardevBackend *backend,
                                          ChardevReturn *ret,
                                          bool *be_opened,
@@ -121,9 +122,8 @@ static CharDriverState *chr_testdev_init(const char *id,
     testdev = g_new0(TestdevCharState, 1);
     testdev->chr = chr = g_new0(CharDriverState, 1);
 
+    chr->driver = driver;
     chr->opaque = testdev;
-    chr->chr_write = testdev_write;
-    chr->chr_free = testdev_free;
 
     return chr;
 }
@@ -132,7 +132,9 @@ static void register_types(void)
 {
     static const CharDriver driver = {
         .kind = CHARDEV_BACKEND_KIND_TESTDEV,
-        .parse = NULL, .create = chr_testdev_init
+        .parse = NULL, .create = chr_testdev_init,
+        .chr_write = testdev_write,
+        .chr_free = testdev_free,
     };
     register_char_driver(&driver);
 }
diff --git a/gdbstub.c b/gdbstub.c
index de62d26096..5dfba33eb9 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1730,6 +1730,10 @@ int gdbserver_start(const char *device)
     CharDriverState *chr = NULL;
     CharDriverState *mon_chr;
     ChardevCommon common = { 0 };
+    static const CharDriver driver = {
+        .kind = -1,
+        .chr_write = gdb_monitor_write
+    };
 
     if (!device)
         return -1;
@@ -1762,8 +1766,7 @@ int gdbserver_start(const char *device)
         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
 
         /* Initialize a monitor terminal for gdb */
-        mon_chr = qemu_chr_alloc(&common, &error_abort);
-        mon_chr->chr_write = gdb_monitor_write;
+        mon_chr = qemu_chr_alloc(&driver, &common, &error_abort);
         monitor_init(mon_chr, 0);
     } else {
         if (qemu_chr_fe_get_driver(&s->chr)) {
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index fbb3109cc1..9c3fb3c8f9 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -462,12 +462,16 @@ qemu_irq *csrhci_pins_get(CharDriverState *chr)
 
 CharDriverState *uart_hci_init(void)
 {
+    static const CharDriver hci_driver = {
+        .kind = -1,
+        .chr_write = csrhci_write,
+        .chr_ioctl = csrhci_ioctl,
+    };
     struct csrhci_s *s = (struct csrhci_s *)
             g_malloc0(sizeof(struct csrhci_s));
 
     s->chr.opaque = s;
-    s->chr.chr_write = csrhci_write;
-    s->chr.chr_ioctl = csrhci_ioctl;
+    s->chr.driver = &hci_driver;
 
     s->hci = qemu_next_hci();
     s->hci->opaque = s;
diff --git a/qemu-char.c b/qemu-char.c
index 7934d9da7c..a81b61491a 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -162,11 +162,15 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
 
 static void qemu_chr_free_common(CharDriverState *chr);
 
-CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp)
+CharDriverState *qemu_chr_alloc(const CharDriver *driver,
+                                ChardevCommon *backend, Error **errp)
 {
     CharDriverState *chr = g_malloc0(sizeof(CharDriverState));
     qemu_mutex_init(&chr->chr_write_lock);
 
+    assert(driver);
+    assert(driver->chr_write);
+
     if (backend->has_logfile) {
         int flags = O_WRONLY | O_CREAT;
         if (backend->has_logappend &&
@@ -186,6 +190,7 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp)
     } else {
         chr->logfd = -1;
     }
+    chr->driver = driver;
 
     return chr;
 }
@@ -252,7 +257,7 @@ static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int
     qemu_mutex_lock(&s->chr_write_lock);
     while (*offset < len) {
     retry:
-        res = s->chr_write(s, buf + *offset, len - *offset);
+        res = s->driver->chr_write(s, buf + *offset, len - *offset);
         if (res < 0 && errno == EAGAIN) {
             g_usleep(100);
             goto retry;
@@ -290,7 +295,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
     }
 
     qemu_mutex_lock(&s->chr_write_lock);
-    ret = s->chr_write(s, buf, len);
+    ret = s->driver->chr_write(s, buf, len);
 
     if (ret > 0) {
         qemu_chr_fe_write_log(s, buf, ret);
@@ -346,7 +351,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
     int offset = 0, counter = 10;
     int res;
 
-    if (!s || !s->chr_sync_read) {
+    if (!s || !s->driver->chr_sync_read) {
         return 0;
     }
 
@@ -356,7 +361,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
 
     while (offset < len) {
     retry:
-        res = s->chr_sync_read(s, buf + offset, len - offset);
+        res = s->driver->chr_sync_read(s, buf + offset, len - offset);
         if (res == -1 && errno == EAGAIN) {
             g_usleep(100);
             goto retry;
@@ -391,10 +396,10 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
     CharDriverState *s = be->chr;
     int res;
 
-    if (!s || !s->chr_ioctl || s->replay) {
+    if (!s || !s->driver->chr_ioctl || s->replay) {
         res = -ENOTSUP;
     } else {
-        res = s->chr_ioctl(s, cmd, arg);
+        res = s->driver->chr_ioctl(s, cmd, arg);
     }
 
     return res;
@@ -453,7 +458,7 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
         return -1;
     }
 
-    return s->get_msgfds ? s->get_msgfds(s, fds, len) : -1;
+    return s->driver->get_msgfds ? s->driver->get_msgfds(s, fds, len) : -1;
 }
 
 int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
@@ -464,12 +469,12 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
         return -1;
     }
 
-    return s->set_msgfds ? s->set_msgfds(s, fds, num) : -1;
+    return s->driver->set_msgfds ? s->driver->set_msgfds(s, fds, num) : -1;
 }
 
 int qemu_chr_add_client(CharDriverState *s, int fd)
 {
-    return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
+    return s->driver->chr_add_client ? s->driver->chr_add_client(s, fd) : -1;
 }
 
 void qemu_chr_fe_accept_input(CharBackend *be)
@@ -480,8 +485,9 @@ void qemu_chr_fe_accept_input(CharBackend *be)
         return;
     }
 
-    if (s->chr_accept_input)
-        s->chr_accept_input(s);
+    if (s->driver->chr_accept_input) {
+        s->driver->chr_accept_input(s);
+    }
     qemu_notify_event();
 }
 
@@ -506,7 +512,8 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(const char *id,
+static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
+                                           const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
                                            bool *be_opened,
@@ -515,15 +522,19 @@ static CharDriverState *qemu_chr_open_null(const char *id,
     CharDriverState *chr;
     ChardevCommon *common = backend->u.null.data;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    chr->chr_write = null_chr_write;
     *be_opened = false;
     return chr;
 }
 
+static const CharDriver null_driver = {
+    .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,
+    .chr_write = null_chr_write
+};
+
 /* MUX driver for serial I/O splitting */
 #define MAX_MUX 4
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
@@ -795,7 +806,11 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
     MuxDriver *d = s->opaque;
     CharDriverState *chr = qemu_chr_fe_get_driver(&d->chr);
 
-    return chr->chr_add_watch(chr, cond);
+    if (!chr->driver->chr_add_watch) {
+        return NULL;
+    }
+
+    return chr->driver->chr_add_watch(chr, cond);
 }
 
 static void mux_chr_free(struct CharDriverState *chr)
@@ -839,7 +854,8 @@ static void mux_set_focus(MuxDriver *d, int focus)
     mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
 }
 
-static CharDriverState *qemu_chr_open_mux(const char *id,
+static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
+                                          const char *id,
                                           ChardevBackend *backend,
                                           ChardevReturn *ret,
                                           bool *be_opened,
@@ -856,7 +872,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
         return NULL;
     }
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -864,14 +880,6 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
 
     chr->opaque = d;
     d->focus = -1;
-    chr->chr_free = mux_chr_free;
-    chr->chr_write = mux_chr_write;
-    chr->chr_accept_input = mux_chr_accept_input;
-    /* Frontend guest-open / -close notification is not support with muxes */
-    chr->chr_set_fe_open = NULL;
-    if (drv->chr_add_watch) {
-        chr->chr_add_watch = mux_chr_add_watch;
-    }
     /* only default to opened state if we've realized the initial
      * set of muxes
      */
@@ -970,8 +978,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
     b->chr_read = fd_read;
     b->chr_event = fd_event;
     b->opaque = opaque;
-    if (s->chr_update_read_handler) {
-        s->chr_update_read_handler(s, context);
+    if (s->driver->chr_update_read_handler) {
+        s->driver->chr_update_read_handler(s, context);
     }
 
     if (set_open) {
@@ -1266,14 +1274,15 @@ static void fd_chr_free(struct CharDriverState *chr)
 }
 
 /* open a character device to a unix fd */
-static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out,
+static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
+                                         int fd_in, int fd_out,
                                          ChardevCommon *backend, Error **errp)
 {
     CharDriverState *chr;
     FDCharDriver *s;
     char *name;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
@@ -1289,15 +1298,12 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out,
     qemu_set_nonblock(fd_out);
     s->chr = chr;
     chr->opaque = s;
-    chr->chr_add_watch = fd_chr_add_watch;
-    chr->chr_write = fd_chr_write;
-    chr->chr_update_read_handler = fd_chr_update_read_handler;
-    chr->chr_free = fd_chr_free;
 
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_pipe(const char *id,
+static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
+                                           const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
                                            bool *be_opened,
@@ -1328,7 +1334,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
             return NULL;
         }
     }
-    return qemu_chr_open_fd(fd_in, fd_out, common, errp);
+    return qemu_chr_open_fd(driver, fd_in, fd_out, common, errp);
 }
 
 /* init terminal so that we can grab keys */
@@ -1380,7 +1386,8 @@ static void qemu_chr_free_stdio(struct CharDriverState *chr)
     fd_chr_free(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(const char *id,
+static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
+                                            const char *id,
                                             ChardevBackend *backend,
                                             ChardevReturn *ret,
                                             bool *be_opened,
@@ -1411,12 +1418,10 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     act.sa_handler = term_stdio_handler;
     sigaction(SIGCONT, &act, NULL);
 
-    chr = qemu_chr_open_fd(0, 1, common, errp);
+    chr = qemu_chr_open_fd(driver, 0, 1, common, errp);
     if (!chr) {
         return NULL;
     }
-    chr->chr_free = qemu_chr_free_stdio;
-    chr->chr_set_echo = qemu_chr_set_echo_stdio;
     if (opts->has_signal) {
         stdio_allow_signal = opts->signal;
     }
@@ -1633,7 +1638,8 @@ static void pty_chr_free(struct CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(const char *id,
+static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
+                                          const char *id,
                                           ChardevBackend *backend,
                                           ChardevReturn *ret,
                                           bool *be_opened,
@@ -1655,7 +1661,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
     close(slave_fd);
     qemu_set_nonblock(master_fd);
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         close(master_fd);
         return NULL;
@@ -1670,10 +1676,6 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
 
     s = g_new0(PtyCharDriver, 1);
     chr->opaque = s;
-    chr->chr_write = pty_chr_write;
-    chr->chr_update_read_handler = pty_chr_update_read_handler;
-    chr->chr_free = pty_chr_free;
-    chr->chr_add_watch = pty_chr_add_watch;
     *be_opened = false;
 
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
@@ -1685,6 +1687,14 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
     return chr;
 }
 
+static const CharDriver pty_driver = {
+    .kind = CHARDEV_BACKEND_KIND_PTY, .create = qemu_chr_open_pty,
+    .chr_write = pty_chr_write,
+    .chr_update_read_handler = pty_chr_update_read_handler,
+    .chr_add_watch = pty_chr_add_watch,
+    .chr_free = pty_chr_free,
+};
+
 static void tty_serial_init(int fd, int speed,
                             int parity, int data_bits, int stop_bits)
 {
@@ -1875,7 +1885,8 @@ static void qemu_chr_free_tty(CharDriverState *chr)
     fd_chr_free(chr);
 }
 
-static CharDriverState *qemu_chr_open_tty_fd(int fd,
+static CharDriverState *qemu_chr_open_tty_fd(const CharDriver *driver,
+                                             int fd,
                                              ChardevCommon *backend,
                                              bool *be_opened,
                                              Error **errp)
@@ -1883,12 +1894,10 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd,
     CharDriverState *chr;
 
     tty_serial_init(fd, 115200, 'N', 8, 1);
-    chr = qemu_chr_open_fd(fd, fd, backend, errp);
+    chr = qemu_chr_open_fd(driver, fd, fd, backend, errp);
     if (!chr) {
         return NULL;
     }
-    chr->chr_ioctl = tty_serial_ioctl;
-    chr->chr_free = qemu_chr_free_tty;
     return chr;
 }
 #endif /* __linux__ || __sun__ */
@@ -2006,7 +2015,8 @@ static void pp_free(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(int fd,
+static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
+                                            int fd,
                                             ChardevCommon *backend,
                                             bool *be_opened,
                                             Error **errp)
@@ -2020,16 +2030,13 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd,
         return NULL;
     }
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
 
     drv = g_new0(ParallelCharDriver, 1);
     chr->opaque = drv;
-    chr->chr_write = null_chr_write;
-    chr->chr_ioctl = pp_ioctl;
-    chr->chr_free = pp_free;
 
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
@@ -2079,20 +2086,19 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(int fd,
+static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
+                                            int fd,
                                             ChardevCommon *backend,
                                             bool *be_opened,
                                             Error **errp)
 {
     CharDriverState *chr;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
     chr->opaque = (void *)(intptr_t)fd;
-    chr->chr_write = null_chr_write;
-    chr->chr_ioctl = pp_ioctl;
     *be_opened = false;
     return chr;
 }
@@ -2314,21 +2320,20 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_path(const char *filename,
+static CharDriverState *qemu_chr_open_win_path(const CharDriver *driver,
+                                               const char *filename,
                                                ChardevCommon *backend,
                                                Error **errp)
 {
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
     s = g_new0(WinCharState, 1);
     chr->opaque = s;
-    chr->chr_write = win_chr_write;
-    chr->chr_free = win_chr_free;
 
     if (win_chr_init(chr, filename, errp) < 0) {
         g_free(s);
@@ -2419,7 +2424,8 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
 }
 
 
-static CharDriverState *qemu_chr_open_pipe(const char *id,
+static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
+                                           const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
                                            bool *be_opened,
@@ -2431,14 +2437,12 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
     WinCharState *s;
     ChardevCommon *common = qapi_ChardevHostdev_base(opts);
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
     s = g_new0(WinCharState, 1);
     chr->opaque = s;
-    chr->chr_write = win_chr_write;
-    chr->chr_free = win_chr_free;
 
     if (win_chr_pipe_init(chr, filename, errp) < 0) {
         g_free(s);
@@ -2448,35 +2452,42 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out,
+static CharDriverState *qemu_chr_open_win_file(const CharDriver *driver,
+                                               HANDLE fd_out,
                                                ChardevCommon *backend,
                                                Error **errp)
 {
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
     s = g_new0(WinCharState, 1);
     s->hcom = fd_out;
     chr->opaque = s;
-    chr->chr_write = win_chr_write;
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_con(const char *id,
+static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
+                                              const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
                                               bool *be_opened,
                                               Error **errp)
 {
     ChardevCommon *common = backend->u.console.data;
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE),
+    return qemu_chr_open_win_file(driver,
+                                  GetStdHandle(STD_OUTPUT_HANDLE),
                                   common, errp);
 }
 
+static const CharDriver console_driver = {
+    .kind = CHARDEV_BACKEND_KIND_CONSOLE, .create = qemu_chr_open_win_con,
+    .chr_write = win_chr_write,
+};
+
 static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -2612,7 +2623,8 @@ static void win_stdio_free(CharDriverState *chr)
     g_free(chr->opaque);
 }
 
-static CharDriverState *qemu_chr_open_stdio(const char *id,
+static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
+                                            const char *id,
                                             ChardevBackend *backend,
                                             ChardevReturn *ret,
                                             bool *be_opened,
@@ -2624,7 +2636,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     int                is_console = 0;
     ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data);
 
-    chr   = qemu_chr_alloc(common, errp);
+    chr   = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -2639,8 +2651,6 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
 
     chr->opaque    = stdio;
-    chr->chr_write = win_stdio_write;
-    chr->chr_free = win_stdio_free;
 
     if (is_console) {
         if (qemu_add_wait_object(stdio->hStdIn,
@@ -2682,7 +2692,6 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
 
     SetConsoleMode(stdio->hStdIn, dwMode);
 
-    chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
     qemu_chr_set_echo_win_stdio(chr, false);
 
     return chr;
@@ -2789,7 +2798,8 @@ static void udp_chr_free(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
+static CharDriverState *qemu_chr_open_udp(const CharDriver *driver,
+                                          QIOChannelSocket *sioc,
                                           ChardevCommon *backend,
                                           bool *be_opened,
                                           Error **errp)
@@ -2797,7 +2807,7 @@ static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
@@ -2807,9 +2817,6 @@ static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
     s->bufcnt = 0;
     s->bufptr = 0;
     chr->opaque = s;
-    chr->chr_write = udp_chr_write;
-    chr->chr_update_read_handler = udp_chr_update_read_handler;
-    chr->chr_free = udp_chr_free;
     /* be isn't opened until we get a connection */
     *be_opened = false;
     return chr;
@@ -3444,8 +3451,8 @@ static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
 
 static int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
 {
-    if (chr->chr_wait_connected) {
-        return chr->chr_wait_connected(chr, errp);
+    if (chr->driver->chr_wait_connected) {
+        return chr->driver->chr_wait_connected(chr, errp);
     }
 
     return 0;
@@ -3565,7 +3572,8 @@ static void ringbuf_chr_free(struct CharDriverState *chr)
     chr->opaque = NULL;
 }
 
-static CharDriverState *qemu_chr_open_ringbuf(const char *id,
+static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
+                                              const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
                                               bool *be_opened,
@@ -3576,7 +3584,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id,
     CharDriverState *chr;
     RingBufCharDriver *d;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -3595,8 +3603,6 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id,
     d->cbuf = g_malloc0(d->size);
 
     chr->opaque = d;
-    chr->chr_write = ringbuf_chr_write;
-    chr->chr_free = ringbuf_chr_free;
 
     return chr;
 
@@ -3608,7 +3614,7 @@ fail:
 
 bool chr_is_ringbuf(const CharDriverState *chr)
 {
-    return chr->chr_write == ringbuf_chr_write;
+    return chr->driver->chr_write == ringbuf_chr_write;
 }
 
 void qmp_ringbuf_write(const char *device, const char *data,
@@ -3887,6 +3893,22 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
     stdio->signal = qemu_opt_get_bool(opts, "signal", true);
 }
 
+static const CharDriver stdio_driver = {
+    .kind = CHARDEV_BACKEND_KIND_STDIO,
+    .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio,
+#ifdef _WIN32
+    .chr_write = win_stdio_write,
+    .chr_set_echo = qemu_chr_set_echo_win_stdio,
+    .chr_free = win_stdio_free,
+#else
+    .chr_add_watch = fd_chr_add_watch,
+    .chr_write = fd_chr_write,
+    .chr_update_read_handler = fd_chr_update_read_handler,
+    .chr_set_echo = qemu_chr_set_echo_stdio,
+    .chr_free = qemu_chr_free_stdio,
+#endif
+};
+
 #ifdef HAVE_CHARDEV_SERIAL
 static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
                                   Error **errp)
@@ -3936,6 +3958,20 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
     dev->device = g_strdup(device);
 }
 
+static const CharDriver pipe_driver = {
+    .kind = CHARDEV_BACKEND_KIND_PIPE,
+    .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe,
+#ifdef _WIN32
+    .chr_write = win_chr_write,
+    .chr_free = win_chr_free,
+#else
+    .chr_add_watch = fd_chr_add_watch,
+    .chr_write = fd_chr_write,
+    .chr_update_read_handler = fd_chr_update_read_handler,
+    .chr_free = fd_chr_free,
+#endif
+};
+
 static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
                                    Error **errp)
 {
@@ -3952,6 +3988,21 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
+static const CharDriver ringbuf_driver = {
+    .kind = CHARDEV_BACKEND_KIND_RINGBUF,
+    .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
+    .chr_write = ringbuf_chr_write,
+    .chr_free = ringbuf_chr_free,
+};
+
+/* Bug-compatibility: */
+static const CharDriver memory_driver = {
+    .kind = CHARDEV_BACKEND_KIND_MEMORY,
+    .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
+    .chr_write = ringbuf_chr_write,
+    .chr_free = ringbuf_chr_free,
+};
+
 static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
                                Error **errp)
 {
@@ -3967,6 +4018,15 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
     mux->chardev = g_strdup(chardev);
 }
 
+static const CharDriver mux_driver = {
+    .kind = CHARDEV_BACKEND_KIND_MUX,
+    .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
+    .chr_free = mux_chr_free,
+    .chr_write = mux_chr_write,
+    .chr_accept_input = mux_chr_accept_input,
+    .chr_add_watch = mux_chr_add_watch,
+};
+
 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
                                   Error **errp)
 {
@@ -4242,7 +4302,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename)
     chr = qemu_chr_new_noreplay(label, filename);
     if (chr) {
         chr->replay = replay_mode != REPLAY_MODE_NONE;
-        if (chr->replay && chr->chr_ioctl) {
+        if (chr->replay && chr->driver->chr_ioctl) {
             fprintf(stderr,
                     "Replay: ioctl is not supported for serial devices yet\n");
         }
@@ -4255,8 +4315,8 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 {
     CharDriverState *chr = be->chr;
 
-    if (chr && chr->chr_set_echo) {
-        chr->chr_set_echo(chr, echo);
+    if (chr && chr->driver->chr_set_echo) {
+        chr->driver->chr_set_echo(chr, echo);
     }
 }
 
@@ -4272,8 +4332,8 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
         return;
     }
     be->fe_open = fe_open;
-    if (chr->chr_set_fe_open) {
-        chr->chr_set_fe_open(chr, fe_open);
+    if (chr->driver->chr_set_fe_open) {
+        chr->driver->chr_set_fe_open(chr, fe_open);
     }
 }
 
@@ -4284,11 +4344,11 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
     GSource *src;
     guint tag;
 
-    if (!s || s->chr_add_watch == NULL) {
+    if (!s || s->driver->chr_add_watch == NULL) {
         return 0;
     }
 
-    src = s->chr_add_watch(s, cond);
+    src = s->driver->chr_add_watch(s, cond);
     if (!src) {
         return 0;
     }
@@ -4304,8 +4364,8 @@ void qemu_chr_fe_disconnect(CharBackend *be)
 {
     CharDriverState *chr = be->chr;
 
-    if (chr && chr->chr_disconnect) {
-        chr->chr_disconnect(chr);
+    if (chr && chr->driver->chr_disconnect) {
+        chr->driver->chr_disconnect(chr);
     }
 }
 
@@ -4325,8 +4385,8 @@ static void qemu_chr_free_common(CharDriverState *chr)
 
 void qemu_chr_free(CharDriverState *chr)
 {
-    if (chr->chr_free) {
-        chr->chr_free(chr);
+    if (chr->driver->chr_free) {
+        chr->driver->chr_free(chr);
     }
     qemu_chr_free_common(chr);
 }
@@ -4498,7 +4558,8 @@ QemuOptsList qemu_chardev_opts = {
 
 #ifdef _WIN32
 
-static CharDriverState *qmp_chardev_open_file(const char *id,
+static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
+                                              const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
                                               bool *be_opened,
@@ -4531,10 +4592,11 @@ static CharDriverState *qmp_chardev_open_file(const char *id,
         error_setg(errp, "open %s failed", file->out);
         return NULL;
     }
-    return qemu_chr_open_win_file(out, common, errp);
+    return qemu_chr_open_win_file(driver, out, common, errp);
 }
 
-static CharDriverState *qmp_chardev_open_serial(const char *id,
+static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
+                                                const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
                                                 bool *be_opened,
@@ -4542,7 +4604,8 @@ static CharDriverState *qmp_chardev_open_serial(const char *id,
 {
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
-    return qemu_chr_open_win_path(serial->device, common, errp);
+
+    return qemu_chr_open_win_path(driver, serial->device, common, errp);
 }
 
 #else /* WIN32 */
@@ -4559,7 +4622,8 @@ static int qmp_chardev_open_file_source(char *src, int flags,
     return fd;
 }
 
-static CharDriverState *qmp_chardev_open_file(const char *id,
+static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
+                                              const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
                                               bool *be_opened,
@@ -4590,11 +4654,12 @@ static CharDriverState *qmp_chardev_open_file(const char *id,
         }
     }
 
-    return qemu_chr_open_fd(in, out, common, errp);
+    return qemu_chr_open_fd(driver, in, out, common, errp);
 }
 
 #ifdef HAVE_CHARDEV_SERIAL
-static CharDriverState *qmp_chardev_open_serial(const char *id,
+static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
+                                                const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
                                                 bool *be_opened,
@@ -4609,12 +4674,14 @@ static CharDriverState *qmp_chardev_open_serial(const char *id,
         return NULL;
     }
     qemu_set_nonblock(fd);
-    return qemu_chr_open_tty_fd(fd, common, be_opened, errp);
+
+    return qemu_chr_open_tty_fd(driver, fd, common, be_opened, errp);
 }
 #endif
 
 #ifdef HAVE_CHARDEV_PARPORT
-static CharDriverState *qmp_chardev_open_parallel(const char *id,
+static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
+                                                  const char *id,
                                                   ChardevBackend *backend,
                                                   ChardevReturn *ret,
                                                   bool *be_opened,
@@ -4628,12 +4695,57 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id,
     if (fd < 0) {
         return NULL;
     }
-    return qemu_chr_open_pp_fd(fd, common, be_opened, errp);
+    return qemu_chr_open_pp_fd(driver, fd, common, be_opened, errp);
 }
+
+static const CharDriver parallel_driver = {
+    .alias = "parport", .kind = CHARDEV_BACKEND_KIND_PARALLEL,
+    .parse = qemu_chr_parse_parallel, .create = qmp_chardev_open_parallel,
+#if defined(__linux__)
+    .chr_write = null_chr_write,
+    .chr_ioctl = pp_ioctl,
+    .chr_free = pp_free,
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+    .chr_write = null_chr_write;
+    .chr_ioctl = pp_ioctl;
+    /* FIXME: no chr_free */
+#endif
+};
 #endif
 
 #endif /* WIN32 */
 
+static const CharDriver file_driver = {
+    .kind = CHARDEV_BACKEND_KIND_FILE,
+    .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file,
+#ifdef _WIN32
+    .chr_write = win_chr_write,
+    /* FIXME: no chr_free */
+#else
+    .chr_add_watch = fd_chr_add_watch,
+    .chr_write = fd_chr_write,
+    .chr_update_read_handler = fd_chr_update_read_handler,
+    .chr_free = fd_chr_free,
+#endif
+};
+
+#ifdef HAVE_CHARDEV_SERIAL
+static const CharDriver serial_driver = {
+    .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
+    .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
+#ifdef _WIN32
+    .chr_write = win_chr_write,
+    .chr_free = win_chr_free,
+#else
+    .chr_add_watch = fd_chr_add_watch,
+    .chr_write = fd_chr_write,
+    .chr_update_read_handler = fd_chr_update_read_handler,
+    .chr_ioctl = tty_serial_ioctl,
+    .chr_free = qemu_chr_free_tty,
+#endif
+};
+#endif
+
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
     CharDriverState *chr = opaque;
@@ -4655,7 +4767,8 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
     return false;
 }
 
-static CharDriverState *qmp_chardev_open_socket(const char *id,
+static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
+                                                const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
                                                 bool *be_opened,
@@ -4673,7 +4786,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
     ChardevCommon *common = qapi_ChardevSocket_base(sock);
     QIOChannelSocket *sioc = NULL;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -4724,16 +4837,6 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
     }
 
     chr->opaque = s;
-    chr->chr_wait_connected = tcp_chr_wait_connected;
-    chr->chr_write = tcp_chr_write;
-    chr->chr_sync_read = tcp_chr_sync_read;
-    chr->chr_free = tcp_chr_free;
-    chr->chr_disconnect = tcp_chr_disconnect;
-    chr->get_msgfds = tcp_get_msgfds;
-    chr->set_msgfds = tcp_set_msgfds;
-    chr->chr_add_client = tcp_chr_add_client;
-    chr->chr_add_watch = tcp_chr_add_watch;
-    chr->chr_update_read_handler = tcp_chr_update_read_handler;
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
@@ -4795,7 +4898,23 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
     return NULL;
 }
 
-static CharDriverState *qmp_chardev_open_udp(const char *id,
+static const CharDriver socket_driver = {
+    .kind = CHARDEV_BACKEND_KIND_SOCKET,
+    .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket,
+    .chr_wait_connected = tcp_chr_wait_connected,
+    .chr_write = tcp_chr_write,
+    .chr_sync_read = tcp_chr_sync_read,
+    .chr_disconnect = tcp_chr_disconnect,
+    .get_msgfds = tcp_get_msgfds,
+    .set_msgfds = tcp_set_msgfds,
+    .chr_add_client = tcp_chr_add_client,
+    .chr_add_watch = tcp_chr_add_watch,
+    .chr_update_read_handler = tcp_chr_update_read_handler,
+    .chr_free = tcp_chr_free,
+};
+
+static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
+                                             const char *id,
                                              ChardevBackend *backend,
                                              ChardevReturn *ret,
                                              bool *be_opened,
@@ -4813,7 +4932,8 @@ static CharDriverState *qmp_chardev_open_udp(const char *id,
         object_unref(OBJECT(sioc));
         return NULL;
     }
-    chr = qemu_chr_open_udp(sioc, common, be_opened, errp);
+
+    chr = qemu_chr_open_udp(driver, sioc, common, be_opened, errp);
 
     name = g_strdup_printf("chardev-udp-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
@@ -4822,6 +4942,13 @@ static CharDriverState *qmp_chardev_open_udp(const char *id,
     return chr;
 }
 
+static const CharDriver udp_driver = {
+    .kind = CHARDEV_BACKEND_KIND_UDP,
+    .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
+    .chr_write = udp_chr_write,
+    .chr_update_read_handler = udp_chr_update_read_handler,
+    .chr_free = udp_chr_free,
+};
 
 bool qemu_chr_has_feature(CharDriverState *chr,
                           CharDriverFeature feature)
@@ -4857,7 +4984,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         goto out_error;
     }
 
-    chr = cd->create(id, backend, ret, &be_opened, &local_err);
+    chr = cd->create(cd, id, backend, ret, &be_opened, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out_error;
@@ -4910,49 +5037,33 @@ void qemu_chr_cleanup(void)
 
 static void register_types(void)
 {
-    int i;
-    static const CharDriver drivers[] = {
-        { .kind = CHARDEV_BACKEND_KIND_NULL, .parse = NULL,
-          .create = qemu_chr_open_null },
-        { .kind = CHARDEV_BACKEND_KIND_SOCKET,
-          .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket },
-        { .kind = CHARDEV_BACKEND_KIND_UDP, .parse = qemu_chr_parse_udp,
-          .create = qmp_chardev_open_udp },
-        { .kind = CHARDEV_BACKEND_KIND_RINGBUF,
-          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf },
-        { .kind = CHARDEV_BACKEND_KIND_FILE,
-          .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file },
-        { .kind = CHARDEV_BACKEND_KIND_STDIO,
-          .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
-#if defined HAVE_CHARDEV_SERIAL
-        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
-          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
+    static const CharDriver *drivers[] = {
+        &null_driver,
+        &socket_driver,
+        &udp_driver,
+        &ringbuf_driver,
+        &file_driver,
+        &stdio_driver,
+#ifdef HAVE_CHARDEV_SERIAL
+        &serial_driver,
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
-        { .kind = CHARDEV_BACKEND_KIND_PARALLEL, .alias = "parport",
-          .parse = qemu_chr_parse_parallel,
-          .create = qmp_chardev_open_parallel },
+        &parallel_driver,
 #endif
 #ifdef HAVE_CHARDEV_PTY
-        { .kind = CHARDEV_BACKEND_KIND_PTY,
-          .parse = NULL, .create = qemu_chr_open_pty },
+        &pty_driver,
 #endif
 #ifdef _WIN32
-        { .kind = CHARDEV_BACKEND_KIND_CONSOLE, .parse = NULL,
-          .create = qemu_chr_open_win_con },
+        &console_driver,
 #endif
-        { .kind = CHARDEV_BACKEND_KIND_PIPE,
-          .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe },
-        { .kind = CHARDEV_BACKEND_KIND_MUX, .parse = qemu_chr_parse_mux,
-          .create = qemu_chr_open_mux },
-        /* Bug-compatibility: */
-        { .kind = CHARDEV_BACKEND_KIND_MEMORY,
-          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf },
+        &pipe_driver,
+        &mux_driver,
+        &memory_driver
     };
-
+    int i;
 
     for (i = 0; i < ARRAY_SIZE(drivers); i++) {
-        register_char_driver(&drivers[i]);
+        register_char_driver(drivers[i]);
     }
 
     /* this must be done after machine init, since we register FEs with muxes
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 8e9151db5c..da3a9c4547 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -260,16 +260,15 @@ static void spice_chr_accept_input(struct CharDriverState *chr)
     spice_server_char_device_wakeup(&s->sin);
 }
 
-static CharDriverState *chr_open(const char *subtype,
-                                 void (*set_fe_open)(struct CharDriverState *,
-                                                     int),
+static CharDriverState *chr_open(const CharDriver *driver,
+                                 const char *subtype,
                                  ChardevCommon *backend,
                                  Error **errp)
 {
     CharDriverState *chr;
     SpiceCharDriver *s;
 
-    chr = qemu_chr_alloc(backend, errp);
+    chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
@@ -278,18 +277,14 @@ static CharDriverState *chr_open(const char *subtype,
     s->active = false;
     s->sin.subtype = g_strdup(subtype);
     chr->opaque = s;
-    chr->chr_write = spice_chr_write;
-    chr->chr_add_watch = spice_chr_add_watch;
-    chr->chr_free = spice_chr_free;
-    chr->chr_set_fe_open = set_fe_open;
-    chr->chr_accept_input = spice_chr_accept_input;
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
 
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
+static CharDriverState *qemu_chr_open_spice_vmc(const CharDriver *driver,
+                                                const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
                                                 bool *be_opened,
@@ -312,11 +307,12 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
     }
 
     *be_opened = false;
-    return chr_open(type, spice_vmc_set_fe_open, common, errp);
+    return chr_open(driver, type, common, errp);
 }
 
 #if SPICE_SERVER_VERSION >= 0x000c02
-static CharDriverState *qemu_chr_open_spice_port(const char *id,
+static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
+                                                 const char *id,
                                                  ChardevBackend *backend,
                                                  ChardevReturn *ret,
                                                  bool *be_opened,
@@ -333,7 +329,7 @@ static CharDriverState *qemu_chr_open_spice_port(const char *id,
         return NULL;
     }
 
-    chr = chr_open("port", spice_port_set_fe_open, common, errp);
+    chr = chr_open(driver, "port", common, errp);
     if (!chr) {
         return NULL;
     }
@@ -391,11 +387,21 @@ static void register_types(void)
 {
     static const CharDriver vmc_driver = {
         .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
-        .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc
+        .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc,
+        .chr_write = spice_chr_write,
+        .chr_add_watch = spice_chr_add_watch,
+        .chr_set_fe_open = spice_vmc_set_fe_open,
+        .chr_accept_input = spice_chr_accept_input,
+        .chr_free = spice_chr_free,
     };
     static const CharDriver port_driver = {
         .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
-        .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port
+        .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port,
+        .chr_write = spice_chr_write,
+        .chr_add_watch = spice_chr_add_watch,
+        .chr_set_fe_open = spice_port_set_fe_open,
+        .chr_accept_input = spice_chr_accept_input,
+        .chr_free = spice_chr_free,
     };
     register_char_driver(&vmc_driver);
     register_char_driver(&port_driver);
diff --git a/ui/console.c b/ui/console.c
index 764501b363..41becd1ca7 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1040,6 +1040,10 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
     QemuConsole *s = chr->opaque;
     int i;
 
+    if (!s->ds) {
+        return 0;
+    }
+
     s->update_x0 = s->width * FONT_WIDTH;
     s->update_y0 = s->height * FONT_HEIGHT;
     s->update_x1 = 0;
@@ -1989,8 +1993,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 
     s = chr->opaque;
 
-    chr->chr_write = console_puts;
-
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
@@ -2037,6 +2039,8 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
     qemu_chr_be_generic_open(chr);
 }
 
+static const CharDriver vc_driver;
+
 static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 {
     ChardevCommon *common = qapi_ChardevVC_base(vc);
@@ -2045,7 +2049,7 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
     unsigned width = 0;
     unsigned height = 0;
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(&vc_driver, common, errp);
     if (!chr) {
         return NULL;
     }
@@ -2078,7 +2082,6 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 
     s->chr = chr;
     chr->opaque = s;
-    chr->chr_set_echo = text_console_set_echo;
 
     if (display_state) {
         text_console_do_init(chr, display_state);
@@ -2088,7 +2091,8 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 
 static VcHandler *vc_handler = text_console_init;
 
-static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
+static CharDriverState *vc_init(const CharDriver *driver,
+                                const char *id, ChardevBackend *backend,
                                 ChardevReturn *ret, bool *be_opened,
                                 Error **errp)
 {
@@ -2180,13 +2184,15 @@ static const TypeInfo qemu_console_info = {
     .class_size = sizeof(QemuConsoleClass),
 };
 
+static const CharDriver vc_driver = {
+    .kind = CHARDEV_BACKEND_KIND_VC,
+    .parse = qemu_chr_parse_vc, .create = vc_init,
+    .chr_write = console_puts,
+    .chr_set_echo = text_console_set_echo,
+};
+
 static void register_types(void)
 {
-    static const CharDriver vc_driver = {
-        .kind = CHARDEV_BACKEND_KIND_VC,
-        .parse = qemu_chr_parse_vc, .create = vc_init
-    };
-
     type_register_static(&qemu_console_info);
     register_char_driver(&vc_driver);
 }
diff --git a/ui/gtk.c b/ui/gtk.c
index 67c52179ee..575651abcb 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1693,6 +1693,12 @@ static CharDriverState *vcs[MAX_VCS];
 
 static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
 {
+    static const CharDriver gd_vc_driver = {
+        .kind = CHARDEV_BACKEND_KIND_VC,
+        .chr_write = gd_vc_chr_write,
+        .chr_set_echo = gd_vc_chr_set_echo,
+    };
+
     ChardevCommon *common = qapi_ChardevVC_base(vc);
     CharDriverState *chr;
 
@@ -1701,14 +1707,11 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
         return NULL;
     }
 
-    chr = qemu_chr_alloc(common, errp);
+    chr = qemu_chr_alloc(&gd_vc_driver, common, errp);
     if (!chr) {
         return NULL;
     }
 
-    chr->chr_write = gd_vc_chr_write;
-    chr->chr_set_echo = gd_vc_chr_set_echo;
-
     /* Temporary, until gd_vc_vte_init runs.  */
     chr->opaque = g_new0(VirtualConsole, 1);
 
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index c8750ede21..09e40ef9b8 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -85,24 +85,11 @@ typedef struct CharBackend {
     int fe_open;
 } CharBackend;
 
+typedef struct CharDriver CharDriver;
+
 struct CharDriverState {
+    const CharDriver *driver;
     QemuMutex chr_write_lock;
-    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
-    int (*chr_sync_read)(struct CharDriverState *s,
-                         const uint8_t *buf, int len);
-    GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
-    void (*chr_update_read_handler)(struct CharDriverState *s,
-                                    GMainContext *context);
-    int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
-    int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
-    int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
-    int (*chr_add_client)(struct CharDriverState *chr, int fd);
-    int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
-    void (*chr_free)(struct CharDriverState *chr);
-    void (*chr_disconnect)(struct CharDriverState *chr);
-    void (*chr_accept_input)(struct CharDriverState *chr);
-    void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
-    void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
     CharBackend *be;
     void *opaque;
     char *label;
@@ -125,7 +112,8 @@ struct CharDriverState {
  *
  * Returns: a newly allocated CharDriverState, or NULL on error.
  */
-CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp);
+CharDriverState *qemu_chr_alloc(const CharDriver *driver,
+                                ChardevCommon *backend, Error **errp);
 
 /**
  * @qemu_chr_new_from_opts:
@@ -473,15 +461,33 @@ void qemu_chr_set_feature(CharDriverState *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
-typedef struct CharDriver {
+struct CharDriver {
     const char *alias;
     ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
-    CharDriverState *(*create)(const char *id,
+    CharDriverState *(*create)(const CharDriver *driver,
+                               const char *id,
                                ChardevBackend *backend,
                                ChardevReturn *ret, bool *be_opened,
                                Error **errp);
-} CharDriver;
+
+    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
+    int (*chr_sync_read)(struct CharDriverState *s,
+                         const uint8_t *buf, int len);
+    GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
+    void (*chr_update_read_handler)(struct CharDriverState *s,
+                                    GMainContext *context);
+    int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
+    int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
+    int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
+    int (*chr_add_client)(struct CharDriverState *chr, int fd);
+    int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
+    void (*chr_free)(struct CharDriverState *chr);
+    void (*chr_disconnect)(struct CharDriverState *chr);
+    void (*chr_accept_input)(struct CharDriverState *chr);
+    void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
+    void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
+};
 
 void register_char_driver(const CharDriver *driver);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (3 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-14 16:05   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind() Marc-André Lureau
                   ` (50 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This shorten a bit the code.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 97 ++++++++++++++++++++-----------------------------------------
 1 file changed, 31 insertions(+), 66 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index a81b61491a..cc7731a680 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1884,22 +1884,6 @@ static void qemu_chr_free_tty(CharDriverState *chr)
 {
     fd_chr_free(chr);
 }
-
-static CharDriverState *qemu_chr_open_tty_fd(const CharDriver *driver,
-                                             int fd,
-                                             ChardevCommon *backend,
-                                             bool *be_opened,
-                                             Error **errp)
-{
-    CharDriverState *chr;
-
-    tty_serial_init(fd, 115200, 'N', 8, 1);
-    chr = qemu_chr_open_fd(driver, fd, fd, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    return chr;
-}
 #endif /* __linux__ || __sun__ */
 
 #if defined(__linux__)
@@ -2320,29 +2304,6 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_path(const CharDriver *driver,
-                                               const char *filename,
-                                               ChardevCommon *backend,
-                                               Error **errp)
-{
-    CharDriverState *chr;
-    WinCharState *s;
-
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = g_new0(WinCharState, 1);
-    chr->opaque = s;
-
-    if (win_chr_init(chr, filename, errp) < 0) {
-        g_free(s);
-        qemu_chr_free_common(chr);
-        return NULL;
-    }
-    return chr;
-}
-
 static int win_chr_pipe_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2798,30 +2759,6 @@ static void udp_chr_free(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(const CharDriver *driver,
-                                          QIOChannelSocket *sioc,
-                                          ChardevCommon *backend,
-                                          bool *be_opened,
-                                          Error **errp)
-{
-    CharDriverState *chr = NULL;
-    NetCharDriver *s = NULL;
-
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = g_new0(NetCharDriver, 1);
-
-    s->ioc = QIO_CHANNEL(sioc);
-    s->bufcnt = 0;
-    s->bufptr = 0;
-    chr->opaque = s;
-    /* be isn't opened until we get a connection */
-    *be_opened = false;
-    return chr;
-}
-
 /***********************************************************/
 /* TCP Net console */
 
@@ -4604,8 +4541,23 @@ static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
 {
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_chr_alloc(driver, common, errp);
+    if (!chr) {
+        return NULL;
+    }
+
+    s = g_new0(WinCharState, 1);
+    chr->opaque = s;
+    if (win_chr_init(chr, serial->device, errp) < 0) {
+        g_free(s);
+        qemu_chr_free_common(chr);
+        return NULL;
+    }
 
-    return qemu_chr_open_win_path(driver, serial->device, common, errp);
+    return chr;
 }
 
 #else /* WIN32 */
@@ -4674,8 +4626,9 @@ static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
         return NULL;
     }
     qemu_set_nonblock(fd);
+    tty_serial_init(fd, 115200, 'N', 8, 1);
 
-    return qemu_chr_open_tty_fd(driver, fd, common, be_opened, errp);
+    return qemu_chr_open_fd(driver, fd, fd, common, errp);
 }
 #endif
 
@@ -4925,6 +4878,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
     QIOChannelSocket *sioc = qio_channel_socket_new();
     char *name;
     CharDriverState *chr;
+    NetCharDriver *s;
 
     if (qio_channel_socket_dgram_sync(sioc,
                                       udp->local, udp->remote,
@@ -4933,12 +4887,23 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
         return NULL;
     }
 
-    chr = qemu_chr_open_udp(driver, sioc, common, be_opened, errp);
+    chr = qemu_chr_alloc(driver, common, errp);
+    if (!chr) {
+        return NULL;
+    }
 
     name = g_strdup_printf("chardev-udp-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
+    s = g_new0(NetCharDriver, 1);
+    s->ioc = QIO_CHANNEL(sioc);
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    chr->opaque = s;
+    /* be isn't opened until we get a connection */
+    *be_opened = false;
+
     return chr;
 }
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind()
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (4 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-19 21:16   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay Marc-André Lureau
                   ` (49 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This allows to remove the "is_mux" field from CharDriverState.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c             |  2 +-
 qemu-char.c           | 21 ++++++++++-----------
 include/sysemu/char.h | 15 +++++++++++++--
 3 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/monitor.c b/monitor.c
index 0841d436b0..17948f5289 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3194,7 +3194,7 @@ static void ringbuf_completion(ReadLineState *rs, const char *str)
 
         if (!strncmp(chr_info->label, str, len)) {
             CharDriverState *chr = qemu_chr_find(chr_info->label);
-            if (chr && chr_is_ringbuf(chr)) {
+            if (chr && qemu_chr_is_ringbuf(chr)) {
                 readline_add_completion(rs, chr_info->label);
             }
         }
diff --git a/qemu-char.c b/qemu-char.c
index cc7731a680..2302a9dfb3 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -780,7 +780,7 @@ static void muxes_realize_done(Notifier *notifier, void *unused)
     CharDriverState *chr;
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
-        if (chr->is_mux) {
+        if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
             MuxDriver *d = chr->opaque;
             int i;
 
@@ -884,7 +884,6 @@ static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
      * set of muxes
      */
     *be_opened = muxes_realized;
-    chr->is_mux = 1;
     if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
         qemu_chr_free(chr);
         return NULL;
@@ -902,7 +901,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
 {
     int tag = 0;
 
-    if (s->is_mux) {
+    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
         MuxDriver *d = s->opaque;
 
         if (d->mux_cnt >= MAX_MUX) {
@@ -929,7 +928,7 @@ unavailable:
 
 static bool qemu_chr_is_busy(CharDriverState *s)
 {
-    if (s->is_mux) {
+    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
         MuxDriver *d = s->opaque;
         return d->mux_cnt >= 0;
     } else {
@@ -944,7 +943,7 @@ void qemu_chr_fe_deinit(CharBackend *b)
     if (b->chr) {
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
         b->chr->be = NULL;
-        if (b->chr->is_mux) {
+        if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
             MuxDriver *d = b->chr->opaque;
             d->backends[b->tag] = NULL;
         }
@@ -995,7 +994,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         }
     }
 
-    if (s->is_mux) {
+    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
         mux_chr_set_handlers(s, context);
     }
 }
@@ -1006,7 +1005,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
         return;
     }
 
-    if (b->chr->is_mux) {
+    if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
         mux_set_focus(b->chr->opaque, b->tag);
     }
 }
@@ -3549,9 +3548,9 @@ fail:
     return NULL;
 }
 
-bool chr_is_ringbuf(const CharDriverState *chr)
+ChardevBackendKind qemu_chr_get_kind(const CharDriverState *chr)
 {
-    return chr->driver->chr_write == ringbuf_chr_write;
+    return chr->driver->kind;
 }
 
 void qmp_ringbuf_write(const char *device, const char *data,
@@ -3569,7 +3568,7 @@ void qmp_ringbuf_write(const char *device, const char *data,
         return;
     }
 
-    if (!chr_is_ringbuf(chr)) {
+    if (!qemu_chr_is_ringbuf(chr)) {
         error_setg(errp,"%s is not a ringbuf device", device);
         return;
     }
@@ -3613,7 +3612,7 @@ char *qmp_ringbuf_read(const char *device, int64_t size,
         return NULL;
     }
 
-    if (!chr_is_ringbuf(chr)) {
+    if (!qemu_chr_is_ringbuf(chr)) {
         error_setg(errp,"%s is not a ringbuf device", device);
         return NULL;
     }
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 09e40ef9b8..4948aeefcb 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -96,7 +96,6 @@ struct CharDriverState {
     char *filename;
     int logfd;
     int be_open;
-    int is_mux;
     guint fd_in_tag;
     bool replay;
     DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
@@ -453,7 +452,19 @@ void qemu_chr_be_generic_open(CharDriverState *s);
 void qemu_chr_fe_accept_input(CharBackend *be);
 int qemu_chr_add_client(CharDriverState *s, int fd);
 CharDriverState *qemu_chr_find(const char *name);
-bool chr_is_ringbuf(const CharDriverState *chr);
+
+/**
+ * @qemu_chr_get_kind:
+ *
+ * Returns the kind of char backend, or -1 if unspecified.
+ */
+ChardevBackendKind qemu_chr_get_kind(const CharDriverState *chr);
+
+static inline bool qemu_chr_is_ringbuf(const CharDriverState *chr)
+{
+    return qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_RINGBUF ||
+        qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MEMORY;
+}
 
 bool qemu_chr_has_feature(CharDriverState *chr,
                           CharDriverFeature feature);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (5 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind() Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-19 21:58   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object Marc-André Lureau
                   ` (48 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Use a feature flag rather than a structure field for "replay".

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c           | 33 ++++++++++++++++++++-------------
 include/sysemu/char.h |  3 ++-
 2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 2302a9dfb3..c9857c9710 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -277,6 +277,11 @@ static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int
     return res;
 }
 
+static bool qemu_chr_replay(CharDriverState *chr)
+{
+    return qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
+}
+
 int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
 {
     CharDriverState *s = be->chr;
@@ -286,7 +291,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
         return 0;
     }
 
-    if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
         int offset;
         replay_char_write_event_load(&ret, &offset);
         assert(offset <= len);
@@ -303,7 +308,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
 
     qemu_mutex_unlock(&s->chr_write_lock);
     
-    if (s->replay && replay_mode == REPLAY_MODE_RECORD) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
         replay_char_write_event_save(ret, ret < 0 ? 0 : ret);
     }
     
@@ -315,7 +320,7 @@ static int qemu_chr_write_all(CharDriverState *s, const uint8_t *buf, int len)
     int offset;
     int res;
 
-    if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
         replay_char_write_event_load(&res, &offset);
         assert(offset <= len);
         qemu_chr_fe_write_buffer(s, buf, offset, &offset);
@@ -324,7 +329,7 @@ static int qemu_chr_write_all(CharDriverState *s, const uint8_t *buf, int len)
 
     res = qemu_chr_fe_write_buffer(s, buf, len, &offset);
 
-    if (s->replay && replay_mode == REPLAY_MODE_RECORD) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
         replay_char_write_event_save(res, offset);
     }
 
@@ -355,7 +360,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
         return 0;
     }
 
-    if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
         return replay_char_read_all_load(buf);
     }
 
@@ -372,7 +377,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
         }
 
         if (res < 0) {
-            if (s->replay && replay_mode == REPLAY_MODE_RECORD) {
+            if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
                 replay_char_read_all_save_error(res);
             }
             return res;
@@ -385,7 +390,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
         }
     }
 
-    if (s->replay && replay_mode == REPLAY_MODE_RECORD) {
+    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
         replay_char_read_all_save_buf(buf, offset);
     }
     return offset;
@@ -396,7 +401,7 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
     CharDriverState *s = be->chr;
     int res;
 
-    if (!s || !s->driver->chr_ioctl || s->replay) {
+    if (!s || !s->driver->chr_ioctl || qemu_chr_replay(s)) {
         res = -ENOTSUP;
     } else {
         res = s->driver->chr_ioctl(s, cmd, arg);
@@ -427,7 +432,7 @@ void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
 
 void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
 {
-    if (s->replay) {
+    if (qemu_chr_replay(s)) {
         if (replay_mode == REPLAY_MODE_PLAY) {
             return;
         }
@@ -442,7 +447,7 @@ int qemu_chr_fe_get_msgfd(CharBackend *be)
     CharDriverState *s = be->chr;
     int fd;
     int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
-    if (s && s->replay) {
+    if (s && qemu_chr_replay(s)) {
         fprintf(stderr,
                 "Replay: get msgfd is not supported for serial devices yet\n");
         exit(1);
@@ -4237,8 +4242,10 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename)
     CharDriverState *chr;
     chr = qemu_chr_new_noreplay(label, filename);
     if (chr) {
-        chr->replay = replay_mode != REPLAY_MODE_NONE;
-        if (chr->replay && chr->driver->chr_ioctl) {
+        if (replay_mode != REPLAY_MODE_NONE) {
+            qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
+        }
+        if (qemu_chr_replay(chr) && chr->driver->chr_ioctl) {
             fprintf(stderr,
                     "Replay: ioctl is not supported for serial devices yet\n");
         }
@@ -4982,7 +4989,7 @@ void qmp_chardev_remove(const char *id, Error **errp)
         error_setg(errp, "Chardev '%s' is busy", id);
         return;
     }
-    if (chr->replay) {
+    if (qemu_chr_replay(chr)) {
         error_setg(errp,
             "Chardev '%s' cannot be unplugged in record/replay mode", id);
         return;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 4948aeefcb..07dfa59afe 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -69,6 +69,8 @@ typedef enum {
     /* Whether it is possible to send/recv file descriptors
      * over the data channel */
     QEMU_CHAR_FEATURE_FD_PASS,
+    /* Whether replay or record mode is enabled */
+    QEMU_CHAR_FEATURE_REPLAY,
 
     QEMU_CHAR_FEATURE_LAST,
 } CharDriverFeature;
@@ -97,7 +99,6 @@ struct CharDriverState {
     int logfd;
     int be_open;
     guint fd_in_tag;
-    bool replay;
     DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
     QTAILQ_ENTRY(CharDriverState) next;
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (6 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 20:24   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc() Marc-André Lureau
                   ` (47 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Use a single allocation for CharDriverState, this avoids extra
allocations & pointers, and is a step towards more object-oriented
CharDriver.

Gtk console is a bit peculiar, gd_vc_chr_set_echo
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |  23 ++---
 backends/msmouse.c    |  16 +--
 backends/testdev.c    |  22 ++--
 gdbstub.c             |   1 +
 hw/bt/hci-csr.c       |  10 +-
 qemu-char.c           | 280 ++++++++++++++++++++++++++------------------------
 spice-qemu-char.c     |  39 +++----
 ui/console.c          |  21 ++--
 ui/gtk.c              |  30 ++++--
 include/sysemu/char.h |   2 +-
 10 files changed, 230 insertions(+), 214 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index ef6178993a..6244929ac6 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -87,7 +87,7 @@
 #define BUF_SIZE 256
 
 typedef struct {
-    CharDriverState *chr;
+    CharDriverState parent;
 
     brlapi_handle_t *brlapi;
     int brlapi_fd;
@@ -270,7 +270,7 @@ static int baum_deferred_init(BaumDriverState *baum)
 /* The serial port can receive more of our data */
 static void baum_accept_input(struct CharDriverState *chr)
 {
-    BaumDriverState *baum = chr->opaque;
+    BaumDriverState *baum = (BaumDriverState *)chr;
     int room, first;
 
     if (!baum->out_buf_used)
@@ -296,22 +296,23 @@ static void baum_accept_input(struct CharDriverState *chr)
 /* We want to send a packet */
 static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 {
+    CharDriverState *chr = (CharDriverState *)baum;
     uint8_t io_buf[1 + 2 * len], *cur = io_buf;
     int room;
     *cur++ = ESC;
     while (len--)
         if ((*cur++ = *buf++) == ESC)
             *cur++ = ESC;
-    room = qemu_chr_be_can_write(baum->chr);
+    room = qemu_chr_be_can_write(chr);
     len = cur - io_buf;
     if (len <= room) {
         /* Fits */
-        qemu_chr_be_write(baum->chr, io_buf, len);
+        qemu_chr_be_write(chr, io_buf, len);
     } else {
         int first;
         uint8_t out;
         /* Can't fit all, send what can be, and store the rest. */
-        qemu_chr_be_write(baum->chr, io_buf, room);
+        qemu_chr_be_write(chr, io_buf, room);
         len -= room;
         cur = io_buf + room;
         if (len > BUF_SIZE - baum->out_buf_used) {
@@ -486,7 +487,7 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 /* The other end is writing some data.  Store it and try to interpret */
 static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    BaumDriverState *baum = chr->opaque;
+    BaumDriverState *baum = (BaumDriverState *)chr;
     int tocopy, cur, eaten, orig_len = len;
 
     if (!len)
@@ -627,14 +628,13 @@ static void baum_chr_read(void *opaque)
 
 static void baum_free(struct CharDriverState *chr)
 {
-    BaumDriverState *baum = chr->opaque;
+    BaumDriverState *baum = (BaumDriverState *)chr;
 
     timer_free(baum->cellCount_timer);
     if (baum->brlapi) {
         brlapi__closeConnection(baum->brlapi);
         g_free(baum->brlapi);
     }
-    g_free(baum);
 }
 
 static CharDriverState *chr_baum_init(const CharDriver *driver,
@@ -653,10 +653,7 @@ static CharDriverState *chr_baum_init(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    baum = g_malloc0(sizeof(BaumDriverState));
-    baum->chr = chr;
-
-    chr->opaque = baum;
+    baum = (BaumDriverState *)chr;
 
     handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
@@ -678,13 +675,13 @@ static CharDriverState *chr_baum_init(const CharDriver *driver,
 fail_handle:
     g_free(handle);
     g_free(chr);
-    g_free(baum);
     return NULL;
 }
 
 static void register_types(void)
 {
     static const CharDriver driver = {
+        .instance_size = sizeof(BaumDriverState),
         .kind = CHARDEV_BACKEND_KIND_BRAILLE,
         .parse = NULL, .create = chr_baum_init,
         .chr_write = baum_write,
diff --git a/backends/msmouse.c b/backends/msmouse.c
index a2f9f7a235..e954720e28 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -31,7 +31,8 @@
 #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
 
 typedef struct {
-    CharDriverState *chr;
+    CharDriverState parent;
+
     QemuInputHandlerState *hs;
     int axis[INPUT_AXIS__MAX];
     bool btns[INPUT_BUTTON__MAX];
@@ -42,7 +43,7 @@ typedef struct {
 
 static void msmouse_chr_accept_input(CharDriverState *chr)
 {
-    MouseState *mouse = chr->opaque;
+    MouseState *mouse = (MouseState *)chr;
     int len;
 
     len = qemu_chr_be_can_write(chr);
@@ -122,9 +123,10 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
 static void msmouse_input_sync(DeviceState *dev)
 {
     MouseState *mouse = (MouseState *)dev;
+    CharDriverState *chr = (CharDriverState *)dev;
 
     msmouse_queue_event(mouse);
-    msmouse_chr_accept_input(mouse->chr);
+    msmouse_chr_accept_input(chr);
 }
 
 static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
@@ -135,10 +137,9 @@ static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int
 
 static void msmouse_chr_free(struct CharDriverState *chr)
 {
-    MouseState *mouse = chr->opaque;
+    MouseState *mouse = (MouseState *)chr;
 
     qemu_input_handler_unregister(mouse->hs);
-    g_free(mouse);
 }
 
 static QemuInputHandler msmouse_handler = {
@@ -165,12 +166,10 @@ static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
     }
     *be_opened = false;
 
-    mouse = g_new0(MouseState, 1);
+    mouse = (MouseState *)chr;
     mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
                                             &msmouse_handler);
 
-    mouse->chr = chr;
-    chr->opaque = mouse;
 
     return chr;
 }
@@ -178,6 +177,7 @@ static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
 static void register_types(void)
 {
     static const CharDriver driver = {
+        .instance_size = sizeof(MouseState),
         .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
         .parse = NULL, .create = qemu_chr_open_msmouse,
         .chr_write = msmouse_chr_write,
diff --git a/backends/testdev.c b/backends/testdev.c
index 92aefe9f8a..69cf188b95 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -30,7 +30,8 @@
 #define BUF_SIZE 32
 
 typedef struct {
-    CharDriverState *chr;
+    CharDriverState parent;
+
     uint8_t in_buf[32];
     int in_buf_used;
 } TestdevCharState;
@@ -79,7 +80,7 @@ static int testdev_eat_packet(TestdevCharState *testdev)
 /* The other end is writing some data.  Store it and try to interpret */
 static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    TestdevCharState *testdev = chr->opaque;
+    TestdevCharState *testdev = (TestdevCharState *)chr;
     int tocopy, eaten, orig_len = len;
 
     while (len) {
@@ -102,13 +103,6 @@ static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
     return orig_len;
 }
 
-static void testdev_free(struct CharDriverState *chr)
-{
-    TestdevCharState *testdev = chr->opaque;
-
-    g_free(testdev);
-}
-
 static CharDriverState *chr_testdev_init(const CharDriver *driver,
                                          const char *id,
                                          ChardevBackend *backend,
@@ -116,14 +110,10 @@ static CharDriverState *chr_testdev_init(const CharDriver *driver,
                                          bool *be_opened,
                                          Error **errp)
 {
-    TestdevCharState *testdev;
-    CharDriverState *chr;
-
-    testdev = g_new0(TestdevCharState, 1);
-    testdev->chr = chr = g_new0(CharDriverState, 1);
+    TestdevCharState *testdev = g_new0(TestdevCharState, 1);;
+    CharDriverState *chr = (CharDriverState *)testdev;
 
     chr->driver = driver;
-    chr->opaque = testdev;
 
     return chr;
 }
@@ -131,10 +121,10 @@ static CharDriverState *chr_testdev_init(const CharDriver *driver,
 static void register_types(void)
 {
     static const CharDriver driver = {
+        .instance_size = sizeof(TestdevCharState),
         .kind = CHARDEV_BACKEND_KIND_TESTDEV,
         .parse = NULL, .create = chr_testdev_init,
         .chr_write = testdev_write,
-        .chr_free = testdev_free,
     };
     register_char_driver(&driver);
 }
diff --git a/gdbstub.c b/gdbstub.c
index 5dfba33eb9..a8def2fd6f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1731,6 +1731,7 @@ int gdbserver_start(const char *device)
     CharDriverState *mon_chr;
     ChardevCommon common = { 0 };
     static const CharDriver driver = {
+        .instance_size = sizeof(CharDriverState),
         .kind = -1,
         .chr_write = gdb_monitor_write
     };
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index 9c3fb3c8f9..bf2deb0497 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -28,11 +28,11 @@
 #include "hw/bt.h"
 
 struct csrhci_s {
+    CharDriverState chr;
     int enable;
     qemu_irq *pins;
     int pin_state;
     int modem_state;
-    CharDriverState chr;
 #define FIFO_LEN	4096
     int out_start;
     int out_len;
@@ -314,7 +314,7 @@ static void csrhci_ready_for_next_inpkt(struct csrhci_s *s)
 static int csrhci_write(struct CharDriverState *chr,
                 const uint8_t *buf, int len)
 {
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    struct csrhci_s *s = (struct csrhci_s *)chr;
     int total = 0;
 
     if (!s->enable)
@@ -387,7 +387,7 @@ static void csrhci_out_hci_packet_acl(void *opaque,
 static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
 {
     QEMUSerialSetParams *ssp;
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    struct csrhci_s *s = (struct csrhci_s *) chr;
     int prev_state = s->modem_state;
 
     switch (cmd) {
@@ -455,7 +455,7 @@ static void csrhci_pins(void *opaque, int line, int level)
 
 qemu_irq *csrhci_pins_get(CharDriverState *chr)
 {
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    struct csrhci_s *s = (struct csrhci_s *) chr;
 
     return s->pins;
 }
@@ -463,6 +463,7 @@ qemu_irq *csrhci_pins_get(CharDriverState *chr)
 CharDriverState *uart_hci_init(void)
 {
     static const CharDriver hci_driver = {
+        .instance_size = sizeof(struct csrhci_s),
         .kind = -1,
         .chr_write = csrhci_write,
         .chr_ioctl = csrhci_ioctl,
@@ -470,7 +471,6 @@ CharDriverState *uart_hci_init(void)
     struct csrhci_s *s = (struct csrhci_s *)
             g_malloc0(sizeof(struct csrhci_s));
 
-    s->chr.opaque = s;
     s->chr.driver = &hci_driver;
 
     s->hci = qemu_next_hci();
diff --git a/qemu-char.c b/qemu-char.c
index c9857c9710..cc1cf3b676 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -165,12 +165,14 @@ static void qemu_chr_free_common(CharDriverState *chr);
 CharDriverState *qemu_chr_alloc(const CharDriver *driver,
                                 ChardevCommon *backend, Error **errp)
 {
-    CharDriverState *chr = g_malloc0(sizeof(CharDriverState));
-    qemu_mutex_init(&chr->chr_write_lock);
+    CharDriverState *chr;
 
     assert(driver);
     assert(driver->chr_write);
+    assert(driver->instance_size >= sizeof(CharDriverState));
 
+    chr = g_malloc0(driver->instance_size);
+    qemu_mutex_init(&chr->chr_write_lock);
     if (backend->has_logfile) {
         int flags = O_WRONLY | O_CREAT;
         if (backend->has_logappend &&
@@ -536,6 +538,7 @@ static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
 }
 
 static const CharDriver null_driver = {
+    .instance_size = sizeof(CharDriverState),
     .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,
     .chr_write = null_chr_write
 };
@@ -545,6 +548,7 @@ static const CharDriver null_driver = {
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
 struct MuxDriver {
+    CharDriverState parent;
     CharBackend *backends[MAX_MUX];
     CharBackend chr;
     int focus;
@@ -567,7 +571,7 @@ struct MuxDriver {
 /* Called with chr_write_lock held.  */
 static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int ret;
     if (!d->timestamps) {
         ret = qemu_chr_fe_write(&d->chr, buf, len);
@@ -701,7 +705,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
 
 static void mux_chr_accept_input(CharDriverState *chr)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -714,8 +718,7 @@ static void mux_chr_accept_input(CharDriverState *chr)
 
 static int mux_chr_can_read(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -733,7 +736,7 @@ static int mux_chr_can_read(void *opaque)
 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 {
     CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
     int i;
@@ -755,8 +758,7 @@ static bool muxes_realized;
 
 static void mux_chr_event(void *opaque, int event)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int i;
 
     if (!muxes_realized) {
@@ -786,7 +788,7 @@ static void muxes_realize_done(Notifier *notifier, void *unused)
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
         if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = chr->opaque;
+            MuxDriver *d = (MuxDriver *)chr;
             int i;
 
             /* send OPENED to all already-attached FEs */
@@ -808,7 +810,7 @@ static Notifier muxes_realize_notify = {
 
 static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 {
-    MuxDriver *d = s->opaque;
+    MuxDriver *d = (MuxDriver *)s;
     CharDriverState *chr = qemu_chr_fe_get_driver(&d->chr);
 
     if (!chr->driver->chr_add_watch) {
@@ -820,7 +822,7 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 
 static void mux_chr_free(struct CharDriverState *chr)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int i;
 
     for (i = 0; i < d->mux_cnt; i++) {
@@ -830,12 +832,11 @@ static void mux_chr_free(struct CharDriverState *chr)
         }
     }
     qemu_chr_fe_deinit(&d->chr);
-    g_free(d);
 }
 
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
 
     /* Fix up the real driver with mux routines */
     qemu_chr_fe_set_handlers(&d->chr,
@@ -881,9 +882,7 @@ static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    d = g_new0(MuxDriver, 1);
-
-    chr->opaque = d;
+    d = (MuxDriver *)chr;
     d->focus = -1;
     /* only default to opened state if we've realized the initial
      * set of muxes
@@ -907,7 +906,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     int tag = 0;
 
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = s->opaque;
+        MuxDriver *d = (MuxDriver *)s;
 
         if (d->mux_cnt >= MAX_MUX) {
             goto unavailable;
@@ -934,7 +933,7 @@ unavailable:
 static bool qemu_chr_is_busy(CharDriverState *s)
 {
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = s->opaque;
+        MuxDriver *d = (MuxDriver *)s;
         return d->mux_cnt >= 0;
     } else {
         return s->be != NULL;
@@ -949,7 +948,7 @@ void qemu_chr_fe_deinit(CharBackend *b)
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
         b->chr->be = NULL;
         if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = b->chr->opaque;
+            MuxDriver *d = (MuxDriver *)b->chr;
             d->backends[b->tag] = NULL;
         }
         b->chr = NULL;
@@ -1011,7 +1010,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
     }
 
     if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-        mux_set_focus(b->chr->opaque, b->tag);
+        mux_set_focus((MuxDriver *)b->chr, b->tag);
     }
 }
 
@@ -1189,6 +1188,7 @@ static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
 
 
 typedef struct FDCharDriver {
+    CharDriverState parent;
     CharDriverState *chr;
     QIOChannel *ioc_in, *ioc_out;
     int max_size;
@@ -1197,15 +1197,15 @@ typedef struct FDCharDriver {
 /* Called with chr_write_lock held.  */
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    FDCharDriver *s = chr->opaque;
-    
+    FDCharDriver *s = (FDCharDriver *)chr;
+
     return io_channel_send(s->ioc_out, buf, len);
 }
 
 static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = opaque;
     int len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1235,7 +1235,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static int fd_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -1243,14 +1243,14 @@ static int fd_chr_read_poll(void *opaque)
 
 static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
     return qio_channel_create_watch(s->ioc_out, cond);
 }
 
 static void fd_chr_update_read_handler(CharDriverState *chr,
                                        GMainContext *context)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1263,7 +1263,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr,
 
 static void fd_chr_free(struct CharDriverState *chr)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1273,7 +1273,6 @@ static void fd_chr_free(struct CharDriverState *chr)
         object_unref(OBJECT(s->ioc_out));
     }
 
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -1290,7 +1289,7 @@ static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(FDCharDriver, 1);
+    s = (FDCharDriver *)chr;
     s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
     name = g_strdup_printf("chardev-file-in-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
@@ -1301,7 +1300,6 @@ static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
     g_free(name);
     qemu_set_nonblock(fd_out);
     s->chr = chr;
-    chr->opaque = s;
 
     return chr;
 }
@@ -1442,6 +1440,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 #define HAVE_CHARDEV_PTY 1
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     int read_bytes;
 
@@ -1457,7 +1456,7 @@ static void pty_chr_state(CharDriverState *chr, int connected);
 static gboolean pty_chr_timer(gpointer opaque)
 {
     struct CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     s->timer_tag = 0;
@@ -1473,7 +1472,7 @@ static gboolean pty_chr_timer(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     char *name;
 
     if (s->timer_tag) {
@@ -1495,7 +1494,7 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
 /* Called with chr_write_lock held.  */
 static void pty_chr_update_read_handler_locked(CharDriverState *chr)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     GPollFD pfd;
     int rc;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
@@ -1526,7 +1525,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr,
 /* Called with chr_write_lock held.  */
 static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     if (!s->connected) {
         /* guest sends data, check for (re-)connect */
@@ -1540,7 +1539,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     if (!s->connected) {
         return NULL;
     }
@@ -1550,7 +1549,7 @@ static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 static int pty_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
@@ -1559,7 +1558,7 @@ static int pty_chr_read_poll(void *opaque)
 static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
     gsize len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1584,7 +1583,7 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     s->open_tag = 0;
     qemu_chr_be_generic_open(chr);
@@ -1594,7 +1593,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_state(CharDriverState *chr, int connected)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     if (!connected) {
         if (s->open_tag) {
@@ -1628,7 +1627,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
 
 static void pty_chr_free(struct CharDriverState *chr)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_state(chr, 0);
@@ -1638,7 +1637,6 @@ static void pty_chr_free(struct CharDriverState *chr)
         s->timer_tag = 0;
     }
     qemu_mutex_unlock(&chr->chr_write_lock);
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -1678,20 +1676,19 @@ static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
     fprintf(stderr, "char device redirected to %s (label %s)\n",
             pty_name, id);
 
-    s = g_new0(PtyCharDriver, 1);
-    chr->opaque = s;
-    *be_opened = false;
-
+    s = (PtyCharDriver *)chr;
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
     name = g_strdup_printf("chardev-pty-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
     g_free(name);
     s->timer_tag = 0;
+    *be_opened = false;
 
     return chr;
 }
 
 static const CharDriver pty_driver = {
+    .instance_size = sizeof(PtyCharDriver),
     .kind = CHARDEV_BACKEND_KIND_PTY, .create = qemu_chr_open_pty,
     .chr_write = pty_chr_write,
     .chr_update_read_handler = pty_chr_update_read_handler,
@@ -1816,7 +1813,7 @@ static void tty_serial_init(int fd, int speed,
 
 static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 
     switch(cmd) {
@@ -1895,6 +1892,7 @@ static void qemu_chr_free_tty(CharDriverState *chr)
 #define HAVE_CHARDEV_PARPORT 1
 
 typedef struct {
+    CharDriverState parent;
     int fd;
     int mode;
 } ParallelCharDriver;
@@ -1912,7 +1910,7 @@ static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
 
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    ParallelCharDriver *drv = chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     int fd = drv->fd;
     uint8_t b;
 
@@ -1993,13 +1991,12 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 
 static void pp_free(CharDriverState *chr)
 {
-    ParallelCharDriver *drv = chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     int fd = drv->fd;
 
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
     ioctl(fd, PPRELEASE);
     close(fd);
-    g_free(drv);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -2023,9 +2020,7 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
         return NULL;
     }
 
-    drv = g_new0(ParallelCharDriver, 1);
-    chr->opaque = drv;
-
+    drv = (ParallelCharDriver *)chr;
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
@@ -2037,35 +2032,45 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 
 #define HAVE_CHARDEV_PARPORT 1
 
+typedef struct {
+    CharDriverState parent;
+    int fd;
+} ParallelCharDriver;
+
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)(intptr_t)chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     uint8_t b;
 
-    switch(cmd) {
+    switch (cmd) {
     case CHR_IOCTL_PP_READ_DATA:
-        if (ioctl(fd, PPIGDATA, &b) < 0)
+        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     case CHR_IOCTL_PP_WRITE_DATA:
         b = *(uint8_t *)arg;
-        if (ioctl(fd, PPISDATA, &b) < 0)
+        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
             return -ENOTSUP;
+        }
         break;
     case CHR_IOCTL_PP_READ_CONTROL:
-        if (ioctl(fd, PPIGCTRL, &b) < 0)
+        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     case CHR_IOCTL_PP_WRITE_CONTROL:
         b = *(uint8_t *)arg;
-        if (ioctl(fd, PPISCTRL, &b) < 0)
+        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
             return -ENOTSUP;
+        }
         break;
     case CHR_IOCTL_PP_READ_STATUS:
-        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     default:
@@ -2081,12 +2086,14 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
                                             Error **errp)
 {
     CharDriverState *chr;
+    ParallelCharDriver *drv;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    chr->opaque = (void *)(intptr_t)fd;
+    drv = (ParallelCharDriver *)chr;
+    drv->fd = fd;
     *be_opened = false;
     return chr;
 }
@@ -2097,6 +2104,7 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 #define HAVE_CHARDEV_SERIAL 1
 
 typedef struct {
+    CharDriverState parent;
     int max_size;
     HANDLE hcom, hrecv, hsend;
     OVERLAPPED orecv;
@@ -2108,6 +2116,7 @@ typedef struct {
 } WinCharState;
 
 typedef struct {
+    CharDriverState parent;
     HANDLE  hStdIn;
     HANDLE  hInputReadyEvent;
     HANDLE  hInputDoneEvent;
@@ -2125,7 +2134,7 @@ static int win_chr_pipe_poll(void *opaque);
 
 static void win_chr_free(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     if (s->hsend) {
         CloseHandle(s->hsend);
@@ -2149,7 +2158,7 @@ static void win_chr_free(CharDriverState *chr)
 
 static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     COMMCONFIG comcfg;
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
     COMSTAT comstat;
@@ -2217,7 +2226,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp
 /* Called with chr_write_lock held.  */
 static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     DWORD len, ret, size, err;
 
     len = len1;
@@ -2251,7 +2260,7 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
 
 static int win_chr_read_poll(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -2259,7 +2268,7 @@ static int win_chr_read_poll(CharDriverState *chr)
 
 static void win_chr_readfile(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     int ret, err;
     uint8_t buf[READ_BUF_LEN];
     DWORD size;
@@ -2281,7 +2290,7 @@ static void win_chr_readfile(CharDriverState *chr)
 
 static void win_chr_read(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     if (s->len > s->max_size)
         s->len = s->max_size;
@@ -2294,7 +2303,7 @@ static void win_chr_read(CharDriverState *chr)
 static int win_chr_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
+    WinCharState *s = opaque;
     COMSTAT status;
     DWORD comerr;
 
@@ -2311,7 +2320,7 @@ static int win_chr_poll(void *opaque)
 static int win_chr_pipe_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
+    WinCharState *s = opaque;
     DWORD size;
 
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
@@ -2327,7 +2336,7 @@ static int win_chr_pipe_poll(void *opaque)
 static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
                              Error **errp)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     OVERLAPPED ov;
     int ret;
     DWORD size;
@@ -2399,18 +2408,14 @@ static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
     ChardevHostdev *opts = backend->u.pipe.data;
     const char *filename = opts->device;
     CharDriverState *chr;
-    WinCharState *s;
     ChardevCommon *common = qapi_ChardevHostdev_base(opts);
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    s = g_new0(WinCharState, 1);
-    chr->opaque = s;
 
     if (win_chr_pipe_init(chr, filename, errp) < 0) {
-        g_free(s);
         qemu_chr_free_common(chr);
         return NULL;
     }
@@ -2429,9 +2434,8 @@ static CharDriverState *qemu_chr_open_win_file(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(WinCharState, 1);
+    s = (WinCharState *)chr;
     s->hcom = fd_out;
-    chr->opaque = s;
     return chr;
 }
 
@@ -2449,6 +2453,7 @@ static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
 }
 
 static const CharDriver console_driver = {
+    .instance_size = sizeof(WinCharState),
     .kind = CHARDEV_BACKEND_KIND_CONSOLE, .create = qemu_chr_open_win_con,
     .chr_write = win_chr_write,
 };
@@ -2475,7 +2480,7 @@ static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
 static void win_stdio_wait_func(void *opaque)
 {
     CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = opaque;
     INPUT_RECORD       buf[4];
     int                ret;
     DWORD              dwSize;
@@ -2508,8 +2513,7 @@ static void win_stdio_wait_func(void *opaque)
 
 static DWORD WINAPI win_stdio_thread(LPVOID param)
 {
-    CharDriverState   *chr   = param;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = param;
     int                ret;
     DWORD              dwSize;
 
@@ -2548,7 +2552,7 @@ static DWORD WINAPI win_stdio_thread(LPVOID param)
 static void win_stdio_thread_wait_func(void *opaque)
 {
     CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = opaque;
 
     if (qemu_chr_be_can_write(chr)) {
         qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
@@ -2559,7 +2563,7 @@ static void win_stdio_thread_wait_func(void *opaque)
 
 static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
 {
-    WinStdioCharState *stdio  = chr->opaque;
+    WinStdioCharState *stdio  = (WinStdioCharState *)chr;
     DWORD              dwMode = 0;
 
     GetConsoleMode(stdio->hStdIn, &dwMode);
@@ -2573,7 +2577,7 @@ static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
 
 static void win_stdio_free(CharDriverState *chr)
 {
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = (WinStdioCharState *)chr;
 
     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
         CloseHandle(stdio->hInputReadyEvent);
@@ -2584,8 +2588,6 @@ static void win_stdio_free(CharDriverState *chr)
     if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
         TerminateThread(stdio->hInputThread, 0);
     }
-
-    g_free(chr->opaque);
 }
 
 static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
@@ -2605,7 +2607,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    stdio = g_new0(WinStdioCharState, 1);
+    stdio = (WinStdioCharState *)chr;
 
     stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
     if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
@@ -2615,8 +2617,6 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 
     is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
 
-    chr->opaque    = stdio;
-
     if (is_console) {
         if (qemu_add_wait_object(stdio->hStdIn,
                                  win_stdio_wait_func, chr)) {
@@ -2676,6 +2676,7 @@ err1:
 /* UDP Net console */
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     uint8_t buf[READ_BUF_LEN];
     int bufcnt;
@@ -2686,7 +2687,7 @@ typedef struct {
 /* Called with chr_write_lock held.  */
 static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     return qio_channel_write(
         s->ioc, (const char *)buf, len, NULL);
@@ -2695,7 +2696,7 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int udp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
 
@@ -2713,7 +2714,7 @@ static int udp_chr_read_poll(void *opaque)
 static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = opaque;
     ssize_t ret;
 
     if (s->max_size == 0) {
@@ -2740,7 +2741,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static void udp_chr_update_read_handler(CharDriverState *chr,
                                         GMainContext *context)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2753,13 +2754,12 @@ static void udp_chr_update_read_handler(CharDriverState *chr,
 
 static void udp_chr_free(CharDriverState *chr)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
         object_unref(OBJECT(s->ioc));
     }
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -2767,6 +2767,7 @@ static void udp_chr_free(CharDriverState *chr)
 /* TCP Net console */
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc; /* Client I/O channel */
     QIOChannelSocket *sioc; /* Client master channel */
     QIOChannelSocket *listen_ioc;
@@ -2795,8 +2796,9 @@ static gboolean socket_reconnect_timeout(gpointer opaque);
 
 static void qemu_chr_socket_restart_timer(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     char *name;
+
     assert(s->connected == 0);
     s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
                                                socket_reconnect_timeout, chr);
@@ -2808,7 +2810,7 @@ static void qemu_chr_socket_restart_timer(CharDriverState *chr)
 static void check_report_connect_error(CharDriverState *chr,
                                        Error *err)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connect_err_reported) {
         error_report("Unable to connect character device %s: %s",
@@ -2825,7 +2827,8 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
 /* Called with chr_write_lock held.  */
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     if (s->connected) {
         int ret =  io_channel_send_full(s->ioc, buf, len,
                                         s->write_msgfds,
@@ -2848,7 +2851,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int tcp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     if (!s->connected)
         return 0;
     s->max_size = qemu_chr_be_can_write(chr);
@@ -2907,7 +2910,8 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
 
 static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
 
     assert(num <= TCP_MAX_FDS);
@@ -2932,7 +2936,7 @@ static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
 
 static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     /* clear old pending fd array */
     g_free(s->write_msgfds);
@@ -2957,7 +2961,7 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
 
 static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     struct iovec iov = { .iov_base = buf, .iov_len = len };
     int ret;
     size_t i;
@@ -3014,13 +3018,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 
 static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     return qio_channel_create_watch(s->ioc, cond);
 }
 
 static void tcp_chr_free_connection(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     int i;
 
     if (!s->connected) {
@@ -3049,7 +3053,7 @@ static void tcp_chr_free_connection(CharDriverState *chr)
 
 static void tcp_chr_disconnect(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connected) {
         return;
@@ -3072,7 +3076,7 @@ static void tcp_chr_disconnect(CharDriverState *chr)
 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     uint8_t buf[READ_BUF_LEN];
     int len, size;
 
@@ -3098,7 +3102,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     int size;
 
     if (!s->connected) {
@@ -3117,7 +3121,7 @@ static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
 static void tcp_chr_connect(void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
 
     g_free(chr->filename);
     chr->filename = sockaddr_to_str(
@@ -3138,7 +3142,7 @@ static void tcp_chr_connect(void *opaque)
 static void tcp_chr_update_read_handler(CharDriverState *chr,
                                         GMainContext *context)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connected) {
         return;
@@ -3189,7 +3193,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 
 static void tcp_chr_telnet_init(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     TCPCharDriverTelnetInit *init =
         g_new0(TCPCharDriverTelnetInit, 1);
     size_t n = 0;
@@ -3225,7 +3229,7 @@ static void tcp_chr_tls_handshake(Object *source,
                                   gpointer user_data)
 {
     CharDriverState *chr = user_data;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = user_data;
 
     if (err) {
         tcp_chr_disconnect(chr);
@@ -3241,7 +3245,7 @@ static void tcp_chr_tls_handshake(Object *source,
 
 static void tcp_chr_tls_init(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     QIOChannelTLS *tioc;
     Error *err = NULL;
     gchar *name;
@@ -3280,7 +3284,7 @@ static void tcp_chr_tls_init(CharDriverState *chr)
 static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
                                         QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     char *name;
     name = g_strdup_printf("chardev-tcp-%s-%s",
                            s->is_listen ? "server" : "client",
@@ -3292,7 +3296,8 @@ static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
 
 static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     if (s->ioc != NULL) {
 	return -1;
     }
@@ -3363,7 +3368,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
 
 static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     QIOChannelSocket *sioc;
 
     /* It can't wait on s->connected, since it is set asynchronously
@@ -3411,7 +3416,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 
 static void tcp_chr_free(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     tcp_chr_free_connection(chr);
 
@@ -3430,7 +3435,7 @@ static void tcp_chr_free(CharDriverState *chr)
     if (s->tls_creds) {
         object_unref(OBJECT(s->tls_creds));
     }
-    g_free(s);
+
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -3439,7 +3444,7 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 {
     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (err) {
         check_report_connect_error(chr, err);
@@ -3457,6 +3462,7 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 /* Ring buffer chardev */
 
 typedef struct {
+    CharDriverState parent;
     size_t size;
     size_t prod;
     size_t cons;
@@ -3465,7 +3471,7 @@ typedef struct {
 
 static size_t ringbuf_count(const CharDriverState *chr)
 {
-    const RingBufCharDriver *d = chr->opaque;
+    const RingBufCharDriver *d = (RingBufCharDriver *)chr;
 
     return d->prod - d->cons;
 }
@@ -3473,7 +3479,7 @@ static size_t ringbuf_count(const CharDriverState *chr)
 /* Called with chr_write_lock held.  */
 static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
     int i;
 
     if (!buf || (len < 0)) {
@@ -3492,7 +3498,7 @@ static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
     int i;
 
     qemu_mutex_lock(&chr->chr_write_lock);
@@ -3506,11 +3512,9 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
 
 static void ringbuf_chr_free(struct CharDriverState *chr)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
 
     g_free(d->cbuf);
-    g_free(d);
-    chr->opaque = NULL;
 }
 
 static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
@@ -3529,7 +3533,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    d = g_malloc(sizeof(*d));
+    d = (RingBufCharDriver *)chr;
 
     d->size = opts->has_size ? opts->size : 65536;
 
@@ -3543,12 +3547,9 @@ static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
     d->cons = 0;
     d->cbuf = g_malloc0(d->size);
 
-    chr->opaque = d;
-
     return chr;
 
 fail:
-    g_free(d);
     qemu_chr_free_common(chr);
     return NULL;
 }
@@ -3838,10 +3839,12 @@ static const CharDriver stdio_driver = {
     .kind = CHARDEV_BACKEND_KIND_STDIO,
     .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio,
 #ifdef _WIN32
+    sizeof(WinStdioCharState),
     .chr_write = win_stdio_write,
     .chr_set_echo = qemu_chr_set_echo_win_stdio,
     .chr_free = win_stdio_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3903,9 +3906,11 @@ static const CharDriver pipe_driver = {
     .kind = CHARDEV_BACKEND_KIND_PIPE,
     .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3930,6 +3935,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver ringbuf_driver = {
+    .instance_size = sizeof(RingBufCharDriver),
     .kind = CHARDEV_BACKEND_KIND_RINGBUF,
     .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
     .chr_write = ringbuf_chr_write,
@@ -3938,6 +3944,7 @@ static const CharDriver ringbuf_driver = {
 
 /* Bug-compatibility: */
 static const CharDriver memory_driver = {
+    .instance_size = sizeof(RingBufCharDriver),
     .kind = CHARDEV_BACKEND_KIND_MEMORY,
     .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
     .chr_write = ringbuf_chr_write,
@@ -3960,6 +3967,7 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver mux_driver = {
+    .instance_size = sizeof(MuxDriver),
     .kind = CHARDEV_BACKEND_KIND_MUX,
     .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
     .chr_free = mux_chr_free,
@@ -4548,17 +4556,13 @@ static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
     CharDriverState *chr;
-    WinCharState *s;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
 
-    s = g_new0(WinCharState, 1);
-    chr->opaque = s;
     if (win_chr_init(chr, serial->device, errp) < 0) {
-        g_free(s);
         qemu_chr_free_common(chr);
         return NULL;
     }
@@ -4658,6 +4662,7 @@ static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
 }
 
 static const CharDriver parallel_driver = {
+    .instance_size = sizeof(ParallelCharDriver),
     .alias = "parport", .kind = CHARDEV_BACKEND_KIND_PARALLEL,
     .parse = qemu_chr_parse_parallel, .create = qmp_chardev_open_parallel,
 #if defined(__linux__)
@@ -4678,9 +4683,11 @@ static const CharDriver file_driver = {
     .kind = CHARDEV_BACKEND_KIND_FILE,
     .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     /* FIXME: no chr_free */
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4693,9 +4700,11 @@ static const CharDriver serial_driver = {
     .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
     .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4708,7 +4717,7 @@ static const CharDriver serial_driver = {
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     QIOChannelSocket *sioc;
 
     s->reconnect_timer = 0;
@@ -4749,7 +4758,7 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(TCPCharDriver, 1);
+    s = (TCPCharDriver *)chr;
 
     s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
@@ -4795,7 +4804,6 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
         qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
     }
 
-    chr->opaque = s;
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
@@ -4852,12 +4860,12 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
     if (s->tls_creds) {
         object_unref(OBJECT(s->tls_creds));
     }
-    g_free(s);
     qemu_chr_free_common(chr);
     return NULL;
 }
 
 static const CharDriver socket_driver = {
+    .instance_size = sizeof(TCPCharDriver),
     .kind = CHARDEV_BACKEND_KIND_SOCKET,
     .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket,
     .chr_wait_connected = tcp_chr_wait_connected,
@@ -4902,11 +4910,10 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
-    s = g_new0(NetCharDriver, 1);
+    s = (NetCharDriver *)chr;
     s->ioc = QIO_CHANNEL(sioc);
     s->bufcnt = 0;
     s->bufptr = 0;
-    chr->opaque = s;
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
@@ -4914,6 +4921,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
 }
 
 static const CharDriver udp_driver = {
+    .instance_size = sizeof(NetCharDriver),
     .kind = CHARDEV_BACKEND_KIND_UDP,
     .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
     .chr_write = udp_chr_write,
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index da3a9c4547..4118059c96 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -7,7 +7,8 @@
 
 
 typedef struct SpiceCharDriver {
-    CharDriverState*      chr;
+    CharDriverState       parent;
+
     SpiceCharDeviceInstance     sin;
     bool                  active;
     bool                  blocked;
@@ -27,17 +28,18 @@ static QLIST_HEAD(, SpiceCharDriver) spice_chars =
 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
 {
     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    CharDriverState *chr = (CharDriverState *)scd;
     ssize_t out = 0;
     ssize_t last_out;
     uint8_t* p = (uint8_t*)buf;
 
     while (len > 0) {
-        int can_write = qemu_chr_be_can_write(scd->chr);
+        int can_write = qemu_chr_be_can_write(chr);
         last_out = MIN(len, can_write);
         if (last_out <= 0) {
             break;
         }
-        qemu_chr_be_write(scd->chr, p, last_out);
+        qemu_chr_be_write(chr, p, last_out);
         out += last_out;
         len -= last_out;
         p += last_out;
@@ -70,6 +72,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
 {
     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    CharDriverState *chr = (CharDriverState *)scd;
     int chr_event;
 
     switch (event) {
@@ -81,20 +84,21 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
     }
 
     trace_spice_vmc_event(chr_event);
-    qemu_chr_be_event(scd->chr, chr_event);
+    qemu_chr_be_event(chr, chr_event);
 }
 #endif
 
 static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
 {
     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    CharDriverState *chr = (CharDriverState *)scd;
 
-    if ((scd->chr->be_open && connected) ||
-        (!scd->chr->be_open && !connected)) {
+    if ((chr->be_open && connected) ||
+        (!chr->be_open && !connected)) {
         return;
     }
 
-    qemu_chr_be_event(scd->chr,
+    qemu_chr_be_event(chr,
                       connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
 }
 
@@ -168,7 +172,7 @@ static GSourceFuncs SpiceCharSourceFuncs = {
 
 static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    SpiceCharDriver *scd = chr->opaque;
+    SpiceCharDriver *scd = (SpiceCharDriver *)chr;
     SpiceCharSource *src;
 
     assert(cond & G_IO_OUT);
@@ -182,7 +186,7 @@ static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 
 static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    SpiceCharDriver *s = chr->opaque;
+    SpiceCharDriver *s = (SpiceCharDriver *)chr;
     int read_bytes;
 
     assert(s->datalen == 0);
@@ -201,7 +205,7 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static void spice_chr_free(struct CharDriverState *chr)
 {
-    SpiceCharDriver *s = chr->opaque;
+    SpiceCharDriver *s = (SpiceCharDriver *)chr;
 
     vmc_unregister_interface(s);
     QLIST_REMOVE(s, next);
@@ -210,12 +214,11 @@ static void spice_chr_free(struct CharDriverState *chr)
 #if SPICE_SERVER_VERSION >= 0x000c02
     g_free((char *)s->sin.portname);
 #endif
-    g_free(s);
 }
 
 static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
 {
-    SpiceCharDriver *s = chr->opaque;
+    SpiceCharDriver *s = (SpiceCharDriver *)chr;
     if (fe_open) {
         vmc_register_interface(s);
     } else {
@@ -226,7 +229,7 @@ static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
 static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
 {
 #if SPICE_SERVER_VERSION >= 0x000c02
-    SpiceCharDriver *s = chr->opaque;
+    SpiceCharDriver *s = (SpiceCharDriver *)chr;
 
     if (fe_open) {
         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
@@ -255,7 +258,7 @@ static void print_allowed_subtypes(void)
 
 static void spice_chr_accept_input(struct CharDriverState *chr)
 {
-    SpiceCharDriver *s = chr->opaque;
+    SpiceCharDriver *s = (SpiceCharDriver *)chr;
 
     spice_server_char_device_wakeup(&s->sin);
 }
@@ -272,11 +275,9 @@ static CharDriverState *chr_open(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_malloc0(sizeof(SpiceCharDriver));
-    s->chr = chr;
+    s = (SpiceCharDriver *)chr;
     s->active = false;
     s->sin.subtype = g_strdup(subtype);
-    chr->opaque = s;
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
 
@@ -334,7 +335,7 @@ static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
         return NULL;
     }
     *be_opened = false;
-    s = chr->opaque;
+    s = (SpiceCharDriver *)chr;
     s->sin.portname = g_strdup(name);
 
     return chr;
@@ -386,6 +387,7 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
 static void register_types(void)
 {
     static const CharDriver vmc_driver = {
+        .instance_size = sizeof(SpiceCharDriver),
         .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
         .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc,
         .chr_write = spice_chr_write,
@@ -395,6 +397,7 @@ static void register_types(void)
         .chr_free = spice_chr_free,
     };
     static const CharDriver port_driver = {
+        .instance_size = sizeof(SpiceCharDriver),
         .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
         .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port,
         .chr_write = spice_chr_write,
diff --git a/ui/console.c b/ui/console.c
index 41becd1ca7..cda1b56024 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1035,9 +1035,15 @@ void console_select(unsigned int index)
     }
 }
 
+typedef struct VCDriverState {
+    CharDriverState parent;
+    QemuConsole *console;
+} VCDriverState;
+
 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    QemuConsole *s = chr->opaque;
+    VCDriverState *drv = (VCDriverState *)chr;
+    QemuConsole *s = drv->console;
     int i;
 
     if (!s->ds) {
@@ -1947,7 +1953,8 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
 
 static void text_console_set_echo(CharDriverState *chr, bool echo)
 {
-    QemuConsole *s = chr->opaque;
+    VCDriverState *drv = (VCDriverState *)chr;
+    QemuConsole *s = drv->console;
 
     s->echo = echo;
 }
@@ -1987,12 +1994,11 @@ static const GraphicHwOps text_console_ops = {
 
 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 {
-    QemuConsole *s;
+    VCDriverState *drv = (VCDriverState *)chr;
+    QemuConsole *s = drv->console;
     int g_width = 80 * FONT_WIDTH;
     int g_height = 24 * FONT_HEIGHT;
 
-    s = chr->opaque;
-
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
@@ -2045,6 +2051,7 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 {
     ChardevCommon *common = qapi_ChardevVC_base(vc);
     CharDriverState *chr;
+    VCDriverState *drv;
     QemuConsole *s;
     unsigned width = 0;
     unsigned height = 0;
@@ -2081,7 +2088,8 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
     }
 
     s->chr = chr;
-    chr->opaque = s;
+    drv = (VCDriverState *)chr;
+    drv->console = s;
 
     if (display_state) {
         text_console_do_init(chr, display_state);
@@ -2185,6 +2193,7 @@ static const TypeInfo qemu_console_info = {
 };
 
 static const CharDriver vc_driver = {
+    .instance_size = sizeof(VCDriverState),
     .kind = CHARDEV_BACKEND_KIND_VC,
     .parse = qemu_chr_parse_vc, .create = vc_init,
     .chr_write = console_puts,
diff --git a/ui/gtk.c b/ui/gtk.c
index 575651abcb..feca4047e2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -178,6 +178,12 @@ struct GtkDisplayState {
     bool ignore_keys;
 };
 
+typedef struct VCDriverState {
+    CharDriverState parent;
+    VirtualConsole *console;
+    bool echo;
+} VCDriverState;
+
 static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
 static void gd_ungrab_pointer(GtkDisplayState *s);
 static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
@@ -1675,7 +1681,8 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
 
 static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    VirtualConsole *vc = chr->opaque;
+    VCDriverState *vcd = (VCDriverState *)chr;
+    VirtualConsole *vc = vcd->console;
 
     vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
     return len;
@@ -1683,9 +1690,14 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
 {
-    VirtualConsole *vc = chr->opaque;
+    VCDriverState *vcd = (VCDriverState *)chr;
+    VirtualConsole *vc = vcd->console;
 
-    vc->vte.echo = echo;
+    if (vc) {
+        vc->vte.echo = echo;
+    } else {
+        vcd->echo = echo;
+    }
 }
 
 static int nb_vcs;
@@ -1694,6 +1706,7 @@ static CharDriverState *vcs[MAX_VCS];
 static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
 {
     static const CharDriver gd_vc_driver = {
+        .instance_size = sizeof(VCDriverState),
         .kind = CHARDEV_BACKEND_KIND_VC,
         .chr_write = gd_vc_chr_write,
         .chr_set_echo = gd_vc_chr_set_echo,
@@ -1712,9 +1725,6 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
         return NULL;
     }
 
-    /* Temporary, until gd_vc_vte_init runs.  */
-    chr->opaque = g_new0(VirtualConsole, 1);
-
     vcs[nb_vcs++] = chr;
 
     return chr;
@@ -1755,14 +1765,12 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
     GtkWidget *box;
     GtkWidget *scrollbar;
     GtkAdjustment *vadjustment;
-    VirtualConsole *tmp_vc = chr->opaque;
+    VCDriverState *vcd = (VCDriverState *)chr;
 
     vc->s = s;
-    vc->vte.echo = tmp_vc->vte.echo;
-
+    vc->vte.echo = vcd->echo;
     vc->vte.chr = chr;
-    chr->opaque = vc;
-    g_free(tmp_vc);
+    vcd->console = vc;
 
     snprintf(buffer, sizeof(buffer), "vc%d", idx);
     vc->label = g_strdup_printf("%s", vc->vte.chr->label
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 07dfa59afe..5d8ec982a9 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -93,7 +93,6 @@ struct CharDriverState {
     const CharDriver *driver;
     QemuMutex chr_write_lock;
     CharBackend *be;
-    void *opaque;
     char *label;
     char *filename;
     int logfd;
@@ -482,6 +481,7 @@ struct CharDriver {
                                ChardevBackend *backend,
                                ChardevReturn *ret, bool *be_opened,
                                Error **errp);
+    size_t instance_size;
 
     int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
     int (*chr_sync_read)(struct CharDriverState *s,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc()
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (7 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 21:18   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev Marc-André Lureau
                   ` (46 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Use common allocator for CharDriverState.

Rename the now untouched parent field.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/bt/hci-csr.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index bf2deb0497..e2c78b8720 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -26,9 +26,10 @@
 #include "hw/irq.h"
 #include "sysemu/bt.h"
 #include "hw/bt.h"
+#include "qapi/error.h"
 
 struct csrhci_s {
-    CharDriverState chr;
+    CharDriverState parent;
     int enable;
     qemu_irq *pins;
     int pin_state;
@@ -78,7 +79,8 @@ enum {
 
 static inline void csrhci_fifo_wake(struct csrhci_s *s)
 {
-    CharBackend *be = s->chr.be;
+    CharDriverState *chr = (CharDriverState *)s;
+    CharBackend *be = chr->be;
 
     if (!s->enable || !s->out_len)
         return;
@@ -468,10 +470,15 @@ CharDriverState *uart_hci_init(void)
         .chr_write = csrhci_write,
         .chr_ioctl = csrhci_ioctl,
     };
-    struct csrhci_s *s = (struct csrhci_s *)
-            g_malloc0(sizeof(struct csrhci_s));
+    Error *err = NULL;
+    ChardevCommon common = { 0, };
+    CharDriverState *chr = qemu_chr_alloc(&hci_driver, &common, &err);
+    struct csrhci_s *s = (struct csrhci_s *)chr;
 
-    s->chr.driver = &hci_driver;
+    if (err) {
+        error_report_err(err);
+        return NULL;
+    }
 
     s->hci = qemu_next_hci();
     s->hci->opaque = s;
@@ -482,5 +489,5 @@ CharDriverState *uart_hci_init(void)
     s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
     csrhci_reset(s);
 
-    return &s->chr;
+    return chr;
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (8 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc() Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 21:30   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev Marc-André Lureau
                   ` (45 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Uniformify chardev type name.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c                   |  56 +--
 backends/msmouse.c                |  42 +-
 backends/rng-egd.c                |   4 +-
 backends/testdev.c                |  28 +-
 gdbstub.c                         |  12 +-
 hw/arm/fsl-imx25.c                |   2 +-
 hw/arm/fsl-imx31.c                |   2 +-
 hw/arm/fsl-imx6.c                 |   2 +-
 hw/arm/nseries.c                  |   2 +-
 hw/arm/omap2.c                    |   2 +-
 hw/arm/pxa2xx.c                   |   2 +-
 hw/arm/virt.c                     |   2 +-
 hw/bt/hci-csr.c                   |  14 +-
 hw/char/escc.c                    |   2 +-
 hw/char/exynos4210_uart.c         |   2 +-
 hw/char/imx_serial.c              |   2 +-
 hw/char/mcf_uart.c                |   4 +-
 hw/char/omap_uart.c               |   6 +-
 hw/char/parallel.c                |   2 +-
 hw/char/serial-isa.c              |   2 +-
 hw/char/serial.c                  |   4 +-
 hw/char/sh_serial.c               |   2 +-
 hw/char/spapr_vty.c               |   2 +-
 hw/char/virtio-console.c          |   2 +-
 hw/core/qdev-properties-system.c  |   4 +-
 hw/display/milkymist-tmu2.c       |   2 +-
 hw/display/sm501.c                |   2 +-
 hw/isa/isa-bus.c                  |   2 +-
 hw/isa/pc87312.c                  |   2 +-
 hw/mips/mips_malta.c              |   4 +-
 hw/misc/ivshmem.c                 |   2 +-
 hw/misc/milkymist-pfpu.c          |   2 +-
 hw/usb/ccid-card-passthru.c       |   2 +-
 hw/usb/dev-serial.c               |   6 +-
 hw/usb/redirect.c                 |   4 +-
 monitor.c                         |   4 +-
 net/colo-compare.c                |   4 +-
 net/filter-mirror.c               |   4 +-
 net/slirp.c                       |   2 +-
 net/vhost-user.c                  |  10 +-
 qemu-char.c                       | 839 +++++++++++++++++++-------------------
 qmp.c                             |   2 +-
 qtest.c                           |   2 +-
 replay/replay-char.c              |   8 +-
 spice-qemu-char.c                 |  80 ++--
 stubs/get-next-serial.c           |   2 +-
 stubs/monitor-init.c              |   2 +-
 stubs/replay.c                    |   4 +-
 tests/test-char.c                 |  10 +-
 tests/vhost-user-test.c           |   4 +-
 ui/console.c                      |  40 +-
 ui/gtk.c                          |  26 +-
 vl.c                              |  10 +-
 xen-common-stub.c                 |   2 +-
 xen-common.c                      |   4 +-
 hw/lm32/lm32.h                    |   4 +-
 hw/lm32/milkymist-hw.h            |   2 +-
 include/hw/arm/exynos4210.h       |   2 +-
 include/hw/arm/omap.h             |   6 +-
 include/hw/bt.h                   |   4 +-
 include/hw/char/cadence_uart.h    |   2 +-
 include/hw/char/escc.h            |   2 +-
 include/hw/char/pl011.h           |   4 +-
 include/hw/char/serial.h          |   4 +-
 include/hw/char/xilinx_uartlite.h |   2 +-
 include/hw/cris/etraxfs.h         |   2 +-
 include/hw/devices.h              |   2 +-
 include/hw/i386/pc.h              |   2 +-
 include/hw/m68k/mcf.h             |   4 +-
 include/hw/ppc/spapr_vio.h        |   2 +-
 include/hw/qdev-properties.h      |   2 +-
 include/hw/sh4/sh.h               |   2 +-
 include/hw/sparc/grlib.h          |   2 +-
 include/hw/xen/xen.h              |   2 +-
 include/monitor/monitor.h         |   2 +-
 include/qemu/typedefs.h           |   2 +-
 include/sysemu/char.h             |  94 ++---
 include/sysemu/replay.h           |   4 +-
 include/sysemu/sysemu.h           |   4 +-
 include/ui/gtk.h                  |   2 +-
 include/ui/qemu-spice.h           |   2 +-
 81 files changed, 728 insertions(+), 725 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index 6244929ac6..7fd1ebc557 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -87,7 +87,7 @@
 #define BUF_SIZE 256
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
 
     brlapi_handle_t *brlapi;
     int brlapi_fd;
@@ -100,7 +100,7 @@ typedef struct {
     uint8_t out_buf_used, out_buf_ptr;
 
     QEMUTimer *cellCount_timer;
-} BaumDriverState;
+} BaumChardev;
 
 /* Let's assume NABCC by default */
 enum way {
@@ -225,7 +225,7 @@ static const uint8_t nabcc_translation[2][256] = {
 };
 
 /* The guest OS has started discussing with us, finish initializing BrlAPI */
-static int baum_deferred_init(BaumDriverState *baum)
+static int baum_deferred_init(BaumChardev *baum)
 {
 #if defined(CONFIG_SDL)
 #if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
@@ -268,9 +268,9 @@ static int baum_deferred_init(BaumDriverState *baum)
 }
 
 /* The serial port can receive more of our data */
-static void baum_accept_input(struct CharDriverState *chr)
+static void baum_accept_input(struct Chardev *chr)
 {
-    BaumDriverState *baum = (BaumDriverState *)chr;
+    BaumChardev *baum = (BaumChardev *)chr;
     int room, first;
 
     if (!baum->out_buf_used)
@@ -294,9 +294,9 @@ static void baum_accept_input(struct CharDriverState *chr)
 }
 
 /* We want to send a packet */
-static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
+static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
 {
-    CharDriverState *chr = (CharDriverState *)baum;
+    Chardev *chr = (Chardev *)baum;
     uint8_t io_buf[1 + 2 * len], *cur = io_buf;
     int room;
     *cur++ = ESC;
@@ -337,14 +337,14 @@ static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len
 /* Called when the other end seems to have a wrong idea of our display size */
 static void baum_cellCount_timer_cb(void *opaque)
 {
-    BaumDriverState *baum = opaque;
+    BaumChardev *baum = opaque;
     uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
     DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
     baum_write_packet(baum, cell_count, sizeof(cell_count));
 }
 
 /* Try to interpret a whole incoming packet */
-static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
+static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
 {
     const uint8_t *cur = buf;
     uint8_t req = 0;
@@ -485,9 +485,9 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 }
 
 /* The other end is writing some data.  Store it and try to interpret */
-static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int baum_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    BaumDriverState *baum = (BaumDriverState *)chr;
+    BaumChardev *baum = (BaumChardev *)chr;
     int tocopy, cur, eaten, orig_len = len;
 
     if (!len)
@@ -526,14 +526,16 @@ static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
 }
 
 /* Send the key code to the other end */
-static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
+static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value)
+{
     uint8_t packet[] = { type, value };
     DPRINTF("writing key %x %x\n", type, value);
     baum_write_packet(baum, packet, sizeof(packet));
 }
 
-static void baum_send_key2(BaumDriverState *baum, uint8_t type, uint8_t value,
-                           uint8_t value2) {
+static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
+                           uint8_t value2)
+{
     uint8_t packet[] = { type, value, value2 };
     DPRINTF("writing key %x %x\n", type, value);
     baum_write_packet(baum, packet, sizeof(packet));
@@ -542,7 +544,7 @@ static void baum_send_key2(BaumDriverState *baum, uint8_t type, uint8_t value,
 /* We got some data on the BrlAPI socket */
 static void baum_chr_read(void *opaque)
 {
-    BaumDriverState *baum = opaque;
+    BaumChardev *baum = opaque;
     brlapi_keyCode_t code;
     int ret;
     if (!baum->brlapi)
@@ -626,9 +628,9 @@ static void baum_chr_read(void *opaque)
     }
 }
 
-static void baum_free(struct CharDriverState *chr)
+static void baum_free(struct Chardev *chr)
 {
-    BaumDriverState *baum = (BaumDriverState *)chr;
+    BaumChardev *baum = (BaumChardev *)chr;
 
     timer_free(baum->cellCount_timer);
     if (baum->brlapi) {
@@ -637,23 +639,23 @@ static void baum_free(struct CharDriverState *chr)
     }
 }
 
-static CharDriverState *chr_baum_init(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static Chardev *chr_baum_init(const CharDriver *driver,
+                              const char *id,
+                              ChardevBackend *backend,
+                              ChardevReturn *ret,
+                              bool *be_opened,
+                              Error **errp)
 {
     ChardevCommon *common = backend->u.braille.data;
-    BaumDriverState *baum;
-    CharDriverState *chr;
+    BaumChardev *baum;
+    Chardev *chr;
     brlapi_handle_t *handle;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    baum = (BaumDriverState *)chr;
+    baum = (BaumChardev *)chr;
 
     handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
@@ -681,7 +683,7 @@ fail_handle:
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(BaumDriverState),
+        .instance_size = sizeof(BaumChardev),
         .kind = CHARDEV_BACKEND_KIND_BRAILLE,
         .parse = NULL, .create = chr_baum_init,
         .chr_write = baum_write,
diff --git a/backends/msmouse.c b/backends/msmouse.c
index e954720e28..fabc2926d6 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -31,7 +31,7 @@
 #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
 
     QemuInputHandlerState *hs;
     int axis[INPUT_AXIS__MAX];
@@ -39,11 +39,11 @@ typedef struct {
     bool btnc[INPUT_BUTTON__MAX];
     uint8_t outbuf[32];
     int outlen;
-} MouseState;
+} MouseChardev;
 
-static void msmouse_chr_accept_input(CharDriverState *chr)
+static void msmouse_chr_accept_input(Chardev *chr)
 {
-    MouseState *mouse = (MouseState *)chr;
+    MouseChardev *mouse = (MouseChardev *)chr;
     int len;
 
     len = qemu_chr_be_can_write(chr);
@@ -61,7 +61,7 @@ static void msmouse_chr_accept_input(CharDriverState *chr)
     }
 }
 
-static void msmouse_queue_event(MouseState *mouse)
+static void msmouse_queue_event(MouseChardev *mouse)
 {
     unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
     int dx, dy, count = 3;
@@ -98,7 +98,7 @@ static void msmouse_queue_event(MouseState *mouse)
 static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
                                 InputEvent *evt)
 {
-    MouseState *mouse = (MouseState *)dev;
+    MouseChardev *mouse = (MouseChardev *)dev;
     InputMoveEvent *move;
     InputBtnEvent *btn;
 
@@ -122,22 +122,22 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
 
 static void msmouse_input_sync(DeviceState *dev)
 {
-    MouseState *mouse = (MouseState *)dev;
-    CharDriverState *chr = (CharDriverState *)dev;
+    MouseChardev *mouse = (MouseChardev *)dev;
+    Chardev *chr = (Chardev *)dev;
 
     msmouse_queue_event(mouse);
     msmouse_chr_accept_input(chr);
 }
 
-static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
+static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
 {
     /* Ignore writes to mouse port */
     return len;
 }
 
-static void msmouse_chr_free(struct CharDriverState *chr)
+static void msmouse_chr_free(struct Chardev *chr)
 {
-    MouseState *mouse = (MouseState *)chr;
+    MouseChardev *mouse = (MouseChardev *)chr;
 
     qemu_input_handler_unregister(mouse->hs);
 }
@@ -149,16 +149,16 @@ static QemuInputHandler msmouse_handler = {
     .sync  = msmouse_input_sync,
 };
 
-static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
-                                              const char *id,
-                                              ChardevBackend *backend,
-                                              ChardevReturn *ret,
-                                              bool *be_opened,
-                                              Error **errp)
+static Chardev *qemu_chr_open_msmouse(const CharDriver *driver,
+                                      const char *id,
+                                      ChardevBackend *backend,
+                                      ChardevReturn *ret,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevCommon *common = backend->u.msmouse.data;
-    MouseState *mouse;
-    CharDriverState *chr;
+    MouseChardev *mouse;
+    Chardev *chr;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
@@ -166,7 +166,7 @@ static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
     }
     *be_opened = false;
 
-    mouse = (MouseState *)chr;
+    mouse = (MouseChardev *)chr;
     mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
                                             &msmouse_handler);
 
@@ -177,7 +177,7 @@ static CharDriverState *qemu_chr_open_msmouse(const CharDriver *driver,
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(MouseState),
+        .instance_size = sizeof(MouseChardev),
         .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
         .parse = NULL, .create = qemu_chr_open_msmouse,
         .chr_write = msmouse_chr_write,
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 69c04b1b26..380b19a0a1 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -86,7 +86,7 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
 static void rng_egd_opened(RngBackend *b, Error **errp)
 {
     RngEgd *s = RNG_EGD(b);
-    CharDriverState *chr;
+    Chardev *chr;
 
     if (s->chr_name == NULL) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
@@ -125,7 +125,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
 static char *rng_egd_get_chardev(Object *obj, Error **errp)
 {
     RngEgd *s = RNG_EGD(obj);
-    CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
+    Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
 
     if (chr && chr->label) {
         return g_strdup(chr->label);
diff --git a/backends/testdev.c b/backends/testdev.c
index 69cf188b95..1d06c8633e 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -30,14 +30,14 @@
 #define BUF_SIZE 32
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
 
     uint8_t in_buf[32];
     int in_buf_used;
-} TestdevCharState;
+} TestdevChardev;
 
 /* Try to interpret a whole incoming packet */
-static int testdev_eat_packet(TestdevCharState *testdev)
+static int testdev_eat_packet(TestdevChardev *testdev)
 {
     const uint8_t *cur = testdev->in_buf;
     int len = testdev->in_buf_used;
@@ -78,9 +78,9 @@ static int testdev_eat_packet(TestdevCharState *testdev)
 }
 
 /* The other end is writing some data.  Store it and try to interpret */
-static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    TestdevCharState *testdev = (TestdevCharState *)chr;
+    TestdevChardev *testdev = (TestdevChardev *)chr;
     int tocopy, eaten, orig_len = len;
 
     while (len) {
@@ -103,15 +103,15 @@ static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
     return orig_len;
 }
 
-static CharDriverState *chr_testdev_init(const CharDriver *driver,
-                                         const char *id,
-                                         ChardevBackend *backend,
-                                         ChardevReturn *ret,
-                                         bool *be_opened,
-                                         Error **errp)
+static Chardev *chr_testdev_init(const CharDriver *driver,
+                                 const char *id,
+                                 ChardevBackend *backend,
+                                 ChardevReturn *ret,
+                                 bool *be_opened,
+                                 Error **errp)
 {
-    TestdevCharState *testdev = g_new0(TestdevCharState, 1);;
-    CharDriverState *chr = (CharDriverState *)testdev;
+    TestdevChardev *testdev = g_new0(TestdevChardev, 1);;
+    Chardev *chr = (Chardev *)testdev;
 
     chr->driver = driver;
 
@@ -121,7 +121,7 @@ static CharDriverState *chr_testdev_init(const CharDriver *driver,
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(TestdevCharState),
+        .instance_size = sizeof(TestdevChardev),
         .kind = CHARDEV_BACKEND_KIND_TESTDEV,
         .parse = NULL, .create = chr_testdev_init,
         .chr_write = testdev_write,
diff --git a/gdbstub.c b/gdbstub.c
index a8def2fd6f..22fa291bc9 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -303,7 +303,7 @@ typedef struct GDBState {
     int running_state;
 #else
     CharBackend chr;
-    CharDriverState *mon_chr;
+    Chardev *mon_chr;
 #endif
     char syscall_buf[256];
     gdb_syscall_complete_cb current_syscall_cb;
@@ -1471,7 +1471,7 @@ void gdb_exit(CPUArchState *env, int code)
   GDBState *s;
   char buf[4];
 #ifndef CONFIG_USER_ONLY
-  CharDriverState *chr;
+  Chardev *chr;
 #endif
 
   s = gdbserver_state;
@@ -1696,7 +1696,7 @@ static void gdb_monitor_output(GDBState *s, const char *msg, int len)
     put_packet(s, buf);
 }
 
-static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
 {
     const char *p = (const char *)buf;
     int max_sz;
@@ -1727,11 +1727,11 @@ int gdbserver_start(const char *device)
 {
     GDBState *s;
     char gdbstub_device_name[128];
-    CharDriverState *chr = NULL;
-    CharDriverState *mon_chr;
+    Chardev *chr = NULL;
+    Chardev *mon_chr;
     ChardevCommon common = { 0 };
     static const CharDriver driver = {
-        .instance_size = sizeof(CharDriverState),
+        .instance_size = sizeof(Chardev),
         .kind = -1,
         .chr_write = gdb_monitor_write
     };
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 7bb7be76b6..2126f73ca0 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -118,7 +118,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
         };
 
         if (i < MAX_SERIAL_PORTS) {
-            CharDriverState *chr;
+            Chardev *chr;
 
             chr = serial_hds[i];
 
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index f23672b222..dd1c713ae3 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -107,7 +107,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
         };
 
         if (i < MAX_SERIAL_PORTS) {
-            CharDriverState *chr;
+            Chardev *chr;
 
             chr = serial_hds[i];
 
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index e93532fb57..76dd8a48ca 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -187,7 +187,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
         };
 
         if (i < MAX_SERIAL_PORTS) {
-            CharDriverState *chr;
+            Chardev *chr;
 
             chr = serial_hds[i];
 
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index c86cf80514..503a3b6d24 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -786,7 +786,7 @@ static void n8x0_cbus_setup(struct n800_s *s)
 
 static void n8x0_uart_setup(struct n800_s *s)
 {
-    CharDriverState *radio = uart_hci_init();
+    Chardev *radio = uart_hci_init();
 
     qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
                     csrhci_pins_get(radio)[csrhci_pin_reset]);
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 6f05c98d3e..cf1b4ba58f 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -792,7 +792,7 @@ static const MemoryRegionOps omap_sti_fifo_ops = {
 static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
                 MemoryRegion *sysmem,
                 hwaddr channel_base, qemu_irq irq, omap_clk clk,
-                CharDriverState *chr)
+                Chardev *chr)
 {
     struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
 
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 21ea1d6210..6467bb362e 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -2029,7 +2029,7 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
                                        hwaddr base,
                                        qemu_irq irq, qemu_irq rx_dma,
                                        qemu_irq tx_dma,
-                                       CharDriverState *chr)
+                                       Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *sbd;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d04e4acbd9..c10ddaac9c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -626,7 +626,7 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type,
 }
 
 static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart,
-                        MemoryRegion *mem, CharDriverState *chr)
+                        MemoryRegion *mem, Chardev *chr)
 {
     char *nodename;
     hwaddr base = vbi->memmap[uart].base;
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index e2c78b8720..153ed2f1ba 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -29,7 +29,7 @@
 #include "qapi/error.h"
 
 struct csrhci_s {
-    CharDriverState parent;
+    Chardev parent;
     int enable;
     qemu_irq *pins;
     int pin_state;
@@ -79,7 +79,7 @@ enum {
 
 static inline void csrhci_fifo_wake(struct csrhci_s *s)
 {
-    CharDriverState *chr = (CharDriverState *)s;
+    Chardev *chr = (Chardev *)s;
     CharBackend *be = chr->be;
 
     if (!s->enable || !s->out_len)
@@ -313,7 +313,7 @@ static void csrhci_ready_for_next_inpkt(struct csrhci_s *s)
     s->in_hdr = INT_MAX;
 }
 
-static int csrhci_write(struct CharDriverState *chr,
+static int csrhci_write(struct Chardev *chr,
                 const uint8_t *buf, int len)
 {
     struct csrhci_s *s = (struct csrhci_s *)chr;
@@ -386,7 +386,7 @@ static void csrhci_out_hci_packet_acl(void *opaque,
     csrhci_fifo_wake(s);
 }
 
-static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
+static int csrhci_ioctl(struct Chardev *chr, int cmd, void *arg)
 {
     QEMUSerialSetParams *ssp;
     struct csrhci_s *s = (struct csrhci_s *) chr;
@@ -455,14 +455,14 @@ static void csrhci_pins(void *opaque, int line, int level)
     }
 }
 
-qemu_irq *csrhci_pins_get(CharDriverState *chr)
+qemu_irq *csrhci_pins_get(Chardev *chr)
 {
     struct csrhci_s *s = (struct csrhci_s *) chr;
 
     return s->pins;
 }
 
-CharDriverState *uart_hci_init(void)
+Chardev *uart_hci_init(void)
 {
     static const CharDriver hci_driver = {
         .instance_size = sizeof(struct csrhci_s),
@@ -472,7 +472,7 @@ CharDriverState *uart_hci_init(void)
     };
     Error *err = NULL;
     ChardevCommon common = { 0, };
-    CharDriverState *chr = qemu_chr_alloc(&hci_driver, &common, &err);
+    Chardev *chr = qemu_chr_alloc(&hci_driver, &common, &err);
     struct csrhci_s *s = (struct csrhci_s *)chr;
 
     if (err) {
diff --git a/hw/char/escc.c b/hw/char/escc.c
index d6662dc77d..9228091cec 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -689,7 +689,7 @@ static const VMStateDescription vmstate_escc = {
 };
 
 MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
-              CharDriverState *chrA, CharDriverState *chrB,
+              Chardev *chrA, Chardev *chrB,
               int clock, int it_shift)
 {
     DeviceState *dev;
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 571c324004..ad7ab4eb7d 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -586,7 +586,7 @@ static const VMStateDescription vmstate_exynos4210_uart = {
 DeviceState *exynos4210_uart_create(hwaddr addr,
                                     int fifo_size,
                                     int channel,
-                                    CharDriverState *chr,
+                                    Chardev *chr,
                                     qemu_irq irq)
 {
     DeviceState  *dev;
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 99545fc359..52e67f8dc9 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -170,7 +170,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
                              uint64_t value, unsigned size)
 {
     IMXSerialState *s = (IMXSerialState *)opaque;
-    CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
+    Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
     unsigned char ch;
 
     DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index ecaa091190..80c380e077 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -275,7 +275,7 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
     mcf_uart_push_byte(s, buf[0]);
 }
 
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+void *mcf_uart_init(qemu_irq irq, Chardev *chr)
 {
     mcf_uart_state *s;
 
@@ -300,7 +300,7 @@ static const MemoryRegionOps mcf_uart_ops = {
 void mcf_uart_mm_init(MemoryRegion *sysmem,
                       hwaddr base,
                       qemu_irq irq,
-                      CharDriverState *chr)
+                      Chardev *chr)
 {
     mcf_uart_state *s;
 
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index 893ab108bc..31ebb1592c 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -54,7 +54,7 @@ void omap_uart_reset(struct omap_uart_s *s)
 struct omap_uart_s *omap_uart_init(hwaddr base,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
                 qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr)
+                const char *label, Chardev *chr)
 {
     struct omap_uart_s *s = g_new0(struct omap_uart_s, 1);
 
@@ -163,7 +163,7 @@ struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
                 struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
                 qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr)
+                const char *label, Chardev *chr)
 {
     hwaddr base = omap_l4_attach(ta, 0, NULL);
     struct omap_uart_s *s = omap_uart_init(base, irq,
@@ -178,7 +178,7 @@ struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
     return s;
 }
 
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
+void omap_uart_attach(struct omap_uart_s *s, Chardev *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
     s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index f2d56666b7..c71a4a0f4f 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -603,7 +603,7 @@ static const MemoryRegionOps parallel_mm_ops = {
 /* If fd is zero, it means that the parallel device uses the console */
 bool parallel_mm_init(MemoryRegion *address_space,
                       hwaddr base, int it_shift, qemu_irq irq,
-                      CharDriverState *chr)
+                      Chardev *chr)
 {
     ParallelState *s;
 
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 54d3a12f51..d7c5cc11fe 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -121,7 +121,7 @@ static void serial_register_types(void)
 
 type_init(serial_register_types)
 
-static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
+static void serial_isa_init(ISABus *bus, int index, Chardev *chr)
 {
     DeviceState *dev;
     ISADevice *isadev;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index ffbacd8227..11628149a1 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -927,7 +927,7 @@ const MemoryRegionOps serial_io_ops = {
 };
 
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
-                         CharDriverState *chr, MemoryRegion *system_io)
+                         Chardev *chr, MemoryRegion *system_io)
 {
     SerialState *s;
 
@@ -983,7 +983,7 @@ static const MemoryRegionOps serial_mm_ops[3] = {
 SerialState *serial_mm_init(MemoryRegion *address_space,
                             hwaddr base, int it_shift,
                             qemu_irq irq, int baudbase,
-                            CharDriverState *chr, enum device_endian end)
+                            Chardev *chr, enum device_endian end)
 {
     SerialState *s;
 
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 9d35564bcf..303eb0a678 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -356,7 +356,7 @@ static const MemoryRegionOps sh_serial_ops = {
 
 void sh_serial_init(MemoryRegion *sysmem,
                     hwaddr base, int feat,
-                    uint32_t freq, CharDriverState *chr,
+                    uint32_t freq, Chardev *chr,
                     qemu_irq eri_source,
                     qemu_irq rxi_source,
                     qemu_irq txi_source,
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 7c22b8bd0e..e30c8da57c 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -141,7 +141,7 @@ static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return H_SUCCESS;
 }
 
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
+void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev)
 {
     DeviceState *dev;
 
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 776205b4a9..798d9b69fd 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -168,7 +168,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
     VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
     VirtConsole *vcon = VIRTIO_CONSOLE(dev);
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
-    CharDriverState *chr = qemu_chr_fe_get_driver(&vcon->chr);
+    Chardev *chr = qemu_chr_fe_get_driver(&vcon->chr);
 
     if (port->id == 0 && !k->is_console) {
         error_setg(errp, "Port number 0 on virtio-serial devices reserved "
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 1b7ea50e9f..94f4d8bde4 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -179,7 +179,7 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
     Error *local_err = NULL;
     Property *prop = opaque;
     CharBackend *be = qdev_get_prop_ptr(dev, prop);
-    CharDriverState *s;
+    Chardev *s;
     char *str;
 
     if (dev->realized) {
@@ -411,7 +411,7 @@ void qdev_prop_set_drive(DeviceState *dev, const char *name,
 }
 
 void qdev_prop_set_chr(DeviceState *dev, const char *name,
-                       CharDriverState *value)
+                       Chardev *value)
 {
     assert(!value || value->label);
     object_property_set_str(OBJECT(dev),
diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c
index 5c666f9b24..18f27fcd4f 100644
--- a/hw/display/milkymist-tmu2.c
+++ b/hw/display/milkymist-tmu2.c
@@ -85,7 +85,7 @@ struct MilkymistTMU2State {
     SysBusDevice parent_obj;
 
     MemoryRegion regs_region;
-    CharDriverState *chr;
+    Chardev *chr;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 5f71012108..040a0b93f2 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1392,7 +1392,7 @@ static const GraphicHwOps sm501_ops = {
 };
 
 void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
-                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
+                uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr)
 {
     SM501State * s;
     DeviceState *dev;
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 9d07b118c0..166ac936d7 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -287,7 +287,7 @@ MemoryRegion *isa_address_space_io(ISADevice *dev)
 
 type_init(isabus_register_types)
 
-static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
+static void parallel_init(ISABus *bus, int index, Chardev *chr)
 {
     DeviceState *dev;
     ISADevice *isadev;
diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c
index b1c1a0acb1..c707d24db4 100644
--- a/hw/isa/pc87312.c
+++ b/hw/isa/pc87312.c
@@ -268,7 +268,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp)
     DeviceState *d;
     ISADevice *isa;
     ISABus *bus;
-    CharDriverState *chr;
+    Chardev *chr;
     DriveInfo *drive;
     char name[5];
     int i;
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index cf48f420cc..75877de11c 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -551,10 +551,10 @@ static void malta_fgpa_display_event(void *opaque, int event)
 }
 
 static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
-         hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
+         hwaddr base, qemu_irq uart_irq, Chardev *uart_chr)
 {
     MaltaFPGAState *s;
-    CharDriverState *chr;
+    Chardev *chr;
 
     s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
 
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index abeaf3da08..c836222b12 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -868,7 +868,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
         s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
                                                          &error_abort);
     } else {
-        CharDriverState *chr = qemu_chr_fe_get_driver(&s->server_chr);
+        Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr);
         assert(chr);
 
         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c
index 3ca25894f1..86f5e383b0 100644
--- a/hw/misc/milkymist-pfpu.c
+++ b/hw/misc/milkymist-pfpu.c
@@ -125,7 +125,7 @@ struct MilkymistPFPUState {
     SysBusDevice parent_obj;
 
     MemoryRegion regs_region;
-    CharDriverState *chr;
+    Chardev *chr;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 88cb6d8978..daab0d56cf 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -264,7 +264,7 @@ static void ccid_card_vscard_handle_message(PassthruState *card,
 
 static void ccid_card_vscard_drop_connection(PassthruState *card)
 {
-    CharDriverState *chr = qemu_chr_fe_get_driver(&card->cs);
+    Chardev *chr = qemu_chr_fe_get_driver(&card->cs);
 
     qemu_chr_fe_deinit(&card->cs);
     qemu_chr_delete(chr);
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 6066d9b0f7..6d5137383b 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -483,7 +483,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
 {
     USBSerialState *s = USB_SERIAL_DEV(dev);
     Error *local_err = NULL;
-    CharDriverState *chr = qemu_chr_fe_get_driver(&s->cs);
+    Chardev *chr = qemu_chr_fe_get_driver(&s->cs);
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
@@ -512,7 +512,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
 static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
 {
     USBDevice *dev;
-    CharDriverState *cdrv;
+    Chardev *cdrv;
     uint32_t vendorid = 0, productid = 0;
     char label[32];
     static int index;
@@ -564,7 +564,7 @@ static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
 static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
 {
     USBDevice *dev;
-    CharDriverState *cdrv;
+    Chardev *cdrv;
 
     cdrv = qemu_chr_new("braille", "braille");
     if (!cdrv)
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index a65723781e..3359e6a747 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -284,7 +284,7 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
 static int usbredir_write(void *priv, uint8_t *data, int count)
 {
     USBRedirDevice *dev = priv;
-    CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
+    Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
     int r;
 
     if (!chr->be_open) {
@@ -1430,7 +1430,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
 static void usbredir_handle_destroy(USBDevice *udev)
 {
     USBRedirDevice *dev = USB_REDIRECT(udev);
-    CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
+    Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
 
     qemu_chr_fe_deinit(&dev->cs);
     qemu_chr_delete(chr);
diff --git a/monitor.c b/monitor.c
index 17948f5289..a82f547488 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3193,7 +3193,7 @@ static void ringbuf_completion(ReadLineState *rs, const char *str)
         ChardevInfo *chr_info = list->value;
 
         if (!strncmp(chr_info->label, str, len)) {
-            CharDriverState *chr = qemu_chr_find(chr_info->label);
+            Chardev *chr = qemu_chr_find(chr_info->label);
             if (chr && qemu_chr_is_ringbuf(chr)) {
                 readline_add_completion(rs, chr_info->label);
             }
@@ -3981,7 +3981,7 @@ static void __attribute__((constructor)) monitor_lock_init(void)
     qemu_mutex_init(&monitor_lock);
 }
 
-void monitor_init(CharDriverState *chr, int flags)
+void monitor_init(Chardev *chr, int flags)
 {
     static int is_first_init = 1;
     Monitor *mon;
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 9bfc736f55..4962976c22 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -564,7 +564,7 @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs)
  * Return 0 is success.
  * Return 1 is failed.
  */
-static int find_and_check_chardev(CharDriverState **chr,
+static int find_and_check_chardev(Chardev **chr,
                                   char *chr_name,
                                   Error **errp)
 {
@@ -611,7 +611,7 @@ static void check_old_packet_regular(void *opaque)
 static void colo_compare_complete(UserCreatable *uc, Error **errp)
 {
     CompareState *s = COLO_COMPARE(uc);
-    CharDriverState *chr;
+    Chardev *chr;
     char thread_name[64];
     static int compare_id;
 
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index b7d645617c..aa0aa98fa5 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -191,7 +191,7 @@ static void filter_redirector_cleanup(NetFilterState *nf)
 static void filter_mirror_setup(NetFilterState *nf, Error **errp)
 {
     MirrorState *s = FILTER_MIRROR(nf);
-    CharDriverState *chr;
+    Chardev *chr;
 
     if (!s->outdev) {
         error_setg(errp, "filter mirror needs 'outdev' "
@@ -220,7 +220,7 @@ static void redirector_rs_finalize(SocketReadState *rs)
 static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
-    CharDriverState *chr;
+    Chardev *chr;
 
     if (!s->indev && !s->outdev) {
         error_setg(errp, "filter redirector needs 'indev' or "
diff --git a/net/slirp.c b/net/slirp.c
index bcd1c5f57d..f97ec23345 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -748,7 +748,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         }
     } else {
         Error *err = NULL;
-        CharDriverState *chr = qemu_chr_new(buf, p);
+        Chardev *chr = qemu_chr_new(buf, p);
 
         if (!chr) {
             error_report("could not open guest forwarding device '%s'", buf);
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 7aff77ee4a..b0f0ab6cc8 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -195,7 +195,7 @@ static void net_vhost_user_event(void *opaque, int event)
     const char *name = opaque;
     NetClientState *ncs[MAX_QUEUE_NUM];
     VhostUserState *s;
-    CharDriverState *chr;
+    Chardev *chr;
     Error *err = NULL;
     int queues;
 
@@ -232,7 +232,7 @@ static void net_vhost_user_event(void *opaque, int event)
 }
 
 static int net_vhost_user_init(NetClientState *peer, const char *device,
-                               const char *name, CharDriverState *chr,
+                               const char *name, Chardev *chr,
                                int queues)
 {
     Error *err = NULL;
@@ -274,10 +274,10 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
     return 0;
 }
 
-static CharDriverState *net_vhost_claim_chardev(
+static Chardev *net_vhost_claim_chardev(
     const NetdevVhostUserOptions *opts, Error **errp)
 {
-    CharDriverState *chr = qemu_chr_find(opts->chardev);
+    Chardev *chr = qemu_chr_find(opts->chardev);
 
     if (chr == NULL) {
         error_setg(errp, "chardev \"%s\" not found", opts->chardev);
@@ -324,7 +324,7 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
 {
     int queues;
     const NetdevVhostUserOptions *vhost_user_opts;
-    CharDriverState *chr;
+    Chardev *chr;
 
     assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
     vhost_user_opts = &netdev->u.vhost_user;
diff --git a/qemu-char.c b/qemu-char.c
index cc1cf3b676..24169a95b5 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -89,7 +89,7 @@
 #define READ_RETRIES 10
 #define TCP_MAX_FDS 16
 
-typedef struct MuxDriver MuxDriver;
+typedef struct MuxChardev MuxChardev;
 
 /***********************************************************/
 /* Socket address helpers */
@@ -157,19 +157,19 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
 /***********************************************************/
 /* character device */
 
-static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
     QTAILQ_HEAD_INITIALIZER(chardevs);
 
-static void qemu_chr_free_common(CharDriverState *chr);
+static void qemu_chr_free_common(Chardev *chr);
 
-CharDriverState *qemu_chr_alloc(const CharDriver *driver,
+Chardev *qemu_chr_alloc(const CharDriver *driver,
                                 ChardevCommon *backend, Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     assert(driver);
     assert(driver->chr_write);
-    assert(driver->instance_size >= sizeof(CharDriverState));
+    assert(driver->instance_size >= sizeof(Chardev));
 
     chr = g_malloc0(driver->instance_size);
     qemu_mutex_init(&chr->chr_write_lock);
@@ -197,7 +197,7 @@ CharDriverState *qemu_chr_alloc(const CharDriver *driver,
     return chr;
 }
 
-void qemu_chr_be_event(CharDriverState *s, int event)
+void qemu_chr_be_event(Chardev *s, int event)
 {
     CharBackend *be = s->be;
 
@@ -218,7 +218,7 @@ void qemu_chr_be_event(CharDriverState *s, int event)
     be->chr_event(be->opaque, event);
 }
 
-void qemu_chr_be_generic_open(CharDriverState *s)
+void qemu_chr_be_generic_open(Chardev *s)
 {
     qemu_chr_be_event(s, CHR_EVENT_OPENED);
 }
@@ -226,7 +226,7 @@ void qemu_chr_be_generic_open(CharDriverState *s)
 
 /* Not reporting errors from writing to logfile, as logs are
  * defined to be "best effort" only */
-static void qemu_chr_fe_write_log(CharDriverState *s,
+static void qemu_chr_fe_write_log(Chardev *s,
                                   const uint8_t *buf, size_t len)
 {
     size_t done = 0;
@@ -251,7 +251,8 @@ static void qemu_chr_fe_write_log(CharDriverState *s,
     }
 }
 
-static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int len, int *offset)
+static int qemu_chr_fe_write_buffer(Chardev *s,
+                                    const uint8_t *buf, int len, int *offset)
 {
     int res = 0;
     *offset = 0;
@@ -279,14 +280,14 @@ static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int
     return res;
 }
 
-static bool qemu_chr_replay(CharDriverState *chr)
+static bool qemu_chr_replay(Chardev *chr)
 {
     return qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
 }
 
 int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
     int ret;
 
     if (!s) {
@@ -317,7 +318,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
     return ret;
 }
 
-static int qemu_chr_write_all(CharDriverState *s, const uint8_t *buf, int len)
+static int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len)
 {
     int offset;
     int res;
@@ -343,7 +344,7 @@ static int qemu_chr_write_all(CharDriverState *s, const uint8_t *buf, int len)
 
 int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
 
     if (!s) {
         return 0;
@@ -354,7 +355,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
 
 int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
     int offset = 0, counter = 10;
     int res;
 
@@ -400,7 +401,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
 
 int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
     int res;
 
     if (!s || !s->driver->chr_ioctl || qemu_chr_replay(s)) {
@@ -412,7 +413,7 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
     return res;
 }
 
-int qemu_chr_be_can_write(CharDriverState *s)
+int qemu_chr_be_can_write(Chardev *s)
 {
     CharBackend *be = s->be;
 
@@ -423,7 +424,7 @@ int qemu_chr_be_can_write(CharDriverState *s)
     return be->chr_can_read(be->opaque);
 }
 
-void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
 {
     CharBackend *be = s->be;
 
@@ -432,7 +433,7 @@ void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
     }
 }
 
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
 {
     if (qemu_chr_replay(s)) {
         if (replay_mode == REPLAY_MODE_PLAY) {
@@ -446,7 +447,7 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
 
 int qemu_chr_fe_get_msgfd(CharBackend *be)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
     int fd;
     int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
     if (s && qemu_chr_replay(s)) {
@@ -459,7 +460,7 @@ int qemu_chr_fe_get_msgfd(CharBackend *be)
 
 int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
 
     if (!s) {
         return -1;
@@ -470,7 +471,7 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
 
 int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
 
     if (!s) {
         return -1;
@@ -479,14 +480,14 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
     return s->driver->set_msgfds ? s->driver->set_msgfds(s, fds, num) : -1;
 }
 
-int qemu_chr_add_client(CharDriverState *s, int fd)
+int qemu_chr_add_client(Chardev *s, int fd)
 {
     return s->driver->chr_add_client ? s->driver->chr_add_client(s, fd) : -1;
 }
 
 void qemu_chr_fe_accept_input(CharBackend *be)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
 
     if (!s) {
         return;
@@ -510,23 +511,23 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
     va_end(ap);
 }
 
-static void remove_fd_in_watch(CharDriverState *chr);
-static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
-static void mux_set_focus(MuxDriver *d, int focus);
+static void remove_fd_in_watch(Chardev *chr);
+static void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
+static void mux_set_focus(MuxChardev *d, int focus);
 
-static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
-                                           const char *id,
-                                           ChardevBackend *backend,
-                                           ChardevReturn *ret,
-                                           bool *be_opened,
-                                           Error **errp)
+static Chardev *qemu_chr_open_null(const CharDriver *driver,
+                                   const char *id,
+                                   ChardevBackend *backend,
+                                   ChardevReturn *ret,
+                                   bool *be_opened,
+                                   Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     ChardevCommon *common = backend->u.null.data;
 
     chr = qemu_chr_alloc(driver, common, errp);
@@ -538,7 +539,7 @@ static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
 }
 
 static const CharDriver null_driver = {
-    .instance_size = sizeof(CharDriverState),
+    .instance_size = sizeof(Chardev),
     .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,
     .chr_write = null_chr_write
 };
@@ -547,8 +548,8 @@ static const CharDriver null_driver = {
 #define MAX_MUX 4
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
-struct MuxDriver {
-    CharDriverState parent;
+struct MuxChardev {
+    Chardev parent;
     CharBackend *backends[MAX_MUX];
     CharBackend chr;
     int focus;
@@ -563,15 +564,15 @@ struct MuxDriver {
     int cons[MAX_MUX];
     int timestamps;
 
-    /* Protected by the CharDriverState chr_write_lock.  */
+    /* Protected by the Chardev chr_write_lock.  */
     int linestart;
     int64_t timestamps_start;
 };
 
 /* Called with chr_write_lock held.  */
-static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    MuxDriver *d = (MuxDriver *)chr;
+    MuxChardev *d = (MuxChardev *)chr;
     int ret;
     if (!d->timestamps) {
         ret = qemu_chr_fe_write(&d->chr, buf, len);
@@ -623,7 +624,7 @@ static const char * const mux_help[] = {
 };
 
 int term_escape_char = 0x01; /* ctrl-a is used for escape */
-static void mux_print_help(CharDriverState *chr)
+static void mux_print_help(Chardev *chr)
 {
     int i, j;
     char ebuf[15] = "Escape-Char";
@@ -650,7 +651,7 @@ static void mux_print_help(CharDriverState *chr)
     }
 }
 
-static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
 {
     CharBackend *be = d->backends[mux_nr];
 
@@ -659,7 +660,7 @@ static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
     }
 }
 
-static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
 {
     if (d->term_got_escape) {
         d->term_got_escape = 0;
@@ -703,9 +704,9 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
     return 0;
 }
 
-static void mux_chr_accept_input(CharDriverState *chr)
+static void mux_chr_accept_input(Chardev *chr)
 {
-    MuxDriver *d = (MuxDriver *)chr;
+    MuxChardev *d = (MuxChardev *)chr;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -718,7 +719,7 @@ static void mux_chr_accept_input(CharDriverState *chr)
 
 static int mux_chr_can_read(void *opaque)
 {
-    MuxDriver *d = opaque;
+    MuxChardev *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -735,8 +736,8 @@ static int mux_chr_can_read(void *opaque)
 
 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = opaque;
+    Chardev *chr = opaque;
+    MuxChardev *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
     int i;
@@ -758,7 +759,7 @@ static bool muxes_realized;
 
 static void mux_chr_event(void *opaque, int event)
 {
-    MuxDriver *d = opaque;
+    MuxChardev *d = opaque;
     int i;
 
     if (!muxes_realized) {
@@ -784,11 +785,11 @@ static void mux_chr_event(void *opaque, int event)
  */
 static void muxes_realize_done(Notifier *notifier, void *unused)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
         if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = (MuxDriver *)chr;
+            MuxChardev *d = (MuxChardev *)chr;
             int i;
 
             /* send OPENED to all already-attached FEs */
@@ -808,10 +809,10 @@ static Notifier muxes_realize_notify = {
     .notify = muxes_realize_done,
 };
 
-static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
+static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
 {
-    MuxDriver *d = (MuxDriver *)s;
-    CharDriverState *chr = qemu_chr_fe_get_driver(&d->chr);
+    MuxChardev *d = (MuxChardev *)s;
+    Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
 
     if (!chr->driver->chr_add_watch) {
         return NULL;
@@ -820,9 +821,9 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
     return chr->driver->chr_add_watch(chr, cond);
 }
 
-static void mux_chr_free(struct CharDriverState *chr)
+static void mux_chr_free(struct Chardev *chr)
 {
-    MuxDriver *d = (MuxDriver *)chr;
+    MuxChardev *d = (MuxChardev *)chr;
     int i;
 
     for (i = 0; i < d->mux_cnt; i++) {
@@ -834,9 +835,9 @@ static void mux_chr_free(struct CharDriverState *chr)
     qemu_chr_fe_deinit(&d->chr);
 }
 
-static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
+static void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
 {
-    MuxDriver *d = (MuxDriver *)chr;
+    MuxChardev *d = (MuxChardev *)chr;
 
     /* Fix up the real driver with mux routines */
     qemu_chr_fe_set_handlers(&d->chr,
@@ -847,7 +848,7 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
                              context, true);
 }
 
-static void mux_set_focus(MuxDriver *d, int focus)
+static void mux_set_focus(MuxChardev *d, int focus)
 {
     assert(focus >= 0);
     assert(focus < d->mux_cnt);
@@ -860,16 +861,16 @@ static void mux_set_focus(MuxDriver *d, int focus)
     mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
 }
 
-static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
-                                          const char *id,
-                                          ChardevBackend *backend,
-                                          ChardevReturn *ret,
-                                          bool *be_opened,
-                                          Error **errp)
+static Chardev *qemu_chr_open_mux(const CharDriver *driver,
+                                  const char *id,
+                                  ChardevBackend *backend,
+                                  ChardevReturn *ret,
+                                  bool *be_opened,
+                                  Error **errp)
 {
     ChardevMux *mux = backend->u.mux.data;
-    CharDriverState *chr, *drv;
-    MuxDriver *d;
+    Chardev *chr, *drv;
+    MuxChardev *d;
     ChardevCommon *common = qapi_ChardevMux_base(mux);
 
     drv = qemu_chr_find(mux->chardev);
@@ -882,7 +883,7 @@ static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    d = (MuxDriver *)chr;
+    d = (MuxChardev *)chr;
     d->focus = -1;
     /* only default to opened state if we've realized the initial
      * set of muxes
@@ -896,17 +897,17 @@ static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
     return chr;
 }
 
-CharDriverState *qemu_chr_fe_get_driver(CharBackend *be)
+Chardev *qemu_chr_fe_get_driver(CharBackend *be)
 {
     return be->chr;
 }
 
-bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
+bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
 {
     int tag = 0;
 
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = (MuxDriver *)s;
+        MuxChardev *d = (MuxChardev *)s;
 
         if (d->mux_cnt >= MAX_MUX) {
             goto unavailable;
@@ -930,10 +931,10 @@ unavailable:
     return false;
 }
 
-static bool qemu_chr_is_busy(CharDriverState *s)
+static bool qemu_chr_is_busy(Chardev *s)
 {
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = (MuxDriver *)s;
+        MuxChardev *d = (MuxChardev *)s;
         return d->mux_cnt >= 0;
     } else {
         return s->be != NULL;
@@ -948,7 +949,7 @@ void qemu_chr_fe_deinit(CharBackend *b)
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
         b->chr->be = NULL;
         if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = (MuxDriver *)b->chr;
+            MuxChardev *d = (MuxChardev *)b->chr;
             d->backends[b->tag] = NULL;
         }
         b->chr = NULL;
@@ -963,7 +964,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
                               GMainContext *context,
                               bool set_open)
 {
-    CharDriverState *s;
+    Chardev *s;
     int fe_open;
 
     s = b->chr;
@@ -1010,7 +1011,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
     }
 
     if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-        mux_set_focus((MuxDriver *)b->chr, b->tag);
+        mux_set_focus((MuxChardev *)b->chr, b->tag);
     }
 }
 
@@ -1090,7 +1091,7 @@ static GSourceFuncs io_watch_poll_funcs = {
 };
 
 /* Can only be used for read */
-static guint io_add_watch_poll(CharDriverState *chr,
+static guint io_add_watch_poll(Chardev *chr,
                                QIOChannel *ioc,
                                IOCanReadHandler *fd_can_read,
                                QIOChannelFunc fd_read,
@@ -1138,7 +1139,7 @@ static void io_remove_watch_poll(guint tag)
     g_source_destroy(&iwp->parent);
 }
 
-static void remove_fd_in_watch(CharDriverState *chr)
+static void remove_fd_in_watch(Chardev *chr)
 {
     if (chr->fd_in_tag) {
         io_remove_watch_poll(chr->fd_in_tag);
@@ -1187,25 +1188,25 @@ static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
 }
 
 
-typedef struct FDCharDriver {
-    CharDriverState parent;
-    CharDriverState *chr;
+typedef struct FDChardev {
+    Chardev parent;
+    Chardev *chr;
     QIOChannel *ioc_in, *ioc_out;
     int max_size;
-} FDCharDriver;
+} FDChardev;
 
 /* Called with chr_write_lock held.  */
-static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    FDCharDriver *s = (FDCharDriver *)chr;
+    FDChardev *s = (FDChardev *)chr;
 
     return io_channel_send(s->ioc_out, buf, len);
 }
 
 static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    CharDriverState *chr = opaque;
-    FDCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    FDChardev *s = opaque;
     int len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1234,23 +1235,23 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int fd_chr_read_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    FDCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    FDChardev *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
-static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    FDCharDriver *s = (FDCharDriver *)chr;
+    FDChardev *s = (FDChardev *)chr;
     return qio_channel_create_watch(s->ioc_out, cond);
 }
 
-static void fd_chr_update_read_handler(CharDriverState *chr,
+static void fd_chr_update_read_handler(Chardev *chr,
                                        GMainContext *context)
 {
-    FDCharDriver *s = (FDCharDriver *)chr;
+    FDChardev *s = (FDChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1261,9 +1262,9 @@ static void fd_chr_update_read_handler(CharDriverState *chr,
     }
 }
 
-static void fd_chr_free(struct CharDriverState *chr)
+static void fd_chr_free(struct Chardev *chr)
 {
-    FDCharDriver *s = (FDCharDriver *)chr;
+    FDChardev *s = (FDChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1277,19 +1278,19 @@ static void fd_chr_free(struct CharDriverState *chr)
 }
 
 /* open a character device to a unix fd */
-static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
-                                         int fd_in, int fd_out,
-                                         ChardevCommon *backend, Error **errp)
+static Chardev *qemu_chr_open_fd(const CharDriver *driver,
+                                 int fd_in, int fd_out,
+                                 ChardevCommon *backend, Error **errp)
 {
-    CharDriverState *chr;
-    FDCharDriver *s;
+    Chardev *chr;
+    FDChardev *s;
     char *name;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    s = (FDCharDriver *)chr;
+    s = (FDChardev *)chr;
     s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
     name = g_strdup_printf("chardev-file-in-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
@@ -1304,12 +1305,12 @@ static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
-                                           const char *id,
-                                           ChardevBackend *backend,
-                                           ChardevReturn *ret,
-                                           bool *be_opened,
-                                           Error **errp)
+static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
+                                   const char *id,
+                                   ChardevBackend *backend,
+                                   ChardevReturn *ret,
+                                   bool *be_opened,
+                                   Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
     int fd_in, fd_out;
@@ -1346,7 +1347,7 @@ static bool stdio_in_use;
 static bool stdio_allow_signal;
 static bool stdio_echo_state;
 
-static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo);
+static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo);
 
 static void term_exit(void)
 {
@@ -1360,7 +1361,7 @@ static void term_stdio_handler(int sig)
     qemu_chr_set_echo_stdio(NULL, stdio_echo_state);
 }
 
-static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
+static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
 {
     struct termios tty;
 
@@ -1382,21 +1383,21 @@ static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
     tcsetattr (0, TCSANOW, &tty);
 }
 
-static void qemu_chr_free_stdio(struct CharDriverState *chr)
+static void qemu_chr_free_stdio(struct Chardev *chr)
 {
     term_exit();
     fd_chr_free(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
-                                            const char *id,
-                                            ChardevBackend *backend,
-                                            ChardevReturn *ret,
-                                            bool *be_opened,
-                                            Error **errp)
+static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
+                                    const char *id,
+                                    ChardevBackend *backend,
+                                    ChardevReturn *ret,
+                                    bool *be_opened,
+                                    Error **errp)
 {
     ChardevStdio *opts = backend->u.stdio.data;
-    CharDriverState *chr;
+    Chardev *chr;
     struct sigaction act;
     ChardevCommon *common = qapi_ChardevStdio_base(opts);
 
@@ -1440,23 +1441,23 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 #define HAVE_CHARDEV_PTY 1
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     QIOChannel *ioc;
     int read_bytes;
 
-    /* Protected by the CharDriverState chr_write_lock.  */
+    /* Protected by the Chardev chr_write_lock.  */
     int connected;
     guint timer_tag;
     guint open_tag;
-} PtyCharDriver;
+} PtyChardev;
 
-static void pty_chr_update_read_handler_locked(CharDriverState *chr);
-static void pty_chr_state(CharDriverState *chr, int connected);
+static void pty_chr_update_read_handler_locked(Chardev *chr);
+static void pty_chr_state(Chardev *chr, int connected);
 
 static gboolean pty_chr_timer(gpointer opaque)
 {
-    struct CharDriverState *chr = opaque;
-    PtyCharDriver *s = opaque;
+    struct Chardev *chr = opaque;
+    PtyChardev *s = opaque;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     s->timer_tag = 0;
@@ -1470,9 +1471,9 @@ static gboolean pty_chr_timer(gpointer opaque)
 }
 
 /* Called with chr_write_lock held.  */
-static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
+static void pty_chr_rearm_timer(Chardev *chr, int ms)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
     char *name;
 
     if (s->timer_tag) {
@@ -1492,9 +1493,9 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
 }
 
 /* Called with chr_write_lock held.  */
-static void pty_chr_update_read_handler_locked(CharDriverState *chr)
+static void pty_chr_update_read_handler_locked(Chardev *chr)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
     GPollFD pfd;
     int rc;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
@@ -1514,7 +1515,7 @@ static void pty_chr_update_read_handler_locked(CharDriverState *chr)
     }
 }
 
-static void pty_chr_update_read_handler(CharDriverState *chr,
+static void pty_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
     qemu_mutex_lock(&chr->chr_write_lock);
@@ -1523,9 +1524,9 @@ static void pty_chr_update_read_handler(CharDriverState *chr,
 }
 
 /* Called with chr_write_lock held.  */
-static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
 
     if (!s->connected) {
         /* guest sends data, check for (re-)connect */
@@ -1537,9 +1538,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return io_channel_send(s->ioc, buf, len);
 }
 
-static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
     if (!s->connected) {
         return NULL;
     }
@@ -1548,8 +1549,8 @@ static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 
 static int pty_chr_read_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    PtyCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    PtyChardev *s = opaque;
 
     s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
@@ -1557,8 +1558,8 @@ static int pty_chr_read_poll(void *opaque)
 
 static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    CharDriverState *chr = opaque;
-    PtyCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    PtyChardev *s = opaque;
     gsize len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1582,8 +1583,8 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 {
-    CharDriverState *chr = opaque;
-    PtyCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    PtyChardev *s = opaque;
 
     s->open_tag = 0;
     qemu_chr_be_generic_open(chr);
@@ -1591,9 +1592,9 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 }
 
 /* Called with chr_write_lock held.  */
-static void pty_chr_state(CharDriverState *chr, int connected)
+static void pty_chr_state(Chardev *chr, int connected)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
 
     if (!connected) {
         if (s->open_tag) {
@@ -1625,9 +1626,9 @@ static void pty_chr_state(CharDriverState *chr, int connected)
     }
 }
 
-static void pty_chr_free(struct CharDriverState *chr)
+static void pty_chr_free(struct Chardev *chr)
 {
-    PtyCharDriver *s = (PtyCharDriver *)chr;
+    PtyChardev *s = (PtyChardev *)chr;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_state(chr, 0);
@@ -1640,15 +1641,15 @@ static void pty_chr_free(struct CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
-                                          const char *id,
-                                          ChardevBackend *backend,
-                                          ChardevReturn *ret,
-                                          bool *be_opened,
-                                          Error **errp)
+static Chardev *qemu_chr_open_pty(const CharDriver *driver,
+                                  const char *id,
+                                  ChardevBackend *backend,
+                                  ChardevReturn *ret,
+                                  bool *be_opened,
+                                  Error **errp)
 {
-    CharDriverState *chr;
-    PtyCharDriver *s;
+    Chardev *chr;
+    PtyChardev *s;
     int master_fd, slave_fd;
     char pty_name[PATH_MAX];
     ChardevCommon *common = backend->u.pty.data;
@@ -1676,7 +1677,7 @@ static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
     fprintf(stderr, "char device redirected to %s (label %s)\n",
             pty_name, id);
 
-    s = (PtyCharDriver *)chr;
+    s = (PtyChardev *)chr;
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
     name = g_strdup_printf("chardev-pty-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
@@ -1688,7 +1689,7 @@ static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
 }
 
 static const CharDriver pty_driver = {
-    .instance_size = sizeof(PtyCharDriver),
+    .instance_size = sizeof(PtyChardev),
     .kind = CHARDEV_BACKEND_KIND_PTY, .create = qemu_chr_open_pty,
     .chr_write = pty_chr_write,
     .chr_update_read_handler = pty_chr_update_read_handler,
@@ -1811,9 +1812,9 @@ static void tty_serial_init(int fd, int speed,
     tcsetattr (fd, TCSANOW, &tty);
 }
 
-static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
+static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    FDCharDriver *s = (FDCharDriver *)chr;
+    FDChardev *s = (FDChardev *)chr;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 
     switch(cmd) {
@@ -1881,7 +1882,7 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static void qemu_chr_free_tty(CharDriverState *chr)
+static void qemu_chr_free_tty(Chardev *chr)
 {
     fd_chr_free(chr);
 }
@@ -1892,12 +1893,12 @@ static void qemu_chr_free_tty(CharDriverState *chr)
 #define HAVE_CHARDEV_PARPORT 1
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     int fd;
     int mode;
-} ParallelCharDriver;
+} ParallelChardev;
 
-static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
 {
     if (s->mode != mode) {
 	int m = mode;
@@ -1908,9 +1909,9 @@ static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
     return 1;
 }
 
-static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
+    ParallelChardev *drv = (ParallelChardev *)chr;
     int fd = drv->fd;
     uint8_t b;
 
@@ -1989,9 +1990,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static void pp_free(CharDriverState *chr)
+static void pp_free(Chardev *chr)
 {
-    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
+    ParallelChardev *drv = (ParallelChardev *)chr;
     int fd = drv->fd;
 
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
@@ -2000,14 +2001,14 @@ static void pp_free(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
-                                            int fd,
-                                            ChardevCommon *backend,
-                                            bool *be_opened,
-                                            Error **errp)
+static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
+                                    int fd,
+                                    ChardevCommon *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
-    CharDriverState *chr;
-    ParallelCharDriver *drv;
+    Chardev *chr;
+    ParallelChardev *drv;
 
     if (ioctl(fd, PPCLAIM) < 0) {
         error_setg_errno(errp, errno, "not a parallel port");
@@ -2020,7 +2021,7 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
         return NULL;
     }
 
-    drv = (ParallelCharDriver *)chr;
+    drv = (ParallelChardev *)chr;
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
@@ -2033,13 +2034,13 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 #define HAVE_CHARDEV_PARPORT 1
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     int fd;
-} ParallelCharDriver;
+} ParallelChardev;
 
-static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
+    ParallelChardev *drv = (ParallelChardev *)chr;
     uint8_t b;
 
     switch (cmd) {
@@ -2079,20 +2080,20 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
-                                            int fd,
-                                            ChardevCommon *backend,
-                                            bool *be_opened,
-                                            Error **errp)
+static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
+                                    int fd,
+                                    ChardevCommon *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
-    CharDriverState *chr;
-    ParallelCharDriver *drv;
+    Chardev *chr;
+    ParallelChardev *drv;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    drv = (ParallelCharDriver *)chr;
+    drv = (ParallelChardev *)chr;
     drv->fd = fd;
     *be_opened = false;
     return chr;
@@ -2104,25 +2105,25 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 #define HAVE_CHARDEV_SERIAL 1
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     int max_size;
     HANDLE hcom, hrecv, hsend;
     OVERLAPPED orecv;
     BOOL fpipe;
     DWORD len;
 
-    /* Protected by the CharDriverState chr_write_lock.  */
+    /* Protected by the Chardev chr_write_lock.  */
     OVERLAPPED osend;
-} WinCharState;
+} WinChardev;
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     HANDLE  hStdIn;
     HANDLE  hInputReadyEvent;
     HANDLE  hInputDoneEvent;
     HANDLE  hInputThread;
     uint8_t win_stdio_buf;
-} WinStdioCharState;
+} WinStdioChardev;
 
 #define NSENDBUF 2048
 #define NRECVBUF 2048
@@ -2132,9 +2133,9 @@ typedef struct {
 static int win_chr_poll(void *opaque);
 static int win_chr_pipe_poll(void *opaque);
 
-static void win_chr_free(CharDriverState *chr)
+static void win_chr_free(Chardev *chr)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
 
     if (s->hsend) {
         CloseHandle(s->hsend);
@@ -2156,9 +2157,9 @@ static void win_chr_free(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp)
+static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
     COMMCONFIG comcfg;
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
     COMSTAT comstat;
@@ -2224,9 +2225,9 @@ static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp
 }
 
 /* Called with chr_write_lock held.  */
-static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
     DWORD len, ret, size, err;
 
     len = len1;
@@ -2258,17 +2259,17 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
     return len1 - len;
 }
 
-static int win_chr_read_poll(CharDriverState *chr)
+static int win_chr_read_poll(Chardev *chr)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
-static void win_chr_readfile(CharDriverState *chr)
+static void win_chr_readfile(Chardev *chr)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
     int ret, err;
     uint8_t buf[READ_BUF_LEN];
     DWORD size;
@@ -2288,9 +2289,9 @@ static void win_chr_readfile(CharDriverState *chr)
     }
 }
 
-static void win_chr_read(CharDriverState *chr)
+static void win_chr_read(Chardev *chr)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
 
     if (s->len > s->max_size)
         s->len = s->max_size;
@@ -2302,8 +2303,8 @@ static void win_chr_read(CharDriverState *chr)
 
 static int win_chr_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    WinCharState *s = opaque;
+    Chardev *chr = opaque;
+    WinChardev *s = opaque;
     COMSTAT status;
     DWORD comerr;
 
@@ -2319,8 +2320,8 @@ static int win_chr_poll(void *opaque)
 
 static int win_chr_pipe_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    WinCharState *s = opaque;
+    Chardev *chr = opaque;
+    WinChardev *s = opaque;
     DWORD size;
 
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
@@ -2333,10 +2334,10 @@ static int win_chr_pipe_poll(void *opaque)
     return 0;
 }
 
-static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
+static int win_chr_pipe_init(Chardev *chr, const char *filename,
                              Error **errp)
 {
-    WinCharState *s = (WinCharState *)chr;
+    WinChardev *s = (WinChardev *)chr;
     OVERLAPPED ov;
     int ret;
     DWORD size;
@@ -2398,16 +2399,16 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
 }
 
 
-static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
-                                           const char *id,
-                                           ChardevBackend *backend,
-                                           ChardevReturn *ret,
-                                           bool *be_opened,
-                                           Error **errp)
+static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
+                                   const char *id,
+                                   ChardevBackend *backend,
+                                   ChardevReturn *ret,
+                                   bool *be_opened,
+                                   Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
     const char *filename = opts->device;
-    CharDriverState *chr;
+    Chardev *chr;
     ChardevCommon *common = qapi_ChardevHostdev_base(opts);
 
     chr = qemu_chr_alloc(driver, common, errp);
@@ -2422,29 +2423,29 @@ static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_file(const CharDriver *driver,
-                                               HANDLE fd_out,
-                                               ChardevCommon *backend,
-                                               Error **errp)
+static Chardev *qemu_chr_open_win_file(const CharDriver *driver,
+                                       HANDLE fd_out,
+                                       ChardevCommon *backend,
+                                       Error **errp)
 {
-    CharDriverState *chr;
-    WinCharState *s;
+    Chardev *chr;
+    WinChardev *s;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    s = (WinCharState *)chr;
+    s = (WinChardev *)chr;
     s->hcom = fd_out;
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
-                                              const char *id,
-                                              ChardevBackend *backend,
-                                              ChardevReturn *ret,
-                                              bool *be_opened,
-                                              Error **errp)
+static Chardev *qemu_chr_open_win_con(const CharDriver *driver,
+                                      const char *id,
+                                      ChardevBackend *backend,
+                                      ChardevReturn *ret,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevCommon *common = backend->u.console.data;
     return qemu_chr_open_win_file(driver,
@@ -2453,12 +2454,12 @@ static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
 }
 
 static const CharDriver console_driver = {
-    .instance_size = sizeof(WinCharState),
+    .instance_size = sizeof(WinChardev),
     .kind = CHARDEV_BACKEND_KIND_CONSOLE, .create = qemu_chr_open_win_con,
     .chr_write = win_chr_write,
 };
 
-static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
 {
     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
     DWORD   dwSize;
@@ -2479,8 +2480,8 @@ static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static void win_stdio_wait_func(void *opaque)
 {
-    CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = opaque;
+    Chardev   *chr   = opaque;
+    WinStdioChardev *stdio = opaque;
     INPUT_RECORD       buf[4];
     int                ret;
     DWORD              dwSize;
@@ -2513,7 +2514,7 @@ static void win_stdio_wait_func(void *opaque)
 
 static DWORD WINAPI win_stdio_thread(LPVOID param)
 {
-    WinStdioCharState *stdio = param;
+    WinStdioChardev *stdio = param;
     int                ret;
     DWORD              dwSize;
 
@@ -2551,8 +2552,8 @@ static DWORD WINAPI win_stdio_thread(LPVOID param)
 
 static void win_stdio_thread_wait_func(void *opaque)
 {
-    CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = opaque;
+    Chardev   *chr   = opaque;
+    WinStdioChardev *stdio = opaque;
 
     if (qemu_chr_be_can_write(chr)) {
         qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
@@ -2561,9 +2562,9 @@ static void win_stdio_thread_wait_func(void *opaque)
     SetEvent(stdio->hInputDoneEvent);
 }
 
-static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
+static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
 {
-    WinStdioCharState *stdio  = (WinStdioCharState *)chr;
+    WinStdioChardev *stdio  = (WinStdioChardev *)chr;
     DWORD              dwMode = 0;
 
     GetConsoleMode(stdio->hStdIn, &dwMode);
@@ -2575,9 +2576,9 @@ static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
     }
 }
 
-static void win_stdio_free(CharDriverState *chr)
+static void win_stdio_free(Chardev *chr)
 {
-    WinStdioCharState *stdio = (WinStdioCharState *)chr;
+    WinStdioChardev *stdio = (WinStdioChardev *)chr;
 
     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
         CloseHandle(stdio->hInputReadyEvent);
@@ -2590,15 +2591,15 @@ static void win_stdio_free(CharDriverState *chr)
     }
 }
 
-static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
-                                            const char *id,
-                                            ChardevBackend *backend,
-                                            ChardevReturn *ret,
-                                            bool *be_opened,
-                                            Error **errp)
+static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
+                                    const char *id,
+                                    ChardevBackend *backend,
+                                    ChardevReturn *ret,
+                                    bool *be_opened,
+                                    Error **errp)
 {
-    CharDriverState   *chr;
-    WinStdioCharState *stdio;
+    Chardev   *chr;
+    WinStdioChardev *stdio;
     DWORD              dwMode;
     int                is_console = 0;
     ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data);
@@ -2607,7 +2608,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    stdio = (WinStdioCharState *)chr;
+    stdio = (WinStdioChardev *)chr;
 
     stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
     if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
@@ -2676,18 +2677,18 @@ err1:
 /* UDP Net console */
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     QIOChannel *ioc;
     uint8_t buf[READ_BUF_LEN];
     int bufcnt;
     int bufptr;
     int max_size;
-} NetCharDriver;
+} NetChardev;
 
 /* Called with chr_write_lock held.  */
-static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    NetCharDriver *s = (NetCharDriver *)chr;
+    NetChardev *s = (NetChardev *)chr;
 
     return qio_channel_write(
         s->ioc, (const char *)buf, len, NULL);
@@ -2695,8 +2696,8 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static int udp_chr_read_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    NetCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    NetChardev *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
 
@@ -2713,8 +2714,8 @@ static int udp_chr_read_poll(void *opaque)
 
 static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    CharDriverState *chr = opaque;
-    NetCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    NetChardev *s = opaque;
     ssize_t ret;
 
     if (s->max_size == 0) {
@@ -2738,10 +2739,10 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     return TRUE;
 }
 
-static void udp_chr_update_read_handler(CharDriverState *chr,
+static void udp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    NetCharDriver *s = (NetCharDriver *)chr;
+    NetChardev *s = (NetChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2752,9 +2753,9 @@ static void udp_chr_update_read_handler(CharDriverState *chr,
     }
 }
 
-static void udp_chr_free(CharDriverState *chr)
+static void udp_chr_free(Chardev *chr)
 {
-    NetCharDriver *s = (NetCharDriver *)chr;
+    NetChardev *s = (NetChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2767,7 +2768,7 @@ static void udp_chr_free(CharDriverState *chr)
 /* TCP Net console */
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     QIOChannel *ioc; /* Client I/O channel */
     QIOChannelSocket *sioc; /* Client master channel */
     QIOChannelSocket *listen_ioc;
@@ -2790,13 +2791,13 @@ typedef struct {
     guint reconnect_timer;
     int64_t reconnect_time;
     bool connect_err_reported;
-} TCPCharDriver;
+} TCPChardev;
 
 static gboolean socket_reconnect_timeout(gpointer opaque);
 
-static void qemu_chr_socket_restart_timer(CharDriverState *chr)
+static void qemu_chr_socket_restart_timer(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     char *name;
 
     assert(s->connected == 0);
@@ -2807,10 +2808,10 @@ static void qemu_chr_socket_restart_timer(CharDriverState *chr)
     g_free(name);
 }
 
-static void check_report_connect_error(CharDriverState *chr,
+static void check_report_connect_error(Chardev *chr,
                                        Error *err)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (!s->connect_err_reported) {
         error_report("Unable to connect character device %s: %s",
@@ -2825,9 +2826,9 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
                                void *opaque);
 
 /* Called with chr_write_lock held.  */
-static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (s->connected) {
         int ret =  io_channel_send_full(s->ioc, buf, len,
@@ -2850,8 +2851,8 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static int tcp_chr_read_poll(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    TCPChardev *s = opaque;
     if (!s->connected)
         return 0;
     s->max_size = qemu_chr_be_can_write(chr);
@@ -2860,8 +2861,8 @@ static int tcp_chr_read_poll(void *opaque)
 
 #define IAC 255
 #define IAC_BREAK 243
-static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
-                                      TCPCharDriver *s,
+static void tcp_chr_process_IAC_bytes(Chardev *chr,
+                                      TCPChardev *s,
                                       uint8_t *buf, int *size)
 {
     /* Handle any telnet client's basic IAC options to satisfy char by
@@ -2908,9 +2909,9 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
     *size = j;
 }
 
-static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
+static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
 
@@ -2934,9 +2935,9 @@ static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
     return to_copy;
 }
 
-static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
+static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     /* clear old pending fd array */
     g_free(s->write_msgfds);
@@ -2959,9 +2960,9 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
     return 0;
 }
 
-static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     struct iovec iov = { .iov_base = buf, .iov_len = len };
     int ret;
     size_t i;
@@ -3016,15 +3017,15 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
     return ret;
 }
 
-static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     return qio_channel_create_watch(s->ioc, cond);
 }
 
-static void tcp_chr_free_connection(CharDriverState *chr)
+static void tcp_chr_free_connection(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     int i;
 
     if (!s->connected) {
@@ -3051,9 +3052,9 @@ static void tcp_chr_free_connection(CharDriverState *chr)
     s->connected = 0;
 }
 
-static void tcp_chr_disconnect(CharDriverState *chr)
+static void tcp_chr_disconnect(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (!s->connected) {
         return;
@@ -3075,8 +3076,8 @@ static void tcp_chr_disconnect(CharDriverState *chr)
 
 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    TCPChardev *s = opaque;
     uint8_t buf[READ_BUF_LEN];
     int len, size;
 
@@ -3100,9 +3101,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     return TRUE;
 }
 
-static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
+static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     int size;
 
     if (!s->connected) {
@@ -3120,8 +3121,8 @@ static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
 
 static void tcp_chr_connect(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    TCPChardev *s = opaque;
 
     g_free(chr->filename);
     chr->filename = sockaddr_to_str(
@@ -3139,10 +3140,10 @@ static void tcp_chr_connect(void *opaque)
     qemu_chr_be_generic_open(chr);
 }
 
-static void tcp_chr_update_read_handler(CharDriverState *chr,
+static void tcp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (!s->connected) {
         return;
@@ -3158,7 +3159,7 @@ static void tcp_chr_update_read_handler(CharDriverState *chr,
 }
 
 typedef struct {
-    CharDriverState *chr;
+    Chardev *chr;
     char buf[12];
     size_t buflen;
 } TCPCharDriverTelnetInit;
@@ -3191,9 +3192,9 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
     return TRUE;
 }
 
-static void tcp_chr_telnet_init(CharDriverState *chr)
+static void tcp_chr_telnet_init(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     TCPCharDriverTelnetInit *init =
         g_new0(TCPCharDriverTelnetInit, 1);
     size_t n = 0;
@@ -3228,8 +3229,8 @@ static void tcp_chr_tls_handshake(Object *source,
                                   Error *err,
                                   gpointer user_data)
 {
-    CharDriverState *chr = user_data;
-    TCPCharDriver *s = user_data;
+    Chardev *chr = user_data;
+    TCPChardev *s = user_data;
 
     if (err) {
         tcp_chr_disconnect(chr);
@@ -3243,9 +3244,9 @@ static void tcp_chr_tls_handshake(Object *source,
 }
 
 
-static void tcp_chr_tls_init(CharDriverState *chr)
+static void tcp_chr_tls_init(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     QIOChannelTLS *tioc;
     Error *err = NULL;
     gchar *name;
@@ -3281,10 +3282,10 @@ static void tcp_chr_tls_init(CharDriverState *chr)
 }
 
 
-static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
+static void tcp_chr_set_client_ioc_name(Chardev *chr,
                                         QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     char *name;
     name = g_strdup_printf("chardev-tcp-%s-%s",
                            s->is_listen ? "server" : "client",
@@ -3294,9 +3295,9 @@ static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
 
 }
 
-static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
+static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (s->ioc != NULL) {
 	return -1;
@@ -3331,7 +3332,7 @@ static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
 }
 
 
-static int tcp_chr_add_client(CharDriverState *chr, int fd)
+static int tcp_chr_add_client(Chardev *chr, int fd)
 {
     int ret;
     QIOChannelSocket *sioc;
@@ -3350,7 +3351,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
                                GIOCondition cond,
                                void *opaque)
 {
-    CharDriverState *chr = opaque;
+    Chardev *chr = opaque;
     QIOChannelSocket *sioc;
 
     sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
@@ -3366,9 +3367,9 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
     return TRUE;
 }
 
-static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
+static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
     QIOChannelSocket *sioc;
 
     /* It can't wait on s->connected, since it is set asynchronously
@@ -3395,7 +3396,7 @@ static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
     return 0;
 }
 
-static int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
+static int qemu_chr_wait_connected(Chardev *chr, Error **errp)
 {
     if (chr->driver->chr_wait_connected) {
         return chr->driver->chr_wait_connected(chr, errp);
@@ -3414,9 +3415,9 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
     return qemu_chr_wait_connected(be->chr, errp);
 }
 
-static void tcp_chr_free(CharDriverState *chr)
+static void tcp_chr_free(Chardev *chr)
 {
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    TCPChardev *s = (TCPChardev *)chr;
 
     tcp_chr_free_connection(chr);
 
@@ -3443,8 +3444,8 @@ static void tcp_chr_free(CharDriverState *chr)
 static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 {
     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = (TCPCharDriver *)chr;
+    Chardev *chr = opaque;
+    TCPChardev *s = (TCPChardev *)chr;
 
     if (err) {
         check_report_connect_error(chr, err);
@@ -3462,24 +3463,24 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 /* Ring buffer chardev */
 
 typedef struct {
-    CharDriverState parent;
+    Chardev parent;
     size_t size;
     size_t prod;
     size_t cons;
     uint8_t *cbuf;
-} RingBufCharDriver;
+} RingBufChardev;
 
-static size_t ringbuf_count(const CharDriverState *chr)
+static size_t ringbuf_count(const Chardev *chr)
 {
-    const RingBufCharDriver *d = (RingBufCharDriver *)chr;
+    const RingBufChardev *d = (RingBufChardev *)chr;
 
     return d->prod - d->cons;
 }
 
 /* Called with chr_write_lock held.  */
-static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = (RingBufCharDriver *)chr;
+    RingBufChardev *d = (RingBufChardev *)chr;
     int i;
 
     if (!buf || (len < 0)) {
@@ -3496,9 +3497,9 @@ static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
+static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = (RingBufCharDriver *)chr;
+    RingBufChardev *d = (RingBufChardev *)chr;
     int i;
 
     qemu_mutex_lock(&chr->chr_write_lock);
@@ -3510,30 +3511,30 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
     return i;
 }
 
-static void ringbuf_chr_free(struct CharDriverState *chr)
+static void ringbuf_chr_free(struct Chardev *chr)
 {
-    RingBufCharDriver *d = (RingBufCharDriver *)chr;
+    RingBufChardev *d = (RingBufChardev *)chr;
 
     g_free(d->cbuf);
 }
 
-static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
-                                              const char *id,
-                                              ChardevBackend *backend,
-                                              ChardevReturn *ret,
-                                              bool *be_opened,
-                                              Error **errp)
+static Chardev *qemu_chr_open_ringbuf(const CharDriver *driver,
+                                      const char *id,
+                                      ChardevBackend *backend,
+                                      ChardevReturn *ret,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevRingbuf *opts = backend->u.ringbuf.data;
     ChardevCommon *common = qapi_ChardevRingbuf_base(opts);
-    CharDriverState *chr;
-    RingBufCharDriver *d;
+    Chardev *chr;
+    RingBufChardev *d;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    d = (RingBufCharDriver *)chr;
+    d = (RingBufChardev *)chr;
 
     d->size = opts->has_size ? opts->size : 65536;
 
@@ -3554,7 +3555,7 @@ fail:
     return NULL;
 }
 
-ChardevBackendKind qemu_chr_get_kind(const CharDriverState *chr)
+ChardevBackendKind qemu_chr_get_kind(const Chardev *chr)
 {
     return chr->driver->kind;
 }
@@ -3563,7 +3564,7 @@ void qmp_ringbuf_write(const char *device, const char *data,
                        bool has_format, enum DataFormat format,
                        Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     const uint8_t *write_data;
     int ret;
     gsize write_count;
@@ -3607,7 +3608,7 @@ char *qmp_ringbuf_read(const char *device, int64_t size,
                        bool has_format, enum DataFormat format,
                        Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     uint8_t *read_data;
     size_t count;
     char *data;
@@ -3839,12 +3840,12 @@ static const CharDriver stdio_driver = {
     .kind = CHARDEV_BACKEND_KIND_STDIO,
     .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio,
 #ifdef _WIN32
-    sizeof(WinStdioCharState),
+    sizeof(WinStdioChardev),
     .chr_write = win_stdio_write,
     .chr_set_echo = qemu_chr_set_echo_win_stdio,
     .chr_free = win_stdio_free,
 #else
-    sizeof(FDCharDriver),
+    sizeof(FDChardev),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3906,11 +3907,11 @@ static const CharDriver pipe_driver = {
     .kind = CHARDEV_BACKEND_KIND_PIPE,
     .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe,
 #ifdef _WIN32
-    sizeof(WinCharState),
+    sizeof(WinChardev),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
-    sizeof(FDCharDriver),
+    sizeof(FDChardev),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3935,7 +3936,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver ringbuf_driver = {
-    .instance_size = sizeof(RingBufCharDriver),
+    .instance_size = sizeof(RingBufChardev),
     .kind = CHARDEV_BACKEND_KIND_RINGBUF,
     .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
     .chr_write = ringbuf_chr_write,
@@ -3944,7 +3945,7 @@ static const CharDriver ringbuf_driver = {
 
 /* Bug-compatibility: */
 static const CharDriver memory_driver = {
-    .instance_size = sizeof(RingBufCharDriver),
+    .instance_size = sizeof(RingBufChardev),
     .kind = CHARDEV_BACKEND_KIND_MEMORY,
     .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
     .chr_write = ringbuf_chr_write,
@@ -3967,7 +3968,7 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver mux_driver = {
-    .instance_size = sizeof(MuxDriver),
+    .instance_size = sizeof(MuxChardev),
     .kind = CHARDEV_BACKEND_KIND_MUX,
     .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
     .chr_free = mux_chr_free,
@@ -4110,12 +4111,12 @@ void register_char_driver(const CharDriver *driver)
     backends[driver->kind] = driver;
 }
 
-CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                        Error **errp)
+Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
+                                Error **errp)
 {
     Error *local_err = NULL;
     const CharDriver *cd;
-    CharDriverState *chr;
+    Chardev *chr;
     int i;
     ChardevReturn *ret = NULL;
     ChardevBackend *backend;
@@ -4219,10 +4220,10 @@ err:
     return NULL;
 }
 
-CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename)
+Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
 {
     const char *p;
-    CharDriverState *chr;
+    Chardev *chr;
     QemuOpts *opts;
     Error *err = NULL;
 
@@ -4245,9 +4246,9 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename)
     return chr;
 }
 
-CharDriverState *qemu_chr_new(const char *label, const char *filename)
+Chardev *qemu_chr_new(const char *label, const char *filename)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     chr = qemu_chr_new_noreplay(label, filename);
     if (chr) {
         if (replay_mode != REPLAY_MODE_NONE) {
@@ -4264,7 +4265,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename)
 
 void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 {
-    CharDriverState *chr = be->chr;
+    Chardev *chr = be->chr;
 
     if (chr && chr->driver->chr_set_echo) {
         chr->driver->chr_set_echo(chr, echo);
@@ -4273,7 +4274,7 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 
 void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
 {
-    CharDriverState *chr = be->chr;
+    Chardev *chr = be->chr;
 
     if (!chr) {
         return;
@@ -4291,7 +4292,7 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
 guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
                             GIOFunc func, void *user_data)
 {
-    CharDriverState *s = be->chr;
+    Chardev *s = be->chr;
     GSource *src;
     guint tag;
 
@@ -4313,14 +4314,14 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
 
 void qemu_chr_fe_disconnect(CharBackend *be)
 {
-    CharDriverState *chr = be->chr;
+    Chardev *chr = be->chr;
 
     if (chr && chr->driver->chr_disconnect) {
         chr->driver->chr_disconnect(chr);
     }
 }
 
-static void qemu_chr_free_common(CharDriverState *chr)
+static void qemu_chr_free_common(Chardev *chr)
 {
     if (chr->be) {
         chr->be->chr = NULL;
@@ -4334,7 +4335,7 @@ static void qemu_chr_free_common(CharDriverState *chr)
     g_free(chr);
 }
 
-void qemu_chr_free(CharDriverState *chr)
+void qemu_chr_free(Chardev *chr)
 {
     if (chr->driver->chr_free) {
         chr->driver->chr_free(chr);
@@ -4342,7 +4343,7 @@ void qemu_chr_free(CharDriverState *chr)
     qemu_chr_free_common(chr);
 }
 
-void qemu_chr_delete(CharDriverState *chr)
+void qemu_chr_delete(Chardev *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
     qemu_chr_free(chr);
@@ -4351,7 +4352,7 @@ void qemu_chr_delete(CharDriverState *chr)
 ChardevInfoList *qmp_query_chardev(Error **errp)
 {
     ChardevInfoList *chr_list = NULL;
-    CharDriverState *chr;
+    Chardev *chr;
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
         ChardevInfoList *info = g_malloc0(sizeof(*info));
@@ -4401,9 +4402,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
     return backend_list;
 }
 
-CharDriverState *qemu_chr_find(const char *name)
+Chardev *qemu_chr_find(const char *name)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
         if (strcmp(chr->label, name) != 0)
@@ -4509,12 +4510,12 @@ QemuOptsList qemu_chardev_opts = {
 
 #ifdef _WIN32
 
-static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
-                                              const char *id,
-                                              ChardevBackend *backend,
-                                              ChardevReturn *ret,
-                                              bool *be_opened,
-                                              Error **errp)
+static Chardev *qmp_chardev_open_file(const CharDriver *driver,
+                                      const char *id,
+                                      ChardevBackend *backend,
+                                      ChardevReturn *ret,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
     ChardevCommon *common = qapi_ChardevFile_base(file);
@@ -4546,16 +4547,16 @@ static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
     return qemu_chr_open_win_file(driver, out, common, errp);
 }
 
-static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
-                                                const char *id,
-                                                ChardevBackend *backend,
-                                                ChardevReturn *ret,
-                                                bool *be_opened,
-                                                Error **errp)
+static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
+                                        const char *id,
+                                        ChardevBackend *backend,
+                                        ChardevReturn *ret,
+                                        bool *be_opened,
+                                        Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
-    CharDriverState *chr;
+    Chardev *chr;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
@@ -4584,12 +4585,12 @@ static int qmp_chardev_open_file_source(char *src, int flags,
     return fd;
 }
 
-static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
-                                              const char *id,
-                                              ChardevBackend *backend,
-                                              ChardevReturn *ret,
-                                              bool *be_opened,
-                                              Error **errp)
+static Chardev *qmp_chardev_open_file(const CharDriver *driver,
+                                      const char *id,
+                                      ChardevBackend *backend,
+                                      ChardevReturn *ret,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
     ChardevCommon *common = qapi_ChardevFile_base(file);
@@ -4620,12 +4621,12 @@ static CharDriverState *qmp_chardev_open_file(const CharDriver *driver,
 }
 
 #ifdef HAVE_CHARDEV_SERIAL
-static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
-                                                const char *id,
-                                                ChardevBackend *backend,
-                                                ChardevReturn *ret,
-                                                bool *be_opened,
-                                                Error **errp)
+static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
+                                        const char *id,
+                                        ChardevBackend *backend,
+                                        ChardevReturn *ret,
+                                        bool *be_opened,
+                                        Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
@@ -4643,12 +4644,12 @@ static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
 #endif
 
 #ifdef HAVE_CHARDEV_PARPORT
-static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
-                                                  const char *id,
-                                                  ChardevBackend *backend,
-                                                  ChardevReturn *ret,
-                                                  bool *be_opened,
-                                                  Error **errp)
+static Chardev *qmp_chardev_open_parallel(const CharDriver *driver,
+                                          const char *id,
+                                          ChardevBackend *backend,
+                                          ChardevReturn *ret,
+                                          bool *be_opened,
+                                          Error **errp)
 {
     ChardevHostdev *parallel = backend->u.parallel.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(parallel);
@@ -4662,7 +4663,7 @@ static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
 }
 
 static const CharDriver parallel_driver = {
-    .instance_size = sizeof(ParallelCharDriver),
+    .instance_size = sizeof(ParallelChardev),
     .alias = "parport", .kind = CHARDEV_BACKEND_KIND_PARALLEL,
     .parse = qemu_chr_parse_parallel, .create = qmp_chardev_open_parallel,
 #if defined(__linux__)
@@ -4683,11 +4684,11 @@ static const CharDriver file_driver = {
     .kind = CHARDEV_BACKEND_KIND_FILE,
     .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file,
 #ifdef _WIN32
-    sizeof(WinCharState),
+    sizeof(WinChardev),
     .chr_write = win_chr_write,
     /* FIXME: no chr_free */
 #else
-    sizeof(FDCharDriver),
+    sizeof(FDChardev),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4700,11 +4701,11 @@ static const CharDriver serial_driver = {
     .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
     .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
 #ifdef _WIN32
-    sizeof(WinCharState),
+    sizeof(WinChardev),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
-    sizeof(FDCharDriver),
+    sizeof(FDChardev),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4716,8 +4717,8 @@ static const CharDriver serial_driver = {
 
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = opaque;
+    Chardev *chr = opaque;
+    TCPChardev *s = opaque;
     QIOChannelSocket *sioc;
 
     s->reconnect_timer = 0;
@@ -4735,15 +4736,15 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
     return false;
 }
 
-static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
-                                                const char *id,
-                                                ChardevBackend *backend,
-                                                ChardevReturn *ret,
-                                                bool *be_opened,
-                                                Error **errp)
+static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
+                                        const char *id,
+                                        ChardevBackend *backend,
+                                        ChardevReturn *ret,
+                                        bool *be_opened,
+                                        Error **errp)
 {
-    CharDriverState *chr;
-    TCPCharDriver *s;
+    Chardev *chr;
+    TCPChardev *s;
     ChardevSocket *sock = backend->u.socket.data;
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
@@ -4758,7 +4759,7 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = (TCPCharDriver *)chr;
+    s = (TCPChardev *)chr;
 
     s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
@@ -4865,7 +4866,7 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
 }
 
 static const CharDriver socket_driver = {
-    .instance_size = sizeof(TCPCharDriver),
+    .instance_size = sizeof(TCPChardev),
     .kind = CHARDEV_BACKEND_KIND_SOCKET,
     .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket,
     .chr_wait_connected = tcp_chr_wait_connected,
@@ -4880,19 +4881,19 @@ static const CharDriver socket_driver = {
     .chr_free = tcp_chr_free,
 };
 
-static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
-                                             const char *id,
-                                             ChardevBackend *backend,
-                                             ChardevReturn *ret,
-                                             bool *be_opened,
-                                             Error **errp)
+static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
+                                     const char *id,
+                                     ChardevBackend *backend,
+                                     ChardevReturn *ret,
+                                     bool *be_opened,
+                                     Error **errp)
 {
     ChardevUdp *udp = backend->u.udp.data;
     ChardevCommon *common = qapi_ChardevUdp_base(udp);
     QIOChannelSocket *sioc = qio_channel_socket_new();
     char *name;
-    CharDriverState *chr;
-    NetCharDriver *s;
+    Chardev *chr;
+    NetChardev *s;
 
     if (qio_channel_socket_dgram_sync(sioc,
                                       udp->local, udp->remote,
@@ -4910,7 +4911,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
-    s = (NetCharDriver *)chr;
+    s = (NetChardev *)chr;
     s->ioc = QIO_CHANNEL(sioc);
     s->bufcnt = 0;
     s->bufptr = 0;
@@ -4921,7 +4922,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
 }
 
 static const CharDriver udp_driver = {
-    .instance_size = sizeof(NetCharDriver),
+    .instance_size = sizeof(NetChardev),
     .kind = CHARDEV_BACKEND_KIND_UDP,
     .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
     .chr_write = udp_chr_write,
@@ -4929,13 +4930,13 @@ static const CharDriver udp_driver = {
     .chr_free = udp_chr_free,
 };
 
-bool qemu_chr_has_feature(CharDriverState *chr,
+bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature)
 {
     return test_bit(feature, chr->features);
 }
 
-void qemu_chr_set_feature(CharDriverState *chr,
+void qemu_chr_set_feature(Chardev *chr,
                            CharDriverFeature feature)
 {
     return set_bit(feature, chr->features);
@@ -4945,7 +4946,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
     ChardevReturn *ret = g_new0(ChardevReturn, 1);
-    CharDriverState *chr = NULL;
+    Chardev *chr = NULL;
     const CharDriver *cd;
     Error *local_err = NULL;
     bool be_opened = true;
@@ -4986,7 +4987,7 @@ out_error:
 
 void qmp_chardev_remove(const char *id, Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     chr = qemu_chr_find(id);
     if (chr == NULL) {
@@ -5007,7 +5008,7 @@ void qmp_chardev_remove(const char *id, Error **errp)
 
 void qemu_chr_cleanup(void)
 {
-    CharDriverState *chr, *tmp;
+    Chardev *chr, *tmp;
 
     QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) {
         qemu_chr_delete(chr);
diff --git a/qmp.c b/qmp.c
index 0028f0b30e..d9554062ed 100644
--- a/qmp.c
+++ b/qmp.c
@@ -616,7 +616,7 @@ void qmp_add_client(const char *protocol, const char *fdname,
                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                     Error **errp)
 {
-    CharDriverState *s;
+    Chardev *s;
     int fd;
 
     fd = monitor_get_fd(cur_mon, fdname, errp);
diff --git a/qtest.c b/qtest.c
index 46b99aed52..b307db9ade 100644
--- a/qtest.c
+++ b/qtest.c
@@ -668,7 +668,7 @@ static int qtest_init_accel(MachineState *ms)
 
 void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     chr = qemu_chr_new("qtest", qtest_chrdev);
 
diff --git a/replay/replay-char.c b/replay/replay-char.c
index edf46ab9df..aa65955942 100755
--- a/replay/replay-char.c
+++ b/replay/replay-char.c
@@ -18,7 +18,7 @@
 
 /* Char drivers that generate qemu_chr_be_write events
    that should be saved into the log. */
-static CharDriverState **char_drivers;
+static Chardev **char_drivers;
 static int drivers_count;
 
 /* Char event attributes. */
@@ -28,7 +28,7 @@ typedef struct CharEvent {
     size_t len;
 } CharEvent;
 
-static int find_char_driver(CharDriverState *chr)
+static int find_char_driver(Chardev *chr)
 {
     int i = 0;
     for ( ; i < drivers_count ; ++i) {
@@ -39,7 +39,7 @@ static int find_char_driver(CharDriverState *chr)
     return -1;
 }
 
-void replay_register_char_driver(CharDriverState *chr)
+void replay_register_char_driver(Chardev *chr)
 {
     if (replay_mode == REPLAY_MODE_NONE) {
         return;
@@ -49,7 +49,7 @@ void replay_register_char_driver(CharDriverState *chr)
     char_drivers[drivers_count++] = chr;
 }
 
-void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void replay_chr_be_write(Chardev *s, uint8_t *buf, int len)
 {
     CharEvent *event = g_malloc0(sizeof(CharEvent));
 
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 4118059c96..5feb88c1ec 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -6,29 +6,29 @@
 #include <spice/protocol.h>
 
 
-typedef struct SpiceCharDriver {
-    CharDriverState       parent;
+typedef struct SpiceChardev {
+    Chardev               parent;
 
-    SpiceCharDeviceInstance     sin;
+    SpiceCharDeviceInstance sin;
     bool                  active;
     bool                  blocked;
     const uint8_t         *datapos;
     int                   datalen;
-    QLIST_ENTRY(SpiceCharDriver) next;
-} SpiceCharDriver;
+    QLIST_ENTRY(SpiceChardev) next;
+} SpiceChardev;
 
 typedef struct SpiceCharSource {
     GSource               source;
-    SpiceCharDriver       *scd;
+    SpiceChardev       *scd;
 } SpiceCharSource;
 
-static QLIST_HEAD(, SpiceCharDriver) spice_chars =
+static QLIST_HEAD(, SpiceChardev) spice_chars =
     QLIST_HEAD_INITIALIZER(spice_chars);
 
 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
 {
-    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
-    CharDriverState *chr = (CharDriverState *)scd;
+    SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
+    Chardev *chr = (Chardev *)scd;
     ssize_t out = 0;
     ssize_t last_out;
     uint8_t* p = (uint8_t*)buf;
@@ -51,7 +51,7 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
 
 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
 {
-    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
     int bytes = MIN(len, scd->datalen);
 
     if (bytes > 0) {
@@ -71,8 +71,8 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
 #if SPICE_SERVER_VERSION >= 0x000c02
 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
 {
-    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
-    CharDriverState *chr = (CharDriverState *)scd;
+    SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
+    Chardev *chr = (Chardev *)scd;
     int chr_event;
 
     switch (event) {
@@ -90,8 +90,8 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
 
 static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
 {
-    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
-    CharDriverState *chr = (CharDriverState *)scd;
+    SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
+    Chardev *chr = (Chardev *)scd;
 
     if ((chr->be_open && connected) ||
         (!chr->be_open && !connected)) {
@@ -119,7 +119,7 @@ static SpiceCharDeviceInterface vmc_interface = {
 };
 
 
-static void vmc_register_interface(SpiceCharDriver *scd)
+static void vmc_register_interface(SpiceChardev *scd)
 {
     if (scd->active) {
         return;
@@ -130,7 +130,7 @@ static void vmc_register_interface(SpiceCharDriver *scd)
     trace_spice_vmc_register_interface(scd);
 }
 
-static void vmc_unregister_interface(SpiceCharDriver *scd)
+static void vmc_unregister_interface(SpiceChardev *scd)
 {
     if (!scd->active) {
         return;
@@ -170,9 +170,9 @@ static GSourceFuncs SpiceCharSourceFuncs = {
     .dispatch = spice_char_source_dispatch,
 };
 
-static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    SpiceCharDriver *scd = (SpiceCharDriver *)chr;
+    SpiceChardev *scd = (SpiceChardev *)chr;
     SpiceCharSource *src;
 
     assert(cond & G_IO_OUT);
@@ -184,9 +184,9 @@ static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
     return (GSource *)src;
 }
 
-static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    SpiceCharDriver *s = (SpiceCharDriver *)chr;
+    SpiceChardev *s = (SpiceChardev *)chr;
     int read_bytes;
 
     assert(s->datalen == 0);
@@ -203,9 +203,9 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return read_bytes;
 }
 
-static void spice_chr_free(struct CharDriverState *chr)
+static void spice_chr_free(struct Chardev *chr)
 {
-    SpiceCharDriver *s = (SpiceCharDriver *)chr;
+    SpiceChardev *s = (SpiceChardev *)chr;
 
     vmc_unregister_interface(s);
     QLIST_REMOVE(s, next);
@@ -216,9 +216,9 @@ static void spice_chr_free(struct CharDriverState *chr)
 #endif
 }
 
-static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
+static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
 {
-    SpiceCharDriver *s = (SpiceCharDriver *)chr;
+    SpiceChardev *s = (SpiceChardev *)chr;
     if (fe_open) {
         vmc_register_interface(s);
     } else {
@@ -226,10 +226,10 @@ static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
     }
 }
 
-static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
+static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
 {
 #if SPICE_SERVER_VERSION >= 0x000c02
-    SpiceCharDriver *s = (SpiceCharDriver *)chr;
+    SpiceChardev *s = (SpiceChardev *)chr;
 
     if (fe_open) {
         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
@@ -256,26 +256,26 @@ static void print_allowed_subtypes(void)
     fprintf(stderr, "\n");
 }
 
-static void spice_chr_accept_input(struct CharDriverState *chr)
+static void spice_chr_accept_input(struct Chardev *chr)
 {
-    SpiceCharDriver *s = (SpiceCharDriver *)chr;
+    SpiceChardev *s = (SpiceChardev *)chr;
 
     spice_server_char_device_wakeup(&s->sin);
 }
 
-static CharDriverState *chr_open(const CharDriver *driver,
+static Chardev *chr_open(const CharDriver *driver,
                                  const char *subtype,
                                  ChardevCommon *backend,
                                  Error **errp)
 {
-    CharDriverState *chr;
-    SpiceCharDriver *s;
+    Chardev *chr;
+    SpiceChardev *s;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    s = (SpiceCharDriver *)chr;
+    s = (SpiceChardev *)chr;
     s->active = false;
     s->sin.subtype = g_strdup(subtype);
 
@@ -284,7 +284,7 @@ static CharDriverState *chr_open(const CharDriver *driver,
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_spice_vmc(const CharDriver *driver,
+static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
                                                 const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
@@ -312,7 +312,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const CharDriver *driver,
 }
 
 #if SPICE_SERVER_VERSION >= 0x000c02
-static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
+static Chardev *qemu_chr_open_spice_port(const CharDriver *driver,
                                                  const char *id,
                                                  ChardevBackend *backend,
                                                  ChardevReturn *ret,
@@ -322,8 +322,8 @@ static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
     ChardevSpicePort *spiceport = backend->u.spiceport.data;
     const char *name = spiceport->fqdn;
     ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
-    CharDriverState *chr;
-    SpiceCharDriver *s;
+    Chardev *chr;
+    SpiceChardev *s;
 
     if (name == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
@@ -335,7 +335,7 @@ static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
         return NULL;
     }
     *be_opened = false;
-    s = (SpiceCharDriver *)chr;
+    s = (SpiceChardev *)chr;
     s->sin.portname = g_strdup(name);
 
     return chr;
@@ -343,7 +343,7 @@ static CharDriverState *qemu_chr_open_spice_port(const CharDriver *driver,
 
 void qemu_spice_register_ports(void)
 {
-    SpiceCharDriver *s;
+    SpiceChardev *s;
 
     QLIST_FOREACH(s, &spice_chars, next) {
         if (s->sin.portname == NULL) {
@@ -387,7 +387,7 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
 static void register_types(void)
 {
     static const CharDriver vmc_driver = {
-        .instance_size = sizeof(SpiceCharDriver),
+        .instance_size = sizeof(SpiceChardev),
         .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
         .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc,
         .chr_write = spice_chr_write,
@@ -397,7 +397,7 @@ static void register_types(void)
         .chr_free = spice_chr_free,
     };
     static const CharDriver port_driver = {
-        .instance_size = sizeof(SpiceCharDriver),
+        .instance_size = sizeof(SpiceChardev),
         .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
         .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port,
         .chr_write = spice_chr_write,
diff --git a/stubs/get-next-serial.c b/stubs/get-next-serial.c
index 6ff6a6d3b2..df425e95c7 100644
--- a/stubs/get-next-serial.c
+++ b/stubs/get-next-serial.c
@@ -1,4 +1,4 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 
-CharDriverState *serial_hds[0];
+Chardev *serial_hds[0];
diff --git a/stubs/monitor-init.c b/stubs/monitor-init.c
index de1bc7cd54..ebe56c2819 100644
--- a/stubs/monitor-init.c
+++ b/stubs/monitor-init.c
@@ -2,6 +2,6 @@
 #include "qemu-common.h"
 #include "monitor/monitor.h"
 
-void monitor_init(CharDriverState *chr, int flags)
+void monitor_init(Chardev *chr, int flags)
 {
 }
diff --git a/stubs/replay.c b/stubs/replay.c
index d9a6da99d2..9c8aa48c9c 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -30,11 +30,11 @@ void replay_finish(void)
 {
 }
 
-void replay_register_char_driver(CharDriverState *chr)
+void replay_register_char_driver(Chardev *chr)
 {
 }
 
-void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void replay_chr_be_write(Chardev *s, uint8_t *buf, int len)
 {
     abort();
 }
diff --git a/tests/test-char.c b/tests/test-char.c
index 241685afbb..da69f110e4 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -40,7 +40,7 @@ static void fe_event(void *opaque, int event)
 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
 static void char_stdio_test_subprocess(void)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     CharBackend be;
     int ret;
 
@@ -68,7 +68,7 @@ static void char_stdio_test(void)
 static void char_ringbuf_test(void)
 {
     QemuOpts *opts;
-    CharDriverState *chr;
+    Chardev *chr;
     CharBackend be;
     char *data;
     int ret;
@@ -109,7 +109,7 @@ static void char_ringbuf_test(void)
 static void char_mux_test(void)
 {
     QemuOpts *opts;
-    CharDriverState *chr, *base;
+    Chardev *chr, *base;
     char *data;
     FeHandler h1 = { 0, }, h2 = { 0, };
     CharBackend chr_be1, chr_be2;
@@ -185,7 +185,7 @@ static void char_mux_test(void)
 static void char_null_test(void)
 {
     Error *err = NULL;
-    CharDriverState *chr;
+    Chardev *chr;
     CharBackend be;
     int ret;
 
@@ -227,7 +227,7 @@ static void char_null_test(void)
 
 static void char_invalid_test(void)
 {
-    CharDriverState *chr;
+    Chardev *chr;
 
     chr = qemu_chr_new("label-invalid", "invalid");
     g_assert_null(chr);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 96bf00eefa..f3ac6ea21a 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -454,7 +454,7 @@ static void chr_event(void *opaque, int event)
 static void test_server_create_chr(TestServer *server, const gchar *opt)
 {
     gchar *chr_path;
-    CharDriverState *chr;
+    Chardev *chr;
 
     chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
     chr = qemu_chr_new(server->chr_name, chr_path);
@@ -486,7 +486,7 @@ static inline void test_server_connect(TestServer *server)
 static gboolean _test_server_free(TestServer *server)
 {
     int i;
-    CharDriverState *chr = qemu_chr_fe_get_driver(&server->chr);
+    Chardev *chr = qemu_chr_fe_get_driver(&server->chr);
 
     qemu_chr_fe_deinit(&server->chr);
     qemu_chr_delete(chr);
diff --git a/ui/console.c b/ui/console.c
index cda1b56024..80d10c7a4c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -157,7 +157,7 @@ struct QemuConsole {
     int esc_params[MAX_ESC_PARAMS];
     int nb_esc_params;
 
-    CharDriverState *chr;
+    Chardev *chr;
     /* fifo for key pressed */
     QEMUFIFO out_fifo;
     uint8_t out_fifo_buf[16];
@@ -182,7 +182,7 @@ static int nb_consoles = 0;
 static bool cursor_visible_phase;
 static QEMUTimer *cursor_timer;
 
-static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
+static void text_console_do_init(Chardev *chr, DisplayState *ds);
 static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
 static void text_console_update_cursor_timer(void);
@@ -1035,14 +1035,14 @@ void console_select(unsigned int index)
     }
 }
 
-typedef struct VCDriverState {
-    CharDriverState parent;
+typedef struct VCChardev {
+    Chardev parent;
     QemuConsole *console;
-} VCDriverState;
+} VCChardev;
 
-static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
+static int console_puts(Chardev *chr, const uint8_t *buf, int len)
 {
-    VCDriverState *drv = (VCDriverState *)chr;
+    VCChardev *drv = (VCChardev *)chr;
     QemuConsole *s = drv->console;
     int i;
 
@@ -1951,9 +1951,9 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
     return con ? surface_height(con->surface) : fallback;
 }
 
-static void text_console_set_echo(CharDriverState *chr, bool echo)
+static void text_console_set_echo(Chardev *chr, bool echo)
 {
-    VCDriverState *drv = (VCDriverState *)chr;
+    VCChardev *drv = (VCChardev *)chr;
     QemuConsole *s = drv->console;
 
     s->echo = echo;
@@ -1992,9 +1992,9 @@ static const GraphicHwOps text_console_ops = {
     .text_update = text_console_update,
 };
 
-static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
+static void text_console_do_init(Chardev *chr, DisplayState *ds)
 {
-    VCDriverState *drv = (VCDriverState *)chr;
+    VCChardev *drv = (VCChardev *)chr;
     QemuConsole *s = drv->console;
     int g_width = 80 * FONT_WIDTH;
     int g_height = 24 * FONT_HEIGHT;
@@ -2047,11 +2047,11 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 
 static const CharDriver vc_driver;
 
-static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
+static Chardev *text_console_init(ChardevVC *vc, Error **errp)
 {
     ChardevCommon *common = qapi_ChardevVC_base(vc);
-    CharDriverState *chr;
-    VCDriverState *drv;
+    Chardev *chr;
+    VCChardev *drv;
     QemuConsole *s;
     unsigned width = 0;
     unsigned height = 0;
@@ -2088,7 +2088,7 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
     }
 
     s->chr = chr;
-    drv = (VCDriverState *)chr;
+    drv = (VCChardev *)chr;
     drv->console = s;
 
     if (display_state) {
@@ -2099,10 +2099,10 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 
 static VcHandler *vc_handler = text_console_init;
 
-static CharDriverState *vc_init(const CharDriver *driver,
-                                const char *id, ChardevBackend *backend,
-                                ChardevReturn *ret, bool *be_opened,
-                                Error **errp)
+static Chardev *vc_init(const CharDriver *driver,
+                        const char *id, ChardevBackend *backend,
+                        ChardevReturn *ret, bool *be_opened,
+                        Error **errp)
 {
     /* console/chardev init sometimes completes elsewhere in a 2nd
      * stage, so defer OPENED events until they are fully initialized
@@ -2193,7 +2193,7 @@ static const TypeInfo qemu_console_info = {
 };
 
 static const CharDriver vc_driver = {
-    .instance_size = sizeof(VCDriverState),
+    .instance_size = sizeof(VCChardev),
     .kind = CHARDEV_BACKEND_KIND_VC,
     .parse = qemu_chr_parse_vc, .create = vc_init,
     .chr_write = console_puts,
diff --git a/ui/gtk.c b/ui/gtk.c
index feca4047e2..32df26e5d7 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -178,11 +178,11 @@ struct GtkDisplayState {
     bool ignore_keys;
 };
 
-typedef struct VCDriverState {
-    CharDriverState parent;
+typedef struct VCChardev {
+    Chardev parent;
     VirtualConsole *console;
     bool echo;
-} VCDriverState;
+} VCChardev;
 
 static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
 static void gd_ungrab_pointer(GtkDisplayState *s);
@@ -1679,18 +1679,18 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
     }
 }
 
-static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    VCDriverState *vcd = (VCDriverState *)chr;
+    VCChardev *vcd = (VCChardev *)chr;
     VirtualConsole *vc = vcd->console;
 
     vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
     return len;
 }
 
-static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
+static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
 {
-    VCDriverState *vcd = (VCDriverState *)chr;
+    VCChardev *vcd = (VCChardev *)chr;
     VirtualConsole *vc = vcd->console;
 
     if (vc) {
@@ -1701,19 +1701,19 @@ static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
 }
 
 static int nb_vcs;
-static CharDriverState *vcs[MAX_VCS];
+static Chardev *vcs[MAX_VCS];
 
-static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
+static Chardev *gd_vc_handler(ChardevVC *vc, Error **errp)
 {
     static const CharDriver gd_vc_driver = {
-        .instance_size = sizeof(VCDriverState),
+        .instance_size = sizeof(VCChardev),
         .kind = CHARDEV_BACKEND_KIND_VC,
         .chr_write = gd_vc_chr_write,
         .chr_set_echo = gd_vc_chr_set_echo,
     };
 
     ChardevCommon *common = qapi_ChardevVC_base(vc);
-    CharDriverState *chr;
+    Chardev *chr;
 
     if (nb_vcs == MAX_VCS) {
         error_setg(errp, "Maximum number of consoles reached");
@@ -1758,14 +1758,14 @@ static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
 }
 
 static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
-                              CharDriverState *chr, int idx,
+                              Chardev *chr, int idx,
                               GSList *group, GtkWidget *view_menu)
 {
     char buffer[32];
     GtkWidget *box;
     GtkWidget *scrollbar;
     GtkAdjustment *vadjustment;
-    VCDriverState *vcd = (VCDriverState *)chr;
+    VCChardev *vcd = (VCChardev *)chr;
 
     vc->s = s;
     vc->vte.echo = vcd->echo;
diff --git a/vl.c b/vl.c
index d77dd862f9..8296f8da49 100644
--- a/vl.c
+++ b/vl.c
@@ -149,10 +149,10 @@ static int full_screen = 0;
 static int no_frame = 0;
 int no_quit = 0;
 static bool grab_on_hover;
-CharDriverState *serial_hds[MAX_SERIAL_PORTS];
-CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
-CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
-CharDriverState *sclp_hds[MAX_SCLP_CONSOLES];
+Chardev *serial_hds[MAX_SERIAL_PORTS];
+Chardev *parallel_hds[MAX_PARALLEL_PORTS];
+Chardev *virtcon_hds[MAX_VIRTIO_CONSOLES];
+Chardev *sclp_hds[MAX_SCLP_CONSOLES];
 int win2k_install_hack = 0;
 int singlestep = 0;
 int smp_cpus = 1;
@@ -2400,7 +2400,7 @@ static int fsdev_init_func(void *opaque, QemuOpts *opts, Error **errp)
 
 static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
 {
-    CharDriverState *chr;
+    Chardev *chr;
     const char *chardev;
     const char *mode;
     int flags;
diff --git a/xen-common-stub.c b/xen-common-stub.c
index 699c3f1c64..09fce2dd36 100644
--- a/xen-common-stub.c
+++ b/xen-common-stub.c
@@ -9,6 +9,6 @@
 #include "qemu-common.h"
 #include "hw/xen/xen.h"
 
-void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+void xenstore_store_pv_console_info(int i, Chardev *chr)
 {
 }
diff --git a/xen-common.c b/xen-common.c
index 909976071c..fd2c92847e 100644
--- a/xen-common.c
+++ b/xen-common.c
@@ -25,7 +25,7 @@
     do { } while (0)
 #endif
 
-static int store_dev_info(int domid, CharDriverState *cs, const char *string)
+static int store_dev_info(int domid, Chardev *cs, const char *string)
 {
     struct xs_handle *xs = NULL;
     char *path = NULL;
@@ -74,7 +74,7 @@ out:
     return ret;
 }
 
-void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+void xenstore_store_pv_console_info(int i, Chardev *chr)
 {
     if (i == 0) {
         store_dev_info(xen_domid, chr, "/console");
diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h
index db9eb29ea4..d1514a61b3 100644
--- a/hw/lm32/lm32.h
+++ b/hw/lm32/lm32.h
@@ -16,7 +16,7 @@ static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
     return dev;
 }
 
-static inline DeviceState *lm32_juart_init(CharDriverState *chr)
+static inline DeviceState *lm32_juart_init(Chardev *chr)
 {
     DeviceState *dev;
 
@@ -29,7 +29,7 @@ static inline DeviceState *lm32_juart_init(CharDriverState *chr)
 
 static inline DeviceState *lm32_uart_create(hwaddr addr,
                                             qemu_irq irq,
-                                            CharDriverState *chr)
+                                            Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h
index 4418b44ca9..d3be0cfb3a 100644
--- a/hw/lm32/milkymist-hw.h
+++ b/hw/lm32/milkymist-hw.h
@@ -6,7 +6,7 @@
 
 static inline DeviceState *milkymist_uart_create(hwaddr base,
                                                  qemu_irq irq,
-                                                 CharDriverState *chr)
+                                                 Chardev *chr)
 {
     DeviceState *dev;
 
diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h
index 29fef8bfa1..4f6889dbad 100644
--- a/include/hw/arm/exynos4210.h
+++ b/include/hw/arm/exynos4210.h
@@ -131,7 +131,7 @@ void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
 DeviceState *exynos4210_uart_create(hwaddr addr,
                                     int fifo_size,
                                     int channel,
-                                    CharDriverState *chr,
+                                    Chardev *chr,
                                     qemu_irq irq);
 
 #endif /* EXYNOS4210_H */
diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h
index f026c8df57..80d326ef8a 100644
--- a/include/hw/arm/omap.h
+++ b/include/hw/arm/omap.h
@@ -664,14 +664,14 @@ struct omap_uart_s;
 struct omap_uart_s *omap_uart_init(hwaddr base,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
                 qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr);
+                const char *label, Chardev *chr);
 struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
                 struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
                 qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr);
+                const char *label, Chardev *chr);
 void omap_uart_reset(struct omap_uart_s *s);
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
+void omap_uart_attach(struct omap_uart_s *s, Chardev *chr);
 
 struct omap_mpuio_s;
 qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
diff --git a/include/hw/bt.h b/include/hw/bt.h
index 2fa22bdab6..b5e11d4d43 100644
--- a/include/hw/bt.h
+++ b/include/hw/bt.h
@@ -127,8 +127,8 @@ enum {
     csrhci_pin_wakeup,
     __csrhci_pins,
 };
-qemu_irq *csrhci_pins_get(CharDriverState *chr);
-CharDriverState *uart_hci_init(void);
+qemu_irq *csrhci_pins_get(Chardev *chr);
+Chardev *uart_hci_init(void);
 
 /* bt-l2cap.c */
 struct bt_l2cap_device_s;
diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h
index ca75eb5e32..c836db4b74 100644
--- a/include/hw/char/cadence_uart.h
+++ b/include/hw/char/cadence_uart.h
@@ -51,7 +51,7 @@ typedef struct {
 
 static inline DeviceState *cadence_uart_create(hwaddr addr,
                                         qemu_irq irq,
-                                        CharDriverState *chr)
+                                        Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h
index 297e2ebcda..08ae122386 100644
--- a/include/hw/char/escc.h
+++ b/include/hw/char/escc.h
@@ -5,7 +5,7 @@
 #define TYPE_ESCC "escc"
 #define ESCC_SIZE 4
 MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
-              CharDriverState *chrA, CharDriverState *chrB,
+              Chardev *chrA, Chardev *chrB,
               int clock, int it_shift);
 
 void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
index 0ca7c19410..83649324b6 100644
--- a/include/hw/char/pl011.h
+++ b/include/hw/char/pl011.h
@@ -17,7 +17,7 @@
 
 static inline DeviceState *pl011_create(hwaddr addr,
                                         qemu_irq irq,
-                                        CharDriverState *chr)
+                                        Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -34,7 +34,7 @@ static inline DeviceState *pl011_create(hwaddr addr,
 
 static inline DeviceState *pl011_luminary_create(hwaddr addr,
                                                  qemu_irq irq,
-                                                 CharDriverState *chr)
+                                                 Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index c928d7d907..daebb076c2 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -88,11 +88,11 @@ void serial_set_frequency(SerialState *s, uint32_t frequency);
 
 /* legacy pre qom */
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
-                         CharDriverState *chr, MemoryRegion *system_io);
+                         Chardev *chr, MemoryRegion *system_io);
 SerialState *serial_mm_init(MemoryRegion *address_space,
                             hwaddr base, int it_shift,
                             qemu_irq irq, int baudbase,
-                            CharDriverState *chr, enum device_endian end);
+                            Chardev *chr, enum device_endian end);
 
 /* serial-isa.c */
 #define TYPE_ISA_SERIAL "isa-serial"
diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h
index 8b4fc54953..634086b657 100644
--- a/include/hw/char/xilinx_uartlite.h
+++ b/include/hw/char/xilinx_uartlite.h
@@ -17,7 +17,7 @@
 
 static inline DeviceState *xilinx_uartlite_create(hwaddr addr,
                                         qemu_irq irq,
-                                        CharDriverState *chr)
+                                        Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h
index 723a2753c8..8da965addb 100644
--- a/include/hw/cris/etraxfs.h
+++ b/include/hw/cris/etraxfs.h
@@ -48,7 +48,7 @@ etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr,
 
 static inline DeviceState *etraxfs_ser_create(hwaddr addr,
                                               qemu_irq irq,
-                                              CharDriverState *chr)
+                                              Chardev *chr)
 {
     DeviceState *dev;
     SysBusDevice *s;
diff --git a/include/hw/devices.h b/include/hw/devices.h
index c60bcabae3..7475b714de 100644
--- a/include/hw/devices.h
+++ b/include/hw/devices.h
@@ -65,6 +65,6 @@ qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
 /* sm501.c */
 void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base,
                 uint32_t local_mem_bytes, qemu_irq irq,
-                CharDriverState *chr);
+                Chardev *chr);
 
 #endif
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 4b74130559..a0f5133560 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -175,7 +175,7 @@ void parallel_hds_isa_init(ISABus *bus, int n);
 
 bool parallel_mm_init(MemoryRegion *address_space,
                       hwaddr base, int it_shift, qemu_irq irq,
-                      CharDriverState *chr);
+                      Chardev *chr);
 
 /* i8259.c */
 
diff --git a/include/hw/m68k/mcf.h b/include/hw/m68k/mcf.h
index 0f0d2288e6..08d6af8713 100644
--- a/include/hw/m68k/mcf.h
+++ b/include/hw/m68k/mcf.h
@@ -11,10 +11,10 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
                        unsigned size);
 void mcf_uart_write(void *opaque, hwaddr addr,
                     uint64_t val, unsigned size);
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr);
+void *mcf_uart_init(qemu_irq irq, Chardev *chr);
 void mcf_uart_mm_init(struct MemoryRegion *sysmem,
                       hwaddr base,
-                      qemu_irq irq, CharDriverState *chr);
+                      qemu_irq irq, Chardev *chr);
 
 /* mcf_intc.c */
 qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem,
diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h
index 14f502240e..fc6f673ea0 100644
--- a/include/hw/ppc/spapr_vio.h
+++ b/include/hw/ppc/spapr_vio.h
@@ -127,7 +127,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
 
 VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg);
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev);
+void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev);
 void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd);
 void spapr_vscsi_create(VIOsPAPRBus *bus);
 
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 306bbab088..7ac315331a 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -184,7 +184,7 @@ void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
 void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
-void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
+void qdev_prop_set_chr(DeviceState *dev, const char *name, Chardev *value);
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value);
 void qdev_prop_set_drive(DeviceState *dev, const char *name,
                          BlockBackend *value, Error **errp);
diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h
index 070312d921..1e733a9cde 100644
--- a/include/hw/sh4/sh.h
+++ b/include/hw/sh4/sh.h
@@ -42,7 +42,7 @@ void tmu012_init(struct MemoryRegion *sysmem, hwaddr base,
 #define SH_SERIAL_FEAT_SCIF (1 << 0)
 void sh_serial_init(MemoryRegion *sysmem,
                     hwaddr base, int feat,
-		     uint32_t freq, CharDriverState *chr,
+                    uint32_t freq, Chardev *chr,
 		     qemu_irq eri_source,
 		     qemu_irq rxi_source,
 		     qemu_irq txi_source,
diff --git a/include/hw/sparc/grlib.h b/include/hw/sparc/grlib.h
index afbb9bc07c..61a345c269 100644
--- a/include/hw/sparc/grlib.h
+++ b/include/hw/sparc/grlib.h
@@ -100,7 +100,7 @@ DeviceState *grlib_gptimer_create(hwaddr  base,
 
 static inline
 DeviceState *grlib_apbuart_create(hwaddr  base,
-                                  CharDriverState    *serial,
+                                  Chardev    *serial,
                                   qemu_irq            irq)
 {
     DeviceState *dev;
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index a8f3afb03b..09c2ce5170 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -37,7 +37,7 @@ int xen_is_pirq_msi(uint32_t msi_data);
 
 qemu_irq *xen_interrupt_controller_init(void);
 
-void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
+void xenstore_store_pv_console_info(int i, struct Chardev *chr);
 
 void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory);
 
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 8cc532ec0e..e64b944d7c 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -16,7 +16,7 @@ extern Monitor *cur_mon;
 
 bool monitor_cur_is_qmp(void);
 
-void monitor_init(CharDriverState *chr, int flags);
+void monitor_init(Chardev *chr, int flags);
 void monitor_cleanup(void);
 
 int monitor_suspend(Monitor *mon);
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 1b8c30a7a0..3b54289e5a 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -17,7 +17,7 @@ typedef struct BlockBackendRootState BlockBackendRootState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct BusClass BusClass;
 typedef struct BusState BusState;
-typedef struct CharDriverState CharDriverState;
+typedef struct Chardev Chardev;
 typedef struct CompatProperty CompatProperty;
 typedef struct CPUAddressSpace CPUAddressSpace;
 typedef struct CPUState CPUState;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 5d8ec982a9..029b14c8b6 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -76,9 +76,9 @@ typedef enum {
 } CharDriverFeature;
 
 /* This is the backend as seen by frontend, the actual backend is
- * CharDriverState */
+ * Chardev */
 typedef struct CharBackend {
-    CharDriverState *chr;
+    Chardev *chr;
     IOEventHandler *chr_event;
     IOCanReadHandler *chr_can_read;
     IOReadHandler *chr_read;
@@ -89,7 +89,7 @@ typedef struct CharBackend {
 
 typedef struct CharDriver CharDriver;
 
-struct CharDriverState {
+struct Chardev {
     const CharDriver *driver;
     QemuMutex chr_write_lock;
     CharBackend *be;
@@ -99,7 +99,7 @@ struct CharDriverState {
     int be_open;
     guint fd_in_tag;
     DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
-    QTAILQ_ENTRY(CharDriverState) next;
+    QTAILQ_ENTRY(Chardev) next;
 };
 
 /**
@@ -107,12 +107,12 @@ struct CharDriverState {
  * @backend: the common backend config
  * @errp: pointer to a NULL-initialized error object
  *
- * Allocate and initialize a new CharDriverState.
+ * Allocate and initialize a new Chardev.
  *
- * Returns: a newly allocated CharDriverState, or NULL on error.
+ * Returns: a newly allocated Chardev, or NULL on error.
  */
-CharDriverState *qemu_chr_alloc(const CharDriver *driver,
-                                ChardevCommon *backend, Error **errp);
+Chardev *qemu_chr_alloc(const CharDriver *driver,
+                        ChardevCommon *backend, Error **errp);
 
 /**
  * @qemu_chr_new_from_opts:
@@ -123,8 +123,8 @@ CharDriverState *qemu_chr_alloc(const CharDriver *driver,
  *
  * Returns: a new character backend
  */
-CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                        Error **errp);
+Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
+                                Error **errp);
 
 /**
  * @qemu_chr_parse_common:
@@ -146,7 +146,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
  *
  * Returns: a new character backend
  */
-CharDriverState *qemu_chr_new(const char *label, const char *filename);
+Chardev *qemu_chr_new(const char *label, const char *filename);
 
 
 /**
@@ -184,7 +184,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
  *
  * Returns: a new character backend
  */
-CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename);
+Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
 
 /**
  * @qemu_chr_delete:
@@ -192,14 +192,14 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename);
  * Destroy a character backend and remove it from the list of
  * identified character backends.
  */
-void qemu_chr_delete(CharDriverState *chr);
+void qemu_chr_delete(Chardev *chr);
 
 /**
  * @qemu_chr_free:
  *
  * Destroy a character backend.
  */
-void qemu_chr_free(CharDriverState *chr);
+void qemu_chr_free(Chardev *chr);
 
 /**
  * @qemu_chr_fe_set_echo:
@@ -353,7 +353,7 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num);
  *
  * Returns: the number of bytes the front end can receive via @qemu_chr_be_write
  */
-int qemu_chr_be_can_write(CharDriverState *s);
+int qemu_chr_be_can_write(Chardev *s);
 
 /**
  * @qemu_chr_be_write:
@@ -365,7 +365,7 @@ int qemu_chr_be_can_write(CharDriverState *s);
  * @buf a buffer to receive data from the front end
  * @len the number of bytes to receive from the front end
  */
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
 
 /**
  * @qemu_chr_be_write_impl:
@@ -375,7 +375,7 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
  * @buf a buffer to receive data from the front end
  * @len the number of bytes to receive from the front end
  */
-void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
 
 /**
  * @qemu_chr_be_event:
@@ -384,7 +384,7 @@ void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
  *
  * @event the event to send
  */
-void qemu_chr_be_event(CharDriverState *s, int event);
+void qemu_chr_be_event(Chardev *s, int event);
 
 /**
  * @qemu_chr_fe_init:
@@ -395,7 +395,7 @@ void qemu_chr_be_event(CharDriverState *s, int event);
  *
  * Returns: false on error.
  */
-bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
+bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp);
 
 /**
  * @qemu_chr_fe_get_driver:
@@ -403,7 +403,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
  * Returns the driver associated with a CharBackend or NULL if no
  * associated CharDriver.
  */
-CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
+Chardev *qemu_chr_fe_get_driver(CharBackend *be);
 
 /**
  * @qemu_chr_fe_deinit:
@@ -448,27 +448,27 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
  */
 void qemu_chr_fe_take_focus(CharBackend *b);
 
-void qemu_chr_be_generic_open(CharDriverState *s);
+void qemu_chr_be_generic_open(Chardev *s);
 void qemu_chr_fe_accept_input(CharBackend *be);
-int qemu_chr_add_client(CharDriverState *s, int fd);
-CharDriverState *qemu_chr_find(const char *name);
+int qemu_chr_add_client(Chardev *s, int fd);
+Chardev *qemu_chr_find(const char *name);
 
 /**
  * @qemu_chr_get_kind:
  *
  * Returns the kind of char backend, or -1 if unspecified.
  */
-ChardevBackendKind qemu_chr_get_kind(const CharDriverState *chr);
+ChardevBackendKind qemu_chr_get_kind(const Chardev *chr);
 
-static inline bool qemu_chr_is_ringbuf(const CharDriverState *chr)
+static inline bool qemu_chr_is_ringbuf(const Chardev *chr)
 {
     return qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_RINGBUF ||
         qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MEMORY;
 }
 
-bool qemu_chr_has_feature(CharDriverState *chr,
+bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature);
-void qemu_chr_set_feature(CharDriverState *chr,
+void qemu_chr_set_feature(Chardev *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
@@ -476,29 +476,29 @@ struct CharDriver {
     const char *alias;
     ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
-    CharDriverState *(*create)(const CharDriver *driver,
-                               const char *id,
-                               ChardevBackend *backend,
-                               ChardevReturn *ret, bool *be_opened,
-                               Error **errp);
+    Chardev *(*create)(const CharDriver *driver,
+                       const char *id,
+                       ChardevBackend *backend,
+                       ChardevReturn *ret, bool *be_opened,
+                       Error **errp);
     size_t instance_size;
 
-    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
-    int (*chr_sync_read)(struct CharDriverState *s,
+    int (*chr_write)(struct Chardev *s, const uint8_t *buf, int len);
+    int (*chr_sync_read)(struct Chardev *s,
                          const uint8_t *buf, int len);
-    GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
-    void (*chr_update_read_handler)(struct CharDriverState *s,
+    GSource *(*chr_add_watch)(struct Chardev *s, GIOCondition cond);
+    void (*chr_update_read_handler)(struct Chardev *s,
                                     GMainContext *context);
-    int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
-    int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
-    int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
-    int (*chr_add_client)(struct CharDriverState *chr, int fd);
-    int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
-    void (*chr_free)(struct CharDriverState *chr);
-    void (*chr_disconnect)(struct CharDriverState *chr);
-    void (*chr_accept_input)(struct CharDriverState *chr);
-    void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
-    void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
+    int (*chr_ioctl)(struct Chardev *s, int cmd, void *arg);
+    int (*get_msgfds)(struct Chardev *s, int* fds, int num);
+    int (*set_msgfds)(struct Chardev *s, int *fds, int num);
+    int (*chr_add_client)(struct Chardev *chr, int fd);
+    int (*chr_wait_connected)(struct Chardev *chr, Error **errp);
+    void (*chr_free)(struct Chardev *chr);
+    void (*chr_disconnect)(struct Chardev *chr);
+    void (*chr_accept_input)(struct Chardev *chr);
+    void (*chr_set_echo)(struct Chardev *chr, bool echo);
+    void (*chr_set_fe_open)(struct Chardev *chr, int fe_open);
 };
 
 void register_char_driver(const CharDriver *driver);
@@ -507,7 +507,7 @@ extern int term_escape_char;
 
 
 /* console.c */
-typedef CharDriverState *(VcHandler)(ChardevVC *vc, Error **errp);
+typedef Chardev *(VcHandler)(ChardevVC *vc, Error **errp);
 void register_vc_handler(VcHandler *handler);
 
 #endif
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index f80d6d28e8..b4f8d33e3f 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -123,9 +123,9 @@ uint64_t blkreplay_next_id(void);
 /* Character device */
 
 /*! Registers char driver to save it's events */
-void replay_register_char_driver(struct CharDriverState *chr);
+void replay_register_char_driver(struct Chardev *chr);
 /*! Saves write to char device event to the log */
-void replay_chr_be_write(struct CharDriverState *s, uint8_t *buf, int len);
+void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len);
 /*! Writes char write return value to the replay log. */
 void replay_char_write_event_save(int res, int offset);
 /*! Reads char write return value from the replay log. */
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 66c6f1577e..3d46e329ec 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -197,13 +197,13 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict);
 
 #define MAX_SERIAL_PORTS 4
 
-extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+extern Chardev *serial_hds[MAX_SERIAL_PORTS];
 
 /* parallel ports */
 
 #define MAX_PARALLEL_PORTS 3
 
-extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+extern Chardev *parallel_hds[MAX_PARALLEL_PORTS];
 
 void hmp_usb_add(Monitor *mon, const QDict *qdict);
 void hmp_usb_del(Monitor *mon, const QDict *qdict);
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 42ca0fea8b..6bbb672615 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -60,7 +60,7 @@ typedef struct VirtualVteConsole {
     GtkWidget *box;
     GtkWidget *scrollbar;
     GtkWidget *terminal;
-    CharDriverState *chr;
+    Chardev *chr;
     bool echo;
 } VirtualVteConsole;
 #endif
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index 75e12396bb..52a9f8808b 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -51,7 +51,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
 #if SPICE_SERVER_VERSION >= 0x000c02
 void qemu_spice_register_ports(void);
 #else
-static inline CharDriverState *qemu_chr_open_spice_port(const char *name)
+static inline Chardev *qemu_chr_open_spice_port(const char *name)
 { return NULL; }
 #endif
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (9 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 21:55   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting Marc-André Lureau
                   ` (44 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Rename the types to follow the name of the chardev kind.
- socket: TCPChardev -> SocketChardev
- udp: NetChardev -> UdpChardev

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 74 ++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 24169a95b5..9220001906 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2683,12 +2683,12 @@ typedef struct {
     int bufcnt;
     int bufptr;
     int max_size;
-} NetChardev;
+} UdpChardev;
 
 /* Called with chr_write_lock held.  */
 static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    NetChardev *s = (NetChardev *)chr;
+    UdpChardev *s = (UdpChardev *)chr;
 
     return qio_channel_write(
         s->ioc, (const char *)buf, len, NULL);
@@ -2697,7 +2697,7 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 static int udp_chr_read_poll(void *opaque)
 {
     Chardev *chr = opaque;
-    NetChardev *s = opaque;
+    UdpChardev *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
 
@@ -2715,7 +2715,7 @@ static int udp_chr_read_poll(void *opaque)
 static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     Chardev *chr = opaque;
-    NetChardev *s = opaque;
+    UdpChardev *s = opaque;
     ssize_t ret;
 
     if (s->max_size == 0) {
@@ -2742,7 +2742,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static void udp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    NetChardev *s = (NetChardev *)chr;
+    UdpChardev *s = (UdpChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2755,7 +2755,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
 
 static void udp_chr_free(Chardev *chr)
 {
-    NetChardev *s = (NetChardev *)chr;
+    UdpChardev *s = (UdpChardev *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2791,13 +2791,13 @@ typedef struct {
     guint reconnect_timer;
     int64_t reconnect_time;
     bool connect_err_reported;
-} TCPChardev;
+} SocketChardev;
 
 static gboolean socket_reconnect_timeout(gpointer opaque);
 
 static void qemu_chr_socket_restart_timer(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     char *name;
 
     assert(s->connected == 0);
@@ -2811,7 +2811,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
 static void check_report_connect_error(Chardev *chr,
                                        Error *err)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (!s->connect_err_reported) {
         error_report("Unable to connect character device %s: %s",
@@ -2828,7 +2828,7 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
 /* Called with chr_write_lock held.  */
 static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (s->connected) {
         int ret =  io_channel_send_full(s->ioc, buf, len,
@@ -2852,7 +2852,7 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 static int tcp_chr_read_poll(void *opaque)
 {
     Chardev *chr = opaque;
-    TCPChardev *s = opaque;
+    SocketChardev *s = opaque;
     if (!s->connected)
         return 0;
     s->max_size = qemu_chr_be_can_write(chr);
@@ -2862,7 +2862,7 @@ static int tcp_chr_read_poll(void *opaque)
 #define IAC 255
 #define IAC_BREAK 243
 static void tcp_chr_process_IAC_bytes(Chardev *chr,
-                                      TCPChardev *s,
+                                      SocketChardev *s,
                                       uint8_t *buf, int *size)
 {
     /* Handle any telnet client's basic IAC options to satisfy char by
@@ -2911,7 +2911,7 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
 
 static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
 
@@ -2937,7 +2937,7 @@ static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
 
 static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     /* clear old pending fd array */
     g_free(s->write_msgfds);
@@ -2962,7 +2962,7 @@ static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
 
 static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     struct iovec iov = { .iov_base = buf, .iov_len = len };
     int ret;
     size_t i;
@@ -3019,13 +3019,13 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
 
 static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     return qio_channel_create_watch(s->ioc, cond);
 }
 
 static void tcp_chr_free_connection(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     int i;
 
     if (!s->connected) {
@@ -3054,7 +3054,7 @@ static void tcp_chr_free_connection(Chardev *chr)
 
 static void tcp_chr_disconnect(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (!s->connected) {
         return;
@@ -3077,7 +3077,7 @@ static void tcp_chr_disconnect(Chardev *chr)
 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     Chardev *chr = opaque;
-    TCPChardev *s = opaque;
+    SocketChardev *s = opaque;
     uint8_t buf[READ_BUF_LEN];
     int len, size;
 
@@ -3103,7 +3103,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     int size;
 
     if (!s->connected) {
@@ -3122,7 +3122,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
 static void tcp_chr_connect(void *opaque)
 {
     Chardev *chr = opaque;
-    TCPChardev *s = opaque;
+    SocketChardev *s = opaque;
 
     g_free(chr->filename);
     chr->filename = sockaddr_to_str(
@@ -3143,7 +3143,7 @@ static void tcp_chr_connect(void *opaque)
 static void tcp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (!s->connected) {
         return;
@@ -3194,7 +3194,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 
 static void tcp_chr_telnet_init(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     TCPCharDriverTelnetInit *init =
         g_new0(TCPCharDriverTelnetInit, 1);
     size_t n = 0;
@@ -3230,7 +3230,7 @@ static void tcp_chr_tls_handshake(Object *source,
                                   gpointer user_data)
 {
     Chardev *chr = user_data;
-    TCPChardev *s = user_data;
+    SocketChardev *s = user_data;
 
     if (err) {
         tcp_chr_disconnect(chr);
@@ -3246,7 +3246,7 @@ static void tcp_chr_tls_handshake(Object *source,
 
 static void tcp_chr_tls_init(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     QIOChannelTLS *tioc;
     Error *err = NULL;
     gchar *name;
@@ -3285,7 +3285,7 @@ static void tcp_chr_tls_init(Chardev *chr)
 static void tcp_chr_set_client_ioc_name(Chardev *chr,
                                         QIOChannelSocket *sioc)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     char *name;
     name = g_strdup_printf("chardev-tcp-%s-%s",
                            s->is_listen ? "server" : "client",
@@ -3297,7 +3297,7 @@ static void tcp_chr_set_client_ioc_name(Chardev *chr,
 
 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (s->ioc != NULL) {
 	return -1;
@@ -3369,7 +3369,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
 
 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
     QIOChannelSocket *sioc;
 
     /* It can't wait on s->connected, since it is set asynchronously
@@ -3417,7 +3417,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 
 static void tcp_chr_free(Chardev *chr)
 {
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     tcp_chr_free_connection(chr);
 
@@ -3445,7 +3445,7 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 {
     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
     Chardev *chr = opaque;
-    TCPChardev *s = (TCPChardev *)chr;
+    SocketChardev *s = (SocketChardev *)chr;
 
     if (err) {
         check_report_connect_error(chr, err);
@@ -4718,7 +4718,7 @@ static const CharDriver serial_driver = {
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
     Chardev *chr = opaque;
-    TCPChardev *s = opaque;
+    SocketChardev *s = opaque;
     QIOChannelSocket *sioc;
 
     s->reconnect_timer = 0;
@@ -4744,7 +4744,7 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
                                         Error **errp)
 {
     Chardev *chr;
-    TCPChardev *s;
+    SocketChardev *s;
     ChardevSocket *sock = backend->u.socket.data;
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
@@ -4759,7 +4759,7 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = (TCPChardev *)chr;
+    s = (SocketChardev *)chr;
 
     s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
@@ -4866,7 +4866,7 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
 }
 
 static const CharDriver socket_driver = {
-    .instance_size = sizeof(TCPChardev),
+    .instance_size = sizeof(SocketChardev),
     .kind = CHARDEV_BACKEND_KIND_SOCKET,
     .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket,
     .chr_wait_connected = tcp_chr_wait_connected,
@@ -4893,7 +4893,7 @@ static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
     QIOChannelSocket *sioc = qio_channel_socket_new();
     char *name;
     Chardev *chr;
-    NetChardev *s;
+    UdpChardev *s;
 
     if (qio_channel_socket_dgram_sync(sioc,
                                       udp->local, udp->remote,
@@ -4911,7 +4911,7 @@ static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
-    s = (NetChardev *)chr;
+    s = (UdpChardev *)chr;
     s->ioc = QIO_CHANNEL(sioc);
     s->bufcnt = 0;
     s->bufptr = 0;
@@ -4922,7 +4922,7 @@ static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
 }
 
 static const CharDriver udp_driver = {
-    .instance_size = sizeof(NetChardev),
+    .instance_size = sizeof(UdpChardev),
     .kind = CHARDEV_BACKEND_KIND_UDP,
     .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
     .chr_write = udp_chr_write,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (10 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 22:00   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 13/54] char: use error_report() Marc-André Lureau
                   ` (43 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Set errp to report errors up.

Use error_report() to give hints about parameters on the right monitor,
instead of a direct fprintf() call.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 spice-qemu-char.c | 29 +++++++++--------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 5feb88c1ec..4e934cf224 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -2,6 +2,7 @@
 #include "trace.h"
 #include "ui/qemu-spice.h"
 #include "sysemu/char.h"
+#include "qemu/error-report.h"
 #include <spice.h>
 #include <spice/protocol.h>
 
@@ -239,23 +240,6 @@ static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
 #endif
 }
 
-static void print_allowed_subtypes(void)
-{
-    const char** psubtype;
-    int i;
-
-    fprintf(stderr, "allowed names: ");
-    for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
-        *psubtype != NULL; ++psubtype, ++i) {
-        if (i == 0) {
-            fprintf(stderr, "%s", *psubtype);
-        } else {
-            fprintf(stderr, ", %s", *psubtype);
-        }
-    }
-    fprintf(stderr, "\n");
-}
-
 static void spice_chr_accept_input(struct Chardev *chr)
 {
     SpiceChardev *s = (SpiceChardev *)chr;
@@ -302,8 +286,13 @@ static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
         }
     }
     if (*psubtype == NULL) {
-        fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
-        print_allowed_subtypes();
+        char *subtypes = g_strjoinv(", ",
+            (gchar **)spice_server_char_device_recognized_subtypes());
+
+        error_setg(errp, "unsupported type name: %s", type);
+        error_report("allowed spice char type names: %s", subtypes);
+
+        g_free(subtypes);
         return NULL;
     }
 
@@ -326,7 +315,7 @@ static Chardev *qemu_chr_open_spice_port(const CharDriver *driver,
     SpiceChardev *s;
 
     if (name == NULL) {
-        fprintf(stderr, "spice-qemu-char: missing name parameter\n");
+        error_setg(errp, "missing name parameter");
         return NULL;
     }
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 13/54] char: use error_report()
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (11 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 22:04   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver Marc-André Lureau
                   ` (42 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Prefer error_report() over fprintf(stderr..)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 9220001906..315037049b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -451,8 +451,8 @@ int qemu_chr_fe_get_msgfd(CharBackend *be)
     int fd;
     int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
     if (s && qemu_chr_replay(s)) {
-        fprintf(stderr,
-                "Replay: get msgfd is not supported for serial devices yet\n");
+        error_report("Replay: get msgfd is not supported "
+                     "for serial devices yet");
         exit(1);
     }
     return res;
@@ -1674,8 +1674,8 @@ static Chardev *qemu_chr_open_pty(const CharDriver *driver,
     ret->pty = g_strdup(pty_name);
     ret->has_pty = true;
 
-    fprintf(stderr, "char device redirected to %s (label %s)\n",
-            pty_name, id);
+    error_report("char device redirected to %s (label %s)",
+                 pty_name, id);
 
     s = (PtyChardev *)chr;
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
@@ -3376,8 +3376,8 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
      * in TLS and telnet cases, only wait for an accepted socket */
     while (!s->ioc) {
         if (s->is_listen) {
-            fprintf(stderr, "QEMU waiting for connection on: %s\n",
-                    chr->filename);
+            error_report("QEMU waiting for connection on: %s",
+                         chr->filename);
             qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
             tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
             qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
@@ -4130,17 +4130,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
     }
 
     if (is_help_option(qemu_opt_get(opts, "backend"))) {
-        fprintf(stderr, "Available chardev backend types:\n");
+        GString *str = g_string_new("");
         for (i = 0; i < ARRAY_SIZE(backends); i++) {
             cd = backends[i];
             if (cd) {
-                fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
+                g_string_append_printf(str, "\n%s", ChardevBackendKind_lookup[cd->kind]);
                 if (cd->alias) {
-                    fprintf(stderr, "%s\n", cd->alias);
+                    g_string_append_printf(str, "\n%s", cd->alias);
                 }
             }
         }
-        exit(!is_help_option(qemu_opt_get(opts, "backend")));
+
+        error_report("Available chardev backend types: %s", str->str);
+        g_string_free(str, true);
+        exit(0);
     }
 
     if (id == NULL) {
@@ -4255,8 +4258,8 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
             qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
         }
         if (qemu_chr_replay(chr) && chr->driver->chr_ioctl) {
-            fprintf(stderr,
-                    "Replay: ioctl is not supported for serial devices yet\n");
+            error_report("Replay: ioctl is not supported "
+                         "for serial devices yet");
         }
         replay_register_char_driver(chr);
     }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (12 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 13/54] char: use error_report() Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-04 22:26   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 15/54] chardev: qom-ify Marc-André Lureau
                   ` (41 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Instead of registering a vc handler to allocate the Gtk VC Chardev,
overwrite the console.c char driver.

A later patch, when switching to QOM, will register a default console vc
QOM class if none has been registered before.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 ui/console.c          | 24 +++++++-----------------
 ui/gtk.c              | 30 +++++++++++++++++++++---------
 include/sysemu/char.h |  4 +---
 3 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index 80d10c7a4c..9a16e1b743 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2047,8 +2047,12 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
 
 static const CharDriver vc_driver;
 
-static Chardev *text_console_init(ChardevVC *vc, Error **errp)
+static Chardev *vc_init(const CharDriver *driver,
+                        const char *id, ChardevBackend *backend,
+                        ChardevReturn *ret, bool *be_opened,
+                        Error **errp)
 {
+    ChardevVC *vc = backend->u.vc.data;
     ChardevCommon *common = qapi_ChardevVC_base(vc);
     Chardev *chr;
     VCChardev *drv;
@@ -2094,26 +2098,13 @@ static Chardev *text_console_init(ChardevVC *vc, Error **errp)
     if (display_state) {
         text_console_do_init(chr, display_state);
     }
-    return chr;
-}
 
-static VcHandler *vc_handler = text_console_init;
-
-static Chardev *vc_init(const CharDriver *driver,
-                        const char *id, ChardevBackend *backend,
-                        ChardevReturn *ret, bool *be_opened,
-                        Error **errp)
-{
     /* console/chardev init sometimes completes elsewhere in a 2nd
      * stage, so defer OPENED events until they are fully initialized
      */
     *be_opened = false;
-    return vc_handler(backend->u.vc.data, errp);
-}
 
-void register_vc_handler(VcHandler *handler)
-{
-    vc_handler = handler;
+    return chr;
 }
 
 void qemu_console_resize(QemuConsole *s, int width, int height)
@@ -2151,8 +2142,7 @@ PixelFormat qemu_default_pixelformat(int bpp)
     return pf;
 }
 
-static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
-                              Error **errp)
+void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
 {
     int val;
     ChardevVC *vc;
diff --git a/ui/gtk.c b/ui/gtk.c
index 32df26e5d7..efa50524bf 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1702,16 +1702,14 @@ static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
 
 static int nb_vcs;
 static Chardev *vcs[MAX_VCS];
+static const CharDriver gd_vc_driver;
 
-static Chardev *gd_vc_handler(ChardevVC *vc, Error **errp)
+static Chardev *vc_init(const CharDriver *driver,
+                        const char *id, ChardevBackend *backend,
+                        ChardevReturn *ret, bool *be_opened,
+                        Error **errp)
 {
-    static const CharDriver gd_vc_driver = {
-        .instance_size = sizeof(VCChardev),
-        .kind = CHARDEV_BACKEND_KIND_VC,
-        .chr_write = gd_vc_chr_write,
-        .chr_set_echo = gd_vc_chr_set_echo,
-    };
-
+    ChardevVC *vc = backend->u.vc.data;
     ChardevCommon *common = qapi_ChardevVC_base(vc);
     Chardev *chr;
 
@@ -1727,9 +1725,22 @@ static Chardev *gd_vc_handler(ChardevVC *vc, Error **errp)
 
     vcs[nb_vcs++] = chr;
 
+    /* console/chardev init sometimes completes elsewhere in a 2nd
+     * stage, so defer OPENED events until they are fully initialized
+     */
+    *be_opened = false;
+
     return chr;
 }
 
+static const CharDriver gd_vc_driver = {
+    .instance_size = sizeof(VCChardev),
+    .kind = CHARDEV_BACKEND_KIND_VC,
+    .parse = qemu_chr_parse_vc, .create = vc_init,
+    .chr_write = gd_vc_chr_write,
+    .chr_set_echo = gd_vc_chr_set_echo,
+};
+
 static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
                          gpointer user_data)
 {
@@ -2317,6 +2328,7 @@ void early_gtk_display_init(int opengl)
     }
 
 #if defined(CONFIG_VTE)
-    register_vc_handler(gd_vc_handler);
+    /* overwrite the console.c vc driver */
+    register_char_driver(&gd_vc_driver);
 #endif
 }
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 029b14c8b6..384f3ce9b7 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -505,9 +505,7 @@ void register_char_driver(const CharDriver *driver);
 
 extern int term_escape_char;
 
-
 /* console.c */
-typedef Chardev *(VcHandler)(ChardevVC *vc, Error **errp);
-void register_vc_handler(VcHandler *handler);
+void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp);
 
 #endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 15/54] chardev: qom-ify
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (13 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2017-01-05  2:30   ` Eric Blake
  2017-01-05 15:54   ` Eric Blake
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 16/54] spice-qemu-char: convert to finalize Marc-André Lureau
                   ` (40 subsequent siblings)
  55 siblings, 2 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Turn Chardev into Object.

qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It
will call qemu_char_open() to open/intialize the chardev with the
ChardevCommon *backend settings.

The CharDriver::create() callback is turned into a ChardevClass::open()
which is called from the newly introduced qemu_chardev_open().

"chardev-gdb" and "chardev-hci" are internal chardev and aren't
creatable directly with -chardev. Use a new internal flag to disable
them. We may want to use TYPE_USER_CREATABLE interface instead, or
perhaps allow -chardev usage.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |   70 +--
 backends/msmouse.c    |   57 ++-
 backends/testdev.c    |   34 +-
 gdbstub.c             |   33 +-
 hw/bt/hci-csr.c       |   54 +-
 monitor.c             |    2 +-
 qemu-char.c           | 1334 ++++++++++++++++++++++++++-----------------------
 spice-qemu-char.c     |  144 +++---
 ui/console.c          |   73 +--
 ui/gtk.c              |   51 +-
 vl.c                  |    2 +
 include/sysemu/char.h |  107 ++--
 include/ui/console.h  |    2 +
 13 files changed, 1084 insertions(+), 879 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index 7fd1ebc557..80103b6098 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -102,6 +102,9 @@ typedef struct {
     QEMUTimer *cellCount_timer;
 } BaumChardev;
 
+#define TYPE_CHARDEV_BRAILLE "chardev-braille"
+#define BAUM_CHARDEV(obj) OBJECT_CHECK(BaumChardev, (obj), TYPE_CHARDEV_BRAILLE)
+
 /* Let's assume NABCC by default */
 enum way {
     DOTS2ASCII,
@@ -268,9 +271,9 @@ static int baum_deferred_init(BaumChardev *baum)
 }
 
 /* The serial port can receive more of our data */
-static void baum_accept_input(struct Chardev *chr)
+static void baum_chr_accept_input(struct Chardev *chr)
 {
-    BaumChardev *baum = (BaumChardev *)chr;
+    BaumChardev *baum = BAUM_CHARDEV(chr);
     int room, first;
 
     if (!baum->out_buf_used)
@@ -296,7 +299,7 @@ static void baum_accept_input(struct Chardev *chr)
 /* We want to send a packet */
 static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
 {
-    Chardev *chr = (Chardev *)baum;
+    Chardev *chr = CHARDEV(baum);
     uint8_t io_buf[1 + 2 * len], *cur = io_buf;
     int room;
     *cur++ = ESC;
@@ -337,7 +340,7 @@ static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
 /* Called when the other end seems to have a wrong idea of our display size */
 static void baum_cellCount_timer_cb(void *opaque)
 {
-    BaumChardev *baum = opaque;
+    BaumChardev *baum = BAUM_CHARDEV(opaque);
     uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
     DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
     baum_write_packet(baum, cell_count, sizeof(cell_count));
@@ -485,9 +488,9 @@ static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
 }
 
 /* The other end is writing some data.  Store it and try to interpret */
-static int baum_write(Chardev *chr, const uint8_t *buf, int len)
+static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    BaumChardev *baum = (BaumChardev *)chr;
+    BaumChardev *baum = BAUM_CHARDEV(chr);
     int tocopy, cur, eaten, orig_len = len;
 
     if (!len)
@@ -544,7 +547,7 @@ static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
 /* We got some data on the BrlAPI socket */
 static void baum_chr_read(void *opaque)
 {
-    BaumChardev *baum = opaque;
+    BaumChardev *baum = BAUM_CHARDEV(opaque);
     brlapi_keyCode_t code;
     int ret;
     if (!baum->brlapi)
@@ -628,9 +631,9 @@ static void baum_chr_read(void *opaque)
     }
 }
 
-static void baum_free(struct Chardev *chr)
+static void baum_chr_free(Chardev *chr)
 {
-    BaumChardev *baum = (BaumChardev *)chr;
+    BaumChardev *baum = BAUM_CHARDEV(chr);
 
     timer_free(baum->cellCount_timer);
     if (baum->brlapi) {
@@ -639,24 +642,14 @@ static void baum_free(struct Chardev *chr)
     }
 }
 
-static Chardev *chr_baum_init(const CharDriver *driver,
-                              const char *id,
-                              ChardevBackend *backend,
-                              ChardevReturn *ret,
-                              bool *be_opened,
-                              Error **errp)
+static void baum_chr_open(Chardev *chr,
+                          ChardevBackend *backend,
+                          bool *be_opened,
+                          Error **errp)
 {
-    ChardevCommon *common = backend->u.braille.data;
-    BaumChardev *baum;
-    Chardev *chr;
+    BaumChardev *baum = BAUM_CHARDEV(chr);
     brlapi_handle_t *handle;
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-    baum = (BaumChardev *)chr;
-
     handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
 
@@ -664,34 +657,41 @@ static Chardev *chr_baum_init(const CharDriver *driver,
     if (baum->brlapi_fd == -1) {
         error_setg(errp, "brlapi__openConnection: %s",
                    brlapi_strerror(brlapi_error_location()));
-        goto fail_handle;
+        g_free(handle);
+        return;
     }
     baum->deferred_init = 0;
 
     baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
 
     qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
+}
 
-    return chr;
+static void char_braille_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
 
-fail_handle:
-    g_free(handle);
-    g_free(chr);
-    return NULL;
+    cc->open = baum_chr_open;
+    cc->chr_write = baum_chr_write;
+    cc->chr_accept_input = baum_chr_accept_input;
+    cc->chr_free = baum_chr_free;
 }
 
+static const TypeInfo char_braille_type_info = {
+    .name = TYPE_CHARDEV_BRAILLE,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(BaumChardev),
+    .class_init = char_braille_class_init,
+};
+
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(BaumChardev),
         .kind = CHARDEV_BACKEND_KIND_BRAILLE,
-        .parse = NULL, .create = chr_baum_init,
-        .chr_write = baum_write,
-        .chr_accept_input = baum_accept_input,
-        .chr_free = baum_free,
     };
 
     register_char_driver(&driver);
+    type_register_static(&char_braille_type_info);
 }
 
 type_init(register_types);
diff --git a/backends/msmouse.c b/backends/msmouse.c
index fabc2926d6..936a5476d5 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -41,9 +41,13 @@ typedef struct {
     int outlen;
 } MouseChardev;
 
+#define TYPE_CHARDEV_MSMOUSE "chardev-msmouse"
+#define MOUSE_CHARDEV(obj)                                      \
+    OBJECT_CHECK(MouseChardev, (obj), TYPE_CHARDEV_MSMOUSE)
+
 static void msmouse_chr_accept_input(Chardev *chr)
 {
-    MouseChardev *mouse = (MouseChardev *)chr;
+    MouseChardev *mouse = MOUSE_CHARDEV(chr);
     int len;
 
     len = qemu_chr_be_can_write(chr);
@@ -98,7 +102,7 @@ static void msmouse_queue_event(MouseChardev *mouse)
 static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
                                 InputEvent *evt)
 {
-    MouseChardev *mouse = (MouseChardev *)dev;
+    MouseChardev *mouse = MOUSE_CHARDEV(dev);
     InputMoveEvent *move;
     InputBtnEvent *btn;
 
@@ -122,8 +126,8 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
 
 static void msmouse_input_sync(DeviceState *dev)
 {
-    MouseChardev *mouse = (MouseChardev *)dev;
-    Chardev *chr = (Chardev *)dev;
+    MouseChardev *mouse = MOUSE_CHARDEV(dev);
+    Chardev *chr = CHARDEV(dev);
 
     msmouse_queue_event(mouse);
     msmouse_chr_accept_input(chr);
@@ -137,7 +141,7 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
 
 static void msmouse_chr_free(struct Chardev *chr)
 {
-    MouseChardev *mouse = (MouseChardev *)chr;
+    MouseChardev *mouse = MOUSE_CHARDEV(chr);
 
     qemu_input_handler_unregister(mouse->hs);
 }
@@ -149,42 +153,43 @@ static QemuInputHandler msmouse_handler = {
     .sync  = msmouse_input_sync,
 };
 
-static Chardev *qemu_chr_open_msmouse(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static void msmouse_chr_open(Chardev *chr,
+                             ChardevBackend *backend,
+                             bool *be_opened,
+                             Error **errp)
 {
-    ChardevCommon *common = backend->u.msmouse.data;
-    MouseChardev *mouse;
-    Chardev *chr;
+    MouseChardev *mouse = MOUSE_CHARDEV(chr);
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
     *be_opened = false;
-
-    mouse = (MouseChardev *)chr;
     mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
                                             &msmouse_handler);
+}
 
+static void char_msmouse_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    return chr;
+    cc->open = msmouse_chr_open;
+    cc->chr_write = msmouse_chr_write;
+    cc->chr_accept_input = msmouse_chr_accept_input;
+    cc->chr_free = msmouse_chr_free;
 }
 
+static const TypeInfo char_msmouse_type_info = {
+    .name = TYPE_CHARDEV_MSMOUSE,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(MouseChardev),
+    .class_init = char_msmouse_class_init,
+};
+
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(MouseChardev),
         .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
-        .parse = NULL, .create = qemu_chr_open_msmouse,
-        .chr_write = msmouse_chr_write,
-        .chr_accept_input = msmouse_chr_accept_input,
-        .chr_free = msmouse_chr_free,
     };
+
     register_char_driver(&driver);
+    type_register_static(&char_msmouse_type_info);
 }
 
 type_init(register_types);
diff --git a/backends/testdev.c b/backends/testdev.c
index 1d06c8633e..ea15143713 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -36,6 +36,10 @@ typedef struct {
     int in_buf_used;
 } TestdevChardev;
 
+#define TYPE_CHARDEV_TESTDEV "chardev-testdev"
+#define TESTDEV_CHARDEV(obj)                                    \
+    OBJECT_CHECK(TestdevChardev, (obj), TYPE_CHARDEV_TESTDEV)
+
 /* Try to interpret a whole incoming packet */
 static int testdev_eat_packet(TestdevChardev *testdev)
 {
@@ -78,9 +82,9 @@ static int testdev_eat_packet(TestdevChardev *testdev)
 }
 
 /* The other end is writing some data.  Store it and try to interpret */
-static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
+static int testdev_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    TestdevChardev *testdev = (TestdevChardev *)chr;
+    TestdevChardev *testdev = TESTDEV_CHARDEV(chr);
     int tocopy, eaten, orig_len = len;
 
     while (len) {
@@ -103,30 +107,28 @@ static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
     return orig_len;
 }
 
-static Chardev *chr_testdev_init(const CharDriver *driver,
-                                 const char *id,
-                                 ChardevBackend *backend,
-                                 ChardevReturn *ret,
-                                 bool *be_opened,
-                                 Error **errp)
+static void char_testdev_class_init(ObjectClass *oc, void *data)
 {
-    TestdevChardev *testdev = g_new0(TestdevChardev, 1);;
-    Chardev *chr = (Chardev *)testdev;
-
-    chr->driver = driver;
+    ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    return chr;
+    cc->chr_write = testdev_chr_write;
 }
 
+static const TypeInfo char_testdev_type_info = {
+    .name = TYPE_CHARDEV_TESTDEV,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(TestdevChardev),
+    .class_init = char_testdev_class_init,
+};
+
 static void register_types(void)
 {
     static const CharDriver driver = {
-        .instance_size = sizeof(TestdevChardev),
         .kind = CHARDEV_BACKEND_KIND_TESTDEV,
-        .parse = NULL, .create = chr_testdev_init,
-        .chr_write = testdev_write,
     };
+
     register_char_driver(&driver);
+    type_register_static(&char_testdev_type_info);
 }
 
 type_init(register_types);
diff --git a/gdbstub.c b/gdbstub.c
index 22fa291bc9..ee9286a01b 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1723,18 +1723,29 @@ static void gdb_sigterm_handler(int signal)
 }
 #endif
 
+
+static void char_gdb_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->internal = true;
+    cc->chr_write = gdb_monitor_write;
+}
+
+#define TYPE_CHARDEV_GDB "chardev-gdb"
+
+static const TypeInfo char_gdb_type_info = {
+    .name = TYPE_CHARDEV_GDB,
+    .parent = TYPE_CHARDEV,
+    .class_init = char_gdb_class_init,
+};
+
 int gdbserver_start(const char *device)
 {
     GDBState *s;
     char gdbstub_device_name[128];
     Chardev *chr = NULL;
     Chardev *mon_chr;
-    ChardevCommon common = { 0 };
-    static const CharDriver driver = {
-        .instance_size = sizeof(Chardev),
-        .kind = -1,
-        .chr_write = gdb_monitor_write
-    };
 
     if (!device)
         return -1;
@@ -1767,7 +1778,8 @@ int gdbserver_start(const char *device)
         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
 
         /* Initialize a monitor terminal for gdb */
-        mon_chr = qemu_chr_alloc(&driver, &common, &error_abort);
+        mon_chr = qemu_chardev_new("gdb", TYPE_CHARDEV_GDB,
+                                   NULL, &error_abort);
         monitor_init(mon_chr, 0);
     } else {
         if (qemu_chr_fe_get_driver(&s->chr)) {
@@ -1790,4 +1802,11 @@ int gdbserver_start(const char *device)
 
     return 0;
 }
+
+static void register_types(void)
+{
+    type_register_static(&char_gdb_type_info);
+}
+
+type_init(register_types);
 #endif
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index 153ed2f1ba..c9dbbcf3a5 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -55,6 +55,9 @@ struct csrhci_s {
     struct HCIInfo *hci;
 };
 
+#define TYPE_CHARDEV_HCI "chardev-hci"
+#define HCI_CHARDEV(obj) OBJECT_CHECK(struct csrhci_s, (obj), TYPE_CHARDEV_HCI)
+
 /* H4+ packet types */
 enum {
     H4_CMD_PKT   = 1,
@@ -462,23 +465,12 @@ qemu_irq *csrhci_pins_get(Chardev *chr)
     return s->pins;
 }
 
-Chardev *uart_hci_init(void)
+static void csrhci_open(Chardev *chr,
+                        ChardevBackend *backend,
+                        bool *be_opened,
+                        Error **errp)
 {
-    static const CharDriver hci_driver = {
-        .instance_size = sizeof(struct csrhci_s),
-        .kind = -1,
-        .chr_write = csrhci_write,
-        .chr_ioctl = csrhci_ioctl,
-    };
-    Error *err = NULL;
-    ChardevCommon common = { 0, };
-    Chardev *chr = qemu_chr_alloc(&hci_driver, &common, &err);
-    struct csrhci_s *s = (struct csrhci_s *)chr;
-
-    if (err) {
-        error_report_err(err);
-        return NULL;
-    }
+    struct csrhci_s *s = HCI_CHARDEV(chr);
 
     s->hci = qemu_next_hci();
     s->hci->opaque = s;
@@ -488,6 +480,34 @@ Chardev *uart_hci_init(void)
     s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s);
     s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
     csrhci_reset(s);
+}
+
+static void char_hci_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->internal = true;
+    cc->open = csrhci_open;
+    cc->chr_write = csrhci_write;
+    cc->chr_ioctl = csrhci_ioctl;
+}
+
+static const TypeInfo char_hci_type_info = {
+    .name = TYPE_CHARDEV_HCI,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(struct csrhci_s),
+    .class_init = char_hci_class_init,
+};
 
-    return chr;
+Chardev *uart_hci_init(void)
+{
+    return qemu_chardev_new("hci-csr", TYPE_CHARDEV_HCI,
+                            NULL, &error_abort);
 }
+
+static void register_types(void)
+{
+    type_register_static(&char_hci_type_info);
+}
+
+type_init(register_types);
diff --git a/monitor.c b/monitor.c
index a82f547488..90ca4d737a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3194,7 +3194,7 @@ static void ringbuf_completion(ReadLineState *rs, const char *str)
 
         if (!strncmp(chr_info->label, str, len)) {
             Chardev *chr = qemu_chr_find(chr_info->label);
-            if (chr && qemu_chr_is_ringbuf(chr)) {
+            if (chr && CHARDEV_IS_RINGBUF(chr)) {
                 readline_add_completion(rs, chr_info->label);
             }
         }
diff --git a/qemu-char.c b/qemu-char.c
index 315037049b..d5656007da 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -160,43 +160,6 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
 static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
     QTAILQ_HEAD_INITIALIZER(chardevs);
 
-static void qemu_chr_free_common(Chardev *chr);
-
-Chardev *qemu_chr_alloc(const CharDriver *driver,
-                                ChardevCommon *backend, Error **errp)
-{
-    Chardev *chr;
-
-    assert(driver);
-    assert(driver->chr_write);
-    assert(driver->instance_size >= sizeof(Chardev));
-
-    chr = g_malloc0(driver->instance_size);
-    qemu_mutex_init(&chr->chr_write_lock);
-    if (backend->has_logfile) {
-        int flags = O_WRONLY | O_CREAT;
-        if (backend->has_logappend &&
-            backend->logappend) {
-            flags |= O_APPEND;
-        } else {
-            flags |= O_TRUNC;
-        }
-        chr->logfd = qemu_open(backend->logfile, flags, 0666);
-        if (chr->logfd < 0) {
-            error_setg_errno(errp, errno,
-                             "Unable to open logfile %s",
-                             backend->logfile);
-            g_free(chr);
-            return NULL;
-        }
-    } else {
-        chr->logfd = -1;
-    }
-    chr->driver = driver;
-
-    return chr;
-}
-
 void qemu_chr_be_event(Chardev *s, int event)
 {
     CharBackend *be = s->be;
@@ -254,13 +217,14 @@ static void qemu_chr_fe_write_log(Chardev *s,
 static int qemu_chr_fe_write_buffer(Chardev *s,
                                     const uint8_t *buf, int len, int *offset)
 {
+    ChardevClass *cc = CHARDEV_GET_CLASS(s);
     int res = 0;
     *offset = 0;
 
     qemu_mutex_lock(&s->chr_write_lock);
     while (*offset < len) {
     retry:
-        res = s->driver->chr_write(s, buf + *offset, len - *offset);
+        res = cc->chr_write(s, buf + *offset, len - *offset);
         if (res < 0 && errno == EAGAIN) {
             g_usleep(100);
             goto retry;
@@ -288,6 +252,7 @@ static bool qemu_chr_replay(Chardev *chr)
 int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
 {
     Chardev *s = be->chr;
+    ChardevClass *cc;
     int ret;
 
     if (!s) {
@@ -302,8 +267,9 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
         return ret;
     }
 
+    cc = CHARDEV_GET_CLASS(s);
     qemu_mutex_lock(&s->chr_write_lock);
-    ret = s->driver->chr_write(s, buf, len);
+    ret = cc->chr_write(s, buf, len);
 
     if (ret > 0) {
         qemu_chr_fe_write_log(s, buf, ret);
@@ -359,7 +325,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
     int offset = 0, counter = 10;
     int res;
 
-    if (!s || !s->driver->chr_sync_read) {
+    if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
         return 0;
     }
 
@@ -369,7 +335,8 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
 
     while (offset < len) {
     retry:
-        res = s->driver->chr_sync_read(s, buf + offset, len - offset);
+        res = CHARDEV_GET_CLASS(s)->chr_sync_read(s, buf + offset,
+                                                  len - offset);
         if (res == -1 && errno == EAGAIN) {
             g_usleep(100);
             goto retry;
@@ -404,10 +371,10 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
     Chardev *s = be->chr;
     int res;
 
-    if (!s || !s->driver->chr_ioctl || qemu_chr_replay(s)) {
+    if (!s || !CHARDEV_GET_CLASS(s)->chr_ioctl || qemu_chr_replay(s)) {
         res = -ENOTSUP;
     } else {
-        res = s->driver->chr_ioctl(s, cmd, arg);
+        res = CHARDEV_GET_CLASS(s)->chr_ioctl(s, cmd, arg);
     }
 
     return res;
@@ -466,7 +433,8 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
         return -1;
     }
 
-    return s->driver->get_msgfds ? s->driver->get_msgfds(s, fds, len) : -1;
+    return CHARDEV_GET_CLASS(s)->get_msgfds ?
+        CHARDEV_GET_CLASS(s)->get_msgfds(s, fds, len) : -1;
 }
 
 int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
@@ -477,12 +445,14 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
         return -1;
     }
 
-    return s->driver->set_msgfds ? s->driver->set_msgfds(s, fds, num) : -1;
+    return CHARDEV_GET_CLASS(s)->set_msgfds ?
+        CHARDEV_GET_CLASS(s)->set_msgfds(s, fds, num) : -1;
 }
 
 int qemu_chr_add_client(Chardev *s, int fd)
 {
-    return s->driver->chr_add_client ? s->driver->chr_add_client(s, fd) : -1;
+    return CHARDEV_GET_CLASS(s)->chr_add_client ?
+        CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
 }
 
 void qemu_chr_fe_accept_input(CharBackend *be)
@@ -493,8 +463,8 @@ void qemu_chr_fe_accept_input(CharBackend *be)
         return;
     }
 
-    if (s->driver->chr_accept_input) {
-        s->driver->chr_accept_input(s);
+    if (CHARDEV_GET_CLASS(s)->chr_accept_input) {
+        CHARDEV_GET_CLASS(s)->chr_accept_input(s);
     }
     qemu_notify_event();
 }
@@ -515,33 +485,98 @@ static void remove_fd_in_watch(Chardev *chr);
 static void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
 static void mux_set_focus(MuxChardev *d, int focus);
 
-static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
+static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
+                           bool *be_opened, Error **errp)
 {
-    return len;
+    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
+    /* Any ChardevCommon member would work */
+    ChardevCommon *common = backend ? backend->u.null.data : NULL;
+
+    if (common && common->has_logfile) {
+        int flags = O_WRONLY | O_CREAT;
+        if (common->has_logappend &&
+            common->logappend) {
+            flags |= O_APPEND;
+        } else {
+            flags |= O_TRUNC;
+        }
+        chr->logfd = qemu_open(common->logfile, flags, 0666);
+        if (chr->logfd < 0) {
+            error_setg_errno(errp, errno,
+                             "Unable to open logfile %s",
+                             common->logfile);
+            return;
+        }
+    }
+
+    if (cc->open) {
+        cc->open(chr, backend, be_opened, errp);
+    }
 }
 
-static Chardev *qemu_chr_open_null(const CharDriver *driver,
-                                   const char *id,
-                                   ChardevBackend *backend,
-                                   ChardevReturn *ret,
-                                   bool *be_opened,
-                                   Error **errp)
+static void char_init(Object *obj)
 {
-    Chardev *chr;
-    ChardevCommon *common = backend->u.null.data;
+    Chardev *chr = CHARDEV(obj);
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
+    chr->logfd = -1;
+    qemu_mutex_init(&chr->chr_write_lock);
+}
+
+static void char_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+
+    if (chr->be) {
+        chr->be->chr = NULL;
+    }
+    g_free(chr->filename);
+    g_free(chr->label);
+    if (chr->logfd != -1) {
+        close(chr->logfd);
     }
+    qemu_mutex_destroy(&chr->chr_write_lock);
+}
+
+static const TypeInfo char_type_info = {
+    .name = TYPE_CHARDEV,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(Chardev),
+    .instance_init = char_init,
+    .instance_finalize = char_finalize,
+    .abstract = true,
+    .class_size = sizeof(ChardevClass),
+};
+
+static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    return len;
+}
+
+static void null_chr_open(Chardev *chr,
+                          ChardevBackend *backend,
+                          bool *be_opened,
+                          Error **errp)
+{
     *be_opened = false;
-    return chr;
 }
 
 static const CharDriver null_driver = {
+    .kind = CHARDEV_BACKEND_KIND_NULL,
+};
+
+static void char_null_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = null_chr_open;
+    cc->chr_write = null_chr_write;
+}
+
+static const TypeInfo char_null_type_info = {
+    .name = TYPE_CHARDEV_NULL,
+    .parent = TYPE_CHARDEV,
     .instance_size = sizeof(Chardev),
-    .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,
-    .chr_write = null_chr_write
+    .class_init = char_null_class_init,
 };
 
 /* MUX driver for serial I/O splitting */
@@ -569,10 +604,12 @@ struct MuxChardev {
     int64_t timestamps_start;
 };
 
+#define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX)
+
 /* Called with chr_write_lock held.  */
 static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    MuxChardev *d = (MuxChardev *)chr;
+    MuxChardev *d = MUX_CHARDEV(chr);
     int ret;
     if (!d->timestamps) {
         ret = qemu_chr_fe_write(&d->chr, buf, len);
@@ -706,7 +743,7 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
 
 static void mux_chr_accept_input(Chardev *chr)
 {
-    MuxChardev *d = (MuxChardev *)chr;
+    MuxChardev *d = MUX_CHARDEV(chr);
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -719,7 +756,7 @@ static void mux_chr_accept_input(Chardev *chr)
 
 static int mux_chr_can_read(void *opaque)
 {
-    MuxChardev *d = opaque;
+    MuxChardev *d = MUX_CHARDEV(opaque);
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -736,8 +773,8 @@ static int mux_chr_can_read(void *opaque)
 
 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 {
-    Chardev *chr = opaque;
-    MuxChardev *d = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    MuxChardev *d = MUX_CHARDEV(opaque);
     int m = d->focus;
     CharBackend *be = d->backends[m];
     int i;
@@ -759,7 +796,7 @@ static bool muxes_realized;
 
 static void mux_chr_event(void *opaque, int event)
 {
-    MuxChardev *d = opaque;
+    MuxChardev *d = MUX_CHARDEV(opaque);
     int i;
 
     if (!muxes_realized) {
@@ -788,8 +825,8 @@ static void muxes_realize_done(Notifier *notifier, void *unused)
     Chardev *chr;
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
-        if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxChardev *d = (MuxChardev *)chr;
+        if (CHARDEV_IS_MUX(chr)) {
+            MuxChardev *d = MUX_CHARDEV(chr);
             int i;
 
             /* send OPENED to all already-attached FEs */
@@ -811,19 +848,20 @@ static Notifier muxes_realize_notify = {
 
 static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
 {
-    MuxChardev *d = (MuxChardev *)s;
+    MuxChardev *d = MUX_CHARDEV(s);
     Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
+    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
 
-    if (!chr->driver->chr_add_watch) {
+    if (!cc->chr_add_watch) {
         return NULL;
     }
 
-    return chr->driver->chr_add_watch(chr, cond);
+    return cc->chr_add_watch(chr, cond);
 }
 
 static void mux_chr_free(struct Chardev *chr)
 {
-    MuxChardev *d = (MuxChardev *)chr;
+    MuxChardev *d = MUX_CHARDEV(chr);
     int i;
 
     for (i = 0; i < d->mux_cnt; i++) {
@@ -837,7 +875,7 @@ static void mux_chr_free(struct Chardev *chr)
 
 static void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
 {
-    MuxChardev *d = (MuxChardev *)chr;
+    MuxChardev *d = MUX_CHARDEV(chr);
 
     /* Fix up the real driver with mux routines */
     qemu_chr_fe_set_handlers(&d->chr,
@@ -861,40 +899,27 @@ static void mux_set_focus(MuxChardev *d, int focus)
     mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
 }
 
-static Chardev *qemu_chr_open_mux(const CharDriver *driver,
-                                  const char *id,
-                                  ChardevBackend *backend,
-                                  ChardevReturn *ret,
-                                  bool *be_opened,
-                                  Error **errp)
+static void qemu_chr_open_mux(Chardev *chr,
+                              ChardevBackend *backend,
+                              bool *be_opened,
+                              Error **errp)
 {
     ChardevMux *mux = backend->u.mux.data;
-    Chardev *chr, *drv;
-    MuxChardev *d;
-    ChardevCommon *common = qapi_ChardevMux_base(mux);
+    Chardev *drv;
+    MuxChardev *d = MUX_CHARDEV(chr);
 
     drv = qemu_chr_find(mux->chardev);
     if (drv == NULL) {
         error_setg(errp, "mux: base chardev %s not found", mux->chardev);
-        return NULL;
+        return;
     }
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-    d = (MuxChardev *)chr;
     d->focus = -1;
     /* only default to opened state if we've realized the initial
      * set of muxes
      */
     *be_opened = muxes_realized;
-    if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
-        qemu_chr_free(chr);
-        return NULL;
-    }
-
-    return chr;
+    qemu_chr_fe_init(&d->chr, drv, errp);
 }
 
 Chardev *qemu_chr_fe_get_driver(CharBackend *be)
@@ -906,8 +931,8 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
 {
     int tag = 0;
 
-    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxChardev *d = (MuxChardev *)s;
+    if (CHARDEV_IS_MUX(s)) {
+        MuxChardev *d = MUX_CHARDEV(s);
 
         if (d->mux_cnt >= MAX_MUX) {
             goto unavailable;
@@ -933,8 +958,8 @@ unavailable:
 
 static bool qemu_chr_is_busy(Chardev *s)
 {
-    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxChardev *d = (MuxChardev *)s;
+    if (CHARDEV_IS_MUX(s)) {
+        MuxChardev *d = MUX_CHARDEV(s);
         return d->mux_cnt >= 0;
     } else {
         return s->be != NULL;
@@ -948,8 +973,8 @@ void qemu_chr_fe_deinit(CharBackend *b)
     if (b->chr) {
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
         b->chr->be = NULL;
-        if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxChardev *d = (MuxChardev *)b->chr;
+        if (CHARDEV_IS_MUX(b->chr)) {
+            MuxChardev *d = MUX_CHARDEV(b->chr);
             d->backends[b->tag] = NULL;
         }
         b->chr = NULL;
@@ -965,6 +990,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
                               bool set_open)
 {
     Chardev *s;
+    ChardevClass *cc;
     int fe_open;
 
     s = b->chr;
@@ -972,6 +998,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         return;
     }
 
+    cc = CHARDEV_GET_CLASS(s);
     if (!opaque && !fd_can_read && !fd_read && !fd_event) {
         fe_open = 0;
         remove_fd_in_watch(s);
@@ -982,8 +1009,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
     b->chr_read = fd_read;
     b->chr_event = fd_event;
     b->opaque = opaque;
-    if (s->driver->chr_update_read_handler) {
-        s->driver->chr_update_read_handler(s, context);
+    if (cc->chr_update_read_handler) {
+        cc->chr_update_read_handler(s, context);
     }
 
     if (set_open) {
@@ -999,7 +1026,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         }
     }
 
-    if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
+    if (CHARDEV_IS_MUX(s)) {
         mux_chr_set_handlers(s, context);
     }
 }
@@ -1010,8 +1037,8 @@ void qemu_chr_fe_take_focus(CharBackend *b)
         return;
     }
 
-    if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-        mux_set_focus((MuxChardev *)b->chr, b->tag);
+    if (CHARDEV_IS_MUX(b->chr)) {
+        mux_set_focus(MUX_CHARDEV(b->chr), b->tag);
     }
 }
 
@@ -1187,7 +1214,6 @@ static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
     return io_channel_send_full(ioc, buf, len, NULL, 0);
 }
 
-
 typedef struct FDChardev {
     Chardev parent;
     Chardev *chr;
@@ -1195,18 +1221,21 @@ typedef struct FDChardev {
     int max_size;
 } FDChardev;
 
+#define TYPE_CHARDEV_FD "chardev-fd"
+#define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD)
+
 /* Called with chr_write_lock held.  */
 static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    FDChardev *s = (FDChardev *)chr;
+    FDChardev *s = FD_CHARDEV(chr);
 
     return io_channel_send(s->ioc_out, buf, len);
 }
 
 static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    Chardev *chr = opaque;
-    FDChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    FDChardev *s = FD_CHARDEV(opaque);
     int len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1235,8 +1264,8 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int fd_chr_read_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    FDChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    FDChardev *s = FD_CHARDEV(opaque);
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -1244,14 +1273,14 @@ static int fd_chr_read_poll(void *opaque)
 
 static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    FDChardev *s = (FDChardev *)chr;
+    FDChardev *s = FD_CHARDEV(chr);
     return qio_channel_create_watch(s->ioc_out, cond);
 }
 
 static void fd_chr_update_read_handler(Chardev *chr,
                                        GMainContext *context)
 {
-    FDChardev *s = (FDChardev *)chr;
+    FDChardev *s = FD_CHARDEV(chr);
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1264,7 +1293,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
 
 static void fd_chr_free(struct Chardev *chr)
 {
-    FDChardev *s = (FDChardev *)chr;
+    FDChardev *s = FD_CHARDEV(chr);
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1278,19 +1307,12 @@ static void fd_chr_free(struct Chardev *chr)
 }
 
 /* open a character device to a unix fd */
-static Chardev *qemu_chr_open_fd(const CharDriver *driver,
-                                 int fd_in, int fd_out,
-                                 ChardevCommon *backend, Error **errp)
+static void qemu_chr_open_fd(Chardev *chr,
+                             int fd_in, int fd_out)
 {
-    Chardev *chr;
-    FDChardev *s;
+    FDChardev *s = FD_CHARDEV(chr);
     char *name;
 
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = (FDChardev *)chr;
     s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
     name = g_strdup_printf("chardev-file-in-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
@@ -1301,24 +1323,36 @@ static Chardev *qemu_chr_open_fd(const CharDriver *driver,
     g_free(name);
     qemu_set_nonblock(fd_out);
     s->chr = chr;
+}
 
-    return chr;
+static void char_fd_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_add_watch = fd_chr_add_watch;
+    cc->chr_write = fd_chr_write;
+    cc->chr_update_read_handler = fd_chr_update_read_handler;
+    cc->chr_free = fd_chr_free;
 }
 
-static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
-                                   const char *id,
-                                   ChardevBackend *backend,
-                                   ChardevReturn *ret,
-                                   bool *be_opened,
-                                   Error **errp)
+static const TypeInfo char_fd_type_info = {
+    .name = TYPE_CHARDEV_FD,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(FDChardev),
+    .class_init = char_fd_class_init,
+    .abstract = true,
+};
+
+static void qemu_chr_open_pipe(Chardev *chr,
+                               ChardevBackend *backend,
+                               bool *be_opened,
+                               Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
     int fd_in, fd_out;
     char *filename_in;
     char *filename_out;
     const char *filename = opts->device;
-    ChardevCommon *common = qapi_ChardevHostdev_base(opts);
-
 
     filename_in = g_strdup_printf("%s.in", filename);
     filename_out = g_strdup_printf("%s.out", filename);
@@ -1334,10 +1368,10 @@ static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
         TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
         if (fd_in < 0) {
             error_setg_file_open(errp, errno, filename);
-            return NULL;
+            return;
         }
     }
-    return qemu_chr_open_fd(driver, fd_in, fd_out, common, errp);
+    qemu_chr_open_fd(chr, fd_in, fd_out);
 }
 
 /* init terminal so that we can grab keys */
@@ -1389,26 +1423,22 @@ static void qemu_chr_free_stdio(struct Chardev *chr)
     fd_chr_free(chr);
 }
 
-static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
-                                    const char *id,
-                                    ChardevBackend *backend,
-                                    ChardevReturn *ret,
-                                    bool *be_opened,
-                                    Error **errp)
+static void qemu_chr_open_stdio(Chardev *chr,
+                                ChardevBackend *backend,
+                                bool *be_opened,
+                                Error **errp)
 {
     ChardevStdio *opts = backend->u.stdio.data;
-    Chardev *chr;
     struct sigaction act;
-    ChardevCommon *common = qapi_ChardevStdio_base(opts);
 
     if (is_daemonized()) {
         error_setg(errp, "cannot use stdio with -daemonize");
-        return NULL;
+        return;
     }
 
     if (stdio_in_use) {
         error_setg(errp, "cannot use stdio by multiple character devices");
-        return NULL;
+        return;
     }
 
     stdio_in_use = true;
@@ -1421,19 +1451,15 @@ static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
     act.sa_handler = term_stdio_handler;
     sigaction(SIGCONT, &act, NULL);
 
-    chr = qemu_chr_open_fd(driver, 0, 1, common, errp);
-    if (!chr) {
-        return NULL;
-    }
+    qemu_chr_open_fd(chr, 0, 1);
+
     if (opts->has_signal) {
         stdio_allow_signal = opts->signal;
     }
     qemu_chr_set_echo_stdio(chr, false);
-
-    return chr;
 }
 
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)     \
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
     || defined(__GLIBC__)
 
@@ -1451,13 +1477,15 @@ typedef struct {
     guint open_tag;
 } PtyChardev;
 
+#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
+
 static void pty_chr_update_read_handler_locked(Chardev *chr);
 static void pty_chr_state(Chardev *chr, int connected);
 
 static gboolean pty_chr_timer(gpointer opaque)
 {
-    struct Chardev *chr = opaque;
-    PtyChardev *s = opaque;
+    struct Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
 
     qemu_mutex_lock(&chr->chr_write_lock);
     s->timer_tag = 0;
@@ -1473,7 +1501,7 @@ static gboolean pty_chr_timer(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_rearm_timer(Chardev *chr, int ms)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
     char *name;
 
     if (s->timer_tag) {
@@ -1495,7 +1523,7 @@ static void pty_chr_rearm_timer(Chardev *chr, int ms)
 /* Called with chr_write_lock held.  */
 static void pty_chr_update_read_handler_locked(Chardev *chr)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
     GPollFD pfd;
     int rc;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
@@ -1524,9 +1552,9 @@ static void pty_chr_update_read_handler(Chardev *chr,
 }
 
 /* Called with chr_write_lock held.  */
-static int pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
+static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
 
     if (!s->connected) {
         /* guest sends data, check for (re-)connect */
@@ -1540,7 +1568,7 @@ static int pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
     if (!s->connected) {
         return NULL;
     }
@@ -1549,8 +1577,8 @@ static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
 
 static int pty_chr_read_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    PtyChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
 
     s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
@@ -1558,8 +1586,8 @@ static int pty_chr_read_poll(void *opaque)
 
 static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    Chardev *chr = opaque;
-    PtyChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
     gsize len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1583,8 +1611,8 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 {
-    Chardev *chr = opaque;
-    PtyChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
 
     s->open_tag = 0;
     qemu_chr_be_generic_open(chr);
@@ -1594,7 +1622,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_state(Chardev *chr, int connected)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
 
     if (!connected) {
         if (s->open_tag) {
@@ -1628,7 +1656,7 @@ static void pty_chr_state(Chardev *chr, int connected)
 
 static void pty_chr_free(struct Chardev *chr)
 {
-    PtyChardev *s = (PtyChardev *)chr;
+    PtyChardev *s = PTY_CHARDEV(chr);
 
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_state(chr, 0);
@@ -1641,60 +1669,58 @@ static void pty_chr_free(struct Chardev *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static Chardev *qemu_chr_open_pty(const CharDriver *driver,
-                                  const char *id,
-                                  ChardevBackend *backend,
-                                  ChardevReturn *ret,
-                                  bool *be_opened,
-                                  Error **errp)
+static void char_pty_open(Chardev *chr,
+                          ChardevBackend *backend,
+                          bool *be_opened,
+                          Error **errp)
 {
-    Chardev *chr;
     PtyChardev *s;
     int master_fd, slave_fd;
     char pty_name[PATH_MAX];
-    ChardevCommon *common = backend->u.pty.data;
     char *name;
 
     master_fd = qemu_openpty_raw(&slave_fd, pty_name);
     if (master_fd < 0) {
         error_setg_errno(errp, errno, "Failed to create PTY");
-        return NULL;
+        return;
     }
 
     close(slave_fd);
     qemu_set_nonblock(master_fd);
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        close(master_fd);
-        return NULL;
-    }
-
     chr->filename = g_strdup_printf("pty:%s", pty_name);
-    ret->pty = g_strdup(pty_name);
-    ret->has_pty = true;
-
     error_report("char device redirected to %s (label %s)",
-                 pty_name, id);
+                 pty_name, chr->label);
 
-    s = (PtyChardev *)chr;
+    s = PTY_CHARDEV(chr);
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
     name = g_strdup_printf("chardev-pty-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
     g_free(name);
     s->timer_tag = 0;
     *be_opened = false;
-
-    return chr;
 }
 
 static const CharDriver pty_driver = {
+    .kind = CHARDEV_BACKEND_KIND_PTY
+};
+
+static void char_pty_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = char_pty_open;
+    cc->chr_write = char_pty_chr_write;
+    cc->chr_update_read_handler = pty_chr_update_read_handler;
+    cc->chr_add_watch = pty_chr_add_watch;
+    cc->chr_free = pty_chr_free;
+}
+
+static const TypeInfo char_pty_type_info = {
+    .name = TYPE_CHARDEV_PTY,
+    .parent = TYPE_CHARDEV,
     .instance_size = sizeof(PtyChardev),
-    .kind = CHARDEV_BACKEND_KIND_PTY, .create = qemu_chr_open_pty,
-    .chr_write = pty_chr_write,
-    .chr_update_read_handler = pty_chr_update_read_handler,
-    .chr_add_watch = pty_chr_add_watch,
-    .chr_free = pty_chr_free,
+    .class_init = char_pty_class_init,
 };
 
 static void tty_serial_init(int fd, int speed,
@@ -1814,7 +1840,7 @@ static void tty_serial_init(int fd, int speed,
 
 static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    FDChardev *s = (FDChardev *)chr;
+    FDChardev *s = FD_CHARDEV(chr);
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 
     switch(cmd) {
@@ -1898,6 +1924,9 @@ typedef struct {
     int mode;
 } ParallelChardev;
 
+#define PARALLEL_CHARDEV(obj) \
+    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
 static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
 {
     if (s->mode != mode) {
@@ -1911,7 +1940,7 @@ static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
 
 static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    ParallelChardev *drv = (ParallelChardev *)chr;
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
     int fd = drv->fd;
     uint8_t b;
 
@@ -1992,7 +2021,7 @@ static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 
 static void pp_free(Chardev *chr)
 {
-    ParallelChardev *drv = (ParallelChardev *)chr;
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
     int fd = drv->fd;
 
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
@@ -2001,31 +2030,21 @@ static void pp_free(Chardev *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
-                                    int fd,
-                                    ChardevCommon *backend,
-                                    bool *be_opened,
-                                    Error **errp)
+static void qemu_chr_open_pp_fd(Chardev *chr,
+                                int fd,
+                                bool *be_opened,
+                                Error **errp)
 {
-    Chardev *chr;
-    ParallelChardev *drv;
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
 
     if (ioctl(fd, PPCLAIM) < 0) {
         error_setg_errno(errp, errno, "not a parallel port");
         close(fd);
-        return NULL;
-    }
-
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
+        return;
     }
 
-    drv = (ParallelChardev *)chr;
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
-
-    return chr;
 }
 #endif /* __linux__ */
 
@@ -2038,9 +2057,12 @@ typedef struct {
     int fd;
 } ParallelChardev;
 
+#define PARALLEL_CHARDEV(obj)                                   \
+    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
 static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 {
-    ParallelChardev *drv = (ParallelChardev *)chr;
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
     uint8_t b;
 
     switch (cmd) {
@@ -2080,23 +2102,14 @@ static int pp_ioctl(Chardev *chr, int cmd, void *arg)
     return 0;
 }
 
-static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
-                                    int fd,
-                                    ChardevCommon *backend,
-                                    bool *be_opened,
-                                    Error **errp)
+static void qemu_chr_open_pp_fd(Chardev *chr,
+                                int fd,
+                                bool *be_opened,
+                                Error **errp)
 {
-    Chardev *chr;
-    ParallelChardev *drv;
-
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    drv = (ParallelChardev *)chr;
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
     drv->fd = fd;
     *be_opened = false;
-    return chr;
 }
 #endif
 
@@ -2116,6 +2129,9 @@ typedef struct {
     OVERLAPPED osend;
 } WinChardev;
 
+#define TYPE_CHARDEV_WIN "chardev-win"
+#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN)
+
 typedef struct {
     Chardev parent;
     HANDLE  hStdIn;
@@ -2125,6 +2141,10 @@ typedef struct {
     uint8_t win_stdio_buf;
 } WinStdioChardev;
 
+#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
+#define WIN_STDIO_CHARDEV(obj)                                  \
+    OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
+
 #define NSENDBUF 2048
 #define NRECVBUF 2048
 #define MAXCONNECT 1
@@ -2135,7 +2155,7 @@ static int win_chr_pipe_poll(void *opaque);
 
 static void win_chr_free(Chardev *chr)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
 
     if (s->hsend) {
         CloseHandle(s->hsend);
@@ -2159,7 +2179,7 @@ static void win_chr_free(Chardev *chr)
 
 static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
     COMMCONFIG comcfg;
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
     COMSTAT comstat;
@@ -2227,7 +2247,7 @@ static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
 /* Called with chr_write_lock held.  */
 static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
     DWORD len, ret, size, err;
 
     len = len1;
@@ -2261,7 +2281,7 @@ static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
 
 static int win_chr_read_poll(Chardev *chr)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -2269,7 +2289,8 @@ static int win_chr_read_poll(Chardev *chr)
 
 static void win_chr_readfile(Chardev *chr)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
+
     int ret, err;
     uint8_t buf[READ_BUF_LEN];
     DWORD size;
@@ -2291,7 +2312,7 @@ static void win_chr_readfile(Chardev *chr)
 
 static void win_chr_read(Chardev *chr)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
 
     if (s->len > s->max_size)
         s->len = s->max_size;
@@ -2303,8 +2324,8 @@ static void win_chr_read(Chardev *chr)
 
 static int win_chr_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    WinChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    WinChardev *s = WIN_CHARDEV(opaque);
     COMSTAT status;
     DWORD comerr;
 
@@ -2320,8 +2341,8 @@ static int win_chr_poll(void *opaque)
 
 static int win_chr_pipe_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    WinChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    WinChardev *s = WIN_CHARDEV(opaque);
     DWORD size;
 
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
@@ -2337,7 +2358,7 @@ static int win_chr_pipe_poll(void *opaque)
 static int win_chr_pipe_init(Chardev *chr, const char *filename,
                              Error **errp)
 {
-    WinChardev *s = (WinChardev *)chr;
+    WinChardev *s = WIN_CHARDEV(chr);
     OVERLAPPED ov;
     int ret;
     DWORD size;
@@ -2399,64 +2420,66 @@ static int win_chr_pipe_init(Chardev *chr, const char *filename,
 }
 
 
-static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
-                                   const char *id,
-                                   ChardevBackend *backend,
-                                   ChardevReturn *ret,
-                                   bool *be_opened,
-                                   Error **errp)
+static void qemu_chr_open_pipe(Chardev *chr,
+                               ChardevBackend *backend,
+                               bool *be_opened,
+                               Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
     const char *filename = opts->device;
-    Chardev *chr;
-    ChardevCommon *common = qapi_ChardevHostdev_base(opts);
-
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
 
     if (win_chr_pipe_init(chr, filename, errp) < 0) {
-        qemu_chr_free_common(chr);
-        return NULL;
+        return;
     }
-    return chr;
 }
 
-static Chardev *qemu_chr_open_win_file(const CharDriver *driver,
-                                       HANDLE fd_out,
-                                       ChardevCommon *backend,
-                                       Error **errp)
+static void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
 {
-    Chardev *chr;
-    WinChardev *s;
+    WinChardev *s = WIN_CHARDEV(chr);
 
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = (WinChardev *)chr;
     s->hcom = fd_out;
-    return chr;
 }
 
-static Chardev *qemu_chr_open_win_con(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static void char_win_class_init(ObjectClass *oc, void *data)
 {
-    ChardevCommon *common = backend->u.console.data;
-    return qemu_chr_open_win_file(driver,
-                                  GetStdHandle(STD_OUTPUT_HANDLE),
-                                  common, errp);
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_write = win_chr_write;
+    cc->chr_free = win_chr_free;
 }
 
-static const CharDriver console_driver = {
+static const TypeInfo char_win_type_info = {
+    .name = TYPE_CHARDEV_WIN,
+    .parent = TYPE_CHARDEV,
     .instance_size = sizeof(WinChardev),
-    .kind = CHARDEV_BACKEND_KIND_CONSOLE, .create = qemu_chr_open_win_con,
-    .chr_write = win_chr_write,
+    .class_init = char_win_class_init,
+    .abstract = true,
+};
+
+static void qemu_chr_open_win_con(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
+{
+    qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
+static const CharDriver console_driver = {
+    .kind = CHARDEV_BACKEND_KIND_CONSOLE
+};
+
+static void char_console_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_win_con;
+    cc->chr_free = NULL;
+}
+
+static const TypeInfo char_console_type_info = {
+    .name = TYPE_CHARDEV_CONSOLE,
+    .parent = TYPE_CHARDEV_WIN,
+    .class_init = char_console_class_init,
 };
 
 static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
@@ -2480,8 +2503,8 @@ static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
 
 static void win_stdio_wait_func(void *opaque)
 {
-    Chardev   *chr   = opaque;
-    WinStdioChardev *stdio = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
     INPUT_RECORD       buf[4];
     int                ret;
     DWORD              dwSize;
@@ -2514,7 +2537,7 @@ static void win_stdio_wait_func(void *opaque)
 
 static DWORD WINAPI win_stdio_thread(LPVOID param)
 {
-    WinStdioChardev *stdio = param;
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
     int                ret;
     DWORD              dwSize;
 
@@ -2552,8 +2575,8 @@ static DWORD WINAPI win_stdio_thread(LPVOID param)
 
 static void win_stdio_thread_wait_func(void *opaque)
 {
-    Chardev   *chr   = opaque;
-    WinStdioChardev *stdio = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
 
     if (qemu_chr_be_can_write(chr)) {
         qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
@@ -2564,7 +2587,7 @@ static void win_stdio_thread_wait_func(void *opaque)
 
 static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
 {
-    WinStdioChardev *stdio  = (WinStdioChardev *)chr;
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
     DWORD              dwMode = 0;
 
     GetConsoleMode(stdio->hStdIn, &dwMode);
@@ -2578,7 +2601,7 @@ static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
 
 static void win_stdio_free(Chardev *chr)
 {
-    WinStdioChardev *stdio = (WinStdioChardev *)chr;
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
 
     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
         CloseHandle(stdio->hInputReadyEvent);
@@ -2591,29 +2614,26 @@ static void win_stdio_free(Chardev *chr)
     }
 }
 
-static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
-                                    const char *id,
-                                    ChardevBackend *backend,
-                                    ChardevReturn *ret,
-                                    bool *be_opened,
-                                    Error **errp)
+static const TypeInfo char_win_stdio_type_info = {
+    .name = TYPE_CHARDEV_WIN_STDIO,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(WinStdioChardev),
+    .abstract = true,
+};
+
+static void qemu_chr_open_stdio(Chardev *chr,
+                                ChardevBackend *backend,
+                                bool *be_opened,
+                                Error **errp)
 {
-    Chardev   *chr;
-    WinStdioChardev *stdio;
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
     DWORD              dwMode;
     int                is_console = 0;
-    ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data);
-
-    chr   = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-    stdio = (WinStdioChardev *)chr;
 
     stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
     if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
         error_setg(errp, "cannot open stdio: invalid handle");
-        return NULL;
+        return;
     }
 
     is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
@@ -2660,7 +2680,7 @@ static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
 
     qemu_chr_set_echo_win_stdio(chr, false);
 
-    return chr;
+    return;
 
 err3:
     qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
@@ -2669,7 +2689,6 @@ err2:
     CloseHandle(stdio->hInputDoneEvent);
 err1:
     qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
-    return NULL;
 }
 #endif /* !_WIN32 */
 
@@ -2685,10 +2704,12 @@ typedef struct {
     int max_size;
 } UdpChardev;
 
+#define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP)
+
 /* Called with chr_write_lock held.  */
 static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    UdpChardev *s = (UdpChardev *)chr;
+    UdpChardev *s = UDP_CHARDEV(chr);
 
     return qio_channel_write(
         s->ioc, (const char *)buf, len, NULL);
@@ -2696,8 +2717,8 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static int udp_chr_read_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    UdpChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    UdpChardev *s = UDP_CHARDEV(opaque);
 
     s->max_size = qemu_chr_be_can_write(chr);
 
@@ -2714,8 +2735,8 @@ static int udp_chr_read_poll(void *opaque)
 
 static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    Chardev *chr = opaque;
-    UdpChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    UdpChardev *s = UDP_CHARDEV(opaque);
     ssize_t ret;
 
     if (s->max_size == 0) {
@@ -2742,7 +2763,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static void udp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    UdpChardev *s = (UdpChardev *)chr;
+    UdpChardev *s = UDP_CHARDEV(chr);
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2755,7 +2776,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
 
 static void udp_chr_free(Chardev *chr)
 {
-    UdpChardev *s = (UdpChardev *)chr;
+    UdpChardev *s = UDP_CHARDEV(chr);
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2793,11 +2814,14 @@ typedef struct {
     bool connect_err_reported;
 } SocketChardev;
 
+#define SOCKET_CHARDEV(obj)                                     \
+    OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
+
 static gboolean socket_reconnect_timeout(gpointer opaque);
 
 static void qemu_chr_socket_restart_timer(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     char *name;
 
     assert(s->connected == 0);
@@ -2811,7 +2835,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
 static void check_report_connect_error(Chardev *chr,
                                        Error *err)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (!s->connect_err_reported) {
         error_report("Unable to connect character device %s: %s",
@@ -2828,7 +2852,7 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
 /* Called with chr_write_lock held.  */
 static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (s->connected) {
         int ret =  io_channel_send_full(s->ioc, buf, len,
@@ -2851,8 +2875,8 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static int tcp_chr_read_poll(void *opaque)
 {
-    Chardev *chr = opaque;
-    SocketChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
     if (!s->connected)
         return 0;
     s->max_size = qemu_chr_be_can_write(chr);
@@ -2911,7 +2935,7 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
 
 static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
 
@@ -2937,7 +2961,7 @@ static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
 
 static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     /* clear old pending fd array */
     g_free(s->write_msgfds);
@@ -2962,7 +2986,7 @@ static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
 
 static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     struct iovec iov = { .iov_base = buf, .iov_len = len };
     int ret;
     size_t i;
@@ -3019,13 +3043,13 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
 
 static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     return qio_channel_create_watch(s->ioc, cond);
 }
 
 static void tcp_chr_free_connection(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     int i;
 
     if (!s->connected) {
@@ -3054,7 +3078,7 @@ static void tcp_chr_free_connection(Chardev *chr)
 
 static void tcp_chr_disconnect(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (!s->connected) {
         return;
@@ -3076,8 +3100,8 @@ static void tcp_chr_disconnect(Chardev *chr)
 
 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
-    Chardev *chr = opaque;
-    SocketChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
     uint8_t buf[READ_BUF_LEN];
     int len, size;
 
@@ -3103,7 +3127,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     int size;
 
     if (!s->connected) {
@@ -3121,8 +3145,8 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
 
 static void tcp_chr_connect(void *opaque)
 {
-    Chardev *chr = opaque;
-    SocketChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
 
     g_free(chr->filename);
     chr->filename = sockaddr_to_str(
@@ -3143,7 +3167,7 @@ static void tcp_chr_connect(void *opaque)
 static void tcp_chr_update_read_handler(Chardev *chr,
                                         GMainContext *context)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (!s->connected) {
         return;
@@ -3194,7 +3218,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 
 static void tcp_chr_telnet_init(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     TCPCharDriverTelnetInit *init =
         g_new0(TCPCharDriverTelnetInit, 1);
     size_t n = 0;
@@ -3246,7 +3270,7 @@ static void tcp_chr_tls_handshake(Object *source,
 
 static void tcp_chr_tls_init(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     QIOChannelTLS *tioc;
     Error *err = NULL;
     gchar *name;
@@ -3285,7 +3309,7 @@ static void tcp_chr_tls_init(Chardev *chr)
 static void tcp_chr_set_client_ioc_name(Chardev *chr,
                                         QIOChannelSocket *sioc)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     char *name;
     name = g_strdup_printf("chardev-tcp-%s-%s",
                            s->is_listen ? "server" : "client",
@@ -3297,7 +3321,7 @@ static void tcp_chr_set_client_ioc_name(Chardev *chr,
 
 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (s->ioc != NULL) {
 	return -1;
@@ -3351,7 +3375,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
                                GIOCondition cond,
                                void *opaque)
 {
-    Chardev *chr = opaque;
+    Chardev *chr = CHARDEV(opaque);
     QIOChannelSocket *sioc;
 
     sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
@@ -3369,7 +3393,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
 
 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     QIOChannelSocket *sioc;
 
     /* It can't wait on s->connected, since it is set asynchronously
@@ -3398,8 +3422,10 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
 
 static int qemu_chr_wait_connected(Chardev *chr, Error **errp)
 {
-    if (chr->driver->chr_wait_connected) {
-        return chr->driver->chr_wait_connected(chr, errp);
+    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
+
+    if (cc->chr_wait_connected) {
+        return cc->chr_wait_connected(chr, errp);
     }
 
     return 0;
@@ -3417,7 +3443,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 
 static void tcp_chr_free(Chardev *chr)
 {
-    SocketChardev *s = (SocketChardev *)chr;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     tcp_chr_free_connection(chr);
 
@@ -3444,8 +3470,8 @@ static void tcp_chr_free(Chardev *chr)
 static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 {
     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
-    Chardev *chr = opaque;
-    SocketChardev *s = (SocketChardev *)chr;
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(chr);
 
     if (err) {
         check_report_connect_error(chr, err);
@@ -3470,9 +3496,12 @@ typedef struct {
     uint8_t *cbuf;
 } RingBufChardev;
 
+#define RINGBUF_CHARDEV(obj)                                    \
+    OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF)
+
 static size_t ringbuf_count(const Chardev *chr)
 {
-    const RingBufChardev *d = (RingBufChardev *)chr;
+    const RingBufChardev *d = RINGBUF_CHARDEV(chr);
 
     return d->prod - d->cons;
 }
@@ -3480,7 +3509,7 @@ static size_t ringbuf_count(const Chardev *chr)
 /* Called with chr_write_lock held.  */
 static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    RingBufChardev *d = (RingBufChardev *)chr;
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
     int i;
 
     if (!buf || (len < 0)) {
@@ -3499,7 +3528,7 @@ static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
 {
-    RingBufChardev *d = (RingBufChardev *)chr;
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
     int i;
 
     qemu_mutex_lock(&chr->chr_write_lock);
@@ -3513,51 +3542,30 @@ static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
 
 static void ringbuf_chr_free(struct Chardev *chr)
 {
-    RingBufChardev *d = (RingBufChardev *)chr;
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
 
     g_free(d->cbuf);
 }
 
-static Chardev *qemu_chr_open_ringbuf(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static void qemu_chr_open_ringbuf(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
 {
     ChardevRingbuf *opts = backend->u.ringbuf.data;
-    ChardevCommon *common = qapi_ChardevRingbuf_base(opts);
-    Chardev *chr;
-    RingBufChardev *d;
-
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-    d = (RingBufChardev *)chr;
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
 
     d->size = opts->has_size ? opts->size : 65536;
 
     /* The size must be power of 2 */
     if (d->size & (d->size - 1)) {
         error_setg(errp, "size of ringbuf chardev must be power of two");
-        goto fail;
+        return;
     }
 
     d->prod = 0;
     d->cons = 0;
     d->cbuf = g_malloc0(d->size);
-
-    return chr;
-
-fail:
-    qemu_chr_free_common(chr);
-    return NULL;
-}
-
-ChardevBackendKind qemu_chr_get_kind(const Chardev *chr)
-{
-    return chr->driver->kind;
 }
 
 void qmp_ringbuf_write(const char *device, const char *data,
@@ -3575,7 +3583,7 @@ void qmp_ringbuf_write(const char *device, const char *data,
         return;
     }
 
-    if (!qemu_chr_is_ringbuf(chr)) {
+    if (!CHARDEV_IS_RINGBUF(chr)) {
         error_setg(errp,"%s is not a ringbuf device", device);
         return;
     }
@@ -3619,7 +3627,7 @@ char *qmp_ringbuf_read(const char *device, int64_t size,
         return NULL;
     }
 
-    if (!qemu_chr_is_ringbuf(chr)) {
+    if (!CHARDEV_IS_RINGBUF(chr)) {
         error_setg(errp,"%s is not a ringbuf device", device);
         return NULL;
     }
@@ -3838,20 +3846,32 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
 
 static const CharDriver stdio_driver = {
     .kind = CHARDEV_BACKEND_KIND_STDIO,
-    .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio,
+    .parse = qemu_chr_parse_stdio
+};
+
+static void char_stdio_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_stdio;
+#ifdef _WIN32
+    cc->chr_write = win_stdio_write;
+    cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
+    cc->chr_free = win_stdio_free;
+#else
+    cc->chr_set_echo = qemu_chr_set_echo_stdio;
+    cc->chr_free = qemu_chr_free_stdio;
+#endif
+}
+
+static const TypeInfo char_stdio_type_info = {
+    .name = TYPE_CHARDEV_STDIO,
 #ifdef _WIN32
-    sizeof(WinStdioChardev),
-    .chr_write = win_stdio_write,
-    .chr_set_echo = qemu_chr_set_echo_win_stdio,
-    .chr_free = win_stdio_free,
+    .parent = TYPE_CHARDEV_WIN_STDIO,
 #else
-    sizeof(FDChardev),
-    .chr_add_watch = fd_chr_add_watch,
-    .chr_write = fd_chr_write,
-    .chr_update_read_handler = fd_chr_update_read_handler,
-    .chr_set_echo = qemu_chr_set_echo_stdio,
-    .chr_free = qemu_chr_free_stdio,
+    .parent = TYPE_CHARDEV_FD,
 #endif
+    .class_init = char_stdio_class_init,
 };
 
 #ifdef HAVE_CHARDEV_SERIAL
@@ -3905,18 +3925,24 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
 
 static const CharDriver pipe_driver = {
     .kind = CHARDEV_BACKEND_KIND_PIPE,
-    .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe,
+    .parse = qemu_chr_parse_pipe
+};
+
+static void char_pipe_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_pipe;
+}
+
+static const TypeInfo char_pipe_type_info = {
+    .name = TYPE_CHARDEV_PIPE,
 #ifdef _WIN32
-    sizeof(WinChardev),
-    .chr_write = win_chr_write,
-    .chr_free = win_chr_free,
+    .parent = TYPE_CHARDEV_WIN,
 #else
-    sizeof(FDChardev),
-    .chr_add_watch = fd_chr_add_watch,
-    .chr_write = fd_chr_write,
-    .chr_update_read_handler = fd_chr_update_read_handler,
-    .chr_free = fd_chr_free,
+    .parent = TYPE_CHARDEV_FD,
 #endif
+    .class_init = char_pipe_class_init,
 };
 
 static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
@@ -3936,20 +3962,35 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver ringbuf_driver = {
-    .instance_size = sizeof(RingBufChardev),
     .kind = CHARDEV_BACKEND_KIND_RINGBUF,
-    .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
-    .chr_write = ringbuf_chr_write,
-    .chr_free = ringbuf_chr_free,
+    .parse = qemu_chr_parse_ringbuf
+};
+
+static void char_ringbuf_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_ringbuf;
+    cc->chr_write = ringbuf_chr_write;
+    cc->chr_free = ringbuf_chr_free;
+}
+
+static const TypeInfo char_ringbuf_type_info = {
+    .name = TYPE_CHARDEV_RINGBUF,
+    .parent = TYPE_CHARDEV,
+    .class_init = char_ringbuf_class_init,
+    .instance_size = sizeof(RingBufChardev),
 };
 
 /* Bug-compatibility: */
 static const CharDriver memory_driver = {
-    .instance_size = sizeof(RingBufChardev),
     .kind = CHARDEV_BACKEND_KIND_MEMORY,
-    .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf,
-    .chr_write = ringbuf_chr_write,
-    .chr_free = ringbuf_chr_free,
+    .parse = qemu_chr_parse_ringbuf
+};
+
+static const TypeInfo char_memory_type_info = {
+    .name = TYPE_CHARDEV_MEMORY,
+    .parent = TYPE_CHARDEV_RINGBUF,
 };
 
 static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
@@ -3968,13 +4009,26 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver mux_driver = {
-    .instance_size = sizeof(MuxChardev),
     .kind = CHARDEV_BACKEND_KIND_MUX,
-    .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
-    .chr_free = mux_chr_free,
-    .chr_write = mux_chr_write,
-    .chr_accept_input = mux_chr_accept_input,
-    .chr_add_watch = mux_chr_add_watch,
+    .parse = qemu_chr_parse_mux
+};
+
+static void char_mux_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_mux;
+    cc->chr_free = mux_chr_free;
+    cc->chr_write = mux_chr_write;
+    cc->chr_accept_input = mux_chr_accept_input;
+    cc->chr_add_watch = mux_chr_add_watch;
+}
+
+static const TypeInfo char_mux_type_info = {
+    .name = TYPE_CHARDEV_MUX,
+    .parent = TYPE_CHARDEV,
+    .class_init = char_mux_class_init,
+    .instance_size = sizeof(MuxChardev),
 };
 
 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
@@ -4257,7 +4311,7 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
         if (replay_mode != REPLAY_MODE_NONE) {
             qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
         }
-        if (qemu_chr_replay(chr) && chr->driver->chr_ioctl) {
+        if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
             error_report("Replay: ioctl is not supported "
                          "for serial devices yet");
         }
@@ -4270,8 +4324,8 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 {
     Chardev *chr = be->chr;
 
-    if (chr && chr->driver->chr_set_echo) {
-        chr->driver->chr_set_echo(chr, echo);
+    if (chr && CHARDEV_GET_CLASS(chr)->chr_set_echo) {
+        CHARDEV_GET_CLASS(chr)->chr_set_echo(chr, echo);
     }
 }
 
@@ -4287,8 +4341,8 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
         return;
     }
     be->fe_open = fe_open;
-    if (chr->driver->chr_set_fe_open) {
-        chr->driver->chr_set_fe_open(chr, fe_open);
+    if (CHARDEV_GET_CLASS(chr)->chr_set_fe_open) {
+        CHARDEV_GET_CLASS(chr)->chr_set_fe_open(chr, fe_open);
     }
 }
 
@@ -4299,11 +4353,11 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
     GSource *src;
     guint tag;
 
-    if (!s || s->driver->chr_add_watch == NULL) {
+    if (!s || CHARDEV_GET_CLASS(s)->chr_add_watch == NULL) {
         return 0;
     }
 
-    src = s->driver->chr_add_watch(s, cond);
+    src = CHARDEV_GET_CLASS(s)->chr_add_watch(s, cond);
     if (!src) {
         return 0;
     }
@@ -4319,31 +4373,17 @@ void qemu_chr_fe_disconnect(CharBackend *be)
 {
     Chardev *chr = be->chr;
 
-    if (chr && chr->driver->chr_disconnect) {
-        chr->driver->chr_disconnect(chr);
-    }
-}
-
-static void qemu_chr_free_common(Chardev *chr)
-{
-    if (chr->be) {
-        chr->be->chr = NULL;
+    if (chr && CHARDEV_GET_CLASS(chr)->chr_disconnect) {
+        CHARDEV_GET_CLASS(chr)->chr_disconnect(chr);
     }
-    g_free(chr->filename);
-    g_free(chr->label);
-    if (chr->logfd != -1) {
-        close(chr->logfd);
-    }
-    qemu_mutex_destroy(&chr->chr_write_lock);
-    g_free(chr);
 }
 
 void qemu_chr_free(Chardev *chr)
 {
-    if (chr->driver->chr_free) {
-        chr->driver->chr_free(chr);
+    if (CHARDEV_GET_CLASS(chr)->chr_free) {
+        CHARDEV_GET_CLASS(chr)->chr_free(chr);
     }
-    qemu_chr_free_common(chr);
+    object_unref(OBJECT(chr));
 }
 
 void qemu_chr_delete(Chardev *chr)
@@ -4513,22 +4553,19 @@ QemuOptsList qemu_chardev_opts = {
 
 #ifdef _WIN32
 
-static Chardev *qmp_chardev_open_file(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static void qmp_chardev_open_file(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
-    ChardevCommon *common = qapi_ChardevFile_base(file);
     HANDLE out;
     DWORD accessmode;
     DWORD flags;
 
     if (file->has_in) {
         error_setg(errp, "input file not supported");
-        return NULL;
+        return;
     }
 
     if (file->has_append && file->append) {
@@ -4545,33 +4582,20 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
                      FILE_ATTRIBUTE_NORMAL, NULL);
     if (out == INVALID_HANDLE_VALUE) {
         error_setg(errp, "open %s failed", file->out);
-        return NULL;
+        return;
     }
-    return qemu_chr_open_win_file(driver, out, common, errp);
+
+    qemu_chr_open_win_file(chr, out);
 }
 
-static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
-                                        const char *id,
-                                        ChardevBackend *backend,
-                                        ChardevReturn *ret,
-                                        bool *be_opened,
-                                        Error **errp)
+static void qmp_chardev_open_serial(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
-    ChardevCommon *common = qapi_ChardevHostdev_base(serial);
-    Chardev *chr;
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-
-    if (win_chr_init(chr, serial->device, errp) < 0) {
-        qemu_chr_free_common(chr);
-        return NULL;
-    }
-
-    return chr;
+    win_chr_init(chr, serial->device, errp);
 }
 
 #else /* WIN32 */
@@ -4588,15 +4612,12 @@ static int qmp_chardev_open_file_source(char *src, int flags,
     return fd;
 }
 
-static Chardev *qmp_chardev_open_file(const CharDriver *driver,
-                                      const char *id,
-                                      ChardevBackend *backend,
-                                      ChardevReturn *ret,
-                                      bool *be_opened,
-                                      Error **errp)
+static void qmp_chardev_open_file(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
-    ChardevCommon *common = qapi_ChardevFile_base(file);
     int flags, in = -1, out;
 
     flags = O_WRONLY | O_CREAT | O_BINARY;
@@ -4608,7 +4629,7 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
 
     out = qmp_chardev_open_file_source(file->out, flags, errp);
     if (out < 0) {
-        return NULL;
+        return;
     }
 
     if (file->has_in) {
@@ -4616,68 +4637,75 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
         in = qmp_chardev_open_file_source(file->in, flags, errp);
         if (in < 0) {
             qemu_close(out);
-            return NULL;
+            return;
         }
     }
 
-    return qemu_chr_open_fd(driver, in, out, common, errp);
+    qemu_chr_open_fd(chr, in, out);
 }
 
 #ifdef HAVE_CHARDEV_SERIAL
-static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
-                                        const char *id,
-                                        ChardevBackend *backend,
-                                        ChardevReturn *ret,
-                                        bool *be_opened,
-                                        Error **errp)
+static void qmp_chardev_open_serial(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
-    ChardevCommon *common = qapi_ChardevHostdev_base(serial);
     int fd;
 
     fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
     if (fd < 0) {
-        return NULL;
+        return;
     }
     qemu_set_nonblock(fd);
     tty_serial_init(fd, 115200, 'N', 8, 1);
 
-    return qemu_chr_open_fd(driver, fd, fd, common, errp);
+    qemu_chr_open_fd(chr, fd, fd);
 }
 #endif
 
 #ifdef HAVE_CHARDEV_PARPORT
-static Chardev *qmp_chardev_open_parallel(const CharDriver *driver,
-                                          const char *id,
-                                          ChardevBackend *backend,
-                                          ChardevReturn *ret,
-                                          bool *be_opened,
-                                          Error **errp)
+static void qmp_chardev_open_parallel(Chardev *chr,
+                                      ChardevBackend *backend,
+                                      bool *be_opened,
+                                      Error **errp)
 {
     ChardevHostdev *parallel = backend->u.parallel.data;
-    ChardevCommon *common = qapi_ChardevHostdev_base(parallel);
     int fd;
 
     fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
     if (fd < 0) {
-        return NULL;
+        return;
     }
-    return qemu_chr_open_pp_fd(driver, fd, common, be_opened, errp);
+    qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
 }
 
 static const CharDriver parallel_driver = {
-    .instance_size = sizeof(ParallelChardev),
     .alias = "parport", .kind = CHARDEV_BACKEND_KIND_PARALLEL,
-    .parse = qemu_chr_parse_parallel, .create = qmp_chardev_open_parallel,
+    .parse = qemu_chr_parse_parallel
+};
+
+static void char_parallel_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qmp_chardev_open_parallel;
 #if defined(__linux__)
-    .chr_write = null_chr_write,
-    .chr_ioctl = pp_ioctl,
-    .chr_free = pp_free,
+    cc->chr_write = null_chr_write;
+    cc->chr_ioctl = pp_ioctl;
+    cc->chr_free = pp_free;
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-    .chr_write = null_chr_write;
-    .chr_ioctl = pp_ioctl;
     /* FIXME: no chr_free */
+    cc->chr_write = null_chr_write;
+    cc->chr_ioctl = pp_ioctl;
 #endif
+}
+
+static const TypeInfo char_parallel_type_info = {
+    .name = TYPE_CHARDEV_PARALLEL,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(ParallelChardev),
+    .class_init = char_parallel_class_init,
 };
 #endif
 
@@ -4685,43 +4713,63 @@ static const CharDriver parallel_driver = {
 
 static const CharDriver file_driver = {
     .kind = CHARDEV_BACKEND_KIND_FILE,
-    .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file,
+    .parse = qemu_chr_parse_file_out
+};
+
+static void char_file_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qmp_chardev_open_file;
 #ifdef _WIN32
-    sizeof(WinChardev),
-    .chr_write = win_chr_write,
     /* FIXME: no chr_free */
+    cc->chr_free = NULL;
+#endif
+}
+
+static const TypeInfo char_file_type_info = {
+    .name = TYPE_CHARDEV_FILE,
+#ifdef _WIN32
+    .parent = TYPE_CHARDEV_WIN,
 #else
-    sizeof(FDChardev),
-    .chr_add_watch = fd_chr_add_watch,
-    .chr_write = fd_chr_write,
-    .chr_update_read_handler = fd_chr_update_read_handler,
-    .chr_free = fd_chr_free,
+    .parent = TYPE_CHARDEV_FD,
 #endif
+    .class_init = char_file_class_init,
 };
 
 #ifdef HAVE_CHARDEV_SERIAL
+
 static const CharDriver serial_driver = {
     .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
-    .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
+    .parse = qemu_chr_parse_serial
+};
+
+static void char_serial_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qmp_chardev_open_serial;
+#ifndef _WIN32
+    cc->chr_ioctl = tty_serial_ioctl;
+    cc->chr_free = qemu_chr_free_tty;
+#endif
+}
+
+static const TypeInfo char_serial_type_info = {
+    .name = TYPE_CHARDEV_SERIAL,
 #ifdef _WIN32
-    sizeof(WinChardev),
-    .chr_write = win_chr_write,
-    .chr_free = win_chr_free,
+    .parent = TYPE_CHARDEV_WIN,
 #else
-    sizeof(FDChardev),
-    .chr_add_watch = fd_chr_add_watch,
-    .chr_write = fd_chr_write,
-    .chr_update_read_handler = fd_chr_update_read_handler,
-    .chr_ioctl = tty_serial_ioctl,
-    .chr_free = qemu_chr_free_tty,
+    .parent = TYPE_CHARDEV_FD,
 #endif
+    .class_init = char_serial_class_init,
 };
 #endif
 
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
-    Chardev *chr = opaque;
-    SocketChardev *s = opaque;
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
     QIOChannelSocket *sioc;
 
     s->reconnect_timer = 0;
@@ -4739,15 +4787,12 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
     return false;
 }
 
-static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
-                                        const char *id,
-                                        ChardevBackend *backend,
-                                        ChardevReturn *ret,
-                                        bool *be_opened,
-                                        Error **errp)
+static void qmp_chardev_open_socket(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
-    Chardev *chr;
-    SocketChardev *s;
+    SocketChardev *s = SOCKET_CHARDEV(chr);
     ChardevSocket *sock = backend->u.socket.data;
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
@@ -4755,15 +4800,8 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
     bool is_telnet      = sock->has_telnet  ? sock->telnet  : false;
     bool is_waitconnect = sock->has_wait    ? sock->wait    : false;
     int64_t reconnect   = sock->has_reconnect ? sock->reconnect : 0;
-    ChardevCommon *common = qapi_ChardevSocket_base(sock);
     QIOChannelSocket *sioc = NULL;
 
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = (SocketChardev *)chr;
-
     s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
     s->is_telnet = is_telnet;
@@ -4855,82 +4893,94 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
         }
     }
 
-    return chr;
+    return;
 
- error:
+error:
     if (sioc) {
         object_unref(OBJECT(sioc));
     }
     if (s->tls_creds) {
         object_unref(OBJECT(s->tls_creds));
     }
-    qemu_chr_free_common(chr);
-    return NULL;
 }
 
 static const CharDriver socket_driver = {
-    .instance_size = sizeof(SocketChardev),
     .kind = CHARDEV_BACKEND_KIND_SOCKET,
-    .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket,
-    .chr_wait_connected = tcp_chr_wait_connected,
-    .chr_write = tcp_chr_write,
-    .chr_sync_read = tcp_chr_sync_read,
-    .chr_disconnect = tcp_chr_disconnect,
-    .get_msgfds = tcp_get_msgfds,
-    .set_msgfds = tcp_set_msgfds,
-    .chr_add_client = tcp_chr_add_client,
-    .chr_add_watch = tcp_chr_add_watch,
-    .chr_update_read_handler = tcp_chr_update_read_handler,
-    .chr_free = tcp_chr_free,
+    .parse = qemu_chr_parse_socket
+};
+
+static void char_socket_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qmp_chardev_open_socket;
+    cc->chr_wait_connected = tcp_chr_wait_connected;
+    cc->chr_write = tcp_chr_write;
+    cc->chr_sync_read = tcp_chr_sync_read;
+    cc->chr_disconnect = tcp_chr_disconnect;
+    cc->get_msgfds = tcp_get_msgfds;
+    cc->set_msgfds = tcp_set_msgfds;
+    cc->chr_add_client = tcp_chr_add_client;
+    cc->chr_add_watch = tcp_chr_add_watch;
+    cc->chr_update_read_handler = tcp_chr_update_read_handler;
+    cc->chr_free = tcp_chr_free;
+}
+
+static const TypeInfo char_socket_type_info = {
+    .name = TYPE_CHARDEV_SOCKET,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(SocketChardev),
+    .class_init = char_socket_class_init,
 };
 
-static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
-                                     const char *id,
-                                     ChardevBackend *backend,
-                                     ChardevReturn *ret,
-                                     bool *be_opened,
-                                     Error **errp)
+static void qmp_chardev_open_udp(Chardev *chr,
+                                 ChardevBackend *backend,
+                                 bool *be_opened,
+                                 Error **errp)
 {
     ChardevUdp *udp = backend->u.udp.data;
-    ChardevCommon *common = qapi_ChardevUdp_base(udp);
     QIOChannelSocket *sioc = qio_channel_socket_new();
     char *name;
-    Chardev *chr;
-    UdpChardev *s;
+    UdpChardev *s = UDP_CHARDEV(chr);
 
     if (qio_channel_socket_dgram_sync(sioc,
                                       udp->local, udp->remote,
                                       errp) < 0) {
         object_unref(OBJECT(sioc));
-        return NULL;
-    }
-
-    chr = qemu_chr_alloc(driver, common, errp);
-    if (!chr) {
-        return NULL;
+        return;
     }
 
     name = g_strdup_printf("chardev-udp-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
-    s = (UdpChardev *)chr;
     s->ioc = QIO_CHANNEL(sioc);
     s->bufcnt = 0;
     s->bufptr = 0;
     /* be isn't opened until we get a connection */
     *be_opened = false;
-
-    return chr;
 }
 
 static const CharDriver udp_driver = {
-    .instance_size = sizeof(UdpChardev),
     .kind = CHARDEV_BACKEND_KIND_UDP,
-    .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
-    .chr_write = udp_chr_write,
-    .chr_update_read_handler = udp_chr_update_read_handler,
-    .chr_free = udp_chr_free,
+    .parse = qemu_chr_parse_udp
+};
+
+static void char_udp_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qmp_chardev_open_udp;
+    cc->chr_write = udp_chr_write;
+    cc->chr_update_read_handler = udp_chr_update_read_handler;
+    cc->chr_free = udp_chr_free;
+}
+
+static const TypeInfo char_udp_type_info = {
+    .name = TYPE_CHARDEV_UDP,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(UdpChardev),
+    .class_init = char_udp_class_init,
 };
 
 bool qemu_chr_has_feature(Chardev *chr,
@@ -4945,47 +4995,92 @@ void qemu_chr_set_feature(Chardev *chr,
     return set_bit(feature, chr->features);
 }
 
-ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
-                               Error **errp)
+static const ChardevClass *char_get_class(const char *driver, Error **errp)
+{
+    ObjectClass *oc;
+    const ChardevClass *cc;
+    char *typename = g_strdup_printf("chardev-%s", driver);
+
+    oc = object_class_by_name(typename);
+    g_free(typename);
+
+    if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
+        error_setg(errp, "'%s' is not a valid char driver name", driver);
+        return NULL;
+    }
+
+    if (object_class_is_abstract(oc)) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
+                   "abstract device type");
+        return NULL;
+    }
+
+    cc = CHARDEV_CLASS(oc);
+
+    return cc;
+}
+
+Chardev *qemu_chardev_new(const char *id, const char *typename,
+                          ChardevBackend *backend, Error **errp)
 {
-    ChardevReturn *ret = g_new0(ChardevReturn, 1);
     Chardev *chr = NULL;
-    const CharDriver *cd;
     Error *local_err = NULL;
     bool be_opened = true;
 
-    chr = qemu_chr_find(id);
-    if (chr) {
-        error_setg(errp, "Chardev '%s' already exists", id);
-        goto out_error;
-    }
+    assert(g_str_has_prefix(typename, "chardev-"));
 
-    cd = (int)backend->type >= 0 && backend->type < ARRAY_SIZE(backends) ?
-        backends[backend->type] : NULL;
-    if (cd == NULL) {
-        error_setg(errp, "chardev backend not available");
-        goto out_error;
-    }
+    chr = CHARDEV(object_new(typename));
+    chr->label = g_strdup(id);
 
-    chr = cd->create(cd, id, backend, ret, &be_opened, &local_err);
+    qemu_char_open(chr, backend, &be_opened, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
-        goto out_error;
+        object_unref(OBJECT(chr));
+        return NULL;
     }
 
-    chr->label = g_strdup(id);
     if (!chr->filename) {
-        chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
+        chr->filename = g_strdup(typename + 8);
     }
     if (be_opened) {
         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
     }
+
+    return chr;
+}
+
+ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
+                               Error **errp)
+{
+    const ChardevClass *cc;
+    ChardevReturn *ret;
+    Chardev *chr;
+
+    chr = qemu_chr_find(id);
+    if (chr) {
+        error_setg(errp, "Chardev '%s' already exists", id);
+        return NULL;
+    }
+
+    cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
+    if (!cc) {
+        return NULL;
+    }
+
+    chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
+                           backend, errp);
+    if (!chr) {
+        return NULL;
+    }
+
+    ret = g_new0(ChardevReturn, 1);
+    if (CHARDEV_IS_PTY(chr)) {
+        ret->pty = g_strdup(chr->filename + 4);
+        ret->has_pty = true;
+    }
+
     QTAILQ_INSERT_TAIL(&chardevs, chr, next);
     return ret;
-
-out_error:
-    g_free(ret);
-    return NULL;
 }
 
 void qmp_chardev_remove(const char *id, Error **errp)
@@ -5020,33 +5115,44 @@ void qemu_chr_cleanup(void)
 
 static void register_types(void)
 {
-    static const CharDriver *drivers[] = {
-        &null_driver,
-        &socket_driver,
-        &udp_driver,
-        &ringbuf_driver,
-        &file_driver,
-        &stdio_driver,
+    static const struct {
+        const CharDriver *driver;
+        const TypeInfo *type;
+    } chardevs[] = {
+        { &null_driver, &char_null_type_info },
+        { &socket_driver, &char_socket_type_info },
+        { &udp_driver, &char_udp_type_info },
+        { &ringbuf_driver, &char_ringbuf_type_info },
+        { &file_driver, &char_file_type_info },
+        { &stdio_driver, &char_stdio_type_info },
 #ifdef HAVE_CHARDEV_SERIAL
-        &serial_driver,
+        { &serial_driver, &char_serial_type_info },
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
-        &parallel_driver,
+        { &parallel_driver, &char_parallel_type_info },
 #endif
 #ifdef HAVE_CHARDEV_PTY
-        &pty_driver,
+        { &pty_driver, &char_pty_type_info },
 #endif
 #ifdef _WIN32
-        &console_driver,
+        { &console_driver, &char_console_type_info },
 #endif
-        &pipe_driver,
-        &mux_driver,
-        &memory_driver
+        { &pipe_driver, &char_pipe_type_info },
+        { &mux_driver, &char_mux_type_info },
+        { &memory_driver, &char_memory_type_info }
     };
     int i;
 
-    for (i = 0; i < ARRAY_SIZE(drivers); i++) {
-        register_char_driver(drivers[i]);
+    type_register_static(&char_type_info);
+#ifndef _WIN32
+    type_register_static(&char_fd_type_info);
+#else
+    type_register_static(&char_win_type_info);
+    type_register_static(&char_win_stdio_type_info);
+#endif
+    for (i = 0; i < ARRAY_SIZE(chardevs); i++) {
+        type_register_static(chardevs[i].type);
+        register_char_driver(chardevs[i].driver);
     }
 
     /* this must be done after machine init, since we register FEs with muxes
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 4e934cf224..e27b86622a 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -18,6 +18,12 @@ typedef struct SpiceChardev {
     QLIST_ENTRY(SpiceChardev) next;
 } SpiceChardev;
 
+#define TYPE_CHARDEV_SPICE "chardev-spice"
+#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
+#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"
+
+#define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE)
+
 typedef struct SpiceCharSource {
     GSource               source;
     SpiceChardev       *scd;
@@ -29,7 +35,7 @@ static QLIST_HEAD(, SpiceChardev) spice_chars =
 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
 {
     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
-    Chardev *chr = (Chardev *)scd;
+    Chardev *chr = CHARDEV(scd);
     ssize_t out = 0;
     ssize_t last_out;
     uint8_t* p = (uint8_t*)buf;
@@ -73,7 +79,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
 {
     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
-    Chardev *chr = (Chardev *)scd;
+    Chardev *chr = CHARDEV(scd);
     int chr_event;
 
     switch (event) {
@@ -92,7 +98,7 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
 static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
 {
     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
-    Chardev *chr = (Chardev *)scd;
+    Chardev *chr = CHARDEV(scd);
 
     if ((chr->be_open && connected) ||
         (!chr->be_open && !connected)) {
@@ -173,7 +179,7 @@ static GSourceFuncs SpiceCharSourceFuncs = {
 
 static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
 {
-    SpiceChardev *scd = (SpiceChardev *)chr;
+    SpiceChardev *scd = SPICE_CHARDEV(chr);
     SpiceCharSource *src;
 
     assert(cond & G_IO_OUT);
@@ -187,7 +193,7 @@ static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
 
 static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    SpiceChardev *s = (SpiceChardev *)chr;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
     int read_bytes;
 
     assert(s->datalen == 0);
@@ -206,7 +212,7 @@ static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static void spice_chr_free(struct Chardev *chr)
 {
-    SpiceChardev *s = (SpiceChardev *)chr;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
 
     vmc_unregister_interface(s);
     QLIST_REMOVE(s, next);
@@ -219,7 +225,7 @@ static void spice_chr_free(struct Chardev *chr)
 
 static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
 {
-    SpiceChardev *s = (SpiceChardev *)chr;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
     if (fe_open) {
         vmc_register_interface(s);
     } else {
@@ -230,7 +236,7 @@ static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
 static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
 {
 #if SPICE_SERVER_VERSION >= 0x000c02
-    SpiceChardev *s = (SpiceChardev *)chr;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
 
     if (fe_open) {
         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
@@ -242,43 +248,29 @@ static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
 
 static void spice_chr_accept_input(struct Chardev *chr)
 {
-    SpiceChardev *s = (SpiceChardev *)chr;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
 
     spice_server_char_device_wakeup(&s->sin);
 }
 
-static Chardev *chr_open(const CharDriver *driver,
-                                 const char *subtype,
-                                 ChardevCommon *backend,
-                                 Error **errp)
+static void chr_open(Chardev *chr, const char *subtype)
 {
-    Chardev *chr;
-    SpiceChardev *s;
+    SpiceChardev *s = SPICE_CHARDEV(chr);
 
-    chr = qemu_chr_alloc(driver, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-    s = (SpiceChardev *)chr;
     s->active = false;
     s->sin.subtype = g_strdup(subtype);
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
-
-    return chr;
 }
 
-static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
-                                                const char *id,
-                                                ChardevBackend *backend,
-                                                ChardevReturn *ret,
-                                                bool *be_opened,
-                                                Error **errp)
+static void qemu_chr_open_spice_vmc(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
 {
     ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
     const char *type = spicevmc->type;
     const char **psubtype = spice_server_char_device_recognized_subtypes();
-    ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
 
     for (; *psubtype != NULL; ++psubtype) {
         if (strcmp(type, *psubtype) == 0) {
@@ -293,41 +285,33 @@ static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
         error_report("allowed spice char type names: %s", subtypes);
 
         g_free(subtypes);
-        return NULL;
+        return;
     }
 
     *be_opened = false;
-    return chr_open(driver, type, common, errp);
+    chr_open(chr, type);
 }
 
 #if SPICE_SERVER_VERSION >= 0x000c02
-static Chardev *qemu_chr_open_spice_port(const CharDriver *driver,
-                                                 const char *id,
-                                                 ChardevBackend *backend,
-                                                 ChardevReturn *ret,
-                                                 bool *be_opened,
-                                                 Error **errp)
+static void qemu_chr_open_spice_port(Chardev *chr,
+                                     ChardevBackend *backend,
+                                     bool *be_opened,
+                                     Error **errp)
 {
     ChardevSpicePort *spiceport = backend->u.spiceport.data;
     const char *name = spiceport->fqdn;
-    ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
-    Chardev *chr;
     SpiceChardev *s;
 
     if (name == NULL) {
         error_setg(errp, "missing name parameter");
-        return NULL;
+        return;
     }
 
-    chr = chr_open(driver, "port", common, errp);
-    if (!chr) {
-        return NULL;
-    }
+    chr_open(chr, "port");
+
     *be_opened = false;
-    s = (SpiceChardev *)chr;
+    s = SPICE_CHARDEV(chr);
     s->sin.portname = g_strdup(name);
-
-    return chr;
 }
 
 void qemu_spice_register_ports(void)
@@ -373,30 +357,68 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
     spiceport->fqdn = g_strdup(name);
 }
 
+static void char_spice_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_write = spice_chr_write;
+    cc->chr_add_watch = spice_chr_add_watch;
+    cc->chr_accept_input = spice_chr_accept_input;
+    cc->chr_free = spice_chr_free;
+}
+
+static const TypeInfo char_spice_type_info = {
+    .name = TYPE_CHARDEV_SPICE,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(SpiceChardev),
+    .class_init = char_spice_class_init,
+    .abstract = true,
+};
+
+static void char_spicevmc_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_spice_vmc;
+    cc->chr_set_fe_open = spice_vmc_set_fe_open;
+}
+
+static const TypeInfo char_spicevmc_type_info = {
+    .name = TYPE_CHARDEV_SPICEVMC,
+    .parent = TYPE_CHARDEV_SPICE,
+    .class_init = char_spicevmc_class_init,
+};
+
+static void char_spiceport_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_spice_port;
+    cc->chr_set_fe_open = spice_port_set_fe_open;
+}
+
+static const TypeInfo char_spiceport_type_info = {
+    .name = TYPE_CHARDEV_SPICEPORT,
+    .parent = TYPE_CHARDEV_SPICE,
+    .class_init = char_spiceport_class_init,
+};
+
 static void register_types(void)
 {
     static const CharDriver vmc_driver = {
-        .instance_size = sizeof(SpiceChardev),
         .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
-        .parse = qemu_chr_parse_spice_vmc, .create = qemu_chr_open_spice_vmc,
-        .chr_write = spice_chr_write,
-        .chr_add_watch = spice_chr_add_watch,
-        .chr_set_fe_open = spice_vmc_set_fe_open,
-        .chr_accept_input = spice_chr_accept_input,
-        .chr_free = spice_chr_free,
+        .parse = qemu_chr_parse_spice_vmc
     };
     static const CharDriver port_driver = {
-        .instance_size = sizeof(SpiceChardev),
         .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
-        .parse = qemu_chr_parse_spice_port, .create = qemu_chr_open_spice_port,
-        .chr_write = spice_chr_write,
-        .chr_add_watch = spice_chr_add_watch,
-        .chr_set_fe_open = spice_port_set_fe_open,
-        .chr_accept_input = spice_chr_accept_input,
-        .chr_free = spice_chr_free,
+        .parse = qemu_chr_parse_spice_port
     };
     register_char_driver(&vmc_driver);
     register_char_driver(&port_driver);
+
+    type_register_static(&char_spice_type_info);
+    type_register_static(&char_spicevmc_type_info);
+    type_register_static(&char_spiceport_type_info);
 }
 
 type_init(register_types);
diff --git a/ui/console.c b/ui/console.c
index 9a16e1b743..5fc29e36f6 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1040,9 +1040,12 @@ typedef struct VCChardev {
     QemuConsole *console;
 } VCChardev;
 
-static int console_puts(Chardev *chr, const uint8_t *buf, int len)
+#define TYPE_CHARDEV_VC "chardev-vc"
+#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
+
+static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    VCChardev *drv = (VCChardev *)chr;
+    VCChardev *drv = VC_CHARDEV(chr);
     QemuConsole *s = drv->console;
     int i;
 
@@ -1128,13 +1131,13 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
             *q++ = '[';
             *q++ = keysym & 0xff;
         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
-            console_puts(s->chr, (const uint8_t *) "\r", 1);
+            vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
             *q++ = '\n';
         } else {
             *q++ = keysym;
         }
         if (s->echo) {
-            console_puts(s->chr, buf, q - buf);
+            vc_chr_write(s->chr, buf, q - buf);
         }
         be = s->chr->be;
         if (be && be->chr_read) {
@@ -1951,9 +1954,9 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
     return con ? surface_height(con->surface) : fallback;
 }
 
-static void text_console_set_echo(Chardev *chr, bool echo)
+static void vc_chr_set_echo(Chardev *chr, bool echo)
 {
-    VCChardev *drv = (VCChardev *)chr;
+    VCChardev *drv = VC_CHARDEV(chr);
     QemuConsole *s = drv->console;
 
     s->echo = echo;
@@ -1994,7 +1997,7 @@ static const GraphicHwOps text_console_ops = {
 
 static void text_console_do_init(Chardev *chr, DisplayState *ds)
 {
-    VCChardev *drv = (VCChardev *)chr;
+    VCChardev *drv = VC_CHARDEV(chr);
     QemuConsole *s = drv->console;
     int g_width = 80 * FONT_WIDTH;
     int g_height = 24 * FONT_HEIGHT;
@@ -2038,7 +2041,7 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
 
         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
-        console_puts(chr, (uint8_t*)msg, len);
+        vc_chr_write(chr, (uint8_t *)msg, len);
         s->t_attrib = s->t_attrib_default;
     }
 
@@ -2047,24 +2050,17 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
 
 static const CharDriver vc_driver;
 
-static Chardev *vc_init(const CharDriver *driver,
-                        const char *id, ChardevBackend *backend,
-                        ChardevReturn *ret, bool *be_opened,
-                        Error **errp)
+static void vc_open(Chardev *chr,
+                    ChardevBackend *backend,
+                    bool *be_opened,
+                    Error **errp)
 {
     ChardevVC *vc = backend->u.vc.data;
-    ChardevCommon *common = qapi_ChardevVC_base(vc);
-    Chardev *chr;
-    VCChardev *drv;
+    VCChardev *drv = VC_CHARDEV(chr);
     QemuConsole *s;
     unsigned width = 0;
     unsigned height = 0;
 
-    chr = qemu_chr_alloc(&vc_driver, common, errp);
-    if (!chr) {
-        return NULL;
-    }
-
     if (vc->has_width) {
         width = vc->width;
     } else if (vc->has_cols) {
@@ -2086,13 +2082,11 @@ static Chardev *vc_init(const CharDriver *driver,
     }
 
     if (!s) {
-        g_free(chr);
         error_setg(errp, "cannot create text console");
-        return NULL;
+        return;
     }
 
     s->chr = chr;
-    drv = (VCChardev *)chr;
     drv->console = s;
 
     if (display_state) {
@@ -2103,8 +2097,6 @@ static Chardev *vc_init(const CharDriver *driver,
      * stage, so defer OPENED events until they are fully initialized
      */
     *be_opened = false;
-
-    return chr;
 }
 
 void qemu_console_resize(QemuConsole *s, int width, int height)
@@ -2182,18 +2174,39 @@ static const TypeInfo qemu_console_info = {
     .class_size = sizeof(QemuConsoleClass),
 };
 
-static const CharDriver vc_driver = {
+static void char_vc_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = vc_open;
+    cc->chr_write = vc_chr_write;
+    cc->chr_set_echo = vc_chr_set_echo;
+}
+
+static const TypeInfo char_vc_type_info = {
+    .name = TYPE_CHARDEV_VC,
+    .parent = TYPE_CHARDEV,
     .instance_size = sizeof(VCChardev),
+    .class_init = char_vc_class_init,
+};
+
+void qemu_console_early_init(void)
+{
+    /* set the default vc driver */
+    if (!object_class_by_name(TYPE_CHARDEV_VC)) {
+        type_register(&char_vc_type_info);
+        register_char_driver(&vc_driver);
+    }
+}
+
+static const CharDriver vc_driver = {
     .kind = CHARDEV_BACKEND_KIND_VC,
-    .parse = qemu_chr_parse_vc, .create = vc_init,
-    .chr_write = console_puts,
-    .chr_set_echo = text_console_set_echo,
+    .parse = qemu_chr_parse_vc
 };
 
 static void register_types(void)
 {
     type_register_static(&qemu_console_info);
-    register_char_driver(&vc_driver);
 }
 
 type_init(register_types);
diff --git a/ui/gtk.c b/ui/gtk.c
index efa50524bf..03573a3ff3 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -184,6 +184,9 @@ typedef struct VCChardev {
     bool echo;
 } VCChardev;
 
+#define TYPE_CHARDEV_VC "chardev-vc"
+#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
+
 static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
 static void gd_ungrab_pointer(GtkDisplayState *s);
 static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
@@ -1681,7 +1684,7 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
 
 static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
-    VCChardev *vcd = (VCChardev *)chr;
+    VCChardev *vcd = VC_CHARDEV(chr);
     VirtualConsole *vc = vcd->console;
 
     vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
@@ -1690,7 +1693,7 @@ static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
 
 static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
 {
-    VCChardev *vcd = (VCChardev *)chr;
+    VCChardev *vcd = VC_CHARDEV(chr);
     VirtualConsole *vc = vcd->console;
 
     if (vc) {
@@ -1704,23 +1707,14 @@ static int nb_vcs;
 static Chardev *vcs[MAX_VCS];
 static const CharDriver gd_vc_driver;
 
-static Chardev *vc_init(const CharDriver *driver,
-                        const char *id, ChardevBackend *backend,
-                        ChardevReturn *ret, bool *be_opened,
-                        Error **errp)
+static void gd_vc_open(Chardev *chr,
+                       ChardevBackend *backend,
+                       bool *be_opened,
+                       Error **errp)
 {
-    ChardevVC *vc = backend->u.vc.data;
-    ChardevCommon *common = qapi_ChardevVC_base(vc);
-    Chardev *chr;
-
     if (nb_vcs == MAX_VCS) {
         error_setg(errp, "Maximum number of consoles reached");
-        return NULL;
-    }
-
-    chr = qemu_chr_alloc(&gd_vc_driver, common, errp);
-    if (!chr) {
-        return NULL;
+        return;
     }
 
     vcs[nb_vcs++] = chr;
@@ -1729,16 +1723,27 @@ static Chardev *vc_init(const CharDriver *driver,
      * stage, so defer OPENED events until they are fully initialized
      */
     *be_opened = false;
+}
 
-    return chr;
+static void char_gd_vc_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = gd_vc_open;
+    cc->chr_write = gd_vc_chr_write;
+    cc->chr_set_echo = gd_vc_chr_set_echo;
 }
 
-static const CharDriver gd_vc_driver = {
+static const TypeInfo char_gd_vc_type_info = {
+    .name = TYPE_CHARDEV_VC,
+    .parent = TYPE_CHARDEV,
     .instance_size = sizeof(VCChardev),
+    .class_init = char_gd_vc_class_init,
+};
+
+static const CharDriver gd_vc_driver = {
     .kind = CHARDEV_BACKEND_KIND_VC,
-    .parse = qemu_chr_parse_vc, .create = vc_init,
-    .chr_write = gd_vc_chr_write,
-    .chr_set_echo = gd_vc_chr_set_echo,
+    .parse = qemu_chr_parse_vc
 };
 
 static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
@@ -1776,7 +1781,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
     GtkWidget *box;
     GtkWidget *scrollbar;
     GtkAdjustment *vadjustment;
-    VCChardev *vcd = (VCChardev *)chr;
+    VCChardev *vcd = VC_CHARDEV(chr);
 
     vc->s = s;
     vc->vte.echo = vcd->echo;
@@ -2328,7 +2333,7 @@ void early_gtk_display_init(int opengl)
     }
 
 #if defined(CONFIG_VTE)
-    /* overwrite the console.c vc driver */
+    type_register(&char_gd_vc_type_info);
     register_char_driver(&gd_vc_driver);
 #endif
 }
diff --git a/vl.c b/vl.c
index 8296f8da49..144a472990 100644
--- a/vl.c
+++ b/vl.c
@@ -4315,6 +4315,8 @@ int main(int argc, char **argv, char **envp)
         sdl_display_early_init(request_opengl);
     }
 
+    qemu_console_early_init();
+
     if (request_opengl == 1 && display_opengl == 0) {
 #if defined(CONFIG_OPENGL)
         error_report("OpenGL is not supported by the display");
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 384f3ce9b7..1ee8aa4325 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -10,6 +10,7 @@
 #include "qapi/qmp/qstring.h"
 #include "qemu/main-loop.h"
 #include "qemu/bitmap.h"
+#include "qom/object.h"
 
 /* character device */
 
@@ -90,7 +91,8 @@ typedef struct CharBackend {
 typedef struct CharDriver CharDriver;
 
 struct Chardev {
-    const CharDriver *driver;
+    Object parent_obj;
+
     QemuMutex chr_write_lock;
     CharBackend *be;
     char *label;
@@ -102,18 +104,6 @@ struct Chardev {
     QTAILQ_ENTRY(Chardev) next;
 };
 
-/**
- * qemu_chr_alloc:
- * @backend: the common backend config
- * @errp: pointer to a NULL-initialized error object
- *
- * Allocate and initialize a new Chardev.
- *
- * Returns: a newly allocated Chardev, or NULL on error.
- */
-Chardev *qemu_chr_alloc(const CharDriver *driver,
-                        ChardevCommon *backend, Error **errp);
-
 /**
  * @qemu_chr_new_from_opts:
  *
@@ -453,54 +443,73 @@ void qemu_chr_fe_accept_input(CharBackend *be);
 int qemu_chr_add_client(Chardev *s, int fd);
 Chardev *qemu_chr_find(const char *name);
 
-/**
- * @qemu_chr_get_kind:
- *
- * Returns the kind of char backend, or -1 if unspecified.
- */
-ChardevBackendKind qemu_chr_get_kind(const Chardev *chr);
-
-static inline bool qemu_chr_is_ringbuf(const Chardev *chr)
-{
-    return qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_RINGBUF ||
-        qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MEMORY;
-}
-
 bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature);
 void qemu_chr_set_feature(Chardev *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
+#define TYPE_CHARDEV "chardev"
+#define CHARDEV(obj) OBJECT_CHECK(Chardev, (obj), TYPE_CHARDEV)
+#define CHARDEV_CLASS(klass) \
+    OBJECT_CLASS_CHECK(ChardevClass, (klass), TYPE_CHARDEV)
+#define CHARDEV_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(ChardevClass, (obj), TYPE_CHARDEV)
+
+#define TYPE_CHARDEV_NULL "chardev-null"
+#define TYPE_CHARDEV_MUX "chardev-mux"
+#define TYPE_CHARDEV_RINGBUF "chardev-ringbuf"
+#define TYPE_CHARDEV_PTY "chardev-pty"
+#define TYPE_CHARDEV_CONSOLE "chardev-console"
+#define TYPE_CHARDEV_STDIO "chardev-stdio"
+#define TYPE_CHARDEV_PIPE "chardev-pipe"
+#define TYPE_CHARDEV_MEMORY "chardev-memory"
+#define TYPE_CHARDEV_PARALLEL "chardev-parallel"
+#define TYPE_CHARDEV_FILE "chardev-file"
+#define TYPE_CHARDEV_SERIAL "chardev-serial"
+#define TYPE_CHARDEV_SOCKET "chardev-socket"
+#define TYPE_CHARDEV_UDP "chardev-udp"
+
+#define CHARDEV_IS_MUX(chr) \
+    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
+#define CHARDEV_IS_RINGBUF(chr) \
+    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
+#define CHARDEV_IS_PTY(chr) \
+    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_PTY)
+
+typedef struct ChardevClass {
+    ObjectClass parent_class;
+
+    bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
+
+    void (*open)(Chardev *chr, ChardevBackend *backend,
+                 bool *be_opened, Error **errp);
+
+    int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
+    int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
+    GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
+    void (*chr_update_read_handler)(Chardev *s, GMainContext *context);
+    int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
+    int (*get_msgfds)(Chardev *s, int* fds, int num);
+    int (*set_msgfds)(Chardev *s, int *fds, int num);
+    int (*chr_add_client)(Chardev *chr, int fd);
+    int (*chr_wait_connected)(Chardev *chr, Error **errp);
+    void (*chr_free)(Chardev *chr);
+    void (*chr_disconnect)(Chardev *chr);
+    void (*chr_accept_input)(Chardev *chr);
+    void (*chr_set_echo)(Chardev *chr, bool echo);
+    void (*chr_set_fe_open)(Chardev *chr, int fe_open);
+} ChardevClass;
+
 struct CharDriver {
     const char *alias;
     ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
-    Chardev *(*create)(const CharDriver *driver,
-                       const char *id,
-                       ChardevBackend *backend,
-                       ChardevReturn *ret, bool *be_opened,
-                       Error **errp);
-    size_t instance_size;
-
-    int (*chr_write)(struct Chardev *s, const uint8_t *buf, int len);
-    int (*chr_sync_read)(struct Chardev *s,
-                         const uint8_t *buf, int len);
-    GSource *(*chr_add_watch)(struct Chardev *s, GIOCondition cond);
-    void (*chr_update_read_handler)(struct Chardev *s,
-                                    GMainContext *context);
-    int (*chr_ioctl)(struct Chardev *s, int cmd, void *arg);
-    int (*get_msgfds)(struct Chardev *s, int* fds, int num);
-    int (*set_msgfds)(struct Chardev *s, int *fds, int num);
-    int (*chr_add_client)(struct Chardev *chr, int fd);
-    int (*chr_wait_connected)(struct Chardev *chr, Error **errp);
-    void (*chr_free)(struct Chardev *chr);
-    void (*chr_disconnect)(struct Chardev *chr);
-    void (*chr_accept_input)(struct Chardev *chr);
-    void (*chr_set_echo)(struct Chardev *chr, bool echo);
-    void (*chr_set_fe_open)(struct Chardev *chr, int fe_open);
 };
 
+Chardev *qemu_chardev_new(const char *id, const char *typename,
+                          ChardevBackend *backend, Error **errp);
+
 void register_char_driver(const CharDriver *driver);
 
 extern int term_escape_char;
diff --git a/include/ui/console.h b/include/ui/console.h
index e2589e2134..32dafdb038 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -380,6 +380,8 @@ void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
 
+void qemu_console_early_init(void);
+
 QemuConsole *qemu_console_lookup_by_index(unsigned int index);
 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 16/54] spice-qemu-char: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (14 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 15/54] chardev: qom-ify Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 17/54] baum: " Marc-André Lureau
                   ` (39 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 spice-qemu-char.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index e27b86622a..af30143720 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -210,9 +210,9 @@ static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
     return read_bytes;
 }
 
-static void spice_chr_free(struct Chardev *chr)
+static void char_spice_finalize(Object *obj)
 {
-    SpiceChardev *s = SPICE_CHARDEV(chr);
+    SpiceChardev *s = SPICE_CHARDEV(obj);
 
     vmc_unregister_interface(s);
     QLIST_REMOVE(s, next);
@@ -364,13 +364,13 @@ static void char_spice_class_init(ObjectClass *oc, void *data)
     cc->chr_write = spice_chr_write;
     cc->chr_add_watch = spice_chr_add_watch;
     cc->chr_accept_input = spice_chr_accept_input;
-    cc->chr_free = spice_chr_free;
 }
 
 static const TypeInfo char_spice_type_info = {
     .name = TYPE_CHARDEV_SPICE,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(SpiceChardev),
+    .instance_finalize = char_spice_finalize,
     .class_init = char_spice_class_init,
     .abstract = true,
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 17/54] baum: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (15 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 16/54] spice-qemu-char: convert to finalize Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 18/54] msmouse: " Marc-André Lureau
                   ` (38 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index 80103b6098..e6758a4dbc 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -631,9 +631,9 @@ static void baum_chr_read(void *opaque)
     }
 }
 
-static void baum_chr_free(Chardev *chr)
+static void char_braille_finalize(Object *obj)
 {
-    BaumChardev *baum = BAUM_CHARDEV(chr);
+    BaumChardev *baum = BAUM_CHARDEV(obj);
 
     timer_free(baum->cellCount_timer);
     if (baum->brlapi) {
@@ -674,13 +674,13 @@ static void char_braille_class_init(ObjectClass *oc, void *data)
     cc->open = baum_chr_open;
     cc->chr_write = baum_chr_write;
     cc->chr_accept_input = baum_chr_accept_input;
-    cc->chr_free = baum_chr_free;
 }
 
 static const TypeInfo char_braille_type_info = {
     .name = TYPE_CHARDEV_BRAILLE,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(BaumChardev),
+    .instance_finalize = char_braille_finalize,
     .class_init = char_braille_class_init,
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 18/54] msmouse: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (16 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 17/54] baum: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 19/54] mux: " Marc-André Lureau
                   ` (37 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/msmouse.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/backends/msmouse.c b/backends/msmouse.c
index 936a5476d5..55c344f0e1 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -139,9 +139,9 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
     return len;
 }
 
-static void msmouse_chr_free(struct Chardev *chr)
+static void char_msmouse_finalize(Object *obj)
 {
-    MouseChardev *mouse = MOUSE_CHARDEV(chr);
+    MouseChardev *mouse = MOUSE_CHARDEV(obj);
 
     qemu_input_handler_unregister(mouse->hs);
 }
@@ -172,13 +172,13 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
     cc->open = msmouse_chr_open;
     cc->chr_write = msmouse_chr_write;
     cc->chr_accept_input = msmouse_chr_accept_input;
-    cc->chr_free = msmouse_chr_free;
 }
 
 static const TypeInfo char_msmouse_type_info = {
     .name = TYPE_CHARDEV_MSMOUSE,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(MouseChardev),
+    .instance_finalize = char_msmouse_finalize,
     .class_init = char_msmouse_class_init,
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 19/54] mux: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (17 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 18/54] msmouse: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 20/54] char-udp: " Marc-André Lureau
                   ` (36 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index d5656007da..3b08155a8f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -859,9 +859,9 @@ static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
     return cc->chr_add_watch(chr, cond);
 }
 
-static void mux_chr_free(struct Chardev *chr)
+static void char_mux_finalize(Object *obj)
 {
-    MuxChardev *d = MUX_CHARDEV(chr);
+    MuxChardev *d = MUX_CHARDEV(obj);
     int i;
 
     for (i = 0; i < d->mux_cnt; i++) {
@@ -4018,7 +4018,6 @@ static void char_mux_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->open = qemu_chr_open_mux;
-    cc->chr_free = mux_chr_free;
     cc->chr_write = mux_chr_write;
     cc->chr_accept_input = mux_chr_accept_input;
     cc->chr_add_watch = mux_chr_add_watch;
@@ -4029,6 +4028,7 @@ static const TypeInfo char_mux_type_info = {
     .parent = TYPE_CHARDEV,
     .class_init = char_mux_class_init,
     .instance_size = sizeof(MuxChardev),
+    .instance_finalize = char_mux_finalize,
 };
 
 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 20/54] char-udp: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (18 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 19/54] mux: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 21/54] char-socket: " Marc-André Lureau
                   ` (35 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 3b08155a8f..06281c60e7 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2774,9 +2774,10 @@ static void udp_chr_update_read_handler(Chardev *chr,
     }
 }
 
-static void udp_chr_free(Chardev *chr)
+static void char_udp_finalize(Object *obj)
 {
-    UdpChardev *s = UDP_CHARDEV(chr);
+    Chardev *chr = CHARDEV(obj);
+    UdpChardev *s = UDP_CHARDEV(obj);
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -4973,13 +4974,13 @@ static void char_udp_class_init(ObjectClass *oc, void *data)
     cc->open = qmp_chardev_open_udp;
     cc->chr_write = udp_chr_write;
     cc->chr_update_read_handler = udp_chr_update_read_handler;
-    cc->chr_free = udp_chr_free;
 }
 
 static const TypeInfo char_udp_type_info = {
     .name = TYPE_CHARDEV_UDP,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(UdpChardev),
+    .instance_finalize = char_udp_finalize,
     .class_init = char_udp_class_init,
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 21/54] char-socket: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (19 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 20/54] char-udp: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 22/54] char-pty: " Marc-André Lureau
                   ` (34 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 06281c60e7..ea8b12fa4f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3442,9 +3442,10 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
     return qemu_chr_wait_connected(be->chr, errp);
 }
 
-static void tcp_chr_free(Chardev *chr)
+static void char_socket_finalize(Object *obj)
 {
-    SocketChardev *s = SOCKET_CHARDEV(chr);
+    Chardev *chr = CHARDEV(obj);
+    SocketChardev *s = SOCKET_CHARDEV(obj);
 
     tcp_chr_free_connection(chr);
 
@@ -4924,13 +4925,13 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
     cc->chr_add_client = tcp_chr_add_client;
     cc->chr_add_watch = tcp_chr_add_watch;
     cc->chr_update_read_handler = tcp_chr_update_read_handler;
-    cc->chr_free = tcp_chr_free;
 }
 
 static const TypeInfo char_socket_type_info = {
     .name = TYPE_CHARDEV_SOCKET,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(SocketChardev),
+    .instance_finalize = char_socket_finalize,
     .class_init = char_socket_class_init,
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 22/54] char-pty: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (20 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 21/54] char-socket: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 23/54] char-ringbuf: " Marc-André Lureau
                   ` (33 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index ea8b12fa4f..21eb2d9135 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1654,9 +1654,10 @@ static void pty_chr_state(Chardev *chr, int connected)
     }
 }
 
-static void pty_chr_free(struct Chardev *chr)
+static void char_pty_finalize(Object *obj)
 {
-    PtyChardev *s = PTY_CHARDEV(chr);
+    Chardev *chr = CHARDEV(obj);
+    PtyChardev *s = PTY_CHARDEV(obj);
 
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_state(chr, 0);
@@ -1713,13 +1714,13 @@ static void char_pty_class_init(ObjectClass *oc, void *data)
     cc->chr_write = char_pty_chr_write;
     cc->chr_update_read_handler = pty_chr_update_read_handler;
     cc->chr_add_watch = pty_chr_add_watch;
-    cc->chr_free = pty_chr_free;
 }
 
 static const TypeInfo char_pty_type_info = {
     .name = TYPE_CHARDEV_PTY,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(PtyChardev),
+    .instance_finalize = char_pty_finalize,
     .class_init = char_pty_class_init,
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 23/54] char-ringbuf: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (21 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 22/54] char-pty: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 24/54] char-parallel: convert parallel " Marc-André Lureau
                   ` (32 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 21eb2d9135..4d7f82a45b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3543,9 +3543,9 @@ static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
     return i;
 }
 
-static void ringbuf_chr_free(struct Chardev *chr)
+static void char_ringbuf_finalize(Object *obj)
 {
-    RingBufChardev *d = RINGBUF_CHARDEV(chr);
+    RingBufChardev *d = RINGBUF_CHARDEV(obj);
 
     g_free(d->cbuf);
 }
@@ -3975,7 +3975,6 @@ static void char_ringbuf_class_init(ObjectClass *oc, void *data)
 
     cc->open = qemu_chr_open_ringbuf;
     cc->chr_write = ringbuf_chr_write;
-    cc->chr_free = ringbuf_chr_free;
 }
 
 static const TypeInfo char_ringbuf_type_info = {
@@ -3983,6 +3982,7 @@ static const TypeInfo char_ringbuf_type_info = {
     .parent = TYPE_CHARDEV,
     .class_init = char_ringbuf_class_init,
     .instance_size = sizeof(RingBufChardev),
+    .instance_finalize = char_ringbuf_finalize,
 };
 
 /* Bug-compatibility: */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 24/54] char-parallel: convert parallel to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (22 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 23/54] char-ringbuf: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 25/54] char-stdio: convert " Marc-André Lureau
                   ` (31 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 4d7f82a45b..403b8a3dc7 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2020,17 +2020,6 @@ static int pp_ioctl(Chardev *chr, int cmd, void *arg)
     return 0;
 }
 
-static void pp_free(Chardev *chr)
-{
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-    int fd = drv->fd;
-
-    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
-    ioctl(fd, PPRELEASE);
-    close(fd);
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
 static void qemu_chr_open_pp_fd(Chardev *chr,
                                 int fd,
                                 bool *be_opened,
@@ -4696,18 +4685,33 @@ static void char_parallel_class_init(ObjectClass *oc, void *data)
 #if defined(__linux__)
     cc->chr_write = null_chr_write;
     cc->chr_ioctl = pp_ioctl;
-    cc->chr_free = pp_free;
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-    /* FIXME: no chr_free */
     cc->chr_write = null_chr_write;
     cc->chr_ioctl = pp_ioctl;
 #endif
 }
 
+static void char_parallel_finalize(Object *obj)
+{
+#if defined(__linux__)
+    Chardev *chr = CHARDEV(obj);
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+    /* FIXME: close fd? */
+#endif
+}
+
 static const TypeInfo char_parallel_type_info = {
     .name = TYPE_CHARDEV_PARALLEL,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(ParallelChardev),
+    .instance_finalize = char_parallel_finalize,
     .class_init = char_parallel_class_init,
 };
 #endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 25/54] char-stdio: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (23 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 24/54] char-parallel: convert parallel " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 26/54] char-win-stdio: " Marc-André Lureau
                   ` (30 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 403b8a3dc7..8a5953954c 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1417,10 +1417,10 @@ static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
     tcsetattr (0, TCSANOW, &tty);
 }
 
-static void qemu_chr_free_stdio(struct Chardev *chr)
+static void char_stdio_finalize(Object *obj)
 {
     term_exit();
-    fd_chr_free(chr);
+    fd_chr_free(CHARDEV(chr));
 }
 
 static void qemu_chr_open_stdio(Chardev *chr,
@@ -3852,7 +3852,6 @@ static void char_stdio_class_init(ObjectClass *oc, void *data)
     cc->chr_free = win_stdio_free;
 #else
     cc->chr_set_echo = qemu_chr_set_echo_stdio;
-    cc->chr_free = qemu_chr_free_stdio;
 #endif
 }
 
@@ -3862,6 +3861,7 @@ static const TypeInfo char_stdio_type_info = {
     .parent = TYPE_CHARDEV_WIN_STDIO,
 #else
     .parent = TYPE_CHARDEV_FD,
+    .instance_finalize = char_stdio_finalize,
 #endif
     .class_init = char_stdio_class_init,
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 26/54] char-win-stdio: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (24 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 25/54] char-stdio: convert " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 27/54] char-win: do not override chr_free Marc-André Lureau
                   ` (29 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 8a5953954c..3dfb249d81 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2589,9 +2589,9 @@ static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
     }
 }
 
-static void win_stdio_free(Chardev *chr)
+static void char_win_stdio_finalize(Object *obj)
 {
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
 
     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
         CloseHandle(stdio->hInputReadyEvent);
@@ -2608,6 +2608,7 @@ static const TypeInfo char_win_stdio_type_info = {
     .name = TYPE_CHARDEV_WIN_STDIO,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(WinStdioChardev),
+    .instance_finalize = char_win_stdio_finalize,
     .abstract = true,
 };
 
@@ -3849,7 +3850,6 @@ static void char_stdio_class_init(ObjectClass *oc, void *data)
 #ifdef _WIN32
     cc->chr_write = win_stdio_write;
     cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
-    cc->chr_free = win_stdio_free;
 #else
     cc->chr_set_echo = qemu_chr_set_echo_stdio;
 #endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 27/54] char-win: do not override chr_free
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (25 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 26/54] char-win-stdio: " Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 28/54] char-win: convert to finalize Marc-André Lureau
                   ` (28 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

For some unclear reason to me, char-file does not have chr_free on
win32. Since we want to switch to instance finalizer instead of class
chr_free, we should be able to run the base WinChardev class finalizer
in any case. Use a boolean to skip free to ease the transition to
instance finalizer.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 3dfb249d81..63b254f632 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2117,6 +2117,8 @@ typedef struct {
 
     /* Protected by the Chardev chr_write_lock.  */
     OVERLAPPED osend;
+    /* FIXME: file/console do not finalize */
+    BOOL skip_free;
 } WinChardev;
 
 #define TYPE_CHARDEV_WIN "chardev-win"
@@ -2147,6 +2149,10 @@ static void win_chr_free(Chardev *chr)
 {
     WinChardev *s = WIN_CHARDEV(chr);
 
+    if (s->skip_free) {
+        return;
+    }
+
     if (s->hsend) {
         CloseHandle(s->hsend);
         s->hsend = NULL;
@@ -2427,6 +2433,7 @@ static void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
 {
     WinChardev *s = WIN_CHARDEV(chr);
 
+    s->skip_free = true;
     s->hcom = fd_out;
 }
 
@@ -2463,7 +2470,6 @@ static void char_console_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->open = qemu_chr_open_win_con;
-    cc->chr_free = NULL;
 }
 
 static const TypeInfo char_console_type_info = {
@@ -4728,10 +4734,6 @@ static void char_file_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->open = qmp_chardev_open_file;
-#ifdef _WIN32
-    /* FIXME: no chr_free */
-    cc->chr_free = NULL;
-#endif
 }
 
 static const TypeInfo char_file_type_info = {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 28/54] char-win: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (26 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 27/54] char-win: do not override chr_free Marc-André Lureau
@ 2016-12-12 22:42 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 29/54] char-fd: " Marc-André Lureau
                   ` (27 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 63b254f632..939c598c35 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2145,8 +2145,9 @@ typedef struct {
 static int win_chr_poll(void *opaque);
 static int win_chr_pipe_poll(void *opaque);
 
-static void win_chr_free(Chardev *chr)
+static void char_win_finalize(Object *obj)
 {
+    Chardev *chr = CHARDEV(obj);
     WinChardev *s = WIN_CHARDEV(chr);
 
     if (s->skip_free) {
@@ -2236,7 +2237,6 @@ static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
     return 0;
 
  fail:
-    win_chr_free(chr);
     return -1;
 }
 
@@ -2411,7 +2411,6 @@ static int win_chr_pipe_init(Chardev *chr, const char *filename,
     return 0;
 
  fail:
-    win_chr_free(chr);
     return -1;
 }
 
@@ -2442,13 +2441,13 @@ static void char_win_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->chr_write = win_chr_write;
-    cc->chr_free = win_chr_free;
 }
 
 static const TypeInfo char_win_type_info = {
     .name = TYPE_CHARDEV_WIN,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(WinChardev),
+    .instance_finalize = char_win_finalize,
     .class_init = char_win_class_init,
     .abstract = true,
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 29/54] char-fd: convert to finalize
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (27 preceding siblings ...)
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 28/54] char-win: convert to finalize Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 30/54] char: remove chr_free Marc-André Lureau
                   ` (26 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

char-serial inherits from char-fd finalizer.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 939c598c35..5d4cb85cea 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1291,9 +1291,10 @@ static void fd_chr_update_read_handler(Chardev *chr,
     }
 }
 
-static void fd_chr_free(struct Chardev *chr)
+static void char_fd_finalize(Object *obj)
 {
-    FDChardev *s = FD_CHARDEV(chr);
+    Chardev *chr = CHARDEV(obj);
+    FDChardev *s = FD_CHARDEV(obj);
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1332,13 +1333,13 @@ static void char_fd_class_init(ObjectClass *oc, void *data)
     cc->chr_add_watch = fd_chr_add_watch;
     cc->chr_write = fd_chr_write;
     cc->chr_update_read_handler = fd_chr_update_read_handler;
-    cc->chr_free = fd_chr_free;
 }
 
 static const TypeInfo char_fd_type_info = {
     .name = TYPE_CHARDEV_FD,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(FDChardev),
+    .instance_finalize = char_fd_finalize,
     .class_init = char_fd_class_init,
     .abstract = true,
 };
@@ -1420,7 +1421,6 @@ static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
 static void char_stdio_finalize(Object *obj)
 {
     term_exit();
-    fd_chr_free(CHARDEV(chr));
 }
 
 static void qemu_chr_open_stdio(Chardev *chr,
@@ -1908,11 +1908,6 @@ static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
     }
     return 0;
 }
-
-static void qemu_chr_free_tty(Chardev *chr)
-{
-    fd_chr_free(chr);
-}
 #endif /* __linux__ || __sun__ */
 
 #if defined(__linux__)
@@ -4759,7 +4754,6 @@ static void char_serial_class_init(ObjectClass *oc, void *data)
     cc->open = qmp_chardev_open_serial;
 #ifndef _WIN32
     cc->chr_ioctl = tty_serial_ioctl;
-    cc->chr_free = qemu_chr_free_tty;
 #endif
 }
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 30/54] char: remove chr_free
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (28 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 29/54] char-fd: " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 31/54] char: get rid of CharDriver Marc-André Lureau
                   ` (25 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Now it uses Object instance_finalize instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c           | 10 +---------
 include/sysemu/char.h |  8 --------
 2 files changed, 1 insertion(+), 17 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 5d4cb85cea..ce963d3875 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -4370,18 +4370,10 @@ void qemu_chr_fe_disconnect(CharBackend *be)
     }
 }
 
-void qemu_chr_free(Chardev *chr)
-{
-    if (CHARDEV_GET_CLASS(chr)->chr_free) {
-        CHARDEV_GET_CLASS(chr)->chr_free(chr);
-    }
-    object_unref(OBJECT(chr));
-}
-
 void qemu_chr_delete(Chardev *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
-    qemu_chr_free(chr);
+    object_unref(OBJECT(chr));
 }
 
 ChardevInfoList *qmp_query_chardev(Error **errp)
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 1ee8aa4325..15ae33d8fd 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -184,13 +184,6 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
  */
 void qemu_chr_delete(Chardev *chr);
 
-/**
- * @qemu_chr_free:
- *
- * Destroy a character backend.
- */
-void qemu_chr_free(Chardev *chr);
-
 /**
  * @qemu_chr_fe_set_echo:
  *
@@ -494,7 +487,6 @@ typedef struct ChardevClass {
     int (*set_msgfds)(Chardev *s, int *fds, int num);
     int (*chr_add_client)(Chardev *chr, int fd);
     int (*chr_wait_connected)(Chardev *chr, Error **errp);
-    void (*chr_free)(Chardev *chr);
     void (*chr_disconnect)(Chardev *chr);
     void (*chr_accept_input)(Chardev *chr);
     void (*chr_set_echo)(Chardev *chr, bool echo);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 31/54] char: get rid of CharDriver
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (29 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 30/54] char: remove chr_free Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 32/54] char: remove class kind field Marc-André Lureau
                   ` (24 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |   6 +-
 backends/msmouse.c    |   6 +-
 backends/testdev.c    |   6 +-
 qemu-char.c           | 281 +++++++++++++++++++++-----------------------------
 spice-qemu-char.c     |  15 +--
 ui/console.c          |  10 +-
 ui/gtk.c              |  10 +-
 include/sysemu/char.h |  12 +--
 8 files changed, 133 insertions(+), 213 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index e6758a4dbc..e4c4c53486 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -671,6 +671,7 @@ static void char_braille_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_BRAILLE;
     cc->open = baum_chr_open;
     cc->chr_write = baum_chr_write;
     cc->chr_accept_input = baum_chr_accept_input;
@@ -686,11 +687,6 @@ static const TypeInfo char_braille_type_info = {
 
 static void register_types(void)
 {
-    static const CharDriver driver = {
-        .kind = CHARDEV_BACKEND_KIND_BRAILLE,
-    };
-
-    register_char_driver(&driver);
     type_register_static(&char_braille_type_info);
 }
 
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 55c344f0e1..28689b3e29 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -169,6 +169,7 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_MSMOUSE;
     cc->open = msmouse_chr_open;
     cc->chr_write = msmouse_chr_write;
     cc->chr_accept_input = msmouse_chr_accept_input;
@@ -184,11 +185,6 @@ static const TypeInfo char_msmouse_type_info = {
 
 static void register_types(void)
 {
-    static const CharDriver driver = {
-        .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
-    };
-
-    register_char_driver(&driver);
     type_register_static(&char_msmouse_type_info);
 }
 
diff --git a/backends/testdev.c b/backends/testdev.c
index ea15143713..243454aaa3 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -111,6 +111,7 @@ static void char_testdev_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_TESTDEV;
     cc->chr_write = testdev_chr_write;
 }
 
@@ -123,11 +124,6 @@ static const TypeInfo char_testdev_type_info = {
 
 static void register_types(void)
 {
-    static const CharDriver driver = {
-        .kind = CHARDEV_BACKEND_KIND_TESTDEV,
-    };
-
-    register_char_driver(&driver);
     type_register_static(&char_testdev_type_info);
 }
 
diff --git a/qemu-char.c b/qemu-char.c
index ce963d3875..9a4028059e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -560,16 +560,13 @@ static void null_chr_open(Chardev *chr,
     *be_opened = false;
 }
 
-static const CharDriver null_driver = {
-    .kind = CHARDEV_BACKEND_KIND_NULL,
-};
-
 static void char_null_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->open = null_chr_open;
     cc->chr_write = null_chr_write;
+    cc->kind = CHARDEV_BACKEND_KIND_NULL;
 }
 
 static const TypeInfo char_null_type_info = {
@@ -1702,14 +1699,11 @@ static void char_pty_open(Chardev *chr,
     *be_opened = false;
 }
 
-static const CharDriver pty_driver = {
-    .kind = CHARDEV_BACKEND_KIND_PTY
-};
-
 static void char_pty_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_PTY;
     cc->open = char_pty_open;
     cc->chr_write = char_pty_chr_write;
     cc->chr_update_read_handler = pty_chr_update_read_handler;
@@ -2455,14 +2449,11 @@ static void qemu_chr_open_win_con(Chardev *chr,
     qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
 }
 
-static const CharDriver console_driver = {
-    .kind = CHARDEV_BACKEND_KIND_CONSOLE
-};
-
 static void char_console_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_CONSOLE;
     cc->open = qemu_chr_open_win_con;
 }
 
@@ -3837,15 +3828,12 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
     stdio->signal = qemu_opt_get_bool(opts, "signal", true);
 }
 
-static const CharDriver stdio_driver = {
-    .kind = CHARDEV_BACKEND_KIND_STDIO,
-    .parse = qemu_chr_parse_stdio
-};
-
 static void char_stdio_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_STDIO;
+    cc->parse = qemu_chr_parse_stdio;
     cc->open = qemu_chr_open_stdio;
 #ifdef _WIN32
     cc->chr_write = win_stdio_write;
@@ -3915,15 +3903,12 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
     dev->device = g_strdup(device);
 }
 
-static const CharDriver pipe_driver = {
-    .kind = CHARDEV_BACKEND_KIND_PIPE,
-    .parse = qemu_chr_parse_pipe
-};
-
 static void char_pipe_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_PIPE;
+    cc->parse = qemu_chr_parse_pipe;
     cc->open = qemu_chr_open_pipe;
 }
 
@@ -3953,15 +3938,12 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
-static const CharDriver ringbuf_driver = {
-    .kind = CHARDEV_BACKEND_KIND_RINGBUF,
-    .parse = qemu_chr_parse_ringbuf
-};
-
 static void char_ringbuf_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_RINGBUF;
+    cc->parse = qemu_chr_parse_ringbuf;
     cc->open = qemu_chr_open_ringbuf;
     cc->chr_write = ringbuf_chr_write;
 }
@@ -3975,14 +3957,17 @@ static const TypeInfo char_ringbuf_type_info = {
 };
 
 /* Bug-compatibility: */
-static const CharDriver memory_driver = {
-    .kind = CHARDEV_BACKEND_KIND_MEMORY,
-    .parse = qemu_chr_parse_ringbuf
-};
+static void char_memory_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->kind = CHARDEV_BACKEND_KIND_MEMORY;
+}
 
 static const TypeInfo char_memory_type_info = {
     .name = TYPE_CHARDEV_MEMORY,
     .parent = TYPE_CHARDEV_RINGBUF,
+    .class_init = char_memory_class_init,
 };
 
 static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
@@ -4000,15 +3985,12 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
     mux->chardev = g_strdup(chardev);
 }
 
-static const CharDriver mux_driver = {
-    .kind = CHARDEV_BACKEND_KIND_MUX,
-    .parse = qemu_chr_parse_mux
-};
-
 static void char_mux_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_MUX;
+    cc->parse = qemu_chr_parse_mux;
     cc->open = qemu_chr_open_mux;
     cc->chr_write = mux_chr_write;
     cc->chr_accept_input = mux_chr_accept_input;
@@ -4150,43 +4132,75 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
-static const CharDriver *backends[CHARDEV_BACKEND_KIND__MAX];
-
-void register_char_driver(const CharDriver *driver)
+static const ChardevClass *char_get_class(const char *driver, Error **errp)
 {
-    backends[driver->kind] = driver;
+    ObjectClass *oc;
+    const ChardevClass *cc;
+    char *typename = g_strdup_printf("chardev-%s", driver);
+
+    oc = object_class_by_name(typename);
+    g_free(typename);
+
+    if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
+        error_setg(errp, "'%s' is not a valid char driver name", driver);
+        return NULL;
+    }
+
+    if (object_class_is_abstract(oc)) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
+                   "abstract device type");
+        return NULL;
+    }
+
+    cc = CHARDEV_CLASS(oc);
+    if (cc->internal) {
+        error_setg(errp, "'%s' is not a valid char driver name", driver);
+        return NULL;
+    }
+
+    return cc;
 }
 
+static const struct ChardevAlias {
+    const char *typename;
+    const char *alias;
+} chardev_alias_table[] = {
+#ifdef HAVE_CHARDEV_PARPORT
+    { "parallel", "parport" },
+#endif
+#ifdef HAVE_CHARDEV_SERIAL
+    { "serial", "tty" },
+#endif
+};
+
 Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
                                 Error **errp)
 {
     Error *local_err = NULL;
-    const CharDriver *cd;
+    const ChardevClass *cc;
     Chardev *chr;
     int i;
     ChardevReturn *ret = NULL;
     ChardevBackend *backend;
     const char *id = qemu_opts_id(opts);
+    const char *bname = qemu_opt_get(opts, "backend");
     char *bid = NULL;
 
-    if (qemu_opt_get(opts, "backend") == NULL) {
+    if (bname == NULL) {
         error_setg(errp, "chardev: \"%s\" missing backend",
                    qemu_opts_id(opts));
         goto err;
     }
 
-    if (is_help_option(qemu_opt_get(opts, "backend"))) {
+    if (is_help_option(bname)) {
         GString *str = g_string_new("");
-        for (i = 0; i < ARRAY_SIZE(backends); i++) {
-            cd = backends[i];
-            if (cd) {
-                g_string_append_printf(str, "\n%s", ChardevBackendKind_lookup[cd->kind]);
-                if (cd->alias) {
-                    g_string_append_printf(str, "\n%s", cd->alias);
-                }
-            }
+        ChardevBackendInfoList *l, *il = qmp_query_chardev_backends(NULL);
+
+        for (l = il; l != NULL; l = l->next) {
+            g_string_append_printf(str, "\n%s", l->value->name);
         }
 
+        qapi_free_ChardevBackendInfoList(l);
         error_report("Available chardev backend types: %s", str->str);
         g_string_free(str, true);
         exit(0);
@@ -4197,22 +4211,15 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
         goto err;
     }
 
-    cd = NULL;
-    for (i = 0; i < ARRAY_SIZE(backends); i++) {
-        const char *name = qemu_opt_get(opts, "backend");
-        cd = backends[i];
-
-        if (!cd) {
-            continue;
-        }
-        if (g_str_equal(ChardevBackendKind_lookup[cd->kind], name) ||
-            (cd->alias && g_str_equal(cd->alias, name))) {
+    for (i = 0; i < ARRAY_SIZE(chardev_alias_table); i++) {
+        if (g_str_equal(bname, chardev_alias_table[i].alias)) {
+            bname = chardev_alias_table[i].typename;
             break;
         }
     }
-    if (cd == NULL) {
-        error_setg(errp, "chardev: backend \"%s\" not found",
-                   qemu_opt_get(opts, "backend"));
+
+    cc = char_get_class(bname, errp);
+    if (cc == NULL) {
         goto err;
     }
 
@@ -4223,17 +4230,17 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
     }
 
     chr = NULL;
-    backend->type = cd->kind;
-    if (cd->parse) {
-        cd->parse(opts, backend, &local_err);
+    backend->type = cc->kind;
+    if (cc->parse) {
+        cc->parse(opts, backend, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
             goto qapi_out;
         }
     } else {
-        ChardevCommon *cc = g_new0(ChardevCommon, 1);
-        qemu_chr_parse_common(opts, cc);
-        backend->u.null.data = cc; /* Any ChardevCommon member would work */
+        ChardevCommon *ccom = g_new0(ChardevCommon, 1);
+        qemu_chr_parse_common(opts, ccom);
+        backend->u.null.data = ccom; /* Any ChardevCommon member would work */
     }
 
     ret = qmp_chardev_add(bid ? bid : id, backend, errp);
@@ -4396,7 +4403,7 @@ ChardevInfoList *qmp_query_chardev(Error **errp)
 }
 
 static ChardevBackendInfoList *
-qmp_prepend_backend(ChardevBackendInfoList *list, const CharDriver *c,
+qmp_prepend_backend(ChardevBackendInfoList *list,
                     const char *name)
 {
     ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
@@ -4410,21 +4417,24 @@ qmp_prepend_backend(ChardevBackendInfoList *list, const CharDriver *c,
 ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
 {
     ChardevBackendInfoList *backend_list = NULL;
-    const CharDriver *c;
+    GSList *l, *list = object_class_get_list(TYPE_CHARDEV, false);
     int i;
 
-    for (i = 0; i < ARRAY_SIZE(backends); i++) {
-        c = backends[i];
-        if (!c) {
+    for (l = list; l; l = l->next) {
+        ObjectClass *klass = l->data;
+        assert(g_str_has_prefix(object_class_get_name(klass), "chardev-"));
+        if (CHARDEV_CLASS(klass)->internal) {
             continue;
         }
+        backend_list = qmp_prepend_backend(backend_list,
+                                           object_class_get_name(klass) + 8);
 
-        backend_list = qmp_prepend_backend(backend_list, c,
-                                           ChardevBackendKind_lookup[c->kind]);
-        if (c->alias) {
-            backend_list = qmp_prepend_backend(backend_list, c, c->alias);
-        }
     }
+    for (i = 0; i < ARRAY_SIZE(chardev_alias_table); i++) {
+        backend_list = qmp_prepend_backend(backend_list,
+                                           chardev_alias_table[i].alias);
+    }
+    g_slist_free(l);
 
     return backend_list;
 }
@@ -4664,15 +4674,12 @@ static void qmp_chardev_open_parallel(Chardev *chr,
     qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
 }
 
-static const CharDriver parallel_driver = {
-    .alias = "parport", .kind = CHARDEV_BACKEND_KIND_PARALLEL,
-    .parse = qemu_chr_parse_parallel
-};
-
 static void char_parallel_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_PARALLEL;
+    cc->parse = qemu_chr_parse_parallel;
     cc->open = qmp_chardev_open_parallel;
 #if defined(__linux__)
     cc->chr_write = null_chr_write;
@@ -4710,15 +4717,12 @@ static const TypeInfo char_parallel_type_info = {
 
 #endif /* WIN32 */
 
-static const CharDriver file_driver = {
-    .kind = CHARDEV_BACKEND_KIND_FILE,
-    .parse = qemu_chr_parse_file_out
-};
-
 static void char_file_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_FILE;
+    cc->parse = qemu_chr_parse_file_out;
     cc->open = qmp_chardev_open_file;
 }
 
@@ -4734,15 +4738,12 @@ static const TypeInfo char_file_type_info = {
 
 #ifdef HAVE_CHARDEV_SERIAL
 
-static const CharDriver serial_driver = {
-    .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
-    .parse = qemu_chr_parse_serial
-};
-
 static void char_serial_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_SERIAL;
+    cc->parse = qemu_chr_parse_serial;
     cc->open = qmp_chardev_open_serial;
 #ifndef _WIN32
     cc->chr_ioctl = tty_serial_ioctl;
@@ -4898,15 +4899,12 @@ error:
     }
 }
 
-static const CharDriver socket_driver = {
-    .kind = CHARDEV_BACKEND_KIND_SOCKET,
-    .parse = qemu_chr_parse_socket
-};
-
 static void char_socket_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_SOCKET;
+    cc->parse = qemu_chr_parse_socket;
     cc->open = qmp_chardev_open_socket;
     cc->chr_wait_connected = tcp_chr_wait_connected;
     cc->chr_write = tcp_chr_write;
@@ -4955,15 +4953,12 @@ static void qmp_chardev_open_udp(Chardev *chr,
     *be_opened = false;
 }
 
-static const CharDriver udp_driver = {
-    .kind = CHARDEV_BACKEND_KIND_UDP,
-    .parse = qemu_chr_parse_udp
-};
-
 static void char_udp_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_UDP;
+    cc->parse = qemu_chr_parse_udp;
     cc->open = qmp_chardev_open_udp;
     cc->chr_write = udp_chr_write;
     cc->chr_update_read_handler = udp_chr_update_read_handler;
@@ -4989,31 +4984,6 @@ void qemu_chr_set_feature(Chardev *chr,
     return set_bit(feature, chr->features);
 }
 
-static const ChardevClass *char_get_class(const char *driver, Error **errp)
-{
-    ObjectClass *oc;
-    const ChardevClass *cc;
-    char *typename = g_strdup_printf("chardev-%s", driver);
-
-    oc = object_class_by_name(typename);
-    g_free(typename);
-
-    if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
-        error_setg(errp, "'%s' is not a valid char driver name", driver);
-        return NULL;
-    }
-
-    if (object_class_is_abstract(oc)) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
-                   "abstract device type");
-        return NULL;
-    }
-
-    cc = CHARDEV_CLASS(oc);
-
-    return cc;
-}
-
 Chardev *qemu_chardev_new(const char *id, const char *typename,
                           ChardevBackend *backend, Error **errp)
 {
@@ -5109,45 +5079,34 @@ void qemu_chr_cleanup(void)
 
 static void register_types(void)
 {
-    static const struct {
-        const CharDriver *driver;
-        const TypeInfo *type;
-    } chardevs[] = {
-        { &null_driver, &char_null_type_info },
-        { &socket_driver, &char_socket_type_info },
-        { &udp_driver, &char_udp_type_info },
-        { &ringbuf_driver, &char_ringbuf_type_info },
-        { &file_driver, &char_file_type_info },
-        { &stdio_driver, &char_stdio_type_info },
+    type_register_static(&char_type_info);
+#ifndef _WIN32
+    type_register_static(&char_fd_type_info);
+#else
+    type_register_static(&char_win_type_info);
+    type_register_static(&char_win_stdio_type_info);
+#endif
+    type_register_static(&char_null_type_info);
+    type_register_static(&char_socket_type_info);
+    type_register_static(&char_udp_type_info);
+    type_register_static(&char_ringbuf_type_info);
+    type_register_static(&char_file_type_info);
+    type_register_static(&char_stdio_type_info);
 #ifdef HAVE_CHARDEV_SERIAL
-        { &serial_driver, &char_serial_type_info },
+    type_register_static(&char_serial_type_info);
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
-        { &parallel_driver, &char_parallel_type_info },
+    type_register_static(&char_parallel_type_info);
 #endif
 #ifdef HAVE_CHARDEV_PTY
-        { &pty_driver, &char_pty_type_info },
+    type_register_static(&char_pty_type_info);
 #endif
 #ifdef _WIN32
-        { &console_driver, &char_console_type_info },
-#endif
-        { &pipe_driver, &char_pipe_type_info },
-        { &mux_driver, &char_mux_type_info },
-        { &memory_driver, &char_memory_type_info }
-    };
-    int i;
-
-    type_register_static(&char_type_info);
-#ifndef _WIN32
-    type_register_static(&char_fd_type_info);
-#else
-    type_register_static(&char_win_type_info);
-    type_register_static(&char_win_stdio_type_info);
+    type_register_static(&char_console_type_info);
 #endif
-    for (i = 0; i < ARRAY_SIZE(chardevs); i++) {
-        type_register_static(chardevs[i].type);
-        register_char_driver(chardevs[i].driver);
-    }
+    type_register_static(&char_pipe_type_info);
+    type_register_static(&char_mux_type_info);
+    type_register_static(&char_memory_type_info);
 
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index af30143720..298a951681 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -379,6 +379,8 @@ static void char_spicevmc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_SPICEVMC;
+    cc->parse = qemu_chr_parse_spice_vmc;
     cc->open = qemu_chr_open_spice_vmc;
     cc->chr_set_fe_open = spice_vmc_set_fe_open;
 }
@@ -393,6 +395,8 @@ static void char_spiceport_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_SPICEPORT;
+    cc->parse = qemu_chr_parse_spice_port;
     cc->open = qemu_chr_open_spice_port;
     cc->chr_set_fe_open = spice_port_set_fe_open;
 }
@@ -405,17 +409,6 @@ static const TypeInfo char_spiceport_type_info = {
 
 static void register_types(void)
 {
-    static const CharDriver vmc_driver = {
-        .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
-        .parse = qemu_chr_parse_spice_vmc
-    };
-    static const CharDriver port_driver = {
-        .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
-        .parse = qemu_chr_parse_spice_port
-    };
-    register_char_driver(&vmc_driver);
-    register_char_driver(&port_driver);
-
     type_register_static(&char_spice_type_info);
     type_register_static(&char_spicevmc_type_info);
     type_register_static(&char_spiceport_type_info);
diff --git a/ui/console.c b/ui/console.c
index 5fc29e36f6..712fa1aec1 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2048,8 +2048,6 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
     qemu_chr_be_generic_open(chr);
 }
 
-static const CharDriver vc_driver;
-
 static void vc_open(Chardev *chr,
                     ChardevBackend *backend,
                     bool *be_opened,
@@ -2178,6 +2176,8 @@ static void char_vc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_VC;
+    cc->parse = qemu_chr_parse_vc;
     cc->open = vc_open;
     cc->chr_write = vc_chr_write;
     cc->chr_set_echo = vc_chr_set_echo;
@@ -2195,15 +2195,9 @@ void qemu_console_early_init(void)
     /* set the default vc driver */
     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
         type_register(&char_vc_type_info);
-        register_char_driver(&vc_driver);
     }
 }
 
-static const CharDriver vc_driver = {
-    .kind = CHARDEV_BACKEND_KIND_VC,
-    .parse = qemu_chr_parse_vc
-};
-
 static void register_types(void)
 {
     type_register_static(&qemu_console_info);
diff --git a/ui/gtk.c b/ui/gtk.c
index 03573a3ff3..aa3412d09c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1705,8 +1705,6 @@ static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
 
 static int nb_vcs;
 static Chardev *vcs[MAX_VCS];
-static const CharDriver gd_vc_driver;
-
 static void gd_vc_open(Chardev *chr,
                        ChardevBackend *backend,
                        bool *be_opened,
@@ -1729,6 +1727,8 @@ static void char_gd_vc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->kind = CHARDEV_BACKEND_KIND_VC;
+    cc->parse = qemu_chr_parse_vc;
     cc->open = gd_vc_open;
     cc->chr_write = gd_vc_chr_write;
     cc->chr_set_echo = gd_vc_chr_set_echo;
@@ -1741,11 +1741,6 @@ static const TypeInfo char_gd_vc_type_info = {
     .class_init = char_gd_vc_class_init,
 };
 
-static const CharDriver gd_vc_driver = {
-    .kind = CHARDEV_BACKEND_KIND_VC,
-    .parse = qemu_chr_parse_vc
-};
-
 static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
                          gpointer user_data)
 {
@@ -2334,6 +2329,5 @@ void early_gtk_display_init(int opengl)
 
 #if defined(CONFIG_VTE)
     type_register(&char_gd_vc_type_info);
-    register_char_driver(&gd_vc_driver);
 #endif
 }
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 15ae33d8fd..203e8e84e3 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -88,8 +88,6 @@ typedef struct CharBackend {
     int fe_open;
 } CharBackend;
 
-typedef struct CharDriver CharDriver;
-
 struct Chardev {
     Object parent_obj;
 
@@ -474,6 +472,8 @@ typedef struct ChardevClass {
     ObjectClass parent_class;
 
     bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
+    ChardevBackendKind kind;
+    void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
 
     void (*open)(Chardev *chr, ChardevBackend *backend,
                  bool *be_opened, Error **errp);
@@ -493,17 +493,9 @@ typedef struct ChardevClass {
     void (*chr_set_fe_open)(Chardev *chr, int fe_open);
 } ChardevClass;
 
-struct CharDriver {
-    const char *alias;
-    ChardevBackendKind kind;
-    void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
-};
-
 Chardev *qemu_chardev_new(const char *id, const char *typename,
                           ChardevBackend *backend, Error **errp);
 
-void register_char_driver(const CharDriver *driver);
-
 extern int term_escape_char;
 
 /* console.c */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 32/54] char: remove class kind field
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (30 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 31/54] char: get rid of CharDriver Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 33/54] char: move to chardev/ Marc-André Lureau
                   ` (23 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

The class kind is only necessary to lookup the chardev name in
qmp_chardev_add() after calling qemu_chr_new_from_opts(). However,
qemu_chr_new_from_opts() can be changed to use a non-qmp function using
the chardev class typename. Introduce qemu_chardev_add() to be called
from qemu_chr_new_from_opts() and remove the class chardev kind field.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/baum.c       |  1 -
 backends/msmouse.c    |  1 -
 backends/testdev.c    |  1 -
 qemu-char.c           | 96 ++++++++++++++++++++++-----------------------------
 spice-qemu-char.c     |  2 --
 ui/console.c          |  1 -
 ui/gtk.c              |  1 -
 include/sysemu/char.h |  1 -
 8 files changed, 42 insertions(+), 62 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index e4c4c53486..64dbeb1a5f 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -671,7 +671,6 @@ static void char_braille_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_BRAILLE;
     cc->open = baum_chr_open;
     cc->chr_write = baum_chr_write;
     cc->chr_accept_input = baum_chr_accept_input;
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 28689b3e29..d2c3162f1e 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -169,7 +169,6 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_MSMOUSE;
     cc->open = msmouse_chr_open;
     cc->chr_write = msmouse_chr_write;
     cc->chr_accept_input = msmouse_chr_accept_input;
diff --git a/backends/testdev.c b/backends/testdev.c
index 243454aaa3..7df9248a13 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -111,7 +111,6 @@ static void char_testdev_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_TESTDEV;
     cc->chr_write = testdev_chr_write;
 }
 
diff --git a/qemu-char.c b/qemu-char.c
index 9a4028059e..4708b85c2e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -566,7 +566,6 @@ static void char_null_class_init(ObjectClass *oc, void *data)
 
     cc->open = null_chr_open;
     cc->chr_write = null_chr_write;
-    cc->kind = CHARDEV_BACKEND_KIND_NULL;
 }
 
 static const TypeInfo char_null_type_info = {
@@ -1703,7 +1702,6 @@ static void char_pty_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_PTY;
     cc->open = char_pty_open;
     cc->chr_write = char_pty_chr_write;
     cc->chr_update_read_handler = pty_chr_update_read_handler;
@@ -2453,7 +2451,6 @@ static void char_console_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_CONSOLE;
     cc->open = qemu_chr_open_win_con;
 }
 
@@ -3832,7 +3829,6 @@ static void char_stdio_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_STDIO;
     cc->parse = qemu_chr_parse_stdio;
     cc->open = qemu_chr_open_stdio;
 #ifdef _WIN32
@@ -3907,7 +3903,6 @@ static void char_pipe_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_PIPE;
     cc->parse = qemu_chr_parse_pipe;
     cc->open = qemu_chr_open_pipe;
 }
@@ -3942,7 +3937,6 @@ static void char_ringbuf_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_RINGBUF;
     cc->parse = qemu_chr_parse_ringbuf;
     cc->open = qemu_chr_open_ringbuf;
     cc->chr_write = ringbuf_chr_write;
@@ -3957,17 +3951,9 @@ static const TypeInfo char_ringbuf_type_info = {
 };
 
 /* Bug-compatibility: */
-static void char_memory_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->kind = CHARDEV_BACKEND_KIND_MEMORY;
-}
-
 static const TypeInfo char_memory_type_info = {
     .name = TYPE_CHARDEV_MEMORY,
     .parent = TYPE_CHARDEV_RINGBUF,
-    .class_init = char_memory_class_init,
 };
 
 static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
@@ -3989,7 +3975,6 @@ static void char_mux_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_MUX;
     cc->parse = qemu_chr_parse_mux;
     cc->open = qemu_chr_open_mux;
     cc->chr_write = mux_chr_write;
@@ -4161,6 +4146,26 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
     return cc;
 }
 
+static Chardev *qemu_chardev_add(const char *id, const char *typename,
+                                 ChardevBackend *backend, Error **errp)
+{
+    Chardev *chr;
+
+    chr = qemu_chr_find(id);
+    if (chr) {
+        error_setg(errp, "Chardev '%s' already exists", id);
+        return NULL;
+    }
+
+    chr = qemu_chardev_new(id, typename, backend, errp);
+    if (!chr) {
+        return NULL;
+    }
+
+    QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+    return chr;
+}
+
 static const struct ChardevAlias {
     const char *typename;
     const char *alias;
@@ -4180,8 +4185,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
     const ChardevClass *cc;
     Chardev *chr;
     int i;
-    ChardevReturn *ret = NULL;
-    ChardevBackend *backend;
+    ChardevBackend *backend = NULL;
     const char *id = qemu_opts_id(opts);
     const char *bname = qemu_opt_get(opts, "backend");
     char *bid = NULL;
@@ -4189,7 +4193,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
     if (bname == NULL) {
         error_setg(errp, "chardev: \"%s\" missing backend",
                    qemu_opts_id(opts));
-        goto err;
+        return NULL;
     }
 
     if (is_help_option(bname)) {
@@ -4208,7 +4212,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
 
     if (id == NULL) {
         error_setg(errp, "chardev: no id specified");
-        goto err;
+        return NULL;
     }
 
     for (i = 0; i < ARRAY_SIZE(chardev_alias_table); i++) {
@@ -4220,22 +4224,22 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
 
     cc = char_get_class(bname, errp);
     if (cc == NULL) {
-        goto err;
+        return NULL;
     }
 
     backend = g_new0(ChardevBackend, 1);
+    backend->type = CHARDEV_BACKEND_KIND_NULL;
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
         bid = g_strdup_printf("%s-base", id);
     }
 
     chr = NULL;
-    backend->type = cc->kind;
     if (cc->parse) {
         cc->parse(opts, backend, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
-            goto qapi_out;
+            goto out;
         }
     } else {
         ChardevCommon *ccom = g_new0(ChardevCommon, 1);
@@ -4243,37 +4247,33 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
         backend->u.null.data = ccom; /* Any ChardevCommon member would work */
     }
 
-    ret = qmp_chardev_add(bid ? bid : id, backend, errp);
-    if (!ret) {
-        goto qapi_out;
+    chr = qemu_chardev_add(bid ? bid : id,
+                           object_class_get_name(OBJECT_CLASS(cc)),
+                           backend, errp);
+    if (chr == NULL) {
+        goto out;
     }
 
     if (bid) {
+        Chardev *mux;
         qapi_free_ChardevBackend(backend);
-        qapi_free_ChardevReturn(ret);
         backend = g_new0(ChardevBackend, 1);
-        backend->u.mux.data = g_new0(ChardevMux, 1);
         backend->type = CHARDEV_BACKEND_KIND_MUX;
+        backend->u.mux.data = g_new0(ChardevMux, 1);
         backend->u.mux.data->chardev = g_strdup(bid);
-        ret = qmp_chardev_add(id, backend, errp);
-        if (!ret) {
-            chr = qemu_chr_find(bid);
+        mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp);
+        if (mux == NULL) {
             qemu_chr_delete(chr);
             chr = NULL;
-            goto qapi_out;
+            goto out;
         }
+        chr = mux;
     }
 
-    chr = qemu_chr_find(id);
-
-qapi_out:
+out:
     qapi_free_ChardevBackend(backend);
-    qapi_free_ChardevReturn(ret);
     g_free(bid);
     return chr;
-
-err:
-    return NULL;
 }
 
 Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
@@ -4678,7 +4678,6 @@ static void char_parallel_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_PARALLEL;
     cc->parse = qemu_chr_parse_parallel;
     cc->open = qmp_chardev_open_parallel;
 #if defined(__linux__)
@@ -4721,7 +4720,6 @@ static void char_file_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_FILE;
     cc->parse = qemu_chr_parse_file_out;
     cc->open = qmp_chardev_open_file;
 }
@@ -4742,7 +4740,6 @@ static void char_serial_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_SERIAL;
     cc->parse = qemu_chr_parse_serial;
     cc->open = qmp_chardev_open_serial;
 #ifndef _WIN32
@@ -4903,7 +4900,6 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_SOCKET;
     cc->parse = qemu_chr_parse_socket;
     cc->open = qmp_chardev_open_socket;
     cc->chr_wait_connected = tcp_chr_wait_connected;
@@ -4957,7 +4953,6 @@ static void char_udp_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_UDP;
     cc->parse = qemu_chr_parse_udp;
     cc->open = qmp_chardev_open_udp;
     cc->chr_write = udp_chr_write;
@@ -5016,24 +5011,18 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
-    const ChardevClass *cc;
     ChardevReturn *ret;
+    const ChardevClass *cc;
     Chardev *chr;
 
-    chr = qemu_chr_find(id);
-    if (chr) {
-        error_setg(errp, "Chardev '%s' already exists", id);
-        return NULL;
-    }
-
     cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
-    if (!cc) {
+    if (cc == NULL) {
         return NULL;
     }
 
-    chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
+    chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)),
                            backend, errp);
-    if (!chr) {
+    if (chr == NULL) {
         return NULL;
     }
 
@@ -5043,7 +5032,6 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         ret->has_pty = true;
     }
 
-    QTAILQ_INSERT_TAIL(&chardevs, chr, next);
     return ret;
 }
 
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 298a951681..dbc81ba4f6 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -379,7 +379,6 @@ static void char_spicevmc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_SPICEVMC;
     cc->parse = qemu_chr_parse_spice_vmc;
     cc->open = qemu_chr_open_spice_vmc;
     cc->chr_set_fe_open = spice_vmc_set_fe_open;
@@ -395,7 +394,6 @@ static void char_spiceport_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_SPICEPORT;
     cc->parse = qemu_chr_parse_spice_port;
     cc->open = qemu_chr_open_spice_port;
     cc->chr_set_fe_open = spice_port_set_fe_open;
diff --git a/ui/console.c b/ui/console.c
index 712fa1aec1..1b66868a08 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2176,7 +2176,6 @@ static void char_vc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_VC;
     cc->parse = qemu_chr_parse_vc;
     cc->open = vc_open;
     cc->chr_write = vc_chr_write;
diff --git a/ui/gtk.c b/ui/gtk.c
index aa3412d09c..8aa8edbf40 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1727,7 +1727,6 @@ static void char_gd_vc_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
-    cc->kind = CHARDEV_BACKEND_KIND_VC;
     cc->parse = qemu_chr_parse_vc;
     cc->open = gd_vc_open;
     cc->chr_write = gd_vc_chr_write;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 203e8e84e3..297add973c 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -472,7 +472,6 @@ typedef struct ChardevClass {
     ObjectClass parent_class;
 
     bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
-    ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
 
     void (*open)(Chardev *chr, ChardevBackend *backend,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 33/54] char: move to chardev/
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (31 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 32/54] char: remove class kind field Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y Marc-André Lureau
                   ` (22 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

The following commits will split char.c in several files. Let's put them
in a subdirectory.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qemu-char.c => chardev/char.c | 0
 Makefile.objs                 | 2 +-
 chardev/Makefile.objs         | 1 +
 tests/Makefile.include        | 6 +++---
 MAINTAINERS                   | 2 +-
 5 files changed, 6 insertions(+), 5 deletions(-)
 rename qemu-char.c => chardev/char.c (100%)
 create mode 100644 chardev/Makefile.objs

diff --git a/qemu-char.c b/chardev/char.c
similarity index 100%
rename from qemu-char.c
rename to chardev/char.c
diff --git a/Makefile.objs b/Makefile.objs
index 06f74b8b99..6cf903baa1 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -51,7 +51,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
 common-obj-$(CONFIG_LINUX) += fsdev/
 
 common-obj-y += migration/
-common-obj-y += qemu-char.o #aio.o
+common-obj-y += chardev/ #aio.o
 common-obj-y += page_cache.o
 
 common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
new file mode 100644
index 0000000000..3fc5539518
--- /dev/null
+++ b/chardev/Makefile.objs
@@ -0,0 +1 @@
+common-obj-y += char.o
diff --git a/tests/Makefile.include b/tests/Makefile.include
index e98d3b6bb3..ca57fe61d6 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -9,7 +9,7 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
 check-unit-y = tests/check-qdict$(EXESUF)
 gcov-files-check-qdict-y = qobject/qdict.c
 check-unit-y += tests/test-char$(EXESUF)
-gcov-files-check-qdict-y = qemu-char.c
+gcov-files-check-qdict-y = chardev/char.c
 check-unit-y += tests/check-qfloat$(EXESUF)
 gcov-files-check-qfloat-y = qobject/qfloat.c
 check-unit-y += tests/check-qint$(EXESUF)
@@ -488,7 +488,7 @@ tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
 tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
 tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
 
-tests/test-char$(EXESUF): tests/test-char.o qemu-char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
+tests/test-char$(EXESUF): tests/test-char.o chardev/char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
 tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
 tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
 tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
@@ -678,7 +678,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
 tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
 tests/postcopy-test$(EXESUF): tests/postcopy-test.o
-tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y)
+tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o chardev/char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y)
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
 tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4a605791fc..9e4817fd4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1175,7 +1175,7 @@ T: git git://github.com/jnsnow/qemu.git bitmaps
 Character device backends
 M: Paolo Bonzini <pbonzini@redhat.com>
 S: Maintained
-F: qemu-char.c
+F: chardev/
 F: backends/msmouse.c
 F: backends/testdev.c
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (32 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 33/54] char: move to chardev/ Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-13 11:10   ` Paolo Bonzini
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 35/54] char: make null_chr_write() the default method Marc-André Lureau
                   ` (21 subsequent siblings)
  55 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This will help to split char.c in several units without having to
reference them all everywhere.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile               | 3 ++-
 Makefile.objs          | 4 +++-
 Makefile.target        | 3 +++
 chardev/Makefile.objs  | 2 +-
 tests/Makefile.include | 4 ++--
 5 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index 474cc5e66a..318a3499ab 100644
--- a/Makefile
+++ b/Makefile
@@ -145,6 +145,7 @@ endif
 
 dummy := $(call unnest-vars,, \
                 stub-obj-y \
+                chardev-obj-y \
                 util-obj-y \
                 qga-obj-y \
                 ivshmem-client-obj-y \
@@ -220,7 +221,7 @@ subdir-dtc:dtc/libfdt dtc/tests
 dtc/%:
 	mkdir -p $@
 
-$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
+$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(chardev-obj-y) $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
 
 ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
 # Only keep -O and -g cflags
diff --git a/Makefile.objs b/Makefile.objs
index 6cf903baa1..ccd627d8bb 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -51,7 +51,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
 common-obj-$(CONFIG_LINUX) += fsdev/
 
 common-obj-y += migration/
-common-obj-y += chardev/ #aio.o
+common-obj-y += #aio.o
 common-obj-y += page_cache.o
 
 common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
@@ -79,6 +79,8 @@ common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
 
 common-obj-$(CONFIG_FDT) += device_tree.o
 
+chardev-obj-y = chardev/
+
 ######################################################################
 # qapi
 
diff --git a/Makefile.target b/Makefile.target
index 7a5080e94a..8799cd9972 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -170,12 +170,14 @@ all-obj-y := $(obj-y)
 target-obj-y :=
 block-obj-y :=
 common-obj-y :=
+chardev-obj-y :=
 include $(SRC_PATH)/Makefile.objs
 dummy := $(call unnest-vars,,target-obj-y)
 target-obj-y-save := $(target-obj-y)
 dummy := $(call unnest-vars,.., \
                block-obj-y \
                block-obj-m \
+               chardev-obj-y \
                crypto-obj-y \
                crypto-aes-obj-y \
                qom-obj-y \
@@ -184,6 +186,7 @@ dummy := $(call unnest-vars,.., \
                common-obj-m)
 target-obj-y := $(target-obj-y-save)
 all-obj-y += $(common-obj-y)
+all-obj-y += $(chardev-obj-y)
 all-obj-y += $(target-obj-y)
 all-obj-y += $(qom-obj-y)
 all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 3fc5539518..8bf131b461 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1 +1 @@
-common-obj-y += char.o
+chardev-obj-y += char.o
diff --git a/tests/Makefile.include b/tests/Makefile.include
index ca57fe61d6..c719c7a7a4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -488,7 +488,7 @@ tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
 tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
 tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
 
-tests/test-char$(EXESUF): tests/test-char.o chardev/char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
+tests/test-char$(EXESUF): tests/test-char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y) $(chardev-obj-y)
 tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
 tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
 tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
@@ -678,7 +678,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
 tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
 tests/postcopy-test$(EXESUF): tests/postcopy-test.o
-tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o chardev/char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y)
+tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) $(chardev-obj-y)
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
 tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 35/54] char: make null_chr_write() the default method
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (33 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 36/54] char: move null chardev to its own file Marc-André Lureau
                   ` (20 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

All chardev must implement chr_write(), but parallel and null chardev
both use null_chr_write(). Move it to the base class, so we don't need
to export the function when splitting the chardev in respective files.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index 4708b85c2e..caed775889 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -522,6 +522,18 @@ static void char_init(Object *obj)
     qemu_mutex_init(&chr->chr_write_lock);
 }
 
+static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    return len;
+}
+
+static void char_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_write = null_chr_write;
+}
+
 static void char_finalize(Object *obj)
 {
     Chardev *chr = CHARDEV(obj);
@@ -545,13 +557,9 @@ static const TypeInfo char_type_info = {
     .instance_finalize = char_finalize,
     .abstract = true,
     .class_size = sizeof(ChardevClass),
+    .class_init = char_class_init,
 };
 
-static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    return len;
-}
-
 static void null_chr_open(Chardev *chr,
                           ChardevBackend *backend,
                           bool *be_opened,
@@ -565,7 +573,6 @@ static void char_null_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->open = null_chr_open;
-    cc->chr_write = null_chr_write;
 }
 
 static const TypeInfo char_null_type_info = {
@@ -4681,10 +4688,8 @@ static void char_parallel_class_init(ObjectClass *oc, void *data)
     cc->parse = qemu_chr_parse_parallel;
     cc->open = qmp_chardev_open_parallel;
 #if defined(__linux__)
-    cc->chr_write = null_chr_write;
     cc->chr_ioctl = pp_ioctl;
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-    cc->chr_write = null_chr_write;
     cc->chr_ioctl = pp_ioctl;
 #endif
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 36/54] char: move null chardev to its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (34 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 35/54] char: make null_chr_write() the default method Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 37/54] char: move mux " Marc-André Lureau
                   ` (19 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-null.c   | 31 +++++++++++++++++++++++++++++++
 chardev/char.c        | 23 -----------------------
 chardev/Makefile.objs |  1 +
 3 files changed, 32 insertions(+), 23 deletions(-)
 create mode 100644 chardev/char-null.c

diff --git a/chardev/char-null.c b/chardev/char-null.c
new file mode 100644
index 0000000000..18a49f5802
--- /dev/null
+++ b/chardev/char-null.c
@@ -0,0 +1,31 @@
+#include "qemu/osdep.h"
+#include "sysemu/char.h"
+
+static void null_chr_open(Chardev *chr,
+                          ChardevBackend *backend,
+                          bool *be_opened,
+                          Error **errp)
+{
+    *be_opened = false;
+}
+
+static void char_null_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = null_chr_open;
+}
+
+static const TypeInfo char_null_type_info = {
+    .name = TYPE_CHARDEV_NULL,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(Chardev),
+    .class_init = char_null_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_null_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index caed775889..d31ba110ca 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -560,28 +560,6 @@ static const TypeInfo char_type_info = {
     .class_init = char_class_init,
 };
 
-static void null_chr_open(Chardev *chr,
-                          ChardevBackend *backend,
-                          bool *be_opened,
-                          Error **errp)
-{
-    *be_opened = false;
-}
-
-static void char_null_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->open = null_chr_open;
-}
-
-static const TypeInfo char_null_type_info = {
-    .name = TYPE_CHARDEV_NULL,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(Chardev),
-    .class_init = char_null_class_init,
-};
-
 /* MUX driver for serial I/O splitting */
 #define MAX_MUX 4
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
@@ -5079,7 +5057,6 @@ static void register_types(void)
     type_register_static(&char_win_type_info);
     type_register_static(&char_win_stdio_type_info);
 #endif
-    type_register_static(&char_null_type_info);
     type_register_static(&char_socket_type_info);
     type_register_static(&char_udp_type_info);
     type_register_static(&char_ringbuf_type_info);
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 8bf131b461..be7ff800c3 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1 +1,2 @@
 chardev-obj-y += char.o
+chardev-obj-y += char-null.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 37/54] char: move mux to its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (35 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 36/54] char: move null chardev to its own file Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 38/54] char: move ringbuf/memory " Marc-André Lureau
                   ` (18 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

A mechanical move, except that qemu_chr_write_all() needs to be declared
in char.h header to be used from chardev unit files.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-mux.c    | 332 +++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 348 +-------------------------------------------------
 chardev/Makefile.objs |   1 +
 chardev/char-mux.h    |  40 ++++++
 include/sysemu/char.h |   3 +-
 5 files changed, 377 insertions(+), 347 deletions(-)
 create mode 100644 chardev/char-mux.c
 create mode 100644 chardev/char-mux.h

diff --git a/chardev/char-mux.c b/chardev/char-mux.c
new file mode 100644
index 0000000000..ca7fb75841
--- /dev/null
+++ b/chardev/char-mux.c
@@ -0,0 +1,332 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/char.h"
+#include "sysemu/block-backend.h"
+#include "char-mux.h"
+
+/* MUX driver for serial I/O splitting */
+
+/* Called with chr_write_lock held.  */
+static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    MuxChardev *d = MUX_CHARDEV(chr);
+    int ret;
+    if (!d->timestamps) {
+        ret = qemu_chr_fe_write(&d->chr, buf, len);
+    } else {
+        int i;
+
+        ret = 0;
+        for (i = 0; i < len; i++) {
+            if (d->linestart) {
+                char buf1[64];
+                int64_t ti;
+                int secs;
+
+                ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+                if (d->timestamps_start == -1) {
+                    d->timestamps_start = ti;
+                }
+                ti -= d->timestamps_start;
+                secs = ti / 1000;
+                snprintf(buf1, sizeof(buf1),
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)(ti % 1000));
+                /* XXX this blocks entire thread. Rewrite to use
+                 * qemu_chr_fe_write and background I/O callbacks */
+                qemu_chr_fe_write_all(&d->chr,
+                                      (uint8_t *)buf1, strlen(buf1));
+                d->linestart = 0;
+            }
+            ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
+            if (buf[i] == '\n') {
+                d->linestart = 1;
+            }
+        }
+    }
+    return ret;
+}
+
+static const char * const mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% t    toggle console timestamps\n\r",
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(Chardev *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        snprintf(cbuf, sizeof(cbuf), "\n\r");
+        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
+    } else {
+        snprintf(cbuf, sizeof(cbuf),
+                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
+                 term_escape_char);
+    }
+    /* XXX this blocks entire thread. Rewrite to use
+     * qemu_chr_fe_write and background I/O callbacks */
+    qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j = 0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%') {
+                qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
+            } else {
+                qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
+            }
+        }
+    }
+}
+
+void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
+{
+    CharBackend *be = d->backends[mux_nr];
+
+    if (be && be->chr_event) {
+        be->chr_event(be->opaque, event);
+    }
+}
+
+static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char) {
+            goto send_char;
+        }
+        switch (ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            {
+                 const char *term =  "QEMU: Terminated\n\r";
+                 qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
+                 exit(0);
+                 break;
+            }
+        case 's':
+            blk_commit_all();
+            break;
+        case 'b':
+            qemu_chr_be_event(chr, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            assert(d->mux_cnt > 0); /* handler registered with first fe */
+            /* Switch to the next registered device */
+            mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
+            break;
+        case 't':
+            d->timestamps = !d->timestamps;
+            d->timestamps_start = -1;
+            d->linestart = 0;
+            break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static void mux_chr_accept_input(Chardev *chr)
+{
+    MuxChardev *d = MUX_CHARDEV(chr);
+    int m = d->focus;
+    CharBackend *be = d->backends[m];
+
+    while (be && d->prod[m] != d->cons[m] &&
+           be->chr_can_read && be->chr_can_read(be->opaque)) {
+        be->chr_read(be->opaque,
+                     &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
+    }
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    MuxChardev *d = MUX_CHARDEV(opaque);
+    int m = d->focus;
+    CharBackend *be = d->backends[m];
+
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
+        return 1;
+    }
+
+    if (be && be->chr_can_read) {
+        return be->chr_can_read(be->opaque);
+    }
+
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    Chardev *chr = CHARDEV(opaque);
+    MuxChardev *d = MUX_CHARDEV(opaque);
+    int m = d->focus;
+    CharBackend *be = d->backends[m];
+    int i;
+
+    mux_chr_accept_input(opaque);
+
+    for (i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i])) {
+            if (d->prod[m] == d->cons[m] &&
+                be && be->chr_can_read &&
+                be->chr_can_read(be->opaque)) {
+                be->chr_read(be->opaque, &buf[i], 1);
+            } else {
+                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
+            }
+        }
+}
+
+bool muxes_realized;
+
+static void mux_chr_event(void *opaque, int event)
+{
+    MuxChardev *d = MUX_CHARDEV(opaque);
+    int i;
+
+    if (!muxes_realized) {
+        return;
+    }
+
+    /* Send the event to all registered listeners */
+    for (i = 0; i < d->mux_cnt; i++) {
+        mux_chr_send_event(d, i, event);
+    }
+}
+
+static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
+{
+    MuxChardev *d = MUX_CHARDEV(s);
+    Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
+    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
+
+    if (!cc->chr_add_watch) {
+        return NULL;
+    }
+
+    return cc->chr_add_watch(chr, cond);
+}
+
+static void char_mux_finalize(Object *obj)
+{
+    MuxChardev *d = MUX_CHARDEV(obj);
+    int i;
+
+    for (i = 0; i < d->mux_cnt; i++) {
+        CharBackend *be = d->backends[i];
+        if (be) {
+            be->chr = NULL;
+        }
+    }
+    qemu_chr_fe_deinit(&d->chr);
+}
+
+void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
+{
+    MuxChardev *d = MUX_CHARDEV(chr);
+
+    /* Fix up the real driver with mux routines */
+    qemu_chr_fe_set_handlers(&d->chr,
+                             mux_chr_can_read,
+                             mux_chr_read,
+                             mux_chr_event,
+                             chr,
+                             context, true);
+}
+
+void mux_set_focus(MuxChardev *d, int focus)
+{
+    assert(focus >= 0);
+    assert(focus < d->mux_cnt);
+
+    if (d->focus != -1) {
+        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+    }
+
+    d->focus = focus;
+    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+}
+
+static void qemu_chr_open_mux(Chardev *chr,
+                              ChardevBackend *backend,
+                              bool *be_opened,
+                              Error **errp)
+{
+    ChardevMux *mux = backend->u.mux.data;
+    Chardev *drv;
+    MuxChardev *d = MUX_CHARDEV(chr);
+
+    drv = qemu_chr_find(mux->chardev);
+    if (drv == NULL) {
+        error_setg(errp, "mux: base chardev %s not found", mux->chardev);
+        return;
+    }
+
+    d->focus = -1;
+    /* only default to opened state if we've realized the initial
+     * set of muxes
+     */
+    *be_opened = muxes_realized;
+    qemu_chr_fe_init(&d->chr, drv, errp);
+}
+
+static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
+                               Error **errp)
+{
+    const char *chardev = qemu_opt_get(opts, "chardev");
+    ChardevMux *mux;
+
+    if (chardev == NULL) {
+        error_setg(errp, "chardev: mux: no chardev given");
+        return;
+    }
+    mux = backend->u.mux.data = g_new0(ChardevMux, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
+    mux->chardev = g_strdup(chardev);
+}
+
+static void char_mux_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_mux;
+    cc->open = qemu_chr_open_mux;
+    cc->chr_write = mux_chr_write;
+    cc->chr_accept_input = mux_chr_accept_input;
+    cc->chr_add_watch = mux_chr_add_watch;
+}
+
+static const TypeInfo char_mux_type_info = {
+    .name = TYPE_CHARDEV_MUX,
+    .parent = TYPE_CHARDEV,
+    .class_init = char_mux_class_init,
+    .instance_size = sizeof(MuxChardev),
+    .instance_finalize = char_mux_finalize,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_mux_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index d31ba110ca..3138bfcd19 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -85,12 +85,12 @@
 #include "qemu/sockets.h"
 #include "ui/qemu-spice.h"
 
+#include "char-mux.h"
+
 #define READ_BUF_LEN 4096
 #define READ_RETRIES 10
 #define TCP_MAX_FDS 16
 
-typedef struct MuxChardev MuxChardev;
-
 /***********************************************************/
 /* Socket address helpers */
 
@@ -284,7 +284,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
     return ret;
 }
 
-static int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len)
+int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len)
 {
     int offset;
     int res;
@@ -482,8 +482,6 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 }
 
 static void remove_fd_in_watch(Chardev *chr);
-static void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
-static void mux_set_focus(MuxChardev *d, int focus);
 
 static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
                            bool *be_opened, Error **errp)
@@ -560,235 +558,6 @@ static const TypeInfo char_type_info = {
     .class_init = char_class_init,
 };
 
-/* MUX driver for serial I/O splitting */
-#define MAX_MUX 4
-#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
-#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
-struct MuxChardev {
-    Chardev parent;
-    CharBackend *backends[MAX_MUX];
-    CharBackend chr;
-    int focus;
-    int mux_cnt;
-    int term_got_escape;
-    int max_size;
-    /* Intermediate input buffer allows to catch escape sequences even if the
-       currently active device is not accepting any input - but only until it
-       is full as well. */
-    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
-    int prod[MAX_MUX];
-    int cons[MAX_MUX];
-    int timestamps;
-
-    /* Protected by the Chardev chr_write_lock.  */
-    int linestart;
-    int64_t timestamps_start;
-};
-
-#define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX)
-
-/* Called with chr_write_lock held.  */
-static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    MuxChardev *d = MUX_CHARDEV(chr);
-    int ret;
-    if (!d->timestamps) {
-        ret = qemu_chr_fe_write(&d->chr, buf, len);
-    } else {
-        int i;
-
-        ret = 0;
-        for (i = 0; i < len; i++) {
-            if (d->linestart) {
-                char buf1[64];
-                int64_t ti;
-                int secs;
-
-                ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-                if (d->timestamps_start == -1)
-                    d->timestamps_start = ti;
-                ti -= d->timestamps_start;
-                secs = ti / 1000;
-                snprintf(buf1, sizeof(buf1),
-                         "[%02d:%02d:%02d.%03d] ",
-                         secs / 3600,
-                         (secs / 60) % 60,
-                         secs % 60,
-                         (int)(ti % 1000));
-                /* XXX this blocks entire thread. Rewrite to use
-                 * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(&d->chr,
-                                      (uint8_t *)buf1, strlen(buf1));
-                d->linestart = 0;
-            }
-            ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
-            if (buf[i] == '\n') {
-                d->linestart = 1;
-            }
-        }
-    }
-    return ret;
-}
-
-static const char * const mux_help[] = {
-    "% h    print this help\n\r",
-    "% x    exit emulator\n\r",
-    "% s    save disk data back to file (if -snapshot)\n\r",
-    "% t    toggle console timestamps\n\r",
-    "% b    send break (magic sysrq)\n\r",
-    "% c    switch between console and monitor\n\r",
-    "% %  sends %\n\r",
-    NULL
-};
-
-int term_escape_char = 0x01; /* ctrl-a is used for escape */
-static void mux_print_help(Chardev *chr)
-{
-    int i, j;
-    char ebuf[15] = "Escape-Char";
-    char cbuf[50] = "\n\r";
-
-    if (term_escape_char > 0 && term_escape_char < 26) {
-        snprintf(cbuf, sizeof(cbuf), "\n\r");
-        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
-    } else {
-        snprintf(cbuf, sizeof(cbuf),
-                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
-                 term_escape_char);
-    }
-    /* XXX this blocks entire thread. Rewrite to use
-     * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
-    for (i = 0; mux_help[i] != NULL; i++) {
-        for (j=0; mux_help[i][j] != '\0'; j++) {
-            if (mux_help[i][j] == '%')
-                qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
-            else
-                qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
-        }
-    }
-}
-
-static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
-{
-    CharBackend *be = d->backends[mux_nr];
-
-    if (be && be->chr_event) {
-        be->chr_event(be->opaque, event);
-    }
-}
-
-static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
-{
-    if (d->term_got_escape) {
-        d->term_got_escape = 0;
-        if (ch == term_escape_char)
-            goto send_char;
-        switch(ch) {
-        case '?':
-        case 'h':
-            mux_print_help(chr);
-            break;
-        case 'x':
-            {
-                 const char *term =  "QEMU: Terminated\n\r";
-                 qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
-                 exit(0);
-                 break;
-            }
-        case 's':
-            blk_commit_all();
-            break;
-        case 'b':
-            qemu_chr_be_event(chr, CHR_EVENT_BREAK);
-            break;
-        case 'c':
-            assert(d->mux_cnt > 0); /* handler registered with first fe */
-            /* Switch to the next registered device */
-            mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
-            break;
-        case 't':
-            d->timestamps = !d->timestamps;
-            d->timestamps_start = -1;
-            d->linestart = 0;
-            break;
-        }
-    } else if (ch == term_escape_char) {
-        d->term_got_escape = 1;
-    } else {
-    send_char:
-        return 1;
-    }
-    return 0;
-}
-
-static void mux_chr_accept_input(Chardev *chr)
-{
-    MuxChardev *d = MUX_CHARDEV(chr);
-    int m = d->focus;
-    CharBackend *be = d->backends[m];
-
-    while (be && d->prod[m] != d->cons[m] &&
-           be->chr_can_read && be->chr_can_read(be->opaque)) {
-        be->chr_read(be->opaque,
-                     &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
-    }
-}
-
-static int mux_chr_can_read(void *opaque)
-{
-    MuxChardev *d = MUX_CHARDEV(opaque);
-    int m = d->focus;
-    CharBackend *be = d->backends[m];
-
-    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
-        return 1;
-    }
-
-    if (be && be->chr_can_read) {
-        return be->chr_can_read(be->opaque);
-    }
-
-    return 0;
-}
-
-static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
-{
-    Chardev *chr = CHARDEV(opaque);
-    MuxChardev *d = MUX_CHARDEV(opaque);
-    int m = d->focus;
-    CharBackend *be = d->backends[m];
-    int i;
-
-    mux_chr_accept_input(opaque);
-
-    for (i = 0; i < size; i++)
-        if (mux_proc_byte(chr, d, buf[i])) {
-            if (d->prod[m] == d->cons[m] &&
-                be && be->chr_can_read &&
-                be->chr_can_read(be->opaque))
-                be->chr_read(be->opaque, &buf[i], 1);
-            else
-                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
-        }
-}
-
-static bool muxes_realized;
-
-static void mux_chr_event(void *opaque, int event)
-{
-    MuxChardev *d = MUX_CHARDEV(opaque);
-    int i;
-
-    if (!muxes_realized) {
-        return;
-    }
-
-    /* Send the event to all registered listeners */
-    for (i = 0; i < d->mux_cnt; i++)
-        mux_chr_send_event(d, i, event);
-}
-
 /**
  * Called after processing of default and command-line-specified
  * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
@@ -827,82 +596,6 @@ static Notifier muxes_realize_notify = {
     .notify = muxes_realize_done,
 };
 
-static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
-{
-    MuxChardev *d = MUX_CHARDEV(s);
-    Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
-    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
-
-    if (!cc->chr_add_watch) {
-        return NULL;
-    }
-
-    return cc->chr_add_watch(chr, cond);
-}
-
-static void char_mux_finalize(Object *obj)
-{
-    MuxChardev *d = MUX_CHARDEV(obj);
-    int i;
-
-    for (i = 0; i < d->mux_cnt; i++) {
-        CharBackend *be = d->backends[i];
-        if (be) {
-            be->chr = NULL;
-        }
-    }
-    qemu_chr_fe_deinit(&d->chr);
-}
-
-static void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
-{
-    MuxChardev *d = MUX_CHARDEV(chr);
-
-    /* Fix up the real driver with mux routines */
-    qemu_chr_fe_set_handlers(&d->chr,
-                             mux_chr_can_read,
-                             mux_chr_read,
-                             mux_chr_event,
-                             chr,
-                             context, true);
-}
-
-static void mux_set_focus(MuxChardev *d, int focus)
-{
-    assert(focus >= 0);
-    assert(focus < d->mux_cnt);
-
-    if (d->focus != -1) {
-        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
-    }
-
-    d->focus = focus;
-    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
-}
-
-static void qemu_chr_open_mux(Chardev *chr,
-                              ChardevBackend *backend,
-                              bool *be_opened,
-                              Error **errp)
-{
-    ChardevMux *mux = backend->u.mux.data;
-    Chardev *drv;
-    MuxChardev *d = MUX_CHARDEV(chr);
-
-    drv = qemu_chr_find(mux->chardev);
-    if (drv == NULL) {
-        error_setg(errp, "mux: base chardev %s not found", mux->chardev);
-        return;
-    }
-
-    d->focus = -1;
-    /* only default to opened state if we've realized the initial
-     * set of muxes
-     */
-    *be_opened = muxes_realized;
-    qemu_chr_fe_init(&d->chr, drv, errp);
-}
-
 Chardev *qemu_chr_fe_get_driver(CharBackend *be)
 {
     return be->chr;
@@ -3941,40 +3634,6 @@ static const TypeInfo char_memory_type_info = {
     .parent = TYPE_CHARDEV_RINGBUF,
 };
 
-static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
-                               Error **errp)
-{
-    const char *chardev = qemu_opt_get(opts, "chardev");
-    ChardevMux *mux;
-
-    if (chardev == NULL) {
-        error_setg(errp, "chardev: mux: no chardev given");
-        return;
-    }
-    mux = backend->u.mux.data = g_new0(ChardevMux, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
-    mux->chardev = g_strdup(chardev);
-}
-
-static void char_mux_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_mux;
-    cc->open = qemu_chr_open_mux;
-    cc->chr_write = mux_chr_write;
-    cc->chr_accept_input = mux_chr_accept_input;
-    cc->chr_add_watch = mux_chr_add_watch;
-}
-
-static const TypeInfo char_mux_type_info = {
-    .name = TYPE_CHARDEV_MUX,
-    .parent = TYPE_CHARDEV,
-    .class_init = char_mux_class_init,
-    .instance_size = sizeof(MuxChardev),
-    .instance_finalize = char_mux_finalize,
-};
-
 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
                                   Error **errp)
 {
@@ -5075,7 +4734,6 @@ static void register_types(void)
     type_register_static(&char_console_type_info);
 #endif
     type_register_static(&char_pipe_type_info);
-    type_register_static(&char_mux_type_info);
     type_register_static(&char_memory_type_info);
 
     /* this must be done after machine init, since we register FEs with muxes
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index be7ff800c3..f1ccc40ae1 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,2 +1,3 @@
 chardev-obj-y += char.o
+chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
diff --git a/chardev/char-mux.h b/chardev/char-mux.h
new file mode 100644
index 0000000000..c0a000838a
--- /dev/null
+++ b/chardev/char-mux.h
@@ -0,0 +1,40 @@
+#ifndef CHAR_MUX_H
+#define CHAR_MUX_H
+
+#include "sysemu/char.h"
+
+extern bool muxes_realized;
+
+#define MAX_MUX 4
+#define MUX_BUFFER_SIZE 32 /* Must be a power of 2.  */
+#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
+typedef struct MuxChardev {
+    Chardev parent;
+    CharBackend *backends[MAX_MUX];
+    CharBackend chr;
+    int focus;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+    /* Intermediate input buffer allows to catch escape sequences even if the
+       currently active device is not accepting any input - but only until it
+       is full as well. */
+    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+    int prod[MAX_MUX];
+    int cons[MAX_MUX];
+    int timestamps;
+
+    /* Protected by the Chardev chr_write_lock.  */
+    int linestart;
+    int64_t timestamps_start;
+} MuxChardev;
+
+#define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX)
+#define CHARDEV_IS_MUX(chr)                             \
+    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
+
+void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
+void mux_set_focus(MuxChardev *d, int focus);
+void mux_chr_send_event(MuxChardev *d, int mux_nr, int event);
+
+#endif /* CHAR_MUX_H */
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 297add973c..dd91c4c03e 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -439,6 +439,7 @@ bool qemu_chr_has_feature(Chardev *chr,
 void qemu_chr_set_feature(Chardev *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
+int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len);
 
 #define TYPE_CHARDEV "chardev"
 #define CHARDEV(obj) OBJECT_CHECK(Chardev, (obj), TYPE_CHARDEV)
@@ -461,8 +462,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 #define TYPE_CHARDEV_SOCKET "chardev-socket"
 #define TYPE_CHARDEV_UDP "chardev-udp"
 
-#define CHARDEV_IS_MUX(chr) \
-    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
 #define CHARDEV_IS_RINGBUF(chr) \
     object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
 #define CHARDEV_IS_PTY(chr) \
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 38/54] char: move ringbuf/memory to its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (36 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 37/54] char: move mux " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 39/54] char: rename and move to header CHR_READ_BUF_LEN Marc-André Lureau
                   ` (17 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-ringbuf.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c         | 217 -----------------------------------------------
 chardev/Makefile.objs  |   1 +
 3 files changed, 226 insertions(+), 217 deletions(-)
 create mode 100644 chardev/char-ringbuf.c

diff --git a/chardev/char-ringbuf.c b/chardev/char-ringbuf.c
new file mode 100644
index 0000000000..fccf9d25a0
--- /dev/null
+++ b/chardev/char-ringbuf.c
@@ -0,0 +1,225 @@
+#include "qemu/osdep.h"
+#include "sysemu/char.h"
+#include "qmp-commands.h"
+#include "qemu/base64.h"
+
+/* Ring buffer chardev */
+
+typedef struct {
+    Chardev parent;
+    size_t size;
+    size_t prod;
+    size_t cons;
+    uint8_t *cbuf;
+} RingBufChardev;
+
+#define RINGBUF_CHARDEV(obj)                                    \
+    OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF)
+
+static size_t ringbuf_count(const Chardev *chr)
+{
+    const RingBufChardev *d = RINGBUF_CHARDEV(chr);
+
+    return d->prod - d->cons;
+}
+
+static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
+    int i;
+
+    if (!buf || (len < 0)) {
+        return -1;
+    }
+
+    for (i = 0; i < len; i++) {
+        d->cbuf[d->prod++ & (d->size - 1)] = buf[i];
+        if (d->prod - d->cons > d->size) {
+            d->cons = d->prod - d->size;
+        }
+    }
+
+    return len;
+}
+
+static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
+{
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
+    int i;
+
+    qemu_mutex_lock(&chr->chr_write_lock);
+    for (i = 0; i < len && d->cons != d->prod; i++) {
+        buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
+    }
+    qemu_mutex_unlock(&chr->chr_write_lock);
+
+    return i;
+}
+
+static void char_ringbuf_finalize(Object *obj)
+{
+    RingBufChardev *d = RINGBUF_CHARDEV(obj);
+
+    g_free(d->cbuf);
+}
+
+static void qemu_chr_open_ringbuf(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
+{
+    ChardevRingbuf *opts = backend->u.ringbuf.data;
+    RingBufChardev *d = RINGBUF_CHARDEV(chr);
+
+    d->size = opts->has_size ? opts->size : 65536;
+
+    /* The size must be power of 2 */
+    if (d->size & (d->size - 1)) {
+        error_setg(errp, "size of ringbuf chardev must be power of two");
+        return;
+    }
+
+    d->prod = 0;
+    d->cons = 0;
+    d->cbuf = g_malloc0(d->size);
+}
+
+void qmp_ringbuf_write(const char *device, const char *data,
+                       bool has_format, enum DataFormat format,
+                       Error **errp)
+{
+    Chardev *chr;
+    const uint8_t *write_data;
+    int ret;
+    gsize write_count;
+
+    chr = qemu_chr_find(device);
+    if (!chr) {
+        error_setg(errp, "Device '%s' not found", device);
+        return;
+    }
+
+    if (!CHARDEV_IS_RINGBUF(chr)) {
+        error_setg(errp, "%s is not a ringbuf device", device);
+        return;
+    }
+
+    if (has_format && (format == DATA_FORMAT_BASE64)) {
+        write_data = qbase64_decode(data, -1,
+                                    &write_count,
+                                    errp);
+        if (!write_data) {
+            return;
+        }
+    } else {
+        write_data = (uint8_t *)data;
+        write_count = strlen(data);
+    }
+
+    ret = ringbuf_chr_write(chr, write_data, write_count);
+
+    if (write_data != (uint8_t *)data) {
+        g_free((void *)write_data);
+    }
+
+    if (ret < 0) {
+        error_setg(errp, "Failed to write to device %s", device);
+        return;
+    }
+}
+
+char *qmp_ringbuf_read(const char *device, int64_t size,
+                       bool has_format, enum DataFormat format,
+                       Error **errp)
+{
+    Chardev *chr;
+    uint8_t *read_data;
+    size_t count;
+    char *data;
+
+    chr = qemu_chr_find(device);
+    if (!chr) {
+        error_setg(errp, "Device '%s' not found", device);
+        return NULL;
+    }
+
+    if (!CHARDEV_IS_RINGBUF(chr)) {
+        error_setg(errp, "%s is not a ringbuf device", device);
+        return NULL;
+    }
+
+    if (size <= 0) {
+        error_setg(errp, "size must be greater than zero");
+        return NULL;
+    }
+
+    count = ringbuf_count(chr);
+    size = size > count ? count : size;
+    read_data = g_malloc(size + 1);
+
+    ringbuf_chr_read(chr, read_data, size);
+
+    if (has_format && (format == DATA_FORMAT_BASE64)) {
+        data = g_base64_encode(read_data, size);
+        g_free(read_data);
+    } else {
+        /*
+         * FIXME should read only complete, valid UTF-8 characters up
+         * to @size bytes.  Invalid sequences should be replaced by a
+         * suitable replacement character.  Except when (and only
+         * when) ring buffer lost characters since last read, initial
+         * continuation characters should be dropped.
+         */
+        read_data[size] = 0;
+        data = (char *)read_data;
+    }
+
+    return data;
+}
+
+static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
+                                   Error **errp)
+{
+    int val;
+    ChardevRingbuf *ringbuf;
+
+    ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
+
+    val = qemu_opt_get_size(opts, "size", 0);
+    if (val != 0) {
+        ringbuf->has_size = true;
+        ringbuf->size = val;
+    }
+}
+
+static void char_ringbuf_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_ringbuf;
+    cc->open = qemu_chr_open_ringbuf;
+    cc->chr_write = ringbuf_chr_write;
+}
+
+static const TypeInfo char_ringbuf_type_info = {
+    .name = TYPE_CHARDEV_RINGBUF,
+    .parent = TYPE_CHARDEV,
+    .class_init = char_ringbuf_class_init,
+    .instance_size = sizeof(RingBufChardev),
+    .instance_finalize = char_ringbuf_finalize,
+};
+
+/* Bug-compatibility: */
+static const TypeInfo char_memory_type_info = {
+    .name = TYPE_CHARDEV_MEMORY,
+    .parent = TYPE_CHARDEV_RINGBUF,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_ringbuf_type_info);
+    type_register_static(&char_memory_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 3138bfcd19..94b42bbe01 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -3144,182 +3144,6 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
 }
 
 
-/*********************************************************/
-/* Ring buffer chardev */
-
-typedef struct {
-    Chardev parent;
-    size_t size;
-    size_t prod;
-    size_t cons;
-    uint8_t *cbuf;
-} RingBufChardev;
-
-#define RINGBUF_CHARDEV(obj)                                    \
-    OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF)
-
-static size_t ringbuf_count(const Chardev *chr)
-{
-    const RingBufChardev *d = RINGBUF_CHARDEV(chr);
-
-    return d->prod - d->cons;
-}
-
-/* Called with chr_write_lock held.  */
-static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    RingBufChardev *d = RINGBUF_CHARDEV(chr);
-    int i;
-
-    if (!buf || (len < 0)) {
-        return -1;
-    }
-
-    for (i = 0; i < len; i++ ) {
-        d->cbuf[d->prod++ & (d->size - 1)] = buf[i];
-        if (d->prod - d->cons > d->size) {
-            d->cons = d->prod - d->size;
-        }
-    }
-
-    return len;
-}
-
-static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
-{
-    RingBufChardev *d = RINGBUF_CHARDEV(chr);
-    int i;
-
-    qemu_mutex_lock(&chr->chr_write_lock);
-    for (i = 0; i < len && d->cons != d->prod; i++) {
-        buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
-    }
-    qemu_mutex_unlock(&chr->chr_write_lock);
-
-    return i;
-}
-
-static void char_ringbuf_finalize(Object *obj)
-{
-    RingBufChardev *d = RINGBUF_CHARDEV(obj);
-
-    g_free(d->cbuf);
-}
-
-static void qemu_chr_open_ringbuf(Chardev *chr,
-                                  ChardevBackend *backend,
-                                  bool *be_opened,
-                                  Error **errp)
-{
-    ChardevRingbuf *opts = backend->u.ringbuf.data;
-    RingBufChardev *d = RINGBUF_CHARDEV(chr);
-
-    d->size = opts->has_size ? opts->size : 65536;
-
-    /* The size must be power of 2 */
-    if (d->size & (d->size - 1)) {
-        error_setg(errp, "size of ringbuf chardev must be power of two");
-        return;
-    }
-
-    d->prod = 0;
-    d->cons = 0;
-    d->cbuf = g_malloc0(d->size);
-}
-
-void qmp_ringbuf_write(const char *device, const char *data,
-                       bool has_format, enum DataFormat format,
-                       Error **errp)
-{
-    Chardev *chr;
-    const uint8_t *write_data;
-    int ret;
-    gsize write_count;
-
-    chr = qemu_chr_find(device);
-    if (!chr) {
-        error_setg(errp, "Device '%s' not found", device);
-        return;
-    }
-
-    if (!CHARDEV_IS_RINGBUF(chr)) {
-        error_setg(errp,"%s is not a ringbuf device", device);
-        return;
-    }
-
-    if (has_format && (format == DATA_FORMAT_BASE64)) {
-        write_data = qbase64_decode(data, -1,
-                                    &write_count,
-                                    errp);
-        if (!write_data) {
-            return;
-        }
-    } else {
-        write_data = (uint8_t *)data;
-        write_count = strlen(data);
-    }
-
-    ret = ringbuf_chr_write(chr, write_data, write_count);
-
-    if (write_data != (uint8_t *)data) {
-        g_free((void *)write_data);
-    }
-
-    if (ret < 0) {
-        error_setg(errp, "Failed to write to device %s", device);
-        return;
-    }
-}
-
-char *qmp_ringbuf_read(const char *device, int64_t size,
-                       bool has_format, enum DataFormat format,
-                       Error **errp)
-{
-    Chardev *chr;
-    uint8_t *read_data;
-    size_t count;
-    char *data;
-
-    chr = qemu_chr_find(device);
-    if (!chr) {
-        error_setg(errp, "Device '%s' not found", device);
-        return NULL;
-    }
-
-    if (!CHARDEV_IS_RINGBUF(chr)) {
-        error_setg(errp,"%s is not a ringbuf device", device);
-        return NULL;
-    }
-
-    if (size <= 0) {
-        error_setg(errp, "size must be greater than zero");
-        return NULL;
-    }
-
-    count = ringbuf_count(chr);
-    size = size > count ? count : size;
-    read_data = g_malloc(size + 1);
-
-    ringbuf_chr_read(chr, read_data, size);
-
-    if (has_format && (format == DATA_FORMAT_BASE64)) {
-        data = g_base64_encode(read_data, size);
-        g_free(read_data);
-    } else {
-        /*
-         * FIXME should read only complete, valid UTF-8 characters up
-         * to @size bytes.  Invalid sequences should be replaced by a
-         * suitable replacement character.  Except when (and only
-         * when) ring buffer lost characters since last read, initial
-         * continuation characters should be dropped.
-         */
-        read_data[size] = 0;
-        data = (char *)read_data;
-    }
-
-    return data;
-}
-
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
@@ -3595,45 +3419,6 @@ static const TypeInfo char_pipe_type_info = {
     .class_init = char_pipe_class_init,
 };
 
-static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
-                                   Error **errp)
-{
-    int val;
-    ChardevRingbuf *ringbuf;
-
-    ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
-
-    val = qemu_opt_get_size(opts, "size", 0);
-    if (val != 0) {
-        ringbuf->has_size = true;
-        ringbuf->size = val;
-    }
-}
-
-static void char_ringbuf_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_ringbuf;
-    cc->open = qemu_chr_open_ringbuf;
-    cc->chr_write = ringbuf_chr_write;
-}
-
-static const TypeInfo char_ringbuf_type_info = {
-    .name = TYPE_CHARDEV_RINGBUF,
-    .parent = TYPE_CHARDEV,
-    .class_init = char_ringbuf_class_init,
-    .instance_size = sizeof(RingBufChardev),
-    .instance_finalize = char_ringbuf_finalize,
-};
-
-/* Bug-compatibility: */
-static const TypeInfo char_memory_type_info = {
-    .name = TYPE_CHARDEV_MEMORY,
-    .parent = TYPE_CHARDEV_RINGBUF,
-};
-
 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
                                   Error **errp)
 {
@@ -4718,7 +4503,6 @@ static void register_types(void)
 #endif
     type_register_static(&char_socket_type_info);
     type_register_static(&char_udp_type_info);
-    type_register_static(&char_ringbuf_type_info);
     type_register_static(&char_file_type_info);
     type_register_static(&char_stdio_type_info);
 #ifdef HAVE_CHARDEV_SERIAL
@@ -4734,7 +4518,6 @@ static void register_types(void)
     type_register_static(&char_console_type_info);
 #endif
     type_register_static(&char_pipe_type_info);
-    type_register_static(&char_memory_type_info);
 
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index f1ccc40ae1..d4ffb8d70e 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,3 +1,4 @@
 chardev-obj-y += char.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
+chardev-obj-y += char-ringbuf.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 39/54] char: rename and move to header CHR_READ_BUF_LEN
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (37 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 38/54] char: move ringbuf/memory " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 40/54] char: remove unused READ_RETRIES Marc-André Lureau
                   ` (16 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This define is used by several character devices, place it in char
common header.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char.c        | 13 ++++++-------
 include/sysemu/char.h |  1 +
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index 94b42bbe01..1fdfa98954 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -87,7 +87,6 @@
 
 #include "char-mux.h"
 
-#define READ_BUF_LEN 4096
 #define READ_RETRIES 10
 #define TCP_MAX_FDS 16
 
@@ -471,7 +470,7 @@ void qemu_chr_fe_accept_input(CharBackend *be)
 
 void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 {
-    char buf[READ_BUF_LEN];
+    char buf[CHR_READ_BUF_LEN];
     va_list ap;
     va_start(ap, fmt);
     vsnprintf(buf, sizeof(buf), fmt, ap);
@@ -911,7 +910,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     Chardev *chr = CHARDEV(opaque);
     FDChardev *s = FD_CHARDEV(opaque);
     int len;
-    uint8_t buf[READ_BUF_LEN];
+    uint8_t buf[CHR_READ_BUF_LEN];
     ssize_t ret;
 
     len = sizeof(buf);
@@ -1263,7 +1262,7 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     Chardev *chr = CHARDEV(opaque);
     PtyChardev *s = PTY_CHARDEV(opaque);
     gsize len;
-    uint8_t buf[READ_BUF_LEN];
+    uint8_t buf[CHR_READ_BUF_LEN];
     ssize_t ret;
 
     len = sizeof(buf);
@@ -1953,7 +1952,7 @@ static void win_chr_readfile(Chardev *chr)
     WinChardev *s = WIN_CHARDEV(chr);
 
     int ret, err;
-    uint8_t buf[READ_BUF_LEN];
+    uint8_t buf[CHR_READ_BUF_LEN];
     DWORD size;
 
     ZeroMemory(&s->orecv, sizeof(s->orecv));
@@ -2355,7 +2354,7 @@ err1:
 typedef struct {
     Chardev parent;
     QIOChannel *ioc;
-    uint8_t buf[READ_BUF_LEN];
+    uint8_t buf[CHR_READ_BUF_LEN];
     int bufcnt;
     int bufptr;
     int max_size;
@@ -2760,7 +2759,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     Chardev *chr = CHARDEV(opaque);
     SocketChardev *s = SOCKET_CHARDEV(opaque);
-    uint8_t buf[READ_BUF_LEN];
+    uint8_t buf[CHR_READ_BUF_LEN];
     int len, size;
 
     if (!s->connected || s->max_size <= 0) {
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index dd91c4c03e..0b96b00d56 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -22,6 +22,7 @@ typedef enum {
     CHR_EVENT_CLOSED /* connection closed */
 } QEMUChrEvent;
 
+#define CHR_READ_BUF_LEN 4096
 
 #define CHR_IOCTL_SERIAL_SET_PARAMS   1
 typedef struct {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 40/54] char: remove unused READ_RETRIES
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (38 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 39/54] char: rename and move to header CHR_READ_BUF_LEN Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 41/54] char: move QIOChannel-related in char-io.h Marc-André Lureau
                   ` (15 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Curiously unused since its introduction in commit 7b0bfdf52d69.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/chardev/char.c b/chardev/char.c
index 1fdfa98954..eb9fb8d984 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -87,7 +87,6 @@
 
 #include "char-mux.h"
 
-#define READ_RETRIES 10
 #define TCP_MAX_FDS 16
 
 /***********************************************************/
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 41/54] char: move QIOChannel-related in char-io.h
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (39 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 40/54] char: remove unused READ_RETRIES Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 42/54] char: move fd chardev in its own file Marc-André Lureau
                   ` (14 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-io.c     | 168 ++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 174 +-------------------------------------------------
 chardev/Makefile.objs |   1 +
 chardev/char-io.h     |  24 +++++++
 4 files changed, 194 insertions(+), 173 deletions(-)
 create mode 100644 chardev/char-io.c
 create mode 100644 chardev/char-io.h

diff --git a/chardev/char-io.c b/chardev/char-io.c
new file mode 100644
index 0000000000..82bc721d1a
--- /dev/null
+++ b/chardev/char-io.c
@@ -0,0 +1,168 @@
+#include "char-io.h"
+
+typedef struct IOWatchPoll {
+    GSource parent;
+
+    QIOChannel *ioc;
+    GSource *src;
+
+    IOCanReadHandler *fd_can_read;
+    GSourceFunc fd_read;
+    void *opaque;
+    GMainContext *context;
+} IOWatchPoll;
+
+static IOWatchPoll *io_watch_poll_from_source(GSource *source)
+{
+    return container_of(source, IOWatchPoll, parent);
+}
+
+static gboolean io_watch_poll_prepare(GSource *source,
+                                      gint *timeout_)
+{
+    IOWatchPoll *iwp = io_watch_poll_from_source(source);
+    bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
+    bool was_active = iwp->src != NULL;
+    if (was_active == now_active) {
+        return FALSE;
+    }
+
+    if (now_active) {
+        iwp->src = qio_channel_create_watch(
+            iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
+        g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
+        g_source_attach(iwp->src, iwp->context);
+    } else {
+        g_source_destroy(iwp->src);
+        g_source_unref(iwp->src);
+        iwp->src = NULL;
+    }
+    return FALSE;
+}
+
+static gboolean io_watch_poll_check(GSource *source)
+{
+    return FALSE;
+}
+
+static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
+                                       gpointer user_data)
+{
+    abort();
+}
+
+static void io_watch_poll_finalize(GSource *source)
+{
+    /* Due to a glib bug, removing the last reference to a source
+     * inside a finalize callback causes recursive locking (and a
+     * deadlock).  This is not a problem inside other callbacks,
+     * including dispatch callbacks, so we call io_remove_watch_poll
+     * to remove this source.  At this point, iwp->src must
+     * be NULL, or we would leak it.
+     *
+     * This would be solved much more elegantly by child sources,
+     * but we support older glib versions that do not have them.
+     */
+    IOWatchPoll *iwp = io_watch_poll_from_source(source);
+    assert(iwp->src == NULL);
+}
+
+static GSourceFuncs io_watch_poll_funcs = {
+    .prepare = io_watch_poll_prepare,
+    .check = io_watch_poll_check,
+    .dispatch = io_watch_poll_dispatch,
+    .finalize = io_watch_poll_finalize,
+};
+
+guint io_add_watch_poll(Chardev *chr,
+                        QIOChannel *ioc,
+                        IOCanReadHandler *fd_can_read,
+                        QIOChannelFunc fd_read,
+                        gpointer user_data,
+                        GMainContext *context)
+{
+    IOWatchPoll *iwp;
+    int tag;
+    char *name;
+
+    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
+                                       sizeof(IOWatchPoll));
+    iwp->fd_can_read = fd_can_read;
+    iwp->opaque = user_data;
+    iwp->ioc = ioc;
+    iwp->fd_read = (GSourceFunc) fd_read;
+    iwp->src = NULL;
+    iwp->context = context;
+
+    name = g_strdup_printf("chardev-iowatch-%s", chr->label);
+    g_source_set_name((GSource *)iwp, name);
+    g_free(name);
+
+    tag = g_source_attach(&iwp->parent, context);
+    g_source_unref(&iwp->parent);
+    return tag;
+}
+
+static void io_remove_watch_poll(guint tag)
+{
+    GSource *source;
+    IOWatchPoll *iwp;
+
+    g_return_if_fail(tag > 0);
+
+    source = g_main_context_find_source_by_id(NULL, tag);
+    g_return_if_fail(source != NULL);
+
+    iwp = io_watch_poll_from_source(source);
+    if (iwp->src) {
+        g_source_destroy(iwp->src);
+        g_source_unref(iwp->src);
+        iwp->src = NULL;
+    }
+    g_source_destroy(&iwp->parent);
+}
+
+void remove_fd_in_watch(Chardev *chr)
+{
+    if (chr->fd_in_tag) {
+        io_remove_watch_poll(chr->fd_in_tag);
+        chr->fd_in_tag = 0;
+    }
+}
+
+int io_channel_send_full(QIOChannel *ioc,
+                         const void *buf, size_t len,
+                         int *fds, size_t nfds)
+{
+    size_t offset = 0;
+
+    while (offset < len) {
+        ssize_t ret = 0;
+        struct iovec iov = { .iov_base = (char *)buf + offset,
+                             .iov_len = len - offset };
+
+        ret = qio_channel_writev_full(
+            ioc, &iov, 1,
+            fds, nfds, NULL);
+        if (ret == QIO_CHANNEL_ERR_BLOCK) {
+            if (offset) {
+                return offset;
+            }
+
+            errno = EAGAIN;
+            return -1;
+        } else if (ret < 0) {
+            errno = EINVAL;
+            return -1;
+        }
+
+        offset += ret;
+    }
+
+    return offset;
+}
+
+int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
+{
+    return io_channel_send_full(ioc, buf, len, NULL, 0);
+}
diff --git a/chardev/char.c b/chardev/char.c
index eb9fb8d984..c342d40dcc 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -86,6 +86,7 @@
 #include "ui/qemu-spice.h"
 
 #include "char-mux.h"
+#include "char-io.h"
 
 #define TCP_MAX_FDS 16
 
@@ -479,8 +480,6 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
     va_end(ap);
 }
 
-static void remove_fd_in_watch(Chardev *chr);
-
 static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
                            bool *be_opened, Error **errp)
 {
@@ -714,178 +713,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
     }
 }
 
-typedef struct IOWatchPoll
-{
-    GSource parent;
-
-    QIOChannel *ioc;
-    GSource *src;
-
-    IOCanReadHandler *fd_can_read;
-    GSourceFunc fd_read;
-    void *opaque;
-    GMainContext *context;
-} IOWatchPoll;
-
-static IOWatchPoll *io_watch_poll_from_source(GSource *source)
-{
-    return container_of(source, IOWatchPoll, parent);
-}
-
-static gboolean io_watch_poll_prepare(GSource *source,
-                                      gint *timeout_)
-{
-    IOWatchPoll *iwp = io_watch_poll_from_source(source);
-    bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
-    bool was_active = iwp->src != NULL;
-    if (was_active == now_active) {
-        return FALSE;
-    }
-
-    if (now_active) {
-        iwp->src = qio_channel_create_watch(
-            iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
-        g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
-        g_source_attach(iwp->src, iwp->context);
-    } else {
-        g_source_destroy(iwp->src);
-        g_source_unref(iwp->src);
-        iwp->src = NULL;
-    }
-    return FALSE;
-}
-
-static gboolean io_watch_poll_check(GSource *source)
-{
-    return FALSE;
-}
-
-static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
-                                       gpointer user_data)
-{
-    abort();
-}
-
-static void io_watch_poll_finalize(GSource *source)
-{
-    /* Due to a glib bug, removing the last reference to a source
-     * inside a finalize callback causes recursive locking (and a
-     * deadlock).  This is not a problem inside other callbacks,
-     * including dispatch callbacks, so we call io_remove_watch_poll
-     * to remove this source.  At this point, iwp->src must
-     * be NULL, or we would leak it.
-     *
-     * This would be solved much more elegantly by child sources,
-     * but we support older glib versions that do not have them.
-     */
-    IOWatchPoll *iwp = io_watch_poll_from_source(source);
-    assert(iwp->src == NULL);
-}
-
-static GSourceFuncs io_watch_poll_funcs = {
-    .prepare = io_watch_poll_prepare,
-    .check = io_watch_poll_check,
-    .dispatch = io_watch_poll_dispatch,
-    .finalize = io_watch_poll_finalize,
-};
-
-/* Can only be used for read */
-static guint io_add_watch_poll(Chardev *chr,
-                               QIOChannel *ioc,
-                               IOCanReadHandler *fd_can_read,
-                               QIOChannelFunc fd_read,
-                               gpointer user_data,
-                               GMainContext *context)
-{
-    IOWatchPoll *iwp;
-    int tag;
-    char *name;
-
-    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
-                                       sizeof(IOWatchPoll));
-    iwp->fd_can_read = fd_can_read;
-    iwp->opaque = user_data;
-    iwp->ioc = ioc;
-    iwp->fd_read = (GSourceFunc) fd_read;
-    iwp->src = NULL;
-    iwp->context = context;
-
-    name = g_strdup_printf("chardev-iowatch-%s", chr->label);
-    g_source_set_name((GSource *)iwp, name);
-    g_free(name);
-
-    tag = g_source_attach(&iwp->parent, context);
-    g_source_unref(&iwp->parent);
-    return tag;
-}
-
-static void io_remove_watch_poll(guint tag)
-{
-    GSource *source;
-    IOWatchPoll *iwp;
-
-    g_return_if_fail (tag > 0);
-
-    source = g_main_context_find_source_by_id(NULL, tag);
-    g_return_if_fail (source != NULL);
-
-    iwp = io_watch_poll_from_source(source);
-    if (iwp->src) {
-        g_source_destroy(iwp->src);
-        g_source_unref(iwp->src);
-        iwp->src = NULL;
-    }
-    g_source_destroy(&iwp->parent);
-}
-
-static void remove_fd_in_watch(Chardev *chr)
-{
-    if (chr->fd_in_tag) {
-        io_remove_watch_poll(chr->fd_in_tag);
-        chr->fd_in_tag = 0;
-    }
-}
-
-
-static int io_channel_send_full(QIOChannel *ioc,
-                                const void *buf, size_t len,
-                                int *fds, size_t nfds)
-{
-    size_t offset = 0;
-
-    while (offset < len) {
-        ssize_t ret = 0;
-        struct iovec iov = { .iov_base = (char *)buf + offset,
-                             .iov_len = len - offset };
-
-        ret = qio_channel_writev_full(
-            ioc, &iov, 1,
-            fds, nfds, NULL);
-        if (ret == QIO_CHANNEL_ERR_BLOCK) {
-            if (offset) {
-                return offset;
-            }
-
-            errno = EAGAIN;
-            return -1;
-        } else if (ret < 0) {
-            errno = EINVAL;
-            return -1;
-        }
-
-        offset += ret;
-    }
-
-    return offset;
-}
-
-
 #ifndef _WIN32
-static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
-{
-    return io_channel_send_full(ioc, buf, len, NULL, 0);
-}
-
 typedef struct FDChardev {
     Chardev parent;
     Chardev *chr;
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index d4ffb8d70e..5f5d3716ac 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,4 +1,5 @@
 chardev-obj-y += char.o
+chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
diff --git a/chardev/char-io.h b/chardev/char-io.h
new file mode 100644
index 0000000000..ea559fd124
--- /dev/null
+++ b/chardev/char-io.h
@@ -0,0 +1,24 @@
+#ifndef CHAR_IO_H
+#define CHAR_IO_H
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "io/channel.h"
+#include "sysemu/char.h"
+
+/* Can only be used for read */
+guint io_add_watch_poll(Chardev *chr,
+                        QIOChannel *ioc,
+                        IOCanReadHandler *fd_can_read,
+                        QIOChannelFunc fd_read,
+                        gpointer user_data,
+                        GMainContext *context);
+
+void remove_fd_in_watch(Chardev *chr);
+
+int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
+
+int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len,
+                         int *fds, size_t nfds);
+
+#endif /* CHAR_IO_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 42/54] char: move fd chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (40 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 41/54] char: move QIOChannel-related in char-io.h Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 43/54] char: move win chardev base class " Marc-André Lureau
                   ` (13 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-fd.c     | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 147 +-------------------------------------------------
 chardev/Makefile.objs |   1 +
 chardev/char-fd.h     |  21 ++++++++
 4 files changed, 171 insertions(+), 145 deletions(-)
 create mode 100644 chardev/char-fd.c
 create mode 100644 chardev/char-fd.h

diff --git a/chardev/char-fd.c b/chardev/char-fd.c
new file mode 100644
index 0000000000..0328c9335c
--- /dev/null
+++ b/chardev/char-fd.c
@@ -0,0 +1,147 @@
+#include "qemu/osdep.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/char.h"
+#include "io/channel-file.h"
+
+#include "char-fd.h"
+#include "char-io.h"
+
+/* Called with chr_write_lock held.  */
+static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    FDChardev *s = FD_CHARDEV(chr);
+
+    return io_channel_send(s->ioc_out, buf, len);
+}
+
+static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    FDChardev *s = FD_CHARDEV(opaque);
+    int len;
+    uint8_t buf[CHR_READ_BUF_LEN];
+    ssize_t ret;
+
+    len = sizeof(buf);
+    if (len > s->max_size) {
+        len = s->max_size;
+    }
+    if (len == 0) {
+        return TRUE;
+    }
+
+    ret = qio_channel_read(
+        chan, (gchar *)buf, len, NULL);
+    if (ret == 0) {
+        remove_fd_in_watch(chr);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+        return FALSE;
+    }
+    if (ret > 0) {
+        qemu_chr_be_write(chr, buf, ret);
+    }
+
+    return TRUE;
+}
+
+static int fd_chr_read_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    FDChardev *s = FD_CHARDEV(opaque);
+
+    s->max_size = qemu_chr_be_can_write(chr);
+    return s->max_size;
+}
+
+static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
+{
+    FDChardev *s = FD_CHARDEV(chr);
+    return qio_channel_create_watch(s->ioc_out, cond);
+}
+
+static void fd_chr_update_read_handler(Chardev *chr,
+                                       GMainContext *context)
+{
+    FDChardev *s = FD_CHARDEV(chr);
+
+    remove_fd_in_watch(chr);
+    if (s->ioc_in) {
+        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
+                                           fd_chr_read_poll,
+                                           fd_chr_read, chr,
+                                           context);
+    }
+}
+
+static void char_fd_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+    FDChardev *s = FD_CHARDEV(obj);
+
+    remove_fd_in_watch(chr);
+    if (s->ioc_in) {
+        object_unref(OBJECT(s->ioc_in));
+    }
+    if (s->ioc_out) {
+        object_unref(OBJECT(s->ioc_out));
+    }
+
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+}
+
+int qmp_chardev_open_file_source(char *src, int flags, Error **errp)
+{
+    int fd = -1;
+
+    TFR(fd = qemu_open(src, flags, 0666));
+    if (fd == -1) {
+        error_setg_file_open(errp, errno, src);
+    }
+    return fd;
+}
+
+/* open a character device to a unix fd */
+void qemu_chr_open_fd(Chardev *chr,
+                      int fd_in, int fd_out)
+{
+    FDChardev *s = FD_CHARDEV(chr);
+    char *name;
+
+    s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
+    name = g_strdup_printf("chardev-file-in-%s", chr->label);
+    qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
+    g_free(name);
+    s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
+    name = g_strdup_printf("chardev-file-out-%s", chr->label);
+    qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
+    g_free(name);
+    qemu_set_nonblock(fd_out);
+    s->chr = chr;
+}
+
+static void char_fd_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_add_watch = fd_chr_add_watch;
+    cc->chr_write = fd_chr_write;
+    cc->chr_update_read_handler = fd_chr_update_read_handler;
+}
+
+static const TypeInfo char_fd_type_info = {
+    .name = TYPE_CHARDEV_FD,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(FDChardev),
+    .instance_finalize = char_fd_finalize,
+    .class_init = char_fd_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_fd_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index c342d40dcc..17d47395a7 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -86,6 +86,7 @@
 #include "ui/qemu-spice.h"
 
 #include "char-mux.h"
+#include "char-fd.h"
 #include "char-io.h"
 
 #define TCP_MAX_FDS 16
@@ -714,136 +715,6 @@ void qemu_chr_fe_take_focus(CharBackend *b)
 }
 
 #ifndef _WIN32
-typedef struct FDChardev {
-    Chardev parent;
-    Chardev *chr;
-    QIOChannel *ioc_in, *ioc_out;
-    int max_size;
-} FDChardev;
-
-#define TYPE_CHARDEV_FD "chardev-fd"
-#define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD)
-
-/* Called with chr_write_lock held.  */
-static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    FDChardev *s = FD_CHARDEV(chr);
-
-    return io_channel_send(s->ioc_out, buf, len);
-}
-
-static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    FDChardev *s = FD_CHARDEV(opaque);
-    int len;
-    uint8_t buf[CHR_READ_BUF_LEN];
-    ssize_t ret;
-
-    len = sizeof(buf);
-    if (len > s->max_size) {
-        len = s->max_size;
-    }
-    if (len == 0) {
-        return TRUE;
-    }
-
-    ret = qio_channel_read(
-        chan, (gchar *)buf, len, NULL);
-    if (ret == 0) {
-        remove_fd_in_watch(chr);
-        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-        return FALSE;
-    }
-    if (ret > 0) {
-        qemu_chr_be_write(chr, buf, ret);
-    }
-
-    return TRUE;
-}
-
-static int fd_chr_read_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    FDChardev *s = FD_CHARDEV(opaque);
-
-    s->max_size = qemu_chr_be_can_write(chr);
-    return s->max_size;
-}
-
-static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
-{
-    FDChardev *s = FD_CHARDEV(chr);
-    return qio_channel_create_watch(s->ioc_out, cond);
-}
-
-static void fd_chr_update_read_handler(Chardev *chr,
-                                       GMainContext *context)
-{
-    FDChardev *s = FD_CHARDEV(chr);
-
-    remove_fd_in_watch(chr);
-    if (s->ioc_in) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
-                                           fd_chr_read_poll,
-                                           fd_chr_read, chr,
-                                           context);
-    }
-}
-
-static void char_fd_finalize(Object *obj)
-{
-    Chardev *chr = CHARDEV(obj);
-    FDChardev *s = FD_CHARDEV(obj);
-
-    remove_fd_in_watch(chr);
-    if (s->ioc_in) {
-        object_unref(OBJECT(s->ioc_in));
-    }
-    if (s->ioc_out) {
-        object_unref(OBJECT(s->ioc_out));
-    }
-
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
-/* open a character device to a unix fd */
-static void qemu_chr_open_fd(Chardev *chr,
-                             int fd_in, int fd_out)
-{
-    FDChardev *s = FD_CHARDEV(chr);
-    char *name;
-
-    s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
-    name = g_strdup_printf("chardev-file-in-%s", chr->label);
-    qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
-    g_free(name);
-    s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
-    name = g_strdup_printf("chardev-file-out-%s", chr->label);
-    qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
-    g_free(name);
-    qemu_set_nonblock(fd_out);
-    s->chr = chr;
-}
-
-static void char_fd_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->chr_add_watch = fd_chr_add_watch;
-    cc->chr_write = fd_chr_write;
-    cc->chr_update_read_handler = fd_chr_update_read_handler;
-}
-
-static const TypeInfo char_fd_type_info = {
-    .name = TYPE_CHARDEV_FD,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(FDChardev),
-    .instance_finalize = char_fd_finalize,
-    .class_init = char_fd_class_init,
-    .abstract = true,
-};
-
 static void qemu_chr_open_pipe(Chardev *chr,
                                ChardevBackend *backend,
                                bool *be_opened,
@@ -3849,18 +3720,6 @@ static void qmp_chardev_open_serial(Chardev *chr,
 
 #else /* WIN32 */
 
-static int qmp_chardev_open_file_source(char *src, int flags,
-                                        Error **errp)
-{
-    int fd = -1;
-
-    TFR(fd = qemu_open(src, flags, 0666));
-    if (fd == -1) {
-        error_setg_file_open(errp, errno, src);
-    }
-    return fd;
-}
-
 static void qmp_chardev_open_file(Chardev *chr,
                                   ChardevBackend *backend,
                                   bool *be_opened,
@@ -4321,9 +4180,7 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-#ifndef _WIN32
-    type_register_static(&char_fd_type_info);
-#else
+#ifdef _WIN32
     type_register_static(&char_win_type_info);
     type_register_static(&char_win_stdio_type_info);
 #endif
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 5f5d3716ac..d2f03dc5df 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,4 +1,5 @@
 chardev-obj-y += char.o
+chardev-obj-$(CONFIG_POSIX) += char-fd.o
 chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
diff --git a/chardev/char-fd.h b/chardev/char-fd.h
new file mode 100644
index 0000000000..beef7c111a
--- /dev/null
+++ b/chardev/char-fd.h
@@ -0,0 +1,21 @@
+#ifndef CHAR_FD_H
+#define CHAR_FD_H
+
+#include "io/channel.h"
+#include "sysemu/char.h"
+
+typedef struct FDChardev {
+    Chardev parent;
+    Chardev *chr;
+    QIOChannel *ioc_in, *ioc_out;
+    int max_size;
+} FDChardev;
+
+#define TYPE_CHARDEV_FD "chardev-fd"
+
+#define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD)
+
+void qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out);
+int qmp_chardev_open_file_source(char *src, int flags, Error **errp);
+
+#endif /* CHAR_FD_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 43/54] char: move win chardev base class in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (41 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 42/54] char: move fd chardev in its own file Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 44/54] char: move win-stdio into " Marc-André Lureau
                   ` (12 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-win.c    | 245 +++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 256 +-------------------------------------------------
 chardev/Makefile.objs |   1 +
 chardev/char-win.h    |  30 ++++++
 4 files changed, 279 insertions(+), 253 deletions(-)
 create mode 100644 chardev/char-win.c
 create mode 100644 chardev/char-win.h

diff --git a/chardev/char-win.c b/chardev/char-win.c
new file mode 100644
index 0000000000..ad69c384fe
--- /dev/null
+++ b/chardev/char-win.c
@@ -0,0 +1,245 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "char-win.h"
+
+static void win_chr_readfile(Chardev *chr)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+
+    int ret, err;
+    uint8_t buf[CHR_READ_BUF_LEN];
+    DWORD size;
+
+    ZeroMemory(&s->orecv, sizeof(s->orecv));
+    s->orecv.hEvent = s->hrecv;
+    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+        }
+    }
+
+    if (size > 0) {
+        qemu_chr_be_write(chr, buf, size);
+    }
+}
+
+static void win_chr_read(Chardev *chr)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+
+    if (s->len > s->max_size) {
+        s->len = s->max_size;
+    }
+    if (s->len == 0) {
+        return;
+    }
+
+    win_chr_readfile(chr);
+}
+
+static int win_chr_read_poll(Chardev *chr)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+
+    s->max_size = qemu_chr_be_can_write(chr);
+    return s->max_size;
+}
+
+static int win_chr_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    WinChardev *s = WIN_CHARDEV(opaque);
+    COMSTAT status;
+    DWORD comerr;
+
+    ClearCommError(s->hcom, &comerr, &status);
+    if (status.cbInQue > 0) {
+        s->len = status.cbInQue;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+int win_chr_init(Chardev *chr, const char *filename, Error **errp)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+    COMMCONFIG comcfg;
+    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+    COMSTAT comstat;
+    DWORD size;
+    DWORD err;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        error_setg(errp, "Failed CreateEvent");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        error_setg(errp, "Failed CreateEvent");
+        goto fail;
+    }
+
+    s->hcom = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        error_setg(errp, "Failed CreateFile (%lu)", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+        error_setg(errp, "Failed SetupComm");
+        goto fail;
+    }
+
+    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+    size = sizeof(COMMCONFIG);
+    GetDefaultCommConfig(filename, &comcfg, &size);
+    comcfg.dcb.DCBlength = sizeof(DCB);
+    CommConfigDialog(filename, NULL, &comcfg);
+
+    if (!SetCommState(s->hcom, &comcfg.dcb)) {
+        error_setg(errp, "Failed SetCommState");
+        goto fail;
+    }
+
+    if (!SetCommMask(s->hcom, EV_ERR)) {
+        error_setg(errp, "Failed SetCommMask");
+        goto fail;
+    }
+
+    cto.ReadIntervalTimeout = MAXDWORD;
+    if (!SetCommTimeouts(s->hcom, &cto)) {
+        error_setg(errp, "Failed SetCommTimeouts");
+        goto fail;
+    }
+
+    if (!ClearCommError(s->hcom, &err, &comstat)) {
+        error_setg(errp, "Failed ClearCommError");
+        goto fail;
+    }
+    qemu_add_polling_cb(win_chr_poll, chr);
+    return 0;
+
+ fail:
+    return -1;
+}
+
+int win_chr_pipe_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    WinChardev *s = WIN_CHARDEV(opaque);
+    DWORD size;
+
+    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+    if (size > 0) {
+        s->len = size;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+/* Called with chr_write_lock held.  */
+static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+    DWORD len, ret, size, err;
+
+    len = len1;
+    ZeroMemory(&s->osend, sizeof(s->osend));
+    s->osend.hEvent = s->hsend;
+    while (len > 0) {
+        if (s->hsend) {
+            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+        } else {
+            ret = WriteFile(s->hcom, buf, len, &size, NULL);
+        }
+        if (!ret) {
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                if (ret) {
+                    buf += size;
+                    len -= size;
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else {
+            buf += size;
+            len -= size;
+        }
+    }
+    return len1 - len;
+}
+
+static void char_win_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+    WinChardev *s = WIN_CHARDEV(chr);
+
+    if (s->skip_free) {
+        return;
+    }
+
+    if (s->hsend) {
+        CloseHandle(s->hsend);
+        s->hsend = NULL;
+    }
+    if (s->hrecv) {
+        CloseHandle(s->hrecv);
+        s->hrecv = NULL;
+    }
+    if (s->hcom) {
+        CloseHandle(s->hcom);
+        s->hcom = NULL;
+    }
+    if (s->fpipe) {
+        qemu_del_polling_cb(win_chr_pipe_poll, chr);
+    } else {
+        qemu_del_polling_cb(win_chr_poll, chr);
+    }
+
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+}
+
+void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+
+    s->skip_free = true;
+    s->hcom = fd_out;
+}
+
+static void char_win_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->chr_write = win_chr_write;
+}
+
+static const TypeInfo char_win_type_info = {
+    .name = TYPE_CHARDEV_WIN,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(WinChardev),
+    .instance_finalize = char_win_finalize,
+    .class_init = char_win_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_win_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 17d47395a7..3b7140482c 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -88,6 +88,9 @@
 #include "char-mux.h"
 #include "char-fd.h"
 #include "char-io.h"
+#ifdef _WIN32
+#include "char-win.h"
+#endif
 
 #define TCP_MAX_FDS 16
 
@@ -1469,23 +1472,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr,
 
 #define HAVE_CHARDEV_SERIAL 1
 
-typedef struct {
-    Chardev parent;
-    int max_size;
-    HANDLE hcom, hrecv, hsend;
-    OVERLAPPED orecv;
-    BOOL fpipe;
-    DWORD len;
-
-    /* Protected by the Chardev chr_write_lock.  */
-    OVERLAPPED osend;
-    /* FIXME: file/console do not finalize */
-    BOOL skip_free;
-} WinChardev;
-
-#define TYPE_CHARDEV_WIN "chardev-win"
-#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN)
-
 typedef struct {
     Chardev parent;
     HANDLE  hStdIn;
@@ -1499,220 +1485,9 @@ typedef struct {
 #define WIN_STDIO_CHARDEV(obj)                                  \
     OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
 
-#define NSENDBUF 2048
-#define NRECVBUF 2048
 #define MAXCONNECT 1
 #define NTIMEOUT 5000
 
-static int win_chr_poll(void *opaque);
-static int win_chr_pipe_poll(void *opaque);
-
-static void char_win_finalize(Object *obj)
-{
-    Chardev *chr = CHARDEV(obj);
-    WinChardev *s = WIN_CHARDEV(chr);
-
-    if (s->skip_free) {
-        return;
-    }
-
-    if (s->hsend) {
-        CloseHandle(s->hsend);
-        s->hsend = NULL;
-    }
-    if (s->hrecv) {
-        CloseHandle(s->hrecv);
-        s->hrecv = NULL;
-    }
-    if (s->hcom) {
-        CloseHandle(s->hcom);
-        s->hcom = NULL;
-    }
-    if (s->fpipe)
-        qemu_del_polling_cb(win_chr_pipe_poll, chr);
-    else
-        qemu_del_polling_cb(win_chr_poll, chr);
-
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
-static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-    COMMCONFIG comcfg;
-    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
-    COMSTAT comstat;
-    DWORD size;
-    DWORD err;
-
-    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hsend) {
-        error_setg(errp, "Failed CreateEvent");
-        goto fail;
-    }
-    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hrecv) {
-        error_setg(errp, "Failed CreateEvent");
-        goto fail;
-    }
-
-    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
-                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
-    if (s->hcom == INVALID_HANDLE_VALUE) {
-        error_setg(errp, "Failed CreateFile (%lu)", GetLastError());
-        s->hcom = NULL;
-        goto fail;
-    }
-
-    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
-        error_setg(errp, "Failed SetupComm");
-        goto fail;
-    }
-
-    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
-    size = sizeof(COMMCONFIG);
-    GetDefaultCommConfig(filename, &comcfg, &size);
-    comcfg.dcb.DCBlength = sizeof(DCB);
-    CommConfigDialog(filename, NULL, &comcfg);
-
-    if (!SetCommState(s->hcom, &comcfg.dcb)) {
-        error_setg(errp, "Failed SetCommState");
-        goto fail;
-    }
-
-    if (!SetCommMask(s->hcom, EV_ERR)) {
-        error_setg(errp, "Failed SetCommMask");
-        goto fail;
-    }
-
-    cto.ReadIntervalTimeout = MAXDWORD;
-    if (!SetCommTimeouts(s->hcom, &cto)) {
-        error_setg(errp, "Failed SetCommTimeouts");
-        goto fail;
-    }
-
-    if (!ClearCommError(s->hcom, &err, &comstat)) {
-        error_setg(errp, "Failed ClearCommError");
-        goto fail;
-    }
-    qemu_add_polling_cb(win_chr_poll, chr);
-    return 0;
-
- fail:
-    return -1;
-}
-
-/* Called with chr_write_lock held.  */
-static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-    DWORD len, ret, size, err;
-
-    len = len1;
-    ZeroMemory(&s->osend, sizeof(s->osend));
-    s->osend.hEvent = s->hsend;
-    while (len > 0) {
-        if (s->hsend)
-            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
-        else
-            ret = WriteFile(s->hcom, buf, len, &size, NULL);
-        if (!ret) {
-            err = GetLastError();
-            if (err == ERROR_IO_PENDING) {
-                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
-                if (ret) {
-                    buf += size;
-                    len -= size;
-                } else {
-                    break;
-                }
-            } else {
-                break;
-            }
-        } else {
-            buf += size;
-            len -= size;
-        }
-    }
-    return len1 - len;
-}
-
-static int win_chr_read_poll(Chardev *chr)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-
-    s->max_size = qemu_chr_be_can_write(chr);
-    return s->max_size;
-}
-
-static void win_chr_readfile(Chardev *chr)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-
-    int ret, err;
-    uint8_t buf[CHR_READ_BUF_LEN];
-    DWORD size;
-
-    ZeroMemory(&s->orecv, sizeof(s->orecv));
-    s->orecv.hEvent = s->hrecv;
-    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
-    if (!ret) {
-        err = GetLastError();
-        if (err == ERROR_IO_PENDING) {
-            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
-        }
-    }
-
-    if (size > 0) {
-        qemu_chr_be_write(chr, buf, size);
-    }
-}
-
-static void win_chr_read(Chardev *chr)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-
-    if (s->len > s->max_size)
-        s->len = s->max_size;
-    if (s->len == 0)
-        return;
-
-    win_chr_readfile(chr);
-}
-
-static int win_chr_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    WinChardev *s = WIN_CHARDEV(opaque);
-    COMSTAT status;
-    DWORD comerr;
-
-    ClearCommError(s->hcom, &comerr, &status);
-    if (status.cbInQue > 0) {
-        s->len = status.cbInQue;
-        win_chr_read_poll(chr);
-        win_chr_read(chr);
-        return 1;
-    }
-    return 0;
-}
-
-static int win_chr_pipe_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    WinChardev *s = WIN_CHARDEV(opaque);
-    DWORD size;
-
-    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
-    if (size > 0) {
-        s->len = size;
-        win_chr_read_poll(chr);
-        win_chr_read(chr);
-        return 1;
-    }
-    return 0;
-}
-
 static int win_chr_pipe_init(Chardev *chr, const char *filename,
                              Error **errp)
 {
@@ -1790,30 +1565,6 @@ static void qemu_chr_open_pipe(Chardev *chr,
     }
 }
 
-static void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-
-    s->skip_free = true;
-    s->hcom = fd_out;
-}
-
-static void char_win_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->chr_write = win_chr_write;
-}
-
-static const TypeInfo char_win_type_info = {
-    .name = TYPE_CHARDEV_WIN,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(WinChardev),
-    .instance_finalize = char_win_finalize,
-    .class_init = char_win_class_init,
-    .abstract = true,
-};
-
 static void qemu_chr_open_win_con(Chardev *chr,
                                   ChardevBackend *backend,
                                   bool *be_opened,
@@ -4181,7 +3932,6 @@ static void register_types(void)
 {
     type_register_static(&char_type_info);
 #ifdef _WIN32
-    type_register_static(&char_win_type_info);
     type_register_static(&char_win_stdio_type_info);
 #endif
     type_register_static(&char_socket_type_info);
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index d2f03dc5df..bdf5a112a7 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -4,3 +4,4 @@ chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
+chardev-obj-$(CONFIG_WIN32) += char-win.o
diff --git a/chardev/char-win.h b/chardev/char-win.h
new file mode 100644
index 0000000000..e91b5004ab
--- /dev/null
+++ b/chardev/char-win.h
@@ -0,0 +1,30 @@
+#ifndef CHAR_WIN_H
+#define CHAR_WIN_H
+
+#include "sysemu/char.h"
+
+typedef struct {
+    Chardev parent;
+    int max_size;
+    HANDLE hcom, hrecv, hsend;
+    OVERLAPPED orecv;
+    BOOL fpipe;
+    DWORD len;
+
+    /* Protected by the Chardev chr_write_lock.  */
+    OVERLAPPED osend;
+    /* FIXME: file/console do not finalize */
+    BOOL skip_free;
+} WinChardev;
+
+#define NSENDBUF 2048
+#define NRECVBUF 2048
+
+#define TYPE_CHARDEV_WIN "chardev-win"
+#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN)
+
+void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out);
+int win_chr_init(Chardev *chr, const char *filename, Error **errp);
+int win_chr_pipe_poll(void *opaque);
+
+#endif /* CHAR_WIN_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 44/54] char: move win-stdio into its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (42 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 43/54] char: move win chardev base class " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 45/54] char: move socket chardev to itw " Marc-André Lureau
                   ` (11 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-win-stdio.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c           | 231 +-------------------------------------------
 chardev/Makefile.objs    |   1 +
 chardev/char-win-stdio.h |   6 ++
 4 files changed, 252 insertions(+), 229 deletions(-)
 create mode 100644 chardev/char-win-stdio.c
 create mode 100644 chardev/char-win-stdio.h

diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c
new file mode 100644
index 0000000000..78d1f7cf29
--- /dev/null
+++ b/chardev/char-win-stdio.c
@@ -0,0 +1,243 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "char-win.h"
+#include "char-win-stdio.h"
+
+typedef struct {
+    Chardev parent;
+    HANDLE  hStdIn;
+    HANDLE  hInputReadyEvent;
+    HANDLE  hInputDoneEvent;
+    HANDLE  hInputThread;
+    uint8_t win_stdio_buf;
+} WinStdioChardev;
+
+#define WIN_STDIO_CHARDEV(obj)                                          \
+    OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
+
+static void win_stdio_wait_func(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
+    INPUT_RECORD       buf[4];
+    int                ret;
+    DWORD              dwSize;
+    int                i;
+
+    ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(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)
+{
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
+    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)
+{
+    Chardev *chr = CHARDEV(opaque);
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(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(Chardev *chr, bool echo)
+{
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
+    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 qemu_chr_open_stdio(Chardev *chr,
+                                ChardevBackend *backend,
+                                bool *be_opened,
+                                Error **errp)
+{
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
+    DWORD              dwMode;
+    int                is_console = 0;
+
+    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
+        error_setg(errp, "cannot open stdio: invalid handle");
+        return;
+    }
+
+    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+
+    if (is_console) {
+        if (qemu_add_wait_object(stdio->hStdIn,
+                                 win_stdio_wait_func, chr)) {
+            error_setg(errp, "qemu_add_wait_object: failed");
+            goto err1;
+        }
+    } else {
+        DWORD   dwId;
+
+        stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+        stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
+        if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+            || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+            error_setg(errp, "cannot create event");
+            goto err2;
+        }
+        if (qemu_add_wait_object(stdio->hInputReadyEvent,
+                                 win_stdio_thread_wait_func, chr)) {
+            error_setg(errp, "qemu_add_wait_object: failed");
+            goto err2;
+        }
+        stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
+                                               chr, 0, &dwId);
+
+        if (stdio->hInputThread == INVALID_HANDLE_VALUE) {
+            error_setg(errp, "cannot create stdio thread");
+            goto err3;
+        }
+    }
+
+    dwMode |= ENABLE_LINE_INPUT;
+
+    if (is_console) {
+        /* set the terminal in raw mode */
+        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
+        dwMode |= ENABLE_PROCESSED_INPUT;
+    }
+
+    SetConsoleMode(stdio->hStdIn, dwMode);
+
+    qemu_chr_set_echo_win_stdio(chr, false);
+
+    return;
+
+err3:
+    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
+err2:
+    CloseHandle(stdio->hInputReadyEvent);
+    CloseHandle(stdio->hInputDoneEvent);
+err1:
+    qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
+}
+
+static void char_win_stdio_finalize(Object *obj)
+{
+    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
+
+    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);
+    }
+}
+
+static int win_stdio_write(Chardev *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 char_win_stdio_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_stdio;
+    cc->chr_write = win_stdio_write;
+    cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
+}
+
+static const TypeInfo char_win_stdio_type_info = {
+    .name = TYPE_CHARDEV_WIN_STDIO,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(WinStdioChardev),
+    .instance_finalize = char_win_stdio_finalize,
+    .class_init = char_win_stdio_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_win_stdio_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 3b7140482c..470549afa4 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -90,6 +90,7 @@
 #include "char-io.h"
 #ifdef _WIN32
 #include "char-win.h"
+#include "char-win-stdio.h"
 #endif
 
 #define TCP_MAX_FDS 16
@@ -1472,19 +1473,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr,
 
 #define HAVE_CHARDEV_SERIAL 1
 
-typedef struct {
-    Chardev parent;
-    HANDLE  hStdIn;
-    HANDLE  hInputReadyEvent;
-    HANDLE  hInputDoneEvent;
-    HANDLE  hInputThread;
-    uint8_t win_stdio_buf;
-} WinStdioChardev;
-
-#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
-#define WIN_STDIO_CHARDEV(obj)                                  \
-    OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
-
 #define MAXCONNECT 1
 #define NTIMEOUT 5000
 
@@ -1586,215 +1574,6 @@ static const TypeInfo char_console_type_info = {
     .class_init = char_console_class_init,
 };
 
-static int win_stdio_write(Chardev *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)
-{
-    Chardev *chr = CHARDEV(opaque);
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
-    INPUT_RECORD       buf[4];
-    int                ret;
-    DWORD              dwSize;
-    int                i;
-
-    ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(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)
-{
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
-    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)
-{
-    Chardev *chr = CHARDEV(opaque);
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(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(Chardev *chr, bool echo)
-{
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
-    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 char_win_stdio_finalize(Object *obj)
-{
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
-
-    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);
-    }
-}
-
-static const TypeInfo char_win_stdio_type_info = {
-    .name = TYPE_CHARDEV_WIN_STDIO,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(WinStdioChardev),
-    .instance_finalize = char_win_stdio_finalize,
-    .abstract = true,
-};
-
-static void qemu_chr_open_stdio(Chardev *chr,
-                                ChardevBackend *backend,
-                                bool *be_opened,
-                                Error **errp)
-{
-    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
-    DWORD              dwMode;
-    int                is_console = 0;
-
-    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
-    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
-        error_setg(errp, "cannot open stdio: invalid handle");
-        return;
-    }
-
-    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
-
-    if (is_console) {
-        if (qemu_add_wait_object(stdio->hStdIn,
-                                 win_stdio_wait_func, chr)) {
-            error_setg(errp, "qemu_add_wait_object: failed");
-            goto err1;
-        }
-    } else {
-        DWORD   dwId;
-            
-        stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-        stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
-            || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
-            error_setg(errp, "cannot create event");
-            goto err2;
-        }
-        if (qemu_add_wait_object(stdio->hInputReadyEvent,
-                                 win_stdio_thread_wait_func, chr)) {
-            error_setg(errp, "qemu_add_wait_object: failed");
-            goto err2;
-        }
-        stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
-                                               chr, 0, &dwId);
-
-        if (stdio->hInputThread == INVALID_HANDLE_VALUE) {
-            error_setg(errp, "cannot create stdio thread");
-            goto err3;
-        }
-    }
-
-    dwMode |= ENABLE_LINE_INPUT;
-
-    if (is_console) {
-        /* set the terminal in raw mode */
-        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
-        dwMode |= ENABLE_PROCESSED_INPUT;
-    }
-
-    SetConsoleMode(stdio->hStdIn, dwMode);
-
-    qemu_chr_set_echo_win_stdio(chr, false);
-
-    return;
-
-err3:
-    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
-err2:
-    CloseHandle(stdio->hInputReadyEvent);
-    CloseHandle(stdio->hInputDoneEvent);
-err1:
-    qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
-}
 #endif /* !_WIN32 */
 
 /***********************************************************/
@@ -2780,11 +2559,8 @@ static void char_stdio_class_init(ObjectClass *oc, void *data)
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
     cc->parse = qemu_chr_parse_stdio;
+#ifndef _WIN32
     cc->open = qemu_chr_open_stdio;
-#ifdef _WIN32
-    cc->chr_write = win_stdio_write;
-    cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
-#else
     cc->chr_set_echo = qemu_chr_set_echo_stdio;
 #endif
 }
@@ -3931,9 +3707,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-#ifdef _WIN32
-    type_register_static(&char_win_stdio_type_info);
-#endif
     type_register_static(&char_socket_type_info);
     type_register_static(&char_udp_type_info);
     type_register_static(&char_file_type_info);
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index bdf5a112a7..3c4a328de8 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -5,3 +5,4 @@ chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
 chardev-obj-$(CONFIG_WIN32) += char-win.o
+chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
diff --git a/chardev/char-win-stdio.h b/chardev/char-win-stdio.h
new file mode 100644
index 0000000000..50ad99300a
--- /dev/null
+++ b/chardev/char-win-stdio.h
@@ -0,0 +1,6 @@
+#ifndef CHAR_WIN_STDIO_H
+#define CHAR_WIN_STDIO_H
+
+#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
+
+#endif /* CHAR_WIN_STDIO_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 45/54] char: move socket chardev to itw own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (43 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 44/54] char: move win-stdio into " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 46/54] char: move udp chardev in its " Marc-André Lureau
                   ` (10 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-socket.c | 995 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 980 +------------------------------------------------
 chardev/Makefile.objs |   1 +
 include/sysemu/char.h |   1 +
 4 files changed, 998 insertions(+), 979 deletions(-)
 create mode 100644 chardev/char-socket.c

diff --git a/chardev/char-socket.c b/chardev/char-socket.c
new file mode 100644
index 0000000000..6b1ede732f
--- /dev/null
+++ b/chardev/char-socket.c
@@ -0,0 +1,995 @@
+#include "qemu/osdep.h"
+#include "sysemu/char.h"
+#include "io/channel-socket.h"
+#include "io/channel-tls.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/clone-visitor.h"
+
+#include "char-io.h"
+
+/***********************************************************/
+/* TCP Net console */
+
+#define TCP_MAX_FDS 16
+
+typedef struct {
+    Chardev parent;
+    QIOChannel *ioc; /* Client I/O channel */
+    QIOChannelSocket *sioc; /* Client master channel */
+    QIOChannelSocket *listen_ioc;
+    guint listen_tag;
+    QCryptoTLSCreds *tls_creds;
+    int connected;
+    int max_size;
+    int do_telnetopt;
+    int do_nodelay;
+    int is_unix;
+    int *read_msgfds;
+    size_t read_msgfds_num;
+    int *write_msgfds;
+    size_t write_msgfds_num;
+
+    SocketAddress *addr;
+    bool is_listen;
+    bool is_telnet;
+
+    guint reconnect_timer;
+    int64_t reconnect_time;
+    bool connect_err_reported;
+} SocketChardev;
+
+#define SOCKET_CHARDEV(obj)                                     \
+    OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
+
+static gboolean socket_reconnect_timeout(gpointer opaque);
+
+static void qemu_chr_socket_restart_timer(Chardev *chr)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    char *name;
+
+    assert(s->connected == 0);
+    s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
+                                               socket_reconnect_timeout, chr);
+    name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
+    g_source_set_name_by_id(s->reconnect_timer, name);
+    g_free(name);
+}
+
+static void check_report_connect_error(Chardev *chr,
+                                       Error *err)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (!s->connect_err_reported) {
+        error_report("Unable to connect character device %s: %s",
+                     chr->label, error_get_pretty(err));
+        s->connect_err_reported = true;
+    }
+    qemu_chr_socket_restart_timer(chr);
+}
+
+static gboolean tcp_chr_accept(QIOChannel *chan,
+                               GIOCondition cond,
+                               void *opaque);
+
+/* Called with chr_write_lock held.  */
+static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (s->connected) {
+        int ret =  io_channel_send_full(s->ioc, buf, len,
+                                        s->write_msgfds,
+                                        s->write_msgfds_num);
+
+        /* free the written msgfds, no matter what */
+        if (s->write_msgfds_num) {
+            g_free(s->write_msgfds);
+            s->write_msgfds = 0;
+            s->write_msgfds_num = 0;
+        }
+
+        return ret;
+    } else {
+        /* XXX: indicate an error ? */
+        return len;
+    }
+}
+
+static int tcp_chr_read_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
+    if (!s->connected) {
+        return 0;
+    }
+    s->max_size = qemu_chr_be_can_write(chr);
+    return s->max_size;
+}
+
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(Chardev *chr,
+                                      SocketChardev *s,
+                                      uint8_t *buf, int *size)
+{
+    /* Handle any telnet client's basic IAC options to satisfy char by
+     * char mode with no echo.  All IAC options will be removed from
+     * the buf and the do_telnetopt variable will be used to track the
+     * state of the width of the IAC information.
+     *
+     * IAC commands come in sets of 3 bytes with the exception of the
+     * "IAC BREAK" command and the double IAC.
+     */
+
+    int i;
+    int j = 0;
+
+    for (i = 0; i < *size; i++) {
+        if (s->do_telnetopt > 1) {
+            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                /* Double IAC means send an IAC */
+                if (j != i) {
+                    buf[j] = buf[i];
+                }
+                j++;
+                s->do_telnetopt = 1;
+            } else {
+                if ((unsigned char)buf[i] == IAC_BREAK
+                    && s->do_telnetopt == 2) {
+                    /* Handle IAC break commands by sending a serial break */
+                    qemu_chr_be_event(chr, CHR_EVENT_BREAK);
+                    s->do_telnetopt++;
+                }
+                s->do_telnetopt++;
+            }
+            if (s->do_telnetopt >= 4) {
+                s->do_telnetopt = 1;
+            }
+        } else {
+            if ((unsigned char)buf[i] == IAC) {
+                s->do_telnetopt = 2;
+            } else {
+                if (j != i) {
+                    buf[j] = buf[i];
+                }
+                j++;
+            }
+        }
+    }
+    *size = j;
+}
+
+static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
+
+    assert(num <= TCP_MAX_FDS);
+
+    if (to_copy) {
+        int i;
+
+        memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
+
+        /* Close unused fds */
+        for (i = to_copy; i < s->read_msgfds_num; i++) {
+            close(s->read_msgfds[i]);
+        }
+
+        g_free(s->read_msgfds);
+        s->read_msgfds = 0;
+        s->read_msgfds_num = 0;
+    }
+
+    return to_copy;
+}
+
+static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    /* clear old pending fd array */
+    g_free(s->write_msgfds);
+    s->write_msgfds = NULL;
+    s->write_msgfds_num = 0;
+
+    if (!s->connected ||
+        !qio_channel_has_feature(s->ioc,
+                                 QIO_CHANNEL_FEATURE_FD_PASS)) {
+        return -1;
+    }
+
+    if (num) {
+        s->write_msgfds = g_new(int, num);
+        memcpy(s->write_msgfds, fds, num * sizeof(int));
+    }
+
+    s->write_msgfds_num = num;
+
+    return 0;
+}
+
+static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    struct iovec iov = { .iov_base = buf, .iov_len = len };
+    int ret;
+    size_t i;
+    int *msgfds = NULL;
+    size_t msgfds_num = 0;
+
+    if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
+        ret = qio_channel_readv_full(s->ioc, &iov, 1,
+                                     &msgfds, &msgfds_num,
+                                     NULL);
+    } else {
+        ret = qio_channel_readv_full(s->ioc, &iov, 1,
+                                     NULL, NULL,
+                                     NULL);
+    }
+
+    if (ret == QIO_CHANNEL_ERR_BLOCK) {
+        errno = EAGAIN;
+        ret = -1;
+    } else if (ret == -1) {
+        errno = EIO;
+    }
+
+    if (msgfds_num) {
+        /* close and clean read_msgfds */
+        for (i = 0; i < s->read_msgfds_num; i++) {
+            close(s->read_msgfds[i]);
+        }
+
+        if (s->read_msgfds_num) {
+            g_free(s->read_msgfds);
+        }
+
+        s->read_msgfds = msgfds;
+        s->read_msgfds_num = msgfds_num;
+    }
+
+    for (i = 0; i < s->read_msgfds_num; i++) {
+        int fd = s->read_msgfds[i];
+        if (fd < 0) {
+            continue;
+        }
+
+        /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
+        qemu_set_block(fd);
+
+#ifndef MSG_CMSG_CLOEXEC
+        qemu_set_cloexec(fd);
+#endif
+    }
+
+    return ret;
+}
+
+static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    return qio_channel_create_watch(s->ioc, cond);
+}
+
+static void tcp_chr_free_connection(Chardev *chr)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    int i;
+
+    if (!s->connected) {
+        return;
+    }
+
+    if (s->read_msgfds_num) {
+        for (i = 0; i < s->read_msgfds_num; i++) {
+            close(s->read_msgfds[i]);
+        }
+        g_free(s->read_msgfds);
+        s->read_msgfds = NULL;
+        s->read_msgfds_num = 0;
+    }
+
+    tcp_set_msgfds(chr, NULL, 0);
+    remove_fd_in_watch(chr);
+    object_unref(OBJECT(s->sioc));
+    s->sioc = NULL;
+    object_unref(OBJECT(s->ioc));
+    s->ioc = NULL;
+    g_free(chr->filename);
+    chr->filename = NULL;
+    s->connected = 0;
+}
+
+static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
+                                  bool is_listen, bool is_telnet)
+{
+    switch (addr->type) {
+    case SOCKET_ADDRESS_KIND_INET:
+        return g_strdup_printf("%s%s:%s:%s%s", prefix,
+                               is_telnet ? "telnet" : "tcp",
+                               addr->u.inet.data->host,
+                               addr->u.inet.data->port,
+                               is_listen ? ",server" : "");
+        break;
+    case SOCKET_ADDRESS_KIND_UNIX:
+        return g_strdup_printf("%sunix:%s%s", prefix,
+                               addr->u.q_unix.data->path,
+                               is_listen ? ",server" : "");
+        break;
+    case SOCKET_ADDRESS_KIND_FD:
+        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
+                               is_listen ? ",server" : "");
+        break;
+    default:
+        abort();
+    }
+}
+
+static void tcp_chr_disconnect(Chardev *chr)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (!s->connected) {
+        return;
+    }
+
+    tcp_chr_free_connection(chr);
+
+    if (s->listen_ioc) {
+        s->listen_tag = qio_channel_add_watch(
+            QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
+    }
+    chr->filename = SocketAddress_to_str("disconnected:", s->addr,
+                                         s->is_listen, s->is_telnet);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+    if (s->reconnect_time) {
+        qemu_chr_socket_restart_timer(chr);
+    }
+}
+
+static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
+    uint8_t buf[CHR_READ_BUF_LEN];
+    int len, size;
+
+    if (!s->connected || s->max_size <= 0) {
+        return TRUE;
+    }
+    len = sizeof(buf);
+    if (len > s->max_size) {
+        len = s->max_size;
+    }
+    size = tcp_chr_recv(chr, (void *)buf, len);
+    if (size == 0 || size == -1) {
+        /* connection closed */
+        tcp_chr_disconnect(chr);
+    } else if (size > 0) {
+        if (s->do_telnetopt) {
+            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+        }
+        if (size > 0) {
+            qemu_chr_be_write(chr, buf, size);
+        }
+    }
+
+    return TRUE;
+}
+
+static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    int size;
+
+    if (!s->connected) {
+        return 0;
+    }
+
+    size = tcp_chr_recv(chr, (void *) buf, len);
+    if (size == 0) {
+        /* connection closed */
+        tcp_chr_disconnect(chr);
+    }
+
+    return size;
+}
+
+static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
+                             struct sockaddr_storage *ps, socklen_t ps_len,
+                             bool is_listen, bool is_telnet)
+{
+    char shost[NI_MAXHOST], sserv[NI_MAXSERV];
+    char phost[NI_MAXHOST], pserv[NI_MAXSERV];
+    const char *left = "", *right = "";
+
+    switch (ss->ss_family) {
+#ifndef _WIN32
+    case AF_UNIX:
+        return g_strdup_printf("unix:%s%s",
+                               ((struct sockaddr_un *)(ss))->sun_path,
+                               is_listen ? ",server" : "");
+#endif
+    case AF_INET6:
+        left  = "[";
+        right = "]";
+        /* fall through */
+    case AF_INET:
+        getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
+                    sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
+        getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
+                    pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
+        return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
+                               is_telnet ? "telnet" : "tcp",
+                               left, shost, right, sserv,
+                               is_listen ? ",server" : "",
+                               left, phost, right, pserv);
+
+    default:
+        return g_strdup_printf("unknown");
+    }
+}
+
+static void tcp_chr_connect(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
+
+    g_free(chr->filename);
+    chr->filename = sockaddr_to_str(
+        &s->sioc->localAddr, s->sioc->localAddrLen,
+        &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
+        s->is_listen, s->is_telnet);
+
+    s->connected = 1;
+    if (s->ioc) {
+        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+                                           tcp_chr_read_poll,
+                                           tcp_chr_read,
+                                           chr, NULL);
+    }
+    qemu_chr_be_generic_open(chr);
+}
+
+static void tcp_chr_update_read_handler(Chardev *chr,
+                                        GMainContext *context)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (!s->connected) {
+        return;
+    }
+
+    remove_fd_in_watch(chr);
+    if (s->ioc) {
+        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+                                           tcp_chr_read_poll,
+                                           tcp_chr_read, chr,
+                                           context);
+    }
+}
+
+typedef struct {
+    Chardev *chr;
+    char buf[12];
+    size_t buflen;
+} TCPCharDriverTelnetInit;
+
+static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
+                                       GIOCondition cond G_GNUC_UNUSED,
+                                       gpointer user_data)
+{
+    TCPCharDriverTelnetInit *init = user_data;
+    ssize_t ret;
+
+    ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
+    if (ret < 0) {
+        if (ret == QIO_CHANNEL_ERR_BLOCK) {
+            ret = 0;
+        } else {
+            tcp_chr_disconnect(init->chr);
+            return FALSE;
+        }
+    }
+    init->buflen -= ret;
+
+    if (init->buflen == 0) {
+        tcp_chr_connect(init->chr);
+        return FALSE;
+    }
+
+    memmove(init->buf, init->buf + ret, init->buflen);
+
+    return TRUE;
+}
+
+static void tcp_chr_telnet_init(Chardev *chr)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    TCPCharDriverTelnetInit *init =
+        g_new0(TCPCharDriverTelnetInit, 1);
+    size_t n = 0;
+
+    init->chr = chr;
+    init->buflen = 12;
+
+#define IACSET(x, a, b, c)                      \
+    do {                                        \
+        x[n++] = a;                             \
+        x[n++] = b;                             \
+        x[n++] = c;                             \
+    } while (0)
+
+    /* Prep the telnet negotion to put telnet in binary,
+     * no echo, single char mode */
+    IACSET(init->buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+    IACSET(init->buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+    IACSET(init->buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+    IACSET(init->buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+
+#undef IACSET
+
+    qio_channel_add_watch(
+        s->ioc, G_IO_OUT,
+        tcp_chr_telnet_init_io,
+        init, NULL);
+}
+
+
+static void tcp_chr_tls_handshake(Object *source,
+                                  Error *err,
+                                  gpointer user_data)
+{
+    Chardev *chr = user_data;
+    SocketChardev *s = user_data;
+
+    if (err) {
+        tcp_chr_disconnect(chr);
+    } else {
+        if (s->do_telnetopt) {
+            tcp_chr_telnet_init(chr);
+        } else {
+            tcp_chr_connect(chr);
+        }
+    }
+}
+
+
+static void tcp_chr_tls_init(Chardev *chr)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    QIOChannelTLS *tioc;
+    Error *err = NULL;
+    gchar *name;
+
+    if (s->is_listen) {
+        tioc = qio_channel_tls_new_server(
+            s->ioc, s->tls_creds,
+            NULL, /* XXX Use an ACL */
+            &err);
+    } else {
+        tioc = qio_channel_tls_new_client(
+            s->ioc, s->tls_creds,
+            s->addr->u.inet.data->host,
+            &err);
+    }
+    if (tioc == NULL) {
+        error_free(err);
+        tcp_chr_disconnect(chr);
+        return;
+    }
+    name = g_strdup_printf("chardev-tls-%s-%s",
+                           s->is_listen ? "server" : "client",
+                           chr->label);
+    qio_channel_set_name(QIO_CHANNEL(tioc), name);
+    g_free(name);
+    object_unref(OBJECT(s->ioc));
+    s->ioc = QIO_CHANNEL(tioc);
+
+    qio_channel_tls_handshake(tioc,
+                              tcp_chr_tls_handshake,
+                              chr,
+                              NULL);
+}
+
+
+static void tcp_chr_set_client_ioc_name(Chardev *chr,
+                                        QIOChannelSocket *sioc)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    char *name;
+    name = g_strdup_printf("chardev-tcp-%s-%s",
+                           s->is_listen ? "server" : "client",
+                           chr->label);
+    qio_channel_set_name(QIO_CHANNEL(sioc), name);
+    g_free(name);
+
+}
+
+static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (s->ioc != NULL) {
+        return -1;
+    }
+
+    s->ioc = QIO_CHANNEL(sioc);
+    object_ref(OBJECT(sioc));
+    s->sioc = sioc;
+    object_ref(OBJECT(sioc));
+
+    qio_channel_set_blocking(s->ioc, false, NULL);
+
+    if (s->do_nodelay) {
+        qio_channel_set_delay(s->ioc, false);
+    }
+    if (s->listen_tag) {
+        g_source_remove(s->listen_tag);
+        s->listen_tag = 0;
+    }
+
+    if (s->tls_creds) {
+        tcp_chr_tls_init(chr);
+    } else {
+        if (s->do_telnetopt) {
+            tcp_chr_telnet_init(chr);
+        } else {
+            tcp_chr_connect(chr);
+        }
+    }
+
+    return 0;
+}
+
+
+static int tcp_chr_add_client(Chardev *chr, int fd)
+{
+    int ret;
+    QIOChannelSocket *sioc;
+
+    sioc = qio_channel_socket_new_fd(fd, NULL);
+    if (!sioc) {
+        return -1;
+    }
+    tcp_chr_set_client_ioc_name(chr, sioc);
+    ret = tcp_chr_new_client(chr, sioc);
+    object_unref(OBJECT(sioc));
+    return ret;
+}
+
+static gboolean tcp_chr_accept(QIOChannel *channel,
+                               GIOCondition cond,
+                               void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    QIOChannelSocket *sioc;
+
+    sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
+                                     NULL);
+    if (!sioc) {
+        return TRUE;
+    }
+
+    tcp_chr_new_client(chr, sioc);
+
+    object_unref(OBJECT(sioc));
+
+    return TRUE;
+}
+
+static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    QIOChannelSocket *sioc;
+
+    /* It can't wait on s->connected, since it is set asynchronously
+     * in TLS and telnet cases, only wait for an accepted socket */
+    while (!s->ioc) {
+        if (s->is_listen) {
+            error_report("QEMU waiting for connection on: %s",
+                         chr->filename);
+            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
+            tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
+            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
+        } else {
+            sioc = qio_channel_socket_new();
+            tcp_chr_set_client_ioc_name(chr, sioc);
+            if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
+                object_unref(OBJECT(sioc));
+                return -1;
+            }
+            tcp_chr_new_client(chr, sioc);
+            object_unref(OBJECT(sioc));
+        }
+    }
+
+    return 0;
+}
+
+static void char_socket_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+    SocketChardev *s = SOCKET_CHARDEV(obj);
+
+    tcp_chr_free_connection(chr);
+
+    if (s->reconnect_timer) {
+        g_source_remove(s->reconnect_timer);
+        s->reconnect_timer = 0;
+    }
+    qapi_free_SocketAddress(s->addr);
+    if (s->listen_tag) {
+        g_source_remove(s->listen_tag);
+        s->listen_tag = 0;
+    }
+    if (s->listen_ioc) {
+        object_unref(OBJECT(s->listen_ioc));
+    }
+    if (s->tls_creds) {
+        object_unref(OBJECT(s->tls_creds));
+    }
+
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+}
+
+
+static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
+{
+    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+
+    if (err) {
+        check_report_connect_error(chr, err);
+        object_unref(src);
+        return;
+    }
+
+    s->connect_err_reported = false;
+    tcp_chr_new_client(chr, sioc);
+    object_unref(OBJECT(sioc));
+}
+static gboolean socket_reconnect_timeout(gpointer opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    SocketChardev *s = SOCKET_CHARDEV(opaque);
+    QIOChannelSocket *sioc;
+
+    s->reconnect_timer = 0;
+
+    if (chr->be_open) {
+        return false;
+    }
+
+    sioc = qio_channel_socket_new();
+    tcp_chr_set_client_ioc_name(chr, sioc);
+    qio_channel_socket_connect_async(sioc, s->addr,
+                                     qemu_chr_socket_connected,
+                                     chr, NULL);
+
+    return false;
+}
+
+static void qmp_chardev_open_socket(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
+{
+    SocketChardev *s = SOCKET_CHARDEV(chr);
+    ChardevSocket *sock = backend->u.socket.data;
+    SocketAddress *addr = sock->addr;
+    bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
+    bool is_listen      = sock->has_server  ? sock->server  : true;
+    bool is_telnet      = sock->has_telnet  ? sock->telnet  : false;
+    bool is_waitconnect = sock->has_wait    ? sock->wait    : false;
+    int64_t reconnect   = sock->has_reconnect ? sock->reconnect : 0;
+    QIOChannelSocket *sioc = NULL;
+
+    s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
+    s->is_listen = is_listen;
+    s->is_telnet = is_telnet;
+    s->do_nodelay = do_nodelay;
+    if (sock->tls_creds) {
+        Object *creds;
+        creds = object_resolve_path_component(
+            object_get_objects_root(), sock->tls_creds);
+        if (!creds) {
+            error_setg(errp, "No TLS credentials with id '%s'",
+                       sock->tls_creds);
+            goto error;
+        }
+        s->tls_creds = (QCryptoTLSCreds *)
+            object_dynamic_cast(creds,
+                                TYPE_QCRYPTO_TLS_CREDS);
+        if (!s->tls_creds) {
+            error_setg(errp, "Object with id '%s' is not TLS credentials",
+                       sock->tls_creds);
+            goto error;
+        }
+        object_ref(OBJECT(s->tls_creds));
+        if (is_listen) {
+            if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+                error_setg(errp, "%s",
+                           "Expected TLS credentials for server endpoint");
+                goto error;
+            }
+        } else {
+            if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+                error_setg(errp, "%s",
+                           "Expected TLS credentials for client endpoint");
+                goto error;
+            }
+        }
+    }
+
+    s->addr = QAPI_CLONE(SocketAddress, sock->addr);
+
+    qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
+    if (s->is_unix) {
+        qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
+    }
+
+    /* be isn't opened until we get a connection */
+    *be_opened = false;
+
+    chr->filename = SocketAddress_to_str("disconnected:",
+                                         addr, is_listen, is_telnet);
+
+    if (is_listen) {
+        if (is_telnet) {
+            s->do_telnetopt = 1;
+        }
+    } else if (reconnect > 0) {
+        s->reconnect_time = reconnect;
+    }
+
+    if (s->reconnect_time) {
+        sioc = qio_channel_socket_new();
+        tcp_chr_set_client_ioc_name(chr, sioc);
+        qio_channel_socket_connect_async(sioc, s->addr,
+                                         qemu_chr_socket_connected,
+                                         chr, NULL);
+    } else {
+        if (s->is_listen) {
+            char *name;
+            sioc = qio_channel_socket_new();
+
+            name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
+            qio_channel_set_name(QIO_CHANNEL(sioc), name);
+            g_free(name);
+
+            if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
+                goto error;
+            }
+            s->listen_ioc = sioc;
+            if (is_waitconnect &&
+                qemu_chr_wait_connected(chr, errp) < 0) {
+                goto error;
+            }
+            if (!s->ioc) {
+                s->listen_tag = qio_channel_add_watch(
+                    QIO_CHANNEL(s->listen_ioc), G_IO_IN,
+                    tcp_chr_accept, chr, NULL);
+            }
+        } else if (qemu_chr_wait_connected(chr, errp) < 0) {
+            goto error;
+        }
+    }
+
+    return;
+
+error:
+    if (sioc) {
+        object_unref(OBJECT(sioc));
+    }
+    if (s->tls_creds) {
+        object_unref(OBJECT(s->tls_creds));
+    }
+}
+
+static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
+                                  Error **errp)
+{
+    bool is_listen      = qemu_opt_get_bool(opts, "server", false);
+    bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
+    bool is_telnet      = qemu_opt_get_bool(opts, "telnet", false);
+    bool do_nodelay     = !qemu_opt_get_bool(opts, "delay", true);
+    int64_t reconnect   = qemu_opt_get_number(opts, "reconnect", 0);
+    const char *path = qemu_opt_get(opts, "path");
+    const char *host = qemu_opt_get(opts, "host");
+    const char *port = qemu_opt_get(opts, "port");
+    const char *tls_creds = qemu_opt_get(opts, "tls-creds");
+    SocketAddress *addr;
+    ChardevSocket *sock;
+
+    if (!path) {
+        if (!host) {
+            error_setg(errp, "chardev: socket: no host given");
+            return;
+        }
+        if (!port) {
+            error_setg(errp, "chardev: socket: no port given");
+            return;
+        }
+    } else {
+        if (tls_creds) {
+            error_setg(errp, "TLS can only be used over TCP socket");
+            return;
+        }
+    }
+
+    sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
+
+    sock->has_nodelay = true;
+    sock->nodelay = do_nodelay;
+    sock->has_server = true;
+    sock->server = is_listen;
+    sock->has_telnet = true;
+    sock->telnet = is_telnet;
+    sock->has_wait = true;
+    sock->wait = is_waitconnect;
+    sock->has_reconnect = true;
+    sock->reconnect = reconnect;
+    sock->tls_creds = g_strdup(tls_creds);
+
+    addr = g_new0(SocketAddress, 1);
+    if (path) {
+        UnixSocketAddress *q_unix;
+        addr->type = SOCKET_ADDRESS_KIND_UNIX;
+        q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+        q_unix->path = g_strdup(path);
+    } else {
+        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->u.inet.data = g_new(InetSocketAddress, 1);
+        *addr->u.inet.data = (InetSocketAddress) {
+            .host = g_strdup(host),
+            .port = g_strdup(port),
+            .has_to = qemu_opt_get(opts, "to"),
+            .to = qemu_opt_get_number(opts, "to", 0),
+            .has_ipv4 = qemu_opt_get(opts, "ipv4"),
+            .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
+            .has_ipv6 = qemu_opt_get(opts, "ipv6"),
+            .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
+        };
+    }
+    sock->addr = addr;
+}
+
+static void char_socket_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_socket;
+    cc->open = qmp_chardev_open_socket;
+    cc->chr_wait_connected = tcp_chr_wait_connected;
+    cc->chr_write = tcp_chr_write;
+    cc->chr_sync_read = tcp_chr_sync_read;
+    cc->chr_disconnect = tcp_chr_disconnect;
+    cc->get_msgfds = tcp_get_msgfds;
+    cc->set_msgfds = tcp_set_msgfds;
+    cc->chr_add_client = tcp_chr_add_client;
+    cc->chr_add_watch = tcp_chr_add_watch;
+    cc->chr_update_read_handler = tcp_chr_update_read_handler;
+}
+
+static const TypeInfo char_socket_type_info = {
+    .name = TYPE_CHARDEV_SOCKET,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(SocketChardev),
+    .instance_finalize = char_socket_finalize,
+    .class_init = char_socket_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_socket_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 470549afa4..784a60ac53 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -93,71 +93,6 @@
 #include "char-win-stdio.h"
 #endif
 
-#define TCP_MAX_FDS 16
-
-/***********************************************************/
-/* Socket address helpers */
-
-static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
-                                  bool is_listen, bool is_telnet)
-{
-    switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        return g_strdup_printf("%s%s:%s:%s%s", prefix,
-                               is_telnet ? "telnet" : "tcp",
-                               addr->u.inet.data->host,
-                               addr->u.inet.data->port,
-                               is_listen ? ",server" : "");
-        break;
-    case SOCKET_ADDRESS_KIND_UNIX:
-        return g_strdup_printf("%sunix:%s%s", prefix,
-                               addr->u.q_unix.data->path,
-                               is_listen ? ",server" : "");
-        break;
-    case SOCKET_ADDRESS_KIND_FD:
-        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
-                               is_listen ? ",server" : "");
-        break;
-    default:
-        abort();
-    }
-}
-
-static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
-                             struct sockaddr_storage *ps, socklen_t ps_len,
-                             bool is_listen, bool is_telnet)
-{
-    char shost[NI_MAXHOST], sserv[NI_MAXSERV];
-    char phost[NI_MAXHOST], pserv[NI_MAXSERV];
-    const char *left = "", *right = "";
-
-    switch (ss->ss_family) {
-#ifndef _WIN32
-    case AF_UNIX:
-        return g_strdup_printf("unix:%s%s",
-                               ((struct sockaddr_un *)(ss))->sun_path,
-                               is_listen ? ",server" : "");
-#endif
-    case AF_INET6:
-        left  = "[";
-        right = "]";
-        /* fall through */
-    case AF_INET:
-        getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
-                    sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
-        getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
-                    pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
-        return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
-                               is_telnet ? "telnet" : "tcp",
-                               left, shost, right, sserv,
-                               is_listen ? ",server" : "",
-                               left, phost, right, pserv);
-
-    default:
-        return g_strdup_printf("unknown");
-    }
-}
-
 /***********************************************************/
 /* character device */
 
@@ -1670,642 +1605,7 @@ static void char_udp_finalize(Object *obj)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-/***********************************************************/
-/* TCP Net console */
-
-typedef struct {
-    Chardev parent;
-    QIOChannel *ioc; /* Client I/O channel */
-    QIOChannelSocket *sioc; /* Client master channel */
-    QIOChannelSocket *listen_ioc;
-    guint listen_tag;
-    QCryptoTLSCreds *tls_creds;
-    int connected;
-    int max_size;
-    int do_telnetopt;
-    int do_nodelay;
-    int is_unix;
-    int *read_msgfds;
-    size_t read_msgfds_num;
-    int *write_msgfds;
-    size_t write_msgfds_num;
-
-    SocketAddress *addr;
-    bool is_listen;
-    bool is_telnet;
-
-    guint reconnect_timer;
-    int64_t reconnect_time;
-    bool connect_err_reported;
-} SocketChardev;
-
-#define SOCKET_CHARDEV(obj)                                     \
-    OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
-
-static gboolean socket_reconnect_timeout(gpointer opaque);
-
-static void qemu_chr_socket_restart_timer(Chardev *chr)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    char *name;
-
-    assert(s->connected == 0);
-    s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
-                                               socket_reconnect_timeout, chr);
-    name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
-    g_source_set_name_by_id(s->reconnect_timer, name);
-    g_free(name);
-}
-
-static void check_report_connect_error(Chardev *chr,
-                                       Error *err)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (!s->connect_err_reported) {
-        error_report("Unable to connect character device %s: %s",
-                     chr->label, error_get_pretty(err));
-        s->connect_err_reported = true;
-    }
-    qemu_chr_socket_restart_timer(chr);
-}
-
-static gboolean tcp_chr_accept(QIOChannel *chan,
-                               GIOCondition cond,
-                               void *opaque);
-
-/* Called with chr_write_lock held.  */
-static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (s->connected) {
-        int ret =  io_channel_send_full(s->ioc, buf, len,
-                                        s->write_msgfds,
-                                        s->write_msgfds_num);
-
-        /* free the written msgfds, no matter what */
-        if (s->write_msgfds_num) {
-            g_free(s->write_msgfds);
-            s->write_msgfds = 0;
-            s->write_msgfds_num = 0;
-        }
-
-        return ret;
-    } else {
-        /* XXX: indicate an error ? */
-        return len;
-    }
-}
-
-static int tcp_chr_read_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    SocketChardev *s = SOCKET_CHARDEV(opaque);
-    if (!s->connected)
-        return 0;
-    s->max_size = qemu_chr_be_can_write(chr);
-    return s->max_size;
-}
-
-#define IAC 255
-#define IAC_BREAK 243
-static void tcp_chr_process_IAC_bytes(Chardev *chr,
-                                      SocketChardev *s,
-                                      uint8_t *buf, int *size)
-{
-    /* Handle any telnet client's basic IAC options to satisfy char by
-     * char mode with no echo.  All IAC options will be removed from
-     * the buf and the do_telnetopt variable will be used to track the
-     * state of the width of the IAC information.
-     *
-     * IAC commands come in sets of 3 bytes with the exception of the
-     * "IAC BREAK" command and the double IAC.
-     */
-
-    int i;
-    int j = 0;
-
-    for (i = 0; i < *size; i++) {
-        if (s->do_telnetopt > 1) {
-            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
-                /* Double IAC means send an IAC */
-                if (j != i)
-                    buf[j] = buf[i];
-                j++;
-                s->do_telnetopt = 1;
-            } else {
-                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
-                    /* Handle IAC break commands by sending a serial break */
-                    qemu_chr_be_event(chr, CHR_EVENT_BREAK);
-                    s->do_telnetopt++;
-                }
-                s->do_telnetopt++;
-            }
-            if (s->do_telnetopt >= 4) {
-                s->do_telnetopt = 1;
-            }
-        } else {
-            if ((unsigned char)buf[i] == IAC) {
-                s->do_telnetopt = 2;
-            } else {
-                if (j != i)
-                    buf[j] = buf[i];
-                j++;
-            }
-        }
-    }
-    *size = j;
-}
-
-static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
-
-    assert(num <= TCP_MAX_FDS);
-
-    if (to_copy) {
-        int i;
-
-        memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
-
-        /* Close unused fds */
-        for (i = to_copy; i < s->read_msgfds_num; i++) {
-            close(s->read_msgfds[i]);
-        }
-
-        g_free(s->read_msgfds);
-        s->read_msgfds = 0;
-        s->read_msgfds_num = 0;
-    }
-
-    return to_copy;
-}
-
-static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    /* clear old pending fd array */
-    g_free(s->write_msgfds);
-    s->write_msgfds = NULL;
-    s->write_msgfds_num = 0;
-
-    if (!s->connected ||
-        !qio_channel_has_feature(s->ioc,
-                                 QIO_CHANNEL_FEATURE_FD_PASS)) {
-        return -1;
-    }
-
-    if (num) {
-        s->write_msgfds = g_new(int, num);
-        memcpy(s->write_msgfds, fds, num * sizeof(int));
-    }
-
-    s->write_msgfds_num = num;
-
-    return 0;
-}
-
-static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    struct iovec iov = { .iov_base = buf, .iov_len = len };
-    int ret;
-    size_t i;
-    int *msgfds = NULL;
-    size_t msgfds_num = 0;
-
-    if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
-        ret = qio_channel_readv_full(s->ioc, &iov, 1,
-                                     &msgfds, &msgfds_num,
-                                     NULL);
-    } else {
-        ret = qio_channel_readv_full(s->ioc, &iov, 1,
-                                     NULL, NULL,
-                                     NULL);
-    }
-
-    if (ret == QIO_CHANNEL_ERR_BLOCK) {
-        errno = EAGAIN;
-        ret = -1;
-    } else if (ret == -1) {
-        errno = EIO;
-    }
-
-    if (msgfds_num) {
-        /* close and clean read_msgfds */
-        for (i = 0; i < s->read_msgfds_num; i++) {
-            close(s->read_msgfds[i]);
-        }
-
-        if (s->read_msgfds_num) {
-            g_free(s->read_msgfds);
-        }
-
-        s->read_msgfds = msgfds;
-        s->read_msgfds_num = msgfds_num;
-    }
-
-    for (i = 0; i < s->read_msgfds_num; i++) {
-        int fd = s->read_msgfds[i];
-        if (fd < 0) {
-            continue;
-        }
-
-        /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
-        qemu_set_block(fd);
-
-#ifndef MSG_CMSG_CLOEXEC
-        qemu_set_cloexec(fd);
-#endif
-    }
-
-    return ret;
-}
-
-static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    return qio_channel_create_watch(s->ioc, cond);
-}
-
-static void tcp_chr_free_connection(Chardev *chr)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    int i;
-
-    if (!s->connected) {
-        return;
-    }
-
-    if (s->read_msgfds_num) {
-        for (i = 0; i < s->read_msgfds_num; i++) {
-            close(s->read_msgfds[i]);
-        }
-        g_free(s->read_msgfds);
-        s->read_msgfds = NULL;
-        s->read_msgfds_num = 0;
-    }
-
-    tcp_set_msgfds(chr, NULL, 0);
-    remove_fd_in_watch(chr);
-    object_unref(OBJECT(s->sioc));
-    s->sioc = NULL;
-    object_unref(OBJECT(s->ioc));
-    s->ioc = NULL;
-    g_free(chr->filename);
-    chr->filename = NULL;
-    s->connected = 0;
-}
-
-static void tcp_chr_disconnect(Chardev *chr)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (!s->connected) {
-        return;
-    }
-
-    tcp_chr_free_connection(chr);
-
-    if (s->listen_ioc) {
-        s->listen_tag = qio_channel_add_watch(
-            QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
-    }
-    chr->filename = SocketAddress_to_str("disconnected:", s->addr,
-                                         s->is_listen, s->is_telnet);
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-    if (s->reconnect_time) {
-        qemu_chr_socket_restart_timer(chr);
-    }
-}
-
-static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    SocketChardev *s = SOCKET_CHARDEV(opaque);
-    uint8_t buf[CHR_READ_BUF_LEN];
-    int len, size;
-
-    if (!s->connected || s->max_size <= 0) {
-        return TRUE;
-    }
-    len = sizeof(buf);
-    if (len > s->max_size)
-        len = s->max_size;
-    size = tcp_chr_recv(chr, (void *)buf, len);
-    if (size == 0 || size == -1) {
-        /* connection closed */
-        tcp_chr_disconnect(chr);
-    } else if (size > 0) {
-        if (s->do_telnetopt)
-            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
-        if (size > 0)
-            qemu_chr_be_write(chr, buf, size);
-    }
-
-    return TRUE;
-}
-
-static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    int size;
-
-    if (!s->connected) {
-        return 0;
-    }
-
-    size = tcp_chr_recv(chr, (void *) buf, len);
-    if (size == 0) {
-        /* connection closed */
-        tcp_chr_disconnect(chr);
-    }
-
-    return size;
-}
-
-static void tcp_chr_connect(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    SocketChardev *s = SOCKET_CHARDEV(opaque);
-
-    g_free(chr->filename);
-    chr->filename = sockaddr_to_str(
-        &s->sioc->localAddr, s->sioc->localAddrLen,
-        &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
-        s->is_listen, s->is_telnet);
-
-    s->connected = 1;
-    if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
-                                           tcp_chr_read_poll,
-                                           tcp_chr_read,
-                                           chr, NULL);
-    }
-    qemu_chr_be_generic_open(chr);
-}
-
-static void tcp_chr_update_read_handler(Chardev *chr,
-                                        GMainContext *context)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (!s->connected) {
-        return;
-    }
-
-    remove_fd_in_watch(chr);
-    if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
-                                           tcp_chr_read_poll,
-                                           tcp_chr_read, chr,
-                                           context);
-    }
-}
-
-typedef struct {
-    Chardev *chr;
-    char buf[12];
-    size_t buflen;
-} TCPCharDriverTelnetInit;
-
-static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
-                                       GIOCondition cond G_GNUC_UNUSED,
-                                       gpointer user_data)
-{
-    TCPCharDriverTelnetInit *init = user_data;
-    ssize_t ret;
-
-    ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
-    if (ret < 0) {
-        if (ret == QIO_CHANNEL_ERR_BLOCK) {
-            ret = 0;
-        } else {
-            tcp_chr_disconnect(init->chr);
-            return FALSE;
-        }
-    }
-    init->buflen -= ret;
-
-    if (init->buflen == 0) {
-        tcp_chr_connect(init->chr);
-        return FALSE;
-    }
-
-    memmove(init->buf, init->buf + ret, init->buflen);
-
-    return TRUE;
-}
-
-static void tcp_chr_telnet_init(Chardev *chr)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    TCPCharDriverTelnetInit *init =
-        g_new0(TCPCharDriverTelnetInit, 1);
-    size_t n = 0;
-
-    init->chr = chr;
-    init->buflen = 12;
-
-#define IACSET(x, a, b, c)                      \
-    do {                                        \
-        x[n++] = a;                             \
-        x[n++] = b;                             \
-        x[n++] = c;                             \
-    } while (0)
-
-    /* Prep the telnet negotion to put telnet in binary,
-     * no echo, single char mode */
-    IACSET(init->buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
-    IACSET(init->buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
-    IACSET(init->buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
-    IACSET(init->buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
-
-#undef IACSET
-
-    qio_channel_add_watch(
-        s->ioc, G_IO_OUT,
-        tcp_chr_telnet_init_io,
-        init, NULL);
-}
-
-
-static void tcp_chr_tls_handshake(Object *source,
-                                  Error *err,
-                                  gpointer user_data)
-{
-    Chardev *chr = user_data;
-    SocketChardev *s = user_data;
-
-    if (err) {
-        tcp_chr_disconnect(chr);
-    } else {
-        if (s->do_telnetopt) {
-            tcp_chr_telnet_init(chr);
-        } else {
-            tcp_chr_connect(chr);
-        }
-    }
-}
-
-
-static void tcp_chr_tls_init(Chardev *chr)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    QIOChannelTLS *tioc;
-    Error *err = NULL;
-    gchar *name;
-
-    if (s->is_listen) {
-        tioc = qio_channel_tls_new_server(
-            s->ioc, s->tls_creds,
-            NULL, /* XXX Use an ACL */
-            &err);
-    } else {
-        tioc = qio_channel_tls_new_client(
-            s->ioc, s->tls_creds,
-            s->addr->u.inet.data->host,
-            &err);
-    }
-    if (tioc == NULL) {
-        error_free(err);
-        tcp_chr_disconnect(chr);
-        return;
-    }
-    name = g_strdup_printf("chardev-tls-%s-%s",
-                           s->is_listen ? "server" : "client",
-                           chr->label);
-    qio_channel_set_name(QIO_CHANNEL(tioc), name);
-    g_free(name);
-    object_unref(OBJECT(s->ioc));
-    s->ioc = QIO_CHANNEL(tioc);
-
-    qio_channel_tls_handshake(tioc,
-                              tcp_chr_tls_handshake,
-                              chr,
-                              NULL);
-}
-
-
-static void tcp_chr_set_client_ioc_name(Chardev *chr,
-                                        QIOChannelSocket *sioc)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    char *name;
-    name = g_strdup_printf("chardev-tcp-%s-%s",
-                           s->is_listen ? "server" : "client",
-                           chr->label);
-    qio_channel_set_name(QIO_CHANNEL(sioc), name);
-    g_free(name);
-
-}
-
-static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (s->ioc != NULL) {
-	return -1;
-    }
-
-    s->ioc = QIO_CHANNEL(sioc);
-    object_ref(OBJECT(sioc));
-    s->sioc = sioc;
-    object_ref(OBJECT(sioc));
-
-    qio_channel_set_blocking(s->ioc, false, NULL);
-
-    if (s->do_nodelay) {
-        qio_channel_set_delay(s->ioc, false);
-    }
-    if (s->listen_tag) {
-        g_source_remove(s->listen_tag);
-        s->listen_tag = 0;
-    }
-
-    if (s->tls_creds) {
-        tcp_chr_tls_init(chr);
-    } else {
-        if (s->do_telnetopt) {
-            tcp_chr_telnet_init(chr);
-        } else {
-            tcp_chr_connect(chr);
-        }
-    }
-
-    return 0;
-}
-
-
-static int tcp_chr_add_client(Chardev *chr, int fd)
-{
-    int ret;
-    QIOChannelSocket *sioc;
-
-    sioc = qio_channel_socket_new_fd(fd, NULL);
-    if (!sioc) {
-        return -1;
-    }
-    tcp_chr_set_client_ioc_name(chr, sioc);
-    ret = tcp_chr_new_client(chr, sioc);
-    object_unref(OBJECT(sioc));
-    return ret;
-}
-
-static gboolean tcp_chr_accept(QIOChannel *channel,
-                               GIOCondition cond,
-                               void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    QIOChannelSocket *sioc;
-
-    sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
-                                     NULL);
-    if (!sioc) {
-        return TRUE;
-    }
-
-    tcp_chr_new_client(chr, sioc);
-
-    object_unref(OBJECT(sioc));
-
-    return TRUE;
-}
-
-static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    QIOChannelSocket *sioc;
-
-    /* It can't wait on s->connected, since it is set asynchronously
-     * in TLS and telnet cases, only wait for an accepted socket */
-    while (!s->ioc) {
-        if (s->is_listen) {
-            error_report("QEMU waiting for connection on: %s",
-                         chr->filename);
-            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
-            tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
-            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
-        } else {
-            sioc = qio_channel_socket_new();
-            tcp_chr_set_client_ioc_name(chr, sioc);
-            if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
-                object_unref(OBJECT(sioc));
-                return -1;
-            }
-            tcp_chr_new_client(chr, sioc);
-            object_unref(OBJECT(sioc));
-        }
-    }
-
-    return 0;
-}
-
-static int qemu_chr_wait_connected(Chardev *chr, Error **errp)
+int qemu_chr_wait_connected(Chardev *chr, Error **errp)
 {
     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
 
@@ -2326,51 +1626,6 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
     return qemu_chr_wait_connected(be->chr, errp);
 }
 
-static void char_socket_finalize(Object *obj)
-{
-    Chardev *chr = CHARDEV(obj);
-    SocketChardev *s = SOCKET_CHARDEV(obj);
-
-    tcp_chr_free_connection(chr);
-
-    if (s->reconnect_timer) {
-        g_source_remove(s->reconnect_timer);
-        s->reconnect_timer = 0;
-    }
-    qapi_free_SocketAddress(s->addr);
-    if (s->listen_tag) {
-        g_source_remove(s->listen_tag);
-        s->listen_tag = 0;
-    }
-    if (s->listen_ioc) {
-        object_unref(OBJECT(s->listen_ioc));
-    }
-    if (s->tls_creds) {
-        object_unref(OBJECT(s->tls_creds));
-    }
-
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
-
-static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
-{
-    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
-    Chardev *chr = CHARDEV(opaque);
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-
-    if (err) {
-        check_report_connect_error(chr, err);
-        object_unref(src);
-        return;
-    }
-
-    s->connect_err_reported = false;
-    tcp_chr_new_client(chr, sioc);
-    object_unref(OBJECT(sioc));
-}
-
-
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
@@ -2643,75 +1898,6 @@ static const TypeInfo char_pipe_type_info = {
     .class_init = char_pipe_class_init,
 };
 
-static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
-                                  Error **errp)
-{
-    bool is_listen      = qemu_opt_get_bool(opts, "server", false);
-    bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
-    bool is_telnet      = qemu_opt_get_bool(opts, "telnet", false);
-    bool do_nodelay     = !qemu_opt_get_bool(opts, "delay", true);
-    int64_t reconnect   = qemu_opt_get_number(opts, "reconnect", 0);
-    const char *path = qemu_opt_get(opts, "path");
-    const char *host = qemu_opt_get(opts, "host");
-    const char *port = qemu_opt_get(opts, "port");
-    const char *tls_creds = qemu_opt_get(opts, "tls-creds");
-    SocketAddress *addr;
-    ChardevSocket *sock;
-
-    if (!path) {
-        if (!host) {
-            error_setg(errp, "chardev: socket: no host given");
-            return;
-        }
-        if (!port) {
-            error_setg(errp, "chardev: socket: no port given");
-            return;
-        }
-    } else {
-        if (tls_creds) {
-            error_setg(errp, "TLS can only be used over TCP socket");
-            return;
-        }
-    }
-
-    sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
-
-    sock->has_nodelay = true;
-    sock->nodelay = do_nodelay;
-    sock->has_server = true;
-    sock->server = is_listen;
-    sock->has_telnet = true;
-    sock->telnet = is_telnet;
-    sock->has_wait = true;
-    sock->wait = is_waitconnect;
-    sock->has_reconnect = true;
-    sock->reconnect = reconnect;
-    sock->tls_creds = g_strdup(tls_creds);
-
-    addr = g_new0(SocketAddress, 1);
-    if (path) {
-        UnixSocketAddress *q_unix;
-        addr->type = SOCKET_ADDRESS_KIND_UNIX;
-        q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-        q_unix->path = g_strdup(path);
-    } else {
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet.data = g_new(InetSocketAddress, 1);
-        *addr->u.inet.data = (InetSocketAddress) {
-            .host = g_strdup(host),
-            .port = g_strdup(port),
-            .has_to = qemu_opt_get(opts, "to"),
-            .to = qemu_opt_get_number(opts, "to", 0),
-            .has_ipv4 = qemu_opt_get(opts, "ipv4"),
-            .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
-            .has_ipv6 = qemu_opt_get(opts, "ipv6"),
-            .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
-        };
-    }
-    sock->addr = addr;
-}
-
 static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
                                Error **errp)
 {
@@ -3397,169 +2583,6 @@ static const TypeInfo char_serial_type_info = {
 };
 #endif
 
-static gboolean socket_reconnect_timeout(gpointer opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    SocketChardev *s = SOCKET_CHARDEV(opaque);
-    QIOChannelSocket *sioc;
-
-    s->reconnect_timer = 0;
-
-    if (chr->be_open) {
-        return false;
-    }
-
-    sioc = qio_channel_socket_new();
-    tcp_chr_set_client_ioc_name(chr, sioc);
-    qio_channel_socket_connect_async(sioc, s->addr,
-                                     qemu_chr_socket_connected,
-                                     chr, NULL);
-
-    return false;
-}
-
-static void qmp_chardev_open_socket(Chardev *chr,
-                                    ChardevBackend *backend,
-                                    bool *be_opened,
-                                    Error **errp)
-{
-    SocketChardev *s = SOCKET_CHARDEV(chr);
-    ChardevSocket *sock = backend->u.socket.data;
-    SocketAddress *addr = sock->addr;
-    bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
-    bool is_listen      = sock->has_server  ? sock->server  : true;
-    bool is_telnet      = sock->has_telnet  ? sock->telnet  : false;
-    bool is_waitconnect = sock->has_wait    ? sock->wait    : false;
-    int64_t reconnect   = sock->has_reconnect ? sock->reconnect : 0;
-    QIOChannelSocket *sioc = NULL;
-
-    s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
-    s->is_listen = is_listen;
-    s->is_telnet = is_telnet;
-    s->do_nodelay = do_nodelay;
-    if (sock->tls_creds) {
-        Object *creds;
-        creds = object_resolve_path_component(
-            object_get_objects_root(), sock->tls_creds);
-        if (!creds) {
-            error_setg(errp, "No TLS credentials with id '%s'",
-                       sock->tls_creds);
-            goto error;
-        }
-        s->tls_creds = (QCryptoTLSCreds *)
-            object_dynamic_cast(creds,
-                                TYPE_QCRYPTO_TLS_CREDS);
-        if (!s->tls_creds) {
-            error_setg(errp, "Object with id '%s' is not TLS credentials",
-                       sock->tls_creds);
-            goto error;
-        }
-        object_ref(OBJECT(s->tls_creds));
-        if (is_listen) {
-            if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
-                error_setg(errp, "%s",
-                           "Expected TLS credentials for server endpoint");
-                goto error;
-            }
-        } else {
-            if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
-                error_setg(errp, "%s",
-                           "Expected TLS credentials for client endpoint");
-                goto error;
-            }
-        }
-    }
-
-    s->addr = QAPI_CLONE(SocketAddress, sock->addr);
-
-    qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
-    if (s->is_unix) {
-        qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
-    }
-
-    /* be isn't opened until we get a connection */
-    *be_opened = false;
-
-    chr->filename = SocketAddress_to_str("disconnected:",
-                                         addr, is_listen, is_telnet);
-
-    if (is_listen) {
-        if (is_telnet) {
-            s->do_telnetopt = 1;
-        }
-    } else if (reconnect > 0) {
-        s->reconnect_time = reconnect;
-    }
-
-    if (s->reconnect_time) {
-        sioc = qio_channel_socket_new();
-        tcp_chr_set_client_ioc_name(chr, sioc);
-        qio_channel_socket_connect_async(sioc, s->addr,
-                                         qemu_chr_socket_connected,
-                                         chr, NULL);
-    } else {
-        if (s->is_listen) {
-            char *name;
-            sioc = qio_channel_socket_new();
-
-            name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
-            qio_channel_set_name(QIO_CHANNEL(sioc), name);
-            g_free(name);
-
-            if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
-                goto error;
-            }
-            s->listen_ioc = sioc;
-            if (is_waitconnect &&
-                qemu_chr_wait_connected(chr, errp) < 0) {
-                goto error;
-            }
-            if (!s->ioc) {
-                s->listen_tag = qio_channel_add_watch(
-                    QIO_CHANNEL(s->listen_ioc), G_IO_IN,
-                    tcp_chr_accept, chr, NULL);
-            }
-        } else if (qemu_chr_wait_connected(chr, errp) < 0) {
-            goto error;
-        }
-    }
-
-    return;
-
-error:
-    if (sioc) {
-        object_unref(OBJECT(sioc));
-    }
-    if (s->tls_creds) {
-        object_unref(OBJECT(s->tls_creds));
-    }
-}
-
-static void char_socket_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_socket;
-    cc->open = qmp_chardev_open_socket;
-    cc->chr_wait_connected = tcp_chr_wait_connected;
-    cc->chr_write = tcp_chr_write;
-    cc->chr_sync_read = tcp_chr_sync_read;
-    cc->chr_disconnect = tcp_chr_disconnect;
-    cc->get_msgfds = tcp_get_msgfds;
-    cc->set_msgfds = tcp_set_msgfds;
-    cc->chr_add_client = tcp_chr_add_client;
-    cc->chr_add_watch = tcp_chr_add_watch;
-    cc->chr_update_read_handler = tcp_chr_update_read_handler;
-}
-
-static const TypeInfo char_socket_type_info = {
-    .name = TYPE_CHARDEV_SOCKET,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(SocketChardev),
-    .instance_finalize = char_socket_finalize,
-    .class_init = char_socket_class_init,
-};
-
 static void qmp_chardev_open_udp(Chardev *chr,
                                  ChardevBackend *backend,
                                  bool *be_opened,
@@ -3707,7 +2730,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-    type_register_static(&char_socket_type_info);
     type_register_static(&char_udp_type_info);
     type_register_static(&char_file_type_info);
     type_register_static(&char_stdio_type_info);
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 3c4a328de8..c57c375d5b 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -4,5 +4,6 @@ chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
+chardev-obj-y += char-socket.o
 chardev-obj-$(CONFIG_WIN32) += char-win.o
 chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 0b96b00d56..264d1b7030 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -441,6 +441,7 @@ void qemu_chr_set_feature(Chardev *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len);
+int qemu_chr_wait_connected(Chardev *chr, Error **errp);
 
 #define TYPE_CHARDEV "chardev"
 #define CHARDEV(obj) OBJECT_CHECK(Chardev, (obj), TYPE_CHARDEV)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 46/54] char: move udp chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (44 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 45/54] char: move socket chardev to itw " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 47/54] char: move file " Marc-André Lureau
                   ` (9 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-udp.c    | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 199 -----------------------------------------------
 chardev/Makefile.objs |   1 +
 3 files changed, 212 insertions(+), 199 deletions(-)
 create mode 100644 chardev/char-udp.c

diff --git a/chardev/char-udp.c b/chardev/char-udp.c
new file mode 100644
index 0000000000..6e98c1b360
--- /dev/null
+++ b/chardev/char-udp.c
@@ -0,0 +1,211 @@
+#include "qemu/osdep.h"
+#include "sysemu/char.h"
+#include "io/channel-socket.h"
+#include "qapi/error.h"
+
+#include "char-io.h"
+
+/***********************************************************/
+/* UDP Net console */
+
+typedef struct {
+    Chardev parent;
+    QIOChannel *ioc;
+    uint8_t buf[CHR_READ_BUF_LEN];
+    int bufcnt;
+    int bufptr;
+    int max_size;
+} UdpChardev;
+
+#define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP)
+
+/* Called with chr_write_lock held.  */
+static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    UdpChardev *s = UDP_CHARDEV(chr);
+
+    return qio_channel_write(
+        s->ioc, (const char *)buf, len, NULL);
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    UdpChardev *s = UDP_CHARDEV(opaque);
+
+    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_be_write(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_be_can_write(chr);
+    }
+    return s->max_size;
+}
+
+static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    UdpChardev *s = UDP_CHARDEV(opaque);
+    ssize_t ret;
+
+    if (s->max_size == 0) {
+        return TRUE;
+    }
+    ret = qio_channel_read(
+        s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
+    if (ret <= 0) {
+        remove_fd_in_watch(chr);
+        return FALSE;
+    }
+    s->bufcnt = ret;
+
+    s->bufptr = 0;
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_be_can_write(chr);
+    }
+
+    return TRUE;
+}
+
+static void udp_chr_update_read_handler(Chardev *chr,
+                                        GMainContext *context)
+{
+    UdpChardev *s = UDP_CHARDEV(chr);
+
+    remove_fd_in_watch(chr);
+    if (s->ioc) {
+        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+                                           udp_chr_read_poll,
+                                           udp_chr_read, chr,
+                                           context);
+    }
+}
+
+static void char_udp_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+    UdpChardev *s = UDP_CHARDEV(obj);
+
+    remove_fd_in_watch(chr);
+    if (s->ioc) {
+        object_unref(OBJECT(s->ioc));
+    }
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+}
+
+static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
+                               Error **errp)
+{
+    const char *host = qemu_opt_get(opts, "host");
+    const char *port = qemu_opt_get(opts, "port");
+    const char *localaddr = qemu_opt_get(opts, "localaddr");
+    const char *localport = qemu_opt_get(opts, "localport");
+    bool has_local = false;
+    SocketAddress *addr;
+    ChardevUdp *udp;
+
+    if (host == NULL || strlen(host) == 0) {
+        host = "localhost";
+    }
+    if (port == NULL || strlen(port) == 0) {
+        error_setg(errp, "chardev: udp: remote port not specified");
+        return;
+    }
+    if (localport == NULL || strlen(localport) == 0) {
+        localport = "0";
+    } else {
+        has_local = true;
+    }
+    if (localaddr == NULL || strlen(localaddr) == 0) {
+        localaddr = "";
+    } else {
+        has_local = true;
+    }
+
+    udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
+
+    addr = g_new0(SocketAddress, 1);
+    addr->type = SOCKET_ADDRESS_KIND_INET;
+    addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *addr->u.inet.data = (InetSocketAddress) {
+        .host = g_strdup(host),
+        .port = g_strdup(port),
+        .has_ipv4 = qemu_opt_get(opts, "ipv4"),
+        .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
+        .has_ipv6 = qemu_opt_get(opts, "ipv6"),
+        .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
+    };
+    udp->remote = addr;
+
+    if (has_local) {
+        udp->has_local = true;
+        addr = g_new0(SocketAddress, 1);
+        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->u.inet.data = g_new(InetSocketAddress, 1);
+        *addr->u.inet.data = (InetSocketAddress) {
+            .host = g_strdup(localaddr),
+            .port = g_strdup(localport),
+        };
+        udp->local = addr;
+    }
+}
+
+static void qmp_chardev_open_udp(Chardev *chr,
+                                 ChardevBackend *backend,
+                                 bool *be_opened,
+                                 Error **errp)
+{
+    ChardevUdp *udp = backend->u.udp.data;
+    QIOChannelSocket *sioc = qio_channel_socket_new();
+    char *name;
+    UdpChardev *s = UDP_CHARDEV(chr);
+
+    if (qio_channel_socket_dgram_sync(sioc,
+                                      udp->local, udp->remote,
+                                      errp) < 0) {
+        object_unref(OBJECT(sioc));
+        return;
+    }
+
+    name = g_strdup_printf("chardev-udp-%s", chr->label);
+    qio_channel_set_name(QIO_CHANNEL(sioc), name);
+    g_free(name);
+
+    s->ioc = QIO_CHANNEL(sioc);
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    /* be isn't opened until we get a connection */
+    *be_opened = false;
+}
+
+static void char_udp_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_udp;
+    cc->open = qmp_chardev_open_udp;
+    cc->chr_write = udp_chr_write;
+    cc->chr_update_read_handler = udp_chr_update_read_handler;
+}
+
+static const TypeInfo char_udp_type_info = {
+    .name = TYPE_CHARDEV_UDP,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(UdpChardev),
+    .instance_finalize = char_udp_finalize,
+    .class_init = char_udp_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_udp_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 784a60ac53..a5938e987d 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -1511,100 +1511,6 @@ static const TypeInfo char_console_type_info = {
 
 #endif /* !_WIN32 */
 
-/***********************************************************/
-/* UDP Net console */
-
-typedef struct {
-    Chardev parent;
-    QIOChannel *ioc;
-    uint8_t buf[CHR_READ_BUF_LEN];
-    int bufcnt;
-    int bufptr;
-    int max_size;
-} UdpChardev;
-
-#define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP)
-
-/* Called with chr_write_lock held.  */
-static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    UdpChardev *s = UDP_CHARDEV(chr);
-
-    return qio_channel_write(
-        s->ioc, (const char *)buf, len, NULL);
-}
-
-static int udp_chr_read_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    UdpChardev *s = UDP_CHARDEV(opaque);
-
-    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_be_write(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_be_can_write(chr);
-    }
-    return s->max_size;
-}
-
-static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    UdpChardev *s = UDP_CHARDEV(opaque);
-    ssize_t ret;
-
-    if (s->max_size == 0) {
-        return TRUE;
-    }
-    ret = qio_channel_read(
-        s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
-    if (ret <= 0) {
-        remove_fd_in_watch(chr);
-        return FALSE;
-    }
-    s->bufcnt = ret;
-
-    s->bufptr = 0;
-    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_be_can_write(chr);
-    }
-
-    return TRUE;
-}
-
-static void udp_chr_update_read_handler(Chardev *chr,
-                                        GMainContext *context)
-{
-    UdpChardev *s = UDP_CHARDEV(chr);
-
-    remove_fd_in_watch(chr);
-    if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
-                                           udp_chr_read_poll,
-                                           udp_chr_read, chr,
-                                           context);
-    }
-}
-
-static void char_udp_finalize(Object *obj)
-{
-    Chardev *chr = CHARDEV(obj);
-    UdpChardev *s = UDP_CHARDEV(obj);
-
-    remove_fd_in_watch(chr);
-    if (s->ioc) {
-        object_unref(OBJECT(s->ioc));
-    }
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
 {
     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
@@ -1898,64 +1804,6 @@ static const TypeInfo char_pipe_type_info = {
     .class_init = char_pipe_class_init,
 };
 
-static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
-                               Error **errp)
-{
-    const char *host = qemu_opt_get(opts, "host");
-    const char *port = qemu_opt_get(opts, "port");
-    const char *localaddr = qemu_opt_get(opts, "localaddr");
-    const char *localport = qemu_opt_get(opts, "localport");
-    bool has_local = false;
-    SocketAddress *addr;
-    ChardevUdp *udp;
-
-    if (host == NULL || strlen(host) == 0) {
-        host = "localhost";
-    }
-    if (port == NULL || strlen(port) == 0) {
-        error_setg(errp, "chardev: udp: remote port not specified");
-        return;
-    }
-    if (localport == NULL || strlen(localport) == 0) {
-        localport = "0";
-    } else {
-        has_local = true;
-    }
-    if (localaddr == NULL || strlen(localaddr) == 0) {
-        localaddr = "";
-    } else {
-        has_local = true;
-    }
-
-    udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
-
-    addr = g_new0(SocketAddress, 1);
-    addr->type = SOCKET_ADDRESS_KIND_INET;
-    addr->u.inet.data = g_new(InetSocketAddress, 1);
-    *addr->u.inet.data = (InetSocketAddress) {
-        .host = g_strdup(host),
-        .port = g_strdup(port),
-        .has_ipv4 = qemu_opt_get(opts, "ipv4"),
-        .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
-        .has_ipv6 = qemu_opt_get(opts, "ipv6"),
-        .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
-    };
-    udp->remote = addr;
-
-    if (has_local) {
-        udp->has_local = true;
-        addr = g_new0(SocketAddress, 1);
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet.data = g_new(InetSocketAddress, 1);
-        *addr->u.inet.data = (InetSocketAddress) {
-            .host = g_strdup(localaddr),
-            .port = g_strdup(localport),
-        };
-        udp->local = addr;
-    }
-}
-
 static const ChardevClass *char_get_class(const char *driver, Error **errp)
 {
     ObjectClass *oc;
@@ -2583,52 +2431,6 @@ static const TypeInfo char_serial_type_info = {
 };
 #endif
 
-static void qmp_chardev_open_udp(Chardev *chr,
-                                 ChardevBackend *backend,
-                                 bool *be_opened,
-                                 Error **errp)
-{
-    ChardevUdp *udp = backend->u.udp.data;
-    QIOChannelSocket *sioc = qio_channel_socket_new();
-    char *name;
-    UdpChardev *s = UDP_CHARDEV(chr);
-
-    if (qio_channel_socket_dgram_sync(sioc,
-                                      udp->local, udp->remote,
-                                      errp) < 0) {
-        object_unref(OBJECT(sioc));
-        return;
-    }
-
-    name = g_strdup_printf("chardev-udp-%s", chr->label);
-    qio_channel_set_name(QIO_CHANNEL(sioc), name);
-    g_free(name);
-
-    s->ioc = QIO_CHANNEL(sioc);
-    s->bufcnt = 0;
-    s->bufptr = 0;
-    /* be isn't opened until we get a connection */
-    *be_opened = false;
-}
-
-static void char_udp_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_udp;
-    cc->open = qmp_chardev_open_udp;
-    cc->chr_write = udp_chr_write;
-    cc->chr_update_read_handler = udp_chr_update_read_handler;
-}
-
-static const TypeInfo char_udp_type_info = {
-    .name = TYPE_CHARDEV_UDP,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(UdpChardev),
-    .instance_finalize = char_udp_finalize,
-    .class_init = char_udp_class_init,
-};
-
 bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature)
 {
@@ -2730,7 +2532,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-    type_register_static(&char_udp_type_info);
     type_register_static(&char_file_type_info);
     type_register_static(&char_stdio_type_info);
 #ifdef HAVE_CHARDEV_SERIAL
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index c57c375d5b..dddef029e7 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -5,5 +5,6 @@ chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
 chardev-obj-y += char-socket.o
+chardev-obj-y += char-udp.o
 chardev-obj-$(CONFIG_WIN32) += char-win.o
 chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 47/54] char: move file chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (45 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 46/54] char: move udp chardev in its " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 48/54] char: move stdio " Marc-André Lureau
                   ` (8 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-file.c   | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 104 ---------------------------------------------
 chardev/Makefile.objs |   1 +
 3 files changed, 116 insertions(+), 104 deletions(-)
 create mode 100644 chardev/char-file.c

diff --git a/chardev/char-file.c b/chardev/char-file.c
new file mode 100644
index 0000000000..2d751914e5
--- /dev/null
+++ b/chardev/char-file.c
@@ -0,0 +1,115 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/char.h"
+
+#ifdef _WIN32
+#include "char-win.h"
+#else
+#include "char-fd.h"
+#endif
+
+static void qmp_chardev_open_file(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
+{
+    ChardevFile *file = backend->u.file.data;
+#ifdef _WIN32
+    HANDLE out;
+    DWORD accessmode;
+    DWORD flags;
+
+    if (file->has_in) {
+        error_setg(errp, "input file not supported");
+        return;
+    }
+
+    if (file->has_append && file->append) {
+        /* Append to file if it already exists. */
+        accessmode = FILE_GENERIC_WRITE & ~FILE_WRITE_DATA;
+        flags = OPEN_ALWAYS;
+    } else {
+        /* Truncate file if it already exists. */
+        accessmode = GENERIC_WRITE;
+        flags = CREATE_ALWAYS;
+    }
+
+    out = CreateFile(file->out, accessmode, FILE_SHARE_READ, NULL, flags,
+                     FILE_ATTRIBUTE_NORMAL, NULL);
+    if (out == INVALID_HANDLE_VALUE) {
+        error_setg(errp, "open %s failed", file->out);
+        return;
+    }
+
+    qemu_chr_open_win_file(chr, out);
+#else
+    int flags, in = -1, out;
+
+    flags = O_WRONLY | O_CREAT | O_BINARY;
+    if (file->has_append && file->append) {
+        flags |= O_APPEND;
+    } else {
+        flags |= O_TRUNC;
+    }
+
+    out = qmp_chardev_open_file_source(file->out, flags, errp);
+    if (out < 0) {
+        return;
+    }
+
+    if (file->has_in) {
+        flags = O_RDONLY;
+        in = qmp_chardev_open_file_source(file->in, flags, errp);
+        if (in < 0) {
+            qemu_close(out);
+            return;
+        }
+    }
+
+    qemu_chr_open_fd(chr, in, out);
+#endif
+}
+
+static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
+                                    Error **errp)
+{
+    const char *path = qemu_opt_get(opts, "path");
+    ChardevFile *file;
+
+    if (path == NULL) {
+        error_setg(errp, "chardev: file: no filename given");
+        return;
+    }
+    file = backend->u.file.data = g_new0(ChardevFile, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevFile_base(file));
+    file->out = g_strdup(path);
+
+    file->has_append = true;
+    file->append = qemu_opt_get_bool(opts, "append", false);
+}
+
+static void char_file_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_file_out;
+    cc->open = qmp_chardev_open_file;
+}
+
+static const TypeInfo char_file_type_info = {
+    .name = TYPE_CHARDEV_FILE,
+#ifdef _WIN32
+    .parent = TYPE_CHARDEV_WIN,
+#else
+    .parent = TYPE_CHARDEV_FD,
+#endif
+    .class_init = char_file_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_file_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index a5938e987d..49bc1c8962 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -1686,24 +1686,6 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
 }
 
 
-static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
-                                    Error **errp)
-{
-    const char *path = qemu_opt_get(opts, "path");
-    ChardevFile *file;
-
-    if (path == NULL) {
-        error_setg(errp, "chardev: file: no filename given");
-        return;
-    }
-    file = backend->u.file.data = g_new0(ChardevFile, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevFile_base(file));
-    file->out = g_strdup(path);
-
-    file->has_append = true;
-    file->append = qemu_opt_get_bool(opts, "append", false);
-}
-
 static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
                                  Error **errp)
 {
@@ -2234,41 +2216,6 @@ QemuOptsList qemu_chardev_opts = {
 
 #ifdef _WIN32
 
-static void qmp_chardev_open_file(Chardev *chr,
-                                  ChardevBackend *backend,
-                                  bool *be_opened,
-                                  Error **errp)
-{
-    ChardevFile *file = backend->u.file.data;
-    HANDLE out;
-    DWORD accessmode;
-    DWORD flags;
-
-    if (file->has_in) {
-        error_setg(errp, "input file not supported");
-        return;
-    }
-
-    if (file->has_append && file->append) {
-        /* Append to file if it already exists. */
-        accessmode = FILE_GENERIC_WRITE & ~FILE_WRITE_DATA;
-        flags = OPEN_ALWAYS;
-    } else {
-        /* Truncate file if it already exists. */
-        accessmode = GENERIC_WRITE;
-        flags = CREATE_ALWAYS;
-    }
-
-    out = CreateFile(file->out, accessmode, FILE_SHARE_READ, NULL, flags,
-                     FILE_ATTRIBUTE_NORMAL, NULL);
-    if (out == INVALID_HANDLE_VALUE) {
-        error_setg(errp, "open %s failed", file->out);
-        return;
-    }
-
-    qemu_chr_open_win_file(chr, out);
-}
-
 static void qmp_chardev_open_serial(Chardev *chr,
                                     ChardevBackend *backend,
                                     bool *be_opened,
@@ -2281,38 +2228,6 @@ static void qmp_chardev_open_serial(Chardev *chr,
 
 #else /* WIN32 */
 
-static void qmp_chardev_open_file(Chardev *chr,
-                                  ChardevBackend *backend,
-                                  bool *be_opened,
-                                  Error **errp)
-{
-    ChardevFile *file = backend->u.file.data;
-    int flags, in = -1, out;
-
-    flags = O_WRONLY | O_CREAT | O_BINARY;
-    if (file->has_append && file->append) {
-        flags |= O_APPEND;
-    } else {
-        flags |= O_TRUNC;
-    }
-
-    out = qmp_chardev_open_file_source(file->out, flags, errp);
-    if (out < 0) {
-        return;
-    }
-
-    if (file->has_in) {
-        flags = O_RDONLY;
-        in = qmp_chardev_open_file_source(file->in, flags, errp);
-        if (in < 0) {
-            qemu_close(out);
-            return;
-        }
-    }
-
-    qemu_chr_open_fd(chr, in, out);
-}
-
 #ifdef HAVE_CHARDEV_SERIAL
 static void qmp_chardev_open_serial(Chardev *chr,
                                     ChardevBackend *backend,
@@ -2389,24 +2304,6 @@ static const TypeInfo char_parallel_type_info = {
 
 #endif /* WIN32 */
 
-static void char_file_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_file_out;
-    cc->open = qmp_chardev_open_file;
-}
-
-static const TypeInfo char_file_type_info = {
-    .name = TYPE_CHARDEV_FILE,
-#ifdef _WIN32
-    .parent = TYPE_CHARDEV_WIN,
-#else
-    .parent = TYPE_CHARDEV_FD,
-#endif
-    .class_init = char_file_class_init,
-};
-
 #ifdef HAVE_CHARDEV_SERIAL
 
 static void char_serial_class_init(ObjectClass *oc, void *data)
@@ -2532,7 +2429,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-    type_register_static(&char_file_type_info);
     type_register_static(&char_stdio_type_info);
 #ifdef HAVE_CHARDEV_SERIAL
     type_register_static(&char_serial_type_info);
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index dddef029e7..0051a7a819 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,5 +1,6 @@
 chardev-obj-y += char.o
 chardev-obj-$(CONFIG_POSIX) += char-fd.o
+chardev-obj-y += char-file.o
 chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 48/54] char: move stdio in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (46 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 47/54] char: move file " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 49/54] char: move console " Marc-André Lureau
                   ` (7 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-stdio.c  | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 122 +------------------------------------------
 chardev/Makefile.objs |   1 +
 3 files changed, 142 insertions(+), 121 deletions(-)
 create mode 100644 chardev/char-stdio.c

diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c
new file mode 100644
index 0000000000..342125d616
--- /dev/null
+++ b/chardev/char-stdio.c
@@ -0,0 +1,140 @@
+#include "qemu/osdep.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/char.h"
+
+#ifdef _WIN32
+#include "char-win.h"
+#include "char-win-stdio.h"
+#else
+#include <termios.h>
+#include "char-fd.h"
+#endif
+
+#ifndef _WIN32
+/* init terminal so that we can grab keys */
+static struct termios oldtty;
+static int old_fd0_flags;
+static bool stdio_in_use;
+static bool stdio_allow_signal;
+static bool stdio_echo_state;
+
+static void term_exit(void)
+{
+    tcsetattr(0, TCSANOW, &oldtty);
+    fcntl(0, F_SETFL, old_fd0_flags);
+}
+
+static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
+{
+    struct termios tty;
+
+    stdio_echo_state = echo;
+    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_cflag &= ~(CSIZE | PARENB);
+        tty.c_cflag |= CS8;
+        tty.c_cc[VMIN] = 1;
+        tty.c_cc[VTIME] = 0;
+    }
+    if (!stdio_allow_signal) {
+        tty.c_lflag &= ~ISIG;
+    }
+
+    tcsetattr(0, TCSANOW, &tty);
+}
+
+static void term_stdio_handler(int sig)
+{
+    /* restore echo after resume from suspend. */
+    qemu_chr_set_echo_stdio(NULL, stdio_echo_state);
+}
+
+static void qemu_chr_open_stdio(Chardev *chr,
+                                ChardevBackend *backend,
+                                bool *be_opened,
+                                Error **errp)
+{
+    ChardevStdio *opts = backend->u.stdio.data;
+    struct sigaction act;
+
+    if (is_daemonized()) {
+        error_setg(errp, "cannot use stdio with -daemonize");
+        return;
+    }
+
+    if (stdio_in_use) {
+        error_setg(errp, "cannot use stdio by multiple character devices");
+        return;
+    }
+
+    stdio_in_use = true;
+    old_fd0_flags = fcntl(0, F_GETFL);
+    tcgetattr(0, &oldtty);
+    qemu_set_nonblock(0);
+    atexit(term_exit);
+
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = term_stdio_handler;
+    sigaction(SIGCONT, &act, NULL);
+
+    qemu_chr_open_fd(chr, 0, 1);
+
+    if (opts->has_signal) {
+        stdio_allow_signal = opts->signal;
+    }
+    qemu_chr_set_echo_stdio(chr, false);
+}
+#endif
+
+static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
+                                 Error **errp)
+{
+    ChardevStdio *stdio;
+
+    stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
+    stdio->has_signal = true;
+    stdio->signal = qemu_opt_get_bool(opts, "signal", true);
+}
+
+static void char_stdio_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_stdio;
+#ifndef _WIN32
+    cc->open = qemu_chr_open_stdio;
+    cc->chr_set_echo = qemu_chr_set_echo_stdio;
+#endif
+}
+
+static void char_stdio_finalize(Object *obj)
+{
+#ifndef _WIN32
+    term_exit();
+#endif
+}
+
+static const TypeInfo char_stdio_type_info = {
+    .name = TYPE_CHARDEV_STDIO,
+#ifdef _WIN32
+    .parent = TYPE_CHARDEV_WIN_STDIO,
+#else
+    .parent = TYPE_CHARDEV_FD,
+#endif
+    .instance_finalize = char_stdio_finalize,
+    .class_init = char_stdio_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_stdio_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 49bc1c8962..7421570399 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -90,7 +90,6 @@
 #include "char-io.h"
 #ifdef _WIN32
 #include "char-win.h"
-#include "char-win-stdio.h"
 #endif
 
 /***********************************************************/
@@ -685,91 +684,7 @@ static void qemu_chr_open_pipe(Chardev *chr,
     qemu_chr_open_fd(chr, fd_in, fd_out);
 }
 
-/* init terminal so that we can grab keys */
-static struct termios oldtty;
-static int old_fd0_flags;
-static bool stdio_in_use;
-static bool stdio_allow_signal;
-static bool stdio_echo_state;
-
-static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo);
-
-static void term_exit(void)
-{
-    tcsetattr (0, TCSANOW, &oldtty);
-    fcntl(0, F_SETFL, old_fd0_flags);
-}
-
-static void term_stdio_handler(int sig)
-{
-    /* restore echo after resume from suspend. */
-    qemu_chr_set_echo_stdio(NULL, stdio_echo_state);
-}
-
-static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
-{
-    struct termios tty;
-
-    stdio_echo_state = echo;
-    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_cflag &= ~(CSIZE|PARENB);
-        tty.c_cflag |= CS8;
-        tty.c_cc[VMIN] = 1;
-        tty.c_cc[VTIME] = 0;
-    }
-    if (!stdio_allow_signal)
-        tty.c_lflag &= ~ISIG;
-
-    tcsetattr (0, TCSANOW, &tty);
-}
-
-static void char_stdio_finalize(Object *obj)
-{
-    term_exit();
-}
-
-static void qemu_chr_open_stdio(Chardev *chr,
-                                ChardevBackend *backend,
-                                bool *be_opened,
-                                Error **errp)
-{
-    ChardevStdio *opts = backend->u.stdio.data;
-    struct sigaction act;
-
-    if (is_daemonized()) {
-        error_setg(errp, "cannot use stdio with -daemonize");
-        return;
-    }
-
-    if (stdio_in_use) {
-        error_setg(errp, "cannot use stdio by multiple character devices");
-        return;
-    }
-
-    stdio_in_use = true;
-    old_fd0_flags = fcntl(0, F_GETFL);
-    tcgetattr(0, &oldtty);
-    qemu_set_nonblock(0);
-    atexit(term_exit);
-
-    memset(&act, 0, sizeof(act));
-    act.sa_handler = term_stdio_handler;
-    sigaction(SIGCONT, &act, NULL);
-
-    qemu_chr_open_fd(chr, 0, 1);
-
-    if (opts->has_signal) {
-        stdio_allow_signal = opts->signal;
-    }
-    qemu_chr_set_echo_stdio(chr, false);
-}
-
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)     \
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
     || defined(__GLIBC__)
 
@@ -1685,40 +1600,6 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
     backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
 }
 
-
-static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
-                                 Error **errp)
-{
-    ChardevStdio *stdio;
-
-    stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
-    stdio->has_signal = true;
-    stdio->signal = qemu_opt_get_bool(opts, "signal", true);
-}
-
-static void char_stdio_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_stdio;
-#ifndef _WIN32
-    cc->open = qemu_chr_open_stdio;
-    cc->chr_set_echo = qemu_chr_set_echo_stdio;
-#endif
-}
-
-static const TypeInfo char_stdio_type_info = {
-    .name = TYPE_CHARDEV_STDIO,
-#ifdef _WIN32
-    .parent = TYPE_CHARDEV_WIN_STDIO,
-#else
-    .parent = TYPE_CHARDEV_FD,
-    .instance_finalize = char_stdio_finalize,
-#endif
-    .class_init = char_stdio_class_init,
-};
-
 #ifdef HAVE_CHARDEV_SERIAL
 static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
                                   Error **errp)
@@ -2429,7 +2310,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-    type_register_static(&char_stdio_type_info);
 #ifdef HAVE_CHARDEV_SERIAL
     type_register_static(&char_serial_type_info);
 #endif
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 0051a7a819..ee40e8a1d7 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -6,6 +6,7 @@ chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-ringbuf.o
 chardev-obj-y += char-socket.o
+chardev-obj-y += char-stdio.o
 chardev-obj-y += char-udp.o
 chardev-obj-$(CONFIG_WIN32) += char-win.o
 chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 49/54] char: move console in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (47 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 48/54] char: move stdio " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 50/54] char: move pipe chardev " Marc-André Lureau
                   ` (6 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-console.c | 30 ++++++++++++++++++++++++++++++
 chardev/char.c         | 24 ------------------------
 chardev/Makefile.objs  |  1 +
 3 files changed, 31 insertions(+), 24 deletions(-)
 create mode 100644 chardev/char-console.c

diff --git a/chardev/char-console.c b/chardev/char-console.c
new file mode 100644
index 0000000000..6cc8336622
--- /dev/null
+++ b/chardev/char-console.c
@@ -0,0 +1,30 @@
+#include "qemu/osdep.h"
+#include "char-win.h"
+
+static void qemu_chr_open_win_con(Chardev *chr,
+                                  ChardevBackend *backend,
+                                  bool *be_opened,
+                                  Error **errp)
+{
+    qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
+static void char_console_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = qemu_chr_open_win_con;
+}
+
+static const TypeInfo char_console_type_info = {
+    .name = TYPE_CHARDEV_CONSOLE,
+    .parent = TYPE_CHARDEV_WIN,
+    .class_init = char_console_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_console_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 7421570399..3975236cd9 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -1403,27 +1403,6 @@ static void qemu_chr_open_pipe(Chardev *chr,
     }
 }
 
-static void qemu_chr_open_win_con(Chardev *chr,
-                                  ChardevBackend *backend,
-                                  bool *be_opened,
-                                  Error **errp)
-{
-    qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
-}
-
-static void char_console_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->open = qemu_chr_open_win_con;
-}
-
-static const TypeInfo char_console_type_info = {
-    .name = TYPE_CHARDEV_CONSOLE,
-    .parent = TYPE_CHARDEV_WIN,
-    .class_init = char_console_class_init,
-};
-
 #endif /* !_WIN32 */
 
 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
@@ -2319,9 +2298,6 @@ static void register_types(void)
 #ifdef HAVE_CHARDEV_PTY
     type_register_static(&char_pty_type_info);
 #endif
-#ifdef _WIN32
-    type_register_static(&char_console_type_info);
-#endif
     type_register_static(&char_pipe_type_info);
 
     /* this must be done after machine init, since we register FEs with muxes
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index ee40e8a1d7..265a6dad5d 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -1,4 +1,5 @@
 chardev-obj-y += char.o
+chardev-obj-$(CONFIG_WIN32) += char-console.o
 chardev-obj-$(CONFIG_POSIX) += char-fd.o
 chardev-obj-y += char-file.o
 chardev-obj-y += char-io.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 50/54] char: move pipe chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (48 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 49/54] char: move console " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 51/54] char: move pty " Marc-André Lureau
                   ` (5 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-pipe.c   | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 141 ------------------------------------------
 chardev/Makefile.objs |   1 +
 3 files changed, 168 insertions(+), 141 deletions(-)
 create mode 100644 chardev/char-pipe.c

diff --git a/chardev/char-pipe.c b/chardev/char-pipe.c
new file mode 100644
index 0000000000..1c86a695b4
--- /dev/null
+++ b/chardev/char-pipe.c
@@ -0,0 +1,167 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/char.h"
+
+#ifdef _WIN32
+#include "char-win.h"
+#else
+#include "char-fd.h"
+#endif
+
+#ifdef _WIN32
+#define MAXCONNECT 1
+#define NTIMEOUT 5000
+
+static int win_chr_pipe_init(Chardev *chr, const char *filename,
+                             Error **errp)
+{
+    WinChardev *s = WIN_CHARDEV(chr);
+    OVERLAPPED ov;
+    int ret;
+    DWORD size;
+    char *openname;
+
+    s->fpipe = TRUE;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        error_setg(errp, "Failed CreateEvent");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        error_setg(errp, "Failed CreateEvent");
+        goto fail;
+    }
+
+    openname = g_strdup_printf("\\\\.\\pipe\\%s", filename);
+    s->hcom = CreateNamedPipe(openname,
+                              PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                              PIPE_WAIT,
+                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+    g_free(openname);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    ZeroMemory(&ov, sizeof(ov));
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ret = ConnectNamedPipe(s->hcom, &ov);
+    if (ret) {
+        error_setg(errp, "Failed ConnectNamedPipe");
+        goto fail;
+    }
+
+    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+    if (!ret) {
+        error_setg(errp, "Failed GetOverlappedResult");
+        if (ov.hEvent) {
+            CloseHandle(ov.hEvent);
+            ov.hEvent = NULL;
+        }
+        goto fail;
+    }
+
+    if (ov.hEvent) {
+        CloseHandle(ov.hEvent);
+        ov.hEvent = NULL;
+    }
+    qemu_add_polling_cb(win_chr_pipe_poll, chr);
+    return 0;
+
+ fail:
+    return -1;
+}
+
+static void qemu_chr_open_pipe(Chardev *chr,
+                               ChardevBackend *backend,
+                               bool *be_opened,
+                               Error **errp)
+{
+    ChardevHostdev *opts = backend->u.pipe.data;
+    const char *filename = opts->device;
+
+    if (win_chr_pipe_init(chr, filename, errp) < 0) {
+        return;
+    }
+}
+
+#else
+
+static void qemu_chr_open_pipe(Chardev *chr,
+                               ChardevBackend *backend,
+                               bool *be_opened,
+                               Error **errp)
+{
+    ChardevHostdev *opts = backend->u.pipe.data;
+    int fd_in, fd_out;
+    char *filename_in;
+    char *filename_out;
+    const char *filename = opts->device;
+
+    filename_in = g_strdup_printf("%s.in", filename);
+    filename_out = g_strdup_printf("%s.out", filename);
+    TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
+    TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
+    g_free(filename_in);
+    g_free(filename_out);
+    if (fd_in < 0 || fd_out < 0) {
+        if (fd_in >= 0) {
+            close(fd_in);
+        }
+        if (fd_out >= 0) {
+            close(fd_out);
+        }
+        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0) {
+            error_setg_file_open(errp, errno, filename);
+            return;
+        }
+    }
+    qemu_chr_open_fd(chr, fd_in, fd_out);
+}
+
+#endif /* !_WIN32 */
+
+static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
+                                Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+    ChardevHostdev *dev;
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: pipe: no device path given");
+        return;
+    }
+    dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
+    dev->device = g_strdup(device);
+}
+
+static void char_pipe_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_pipe;
+    cc->open = qemu_chr_open_pipe;
+}
+
+static const TypeInfo char_pipe_type_info = {
+    .name = TYPE_CHARDEV_PIPE,
+#ifdef _WIN32
+    .parent = TYPE_CHARDEV_WIN,
+#else
+    .parent = TYPE_CHARDEV_FD,
+#endif
+    .class_init = char_pipe_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_pipe_type_info);
+}
+
+type_init(register_types);
diff --git a/chardev/char.c b/chardev/char.c
index 3975236cd9..fce8056222 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -653,36 +653,6 @@ void qemu_chr_fe_take_focus(CharBackend *b)
 }
 
 #ifndef _WIN32
-static void qemu_chr_open_pipe(Chardev *chr,
-                               ChardevBackend *backend,
-                               bool *be_opened,
-                               Error **errp)
-{
-    ChardevHostdev *opts = backend->u.pipe.data;
-    int fd_in, fd_out;
-    char *filename_in;
-    char *filename_out;
-    const char *filename = opts->device;
-
-    filename_in = g_strdup_printf("%s.in", filename);
-    filename_out = g_strdup_printf("%s.out", filename);
-    TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
-    TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
-    g_free(filename_in);
-    g_free(filename_out);
-    if (fd_in < 0 || fd_out < 0) {
-	if (fd_in >= 0)
-	    close(fd_in);
-	if (fd_out >= 0)
-	    close(fd_out);
-        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
-        if (fd_in < 0) {
-            error_setg_file_open(errp, errno, filename);
-            return;
-        }
-    }
-    qemu_chr_open_fd(chr, fd_in, fd_out);
-}
 
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
@@ -1326,83 +1296,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr,
 #define MAXCONNECT 1
 #define NTIMEOUT 5000
 
-static int win_chr_pipe_init(Chardev *chr, const char *filename,
-                             Error **errp)
-{
-    WinChardev *s = WIN_CHARDEV(chr);
-    OVERLAPPED ov;
-    int ret;
-    DWORD size;
-    char *openname;
-
-    s->fpipe = TRUE;
-
-    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hsend) {
-        error_setg(errp, "Failed CreateEvent");
-        goto fail;
-    }
-    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hrecv) {
-        error_setg(errp, "Failed CreateEvent");
-        goto fail;
-    }
-
-    openname = g_strdup_printf("\\\\.\\pipe\\%s", filename);
-    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
-                              PIPE_WAIT,
-                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
-    g_free(openname);
-    if (s->hcom == INVALID_HANDLE_VALUE) {
-        error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
-        s->hcom = NULL;
-        goto fail;
-    }
-
-    ZeroMemory(&ov, sizeof(ov));
-    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-    ret = ConnectNamedPipe(s->hcom, &ov);
-    if (ret) {
-        error_setg(errp, "Failed ConnectNamedPipe");
-        goto fail;
-    }
-
-    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
-    if (!ret) {
-        error_setg(errp, "Failed GetOverlappedResult");
-        if (ov.hEvent) {
-            CloseHandle(ov.hEvent);
-            ov.hEvent = NULL;
-        }
-        goto fail;
-    }
-
-    if (ov.hEvent) {
-        CloseHandle(ov.hEvent);
-        ov.hEvent = NULL;
-    }
-    qemu_add_polling_cb(win_chr_pipe_poll, chr);
-    return 0;
-
- fail:
-    return -1;
-}
-
-
-static void qemu_chr_open_pipe(Chardev *chr,
-                               ChardevBackend *backend,
-                               bool *be_opened,
-                               Error **errp)
-{
-    ChardevHostdev *opts = backend->u.pipe.data;
-    const char *filename = opts->device;
-
-    if (win_chr_pipe_init(chr, filename, errp) < 0) {
-        return;
-    }
-}
-
 #endif /* !_WIN32 */
 
 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
@@ -1613,39 +1506,6 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
 }
 #endif
 
-static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
-                                Error **errp)
-{
-    const char *device = qemu_opt_get(opts, "path");
-    ChardevHostdev *dev;
-
-    if (device == NULL) {
-        error_setg(errp, "chardev: pipe: no device path given");
-        return;
-    }
-    dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
-    dev->device = g_strdup(device);
-}
-
-static void char_pipe_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_pipe;
-    cc->open = qemu_chr_open_pipe;
-}
-
-static const TypeInfo char_pipe_type_info = {
-    .name = TYPE_CHARDEV_PIPE,
-#ifdef _WIN32
-    .parent = TYPE_CHARDEV_WIN,
-#else
-    .parent = TYPE_CHARDEV_FD,
-#endif
-    .class_init = char_pipe_class_init,
-};
-
 static const ChardevClass *char_get_class(const char *driver, Error **errp)
 {
     ObjectClass *oc;
@@ -2298,7 +2158,6 @@ static void register_types(void)
 #ifdef HAVE_CHARDEV_PTY
     type_register_static(&char_pty_type_info);
 #endif
-    type_register_static(&char_pipe_type_info);
 
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 265a6dad5d..778b312377 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -5,6 +5,7 @@ chardev-obj-y += char-file.o
 chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
+chardev-obj-y += char-pipe.o
 chardev-obj-y += char-ringbuf.o
 chardev-obj-y += char-socket.o
 chardev-obj-y += char-stdio.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 51/54] char: move pty chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (49 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 50/54] char: move pipe chardev " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 52/54] char: move serial chardev to itw " Marc-André Lureau
                   ` (4 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-pty.c    | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 258 ----------------------------------------------
 chardev/Makefile.objs |   1 +
 3 files changed, 278 insertions(+), 258 deletions(-)
 create mode 100644 chardev/char-pty.c

diff --git a/chardev/char-pty.c b/chardev/char-pty.c
new file mode 100644
index 0000000000..bd9fdfa60d
--- /dev/null
+++ b/chardev/char-pty.c
@@ -0,0 +1,277 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/char.h"
+#include "io/channel-file.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+
+#include "char-io.h"
+
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__GLIBC__)
+
+typedef struct {
+    Chardev parent;
+    QIOChannel *ioc;
+    int read_bytes;
+
+    /* Protected by the Chardev chr_write_lock.  */
+    int connected;
+    guint timer_tag;
+    guint open_tag;
+} PtyChardev;
+
+#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
+
+static void pty_chr_update_read_handler_locked(Chardev *chr);
+static void pty_chr_state(Chardev *chr, int connected);
+
+static gboolean pty_chr_timer(gpointer opaque)
+{
+    struct Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
+
+    qemu_mutex_lock(&chr->chr_write_lock);
+    s->timer_tag = 0;
+    s->open_tag = 0;
+    if (!s->connected) {
+        /* Next poll ... */
+        pty_chr_update_read_handler_locked(chr);
+    }
+    qemu_mutex_unlock(&chr->chr_write_lock);
+    return FALSE;
+}
+
+/* Called with chr_write_lock held.  */
+static void pty_chr_rearm_timer(Chardev *chr, int ms)
+{
+    PtyChardev *s = PTY_CHARDEV(chr);
+    char *name;
+
+    if (s->timer_tag) {
+        g_source_remove(s->timer_tag);
+        s->timer_tag = 0;
+    }
+
+    if (ms == 1000) {
+        name = g_strdup_printf("pty-timer-secs-%s", chr->label);
+        s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
+    } else {
+        name = g_strdup_printf("pty-timer-ms-%s", chr->label);
+        s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
+    }
+    g_source_set_name_by_id(s->timer_tag, name);
+    g_free(name);
+}
+
+/* Called with chr_write_lock held.  */
+static void pty_chr_update_read_handler_locked(Chardev *chr)
+{
+    PtyChardev *s = PTY_CHARDEV(chr);
+    GPollFD pfd;
+    int rc;
+    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
+
+    pfd.fd = fioc->fd;
+    pfd.events = G_IO_OUT;
+    pfd.revents = 0;
+    do {
+        rc = g_poll(&pfd, 1, 0);
+    } while (rc == -1 && errno == EINTR);
+    assert(rc >= 0);
+
+    if (pfd.revents & G_IO_HUP) {
+        pty_chr_state(chr, 0);
+    } else {
+        pty_chr_state(chr, 1);
+    }
+}
+
+static void pty_chr_update_read_handler(Chardev *chr,
+                                        GMainContext *context)
+{
+    qemu_mutex_lock(&chr->chr_write_lock);
+    pty_chr_update_read_handler_locked(chr);
+    qemu_mutex_unlock(&chr->chr_write_lock);
+}
+
+/* Called with chr_write_lock held.  */
+static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    PtyChardev *s = PTY_CHARDEV(chr);
+
+    if (!s->connected) {
+        /* guest sends data, check for (re-)connect */
+        pty_chr_update_read_handler_locked(chr);
+        if (!s->connected) {
+            return 0;
+        }
+    }
+    return io_channel_send(s->ioc, buf, len);
+}
+
+static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
+{
+    PtyChardev *s = PTY_CHARDEV(chr);
+    if (!s->connected) {
+        return NULL;
+    }
+    return qio_channel_create_watch(s->ioc, cond);
+}
+
+static int pty_chr_read_poll(void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
+
+    s->read_bytes = qemu_chr_be_can_write(chr);
+    return s->read_bytes;
+}
+
+static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
+    gsize len;
+    uint8_t buf[CHR_READ_BUF_LEN];
+    ssize_t ret;
+
+    len = sizeof(buf);
+    if (len > s->read_bytes) {
+        len = s->read_bytes;
+    }
+    if (len == 0) {
+        return TRUE;
+    }
+    ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
+    if (ret <= 0) {
+        pty_chr_state(chr, 0);
+        return FALSE;
+    } else {
+        pty_chr_state(chr, 1);
+        qemu_chr_be_write(chr, buf, ret);
+    }
+    return TRUE;
+}
+
+static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
+{
+    Chardev *chr = CHARDEV(opaque);
+    PtyChardev *s = PTY_CHARDEV(opaque);
+
+    s->open_tag = 0;
+    qemu_chr_be_generic_open(chr);
+    return FALSE;
+}
+
+/* Called with chr_write_lock held.  */
+static void pty_chr_state(Chardev *chr, int connected)
+{
+    PtyChardev *s = PTY_CHARDEV(chr);
+
+    if (!connected) {
+        if (s->open_tag) {
+            g_source_remove(s->open_tag);
+            s->open_tag = 0;
+        }
+        remove_fd_in_watch(chr);
+        s->connected = 0;
+        /* (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. */
+        pty_chr_rearm_timer(chr, 1000);
+    } else {
+        if (s->timer_tag) {
+            g_source_remove(s->timer_tag);
+            s->timer_tag = 0;
+        }
+        if (!s->connected) {
+            g_assert(s->open_tag == 0);
+            s->connected = 1;
+            s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
+        }
+        if (!chr->fd_in_tag) {
+            chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+                                               pty_chr_read_poll,
+                                               pty_chr_read,
+                                               chr, NULL);
+        }
+    }
+}
+
+static void char_pty_finalize(Object *obj)
+{
+    Chardev *chr = CHARDEV(obj);
+    PtyChardev *s = PTY_CHARDEV(obj);
+
+    qemu_mutex_lock(&chr->chr_write_lock);
+    pty_chr_state(chr, 0);
+    object_unref(OBJECT(s->ioc));
+    if (s->timer_tag) {
+        g_source_remove(s->timer_tag);
+        s->timer_tag = 0;
+    }
+    qemu_mutex_unlock(&chr->chr_write_lock);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+}
+
+static void char_pty_open(Chardev *chr,
+                          ChardevBackend *backend,
+                          bool *be_opened,
+                          Error **errp)
+{
+    PtyChardev *s;
+    int master_fd, slave_fd;
+    char pty_name[PATH_MAX];
+    char *name;
+
+    master_fd = qemu_openpty_raw(&slave_fd, pty_name);
+    if (master_fd < 0) {
+        error_setg_errno(errp, errno, "Failed to create PTY");
+        return;
+    }
+
+    close(slave_fd);
+    qemu_set_nonblock(master_fd);
+
+    chr->filename = g_strdup_printf("pty:%s", pty_name);
+    error_report("char device redirected to %s (label %s)",
+                 pty_name, chr->label);
+
+    s = PTY_CHARDEV(chr);
+    s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
+    name = g_strdup_printf("chardev-pty-%s", chr->label);
+    qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
+    g_free(name);
+    s->timer_tag = 0;
+    *be_opened = false;
+}
+
+static void char_pty_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->open = char_pty_open;
+    cc->chr_write = char_pty_chr_write;
+    cc->chr_update_read_handler = pty_chr_update_read_handler;
+    cc->chr_add_watch = pty_chr_add_watch;
+}
+
+static const TypeInfo char_pty_type_info = {
+    .name = TYPE_CHARDEV_PTY,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(PtyChardev),
+    .instance_finalize = char_pty_finalize,
+    .class_init = char_pty_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_pty_type_info);
+}
+
+type_init(register_types);
+
+#endif
diff --git a/chardev/char.c b/chardev/char.c
index fce8056222..2a7eb9a5b4 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -659,261 +659,6 @@ void qemu_chr_fe_take_focus(CharBackend *b)
     || defined(__GLIBC__)
 
 #define HAVE_CHARDEV_SERIAL 1
-#define HAVE_CHARDEV_PTY 1
-
-typedef struct {
-    Chardev parent;
-    QIOChannel *ioc;
-    int read_bytes;
-
-    /* Protected by the Chardev chr_write_lock.  */
-    int connected;
-    guint timer_tag;
-    guint open_tag;
-} PtyChardev;
-
-#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
-
-static void pty_chr_update_read_handler_locked(Chardev *chr);
-static void pty_chr_state(Chardev *chr, int connected);
-
-static gboolean pty_chr_timer(gpointer opaque)
-{
-    struct Chardev *chr = CHARDEV(opaque);
-    PtyChardev *s = PTY_CHARDEV(opaque);
-
-    qemu_mutex_lock(&chr->chr_write_lock);
-    s->timer_tag = 0;
-    s->open_tag = 0;
-    if (!s->connected) {
-        /* Next poll ... */
-        pty_chr_update_read_handler_locked(chr);
-    }
-    qemu_mutex_unlock(&chr->chr_write_lock);
-    return FALSE;
-}
-
-/* Called with chr_write_lock held.  */
-static void pty_chr_rearm_timer(Chardev *chr, int ms)
-{
-    PtyChardev *s = PTY_CHARDEV(chr);
-    char *name;
-
-    if (s->timer_tag) {
-        g_source_remove(s->timer_tag);
-        s->timer_tag = 0;
-    }
-
-    if (ms == 1000) {
-        name = g_strdup_printf("pty-timer-secs-%s", chr->label);
-        s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
-    } else {
-        name = g_strdup_printf("pty-timer-ms-%s", chr->label);
-        s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
-    }
-    g_source_set_name_by_id(s->timer_tag, name);
-    g_free(name);
-}
-
-/* Called with chr_write_lock held.  */
-static void pty_chr_update_read_handler_locked(Chardev *chr)
-{
-    PtyChardev *s = PTY_CHARDEV(chr);
-    GPollFD pfd;
-    int rc;
-    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
-
-    pfd.fd = fioc->fd;
-    pfd.events = G_IO_OUT;
-    pfd.revents = 0;
-    do {
-        rc = g_poll(&pfd, 1, 0);
-    } while (rc == -1 && errno == EINTR);
-    assert(rc >= 0);
-
-    if (pfd.revents & G_IO_HUP) {
-        pty_chr_state(chr, 0);
-    } else {
-        pty_chr_state(chr, 1);
-    }
-}
-
-static void pty_chr_update_read_handler(Chardev *chr,
-                                        GMainContext *context)
-{
-    qemu_mutex_lock(&chr->chr_write_lock);
-    pty_chr_update_read_handler_locked(chr);
-    qemu_mutex_unlock(&chr->chr_write_lock);
-}
-
-/* Called with chr_write_lock held.  */
-static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    PtyChardev *s = PTY_CHARDEV(chr);
-
-    if (!s->connected) {
-        /* guest sends data, check for (re-)connect */
-        pty_chr_update_read_handler_locked(chr);
-        if (!s->connected) {
-            return 0;
-        }
-    }
-    return io_channel_send(s->ioc, buf, len);
-}
-
-static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
-{
-    PtyChardev *s = PTY_CHARDEV(chr);
-    if (!s->connected) {
-        return NULL;
-    }
-    return qio_channel_create_watch(s->ioc, cond);
-}
-
-static int pty_chr_read_poll(void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    PtyChardev *s = PTY_CHARDEV(opaque);
-
-    s->read_bytes = qemu_chr_be_can_write(chr);
-    return s->read_bytes;
-}
-
-static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    PtyChardev *s = PTY_CHARDEV(opaque);
-    gsize len;
-    uint8_t buf[CHR_READ_BUF_LEN];
-    ssize_t ret;
-
-    len = sizeof(buf);
-    if (len > s->read_bytes)
-        len = s->read_bytes;
-    if (len == 0) {
-        return TRUE;
-    }
-    ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
-    if (ret <= 0) {
-        pty_chr_state(chr, 0);
-        return FALSE;
-    } else {
-        pty_chr_state(chr, 1);
-        qemu_chr_be_write(chr, buf, ret);
-    }
-    return TRUE;
-}
-
-static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
-{
-    Chardev *chr = CHARDEV(opaque);
-    PtyChardev *s = PTY_CHARDEV(opaque);
-
-    s->open_tag = 0;
-    qemu_chr_be_generic_open(chr);
-    return FALSE;
-}
-
-/* Called with chr_write_lock held.  */
-static void pty_chr_state(Chardev *chr, int connected)
-{
-    PtyChardev *s = PTY_CHARDEV(chr);
-
-    if (!connected) {
-        if (s->open_tag) {
-            g_source_remove(s->open_tag);
-            s->open_tag = 0;
-        }
-        remove_fd_in_watch(chr);
-        s->connected = 0;
-        /* (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. */
-        pty_chr_rearm_timer(chr, 1000);
-    } else {
-        if (s->timer_tag) {
-            g_source_remove(s->timer_tag);
-            s->timer_tag = 0;
-        }
-        if (!s->connected) {
-            g_assert(s->open_tag == 0);
-            s->connected = 1;
-            s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
-        }
-        if (!chr->fd_in_tag) {
-            chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
-                                               pty_chr_read_poll,
-                                               pty_chr_read,
-                                               chr, NULL);
-        }
-    }
-}
-
-static void char_pty_finalize(Object *obj)
-{
-    Chardev *chr = CHARDEV(obj);
-    PtyChardev *s = PTY_CHARDEV(obj);
-
-    qemu_mutex_lock(&chr->chr_write_lock);
-    pty_chr_state(chr, 0);
-    object_unref(OBJECT(s->ioc));
-    if (s->timer_tag) {
-        g_source_remove(s->timer_tag);
-        s->timer_tag = 0;
-    }
-    qemu_mutex_unlock(&chr->chr_write_lock);
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-}
-
-static void char_pty_open(Chardev *chr,
-                          ChardevBackend *backend,
-                          bool *be_opened,
-                          Error **errp)
-{
-    PtyChardev *s;
-    int master_fd, slave_fd;
-    char pty_name[PATH_MAX];
-    char *name;
-
-    master_fd = qemu_openpty_raw(&slave_fd, pty_name);
-    if (master_fd < 0) {
-        error_setg_errno(errp, errno, "Failed to create PTY");
-        return;
-    }
-
-    close(slave_fd);
-    qemu_set_nonblock(master_fd);
-
-    chr->filename = g_strdup_printf("pty:%s", pty_name);
-    error_report("char device redirected to %s (label %s)",
-                 pty_name, chr->label);
-
-    s = PTY_CHARDEV(chr);
-    s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
-    name = g_strdup_printf("chardev-pty-%s", chr->label);
-    qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
-    g_free(name);
-    s->timer_tag = 0;
-    *be_opened = false;
-}
-
-static void char_pty_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->open = char_pty_open;
-    cc->chr_write = char_pty_chr_write;
-    cc->chr_update_read_handler = pty_chr_update_read_handler;
-    cc->chr_add_watch = pty_chr_add_watch;
-}
-
-static const TypeInfo char_pty_type_info = {
-    .name = TYPE_CHARDEV_PTY,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(PtyChardev),
-    .instance_finalize = char_pty_finalize,
-    .class_init = char_pty_class_init,
-};
 
 static void tty_serial_init(int fd, int speed,
                             int parity, int data_bits, int stop_bits)
@@ -2155,9 +1900,6 @@ static void register_types(void)
 #ifdef HAVE_CHARDEV_PARPORT
     type_register_static(&char_parallel_type_info);
 #endif
-#ifdef HAVE_CHARDEV_PTY
-    type_register_static(&char_pty_type_info);
-#endif
 
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 778b312377..b2c14fe795 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -6,6 +6,7 @@ chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
 chardev-obj-y += char-pipe.o
+chardev-obj-$(CONFIG_POSIX) += char-pty.o
 chardev-obj-y += char-ringbuf.o
 chardev-obj-y += char-socket.o
 chardev-obj-y += char-stdio.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 52/54] char: move serial chardev to itw own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (50 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 51/54] char: move pty " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 53/54] char: move parallel chardev in its " Marc-André Lureau
                   ` (3 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-serial.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c        | 280 +----------------------------------------------
 chardev/Makefile.objs |   1 +
 chardev/char-serial.h |  12 +++
 4 files changed, 309 insertions(+), 278 deletions(-)
 create mode 100644 chardev/char-serial.c
 create mode 100644 chardev/char-serial.h

diff --git a/chardev/char-serial.c b/chardev/char-serial.c
new file mode 100644
index 0000000000..ab45166615
--- /dev/null
+++ b/chardev/char-serial.c
@@ -0,0 +1,294 @@
+#include "qemu/osdep.h"
+#include "qemu/sockets.h"
+#include "io/channel-file.h"
+#include "qapi/error.h"
+
+#ifdef _WIN32
+#include "char-win.h"
+#else
+#include <sys/ioctl.h>
+#include <termios.h>
+#include "char-fd.h"
+#endif
+
+#include "char-serial.h"
+
+#ifdef _WIN32
+
+static void qmp_chardev_open_serial(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
+{
+    ChardevHostdev *serial = backend->u.serial.data;
+
+    win_chr_init(chr, serial->device, errp);
+}
+
+#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__GLIBC__)
+
+static void tty_serial_init(int fd, int speed,
+                            int parity, int data_bits, int stop_bits)
+{
+    struct termios tty;
+    speed_t spd;
+
+#if 0
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr(fd, &tty);
+
+#define check_speed(val) if (speed <= val) { spd = B##val; break; }
+    speed = speed * 10 / 11;
+    do {
+        check_speed(50);
+        check_speed(75);
+        check_speed(110);
+        check_speed(134);
+        check_speed(150);
+        check_speed(200);
+        check_speed(300);
+        check_speed(600);
+        check_speed(1200);
+        check_speed(1800);
+        check_speed(2400);
+        check_speed(4800);
+        check_speed(9600);
+        check_speed(19200);
+        check_speed(38400);
+        /* Non-Posix values follow. They may be unsupported on some systems. */
+        check_speed(57600);
+        check_speed(115200);
+#ifdef B230400
+        check_speed(230400);
+#endif
+#ifdef B460800
+        check_speed(460800);
+#endif
+#ifdef B500000
+        check_speed(500000);
+#endif
+#ifdef B576000
+        check_speed(576000);
+#endif
+#ifdef B921600
+        check_speed(921600);
+#endif
+#ifdef B1000000
+        check_speed(1000000);
+#endif
+#ifdef B1152000
+        check_speed(1152000);
+#endif
+#ifdef B1500000
+        check_speed(1500000);
+#endif
+#ifdef B2000000
+        check_speed(2000000);
+#endif
+#ifdef B2500000
+        check_speed(2500000);
+#endif
+#ifdef B3000000
+        check_speed(3000000);
+#endif
+#ifdef B3500000
+        check_speed(3500000);
+#endif
+#ifdef B4000000
+        check_speed(4000000);
+#endif
+        spd = B115200;
+    } while (0);
+
+    cfsetispeed(&tty, spd);
+    cfsetospeed(&tty, spd);
+
+    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+                     | INLCR | IGNCR | ICRNL | IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
+    tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
+    switch (data_bits) {
+    default:
+    case 8:
+        tty.c_cflag |= CS8;
+        break;
+    case 7:
+        tty.c_cflag |= CS7;
+        break;
+    case 6:
+        tty.c_cflag |= CS6;
+        break;
+    case 5:
+        tty.c_cflag |= CS5;
+        break;
+    }
+    switch (parity) {
+    default:
+    case 'N':
+        break;
+    case 'E':
+        tty.c_cflag |= PARENB;
+        break;
+    case 'O':
+        tty.c_cflag |= PARENB | PARODD;
+        break;
+    }
+    if (stop_bits == 2) {
+        tty.c_cflag |= CSTOPB;
+    }
+
+    tcsetattr(fd, TCSANOW, &tty);
+}
+
+static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
+{
+    FDChardev *s = FD_CHARDEV(chr);
+    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
+
+    switch (cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        {
+            QEMUSerialSetParams *ssp = arg;
+            tty_serial_init(fioc->fd,
+                            ssp->speed, ssp->parity,
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable) {
+                tcsendbreak(fioc->fd, 1);
+            }
+        }
+        break;
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        {
+            int sarg = 0;
+            int *targ = (int *)arg;
+            ioctl(fioc->fd, TIOCMGET, &sarg);
+            *targ = 0;
+            if (sarg & TIOCM_CTS) {
+                *targ |= CHR_TIOCM_CTS;
+            }
+            if (sarg & TIOCM_CAR) {
+                *targ |= CHR_TIOCM_CAR;
+            }
+            if (sarg & TIOCM_DSR) {
+                *targ |= CHR_TIOCM_DSR;
+            }
+            if (sarg & TIOCM_RI) {
+                *targ |= CHR_TIOCM_RI;
+            }
+            if (sarg & TIOCM_DTR) {
+                *targ |= CHR_TIOCM_DTR;
+            }
+            if (sarg & TIOCM_RTS) {
+                *targ |= CHR_TIOCM_RTS;
+            }
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        {
+            int sarg = *(int *)arg;
+            int targ = 0;
+            ioctl(fioc->fd, TIOCMGET, &targ);
+            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+            if (sarg & CHR_TIOCM_CTS) {
+                targ |= TIOCM_CTS;
+            }
+            if (sarg & CHR_TIOCM_CAR) {
+                targ |= TIOCM_CAR;
+            }
+            if (sarg & CHR_TIOCM_DSR) {
+                targ |= TIOCM_DSR;
+            }
+            if (sarg & CHR_TIOCM_RI) {
+                targ |= TIOCM_RI;
+            }
+            if (sarg & CHR_TIOCM_DTR) {
+                targ |= TIOCM_DTR;
+            }
+            if (sarg & CHR_TIOCM_RTS) {
+                targ |= TIOCM_RTS;
+            }
+            ioctl(fioc->fd, TIOCMSET, &targ);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void qmp_chardev_open_serial(Chardev *chr,
+                                    ChardevBackend *backend,
+                                    bool *be_opened,
+                                    Error **errp)
+{
+    ChardevHostdev *serial = backend->u.serial.data;
+    int fd;
+
+    fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
+    if (fd < 0) {
+        return;
+    }
+    qemu_set_nonblock(fd);
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+
+    qemu_chr_open_fd(chr, fd, fd);
+}
+#endif /* __linux__ || __sun__ */
+
+#ifdef HAVE_CHARDEV_SERIAL
+static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
+                                  Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+    ChardevHostdev *serial;
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: serial/tty: no device path given");
+        return;
+    }
+    serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
+    serial->device = g_strdup(device);
+}
+
+static void char_serial_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_serial;
+    cc->open = qmp_chardev_open_serial;
+#ifndef _WIN32
+    cc->chr_ioctl = tty_serial_ioctl;
+#endif
+}
+
+
+static const TypeInfo char_serial_type_info = {
+    .name = TYPE_CHARDEV_SERIAL,
+#ifdef _WIN32
+    .parent = TYPE_CHARDEV_WIN,
+#else
+    .parent = TYPE_CHARDEV_FD,
+#endif
+    .class_init = char_serial_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_serial_type_info);
+}
+
+type_init(register_types);
+
+#endif
diff --git a/chardev/char.c b/chardev/char.c
index 2a7eb9a5b4..18a2023624 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -36,7 +36,6 @@
 #include "qapi-visit.h"
 #include "qemu/base64.h"
 #include "io/channel-socket.h"
-#include "io/channel-file.h"
 #include "io/channel-tls.h"
 #include "sysemu/replay.h"
 #include "qemu/help_option.h"
@@ -46,7 +45,6 @@
 #ifndef _WIN32
 #include <sys/times.h>
 #include <sys/wait.h>
-#include <termios.h>
 #include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
@@ -91,6 +89,7 @@
 #ifdef _WIN32
 #include "char-win.h"
 #endif
+#include "char-serial.h"
 
 /***********************************************************/
 /* character device */
@@ -654,198 +653,6 @@ void qemu_chr_fe_take_focus(CharBackend *b)
 
 #ifndef _WIN32
 
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
-    || defined(__GLIBC__)
-
-#define HAVE_CHARDEV_SERIAL 1
-
-static void tty_serial_init(int fd, int speed,
-                            int parity, int data_bits, int stop_bits)
-{
-    struct termios tty;
-    speed_t spd;
-
-#if 0
-    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
-           speed, parity, data_bits, stop_bits);
-#endif
-    tcgetattr (fd, &tty);
-
-#define check_speed(val) if (speed <= val) { spd = B##val; break; }
-    speed = speed * 10 / 11;
-    do {
-        check_speed(50);
-        check_speed(75);
-        check_speed(110);
-        check_speed(134);
-        check_speed(150);
-        check_speed(200);
-        check_speed(300);
-        check_speed(600);
-        check_speed(1200);
-        check_speed(1800);
-        check_speed(2400);
-        check_speed(4800);
-        check_speed(9600);
-        check_speed(19200);
-        check_speed(38400);
-        /* Non-Posix values follow. They may be unsupported on some systems. */
-        check_speed(57600);
-        check_speed(115200);
-#ifdef B230400
-        check_speed(230400);
-#endif
-#ifdef B460800
-        check_speed(460800);
-#endif
-#ifdef B500000
-        check_speed(500000);
-#endif
-#ifdef B576000
-        check_speed(576000);
-#endif
-#ifdef B921600
-        check_speed(921600);
-#endif
-#ifdef B1000000
-        check_speed(1000000);
-#endif
-#ifdef B1152000
-        check_speed(1152000);
-#endif
-#ifdef B1500000
-        check_speed(1500000);
-#endif
-#ifdef B2000000
-        check_speed(2000000);
-#endif
-#ifdef B2500000
-        check_speed(2500000);
-#endif
-#ifdef B3000000
-        check_speed(3000000);
-#endif
-#ifdef B3500000
-        check_speed(3500000);
-#endif
-#ifdef B4000000
-        check_speed(4000000);
-#endif
-        spd = B115200;
-    } while (0);
-
-    cfsetispeed(&tty, spd);
-    cfsetospeed(&tty, spd);
-
-    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
-                          |INLCR|IGNCR|ICRNL|IXON);
-    tty.c_oflag |= OPOST;
-    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
-    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
-    switch(data_bits) {
-    default:
-    case 8:
-        tty.c_cflag |= CS8;
-        break;
-    case 7:
-        tty.c_cflag |= CS7;
-        break;
-    case 6:
-        tty.c_cflag |= CS6;
-        break;
-    case 5:
-        tty.c_cflag |= CS5;
-        break;
-    }
-    switch(parity) {
-    default:
-    case 'N':
-        break;
-    case 'E':
-        tty.c_cflag |= PARENB;
-        break;
-    case 'O':
-        tty.c_cflag |= PARENB | PARODD;
-        break;
-    }
-    if (stop_bits == 2)
-        tty.c_cflag |= CSTOPB;
-
-    tcsetattr (fd, TCSANOW, &tty);
-}
-
-static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
-{
-    FDChardev *s = FD_CHARDEV(chr);
-    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
-
-    switch(cmd) {
-    case CHR_IOCTL_SERIAL_SET_PARAMS:
-        {
-            QEMUSerialSetParams *ssp = arg;
-            tty_serial_init(fioc->fd,
-                            ssp->speed, ssp->parity,
-                            ssp->data_bits, ssp->stop_bits);
-        }
-        break;
-    case CHR_IOCTL_SERIAL_SET_BREAK:
-        {
-            int enable = *(int *)arg;
-            if (enable) {
-                tcsendbreak(fioc->fd, 1);
-            }
-        }
-        break;
-    case CHR_IOCTL_SERIAL_GET_TIOCM:
-        {
-            int sarg = 0;
-            int *targ = (int *)arg;
-            ioctl(fioc->fd, TIOCMGET, &sarg);
-            *targ = 0;
-            if (sarg & TIOCM_CTS)
-                *targ |= CHR_TIOCM_CTS;
-            if (sarg & TIOCM_CAR)
-                *targ |= CHR_TIOCM_CAR;
-            if (sarg & TIOCM_DSR)
-                *targ |= CHR_TIOCM_DSR;
-            if (sarg & TIOCM_RI)
-                *targ |= CHR_TIOCM_RI;
-            if (sarg & TIOCM_DTR)
-                *targ |= CHR_TIOCM_DTR;
-            if (sarg & TIOCM_RTS)
-                *targ |= CHR_TIOCM_RTS;
-        }
-        break;
-    case CHR_IOCTL_SERIAL_SET_TIOCM:
-        {
-            int sarg = *(int *)arg;
-            int targ = 0;
-            ioctl(fioc->fd, TIOCMGET, &targ);
-            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
-                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
-            if (sarg & CHR_TIOCM_CTS)
-                targ |= TIOCM_CTS;
-            if (sarg & CHR_TIOCM_CAR)
-                targ |= TIOCM_CAR;
-            if (sarg & CHR_TIOCM_DSR)
-                targ |= TIOCM_DSR;
-            if (sarg & CHR_TIOCM_RI)
-                targ |= TIOCM_RI;
-            if (sarg & CHR_TIOCM_DTR)
-                targ |= TIOCM_DTR;
-            if (sarg & CHR_TIOCM_RTS)
-                targ |= TIOCM_RTS;
-            ioctl(fioc->fd, TIOCMSET, &targ);
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-#endif /* __linux__ || __sun__ */
-
 #if defined(__linux__)
 
 #define HAVE_CHARDEV_PARPORT 1
@@ -1034,13 +841,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr,
 }
 #endif
 
-#else /* _WIN32 */
-
-#define HAVE_CHARDEV_SERIAL 1
-
-#define MAXCONNECT 1
-#define NTIMEOUT 5000
-
 #endif /* !_WIN32 */
 
 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
@@ -1217,23 +1017,6 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
     backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
 }
 
-#ifdef HAVE_CHARDEV_SERIAL
-static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
-                                  Error **errp)
-{
-    const char *device = qemu_opt_get(opts, "path");
-    ChardevHostdev *serial;
-
-    if (device == NULL) {
-        error_setg(errp, "chardev: serial/tty: no device path given");
-        return;
-    }
-    serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
-    serial->device = g_strdup(device);
-}
-#endif
-
 #ifdef HAVE_CHARDEV_PARPORT
 static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
                                     Error **errp)
@@ -1679,39 +1462,7 @@ QemuOptsList qemu_chardev_opts = {
     },
 };
 
-#ifdef _WIN32
-
-static void qmp_chardev_open_serial(Chardev *chr,
-                                    ChardevBackend *backend,
-                                    bool *be_opened,
-                                    Error **errp)
-{
-    ChardevHostdev *serial = backend->u.serial.data;
-
-    win_chr_init(chr, serial->device, errp);
-}
-
-#else /* WIN32 */
-
-#ifdef HAVE_CHARDEV_SERIAL
-static void qmp_chardev_open_serial(Chardev *chr,
-                                    ChardevBackend *backend,
-                                    bool *be_opened,
-                                    Error **errp)
-{
-    ChardevHostdev *serial = backend->u.serial.data;
-    int fd;
-
-    fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
-    if (fd < 0) {
-        return;
-    }
-    qemu_set_nonblock(fd);
-    tty_serial_init(fd, 115200, 'N', 8, 1);
-
-    qemu_chr_open_fd(chr, fd, fd);
-}
-#endif
+#ifndef _WIN32
 
 #ifdef HAVE_CHARDEV_PARPORT
 static void qmp_chardev_open_parallel(Chardev *chr,
@@ -1769,30 +1520,6 @@ static const TypeInfo char_parallel_type_info = {
 
 #endif /* WIN32 */
 
-#ifdef HAVE_CHARDEV_SERIAL
-
-static void char_serial_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_serial;
-    cc->open = qmp_chardev_open_serial;
-#ifndef _WIN32
-    cc->chr_ioctl = tty_serial_ioctl;
-#endif
-}
-
-static const TypeInfo char_serial_type_info = {
-    .name = TYPE_CHARDEV_SERIAL,
-#ifdef _WIN32
-    .parent = TYPE_CHARDEV_WIN,
-#else
-    .parent = TYPE_CHARDEV_FD,
-#endif
-    .class_init = char_serial_class_init,
-};
-#endif
-
 bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature)
 {
@@ -1894,9 +1621,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-#ifdef HAVE_CHARDEV_SERIAL
-    type_register_static(&char_serial_type_info);
-#endif
 #ifdef HAVE_CHARDEV_PARPORT
     type_register_static(&char_parallel_type_info);
 #endif
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index b2c14fe795..45fc8af0c4 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -8,6 +8,7 @@ chardev-obj-y += char-null.o
 chardev-obj-y += char-pipe.o
 chardev-obj-$(CONFIG_POSIX) += char-pty.o
 chardev-obj-y += char-ringbuf.o
+chardev-obj-y += char-serial.o
 chardev-obj-y += char-socket.o
 chardev-obj-y += char-stdio.o
 chardev-obj-y += char-udp.o
diff --git a/chardev/char-serial.h b/chardev/char-serial.h
new file mode 100644
index 0000000000..404e3d0305
--- /dev/null
+++ b/chardev/char-serial.h
@@ -0,0 +1,12 @@
+#ifndef CHAR_SERIAL_H
+#define CHAR_SERIAL_H
+
+#ifdef _WIN32
+#define HAVE_CHARDEV_SERIAL 1
+#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)    \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__GLIBC__)
+#define HAVE_CHARDEV_SERIAL 1
+#endif
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 53/54] char: move parallel chardev in its own file
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (51 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 52/54] char: move serial chardev to itw " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 54/54] char: headers clean-up Marc-André Lureau
                   ` (2 subsequent siblings)
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char-parallel.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c          | 287 +----------------------------------------------
 chardev/Makefile.objs   |   1 +
 chardev/char-parallel.h |   9 ++
 4 files changed, 303 insertions(+), 286 deletions(-)
 create mode 100644 chardev/char-parallel.c
 create mode 100644 chardev/char-parallel.h

diff --git a/chardev/char-parallel.c b/chardev/char-parallel.c
new file mode 100644
index 0000000000..d5c1d4c13c
--- /dev/null
+++ b/chardev/char-parallel.c
@@ -0,0 +1,292 @@
+#include "qemu/osdep.h"
+#include "sysemu/char.h"
+#include "qapi/error.h"
+#include <sys/ioctl.h>
+
+#ifdef CONFIG_BSD
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#elif defined(__DragonFly__)
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
+#endif
+#else
+#ifdef __linux__
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#endif
+
+#include "char-fd.h"
+#include "char-parallel.h"
+
+#if defined(__linux__)
+
+typedef struct {
+    Chardev parent;
+    int fd;
+    int mode;
+} ParallelChardev;
+
+#define PARALLEL_CHARDEV(obj) \
+    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
+static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
+{
+    if (s->mode != mode) {
+        int m = mode;
+        if (ioctl(s->fd, PPSETMODE, &m) < 0) {
+            return 0;
+        }
+        s->mode = mode;
+    }
+    return 1;
+}
+
+static int pp_ioctl(Chardev *chr, int cmd, void *arg)
+{
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+    int fd = drv->fd;
+    uint8_t b;
+
+    switch (cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0) {
+            return -ENOTSUP;
+        }
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0) {
+            return -ENOTSUP;
+        }
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0) {
+            return -ENOTSUP;
+        }
+        /* Linux gives only the lowest bits, and no way to know data
+           direction! For better compatibility set the fixed upper
+           bits. */
+        *(uint8_t *)arg = b | 0xc0;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0) {
+            return -ENOTSUP;
+        }
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0) {
+            return -ENOTSUP;
+        }
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_DATA_DIR:
+        if (ioctl(fd, PPDATADIR, (int *)arg) < 0) {
+            return -ENOTSUP;
+        }
+        break;
+    case CHR_IOCTL_PP_EPP_READ_ADDR:
+        if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
+            struct ParallelIOArg *parg = arg;
+            int n = read(fd, parg->buffer, parg->count);
+            if (n != parg->count) {
+                return -EIO;
+            }
+        }
+        break;
+    case CHR_IOCTL_PP_EPP_READ:
+        if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+            struct ParallelIOArg *parg = arg;
+            int n = read(fd, parg->buffer, parg->count);
+            if (n != parg->count) {
+                return -EIO;
+            }
+        }
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+        if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
+            struct ParallelIOArg *parg = arg;
+            int n = write(fd, parg->buffer, parg->count);
+            if (n != parg->count) {
+                return -EIO;
+            }
+        }
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE:
+        if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+            struct ParallelIOArg *parg = arg;
+            int n = write(fd, parg->buffer, parg->count);
+            if (n != parg->count) {
+                return -EIO;
+            }
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void qemu_chr_open_pp_fd(Chardev *chr,
+                                int fd,
+                                bool *be_opened,
+                                Error **errp)
+{
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        error_setg_errno(errp, errno, "not a parallel port");
+        close(fd);
+        return;
+    }
+
+    drv->fd = fd;
+    drv->mode = IEEE1284_MODE_COMPAT;
+}
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+
+typedef struct {
+    Chardev parent;
+    int fd;
+} ParallelChardev;
+
+#define PARALLEL_CHARDEV(obj)                                   \
+    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
+static int pp_ioctl(Chardev *chr, int cmd, void *arg)
+{
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+    uint8_t b;
+
+    switch (cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
+            return -ENOTSUP;
+        }
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
+            return -ENOTSUP;
+        }
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
+            return -ENOTSUP;
+        }
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
+            return -ENOTSUP;
+        }
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
+            return -ENOTSUP;
+        }
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void qemu_chr_open_pp_fd(Chardev *chr,
+                                int fd,
+                                bool *be_opened,
+                                Error **errp)
+{
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+    drv->fd = fd;
+    *be_opened = false;
+}
+#endif
+
+#ifdef HAVE_CHARDEV_PARPORT
+static void qmp_chardev_open_parallel(Chardev *chr,
+                                      ChardevBackend *backend,
+                                      bool *be_opened,
+                                      Error **errp)
+{
+    ChardevHostdev *parallel = backend->u.parallel.data;
+    int fd;
+
+    fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
+    if (fd < 0) {
+        return;
+    }
+    qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
+}
+
+static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
+                                    Error **errp)
+{
+    const char *device = qemu_opt_get(opts, "path");
+    ChardevHostdev *parallel;
+
+    if (device == NULL) {
+        error_setg(errp, "chardev: parallel: no device path given");
+        return;
+    }
+    parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
+    parallel->device = g_strdup(device);
+}
+
+static void char_parallel_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = qemu_chr_parse_parallel;
+    cc->open = qmp_chardev_open_parallel;
+#if defined(__linux__)
+    cc->chr_ioctl = pp_ioctl;
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+    defined(__DragonFly__)
+    cc->chr_ioctl = pp_ioctl;
+#endif
+}
+
+static void char_parallel_finalize(Object *obj)
+{
+#if defined(__linux__)
+    Chardev *chr = CHARDEV(obj);
+    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+    defined(__DragonFly__)
+    /* FIXME: close fd? */
+#endif
+}
+
+static const TypeInfo char_parallel_type_info = {
+    .name = TYPE_CHARDEV_PARALLEL,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(ParallelChardev),
+    .instance_finalize = char_parallel_finalize,
+    .class_init = char_parallel_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&char_parallel_type_info);
+}
+
+type_init(register_types);
+
+#endif
diff --git a/chardev/char.c b/chardev/char.c
index 18a2023624..a727c56390 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -53,19 +53,6 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <sys/select.h>
-#ifdef CONFIG_BSD
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <dev/ppbus/ppi.h>
-#include <dev/ppbus/ppbconf.h>
-#elif defined(__DragonFly__)
-#include <dev/misc/ppi/ppi.h>
-#include <bus/ppbus/ppbconf.h>
-#endif
-#else
-#ifdef __linux__
-#include <linux/ppdev.h>
-#include <linux/parport.h>
-#endif
 #ifdef __sun__
 #include <sys/ethernet.h>
 #include <sys/sockio.h>
@@ -78,17 +65,16 @@
 #include <netinet/tcp.h>
 #endif
 #endif
-#endif
 
 #include "qemu/sockets.h"
 #include "ui/qemu-spice.h"
 
 #include "char-mux.h"
-#include "char-fd.h"
 #include "char-io.h"
 #ifdef _WIN32
 #include "char-win.h"
 #endif
+#include "char-parallel.h"
 #include "char-serial.h"
 
 /***********************************************************/
@@ -123,7 +109,6 @@ void qemu_chr_be_generic_open(Chardev *s)
     qemu_chr_be_event(s, CHR_EVENT_OPENED);
 }
 
-
 /* Not reporting errors from writing to logfile, as logs are
  * defined to be "best effort" only */
 static void qemu_chr_fe_write_log(Chardev *s,
@@ -651,198 +636,6 @@ void qemu_chr_fe_take_focus(CharBackend *b)
     }
 }
 
-#ifndef _WIN32
-
-#if defined(__linux__)
-
-#define HAVE_CHARDEV_PARPORT 1
-
-typedef struct {
-    Chardev parent;
-    int fd;
-    int mode;
-} ParallelChardev;
-
-#define PARALLEL_CHARDEV(obj) \
-    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
-
-static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
-{
-    if (s->mode != mode) {
-	int m = mode;
-        if (ioctl(s->fd, PPSETMODE, &m) < 0)
-            return 0;
-	s->mode = mode;
-    }
-    return 1;
-}
-
-static int pp_ioctl(Chardev *chr, int cmd, void *arg)
-{
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-    int fd = drv->fd;
-    uint8_t b;
-
-    switch(cmd) {
-    case CHR_IOCTL_PP_READ_DATA:
-        if (ioctl(fd, PPRDATA, &b) < 0)
-            return -ENOTSUP;
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_WRITE_DATA:
-        b = *(uint8_t *)arg;
-        if (ioctl(fd, PPWDATA, &b) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_READ_CONTROL:
-        if (ioctl(fd, PPRCONTROL, &b) < 0)
-            return -ENOTSUP;
-	/* Linux gives only the lowest bits, and no way to know data
-	   direction! For better compatibility set the fixed upper
-	   bits. */
-        *(uint8_t *)arg = b | 0xc0;
-        break;
-    case CHR_IOCTL_PP_WRITE_CONTROL:
-        b = *(uint8_t *)arg;
-        if (ioctl(fd, PPWCONTROL, &b) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_READ_STATUS:
-        if (ioctl(fd, PPRSTATUS, &b) < 0)
-            return -ENOTSUP;
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_DATA_DIR:
-        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_EPP_READ_ADDR:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = read(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_READ:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = read(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = write(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_WRITE:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = write(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static void qemu_chr_open_pp_fd(Chardev *chr,
-                                int fd,
-                                bool *be_opened,
-                                Error **errp)
-{
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-
-    if (ioctl(fd, PPCLAIM) < 0) {
-        error_setg_errno(errp, errno, "not a parallel port");
-        close(fd);
-        return;
-    }
-
-    drv->fd = fd;
-    drv->mode = IEEE1284_MODE_COMPAT;
-}
-#endif /* __linux__ */
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-
-#define HAVE_CHARDEV_PARPORT 1
-
-typedef struct {
-    Chardev parent;
-    int fd;
-} ParallelChardev;
-
-#define PARALLEL_CHARDEV(obj)                                   \
-    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
-
-static int pp_ioctl(Chardev *chr, int cmd, void *arg)
-{
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-    uint8_t b;
-
-    switch (cmd) {
-    case CHR_IOCTL_PP_READ_DATA:
-        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
-            return -ENOTSUP;
-        }
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_WRITE_DATA:
-        b = *(uint8_t *)arg;
-        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
-            return -ENOTSUP;
-        }
-        break;
-    case CHR_IOCTL_PP_READ_CONTROL:
-        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
-            return -ENOTSUP;
-        }
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_WRITE_CONTROL:
-        b = *(uint8_t *)arg;
-        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
-            return -ENOTSUP;
-        }
-        break;
-    case CHR_IOCTL_PP_READ_STATUS:
-        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
-            return -ENOTSUP;
-        }
-        *(uint8_t *)arg = b;
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static void qemu_chr_open_pp_fd(Chardev *chr,
-                                int fd,
-                                bool *be_opened,
-                                Error **errp)
-{
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-    drv->fd = fd;
-    *be_opened = false;
-}
-#endif
-
-#endif /* !_WIN32 */
-
 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
 {
     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
@@ -1017,23 +810,6 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
     backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
 }
 
-#ifdef HAVE_CHARDEV_PARPORT
-static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
-                                    Error **errp)
-{
-    const char *device = qemu_opt_get(opts, "path");
-    ChardevHostdev *parallel;
-
-    if (device == NULL) {
-        error_setg(errp, "chardev: parallel: no device path given");
-        return;
-    }
-    parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
-    parallel->device = g_strdup(device);
-}
-#endif
-
 static const ChardevClass *char_get_class(const char *driver, Error **errp)
 {
     ObjectClass *oc;
@@ -1462,64 +1238,6 @@ QemuOptsList qemu_chardev_opts = {
     },
 };
 
-#ifndef _WIN32
-
-#ifdef HAVE_CHARDEV_PARPORT
-static void qmp_chardev_open_parallel(Chardev *chr,
-                                      ChardevBackend *backend,
-                                      bool *be_opened,
-                                      Error **errp)
-{
-    ChardevHostdev *parallel = backend->u.parallel.data;
-    int fd;
-
-    fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
-    if (fd < 0) {
-        return;
-    }
-    qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
-}
-
-static void char_parallel_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = qemu_chr_parse_parallel;
-    cc->open = qmp_chardev_open_parallel;
-#if defined(__linux__)
-    cc->chr_ioctl = pp_ioctl;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-    cc->chr_ioctl = pp_ioctl;
-#endif
-}
-
-static void char_parallel_finalize(Object *obj)
-{
-#if defined(__linux__)
-    Chardev *chr = CHARDEV(obj);
-    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
-    int fd = drv->fd;
-
-    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
-    ioctl(fd, PPRELEASE);
-    close(fd);
-    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-    /* FIXME: close fd? */
-#endif
-}
-
-static const TypeInfo char_parallel_type_info = {
-    .name = TYPE_CHARDEV_PARALLEL,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(ParallelChardev),
-    .instance_finalize = char_parallel_finalize,
-    .class_init = char_parallel_class_init,
-};
-#endif
-
-#endif /* WIN32 */
-
 bool qemu_chr_has_feature(Chardev *chr,
                           CharDriverFeature feature)
 {
@@ -1621,9 +1339,6 @@ void qemu_chr_cleanup(void)
 static void register_types(void)
 {
     type_register_static(&char_type_info);
-#ifdef HAVE_CHARDEV_PARPORT
-    type_register_static(&char_parallel_type_info);
-#endif
 
     /* this must be done after machine init, since we register FEs with muxes
      * as part of realize functions like serial_isa_realizefn when -nographic
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index 45fc8af0c4..1feda0f0ed 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -5,6 +5,7 @@ chardev-obj-y += char-file.o
 chardev-obj-y += char-io.o
 chardev-obj-y += char-mux.o
 chardev-obj-y += char-null.o
+chardev-obj-$(CONFIG_POSIX) += char-parallel.o
 chardev-obj-y += char-pipe.o
 chardev-obj-$(CONFIG_POSIX) += char-pty.o
 chardev-obj-y += char-ringbuf.o
diff --git a/chardev/char-parallel.h b/chardev/char-parallel.h
new file mode 100644
index 0000000000..43d285971b
--- /dev/null
+++ b/chardev/char-parallel.h
@@ -0,0 +1,9 @@
+#ifndef CHAR_PARALLEL_H
+#define CHAR_PARALLEL_H
+
+#if defined(__linux__) || defined(__FreeBSD__) || \
+    defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#define HAVE_CHARDEV_PARPORT 1
+#endif
+
+#endif /* CHAR_PARALLEL_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [Qemu-devel] [PATCH 54/54] char: headers clean-up
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (52 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 53/54] char: move parallel chardev in its " Marc-André Lureau
@ 2016-12-12 22:43 ` Marc-André Lureau
  2016-12-13  0:33 ` [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify no-reply
  2017-01-02 10:26 ` Paolo Bonzini
  55 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-12 22:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Those could probably be squashed with earlier patches, however I
couldn't easily identify them, test them or check if there are still
necessary on various platforms.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 chardev/char.c | 39 ---------------------------------------
 1 file changed, 39 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index a727c56390..e03525aec3 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -26,54 +26,15 @@
 #include "qemu/cutils.h"
 #include "monitor/monitor.h"
 #include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
 #include "qemu/error-report.h"
-#include "qemu/timer.h"
 #include "sysemu/char.h"
-#include "hw/usb.h"
 #include "qmp-commands.h"
-#include "qapi/clone-visitor.h"
 #include "qapi-visit.h"
-#include "qemu/base64.h"
-#include "io/channel-socket.h"
-#include "io/channel-tls.h"
 #include "sysemu/replay.h"
 #include "qemu/help_option.h"
 
-#include <zlib.h>
-
-#ifndef _WIN32
-#include <sys/times.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/select.h>
-#ifdef __sun__
-#include <sys/ethernet.h>
-#include <sys/sockio.h>
-#include <netinet/arp.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h> // must come after ip.h
-#include <netinet/udp.h>
-#include <netinet/tcp.h>
-#endif
-#endif
-
-#include "qemu/sockets.h"
-#include "ui/qemu-spice.h"
-
 #include "char-mux.h"
 #include "char-io.h"
-#ifdef _WIN32
-#include "char-win.h"
-#endif
 #include "char-parallel.h"
 #include "char-serial.h"
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (53 preceding siblings ...)
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 54/54] char: headers clean-up Marc-André Lureau
@ 2016-12-13  0:33 ` no-reply
  2017-01-02 10:26 ` Paolo Bonzini
  55 siblings, 0 replies; 85+ messages in thread
From: no-reply @ 2016-12-13  0:33 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: famz, qemu-devel, pbonzini

Hi,

Your series seems to have some coding style problems. See output below for
more information:

Subject: [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
Type: series
Message-id: 20161212224325.20790-1-marcandre.lureau@redhat.com

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
6dd47da char: headers clean-up
eae63eb char: move parallel chardev in its own file
513bbbd char: move serial chardev to itw own file
2aad2df char: move pty chardev in its own file
ca281a9 char: move pipe chardev in its own file
7badddb char: move console in its own file
647d879 char: move stdio in its own file
55a7839 char: move file chardev in its own file
c1d5963 char: move udp chardev in its own file
ca11e13 char: move socket chardev to itw own file
ff7313b char: move win-stdio into its own file
4c6498d char: move win chardev base class in its own file
33aaee6 char: move fd chardev in its own file
4de906b char: move QIOChannel-related in char-io.h
31c1f1a char: remove unused READ_RETRIES
4efc6d4 char: rename and move to header CHR_READ_BUF_LEN
36c17aa char: move ringbuf/memory to its own file
027ca5a char: move mux to its own file
c6d8321 char: move null chardev to its own file
d65b167 char: make null_chr_write() the default method
609664c char: create chardev-obj-y
75fcc6e char: move to chardev/
844de46 char: remove class kind field
ad2221e char: get rid of CharDriver
90b9713 char: remove chr_free
7c4855f char-fd: convert to finalize
43a0815 char-win: convert to finalize
da085e4 char-win: do not override chr_free
41c23fa char-win-stdio: convert to finalize
4fd4b2f char-stdio: convert to finalize
aa5ce7d char-parallel: convert parallel to finalize
1c19acc char-ringbuf: convert to finalize
c57180d char-pty: convert to finalize
2105b5a char-socket: convert to finalize
070b2bc char-udp: convert to finalize
40786d6 mux: convert to finalize
a14b7cc msmouse: convert to finalize
1d27cb9 baum: convert to finalize
4a16040 spice-qemu-char: convert to finalize
1b0eeaa chardev: qom-ify
1b252d2 gtk: overwrite the console.c char driver
465bb1b char: use error_report()
2f15b5a spice-char: improve error reporting
96b38bf char: rename TCPChardev and NetChardev
c4738ef char: rename CharDriverState Chardev
39e99a6 bt: use qemu_chr_alloc()
3bdbe90 char: allocate CharDriverState as a single object
495e3c5 char: use a feature bit for replay
37280da char: introduce generic qemu_chr_get_kind()
0011e50 char: fold single-user functions in caller
72464ef char: move callbacks in CharDriver
6dc33a0 char: use a static array for backends
a3e1bca char: use a const CharDriver
2ac8265 gtk: avoid oob array access

=== OUTPUT BEGIN ===
Checking PATCH 1/54: gtk: avoid oob array access...
Checking PATCH 2/54: char: use a const CharDriver...
Checking PATCH 3/54: char: use a static array for backends...
Checking PATCH 4/54: char: move callbacks in CharDriver...
WARNING: architecture specific defines should be avoided
#1106: FILE: qemu-char.c:4704:
+#if defined(__linux__)

WARNING: line over 80 characters
#1110: FILE: qemu-char.c:4708:
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)

total: 0 errors, 2 warnings, 1365 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 5/54: char: fold single-user functions in caller...
Checking PATCH 6/54: char: introduce generic qemu_chr_get_kind()...
Checking PATCH 7/54: char: use a feature bit for replay...
Checking PATCH 8/54: char: allocate CharDriverState as a single object...
Checking PATCH 9/54: bt: use qemu_chr_alloc()...
Checking PATCH 10/54: char: rename CharDriverState Chardev...
Checking PATCH 11/54: char: rename TCPChardev and NetChardev...
Checking PATCH 12/54: spice-char: improve error reporting...
Checking PATCH 13/54: char: use error_report()...
WARNING: line over 80 characters
#61: FILE: qemu-char.c:4137:
+                g_string_append_printf(str, "\n%s", ChardevBackendKind_lookup[cd->kind]);

total: 0 errors, 1 warnings, 64 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 14/54: gtk: overwrite the console.c char driver...
Checking PATCH 15/54: chardev: qom-ify...
WARNING: architecture specific defines should be avoided
#1385: FILE: qemu-char.c:1462:
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)     \

total: 0 errors, 1 warnings, 3582 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 16/54: spice-qemu-char: convert to finalize...
Checking PATCH 17/54: baum: convert to finalize...
Checking PATCH 18/54: msmouse: convert to finalize...
Checking PATCH 19/54: mux: convert to finalize...
Checking PATCH 20/54: char-udp: convert to finalize...
Checking PATCH 21/54: char-socket: convert to finalize...
Checking PATCH 22/54: char-pty: convert to finalize...
Checking PATCH 23/54: char-ringbuf: convert to finalize...
Checking PATCH 24/54: char-parallel: convert parallel to finalize...
WARNING: architecture specific defines should be avoided
#48: FILE: qemu-char.c:4696:
+#if defined(__linux__)

WARNING: line over 80 characters
#57: FILE: qemu-char.c:4705:
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)

total: 0 errors, 2 warnings, 52 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 25/54: char-stdio: convert to finalize...
Checking PATCH 26/54: char-win-stdio: convert to finalize...
Checking PATCH 27/54: char-win: do not override chr_free...
Checking PATCH 28/54: char-win: convert to finalize...
Checking PATCH 29/54: char-fd: convert to finalize...
Checking PATCH 30/54: char: remove chr_free...
Checking PATCH 31/54: char: get rid of CharDriver...
Checking PATCH 32/54: char: remove class kind field...
Checking PATCH 33/54: char: move to chardev/...
Checking PATCH 34/54: char: create chardev-obj-y...
Checking PATCH 35/54: char: make null_chr_write() the default method...
Checking PATCH 36/54: char: move null chardev to its own file...
Checking PATCH 37/54: char: move mux to its own file...
Checking PATCH 38/54: char: move ringbuf/memory to its own file...
Checking PATCH 39/54: char: rename and move to header CHR_READ_BUF_LEN...
Checking PATCH 40/54: char: remove unused READ_RETRIES...
Checking PATCH 41/54: char: move QIOChannel-related in char-io.h...
Checking PATCH 42/54: char: move fd chardev in its own file...
Checking PATCH 43/54: char: move win chardev base class in its own file...
Checking PATCH 44/54: char: move win-stdio into its own file...
Checking PATCH 45/54: char: move socket chardev to itw own file...
Checking PATCH 46/54: char: move udp chardev in its own file...
Checking PATCH 47/54: char: move file chardev in its own file...
Checking PATCH 48/54: char: move stdio in its own file...
WARNING: architecture specific defines should be avoided
#271: FILE: chardev/char.c:687:
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \

total: 0 errors, 1 warnings, 293 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 49/54: char: move console in its own file...
Checking PATCH 50/54: char: move pipe chardev in its own file...
Checking PATCH 51/54: char: move pty chardev in its own file...
WARNING: architecture specific defines should be avoided
#40: FILE: chardev/char-pty.c:11:
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \

total: 0 errors, 1 warnings, 554 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 52/54: char: move serial chardev to itw own file...
ERROR: if this code is redundant consider removing it
#67: FILE: chardev/char-serial.c:38:
+#if 0

ERROR: braces {} are necessary for all arms of this statement
#73: FILE: chardev/char-serial.c:44:
+#define check_speed(val) if (speed <= val) { spd = B##val; break; }
[...]

total: 2 errors, 0 warnings, 647 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 53/54: char: move parallel chardev in its own file...
WARNING: architecture specific defines should be avoided
#36: FILE: chardev/char-parallel.c:7:
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)

WARNING: architecture specific defines should be avoided
#44: FILE: chardev/char-parallel.c:15:
+#ifdef __linux__

WARNING: architecture specific defines should be avoided
#53: FILE: chardev/char-parallel.c:24:
+#if defined(__linux__)

WARNING: line over 80 characters
#181: FILE: chardev/char-parallel.c:152:
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)

WARNING: architecture specific defines should be avoided
#181: FILE: chardev/char-parallel.c:152:
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)

WARNING: architecture specific defines should be avoided
#281: FILE: chardev/char-parallel.c:252:
+#if defined(__linux__)

WARNING: architecture specific defines should be avoided
#291: FILE: chardev/char-parallel.c:262:
+#if defined(__linux__)

WARNING: architecture specific defines should be avoided
#331: FILE: chardev/char-parallel.h:4:
+#if defined(__linux__) || defined(__FreeBSD__) || \

total: 0 errors, 8 warnings, 646 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 54/54: char: headers clean-up...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y
  2016-12-12 22:43 ` [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y Marc-André Lureau
@ 2016-12-13 11:10   ` Paolo Bonzini
  2016-12-13 12:40     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Paolo Bonzini @ 2016-12-13 11:10 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel



On 12/12/2016 23:43, Marc-André Lureau wrote:
> This will help to split char.c in several units without having to
> reference them all everywhere.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  Makefile               | 3 ++-
>  Makefile.objs          | 4 +++-
>  Makefile.target        | 3 +++
>  chardev/Makefile.objs  | 2 +-
>  tests/Makefile.include | 4 ++--
>  5 files changed, 11 insertions(+), 5 deletions(-)

Any reason to do this instead of keeping common-obj-y?

Thanks,

Paolo

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y
  2016-12-13 11:10   ` Paolo Bonzini
@ 2016-12-13 12:40     ` Marc-André Lureau
  2016-12-13 12:52       ` Paolo Bonzini
  0 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2016-12-13 12:40 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel

Hi

On Tue, Dec 13, 2016 at 2:18 PM Paolo Bonzini <pbonzini@redhat.com> wrote:

>
>
> On 12/12/2016 23:43, Marc-André Lureau wrote:
> > This will help to split char.c in several units without having to
> > reference them all everywhere.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  Makefile               | 3 ++-
> >  Makefile.objs          | 4 +++-
> >  Makefile.target        | 3 +++
> >  chardev/Makefile.objs  | 2 +-
> >  tests/Makefile.include | 4 ++--
> >  5 files changed, 11 insertions(+), 5 deletions(-)
>
> Any reason to do this instead of keeping common-obj-y?
>
>
common-obj-y has a lot of other units, including vl.o, making it not
possible to link with tests/test-char for ex. However, if we changed it to
link with everything except vl.c (or other changes), we may be able to link
with and test spice-qemu-char. The resulting binaries will likely explode
though.

Thanks,
>
> Paolo
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y
  2016-12-13 12:40     ` Marc-André Lureau
@ 2016-12-13 12:52       ` Paolo Bonzini
  0 siblings, 0 replies; 85+ messages in thread
From: Paolo Bonzini @ 2016-12-13 12:52 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel



On 13/12/2016 13:40, Marc-André Lureau wrote:
> 
>     On 12/12/2016 23:43, Marc-André Lureau wrote:
>     > This will help to split char.c in several units without having to
>     > reference them all everywhere.
>     >
>     > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com
>     <mailto:marcandre.lureau@redhat.com>>
>     > ---
>     >  Makefile               | 3 ++-
>     >  Makefile.objs          | 4 +++-
>     >  Makefile.target        | 3 +++
>     >  chardev/Makefile.objs  | 2 +-
>     >  tests/Makefile.include | 4 ++--
>     >  5 files changed, 11 insertions(+), 5 deletions(-)
> 
>     Any reason to do this instead of keeping common-obj-y?
> 
> 
> common-obj-y has a lot of other units, including vl.o, making it not
> possible to link with tests/test-char for ex. However, if we changed it
> to link with everything except vl.c (or other changes), we may be able
> to link with and test spice-qemu-char. The resulting binaries will
> likely explode though.

Ok, so it's for tests.  Fair enough!

Paolo

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 02/54] char: use a const CharDriver
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 02/54] char: use a const CharDriver Marc-André Lureau
@ 2016-12-13 23:11   ` Eric Blake
  2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2016-12-13 23:11 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 3704 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> No need to allocate & copy fileds, let's use static const struct

s/fileds/fields/

> instead.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  backends/baum.c       |   8 +++-
>  backends/msmouse.c    |   7 +++-
>  backends/testdev.c    |   7 +++-
>  qemu-char.c           | 100 ++++++++++++++++++++++++--------------------------
>  spice-qemu-char.c     |  14 +++++--
>  ui/console.c          |   9 +++--
>  include/sysemu/char.h |  19 +++++-----
>  7 files changed, 90 insertions(+), 74 deletions(-)
> 

> +++ b/backends/baum.c
> @@ -686,8 +686,12 @@ fail_handle:
>  
>  static void register_types(void)
>  {
> -    register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL,
> -                         chr_baum_init);
> +    static const CharDriver driver = {
> +        .kind = CHARDEV_BACKEND_KIND_BRAILLE,
> +        .parse = NULL, .create = chr_baum_init

Why did the "braille" string disappear?  Oh, I see... [1]

No need to specify .parse, since C99 initialization guarantees
zero-assignment to any field omitted.

I kind of prefer one struct member per line when doing C99
initialization, rather than bunching two in one line.

I also prefer a trailing comma, as then adding a new (non-zero) member
initialization in a later patch is a one-line addition, rather than
modifying an existing line to add a trailing comma.


> +++ b/backends/msmouse.c
> @@ -179,8 +179,11 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
>  
>  static void register_types(void)
>  {
> -    register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL,
> -                         qemu_chr_open_msmouse);
> +    static const CharDriver driver = {
> +        .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
> +        .parse = NULL, .create = qemu_chr_open_msmouse

Looks like my comments are repeated throughout the patch.


> -void register_char_driver(const char *name, ChardevBackendKind kind,
> -                          CharDriverParse *parse, CharDriverCreate *create)
> +void register_char_driver(const CharDriver *driver)
>  {
> -    CharDriver *s;
> -
> -    s = g_malloc0(sizeof(*s));
> -    s->name = g_strdup(name);
> -    s->kind = kind;
> -    s->parse = parse;
> -    s->create = create;
> -
> -    backends = g_slist_append(backends, s);
> +    backends = g_slist_append(backends, (void *)driver);

Might be worth a comment that this is casting away const (as my first
reaction is "oh, you forgot that C allows automatic conversion of any
pointer to void*")

>  }
>  
>  CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
> @@ -4139,7 +4123,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
>          fprintf(stderr, "Available chardev backend types:\n");
>          for (i = backends; i; i = i->next) {
>              cd = i->data;
> -            fprintf(stderr, "%s\n", cd->name);
> +            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);

...[1] Your series is already long, so don't feel like you have to do
this, but: if I were working on it, I might have done the elimination of
cd->name, the name parameter, and the use of ChardevBackendKind_lookup[]
in one patch (getting rid of JUST the "braille" parameter and friends at
the call sites), and then the const'ification of the remaining
parameters in the second patch.

> +++ b/include/sysemu/char.h

Laszlo's suggestion of the git order file would have promoted this part
of the patch first :)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 03/54] char: use a static array for backends
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 03/54] char: use a static array for backends Marc-André Lureau
@ 2016-12-14 14:52   ` Eric Blake
  2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2016-12-14 14:52 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 6162 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Number and kinds of backends is known at compile-time, use a fixed-sized
> static array to simplify iterations & lookups.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qemu-char.c           | 101 ++++++++++++++++++++++++++++----------------------
>  include/sysemu/char.h |   1 +
>  2 files changed, 58 insertions(+), 44 deletions(-)
> 

> @@ -4121,9 +4121,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
>  
>      if (is_help_option(qemu_opt_get(opts, "backend"))) {
>          fprintf(stderr, "Available chardev backend types:\n");
> -        for (i = backends; i; i = i->next) {
> -            cd = i->data;
> -            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
> +        for (i = 0; i < ARRAY_SIZE(backends); i++) {
> +            cd = backends[i];
> +            if (cd) {
> +                fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
> +                if (cd->alias) {
> +                    fprintf(stderr, "%s\n", cd->alias);
> +                }
> +            }

Where did cd->alias come from?
/me reads rest of patch
Oh, you added it in the .h file. All the more reason to use patch
ordering to list .h changes first, but may also be worth a mention in
the commit message that you add an alias field to cover the cases where
we previously registered a driver twice under two names.

> 
> -        cd = i->data;
> +    cd = NULL;
> +    for (i = 0; i < ARRAY_SIZE(backends); i++) {
> +        const char *name = qemu_opt_get(opts, "backend");
> +        cd = backends[i];

Please hoist the computation of 'name' outside of the loop...

> -        if (strcmp(ChardevBackendKind_lookup[cd->kind],
> -                   qemu_opt_get(opts, "backend")) == 0) {
> +        if (!cd) {
> +            continue;
> +        }
> +        if (g_str_equal(ChardevBackendKind_lookup[cd->kind], name) ||
> +            (cd->alias && g_str_equal(cd->alias, name))) {

Doesn't g_str_equal(NULL, "str") do the right thing without crashing?
Therefore, no need to check if cd->alias is non-NULL.

>              break;
>          }
>      }
> -    if (i == NULL) {
> +    if (cd == NULL) {
>          error_setg(errp, "chardev: backend \"%s\" not found",
>                     qemu_opt_get(opts, "backend"));

...and then reuse 'name' here as well, rather than making multiple
repeated calls to qemu_opt_get().

>  ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
>  {
>      ChardevBackendInfoList *backend_list = NULL;
> -    CharDriver *c = NULL;
> -    GSList *i = NULL;
> +    const CharDriver *c;
> +    int i;
>  
> -    for (i = backends; i; i = i->next) {
> -        ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
> -        c = i->data;
> -        info->value = g_malloc0(sizeof(*info->value));
> -        info->value->name = g_strdup(ChardevBackendKind_lookup[c->kind]);
> +    for (i = 0; i < ARRAY_SIZE(backends); i++) {
> +        c = backends[i];
> +        if (!c) {
> +            continue;
> +        }
>  
> -        info->next = backend_list;
> -        backend_list = info;
> +        backend_list = qmp_prepend_backend(backend_list, c,
> +                                           ChardevBackendKind_lookup[c->kind]);
> +        if (c->alias) {
> +            backend_list = qmp_prepend_backend(backend_list, c, c->alias);

The help text now lists aliases immediately after the canonical name,
while the QMP command now prepends aliases prior to the canonical name.
It doesn't affect correctness, but should you try to make the two lists
appear in the same order?  (Presumably by prepending the alias first,
not second.)


> @@ -4907,16 +4925,11 @@ static void register_types(void)
>          { .kind = CHARDEV_BACKEND_KIND_STDIO,
>            .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
>  #if defined HAVE_CHARDEV_SERIAL
> -        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
> -          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },
> -        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
> +        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
>            .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },

Wait. How did patch 2/54 work? Or did you temporarily break the 'tty'
alias in that patch, and then fix it here?  All the more reason that my
review of 2/54 complaining about getting rid of the cd->name field
should be a separate patch; now I'm convinced of it.  But in that patch,
I suggested the order:

remove cd->name field as redundant with enum array lookup
convert to struct without cd->name

Whereas with this patch in the mix, the steps should probably be:

convert to struct that still has cd->name
add cd->alias to have multiple names
remove cd->name field as redundant with enum array lookup

>  #endif
>  #ifdef HAVE_CHARDEV_PARPORT
> -        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
> -          .parse = qemu_chr_parse_parallel,
> -          .create = qmp_chardev_open_parallel },
> -        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
> +        { .kind = CHARDEV_BACKEND_KIND_PARALLEL, .alias = "parport",
>            .parse = qemu_chr_parse_parallel,
>            .create = qmp_chardev_open_parallel },

Again, another breakage in 2/54.

>  #endif
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 144514c962..c8750ede21 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -474,6 +474,7 @@ void qemu_chr_set_feature(CharDriverState *chr,
>  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
>  
>  typedef struct CharDriver {
> +    const char *alias;
>      ChardevBackendKind kind;
>      void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
>      CharDriverState *(*create)(const char *id,
> 

Overall, I like the direction this is headed in.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver Marc-André Lureau
@ 2016-12-14 16:02   ` Eric Blake
  2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2016-12-14 16:02 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 6887 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> This makes the code more declarative, and avoids to duplicate the

s/to duplicate/duplicating/

> information on all instances.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  backends/baum.c       |  13 +-
>  backends/msmouse.c    |  13 +-
>  backends/testdev.c    |  10 +-
>  gdbstub.c             |   7 +-
>  hw/bt/hci-csr.c       |   8 +-
>  qemu-char.c           | 427 +++++++++++++++++++++++++++++++-------------------
>  spice-qemu-char.c     |  36 +++--
>  ui/console.c          |  26 +--
>  ui/gtk.c              |  11 +-
>  include/sysemu/char.h |  46 +++---

Again, seeing the .h changes first makes a huge difference on code
review.  I'm manually reformatting:

>  10 files changed, 370 insertions(+), 227 deletions(-)

> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index c8750ede21..09e40ef9b8 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -85,24 +85,11 @@ typedef struct CharBackend {
>      int fe_open;
>  } CharBackend;
>
> +typedef struct CharDriver CharDriver;
> +
>  struct CharDriverState {
> +    const CharDriver *driver;
>      QemuMutex chr_write_lock;
> -    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf,
int len);

So all the callbacks are moved into the CharDriver struct...

> @@ -125,7 +112,8 @@ struct CharDriverState {
>   *
>   * Returns: a newly allocated CharDriverState, or NULL on error.
>   */
> -CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp);
> +CharDriverState *qemu_chr_alloc(const CharDriver *driver,
> +                                ChardevCommon *backend, Error **errp);

...and all the entry points are now passed that struct as a new parameter.

>
>  /**
>   * @qemu_chr_new_from_opts:
> @@ -473,15 +461,33 @@ void qemu_chr_set_feature(CharDriverState *chr,
>                            CharDriverFeature feature);
>  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
>
> -typedef struct CharDriver {
> +struct CharDriver {

...the struct already existed, but is now more useful.

Looks worthwhile. I suspect the rest of the patch is mechanical.

> @@ -688,7 +686,10 @@ static void register_types(void)
>  {
>      static const CharDriver driver = {
>          .kind = CHARDEV_BACKEND_KIND_BRAILLE,
> -        .parse = NULL, .create = chr_baum_init
> +        .parse = NULL, .create = chr_baum_init,

And now you see why I asked for trailing commas in 2/54 :)

> +        .chr_write = baum_write,
> +        .chr_accept_input = baum_accept_input,
> +        .chr_free = baum_free,
>      };
>  

> +++ b/gdbstub.c
> @@ -1730,6 +1730,10 @@ int gdbserver_start(const char *device)
>      CharDriverState *chr = NULL;
>      CharDriverState *mon_chr;
>      ChardevCommon common = { 0 };
> +    static const CharDriver driver = {
> +        .kind = -1,
> +        .chr_write = gdb_monitor_write

Trailing comma.

Interesting that this is a new use of CharDriver with an out-of-range
.kind. But I think your code in 3/54 was careful to explicitly handle a
.kind that does not map to one of the public types, so that you are able
to use this as an internal-only driver.


>  
> +static const CharDriver null_driver = {
> +    .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,

One initializer per line is fine.

> +    .chr_write = null_chr_write
> +};
> +

> 
> @@ -864,14 +880,6 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
>  
>      chr->opaque = d;
>      d->focus = -1;
> -    chr->chr_free = mux_chr_free;
> -    chr->chr_write = mux_chr_write;
> -    chr->chr_accept_input = mux_chr_accept_input;
> -    /* Frontend guest-open / -close notification is not support with muxes */
> -    chr->chr_set_fe_open = NULL;
> -    if (drv->chr_add_watch) {
> -        chr->chr_add_watch = mux_chr_add_watch;
> -    }

Here, the callback was only conditionally registered...

> +static const CharDriver mux_driver = {
> +    .kind = CHARDEV_BACKEND_KIND_MUX,
> +    .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
> +    .chr_free = mux_chr_free,
> +    .chr_write = mux_chr_write,
> +    .chr_accept_input = mux_chr_accept_input,
> +    .chr_add_watch = mux_chr_add_watch,
> +};

...but here, it is always registered.  Is that an unintentional semantic
change?


> +#ifdef HAVE_CHARDEV_SERIAL
> +static const CharDriver serial_driver = {
> +    .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
> +    .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
> +#ifdef _WIN32
> +    .chr_write = win_chr_write,
> +    .chr_free = win_chr_free,
> +#else
> +    .chr_add_watch = fd_chr_add_watch,
> +    .chr_write = fd_chr_write,
> +    .chr_update_read_handler = fd_chr_update_read_handler,
> +    .chr_ioctl = tty_serial_ioctl,
> +    .chr_free = qemu_chr_free_tty,
> +#endif
> +};
> +#endif


> @@ -4910,49 +5037,33 @@ void qemu_chr_cleanup(void)
>  
>  static void register_types(void)
>  {
> -    int i;
> -    static const CharDriver drivers[] = {
> -        { .kind = CHARDEV_BACKEND_KIND_NULL, .parse = NULL,
> -          .create = qemu_chr_open_null },
> -        { .kind = CHARDEV_BACKEND_KIND_SOCKET,
> -          .parse = qemu_chr_parse_socket, .create = qmp_chardev_open_socket },
> -        { .kind = CHARDEV_BACKEND_KIND_UDP, .parse = qemu_chr_parse_udp,
> -          .create = qmp_chardev_open_udp },
> -        { .kind = CHARDEV_BACKEND_KIND_RINGBUF,
> -          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf },
> -        { .kind = CHARDEV_BACKEND_KIND_FILE,
> -          .parse = qemu_chr_parse_file_out, .create = qmp_chardev_open_file },
> -        { .kind = CHARDEV_BACKEND_KIND_STDIO,
> -          .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
> -#if defined HAVE_CHARDEV_SERIAL
> -        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
> -          .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial },

It feels like some code motion between 3/54 and 4/54 (you are moving
where the CharDriver is declared); is it worth tweaking the series to
avoid the code motion by declaring the structs in the right place to
begin with?  Not necessarily a show-stopper to the series, though.

> +    static const CharDriver *drivers[] = {
> +        &null_driver,
> +        &socket_driver,
> +        &udp_driver,
> +        &ringbuf_driver,
> +        &file_driver,
> +        &stdio_driver,
> +#ifdef HAVE_CHARDEV_SERIAL
> +        &serial_driver,
>  #endif

Overall impression is that I still like where this is headed.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller Marc-André Lureau
@ 2016-12-14 16:05   ` Eric Blake
  2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2016-12-14 16:05 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 1003 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> This shorten a bit the code.

Grammar:
This shortens the code a bit.

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qemu-char.c | 97 ++++++++++++++++++++-----------------------------------------
>  1 file changed, 31 insertions(+), 66 deletions(-)
> 

>      name = g_strdup_printf("chardev-udp-%s", chr->label);
>      qio_channel_set_name(QIO_CHANNEL(sioc), name);
>      g_free(name);
>  
> +    s = g_new0(NetCharDriver, 1);
> +    s->ioc = QIO_CHANNEL(sioc);
> +    s->bufcnt = 0;
> +    s->bufptr = 0;
> +    chr->opaque = s;
> +    /* be isn't opened until we get a connection */
> +    *be_opened = false;

The assignments to 0 and false are redundant with the g_new0(), if you
want to drop them for even more code reduction.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind()
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind() Marc-André Lureau
@ 2016-12-19 21:16   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2016-12-19 21:16 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 546 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> This allows to remove the "is_mux" field from CharDriverState.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  monitor.c             |  2 +-
>  qemu-char.c           | 21 ++++++++++-----------
>  include/sysemu/char.h | 15 +++++++++++++--
>  3 files changed, 24 insertions(+), 14 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay Marc-André Lureau
@ 2016-12-19 21:58   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2016-12-19 21:58 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 510 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Use a feature flag rather than a structure field for "replay".
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qemu-char.c           | 33 ++++++++++++++++++++-------------
>  include/sysemu/char.h |  3 ++-
>  2 files changed, 22 insertions(+), 14 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>


-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
  2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
                   ` (54 preceding siblings ...)
  2016-12-13  0:33 ` [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify no-reply
@ 2017-01-02 10:26 ` Paolo Bonzini
  2017-01-04 21:20   ` Marc-André Lureau
  55 siblings, 1 reply; 85+ messages in thread
From: Paolo Bonzini @ 2017-01-02 10:26 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel



On 12/12/2016 23:42, Marc-André Lureau wrote:
> 
> Note: this series has been tested with Linux and cross-building with
> mingw. It mostly breaks on other platforms,

What breaks exactly?

Paolo

> help welcome for
> testing. I'd also like to write more chardev backend tests to ensure
> no regression (test-char.c is quite limited for now)

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 03/54] char: use a static array for backends
  2016-12-14 14:52   ` Eric Blake
@ 2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-02 15:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: Marc-André Lureau, qemu-devel, pbonzini

Hi

----- Original Message -----
> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > Number and kinds of backends is known at compile-time, use a fixed-sized
> > static array to simplify iterations & lookups.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  qemu-char.c           | 101
> >  ++++++++++++++++++++++++++++----------------------
> >  include/sysemu/char.h |   1 +
> >  2 files changed, 58 insertions(+), 44 deletions(-)
> > 
> 
> > @@ -4121,9 +4121,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts
> > *opts,
> >  
> >      if (is_help_option(qemu_opt_get(opts, "backend"))) {
> >          fprintf(stderr, "Available chardev backend types:\n");
> > -        for (i = backends; i; i = i->next) {
> > -            cd = i->data;
> > -            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
> > +        for (i = 0; i < ARRAY_SIZE(backends); i++) {
> > +            cd = backends[i];
> > +            if (cd) {
> > +                fprintf(stderr, "%s\n",
> > ChardevBackendKind_lookup[cd->kind]);
> > +                if (cd->alias) {
> > +                    fprintf(stderr, "%s\n", cd->alias);
> > +                }
> > +            }
> 
> Where did cd->alias come from?
> /me reads rest of patch
> Oh, you added it in the .h file. All the more reason to use patch
> ordering to list .h changes first, but may also be worth a mention in
> the commit message that you add an alias field to cover the cases where
> we previously registered a driver twice under two names.

ok

> 
> > 
> > -        cd = i->data;
> > +    cd = NULL;
> > +    for (i = 0; i < ARRAY_SIZE(backends); i++) {
> > +        const char *name = qemu_opt_get(opts, "backend");
> > +        cd = backends[i];
> 
> Please hoist the computation of 'name' outside of the loop...
> 
> > -        if (strcmp(ChardevBackendKind_lookup[cd->kind],
> > -                   qemu_opt_get(opts, "backend")) == 0) {
> > +        if (!cd) {
> > +            continue;
> > +        }
> > +        if (g_str_equal(ChardevBackendKind_lookup[cd->kind], name) ||
> > +            (cd->alias && g_str_equal(cd->alias, name))) {
> 
> Doesn't g_str_equal(NULL, "str") do the right thing without crashing?
> Therefore, no need to check if cd->alias is non-NULL.

No it doesnt, but g_strcmp0 does, let's switch to it.

> 
> >              break;
> >          }
> >      }
> > -    if (i == NULL) {
> > +    if (cd == NULL) {
> >          error_setg(errp, "chardev: backend \"%s\" not found",
> >                     qemu_opt_get(opts, "backend"));
> 
> ...and then reuse 'name' here as well, rather than making multiple
> repeated calls to qemu_opt_get().

ok

> 
> >  ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
> >  {
> >      ChardevBackendInfoList *backend_list = NULL;
> > -    CharDriver *c = NULL;
> > -    GSList *i = NULL;
> > +    const CharDriver *c;
> > +    int i;
> >  
> > -    for (i = backends; i; i = i->next) {
> > -        ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
> > -        c = i->data;
> > -        info->value = g_malloc0(sizeof(*info->value));
> > -        info->value->name = g_strdup(ChardevBackendKind_lookup[c->kind]);
> > +    for (i = 0; i < ARRAY_SIZE(backends); i++) {
> > +        c = backends[i];
> > +        if (!c) {
> > +            continue;
> > +        }
> >  
> > -        info->next = backend_list;
> > -        backend_list = info;
> > +        backend_list = qmp_prepend_backend(backend_list, c,
> > +
> > ChardevBackendKind_lookup[c->kind]);
> > +        if (c->alias) {
> > +            backend_list = qmp_prepend_backend(backend_list, c, c->alias);
> 
> The help text now lists aliases immediately after the canonical name,
> while the QMP command now prepends aliases prior to the canonical name.
> It doesn't affect correctness, but should you try to make the two lists
> appear in the same order?  (Presumably by prepending the alias first,
> not second.)
> 

I don't think it matters. Furthermore, this code is temporary, the "char: get rid of CharDriver" patch will use the same function qmp_query_chardev_backends() to build the list with object_class_get_list() order.

> > @@ -4907,16 +4925,11 @@ static void register_types(void)
> >          { .kind = CHARDEV_BACKEND_KIND_STDIO,
> >            .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
> >  #if defined HAVE_CHARDEV_SERIAL
> > -        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
> > -          .parse = qemu_chr_parse_serial, .create =
> > qmp_chardev_open_serial },
> > -        { .kind = CHARDEV_BACKEND_KIND_SERIAL,
> > +        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
> >            .parse = qemu_chr_parse_serial, .create =
> >            qmp_chardev_open_serial },
> 
> Wait. How did patch 2/54 work? Or did you temporarily break the 'tty'
> alias in that patch, and then fix it here?  All the more reason that my

No, it shouldn't break. There were 2 CharDrivers in case of alias chardev. It uses the "kind" field only to lookup the corresponding name.

> review of 2/54 complaining about getting rid of the cd->name field
> should be a separate patch; now I'm convinced of it.  But in that patch,
> I suggested the order:
> 
> remove cd->name field as redundant with enum array lookup
> convert to struct without cd->name
> 
> Whereas with this patch in the mix, the steps should probably be:
> 
> convert to struct that still has cd->name
> add cd->alias to have multiple names
> remove cd->name field as redundant with enum array lookup
> 

Thus I don't see much point in changing the order.

> >  #endif
> >  #ifdef HAVE_CHARDEV_PARPORT
> > -        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
> > -          .parse = qemu_chr_parse_parallel,
> > -          .create = qmp_chardev_open_parallel },
> > -        { .kind = CHARDEV_BACKEND_KIND_PARALLEL,
> > +        { .kind = CHARDEV_BACKEND_KIND_PARALLEL, .alias = "parport",
> >            .parse = qemu_chr_parse_parallel,
> >            .create = qmp_chardev_open_parallel },
> 
> Again, another breakage in 2/54.

neither

> 
> >  #endif
> > diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> > index 144514c962..c8750ede21 100644
> > --- a/include/sysemu/char.h
> > +++ b/include/sysemu/char.h
> > @@ -474,6 +474,7 @@ void qemu_chr_set_feature(CharDriverState *chr,
> >  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
> >  
> >  typedef struct CharDriver {
> > +    const char *alias;
> >      ChardevBackendKind kind;
> >      void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
> >      CharDriverState *(*create)(const char *id,
> > 
> 
> Overall, I like the direction this is headed in.
> 
> --
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org
> 
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver
  2016-12-14 16:02   ` Eric Blake
@ 2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-02 15:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: Marc-André Lureau, qemu-devel, pbonzini

hi

----- Original Message -----
> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > This makes the code more declarative, and avoids to duplicate the
> 
> s/to duplicate/duplicating/

ok

> 
> > information on all instances.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  backends/baum.c       |  13 +-
> >  backends/msmouse.c    |  13 +-
> >  backends/testdev.c    |  10 +-
> >  gdbstub.c             |   7 +-
> >  hw/bt/hci-csr.c       |   8 +-
> >  qemu-char.c           | 427
> >  +++++++++++++++++++++++++++++++-------------------
> >  spice-qemu-char.c     |  36 +++--
> >  ui/console.c          |  26 +--
> >  ui/gtk.c              |  11 +-
> >  include/sysemu/char.h |  46 +++---
> 
> Again, seeing the .h changes first makes a huge difference on code
> review.  I'm manually reformatting:
> 
> >  10 files changed, 370 insertions(+), 227 deletions(-)
> 
> > diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> > index c8750ede21..09e40ef9b8 100644
> > --- a/include/sysemu/char.h
> > +++ b/include/sysemu/char.h
> > @@ -85,24 +85,11 @@ typedef struct CharBackend {
> >      int fe_open;
> >  } CharBackend;
> >
> > +typedef struct CharDriver CharDriver;
> > +
> >  struct CharDriverState {
> > +    const CharDriver *driver;
> >      QemuMutex chr_write_lock;
> > -    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf,
> int len);
> 
> So all the callbacks are moved into the CharDriver struct...
> 
> > @@ -125,7 +112,8 @@ struct CharDriverState {
> >   *
> >   * Returns: a newly allocated CharDriverState, or NULL on error.
> >   */
> > -CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp);
> > +CharDriverState *qemu_chr_alloc(const CharDriver *driver,
> > +                                ChardevCommon *backend, Error **errp);
> 
> ...and all the entry points are now passed that struct as a new parameter.
> 
> >
> >  /**
> >   * @qemu_chr_new_from_opts:
> > @@ -473,15 +461,33 @@ void qemu_chr_set_feature(CharDriverState *chr,
> >                            CharDriverFeature feature);
> >  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
> >
> > -typedef struct CharDriver {
> > +struct CharDriver {
> 
> ...the struct already existed, but is now more useful.
> 
> Looks worthwhile. I suspect the rest of the patch is mechanical.
> 
> > @@ -688,7 +686,10 @@ static void register_types(void)
> >  {
> >      static const CharDriver driver = {
> >          .kind = CHARDEV_BACKEND_KIND_BRAILLE,
> > -        .parse = NULL, .create = chr_baum_init
> > +        .parse = NULL, .create = chr_baum_init,
> 
> And now you see why I asked for trailing commas in 2/54 :)
> 
> > +        .chr_write = baum_write,
> > +        .chr_accept_input = baum_accept_input,
> > +        .chr_free = baum_free,
> >      };
> >  
> 
> > +++ b/gdbstub.c
> > @@ -1730,6 +1730,10 @@ int gdbserver_start(const char *device)
> >      CharDriverState *chr = NULL;
> >      CharDriverState *mon_chr;
> >      ChardevCommon common = { 0 };
> > +    static const CharDriver driver = {
> > +        .kind = -1,
> > +        .chr_write = gdb_monitor_write
> 
> Trailing comma.
> 
> Interesting that this is a new use of CharDriver with an out-of-range
> .kind. But I think your code in 3/54 was careful to explicitly handle a
> .kind that does not map to one of the public types, so that you are able
> to use this as an internal-only driver.

and kind is removed is later patches "char: remove class kind field"

> 
> 
> >  
> > +static const CharDriver null_driver = {
> > +    .kind = CHARDEV_BACKEND_KIND_NULL, .create = qemu_chr_open_null,
> 
> One initializer per line is fine.
> 
> > +    .chr_write = null_chr_write
> > +};
> > +
> 
> > 
> > @@ -864,14 +880,6 @@ static CharDriverState *qemu_chr_open_mux(const char
> > *id,
> >  
> >      chr->opaque = d;
> >      d->focus = -1;
> > -    chr->chr_free = mux_chr_free;
> > -    chr->chr_write = mux_chr_write;
> > -    chr->chr_accept_input = mux_chr_accept_input;
> > -    /* Frontend guest-open / -close notification is not support with muxes
> > */
> > -    chr->chr_set_fe_open = NULL;
> > -    if (drv->chr_add_watch) {
> > -        chr->chr_add_watch = mux_chr_add_watch;
> > -    }
> 
> Here, the callback was only conditionally registered...
> 
> > +static const CharDriver mux_driver = {
> > +    .kind = CHARDEV_BACKEND_KIND_MUX,
> > +    .parse = qemu_chr_parse_mux, .create = qemu_chr_open_mux,
> > +    .chr_free = mux_chr_free,
> > +    .chr_write = mux_chr_write,
> > +    .chr_accept_input = mux_chr_accept_input,
> > +    .chr_add_watch = mux_chr_add_watch,
> > +};
> 
> ...but here, it is always registered.  Is that an unintentional semantic
> change?
> 

mux_chr_add_watch() also checks if the underlying driver has chr_add_watch(). qemu_chr_fe_add_watch() returns 0 in both cases then.


> 
> > +#ifdef HAVE_CHARDEV_SERIAL
> > +static const CharDriver serial_driver = {
> > +    .alias = "tty", .kind = CHARDEV_BACKEND_KIND_SERIAL,
> > +    .parse = qemu_chr_parse_serial, .create = qmp_chardev_open_serial,
> > +#ifdef _WIN32
> > +    .chr_write = win_chr_write,
> > +    .chr_free = win_chr_free,
> > +#else
> > +    .chr_add_watch = fd_chr_add_watch,
> > +    .chr_write = fd_chr_write,
> > +    .chr_update_read_handler = fd_chr_update_read_handler,
> > +    .chr_ioctl = tty_serial_ioctl,
> > +    .chr_free = qemu_chr_free_tty,
> > +#endif
> > +};
> > +#endif
> 
> 
> > @@ -4910,49 +5037,33 @@ void qemu_chr_cleanup(void)
> >  
> >  static void register_types(void)
> >  {
> > -    int i;
> > -    static const CharDriver drivers[] = {
> > -        { .kind = CHARDEV_BACKEND_KIND_NULL, .parse = NULL,
> > -          .create = qemu_chr_open_null },
> > -        { .kind = CHARDEV_BACKEND_KIND_SOCKET,
> > -          .parse = qemu_chr_parse_socket, .create =
> > qmp_chardev_open_socket },
> > -        { .kind = CHARDEV_BACKEND_KIND_UDP, .parse = qemu_chr_parse_udp,
> > -          .create = qmp_chardev_open_udp },
> > -        { .kind = CHARDEV_BACKEND_KIND_RINGBUF,
> > -          .parse = qemu_chr_parse_ringbuf, .create = qemu_chr_open_ringbuf
> > },
> > -        { .kind = CHARDEV_BACKEND_KIND_FILE,
> > -          .parse = qemu_chr_parse_file_out, .create =
> > qmp_chardev_open_file },
> > -        { .kind = CHARDEV_BACKEND_KIND_STDIO,
> > -          .parse = qemu_chr_parse_stdio, .create = qemu_chr_open_stdio },
> > -#if defined HAVE_CHARDEV_SERIAL
> > -        { .kind = CHARDEV_BACKEND_KIND_SERIAL, .alias = "tty",
> > -          .parse = qemu_chr_parse_serial, .create =
> > qmp_chardev_open_serial },
> 
> It feels like some code motion between 3/54 and 4/54 (you are moving
> where the CharDriver is declared); is it worth tweaking the series to
> avoid the code motion by declaring the structs in the right place to
> begin with?  Not necessarily a show-stopper to the series, though.

I did place it where it felt right at the time I did the change. I don't think we need to care much because all this is going away in the series. No strong feeling though

> 
> > +    static const CharDriver *drivers[] = {
> > +        &null_driver,
> > +        &socket_driver,
> > +        &udp_driver,
> > +        &ringbuf_driver,
> > +        &file_driver,
> > +        &stdio_driver,
> > +#ifdef HAVE_CHARDEV_SERIAL
> > +        &serial_driver,
> >  #endif
> 
> Overall impression is that I still like where this is headed.

thanks

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 02/54] char: use a const CharDriver
  2016-12-13 23:11   ` Eric Blake
@ 2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-02 15:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: Marc-André Lureau, qemu-devel, pbonzini



----- Original Message -----
> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > No need to allocate & copy fileds, let's use static const struct
> 
> s/fileds/fields/
> 

ok

> > instead.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  backends/baum.c       |   8 +++-
> >  backends/msmouse.c    |   7 +++-
> >  backends/testdev.c    |   7 +++-
> >  qemu-char.c           | 100
> >  ++++++++++++++++++++++++--------------------------
> >  spice-qemu-char.c     |  14 +++++--
> >  ui/console.c          |   9 +++--
> >  include/sysemu/char.h |  19 +++++-----
> >  7 files changed, 90 insertions(+), 74 deletions(-)
> > 
> 
> > +++ b/backends/baum.c
> > @@ -686,8 +686,12 @@ fail_handle:
> >  
> >  static void register_types(void)
> >  {
> > -    register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL,
> > -                         chr_baum_init);
> > +    static const CharDriver driver = {
> > +        .kind = CHARDEV_BACKEND_KIND_BRAILLE,
> > +        .parse = NULL, .create = chr_baum_init
> 
> Why did the "braille" string disappear?  Oh, I see... [1]
> 
> No need to specify .parse, since C99 initialization guarantees
> zero-assignment to any field omitted.
> 
> I kind of prefer one struct member per line when doing C99
> initialization, rather than bunching two in one line.
> 
> I also prefer a trailing comma, as then adding a new (non-zero) member
> initialization in a later patch is a one-line addition, rather than
> modifying an existing line to add a trailing comma.

ok fixed

> 
> 
> > +++ b/backends/msmouse.c
> > @@ -179,8 +179,11 @@ static CharDriverState *qemu_chr_open_msmouse(const
> > char *id,
> >  
> >  static void register_types(void)
> >  {
> > -    register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL,
> > -                         qemu_chr_open_msmouse);
> > +    static const CharDriver driver = {
> > +        .kind = CHARDEV_BACKEND_KIND_MSMOUSE,
> > +        .parse = NULL, .create = qemu_chr_open_msmouse
> 
> Looks like my comments are repeated throughout the patch.
> 
> 
> > -void register_char_driver(const char *name, ChardevBackendKind kind,
> > -                          CharDriverParse *parse, CharDriverCreate
> > *create)
> > +void register_char_driver(const CharDriver *driver)
> >  {
> > -    CharDriver *s;
> > -
> > -    s = g_malloc0(sizeof(*s));
> > -    s->name = g_strdup(name);
> > -    s->kind = kind;
> > -    s->parse = parse;
> > -    s->create = create;
> > -
> > -    backends = g_slist_append(backends, s);
> > +    backends = g_slist_append(backends, (void *)driver);
> 
> Might be worth a comment that this is casting away const (as my first
> reaction is "oh, you forgot that C allows automatic conversion of any
> pointer to void*")

ok (note: this going away the next patch)

> 
> >  }
> >  
> >  CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
> > @@ -4139,7 +4123,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts
> > *opts,
> >          fprintf(stderr, "Available chardev backend types:\n");
> >          for (i = backends; i; i = i->next) {
> >              cd = i->data;
> > -            fprintf(stderr, "%s\n", cd->name);
> > +            fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
> 
> ...[1] Your series is already long, so don't feel like you have to do
> this, but: if I were working on it, I might have done the elimination of
> cd->name, the name parameter, and the use of ChardevBackendKind_lookup[]
> in one patch (getting rid of JUST the "braille" parameter and friends at
> the call sites), and then the const'ification of the remaining
> parameters in the second patch.

The series is pretty long already (second version even longer), I don't see much need to split this patch

> 
> > +++ b/include/sysemu/char.h
> 
> Laszlo's suggestion of the git order file would have promoted this part
> of the patch first :)
> 

done

thanks

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller
  2016-12-14 16:05   ` Eric Blake
@ 2017-01-02 15:33     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-02 15:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: Marc-André Lureau, qemu-devel, pbonzini



----- Original Message -----
> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > This shorten a bit the code.
> 
> Grammar:
> This shortens the code a bit.
> 
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  qemu-char.c | 97
> >  ++++++++++++++++++++-----------------------------------------
> >  1 file changed, 31 insertions(+), 66 deletions(-)
> > 
> 
> >      name = g_strdup_printf("chardev-udp-%s", chr->label);
> >      qio_channel_set_name(QIO_CHANNEL(sioc), name);
> >      g_free(name);
> >  
> > +    s = g_new0(NetCharDriver, 1);
> > +    s->ioc = QIO_CHANNEL(sioc);
> > +    s->bufcnt = 0;
> > +    s->bufptr = 0;
> > +    chr->opaque = s;
> > +    /* be isn't opened until we get a connection */
> > +    *be_opened = false;
> 
> The assignments to 0 and false are redundant with the g_new0(), if you
> want to drop them for even more code reduction.
> 

thanks, done

> Reviewed-by: Eric Blake <eblake@redhat.com>
> 
> --
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org
> 
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object Marc-André Lureau
@ 2017-01-04 20:24   ` Eric Blake
  2017-01-04 21:09     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2017-01-04 20:24 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 6492 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Use a single allocation for CharDriverState, this avoids extra
> allocations & pointers, and is a step towards more object-oriented
> CharDriver.
> 
> Gtk console is a bit peculiar, gd_vc_chr_set_echo

Truncated paragraph?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  backends/baum.c       |  23 ++---
>  backends/msmouse.c    |  16 +--
>  backends/testdev.c    |  22 ++--
>  gdbstub.c             |   1 +
>  hw/bt/hci-csr.c       |  10 +-
>  qemu-char.c           | 280 ++++++++++++++++++++++++++------------------------
>  spice-qemu-char.c     |  39 +++----
>  ui/console.c          |  21 ++--
>  ui/gtk.c              |  30 ++++--
>  include/sysemu/char.h |   2 +-
>  10 files changed, 230 insertions(+), 214 deletions(-)
> 
> diff --git a/backends/baum.c b/backends/baum.c
> index ef6178993a..6244929ac6 100644
> --- a/backends/baum.c
> +++ b/backends/baum.c
> @@ -87,7 +87,7 @@
>  #define BUF_SIZE 256
>  
>  typedef struct {
> -    CharDriverState *chr;
> +    CharDriverState parent;
>  
>      brlapi_handle_t *brlapi;
>      int brlapi_fd;
> @@ -270,7 +270,7 @@ static int baum_deferred_init(BaumDriverState *baum)
>  /* The serial port can receive more of our data */
>  static void baum_accept_input(struct CharDriverState *chr)
>  {
> -    BaumDriverState *baum = chr->opaque;
> +    BaumDriverState *baum = (BaumDriverState *)chr;

It might be a little nicer to use:

BaumDriverState *baum = container_of(chr, BaumDriverState, parent);

to avoid a cast and work even if the members are rearranged within the
structure. You can even write a one-line helper function to hide the
cast behind a more legible semantic (for example, see to_qov() in
qobject-output-visitor.c).

(Same comment applies to most other base-to-derived casts in your patch)

> +++ b/hw/bt/hci-csr.c
> @@ -28,11 +28,11 @@
>  #include "hw/bt.h"
>  
>  struct csrhci_s {
> +    CharDriverState chr;
>      int enable;
>      qemu_irq *pins;
>      int pin_state;
>      int modem_state;
> -    CharDriverState chr;
>  #define FIFO_LEN	4096
>      int out_start;
>      int out_len;
> @@ -314,7 +314,7 @@ static void csrhci_ready_for_next_inpkt(struct csrhci_s *s)
>  static int csrhci_write(struct CharDriverState *chr,
>                  const uint8_t *buf, int len)
>  {
> -    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
> +    struct csrhci_s *s = (struct csrhci_s *)chr;

Wonder if a typedef would make this more legible, but maybe as a
separate cleanup.

> +++ b/ui/gtk.c
> @@ -178,6 +178,12 @@ struct GtkDisplayState {
>      bool ignore_keys;
>  };
>  
> +typedef struct VCDriverState {
> +    CharDriverState parent;
> +    VirtualConsole *console;
> +    bool echo;
> +} VCDriverState;
> +
>  static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
>  static void gd_ungrab_pointer(GtkDisplayState *s);
>  static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
> @@ -1675,7 +1681,8 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
>  
>  static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
>  {
> -    VirtualConsole *vc = chr->opaque;
> +    VCDriverState *vcd = (VCDriverState *)chr;
> +    VirtualConsole *vc = vcd->console;
>  
>      vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
>      return len;
> @@ -1683,9 +1690,14 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
>  
>  static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
>  {
> -    VirtualConsole *vc = chr->opaque;
> +    VCDriverState *vcd = (VCDriverState *)chr;
> +    VirtualConsole *vc = vcd->console;
>  
> -    vc->vte.echo = echo;
> +    if (vc) {
> +        vc->vte.echo = echo;
> +    } else {
> +        vcd->echo = echo;
> +    }
>  }
>  
>  static int nb_vcs;
> @@ -1694,6 +1706,7 @@ static CharDriverState *vcs[MAX_VCS];
>  static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
>  {
>      static const CharDriver gd_vc_driver = {
> +        .instance_size = sizeof(VCDriverState),
>          .kind = CHARDEV_BACKEND_KIND_VC,
>          .chr_write = gd_vc_chr_write,
>          .chr_set_echo = gd_vc_chr_set_echo,
> @@ -1712,9 +1725,6 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
>          return NULL;
>      }
>  
> -    /* Temporary, until gd_vc_vte_init runs.  */
> -    chr->opaque = g_new0(VirtualConsole, 1);
> -

Okay, I see the weirdness going on with the 'echo' stuff - you have to
simulate the temporary placeholder for whether or not to set echo, such
that gd_vc_chr_set_echo() can now be called with a NULL opaque where it
used to always have an object to dereference.

>      vcs[nb_vcs++] = chr;
>  
>      return chr;
> @@ -1755,14 +1765,12 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
>      GtkWidget *box;
>      GtkWidget *scrollbar;
>      GtkAdjustment *vadjustment;
> -    VirtualConsole *tmp_vc = chr->opaque;
> +    VCDriverState *vcd = (VCDriverState *)chr;
>  
>      vc->s = s;
> -    vc->vte.echo = tmp_vc->vte.echo;
> -
> +    vc->vte.echo = vcd->echo;
>      vc->vte.chr = chr;
> -    chr->opaque = vc;
> -    g_free(tmp_vc);
> +    vcd->console = vc;
>  

So it is indeed weird, but looks correct in the end.

>      snprintf(buffer, sizeof(buffer), "vc%d", idx);
>      vc->label = g_strdup_printf("%s", vc->vte.chr->label
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 07dfa59afe..5d8ec982a9 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -93,7 +93,6 @@ struct CharDriverState {
>      const CharDriver *driver;
>      QemuMutex chr_write_lock;
>      CharBackend *be;
> -    void *opaque;
>      char *label;
>      char *filename;
>      int logfd;
> @@ -482,6 +481,7 @@ struct CharDriver {
>                                 ChardevBackend *backend,
>                                 ChardevReturn *ret, bool *be_opened,
>                                 Error **errp);
> +    size_t instance_size;

My biggest gripe is the number of casts that could be container_of()
instead; but otherwise it looks like a sane conversion.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object
  2017-01-04 20:24   ` Eric Blake
@ 2017-01-04 21:09     ` Marc-André Lureau
  2017-01-04 21:15       ` Eric Blake
  0 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-04 21:09 UTC (permalink / raw)
  To: Eric Blake, qemu-devel; +Cc: pbonzini

Hi

On Wed, Jan 4, 2017 at 9:26 PM Eric Blake <eblake@redhat.com> wrote:

> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > Use a single allocation for CharDriverState, this avoids extra
> > allocations & pointers, and is a step towards more object-oriented
> > CharDriver.
> >
> > Gtk console is a bit peculiar, gd_vc_chr_set_echo
>
> Truncated paragraph?
>

yes, fixed


>
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  backends/baum.c       |  23 ++---
> >  backends/msmouse.c    |  16 +--
> >  backends/testdev.c    |  22 ++--
> >  gdbstub.c             |   1 +
> >  hw/bt/hci-csr.c       |  10 +-
> >  qemu-char.c           | 280
> ++++++++++++++++++++++++++------------------------
> >  spice-qemu-char.c     |  39 +++----
> >  ui/console.c          |  21 ++--
> >  ui/gtk.c              |  30 ++++--
> >  include/sysemu/char.h |   2 +-
> >  10 files changed, 230 insertions(+), 214 deletions(-)
> >
> > diff --git a/backends/baum.c b/backends/baum.c
> > index ef6178993a..6244929ac6 100644
> > --- a/backends/baum.c
> > +++ b/backends/baum.c
> > @@ -87,7 +87,7 @@
> >  #define BUF_SIZE 256
> >
> >  typedef struct {
> > -    CharDriverState *chr;
> > +    CharDriverState parent;
> >
> >      brlapi_handle_t *brlapi;
> >      int brlapi_fd;
> > @@ -270,7 +270,7 @@ static int baum_deferred_init(BaumDriverState *baum)
> >  /* The serial port can receive more of our data */
> >  static void baum_accept_input(struct CharDriverState *chr)
> >  {
> > -    BaumDriverState *baum = chr->opaque;
> > +    BaumDriverState *baum = (BaumDriverState *)chr;
>
> It might be a little nicer to use:
>
> BaumDriverState *baum = container_of(chr, BaumDriverState, parent);
>
>
The follow-up of the series converts it to the more appropriate
 BaumChardev *baum = BAUM_CHARDEV(obj);

So considering that this is temporary commit, do I have to change that?

to avoid a cast and work even if the members are rearranged within the
> structure. You can even write a one-line helper function to hide the
> cast behind a more legible semantic (for example, see to_qov() in
> qobject-output-visitor.c).
>
> (Same comment applies to most other base-to-derived casts in your patch)
>
> > +++ b/hw/bt/hci-csr.c
> > @@ -28,11 +28,11 @@
> >  #include "hw/bt.h"
> >
> >  struct csrhci_s {
> > +    CharDriverState chr;
> >      int enable;
> >      qemu_irq *pins;
> >      int pin_state;
> >      int modem_state;
> > -    CharDriverState chr;
> >  #define FIFO_LEN     4096
> >      int out_start;
> >      int out_len;
> > @@ -314,7 +314,7 @@ static void csrhci_ready_for_next_inpkt(struct
> csrhci_s *s)
> >  static int csrhci_write(struct CharDriverState *chr,
> >                  const uint8_t *buf, int len)
> >  {
> > -    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
> > +    struct csrhci_s *s = (struct csrhci_s *)chr;
>
> Wonder if a typedef would make this more legible, but maybe as a
> separate cleanup.
>
> > +++ b/ui/gtk.c
> > @@ -178,6 +178,12 @@ struct GtkDisplayState {
> >      bool ignore_keys;
> >  };
> >
> > +typedef struct VCDriverState {
> > +    CharDriverState parent;
> > +    VirtualConsole *console;
> > +    bool echo;
> > +} VCDriverState;
> > +
> >  static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
> >  static void gd_ungrab_pointer(GtkDisplayState *s);
> >  static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
> > @@ -1675,7 +1681,8 @@ static void gd_vc_adjustment_changed(GtkAdjustment
> *adjustment, void *opaque)
> >
> >  static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf,
> int len)
> >  {
> > -    VirtualConsole *vc = chr->opaque;
> > +    VCDriverState *vcd = (VCDriverState *)chr;
> > +    VirtualConsole *vc = vcd->console;
> >
> >      vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char
> *)buf, len);
> >      return len;
> > @@ -1683,9 +1690,14 @@ static int gd_vc_chr_write(CharDriverState *chr,
> const uint8_t *buf, int len)
> >
> >  static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
> >  {
> > -    VirtualConsole *vc = chr->opaque;
> > +    VCDriverState *vcd = (VCDriverState *)chr;
> > +    VirtualConsole *vc = vcd->console;
> >
> > -    vc->vte.echo = echo;
> > +    if (vc) {
> > +        vc->vte.echo = echo;
> > +    } else {
> > +        vcd->echo = echo;
> > +    }
> >  }
> >
> >  static int nb_vcs;
> > @@ -1694,6 +1706,7 @@ static CharDriverState *vcs[MAX_VCS];
> >  static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
> >  {
> >      static const CharDriver gd_vc_driver = {
> > +        .instance_size = sizeof(VCDriverState),
> >          .kind = CHARDEV_BACKEND_KIND_VC,
> >          .chr_write = gd_vc_chr_write,
> >          .chr_set_echo = gd_vc_chr_set_echo,
> > @@ -1712,9 +1725,6 @@ static CharDriverState *gd_vc_handler(ChardevVC
> *vc, Error **errp)
> >          return NULL;
> >      }
> >
> > -    /* Temporary, until gd_vc_vte_init runs.  */
> > -    chr->opaque = g_new0(VirtualConsole, 1);
> > -
>
> Okay, I see the weirdness going on with the 'echo' stuff - you have to
> simulate the temporary placeholder for whether or not to set echo, such
> that gd_vc_chr_set_echo() can now be called with a NULL opaque where it
> used to always have an object to dereference.
>
>
right


> >      vcs[nb_vcs++] = chr;
> >
> >      return chr;
> > @@ -1755,14 +1765,12 @@ static GSList *gd_vc_vte_init(GtkDisplayState
> *s, VirtualConsole *vc,
> >      GtkWidget *box;
> >      GtkWidget *scrollbar;
> >      GtkAdjustment *vadjustment;
> > -    VirtualConsole *tmp_vc = chr->opaque;
> > +    VCDriverState *vcd = (VCDriverState *)chr;
> >
> >      vc->s = s;
> > -    vc->vte.echo = tmp_vc->vte.echo;
> > -
> > +    vc->vte.echo = vcd->echo;
> >      vc->vte.chr = chr;
> > -    chr->opaque = vc;
> > -    g_free(tmp_vc);
> > +    vcd->console = vc;
> >
>
> So it is indeed weird, but looks correct in the end.
>
> >      snprintf(buffer, sizeof(buffer), "vc%d", idx);
> >      vc->label = g_strdup_printf("%s", vc->vte.chr->label
> > diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> > index 07dfa59afe..5d8ec982a9 100644
> > --- a/include/sysemu/char.h
> > +++ b/include/sysemu/char.h
> > @@ -93,7 +93,6 @@ struct CharDriverState {
> >      const CharDriver *driver;
> >      QemuMutex chr_write_lock;
> >      CharBackend *be;
> > -    void *opaque;
> >      char *label;
> >      char *filename;
> >      int logfd;
> > @@ -482,6 +481,7 @@ struct CharDriver {
> >                                 ChardevBackend *backend,
> >                                 ChardevReturn *ret, bool *be_opened,
> >                                 Error **errp);
> > +    size_t instance_size;
>
> My biggest gripe is the number of casts that could be container_of()
> instead; but otherwise it looks like a sane conversion.
>
>
thanks, the goal is to get rid of them, but not in this commit :) See
"chardev: qom-ify".
-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object
  2017-01-04 21:09     ` Marc-André Lureau
@ 2017-01-04 21:15       ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 21:15 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 2285 bytes --]

On 01/04/2017 03:09 PM, Marc-André Lureau wrote:
> Hi
> 
> On Wed, Jan 4, 2017 at 9:26 PM Eric Blake <eblake@redhat.com> wrote:
> 
>> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
>>> Use a single allocation for CharDriverState, this avoids extra
>>> allocations & pointers, and is a step towards more object-oriented
>>> CharDriver.
>>>
>>> Gtk console is a bit peculiar, gd_vc_chr_set_echo
>>
>> Truncated paragraph?
>>
> 
> yes, fixed
> 

>>> @@ -270,7 +270,7 @@ static int baum_deferred_init(BaumDriverState *baum)
>>>  /* The serial port can receive more of our data */
>>>  static void baum_accept_input(struct CharDriverState *chr)
>>>  {
>>> -    BaumDriverState *baum = chr->opaque;
>>> +    BaumDriverState *baum = (BaumDriverState *)chr;
>>
>> It might be a little nicer to use:
>>
>> BaumDriverState *baum = container_of(chr, BaumDriverState, parent);
>>
>>
> The follow-up of the series converts it to the more appropriate
>  BaumChardev *baum = BAUM_CHARDEV(obj);
> 
> So considering that this is temporary commit, do I have to change that?

Ah, nice. So BAUM_CHARDEV(obj) will be a nice wrapper around
container_of(). I can live with it being temporary (although a note in
the commit message can't hurt).

> 
> to avoid a cast and work even if the members are rearranged within the
>> structure. You can even write a one-line helper function to hide the
>> cast behind a more legible semantic (for example, see to_qov() in
>> qobject-output-visitor.c).

My example of to_qov() is matched by your BAUM_CHARDEV() macro.

>> My biggest gripe is the number of casts that could be container_of()
>> instead; but otherwise it looks like a sane conversion.
>>
>>
> thanks, the goal is to get rid of them, but not in this commit :) See
> "chardev: qom-ify".

That's what I get for only reviewing the series one patch at a time. I'm
fine with temporary and partial hacks, but calling them out as such
makes review easier if we know it's going to improve later.

Since I think you've answered my questions, then with an improved commit
message, v2 can add:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc()
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc() Marc-André Lureau
@ 2017-01-04 21:18   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 21:18 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 807 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Use common allocator for CharDriverState.
> 
> Rename the now untouched parent field.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/bt/hci-csr.c | 19 +++++++++++++------
>  1 file changed, 13 insertions(+), 6 deletions(-)
> 

> 
>  static inline void csrhci_fifo_wake(struct csrhci_s *s)
>  {
> -    CharBackend *be = s->chr.be;
> +    CharDriverState *chr = (CharDriverState *)s;

Another one of those temporary casts that got me stuck on 8/54. So with
the same idea of the commit message mentioning that it gets better later
in the series,

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
  2017-01-02 10:26 ` Paolo Bonzini
@ 2017-01-04 21:20   ` Marc-André Lureau
  2017-01-04 21:50     ` Eric Blake
  0 siblings, 1 reply; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-04 21:20 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel, Eric Blake

Hi

On Mon, Jan 2, 2017 at 11:27 AM Paolo Bonzini <pbonzini@redhat.com> wrote:

>
>
> On 12/12/2016 23:42, Marc-André Lureau wrote:
> >
> > Note: this series has been tested with Linux and cross-building with
> > mingw. It mostly breaks on other platforms,
>
> What breaks exactly?
>
>
Not much that I know. I was afraid it would break on BSD (in particular the
move to own file and last patch), so I tested on FreeBSD. The last version
of the series works on win32, linux and freebsd. It can be found on
https://github.com/elmarco/qemu/commits/chrfe It's slightly over 80 patches
now, and needs some win32 fixes I sent earlier (subprocess tests, and
main-loop busy loop fix)

Since Erik started reviewing the series, I suggest to resend the first part
until "qom-ify" patch. Erik, feel free to review the remaining part of the
WIP series, but more changes happened after iirc. What do you think?


Paolo
>
> > help welcome for
> > testing. I'd also like to write more chardev backend tests to ensure
> > no regression (test-char.c is quite limited for now)
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev Marc-André Lureau
@ 2017-01-04 21:30   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 21:30 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 1002 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Uniformify chardev type name.

"Uniformify" - cute :)  I might have written:

Pick a uniform chardev type name.

instead of inventing a word, but you're call on whether to keep it.

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  81 files changed, 728 insertions(+), 725 deletions(-)

Big, but mostly mechanical.

> @@ -268,9 +268,9 @@ static int baum_deferred_init(BaumDriverState *baum)
>  }
>  
>  /* The serial port can receive more of our data */
> -static void baum_accept_input(struct CharDriverState *chr)
> +static void baum_accept_input(struct Chardev *chr)

Do we still need the 'struct' in this parameter list?  Separate cleanup
may be okay.

A grep on your github chrfe branch shows that it looks like you got them
all, so
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify
  2017-01-04 21:20   ` Marc-André Lureau
@ 2017-01-04 21:50     ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 21:50 UTC (permalink / raw)
  To: Marc-André Lureau, Paolo Bonzini, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1455 bytes --]

On 01/04/2017 03:20 PM, Marc-André Lureau wrote:
> Hi
> 
> On Mon, Jan 2, 2017 at 11:27 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
> 
>>
>>
>> On 12/12/2016 23:42, Marc-André Lureau wrote:
>>>
>>> Note: this series has been tested with Linux and cross-building with
>>> mingw. It mostly breaks on other platforms,
>>
>> What breaks exactly?
>>
>>
> Not much that I know. I was afraid it would break on BSD (in particular the
> move to own file and last patch), so I tested on FreeBSD. The last version
> of the series works on win32, linux and freebsd. It can be found on
> https://github.com/elmarco/qemu/commits/chrfe It's slightly over 80 patches
> now, and needs some win32 fixes I sent earlier (subprocess tests, and
> main-loop busy loop fix)
> 
> Since Erik started reviewing the series, I suggest to resend the first part
> until "qom-ify" patch. Erik, feel free to review the remaining part of the
> WIP series, but more changes happened after iirc. What do you think?

It's Eric (but you're not the first, and probably not the last).  The
qom-ify patch is 15/54, right? Okay, I'll complete my review up to that
point, and then you can split the series into two: a v2 through qom-ify
(which should probably be ready to go, or only very little to change),
and the second half which is still the WIP.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev Marc-André Lureau
@ 2017-01-04 21:55   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 21:55 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 573 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Rename the types to follow the name of the chardev kind.
> - socket: TCPChardev -> SocketChardev
> - udp: NetChardev -> UdpChardev
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qemu-char.c | 74 ++++++++++++++++++++++++++++++-------------------------------
>  1 file changed, 37 insertions(+), 37 deletions(-)

Mechanical.
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting Marc-André Lureau
@ 2017-01-04 22:00   ` Eric Blake
  2017-01-05 14:03     ` Marc-André Lureau
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2017-01-04 22:00 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini, Markus Armbruster

[-- Attachment #1: Type: text/plain, Size: 1206 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Set errp to report errors up.
> 
> Use error_report() to give hints about parameters on the right monitor,
> instead of a direct fprintf() call.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  spice-qemu-char.c | 29 +++++++++--------------------
>  1 file changed, 9 insertions(+), 20 deletions(-)
> 

And it's shorter!  I like it.

> @@ -302,8 +286,13 @@ static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
>          }
>      }
>      if (*psubtype == NULL) {
> -        fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
> -        print_allowed_subtypes();
> +        char *subtypes = g_strjoinv(", ",
> +            (gchar **)spice_server_char_device_recognized_subtypes());
> +
> +        error_setg(errp, "unsupported type name: %s", type);
> +        error_report("allowed spice char type names: %s", subtypes);

However, I'm not sure if error_setg() followed by error_report() is
correct; should you be using error_append_hint() instead?  Markus?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 13/54] char: use error_report()
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 13/54] char: use error_report() Marc-André Lureau
@ 2017-01-04 22:04   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 22:04 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 2266 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Prefer error_report() over fprintf(stderr..)
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qemu-char.c | 27 +++++++++++++++------------
>  1 file changed, 15 insertions(+), 12 deletions(-)
> 
> @@ -4130,17 +4130,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
>      }
>  
>      if (is_help_option(qemu_opt_get(opts, "backend"))) {
> -        fprintf(stderr, "Available chardev backend types:\n");
> +        GString *str = g_string_new("");
>          for (i = 0; i < ARRAY_SIZE(backends); i++) {
>              cd = backends[i];
>              if (cd) {
> -                fprintf(stderr, "%s\n", ChardevBackendKind_lookup[cd->kind]);
> +                g_string_append_printf(str, "\n%s", ChardevBackendKind_lookup[cd->kind]);
>                  if (cd->alias) {
> -                    fprintf(stderr, "%s\n", cd->alias);
> +                    g_string_append_printf(str, "\n%s", cd->alias);
>                  }
>              }
>          }
> -        exit(!is_help_option(qemu_opt_get(opts, "backend")));
> +
> +        error_report("Available chardev backend types: %s", str->str);
> +        g_string_free(str, true);
> +        exit(0);

I suppose the g_string_free() could be elided due to the pending exit(),
but it's fine to keep it for lint purposes.  Nice simplification of the
error status.

>      }
>  
>      if (id == NULL) {
> @@ -4255,8 +4258,8 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
>              qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
>          }
>          if (qemu_chr_replay(chr) && chr->driver->chr_ioctl) {
> -            fprintf(stderr,
> -                    "Replay: ioctl is not supported for serial devices yet\n");
> +            error_report("Replay: ioctl is not supported "
> +                         "for serial devices yet");
>          }
>          replay_register_char_driver(chr);

Rather gross that we print the message but plow on anyways, but that's
not this patch's problem.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver Marc-André Lureau
@ 2017-01-04 22:26   ` Eric Blake
  0 siblings, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-04 22:26 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 740 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Instead of registering a vc handler to allocate the Gtk VC Chardev,
> overwrite the console.c char driver.
> 
> A later patch, when switching to QOM, will register a default console vc
> QOM class if none has been registered before.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  ui/console.c          | 24 +++++++-----------------
>  ui/gtk.c              | 30 +++++++++++++++++++++---------
>  include/sysemu/char.h |  4 +---
>  3 files changed, 29 insertions(+), 29 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 15/54] chardev: qom-ify
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 15/54] chardev: qom-ify Marc-André Lureau
@ 2017-01-05  2:30   ` Eric Blake
  2017-01-05 15:54   ` Eric Blake
  1 sibling, 0 replies; 85+ messages in thread
From: Eric Blake @ 2017-01-05  2:30 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 11300 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Turn Chardev into Object.
> 
> qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It
> will call qemu_char_open() to open/intialize the chardev with the
> ChardevCommon *backend settings.
> 
> The CharDriver::create() callback is turned into a ChardevClass::open()
> which is called from the newly introduced qemu_chardev_open().
> 
> "chardev-gdb" and "chardev-hci" are internal chardev and aren't
> creatable directly with -chardev. Use a new internal flag to disable
> them. We may want to use TYPE_USER_CREATABLE interface instead, or
> perhaps allow -chardev usage.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  backends/baum.c       |   70 +--
>  backends/msmouse.c    |   57 ++-
>  backends/testdev.c    |   34 +-
>  gdbstub.c             |   33 +-
>  hw/bt/hci-csr.c       |   54 +-
>  monitor.c             |    2 +-
>  qemu-char.c           | 1334 ++++++++++++++++++++++++++-----------------------
>  spice-qemu-char.c     |  144 +++---
>  ui/console.c          |   73 +--
>  ui/gtk.c              |   51 +-
>  vl.c                  |    2 +
>  include/sysemu/char.h |  107 ++--
>  include/ui/console.h  |    2 +
>  13 files changed, 1084 insertions(+), 879 deletions(-)

Big, but probably not possible to break it into many more chunks.

Rearranging the reply, to put the .h first:

> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 384f3ce9b7..1ee8aa4325 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -10,6 +10,7 @@
>  #include "qapi/qmp/qstring.h"
>  #include "qemu/main-loop.h"
>  #include "qemu/bitmap.h"
> +#include "qom/object.h"
>
>  /* character device */
>
> @@ -90,7 +91,8 @@ typedef struct CharBackend {
>  typedef struct CharDriver CharDriver;
>
>  struct Chardev {
> -    const CharDriver *driver;
> +    Object parent_obj;
> +
>      QemuMutex chr_write_lock;
>      CharBackend *be;
>      char *label;
> @@ -102,18 +104,6 @@ struct Chardev {
>      QTAILQ_ENTRY(Chardev) next;
>  };
>

>
> +#define TYPE_CHARDEV "chardev"
> +#define CHARDEV(obj) OBJECT_CHECK(Chardev, (obj), TYPE_CHARDEV)
> +#define CHARDEV_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(ChardevClass, (klass), TYPE_CHARDEV)
> +#define CHARDEV_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(ChardevClass, (obj), TYPE_CHARDEV)
> +
> +#define TYPE_CHARDEV_NULL "chardev-null"
> +#define TYPE_CHARDEV_MUX "chardev-mux"
> +#define TYPE_CHARDEV_RINGBUF "chardev-ringbuf"
> +#define TYPE_CHARDEV_PTY "chardev-pty"
> +#define TYPE_CHARDEV_CONSOLE "chardev-console"
> +#define TYPE_CHARDEV_STDIO "chardev-stdio"
> +#define TYPE_CHARDEV_PIPE "chardev-pipe"
> +#define TYPE_CHARDEV_MEMORY "chardev-memory"
> +#define TYPE_CHARDEV_PARALLEL "chardev-parallel"
> +#define TYPE_CHARDEV_FILE "chardev-file"
> +#define TYPE_CHARDEV_SERIAL "chardev-serial"
> +#define TYPE_CHARDEV_SOCKET "chardev-socket"
> +#define TYPE_CHARDEV_UDP "chardev-udp"
> +
> +#define CHARDEV_IS_MUX(chr) \
> +    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
> +#define CHARDEV_IS_RINGBUF(chr) \
> +    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
> +#define CHARDEV_IS_PTY(chr) \
> +    object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_PTY)
> +
> +typedef struct ChardevClass {
> +    ObjectClass parent_class;
> +
> +    bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
> +
> +    void (*open)(Chardev *chr, ChardevBackend *backend,
> +                 bool *be_opened, Error **errp);
> +
> +    int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
> +    int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
> +    GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
> +    void (*chr_update_read_handler)(Chardev *s, GMainContext *context);
> +    int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
> +    int (*get_msgfds)(Chardev *s, int* fds, int num);
> +    int (*set_msgfds)(Chardev *s, int *fds, int num);
> +    int (*chr_add_client)(Chardev *chr, int fd);
> +    int (*chr_wait_connected)(Chardev *chr, Error **errp);
> +    void (*chr_free)(Chardev *chr);
> +    void (*chr_disconnect)(Chardev *chr);
> +    void (*chr_accept_input)(Chardev *chr);
> +    void (*chr_set_echo)(Chardev *chr, bool echo);
> +    void (*chr_set_fe_open)(Chardev *chr, int fe_open);
> +} ChardevClass;

Looks nice.

On to the .c:


> 
> diff --git a/backends/baum.c b/backends/baum.c
> index 7fd1ebc557..80103b6098 100644
> --- a/backends/baum.c
> +++ b/backends/baum.c
> @@ -102,6 +102,9 @@ typedef struct {
>      QEMUTimer *cellCount_timer;
>  } BaumChardev;
>  
> +#define TYPE_CHARDEV_BRAILLE "chardev-braille"
> +#define BAUM_CHARDEV(obj) OBJECT_CHECK(BaumChardev, (obj), TYPE_CHARDEV_BRAILLE)

As mentioned earlier, OBJECT_CHECK() is a nice wrapper around
container_of(), so this indeed resolves my earlier concerns on casts.

> +
>  /* Let's assume NABCC by default */
>  enum way {
>      DOTS2ASCII,
> @@ -268,9 +271,9 @@ static int baum_deferred_init(BaumChardev *baum)
>  }
>  
>  /* The serial port can receive more of our data */
> -static void baum_accept_input(struct Chardev *chr)
> +static void baum_chr_accept_input(struct Chardev *chr)

Why the rename?

> @@ -485,9 +488,9 @@ static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
>  }
>  
>  /* The other end is writing some data.  Store it and try to interpret */
> -static int baum_write(Chardev *chr, const uint8_t *buf, int len)
> +static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)

and again

> @@ -544,7 +547,7 @@ static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
>  /* We got some data on the BrlAPI socket */
>  static void baum_chr_read(void *opaque)
>  {

If it is for consistency in the baum callback names, maybe a separate
patch is warranted for that part.

> @@ -515,33 +485,98 @@ static void remove_fd_in_watch(Chardev *chr);
>  static void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
>  static void mux_set_focus(MuxChardev *d, int focus);
>  
> -static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
> +static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
> +                           bool *be_opened, Error **errp)
>  {
> -    return len;
> +    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
> +    /* Any ChardevCommon member would work */
> +    ChardevCommon *common = backend ? backend->u.null.data : NULL;
> +
> +    if (common && common->has_logfile) {
> +        int flags = O_WRONLY | O_CREAT;
> +        if (common->has_logappend &&
> +            common->logappend) {
> +            flags |= O_APPEND;
> +        } else {
> +            flags |= O_TRUNC;
> +        }
> +        chr->logfd = qemu_open(common->logfile, flags, 0666);
> +        if (chr->logfd < 0) {
> +            error_setg_errno(errp, errno,
> +                             "Unable to open logfile %s",
> +                             common->logfile);
> +            return;
> +        }
> +    }
> +
> +    if (cc->open) {
> +        cc->open(chr, backend, be_opened, errp);
> +    }
>  }

Looking good.

> @@ -1421,19 +1451,15 @@ static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
>      act.sa_handler = term_stdio_handler;
>      sigaction(SIGCONT, &act, NULL);
>  
> -    chr = qemu_chr_open_fd(driver, 0, 1, common, errp);
> -    if (!chr) {
> -        return NULL;
> -    }
> +    qemu_chr_open_fd(chr, 0, 1);
> +
>      if (opts->has_signal) {
>          stdio_allow_signal = opts->signal;
>      }
>      qemu_chr_set_echo_stdio(chr, false);
> -
> -    return chr;
>  }
>  
> -#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
> +#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)     \
>      || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \

The change in this #if looks spurious.

> @@ -3905,18 +3925,24 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
>  
>  static const CharDriver pipe_driver = {
>      .kind = CHARDEV_BACKEND_KIND_PIPE,
> -    .parse = qemu_chr_parse_pipe, .create = qemu_chr_open_pipe,
> +    .parse = qemu_chr_parse_pipe
> +};

nit: As pointed out earlier in the series, I like trailing comma in
struct initializations.

>  
>  static const CharDriver udp_driver = {
> -    .instance_size = sizeof(UdpChardev),
>      .kind = CHARDEV_BACKEND_KIND_UDP,
> -    .parse = qemu_chr_parse_udp, .create = qmp_chardev_open_udp,
> -    .chr_write = udp_chr_write,
> -    .chr_update_read_handler = udp_chr_update_read_handler,
> -    .chr_free = udp_chr_free,
> +    .parse = qemu_chr_parse_udp
> +};

Multiple places

> @@ -5020,33 +5115,44 @@ void qemu_chr_cleanup(void)
>  
>  static void register_types(void)
>  {
> -    static const CharDriver *drivers[] = {
> -        &null_driver,
> -        &socket_driver,
> -        &udp_driver,
> -        &ringbuf_driver,
> -        &file_driver,
> -        &stdio_driver,
> +    static const struct {
> +        const CharDriver *driver;
> +        const TypeInfo *type;
> +    } chardevs[] = {
> +        { &null_driver, &char_null_type_info },
> +        { &socket_driver, &char_socket_type_info },
> +        { &udp_driver, &char_udp_type_info },
> +        { &ringbuf_driver, &char_ringbuf_type_info },
> +        { &file_driver, &char_file_type_info },
> +        { &stdio_driver, &char_stdio_type_info },
>  #ifdef HAVE_CHARDEV_SERIAL
> -        &serial_driver,
> +        { &serial_driver, &char_serial_type_info },
>  #endif
>  #ifdef HAVE_CHARDEV_PARPORT
> -        &parallel_driver,
> +        { &parallel_driver, &char_parallel_type_info },
>  #endif
>  #ifdef HAVE_CHARDEV_PTY
> -        &pty_driver,
> +        { &pty_driver, &char_pty_type_info },
>  #endif
>  #ifdef _WIN32
> -        &console_driver,
> +        { &console_driver, &char_console_type_info },
>  #endif
> -        &pipe_driver,
> -        &mux_driver,
> -        &memory_driver
> +        { &pipe_driver, &char_pipe_type_info },
> +        { &mux_driver, &char_mux_type_info },
> +        { &memory_driver, &char_memory_type_info }
>      };
>      int i;
>  
> -    for (i = 0; i < ARRAY_SIZE(drivers); i++) {
> -        register_char_driver(drivers[i]);
> +    type_register_static(&char_type_info);
> +#ifndef _WIN32
> +    type_register_static(&char_fd_type_info);
> +#else
> +    type_register_static(&char_win_type_info);
> +    type_register_static(&char_win_stdio_type_info);
> +#endif
> +    for (i = 0; i < ARRAY_SIZE(chardevs); i++) {
> +        type_register_static(chardevs[i].type);
> +        register_char_driver(chardevs[i].driver);
>      }
>  
>      /* this must be done after machine init, since we register FEs with muxes
> diff --git a/spice-qemu-char.c b/spice-qemu-char.c

So far, looks like a sane conversion.  I've run out of review time
today; I'll have to pick up from this file tomorrow.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting
  2017-01-04 22:00   ` Eric Blake
@ 2017-01-05 14:03     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-05 14:03 UTC (permalink / raw)
  To: Eric Blake, qemu-devel; +Cc: pbonzini, Markus Armbruster

Hi

On Wed, Jan 4, 2017 at 11:00 PM Eric Blake <eblake@redhat.com> wrote:

> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > Set errp to report errors up.
> >
> > Use error_report() to give hints about parameters on the right monitor,
> > instead of a direct fprintf() call.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  spice-qemu-char.c | 29 +++++++++--------------------
> >  1 file changed, 9 insertions(+), 20 deletions(-)
> >
>
> And it's shorter!  I like it.
>
> > @@ -302,8 +286,13 @@ static Chardev *qemu_chr_open_spice_vmc(const
> CharDriver *driver,
> >          }
> >      }
> >      if (*psubtype == NULL) {
> > -        fprintf(stderr, "spice-qemu-char: unsupported type: %s\n",
> type);
> > -        print_allowed_subtypes();
> > +        char *subtypes = g_strjoinv(", ",
> > +            (gchar **)spice_server_char_device_recognized_subtypes());
> > +
> > +        error_setg(errp, "unsupported type name: %s", type);
> > +        error_report("allowed spice char type names: %s", subtypes);
>
> However, I'm not sure if error_setg() followed by error_report() is
> correct; should you be using error_append_hint() instead?  Markus?
>
>
That doesn't work well with command line errors. error_vprintf_unless_qmp()
doesn't print if !cur_mon. I sent a patch on the ML, and I'll follow your
suggestion.



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 15/54] chardev: qom-ify
  2016-12-12 22:42 ` [Qemu-devel] [PATCH 15/54] chardev: qom-ify Marc-André Lureau
  2017-01-05  2:30   ` Eric Blake
@ 2017-01-05 15:54   ` Eric Blake
  2017-01-05 16:20     ` Marc-André Lureau
  1 sibling, 1 reply; 85+ messages in thread
From: Eric Blake @ 2017-01-05 15:54 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: pbonzini

[-- Attachment #1: Type: text/plain, Size: 2214 bytes --]

On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> Turn Chardev into Object.
> 
> qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It
> will call qemu_char_open() to open/intialize the chardev with the
> ChardevCommon *backend settings.

Review part 2:

>  spice-qemu-char.c     |  144 +++---
>  ui/console.c          |   73 +--
>  ui/gtk.c              |   51 +-
>  vl.c                  |    2 +

> +++ b/spice-qemu-char.c
> @@ -18,6 +18,12 @@ typedef struct SpiceChardev {
>      QLIST_ENTRY(SpiceChardev) next;
>  } SpiceChardev;
>  
> +#define TYPE_CHARDEV_SPICE "chardev-spice"
> +#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
> +#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"

Why do we have a lot of TYPE_CHARDEV_* in sysemu/char.h, but not these?
Should they all live in the same place?

> +++ b/ui/console.c
> @@ -1040,9 +1040,12 @@ typedef struct VCChardev {
>      QemuConsole *console;
>  } VCChardev;
>  
> -static int console_puts(Chardev *chr, const uint8_t *buf, int len)
> +#define TYPE_CHARDEV_VC "chardev-vc"
> +#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
> +
> +static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
...

> @@ -1951,9 +1954,9 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
>      return con ? surface_height(con->surface) : fallback;
>  }
>  
> -static void text_console_set_echo(Chardev *chr, bool echo)
> +static void vc_chr_set_echo(Chardev *chr, bool echo)

Should these function renames be split to a separate patch?

> +++ b/ui/gtk.c
> @@ -184,6 +184,9 @@ typedef struct VCChardev {
>      bool echo;
>  } VCChardev;
>  
> +#define TYPE_CHARDEV_VC "chardev-vc"
> +#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)

Why do we have TYPE_CHARDEV_VC and VC_CHARDEV() defined in two different
.c files?

Overall the conversion looks good; as said elsewhere in the thread, I
think you can post a v2 of 1-15 and get that merged first, while still
hammering out the details of the rest of the series.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [Qemu-devel] [PATCH 15/54] chardev: qom-ify
  2017-01-05 15:54   ` Eric Blake
@ 2017-01-05 16:20     ` Marc-André Lureau
  0 siblings, 0 replies; 85+ messages in thread
From: Marc-André Lureau @ 2017-01-05 16:20 UTC (permalink / raw)
  To: Eric Blake; +Cc: Marc-André Lureau, qemu-devel, pbonzini

Hi

----- Original Message -----
> On 12/12/2016 04:42 PM, Marc-André Lureau wrote:
> > Turn Chardev into Object.
> > 
> > qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It
> > will call qemu_char_open() to open/intialize the chardev with the
> > ChardevCommon *backend settings.
> 
> Review part 2:
> 
> >  spice-qemu-char.c     |  144 +++---
> >  ui/console.c          |   73 +--
> >  ui/gtk.c              |   51 +-
> >  vl.c                  |    2 +
> 
> > +++ b/spice-qemu-char.c
> > @@ -18,6 +18,12 @@ typedef struct SpiceChardev {
> >      QLIST_ENTRY(SpiceChardev) next;
> >  } SpiceChardev;
> >  
> > +#define TYPE_CHARDEV_SPICE "chardev-spice"
> > +#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
> > +#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"
> 
> Why do we have a lot of TYPE_CHARDEV_* in sysemu/char.h, but not these?
> Should they all live in the same place?

I think in general, we keep typename private, unless the type is being used by some other file.

In this refactoring series, it's a bit tricky, because there are types such as mux, memory and pty  that are shared with several units (when splitting).

Moving them back and forth in char.h introduces yet again code churning in my tree ;) It would be easier to clean that later in the series. So for this patch, all types and common helper macros for qemu-char.c are in char.h. I'll update commit message with this detail.

> 
> > +++ b/ui/console.c
> > @@ -1040,9 +1040,12 @@ typedef struct VCChardev {
> >      QemuConsole *console;
> >  } VCChardev;
> >  
> > -static int console_puts(Chardev *chr, const uint8_t *buf, int len)
> > +#define TYPE_CHARDEV_VC "chardev-vc"
> > +#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
> > +
> > +static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
> ...
> 
> > @@ -1951,9 +1954,9 @@ int qemu_console_get_height(QemuConsole *con, int
> > fallback)
> >      return con ? surface_height(con->surface) : fallback;
> >  }
> >  
> > -static void text_console_set_echo(Chardev *chr, bool echo)
> > +static void vc_chr_set_echo(Chardev *chr, bool echo)
> 
> Should these function renames be split to a separate patch?

ok

> 
> > +++ b/ui/gtk.c
> > @@ -184,6 +184,9 @@ typedef struct VCChardev {
> >      bool echo;
> >  } VCChardev;
> >  
> > +#define TYPE_CHARDEV_VC "chardev-vc"
> > +#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
> 
> Why do we have TYPE_CHARDEV_VC and VC_CHARDEV() defined in two different
> .c files?
> 
> Overall the conversion looks good; as said elsewhere in the thread, I
> think you can post a v2 of 1-15 and get that merged first, while still
> hammering out the details of the rest of the series.

ok

^ permalink raw reply	[flat|nested] 85+ messages in thread

end of thread, other threads:[~2017-01-05 16:20 UTC | newest]

Thread overview: 85+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-12 22:42 [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 01/54] gtk: avoid oob array access Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 02/54] char: use a const CharDriver Marc-André Lureau
2016-12-13 23:11   ` Eric Blake
2017-01-02 15:33     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 03/54] char: use a static array for backends Marc-André Lureau
2016-12-14 14:52   ` Eric Blake
2017-01-02 15:33     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 04/54] char: move callbacks in CharDriver Marc-André Lureau
2016-12-14 16:02   ` Eric Blake
2017-01-02 15:33     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 05/54] char: fold single-user functions in caller Marc-André Lureau
2016-12-14 16:05   ` Eric Blake
2017-01-02 15:33     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 06/54] char: introduce generic qemu_chr_get_kind() Marc-André Lureau
2016-12-19 21:16   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 07/54] char: use a feature bit for replay Marc-André Lureau
2016-12-19 21:58   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 08/54] char: allocate CharDriverState as a single object Marc-André Lureau
2017-01-04 20:24   ` Eric Blake
2017-01-04 21:09     ` Marc-André Lureau
2017-01-04 21:15       ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 09/54] bt: use qemu_chr_alloc() Marc-André Lureau
2017-01-04 21:18   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 10/54] char: rename CharDriverState Chardev Marc-André Lureau
2017-01-04 21:30   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 11/54] char: rename TCPChardev and NetChardev Marc-André Lureau
2017-01-04 21:55   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 12/54] spice-char: improve error reporting Marc-André Lureau
2017-01-04 22:00   ` Eric Blake
2017-01-05 14:03     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 13/54] char: use error_report() Marc-André Lureau
2017-01-04 22:04   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 14/54] gtk: overwrite the console.c char driver Marc-André Lureau
2017-01-04 22:26   ` Eric Blake
2016-12-12 22:42 ` [Qemu-devel] [PATCH 15/54] chardev: qom-ify Marc-André Lureau
2017-01-05  2:30   ` Eric Blake
2017-01-05 15:54   ` Eric Blake
2017-01-05 16:20     ` Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 16/54] spice-qemu-char: convert to finalize Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 17/54] baum: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 18/54] msmouse: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 19/54] mux: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 20/54] char-udp: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 21/54] char-socket: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 22/54] char-pty: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 23/54] char-ringbuf: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 24/54] char-parallel: convert parallel " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 25/54] char-stdio: convert " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 26/54] char-win-stdio: " Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 27/54] char-win: do not override chr_free Marc-André Lureau
2016-12-12 22:42 ` [Qemu-devel] [PATCH 28/54] char-win: convert to finalize Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 29/54] char-fd: " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 30/54] char: remove chr_free Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 31/54] char: get rid of CharDriver Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 32/54] char: remove class kind field Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 33/54] char: move to chardev/ Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 34/54] char: create chardev-obj-y Marc-André Lureau
2016-12-13 11:10   ` Paolo Bonzini
2016-12-13 12:40     ` Marc-André Lureau
2016-12-13 12:52       ` Paolo Bonzini
2016-12-12 22:43 ` [Qemu-devel] [PATCH 35/54] char: make null_chr_write() the default method Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 36/54] char: move null chardev to its own file Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 37/54] char: move mux " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 38/54] char: move ringbuf/memory " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 39/54] char: rename and move to header CHR_READ_BUF_LEN Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 40/54] char: remove unused READ_RETRIES Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 41/54] char: move QIOChannel-related in char-io.h Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 42/54] char: move fd chardev in its own file Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 43/54] char: move win chardev base class " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 44/54] char: move win-stdio into " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 45/54] char: move socket chardev to itw " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 46/54] char: move udp chardev in its " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 47/54] char: move file " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 48/54] char: move stdio " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 49/54] char: move console " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 50/54] char: move pipe chardev " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 51/54] char: move pty " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 52/54] char: move serial chardev to itw " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 53/54] char: move parallel chardev in its " Marc-André Lureau
2016-12-12 22:43 ` [Qemu-devel] [PATCH 54/54] char: headers clean-up Marc-André Lureau
2016-12-13  0:33 ` [Qemu-devel] [PATCH 00/54] WIP: chardev: qom-ify no-reply
2017-01-02 10:26 ` Paolo Bonzini
2017-01-04 21:20   ` Marc-André Lureau
2017-01-04 21:50     ` Eric Blake

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.