diff mbox

[37/38] char: allocate CharDriverState as a single object

Message ID 20161022101640.20153-1-marcandre.lureau@redhat.com
State New
Headers show

Commit Message

Marc-André Lureau Oct. 22, 2016, 10:16 a.m. UTC
Use a single allocation for CharDriverState, this avoids extra
allocations & pointers, and is a step towards more object-oriented
CharDriver.

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           | 275 ++++++++++++++++++++++++++------------------------
 spice-qemu-char.c     |  39 +++----
 ui/console.c          |  21 ++--
 ui/gtk.c              |  11 +-
 include/sysemu/char.h |   2 +-
 include/ui/gtk.h      |   3 +
 11 files changed, 215 insertions(+), 208 deletions(-)

Comments

Paolo Bonzini Oct. 23, 2016, 12:28 p.m. UTC | #1
On 22/10/2016 12:16, Marc-André Lureau wrote:
> Use a single allocation for CharDriverState, this avoids extra
> allocations & pointers, and is a step towards more object-oriented
> CharDriver.
> 
> 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           | 275 ++++++++++++++++++++++++++------------------------
>  spice-qemu-char.c     |  39 +++----
>  ui/console.c          |  21 ++--
>  ui/gtk.c              |  11 +-
>  include/sysemu/char.h |   2 +-
>  include/ui/gtk.h      |   3 +
>  11 files changed, 215 insertions(+), 208 deletions(-)
> 
> diff --git a/backends/baum.c b/backends/baum.c
> index b2d4719..45a6fd4 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;
> @@ -219,7 +219,7 @@ static const uint8_t nabcc_translation[256] = {
>  /* 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)
> @@ -245,22 +245,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);

Let's use &baum->chr instead, and likewise everywhere else.

Paolo

>      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) {
> @@ -433,7 +434,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)
> @@ -553,14 +554,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,
> @@ -585,10 +585,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;
> @@ -635,7 +632,6 @@ fail:
>  fail_handle:
>      g_free(handle);
>      g_free(chr);
> -    g_free(baum);
>      return NULL;
>  }
>  
> @@ -643,6 +639,7 @@ static void register_types(void)
>  {
>      static const CharDriver driver = {
>          { "braille" }, CHARDEV_BACKEND_KIND_BRAILLE, NULL, chr_baum_init,
> +        sizeof(BaumDriverState),
>          .chr_write = baum_write,
>          .chr_accept_input = baum_accept_input,
>          .chr_free = baum_free,
> diff --git a/backends/msmouse.c b/backends/msmouse.c
> index f71aab0..37e7b82 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;
>  }
> @@ -180,6 +179,7 @@ static void register_types(void)
>      static const CharDriver driver = {
>          { "msmouse" }, CHARDEV_BACKEND_KIND_MSMOUSE,
>          NULL, qemu_chr_open_msmouse,
> +        sizeof(MouseState),
>          .chr_write = msmouse_chr_write,
>          .chr_accept_input = msmouse_chr_accept_input,
>          .chr_free = msmouse_chr_free,
> diff --git a/backends/testdev.c b/backends/testdev.c
> index 774cd47..4b1953b 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;
>  }
> @@ -132,8 +122,8 @@ static void register_types(void)
>  {
>      static const CharDriver driver = {
>          { "testdev" }, CHARDEV_BACKEND_KIND_TESTDEV, NULL, chr_testdev_init,
> +        sizeof(TestdevCharState),
>          .chr_write = testdev_write,
> -        .chr_free = testdev_free,
>      };
>      register_char_driver(&driver);
>  }
> diff --git a/gdbstub.c b/gdbstub.c
> index 8e43836..3a9f857 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1732,6 +1732,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 9c3fb3c..bf2deb0 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 fe8f717..1da7244 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 &&
> @@ -537,6 +539,7 @@ static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
>  
>  static const CharDriver null_driver = {
>      { "null" }, CHARDEV_BACKEND_KIND_NULL, NULL, qemu_chr_open_null,
> +    sizeof(CharDriverState),
>      .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;
> @@ -753,8 +756,7 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
>  
>  static void mux_chr_event(void *opaque, int event)
>  {
> -    CharDriverState *chr = opaque;
> -    MuxDriver *d = chr->opaque;
> +    MuxDriver *d = opaque;
>      int i;
>  
>      /* Send the event to all registered listeners */
> @@ -782,7 +784,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 */
> @@ -804,7 +806,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) {
> @@ -816,7 +818,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++) {
> @@ -826,12 +828,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,
> @@ -877,9 +878,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
> @@ -908,7 +907,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
>      assert(s);
>  
>      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;
> @@ -940,7 +939,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;
> @@ -1006,7 +1005,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);
>      }
>  }
>  
> @@ -1178,6 +1177,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;
> @@ -1186,15 +1186,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;
> @@ -1224,7 +1224,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;
> @@ -1232,14 +1232,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) {
> @@ -1252,7 +1252,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) {
> @@ -1262,7 +1262,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);
>  }
>  
> @@ -1278,12 +1277,11 @@ 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));
>      s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
>      qemu_set_nonblock(fd_out);
>      s->chr = chr;
> -    chr->opaque = s;
>  
>      return chr;
>  }
> @@ -1424,6 +1422,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
>  #define HAVE_CHARDEV_PTY 1
>  
>  typedef struct {
> +    CharDriverState parent;
>      QIOChannel *ioc;
>      int read_bytes;
>  
> @@ -1439,7 +1438,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;
> @@ -1455,7 +1454,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;
>  
>      if (s->timer_tag) {
>          g_source_remove(s->timer_tag);
> @@ -1472,7 +1471,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);
> @@ -1503,7 +1502,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 */
> @@ -1517,7 +1516,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;
>      }
> @@ -1527,7 +1526,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;
> @@ -1536,7 +1535,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;
> @@ -1561,7 +1560,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);
> @@ -1571,7 +1570,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) {
> @@ -1605,7 +1604,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);
> @@ -1615,7 +1614,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);
>  }
>  
> @@ -1654,18 +1652,17 @@ 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));
>      s->timer_tag = 0;
> +    *be_opened = false;
>  
>      return chr;
>  }
>  
>  static const CharDriver pty_driver = {
>      { "pty" }, CHARDEV_BACKEND_KIND_PTY, NULL, qemu_chr_open_pty,
> +    sizeof(PtyCharDriver),
>      .chr_write = pty_chr_write,
>      .chr_update_read_handler = pty_chr_update_read_handler,
>      .chr_add_watch = pty_chr_add_watch,
> @@ -1789,7 +1786,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) {
> @@ -1868,6 +1865,7 @@ static void qemu_chr_free_tty(CharDriverState *chr)
>  #define HAVE_CHARDEV_PARPORT 1
>  
>  typedef struct {
> +    CharDriverState parent;
>      int fd;
>      int mode;
>  } ParallelCharDriver;
> @@ -1885,7 +1883,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;
>  
> @@ -1966,13 +1964,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);
>  }
>  
> @@ -1996,9 +1993,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;
>  
> @@ -2010,35 +2005,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:
> @@ -2054,12 +2059,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;
>  }
> @@ -2070,6 +2077,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;
> @@ -2081,6 +2089,7 @@ typedef struct {
>  } WinCharState;
>  
>  typedef struct {
> +    CharDriverState parent;
>      HANDLE  hStdIn;
>      HANDLE  hInputReadyEvent;
>      HANDLE  hInputDoneEvent;
> @@ -2098,7 +2107,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);
> @@ -2122,7 +2131,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;
> @@ -2190,7 +2199,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;
> @@ -2224,7 +2233,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;
> @@ -2232,7 +2241,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;
> @@ -2254,7 +2263,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;
> @@ -2267,7 +2276,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;
>  
> @@ -2284,7 +2293,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);
> @@ -2300,7 +2309,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;
> @@ -2372,18 +2381,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;
>      }
> @@ -2402,9 +2407,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;
>  }
>  
> @@ -2423,6 +2427,7 @@ static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
>  
>  static const CharDriver console_driver = {
>      { "console" }, CHARDEV_BACKEND_KIND_CONSOLE, NULL, qemu_chr_open_win_con,
> +    sizeof(WinCharState),
>      .chr_write = win_chr_write,
>  };
>  
> @@ -2448,7 +2453,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;
> @@ -2481,8 +2486,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;
>  
> @@ -2521,7 +2525,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);
> @@ -2532,7 +2536,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);
> @@ -2546,7 +2550,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);
> @@ -2557,8 +2561,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,
> @@ -2578,7 +2580,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) {
> @@ -2588,8 +2590,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)) {
> @@ -2649,6 +2649,7 @@ err1:
>  /* UDP Net console */
>  
>  typedef struct {
> +    CharDriverState parent;
>      QIOChannel *ioc;
>      uint8_t buf[READ_BUF_LEN];
>      int bufcnt;
> @@ -2659,7 +2660,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);
> @@ -2668,7 +2669,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);
>  
> @@ -2686,7 +2687,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) {
> @@ -2713,7 +2714,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) {
> @@ -2726,13 +2727,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);
>  }
>  
> @@ -2740,6 +2740,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;
> @@ -2768,7 +2769,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque);
>  
>  static void qemu_chr_socket_restart_timer(CharDriverState *chr)
>  {
> -    TCPCharDriver *s = chr->opaque;
> +    TCPCharDriver *s = (TCPCharDriver *)chr;
>      assert(s->connected == 0);
>      s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
>                                                 socket_reconnect_timeout, chr);
> @@ -2777,7 +2778,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",
> @@ -2794,7 +2795,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,
> @@ -2817,7 +2819,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);
> @@ -2876,7 +2878,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);
> @@ -2901,7 +2904,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);
> @@ -2926,7 +2929,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;
> @@ -2983,13 +2986,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) {
> @@ -3018,7 +3021,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;
> @@ -3041,7 +3044,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;
>  
> @@ -3067,7 +3070,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) {
> @@ -3086,7 +3089,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(
> @@ -3107,7 +3110,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;
> @@ -3158,7 +3161,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;
> @@ -3194,7 +3197,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);
> @@ -3210,7 +3213,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;
>  
> @@ -3242,7 +3245,8 @@ static void tcp_chr_tls_init(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;
>      }
> @@ -3312,7 +3316,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
> @@ -3359,7 +3363,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);
>  
> @@ -3378,7 +3382,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);
>  }
>  
> @@ -3387,7 +3391,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);
> @@ -3405,6 +3409,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;
> @@ -3413,7 +3418,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;
>  }
> @@ -3421,7 +3426,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)) {
> @@ -3440,7 +3445,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);
> @@ -3454,11 +3459,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,
> @@ -3477,7 +3480,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;
>  
> @@ -3491,12 +3494,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;
>  }
> @@ -3786,10 +3786,12 @@ static const CharDriver stdio_driver = {
>      { "stdio" }, CHARDEV_BACKEND_KIND_STDIO,
>      qemu_chr_parse_stdio, 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,
> @@ -3851,9 +3853,11 @@ static const CharDriver pipe_driver = {
>      { "pipe" }, CHARDEV_BACKEND_KIND_PIPE,
>      qemu_chr_parse_pipe, 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,
> @@ -3880,6 +3884,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
>  static const CharDriver ringbuf_driver = {
>      { "ringbuf" }, CHARDEV_BACKEND_KIND_RINGBUF,
>      qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf,
> +    sizeof(RingBufCharDriver),
>      .chr_write = ringbuf_chr_write,
>      .chr_free = ringbuf_chr_free,
>  };
> @@ -3888,6 +3893,7 @@ static const CharDriver ringbuf_driver = {
>  static const CharDriver memory_driver = {
>      { "memory" }, CHARDEV_BACKEND_KIND_MEMORY,
>      qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf,
> +    sizeof(RingBufCharDriver),
>      .chr_write = ringbuf_chr_write,
>      .chr_free = ringbuf_chr_free,
>  };
> @@ -3909,6 +3915,7 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
>  
>  static const CharDriver mux_driver = {
>      { "mux" }, CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux, qemu_chr_open_mux,
> +    sizeof(MuxDriver),
>      .chr_free = mux_chr_free,
>      .chr_write = mux_chr_write,
>      .chr_accept_input = mux_chr_accept_input,
> @@ -4489,17 +4496,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;
>      }
> @@ -4601,6 +4604,7 @@ static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
>  static const CharDriver parallel_driver = {
>      { "parallel", "parport" }, CHARDEV_BACKEND_KIND_PARALLEL,
>      qemu_chr_parse_parallel, qmp_chardev_open_parallel,
> +    sizeof(ParallelCharDriver),
>  #if defined(__linux__)
>      .chr_write = null_chr_write,
>      .chr_ioctl = pp_ioctl,
> @@ -4618,8 +4622,10 @@ static const CharDriver file_driver = {
>      { "file" }, CHARDEV_BACKEND_KIND_FILE,
>      qemu_chr_parse_file_out, qmp_chardev_open_file,
>  #ifdef _WIN32
> +    sizeof(WinCharState),
>      .chr_write = win_chr_write,
>  #else
> +    sizeof(FDCharDriver),
>      .chr_add_watch = fd_chr_add_watch,
>      .chr_write = fd_chr_write,
>      .chr_update_read_handler = fd_chr_update_read_handler,
> @@ -4632,9 +4638,11 @@ static const CharDriver serial_driver = {
>      { "serial", "tty" }, CHARDEV_BACKEND_KIND_SERIAL,
>      qemu_chr_parse_serial, 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,
> @@ -4647,7 +4655,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;
> @@ -4687,7 +4695,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;
> @@ -4733,7 +4741,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;
>  
> @@ -4783,7 +4790,6 @@ 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;
>  }
> @@ -4791,6 +4797,7 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
>  static const CharDriver socket_driver = {
>      { "socket" }, CHARDEV_BACKEND_KIND_SOCKET,
>      qemu_chr_parse_socket, qmp_chardev_open_socket,
> +    sizeof(TCPCharDriver),
>      .chr_wait_connected = tcp_chr_wait_connected,
>      .chr_write = tcp_chr_write,
>      .chr_sync_read = tcp_chr_sync_read,
> @@ -4828,11 +4835,10 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
>          return NULL;
>      }
>  
> -    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;
>  
> @@ -4842,6 +4848,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
>  static const CharDriver udp_driver = {
>      { "udp" }, CHARDEV_BACKEND_KIND_UDP,
>      qemu_chr_parse_udp, qmp_chardev_open_udp,
> +    sizeof(NetCharDriver),
>      .chr_write = udp_chr_write,
>      .chr_update_read_handler = udp_chr_update_read_handler,
>      .chr_free = udp_chr_free,
> diff --git a/spice-qemu-char.c b/spice-qemu-char.c
> index 14afd4a..bd8b898 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;
> @@ -388,6 +389,7 @@ static void register_types(void)
>      static const CharDriver vmc_driver = {
>          { "spicevmc" }, CHARDEV_BACKEND_KIND_SPICEVMC,
>          qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc,
> +        sizeof(SpiceCharDriver),
>          .chr_write = spice_chr_write,
>          .chr_add_watch = spice_chr_add_watch,
>          .chr_set_fe_open = spice_vmc_set_fe_open,
> @@ -397,6 +399,7 @@ static void register_types(void)
>      static const CharDriver port_driver = {
>          { "spiceport" }, CHARDEV_BACKEND_KIND_SPICEPORT,
>          qemu_chr_parse_spice_port, qemu_chr_open_spice_port,
> +        sizeof(SpiceCharDriver),
>          .chr_write = spice_chr_write,
>          .chr_add_watch = spice_chr_add_watch,
>          .chr_set_fe_open = spice_port_set_fe_open,
> diff --git a/ui/console.c b/ui/console.c
> index 2944d22..b8c6328 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;
>  
>      s->update_x0 = s->width * FONT_WIDTH;
> @@ -1943,7 +1949,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;
>  }
> @@ -1983,12 +1990,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);
> @@ -2041,6 +2047,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;
> @@ -2077,7 +2084,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);
> @@ -2182,6 +2190,7 @@ static const TypeInfo qemu_console_info = {
>  
>  static const CharDriver vc_driver = {
>      { "vc" }, CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc, vc_init,
> +    sizeof(VCDriverState),
>      .chr_write = console_puts,
>      .chr_set_echo = text_console_set_echo,
>  };
> diff --git a/ui/gtk.c b/ui/gtk.c
> index 1566faa..03281da 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -1653,7 +1653,7 @@ 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;
> +    VirtualConsole *vc = (VirtualConsole *)chr;
>  
>      vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
>      return len;
> @@ -1661,7 +1661,7 @@ 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;
> +    VirtualConsole *vc = (VirtualConsole *)chr;
>  
>      vc->vte.echo = echo;
>  }
> @@ -1673,6 +1673,7 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
>  {
>      static const CharDriver gd_vc_driver = {
>          { "vc" }, CHARDEV_BACKEND_KIND_VC,
> +        .instance_size = sizeof(VirtualConsole),
>          .chr_write = gd_vc_chr_write,
>          .chr_set_echo = gd_vc_chr_set_echo,
>      };
> @@ -1685,9 +1686,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;
> @@ -1728,13 +1726,12 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
>      GtkWidget *box;
>      GtkWidget *scrollbar;
>      GtkAdjustment *vadjustment;
> -    VirtualConsole *tmp_vc = chr->opaque;
> +    VirtualConsole *tmp_vc = (VirtualConsole *)chr;
>  
>      vc->s = s;
>      vc->vte.echo = tmp_vc->vte.echo;
>  
>      vc->vte.chr = chr;
> -    chr->opaque = vc;
>      g_free(tmp_vc);
>  
>      snprintf(buffer, sizeof(buffer), "vc%d", idx);
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 96b464a..a072edc 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,
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index 42ca0fe..6fec03f 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -23,6 +23,8 @@
>  #include "ui/egl-context.h"
>  #endif
>  
> +#include "sysemu/char.h"
> +
>  /* Compatibility define to let us build on both Gtk2 and Gtk3 */
>  #if GTK_CHECK_VERSION(3, 0, 0)
>  static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
> @@ -71,6 +73,7 @@ typedef enum VirtualConsoleType {
>  } VirtualConsoleType;
>  
>  typedef struct VirtualConsole {
> +    CharDriverState parent;
>      GtkDisplayState *s;
>      char *label;
>      GtkWidget *window;
>
diff mbox

Patch

diff --git a/backends/baum.c b/backends/baum.c
index b2d4719..45a6fd4 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;
@@ -219,7 +219,7 @@  static const uint8_t nabcc_translation[256] = {
 /* 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)
@@ -245,22 +245,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) {
@@ -433,7 +434,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)
@@ -553,14 +554,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,
@@ -585,10 +585,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;
@@ -635,7 +632,6 @@  fail:
 fail_handle:
     g_free(handle);
     g_free(chr);
-    g_free(baum);
     return NULL;
 }
 
@@ -643,6 +639,7 @@  static void register_types(void)
 {
     static const CharDriver driver = {
         { "braille" }, CHARDEV_BACKEND_KIND_BRAILLE, NULL, chr_baum_init,
+        sizeof(BaumDriverState),
         .chr_write = baum_write,
         .chr_accept_input = baum_accept_input,
         .chr_free = baum_free,
diff --git a/backends/msmouse.c b/backends/msmouse.c
index f71aab0..37e7b82 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;
 }
@@ -180,6 +179,7 @@  static void register_types(void)
     static const CharDriver driver = {
         { "msmouse" }, CHARDEV_BACKEND_KIND_MSMOUSE,
         NULL, qemu_chr_open_msmouse,
+        sizeof(MouseState),
         .chr_write = msmouse_chr_write,
         .chr_accept_input = msmouse_chr_accept_input,
         .chr_free = msmouse_chr_free,
diff --git a/backends/testdev.c b/backends/testdev.c
index 774cd47..4b1953b 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;
 }
@@ -132,8 +122,8 @@  static void register_types(void)
 {
     static const CharDriver driver = {
         { "testdev" }, CHARDEV_BACKEND_KIND_TESTDEV, NULL, chr_testdev_init,
+        sizeof(TestdevCharState),
         .chr_write = testdev_write,
-        .chr_free = testdev_free,
     };
     register_char_driver(&driver);
 }
diff --git a/gdbstub.c b/gdbstub.c
index 8e43836..3a9f857 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1732,6 +1732,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 9c3fb3c..bf2deb0 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 fe8f717..1da7244 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 &&
@@ -537,6 +539,7 @@  static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
 
 static const CharDriver null_driver = {
     { "null" }, CHARDEV_BACKEND_KIND_NULL, NULL, qemu_chr_open_null,
+    sizeof(CharDriverState),
     .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;
@@ -753,8 +756,7 @@  static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 
 static void mux_chr_event(void *opaque, int event)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int i;
 
     /* Send the event to all registered listeners */
@@ -782,7 +784,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 */
@@ -804,7 +806,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) {
@@ -816,7 +818,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++) {
@@ -826,12 +828,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,
@@ -877,9 +878,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
@@ -908,7 +907,7 @@  bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     assert(s);
 
     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;
@@ -940,7 +939,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;
@@ -1006,7 +1005,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);
     }
 }
 
@@ -1178,6 +1177,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;
@@ -1186,15 +1186,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;
@@ -1224,7 +1224,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;
@@ -1232,14 +1232,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) {
@@ -1252,7 +1252,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) {
@@ -1262,7 +1262,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);
 }
 
@@ -1278,12 +1277,11 @@  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));
     s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
     qemu_set_nonblock(fd_out);
     s->chr = chr;
-    chr->opaque = s;
 
     return chr;
 }
