qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 4/9] char: keep track of qemu_chr_add_handlers()


From: Marc-André Lureau
Subject: [Qemu-devel] [PATCH 4/9] char: keep track of qemu_chr_add_handlers()
Date: Thu, 13 Oct 2016 15:14:44 +0400

Frontends should use qemu_chr_add_handlers()/qemu_chr_remove_handlers()
with the appropriate tag. This prevents from growing the mux char
frontends. A following patch will add error handling (check tag return
value and add an Error argument).

Signed-off-by: Marc-André Lureau <address@hidden>
---
 backends/rng-egd.c                | 13 ++++++++++---
 gdbstub.c                         | 12 +++++++++---
 hw/arm/pxa2xx.c                   | 14 +++++++++++++-
 hw/arm/strongarm.c                | 19 ++++++++++++++++++-
 hw/char/bcm2835_aux.c             | 13 ++++++++++++-
 hw/char/cadence_uart.c            | 16 +++++++++++++++-
 hw/char/debugcon.c                | 30 ++++++++++++++++--------------
 hw/char/digic-uart.c              | 13 ++++++++++++-
 hw/char/escc.c                    | 17 ++++++++++++++++-
 hw/char/etraxfs_ser.c             | 14 +++++++++++++-
 hw/char/exynos4210_uart.c         | 12 +++++++++++-
 hw/char/grlib_apbuart.c           | 14 +++++++++++++-
 hw/char/imx_serial.c              | 15 +++++++++++++--
 hw/char/ipoctal232.c              | 18 +++++++++++++++++-
 hw/char/lm32_juart.c              | 14 +++++++++++++-
 hw/char/lm32_uart.c               | 14 +++++++++++++-
 hw/char/mcf_uart.c                |  4 +++-
 hw/char/milkymist-uart.c          | 14 +++++++++++++-
 hw/char/pl011.c                   | 14 +++++++++++++-
 hw/char/sclpconsole-lm.c          | 11 ++++++++++-
 hw/char/sclpconsole.c             |  9 ++++++++-
 hw/char/serial.c                  | 10 +++++++---
 hw/char/sh_serial.c               |  8 ++++++--
 hw/char/spapr_vty.c               | 14 +++++++++++++-
 hw/char/stm32f2xx_usart.c         | 13 ++++++++++++-
 hw/char/virtio-console.c          | 10 ++++++++--
 hw/char/xen_console.c             |  8 +++++---
 hw/char/xilinx_uartlite.c         | 17 +++++++++++++++--
 hw/ipmi/ipmi_bmc_extern.c         | 14 +++++++++++++-
 hw/misc/ivshmem.c                 | 12 ++++++++++--
 hw/usb/ccid-card-passthru.c       |  9 ++++++++-
 hw/usb/dev-serial.c               | 16 ++++++++++++++--
 hw/usb/redirect.c                 | 13 ++++++++++++-
 monitor.c                         | 13 ++++++++-----
 net/colo-compare.c                | 22 ++++++++++++++--------
 net/filter-mirror.c               | 14 ++++++++++----
 net/slirp.c                       |  6 ++++--
 net/vhost-user.c                  |  8 +++++---
 qemu-char.c                       |  6 ++++--
 qtest.c                           |  4 +++-
 tests/vhost-user-test.c           |  7 +++++--
 include/hw/char/bcm2835_aux.h     |  1 +
 include/hw/char/cadence_uart.h    |  1 +
 include/hw/char/digic-uart.h      |  1 +
 include/hw/char/imx_serial.h      |  1 +
 include/hw/char/serial.h          |  1 +
 include/hw/char/stm32f2xx_usart.h |  1 +
 47 files changed, 443 insertions(+), 87 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index ba17c07..5d8485f 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -25,6 +25,7 @@ typedef struct RngEgd
     RngBackend parent;
 
     CharDriverState *chr;
+    int chr_tag;
     char *chr_name;
 } RngEgd;
 
@@ -107,8 +108,11 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
     }
 
     /* FIXME we should resubmit pending requests when the CDS reconnects. */
-    qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
-                          NULL, s);
+    if (s->chr_tag == -1) {
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read,
+                                  rng_egd_chr_read, NULL, s);
+    }
 }
 
 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
@@ -137,6 +141,9 @@ static char *rng_egd_get_chardev(Object *obj, Error **errp)
 
 static void rng_egd_init(Object *obj)
 {
+    RngEgd *s = RNG_EGD(obj);
+
+    s->chr_tag = -1;
     object_property_add_str(obj, "chardev",
                             rng_egd_get_chardev, rng_egd_set_chardev,
                             NULL);
@@ -147,7 +154,7 @@ static void rng_egd_finalize(Object *obj)
     RngEgd *s = RNG_EGD(obj);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
         qemu_chr_fe_release(s->chr);
     }
 
diff --git a/gdbstub.c b/gdbstub.c
index ecea8c4..054a1d3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -304,6 +304,7 @@ typedef struct GDBState {
     int running_state;
 #else
     CharDriverState *chr;
+    int chr_tag;
     CharDriverState *mon_chr;
 #endif
     char syscall_buf[256];
@@ -1724,6 +1725,7 @@ int gdbserver_start(const char *device)
     GDBState *s;
     char gdbstub_device_name[128];
     CharDriverState *chr = NULL;
+    int chr_tag = -1;
     CharDriverState *mon_chr;
     ChardevCommon common = { 0 };
 
@@ -1750,8 +1752,9 @@ int gdbserver_start(const char *device)
             return -1;
 
         qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
-                              gdb_chr_event, NULL);
+        chr_tag =
+            qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+                                  gdb_chr_event, NULL);
     }
 
     s = gdbserver_state;
@@ -1766,14 +1769,17 @@ int gdbserver_start(const char *device)
         mon_chr->chr_write = gdb_monitor_write;
         monitor_init(mon_chr, 0);
     } else {
-        if (s->chr)
+        if (s->chr) {
+            qemu_chr_remove_handlers(s->chr, s->chr_tag);
             qemu_chr_delete(s->chr);
+        }
         mon_chr = s->mon_chr;
         memset(s, 0, sizeof(GDBState));
     }
     s->c_cpu = first_cpu;
     s->g_cpu = first_cpu;
     s->chr = chr;
+    s->chr_tag = chr_tag;
     s->state = chr ? RS_IDLE : RS_INACTIVE;
     s->mon_chr = mon_chr;
     s->current_syscall_cb = NULL;
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 0241e07..e17b904 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1765,6 +1765,7 @@ struct PXA2xxFIrState {
     qemu_irq tx_dma;
     uint32_t enable;
     CharDriverState *chr;
+    int chr_tag;
 
     uint8_t control[3];
     uint8_t status[2];
@@ -1975,11 +1976,21 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error 
**errp)
 
     if (s->chr) {
         qemu_chr_fe_claim_no_fail(s->chr);
-        qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
                         pxa2xx_fir_rx, pxa2xx_fir_event, s);
     }
 }
 
