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 <marcandre.lur...@redhat.com> --- 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