diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-14 14:54:37 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-14 14:54:37 -0500 |
commit | 139a4b63e3dd002de79d8c0a7c04fcc5bbeb1307 (patch) | |
tree | b41eac7e4698f68cc7e2431304b4b782f41933e8 | |
parent | 3d34a4110c58bba120bc3d7c96c4b9571994c2a8 (diff) | |
parent | 344bf1e935163d8a4c3cce3ec4c636e1ebd035ce (diff) |
Merge remote-tracking branch 'kraxel/chardev.5' into staging
* kraxel/chardev.5:
spice-qemu-char: Remove dead debugging code
spice-qemu-char: Fix name parameter issues after qapi-ifying
qemu-char.c: fix waiting for telnet connection message
Revert "hmp: Disable chardev-add and chardev-remove"
chardev: add udp support to qapi
chardev: add memory (ringbuf) support to qapi
chardev: add vc support to qapi
chardev: add spice support to qapi
chardev: add pipe support to qapi
chardev: add console support to qapi
chardev: switch pty init to qapi
chardev: switch parallel init to qapi
chardev: switch serial/tty init to qapi
chardev: add stdio support to qapi
chardev: switch file init to qapi
chardev: add braille support to qapi
chardev: add msmouse support to qapi
chardev: switch null init to qapi
chardev: add mux chardev support to qapi
chardev: add support for qapi-based chardev initialization
Conflicts:
ui/console.c
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r-- | backends/baum.c | 4 | ||||
-rw-r--r-- | backends/msmouse.c | 4 | ||||
-rw-r--r-- | hmp-commands.hx | 63 | ||||
-rw-r--r-- | include/char/char.h | 8 | ||||
-rw-r--r-- | include/qemu/sockets.h | 1 | ||||
-rw-r--r-- | include/ui/console.h | 4 | ||||
-rw-r--r-- | include/ui/qemu-spice.h | 7 | ||||
-rw-r--r-- | qapi-schema.json | 104 | ||||
-rw-r--r-- | qemu-char.c | 381 | ||||
-rw-r--r-- | spice-qemu-char.c | 88 | ||||
-rw-r--r-- | ui/console.c | 61 | ||||
-rw-r--r-- | ui/gtk.c | 2 | ||||
-rw-r--r-- | util/qemu-sockets.c | 25 |
13 files changed, 522 insertions, 230 deletions
diff --git a/backends/baum.c b/backends/baum.c index 9063aea2cf..d7d658c224 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -561,7 +561,7 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -static CharDriverState *chr_baum_init(QemuOpts *opts) +CharDriverState *chr_baum_init(void) { BaumDriverState *baum; CharDriverState *chr; @@ -627,7 +627,7 @@ fail_handle: static void register_types(void) { - register_char_driver("braille", chr_baum_init); + register_char_driver_qapi("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL); } type_init(register_types); diff --git a/backends/msmouse.c b/backends/msmouse.c index 407ec87784..61052fe783 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -63,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) +CharDriverState *qemu_chr_open_msmouse(void) { CharDriverState *chr; @@ -78,7 +78,7 @@ static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) static void register_types(void) { - register_char_driver("msmouse", qemu_chr_open_msmouse); + register_char_driver_qapi("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL); } type_init(register_types); diff --git a/hmp-commands.hx b/hmp-commands.hx index 4bda3fea0e..df44906ef9 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1522,38 +1522,37 @@ passed since 1970, i.e. unix epoch. @end table ETEXI -HXCOMM Disabled for now, because it isn't built on top of QMP's chardev-add -HXCOMM { -HXCOMM .name = "chardev-add", -HXCOMM .args_type = "args:s", -HXCOMM .params = "args", -HXCOMM .help = "add chardev", -HXCOMM .mhandler.cmd = hmp_chardev_add, -HXCOMM }, -HXCOMM -HXCOMM STEXI -HXCOMM @item chardev_add args -HXCOMM @findex chardev_add -HXCOMM -HXCOMM chardev_add accepts the same parameters as the -chardev command line switch. -HXCOMM -HXCOMM ETEXI -HXCOMM -HXCOMM { -HXCOMM .name = "chardev-remove", -HXCOMM .args_type = "id:s", -HXCOMM .params = "id", -HXCOMM .help = "remove chardev", -HXCOMM .mhandler.cmd = hmp_chardev_remove, -HXCOMM }, -HXCOMM -HXCOMM STEXI -HXCOMM @item chardev_remove id -HXCOMM @findex chardev_remove -HXCOMM -HXCOMM Removes the chardev @var{id}. -HXCOMM -HXCOMM ETEXI + { + .name = "chardev-add", + .args_type = "args:s", + .params = "args", + .help = "add chardev", + .mhandler.cmd = hmp_chardev_add, + }, + +STEXI +@item chardev_add args +@findex chardev_add + +chardev_add accepts the same parameters as the -chardev command line switch. + +ETEXI + + { + .name = "chardev-remove", + .args_type = "id:s", + .params = "id", + .help = "remove chardev", + .mhandler.cmd = hmp_chardev_remove, + }, + +STEXI +@item chardev_remove id +@findex chardev_remove + +Removes the chardev @var{id}. + +ETEXI { .name = "info", diff --git a/include/char/char.h b/include/char/char.h index 2e24270895..d6a03513bf 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -245,6 +245,8 @@ CharDriverState *qemu_chr_find(const char *name); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)); +void register_char_driver_qapi(const char *name, int kind, + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)); /* add an eventfd to the qemu devices that are polled */ CharDriverState *qemu_chr_open_eventfd(int eventfd); @@ -259,4 +261,10 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr); CharDriverState *qemu_char_get_next_serial(void); +/* msmouse */ +CharDriverState *qemu_chr_open_msmouse(void); + +/* baum.c */ +CharDriverState *chr_baum_init(void); + #endif diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index c5cee4bf2f..ae5c21cba3 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -71,6 +71,7 @@ SocketAddress *socket_parse(const char *str, Error **errp); int socket_connect(SocketAddress *addr, Error **errp, NonBlockingConnectHandler *callback, void *opaque); int socket_listen(SocketAddress *addr, Error **errp); +int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); /* Old, ipv4 only bits. Don't use for new code. */ int parse_host_port(struct sockaddr_in *saddr, const char *str); diff --git a/include/ui/console.h b/include/ui/console.h index c42bca6efe..a37cf65602 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -450,9 +450,9 @@ void qemu_console_resize(DisplayState *ds, int width, int height); void qemu_console_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h); -typedef CharDriverState *(VcHandler)(QemuOpts *); +typedef CharDriverState *(VcHandler)(ChardevVC *vc); -CharDriverState *vc_init(QemuOpts *opts); +CharDriverState *vc_init(ChardevVC *vc); void register_vc_handler(VcHandler *handler); /* sdl.c */ diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index 5a78fd764d..eba6d77d1d 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -44,10 +44,13 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); -CharDriverState *qemu_chr_open_spice(QemuOpts *opts); +CharDriverState *qemu_chr_open_spice_vmc(const char *type); #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); +CharDriverState *qemu_chr_open_spice_port(const char *name); void qemu_spice_register_ports(void); +#else +static inline CharDriverState *qemu_chr_open_spice_port(const char *name) +{ return NULL; } #endif #else /* CONFIG_SPICE */ diff --git a/qapi-schema.json b/qapi-schema.json index 4494e53693..fdaa9da133 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3153,7 +3153,7 @@ ## # @ChardevHostdev: # -# Configuration info for device chardevs. +# Configuration info for device and pipe chardevs. # # @device: The name of the special file for the device, # i.e. /dev/ttyS0 on Unix or COM1: on Windows @@ -3166,7 +3166,7 @@ ## # @ChardevSocket: # -# Configuration info for socket chardevs. +# Configuration info for (stream) socket chardevs. # # @addr: socket address to listen on (server=true) # or connect to (server=false) @@ -3185,6 +3185,93 @@ '*telnet' : 'bool' } } ## +# @ChardevDgram: +# +# Configuration info for datagram socket chardevs. +# +# @remote: remote address +# @local: #optional local address +# +# Since: 1.5 +## +{ 'type': 'ChardevDgram', 'data': { 'remote' : 'SocketAddress', + '*local' : 'SocketAddress' } } + +## +# @ChardevMux: +# +# Configuration info for mux chardevs. +# +# @chardev: name of the base chardev. +# +# Since: 1.5 +## +{ 'type': 'ChardevMux', 'data': { 'chardev' : 'str' } } + +## +# @ChardevStdio: +# +# Configuration info for stdio chardevs. +# +# @signal: #optional Allow signals (such as SIGINT triggered by ^C) +# be delivered to qemu. Default: true in -nographic mode, +# false otherwise. +# +# Since: 1.5 +## +{ 'type': 'ChardevStdio', 'data': { '*signal' : 'bool' } } + +## +# @ChardevSpiceChannel: +# +# Configuration info for spice vm channel chardevs. +# +# @type: kind of channel (for example vdagent). +# +# Since: 1.5 +## +{ 'type': 'ChardevSpiceChannel', 'data': { 'type' : 'str' } } + +## +# @ChardevSpicePort: +# +# Configuration info for spice port chardevs. +# +# @fqdn: name of the channel (see docs/spice-port-fqdn.txt) +# +# Since: 1.5 +## +{ 'type': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' } } + +## +# @ChardevVC: +# +# Configuration info for virtual console chardevs. +# +# @width: console width, in pixels +# @height: console height, in pixels +# @cols: console width, in chars +# @rows: console height, in chars +# +# Since: 1.5 +## +{ 'type': 'ChardevVC', 'data': { '*width' : 'int', + '*height' : 'int', + '*cols' : 'int', + '*rows' : 'int' } } + +## +# @ChardevRingbuf: +# +# Configuration info for memory chardevs +# +# @size: #optional Ringbuffer size, must be power of two, default is 65536 +# +# Since: 1.5 +## +{ 'type': 'ChardevRingbuf', 'data': { '*size' : 'int' } } + +## # @ChardevBackend: # # Configuration info for the new chardev backend. @@ -3196,9 +3283,20 @@ { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', 'serial' : 'ChardevHostdev', 'parallel': 'ChardevHostdev', + 'pipe' : 'ChardevHostdev', 'socket' : 'ChardevSocket', + 'dgram' : 'ChardevDgram', 'pty' : 'ChardevDummy', - 'null' : 'ChardevDummy' } } + 'null' : 'ChardevDummy', + 'mux' : 'ChardevMux', + 'msmouse': 'ChardevDummy', + 'braille': 'ChardevDummy', + 'stdio' : 'ChardevStdio', + 'console': 'ChardevDummy', + 'spicevmc' : 'ChardevSpiceChannel', + 'spiceport' : 'ChardevSpicePort', + 'vc' : 'ChardevVC', + 'memory' : 'ChardevRingbuf' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 83787c74c4..e6337971a5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -217,7 +217,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -static CharDriverState *qemu_chr_open_null(QemuOpts *opts) +static CharDriverState *qemu_chr_open_null(void) { CharDriverState *chr; @@ -841,23 +841,11 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) -{ - int fd_out; - - TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"), - O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); - if (fd_out < 0) { - return NULL; - } - return qemu_chr_open_fd(-1, fd_out); -} - -static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) { int fd_in, fd_out; char filename_in[256], filename_out[256]; - const char *filename = qemu_opt_get(opts, "path"); + const char *filename = opts->device; if (filename == NULL) { fprintf(stderr, "chardev: pipe: no filename given\n"); @@ -920,7 +908,7 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr) fd_chr_close(chr); } -static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) +static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) { CharDriverState *chr; @@ -936,8 +924,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; - stdio_allow_signal = qemu_opt_get_bool(opts, "signal", - display_type != DT_NOGRAPHIC); + stdio_allow_signal = display_type != DT_NOGRAPHIC; + if (opts->has_signal) { + stdio_allow_signal = opts->signal; + } qemu_chr_fe_set_echo(chr, false); return chr; @@ -1167,13 +1157,13 @@ static void pty_chr_close(struct CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pty(const char *id, + ChardevReturn *ret) { CharDriverState *chr; PtyCharDriver *s; struct termios tty; - const char *label; - int master_fd, slave_fd, len; + int master_fd, slave_fd; #if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; #define q_ptsname(x) pty_name @@ -1194,17 +1184,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr = g_malloc0(sizeof(CharDriverState)); - len = strlen(q_ptsname(master_fd)) + 5; - chr->filename = g_malloc(len); - snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd)); - qemu_opt_set(opts, "path", q_ptsname(master_fd)); + chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd)); + ret->pty = g_strdup(q_ptsname(master_fd)); + ret->has_pty = true; - label = qemu_opts_id(opts); - fprintf(stderr, "char device redirected to %s%s%s%s\n", - q_ptsname(master_fd), - label ? " (label " : "", - label ? label : "", - label ? ")" : ""); + fprintf(stderr, "char device redirected to %s (label %s)\n", + q_ptsname(master_fd), id); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; @@ -1429,18 +1414,6 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd) chr->chr_close = qemu_chr_close_tty; return chr; } - -static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) -{ - const char *filename = qemu_opt_get(opts, "path"); - int fd; - - TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); - if (fd < 0) { - return NULL; - } - return qemu_chr_open_tty_fd(fd); -} #endif /* __linux__ || __sun__ */ #if defined(__linux__) @@ -1865,11 +1838,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) return chr; } -static CharDriverState *qemu_chr_open_win(QemuOpts *opts) -{ - return qemu_chr_open_win_path(qemu_opt_get(opts, "path")); -} - static int win_chr_pipe_poll(void *opaque) { CharDriverState *chr = opaque; @@ -1949,9 +1917,9 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) } -static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) { - const char *filename = qemu_opt_get(opts, "path"); + const char *filename = opts->device; CharDriverState *chr; WinCharState *s; @@ -1984,25 +1952,11 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) return chr; } -static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts) +static CharDriverState *qemu_chr_open_win_con(void) { return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } -static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) -{ - const char *file_out = qemu_opt_get(opts, "path"); - HANDLE fd_out; - - fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd_out == INVALID_HANDLE_VALUE) { - return NULL; - } - - return qemu_chr_open_win_file(fd_out); -} - static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); @@ -2140,7 +2094,7 @@ static void win_stdio_close(CharDriverState *chr) g_free(chr); } -static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) +static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) { CharDriverState *chr; WinStdioCharState *stdio; @@ -2307,21 +2261,14 @@ static void udp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_udp_fd(int fd) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; - Error *local_err = NULL; - int fd = -1; chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(NetCharDriver)); - fd = inet_dgram_opts(opts, &local_err); - if (fd < 0) { - goto return_err; - } - s->fd = fd; s->chan = io_channel_from_socket(s->fd); s->bufcnt = 0; @@ -2331,18 +2278,18 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) chr->chr_update_read_handler = udp_chr_update_read_handler; chr->chr_close = udp_chr_close; return chr; +} -return_err: - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - } - g_free(chr); - g_free(s); - if (fd >= 0) { - closesocket(fd); +static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) +{ + Error *local_err = NULL; + int fd = -1; + + fd = inet_dgram_opts(opts, &local_err); + if (fd < 0) { + return NULL; } - return NULL; + return qemu_chr_open_udp_fd(fd); } /***********************************************************/ @@ -2709,7 +2656,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, s->do_nodelay = do_nodelay; getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); - snprintf(chr->filename, 256, "%s:%s:%s%s%s%s", + snprintf(chr->filename, 256, "%s:%s%s%s:%s%s", is_telnet ? "telnet" : "tcp", left, host, right, serv, is_listen ? ",server" : ""); @@ -2930,7 +2877,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) +static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, + Error **errp) { CharDriverState *chr; RingBufCharDriver *d; @@ -2938,14 +2886,11 @@ static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) chr = g_malloc0(sizeof(CharDriverState)); d = g_malloc(sizeof(*d)); - d->size = qemu_opt_get_size(opts, "size", 0); - if (d->size == 0) { - d->size = 65536; - } + d->size = opts->has_size ? opts->size : 65536; /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - error_report("size of ringbuf device must be power of two"); + error_setg(errp, "size of ringbuf chardev must be power of two"); goto fail; } @@ -3186,25 +3131,88 @@ fail: return NULL; } -#ifdef HAVE_CHARDEV_PARPORT +static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *path = qemu_opt_get(opts, "path"); -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) + if (path == NULL) { + error_setg(errp, "chardev: file: no filename given"); + return; + } + backend->file = g_new0(ChardevFile, 1); + backend->file->out = g_strdup(path); +} + +static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, + Error **errp) { - const char *filename = qemu_opt_get(opts, "path"); - int fd; + backend->stdio = g_new0(ChardevStdio, 1); + backend->stdio->has_signal = true; + backend->stdio->signal = + qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); +} - fd = qemu_open(filename, O_RDWR); - if (fd < 0) { - return NULL; +static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: serial/tty: no device path given"); + return; } - return qemu_chr_open_pp_fd(fd); + backend->serial = g_new0(ChardevHostdev, 1); + backend->serial->device = g_strdup(device); } -#endif +static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: parallel: no device path given"); + return; + } + backend->parallel = g_new0(ChardevHostdev, 1); + backend->parallel->device = g_strdup(device); +} + +static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: pipe: no device path given"); + return; + } + backend->pipe = g_new0(ChardevHostdev, 1); + backend->pipe->device = g_strdup(device); +} + +static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + int val; + + backend->memory = g_new0(ChardevRingbuf, 1); + + val = qemu_opt_get_number(opts, "size", 0); + if (val != 0) { + backend->memory->has_size = true; + backend->memory->size = val; + } +} typedef struct CharDriver { const char *name; + /* old, pre qapi */ CharDriverState *(*open)(QemuOpts *opts); + /* new, qapi-based */ + int kind; + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp); } CharDriver; static GSList *backends; @@ -3220,6 +3228,19 @@ void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *) backends = g_slist_append(backends, s); } +void register_char_driver_qapi(const char *name, int kind, + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)) +{ + CharDriver *s; + + s = g_malloc0(sizeof(*s)); + s->name = g_strdup(name); + s->kind = kind; + s->parse = parse; + + backends = g_slist_append(backends, s); +} + CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s), Error **errp) @@ -3251,6 +3272,51 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, return NULL; } + if (!cd->open) { + /* using new, qapi init */ + ChardevBackend *backend = g_new0(ChardevBackend, 1); + ChardevReturn *ret = NULL; + const char *id = qemu_opts_id(opts); + const char *bid = NULL; + + if (qemu_opt_get_bool(opts, "mux", 0)) { + bid = g_strdup_printf("%s-base", id); + } + + chr = NULL; + backend->kind = cd->kind; + if (cd->parse) { + cd->parse(opts, backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + } + ret = qmp_chardev_add(bid ? bid : id, backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + + if (bid) { + qapi_free_ChardevBackend(backend); + qapi_free_ChardevReturn(ret); + backend = g_new0(ChardevBackend, 1); + backend->mux = g_new0(ChardevMux, 1); + backend->kind = CHARDEV_BACKEND_KIND_MUX; + backend->mux->chardev = g_strdup(bid); + ret = qmp_chardev_add(id, backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + } + + chr = qemu_chr_find(id); + + qapi_out: + qapi_free_ChardevBackend(backend); + qapi_free_ChardevReturn(ret); + return chr; + } + chr = cd->open(opts); if (!chr) { error_setg(errp, "chardev: opening backend \"%s\" failed", @@ -3606,11 +3672,23 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, is_telnet, is_waitconnect, errp); } +static CharDriverState *qmp_chardev_open_dgram(ChardevDgram *dgram, + Error **errp) +{ + int fd; + + fd = socket_dgram(dgram->remote, dgram->local, errp); + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_udp_fd(fd); +} + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { ChardevReturn *ret = g_new0(ChardevReturn, 1); - CharDriverState *chr = NULL; + CharDriverState *base, *chr = NULL; chr = qemu_chr_find(id); if (chr) { @@ -3629,24 +3707,61 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_PARALLEL: chr = qmp_chardev_open_parallel(backend->parallel, errp); break; + case CHARDEV_BACKEND_KIND_PIPE: + chr = qemu_chr_open_pipe(backend->pipe); + break; case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; + case CHARDEV_BACKEND_KIND_DGRAM: + chr = qmp_chardev_open_dgram(backend->dgram, errp); + break; #ifdef HAVE_CHARDEV_TTY case CHARDEV_BACKEND_KIND_PTY: - { - /* qemu_chr_open_pty sets "path" in opts */ - QemuOpts *opts; - opts = qemu_opts_create_nofail(qemu_find_opts("chardev")); - chr = qemu_chr_open_pty(opts); - ret->pty = g_strdup(qemu_opt_get(opts, "path")); - ret->has_pty = true; - qemu_opts_del(opts); + chr = qemu_chr_open_pty(id, ret); break; - } #endif case CHARDEV_BACKEND_KIND_NULL: - chr = qemu_chr_open_null(NULL); + chr = qemu_chr_open_null(); + break; + case CHARDEV_BACKEND_KIND_MUX: + base = qemu_chr_find(backend->mux->chardev); + if (base == NULL) { + error_setg(errp, "mux: base chardev %s not found", + backend->mux->chardev); + break; + } + chr = qemu_chr_open_mux(base); + break; + case CHARDEV_BACKEND_KIND_MSMOUSE: + chr = qemu_chr_open_msmouse(); + break; +#ifdef CONFIG_BRLAPI + case CHARDEV_BACKEND_KIND_BRAILLE: + chr = chr_baum_init(); + break; +#endif + case CHARDEV_BACKEND_KIND_STDIO: + chr = qemu_chr_open_stdio(backend->stdio); + break; +#ifdef _WIN32 + case CHARDEV_BACKEND_KIND_CONSOLE: + chr = qemu_chr_open_win_con(); + break; +#endif +#ifdef CONFIG_SPICE + case CHARDEV_BACKEND_KIND_SPICEVMC: + chr = qemu_chr_open_spice_vmc(backend->spicevmc->type); + break; + case CHARDEV_BACKEND_KIND_SPICEPORT: + chr = qemu_chr_open_spice_port(backend->spiceport->fqdn); + break; +#endif + case CHARDEV_BACKEND_KIND_VC: + chr = vc_init(backend->vc); + break; + case CHARDEV_BACKEND_KIND_MEMORY: + chr = qemu_chr_open_ringbuf(backend->memory, errp); break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); @@ -3658,7 +3773,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } if (chr) { chr->label = g_strdup(id); - chr->avail_connections = 1; + chr->avail_connections = + (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; QTAILQ_INSERT_TAIL(&chardevs, chr, next); return ret; } else { @@ -3686,30 +3802,27 @@ void qmp_chardev_remove(const char *id, Error **errp) static void register_types(void) { - register_char_driver("null", qemu_chr_open_null); + register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver("memory", qemu_chr_open_ringbuf); -#ifdef _WIN32 - register_char_driver("file", qemu_chr_open_win_file_out); - register_char_driver("pipe", qemu_chr_open_win_pipe); - register_char_driver("console", qemu_chr_open_win_con); - register_char_driver("serial", qemu_chr_open_win); - register_char_driver("stdio", qemu_chr_open_win_stdio); -#else - register_char_driver("file", qemu_chr_open_file_out); - register_char_driver("pipe", qemu_chr_open_pipe); - register_char_driver("stdio", qemu_chr_open_stdio); -#endif -#ifdef HAVE_CHARDEV_TTY - register_char_driver("tty", qemu_chr_open_tty); - register_char_driver("serial", qemu_chr_open_tty); - register_char_driver("pty", qemu_chr_open_pty); -#endif -#ifdef HAVE_CHARDEV_PARPORT - register_char_driver("parallel", qemu_chr_open_pp); - register_char_driver("parport", qemu_chr_open_pp); -#endif + register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, + qemu_chr_parse_ringbuf); + register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, + qemu_chr_parse_file_out); + register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, + qemu_chr_parse_stdio); + register_char_driver_qapi("serial", CHARDEV_BACKEND_KIND_SERIAL, + qemu_chr_parse_serial); + register_char_driver_qapi("tty", CHARDEV_BACKEND_KIND_SERIAL, + qemu_chr_parse_serial); + register_char_driver_qapi("parallel", CHARDEV_BACKEND_KIND_PARALLEL, + qemu_chr_parse_parallel); + register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL, + qemu_chr_parse_parallel); + register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL); + register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL); + register_char_driver_qapi("pipe", CHARDEV_BACKEND_KIND_PIPE, + qemu_chr_parse_pipe); } type_init(register_types); diff --git a/spice-qemu-char.c b/spice-qemu-char.c index aea3d24e7d..8a9236d0a8 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -8,14 +8,6 @@ #include "qemu/osdep.h" -#define dprintf(_scd, _level, _fmt, ...) \ - do { \ - static unsigned __dprintf_counter = 0; \ - if (_scd->debug >= _level) { \ - fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\ - } \ - } while (0) - typedef struct SpiceCharDriver { CharDriverState* chr; SpiceCharDeviceInstance sin; @@ -24,7 +16,6 @@ typedef struct SpiceCharDriver { uint8_t *buffer; uint8_t *datapos; ssize_t bufsize, datalen; - uint32_t debug; QLIST_ENTRY(SpiceCharDriver) next; } SpiceCharDriver; @@ -49,7 +40,6 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) p += last_out; } - dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out); trace_spice_vmc_write(out, len + out); return out; } @@ -59,7 +49,6 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); int bytes = MIN(len, scd->datalen); - dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); if (bytes > 0) { memcpy(buf, scd->datapos, bytes); scd->datapos += bytes; @@ -84,11 +73,9 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) chr_event = CHR_EVENT_BREAK; break; default: - dprintf(scd, 2, "%s: unknown %d\n", __func__, event); return; } - dprintf(scd, 2, "%s: %d\n", __func__, event); trace_spice_vmc_event(chr_event); qemu_chr_be_event(scd->chr, chr_event); } @@ -141,7 +128,6 @@ static void vmc_register_interface(SpiceCharDriver *scd) if (scd->active) { return; } - dprintf(scd, 1, "%s\n", __func__); scd->sin.base.sif = &vmc_interface.base; qemu_spice_add_interface(&scd->sin.base); scd->active = true; @@ -153,7 +139,6 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) if (!scd->active) { return; } - dprintf(scd, 1, "%s\n", __func__); spice_server_remove_interface(&scd->sin.base); scd->active = false; trace_spice_vmc_unregister_interface(scd); @@ -164,7 +149,6 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { SpiceCharDriver *s = chr->opaque; - dprintf(s, 2, "%s: %d\n", __func__, len); vmc_register_interface(s); assert(s->datalen == 0); if (s->bufsize < len) { @@ -182,9 +166,13 @@ static void spice_chr_close(struct CharDriverState *chr) { SpiceCharDriver *s = chr->opaque; - printf("%s\n", __func__); vmc_unregister_interface(s); QLIST_REMOVE(s, next); + + g_free((char *)s->sin.subtype); +#if SPICE_SERVER_VERSION >= 0x000c02 + g_free((char *)s->sin.portname); +#endif g_free(s); } @@ -217,18 +205,16 @@ static void print_allowed_subtypes(void) fprintf(stderr, "\n"); } -static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) +static CharDriverState *chr_open(const char *subtype) { CharDriverState *chr; SpiceCharDriver *s; - uint32_t debug = qemu_opt_get_number(opts, "debug", 0); chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(SpiceCharDriver)); s->chr = chr; - s->debug = debug; s->active = false; - s->sin.subtype = subtype; + s->sin.subtype = g_strdup(subtype); chr->opaque = s; chr->chr_write = spice_chr_write; chr->chr_close = spice_chr_close; @@ -240,35 +226,32 @@ static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) return chr; } -CharDriverState *qemu_chr_open_spice(QemuOpts *opts) +CharDriverState *qemu_chr_open_spice_vmc(const char *type) { CharDriverState *chr; - const char *name = qemu_opt_get(opts, "name"); const char **psubtype = spice_server_char_device_recognized_subtypes(); - const char *subtype = NULL; - if (name == NULL) { + if (type == NULL) { fprintf(stderr, "spice-qemu-char: missing name parameter\n"); print_allowed_subtypes(); return NULL; } - for(;*psubtype != NULL; ++psubtype) { - if (strcmp(name, *psubtype) == 0) { - subtype = *psubtype; + for (; *psubtype != NULL; ++psubtype) { + if (strcmp(type, *psubtype) == 0) { break; } } - if (subtype == NULL) { - fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name); + if (*psubtype == NULL) { + fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type); print_allowed_subtypes(); return NULL; } - chr = chr_open(opts, subtype); + chr = chr_open(type); #if SPICE_SERVER_VERSION < 0x000901 /* See comment in vmc_state() */ - if (strcmp(subtype, "vdagent") == 0) { + if (strcmp(type, "vdagent") == 0) { qemu_chr_generic_open(chr); } #endif @@ -277,20 +260,19 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) } #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) +CharDriverState *qemu_chr_open_spice_port(const char *name) { CharDriverState *chr; SpiceCharDriver *s; - const char *name = qemu_opt_get(opts, "name"); if (name == NULL) { fprintf(stderr, "spice-qemu-char: missing name parameter\n"); return NULL; } - chr = chr_open(opts, "port"); + chr = chr_open("port"); s = chr->opaque; - s->sin.portname = name; + s->sin.portname = g_strdup(name); return chr; } @@ -308,12 +290,38 @@ void qemu_spice_register_ports(void) } #endif +static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *name = qemu_opt_get(opts, "name"); + + if (name == NULL) { + error_setg(errp, "chardev: spice channel: no name given"); + return; + } + backend->spicevmc = g_new0(ChardevSpiceChannel, 1); + backend->spicevmc->type = g_strdup(name); +} + +static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *name = qemu_opt_get(opts, "name"); + + if (name == NULL) { + error_setg(errp, "chardev: spice port: no name given"); + return; + } + backend->spiceport = g_new0(ChardevSpicePort, 1); + backend->spiceport->fqdn = g_strdup(name); +} + static void register_types(void) { - register_char_driver("spicevmc", qemu_chr_open_spice); -#if SPICE_SERVER_VERSION >= 0x000c02 - register_char_driver("spiceport", qemu_chr_open_spice_port); -#endif + register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC, + qemu_chr_parse_spice_vmc); + register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT, + qemu_chr_parse_spice_port); } type_init(register_types); diff --git a/ui/console.c b/ui/console.c index 0f96177797..27e87f8879 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1537,22 +1537,26 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -static CharDriverState *text_console_init(QemuOpts *opts) +static CharDriverState *text_console_init(ChardevVC *vc) { CharDriverState *chr; QemuConsole *s; - unsigned width; - unsigned height; + unsigned width = 0; + unsigned height = 0; chr = g_malloc0(sizeof(CharDriverState)); - width = qemu_opt_get_number(opts, "width", 0); - if (width == 0) - width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; + if (vc->has_width) { + width = vc->width; + } else if (vc->has_cols) { + width = vc->cols * FONT_WIDTH; + } - height = qemu_opt_get_number(opts, "height", 0); - if (height == 0) - height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT; + if (vc->has_height) { + height = vc->height; + } else if (vc->has_rows) { + height = vc->rows * FONT_HEIGHT; + } if (width == 0 || height == 0) { s = new_console(NULL, TEXT_CONSOLE); @@ -1575,9 +1579,9 @@ static CharDriverState *text_console_init(QemuOpts *opts) static VcHandler *vc_handler = text_console_init; -CharDriverState *vc_init(QemuOpts *opts) +CharDriverState *vc_init(ChardevVC *vc) { - return vc_handler(opts); + return vc_handler(vc); } void register_vc_handler(VcHandler *handler) @@ -1740,9 +1744,42 @@ PixelFormat qemu_default_pixelformat(int bpp) return pf; } +static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + int val; + + backend->vc = g_new0(ChardevVC, 1); + + val = qemu_opt_get_number(opts, "width", 0); + if (val != 0) { + backend->vc->has_width = true; + backend->vc->width = val; + } + + val = qemu_opt_get_number(opts, "height", 0); + if (val != 0) { + backend->vc->has_height = true; + backend->vc->height = val; + } + + val = qemu_opt_get_number(opts, "cols", 0); + if (val != 0) { + backend->vc->has_cols = true; + backend->vc->cols = val; + } + + val = qemu_opt_get_number(opts, "rows", 0); + if (val != 0) { + backend->vc->has_rows = true; + backend->vc->rows = val; + } +} + static void register_types(void) { - register_char_driver("vc", vc_init); + register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC, + qemu_chr_parse_vc); } type_init(register_types); @@ -991,7 +991,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) static int nb_vcs; static CharDriverState *vcs[MAX_VCS]; -static CharDriverState *gd_vc_handler(QemuOpts *opts) +static CharDriverState *gd_vc_handler(ChardevVC *unused) { CharDriverState *chr; diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 3f122965ad..83e4e08e85 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -949,6 +949,31 @@ int socket_listen(SocketAddress *addr, Error **errp) return fd; } +int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) +{ + QemuOpts *opts; + int fd; + + opts = qemu_opts_create_nofail(&dummy_opts); + switch (remote->kind) { + case SOCKET_ADDRESS_KIND_INET: + qemu_opt_set(opts, "host", remote->inet->host); + qemu_opt_set(opts, "port", remote->inet->port); + if (local) { + qemu_opt_set(opts, "localaddr", local->inet->host); + qemu_opt_set(opts, "localport", local->inet->port); + } + fd = inet_dgram_opts(opts, errp); + break; + + default: + error_setg(errp, "socket type unsupported for datagram"); + return -1; + } + qemu_opts_del(opts); + return fd; +} + #ifdef _WIN32 static void socket_cleanup(void) { |