示例#1
0
文件: pmc_sbi.c 项目: Xilinx/qemu
static void ss_stream_out(SlaveBootInt *s)
{
    uint8_t *data;
    uint32_t len;

    if (!DEP_AF_EX32(s->regs, SBI_MODE, SELECT)) {
        return;
    }

    /*FIXME: Impement JTAG, AXI interface */
    while (!s->cs && s->rdwr) {
        if (IF_BURST(s->fifo.num)) {
            data = (uint8_t *) fifo_pop_buf(&s->fifo,
                        SMAP_BURST_SIZE(s),
                        &len);
            qemu_chr_fe_write(&s->chr, data, len);
        }

        if (IF_NON_BURST(s->fifo.num)) {
            data = (uint8_t *) fifo_pop_buf(&s->fifo, 4, &len);
            qemu_chr_fe_write(&s->chr, data, len);
        }

        ss_update_busy_line(s);
        if (s->busy_line) {
            break;
        }
    }
}
示例#2
0
static void ccid_card_vscard_send_msg(PassthruState *s,
        VSCMsgType type, uint32_t reader_id,
        const uint8_t *payload, uint32_t length)
{
    VSCMsgHeader scr_msg_header;

    scr_msg_header.type = htonl(type);
    scr_msg_header.reader_id = htonl(reader_id);
    scr_msg_header.length = htonl(length);
    qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
    qemu_chr_fe_write(s->cs, payload, length);
}
示例#3
0
static void
uart_write(void *opaque, hwaddr addr,
           uint64_t val64, unsigned int size)
{
    SiFiveUARTState *s = opaque;
    uint32_t value = val64;
    unsigned char ch = value;

    switch (addr) {
    case SIFIVE_UART_TXFIFO:
        qemu_chr_fe_write(&s->chr, &ch, 1);
        update_irq(s);
        return;
    case SIFIVE_UART_IE:
        s->ie = val64;
        update_irq(s);
        return;
    case SIFIVE_UART_TXCTRL:
        s->txctrl = val64;
        return;
    case SIFIVE_UART_RXCTRL:
        s->rxctrl = val64;
        return;
    case SIFIVE_UART_DIV:
        s->div = val64;
        return;
    }
    hw_error("%s: bad write: addr=0x%x v=0x%x\n",
        __func__, (int)addr, (int)value);
}
示例#4
0
文件: rng-egd.c 项目: sibiaoluo/qemu
static void rng_egd_request_entropy(RngBackend *b, size_t size,
                                    EntropyReceiveFunc *receive_entropy,
                                    void *opaque)
{
    RngEgd *s = RNG_EGD(b);
    RngRequest *req;

    req = g_malloc(sizeof(*req));

    req->offset = 0;
    req->size = size;
    req->receive_entropy = receive_entropy;
    req->opaque = opaque;
    req->data = g_malloc(req->size);

    while (size > 0) {
        uint8_t header[2];
        uint8_t len = MIN(size, 255);

        /* synchronous entropy request */
        header[0] = 0x02;
        header[1] = len;

        qemu_chr_fe_write(s->chr, header, sizeof(header));

        size -= len;
    }

    s->requests = g_slist_append(s->requests, req);
}
示例#5
0
static void uart_write(void *opaque, hwaddr addr,
                       uint64_t val64, unsigned int size)
{
    AlteraUART *s = opaque;
    uint32_t value = val64;
    unsigned char ch = value;

    addr >>= 2;
    addr &= 0x7;

    switch (addr) {
    case R_TXDATA:
        if (s->chr) {
            qemu_chr_fe_write(s->chr, &ch, 1);
        }

        s->regs[addr] = value;
        break;

    case R_RXDATA:
    case R_STATUS:
        /* No writeable bits */
        break;

    default:
        s->regs[addr] = value;
        break;
    }
    uart_update_irq(s);
}
示例#6
0
static void
ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
    struct etrax_serial *s = opaque;
    unsigned char ch = value;
    D(CPUState *env = s->env);

    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
    addr >>= 2;
    switch (addr)
    {
        case RW_DOUT:
            qemu_chr_fe_write(s->chr, &ch, 1);
            s->regs[R_INTR] |= 3;
            s->pending_tx = 1;
            s->regs[addr] = value;
            break;
        case RW_ACK_INTR:
            if (s->pending_tx) {
                value &= ~1;
                s->pending_tx = 0;
                D(qemu_log("fixedup value=%x r_intr=%x\n",
                           value, s->regs[R_INTR]));
            }
            s->regs[addr] = value;
            s->regs[R_INTR] &= ~value;
            D(printf("r_intr=%x\n", s->regs[R_INTR]));
            break;
        default:
            s->regs[addr] = value;
            break;
    }
    ser_update_irq(s);
}
示例#7
0
static void
ser_write(void *opaque, hwaddr addr,
          uint64_t val64, unsigned int size)
{
    ETRAXSerial *s = opaque;
    uint32_t value = val64;
    unsigned char ch = val64;

    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
    addr >>= 2;
    switch (addr)
    {
        case RW_DOUT:
            qemu_chr_fe_write(s->chr, &ch, 1);
            s->regs[R_INTR] |= 3;
            s->pending_tx = 1;
            s->regs[addr] = value;
            break;
        case RW_ACK_INTR:
            if (s->pending_tx) {
                value &= ~1;
                s->pending_tx = 0;
                D(qemu_log("fixedup value=%x r_intr=%x\n",
                           value, s->regs[R_INTR]));
            }
            s->regs[addr] = value;
            s->regs[R_INTR] &= ~value;
            D(printf("r_intr=%x\n", s->regs[R_INTR]));
            break;
        default:
            s->regs[addr] = value;
            break;
    }
    ser_update_irq(s);
}
示例#8
0
/*
 * Triggered by SCLP's write_event_data
 *  - write console data to character layer
 *  returns < 0 if an error occurred
 */
