1 #include "qemu/osdep.h"
3 #include "ui/qemu-spice.h"
4 #include "sysemu/char.h"
6 #include <spice/protocol.h>
9 typedef struct SpiceCharDriver
{
11 SpiceCharDeviceInstance sin
;
14 const uint8_t *datapos
;
16 QLIST_ENTRY(SpiceCharDriver
) next
;
19 typedef struct SpiceCharSource
{
24 static QLIST_HEAD(, SpiceCharDriver
) spice_chars
=
25 QLIST_HEAD_INITIALIZER(spice_chars
);
27 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
29 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
32 uint8_t* p
= (uint8_t*)buf
;
35 int can_write
= qemu_chr_be_can_write(scd
->chr
);
36 last_out
= MIN(len
, can_write
);
40 qemu_chr_be_write(scd
->chr
, p
, last_out
);
46 trace_spice_vmc_write(out
, len
+ out
);
50 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
52 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
53 int bytes
= MIN(len
, scd
->datalen
);
56 memcpy(buf
, scd
->datapos
, bytes
);
57 scd
->datapos
+= bytes
;
58 scd
->datalen
-= bytes
;
59 assert(scd
->datalen
>= 0);
61 if (scd
->datalen
== 0) {
65 trace_spice_vmc_read(bytes
, len
);
69 #if SPICE_SERVER_VERSION >= 0x000c02
70 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
72 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
76 case SPICE_PORT_EVENT_BREAK
:
77 chr_event
= CHR_EVENT_BREAK
;
83 trace_spice_vmc_event(chr_event
);
84 qemu_chr_be_event(scd
->chr
, chr_event
);
88 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
90 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
92 if ((scd
->chr
->be_open
&& connected
) ||
93 (!scd
->chr
->be_open
&& !connected
)) {
97 qemu_chr_be_event(scd
->chr
,
98 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
101 static SpiceCharDeviceInterface vmc_interface
= {
102 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
103 .base
.description
= "spice virtual channel char device",
104 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
105 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
109 #if SPICE_SERVER_VERSION >= 0x000c02
112 #if SPICE_SERVER_VERSION >= 0x000c06
113 .flags
= SPICE_CHAR_DEVICE_NOTIFY_WRITABLE
,
118 static void vmc_register_interface(SpiceCharDriver
*scd
)
123 scd
->sin
.base
.sif
= &vmc_interface
.base
;
124 qemu_spice_add_interface(&scd
->sin
.base
);
126 trace_spice_vmc_register_interface(scd
);
129 static void vmc_unregister_interface(SpiceCharDriver
*scd
)
134 spice_server_remove_interface(&scd
->sin
.base
);
136 trace_spice_vmc_unregister_interface(scd
);
139 static gboolean
spice_char_source_prepare(GSource
*source
, gint
*timeout
)
141 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
145 return !src
->scd
->blocked
;
148 static gboolean
spice_char_source_check(GSource
*source
)
150 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
152 return !src
->scd
->blocked
;
155 static gboolean
spice_char_source_dispatch(GSource
*source
,
156 GSourceFunc callback
, gpointer user_data
)
158 GIOFunc func
= (GIOFunc
)callback
;
160 return func(NULL
, G_IO_OUT
, user_data
);
163 static GSourceFuncs SpiceCharSourceFuncs
= {
164 .prepare
= spice_char_source_prepare
,
165 .check
= spice_char_source_check
,
166 .dispatch
= spice_char_source_dispatch
,
169 static GSource
*spice_chr_add_watch(CharDriverState
*chr
, GIOCondition cond
)
171 SpiceCharDriver
*scd
= chr
->opaque
;
172 SpiceCharSource
*src
;
174 assert(cond
& G_IO_OUT
);
176 src
= (SpiceCharSource
*)g_source_new(&SpiceCharSourceFuncs
,
177 sizeof(SpiceCharSource
));
180 return (GSource
*)src
;
183 static int spice_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
185 SpiceCharDriver
*s
= chr
->opaque
;
188 assert(s
->datalen
== 0);
191 spice_server_char_device_wakeup(&s
->sin
);
192 read_bytes
= len
- s
->datalen
;
193 if (read_bytes
!= len
) {
194 /* We'll get passed in the unconsumed data with the next call */
202 static void spice_chr_free(struct CharDriverState
*chr
)
204 SpiceCharDriver
*s
= chr
->opaque
;
206 vmc_unregister_interface(s
);
207 QLIST_REMOVE(s
, next
);
209 g_free((char *)s
->sin
.subtype
);
210 #if SPICE_SERVER_VERSION >= 0x000c02
211 g_free((char *)s
->sin
.portname
);
216 static void spice_vmc_set_fe_open(struct CharDriverState
*chr
, int fe_open
)
218 SpiceCharDriver
*s
= chr
->opaque
;
220 vmc_register_interface(s
);
222 vmc_unregister_interface(s
);
226 static void spice_port_set_fe_open(struct CharDriverState
*chr
, int fe_open
)
228 #if SPICE_SERVER_VERSION >= 0x000c02
229 SpiceCharDriver
*s
= chr
->opaque
;
232 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_OPENED
);
234 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_CLOSED
);
239 static void print_allowed_subtypes(void)
241 const char** psubtype
;
244 fprintf(stderr
, "allowed names: ");
245 for(i
=0, psubtype
= spice_server_char_device_recognized_subtypes();
246 *psubtype
!= NULL
; ++psubtype
, ++i
) {
248 fprintf(stderr
, "%s", *psubtype
);
250 fprintf(stderr
, ", %s", *psubtype
);
253 fprintf(stderr
, "\n");
256 static void spice_chr_accept_input(struct CharDriverState
*chr
)
258 SpiceCharDriver
*s
= chr
->opaque
;
260 spice_server_char_device_wakeup(&s
->sin
);
263 static CharDriverState
*chr_open(const CharDriver
*driver
,
265 ChardevCommon
*backend
,
268 CharDriverState
*chr
;
271 chr
= qemu_chr_alloc(driver
, backend
, errp
);
275 s
= g_malloc0(sizeof(SpiceCharDriver
));
278 s
->sin
.subtype
= g_strdup(subtype
);
281 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
286 static CharDriverState
*qemu_chr_open_spice_vmc(const CharDriver
*driver
,
288 ChardevBackend
*backend
,
293 ChardevSpiceChannel
*spicevmc
= backend
->u
.spicevmc
.data
;
294 const char *type
= spicevmc
->type
;
295 const char **psubtype
= spice_server_char_device_recognized_subtypes();
296 ChardevCommon
*common
= qapi_ChardevSpiceChannel_base(spicevmc
);
298 for (; *psubtype
!= NULL
; ++psubtype
) {
299 if (strcmp(type
, *psubtype
) == 0) {
303 if (*psubtype
== NULL
) {
304 fprintf(stderr
, "spice-qemu-char: unsupported type: %s\n", type
);
305 print_allowed_subtypes();
310 return chr_open(driver
, type
, common
, errp
);
313 #if SPICE_SERVER_VERSION >= 0x000c02
314 static CharDriverState
*qemu_chr_open_spice_port(const CharDriver
*driver
,
316 ChardevBackend
*backend
,
321 ChardevSpicePort
*spiceport
= backend
->u
.spiceport
.data
;
322 const char *name
= spiceport
->fqdn
;
323 ChardevCommon
*common
= qapi_ChardevSpicePort_base(spiceport
);
324 CharDriverState
*chr
;
328 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
332 chr
= chr_open(driver
, "port", common
, errp
);
338 s
->sin
.portname
= g_strdup(name
);
343 void qemu_spice_register_ports(void)
347 QLIST_FOREACH(s
, &spice_chars
, next
) {
348 if (s
->sin
.portname
== NULL
) {
351 vmc_register_interface(s
);
356 static void qemu_chr_parse_spice_vmc(QemuOpts
*opts
, ChardevBackend
*backend
,
359 const char *name
= qemu_opt_get(opts
, "name");
360 ChardevSpiceChannel
*spicevmc
;
363 error_setg(errp
, "chardev: spice channel: no name given");
366 spicevmc
= backend
->u
.spicevmc
.data
= g_new0(ChardevSpiceChannel
, 1);
367 qemu_chr_parse_common(opts
, qapi_ChardevSpiceChannel_base(spicevmc
));
368 spicevmc
->type
= g_strdup(name
);
371 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
374 const char *name
= qemu_opt_get(opts
, "name");
375 ChardevSpicePort
*spiceport
;
378 error_setg(errp
, "chardev: spice port: no name given");
381 spiceport
= backend
->u
.spiceport
.data
= g_new0(ChardevSpicePort
, 1);
382 qemu_chr_parse_common(opts
, qapi_ChardevSpicePort_base(spiceport
));
383 spiceport
->fqdn
= g_strdup(name
);
386 static void register_types(void)
388 static const CharDriver vmc_driver
= {
389 .kind
= CHARDEV_BACKEND_KIND_SPICEVMC
,
390 .parse
= qemu_chr_parse_spice_vmc
,
391 .create
= qemu_chr_open_spice_vmc
,
392 .chr_write
= spice_chr_write
,
393 .chr_add_watch
= spice_chr_add_watch
,
394 .chr_set_fe_open
= spice_vmc_set_fe_open
,
395 .chr_accept_input
= spice_chr_accept_input
,
396 .chr_free
= spice_chr_free
,
398 static const CharDriver port_driver
= {
399 .kind
= CHARDEV_BACKEND_KIND_SPICEPORT
,
400 .parse
= qemu_chr_parse_spice_port
,
401 .create
= qemu_chr_open_spice_port
,
402 .chr_write
= spice_chr_write
,
403 .chr_add_watch
= spice_chr_add_watch
,
404 .chr_set_fe_open
= spice_port_set_fe_open
,
405 .chr_accept_input
= spice_chr_accept_input
,
406 .chr_free
= spice_chr_free
,
408 register_char_driver(&vmc_driver
);
409 register_char_driver(&port_driver
);
412 type_init(register_types
);