@@ -1424,6 +1422,7 @@  static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 #define HAVE_CHARDEV_PTY 1
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     int read_bytes;
 
@@ -1439,7 +1438,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;
@@ -1455,7 +1454,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;
 
     if (s->timer_tag) {
         g_source_remove(s->timer_tag);
@@ -1472,7 +1471,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);
@@ -1503,7 +1502,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 */
@@ -1517,7 +1516,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;
     }
@@ -1527,7 +1526,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;
@@ -1536,7 +1535,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;
@@ -1561,7 +1560,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);
@@ -1571,7 +1570,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) {
@@ -1605,7 +1604,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);
@@ -1615,7 +1614,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);
 }
 
@@ -1654,18 +1652,17 @@  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));
     s->timer_tag = 0;
+    *be_opened = false;
 
     return chr;
 }
 
 static const CharDriver pty_driver = {
     { "pty" }, CHARDEV_BACKEND_KIND_PTY, NULL, qemu_chr_open_pty,
+    sizeof(PtyCharDriver),
     .chr_write = pty_chr_write,
     .chr_update_read_handler = pty_chr_update_read_handler,
     .chr_add_watch = pty_chr_add_watch,
@@ -1789,7 +1786,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) {
@@ -1868,6 +1865,7 @@  static void qemu_chr_free_tty(CharDriverState *chr)
 #define HAVE_CHARDEV_PARPORT 1
 
 typedef struct {
+    CharDriverState parent;
     int fd;
     int mode;
 } ParallelCharDriver;
@@ -1885,7 +1883,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;
 
@@ -1966,13 +1964,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);
 }
 
