All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 1/1] spice: add chardev
@ 2010-12-16 11:29 Alon Levy
  2010-12-16 13:21 ` Gerd Hoffmann
  0 siblings, 1 reply; 6+ messages in thread
From: Alon Levy @ 2010-12-16 11:29 UTC (permalink / raw)
  To: qemu-devel

Adding a chardev backend for spice, for usage by spice vdagent in
conjunction with a properly named virtio-serial device.
---
 Makefile.objs     |    2 +-
 qemu-char.c       |    7 ++
 qemu-config.c     |    9 ++
 qemu-options.hx   |   18 ++++-
 spice-qemu-char.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 spice-qemu-char.h |    9 ++
 6 files changed, 265 insertions(+), 2 deletions(-)
 create mode 100644 spice-qemu-char.c
 create mode 100644 spice-qemu-char.h

diff --git a/Makefile.objs b/Makefile.objs
index cebb945..320b2a9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -102,7 +102,7 @@ common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 common-obj-$(CONFIG_WIN32) += version.o
 
-common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
 
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
diff --git a/qemu-char.c b/qemu-char.c
index edc9ad6..82789ba 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -98,6 +98,10 @@
 
 #include "qemu_socket.h"
 
+#ifdef CONFIG_SPICE
+#include "spice-qemu-char.h"
+#endif
+
 #define READ_BUF_LEN 4096
 
 /***********************************************************/
@@ -2495,6 +2499,9 @@ static const struct {
     || defined(__FreeBSD_kernel__)
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
+#ifdef CONFIG_SPICE
+    { .name = "spicevmc",     .open = qemu_chr_open_spice },
+#endif
 };
 
 CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
diff --git a/qemu-config.c b/qemu-config.c
index 965fa46..42cd977 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -147,6 +147,15 @@ static QemuOptsList qemu_chardev_opts = {
             .name = "signal",
             .type = QEMU_OPT_BOOL,
         },
+#ifdef CONFIG_SPICE
+        {
+            .name = "name",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "debug",
+            .type = QEMU_OPT_NUMBER,
+        },
+#endif
         { /* end of list */ }
     },
 };
diff --git a/qemu-options.hx b/qemu-options.hx
index 4d99a58..d8ad070 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1357,6 +1357,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
     "-chardev parport,id=id,path=path[,mux=on|off]\n"
 #endif
+#if defined(CONFIG_SPICE)
+    "-chardev spicevmc,id=id,debug=debug,name=name\n"
+#endif
     , QEMU_ARCH_ALL
 )
 
@@ -1381,7 +1384,10 @@ Backend is one of:
 @option{stdio},
 @option{braille},
 @option{tty},
-@option{parport}.
+@option{parport}
+#if defined(CONFIG_SPICE)
+@option{spicevmc}.
+#endif
 The specific backend will determine the applicable options.
 
 All devices must have an id, which can be any string up to 127 characters long.
@@ -1557,6 +1563,16 @@ Connect to a local parallel port.
 @option{path} specifies the path to the parallel port device. @option{path} is
 required.
 
+#if defined(CONFIG_SPICE)
+@item -chardev spicevmc ,id=@var{id} ,debug=@var{debug}, name=@var{name}
+
+@option{debug} debug level for spicevmc
+
+@option{name} name of spice channel to connect to
+
+Connect to a spice virtual machine channel, such as vdiport.
+#endif
+
 @end table
 ETEXI
 
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
new file mode 100644
index 0000000..a080796
--- /dev/null
+++ b/spice-qemu-char.c
@@ -0,0 +1,222 @@
+#include "config-host.h"
+#include "ui/qemu-spice.h"
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "osdep.h"
+
+#include "spice-qemu-char.h"
+
+//#define SPICE_QEMU_CHAR_USE_IOCTL
+
+#define dprintf(_scd, _level, _fmt, ...)                                \
+    do {                                                                \
+        static unsigned __dprintf_counter = 0;                          \
+        if (_scd->debug >= _level) {                                    \
+            fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
+        }                                                               \
+    } while (0)
+
+#define VMC_MAX_HOST_WRITE    2048
+
+typedef struct SpiceCharDriver {
+    CharDriverState*      chr;
+    SpiceCharDeviceInstance     sin;
+    char                  *subtype;
+    bool                  active;
+    uint8_t               *buffer;
+    uint8_t               *datapos;
+    ssize_t               bufsize, datalen;
+    uint32_t              debug;
+} SpiceCharDriver;
+
+
+static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
+{
+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    ssize_t out = 0;
+    ssize_t last_out;
+    uint8_t* p = (uint8_t*)buf;
+
+    while (len > 0) {
+        last_out = MIN(len, VMC_MAX_HOST_WRITE);
+        qemu_chr_read(scd->chr, p, last_out);
+        if (last_out > 0) {
+            out += last_out;
+            len -= last_out;
+            p += last_out;
+        } else {
+            break;
+        }
+    }
+
+    dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+    return out;
+}
+
+static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+{
+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    int bytes = MIN(len, scd->datalen);
+
+    dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
+    if (bytes > 0) {
+        memcpy(buf, scd->datapos, bytes);
+        scd->datapos += bytes;
+        scd->datalen -= bytes;
+        assert(scd->datalen >= 0);
+        if (scd->datalen == 0) {
+            scd->datapos = 0;
+        }
+    }
+    return bytes;
+}
+
+static SpiceCharDeviceInterface vmc_interface = {
+    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
+    .base.description   = "spice virtual channel char device",
+    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+    .write              = vmc_write,
+    .read               = vmc_read,
+};
+
+
+static void vmc_register_interface(SpiceCharDriver *scd)
+{
+    if (scd->active) {
+        return;
+    }
+    dprintf(scd, 1, "%s\n", __func__);
+    scd->sin.base.sif = &vmc_interface.base;
+    qemu_spice_add_interface(&scd->sin.base);
+    scd->active = true;
+}
+
+static void vmc_unregister_interface(SpiceCharDriver *scd)
+{
+    if (!scd->active) {
+        return;
+    }
+    dprintf(scd, 1, "%s\n", __func__);
+    spice_server_remove_interface(&scd->sin.base);
+    scd->active = false;
+}
+
+
+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 = qemu_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 void spice_chr_close(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+
+    printf("%s\n", __func__);
+    vmc_unregister_interface(s);
+    qemu_free(s);
+    //qemu_chr_event(chr, CHR_EVENT_CLOSED); // TODO: export qemu_chr_event from qemu-char.h
+}
+
+#ifdef SPICE_QEMU_CHAR_USE_IOCTL
+static int spice_chr_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    SpiceCharDriver *s = chr->opaque;
+
+    switch (cmd) {
+        case CHR_IOCTL_VIRT_SERIAL_OPEN:
+            dprintf(s, 2, "%s: open ioctl\n", __func__);
+            vmc_register_interface(s);
+            break;
+        case CHR_IOCTL_VIRT_SERIAL_CLOSE:
+            dprintf(s, 2, "%s: close ioctl\n", __func__);
+            vmc_unregister_interface(s);
+            break;
+        case CHR_IOCTL_VIRT_SERIAL_READY:
+            dprintf(s, 2, "%s: ready ioctl\n", __func__);
+            if (s->active)
+                spice_server_char_device_wakeup(&s->sin);
+            break;
+        default:
+            dprintf(s, 2, "%s: unsupported IOCTL %d\n", __func__, cmd);
+            return -ENOTSUP;
+    }
+    return 0;
+}
+#endif // SPICE_QEMU_CHAR_USE_IOCTL
+
+static void print_allowed_subtypes(void)
+{
+    const char** psubtype;
+    int i;
+
+    fprintf(stderr, "allowed names: ");
+    for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
+        *psubtype != NULL; ++psubtype, ++i) {
+        if (i == 0) {
+            fprintf(stderr, "%s", *psubtype);
+        } else {
+            fprintf(stderr, ", %s", *psubtype);
+        }
+    }
+    fprintf(stderr, "\n");
+}
+
+CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
+{
+    CharDriverState *chr;
+    SpiceCharDriver *s;
+    const char* name = qemu_opt_get(opts, "name");
+    uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
+    const char** psubtype = spice_server_char_device_recognized_subtypes();
+    const char *subtype = NULL;
+
+    if (name == NULL) {
+        fprintf(stderr, "spice-qemu-char: missing name parameter\n");
+        print_allowed_subtypes();
+        return NULL;
+    }
+    for(;*psubtype != NULL; ++psubtype) {
+        if (strcmp(name, *psubtype) == 0) {
+            subtype = *psubtype;
+            break;
+        }
+    }
+    if (subtype == NULL) {
+        fprintf(stderr, "spice-qemu-char: unsupported name\n");
+        print_allowed_subtypes();
+        return NULL;
+    }
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(SpiceCharDriver));
+    s->chr = chr;
+    s->debug = debug;
+    s->active = false;
+    s->sin.subtype = subtype;
+    chr->opaque = s;
+    chr->chr_write = spice_chr_write;
+    chr->chr_close = spice_chr_close;
+#ifdef SPICE_QEMU_CHAR_USE_IOCTL
+    chr->chr_ioctl = spice_chr_ioctl;
+#endif
+
+    qemu_chr_generic_open(chr);
+
+    return chr;
+}
+
diff --git a/spice-qemu-char.h b/spice-qemu-char.h
new file mode 100644
index 0000000..32d5009
--- /dev/null
+++ b/spice-qemu-char.h
@@ -0,0 +1,9 @@
+#ifndef __SPICE_QEMU_CHAR_H__
+#define __SPICE_QEMU_CHAR_H__
+
+#include "qemu-char.h"
+
+CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
+
+#endif // __SPICE_QEMU_CHAR_H__
+
-- 
1.7.3.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 0/1] introduce spice-qemu-char chardev
@ 2010-11-30 14:29 Alon Levy
  2010-11-30 14:29 ` [Qemu-devel] [PATCH 1/1] spice: add chardev Alon Levy
  0 siblings, 1 reply; 6+ messages in thread
