From patchwork Fri Nov 30 13:25:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 202956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 9E7412C0092 for ; Sat, 1 Dec 2012 00:27:38 +1100 (EST) Received: from localhost ([::1]:53768 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TeQcy-00051J-P4 for incoming@patchwork.ozlabs.org; Fri, 30 Nov 2012 08:27:36 -0500 Received: from eggs.gnu.org ([208.118.235.92]:53368) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TeQcj-0004by-0M for qemu-devel@nongnu.org; Fri, 30 Nov 2012 08:27:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TeQcc-0002Ma-IF for qemu-devel@nongnu.org; Fri, 30 Nov 2012 08:27:20 -0500 Received: from mail-pa0-f45.google.com ([209.85.220.45]:51798) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TeQcc-0002MM-8L for qemu-devel@nongnu.org; Fri, 30 Nov 2012 08:27:14 -0500 Received: by mail-pa0-f45.google.com with SMTP id bg2so333376pad.4 for ; Fri, 30 Nov 2012 05:27:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=+m4LZq6UpWpBVxOQM7wsvq5aavjgELHQqtIeZXPhT5Y=; b=yo3QsEdkj96AM2JebGqEdy6gsfHz7Q+9auPsiTcFcMjOhg/sVtLHAasHhJ2o2tS1uK fBbh0b9hIisqhzxQdxphM16rhrYideu9UdX83rLA8auIbm2zAX2rA8XDF4OL6jvm3Laf frXU0R3n63yYjJV1QE+N8CmxRRH7etdzuuMssdif5QmxmbenKPdIbwItkEO18guZ/OMR GGGA4Gi1p5NVL9y4qDz3GOKU2DVZRv4Dt1Om+IZ7zy6m6xbSjzs6v8diEC9r/B0TS7XH RiUE0ujF1f6yr25Hei7NcGRtnxdls0+bMRMIaKp/Dv59WkE5EvtytqzUoqTvrkIMWeze TD7g== Received: by 10.66.87.226 with SMTP id bb2mr3171462pab.57.1354282033186; Fri, 30 Nov 2012 05:27:13 -0800 (PST) Received: from localhost (54.Red-88-0-20.dynamicIP.rima-tde.net. [88.0.20.54]) by mx.google.com with ESMTPS id c8sm2931452pav.4.2012.11.30.05.27.02 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 30 Nov 2012 05:27:12 -0800 (PST) From: "=?UTF-8?q?Marc-Andr=C3=A9=20Lureau?=" To: qemu-devel@nongnu.org Date: Fri, 30 Nov 2012 14:25:45 +0100 Message-Id: <1354281947-20227-5-git-send-email-marcandre.lureau@redhat.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1354281947-20227-1-git-send-email-marcandre.lureau@redhat.com> References: <1354281947-20227-1-git-send-email-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.220.45 Cc: spice-devel@lists.freedesktop.org, alevy@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [Qemu-devel] [PATCH 4/6] spice-qemu-char: add spiceport chardev X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a new spice chardev to allow arbitrary communication between the host and the Spice client (via the spice server). Examples: This allows the Spice client to have a special port for the qemu monitor: ... -chardev spiceport,name=org.qemu.monitor,id=monitorport -mon chardev=monitorport Or to allow arbitrary communication outside of qemu: ... -chardev spiceport,name=org.ovirt.controller,id=...,chardev=ovcsocket -chardev socket,server,host=0.0.0.0,port=4242,id=ovcsocket,nowait The spice client is notified when the qemu socket server has gain or lost a client. The qemu socket client is disconnected when the spice client is disconnected. Signed-off-by: Marc-André Lureau --- qemu-char.c | 1 + qemu-config.c | 3 ++ qemu-options.hx | 14 ++++++ spice-qemu-char.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 3 ++ ui/qemu-spice.h | 1 + 6 files changed, 161 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 1414ca1..bc1c74b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2782,6 +2782,7 @@ static const struct { #endif #ifdef CONFIG_SPICE { .name = "spicevmc", .open = qemu_chr_open_spice }, + { .name = "spiceport", .open = qemu_chr_open_spice_port }, #endif }; diff --git a/qemu-config.c b/qemu-config.c index 10d1ba4..b4e7af3 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -217,6 +217,9 @@ static QemuOptsList qemu_chardev_opts = { },{ .name = "debug", .type = QEMU_OPT_NUMBER, + },{ + .name = "chardev", + .type = QEMU_OPT_STRING, }, { /* end of list */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index fbcf079..d2f09f6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1749,6 +1749,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(CONFIG_SPICE) "-chardev spicevmc,id=id,name=name[,debug=debug]\n" + "-chardev spiceport,id=id,name=name[,chardev=name,debug=debug]\n" #endif , QEMU_ARCH_ALL ) @@ -1776,6 +1777,7 @@ Backend is one of: @option{tty}, @option{parport}, @option{spicevmc}. +@option{spiceport}. The specific backend will determine the applicable options. All devices must have an id, which can be any string up to 127 characters long. @@ -1961,6 +1963,18 @@ required. Connect to a spice virtual machine channel, such as vdiport. +@item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name}, chardev=@var{chardev} + +@option{spiceport} is only available when spice support is built in. + +@option{debug} debug level for spicevmc + +@option{name} name of spice port to connect to + +@option{chardev} name of chardev to connect to + +Connect to a spice port, fixme. + @end table ETEXI diff --git a/spice-qemu-char.c b/spice-qemu-char.c index b86e83a..629b500 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -3,6 +3,7 @@ #include "ui/qemu-spice.h" #include #include +#include #include "osdep.h" @@ -23,6 +24,7 @@ typedef struct SpiceCharDriver { uint8_t *datapos; ssize_t bufsize, datalen; uint32_t debug; + CharDriverState *chardev; } SpiceCharDriver; static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) @@ -67,6 +69,25 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) return bytes; } +static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) +{ + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); + int chr_event; + + switch (event) { + case SPICE_PORT_EVENT_BREAK: + chr_event = CHR_EVENT_BREAK; + break; + default: + dprintf(scd, 2, "%s: unknown %d\n", __func__, event); + return; + } + + dprintf(scd, 2, "%s: %d\n", __func__, event); + trace_spice_vmc_event(chr_event); + qemu_chr_be_event(scd->chr, chr_event); +} + static void vmc_state(SpiceCharDeviceInstance *sin, int connected) { SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); @@ -103,6 +124,7 @@ static SpiceCharDeviceInterface vmc_interface = { .state = vmc_state, .write = vmc_write, .read = vmc_read, + .event = vmc_event, }; @@ -116,6 +138,10 @@ static void vmc_register_interface(SpiceCharDriver *scd) qemu_spice_add_interface(&scd->sin.base); scd->active = true; trace_spice_vmc_register_interface(scd); + + if (scd->chardev != NULL && scd->chardev->opened) { + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_OPENED); + } } static void vmc_unregister_interface(SpiceCharDriver *scd) @@ -242,3 +268,116 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) return chr; } +static int port_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + return qemu_chr_be_can_write(scd->chardev); +} + +static void port_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, size); + trace_spice_port_chardev_write(size); + qemu_chr_fe_write(scd->chardev, buf, size); +} + +static void port_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, event); + + switch (event) { + case CHR_EVENT_CLOSED: + if (scd->chardev != NULL) { + qemu_chr_remove_clients(scd->chardev); + } + break; + } +} + +static int chardev_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *s = chr->opaque; + + if (!chr->opened) { + return 0; + } + + if (s->datalen != 0) { + return 0; + } + + /* FIXME: assume spice can take chunks of 4096 */ + return 4096; +} + +/* Send data from a char device over to the spice port */ +static void chardev_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + + trace_spice_port_chardev_read(size); + /* spicevmc port always send/queue all data */ + qemu_chr_fe_write(chr, buf, size); +} + +static void chardev_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, event); + + switch (event) { + case CHR_EVENT_OPENED: + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_OPENED); + break; + case CHR_EVENT_CLOSED: + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_CLOSED); + break; + } +} + +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) +{ + CharDriverState *chr, *chardev = NULL; + SpiceCharDriver *s; + const char *name = qemu_opt_get(opts, "name"); + const char *chrdev = qemu_opt_get(opts, "chardev"); + + if (name == NULL) { + fprintf(stderr, "spice-qemu-char: missing name parameter\n"); + return NULL; + } + + if (chrdev != NULL) { + chardev = qemu_chr_find(chrdev); + if (chardev == NULL) { + fprintf(stderr, "spice-qemu-char: chardev \"%s\" not found\n", + chrdev); + return NULL; + } + } + + chr = chr_open(opts, "port"); + s = chr->opaque; + s->sin.portname = name; + + if (chardev != NULL) { + s->chardev = chardev; + qemu_chr_add_handlers(chardev, chardev_can_read, + chardev_read, chardev_event, chr); + } + + qemu_chr_add_handlers(chr, port_can_read, port_read, port_event, chr); + + return chr; +} diff --git a/trace-events b/trace-events index 6c6cbf1..26ca363 100644 --- a/trace-events +++ b/trace-events @@ -535,6 +535,9 @@ spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d" spice_vmc_read(int bytes, int len) "spice read %d of requested %d" spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p" +spice_vmc_event(int event) "spice vmc event %d" +spice_port_chardev_read(int bytes) "spice port read %d from chardev" +spice_port_chardev_write(int bytes) "spice port wrote %d to chardev" # hw/lm32_pic.c lm32_pic_raise_irq(void) "Raise CPU interrupt" diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 3299da8..ab1943a 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -46,6 +46,7 @@ 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); +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); #else /* CONFIG_SPICE */ #include "monitor.h"