+static void pxa2xx_fir_unrealize(DeviceState *dev, Error **errp)
+{
+    PXA2xxFIrState *s = PXA2XX_FIR(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
 {
     PXA2xxFIrState *s = opaque;
@@ -2013,6 +2024,7 @@ static void pxa2xx_fir_class_init(ObjectClass *klass, 
void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = pxa2xx_fir_realize;
+    dc->unrealize = pxa2xx_fir_unrealize;
     dc->vmsd = &pxa2xx_fir_vmsd;
     dc->props = pxa2xx_fir_properties;
     dc->reset = pxa2xx_fir_reset;
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 021cbf9..48b4a7c 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -913,6 +913,7 @@ typedef struct StrongARMUARTState {
 
     MemoryRegion iomem;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     uint8_t utcr0;
@@ -1240,7 +1241,8 @@ static void strongarm_uart_init(Object *obj)
     s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr,
                         strongarm_uart_can_receive,
                         strongarm_uart_receive,
                         strongarm_uart_event,
@@ -1248,6 +1250,20 @@ static void strongarm_uart_init(Object *obj)
     }
 }
 
+static void strongarm_uart_finalize(Object *obj)
+{
+    StrongARMUARTState *s = STRONGARM_UART(obj);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+
+    timer_del(s->tx_timer);
+    timer_free(s->tx_timer);
+    timer_del(s->rx_timeout_timer);
+    timer_free(s->rx_timeout_timer);
+}
+
 static void strongarm_uart_reset(DeviceState *dev)
 {
     StrongARMUARTState *s = STRONGARM_UART(dev);
@@ -1327,6 +1343,7 @@ static const TypeInfo strongarm_uart_info = {
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(StrongARMUARTState),
     .instance_init = strongarm_uart_init,
+    .instance_finalize = strongarm_uart_finalize,
     .class_init    = strongarm_uart_class_init,
 };
 
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index f7a845d..5694c32 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -283,11 +283,21 @@ static void bcm2835_aux_realize(DeviceState *dev, Error 
**errp)
     BCM2835AuxState *s = BCM2835_AUX(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
                               bcm2835_aux_receive, NULL, s);
     }
 }
 
+static void bcm2835_aux_unrealize(DeviceState *dev, Error **errp)
+{
+    BCM2835AuxState *s = BCM2835_AUX(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static Property bcm2835_aux_props[] = {
     DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr),
     DEFINE_PROP_END_OF_LIST(),
@@ -298,6 +308,7 @@ static void bcm2835_aux_class_init(ObjectClass *oc, void 
*data)
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     dc->realize = bcm2835_aux_realize;
+    dc->unrealize = bcm2835_aux_unrealize;
     dc->vmsd = &vmstate_bcm2835_aux;
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
     dc->props = bcm2835_aux_props;
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index e3bc52f..7ca8f0a 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -475,11 +475,24 @@ static void cadence_uart_realize(DeviceState *dev, Error 
**errp)
                                           fifo_trigger_update, s);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
                               uart_event, s);
     }
 }
 
