xref: /openbmc/qemu/chardev/spice.c (revision 34d55725)
16b10e573SMarc-André Lureau #include "qemu/osdep.h"
26b10e573SMarc-André Lureau #include "trace.h"
36b10e573SMarc-André Lureau #include "ui/qemu-spice.h"
46b10e573SMarc-André Lureau #include "chardev/char.h"
524fa7da3SMarc-André Lureau #include "chardev/spice.h"
6e688df6bSMarkus Armbruster #include "qapi/error.h"
76b10e573SMarc-André Lureau #include "qemu/error-report.h"
80b8fa32fSMarkus Armbruster #include "qemu/module.h"
9922a01a0SMarkus Armbruster #include "qemu/option.h"
106b10e573SMarc-André Lureau #include <spice/protocol.h>
116b10e573SMarc-André Lureau 
126b10e573SMarc-André Lureau typedef struct SpiceCharSource {
136b10e573SMarc-André Lureau     GSource               source;
146b10e573SMarc-André Lureau     SpiceChardev       *scd;
156b10e573SMarc-André Lureau } SpiceCharSource;
166b10e573SMarc-André Lureau 
vmc_write(SpiceCharDeviceInstance * sin,const uint8_t * buf,int len)176b10e573SMarc-André Lureau static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
186b10e573SMarc-André Lureau {
196b10e573SMarc-André Lureau     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
206b10e573SMarc-André Lureau     Chardev *chr = CHARDEV(scd);
216b10e573SMarc-André Lureau     ssize_t out = 0;
226b10e573SMarc-André Lureau     ssize_t last_out;
236b10e573SMarc-André Lureau     uint8_t* p = (uint8_t*)buf;
246b10e573SMarc-André Lureau 
256b10e573SMarc-André Lureau     while (len > 0) {
266b10e573SMarc-André Lureau         int can_write = qemu_chr_be_can_write(chr);
276b10e573SMarc-André Lureau         last_out = MIN(len, can_write);
286b10e573SMarc-André Lureau         if (last_out <= 0) {
296b10e573SMarc-André Lureau             break;
306b10e573SMarc-André Lureau         }
316b10e573SMarc-André Lureau         qemu_chr_be_write(chr, p, last_out);
326b10e573SMarc-André Lureau         out += last_out;
336b10e573SMarc-André Lureau         len -= last_out;
346b10e573SMarc-André Lureau         p += last_out;
356b10e573SMarc-André Lureau     }
366b10e573SMarc-André Lureau 
376b10e573SMarc-André Lureau     trace_spice_vmc_write(out, len + out);
386b10e573SMarc-André Lureau     return out;
396b10e573SMarc-André Lureau }
406b10e573SMarc-André Lureau 
vmc_read(SpiceCharDeviceInstance * sin,uint8_t * buf,int len)416b10e573SMarc-André Lureau static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
426b10e573SMarc-André Lureau {
436b10e573SMarc-André Lureau     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
446b10e573SMarc-André Lureau     int bytes = MIN(len, scd->datalen);
456b10e573SMarc-André Lureau 
466b10e573SMarc-André Lureau     if (bytes > 0) {
476b10e573SMarc-André Lureau         memcpy(buf, scd->datapos, bytes);
486b10e573SMarc-André Lureau         scd->datapos += bytes;
496b10e573SMarc-André Lureau         scd->datalen -= bytes;
506b10e573SMarc-André Lureau         assert(scd->datalen >= 0);
516b10e573SMarc-André Lureau     }
526b10e573SMarc-André Lureau     if (scd->datalen == 0) {
536b10e573SMarc-André Lureau         scd->datapos = 0;
546b10e573SMarc-André Lureau         scd->blocked = false;
556b10e573SMarc-André Lureau     }
566b10e573SMarc-André Lureau     trace_spice_vmc_read(bytes, len);
576b10e573SMarc-André Lureau     return bytes;
586b10e573SMarc-André Lureau }
596b10e573SMarc-André Lureau 
vmc_event(SpiceCharDeviceInstance * sin,uint8_t event)606b10e573SMarc-André Lureau static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
616b10e573SMarc-André Lureau {
626b10e573SMarc-André Lureau     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
636b10e573SMarc-André Lureau     Chardev *chr = CHARDEV(scd);
646b10e573SMarc-André Lureau     int chr_event;
656b10e573SMarc-André Lureau 
666b10e573SMarc-André Lureau     switch (event) {
676b10e573SMarc-André Lureau     case SPICE_PORT_EVENT_BREAK:
686b10e573SMarc-André Lureau         chr_event = CHR_EVENT_BREAK;
696b10e573SMarc-André Lureau         break;
706b10e573SMarc-André Lureau     default:
716b10e573SMarc-André Lureau         return;
726b10e573SMarc-André Lureau     }
736b10e573SMarc-André Lureau 
746b10e573SMarc-André Lureau     trace_spice_vmc_event(chr_event);
756b10e573SMarc-André Lureau     qemu_chr_be_event(chr, chr_event);
766b10e573SMarc-André Lureau }
776b10e573SMarc-André Lureau 
vmc_state(SpiceCharDeviceInstance * sin,int connected)786b10e573SMarc-André Lureau static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
796b10e573SMarc-André Lureau {
806b10e573SMarc-André Lureau     SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
816b10e573SMarc-André Lureau     Chardev *chr = CHARDEV(scd);
826b10e573SMarc-André Lureau 
836b10e573SMarc-André Lureau     if ((chr->be_open && connected) ||
846b10e573SMarc-André Lureau         (!chr->be_open && !connected)) {
856b10e573SMarc-André Lureau         return;
866b10e573SMarc-André Lureau     }
876b10e573SMarc-André Lureau 
886b10e573SMarc-André Lureau     qemu_chr_be_event(chr,
896b10e573SMarc-André Lureau                       connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
906b10e573SMarc-André Lureau }
916b10e573SMarc-André Lureau 
926b10e573SMarc-André Lureau static SpiceCharDeviceInterface vmc_interface = {
936b10e573SMarc-André Lureau     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
946b10e573SMarc-André Lureau     .base.description   = "spice virtual channel char device",
956b10e573SMarc-André Lureau     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
966b10e573SMarc-André Lureau     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
976b10e573SMarc-André Lureau     .state              = vmc_state,
986b10e573SMarc-André Lureau     .write              = vmc_write,
996b10e573SMarc-André Lureau     .read               = vmc_read,
1006b10e573SMarc-André Lureau     .event              = vmc_event,
1016b10e573SMarc-André Lureau     .flags              = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE,
1026b10e573SMarc-André Lureau };
1036b10e573SMarc-André Lureau 
1046b10e573SMarc-André Lureau 
vmc_register_interface(SpiceChardev * scd)1056b10e573SMarc-André Lureau static void vmc_register_interface(SpiceChardev *scd)
1066b10e573SMarc-André Lureau {
1076b10e573SMarc-André Lureau     if (scd->active) {
1086b10e573SMarc-André Lureau         return;
1096b10e573SMarc-André Lureau     }
1106b10e573SMarc-André Lureau     scd->sin.base.sif = &vmc_interface.base;
11105b53636SGerd Hoffmann     qemu_spice.add_interface(&scd->sin.base);
1126b10e573SMarc-André Lureau     scd->active = true;
1136b10e573SMarc-André Lureau     trace_spice_vmc_register_interface(scd);
1146b10e573SMarc-André Lureau }
1156b10e573SMarc-André Lureau 
vmc_unregister_interface(SpiceChardev * scd)1166b10e573SMarc-André Lureau static void vmc_unregister_interface(SpiceChardev *scd)
1176b10e573SMarc-André Lureau {
1186b10e573SMarc-André Lureau     if (!scd->active) {
1196b10e573SMarc-André Lureau         return;
1206b10e573SMarc-André Lureau     }
1216b10e573SMarc-André Lureau     spice_server_remove_interface(&scd->sin.base);
1226b10e573SMarc-André Lureau     scd->active = false;
1236b10e573SMarc-André Lureau     trace_spice_vmc_unregister_interface(scd);
1246b10e573SMarc-André Lureau }
1256b10e573SMarc-André Lureau 
spice_char_source_prepare(GSource * source,gint * timeout)1266b10e573SMarc-André Lureau static gboolean spice_char_source_prepare(GSource *source, gint *timeout)
1276b10e573SMarc-André Lureau {
1286b10e573SMarc-André Lureau     SpiceCharSource *src = (SpiceCharSource *)source;
129805189abSMarc-André Lureau     Chardev *chr = CHARDEV(src->scd);
1306b10e573SMarc-André Lureau 
1316b10e573SMarc-André Lureau     *timeout = -1;
1326b10e573SMarc-André Lureau 
133805189abSMarc-André Lureau     if (!chr->be_open) {
134805189abSMarc-André Lureau         return true;
135805189abSMarc-André Lureau     }
136805189abSMarc-André Lureau 
1376b10e573SMarc-André Lureau     return !src->scd->blocked;
1386b10e573SMarc-André Lureau }
1396b10e573SMarc-André Lureau 
spice_char_source_check(GSource * source)1406b10e573SMarc-André Lureau static gboolean spice_char_source_check(GSource *source)
1416b10e573SMarc-André Lureau {
1426b10e573SMarc-André Lureau     SpiceCharSource *src = (SpiceCharSource *)source;
143805189abSMarc-André Lureau     Chardev *chr = CHARDEV(src->scd);
144805189abSMarc-André Lureau 
145805189abSMarc-André Lureau     if (!chr->be_open) {
146805189abSMarc-André Lureau         return true;
147805189abSMarc-André Lureau     }
1486b10e573SMarc-André Lureau 
1496b10e573SMarc-André Lureau     return !src->scd->blocked;
1506b10e573SMarc-André Lureau }
1516b10e573SMarc-André Lureau 
spice_char_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)1526b10e573SMarc-André Lureau static gboolean spice_char_source_dispatch(GSource *source,
1536b10e573SMarc-André Lureau     GSourceFunc callback, gpointer user_data)
1546b10e573SMarc-André Lureau {
155805189abSMarc-André Lureau     SpiceCharSource *src = (SpiceCharSource *)source;
156805189abSMarc-André Lureau     Chardev *chr = CHARDEV(src->scd);
1576b10e573SMarc-André Lureau     GIOFunc func = (GIOFunc)callback;
158805189abSMarc-André Lureau     GIOCondition cond = chr->be_open ? G_IO_OUT : G_IO_HUP;
1596b10e573SMarc-André Lureau 
160805189abSMarc-André Lureau     return func(NULL, cond, user_data);
1616b10e573SMarc-André Lureau }
1626b10e573SMarc-André Lureau 
1636b10e573SMarc-André Lureau static GSourceFuncs SpiceCharSourceFuncs = {
1646b10e573SMarc-André Lureau     .prepare  = spice_char_source_prepare,
1656b10e573SMarc-André Lureau     .check    = spice_char_source_check,
1666b10e573SMarc-André Lureau     .dispatch = spice_char_source_dispatch,
1676b10e573SMarc-André Lureau };
1686b10e573SMarc-André Lureau 
spice_chr_add_watch(Chardev * chr,GIOCondition cond)1696b10e573SMarc-André Lureau static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
1706b10e573SMarc-André Lureau {
1716b10e573SMarc-André Lureau     SpiceChardev *scd = SPICE_CHARDEV(chr);
1726b10e573SMarc-André Lureau     SpiceCharSource *src;
1736b10e573SMarc-André Lureau 
1746b10e573SMarc-André Lureau     assert(cond & G_IO_OUT);
1756b10e573SMarc-André Lureau 
1766b10e573SMarc-André Lureau     src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs,
1776b10e573SMarc-André Lureau                                           sizeof(SpiceCharSource));
1786b10e573SMarc-André Lureau     src->scd = scd;
1796b10e573SMarc-André Lureau 
1806b10e573SMarc-André Lureau     return (GSource *)src;
1816b10e573SMarc-André Lureau }
1826b10e573SMarc-André Lureau 
spice_chr_write(Chardev * chr,const uint8_t * buf,int len)1836b10e573SMarc-André Lureau static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
1846b10e573SMarc-André Lureau {
1856b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(chr);
1866b10e573SMarc-André Lureau     int read_bytes;
1876b10e573SMarc-André Lureau 
1886b10e573SMarc-André Lureau     assert(s->datalen == 0);
189a2dc3c8eSMarc-André Lureau 
190a2dc3c8eSMarc-André Lureau     if (!chr->be_open) {
191a2dc3c8eSMarc-André Lureau         trace_spice_chr_discard_write(len);
192a2dc3c8eSMarc-André Lureau         return len;
193a2dc3c8eSMarc-André Lureau     }
194a2dc3c8eSMarc-André Lureau 
1956b10e573SMarc-André Lureau     s->datapos = buf;
1966b10e573SMarc-André Lureau     s->datalen = len;
1976b10e573SMarc-André Lureau     spice_server_char_device_wakeup(&s->sin);
1986b10e573SMarc-André Lureau     read_bytes = len - s->datalen;
1996b10e573SMarc-André Lureau     if (read_bytes != len) {
2006b10e573SMarc-André Lureau         /* We'll get passed in the unconsumed data with the next call */
2016b10e573SMarc-André Lureau         s->datalen = 0;
2026b10e573SMarc-André Lureau         s->datapos = NULL;
2036b10e573SMarc-André Lureau         s->blocked = true;
2046b10e573SMarc-André Lureau     }
2056b10e573SMarc-André Lureau     return read_bytes;
2066b10e573SMarc-André Lureau }
2076b10e573SMarc-André Lureau 
char_spice_finalize(Object * obj)2086b10e573SMarc-André Lureau static void char_spice_finalize(Object *obj)
2096b10e573SMarc-André Lureau {
2106b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(obj);
2116b10e573SMarc-André Lureau 
2126b10e573SMarc-André Lureau     vmc_unregister_interface(s);
2136b10e573SMarc-André Lureau 
2146b10e573SMarc-André Lureau     g_free((char *)s->sin.subtype);
2156b10e573SMarc-André Lureau     g_free((char *)s->sin.portname);
2166b10e573SMarc-André Lureau }
2176b10e573SMarc-André Lureau 
spice_vmc_set_fe_open(struct Chardev * chr,int fe_open)2186b10e573SMarc-André Lureau static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
2196b10e573SMarc-André Lureau {
2206b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(chr);
2216b10e573SMarc-André Lureau     if (fe_open) {
2226b10e573SMarc-André Lureau         vmc_register_interface(s);
2236b10e573SMarc-André Lureau     } else {
2246b10e573SMarc-André Lureau         vmc_unregister_interface(s);
2256b10e573SMarc-André Lureau     }
2266b10e573SMarc-André Lureau }
2276b10e573SMarc-André Lureau 
spice_port_set_fe_open(struct Chardev * chr,int fe_open)2286b10e573SMarc-André Lureau static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
2296b10e573SMarc-André Lureau {
2306b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(chr);
2316b10e573SMarc-André Lureau 
2326b10e573SMarc-André Lureau     if (fe_open) {
2336b10e573SMarc-André Lureau         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
2346b10e573SMarc-André Lureau     } else {
2356b10e573SMarc-André Lureau         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED);
2366b10e573SMarc-André Lureau     }
2376b10e573SMarc-André Lureau }
2386b10e573SMarc-André Lureau 
spice_chr_accept_input(struct Chardev * chr)2396b10e573SMarc-André Lureau static void spice_chr_accept_input(struct Chardev *chr)
2406b10e573SMarc-André Lureau {
2416b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(chr);
2426b10e573SMarc-André Lureau 
2436b10e573SMarc-André Lureau     spice_server_char_device_wakeup(&s->sin);
2446b10e573SMarc-André Lureau }
2456b10e573SMarc-André Lureau 
chr_open(Chardev * chr,const char * subtype)2466b10e573SMarc-André Lureau static void chr_open(Chardev *chr, const char *subtype)
2476b10e573SMarc-André Lureau {
2486b10e573SMarc-André Lureau     SpiceChardev *s = SPICE_CHARDEV(chr);
2496b10e573SMarc-André Lureau 
2506b10e573SMarc-André Lureau     s->active = false;
2516b10e573SMarc-André Lureau     s->sin.subtype = g_strdup(subtype);
2526b10e573SMarc-André Lureau }
2536b10e573SMarc-André Lureau 
qemu_chr_open_spice_vmc(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)2546b10e573SMarc-André Lureau static void qemu_chr_open_spice_vmc(Chardev *chr,
2556b10e573SMarc-André Lureau                                     ChardevBackend *backend,
2566b10e573SMarc-André Lureau                                     bool *be_opened,
2576b10e573SMarc-André Lureau                                     Error **errp)
2586b10e573SMarc-André Lureau {
2596b10e573SMarc-André Lureau     ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
2606b10e573SMarc-André Lureau     const char *type = spicevmc->type;
2616b10e573SMarc-André Lureau     const char **psubtype = spice_server_char_device_recognized_subtypes();
2626b10e573SMarc-André Lureau 
2636b10e573SMarc-André Lureau     for (; *psubtype != NULL; ++psubtype) {
2646b10e573SMarc-André Lureau         if (strcmp(type, *psubtype) == 0) {
2656b10e573SMarc-André Lureau             break;
2666b10e573SMarc-André Lureau         }
2676b10e573SMarc-André Lureau     }
2686b10e573SMarc-André Lureau     if (*psubtype == NULL) {
2696b10e573SMarc-André Lureau         char *subtypes = g_strjoinv(", ",
2706b10e573SMarc-André Lureau             (gchar **)spice_server_char_device_recognized_subtypes());
2716b10e573SMarc-André Lureau 
2726b10e573SMarc-André Lureau         error_setg(errp, "unsupported type name: %s", type);
2736b10e573SMarc-André Lureau         error_append_hint(errp, "allowed spice char type names: %s\n",
2746b10e573SMarc-André Lureau                           subtypes);
2756b10e573SMarc-André Lureau 
2766b10e573SMarc-André Lureau         g_free(subtypes);
2776b10e573SMarc-André Lureau         return;
2786b10e573SMarc-André Lureau     }
2796b10e573SMarc-André Lureau 
2806b10e573SMarc-André Lureau     *be_opened = false;
281a2dc3c8eSMarc-André Lureau #if SPICE_SERVER_VERSION < 0x000e02
282a2dc3c8eSMarc-André Lureau     /* Spice < 0.14.2 doesn't explicitly open smartcard chardev */
283a2dc3c8eSMarc-André Lureau     if (strcmp(type, "smartcard") == 0) {
284a2dc3c8eSMarc-André Lureau         *be_opened = true;
285a2dc3c8eSMarc-André Lureau     }
286a2dc3c8eSMarc-André Lureau #endif
2876b10e573SMarc-André Lureau     chr_open(chr, type);
2886b10e573SMarc-André Lureau }
2896b10e573SMarc-André Lureau 
qemu_chr_open_spice_port(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)29070122d62SGerd Hoffmann static void qemu_chr_open_spice_port(Chardev *chr,
2916b10e573SMarc-André Lureau                                      ChardevBackend *backend,
2926b10e573SMarc-André Lureau                                      bool *be_opened,
2936b10e573SMarc-André Lureau                                      Error **errp)
2946b10e573SMarc-André Lureau {
2956b10e573SMarc-André Lureau     ChardevSpicePort *spiceport = backend->u.spiceport.data;
2966b10e573SMarc-André Lureau     const char *name = spiceport->fqdn;
2976b10e573SMarc-André Lureau     SpiceChardev *s;
2986b10e573SMarc-André Lureau 
2996b10e573SMarc-André Lureau     if (name == NULL) {
3006b10e573SMarc-André Lureau         error_setg(errp, "missing name parameter");
3016b10e573SMarc-André Lureau         return;
3026b10e573SMarc-André Lureau     }
3036b10e573SMarc-André Lureau 
30493ab5844SGerd Hoffmann     if (!using_spice) {
30593ab5844SGerd Hoffmann         error_setg(errp, "spice not enabled");
30693ab5844SGerd Hoffmann         return;
30793ab5844SGerd Hoffmann     }
30893ab5844SGerd Hoffmann 
3096b10e573SMarc-André Lureau     chr_open(chr, "port");
3106b10e573SMarc-André Lureau 
3116b10e573SMarc-André Lureau     *be_opened = false;
3126b10e573SMarc-André Lureau     s = SPICE_CHARDEV(chr);
3136b10e573SMarc-André Lureau     s->sin.portname = g_strdup(name);
3148afbff16SMarc-André Lureau 
3158afbff16SMarc-André Lureau     vmc_register_interface(s);
3168afbff16SMarc-André Lureau }
3176b10e573SMarc-André Lureau 
qemu_chr_parse_spice_vmc(QemuOpts * opts,ChardevBackend * backend,Error ** errp)3186b10e573SMarc-André Lureau static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
3196b10e573SMarc-André Lureau                                      Error **errp)
3206b10e573SMarc-André Lureau {
3216b10e573SMarc-André Lureau     const char *name = qemu_opt_get(opts, "name");
3226b10e573SMarc-André Lureau     ChardevSpiceChannel *spicevmc;
3236b10e573SMarc-André Lureau 
3246b10e573SMarc-André Lureau     if (name == NULL) {
3256b10e573SMarc-André Lureau         error_setg(errp, "chardev: spice channel: no name given");
3266b10e573SMarc-André Lureau         return;
3276b10e573SMarc-André Lureau     }
3286b10e573SMarc-André Lureau     backend->type = CHARDEV_BACKEND_KIND_SPICEVMC;
3296b10e573SMarc-André Lureau     spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1);
3306b10e573SMarc-André Lureau     qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
3316b10e573SMarc-André Lureau     spicevmc->type = g_strdup(name);
3326b10e573SMarc-André Lureau }
3336b10e573SMarc-André Lureau 
qemu_chr_parse_spice_port(QemuOpts * opts,ChardevBackend * backend,Error ** errp)3346b10e573SMarc-André Lureau static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
3356b10e573SMarc-André Lureau                                       Error **errp)
3366b10e573SMarc-André Lureau {
3376b10e573SMarc-André Lureau     const char *name = qemu_opt_get(opts, "name");
3386b10e573SMarc-André Lureau     ChardevSpicePort *spiceport;
3396b10e573SMarc-André Lureau 
3406b10e573SMarc-André Lureau     if (name == NULL) {
3416b10e573SMarc-André Lureau         error_setg(errp, "chardev: spice port: no name given");
3426b10e573SMarc-André Lureau         return;
3436b10e573SMarc-André Lureau     }
3446b10e573SMarc-André Lureau     backend->type = CHARDEV_BACKEND_KIND_SPICEPORT;
3456b10e573SMarc-André Lureau     spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1);
3466b10e573SMarc-André Lureau     qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
3476b10e573SMarc-André Lureau     spiceport->fqdn = g_strdup(name);
3486b10e573SMarc-André Lureau }
3496b10e573SMarc-André Lureau 
char_spice_class_init(ObjectClass * oc,void * data)3506b10e573SMarc-André Lureau static void char_spice_class_init(ObjectClass *oc, void *data)
3516b10e573SMarc-André Lureau {
3526b10e573SMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
3536b10e573SMarc-André Lureau 
3546b10e573SMarc-André Lureau     cc->chr_write = spice_chr_write;
3556b10e573SMarc-André Lureau     cc->chr_add_watch = spice_chr_add_watch;
3566b10e573SMarc-André Lureau     cc->chr_accept_input = spice_chr_accept_input;
3576b10e573SMarc-André Lureau }
3586b10e573SMarc-André Lureau 
3596b10e573SMarc-André Lureau static const TypeInfo char_spice_type_info = {
3606b10e573SMarc-André Lureau     .name = TYPE_CHARDEV_SPICE,
3616b10e573SMarc-André Lureau     .parent = TYPE_CHARDEV,
3626b10e573SMarc-André Lureau     .instance_size = sizeof(SpiceChardev),
3636b10e573SMarc-André Lureau     .instance_finalize = char_spice_finalize,
3646b10e573SMarc-André Lureau     .class_init = char_spice_class_init,
3656b10e573SMarc-André Lureau     .abstract = true,
3666b10e573SMarc-André Lureau };
367882273d9SGerd Hoffmann module_obj(TYPE_CHARDEV_SPICE);
3686b10e573SMarc-André Lureau 
char_spicevmc_class_init(ObjectClass * oc,void * data)3696b10e573SMarc-André Lureau static void char_spicevmc_class_init(ObjectClass *oc, void *data)
3706b10e573SMarc-André Lureau {
3716b10e573SMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
3726b10e573SMarc-André Lureau 
3736b10e573SMarc-André Lureau     cc->parse = qemu_chr_parse_spice_vmc;
3746b10e573SMarc-André Lureau     cc->open = qemu_chr_open_spice_vmc;
3756b10e573SMarc-André Lureau     cc->chr_set_fe_open = spice_vmc_set_fe_open;
3766b10e573SMarc-André Lureau }
3776b10e573SMarc-André Lureau 
3786b10e573SMarc-André Lureau static const TypeInfo char_spicevmc_type_info = {
3796b10e573SMarc-André Lureau     .name = TYPE_CHARDEV_SPICEVMC,
3806b10e573SMarc-André Lureau     .parent = TYPE_CHARDEV_SPICE,
3816b10e573SMarc-André Lureau     .class_init = char_spicevmc_class_init,
3826b10e573SMarc-André Lureau };
383*f288d993SPaolo Bonzini module_obj(TYPE_CHARDEV_SPICEVMC);
3846b10e573SMarc-André Lureau 
char_spiceport_class_init(ObjectClass * oc,void * data)3856b10e573SMarc-André Lureau static void char_spiceport_class_init(ObjectClass *oc, void *data)
3866b10e573SMarc-André Lureau {
3876b10e573SMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
3886b10e573SMarc-André Lureau 
3896b10e573SMarc-André Lureau     cc->parse = qemu_chr_parse_spice_port;
3906b10e573SMarc-André Lureau     cc->open = qemu_chr_open_spice_port;
3916b10e573SMarc-André Lureau     cc->chr_set_fe_open = spice_port_set_fe_open;
3926b10e573SMarc-André Lureau }
3936b10e573SMarc-André Lureau 
3946b10e573SMarc-André Lureau static const TypeInfo char_spiceport_type_info = {
3956b10e573SMarc-André Lureau     .name = TYPE_CHARDEV_SPICEPORT,
3966b10e573SMarc-André Lureau     .parent = TYPE_CHARDEV_SPICE,
3976b10e573SMarc-André Lureau     .class_init = char_spiceport_class_init,
3986b10e573SMarc-André Lureau };
399882273d9SGerd Hoffmann module_obj(TYPE_CHARDEV_SPICEPORT);
4006b10e573SMarc-André Lureau 
register_types(void)4016b10e573SMarc-André Lureau static void register_types(void)
4026b10e573SMarc-André Lureau {
4036b10e573SMarc-André Lureau     type_register_static(&char_spice_type_info);
4046b10e573SMarc-André Lureau     type_register_static(&char_spicevmc_type_info);
4056b10e573SMarc-André Lureau     type_register_static(&char_spiceport_type_info);
4066b10e573SMarc-André Lureau }
4076b10e573SMarc-André Lureau 
4086b10e573SMarc-André Lureau type_init(register_types);
409882273d9SGerd Hoffmann 
410882273d9SGerd Hoffmann module_dep("ui-spice-core");
411