@@ -1996,9 +1993,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;
 
@@ -2010,35 +2005,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:
@@ -2054,12 +2059,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;
 }
@@ -2070,6 +2077,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;
@@ -2081,6 +2089,7 @@  typedef struct {
 } WinCharState;
 
 typedef struct {
+    CharDriverState parent;
     HANDLE  hStdIn;
     HANDLE  hInputReadyEvent;
     HANDLE  hInputDoneEvent;
@@ -2098,7 +2107,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);
@@ -2122,7 +2131,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;
@@ -2190,7 +2199,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;
@@ -2224,7 +2233,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;
@@ -2232,7 +2241,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;
@@ -2254,7 +2263,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;
@@ -2267,7 +2276,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;
 
@@ -2284,7 +2293,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);
@@ -2300,7 +2309,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;
@@ -2372,18 +2381,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;
     }
@@ -2402,9 +2407,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;
 }
 
@@ -2423,6 +2427,7 @@  static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
 
 static const CharDriver console_driver = {
     { "console" }, CHARDEV_BACKEND_KIND_CONSOLE, NULL, qemu_chr_open_win_con,
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
 };
 
@@ -2448,7 +2453,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;
@@ -2481,8 +2486,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;
 
@@ -2521,7 +2525,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);
@@ -2532,7 +2536,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);
@@ -2546,7 +2550,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);
@@ -2557,8 +2561,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,
@@ -2578,7 +2580,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) {
@@ -2588,8 +2590,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)) {
@@ -2649,6 +2649,7 @@  err1:
 /* UDP Net console */
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     uint8_t buf[READ_BUF_LEN];
     int bufcnt;
@@ -2659,7 +2660,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);
@@ -2668,7 +2669,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);
 