+static void cadence_uart_unrealize(DeviceState *dev, Error **errp)
+{
+    CadenceUARTState *s = CADENCE_UART(dev);
+
+    timer_del(s->fifo_trigger_handle);
+    timer_free(s->fifo_trigger_handle);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static void cadence_uart_init(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
@@ -530,6 +543,7 @@ static void cadence_uart_class_init(ObjectClass *klass, 
void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = cadence_uart_realize;
+    dc->unrealize = cadence_uart_unrealize;
     dc->vmsd = &vmstate_cadence_uart;
     dc->reset = cadence_uart_reset;
     dc->props = cadence_uart_properties;
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 4402033..45876a7 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -40,6 +40,7 @@
 typedef struct DebugconState {
     MemoryRegion io;
     CharDriverState *chr;
+    int chr_tag;
     uint32_t readback;
 } DebugconState;
 
@@ -85,34 +86,34 @@ static const MemoryRegionOps debugcon_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void debugcon_realize_core(DebugconState *s, Error **errp)
-{
-    if (!s->chr) {
-        error_setg(errp, "Can't create debugcon device, empty char device");
-        return;
-    }
-
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
-}
-
 static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
 {
     ISADevice *d = ISA_DEVICE(dev);
     ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
     DebugconState *s = &isa->state;
-    Error *err = NULL;
 
-    debugcon_realize_core(s, &err);
-    if (err != NULL) {
-        error_propagate(errp, err);
+    if (!s->chr) {
+        error_setg(errp, "Can't create debugcon device, empty char device");
         return;
     }
+
+    /* necessary to start the be */
+    s->chr_tag = qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+
     memory_region_init_io(&s->io, OBJECT(dev), &debugcon_ops, s,
                           TYPE_ISA_DEBUGCON_DEVICE, 1);
     memory_region_add_subregion(isa_address_space_io(d),
                                 isa->iobase, &s->io);
 }
 
+static void debugcon_isa_unrealizefn(DeviceState *dev, Error **errp)
+{
+    ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
+    DebugconState *s = &isa->state;
+
+    qemu_chr_remove_handlers(s->chr, s->chr_tag);
+}
+
 static Property debugcon_isa_properties[] = {
     DEFINE_PROP_UINT32("iobase", ISADebugconState, iobase, 0xe9),
     DEFINE_PROP_CHR("chardev",  ISADebugconState, state.chr),
@@ -125,6 +126,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, 
void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = debugcon_isa_realizefn;
+    dc->unrealize = debugcon_isa_unrealizefn;
     dc->props = debugcon_isa_properties;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 }
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index e96a9b2..83217a4 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -148,7 +148,17 @@ static void digic_uart_realize(DeviceState *dev, Error 
**errp)
     DigicUartState *s = DIGIC_UART(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+}
+
+static void digic_uart_unrealize(DeviceState *dev, Error **errp)
+{
+    DigicUartState *s = DIGIC_UART(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
     }
 }
 
@@ -182,6 +192,7 @@ static void digic_uart_class_init(ObjectClass *klass, void 
*data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = digic_uart_realize;
+    dc->unrealize = digic_uart_unrealize;
     dc->reset = digic_uart_reset;
     dc->vmsd = &vmstate_digic_uart;
     dc->props = digic_uart_properties;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index aa17397..0cbaf27 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -89,6 +89,7 @@ typedef struct ChannelState {
     uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
     SERIOQueue queue;
     CharDriverState *chr;
+    int chr_tag;
     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
     int disabled;
     int clock;
@@ -1015,7 +1016,8 @@ static void escc_realize(DeviceState *dev, Error **errp)
     for (i = 0; i < 2; i++) {
         if (s->chn[i].chr) {
             s->chn[i].clock = s->frequency / 2;
-            qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+            s->chn[i].chr_tag =
+                qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
                                   serial_receive1, serial_event, &s->chn[i]);
         }
     }
@@ -1030,6 +1032,18 @@ static void escc_realize(DeviceState *dev, Error **errp)
     }
 }
 
+static void escc_unrealize(DeviceState *dev, Error **errp)
+{
+    ESCCState *s = ESCC(dev);
+    unsigned int i;
+
+    for (i = 0; i < 2; i++) {
+        if (s->chn[i].chr) {
+            qemu_chr_remove_handlers(s->chn[i].chr, s->chn[i].chr_tag);
+        }
+    }
+}
+
 static Property escc_properties[] = {
     DEFINE_PROP_UINT32("frequency", ESCCState, frequency,   0),
     DEFINE_PROP_UINT32("it_shift",  ESCCState, it_shift,    0),
@@ -1047,6 +1061,7 @@ static void escc_class_init(ObjectClass *klass, void 
*data)
 
     dc->reset = escc_reset;
     dc->realize = escc_realize;
+    dc->unrealize = escc_unrealize;
     dc->vmsd = &vmstate_escc;
     dc->props = escc_properties;
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index c99cc5d..e606a76 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -54,6 +54,7 @@ typedef struct ETRAXSerial {
 
     MemoryRegion mmio;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     int pending_tx;
@@ -232,12 +233,22 @@ static void etraxfs_ser_realize(DeviceState *dev, Error 
**errp)
     ETRAXSerial *s = ETRAX_SERIAL(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr,
                               serial_can_receive, serial_receive,
                               serial_event, s);
     }
 }
 
+static void etraxfs_ser_unrealize(DeviceState *dev, Error **errp)
+{
+    ETRAXSerial *s = ETRAX_SERIAL(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -245,6 +256,7 @@ static void etraxfs_ser_class_init(ObjectClass *klass, void 
*data)
     dc->reset = etraxfs_ser_reset;
     dc->props = etraxfs_ser_properties;
     dc->realize = etraxfs_ser_realize;
+    dc->unrealize = etraxfs_ser_unrealize;
 }
 
 static const TypeInfo etraxfs_ser_info = {
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 1107578..ba84a4f 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -182,6 +182,7 @@ typedef struct Exynos4210UartState {
     Exynos4210UartFIFO   tx;
 
     CharDriverState  *chr;
+    int chr_tag;
     qemu_irq          irq;
 
     uint32_t channel;
@@ -640,12 +641,20 @@ static int exynos4210_uart_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
+    s->chr_tag =
+        qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
                           exynos4210_uart_receive, exynos4210_uart_event, s);
 
     return 0;
 }
 
+static void exynos4210_uart_unrealize(DeviceState *dev, Error **errp)
+{
+    Exynos4210UartState *s = EXYNOS4210_UART(dev);
+
+    qemu_chr_remove_handlers(s->chr, s->chr_tag);
+}
+
 static Property exynos4210_uart_properties[] = {
     DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
     DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
@@ -663,6 +672,7 @@ static void exynos4210_uart_class_init(ObjectClass *klass, 
void *data)
     dc->reset = exynos4210_uart_reset;
     dc->props = exynos4210_uart_properties;
     dc->vmsd = &vmstate_exynos4210_uart;
+    dc->unrealize = exynos4210_uart_unrealize;
 }
 
 static const TypeInfo exynos4210_uart_info = {
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 778148a..963ca6d 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -79,6 +79,7 @@ typedef struct UART {
     qemu_irq irq;
 
     CharDriverState *chr;
+    int chr_tag;
 
     /* registers */
     uint32_t status;
@@ -242,7 +243,8 @@ static int grlib_apbuart_init(SysBusDevice *dev)
 {
     UART *uart = GRLIB_APB_UART(dev);
 
-    qemu_chr_add_handlers(uart->chr,
+    uart->chr_tag =
+        qemu_chr_add_handlers(uart->chr,
                           grlib_apbuart_can_receive,
                           grlib_apbuart_receive,
                           grlib_apbuart_event,
@@ -271,6 +273,15 @@ static void grlib_apbuart_reset(DeviceState *d)
     uart->current = 0;
 }
 
+static void grlib_apbuart_unrealize(DeviceState *d, Error **errp)
+{
+    UART *uart = GRLIB_APB_UART(d);
+
+    if (uart->chr) {
+        qemu_chr_remove_handlers(uart->chr, uart->chr_tag);
+    }
+}
+
 static Property grlib_apbuart_properties[] = {
     DEFINE_PROP_CHR("chrdev", UART, chr),
     DEFINE_PROP_END_OF_LIST(),
@@ -284,6 +295,7 @@ static void grlib_apbuart_class_init(ObjectClass *klass, 
void *data)
     k->init = grlib_apbuart_init;
     dc->reset = grlib_apbuart_reset;
     dc->props = grlib_apbuart_properties;
+    dc->unrealize = grlib_apbuart_unrealize;
 }
 
 static const TypeInfo grlib_apbuart_info = {
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 5c3fa61..5ac3122 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -319,13 +319,23 @@ static void imx_serial_realize(DeviceState *dev, Error 
**errp)
     IMXSerialState *s = IMX_SERIAL(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
-                              imx_event, s);
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+                                  imx_event, s);
     } else {
         DPRINTF("No char dev for uart\n");
     }
 }
 
+static void imx_serial_unrealize(DeviceState *dev, Error **errp)
+{
+    IMXSerialState *s = IMX_SERIAL(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static void imx_serial_init(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
@@ -347,6 +357,7 @@ static void imx_serial_class_init(ObjectClass *klass, void 
*data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = imx_serial_realize;
+    dc->unrealize = imx_serial_unrealize;
     dc->vmsd = &vmstate_imx_serial;
     dc->reset = imx_serial_reset_at_boot;
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 2859fdd..4adc500 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -94,6 +94,7 @@ typedef struct SCC2698Block SCC2698Block;
 struct SCC2698Channel {
     IPOctalState *ipoctal;
     CharDriverState *dev;
+    int chr_tag;
     bool rx_enabled;
     uint8_t mr[2];
     uint8_t mr_idx;
@@ -547,7 +548,7 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
 
         /* Redirect IP-Octal channels to host character devices */
         if (ch->dev) {
-            qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
+            ch->chr_tag = qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
                                   hostdev_receive, hostdev_event, ch);
             DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
         } else {
@@ -556,6 +557,20 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
     }
 }
 
+static void ipoctal_unrealize(DeviceState *dev, Error **errp)
+{
+    IPOctalState *s = IPOCTAL(dev);
+    unsigned i;
+
+    for (i = 0; i < N_CHANNELS; i++) {
+        SCC2698Channel *ch = &s->ch[i];
+
+        if (ch->dev) {
+            qemu_chr_remove_handlers(ch->dev, ch->chr_tag);
+        }
+    }
+}
+
 static Property ipoctal_properties[] = {
     DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
     DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
@@ -574,6 +589,7 @@ static void ipoctal_class_init(ObjectClass *klass, void 
*data)
     IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
 
     ic->realize     = ipoctal_realize;
+    ic->unrealize   = ipoctal_unrealize;
     ic->io_read     = io_read;
     ic->io_write    = io_write;
     ic->id_read     = id_read;
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index cb1ac76..065195d 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -45,6 +45,7 @@ struct LM32JuartState {
     SysBusDevice parent_obj;
 
     CharDriverState *chr;
+    int chr_tag;
 
     uint32_t jtx;
     uint32_t jrx;
@@ -121,7 +122,17 @@ static void lm32_juart_realize(DeviceState *dev, Error 
**errp)
     LM32JuartState *s = LM32_JUART(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+        s->chr_tag = qemu_chr_add_handlers(s->chr, juart_can_rx,
+                                           juart_rx, juart_event, s);
+    }
+}
+
+static void lm32_juart_unrealize(DeviceState *dev, Error **errp)
+{
+    LM32JuartState *s = LM32_JUART(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
     }
 }
 
@@ -149,6 +160,7 @@ static void lm32_juart_class_init(ObjectClass *klass, void 
*data)
     dc->vmsd = &vmstate_lm32_juart;
     dc->props = lm32_juart_properties;
     dc->realize = lm32_juart_realize;
+    dc->unrealize = lm32_juart_unrealize;
 }
 
 static const TypeInfo lm32_juart_info = {
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index be93697..c94cf19 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -98,6 +98,7 @@ struct LM32UartState {
 
     MemoryRegion iomem;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
@@ -268,7 +269,17 @@ static void lm32_uart_realize(DeviceState *dev, Error 
**errp)
     LM32UartState *s = LM32_UART(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+}
+
+static void lm32_uart_unrealize(DeviceState *dev, Error **errp)
+{
+    LM32UartState *s = LM32_UART(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
     }
 }
 
@@ -295,6 +306,7 @@ static void lm32_uart_class_init(ObjectClass *klass, void 
*data)
     dc->vmsd = &vmstate_lm32_uart;
     dc->props = lm32_uart_properties;
     dc->realize = lm32_uart_realize;
+    dc->unrealize = lm32_uart_unrealize;
 }
 
 static const TypeInfo lm32_uart_info = {
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index c184859..7a677c7 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -27,6 +27,7 @@ typedef struct {
     int rx_enabled;
     qemu_irq irq;
     CharDriverState *chr;
+    int chr_tag;
 } mcf_uart_state;
 
 /* UART Status Register bits.  */
@@ -284,7 +285,8 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
     s->irq = irq;
     if (chr) {
         qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+        s->chr_tag =
+            qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
                               mcf_uart_event, s);
     }
     mcf_uart_reset(s);
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index baddb37..0203512 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -62,6 +62,7 @@ struct MilkymistUartState {
 
     MemoryRegion regs_region;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
@@ -201,7 +202,17 @@ static void milkymist_uart_realize(DeviceState *dev, Error 
**errp)
     MilkymistUartState *s = MILKYMIST_UART(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+}
+
+static void milkymist_uart_unrealize(DeviceState *dev, Error **errp)
+{
+    MilkymistUartState *s = MILKYMIST_UART(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
     }
 }
 
@@ -237,6 +248,7 @@ static void milkymist_uart_class_init(ObjectClass *klass, 
void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = milkymist_uart_realize;
+    dc->unrealize = milkymist_uart_unrealize;
     dc->reset = milkymist_uart_reset;
     dc->vmsd = &vmstate_milkymist_uart;
     dc->props = milkymist_uart_properties;
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 786e605..903c044 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -36,6 +36,7 @@ typedef struct PL011State {
     int read_count;
     int read_trigger;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
     const unsigned char *id;
 } PL011State;
@@ -303,16 +304,27 @@ static void pl011_realize(DeviceState *dev, Error **errp)
     PL011State *s = PL011(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
                               pl011_event, s);
     }
 }
 
+static void pl011_unrealize(DeviceState *dev, Error **errp)
+{
+    PL011State *s = PL011(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static void pl011_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     dc->realize = pl011_realize;
+    dc->unrealize = pl011_unrealize;
     dc->vmsd = &vmstate_pl011;
     dc->props = pl011_properties;
 }
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 9a56326..7c76d9e 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -38,6 +38,7 @@ typedef struct OprtnsCommand {
 typedef struct SCLPConsoleLM {
     SCLPEvent event;
     CharDriverState *chr;
+    int chr_tag;
     bool echo;                  /* immediate echo of input if true        */
     uint32_t write_errors;      /* errors writing to char layer           */
     uint32_t length;            /* length of byte stream in buffer        */
@@ -313,7 +314,9 @@ static int console_init(SCLPEvent *event)
     console_available = true;
 
     if (scon->chr) {
-        qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
+        scon->chr_tag =
+            qemu_chr_add_handlers(scon->chr, chr_can_read,
+                                  chr_read, NULL, scon);
     }
 
     return 0;
@@ -321,6 +324,12 @@ static int console_init(SCLPEvent *event)
 
 static int console_exit(SCLPEvent *event)
 {
+    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
+
+    if (scon->chr) {
+        qemu_chr_remove_handlers(scon->chr, scon->chr_tag);
+    }
+
     return 0;
 }
 
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index a75ad4f..cf0b309 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -32,6 +32,7 @@ typedef struct ASCIIConsoleData {
 typedef struct SCLPConsole {
     SCLPEvent event;
     CharDriverState *chr;
+    int chr_tag;
     uint8_t iov[SIZE_BUFFER_VT220];
     uint32_t iov_sclp;      /* offset in buf for SCLP read operation       */
     uint32_t iov_bs;        /* offset in buf for char layer read operation */
@@ -228,7 +229,8 @@ static int console_init(SCLPEvent *event)
     }
     console_available = true;
     if (scon->chr) {
-        qemu_chr_add_handlers(scon->chr, chr_can_read,
+        scon->chr_tag =
+            qemu_chr_add_handlers(scon->chr, chr_can_read,
                               chr_read, NULL, scon);
     }
 
@@ -250,6 +252,11 @@ static void console_reset(DeviceState *dev)
 
 static int console_exit(SCLPEvent *event)
 {
+    SCLPConsole *scon = SCLP_CONSOLE(event);
+
+    if (scon->chr) {
+        qemu_chr_remove_handlers(scon->chr, scon->chr_tag);
+    }
     return 0;
 }
 
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 3442f47..9d7d57b 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -893,8 +893,9 @@ void serial_realize_core(SerialState *s, Error **errp)
     s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) 
fifo_timeout_int, s);
     qemu_register_reset(serial_reset, s);
 
-    qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
-                          serial_event, s);
+    s->chr_tag =
+        qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+                              serial_event, s);
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
     serial_reset(s);
@@ -902,7 +903,9 @@ void serial_realize_core(SerialState *s, Error **errp)
 
 void serial_exit_core(SerialState *s)
 {
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+    qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    s->chr_tag = -1;
+
     qemu_unregister_reset(serial_reset, s);
 }
 
@@ -933,6 +936,7 @@ SerialState *serial_init(int base, qemu_irq irq, int 
baudbase,
     s->irq = irq;
     s->baudbase = baudbase;
     s->chr = chr;
+    s->chr_tag = -1;
     serial_realize_core(s, &error_fatal);
 
     vmstate_register(NULL, base, &vmstate_serial, s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 97ce562..e093689 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -398,9 +398,13 @@ void sh_serial_init(MemoryRegion *sysmem,
     s->chr = chr;
 
     if (chr) {
+        int tag;
+
         qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
-                             sh_serial_event, s);
+        tag = qemu_chr_add_handlers(chr, sh_serial_can_receive1,
+                                    sh_serial_receive1,
+                                    sh_serial_event, s);
+        assert(tag != -1);
     }
 
     s->eri = eri_source;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 9aeafc0..fdc32e3 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -12,6 +12,7 @@
 typedef struct VIOsPAPRVTYDevice {
     VIOsPAPRDevice sdev;
     CharDriverState *chardev;
+    int chr_tag;
     uint32_t in, out;
     uint8_t buf[VTERM_BUFSIZE];
 } VIOsPAPRVTYDevice;
@@ -74,10 +75,20 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error 
**errp)
         return;
     }
 
-    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+    dev->chr_tag =
+        qemu_chr_add_handlers(dev->chardev, vty_can_receive,
                           vty_receive, NULL, dev);
 }
 
+static void spapr_vty_unrealize(DeviceState *s, Error **errp)
+{
+    VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(s);
+
+    if (dev->chardev) {
+        qemu_chr_remove_handlers(dev->chardev, dev->chr_tag);
+    }
+}
+
 /* Forward declaration */
 static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                                     target_ulong opcode, target_ulong *args)
@@ -173,6 +184,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void 
*data)
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
     dc->props = spapr_vty_properties;
     dc->vmsd = &vmstate_spapr_vty;
+    dc->unrealize = spapr_vty_unrealize;
 }
 
 static const TypeInfo spapr_vty_info = {
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 4c6640d..9f8aac5 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -213,11 +213,21 @@ static void stm32f2xx_usart_realize(DeviceState *dev, 
Error **errp)
     STM32F2XXUsartState *s = STM32F2XX_USART(dev);
 
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
                               stm32f2xx_usart_receive, NULL, s);
     }
 }
 
+static void stm32f2xx_usart_unrealize(DeviceState *dev, Error **errp)
+{
+    STM32F2XXUsartState *s = STM32F2XX_USART(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
+}
+
 static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -225,6 +235,7 @@ static void stm32f2xx_usart_class_init(ObjectClass *klass, 
void *data)
     dc->reset = stm32f2xx_usart_reset;
     dc->props = stm32f2xx_usart_properties;
     dc->realize = stm32f2xx_usart_realize;
+    dc->unrealize = stm32f2xx_usart_unrealize;
 }
 
 static const TypeInfo stm32f2xx_usart_info = {
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index d44c18c..f3f3aa3 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -25,6 +25,7 @@ typedef struct VirtConsole {
     VirtIOSerialPort parent_obj;
 
     CharDriverState *chr;
+    int chr_tag;
     guint watch;
 } VirtConsole;
 
@@ -189,12 +190,14 @@ static void virtconsole_realize(DeviceState *dev, Error 
**errp)
          */
         if (k->is_console) {
             vcon->chr->explicit_fe_open = 0;
-            qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
+            vcon->chr_tag =
+                qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
                                   NULL, vcon);
             virtio_serial_open(port);
         } else {
             vcon->chr->explicit_fe_open = 1;
-            qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
+            vcon->chr_tag =
+                qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
                                   chr_event, vcon);
         }
     }
@@ -207,6 +210,9 @@ static void virtconsole_unrealize(DeviceState *dev, Error 
**errp)
     if (vcon->watch) {
         g_source_remove(vcon->watch);
     }
+    if (vcon->chr) {
+        qemu_chr_remove_handlers(vcon->chr, vcon->chr_tag);
+    }
 }
 
 static void virtconsole_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 83108b0..f263dfa 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -44,6 +44,7 @@ struct XenConsole {
     int               ring_ref;
     void              *sring;
     CharDriverState   *chr;
+    int               chr_tag;
     int               backlog;
 };
 
@@ -237,8 +238,9 @@ static int con_initialise(struct XenDevice *xendev)
     xen_be_bind_evtchn(&con->xendev);
     if (con->chr) {
         if (qemu_chr_fe_claim(con->chr) == 0) {
-            qemu_chr_add_handlers(con->chr, xencons_can_receive,
-                                  xencons_receive, NULL, con);
+            con->chr_tag =
+                qemu_chr_add_handlers(con->chr, xencons_can_receive,
+                                      xencons_receive, NULL, con);
         } else {
             xen_be_printf(xendev, 0,
                           "xen_console_init error chardev %s already used\n",
@@ -260,7 +262,7 @@ static void con_disconnect(struct XenDevice *xendev)
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
 
     if (con->chr) {
-        qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(con->chr, con->chr_tag);
         qemu_chr_fe_release(con->chr);
     }
     xen_be_unbind_evtchn(&con->xendev);
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 3766dc2..e6b103e 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -56,6 +56,7 @@ typedef struct XilinxUARTLite {
 
     MemoryRegion mmio;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     uint8_t rx_fifo[8];
@@ -213,8 +214,19 @@ static void xilinx_uartlite_realize(DeviceState *dev, 
Error **errp)
 {
     XilinxUARTLite *s = XILINX_UARTLITE(dev);
 
-    if (s->chr)
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    if (s->chr) {
+        s->chr_tag =
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+}
+
+static void xilinx_uartlite_unrealize(DeviceState *dev, Error **errp)
+{
+    XilinxUARTLite *s = XILINX_UARTLITE(dev);
+
+    if (s->chr) {
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
+    }
 }
 
 static void xilinx_uartlite_init(Object *obj)
@@ -234,6 +246,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, 
void *data)
 
     dc->reset = xilinx_uartlite_reset;
     dc->realize = xilinx_uartlite_realize;
+    dc->unrealize = xilinx_uartlite_unrealize;
     dc->props = xilinx_uartlite_properties;
 }
 
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index d93e3f3..927bed2 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -63,6 +63,7 @@ typedef struct IPMIBmcExtern {
     IPMIBmc parent;
 
     CharDriverState *chr;
+    int chr_tag;
 
     bool connected;
 
@@ -447,7 +448,17 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, 
Error **errp)
         return;
     }
 
-    qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe);
+    ibe->chr_tag =
+        qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe);
+}
+
+static void ipmi_bmc_extern_unrealize(DeviceState *dev, Error **errp)
+{
+    IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
+
+    if (ibe->chr) {
+        qemu_chr_remove_handlers(ibe->chr, ibe->chr_tag);
+    }
 }
 
 static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
@@ -512,6 +523,7 @@ static void ipmi_bmc_extern_class_init(ObjectClass *oc, 
void *data)
     bk->handle_command = ipmi_bmc_extern_handle_command;
     bk->handle_reset = ipmi_bmc_extern_handle_reset;
     dc->realize = ipmi_bmc_extern_realize;
+    dc->unrealize = ipmi_bmc_extern_unrealize;
     dc->props = ipmi_bmc_extern_properties;
 }
 
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index f803dfd..19079f4 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -89,6 +89,7 @@ typedef struct IVShmemState {
     /* exactly one of these two may be set */
     HostMemoryBackend *hostmem; /* with interrupts */
     CharDriverState *server_chr; /* without interrupts */
+    int server_chr_tag;
 
     /* registers */
     uint32_t intrmask;
@@ -841,6 +842,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error 
**errp)
     uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
         PCI_BASE_ADDRESS_MEM_PREFETCH;
 
