1 #include "qemu/osdep.h"
3 #include "ui/qemu-spice.h"
4 #include "chardev/char.h"
5 #include "chardev/spice.h"
6 #include "qapi/error.h"
7 #include "qemu/error-report.h"
8 #include "qemu/module.h"
9 #include "qemu/option.h"
10 #include <spice/protocol.h>
12 typedef struct SpiceCharSource
{
17 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
19 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
20 Chardev
*chr
= CHARDEV(scd
);
23 uint8_t* p
= (uint8_t*)buf
;
26 int can_write
= qemu_chr_be_can_write(chr
);
27 last_out
= MIN(len
, can_write
);
31 qemu_chr_be_write(chr
, p
, last_out
);
37 trace_spice_vmc_write(out
, len
+ out
);
41 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
43 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
44 int bytes
= MIN(len
, scd
->datalen
);
47 memcpy(buf
, scd
->datapos
, bytes
);
48 scd
->datapos
+= bytes
;
49 scd
->datalen
-= bytes
;
50 assert(scd
->datalen
>= 0);
52 if (scd
->datalen
== 0) {
56 trace_spice_vmc_read(bytes
, len
);
60 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
62 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
63 Chardev
*chr
= CHARDEV(scd
);
67 case SPICE_PORT_EVENT_BREAK
:
68 chr_event
= CHR_EVENT_BREAK
;
74 trace_spice_vmc_event(chr_event
);
75 qemu_chr_be_event(chr
, chr_event
);
78 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
80 SpiceChardev
*scd
= container_of(sin
, SpiceChardev
, sin
);
81 Chardev
*chr
= CHARDEV(scd
);
83 if ((chr
->be_open
&& connected
) ||
84 (!chr
->be_open
&& !connected
)) {
88 qemu_chr_be_event(chr
,
89 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
92 static SpiceCharDeviceInterface vmc_interface
= {
93 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
94 .base
.description
= "spice virtual channel char device",
95 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
96 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
101 #if SPICE_SERVER_VERSION >= 0x000c06
102 .flags
= SPICE_CHAR_DEVICE_NOTIFY_WRITABLE
,
107 static void vmc_register_interface(SpiceChardev
*scd
)
112 scd
->sin
.base
.sif
= &vmc_interface
.base
;
113 qemu_spice
.add_interface(&scd
->sin
.base
);
115 trace_spice_vmc_register_interface(scd
);
118 static void vmc_unregister_interface(SpiceChardev
*scd
)
123 spice_server_remove_interface(&scd
->sin
.base
);
125 trace_spice_vmc_unregister_interface(scd
);
128 static gboolean
spice_char_source_prepare(GSource
*source
, gint
*timeout
)
130 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
131 Chardev
*chr
= CHARDEV(src
->scd
);
139 return !src
->scd
->blocked
;
142 static gboolean
spice_char_source_check(GSource
*source
)
144 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
145 Chardev
*chr
= CHARDEV(src
->scd
);
151 return !src
->scd
->blocked
;
154 static gboolean
spice_char_source_dispatch(GSource
*source
,
155 GSourceFunc callback
, gpointer user_data
)
157 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
158 Chardev
*chr
= CHARDEV(src
->scd
);
159 GIOFunc func
= (GIOFunc
)callback
;
160 GIOCondition cond
= chr
->be_open
? G_IO_OUT
: G_IO_HUP
;
162 return func(NULL
, cond
, user_data
);
165 static GSourceFuncs SpiceCharSourceFuncs
= {
166 .prepare
= spice_char_source_prepare
,
167 .check
= spice_char_source_check
,
168 .dispatch
= spice_char_source_dispatch
,
171 static GSource
*spice_chr_add_watch(Chardev
*chr
, GIOCondition cond
)
173 SpiceChardev
*scd
= SPICE_CHARDEV(chr
);
174 SpiceCharSource
*src
;
176 assert(cond
& G_IO_OUT
);
178 src
= (SpiceCharSource
*)g_source_new(&SpiceCharSourceFuncs
,
179 sizeof(SpiceCharSource
));
182 return (GSource
*)src
;
185 static int spice_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
187 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
190 assert(s
->datalen
== 0);
193 trace_spice_chr_discard_write(len
);
199 spice_server_char_device_wakeup(&s
->sin
);
200 read_bytes
= len
- s
->datalen
;
201 if (read_bytes
!= len
) {
202 /* We'll get passed in the unconsumed data with the next call */
210 static void char_spice_finalize(Object
*obj
)
212 SpiceChardev
*s
= SPICE_CHARDEV(obj
);
214 vmc_unregister_interface(s
);
216 g_free((char *)s
->sin
.subtype
);
217 g_free((char *)s
->sin
.portname
);
220 static void spice_vmc_set_fe_open(struct Chardev
*chr
, int fe_open
)
222 SpiceChardev
*s
= SPICE_CHARDEV(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 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
235 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_OPENED
);
237 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_CLOSED
);
241 static void spice_chr_accept_input(struct Chardev
*chr
)
243 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
245 spice_server_char_device_wakeup(&s
->sin
);
248 static void chr_open(Chardev
*chr
, const char *subtype
)
250 SpiceChardev
*s
= SPICE_CHARDEV(chr
);
253 s
->sin
.subtype
= g_strdup(subtype
);
256 static void qemu_chr_open_spice_vmc(Chardev
*chr
,
257 ChardevBackend
*backend
,
261 ChardevSpiceChannel
*spicevmc
= backend
->u
.spicevmc
.data
;
262 const char *type
= spicevmc
->type
;
263 const char **psubtype
= spice_server_char_device_recognized_subtypes();
265 for (; *psubtype
!= NULL
; ++psubtype
) {
266 if (strcmp(type
, *psubtype
) == 0) {
270 if (*psubtype
== NULL
) {
271 char *subtypes
= g_strjoinv(", ",
272 (gchar
**)spice_server_char_device_recognized_subtypes());
274 error_setg(errp
, "unsupported type name: %s", type
);
275 error_append_hint(errp
, "allowed spice char type names: %s\n",
283 #if SPICE_SERVER_VERSION < 0x000e02
284 /* Spice < 0.14.2 doesn't explicitly open smartcard chardev */
285 if (strcmp(type
, "smartcard") == 0) {
292 static void qemu_chr_open_spice_port(Chardev
*chr
,
293 ChardevBackend
*backend
,
297 ChardevSpicePort
*spiceport
= backend
->u
.spiceport
.data
;
298 const char *name
= spiceport
->fqdn
;
302 error_setg(errp
, "missing name parameter");
307 error_setg(errp
, "spice not enabled");
311 chr_open(chr
, "port");
314 s
= SPICE_CHARDEV(chr
);
315 s
->sin
.portname
= g_strdup(name
);
317 vmc_register_interface(s
);
320 static void qemu_chr_parse_spice_vmc(QemuOpts
*opts
, ChardevBackend
*backend
,
323 const char *name
= qemu_opt_get(opts
, "name");
324 ChardevSpiceChannel
*spicevmc
;
327 error_setg(errp
, "chardev: spice channel: no name given");
330 backend
->type
= CHARDEV_BACKEND_KIND_SPICEVMC
;
331 spicevmc
= backend
->u
.spicevmc
.data
= g_new0(ChardevSpiceChannel
, 1);
332 qemu_chr_parse_common(opts
, qapi_ChardevSpiceChannel_base(spicevmc
));
333 spicevmc
->type
= g_strdup(name
);
336 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
339 const char *name
= qemu_opt_get(opts
, "name");
340 ChardevSpicePort
*spiceport
;
343 error_setg(errp
, "chardev: spice port: no name given");
346 backend
->type
= CHARDEV_BACKEND_KIND_SPICEPORT
;
347 spiceport
= backend
->u
.spiceport
.data
= g_new0(ChardevSpicePort
, 1);
348 qemu_chr_parse_common(opts
, qapi_ChardevSpicePort_base(spiceport
));
349 spiceport
->fqdn
= g_strdup(name
);
352 static void char_spice_class_init(ObjectClass
*oc
, void *data
)
354 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
356 cc
->chr_write
= spice_chr_write
;
357 cc
->chr_add_watch
= spice_chr_add_watch
;
358 cc
->chr_accept_input
= spice_chr_accept_input
;
361 static const TypeInfo char_spice_type_info
= {
362 .name
= TYPE_CHARDEV_SPICE
,
363 .parent
= TYPE_CHARDEV
,
364 .instance_size
= sizeof(SpiceChardev
),
365 .instance_finalize
= char_spice_finalize
,
366 .class_init
= char_spice_class_init
,
369 module_obj(TYPE_CHARDEV_SPICE
);
371 static void char_spicevmc_class_init(ObjectClass
*oc
, void *data
)
373 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
375 cc
->parse
= qemu_chr_parse_spice_vmc
;
376 cc
->open
= qemu_chr_open_spice_vmc
;
377 cc
->chr_set_fe_open
= spice_vmc_set_fe_open
;
380 static const TypeInfo char_spicevmc_type_info
= {
381 .name
= TYPE_CHARDEV_SPICEVMC
,
382 .parent
= TYPE_CHARDEV_SPICE
,
383 .class_init
= char_spicevmc_class_init
,
385 module_obj(TYPE_CHARDEV_SPICEVMC
);
387 static void char_spiceport_class_init(ObjectClass
*oc
, void *data
)
389 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
391 cc
->parse
= qemu_chr_parse_spice_port
;
392 cc
->open
= qemu_chr_open_spice_port
;
393 cc
->chr_set_fe_open
= spice_port_set_fe_open
;
396 static const TypeInfo char_spiceport_type_info
= {
397 .name
= TYPE_CHARDEV_SPICEPORT
,
398 .parent
= TYPE_CHARDEV_SPICE
,
399 .class_init
= char_spiceport_class_init
,
401 module_obj(TYPE_CHARDEV_SPICEPORT
);
403 static void register_types(void)
405 type_register_static(&char_spice_type_info
);
406 type_register_static(&char_spicevmc_type_info
);
407 type_register_static(&char_spiceport_type_info
);
410 type_init(register_types
);
412 module_dep("ui-spice-core");