static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
{
    int ret = 0;
    const uint8_t *buf_offset;

    SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);

    if (!scon->chr) {
        /* If there's no backend, we can just say we consumed all data. */
        return len;
    }

    buf_offset = buf;
    while (len > 0) {
        ret = qemu_chr_fe_write(scon->chr, buf, len);
        if (ret == 0) {
            /* a pty doesn't seem to be connected - no error */
            len = 0;
        } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
            len -= ret;
            buf_offset += ret;
        } else {
            len = 0;
        }
    }

    return ret;
}
示例#9
0
static void uart_write(void *opaque, target_phys_addr_t addr, uint64_t value,
                       unsigned size)
{
    MilkymistUartState *s = opaque;
    unsigned char ch = value;

    trace_milkymist_uart_memory_write(addr, value);

    addr >>= 2;
    switch (addr) {
    case R_RXTX:
        if (s->chr) {
            qemu_chr_fe_write(s->chr, &ch, 1);
        }
        s->regs[R_STAT] |= STAT_TX_EVT;
        break;
    case R_DIV:
    case R_CTRL:
    case R_DBG:
        s->regs[addr] = value;
        break;

    case R_STAT:
        /* write one to clear bits */
        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
        break;

    default:
        error_report("milkymist_uart: write access to unknown register 0x"
                TARGET_FMT_plx, addr << 2);
        break;
    }

    uart_update_irq(s);
}
示例#10
0
static void
grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
                    uint64_t value, unsigned size)
{
    UART          *uart = opaque;
    unsigned char  c    = 0;

    addr &= 0xff;

    /* Unit registers */
    switch (addr) {
    case DATA_OFFSET:
        c = value & 0xFF;
        qemu_chr_fe_write(uart->chr, &c, 1);
        return;

    case STATUS_OFFSET:
        /* Read Only */
        return;

    case CONTROL_OFFSET:
        /* Not supported */
        return;

    case SCALER_OFFSET:
        /* Not supported */
        return;

    default:
        break;
    }

    trace_grlib_apbuart_writel_unknown(addr, value);
}
示例#11
0
static int rdmacm_mux_send(RdmaBackendDev *backend_dev, RdmaCmMuxMsg *msg)
{
    int rc = 0;

    msg->hdr.msg_type = RDMACM_MUX_MSG_TYPE_REQ;
    trace_rdmacm_mux("send", msg->hdr.msg_type, msg->hdr.op_code);
    disable_rdmacm_mux_async(backend_dev);
    rc = qemu_chr_fe_write(backend_dev->rdmacm_mux.chr_be,
                           (const uint8_t *)msg, sizeof(*msg));
    if (rc != sizeof(*msg)) {
        enable_rdmacm_mux_async(backend_dev);
        rdma_error_report("Failed to send request to rdmacm_mux (rc=%d)", rc);
        return -EIO;
    }

    rc = rdmacm_mux_check_op_status(backend_dev->rdmacm_mux.chr_be);
    if (rc) {
        rdma_error_report("Failed to execute rdmacm_mux request %d (rc=%d)",
                          msg->hdr.op_code, rc);
    }

    enable_rdmacm_mux_async(backend_dev);

    return 0;
}
示例#12
0
/* Callback function that's called when the guest sends us data */
static ssize_t flush_buf(VirtIOSerialPort *port,
                         const uint8_t *buf, ssize_t len)
{
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
    ssize_t ret;

    if (!vcon->chr) {
        /* If there's no backend, we can just say we consumed all data. */
        return len;
    }

    ret = qemu_chr_fe_write(vcon->chr, buf, len);
    trace_virtio_console_flush_buf(port->id, len, ret);

    if (ret < len) {
        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);

        /*
         * Ideally we'd get a better error code than just -1, but
         * that's what the chardev interface gives us right now.  If
         * we had a finer-grained message, like -EPIPE, we could close
         * this connection.
         */
        if (ret < 0)
            ret = 0;
        if (!k->is_console) {
            virtio_serial_throttle_port(port, true);
            if (!vcon->watch) {
                vcon->watch = qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT,
                                                    chr_write_unblocked, vcon);
            }
        }
    }
    return ret;
}
示例#13
0
文件: xen_console.c 项目: 8tab/qemu
static void xencons_send(struct XenConsole *con)
{
    ssize_t len, size;

    size = con->buffer.size - con->buffer.consumed;
    if (qemu_chr_fe_backend_connected(&con->chr)) {
        len = qemu_chr_fe_write(&con->chr,
                                con->buffer.data + con->buffer.consumed,
                                size);
    } else {
        len = size;
    }
    if (len < 1) {
        if (!con->backlog) {
            con->backlog = 1;
            xen_pv_printf(&con->xendev, 1,
                          "backlog piling up, nobody listening?\n");
        }
    } else {
        buffer_advance(&con->buffer, len);
        if (con->backlog && len == size) {
            con->backlog = 0;
            xen_pv_printf(&con->xendev, 1, "backlog is gone\n");
        }
    }
}
示例#14
0
static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
                                  void *opaque)
{
    UartState *s = opaque;
    int ret;

    /* instant drain the fifo when there's no back-end */
    if (!s->chr) {
        s->tx_count = 0;
    }

    if (!s->tx_count) {
        return FALSE;
    }

    ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count);
    s->tx_count -= ret;
    memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count);

    if (s->tx_count) {
        int r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT, cadence_uart_xmit, s);
        assert(r);
    }

    uart_update_status(s);
    return FALSE;
}
示例#15
0
static void uart_write(void *opaque, hwaddr addr,
                       uint64_t value, unsigned size)
{
    LM32UartState *s = opaque;
    unsigned char ch = value;

    trace_lm32_uart_memory_write(addr, value);

    addr >>= 2;
    switch (addr) {
    case R_RXTX:
        if (s->chr) {
            qemu_chr_fe_write(s->chr, &ch, 1);
        }
        break;
    case R_IER:
    case R_LCR:
    case R_MCR:
    case R_DIV:
        s->regs[addr] = value;
        break;
    case R_IIR:
    case R_LSR:
    case R_MSR:
        error_report("lm32_uart: write access to read only register 0x"
                TARGET_FMT_plx, addr << 2);
        break;
    default:
        error_report("lm32_uart: write access to unknown register 0x"
                TARGET_FMT_plx, addr << 2);
        break;
    }
    uart_update_irq(s);
}
示例#16
0
/* Callback function that's called when the guest sends us data */
static ssize_t flush_buf(VirtIOSerialPort *port,
                         const uint8_t *buf, ssize_t len)
{
    VirtConsole *vcon = VIRTIO_CONSOLE(port);
    ssize_t ret;

    if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
        /* If there's no backend, we can just say we consumed all data. */
        return len;
    }

    ret = qemu_chr_fe_write(&vcon->chr, buf, len);
    trace_virtio_console_flush_buf(port->id, len, ret);

    if (ret < len) {
        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);

        /*
         * Ideally we'd get a better error code than just -1, but
         * that's what the chardev interface gives us right now.  If
         * we had a finer-grained message, like -EPIPE, we could close
         * this connection.
         */
        if (ret < 0)
            ret = 0;

        /* XXX we should be queuing data to send later for the
         * console devices too rather than silently dropping
         * console data on EAGAIN. The Linux virtio-console
         * hvc driver though does sends with spinlocks held,
         * so if we enable throttling that'll stall the entire
         * guest kernel, not merely the process writing to the
         * console.
         *
         * While we could queue data for later write without
         * enabling throttling, this would result in the guest
         * being able to trigger arbitrary memory usage in QEMU
         * buffering data for later writes.
         *
         * So fixing this problem likely requires fixing the
         * Linux virtio-console hvc driver to not hold spinlocks
         * while writing, and instead merely block the process
         * that's writing. QEMU would then need some way to detect
         * if the guest had the fixed driver too, before we can
         * use throttling on host side.
         */
        if (!k->is_console) {
            virtio_serial_throttle_port(port, true);
            if (!vcon->watch) {
                vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
                                                    G_IO_OUT|G_IO_HUP,
                                                    chr_write_unblocked, vcon);
            }
        }
    }
    return ret;
}
示例#17
0
static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
{
    if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
        return;
    }

    while (size) {
        size -= qemu_chr_fe_write(s->chr, buf, size);
    }
}
示例#18
0
文件: stm32_led.c 项目: xatier/stlink
/*
 * Appelé quand une entrée de led reçoit une IT
 */