+    s->server_chr_tag = -1;
+
     /* IRQFD requires MSI */
     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
         !ivshmem_has_feature(s, IVSHMEM_MSI)) {
@@ -893,8 +896,9 @@ static void ivshmem_common_realize(PCIDevice *dev, Error 
**errp)
             return;
         }
 
-        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
-                              ivshmem_read, NULL, s);
+        s->server_chr_tag =
+            qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
+                                  ivshmem_read, NULL, s);
 
         if (ivshmem_setup_interrupts(s) < 0) {
             error_setg(errp, "failed to initialize interrupts");
@@ -955,6 +959,10 @@ static void ivshmem_exit(PCIDevice *dev)
     }
 
     g_free(s->msi_vectors);
+
+    if (s->server_chr) {
+        qemu_chr_remove_handlers(s->server_chr, s->server_chr_tag);
+    }
 }
 
 static int ivshmem_pre_load(void *opaque)
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 2eacea7..8960972 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -49,6 +49,7 @@ typedef struct PassthruState PassthruState;
 struct PassthruState {
     CCIDCardState base;
     CharDriverState *cs;
+    int chr_tag;
     uint8_t  vscard_in_data[VSCARD_IN_SIZE];
     uint32_t vscard_in_pos;
     uint32_t vscard_in_hdr;
@@ -347,7 +348,7 @@ static int passthru_initfn(CCIDCardState *base)
     card->vscard_in_hdr = 0;
     if (card->cs) {
         DPRINTF(card, D_INFO, "initing chardev\n");
-        qemu_chr_add_handlers(card->cs,
+        card->chr_tag = qemu_chr_add_handlers(card->cs,
             ccid_card_vscard_can_read,
             ccid_card_vscard_read,
             ccid_card_vscard_event, card);
@@ -366,6 +367,12 @@ static int passthru_initfn(CCIDCardState *base)
 
 static int passthru_exitfn(CCIDCardState *base)
 {
+    PassthruState *card = PASSTHRU_CCID_CARD(base);
+
+    if (card->cs) {
+        qemu_chr_remove_handlers(card->cs, card->chr_tag);
+    }
+
     return 0;
 }
 
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 966ad84..4dcfc68 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -104,6 +104,7 @@ typedef struct {
     QEMUSerialSetParams params;
     int latency;        /* ms */
     CharDriverState *cs;
+    int chr_tag;
 } USBSerialState;
 
 #define TYPE_USB_SERIAL "usb-serial-dev"
@@ -499,8 +500,9 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
         return;
     }
 
-    qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
-                          usb_serial_event, s);
+    s->chr_tag =
+        qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
+                              usb_serial_event, s);
     usb_serial_handle_reset(dev);
 
     if (s->cs->be_open && !dev->attached) {
@@ -508,6 +510,15 @@ static void usb_serial_realize(USBDevice *dev, Error 
**errp)
     }
 }
 
