|
|
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); ! 39: qemu_chr_read(scd->chr, p, last_out); ! 40: if (last_out > 0) { ! 41: out += last_out; ! 42: len -= last_out; ! 43: p += last_out; ! 44: } else { ! 45: break; ! 46: } ! 47: } ! 48: ! 49: dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out); ! 50: trace_spice_vmc_write(out, len + out); ! 51: return out; ! 52: } ! 53: ! 54: static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) ! 55: { ! 56: SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); ! 57: int bytes = MIN(len, scd->datalen); ! 58: ! 59: dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); ! 60: if (bytes > 0) { ! 61: memcpy(buf, scd->datapos, bytes); ! 62: scd->datapos += bytes; ! 63: scd->datalen -= bytes; ! 64: assert(scd->datalen >= 0); ! 65: if (scd->datalen == 0) { ! 66: scd->datapos = 0; ! 67: } ! 68: } ! 69: trace_spice_vmc_read(bytes, len); ! 70: return bytes; ! 71: } ! 72: ! 73: static SpiceCharDeviceInterface vmc_interface = { ! 74: .base.type = SPICE_INTERFACE_CHAR_DEVICE, ! 75: .base.description = "spice virtual channel char device", ! 76: .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, ! 77: .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, ! 78: .write = vmc_write, ! 79: .read = vmc_read, ! 80: }; ! 81: ! 82: ! 83: static void vmc_register_interface(SpiceCharDriver *scd) ! 84: { ! 85: if (scd->active) { ! 86: return; ! 87: } ! 88: dprintf(scd, 1, "%s\n", __func__); ! 89: scd->sin.base.sif = &vmc_interface.base; ! 90: qemu_spice_add_interface(&scd->sin.base); ! 91: scd->active = true; ! 92: trace_spice_vmc_register_interface(scd); ! 93: } ! 94: ! 95: static void vmc_unregister_interface(SpiceCharDriver *scd) ! 96: { ! 97: if (!scd->active) { ! 98: return; ! 99: } ! 100: dprintf(scd, 1, "%s\n", __func__); ! 101: spice_server_remove_interface(&scd->sin.base); ! 102: scd->active = false; ! 103: trace_spice_vmc_unregister_interface(scd); ! 104: } ! 105: ! 106: ! 107: static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) ! 108: { ! 109: SpiceCharDriver *s = chr->opaque; ! 110: ! 111: dprintf(s, 2, "%s: %d\n", __func__, len); ! 112: vmc_register_interface(s); ! 113: assert(s->datalen == 0); ! 114: if (s->bufsize < len) { ! 115: s->bufsize = len; ! 116: s->buffer = qemu_realloc(s->buffer, s->bufsize); ! 117: } ! 118: memcpy(s->buffer, buf, len); ! 119: s->datapos = s->buffer; ! 120: s->datalen = len; ! 121: spice_server_char_device_wakeup(&s->sin); ! 122: return len; ! 123: } ! 124: ! 125: static void spice_chr_close(struct CharDriverState *chr) ! 126: { ! 127: SpiceCharDriver *s = chr->opaque; ! 128: ! 129: printf("%s\n", __func__); ! 130: vmc_unregister_interface(s); ! 131: qemu_free(s); ! 132: } ! 133: ! 134: static void print_allowed_subtypes(void) ! 135: { ! 136: const char** psubtype; ! 137: int i; ! 138: ! 139: fprintf(stderr, "allowed names: "); ! 140: for(i=0, psubtype = spice_server_char_device_recognized_subtypes(); ! 141: *psubtype != NULL; ++psubtype, ++i) { ! 142: if (i == 0) { ! 143: fprintf(stderr, "%s", *psubtype); ! 144: } else { ! 145: fprintf(stderr, ", %s", *psubtype); ! 146: } ! 147: } ! 148: fprintf(stderr, "\n"); ! 149: } ! 150: ! 151: CharDriverState *qemu_chr_open_spice(QemuOpts *opts) ! 152: { ! 153: CharDriverState *chr; ! 154: SpiceCharDriver *s; ! 155: const char* name = qemu_opt_get(opts, "name"); ! 156: uint32_t debug = qemu_opt_get_number(opts, "debug", 0); ! 157: const char** psubtype = spice_server_char_device_recognized_subtypes(); ! 158: const char *subtype = NULL; ! 159: ! 160: if (name == NULL) { ! 161: fprintf(stderr, "spice-qemu-char: missing name parameter\n"); ! 162: print_allowed_subtypes(); ! 163: return NULL; ! 164: } ! 165: for(;*psubtype != NULL; ++psubtype) { ! 166: if (strcmp(name, *psubtype) == 0) { ! 167: subtype = *psubtype; ! 168: break; ! 169: } ! 170: } ! 171: if (subtype == NULL) { ! 172: fprintf(stderr, "spice-qemu-char: unsupported name\n"); ! 173: print_allowed_subtypes(); ! 174: return NULL; ! 175: } ! 176: ! 177: chr = qemu_mallocz(sizeof(CharDriverState)); ! 178: s = qemu_mallocz(sizeof(SpiceCharDriver)); ! 179: s->chr = chr; ! 180: s->debug = debug; ! 181: s->active = false; ! 182: s->sin.subtype = subtype; ! 183: chr->opaque = s; ! 184: chr->chr_write = spice_chr_write; ! 185: chr->chr_close = spice_chr_close; ! 186: ! 187: qemu_chr_generic_open(chr); ! 188: ! 189: return chr; ! 190: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.