static void stm32_led_recvirq(void * opaque, int numPin, int level) {
    // the LED change state
    printf("La LED change d'état->%d\n", level);
    stm32_led_state *s = (stm32_led_state *) opaque;
    
    if(s->chr) {
        uint8_t buffer = (uint8_t)level;
        qemu_chr_fe_write(s->chr, &buffer, 1);
    }
}
示例#19
0
文件: test-char.c 项目: 8tab/qemu
static void socket_read(void *opaque, const uint8_t *buf, int size)
{
    SocketIdleData *data = opaque;

    g_assert_cmpint(size, ==, 1);
    g_assert_cmpint(*buf, ==, 'Z');

    size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
    g_assert_cmpint(size, ==, 5);
}
示例#20
0
/* Called with chr_write_lock held.  */
static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
    MuxChardev *d = MUX_CHARDEV(chr);
    int ret;
    if (!d->timestamps) {
        ret = qemu_chr_fe_write(&d->chr, buf, len);
    } else {
        int i;

        ret = 0;
        for (i = 0; i < len; i++) {
            if (d->linestart) {
                char buf1[64];
                int64_t ti;
                int secs;

                ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
                if (d->timestamps_start == -1) {
                    d->timestamps_start = ti;
                }
                ti -= d->timestamps_start;
                secs = ti / 1000;
                snprintf(buf1, sizeof(buf1),
                         "[%02d:%02d:%02d.%03d] ",
                         secs / 3600,
                         (secs / 60) % 60,
                         secs % 60,
                         (int)(ti % 1000));
                /* XXX this blocks entire thread. Rewrite to use
                 * qemu_chr_fe_write and background I/O callbacks */
                qemu_chr_fe_write_all(&d->chr,
                                      (uint8_t *)buf1, strlen(buf1));
                d->linestart = 0;
            }
            ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
            if (buf[i] == '\n') {
                d->linestart = 1;
            }
        }
    }
    return ret;
}
示例#21
0
文件: debugcon.c 项目: 0bliv10n/s2e
static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
    DebugconState *s = opaque;
    unsigned char ch = val;

