1 #include "config-host.h"
3 #include "ui/qemu-spice.h"
6 #include <spice-experimental.h>
7 #include <spice/protocol.h>
9 #include "qemu/osdep.h"
11 typedef struct SpiceCharDriver
{
13 SpiceCharDeviceInstance sin
;
18 ssize_t bufsize
, datalen
;
19 QLIST_ENTRY(SpiceCharDriver
) next
;
22 static QLIST_HEAD(, SpiceCharDriver
) spice_chars
=
23 QLIST_HEAD_INITIALIZER(spice_chars
);
25 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
27 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
30 uint8_t* p
= (uint8_t*)buf
;
33 last_out
= MIN(len
, qemu_chr_be_can_write(scd
->chr
));
37 qemu_chr_be_write(scd
->chr
, p
, last_out
);
43 trace_spice_vmc_write(out
, len
+ out
);
47 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
49 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
50 int bytes
= MIN(len
, scd
->datalen
);
53 memcpy(buf
, scd
->datapos
, bytes
);
54 scd
->datapos
+= bytes
;
55 scd
->datalen
-= bytes
;
56 assert(scd
->datalen
>= 0);
57 if (scd
->datalen
== 0) {
61 trace_spice_vmc_read(bytes
, len
);
65 #if SPICE_SERVER_VERSION >= 0x000c02
66 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
68 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
72 case SPICE_PORT_EVENT_BREAK
:
73 chr_event
= CHR_EVENT_BREAK
;
79 trace_spice_vmc_event(chr_event
);
80 qemu_chr_be_event(scd
->chr
, chr_event
);
84 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
86 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
88 #if SPICE_SERVER_VERSION < 0x000901
90 * spice-server calls the state callback for the agent channel when the
91 * spice client connects / disconnects. Given that not the client but
92 * the server is doing the parsing of the messages this is wrong as the
93 * server is still listening. Worse, this causes the parser in the server
94 * to go out of sync, so we ignore state calls for subtype vdagent
95 * spicevmc chardevs. For the full story see:
96 * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
98 if (strcmp(sin
->subtype
, "vdagent") == 0) {
103 if ((scd
->chr
->opened
&& connected
) ||
104 (!scd
->chr
->opened
&& !connected
)) {
108 qemu_chr_be_event(scd
->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
126 static void vmc_register_interface(SpiceCharDriver
*scd
)
131 scd
->sin
.base
.sif
= &vmc_interface
.base
;
132 qemu_spice_add_interface(&scd
->sin
.base
);
134 trace_spice_vmc_register_interface(scd
);
137 static void vmc_unregister_interface(SpiceCharDriver
*scd
)
142 spice_server_remove_interface(&scd
->sin
.base
);
144 trace_spice_vmc_unregister_interface(scd
);
148 static int spice_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
150 SpiceCharDriver
*s
= chr
->opaque
;
152 vmc_register_interface(s
);
153 assert(s
->datalen
== 0);
154 if (s
->bufsize
< len
) {
156 s
->buffer
= g_realloc(s
->buffer
, s
->bufsize
);
158 memcpy(s
->buffer
, buf
, len
);
159 s
->datapos
= s
->buffer
;
161 spice_server_char_device_wakeup(&s
->sin
);
165 static void spice_chr_close(struct CharDriverState
*chr
)
167 SpiceCharDriver
*s
= chr
->opaque
;
169 vmc_unregister_interface(s
);
170 QLIST_REMOVE(s
, next
);
172 g_free((char *)s
->sin
.subtype
);
173 #if SPICE_SERVER_VERSION >= 0x000c02
174 g_free((char *)s
->sin
.portname
);
179 static void spice_chr_guest_open(struct CharDriverState
*chr
)
181 SpiceCharDriver
*s
= chr
->opaque
;
182 vmc_register_interface(s
);
185 static void spice_chr_guest_close(struct CharDriverState
*chr
)
187 SpiceCharDriver
*s
= chr
->opaque
;
188 vmc_unregister_interface(s
);
191 static void print_allowed_subtypes(void)
193 const char** psubtype
;
196 fprintf(stderr
, "allowed names: ");
197 for(i
=0, psubtype
= spice_server_char_device_recognized_subtypes();
198 *psubtype
!= NULL
; ++psubtype
, ++i
) {
200 fprintf(stderr
, "%s", *psubtype
);
202 fprintf(stderr
, ", %s", *psubtype
);
205 fprintf(stderr
, "\n");
208 static CharDriverState
*chr_open(const char *subtype
)
210 CharDriverState
*chr
;
213 chr
= g_malloc0(sizeof(CharDriverState
));
214 s
= g_malloc0(sizeof(SpiceCharDriver
));
217 s
->sin
.subtype
= g_strdup(subtype
);
219 chr
->chr_write
= spice_chr_write
;
220 chr
->chr_close
= spice_chr_close
;
221 chr
->chr_guest_open
= spice_chr_guest_open
;
222 chr
->chr_guest_close
= spice_chr_guest_close
;
224 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
229 CharDriverState
*qemu_chr_open_spice_vmc(const char *type
)
231 CharDriverState
*chr
;
232 const char **psubtype
= spice_server_char_device_recognized_subtypes();
235 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
236 print_allowed_subtypes();
239 for (; *psubtype
!= NULL
; ++psubtype
) {
240 if (strcmp(type
, *psubtype
) == 0) {
244 if (*psubtype
== NULL
) {
245 fprintf(stderr
, "spice-qemu-char: unsupported type: %s\n", type
);
246 print_allowed_subtypes();
250 chr
= chr_open(type
);
252 #if SPICE_SERVER_VERSION < 0x000901
253 /* See comment in vmc_state() */
254 if (strcmp(type
, "vdagent") == 0) {
255 qemu_chr_generic_open(chr
);
262 #if SPICE_SERVER_VERSION >= 0x000c02
263 CharDriverState
*qemu_chr_open_spice_port(const char *name
)
265 CharDriverState
*chr
;
269 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
273 chr
= chr_open("port");
275 s
->sin
.portname
= g_strdup(name
);
280 void qemu_spice_register_ports(void)
284 QLIST_FOREACH(s
, &spice_chars
, next
) {
285 if (s
->sin
.portname
== NULL
) {
288 vmc_register_interface(s
);
293 static void qemu_chr_parse_spice_vmc(QemuOpts
*opts
, ChardevBackend
*backend
,
296 const char *name
= qemu_opt_get(opts
, "name");
299 error_setg(errp
, "chardev: spice channel: no name given");
302 backend
->spicevmc
= g_new0(ChardevSpiceChannel
, 1);
303 backend
->spicevmc
->type
= g_strdup(name
);
306 static void qemu_chr_parse_spice_port(QemuOpts
*opts
, ChardevBackend
*backend
,
309 const char *name
= qemu_opt_get(opts
, "name");
312 error_setg(errp
, "chardev: spice port: no name given");
315 backend
->spiceport
= g_new0(ChardevSpicePort
, 1);
316 backend
->spiceport
->fqdn
= g_strdup(name
);
319 static void register_types(void)
321 register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC
,
322 qemu_chr_parse_spice_vmc
);
323 register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT
,
324 qemu_chr_parse_spice_port
);
327 type_init(register_types
);