+static void usb_serial_unrealize(USBDevice *dev, Error **errp)
+{
+    USBSerialState *s = USB_SERIAL_DEV(dev);
+
+    if (s->cs) {
+        qemu_chr_remove_handlers(s->cs, s->chr_tag);
+    }
+}
+
 static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
 {
     USBDevice *dev;
@@ -590,6 +601,7 @@ static void usb_serial_dev_class_init(ObjectClass *klass, 
void *data)
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
     uc->realize        = usb_serial_realize;
+    uc->unrealize      = usb_serial_unrealize;
     uc->handle_reset   = usb_serial_handle_reset;
     uc->handle_control = usb_serial_handle_control;
     uc->handle_data    = usb_serial_handle_data;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index d4ca026..7d73c93 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -106,6 +106,7 @@ struct USBRedirDevice {
     USBDevice dev;
     /* Properties */
     CharDriverState *cs;
+    int chr_tag;
     uint8_t debug;
     char *filter_str;
     int32_t bootindex;
@@ -1375,6 +1376,7 @@ static void usbredir_realize(USBDevice *udev, Error 
**errp)
     USBRedirDevice *dev = USB_REDIRECT(udev);
     int i;
 
+    dev->chr_tag = -1;
     if (dev->cs == NULL) {
         error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
         return;
@@ -1406,12 +1408,20 @@ static void usbredir_realize(USBDevice *udev, Error 
**errp)
     dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
 
     /* Let the backend know we are ready */
-    qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
+    dev->chr_tag =
+        qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
                           usbredir_chardev_read, usbredir_chardev_event, dev);
 
     qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
 }
 
+static void usbredir_unrealize(USBDevice *udev, Error **errp)
+{
+    USBRedirDevice *dev = USB_REDIRECT(udev);
+
+    qemu_chr_remove_handlers(dev->cs, dev->chr_tag);
+}
+
 static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
 {
     int i;
@@ -2493,6 +2503,7 @@ static void usbredir_class_initfn(ObjectClass *klass, 
void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     uc->realize        = usbredir_realize;
+    uc->unrealize      = usbredir_unrealize;
     uc->product_desc   = "USB Redirection Device";
     uc->handle_destroy = usbredir_handle_destroy;
     uc->cancel_packet  = usbredir_cancel_packet;
diff --git a/monitor.c b/monitor.c
index 8728dd9..0d6f0ad 100644
--- a/monitor.c
+++ b/monitor.c
@@ -187,6 +187,7 @@ typedef struct {
 
 struct Monitor {
     CharDriverState *chr;
+    int chr_tag;
     int reset_seen;
     int flags;
     int suspend_cnt;
@@ -582,7 +583,7 @@ static void monitor_data_init(Monitor *mon)
 static void monitor_data_destroy(Monitor *mon)
 {
     if (mon->chr) {
-        qemu_chr_add_handlers(mon->chr, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(mon->chr, mon->chr_tag);
     }
     if (monitor_is_qmp(mon)) {
         json_message_parser_destroy(&mon->qmp.parser);
@@ -3988,13 +3989,15 @@ void monitor_init(CharDriverState *chr, int flags)
     }
 
     if (monitor_is_qmp(mon)) {
-        qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
-                              monitor_qmp_event, mon);
+        mon->chr_tag =
+            qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
+                                  monitor_qmp_event, mon);
         qemu_chr_fe_set_echo(chr, true);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
     } else {
-        qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
-                              monitor_event, mon);
+        mon->chr_tag =
+            qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
+                                  monitor_event, mon);
     }
 
     qemu_mutex_lock(&monitor_lock);
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 47703c5..88582c8 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -70,6 +70,8 @@ typedef struct CompareState {
     char *outdev;
     CharDriverState *chr_pri_in;
     CharDriverState *chr_sec_in;
+    int chr_pri_tag;
+    int chr_sec_tag;
     CharDriverState *chr_out;
     SocketReadState pri_rs;
     SocketReadState sec_rs;
@@ -451,7 +453,8 @@ static void compare_pri_chr_in(void *opaque, const uint8_t 
*buf, int size)
 
     ret = net_fill_rstate(&s->pri_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_pri_in, s->chr_pri_tag);
+        s->chr_pri_tag = -1;
         error_report("colo-compare primary_in error");
     }
 }
@@ -467,7 +470,8 @@ static void compare_sec_chr_in(void *opaque, const uint8_t 
*buf, int size)
 
     ret = net_fill_rstate(&s->sec_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_sec_in, s->chr_sec_tag);
+        s->chr_sec_tag = -1;
         error_report("colo-compare secondary_in error");
     }
 }
