All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Alon Levy <alevy@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH 6/6] spice: add chardev (v4)
Date: Tue, 11 Jan 2011 13:08:26 +0100	[thread overview]
Message-ID: <1294747706-31382-8-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1294747706-31382-1-git-send-email-kraxel@redhat.com>

From: Alon Levy <alevy@redhat.com>

Adding a chardev backend for spice, where spice determines what
to do with it based on the name attribute given during chardev creation.
For usage by spice vdagent in conjunction with a properly named
virtio-serial device, and future smartcard channel usage.

Example usage:
 qemu -device virtio-serial -chardev spicevmc,name=vdagent,id=vdagent \
 -device virtserialport,chardev=vdagent,name=com.redhat.spice.0

v3->v4:
 * updated commit message

v1->v3 changes: (v2 had a wrong commit message)
 * removed spice-qemu-char.h, folded into ui/qemu-spice.h
 * removed dead IOCTL code
 * removed comment
 * removed ifdef CONFIG_SPICE from qemu-config.c and qemu-options.hx help.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs     |    2 +-
 qemu-char.c       |    4 +
 qemu-config.c     |    6 ++
 qemu-options.hx   |   16 ++++-
 spice-qemu-char.c |  185 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/qemu-spice.h   |    3 +
 6 files changed, 214 insertions(+), 2 deletions(-)
 create mode 100644 spice-qemu-char.c

diff --git a/Makefile.objs b/Makefile.objs
index c3e52c5..b9e9ef6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -105,7 +105,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..acc7130 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -97,6 +97,7 @@
 #endif
 
 #include "qemu_socket.h"
+#include "ui/qemu-spice.h"
 
 #define READ_BUF_LEN 4096
 
@@ -2495,6 +2496,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..323d3c2 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -146,6 +146,12 @@ static QemuOptsList qemu_chardev_opts = {
         },{
             .name = "signal",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "name",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "debug",
+            .type = QEMU_OPT_NUMBER,
         },
         { /* end of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index 898561d..e0b76bd 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1368,6 +1368,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
 )
 
@@ -1392,7 +1395,8 @@ Backend is one of:
 @option{stdio},
 @option{braille},
 @option{tty},
-@option{parport}.
+@option{parport}
+@option{spicevmc}.
 The specific backend will determine the applicable options.
 
 All devices must have an id, which can be any string up to 127 characters long.
@@ -1568,6 +1572,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..0ffa674
--- /dev/null
+++ b/spice-qemu-char.c
@@ -0,0 +1,185 @@
+#include "config-host.h"
+#include "ui/qemu-spice.h"
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "osdep.h"
+
+#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);
+}
+
+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;
+
+    qemu_chr_generic_open(chr);
+
+    return chr;
+}
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 05dc50a..916e5dc 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -24,6 +24,7 @@
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-char.h"
 
 extern int using_spice;
 
@@ -41,6 +42,8 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
 
+CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
+
 #else  /* CONFIG_SPICE */
 
 #define using_spice 0
-- 
1.7.1

  parent reply	other threads:[~2011-01-11 12:08 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-11 12:08 [Qemu-devel] [PULL v2 0/6] spice patch queue Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 1/6] add migration state change notifiers Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 2/6] spice: client migration Gerd Hoffmann
2011-01-11 13:37   ` [Qemu-devel] " Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 2/6] spice/vnc: " Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 3/6] spice: MAINTAINERS update Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 4/6] vnc/spice: fix "never" and "now" expire_time Gerd Hoffmann
2011-01-11 12:08 ` [Qemu-devel] [PATCH 5/6] spice/qxl: zap spice 0.4 migration compatibility bits Gerd Hoffmann
2011-01-11 12:08 ` Gerd Hoffmann [this message]
2011-01-11 17:08   ` [Qemu-devel] [PATCH 6/6] spice: add chardev (v4) Blue Swirl
2011-01-12 10:07 ` [Qemu-devel] Re: [PULL v2 0/6] spice patch queue Gerd Hoffmann
  -- strict thread matches above, loose matches on Subject: below --
2011-01-10 13:31 [Qemu-devel] [PULL " Gerd Hoffmann
2011-01-10 13:31 ` [Qemu-devel] [PATCH 6/6] spice: add chardev (v4) Gerd Hoffmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1294747706-31382-8-git-send-email-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=alevy@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.