1 #include "config-host.h"
3 #include "ui/qemu-spice.h"
5 #include <spice-experimental.h>
9 #define dprintf(_scd, _level, _fmt, ...) \
11 static unsigned __dprintf_counter = 0; \
12 if (_scd->debug >= _level) { \
13 fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
17 #define VMC_MAX_HOST_WRITE 2048
19 typedef struct SpiceCharDriver
{
21 SpiceCharDeviceInstance sin
;
26 ssize_t bufsize
, datalen
;
30 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
32 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
35 uint8_t* p
= (uint8_t*)buf
;
38 last_out
= MIN(len
, VMC_MAX_HOST_WRITE
);
39 if (qemu_chr_can_read(scd
->chr
) < last_out
) {
42 qemu_chr_read(scd
->chr
, p
, last_out
);
48 dprintf(scd
, 3, "%s: %lu/%zd\n", __func__
, out
, len
+ out
);
49 trace_spice_vmc_write(out
, len
+ out
);
53 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
55 SpiceCharDriver
*scd
= container_of(sin
, SpiceCharDriver
, sin
);
56 int bytes
= MIN(len
, scd
->datalen
);
58 dprintf(scd
, 2, "%s: %p %d/%d/%zd\n", __func__
, scd
->datapos
, len
, bytes
, scd
->datalen
);
60 memcpy(buf
, scd
->datapos
, bytes
);
61 scd
->datapos
+= bytes
;
62 scd
->datalen
-= bytes
;
63 assert(scd
->datalen
>= 0);
64 if (scd
->datalen
== 0) {
68 trace_spice_vmc_read(bytes
, len
);
72 static SpiceCharDeviceInterface vmc_interface
= {
73 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
74 .base
.description
= "spice virtual channel char device",
75 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
76 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
82 static void vmc_register_interface(SpiceCharDriver
*scd
)
87 dprintf(scd
, 1, "%s\n", __func__
);
88 scd
->sin
.base
.sif
= &vmc_interface
.base
;
89 qemu_spice_add_interface(&scd
->sin
.base
);
91 trace_spice_vmc_register_interface(scd
);
94 static void vmc_unregister_interface(SpiceCharDriver
*scd
)
99 dprintf(scd
, 1, "%s\n", __func__
);
100 spice_server_remove_interface(&scd
->sin
.base
);
102 trace_spice_vmc_unregister_interface(scd
);
106 static int spice_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
108 SpiceCharDriver
*s
= chr
->opaque
;
110 dprintf(s
, 2, "%s: %d\n", __func__
, len
);
111 vmc_register_interface(s
);
112 assert(s
->datalen
== 0);
113 if (s
->bufsize
< len
) {
115 s
->buffer
= qemu_realloc(s
->buffer
, s
->bufsize
);
117 memcpy(s
->buffer
, buf
, len
);
118 s
->datapos
= s
->buffer
;
120 spice_server_char_device_wakeup(&s
->sin
);
124 static void spice_chr_close(struct CharDriverState
*chr
)
126 SpiceCharDriver
*s
= chr
->opaque
;
128 printf("%s\n", __func__
);
129 vmc_unregister_interface(s
);
133 static void spice_chr_guest_open(struct CharDriverState
*chr
)
135 SpiceCharDriver
*s
= chr
->opaque
;
136 vmc_register_interface(s
);
139 static void spice_chr_guest_close(struct CharDriverState
*chr
)
141 SpiceCharDriver
*s
= chr
->opaque
;
142 vmc_unregister_interface(s
);
145 static void print_allowed_subtypes(void)
147 const char** psubtype
;
150 fprintf(stderr
, "allowed names: ");
151 for(i
=0, psubtype
= spice_server_char_device_recognized_subtypes();
152 *psubtype
!= NULL
; ++psubtype
, ++i
) {
154 fprintf(stderr
, "%s", *psubtype
);
156 fprintf(stderr
, ", %s", *psubtype
);
159 fprintf(stderr
, "\n");
162 int qemu_chr_open_spice(QemuOpts
*opts
, CharDriverState
**_chr
)
164 CharDriverState
*chr
;
166 const char* name
= qemu_opt_get(opts
, "name");
167 uint32_t debug
= qemu_opt_get_number(opts
, "debug", 0);
168 const char** psubtype
= spice_server_char_device_recognized_subtypes();
169 const char *subtype
= NULL
;
172 fprintf(stderr
, "spice-qemu-char: missing name parameter\n");
173 print_allowed_subtypes();
176 for(;*psubtype
!= NULL
; ++psubtype
) {
177 if (strcmp(name
, *psubtype
) == 0) {
182 if (subtype
== NULL
) {
183 fprintf(stderr
, "spice-qemu-char: unsupported name\n");
184 print_allowed_subtypes();
188 chr
= qemu_mallocz(sizeof(CharDriverState
));
189 s
= qemu_mallocz(sizeof(SpiceCharDriver
));
193 s
->sin
.subtype
= subtype
;
195 chr
->chr_write
= spice_chr_write
;
196 chr
->chr_close
= spice_chr_close
;
197 chr
->chr_guest_open
= spice_chr_guest_open
;
198 chr
->chr_guest_close
= spice_chr_guest_close
;
200 qemu_chr_generic_open(chr
);