@@ -480,10 +484,12 @@ static void *colo_compare_thread(void *opaque)
 
     worker_context = g_main_context_new();
 
-    qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read,
-                          compare_pri_chr_in, NULL, s, worker_context);
-    qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read,
-                          compare_sec_chr_in, NULL, s, worker_context);
+    s->chr_pri_tag =
+        qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read,
+                                   compare_pri_chr_in, NULL, s, 
worker_context);
+    s->chr_sec_tag =
+        qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read,
+                                   compare_sec_chr_in, NULL, s, 
worker_context);
 
     compare_loop = g_main_loop_new(worker_context, FALSE);
 
@@ -703,11 +709,11 @@ static void colo_compare_finalize(Object *obj)
     CompareState *s = COLO_COMPARE(obj);
 
     if (s->chr_pri_in) {
-        qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_pri_in, s->chr_pri_tag);
         qemu_chr_fe_release(s->chr_pri_in);
     }
     if (s->chr_sec_in) {
-        qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_sec_in, s->chr_sec_tag);
         qemu_chr_fe_release(s->chr_sec_in);
     }
     if (s->chr_out) {
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 0ee58d9..8c1d613 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -39,6 +39,7 @@ typedef struct MirrorState {
     char *indev;
     char *outdev;
     CharDriverState *chr_in;
+    int chr_in_tag;
     CharDriverState *chr_out;
     SocketReadState rs;
 } MirrorState;
@@ -110,7 +111,8 @@ static void redirector_chr_read(void *opaque, const uint8_t 
*buf, int size)
     ret = net_fill_rstate(&s->rs, buf, size);
 
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_in, s->chr_in_tag);
+        s->chr_in_tag = -1;
     }
 }
 
