static void vmc_change_state_handler(void *opaque, int running, int reason)
{
    SpiceVirtualChannel *svc = opaque;

    if (running && svc->active) {
        spice_server_char_device_wakeup(&svc->sin);
    }
}
static void vmc_guest_ready(VirtIOSerialPort *port)
{
    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);

    dprintf(svc, 1, "%s\n", __func__);
    if (svc->active) {
        spice_server_char_device_wakeup(&svc->sin);
    }
}
static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
{
    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);

    dprintf(svc, 2, "%s: %zd\n", __func__, len);
    assert(svc->datalen == 0);
    if (svc->bufsize < len) {
        svc->bufsize = len;
        svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
    }
    memcpy(svc->buffer, buf, len);
    svc->datapos = svc->buffer;
    svc->datalen = len;
    virtio_serial_throttle_port(&svc->port, true);
    spice_server_char_device_wakeup(&svc->sin);
}
static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
    SpiceCharDriver *s = chr->opaque;

    dprintf(s, 2, "%s: %d\n", __func__, len);
    vmc_register_interface(s);
    assert(s->datalen == 0);
    if (s->bufsize < len) {
        s->bufsize = len;
        s->buffer = g_realloc(s->buffer, s->bufsize);
    }
    memcpy(s->buffer, buf, len);
    s->datapos = s->buffer;
    s->datalen = len;
    spice_server_char_device_wakeup(&s->sin);
    return len;
}
static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
    SpiceCharDriver *s = chr->opaque;
    int read_bytes;

    vmc_register_interface(s);
    assert(s->datalen == 0);
    s->datapos = buf;
    s->datalen = len;
    spice_server_char_device_wakeup(&s->sin);
    read_bytes = len - s->datalen;
    if (read_bytes != len) {
        /* We'll get passed in the unconsumed data with the next call */
        s->datalen = 0;
        s->datapos = NULL;
        s->blocked = true;
    }
    return read_bytes;
}