]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - spice-qemu-char.c
tcg-ia64: Use A3 form of logical operations
[lisovros/qemu_apohw.git] / spice-qemu-char.c
1 #include "config-host.h"
2 #include "trace.h"
3 #include "ui/qemu-spice.h"
4 #include "sysemu/char.h"
5 #include <spice.h>
6 #include <spice-experimental.h>
7 #include <spice/protocol.h>
8
9 #include "qemu/osdep.h"
10
11 typedef struct SpiceCharDriver {
12     CharDriverState*      chr;
13     SpiceCharDeviceInstance     sin;
14     char                  *subtype;
15     bool                  active;
16     bool                  blocked;
17     const uint8_t         *datapos;
18     int                   datalen;
19     QLIST_ENTRY(SpiceCharDriver) next;
20 } SpiceCharDriver;
21
22 typedef struct SpiceCharSource {
23     GSource               source;
24     SpiceCharDriver       *scd;
25 } SpiceCharSource;
26
27 static QLIST_HEAD(, SpiceCharDriver) spice_chars =
28     QLIST_HEAD_INITIALIZER(spice_chars);
29
30 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
31 {
32     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
33     ssize_t out = 0;
34     ssize_t last_out;
35     uint8_t* p = (uint8_t*)buf;
36
37     while (len > 0) {
38         int can_write = qemu_chr_be_can_write(scd->chr);
39         last_out = MIN(len, can_write);
40         if (last_out <= 0) {
41             break;
42         }
43         qemu_chr_be_write(scd->chr, p, last_out);
44         out += last_out;
45         len -= last_out;
46         p += last_out;
47     }
48
49     trace_spice_vmc_write(out, len + out);
50     return out;
51 }
52
53 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
54 {
55     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
56     int bytes = MIN(len, scd->datalen);
57
58     if (bytes > 0) {
59         memcpy(buf, scd->datapos, bytes);
60         scd->datapos += bytes;
61         scd->datalen -= bytes;
62         assert(scd->datalen >= 0);
63     }
64     if (scd->datalen == 0) {
65         scd->datapos = 0;
66         scd->blocked = false;
67     }
68     trace_spice_vmc_read(bytes, len);
69     return bytes;
70 }
71
72 #if SPICE_SERVER_VERSION >= 0x000c02
73 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
74 {
75     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
76     int chr_event;
77
78     switch (event) {
79     case SPICE_PORT_EVENT_BREAK:
80         chr_event = CHR_EVENT_BREAK;
81         break;
82     default:
83         return;
84     }
85
86     trace_spice_vmc_event(chr_event);
87     qemu_chr_be_event(scd->chr, chr_event);
88 }
89 #endif
90
91 static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
92 {
93     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
94
95     if ((scd->chr->be_open && connected) ||
96         (!scd->chr->be_open && !connected)) {
97         return;
98     }
99
100     qemu_chr_be_event(scd->chr,
101                       connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
102 }
103
104 static SpiceCharDeviceInterface vmc_interface = {
105     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
106     .base.description   = "spice virtual channel char device",
107     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
108     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
109     .state              = vmc_state,
110     .write              = vmc_write,
111     .read               = vmc_read,
112 #if SPICE_SERVER_VERSION >= 0x000c02
113     .event              = vmc_event,
114 #endif
115 };
116
117
118 static void vmc_register_interface(SpiceCharDriver *scd)
119 {
120     if (scd->active) {
121         return;
122     }
123     scd->sin.base.sif = &vmc_interface.base;
124     qemu_spice_add_interface(&scd->sin.base);
125     scd->active = true;
126     trace_spice_vmc_register_interface(scd);
127 }
128
129 static void vmc_unregister_interface(SpiceCharDriver *scd)
130 {
131     if (!scd->active) {
132         return;
133     }
134     spice_server_remove_interface(&scd->sin.base);
135     scd->active = false;
136     trace_spice_vmc_unregister_interface(scd);
137 }
138
139 static gboolean spice_char_source_prepare(GSource *source, gint *timeout)
140 {
141     SpiceCharSource *src = (SpiceCharSource *)source;
142
143     *timeout = -1;
144
145     return !src->scd->blocked;
146 }
147
148 static gboolean spice_char_source_check(GSource *source)
149 {
150     SpiceCharSource *src = (SpiceCharSource *)source;
151
152     return !src->scd->blocked;
153 }
154
155 static gboolean spice_char_source_dispatch(GSource *source,
156     GSourceFunc callback, gpointer user_data)
157 {
158     GIOFunc func = (GIOFunc)callback;
159
160     return func(NULL, G_IO_OUT, user_data);
161 }
162
163 GSourceFuncs SpiceCharSourceFuncs = {
164     .prepare  = spice_char_source_prepare,
165     .check    = spice_char_source_check,
166     .dispatch = spice_char_source_dispatch,
167 };
168
169 static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
170 {
171     SpiceCharDriver *scd = chr->opaque;
172     SpiceCharSource *src;
173
174     assert(cond == G_IO_OUT);
175
176     src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs,
177                                           sizeof(SpiceCharSource));
178     src->scd = scd;
179
180     return (GSource *)src;
181 }
182
183 static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
184 {
185     SpiceCharDriver *s = chr->opaque;
186     int read_bytes;
187
188     assert(s->datalen == 0);
189     s->datapos = buf;
190     s->datalen = len;
191     spice_server_char_device_wakeup(&s->sin);
192     read_bytes = len - s->datalen;
193     if (read_bytes != len) {
194         /* We'll get passed in the unconsumed data with the next call */
195         s->datalen = 0;
196         s->datapos = NULL;
197         s->blocked = true;
198     }
199     return read_bytes;
200 }
201
202 static void spice_chr_close(struct CharDriverState *chr)
203 {
204     SpiceCharDriver *s = chr->opaque;
205
206     vmc_unregister_interface(s);
207     QLIST_REMOVE(s, next);
208
209     g_free((char *)s->sin.subtype);
210 #if SPICE_SERVER_VERSION >= 0x000c02
211     g_free((char *)s->sin.portname);
212 #endif
213     g_free(s);
214 }
215
216 static void spice_chr_set_fe_open(struct CharDriverState *chr, int fe_open)
217 {
218     SpiceCharDriver *s = chr->opaque;
219     if (fe_open) {
220         vmc_register_interface(s);
221     } else {
222         vmc_unregister_interface(s);
223     }
224 }
225
226 static void print_allowed_subtypes(void)
227 {
228     const char** psubtype;
229     int i;
230
231     fprintf(stderr, "allowed names: ");
232     for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
233         *psubtype != NULL; ++psubtype, ++i) {
234         if (i == 0) {
235             fprintf(stderr, "%s", *psubtype);
236         } else {
237             fprintf(stderr, ", %s", *psubtype);
238         }
239     }
240     fprintf(stderr, "\n");
241 }
242
243 static CharDriverState *chr_open(const char *subtype)
244 {
245     CharDriverState *chr;
246     SpiceCharDriver *s;
247
248     chr = g_malloc0(sizeof(CharDriverState));
249     s = g_malloc0(sizeof(SpiceCharDriver));
250     s->chr = chr;
251     s->active = false;
252     s->sin.subtype = g_strdup(subtype);
253     chr->opaque = s;
254     chr->chr_write = spice_chr_write;
255     chr->chr_add_watch = spice_chr_add_watch;
256     chr->chr_close = spice_chr_close;
257     chr->chr_set_fe_open = spice_chr_set_fe_open;
258     chr->explicit_be_open = true;
259
260     QLIST_INSERT_HEAD(&spice_chars, s, next);
261
262     return chr;
263 }
264
265 CharDriverState *qemu_chr_open_spice_vmc(const char *type)
266 {
267     const char **psubtype = spice_server_char_device_recognized_subtypes();
268
269     if (type == NULL) {
270         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
271         print_allowed_subtypes();
272         return NULL;
273     }
274     for (; *psubtype != NULL; ++psubtype) {
275         if (strcmp(type, *psubtype) == 0) {
276             break;
277         }
278     }
279     if (*psubtype == NULL) {
280         fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
281         print_allowed_subtypes();
282         return NULL;
283     }
284
285     return chr_open(type);
286 }
287
288 #if SPICE_SERVER_VERSION >= 0x000c02
289 CharDriverState *qemu_chr_open_spice_port(const char *name)
290 {
291     CharDriverState *chr;
292     SpiceCharDriver *s;
293
294     if (name == NULL) {
295         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
296         return NULL;
297     }
298
299     chr = chr_open("port");
300     s = chr->opaque;
301     s->sin.portname = g_strdup(name);
302
303     return chr;
304 }
305
306 void qemu_spice_register_ports(void)
307 {
308     SpiceCharDriver *s;
309
310     QLIST_FOREACH(s, &spice_chars, next) {
311         if (s->sin.portname == NULL) {
312             continue;
313         }
314         vmc_register_interface(s);
315     }
316 }
317 #endif
318
319 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
320                                      Error **errp)
321 {
322     const char *name = qemu_opt_get(opts, "name");
323
324     if (name == NULL) {
325         error_setg(errp, "chardev: spice channel: no name given");
326         return;
327     }
328     backend->spicevmc = g_new0(ChardevSpiceChannel, 1);
329     backend->spicevmc->type = g_strdup(name);
330 }
331
332 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
333                                       Error **errp)
334 {
335     const char *name = qemu_opt_get(opts, "name");
336
337     if (name == NULL) {
338         error_setg(errp, "chardev: spice port: no name given");
339         return;
340     }
341     backend->spiceport = g_new0(ChardevSpicePort, 1);
342     backend->spiceport->fqdn = g_strdup(name);
343 }
344
345 static void register_types(void)
346 {
347     register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
348                               qemu_chr_parse_spice_vmc);
349     register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
350                               qemu_chr_parse_spice_port);
351 }
352
353 type_init(register_types);