1 #include "config-host.h"
3 #include "ui/qemu-spice.h"
4 #include "sysemu/char.h"
6 #include <spice/protocol.h>
8 #include "qemu/osdep.h"
10 typedef struct SpiceCharDriver
{
12 SpiceCharDeviceInstance sin
;
15 const uint8_t *datapos
;
17 QLIST_ENTRY(SpiceCharDriver
) next
;
20 typedef struct SpiceCharSource
{
25 static QLIST_HEAD(, SpiceCharDriver
) spice_chars
=
26 QLIST_HEAD_INITIALIZER(spice_chars
);
28 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
30 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
33 uint8_t* p
= (uint8_t*)buf
;
36 int can_write
= qemu_chr_be_can_write(scd
->chr
);
37 last_out
= MIN(len
, can_write
);
41 qemu_chr_be_write(scd
->chr
, p
, last_out
);
47 trace_spice_vmc_write(out
, len
+ out
);
51 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
53 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
54 int bytes
= MIN(len
, scd
->datalen
);
57 memcpy(buf
, scd
->datapos
, bytes
);
58 scd
->datapos
+= bytes
;
59 scd
->datalen
-= bytes
;
60 assert(scd
->datalen
>= 0);
62 if (scd
->datalen
== 0) {
66 trace_spice_vmc_read(bytes
, len
);
70 #if SPICE_SERVER_VERSION >= 0x000c02
71 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
73 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
77 case SPICE_PORT_EVENT_BREAK
:
78 chr_event
= CHR_EVENT_BREAK
;
84 trace_spice_vmc_event(chr_event
);
85 qemu_chr_be_event(scd
->chr
, chr_event
);
89 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
91 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
93 if ((scd
->chr
->be_open
&& connected
) ||
94 (!scd
->chr
->be_open
&& !connected
)) {
98 qemu_chr_be_event(scd
->chr
,
99 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
102 static SpiceCharDeviceInterface vmc_interface
= {
103 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
104 .base
.description
= "spice virtual channel char device",
105 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
106 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
110 #if SPICE_SERVER_VERSION >= 0x000c02
113 #if SPICE_SERVER_VERSION >= 0x000c06
114 .flags
= SPICE_CHAR_DEVICE_NOTIFY_WRITABLE
,
119 static void vmc_register_interface(SpiceCharDriver
*scd
)
124 scd
->sin
.base
.sif
= &vmc_interface
.base
;
125 qemu_spice_add_interface(&scd
->sin
.base
);
127 trace_spice_vmc_register_interface(scd
);
130 static void vmc_unregister_interface(SpiceCharDriver
*scd
)
135 spice_server_remove_interface(&scd
->sin
.base
);
137 trace_spice_vmc_unregister_interface(scd
);
140 static gboolean
spice_char_source_prepare(GSource
*source
, gint
*timeout
)
142 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
146 return !src
->scd
->blocked
;
149 static gboolean
spice_char_source_check(GSource
*source
)
151 SpiceCharSource
*src
= (SpiceCharSource
*)source
;
153 return !src
->scd
->blocked
;
156 static gboolean
spice_char_source_dispatch(GSource
*source
,
157 GSourceFunc callback
, gpointer user_data
)
159 GIOFunc func
= (GIOFunc
)callback
;
161 return func(NULL
, G_IO_OUT
, user_data
);
164 static GSourceFuncs SpiceCharSourceFuncs
= {
165 .prepare
= spice_char_source_prepare
,
166 .check
= spice_char_source_check
,
167 .dispatch
= spice_char_source_dispatch
,
170 static GSource
*spice_chr_add_watch(CharDriverState
*chr
, GIOCondition cond
)
172 SpiceCharDriver
*scd
= chr
->opaque
;
173 SpiceCharSource
*src
;
175 assert(cond
& G_IO_OUT
);
177 src
= (SpiceCharSource
*)g_source_new(&SpiceCharSourceFuncs
,
178 sizeof(SpiceCharSource
));
181 return (GSource
*)src
;
184 static int spice_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
186 SpiceCharDriver
*s
= chr
->opaque
;
189 assert(s
->datalen
== 0);
192 spice_server_char_device_wakeup(&s
->sin
);
193 read_bytes
= len
- s
->datalen
;
194 if (read_bytes
!= len
) {
195 /* We'll get passed in the unconsumed data with the next call */
203 static void spice_chr_close(struct CharDriverState
*chr
)
205 SpiceCharDriver
*s
= chr
->opaque
;
207 vmc_unregister_interface(s
);
208 QLIST_REMOVE(s
, next
);
210 g_free((char *)s
->sin
.subtype
);
211 #if SPICE_SERVER_VERSION >= 0x000c02
212 g_free((char *)s
->sin
.portname
);
217 static void spice_vmc_set_fe_open(struct CharDriverState
*chr
, int fe_open
)
219 SpiceCharDriver
*s
= chr
->opaque
;
221 vmc_register_interface(s
);
223 vmc_unregister_interface(s
);
227 static void spice_port_set_fe_open(struct CharDriverState
*chr
, int fe_open
)
229 #if SPICE_SERVER_VERSION >= 0x000c02
230 SpiceCharDriver
*s
= chr
->opaque
;
233 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_OPENED
);
235 spice_server_port_event(&s
->sin
, SPICE_PORT_EVENT_CLOSED
);
240 static void spice_chr_fe_event(struct CharDriverState
*chr
, int event
)
242 #if SPICE_SERVER_VERSION >= 0x000c02
243 SpiceCharDriver
*s
= chr
->opaque
;
245 spice_server_port_event(&s
->sin
, event
);
249 static void print_allowed_subtypes(void)
251 const char** psubtype
;
254 fprintf(stderr
, "allowed names: ");
255 for(i
=0, psubtype
= spice_server_char_device_recognized_subtypes();
256 *psubtype
!= NULL
; ++psubtype
, ++i
) {
258 fprintf(stderr
, "%s", *psubtype
);
260 fprintf(stderr
, ", %s", *psubtype
);
263 fprintf(stderr
, "\n");
266 static void spice_chr_accept_input(struct CharDriverState
*chr
)
268 SpiceCharDriver
*s
= chr
->opaque
;
270 spice_server_char_device_wakeup(&s
->sin
);
273 static CharDriverState
*chr_open(const char *subtype
,
274 void (*set_fe_open
)(struct CharDriverState
*, int))
277 CharDriverState
*chr
;
280 chr
= qemu_chr_alloc();
281 s
= g_malloc0(sizeof(SpiceCharDriver
));
284 s
->sin
.subtype
= g_strdup(subtype
);
286 chr
->chr_write
= spice_chr_write
;
287 chr
->chr_add_watch
= spice_chr_add_watch
;
288 chr
->chr_close
= spice_chr_close
;
289 chr
->chr_set_fe_open
= set_fe_open
;
290 chr
->explicit_be_open
= true;
291 chr
->chr_fe_event
= spice_chr_fe_event
;
292 chr
->chr_accept_input
= spice_chr_accept_input
;
294 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
299 static CharDriverState
*qemu_chr_open_spice_vmc(const char *id
,
300 ChardevBackend
*backend
,
304 const char *type
= backend
->spicevmc
->type
;
305 const char **psubtype
= spice_server_char_device_recognized_subtypes();
307 for (; *psubtype
!= NULL
; ++psubtype
) {
308 if (strcmp(type
, *psubtype
) == 0) {
312 if (*psubtype
== NULL
) {
313 fprintf(stderr
, "spice-qemu-char: unsupported type: %s\n", type
);
314 print_allowed_subtypes();
318 return chr_open(type
, spice_vmc_set_fe_open
);
321 #if SPICE_SERVER_VERSION >= 0x000c02
322 static CharDriverState
*qemu_chr_open_spice_port(const char *id
,
323 ChardevBackend
*backend
,
327 const char *name
= backend
->spiceport
->fqdn
;
328 CharDriverState
*chr
;
332 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
336 chr
= chr_open("port", spice_port_set_fe_open
);
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");
362 error_setg(errp
, "chardev: spice channel: no name given");
365 backend
->spicevmc
= g_new0(ChardevSpiceChannel
, 1);
366 backend
->spicevmc
->type
= g_strdup(name
);
369 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
372 const char *name
= qemu_opt_get(opts
, "name");
375 error_setg(errp
, "chardev: spice port: no name given");
378 backend
->spiceport
= g_new0(ChardevSpicePort
, 1);
379 backend
->spiceport
->fqdn
= g_strdup(name
);
382 static void register_types(void)
384 register_char_driver("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC
,
385 qemu_chr_parse_spice_vmc
, qemu_chr_open_spice_vmc
);
386 register_char_driver("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT
,
387 qemu_chr_parse_spice_port
, qemu_chr_open_spice_port
);
390 type_init(register_types
);