@@ -2686,7 +2687,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) {
@@ -2713,7 +2714,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) {
@@ -2726,13 +2727,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);
 }
 
@@ -2740,6 +2740,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;
@@ -2768,7 +2769,7 @@  static gboolean socket_reconnect_timeout(gpointer opaque);
 
 static void qemu_chr_socket_restart_timer(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     assert(s->connected == 0);
     s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
                                                socket_reconnect_timeout, chr);
@@ -2777,7 +2778,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",
@@ -2794,7 +2795,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,
@@ -2817,7 +2819,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);
@@ -2876,7 +2878,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);
@@ -2901,7 +2904,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);
@@ -2926,7 +2929,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;
@@ -2983,13 +2986,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) {
@@ -3018,7 +3021,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;
@@ -3041,7 +3044,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;
 
@@ -3067,7 +3070,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) {
@@ -3086,7 +3089,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(
@@ -3107,7 +3110,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;
@@ -3158,7 +3161,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;
@@ -3194,7 +3197,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);
@@ -3210,7 +3213,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;
 
@@ -3242,7 +3245,8 @@  static void tcp_chr_tls_init(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;
     }
@@ -3312,7 +3316,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
@@ -3359,7 +3363,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);
 
@@ -3378,7 +3382,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);
 }
 
@@ -3387,7 +3391,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);
@@ -3405,6 +3409,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;
@@ -3413,7 +3418,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;
 }
