1 #include "qemu/osdep.h"
2 #include "trace-root.h"
3 #include "ui/qemu-spice.h"
4 #include "sysemu/char.h"
5 #include "qemu/error-report.h"
7 #include <spice/protocol.h>
10 typedef struct SpiceChardev
{
13 SpiceCharDeviceInstance sin
;
16 const uint8_t *datapos
;
18 QLIST_ENTRY(SpiceChardev
) next
;
21 #define TYPE_CHARDEV_SPICE "chardev-spice"
22 #define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
23 #define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"
25 #define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE)
27 typedef struct SpiceCharSource
{
32 static QLIST_HEAD(, SpiceChardev
) spice_chars
=
33 QLIST_HEAD_INITIALIZER(spice_chars
);
35 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
37 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
38 Chardev
*chr
= CHARDEV(scd
);
41 uint8_t* p
= (uint8_t*)buf
;
44 int can_write
= qemu_chr_be_can_write(chr
);
45 last_out
= MIN(len
, can_write
);
49 qemu_chr_be_write(chr
, p
, last_out
);
55 trace_spice_vmc_write(out
, len
+ out
);
59 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
61 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
62 int bytes
= MIN(len
, scd
->datalen
);
65 memcpy(buf
, scd
->datapos
, bytes
);
66 scd
->datapos
+= bytes
;
67 scd
->datalen
-= bytes
;
68 assert(scd
->datalen
>= 0);
70 if (scd
->datalen
== 0) {
74 trace_spice_vmc_read(bytes
, len
);
78 #if SPICE_SERVER_VERSION >= 0x000c02
79 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
81 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
82 Chardev
*chr
= CHARDEV(scd
);
86 case SPICE_PORT_EVENT_BREAK
:
87 chr_event
= CHR_EVENT_BREAK
;
93 trace_spice_vmc_event(chr_event
);
94 qemu_chr_be_event(chr
, chr_event
);
98 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
100 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
101 Chardev
*chr
= CHARDEV(scd
);
103 if ((chr
->be_open
&& connected
) ||
104 (!chr
->be_open
&& !connected
)) {
108 qemu_chr_be_event(chr
,
109 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
112 static SpiceCharDeviceInterface vmc_interface
= {
113 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
114 .base
.description
= "spice virtual channel char device",
115 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
116 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
120 #if SPICE_SERVER_VERSION >= 0x000c02
123 #if SPICE_SERVER_VERSION >= 0x000c06
124 .flags
= SPICE_CHAR_DEVICE_NOTIFY_WRITABLE
,
129 static void vmc_register_interface(SpiceChardev
*scd
)
134 scd
->sin
.base
.sif
= &vmc_interface
.base
;
135 qemu_spice_add_interface(&scd
->sin
.base
);
137 trace_spice_vmc_register_interface(scd
);
140 static void vmc_unregister_interface(SpiceChardev
*scd
)
145 spice_server_remove_interface(&scd
->sin
.base
);
147 trace_spice_vmc_unregister_interface(scd
);
150 static gboolean
spice_char_source_prepare(GSource
*source
, gint
*timeout
)
152 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
156 return !src
->scd
->blocked
;
159 static gboolean
spice_char_source_check(GSource
*source
)
161 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
163 return !src
->scd
->blocked
;
166 static gboolean
spice_char_source_dispatch(GSource
*source
,
167 GSourceFunc callback
, gpointer user_data
)
169 GIOFunc func
= (GIOFunc
)callback
;
171 return func(NULL
, G_IO_OUT
, user_data
);
174 static GSourceFuncs SpiceCharSourceFuncs
= {
175 .prepare
= spice_char_source_prepare
,
176 .check
= spice_char_source_check
,
177 .dispatch
= spice_char_source_dispatch
,
180 static GSource
*spice_chr_add_watch(Chardev
*chr
, GIOCondition cond
)
182 SpiceChardev
*scd
= SPICE_CHARDEV(chr
);
183 SpiceCharSource
*src
;
185 assert(cond
& G_IO_OUT
);
187 src
= (SpiceCharSource
*)g_source_new(&SpiceCharSourceFuncs
,
188 sizeof(SpiceCharSource
));
191 return (GSource
*)src
;
194 static int spice_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
196 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
199 assert(s
->datalen
== 0);
202 spice_server_char_device_wakeup(&s
->sin
);
203 read_bytes
= len
- s
->datalen
;
204 if (read_bytes
!= len
) {
205 /* We'll get passed in the unconsumed data with the next call */
213 static void char_spice_finalize(Object
*obj
)
215 SpiceChardev
*s
= SPICE_CHARDEV(obj
);
217 vmc_unregister_interface(s
);
218 QLIST_REMOVE(s
, next
);
220 g_free((char *)s
->sin
.subtype
);
221 #if SPICE_SERVER_VERSION >= 0x000c02
222 g_free((char *)s
->sin
.portname
);
226 static void spice_vmc_set_fe_open(struct Chardev
*chr
, int fe_open
)
228 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
230 vmc_register_interface(s
);
232 vmc_unregister_interface(s
);
236 static void spice_port_set_fe_open(struct Chardev
*chr
, int fe_open
)
238 #if SPICE_SERVER_VERSION >= 0x000c02
239 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
242 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_OPENED
);
244 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_CLOSED
);
249 static void spice_chr_accept_input(struct Chardev
*chr
)
251 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
253 spice_server_char_device_wakeup(&s
->sin
);
256 static void chr_open(Chardev
*chr
, const char *subtype
)
258 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
261 s
->sin
.subtype
= g_strdup(subtype
);
263 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
266 static void qemu_chr_open_spice_vmc(Chardev
*chr
,
267 ChardevBackend
*backend
,
271 ChardevSpiceChannel
*spicevmc
= backend
->u
.spicevmc
.data
;
272 const char *type
= spicevmc
->type
;
273 const char **psubtype
= spice_server_char_device_recognized_subtypes();
275 for (; *psubtype
!= NULL
; ++psubtype
) {
276 if (strcmp(type
, *psubtype
) == 0) {
280 if (*psubtype
== NULL
) {
281 char *subtypes
= g_strjoinv(", ",
282 (gchar
**)spice_server_char_device_recognized_subtypes());
284 error_setg(errp
, "unsupported type name: %s", type
);
285 error_append_hint(errp
, "allowed spice char type names: %s\n",
296 #if SPICE_SERVER_VERSION >= 0x000c02
297 static void qemu_chr_open_spice_port(Chardev
*chr
,
298 ChardevBackend
*backend
,
302 ChardevSpicePort
*spiceport
= backend
->u
.spiceport
.data
;
303 const char *name
= spiceport
->fqdn
;
307 error_setg(errp
, "missing name parameter");
311 chr_open(chr
, "port");
314 s
= SPICE_CHARDEV(chr
);
315 s
->sin
.portname
= g_strdup(name
);
318 void qemu_spice_register_ports(void)
322 QLIST_FOREACH(s
, &spice_chars
, next
) {
323 if (s
->sin
.portname
== NULL
) {
326 vmc_register_interface(s
);
331 static void qemu_chr_parse_spice_vmc(QemuOpts
*opts
, ChardevBackend
*backend
,
334 const char *name
= qemu_opt_get(opts
, "name");
335 ChardevSpiceChannel
*spicevmc
;
338 error_setg(errp
, "chardev: spice channel: no name given");
341 backend
->type
= CHARDEV_BACKEND_KIND_SPICEVMC
;
342 spicevmc
= backend
->u
.spicevmc
.data
= g_new0(ChardevSpiceChannel
, 1);
343 qemu_chr_parse_common(opts
, qapi_ChardevSpiceChannel_base(spicevmc
));
344 spicevmc
->type
= g_strdup(name
);
347 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
350 const char *name
= qemu_opt_get(opts
, "name");
351 ChardevSpicePort
*spiceport
;
354 error_setg(errp
, "chardev: spice port: no name given");
357 backend
->type
= CHARDEV_BACKEND_KIND_SPICEPORT
;
358 spiceport
= backend
->u
.spiceport
.data
= g_new0(ChardevSpicePort
, 1);
359 qemu_chr_parse_common(opts
, qapi_ChardevSpicePort_base(spiceport
));
360 spiceport
->fqdn
= g_strdup(name
);
363 static void char_spice_class_init(ObjectClass
*oc
, void *data
)
365 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
367 cc
->chr_write
= spice_chr_write
;
368 cc
->chr_add_watch
= spice_chr_add_watch
;
369 cc
->chr_accept_input
= spice_chr_accept_input
;
372 static const TypeInfo char_spice_type_info
= {
373 .name
= TYPE_CHARDEV_SPICE
,
374 .parent
= TYPE_CHARDEV
,
375 .instance_size
= sizeof(SpiceChardev
),
376 .instance_finalize
= char_spice_finalize
,
377 .class_init
= char_spice_class_init
,
381 static void char_spicevmc_class_init(ObjectClass
*oc
, void *data
)
383 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
385 cc
->parse
= qemu_chr_parse_spice_vmc
;
386 cc
->open
= qemu_chr_open_spice_vmc
;
387 cc
->chr_set_fe_open
= spice_vmc_set_fe_open
;
390 static const TypeInfo char_spicevmc_type_info
= {
391 .name
= TYPE_CHARDEV_SPICEVMC
,
392 .parent
= TYPE_CHARDEV_SPICE
,
393 .class_init
= char_spicevmc_class_init
,
396 static void char_spiceport_class_init(ObjectClass
*oc
, void *data
)
398 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
400 cc
->parse
= qemu_chr_parse_spice_port
;
401 cc
->open
= qemu_chr_open_spice_port
;
402 cc
->chr_set_fe_open
= spice_port_set_fe_open
;
405 static const TypeInfo char_spiceport_type_info
= {
406 .name
= TYPE_CHARDEV_SPICEPORT
,
407 .parent
= TYPE_CHARDEV_SPICE
,
408 .class_init
= char_spiceport_class_init
,
411 static void register_types(void)
413 type_register_static(&char_spice_type_info
);
414 type_register_static(&char_spicevmc_type_info
);
415 type_register_static(&char_spiceport_type_info
);
418 type_init(register_types
);