Merge remote-tracking branch 'spice/spice.v66' into staging
* spice/spice.v66: docs: add spice-port-fqdn.txt spice-qemu-char: register spicevmc ports during qemu_spice_init() spice-qemu-char: keep a list of spice chardev spice-qemu-char: add spiceport chardev spice-qemu-char: factor out CharDriverState creation spice-qemu-char: write to chardev whatever amount it can read qxl+vnc: register a vm state change handler for dummy spice_server qxl: save qemu_create_displaysurface_from result Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
commit
510981a097
19
docs/spice-port-fqdn.txt
Normal file
19
docs/spice-port-fqdn.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
A Spice port channel is an arbitrary communication between the Spice
|
||||||
|
server host side and the client side.
|
||||||
|
|
||||||
|
Thanks to the associated reverse fully qualified domain name (fqdn),
|
||||||
|
a Spice client can handle the various ports appropriately.
|
||||||
|
|
||||||
|
The following fqdn names are reserved by the QEMU project:
|
||||||
|
|
||||||
|
org.qemu.monitor.hmp.0
|
||||||
|
QEMU human monitor
|
||||||
|
|
||||||
|
org.qemu.monitor.qmp.0:
|
||||||
|
QEMU control monitor
|
||||||
|
|
||||||
|
org.qemu.console.serial.0
|
||||||
|
QEMU virtual serial port
|
||||||
|
|
||||||
|
org.qemu.console.debug.0
|
||||||
|
QEMU debug console
|
@ -113,11 +113,12 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||||||
qxl->guest_primary.bits_pp);
|
qxl->guest_primary.bits_pp);
|
||||||
if (qxl->guest_primary.qxl_stride > 0) {
|
if (qxl->guest_primary.qxl_stride > 0) {
|
||||||
qemu_free_displaysurface(vga->ds);
|
qemu_free_displaysurface(vga->ds);
|
||||||
qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
|
vga->ds->surface = qemu_create_displaysurface_from
|
||||||
qxl->guest_primary.surface.height,
|
(qxl->guest_primary.surface.width,
|
||||||
qxl->guest_primary.bits_pp,
|
qxl->guest_primary.surface.height,
|
||||||
qxl->guest_primary.abs_stride,
|
qxl->guest_primary.bits_pp,
|
||||||
qxl->guest_primary.data);
|
qxl->guest_primary.abs_stride,
|
||||||
|
qxl->guest_primary.data);
|
||||||
} else {
|
} else {
|
||||||
qemu_resize_displaysurface(vga->ds,
|
qemu_resize_displaysurface(vga->ds,
|
||||||
qxl->guest_primary.surface.width,
|
qxl->guest_primary.surface.width,
|
||||||
|
@ -2762,6 +2762,9 @@ static const struct {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPICE
|
#ifdef CONFIG_SPICE
|
||||||
{ .name = "spicevmc", .open = qemu_chr_open_spice },
|
{ .name = "spicevmc", .open = qemu_chr_open_spice },
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
{ .name = "spiceport", .open = qemu_chr_open_spice_port },
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1749,6 +1749,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
|
|||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_SPICE)
|
#if defined(CONFIG_SPICE)
|
||||||
"-chardev spicevmc,id=id,name=name[,debug=debug]\n"
|
"-chardev spicevmc,id=id,name=name[,debug=debug]\n"
|
||||||
|
"-chardev spiceport,id=id,name=name[,debug=debug]\n"
|
||||||
#endif
|
#endif
|
||||||
, QEMU_ARCH_ALL
|
, QEMU_ARCH_ALL
|
||||||
)
|
)
|
||||||
@ -1776,6 +1777,7 @@ Backend is one of:
|
|||||||
@option{tty},
|
@option{tty},
|
||||||
@option{parport},
|
@option{parport},
|
||||||
@option{spicevmc}.
|
@option{spicevmc}.
|
||||||
|
@option{spiceport}.
|
||||||
The specific backend will determine the applicable options.
|
The specific backend will determine the applicable options.
|
||||||
|
|
||||||
All devices must have an id, which can be any string up to 127 characters long.
|
All devices must have an id, which can be any string up to 127 characters long.
|
||||||
@ -1961,6 +1963,17 @@ required.
|
|||||||
|
|
||||||
Connect to a spice virtual machine channel, such as vdiport.
|
Connect to a spice virtual machine channel, such as vdiport.
|
||||||
|
|
||||||
|
@item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name}
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
Connect to a spice port, allowing a Spice client to handle the traffic
|
||||||
|
identified by a name (preferably a fqdn).
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "ui/qemu-spice.h"
|
#include "ui/qemu-spice.h"
|
||||||
#include <spice.h>
|
#include <spice.h>
|
||||||
#include <spice-experimental.h>
|
#include <spice-experimental.h>
|
||||||
|
#include <spice/protocol.h>
|
||||||
|
|
||||||
#include "osdep.h"
|
#include "osdep.h"
|
||||||
|
|
||||||
@ -14,8 +15,6 @@
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define VMC_MAX_HOST_WRITE 2048
|
|
||||||
|
|
||||||
typedef struct SpiceCharDriver {
|
typedef struct SpiceCharDriver {
|
||||||
CharDriverState* chr;
|
CharDriverState* chr;
|
||||||
SpiceCharDeviceInstance sin;
|
SpiceCharDeviceInstance sin;
|
||||||
@ -25,8 +24,12 @@ typedef struct SpiceCharDriver {
|
|||||||
uint8_t *datapos;
|
uint8_t *datapos;
|
||||||
ssize_t bufsize, datalen;
|
ssize_t bufsize, datalen;
|
||||||
uint32_t debug;
|
uint32_t debug;
|
||||||
|
QLIST_ENTRY(SpiceCharDriver) next;
|
||||||
} SpiceCharDriver;
|
} SpiceCharDriver;
|
||||||
|
|
||||||
|
static QLIST_HEAD(, SpiceCharDriver) spice_chars =
|
||||||
|
QLIST_HEAD_INITIALIZER(spice_chars);
|
||||||
|
|
||||||
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
||||||
@ -35,8 +38,8 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
|||||||
uint8_t* p = (uint8_t*)buf;
|
uint8_t* p = (uint8_t*)buf;
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
last_out = MIN(len, VMC_MAX_HOST_WRITE);
|
last_out = MIN(len, qemu_chr_be_can_write(scd->chr));
|
||||||
if (qemu_chr_be_can_write(scd->chr) < last_out) {
|
if (last_out <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
qemu_chr_be_write(scd->chr, p, last_out);
|
qemu_chr_be_write(scd->chr, p, last_out);
|
||||||
@ -69,6 +72,27 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
|
static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
|
||||||
{
|
{
|
||||||
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
||||||
@ -105,6 +129,9 @@ static SpiceCharDeviceInterface vmc_interface = {
|
|||||||
.state = vmc_state,
|
.state = vmc_state,
|
||||||
.write = vmc_write,
|
.write = vmc_write,
|
||||||
.read = vmc_read,
|
.read = vmc_read,
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
.event = vmc_event,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -156,6 +183,7 @@ static void spice_chr_close(struct CharDriverState *chr)
|
|||||||
|
|
||||||
printf("%s\n", __func__);
|
printf("%s\n", __func__);
|
||||||
vmc_unregister_interface(s);
|
vmc_unregister_interface(s);
|
||||||
|
QLIST_REMOVE(s, next);
|
||||||
g_free(s);
|
g_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,13 +216,34 @@ static void print_allowed_subtypes(void)
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
SpiceCharDriver *s;
|
SpiceCharDriver *s;
|
||||||
const char* name = qemu_opt_get(opts, "name");
|
|
||||||
uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
|
uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
|
||||||
const char** psubtype = spice_server_char_device_recognized_subtypes();
|
|
||||||
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
|
s = g_malloc0(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;
|
||||||
|
chr->chr_guest_open = spice_chr_guest_open;
|
||||||
|
chr->chr_guest_close = spice_chr_guest_close;
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD(&spice_chars, s, next);
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
||||||
|
{
|
||||||
|
CharDriverState *chr;
|
||||||
|
const char *name = qemu_opt_get(opts, "name");
|
||||||
|
const char **psubtype = spice_server_char_device_recognized_subtypes();
|
||||||
const char *subtype = NULL;
|
const char *subtype = NULL;
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
@ -214,17 +263,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = chr_open(opts, subtype);
|
||||||
s = g_malloc0(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;
|
|
||||||
chr->chr_guest_open = spice_chr_guest_open;
|
|
||||||
chr->chr_guest_close = spice_chr_guest_close;
|
|
||||||
|
|
||||||
#if SPICE_SERVER_VERSION < 0x000901
|
#if SPICE_SERVER_VERSION < 0x000901
|
||||||
/* See comment in vmc_state() */
|
/* See comment in vmc_state() */
|
||||||
@ -235,3 +274,35 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
|||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts)
|
||||||
|
{
|
||||||
|
CharDriverState *chr;
|
||||||
|
SpiceCharDriver *s;
|
||||||
|
const char *name = qemu_opt_get(opts, "name");
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
fprintf(stderr, "spice-qemu-char: missing name parameter\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chr = chr_open(opts, "port");
|
||||||
|
s = chr->opaque;
|
||||||
|
s->sin.portname = name;
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_spice_register_ports(void)
|
||||||
|
{
|
||||||
|
SpiceCharDriver *s;
|
||||||
|
|
||||||
|
QLIST_FOREACH(s, &spice_chars, next) {
|
||||||
|
if (s->sin.portname == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vmc_register_interface(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -535,6 +535,7 @@ 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_read(int bytes, int len) "spice read %d of requested %d"
|
||||||
spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
|
spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
|
||||||
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
|
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
|
||||||
|
spice_vmc_event(int event) "spice vmc event %d"
|
||||||
|
|
||||||
# hw/lm32_pic.c
|
# hw/lm32_pic.c
|
||||||
lm32_pic_raise_irq(void) "Raise CPU interrupt"
|
lm32_pic_raise_irq(void) "Raise CPU interrupt"
|
||||||
|
@ -46,6 +46,10 @@ void do_info_spice_print(Monitor *mon, const QObject *data);
|
|||||||
void do_info_spice(Monitor *mon, QObject **ret_data);
|
void do_info_spice(Monitor *mon, QObject **ret_data);
|
||||||
|
|
||||||
CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
|
CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts);
|
||||||
|
void qemu_spice_register_ports(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#else /* CONFIG_SPICE */
|
#else /* CONFIG_SPICE */
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
|
@ -714,6 +714,10 @@ void qemu_spice_init(void)
|
|||||||
g_free(x509_key_file);
|
g_free(x509_key_file);
|
||||||
g_free(x509_cert_file);
|
g_free(x509_cert_file);
|
||||||
g_free(x509_cacert_file);
|
g_free(x509_cacert_file);
|
||||||
|
|
||||||
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
|
qemu_spice_register_ports();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int qemu_spice_add_interface(SpiceBaseInstance *sin)
|
int qemu_spice_add_interface(SpiceBaseInstance *sin)
|
||||||
@ -732,6 +736,8 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
|
|||||||
*/
|
*/
|
||||||
spice_server = spice_server_new();
|
spice_server = spice_server_new();
|
||||||
spice_server_init(spice_server, &core_interface);
|
spice_server_init(spice_server, &core_interface);
|
||||||
|
qemu_add_vm_change_state_handler(vm_change_state_handler,
|
||||||
|
&spice_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
return spice_server_add_interface(spice_server, sin);
|
return spice_server_add_interface(spice_server, sin);
|
||||||
|
Loading…
Reference in New Issue
Block a user