@@ -3421,7 +3426,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)) {
@@ -3440,7 +3445,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);
@@ -3454,11 +3459,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,
@@ -3477,7 +3480,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;
 
@@ -3491,12 +3494,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;
 }
@@ -3786,10 +3786,12 @@  static const CharDriver stdio_driver = {
     { "stdio" }, CHARDEV_BACKEND_KIND_STDIO,
     qemu_chr_parse_stdio, 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,
@@ -3851,9 +3853,11 @@  static const CharDriver pipe_driver = {
     { "pipe" }, CHARDEV_BACKEND_KIND_PIPE,
     qemu_chr_parse_pipe, 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,
@@ -3880,6 +3884,7 @@  static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 static const CharDriver ringbuf_driver = {
     { "ringbuf" }, CHARDEV_BACKEND_KIND_RINGBUF,
     qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf,
+    sizeof(RingBufCharDriver),
     .chr_write = ringbuf_chr_write,
     .chr_free = ringbuf_chr_free,
 };
@@ -3888,6 +3893,7 @@  static const CharDriver ringbuf_driver = {
 static const CharDriver memory_driver = {
     { "memory" }, CHARDEV_BACKEND_KIND_MEMORY,
     qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf,
+    sizeof(RingBufCharDriver),
     .chr_write = ringbuf_chr_write,
     .chr_free = ringbuf_chr_free,
 };
@@ -3909,6 +3915,7 @@  static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
 
 static const CharDriver mux_driver = {
     { "mux" }, CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux, qemu_chr_open_mux,
+    sizeof(MuxDriver),
     .chr_free = mux_chr_free,
     .chr_write = mux_chr_write,
     .chr_accept_input = mux_chr_accept_input,
@@ -4489,17 +4496,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;
     }
@@ -4601,6 +4604,7 @@  static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
 static const CharDriver parallel_driver = {
     { "parallel", "parport" }, CHARDEV_BACKEND_KIND_PARALLEL,
     qemu_chr_parse_parallel, qmp_chardev_open_parallel,
+    sizeof(ParallelCharDriver),
 #if defined(__linux__)
     .chr_write = null_chr_write,
     .chr_ioctl = pp_ioctl,
@@ -4618,8 +4622,10 @@  static const CharDriver file_driver = {
     { "file" }, CHARDEV_BACKEND_KIND_FILE,
     qemu_chr_parse_file_out, qmp_chardev_open_file,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4632,9 +4638,11 @@  static const CharDriver serial_driver = {
     { "serial", "tty" }, CHARDEV_BACKEND_KIND_SERIAL,
     qemu_chr_parse_serial, 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,
@@ -4647,7 +4655,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;
@@ -4687,7 +4695,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;
@@ -4733,7 +4741,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;
 
@@ -4783,7 +4790,6 @@  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;
 }
@@ -4791,6 +4797,7 @@  static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
 static const CharDriver socket_driver = {
     { "socket" }, CHARDEV_BACKEND_KIND_SOCKET,
     qemu_chr_parse_socket, qmp_chardev_open_socket,
+    sizeof(TCPCharDriver),
     .chr_wait_connected = tcp_chr_wait_connected,
     .chr_write = tcp_chr_write,
     .chr_sync_read = tcp_chr_sync_read,
@@ -4828,11 +4835,10 @@  static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
         return NULL;
     }
 
-    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;
 
@@ -4842,6 +4848,7 @@  static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
 static const CharDriver udp_driver = {
     { "udp" }, CHARDEV_BACKEND_KIND_UDP,
     qemu_chr_parse_udp, qmp_chardev_open_udp,
+    sizeof(NetCharDriver),
     .chr_write = udp_chr_write,
     .chr_update_read_handler = udp_chr_update_read_handler,
     .chr_free = udp_chr_free,
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 14afd4a..bd8b898 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;
@@ -388,6 +389,7 @@  static void register_types(void)
     static const CharDriver vmc_driver = {
         { "spicevmc" }, CHARDEV_BACKEND_KIND_SPICEVMC,
         qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc,
+        sizeof(SpiceCharDriver),
         .chr_write = spice_chr_write,
         .chr_add_watch = spice_chr_add_watch,
         .chr_set_fe_open = spice_vmc_set_fe_open,
@@ -397,6 +399,7 @@  static void register_types(void)
     static const CharDriver port_driver = {
         { "spiceport" }, CHARDEV_BACKEND_KIND_SPICEPORT,
         qemu_chr_parse_spice_port, qemu_chr_open_spice_port,
+        sizeof(SpiceCharDriver),
         .chr_write = spice_chr_write,
         .chr_add_watch = spice_chr_add_watch,
         .chr_set_fe_open = spice_port_set_fe_open,
diff --git a/ui/console.c b/ui/console.c
index 2944d22..b8c6328 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;
 
     s->update_x0 = s->width * FONT_WIDTH;
@@ -1943,7 +1949,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;
 }
@@ -1983,12 +1990,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);
@@ -2041,6 +2047,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;
@@ -2077,7 +2084,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);
@@ -2182,6 +2190,7 @@  static const TypeInfo qemu_console_info = {
 
 static const CharDriver vc_driver = {
     { "vc" }, CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc, vc_init,
+    sizeof(VCDriverState),
     .chr_write = console_puts,
     .chr_set_echo = text_console_set_echo,
 };
diff --git a/ui/gtk.c b/ui/gtk.c
index 1566faa..03281da 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1653,7 +1653,7 @@  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;
+    VirtualConsole *vc = (VirtualConsole *)chr;
 
     vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
     return len;
@@ -1661,7 +1661,7 @@  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;
+    VirtualConsole *vc = (VirtualConsole *)chr;
 
     vc->vte.echo = echo;
 }
@@ -1673,6 +1673,7 @@  static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
 {
     static const CharDriver gd_vc_driver = {
         { "vc" }, CHARDEV_BACKEND_KIND_VC,
+        .instance_size = sizeof(VirtualConsole),
         .chr_write = gd_vc_chr_write,
         .chr_set_echo = gd_vc_chr_set_echo,
     };
@@ -1685,9 +1686,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;
@@ -1728,13 +1726,12 @@  static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
     GtkWidget *box;
     GtkWidget *scrollbar;
     GtkAdjustment *vadjustment;
-    VirtualConsole *tmp_vc = chr->opaque;
+    VirtualConsole *tmp_vc = (VirtualConsole *)chr;
 
     vc->s = s;
     vc->vte.echo = tmp_vc->vte.echo;
 
     vc->vte.chr = chr;
-    chr->opaque = vc;
     g_free(tmp_vc);
 
     snprintf(buffer, sizeof(buffer), "vc%d", idx);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 96b464a..a072edc 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,
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 42ca0fe..6fec03f 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -23,6 +23,8 @@ 
 #include "ui/egl-context.h"
 #endif
 
+#include "sysemu/char.h"
+
 /* Compatibility define to let us build on both Gtk2 and Gtk3 */
 #if GTK_CHECK_VERSION(3, 0, 0)
 static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
@@ -71,6 +73,7 @@  typedef enum VirtualConsoleType {
 } VirtualConsoleType;
 
 typedef struct VirtualConsole {
+    CharDriverState parent;
     GtkDisplayState *s;
     char *label;
     GtkWidget *window;