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>
This commit is contained in:
commit
139a4b63e3
@ -561,7 +561,7 @@ static void baum_close(struct CharDriverState *chr)
|
|||||||
g_free(baum);
|
g_free(baum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *chr_baum_init(QemuOpts *opts)
|
CharDriverState *chr_baum_init(void)
|
||||||
{
|
{
|
||||||
BaumDriverState *baum;
|
BaumDriverState *baum;
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
@ -627,7 +627,7 @@ fail_handle:
|
|||||||
|
|
||||||
static void register_types(void)
|
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);
|
type_init(register_types);
|
||||||
|
@ -63,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
|
|||||||
g_free (chr);
|
g_free (chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
|
CharDriverState *qemu_chr_open_msmouse(void)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
|
|||||||
|
|
||||||
static void register_types(void)
|
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);
|
type_init(register_types);
|
||||||
|
@ -1522,38 +1522,37 @@ passed since 1970, i.e. unix epoch.
|
|||||||
@end table
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
HXCOMM Disabled for now, because it isn't built on top of QMP's chardev-add
|
{
|
||||||
HXCOMM {
|
.name = "chardev-add",
|
||||||
HXCOMM .name = "chardev-add",
|
.args_type = "args:s",
|
||||||
HXCOMM .args_type = "args:s",
|
.params = "args",
|
||||||
HXCOMM .params = "args",
|
.help = "add chardev",
|
||||||
HXCOMM .help = "add chardev",
|
.mhandler.cmd = hmp_chardev_add,
|
||||||
HXCOMM .mhandler.cmd = hmp_chardev_add,
|
},
|
||||||
HXCOMM },
|
|
||||||
HXCOMM
|
STEXI
|
||||||
HXCOMM STEXI
|
@item chardev_add args
|
||||||
HXCOMM @item chardev_add args
|
@findex chardev_add
|
||||||
HXCOMM @findex chardev_add
|
|
||||||
HXCOMM
|
chardev_add accepts the same parameters as the -chardev command line switch.
|
||||||
HXCOMM chardev_add accepts the same parameters as the -chardev command line switch.
|
|
||||||
HXCOMM
|
ETEXI
|
||||||
HXCOMM ETEXI
|
|
||||||
HXCOMM
|
{
|
||||||
HXCOMM {
|
.name = "chardev-remove",
|
||||||
HXCOMM .name = "chardev-remove",
|
.args_type = "id:s",
|
||||||
HXCOMM .args_type = "id:s",
|
.params = "id",
|
||||||
HXCOMM .params = "id",
|
.help = "remove chardev",
|
||||||
HXCOMM .help = "remove chardev",
|
.mhandler.cmd = hmp_chardev_remove,
|
||||||
HXCOMM .mhandler.cmd = hmp_chardev_remove,
|
},
|
||||||
HXCOMM },
|
|
||||||
HXCOMM
|
STEXI
|
||||||
HXCOMM STEXI
|
@item chardev_remove id
|
||||||
HXCOMM @item chardev_remove id
|
@findex chardev_remove
|
||||||
HXCOMM @findex chardev_remove
|
|
||||||
HXCOMM
|
Removes the chardev @var{id}.
|
||||||
HXCOMM Removes the chardev @var{id}.
|
|
||||||
HXCOMM
|
ETEXI
|
||||||
HXCOMM ETEXI
|
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "info",
|
.name = "info",
|
||||||
|
@ -245,6 +245,8 @@ CharDriverState *qemu_chr_find(const char *name);
|
|||||||
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
|
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(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 */
|
/* add an eventfd to the qemu devices that are polled */
|
||||||
CharDriverState *qemu_chr_open_eventfd(int eventfd);
|
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);
|
CharDriverState *qemu_char_get_next_serial(void);
|
||||||
|
|
||||||
|
/* msmouse */
|
||||||
|
CharDriverState *qemu_chr_open_msmouse(void);
|
||||||
|
|
||||||
|
/* baum.c */
|
||||||
|
CharDriverState *chr_baum_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,6 +71,7 @@ SocketAddress *socket_parse(const char *str, Error **errp);
|
|||||||
int socket_connect(SocketAddress *addr, Error **errp,
|
int socket_connect(SocketAddress *addr, Error **errp,
|
||||||
NonBlockingConnectHandler *callback, void *opaque);
|
NonBlockingConnectHandler *callback, void *opaque);
|
||||||
int socket_listen(SocketAddress *addr, Error **errp);
|
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. */
|
/* Old, ipv4 only bits. Don't use for new code. */
|
||||||
int parse_host_port(struct sockaddr_in *saddr, const char *str);
|
int parse_host_port(struct sockaddr_in *saddr, const char *str);
|
||||||
|
@ -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,
|
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
|
||||||
int dst_x, int dst_y, int w, int h);
|
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);
|
void register_vc_handler(VcHandler *handler);
|
||||||
|
|
||||||
/* sdl.c */
|
/* sdl.c */
|
||||||
|
@ -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_print(Monitor *mon, const QObject *data);
|
||||||
void do_info_spice(Monitor *mon, QObject **ret_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
|
#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);
|
void qemu_spice_register_ports(void);
|
||||||
|
#else
|
||||||
|
static inline CharDriverState *qemu_chr_open_spice_port(const char *name)
|
||||||
|
{ return NULL; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* CONFIG_SPICE */
|
#else /* CONFIG_SPICE */
|
||||||
|
104
qapi-schema.json
104
qapi-schema.json
@ -3153,7 +3153,7 @@
|
|||||||
##
|
##
|
||||||
# @ChardevHostdev:
|
# @ChardevHostdev:
|
||||||
#
|
#
|
||||||
# Configuration info for device chardevs.
|
# Configuration info for device and pipe chardevs.
|
||||||
#
|
#
|
||||||
# @device: The name of the special file for the device,
|
# @device: The name of the special file for the device,
|
||||||
# i.e. /dev/ttyS0 on Unix or COM1: on Windows
|
# i.e. /dev/ttyS0 on Unix or COM1: on Windows
|
||||||
@ -3166,7 +3166,7 @@
|
|||||||
##
|
##
|
||||||
# @ChardevSocket:
|
# @ChardevSocket:
|
||||||
#
|
#
|
||||||
# Configuration info for socket chardevs.
|
# Configuration info for (stream) socket chardevs.
|
||||||
#
|
#
|
||||||
# @addr: socket address to listen on (server=true)
|
# @addr: socket address to listen on (server=true)
|
||||||
# or connect to (server=false)
|
# or connect to (server=false)
|
||||||
@ -3184,6 +3184,93 @@
|
|||||||
'*nodelay' : 'bool',
|
'*nodelay' : 'bool',
|
||||||
'*telnet' : 'bool' } }
|
'*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:
|
# @ChardevBackend:
|
||||||
#
|
#
|
||||||
@ -3196,9 +3283,20 @@
|
|||||||
{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
|
{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
|
||||||
'serial' : 'ChardevHostdev',
|
'serial' : 'ChardevHostdev',
|
||||||
'parallel': 'ChardevHostdev',
|
'parallel': 'ChardevHostdev',
|
||||||
|
'pipe' : 'ChardevHostdev',
|
||||||
'socket' : 'ChardevSocket',
|
'socket' : 'ChardevSocket',
|
||||||
|
'dgram' : 'ChardevDgram',
|
||||||
'pty' : 'ChardevDummy',
|
'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:
|
# @ChardevReturn:
|
||||||
|
383
qemu-char.c
383
qemu-char.c
@ -217,7 +217,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
|
static CharDriverState *qemu_chr_open_null(void)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
@ -841,23 +841,11 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
|
|||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
|
static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *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)
|
|
||||||
{
|
{
|
||||||
int fd_in, fd_out;
|
int fd_in, fd_out;
|
||||||
char filename_in[256], filename_out[256];
|
char filename_in[256], filename_out[256];
|
||||||
const char *filename = qemu_opt_get(opts, "path");
|
const char *filename = opts->device;
|
||||||
|
|
||||||
if (filename == NULL) {
|
if (filename == NULL) {
|
||||||
fprintf(stderr, "chardev: pipe: no filename given\n");
|
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);
|
fd_chr_close(chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
|
static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
@ -936,8 +924,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
|
|||||||
chr = qemu_chr_open_fd(0, 1);
|
chr = qemu_chr_open_fd(0, 1);
|
||||||
chr->chr_close = qemu_chr_close_stdio;
|
chr->chr_close = qemu_chr_close_stdio;
|
||||||
chr->chr_set_echo = qemu_chr_set_echo_stdio;
|
chr->chr_set_echo = qemu_chr_set_echo_stdio;
|
||||||
stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
|
stdio_allow_signal = display_type != DT_NOGRAPHIC;
|
||||||
display_type != DT_NOGRAPHIC);
|
if (opts->has_signal) {
|
||||||
|
stdio_allow_signal = opts->signal;
|
||||||
|
}
|
||||||
qemu_chr_fe_set_echo(chr, false);
|
qemu_chr_fe_set_echo(chr, false);
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
@ -1167,13 +1157,13 @@ static void pty_chr_close(struct CharDriverState *chr)
|
|||||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
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;
|
CharDriverState *chr;
|
||||||
PtyCharDriver *s;
|
PtyCharDriver *s;
|
||||||
struct termios tty;
|
struct termios tty;
|
||||||
const char *label;
|
int master_fd, slave_fd;
|
||||||
int master_fd, slave_fd, len;
|
|
||||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||||
char pty_name[PATH_MAX];
|
char pty_name[PATH_MAX];
|
||||||
#define q_ptsname(x) pty_name
|
#define q_ptsname(x) pty_name
|
||||||
@ -1194,17 +1184,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
|
|||||||
|
|
||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
|
|
||||||
len = strlen(q_ptsname(master_fd)) + 5;
|
chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd));
|
||||||
chr->filename = g_malloc(len);
|
ret->pty = g_strdup(q_ptsname(master_fd));
|
||||||
snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd));
|
ret->has_pty = true;
|
||||||
qemu_opt_set(opts, "path", q_ptsname(master_fd));
|
|
||||||
|
|
||||||
label = qemu_opts_id(opts);
|
fprintf(stderr, "char device redirected to %s (label %s)\n",
|
||||||
fprintf(stderr, "char device redirected to %s%s%s%s\n",
|
q_ptsname(master_fd), id);
|
||||||
q_ptsname(master_fd),
|
|
||||||
label ? " (label " : "",
|
|
||||||
label ? label : "",
|
|
||||||
label ? ")" : "");
|
|
||||||
|
|
||||||
s = g_malloc0(sizeof(PtyCharDriver));
|
s = g_malloc0(sizeof(PtyCharDriver));
|
||||||
chr->opaque = s;
|
chr->opaque = s;
|
||||||
@ -1429,18 +1414,6 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd)
|
|||||||
chr->chr_close = qemu_chr_close_tty;
|
chr->chr_close = qemu_chr_close_tty;
|
||||||
return chr;
|
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__ */
|
#endif /* __linux__ || __sun__ */
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
@ -1865,11 +1838,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename)
|
|||||||
return chr;
|
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)
|
static int win_chr_pipe_poll(void *opaque)
|
||||||
{
|
{
|
||||||
CharDriverState *chr = 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;
|
CharDriverState *chr;
|
||||||
WinCharState *s;
|
WinCharState *s;
|
||||||
|
|
||||||
@ -1984,25 +1952,11 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
|
|||||||
return chr;
|
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));
|
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)
|
static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
@ -2140,7 +2094,7 @@ static void win_stdio_close(CharDriverState *chr)
|
|||||||
g_free(chr);
|
g_free(chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts)
|
static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
WinStdioCharState *stdio;
|
WinStdioCharState *stdio;
|
||||||
@ -2307,21 +2261,14 @@ static void udp_chr_close(CharDriverState *chr)
|
|||||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
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;
|
CharDriverState *chr = NULL;
|
||||||
NetCharDriver *s = NULL;
|
NetCharDriver *s = NULL;
|
||||||
Error *local_err = NULL;
|
|
||||||
int fd = -1;
|
|
||||||
|
|
||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
s = g_malloc0(sizeof(NetCharDriver));
|
s = g_malloc0(sizeof(NetCharDriver));
|
||||||
|
|
||||||
fd = inet_dgram_opts(opts, &local_err);
|
|
||||||
if (fd < 0) {
|
|
||||||
goto return_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->chan = io_channel_from_socket(s->fd);
|
s->chan = io_channel_from_socket(s->fd);
|
||||||
s->bufcnt = 0;
|
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_update_read_handler = udp_chr_update_read_handler;
|
||||||
chr->chr_close = udp_chr_close;
|
chr->chr_close = udp_chr_close;
|
||||||
return chr;
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
return_err:
|
static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
|
||||||
if (local_err) {
|
{
|
||||||
qerror_report_err(local_err);
|
Error *local_err = NULL;
|
||||||
error_free(local_err);
|
int fd = -1;
|
||||||
|
|
||||||
|
fd = inet_dgram_opts(opts, &local_err);
|
||||||
|
if (fd < 0) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
g_free(chr);
|
return qemu_chr_open_udp_fd(fd);
|
||||||
g_free(s);
|
|
||||||
if (fd >= 0) {
|
|
||||||
closesocket(fd);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
@ -2709,7 +2656,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
|
|||||||
s->do_nodelay = do_nodelay;
|
s->do_nodelay = do_nodelay;
|
||||||
getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
|
getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
|
||||||
serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
|
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",
|
is_telnet ? "telnet" : "tcp",
|
||||||
left, host, right, serv,
|
left, host, right, serv,
|
||||||
is_listen ? ",server" : "");
|
is_listen ? ",server" : "");
|
||||||
@ -2930,7 +2877,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr)
|
|||||||
chr->opaque = NULL;
|
chr->opaque = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
|
static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
RingBufCharDriver *d;
|
RingBufCharDriver *d;
|
||||||
@ -2938,14 +2886,11 @@ static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
|
|||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
d = g_malloc(sizeof(*d));
|
d = g_malloc(sizeof(*d));
|
||||||
|
|
||||||
d->size = qemu_opt_get_size(opts, "size", 0);
|
d->size = opts->has_size ? opts->size : 65536;
|
||||||
if (d->size == 0) {
|
|
||||||
d->size = 65536;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The size must be power of 2 */
|
/* The size must be power of 2 */
|
||||||
if (d->size & (d->size - 1)) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3186,25 +3131,88 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CHARDEV_PARPORT
|
static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
|
|
||||||
{
|
{
|
||||||
const char *filename = qemu_opt_get(opts, "path");
|
const char *path = qemu_opt_get(opts, "path");
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = qemu_open(filename, O_RDWR);
|
if (path == NULL) {
|
||||||
if (fd < 0) {
|
error_setg(errp, "chardev: file: no filename given");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
return qemu_chr_open_pp_fd(fd);
|
backend->file = g_new0(ChardevFile, 1);
|
||||||
|
backend->file->out = g_strdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
backend->stdio = g_new0(ChardevStdio, 1);
|
||||||
|
backend->stdio->has_signal = true;
|
||||||
|
backend->stdio->signal =
|
||||||
|
qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
backend->serial = g_new0(ChardevHostdev, 1);
|
||||||
|
backend->serial->device = g_strdup(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
typedef struct CharDriver {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
/* old, pre qapi */
|
||||||
CharDriverState *(*open)(QemuOpts *opts);
|
CharDriverState *(*open)(QemuOpts *opts);
|
||||||
|
/* new, qapi-based */
|
||||||
|
int kind;
|
||||||
|
void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
|
||||||
} CharDriver;
|
} CharDriver;
|
||||||
|
|
||||||
static GSList *backends;
|
static GSList *backends;
|
||||||
@ -3220,6 +3228,19 @@ void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)
|
|||||||
backends = g_slist_append(backends, s);
|
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,
|
CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||||
void (*init)(struct CharDriverState *s),
|
void (*init)(struct CharDriverState *s),
|
||||||
Error **errp)
|
Error **errp)
|
||||||
@ -3251,6 +3272,51 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
|
|||||||
return NULL;
|
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);
|
chr = cd->open(opts);
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
error_setg(errp, "chardev: opening backend \"%s\" failed",
|
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);
|
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,
|
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevReturn *ret = g_new0(ChardevReturn, 1);
|
ChardevReturn *ret = g_new0(ChardevReturn, 1);
|
||||||
CharDriverState *chr = NULL;
|
CharDriverState *base, *chr = NULL;
|
||||||
|
|
||||||
chr = qemu_chr_find(id);
|
chr = qemu_chr_find(id);
|
||||||
if (chr) {
|
if (chr) {
|
||||||
@ -3629,24 +3707,61 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
|||||||
case CHARDEV_BACKEND_KIND_PARALLEL:
|
case CHARDEV_BACKEND_KIND_PARALLEL:
|
||||||
chr = qmp_chardev_open_parallel(backend->parallel, errp);
|
chr = qmp_chardev_open_parallel(backend->parallel, errp);
|
||||||
break;
|
break;
|
||||||
|
case CHARDEV_BACKEND_KIND_PIPE:
|
||||||
|
chr = qemu_chr_open_pipe(backend->pipe);
|
||||||
|
break;
|
||||||
case CHARDEV_BACKEND_KIND_SOCKET:
|
case CHARDEV_BACKEND_KIND_SOCKET:
|
||||||
chr = qmp_chardev_open_socket(backend->socket, errp);
|
chr = qmp_chardev_open_socket(backend->socket, errp);
|
||||||
break;
|
break;
|
||||||
|
case CHARDEV_BACKEND_KIND_DGRAM:
|
||||||
|
chr = qmp_chardev_open_dgram(backend->dgram, errp);
|
||||||
|
break;
|
||||||
#ifdef HAVE_CHARDEV_TTY
|
#ifdef HAVE_CHARDEV_TTY
|
||||||
case CHARDEV_BACKEND_KIND_PTY:
|
case CHARDEV_BACKEND_KIND_PTY:
|
||||||
{
|
chr = qemu_chr_open_pty(id, ret);
|
||||||
/* 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);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
case CHARDEV_BACKEND_KIND_NULL:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "unknown chardev backend (%d)", backend->kind);
|
error_setg(errp, "unknown chardev backend (%d)", backend->kind);
|
||||||
@ -3658,7 +3773,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
|||||||
}
|
}
|
||||||
if (chr) {
|
if (chr) {
|
||||||
chr->label = g_strdup(id);
|
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);
|
QTAILQ_INSERT_TAIL(&chardevs, chr, next);
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
@ -3686,30 +3802,27 @@ void qmp_chardev_remove(const char *id, Error **errp)
|
|||||||
|
|
||||||
static void register_types(void)
|
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("socket", qemu_chr_open_socket);
|
||||||
register_char_driver("udp", qemu_chr_open_udp);
|
register_char_driver("udp", qemu_chr_open_udp);
|
||||||
register_char_driver("memory", qemu_chr_open_ringbuf);
|
register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY,
|
||||||
#ifdef _WIN32
|
qemu_chr_parse_ringbuf);
|
||||||
register_char_driver("file", qemu_chr_open_win_file_out);
|
register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE,
|
||||||
register_char_driver("pipe", qemu_chr_open_win_pipe);
|
qemu_chr_parse_file_out);
|
||||||
register_char_driver("console", qemu_chr_open_win_con);
|
register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO,
|
||||||
register_char_driver("serial", qemu_chr_open_win);
|
qemu_chr_parse_stdio);
|
||||||
register_char_driver("stdio", qemu_chr_open_win_stdio);
|
register_char_driver_qapi("serial", CHARDEV_BACKEND_KIND_SERIAL,
|
||||||
#else
|
qemu_chr_parse_serial);
|
||||||
register_char_driver("file", qemu_chr_open_file_out);
|
register_char_driver_qapi("tty", CHARDEV_BACKEND_KIND_SERIAL,
|
||||||
register_char_driver("pipe", qemu_chr_open_pipe);
|
qemu_chr_parse_serial);
|
||||||
register_char_driver("stdio", qemu_chr_open_stdio);
|
register_char_driver_qapi("parallel", CHARDEV_BACKEND_KIND_PARALLEL,
|
||||||
#endif
|
qemu_chr_parse_parallel);
|
||||||
#ifdef HAVE_CHARDEV_TTY
|
register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL,
|
||||||
register_char_driver("tty", qemu_chr_open_tty);
|
qemu_chr_parse_parallel);
|
||||||
register_char_driver("serial", qemu_chr_open_tty);
|
register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL);
|
||||||
register_char_driver("pty", qemu_chr_open_pty);
|
register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL);
|
||||||
#endif
|
register_char_driver_qapi("pipe", CHARDEV_BACKEND_KIND_PIPE,
|
||||||
#ifdef HAVE_CHARDEV_PARPORT
|
qemu_chr_parse_pipe);
|
||||||
register_char_driver("parallel", qemu_chr_open_pp);
|
|
||||||
register_char_driver("parport", qemu_chr_open_pp);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
@ -8,14 +8,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#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 {
|
typedef struct SpiceCharDriver {
|
||||||
CharDriverState* chr;
|
CharDriverState* chr;
|
||||||
SpiceCharDeviceInstance sin;
|
SpiceCharDeviceInstance sin;
|
||||||
@ -24,7 +16,6 @@ typedef struct SpiceCharDriver {
|
|||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
uint8_t *datapos;
|
uint8_t *datapos;
|
||||||
ssize_t bufsize, datalen;
|
ssize_t bufsize, datalen;
|
||||||
uint32_t debug;
|
|
||||||
QLIST_ENTRY(SpiceCharDriver) next;
|
QLIST_ENTRY(SpiceCharDriver) next;
|
||||||
} SpiceCharDriver;
|
} SpiceCharDriver;
|
||||||
|
|
||||||
@ -49,7 +40,6 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
|||||||
p += last_out;
|
p += last_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
|
|
||||||
trace_spice_vmc_write(out, len + out);
|
trace_spice_vmc_write(out, len + out);
|
||||||
return 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);
|
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
||||||
int bytes = MIN(len, scd->datalen);
|
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) {
|
if (bytes > 0) {
|
||||||
memcpy(buf, scd->datapos, bytes);
|
memcpy(buf, scd->datapos, bytes);
|
||||||
scd->datapos += bytes;
|
scd->datapos += bytes;
|
||||||
@ -84,11 +73,9 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
|||||||
chr_event = CHR_EVENT_BREAK;
|
chr_event = CHR_EVENT_BREAK;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintf(scd, 2, "%s: unknown %d\n", __func__, event);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf(scd, 2, "%s: %d\n", __func__, event);
|
|
||||||
trace_spice_vmc_event(chr_event);
|
trace_spice_vmc_event(chr_event);
|
||||||
qemu_chr_be_event(scd->chr, chr_event);
|
qemu_chr_be_event(scd->chr, chr_event);
|
||||||
}
|
}
|
||||||
@ -141,7 +128,6 @@ static void vmc_register_interface(SpiceCharDriver *scd)
|
|||||||
if (scd->active) {
|
if (scd->active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dprintf(scd, 1, "%s\n", __func__);
|
|
||||||
scd->sin.base.sif = &vmc_interface.base;
|
scd->sin.base.sif = &vmc_interface.base;
|
||||||
qemu_spice_add_interface(&scd->sin.base);
|
qemu_spice_add_interface(&scd->sin.base);
|
||||||
scd->active = true;
|
scd->active = true;
|
||||||
@ -153,7 +139,6 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
|
|||||||
if (!scd->active) {
|
if (!scd->active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dprintf(scd, 1, "%s\n", __func__);
|
|
||||||
spice_server_remove_interface(&scd->sin.base);
|
spice_server_remove_interface(&scd->sin.base);
|
||||||
scd->active = false;
|
scd->active = false;
|
||||||
trace_spice_vmc_unregister_interface(scd);
|
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;
|
SpiceCharDriver *s = chr->opaque;
|
||||||
|
|
||||||
dprintf(s, 2, "%s: %d\n", __func__, len);
|
|
||||||
vmc_register_interface(s);
|
vmc_register_interface(s);
|
||||||
assert(s->datalen == 0);
|
assert(s->datalen == 0);
|
||||||
if (s->bufsize < len) {
|
if (s->bufsize < len) {
|
||||||
@ -182,9 +166,13 @@ static void spice_chr_close(struct CharDriverState *chr)
|
|||||||
{
|
{
|
||||||
SpiceCharDriver *s = chr->opaque;
|
SpiceCharDriver *s = chr->opaque;
|
||||||
|
|
||||||
printf("%s\n", __func__);
|
|
||||||
vmc_unregister_interface(s);
|
vmc_unregister_interface(s);
|
||||||
QLIST_REMOVE(s, next);
|
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);
|
g_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,18 +205,16 @@ static void print_allowed_subtypes(void)
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
|
static CharDriverState *chr_open(const char *subtype)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
SpiceCharDriver *s;
|
SpiceCharDriver *s;
|
||||||
uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
|
|
||||||
|
|
||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
s = g_malloc0(sizeof(SpiceCharDriver));
|
s = g_malloc0(sizeof(SpiceCharDriver));
|
||||||
s->chr = chr;
|
s->chr = chr;
|
||||||
s->debug = debug;
|
|
||||||
s->active = false;
|
s->active = false;
|
||||||
s->sin.subtype = subtype;
|
s->sin.subtype = g_strdup(subtype);
|
||||||
chr->opaque = s;
|
chr->opaque = s;
|
||||||
chr->chr_write = spice_chr_write;
|
chr->chr_write = spice_chr_write;
|
||||||
chr->chr_close = spice_chr_close;
|
chr->chr_close = spice_chr_close;
|
||||||
@ -240,35 +226,32 @@ static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
|
|||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
CharDriverState *qemu_chr_open_spice_vmc(const char *type)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
const char *name = qemu_opt_get(opts, "name");
|
|
||||||
const char **psubtype = spice_server_char_device_recognized_subtypes();
|
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");
|
fprintf(stderr, "spice-qemu-char: missing name parameter\n");
|
||||||
print_allowed_subtypes();
|
print_allowed_subtypes();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for(;*psubtype != NULL; ++psubtype) {
|
for (; *psubtype != NULL; ++psubtype) {
|
||||||
if (strcmp(name, *psubtype) == 0) {
|
if (strcmp(type, *psubtype) == 0) {
|
||||||
subtype = *psubtype;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subtype == NULL) {
|
if (*psubtype == NULL) {
|
||||||
fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
|
fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
|
||||||
print_allowed_subtypes();
|
print_allowed_subtypes();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chr = chr_open(opts, subtype);
|
chr = chr_open(type);
|
||||||
|
|
||||||
#if SPICE_SERVER_VERSION < 0x000901
|
#if SPICE_SERVER_VERSION < 0x000901
|
||||||
/* See comment in vmc_state() */
|
/* See comment in vmc_state() */
|
||||||
if (strcmp(subtype, "vdagent") == 0) {
|
if (strcmp(type, "vdagent") == 0) {
|
||||||
qemu_chr_generic_open(chr);
|
qemu_chr_generic_open(chr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -277,20 +260,19 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if SPICE_SERVER_VERSION >= 0x000c02
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts)
|
CharDriverState *qemu_chr_open_spice_port(const char *name)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
SpiceCharDriver *s;
|
SpiceCharDriver *s;
|
||||||
const char *name = qemu_opt_get(opts, "name");
|
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
fprintf(stderr, "spice-qemu-char: missing name parameter\n");
|
fprintf(stderr, "spice-qemu-char: missing name parameter\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chr = chr_open(opts, "port");
|
chr = chr_open("port");
|
||||||
s = chr->opaque;
|
s = chr->opaque;
|
||||||
s->sin.portname = name;
|
s->sin.portname = g_strdup(name);
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
@ -308,12 +290,38 @@ void qemu_spice_register_ports(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
register_char_driver("spicevmc", qemu_chr_open_spice);
|
register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
|
||||||
#if SPICE_SERVER_VERSION >= 0x000c02
|
qemu_chr_parse_spice_vmc);
|
||||||
register_char_driver("spiceport", qemu_chr_open_spice_port);
|
register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
|
||||||
#endif
|
qemu_chr_parse_spice_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
61
ui/console.c
61
ui/console.c
@ -1537,22 +1537,26 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
|
|||||||
chr->init(chr);
|
chr->init(chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CharDriverState *text_console_init(QemuOpts *opts)
|
static CharDriverState *text_console_init(ChardevVC *vc)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
QemuConsole *s;
|
QemuConsole *s;
|
||||||
unsigned width;
|
unsigned width = 0;
|
||||||
unsigned height;
|
unsigned height = 0;
|
||||||
|
|
||||||
chr = g_malloc0(sizeof(CharDriverState));
|
chr = g_malloc0(sizeof(CharDriverState));
|
||||||
|
|
||||||
width = qemu_opt_get_number(opts, "width", 0);
|
if (vc->has_width) {
|
||||||
if (width == 0)
|
width = vc->width;
|
||||||
width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
|
} else if (vc->has_cols) {
|
||||||
|
width = vc->cols * FONT_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
height = qemu_opt_get_number(opts, "height", 0);
|
if (vc->has_height) {
|
||||||
if (height == 0)
|
height = vc->height;
|
||||||
height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
|
} else if (vc->has_rows) {
|
||||||
|
height = vc->rows * FONT_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
s = new_console(NULL, TEXT_CONSOLE);
|
s = new_console(NULL, TEXT_CONSOLE);
|
||||||
@ -1575,9 +1579,9 @@ static CharDriverState *text_console_init(QemuOpts *opts)
|
|||||||
|
|
||||||
static VcHandler *vc_handler = text_console_init;
|
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)
|
void register_vc_handler(VcHandler *handler)
|
||||||
@ -1740,9 +1744,42 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
|||||||
return pf;
|
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)
|
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);
|
type_init(register_types);
|
||||||
|
2
ui/gtk.c
2
ui/gtk.c
@ -991,7 +991,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
|||||||
static int nb_vcs;
|
static int nb_vcs;
|
||||||
static CharDriverState *vcs[MAX_VCS];
|
static CharDriverState *vcs[MAX_VCS];
|
||||||
|
|
||||||
static CharDriverState *gd_vc_handler(QemuOpts *opts)
|
static CharDriverState *gd_vc_handler(ChardevVC *unused)
|
||||||
{
|
{
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
|
@ -949,6 +949,31 @@ int socket_listen(SocketAddress *addr, Error **errp)
|
|||||||
return fd;
|
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
|
#ifdef _WIN32
|
||||||
static void socket_cleanup(void)
|
static void socket_cleanup(void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user