blob: 38b1f6c29b28f86e72b243ee2f4ea161676e94ef [file] [log] [blame]
Peter Maydelld38ea872016-01-29 17:50:05 +00001#include "qemu/osdep.h"
Alon Levycbcc6332011-01-19 10:49:50 +02002#include "trace.h"
3#include "ui/qemu-spice.h"
Paolo Bonzinidccfcd02013-04-08 16:55:25 +02004#include "sysemu/char.h"
Alon Levycbcc6332011-01-19 10:49:50 +02005#include <spice.h>
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +01006#include <spice/protocol.h>
Alon Levycbcc6332011-01-19 10:49:50 +02007
Alon Levycbcc6332011-01-19 10:49:50 +02008
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +03009typedef struct SpiceChardev {
10 Chardev parent;
Marc-André Lureau41ac54b2016-10-21 23:44:44 +030011
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030012 SpiceCharDeviceInstance sin;
Alon Levycbcc6332011-01-19 10:49:50 +020013 bool active;
Hans de Goedeae893e52013-04-05 11:30:22 +020014 bool blocked;
Alon Levyb010cec2013-04-05 11:30:23 +020015 const uint8_t *datapos;
16 int datalen;
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030017 QLIST_ENTRY(SpiceChardev) next;
18} SpiceChardev;
Alon Levycbcc6332011-01-19 10:49:50 +020019
Hans de Goedeae893e52013-04-05 11:30:22 +020020typedef struct SpiceCharSource {
21 GSource source;
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030022 SpiceChardev *scd;
Hans de Goedeae893e52013-04-05 11:30:22 +020023} SpiceCharSource;
24
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030025static QLIST_HEAD(, SpiceChardev) spice_chars =
Marc-André Lureau7a5448c2012-12-05 16:15:35 +010026 QLIST_HEAD_INITIALIZER(spice_chars);
27
Alon Levycbcc6332011-01-19 10:49:50 +020028static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
29{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030030 SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
31 Chardev *chr = (Chardev *)scd;
Alon Levycbcc6332011-01-19 10:49:50 +020032 ssize_t out = 0;
33 ssize_t last_out;
34 uint8_t* p = (uint8_t*)buf;
35
36 while (len > 0) {
Marc-André Lureau41ac54b2016-10-21 23:44:44 +030037 int can_write = qemu_chr_be_can_write(chr);
Hans de Goede75c439b2013-04-05 11:30:24 +020038 last_out = MIN(len, can_write);
Marc-André Lureau07a54d72012-12-05 16:15:32 +010039 if (last_out <= 0) {
Alon Levycbcc6332011-01-19 10:49:50 +020040 break;
41 }
Marc-André Lureau41ac54b2016-10-21 23:44:44 +030042 qemu_chr_be_write(chr, p, last_out);
Hans de Goede35106c22011-03-22 16:28:41 +010043 out += last_out;
44 len -= last_out;
45 p += last_out;
Alon Levycbcc6332011-01-19 10:49:50 +020046 }
47
Alon Levycbcc6332011-01-19 10:49:50 +020048 trace_spice_vmc_write(out, len + out);
49 return out;
50}
51
52static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
53{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030054 SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
Alon Levycbcc6332011-01-19 10:49:50 +020055 int bytes = MIN(len, scd->datalen);
56
Alon Levycbcc6332011-01-19 10:49:50 +020057 if (bytes > 0) {
58 memcpy(buf, scd->datapos, bytes);
59 scd->datapos += bytes;
60 scd->datalen -= bytes;
61 assert(scd->datalen >= 0);
Hans de Goedeae893e52013-04-05 11:30:22 +020062 }
63 if (scd->datalen == 0) {
64 scd->datapos = 0;
65 scd->blocked = false;
Alon Levycbcc6332011-01-19 10:49:50 +020066 }
67 trace_spice_vmc_read(bytes, len);
68 return bytes;
69}
70
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +010071#if SPICE_SERVER_VERSION >= 0x000c02
72static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
73{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030074 SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
75 Chardev *chr = (Chardev *)scd;
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +010076 int chr_event;
77
78 switch (event) {
79 case SPICE_PORT_EVENT_BREAK:
80 chr_event = CHR_EVENT_BREAK;
81 break;
82 default:
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +010083 return;
84 }
85
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +010086 trace_spice_vmc_event(chr_event);
Marc-André Lureau41ac54b2016-10-21 23:44:44 +030087 qemu_chr_be_event(chr, chr_event);
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +010088}
89#endif
90
Hans de Goedef76e4c72011-11-19 10:22:44 +010091static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
92{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +030093 SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
94 Chardev *chr = (Chardev *)scd;
Hans de Goedef76e4c72011-11-19 10:22:44 +010095
Marc-André Lureau41ac54b2016-10-21 23:44:44 +030096 if ((chr->be_open && connected) ||
97 (!chr->be_open && !connected)) {
Hans de Goedef76e4c72011-11-19 10:22:44 +010098 return;
99 }
100
Marc-André Lureau41ac54b2016-10-21 23:44:44 +0300101 qemu_chr_be_event(chr,
Hans de Goedef76e4c72011-11-19 10:22:44 +0100102 connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
103}
104
Alon Levycbcc6332011-01-19 10:49:50 +0200105static SpiceCharDeviceInterface vmc_interface = {
106 .base.type = SPICE_INTERFACE_CHAR_DEVICE,
107 .base.description = "spice virtual channel char device",
108 .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
109 .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
Hans de Goedef76e4c72011-11-19 10:22:44 +0100110 .state = vmc_state,
Alon Levycbcc6332011-01-19 10:49:50 +0200111 .write = vmc_write,
112 .read = vmc_read,
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100113#if SPICE_SERVER_VERSION >= 0x000c02
114 .event = vmc_event,
115#endif
Marc-André Lureaue95e2032015-05-05 16:58:56 +0200116#if SPICE_SERVER_VERSION >= 0x000c06
117 .flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE,
118#endif
Alon Levycbcc6332011-01-19 10:49:50 +0200119};
120
121
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300122static void vmc_register_interface(SpiceChardev *scd)
Alon Levycbcc6332011-01-19 10:49:50 +0200123{
124 if (scd->active) {
125 return;
126 }
Alon Levycbcc6332011-01-19 10:49:50 +0200127 scd->sin.base.sif = &vmc_interface.base;
128 qemu_spice_add_interface(&scd->sin.base);
129 scd->active = true;
130 trace_spice_vmc_register_interface(scd);
131}
132
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300133static void vmc_unregister_interface(SpiceChardev *scd)
Alon Levycbcc6332011-01-19 10:49:50 +0200134{
135 if (!scd->active) {
136 return;
137 }
Alon Levycbcc6332011-01-19 10:49:50 +0200138 spice_server_remove_interface(&scd->sin.base);
139 scd->active = false;
140 trace_spice_vmc_unregister_interface(scd);
141}
142
Hans de Goedeae893e52013-04-05 11:30:22 +0200143static gboolean spice_char_source_prepare(GSource *source, gint *timeout)
144{
145 SpiceCharSource *src = (SpiceCharSource *)source;
146
147 *timeout = -1;
148
149 return !src->scd->blocked;
150}
151
152static gboolean spice_char_source_check(GSource *source)
153{
154 SpiceCharSource *src = (SpiceCharSource *)source;
155
156 return !src->scd->blocked;
157}
158
159static gboolean spice_char_source_dispatch(GSource *source,
160 GSourceFunc callback, gpointer user_data)
161{
162 GIOFunc func = (GIOFunc)callback;
163
164 return func(NULL, G_IO_OUT, user_data);
165}
166
Stefan Weil51575c32015-02-06 22:43:14 +0100167static GSourceFuncs SpiceCharSourceFuncs = {
Hans de Goedeae893e52013-04-05 11:30:22 +0200168 .prepare = spice_char_source_prepare,
169 .check = spice_char_source_check,
170 .dispatch = spice_char_source_dispatch,
171};
172
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300173static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
Hans de Goedeae893e52013-04-05 11:30:22 +0200174{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300175 SpiceChardev *scd = (SpiceChardev *)chr;
Hans de Goedeae893e52013-04-05 11:30:22 +0200176 SpiceCharSource *src;
177
Marc-André Lureauf7a8beb2015-05-28 15:04:58 +0200178 assert(cond & G_IO_OUT);
Hans de Goedeae893e52013-04-05 11:30:22 +0200179
180 src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs,
181 sizeof(SpiceCharSource));
182 src->scd = scd;
183
184 return (GSource *)src;
185}
Alon Levycbcc6332011-01-19 10:49:50 +0200186
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300187static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
Alon Levycbcc6332011-01-19 10:49:50 +0200188{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300189 SpiceChardev *s = (SpiceChardev *)chr;
Hans de Goedeae893e52013-04-05 11:30:22 +0200190 int read_bytes;
Alon Levycbcc6332011-01-19 10:49:50 +0200191
Alon Levycbcc6332011-01-19 10:49:50 +0200192 assert(s->datalen == 0);
Alon Levyb010cec2013-04-05 11:30:23 +0200193 s->datapos = buf;
Alon Levycbcc6332011-01-19 10:49:50 +0200194 s->datalen = len;
195 spice_server_char_device_wakeup(&s->sin);
Hans de Goedeae893e52013-04-05 11:30:22 +0200196 read_bytes = len - s->datalen;
197 if (read_bytes != len) {
198 /* We'll get passed in the unconsumed data with the next call */
199 s->datalen = 0;
200 s->datapos = NULL;
201 s->blocked = true;
202 }
203 return read_bytes;
Alon Levycbcc6332011-01-19 10:49:50 +0200204}
205
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300206static void spice_chr_free(struct Chardev *chr)
Alon Levycbcc6332011-01-19 10:49:50 +0200207{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300208 SpiceChardev *s = (SpiceChardev *)chr;
Alon Levycbcc6332011-01-19 10:49:50 +0200209
Alon Levycbcc6332011-01-19 10:49:50 +0200210 vmc_unregister_interface(s);
Marc-André Lureau7a5448c2012-12-05 16:15:35 +0100211 QLIST_REMOVE(s, next);
Hans de Goede5e9b4732013-03-13 10:41:31 +0100212
213 g_free((char *)s->sin.subtype);
214#if SPICE_SERVER_VERSION >= 0x000c02
215 g_free((char *)s->sin.portname);
216#endif
Alon Levycbcc6332011-01-19 10:49:50 +0200217}
218
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300219static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
Hans de Goedecd8f7df2011-03-24 11:12:04 +0100220{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300221 SpiceChardev *s = (SpiceChardev *)chr;
Hans de Goede574b7112013-03-26 11:07:58 +0100222 if (fe_open) {
223 vmc_register_interface(s);
224 } else {
225 vmc_unregister_interface(s);
226 }
Hans de Goedecd8f7df2011-03-24 11:12:04 +0100227}
228
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300229static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
Marc-André Lureau89091142014-01-11 00:20:24 +0100230{
231#if SPICE_SERVER_VERSION >= 0x000c02
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300232 SpiceChardev *s = (SpiceChardev *)chr;
Marc-André Lureau89091142014-01-11 00:20:24 +0100233
234 if (fe_open) {
235 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
236 } else {
237 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED);
238 }
239#endif
240}
241
Alon Levycbcc6332011-01-19 10:49:50 +0200242static void print_allowed_subtypes(void)
243{
244 const char** psubtype;
245 int i;
246
247 fprintf(stderr, "allowed names: ");
248 for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
249 *psubtype != NULL; ++psubtype, ++i) {
250 if (i == 0) {
251 fprintf(stderr, "%s", *psubtype);
252 } else {
253 fprintf(stderr, ", %s", *psubtype);
254 }
255 }
256 fprintf(stderr, "\n");
257}
258
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300259static void spice_chr_accept_input(struct Chardev *chr)
Marc-André Lureaue95e2032015-05-05 16:58:56 +0200260{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300261 SpiceChardev *s = (SpiceChardev *)chr;
Marc-André Lureaue95e2032015-05-05 16:58:56 +0200262
263 spice_server_char_device_wakeup(&s->sin);
264}
265
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300266static Chardev *chr_open(const CharDriver *driver,
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300267 const char *subtype,
Daniel P. Berranged0d77082016-01-11 12:44:41 +0000268 ChardevCommon *backend,
269 Error **errp)
Alon Levycbcc6332011-01-19 10:49:50 +0200270{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300271 Chardev *chr;
272 SpiceChardev *s;
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100273
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300274 chr = qemu_chr_alloc(driver, backend, errp);
Daniel P. Berranged0d77082016-01-11 12:44:41 +0000275 if (!chr) {
276 return NULL;
277 }
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300278 s = (SpiceChardev *)chr;
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100279 s->active = false;
Hans de Goede5e9b4732013-03-13 10:41:31 +0100280 s->sin.subtype = g_strdup(subtype);
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100281
Marc-André Lureau7a5448c2012-12-05 16:15:35 +0100282 QLIST_INSERT_HEAD(&spice_chars, s, next);
283
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100284 return chr;
285}
286
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300287static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300288 const char *id,
Paolo Bonzini68145e12015-09-29 15:45:47 +0200289 ChardevBackend *backend,
290 ChardevReturn *ret,
Marc-André Lureau82878da2016-10-22 13:09:43 +0300291 bool *be_opened,
Paolo Bonzini68145e12015-09-29 15:45:47 +0200292 Error **errp)
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100293{
Eric Blake32bafa82016-03-17 16:48:37 -0600294 ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
295 const char *type = spicevmc->type;
Marc-André Lureau71b423f2012-12-05 16:15:33 +0100296 const char **psubtype = spice_server_char_device_recognized_subtypes();
Eric Blake32bafa82016-03-17 16:48:37 -0600297 ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
Alon Levycbcc6332011-01-19 10:49:50 +0200298
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100299 for (; *psubtype != NULL; ++psubtype) {
300 if (strcmp(type, *psubtype) == 0) {
Alon Levycbcc6332011-01-19 10:49:50 +0200301 break;
302 }
303 }
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100304 if (*psubtype == NULL) {
305 fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
Alon Levycbcc6332011-01-19 10:49:50 +0200306 print_allowed_subtypes();
Markus Armbruster1f514702012-02-07 15:09:08 +0100307 return NULL;
Alon Levycbcc6332011-01-19 10:49:50 +0200308 }
309
Marc-André Lureau82878da2016-10-22 13:09:43 +0300310 *be_opened = false;
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300311 return chr_open(driver, type, common, errp);
Alon Levycbcc6332011-01-19 10:49:50 +0200312}
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100313
314#if SPICE_SERVER_VERSION >= 0x000c02
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300315static Chardev *qemu_chr_open_spice_port(const CharDriver *driver,
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300316 const char *id,
Paolo Bonzini68145e12015-09-29 15:45:47 +0200317 ChardevBackend *backend,
318 ChardevReturn *ret,
Marc-André Lureau82878da2016-10-22 13:09:43 +0300319 bool *be_opened,
Paolo Bonzini68145e12015-09-29 15:45:47 +0200320 Error **errp)
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100321{
Eric Blake32bafa82016-03-17 16:48:37 -0600322 ChardevSpicePort *spiceport = backend->u.spiceport.data;
323 const char *name = spiceport->fqdn;
324 ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300325 Chardev *chr;
326 SpiceChardev *s;
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100327
328 if (name == NULL) {
329 fprintf(stderr, "spice-qemu-char: missing name parameter\n");
330 return NULL;
331 }
332
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300333 chr = chr_open(driver, "port", common, errp);
Daniel P. Berranged0d77082016-01-11 12:44:41 +0000334 if (!chr) {
335 return NULL;
336 }
Marc-André Lureau82878da2016-10-22 13:09:43 +0300337 *be_opened = false;
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300338 s = (SpiceChardev *)chr;
Hans de Goede5e9b4732013-03-13 10:41:31 +0100339 s->sin.portname = g_strdup(name);
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100340
341 return chr;
342}
Marc-André Lureauafd0b402012-12-05 16:15:36 +0100343
344void qemu_spice_register_ports(void)
345{
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300346 SpiceChardev *s;
Marc-André Lureauafd0b402012-12-05 16:15:36 +0100347
348 QLIST_FOREACH(s, &spice_chars, next) {
349 if (s->sin.portname == NULL) {
350 continue;
351 }
352 vmc_register_interface(s);
353 }
354}
Marc-André Lureau5a49d3e2012-12-05 16:15:34 +0100355#endif
Anthony Liguori26c60612013-03-05 23:21:29 +0530356
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100357static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
358 Error **errp)
359{
360 const char *name = qemu_opt_get(opts, "name");
Eric Blake21a933e2016-02-19 17:19:31 -0700361 ChardevSpiceChannel *spicevmc;
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100362
363 if (name == NULL) {
364 error_setg(errp, "chardev: spice channel: no name given");
365 return;
366 }
Eric Blake32bafa82016-03-17 16:48:37 -0600367 spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1);
Eric Blake21a933e2016-02-19 17:19:31 -0700368 qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
369 spicevmc->type = g_strdup(name);
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100370}
371
372static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
373 Error **errp)
374{
375 const char *name = qemu_opt_get(opts, "name");
Eric Blake21a933e2016-02-19 17:19:31 -0700376 ChardevSpicePort *spiceport;
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100377
378 if (name == NULL) {
379 error_setg(errp, "chardev: spice port: no name given");
380 return;
381 }
Eric Blake32bafa82016-03-17 16:48:37 -0600382 spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1);
Eric Blake21a933e2016-02-19 17:19:31 -0700383 qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
384 spiceport->fqdn = g_strdup(name);
Gerd Hoffmanncd153e22013-02-25 12:39:06 +0100385}
386
Anthony Liguori26c60612013-03-05 23:21:29 +0530387static void register_types(void)
388{
Marc-André Lureau0b812f32016-10-21 16:07:45 +0300389 static const CharDriver vmc_driver = {
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300390 .instance_size = sizeof(SpiceChardev),
Marc-André Lureau0b812f32016-10-21 16:07:45 +0300391 .kind = CHARDEV_BACKEND_KIND_SPICEVMC,
392 .parse = qemu_chr_parse_spice_vmc,
393 .create = qemu_chr_open_spice_vmc,
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300394 .chr_write = spice_chr_write,
395 .chr_add_watch = spice_chr_add_watch,
396 .chr_set_fe_open = spice_vmc_set_fe_open,
397 .chr_accept_input = spice_chr_accept_input,
398 .chr_free = spice_chr_free,
Marc-André Lureau0b812f32016-10-21 16:07:45 +0300399 };
400 static const CharDriver port_driver = {
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300401 .instance_size = sizeof(SpiceChardev),
Marc-André Lureau0b812f32016-10-21 16:07:45 +0300402 .kind = CHARDEV_BACKEND_KIND_SPICEPORT,
403 .parse = qemu_chr_parse_spice_port,
404 .create = qemu_chr_open_spice_port,
Marc-André Lureaub68e9562016-10-21 20:49:37 +0300405 .chr_write = spice_chr_write,
406 .chr_add_watch = spice_chr_add_watch,
407 .chr_set_fe_open = spice_port_set_fe_open,
408 .chr_accept_input = spice_chr_accept_input,
409 .chr_free = spice_chr_free,
Marc-André Lureau0b812f32016-10-21 16:07:45 +0300410 };
411 register_char_driver(&vmc_driver);
412 register_char_driver(&port_driver);
Anthony Liguori26c60612013-03-05 23:21:29 +0530413}
414
415type_init(register_types);