From: Alon Levy @ 2010-11-30 14:29 UTC (permalink / raw)
  To: qemu-devel, spice-devel

Adding a chardev backend for spice, for usage by spice vdagent over a
with virtio-serial device.

Alon Levy (1):
  spice: add chardev

 Makefile.objs     |    2 +-
 qemu-char.c       |    7 ++
 qemu-config.c     |    9 ++
 qemu-options.hx   |   18 ++++-
 spice-qemu-char.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 spice-qemu-char.h |    9 ++
 6 files changed, 265 insertions(+), 2 deletions(-)
 create mode 100644 spice-qemu-char.c
 create mode 100644 spice-qemu-char.h

-- 
1.7.3.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-12-17 12:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-16 11:29 [Qemu-devel] [PATCH 1/1] spice: add chardev Alon Levy
2010-12-16 13:21 ` Gerd Hoffmann
2010-12-16 16:48   ` Alon Levy
2010-12-16 16:53     ` Gerd Hoffmann
2010-12-17 12:54       ` Alon Levy
  -- strict thread matches above, loose matches on Subject: below --
2010-11-30 14:29 [Qemu-devel] [PATCH 0/1] introduce spice-qemu-char chardev Alon Levy
2010-11-30 14:29 ` [Qemu-devel] [PATCH 1/1] spice: add chardev Alon Levy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.