qemu/spice-qemu-char.c
<<
>>
Prefs
   1#include "config-host.h"
   2#include "trace.h"
   3#include "ui/qemu-spice.h"
   4#include <spice.h>
   5#include <spice-experimental.h>
   6
   7#include "osdep.h"
   8
   9#define dprintf(_scd, _level, _fmt, ...)                                \
  10    do {                                                                \
  11        static unsigned __dprintf_counter = 0;                          \
  12        if (_scd->debug >= _level) {                                    \
  13            fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
  14        }                                                               \
  15    } while (0)
  16
  17#define VMC_MAX_HOST_WRITE    2048
  18
  19typedef struct SpiceCharDriver {
  20    CharDriverState*      chr;
  21    SpiceCharDeviceInstance     sin;
  22    char                  *subtype;
  23    bool                  active;
  24    uint8_t               *buffer;
  25    uint8_t               *datapos;
  26    ssize_t               bufsize, datalen;
  27    uint32_t              debug;
  28} SpiceCharDriver;
  29
  30static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
  31{
  32    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  33    ssize_t out = 0;
  34    ssize_t last_out;
  35    uint8_t* p = (uint8_t*)buf;
  36
  37    while (len > 0) {
  38        last_out = MIN(len, VMC_MAX_HOST_WRITE);
  39        if (qemu_chr_can_read(scd->chr) < last_out) {
  40            break;
  41        }
  42        qemu_chr_read(scd->chr, p, last_out);
  43        out += last_out;
  44        len -= last_out;
  45        p += last_out;
  46    }
  47
  48    dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
  49    trace_spice_vmc_write(out, len + out);
  50    return out;
  51}
  52
  53static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
  54{
  55    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  56    int bytes = MIN(len, scd->datalen);
  57
  58    dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
  59    if (bytes > 0) {
  60        memcpy(buf, scd->datapos, bytes);
  61        scd->datapos += bytes;
  62        scd->datalen -= bytes;
  63        assert(scd->datalen >= 0);
  64        if (scd->datalen == 0) {
  65            scd->datapos = 0;
  66        }
  67    }
  68    trace_spice_vmc_read(bytes, len);
  69    return bytes;
  70}
  71
  72static SpiceCharDeviceInterface vmc_interface = {
  73    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
  74    .base.description   = "spice virtual channel char device",
  75    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
  76    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
  77    .write              = vmc_write,
  78    .read               = vmc_read,
  79};
  80
  81
  82static void vmc_register_interface(SpiceCharDriver *scd)
  83{
  84    if (scd->active) {
  85        return;
  86    }
  87    dprintf(scd, 1, "%s\n", __func__);
  88    scd->sin.base.sif = &vmc_interface.base;
  89    qemu_spice_add_interface(&scd->sin.base);
  90    scd->active = true;
  91    trace_spice_vmc_register_interface(scd);
  92}
  93
  94static void vmc_unregister_interface(SpiceCharDriver *scd)
  95{
  96    if (!scd->active) {
  97        return;
  98    }
  99    dprintf(scd, 1, "%s\n", __func__);
 100    spice_server_remove_interface(&scd->sin.base);
 101    scd->active = false;
 102    trace_spice_vmc_unregister_interface(scd);
 103}
 104
 105
 106static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 107{
 108    SpiceCharDriver *s = chr->opaque;
 109
 110    dprintf(s, 2, "%s: %d\n", __func__, len);
 111    vmc_register_interface(s);
 112    assert(s->datalen == 0);
 113    if (s->bufsize < len) {
 114        s->bufsize = len;
 115        s->buffer = qemu_realloc(s->buffer, s->bufsize);
 116    }
 117    memcpy(s->buffer, buf, len);
 118    s->datapos = s->buffer;
 119    s->datalen = len;
 120    spice_server_char_device_wakeup(&s->sin);
 121    return len;
 122}
 123
 124static void spice_chr_close(struct CharDriverState *chr)
 125{
 126    SpiceCharDriver *s = chr->opaque;
 127
 128    printf("%s\n", __func__);
 129    vmc_unregister_interface(s);
 130    qemu_free(s);
 131}
 132
 133static void spice_chr_guest_open(struct CharDriverState *chr)
 134{
 135    SpiceCharDriver *s = chr->opaque;
 136    vmc_register_interface(s);
 137}
 138
 139static void spice_chr_guest_close(struct CharDriverState *chr)
 140{
 141    SpiceCharDriver *s = chr->opaque;
 142    vmc_unregister_interface(s);
 143}
 144
 145static void print_allowed_subtypes(void)
 146{
 147    const char** psubtype;
 148    int i;
 149
 150    fprintf(stderr, "allowed names: ");
 151    for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
 152        *psubtype != NULL; ++psubtype, ++i) {
 153        if (i == 0) {
 154            fprintf(stderr, "%s", *psubtype);
 155        } else {
 156            fprintf(stderr, ", %s", *psubtype);
 157        }
 158    }
 159    fprintf(stderr, "\n");
 160}
 161
 162int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
 163{
 164    CharDriverState *chr;
 165    SpiceCharDriver *s;
 166    const char* name = qemu_opt_get(opts, "name");
 167    uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
 168    const char** psubtype = spice_server_char_device_recognized_subtypes();
 169    const char *subtype = NULL;
 170
 171    if (name == NULL) {
 172        fprintf(stderr, "spice-qemu-char: missing name parameter\n");
 173        print_allowed_subtypes();
 174        return -EINVAL;
 175    }
 176    for(;*psubtype != NULL; ++psubtype) {
 177        if (strcmp(name, *psubtype) == 0) {
 178            subtype = *psubtype;
 179            break;
 180        }
 181    }
 182    if (subtype == NULL) {
 183        fprintf(stderr, "spice-qemu-char: unsupported name\n");
 184        print_allowed_subtypes();
 185        return -EINVAL;
 186    }
 187
 188    chr = qemu_mallocz(sizeof(CharDriverState));
 189    s = qemu_mallocz(sizeof(SpiceCharDriver));
 190    s->chr = chr;
 191    s->debug = debug;
 192    s->active = false;
 193    s->sin.subtype = subtype;
 194    chr->opaque = s;
 195    chr->chr_write = spice_chr_write;
 196    chr->chr_close = spice_chr_close;
 197    chr->chr_guest_open = spice_chr_guest_open;
 198    chr->chr_guest_close = spice_chr_guest_close;
 199
 200    qemu_chr_generic_open(chr);
 201
 202    *_chr = chr;
 203    return 0;
 204}
 205