#ifdef DEBUG_DEBUGCON
    printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
#endif

    qemu_chr_fe_write(s->chr, &ch, 1);
}
示例#22
0
static void uart_tx_pw(DepRegisterInfo *reg, uint64_t value)
{
    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
    if (s->cfg.use_tx) {
        unsigned char ch = value;
        qemu_chr_fe_write(&s->chr, &ch, 1);
        if (s->cfg.tx_interrupt) {
            qemu_irq_pulse(s->irq_tx);
        }
    }
}
示例#23
0
void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
{
    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
    unsigned char ch = jtx & 0xff;

    trace_lm32_juart_set_jtx(s->jtx);

    s->jtx = jtx;
    if (s->chr) {
        qemu_chr_fe_write(s->chr, &ch, 1);
    }
}
示例#24
0
/* Update TxRDY flag and set data if present and enabled.  */
static void mcf_uart_do_tx(mcf_uart_state *s)
{
    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
        if (s->chr)
            qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
        s->sr |= MCF_UART_TxEMP;
    }
    if (s->tx_enabled) {
        s->sr |= MCF_UART_TxRDY;
    } else {
        s->sr &= ~MCF_UART_TxRDY;
    }
}
示例#25
0
文件: test-char.c 项目: 8tab/qemu
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);
}
示例#26
0
static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf,
                                   int size)
{
    assert(size == 1);

    if (*buf == '\r' || *buf == '\n') {
        scon->event.event_pending = true;
        return;
    }
    scon->buf[scon->length] = *buf;
    scon->length += 1;
    if (scon->echo) {
        qemu_chr_fe_write(scon->chr, buf, size);
    }
}
示例#27
0
文件: qtest.c 项目: 0bliv10n/s2e
static void qtest_send(CharDriverState *chr, const char *fmt, ...)
{
    va_list ap;
    char buffer[1024];
    size_t len;

    va_start(ap, fmt);
    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
    va_end(ap);

    qemu_chr_fe_write(chr, (uint8_t *)buffer, len);
    if (qtest_log_fp && qtest_opened) {
        fprintf(qtest_log_fp, "%s", buffer);
    }
}
示例#28
0
文件: test-char.c 项目: 8tab/qemu
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);
}
示例#29
0
static void chr_read(void *opaque, const uint8_t *buf, int size)
{
    SCLPConsoleLM *scon = opaque;

    assert(size == 1);

    if (*buf == '\r' || *buf == '\n') {
        scon->event.event_pending = true;
        sclp_service_interrupt(0);
        return;
    }
    scon->buf[scon->length] = *buf;
    scon->length += 1;
    if (scon->echo) {
        qemu_chr_fe_write(scon->chr, buf, size);
    }
}
示例#30
0
static void continue_send(IPMIBmcExtern *ibe)
{
    int ret;
    if (ibe->outlen == 0) {
        goto check_reset;
    }
 send:
    ret = qemu_chr_fe_write(&ibe->chr, ibe->outbuf + ibe->outpos,
                            ibe->outlen - ibe->outpos);
    if (ret > 0) {
        ibe->outpos += ret;
    }
    if (ibe->outpos < ibe->outlen) {
        /* Not fully transmitted, try again in a 10ms */
        timer_mod_ns(ibe->extern_timer,
                     qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10000000);
    } else {
        /* Sent */
        ibe->outlen = 0;
        ibe->outpos = 0;
        if (!ibe->sending_cmd) {
            ibe->waiting_rsp = true;
        } else {
            ibe->sending_cmd = false;
        }
    check_reset:
        if (ibe->connected && ibe->send_reset) {
            /* Send the reset */
            ibe->outbuf[0] = VM_CMD_RESET;
            ibe->outbuf[1] = VM_CMD_CHAR;
            ibe->outlen = 2;
            ibe->outpos = 0;
            ibe->send_reset = false;
            ibe->sending_cmd = true;
            goto send;
        }

        if (ibe->waiting_rsp) {
            /* Make sure we get a response within 4 seconds. */
            timer_mod_ns(ibe->extern_timer,
                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 4000000000ULL);
        }
    }
    return;
}