static void filter_redirector_setup(NetFilterState *nf, Error **errp) { MirrorState *s = FILTER_REDIRECTOR(nf); Chardev *chr; if (!s->indev && !s->outdev) { error_setg(errp, "filter redirector needs 'indev' or " "'outdev' at least one property set"); return; } else if (s->indev && s->outdev) { if (!strcmp(s->indev, s->outdev)) { error_setg(errp, "'indev' and 'outdev' could not be same " "for filter redirector"); return; } } net_socket_rs_init(&s->rs, redirector_rs_finalize); if (s->indev) { chr = qemu_chr_find(s->indev); if (chr == NULL) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "IN Device '%s' not found", s->indev); return; } if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) { return; } qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read, redirector_chr_read, redirector_chr_event, nf, NULL, true); } if (s->outdev) { chr = qemu_chr_find(s->outdev); if (chr == NULL) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "OUT Device '%s' not found", s->outdev); return; } if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) { return; } } }
/* * Called from the main thread on the primary * to setup colo-compare. */ static void colo_compare_complete(UserCreatable *uc, Error **errp) { CompareState *s = COLO_COMPARE(uc); Chardev *chr; if (!s->pri_indev || !s->sec_indev || !s->outdev || !s->iothread) { error_setg(errp, "colo compare needs 'primary_in' ," "'secondary_in','outdev','iothread' property set"); return; } else if (!strcmp(s->pri_indev, s->outdev) || !strcmp(s->sec_indev, s->outdev) || !strcmp(s->pri_indev, s->sec_indev)) { error_setg(errp, "'indev' and 'outdev' could not be same " "for compare module"); return; } if (find_and_check_chardev(&chr, s->pri_indev, errp) || !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) { return; } if (find_and_check_chardev(&chr, s->sec_indev, errp) || !qemu_chr_fe_init(&s->chr_sec_in, chr, errp)) { return; } if (find_and_check_chardev(&chr, s->outdev, errp) || !qemu_chr_fe_init(&s->chr_out, chr, errp)) { return; } net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr); g_queue_init(&s->conn_list); s->connection_track_table = g_hash_table_new_full(connection_key_hash, connection_key_equal, g_free, connection_destroy); colo_compare_iothread(s); return; }
static int con_init(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); char *type, *dom, label[32]; int ret = 0; const char *output; /* setup */ dom = xs_get_domain_path(xenstore, con->xendev.dom); if (!xendev->dev) { snprintf(con->console, sizeof(con->console), "%s/console", dom); } else { snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); } free(dom); type = xenstore_read_str(con->console, "type"); if (!type || strcmp(type, "ioemu") != 0) { xen_pv_printf(xendev, 1, "not for me (type=%s)\n", type); ret = -1; goto out; } output = xenstore_read_str(con->console, "output"); /* no Xen override, use qemu output device */ if (output == NULL) { if (con->xendev.dev) { qemu_chr_fe_init(&con->chr, serial_hds[con->xendev.dev], &error_abort); } } else { snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); qemu_chr_fe_init(&con->chr, qemu_chr_new(label, output), &error_abort); } xenstore_store_pv_console_info(con->xendev.dev, qemu_chr_fe_get_driver(&con->chr)); out: g_free(type); return ret; }
static void test_server_create_chr(TestServer *server, const gchar *opt) { gchar *chr_path; Chardev *chr; chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); chr = qemu_chr_new(server->chr_name, chr_path); g_free(chr_path); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, chr_event, NULL, server, NULL, true); }
/* * Create UART device. */ SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base, Chardev *chr, qemu_irq irq) { SiFiveUARTState *s = g_malloc0(sizeof(SiFiveUARTState)); s->irq = irq; qemu_chr_fe_init(&s->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event, uart_be_change, s, NULL, true); memory_region_init_io(&s->mmio, NULL, &uart_ops, s, TYPE_SIFIVE_UART, SIFIVE_UART_MAX); memory_region_add_subregion(address_space, base, &s->mmio); return s; }
static void filter_mirror_setup(NetFilterState *nf, Error **errp) { MirrorState *s = FILTER_MIRROR(nf); Chardev *chr; chr = qemu_chr_find(s->outdev); if (chr == NULL) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", s->outdev); return; } qemu_chr_fe_init(&s->chr_out, chr, errp); }
static void char_ringbuf_test(void) { QemuOpts *opts; Chardev *chr; CharBackend be; char *data; int ret; opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); qemu_opt_set(opts, "size", "5", &error_abort); chr = qemu_chr_new_from_opts(opts, NULL); g_assert_null(chr); qemu_opts_del(opts); opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); qemu_opt_set(opts, "size", "2", &error_abort); chr = qemu_chr_new_from_opts(opts, &error_abort); g_assert_nonnull(chr); qemu_opts_del(opts); qemu_chr_fe_init(&be, chr, &error_abort); ret = qemu_chr_fe_write(&be, (void *)"buff", 4); g_assert_cmpint(ret, ==, 4); data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort); g_assert_cmpstr(data, ==, "ff"); g_free(data); data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort); g_assert_cmpstr(data, ==, ""); g_free(data); qemu_chr_fe_deinit(&be, true); /* check alias */ opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label", 1, &error_abort); qemu_opt_set(opts, "backend", "memory", &error_abort); qemu_opt_set(opts, "size", "2", &error_abort); chr = qemu_chr_new_from_opts(opts, NULL); g_assert_nonnull(chr); object_unparent(OBJECT(chr)); qemu_opts_del(opts); }
static void char_stdio_test_subprocess(void) { Chardev *chr; CharBackend be; int ret; chr = qemu_chr_new("label", "stdio"); g_assert_nonnull(chr); qemu_chr_fe_init(&be, chr, &error_abort); qemu_chr_fe_set_open(&be, true); ret = qemu_chr_fe_write(&be, (void *)"buf", 4); g_assert_cmpint(ret, ==, 4); qemu_chr_fe_deinit(&be, true); }
/* If fd is zero, it means that the parallel device uses the console */ bool parallel_mm_init(MemoryRegion *address_space, hwaddr base, int it_shift, qemu_irq irq, Chardev *chr) { ParallelState *s; s = g_malloc0(sizeof(ParallelState)); s->irq = irq; qemu_chr_fe_init(&s->chr, chr, &error_abort); s->it_shift = it_shift; qemu_register_reset(parallel_reset, s); memory_region_init_io(&s->iomem, NULL, ¶llel_mm_ops, s, "parallel", 8 << it_shift); memory_region_add_subregion(address_space, base, &s->iomem); return true; }
static int net_vhost_user_init(NetClientState *peer, const char *device, const char *name, Chardev *chr, int queues) { Error *err = NULL; NetClientState *nc, *nc0 = NULL; VhostUserState *s; int i; assert(name); assert(queues > 0); for (i = 0; i < queues; i++) { nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", i, chr->label); nc->queue_index = i; if (!nc0) { nc0 = nc; s = DO_UPCAST(VhostUserState, nc, nc); if (!qemu_chr_fe_init(&s->chr, chr, &err)) { error_report_err(err); return -1; } } } s = DO_UPCAST(VhostUserState, nc, nc0); do { if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) { error_report_err(err); return -1; } qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, NULL, nc0->name, NULL, true); } while (!s->started); assert(s->vhost_net); return 0; }
static void qemu_chr_open_mux(Chardev *chr, ChardevBackend *backend, bool *be_opened, Error **errp) { ChardevMux *mux = backend->u.mux.data; Chardev *drv; MuxChardev *d = MUX_CHARDEV(chr); drv = qemu_chr_find(mux->chardev); if (drv == NULL) { error_setg(errp, "mux: base chardev %s not found", mux->chardev); return; } d->focus = -1; /* only default to opened state if we've realized the initial * set of muxes */ *be_opened = machine_init_done; qemu_chr_fe_init(&d->chr, drv, errp); }
static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { DeviceState *dev = DEVICE(obj); Error *local_err = NULL; Property *prop = opaque; CharBackend *be = qdev_get_prop_ptr(dev, prop); CharDriverState *s; char *str; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); return; } visit_type_str(v, name, &str, &local_err); if (local_err) { error_propagate(errp, local_err); return; } if (!*str) { g_free(str); be->chr = NULL; return; } s = qemu_chr_find(str); if (s == NULL) { error_setg(errp, "Property '%s.%s' can't find value '%s'", object_get_typename(obj), prop->name, str); } else if (!qemu_chr_fe_init(be, s, errp)) { error_prepend(errp, "Property '%s.%s' can't take value '%s': ", object_get_typename(obj), prop->name, str); } g_free(str); }
static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) { const char *value; value = qemu_opt_get(opts, "chardev"); if (value) { Error *err = NULL; Chardev *dev = qemu_chr_find(value); if (!dev) { error_report("tpm-emulator: tpm chardev '%s' not found.", value); goto err; } if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", value); error_report_err(err); goto err; } tpm_emu->options->chardev = g_strdup(value); } if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { goto err; } /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used * by passthrough driver, which not yet using GIOChannel. */ if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, &tpm_emu->tpm_version)) { error_report("'%s' is not emulating TPM device. Error: %s", tpm_emu->options->chardev, strerror(errno)); goto err; } switch (tpm_emu->tpm_version) { case TPM_VERSION_1_2: trace_tpm_emulator_handle_device_opts_tpm12(); break; case TPM_VERSION_2_0: trace_tpm_emulator_handle_device_opts_tpm2(); break; default: trace_tpm_emulator_handle_device_opts_unspec(); } if (tpm_emulator_probe_caps(tpm_emu) || tpm_emulator_check_caps(tpm_emu)) { goto err; } return tpm_emulator_block_migration(tpm_emu); err: trace_tpm_emulator_handle_device_opts_startup_error(); return -1; }
static void boston_mach_init(MachineState *machine) { DeviceState *dev; BostonState *s; Error *err = NULL; const char *cpu_model; MemoryRegion *flash, *ddr, *ddr_low_alias, *lcd, *platreg; MemoryRegion *sys_mem = get_system_memory(); XilinxPCIEHost *pcie2; PCIDevice *ahci; DriveInfo *hd[6]; Chardev *chr; int fw_size, fit_err; bool is_64b; if ((machine->ram_size % G_BYTE) || (machine->ram_size > (2 * G_BYTE))) { error_report("Memory size must be 1GB or 2GB"); exit(1); } cpu_model = machine->cpu_model ?: "I6400"; dev = qdev_create(NULL, TYPE_MIPS_BOSTON); qdev_init_nofail(dev); s = BOSTON(dev); s->mach = machine; s->cps = g_new0(MIPSCPSState, 1); if (!cpu_supports_cps_smp(cpu_model)) { error_report("Boston requires CPUs which support CPS"); exit(1); } is_64b = cpu_supports_isa(cpu_model, ISA_MIPS64); object_initialize(s->cps, sizeof(MIPSCPSState), TYPE_MIPS_CPS); qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default()); object_property_set_str(OBJECT(s->cps), cpu_model, "cpu-model", &err); object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err); object_property_set_bool(OBJECT(s->cps), true, "realized", &err); if (err != NULL) { error_report("%s", error_get_pretty(err)); exit(1); } sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1); flash = g_new(MemoryRegion, 1); memory_region_init_rom_device(flash, NULL, &boston_flash_ops, s, "boston.flash", 128 * M_BYTE, &err); memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0); ddr = g_new(MemoryRegion, 1); memory_region_allocate_system_memory(ddr, NULL, "boston.ddr", machine->ram_size); memory_region_add_subregion_overlap(sys_mem, 0x80000000, ddr, 0); ddr_low_alias = g_new(MemoryRegion, 1); memory_region_init_alias(ddr_low_alias, NULL, "boston_low.ddr", ddr, 0, MIN(machine->ram_size, (256 * M_BYTE))); memory_region_add_subregion_overlap(sys_mem, 0, ddr_low_alias, 0); xilinx_pcie_init(sys_mem, 0, 0x10000000, 32 * M_BYTE, 0x40000000, 1 * G_BYTE, get_cps_irq(s->cps, 2), false); xilinx_pcie_init(sys_mem, 1, 0x12000000, 32 * M_BYTE, 0x20000000, 512 * M_BYTE, get_cps_irq(s->cps, 1), false); pcie2 = xilinx_pcie_init(sys_mem, 2, 0x14000000, 32 * M_BYTE, 0x16000000, 1 * M_BYTE, get_cps_irq(s->cps, 0), true); platreg = g_new(MemoryRegion, 1); memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, "boston-platregs", 0x1000); memory_region_add_subregion_overlap(sys_mem, 0x17ffd000, platreg, 0); if (!serial_hds[0]) { serial_hds[0] = qemu_chr_new("serial0", "null"); } s->uart = serial_mm_init(sys_mem, 0x17ffe000, 2, get_cps_irq(s->cps, 3), 10000000, serial_hds[0], DEVICE_NATIVE_ENDIAN); lcd = g_new(MemoryRegion, 1); memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8); memory_region_add_subregion_overlap(sys_mem, 0x17fff000, lcd, 0); chr = qemu_chr_new("lcd", "vc:320x240"); qemu_chr_fe_init(&s->lcd_display, chr, NULL); qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL, boston_lcd_event, s, NULL, true); ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, PCI_DEVFN(0, 0), true, TYPE_ICH9_AHCI); g_assert(ARRAY_SIZE(hd) == ICH_AHCI(ahci)->ahci.ports); ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); ahci_ide_create_devs(ahci, hd); if (machine->firmware) { fw_size = load_image_targphys(machine->firmware, 0x1fc00000, 4 * M_BYTE); if (fw_size == -1) { error_printf("unable to load firmware image '%s'\n", machine->firmware); exit(1); } } else if (machine->kernel_filename) { fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s); if (fit_err) { error_printf("unable to load FIT image\n"); exit(1); } gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000, s->kernel_entry, s->fdt_base, is_64b); } else if (!qtest_enabled()) { error_printf("Please provide either a -kernel or -bios argument\n"); exit(1); } }
static void char_mux_test(void) { QemuOpts *opts; Chardev *chr, *base; char *data; FeHandler h1 = { 0, }, h2 = { 0, }; CharBackend chr_be1, chr_be2; opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); qemu_opt_set(opts, "size", "128", &error_abort); qemu_opt_set(opts, "mux", "on", &error_abort); chr = qemu_chr_new_from_opts(opts, &error_abort); g_assert_nonnull(chr); qemu_opts_del(opts); qemu_chr_fe_init(&chr_be1, chr, &error_abort); qemu_chr_fe_set_handlers(&chr_be1, fe_can_read, fe_read, fe_event, NULL, &h1, NULL, true); qemu_chr_fe_init(&chr_be2, chr, &error_abort); qemu_chr_fe_set_handlers(&chr_be2, fe_can_read, fe_read, fe_event, NULL, &h2, NULL, true); qemu_chr_fe_take_focus(&chr_be2); base = qemu_chr_find("mux-label-base"); g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 6); g_assert_cmpstr(h2.read_buf, ==, "hello"); h2.read_count = 0; /* switch focus */ qemu_chr_be_write(base, (void *)"\1c", 2); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h2.read_count, ==, 0); g_assert_cmpint(h1.read_count, ==, 6); g_assert_cmpstr(h1.read_buf, ==, "hello"); h1.read_count = 0; /* remove first handler */ qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, NULL, true); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 0); qemu_chr_be_write(base, (void *)"\1c", 2); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 6); g_assert_cmpstr(h2.read_buf, ==, "hello"); h2.read_count = 0; /* print help */ qemu_chr_be_write(base, (void *)"\1?", 2); data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort); g_assert_cmpint(strlen(data), !=, 0); g_free(data); qemu_chr_fe_deinit(&chr_be1, false); qemu_chr_fe_deinit(&chr_be2, true); }
static void char_mux_test(void) { QemuOpts *opts; Chardev *chr, *base; char *data; FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, }; CharBackend chr_be1, chr_be2; opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); qemu_opt_set(opts, "size", "128", &error_abort); qemu_opt_set(opts, "mux", "on", &error_abort); chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); g_assert_nonnull(chr); qemu_opts_del(opts); qemu_chr_fe_init(&chr_be1, chr, &error_abort); qemu_chr_fe_set_handlers(&chr_be1, fe_can_read, fe_read, fe_event, NULL, &h1, NULL, true); qemu_chr_fe_init(&chr_be2, chr, &error_abort); qemu_chr_fe_set_handlers(&chr_be2, fe_can_read, fe_read, fe_event, NULL, &h2, NULL, true); qemu_chr_fe_take_focus(&chr_be2); base = qemu_chr_find("mux-label-base"); g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 6); g_assert_cmpstr(h2.read_buf, ==, "hello"); h2.read_count = 0; g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */ g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */ /* sending event on the base broadcast to all fe, historical reasons? */ qemu_chr_be_event(base, 42); g_assert_cmpint(h1.last_event, ==, 42); g_assert_cmpint(h2.last_event, ==, 42); qemu_chr_be_event(chr, -1); g_assert_cmpint(h1.last_event, ==, 42); g_assert_cmpint(h2.last_event, ==, -1); /* switch focus */ qemu_chr_be_write(base, (void *)"\1b", 2); g_assert_cmpint(h1.last_event, ==, 42); g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK); qemu_chr_be_write(base, (void *)"\1c", 2); g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN); g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); qemu_chr_be_event(chr, -1); g_assert_cmpint(h1.last_event, ==, -1); g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h2.read_count, ==, 0); g_assert_cmpint(h1.read_count, ==, 6); g_assert_cmpstr(h1.read_buf, ==, "hello"); h1.read_count = 0; qemu_chr_be_write(base, (void *)"\1b", 2); g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK); g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); /* open/close state and corresponding events */ g_assert_true(qemu_chr_fe_backend_open(&chr_be1)); g_assert_true(qemu_chr_fe_backend_open(&chr_be2)); g_assert_true(h1.is_open); g_assert_false(h1.openclose_mismatch); g_assert_true(h2.is_open); g_assert_false(h2.openclose_mismatch); h1.openclose_count = h2.openclose_count = 0; qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, NULL, false); qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL, NULL, NULL, false); g_assert_cmpint(h1.openclose_count, ==, 0); g_assert_cmpint(h2.openclose_count, ==, 0); h1.is_open = h2.is_open = false; qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, fe_event, NULL, &h1, NULL, false); qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, fe_event, NULL, &h2, NULL, false); g_assert_cmpint(h1.openclose_count, ==, 1); g_assert_false(h1.openclose_mismatch); g_assert_cmpint(h2.openclose_count, ==, 1); g_assert_false(h2.openclose_mismatch); qemu_chr_be_event(base, CHR_EVENT_CLOSED); qemu_chr_be_event(base, CHR_EVENT_OPENED); g_assert_cmpint(h1.openclose_count, ==, 3); g_assert_false(h1.openclose_mismatch); g_assert_cmpint(h2.openclose_count, ==, 3); g_assert_false(h2.openclose_mismatch); qemu_chr_fe_set_handlers(&chr_be2, fe_can_read, fe_read, fe_event, NULL, &h2, NULL, false); qemu_chr_fe_set_handlers(&chr_be1, fe_can_read, fe_read, fe_event, NULL, &h1, NULL, false); /* remove first handler */ qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, NULL, true); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 0); qemu_chr_be_write(base, (void *)"\1c", 2); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h1.read_count, ==, 0); g_assert_cmpint(h2.read_count, ==, 6); g_assert_cmpstr(h2.read_buf, ==, "hello"); h2.read_count = 0; /* print help */ qemu_chr_be_write(base, (void *)"\1?", 2); data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort); g_assert_cmpint(strlen(data), !=, 0); g_free(data); qemu_chr_fe_deinit(&chr_be1, false); qemu_chr_fe_deinit(&chr_be2, true); }