1 #include "qemu/osdep.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 typedef struct SpiceCharSource
{
26 static QLIST_HEAD(, SpiceChardev
) spice_chars
=
27 QLIST_HEAD_INITIALIZER(spice_chars
);
29 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
31 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
32 Chardev
*chr
= (Chardev
*)scd
;
35 uint8_t* p
= (uint8_t*)buf
;
38 int can_write
= qemu_chr_be_can_write(chr
);
39 last_out
= MIN(len
, can_write
);
43 qemu_chr_be_write(chr
, p
, last_out
);
49 trace_spice_vmc_write(out
, len
+ out
);
53 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
55 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
56 int bytes
= MIN(len
, scd
->datalen
);
59 memcpy(buf
, scd
->datapos
, bytes
);
60 scd
->datapos
+= bytes
;
61 scd
->datalen
-= bytes
;
62 assert(scd
->datalen
>= 0);
64 if (scd
->datalen
== 0) {
68 trace_spice_vmc_read(bytes
, len
);
72 #if SPICE_SERVER_VERSION >= 0x000c02
73 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
75 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
76 Chardev
*chr
= (Chardev
*)scd
;
80 case SPICE_PORT_EVENT_BREAK
:
81 chr_event
= CHR_EVENT_BREAK
;
87 trace_spice_vmc_event(chr_event
);
88 qemu_chr_be_event(chr
, chr_event
);
92 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
94 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
95 Chardev
*chr
= (Chardev
*)scd
;
97 if ((chr
->be_open
&& connected
) ||
98 (!chr
->be_open
&& !connected
)) {
102 qemu_chr_be_event(chr
,
103 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
106 static SpiceCharDeviceInterface vmc_interface
= {
107 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
108 .base
.description
= "spice virtual channel char device",
109 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
110 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
114 #if SPICE_SERVER_VERSION >= 0x000c02
117 #if SPICE_SERVER_VERSION >= 0x000c06
118 .flags
= SPICE_CHAR_DEVICE_NOTIFY_WRITABLE
,
123 static void vmc_register_interface(SpiceChardev
*scd
)
128 scd
->sin
.base
.sif
= &vmc_interface
.base
;
129 qemu_spice_add_interface(&scd
->sin
.base
);
131 trace_spice_vmc_register_interface(scd
);
134 static void vmc_unregister_interface(SpiceChardev
*scd
)
139 spice_server_remove_interface(&scd
->sin
.base
);
141 trace_spice_vmc_unregister_interface(scd
);
144 static gboolean
spice_char_source_prepare(GSource
*source
, gint
*timeout
)
146 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
150 return !src
->scd
->blocked
;
153 static gboolean
spice_char_source_check(GSource
*source
)
155 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
157 return !src
->scd
->blocked
;
160 static gboolean
spice_char_source_dispatch(GSource
*source
,
161 GSourceFunc callback
, gpointer user_data
)
163 GIOFunc func
= (GIOFunc
)callback
;
165 return func(NULL
, G_IO_OUT
, user_data
);
168 static GSourceFuncs SpiceCharSourceFuncs
= {
169 .prepare
= spice_char_source_prepare
,
170 .check
= spice_char_source_check
,
171 .dispatch
= spice_char_source_dispatch
,
174 static GSource
*spice_chr_add_watch(Chardev
*chr
, GIOCondition cond
)
176 SpiceChardev
*scd
= (SpiceChardev
*)chr
;
177 SpiceCharSource
*src
;
179 assert(cond
& G_IO_OUT
);
181 src
= (SpiceCharSource
*)g_source_new(&SpiceCharSourceFuncs
,
182 sizeof(SpiceCharSource
));
185 return (GSource
*)src
;
188 static int spice_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
190 SpiceChardev
*s
= (SpiceChardev
*)chr
;
193 assert(s
->datalen
== 0);
196 spice_server_char_device_wakeup(&s
->sin
);
197 read_bytes
= len
- s
->datalen
;
198 if (read_bytes
!= len
) {
199 /* We'll get passed in the unconsumed data with the next call */
207 static void spice_chr_free(struct Chardev
*chr
)
209 SpiceChardev
*s
= (SpiceChardev
*)chr
;
211 vmc_unregister_interface(s
);
212 QLIST_REMOVE(s
, next
);
214 g_free((char *)s
->sin
.subtype
);
215 #if SPICE_SERVER_VERSION >= 0x000c02
216 g_free((char *)s
->sin
.portname
);
220 static void spice_vmc_set_fe_open(struct Chardev
*chr
, int fe_open
)
222 SpiceChardev
*s
= (SpiceChardev
*)chr
;
224 vmc_register_interface(s
);
226 vmc_unregister_interface(s
);
230 static void spice_port_set_fe_open(struct Chardev
*chr
, int fe_open
)
232 #if SPICE_SERVER_VERSION >= 0x000c02
233 SpiceChardev
*s
= (SpiceChardev
*)chr
;
236 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_OPENED
);
238 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_CLOSED
);
243 static void spice_chr_accept_input(struct Chardev
*chr
)
245 SpiceChardev
*s
= (SpiceChardev
*)chr
;
247 spice_server_char_device_wakeup(&s
->sin
);
250 static Chardev
*chr_open(const CharDriver
*driver
,
252 ChardevCommon
*backend
,
258 chr
= qemu_chr_alloc(driver
, backend
, errp
);
262 s
= (SpiceChardev
*)chr
;
264 s
->sin
.subtype
= g_strdup(subtype
);
266 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
271 static Chardev
*qemu_chr_open_spice_vmc(const CharDriver
*driver
,
273 ChardevBackend
*backend
,
278 ChardevSpiceChannel
*spicevmc
= backend
->u
.spicevmc
.data
;
279 const char *type
= spicevmc
->type
;
280 const char **psubtype
= spice_server_char_device_recognized_subtypes();
281 ChardevCommon
*common
= qapi_ChardevSpiceChannel_base(spicevmc
);
283 for (; *psubtype
!= NULL
; ++psubtype
) {
284 if (strcmp(type
, *psubtype
) == 0) {
288 if (*psubtype
== NULL
) {
289 char *subtypes
= g_strjoinv(", ",
290 (gchar
**)spice_server_char_device_recognized_subtypes());
292 error_setg(errp
, "unsupported type name: %s", type
);
293 error_append_hint(errp
, "allowed spice char type names: %s\n",
301 return chr_open(driver
, type
, common
, errp
);
304 #if SPICE_SERVER_VERSION >= 0x000c02
305 static Chardev
*qemu_chr_open_spice_port(const CharDriver
*driver
,
307 ChardevBackend
*backend
,
312 ChardevSpicePort
*spiceport
= backend
->u
.spiceport
.data
;
313 const char *name
= spiceport
->fqdn
;
314 ChardevCommon
*common
= qapi_ChardevSpicePort_base(spiceport
);
319 error_setg(errp
, "missing name parameter");
323 chr
= chr_open(driver
, "port", common
, errp
);
328 s
= (SpiceChardev
*)chr
;
329 s
->sin
.portname
= g_strdup(name
);
334 void qemu_spice_register_ports(void)
338 QLIST_FOREACH(s
, &spice_chars
, next
) {
339 if (s
->sin
.portname
== NULL
) {
342 vmc_register_interface(s
);
347 static void qemu_chr_parse_spice_vmc(QemuOpts
*opts
, ChardevBackend
*backend
,
350 const char *name
= qemu_opt_get(opts
, "name");
351 ChardevSpiceChannel
*spicevmc
;
354 error_setg(errp
, "chardev: spice channel: no name given");
357 spicevmc
= backend
->u
.spicevmc
.data
= g_new0(ChardevSpiceChannel
, 1);
358 qemu_chr_parse_common(opts
, qapi_ChardevSpiceChannel_base(spicevmc
));
359 spicevmc
->type
= g_strdup(name
);
362 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
365 const char *name
= qemu_opt_get(opts
, "name");
366 ChardevSpicePort
*spiceport
;
369 error_setg(errp
, "chardev: spice port: no name given");
372 spiceport
= backend
->u
.spiceport
.data
= g_new0(ChardevSpicePort
, 1);
373 qemu_chr_parse_common(opts
, qapi_ChardevSpicePort_base(spiceport
));
374 spiceport
->fqdn
= g_strdup(name
);
377 static void register_types(void)
379 static const CharDriver vmc_driver
= {
380 .instance_size
= sizeof(SpiceChardev
),
381 .kind
= CHARDEV_BACKEND_KIND_SPICEVMC
,
382 .parse
= qemu_chr_parse_spice_vmc
,
383 .create
= qemu_chr_open_spice_vmc
,
384 .chr_write
= spice_chr_write
,
385 .chr_add_watch
= spice_chr_add_watch
,
386 .chr_set_fe_open
= spice_vmc_set_fe_open
,
387 .chr_accept_input
= spice_chr_accept_input
,
388 .chr_free
= spice_chr_free
,
390 static const CharDriver port_driver
= {
391 .instance_size
= sizeof(SpiceChardev
),
392 .kind
= CHARDEV_BACKEND_KIND_SPICEPORT
,
393 .parse
= qemu_chr_parse_spice_port
,
394 .create
= qemu_chr_open_spice_port
,
395 .chr_write
= spice_chr_write
,
396 .chr_add_watch
= spice_chr_add_watch
,
397 .chr_set_fe_open
= spice_port_set_fe_open
,
398 .chr_accept_input
= spice_chr_accept_input
,
399 .chr_free
= spice_chr_free
,
401 register_char_driver(&vmc_driver
);
402 register_char_driver(&port_driver
);
405 type_init(register_types
);