@@ -121,7 +123,8 @@ static void redirector_chr_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_CLOSED:
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_in, s->chr_in_tag);
+        s->chr_in_tag = -1;
         break;
     default:
         break;
@@ -185,7 +188,8 @@ static void filter_redirector_cleanup(NetFilterState *nf)
     MirrorState *s = FILTER_REDIRECTOR(nf);
 
     if (s->chr_in) {
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr_in, s->chr_in_tag);
+        s->chr_in_tag = -1;
         qemu_chr_fe_release(s->chr_in);
     }
     if (s->chr_out) {
@@ -228,6 +232,7 @@ static void filter_redirector_setup(NetFilterState *nf, 
Error **errp)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
 
+    s->chr_in_tag = -1;
     if (!s->indev && !s->outdev) {
         error_setg(errp, "filter redirector needs 'indev' or "
                    "'outdev' at least one property set");
@@ -251,7 +256,8 @@ static void filter_redirector_setup(NetFilterState *nf, 
Error **errp)
         }
 
         qemu_chr_fe_claim_no_fail(s->chr_in);
-        qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read,
+        s->chr_in_tag =
+            qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read,
                               redirector_chr_read, redirector_chr_event, nf);
     }
 
diff --git a/net/slirp.c b/net/slirp.c
index b60893f..80eefb0 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -683,6 +683,7 @@ int net_slirp_smb(const char *exported_dir)
 
 struct GuestFwd {
     CharDriverState *hd;
+    int chr_tag;
     struct in_addr server;
     int port;
     Slirp *slirp;
@@ -765,8 +766,9 @@ static int slirp_guestfwd(SlirpState *s, const char 
*config_str,
         fwd->slirp = s->slirp;
 
         qemu_chr_fe_claim_no_fail(fwd->hd);
-        qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
-                              NULL, fwd);
+        fwd->chr_tag =
+            qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
+                                  NULL, fwd);
     }
     return 0;
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 5b94c84..f3cf623 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -21,6 +21,7 @@
 typedef struct VhostUserState {
     NetClientState nc;
     CharDriverState *chr;
+    int chr_tag;
     VHostNetState *vhost_net;
     guint watch;
     uint64_t acked_features;
@@ -151,7 +152,7 @@ static void vhost_user_cleanup(NetClientState *nc)
         s->vhost_net = NULL;
     }
     if (s->chr) {
-        qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+        qemu_chr_remove_handlers(s->chr, s->chr_tag);
         qemu_chr_fe_release(s->chr);
         s->chr = NULL;
     }
