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 #define dprintf(_scd, _level, _fmt, ...) \
13 static unsigned __dprintf_counter = 0; \
14 if (_scd->debug >= _level) { \
15 fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
19 typedef struct SpiceCharDriver
{
21 SpiceCharDeviceInstance sin
;
26 ssize_t bufsize
, datalen
;
28 QLIST_ENTRY(SpiceCharDriver
) next
;
31 static QLIST_HEAD(, SpiceCharDriver
) spice_chars
=
32 QLIST_HEAD_INITIALIZER(spice_chars
);
34 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
36 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
39 uint8_t* p
= (uint8_t*)buf
;
42 last_out
= MIN(len
, qemu_chr_be_can_write(scd
->chr
));
46 qemu_chr_be_write(scd
->chr
, p
, last_out
);
52 dprintf(scd
, 3, "%s: %zu/%zd\n", __func__
, out
, len
+ out
);
53 trace_spice_vmc_write(out
, len
+ out
);
57 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
59 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
60 int bytes
= MIN(len
, scd
->datalen
);
62 dprintf(scd
, 2, "%s: %p %d/%d/%zd\n", __func__
, scd
->datapos
, len
, bytes
, scd
->datalen
);
64 memcpy(buf
, scd
->datapos
, bytes
);
65 scd
->datapos
+= bytes
;
66 scd
->datalen
-= bytes
;
67 assert(scd
->datalen
>= 0);
68 if (scd
->datalen
== 0) {
72 trace_spice_vmc_read(bytes
, len
);
76 #if SPICE_SERVER_VERSION >= 0x000c02
77 static void vmc_event(SpiceCharDeviceInstance
*sin
, uint8_t event
)
79 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
83 case SPICE_PORT_EVENT_BREAK
:
84 chr_event
= CHR_EVENT_BREAK
;
87 dprintf(scd
, 2, "%s: unknown %d\n", __func__
, event
);
91 dprintf(scd
, 2, "%s: %d\n", __func__
, event
);
92 trace_spice_vmc_event(chr_event
);
93 qemu_chr_be_event(scd
->chr
, chr_event
);
97 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
99 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
101 #if SPICE_SERVER_VERSION < 0x000901
103 * spice-server calls the state callback for the agent channel when the
104 * spice client connects / disconnects. Given that not the client but
105 * the server is doing the parsing of the messages this is wrong as the
106 * server is still listening. Worse, this causes the parser in the server
107 * to go out of sync, so we ignore state calls for subtype vdagent
108 * spicevmc chardevs. For the full story see:
109 * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
111 if (strcmp(sin
->subtype
, "vdagent") == 0) {
116 if ((scd
->chr
->opened
&& connected
) ||
117 (!scd
->chr
->opened
&& !connected
)) {
121 qemu_chr_be_event(scd
->chr
,
122 connected
? CHR_EVENT_OPENED
: CHR_EVENT_CLOSED
);
125 static SpiceCharDeviceInterface vmc_interface
= {
126 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
127 .base
.description
= "spice virtual channel char device",
128 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
129 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
133 #if SPICE_SERVER_VERSION >= 0x000c02
139 static void vmc_register_interface(SpiceCharDriver
*scd
)
144 dprintf(scd
, 1, "%s\n", __func__
);
145 scd
->sin
.base
.sif
= &vmc_interface
.base
;
146 qemu_spice_add_interface(&scd
->sin
.base
);
148 trace_spice_vmc_register_interface(scd
);
151 static void vmc_unregister_interface(SpiceCharDriver
*scd
)
156 dprintf(scd
, 1, "%s\n", __func__
);
157 spice_server_remove_interface(&scd
->sin
.base
);
159 trace_spice_vmc_unregister_interface(scd
);
163 static int spice_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
165 SpiceCharDriver
*s
= chr
->opaque
;
167 dprintf(s
, 2, "%s: %d\n", __func__
, len
);
168 vmc_register_interface(s
);
169 assert(s
->datalen
== 0);
170 if (s
->bufsize
< len
) {
172 s
->buffer
= g_realloc(s
->buffer
, s
->bufsize
);
174 memcpy(s
->buffer
, buf
, len
);
175 s
->datapos
= s
->buffer
;
177 spice_server_char_device_wakeup(&s
->sin
);
181 static void spice_chr_close(struct CharDriverState
*chr
)
183 SpiceCharDriver
*s
= chr
->opaque
;
185 printf("%s\n", __func__
);
186 vmc_unregister_interface(s
);
187 QLIST_REMOVE(s
, next
);
191 static void spice_chr_guest_open(struct CharDriverState
*chr
)
193 SpiceCharDriver
*s
= chr
->opaque
;
194 vmc_register_interface(s
);
197 static void spice_chr_guest_close(struct CharDriverState
*chr
)
199 SpiceCharDriver
*s
= chr
->opaque
;
200 vmc_unregister_interface(s
);
203 static void print_allowed_subtypes(void)
205 const char** psubtype
;
208 fprintf(stderr
, "allowed names: ");
209 for(i
=0, psubtype
= spice_server_char_device_recognized_subtypes();
210 *psubtype
!= NULL
; ++psubtype
, ++i
) {
212 fprintf(stderr
, "%s", *psubtype
);
214 fprintf(stderr
, ", %s", *psubtype
);
217 fprintf(stderr
, "\n");
220 static CharDriverState
*chr_open(QemuOpts
*opts
, const char *subtype
)
222 CharDriverState
*chr
;
224 uint32_t debug
= qemu_opt_get_number(opts
, "debug", 0);
226 chr
= g_malloc0(sizeof(CharDriverState
));
227 s
= g_malloc0(sizeof(SpiceCharDriver
));
231 s
->sin
.subtype
= subtype
;
233 chr
->chr_write
= spice_chr_write
;
234 chr
->chr_close
= spice_chr_close
;
235 chr
->chr_guest_open
= spice_chr_guest_open
;
236 chr
->chr_guest_close
= spice_chr_guest_close
;
238 QLIST_INSERT_HEAD(&spice_chars
, s
, next
);
243 CharDriverState
*qemu_chr_open_spice(QemuOpts
*opts
)
245 CharDriverState
*chr
;
246 const char *name
= qemu_opt_get(opts
, "name");
247 const char **psubtype
= spice_server_char_device_recognized_subtypes();
248 const char *subtype
= NULL
;
251 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
252 print_allowed_subtypes();
255 for(;*psubtype
!= NULL
; ++psubtype
) {
256 if (strcmp(name
, *psubtype
) == 0) {
261 if (subtype
== NULL
) {
262 fprintf(stderr
, "spice-qemu-char: unsupported name: %s\n", name
);
263 print_allowed_subtypes();
267 chr
= chr_open(opts
, subtype
);
269 #if SPICE_SERVER_VERSION < 0x000901
270 /* See comment in vmc_state() */
271 if (strcmp(subtype
, "vdagent") == 0) {
272 qemu_chr_generic_open(chr
);
279 #if SPICE_SERVER_VERSION >= 0x000c02
280 CharDriverState
*qemu_chr_open_spice_port(QemuOpts
*opts
)
282 CharDriverState
*chr
;
284 const char *name
= qemu_opt_get(opts
, "name");
287 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
291 chr
= chr_open(opts
, "port");
293 s
->sin
.portname
= name
;
298 void qemu_spice_register_ports(void)
302 QLIST_FOREACH(s
, &spice_chars
, next
) {
303 if (s
->sin
.portname
== NULL
) {
306 vmc_register_interface(s
);