Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Xing Lin
qemu
Commits
9363ee31
Commit
9363ee31
authored
Feb 01, 2011
by
Anthony Liguori
Browse files
Merge remote branch 'spice/spice.v29.pull' into staging
Conflicts: trace-events
parents
cfb41c82
cbcc6336
Changes
17
Hide whitespace changes
Inline
Side-by-side
MAINTAINERS
View file @
9363ee31
...
...
@@ -383,6 +383,14 @@ S: Odd Fixes
F: gdbstub*
F: gdb-xml/
SPICE
M: Gerd Hoffmann <kraxel@redhat.com>
S: Supported
F: ui/qemu-spice.h
F: ui/spice-*.c
F: audio/spiceaudio.c
F: hw/qxl*
Graphics
M: Anthony Liguori <aliguori@us.ibm.com>
S: Maintained
...
...
Makefile.objs
View file @
9363ee31
...
...
@@ -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
...
...
configure
View file @
9363ee31
...
...
@@ -2208,9 +2208,9 @@ if test "$spice" != "no" ; then
#include <spice.h>
int main(void) { spice_server_new(); return 0; }
EOF
spice_cflags
=
$(
$pkgconfig
--cflags
spice-protocol spice-server 2>/dev/null
)
spice_libs
=
$(
$pkgconfig
--libs
spice-protocol spice-server 2>/dev/null
)
if
$pkgconfig
--atleast-version
=
0.5.3 spice-server
>
/dev/null 2>&1
&&
\
spice_cflags
=
$(
$pkg
_
config
--cflags
spice-protocol spice-server 2>/dev/null
)
spice_libs
=
$(
$pkg
_
config
--libs
spice-protocol spice-server 2>/dev/null
)
if
$pkg
_
config
--atleast-version
=
0.5.3 spice-server
>
/dev/null 2>&1
&&
\
compile_prog
"
$spice_cflags
"
"
$spice_libs
"
;
then
spice
=
"yes"
libs_softmmu
=
"
$libs_softmmu
$spice_libs
"
...
...
hmp-commands.hx
View file @
9363ee31
...
...
@@ -833,6 +833,23 @@ ETEXI
.mhandler.cmd_new = do_snapshot_blkdev,
},
STEXI
@item client_migrate_info @var{protocol} @var{hostname} @var{port} @var{tls-port} @var{cert-subject}
@findex client_migrate_info
Set the spice/vnc connection info for the migration target. The spice/vnc
server will ask the spice/vnc client to automatically reconnect using the
new parameters (if specified) once the vm migration finished successfully.
ETEXI
{
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
.help = "send migration info to spice/vnc client",
.user_print = monitor_user_noop,
.mhandler.cmd_new = client_migrate_info,
},
STEXI
@item snapshot_blkdev
@findex snapshot_blkdev
...
...
hw/qxl.c
View file @
9363ee31
...
...
@@ -866,7 +866,9 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
dprint
(
d
,
1
,
"%s
\n
"
,
__FUNCTION__
);
d
->
mode
=
QXL_MODE_UNDEFINED
;
qemu_mutex_unlock_iothread
();
d
->
ssd
.
worker
->
destroy_primary_surface
(
d
->
ssd
.
worker
,
0
);
qemu_mutex_lock_iothread
();
}
static
void
qxl_set_mode
(
PCIQXLDevice
*
d
,
int
modenr
,
int
loadvm
)
...
...
@@ -1418,43 +1420,10 @@ static int qxl_post_load(void *opaque, int version)
}
dprint
(
d
,
1
,
"%s: done
\n
"
,
__FUNCTION__
);
/* spice 0.4 compatibility -- accept but ignore */
qemu_free
(
d
->
worker_data
);
d
->
worker_data
=
NULL
;
d
->
worker_data_size
=
0
;
return
0
;
}
#define QXL_SAVE_VERSION 20
static
bool
qxl_test_worker_data
(
void
*
opaque
,
int
version_id
)
{
PCIQXLDevice
*
d
=
opaque
;
if
(
d
->
revision
!=
1
)
{
return
false
;
}
if
(
!
d
->
worker_data_size
)
{
return
false
;
}
if
(
!
d
->
worker_data
)
{
d
->
worker_data
=
qemu_malloc
(
d
->
worker_data_size
);
}
return
true
;
}
static
bool
qxl_test_spice04
(
void
*
opaque
,
int
version_id
)
{
PCIQXLDevice
*
d
=
opaque
;
return
d
->
revision
==
1
;
}
static
bool
qxl_test_spice06
(
void
*
opaque
)
{
PCIQXLDevice
*
d
=
opaque
;
return
d
->
revision
>
1
;
}
#define QXL_SAVE_VERSION 21
static
VMStateDescription
qxl_memslot
=
{
.
name
=
"qxl-memslot"
,
...
...
@@ -1486,24 +1455,6 @@ static VMStateDescription qxl_surface = {
}
};
static
VMStateDescription
qxl_vmstate_spice06
=
{
.
name
=
"qxl/spice06"
,
.
version_id
=
QXL_SAVE_VERSION
,
.
minimum_version_id
=
QXL_SAVE_VERSION
,
.
fields
=
(
VMStateField
[])
{
VMSTATE_INT32_EQUAL
(
num_memslots
,
PCIQXLDevice
),
VMSTATE_STRUCT_ARRAY
(
guest_slots
,
PCIQXLDevice
,
NUM_MEMSLOTS
,
0
,
qxl_memslot
,
struct
guest_slots
),
VMSTATE_STRUCT
(
guest_primary
.
surface
,
PCIQXLDevice
,
0
,
qxl_surface
,
QXLSurfaceCreate
),
VMSTATE_INT32_EQUAL
(
num_surfaces
,
PCIQXLDevice
),
VMSTATE_ARRAY
(
guest_surfaces
.
cmds
,
PCIQXLDevice
,
NUM_SURFACES
,
0
,
vmstate_info_uint64
,
uint64_t
),
VMSTATE_UINT64
(
guest_cursor
,
PCIQXLDevice
),
VMSTATE_END_OF_LIST
()
},
};
static
VMStateDescription
qxl_vmstate
=
{
.
name
=
"qxl"
,
.
version_id
=
QXL_SAVE_VERSION
,
...
...
@@ -1519,25 +1470,17 @@ static VMStateDescription qxl_vmstate = {
VMSTATE_UINT32
(
last_release_offset
,
PCIQXLDevice
),
VMSTATE_UINT32
(
mode
,
PCIQXLDevice
),
VMSTATE_UINT32
(
ssd
.
unique
,
PCIQXLDevice
),
/* spice 0.4 sends/expects them */
VMSTATE_VBUFFER_UINT32
(
vga
.
vram_ptr
,
PCIQXLDevice
,
0
,
qxl_test_spice04
,
0
,
vga
.
vram_size
),
VMSTATE_UINT32_TEST
(
worker_data_size
,
PCIQXLDevice
,
qxl_test_spice04
),
VMSTATE_VBUFFER_UINT32
(
worker_data
,
PCIQXLDevice
,
0
,
qxl_test_worker_data
,
0
,
worker_data_size
),
VMSTATE_INT32_EQUAL
(
num_memslots
,
PCIQXLDevice
),
VMSTATE_STRUCT_ARRAY
(
guest_slots
,
PCIQXLDevice
,
NUM_MEMSLOTS
,
0
,
qxl_memslot
,
struct
guest_slots
),
VMSTATE_STRUCT
(
guest_primary
.
surface
,
PCIQXLDevice
,
0
,
qxl_surface
,
QXLSurfaceCreate
),
VMSTATE_INT32_EQUAL
(
num_surfaces
,
PCIQXLDevice
),
VMSTATE_ARRAY
(
guest_surfaces
.
cmds
,
PCIQXLDevice
,
NUM_SURFACES
,
0
,
vmstate_info_uint64
,
uint64_t
),
VMSTATE_UINT64
(
guest_cursor
,
PCIQXLDevice
),
VMSTATE_END_OF_LIST
()
},
.
subsections
=
(
VMStateSubsection
[])
{
{
/* additional spice 0.6 state */
.
vmsd
=
&
qxl_vmstate_spice06
,
.
needed
=
qxl_test_spice06
,
},{
/* end of list */
},
},
};
static
PCIDeviceInfo
qxl_info_primary
=
{
...
...
hw/qxl.h
View file @
9363ee31
...
...
@@ -80,10 +80,6 @@ typedef struct PCIQXLDevice {
/* io bar */
uint32_t
io_base
;
/* spice 0.4 loadvm compatibility */
void
*
worker_data
;
uint32_t
worker_data_size
;
}
PCIQXLDevice
;
#define PANIC_ON(x) if ((x)) { \
...
...
migration.c
View file @
9363ee31
...
...
@@ -36,6 +36,9 @@ static int64_t max_throttle = (32 << 20);
static
MigrationState
*
current_migration
;
static
NotifierList
migration_state_notifiers
=
NOTIFIER_LIST_INITIALIZER
(
migration_state_notifiers
);
int
qemu_start_incoming_migration
(
const
char
*
uri
)
{
const
char
*
p
;
...
...
@@ -121,6 +124,7 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
}
current_migration
=
s
;
notifier_list_notify
(
&
migration_state_notifiers
);
return
0
;
}
...
...
@@ -272,6 +276,7 @@ void migrate_fd_error(FdMigrationState *s)
{
DPRINTF
(
"setting error state
\n
"
);
s
->
state
=
MIG_STATE_ERROR
;
notifier_list_notify
(
&
migration_state_notifiers
);
migrate_fd_cleanup
(
s
);
}
...
...
@@ -329,6 +334,7 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
monitor_resume
(
s
->
mon
);
}
s
->
state
=
MIG_STATE_ERROR
;
notifier_list_notify
(
&
migration_state_notifiers
);
}
return
ret
;
...
...
@@ -389,6 +395,7 @@ void migrate_fd_put_ready(void *opaque)
state
=
MIG_STATE_ERROR
;
}
s
->
state
=
state
;
notifier_list_notify
(
&
migration_state_notifiers
);
}
}
...
...
@@ -408,6 +415,7 @@ void migrate_fd_cancel(MigrationState *mig_state)
DPRINTF
(
"cancelling migration
\n
"
);
s
->
state
=
MIG_STATE_CANCELLED
;
notifier_list_notify
(
&
migration_state_notifiers
);
qemu_savevm_state_cancel
(
s
->
mon
,
s
->
file
);
migrate_fd_cleanup
(
s
);
...
...
@@ -421,6 +429,7 @@ void migrate_fd_release(MigrationState *mig_state)
if
(
s
->
state
==
MIG_STATE_ACTIVE
)
{
s
->
state
=
MIG_STATE_CANCELLED
;
notifier_list_notify
(
&
migration_state_notifiers
);
migrate_fd_cleanup
(
s
);
}
qemu_free
(
s
);
...
...
@@ -452,3 +461,22 @@ int migrate_fd_close(void *opaque)
qemu_set_fd_handler2
(
s
->
fd
,
NULL
,
NULL
,
NULL
,
NULL
);
return
s
->
close
(
s
);
}
void
add_migration_state_change_notifier
(
Notifier
*
notify
)
{
notifier_list_add
(
&
migration_state_notifiers
,
notify
);
}
void
remove_migration_state_change_notifier
(
Notifier
*
notify
)
{
notifier_list_remove
(
&
migration_state_notifiers
,
notify
);
}
int
get_migration_state
(
void
)
{
if
(
current_migration
)
{
return
migrate_fd_get_status
(
current_migration
);
}
else
{
return
MIG_STATE_ERROR
;
}
}
migration.h
View file @
9363ee31
...
...
@@ -16,6 +16,7 @@
#include "qdict.h"
#include "qemu-common.h"
#include "notify.h"
#define MIG_STATE_ERROR -1
#define MIG_STATE_COMPLETED 0
...
...
@@ -134,4 +135,8 @@ static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
return
container_of
(
mig_state
,
FdMigrationState
,
mig_state
);
}
void
add_migration_state_change_notifier
(
Notifier
*
notify
);
void
remove_migration_state_change_notifier
(
Notifier
*
notify
);
int
get_migration_state
(
void
);
#endif
monitor.c
View file @
9363ee31
...
...
@@ -1146,9 +1146,9 @@ static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
time_t
when
;
int
rc
;
if
(
strcmp
(
whenstr
,
"now"
))
{
if
(
strcmp
(
whenstr
,
"now"
)
==
0
)
{
when
=
0
;
}
else
if
(
strcmp
(
whenstr
,
"never"
))
{
}
else
if
(
strcmp
(
whenstr
,
"never"
)
==
0
)
{
when
=
TIME_MAX
;
}
else
if
(
whenstr
[
0
]
==
'+'
)
{
when
=
time
(
NULL
)
+
strtoull
(
whenstr
+
1
,
NULL
,
10
);
...
...
@@ -1183,6 +1183,33 @@ static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
return
-
1
;
}
static
int
client_migrate_info
(
Monitor
*
mon
,
const
QDict
*
qdict
,
QObject
**
ret_data
)
{
const
char
*
protocol
=
qdict_get_str
(
qdict
,
"protocol"
);
const
char
*
hostname
=
qdict_get_str
(
qdict
,
"hostname"
);
const
char
*
subject
=
qdict_get_try_str
(
qdict
,
"cert-subject"
);
int
port
=
qdict_get_try_int
(
qdict
,
"port"
,
-
1
);
int
tls_port
=
qdict_get_try_int
(
qdict
,
"tls-port"
,
-
1
);
int
ret
;
if
(
strcmp
(
protocol
,
"spice"
)
==
0
)
{
if
(
!
using_spice
)
{
qerror_report
(
QERR_DEVICE_NOT_ACTIVE
,
"spice"
);
return
-
1
;
}
ret
=
qemu_spice_migrate_info
(
hostname
,
port
,
tls_port
,
subject
);
if
(
ret
!=
0
)
{
qerror_report
(
QERR_UNDEFINED_ERROR
);
return
-
1
;
}
return
0
;
}
qerror_report
(
QERR_INVALID_PARAMETER
,
"protocol"
);
return
-
1
;
}
static
int
do_screen_dump
(
Monitor
*
mon
,
const
QDict
*
qdict
,
QObject
**
ret_data
)
{
vga_hw_screen_dump
(
qdict_get_str
(
qdict
,
"filename"
));
...
...
qemu-char.c
View file @
9363ee31
...
...
@@ -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
,
...
...
qemu-config.c
View file @
9363ee31
...
...
@@ -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 */
}
},
...
...
qemu-options.hx
View file @
9363ee31
...
...
@@ -1367,6 +1367,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
#endif
#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,name=name[,debug=debug]\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
...
...
qmp-commands.hx
View file @
9363ee31
...
...
@@ -502,6 +502,41 @@ EQMP
.mhandler.cmd_new = do_migrate_set_speed,
},
SQMP
client_migrate_info
------------------
Set the spice/vnc connection info for the migration target. The spice/vnc
server will ask the spice/vnc client to automatically reconnect using the
new parameters (if specified) once the vm migration finished successfully.
Arguments:
- "protocol": protocol: "spice" or "vnc" (json-string)
- "hostname": migration target hostname (json-string)
- "port": spice/vnc tcp port for plaintext channels (json-int, optional)
- "tls-port": spice tcp port for tls-secured channels (json-int, optional)
- "cert-subject": server certificate subject (json-string, optional)
Example:
-> { "execute": "client_migrate_info",
"arguments": { "protocol": "spice",
"hostname": "virt42.lab.kraxel.org",
"port": 1234 } }
<- { "return": {} }
EQMP
{
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
.help = "send migration info to spice/vnc client",
.user_print = monitor_user_noop,
.mhandler.cmd_new = client_migrate_info,
},
SQMP
migrate_set_speed
-----------------
...
...
spice-qemu-char.c
0 → 100644
View file @
9363ee31
#include "config-host.h"
#include "trace.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
);
trace_spice_vmc_write
(
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
;
}
}
trace_spice_vmc_read
(
bytes
,
len
);
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
;
trace_spice_vmc_register_interface
(
scd
);
}
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
;
trace_spice_vmc_unregister_interface
(
scd
);
}
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
;
}
trace-events