@@ -258,14 +259,15 @@ static int net_vhost_user_init(NetClientState *peer, 
const char *device,
     }
 
     s = DO_UPCAST(VhostUserState, nc, nc0);
+    s->chr_tag =
+        qemu_chr_add_handlers(chr, NULL, NULL,
+                              net_vhost_user_event, nc0->name);
     do {
         Error *err = NULL;
         if (qemu_chr_wait_connected(chr, &err) < 0) {
             error_report_err(err);
             return -1;
         }
-        qemu_chr_add_handlers(chr, NULL, NULL,
-                              net_vhost_user_event, nc0->name);
     } while (!s->started);
 
     assert(s->vhost_net);
diff --git a/qemu-char.c b/qemu-char.c
index a7fec6a..261a8f9 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -569,6 +569,7 @@ struct MuxDriver {
     CharDriverState *drv;
     int focus;
     int mux_cnt;
+    int mux_tag;
     int term_got_escape;
     int max_size;
     /* Intermediate input buffer allows to catch escape sequences even if the
@@ -850,8 +851,8 @@ static int mux_chr_new_handler_tag(CharDriverState *chr, 
GMainContext *context)
     }
 
     /* Fix up the real driver with mux routines */
-    if (d->mux_cnt == 0) {
-        qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
+    if (d->mux_tag == -1) {
+        d->mux_tag = qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
                                                 mux_chr_read,
                                                 mux_chr_event,
                                                 chr, context);
@@ -897,6 +898,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
     chr->opaque = d;
     d->drv = drv;
     d->focus = -1;
+    d->mux_tag = -1;
     chr->chr_close = mux_chr_close;
     chr->chr_write = mux_chr_write;
     chr->chr_update_read_handler = mux_chr_update_read_handler;
diff --git a/qtest.c b/qtest.c
index 22482cc..73e07c2 100644
--- a/qtest.c
+++ b/qtest.c
@@ -39,6 +39,7 @@ bool qtest_allowed;
 static DeviceState *irq_intercept_dev;
 static FILE *qtest_log_fp;
 static CharDriverState *qtest_chr;
+static int qtest_chr_tag;
 static GString *inbuf;
 static int irq_levels[MAX_IRQ];
 static qemu_timeval start_time;
@@ -679,7 +680,8 @@ void qtest_init(const char *qtest_chrdev, const char 
*qtest_log, Error **errp)
         qtest_log_fp = stderr;
     }
 
-    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
+    qtest_chr_tag =
+        qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, 
chr);
     qemu_chr_fe_set_echo(chr, true);
 
     inbuf = g_string_new("");
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index d7c48c5..133cbdc 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -142,6 +142,7 @@ typedef struct TestServer {
     gchar *mig_path;
     gchar *chr_name;
     CharDriverState *chr;
+    int chr_tag;
     int fds_num;
     int fds[VHOST_MEMORY_MAX_NREGIONS];
     VhostUserMemory memory;
@@ -458,8 +459,9 @@ static void test_server_create_chr(TestServer *server, 
const gchar *opt)
     server->chr = qemu_chr_new(server->chr_name, chr_path, NULL);
     g_free(chr_path);
 
-    qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
-                          chr_event, server);
+    server->chr_tag =
+        qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
+                              chr_event, server);
 }
 
 static void test_server_listen(TestServer *server)
@@ -484,6 +486,7 @@ static gboolean _test_server_free(TestServer *server)
 {
     int i;
 
+    qemu_chr_remove_handlers(server->chr, server->chr_tag);
     qemu_chr_delete(server->chr);
 
     for (i = 0; i < server->fds_num; i++) {
diff --git a/include/hw/char/bcm2835_aux.h b/include/hw/char/bcm2835_aux.h
index 42f0ee7..c55886e 100644
--- a/include/hw/char/bcm2835_aux.h
+++ b/include/hw/char/bcm2835_aux.h
@@ -23,6 +23,7 @@ typedef struct {
 
     MemoryRegion iomem;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 
     uint8_t read_fifo[BCM2835_AUX_RX_FIFO_LEN];
diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h
index a12773c..e510d15 100644
--- a/include/hw/char/cadence_uart.h
+++ b/include/hw/char/cadence_uart.h
@@ -45,6 +45,7 @@ typedef struct {
     uint32_t tx_count;
     uint64_t char_tx_time;
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
     QEMUTimer *fifo_trigger_handle;
 } CadenceUARTState;
diff --git a/include/hw/char/digic-uart.h b/include/hw/char/digic-uart.h
index 7b3f145..160bf03 100644
--- a/include/hw/char/digic-uart.h
+++ b/include/hw/char/digic-uart.h
@@ -38,6 +38,7 @@ typedef struct DigicUartState {
 
     MemoryRegion regs_region;
     CharDriverState *chr;
+    int chr_tag;
 
     uint32_t reg_rx;
     uint32_t reg_st;
diff --git a/include/hw/char/imx_serial.h b/include/hw/char/imx_serial.h
index 6cd75c0..cbf5859 100644
--- a/include/hw/char/imx_serial.h
+++ b/include/hw/char/imx_serial.h
@@ -97,6 +97,7 @@ typedef struct IMXSerialState {
 
     qemu_irq irq;
     CharDriverState *chr;
+    int chr_tag;
 } IMXSerialState;
 
 #endif
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index a4fd3d5..0ec91ea 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -53,6 +53,7 @@ struct SerialState {
     int thr_ipending;
     qemu_irq irq;
     CharDriverState *chr;
+    int chr_tag;
     int last_break_enable;
     int it_shift;
     int baudbase;
diff --git a/include/hw/char/stm32f2xx_usart.h 
b/include/hw/char/stm32f2xx_usart.h
index b97f192..d9be1c0 100644
--- a/include/hw/char/stm32f2xx_usart.h
+++ b/include/hw/char/stm32f2xx_usart.h
@@ -68,6 +68,7 @@ typedef struct {
     uint32_t usart_gtpr;
 
     CharDriverState *chr;
+    int chr_tag;
     qemu_irq irq;
 } STM32F2XXUsartState;
 #endif /* HW_STM32F2XX_USART_H */
-- 
2.10.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]