|
|
1.1 root 1: #include "config-host.h"
2: #include "trace.h"
3: #include "ui/qemu-spice.h"
4: #include <spice.h>
5: #include <spice-experimental.h>
6:
7: #include "osdep.h"
8:
9: #define dprintf(_scd, _level, _fmt, ...) \
10: do { \
11: static unsigned __dprintf_counter = 0; \
12: if (_scd->debug >= _level) { \
13: fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
14: } \
15: } while (0)
16:
17: #define VMC_MAX_HOST_WRITE 2048
18:
19: typedef struct SpiceCharDriver {
20: CharDriverState* chr;
21: SpiceCharDeviceInstance sin;
22: char *subtype;
23: bool active;
24: uint8_t *buffer;
25: uint8_t *datapos;
26: ssize_t bufsize, datalen;
27: uint32_t debug;
28: } SpiceCharDriver;
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: last_out = MIN(len, VMC_MAX_HOST_WRITE);
1.1.1.2 ! root 39: if (qemu_chr_can_read(scd->chr) < last_out) {
1.1 root 40: break;
41: }
1.1.1.2 ! root 42: qemu_chr_read(scd->chr, p, last_out);
! 43: out += last_out;
! 44: len -= last_out;
! 45: p += last_out;
1.1 root 46: }
47:
48: dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
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: dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
59: if (bytes > 0) {
60: memcpy(buf, scd->datapos, bytes);
61: scd->datapos += bytes;
62: scd->datalen -= bytes;
63: assert(scd->datalen >= 0);
64: if (scd->datalen == 0) {
65: scd->datapos = 0;
66: }
67: }
68: trace_spice_vmc_read(bytes, len);
69: return bytes;
70: }
71:
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,
77: .write = vmc_write,
78: .read = vmc_read,
79: };
80:
81:
82: static void vmc_register_interface(SpiceCharDriver *scd)
83: {
84: if (scd->active) {
85: return;
86: }
87: dprintf(scd, 1, "%s\n", __func__);
88: scd->sin.base.sif = &vmc_interface.base;
89: qemu_spice_add_interface(&scd->sin.base);
90: scd->active = true;
91: trace_spice_vmc_register_interface(scd);
92: }
93:
94: static void vmc_unregister_interface(SpiceCharDriver *scd)
95: {
96: if (!scd->active) {
97: return;
98: }
99: dprintf(scd, 1, "%s\n", __func__);
100: spice_server_remove_interface(&scd->sin.base);
101: scd->active = false;
102: trace_spice_vmc_unregister_interface(scd);
103: }
104:
105:
106: static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
107: {
108: SpiceCharDriver *s = chr->opaque;
109:
110: dprintf(s, 2, "%s: %d\n", __func__, len);
111: vmc_register_interface(s);
112: assert(s->datalen == 0);
113: if (s->bufsize < len) {
114: s->bufsize = len;
115: s->buffer = qemu_realloc(s->buffer, s->bufsize);
116: }
117: memcpy(s->buffer, buf, len);
118: s->datapos = s->buffer;
119: s->datalen = len;
120: spice_server_char_device_wakeup(&s->sin);
121: return len;
122: }
123:
124: static void spice_chr_close(struct CharDriverState *chr)
125: {
126: SpiceCharDriver *s = chr->opaque;
127:
128: printf("%s\n", __func__);
129: vmc_unregister_interface(s);
130: qemu_free(s);
131: }
132:
1.1.1.2 ! root 133: static void spice_chr_guest_open(struct CharDriverState *chr)
! 134: {
! 135: SpiceCharDriver *s = chr->opaque;
! 136: vmc_register_interface(s);
! 137: }
! 138:
! 139: static void spice_chr_guest_close(struct CharDriverState *chr)
! 140: {
! 141: SpiceCharDriver *s = chr->opaque;
! 142: vmc_unregister_interface(s);
! 143: }
! 144:
1.1 root 145: static void print_allowed_subtypes(void)
146: {
147: const char** psubtype;
148: int i;
149:
150: fprintf(stderr, "allowed names: ");
151: for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
152: *psubtype != NULL; ++psubtype, ++i) {
153: if (i == 0) {
154: fprintf(stderr, "%s", *psubtype);
155: } else {
156: fprintf(stderr, ", %s", *psubtype);
157: }
158: }
159: fprintf(stderr, "\n");
160: }
161:
1.1.1.2 ! root 162: int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
1.1 root 163: {
164: CharDriverState *chr;
165: SpiceCharDriver *s;
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;
170:
171: if (name == NULL) {
172: fprintf(stderr, "spice-qemu-char: missing name parameter\n");
173: print_allowed_subtypes();
1.1.1.2 ! root 174: return -EINVAL;
1.1 root 175: }
176: for(;*psubtype != NULL; ++psubtype) {
177: if (strcmp(name, *psubtype) == 0) {
178: subtype = *psubtype;
179: break;
180: }
181: }
182: if (subtype == NULL) {
183: fprintf(stderr, "spice-qemu-char: unsupported name\n");
184: print_allowed_subtypes();
1.1.1.2 ! root 185: return -EINVAL;
1.1 root 186: }
187:
188: chr = qemu_mallocz(sizeof(CharDriverState));
189: s = qemu_mallocz(sizeof(SpiceCharDriver));
190: s->chr = chr;
191: s->debug = debug;
192: s->active = false;
193: s->sin.subtype = subtype;
194: chr->opaque = s;
195: chr->chr_write = spice_chr_write;
196: chr->chr_close = spice_chr_close;
1.1.1.2 ! root 197: chr->chr_guest_open = spice_chr_guest_open;
! 198: chr->chr_guest_close = spice_chr_guest_close;
1.1 root 199:
200: qemu_chr_generic_open(chr);
201:
1.1.1.2 ! root 202: *_chr = chr;
! 203: return 0;
1.1 root 204: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.