X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=qemu-char.c;h=8084a6785d202d4bce89b9990dc52118ac85ac85;hb=b4f763b86dda1de95d595e4630c6ea5485484580;hp=bd2eca824c1b79a0b35052f7a5b9940a92766258;hpb=191bc01bc970bd1e86f34ddeab896b2b27fd5124;p=qemu diff --git a/qemu-char.c b/qemu-char.c index bd2eca8..8084a67 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -106,8 +106,8 @@ /***********************************************************/ /* character device */ -static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = - TAILQ_HEAD_INITIALIZER(chardevs); +static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = + QTAILQ_HEAD_INITIALIZER(chardevs); static int initial_reset_issued; static void qemu_chr_event(CharDriverState *s, int event) @@ -139,7 +139,7 @@ void qemu_chr_initial_reset(void) initial_reset_issued = 1; - TAILQ_FOREACH(chr, &chardevs, next) { + QTAILQ_FOREACH(chr, &chardevs, next) { qemu_chr_reset(chr); } } @@ -233,6 +233,7 @@ typedef struct { IOEventHandler *chr_event[MAX_MUX]; void *ext_opaque[MAX_MUX]; CharDriverState *drv; + int focus; int mux_cnt; int term_got_escape; int max_size; @@ -351,7 +352,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) case 's': { DriveInfo *dinfo; - TAILQ_FOREACH(dinfo, &drives, next) { + QTAILQ_FOREACH(dinfo, &drives, next) { bdrv_commit(dinfo->bdrv); } } @@ -361,11 +362,11 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) break; case 'c': /* Switch to the next registered device */ - mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT); - chr->focus++; - if (chr->focus >= d->mux_cnt) - chr->focus = 0; - mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN); + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); + d->focus++; + if (d->focus >= d->mux_cnt) + d->focus = 0; + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); break; case 't': d->timestamps = !d->timestamps; @@ -384,8 +385,8 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) static void mux_chr_accept_input(CharDriverState *chr) { - int m = chr->focus; MuxDriver *d = chr->opaque; + int m = d->focus; while (d->prod[m] != d->cons[m] && d->chr_can_read[m] && @@ -399,7 +400,7 @@ static int mux_chr_can_read(void *opaque) { CharDriverState *chr = opaque; MuxDriver *d = chr->opaque; - int m = chr->focus; + int m = d->focus; if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) return 1; @@ -412,7 +413,7 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size) { CharDriverState *chr = opaque; MuxDriver *d = chr->opaque; - int m = chr->focus; + int m = d->focus; int i; mux_chr_accept_input (opaque); @@ -456,8 +457,12 @@ static void mux_chr_update_read_handler(CharDriverState *chr) qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, mux_chr_event, chr); } - chr->focus = d->mux_cnt; + if (d->focus != -1) { + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); + } + d->focus = d->mux_cnt; d->mux_cnt++; + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); } static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) @@ -470,7 +475,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->opaque = d; d->drv = drv; - chr->focus = -1; + d->focus = -1; chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; @@ -626,20 +631,27 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static CharDriverState *qemu_chr_open_file_out(const char *file_out) +static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) { int fd_out; - TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); + TFR(fd_out = 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(const char *filename) +static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) { int fd_in, fd_out; char filename_in[256], filename_out[256]; + const char *filename = qemu_opt_get(opts, "path"); + + if (filename == NULL) { + fprintf(stderr, "chardev: pipe: no filename given\n"); + return NULL; + } snprintf(filename_in, 256, "%s.in", filename); snprintf(filename_out, 256, "%s.out", filename); @@ -751,7 +763,7 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr) fd_chr_close(chr); } -static CharDriverState *qemu_chr_open_stdio(void) +static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) { CharDriverState *chr; @@ -949,7 +961,7 @@ static void pty_chr_close(struct CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) { CharDriverState *chr; PtyCharDriver *s; @@ -979,6 +991,7 @@ static CharDriverState *qemu_chr_open_pty(void) len = strlen(q_ptsname(s->fd)) + 5; chr->filename = qemu_malloc(len); snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd)); + qemu_opt_set(opts, "path", q_ptsname(s->fd)); fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd)); chr->opaque = s; @@ -1138,8 +1151,9 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static CharDriverState *qemu_chr_open_tty(const char *filename) +static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) { + const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; int fd; @@ -1271,8 +1285,9 @@ static void pp_close(CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pp(const char *filename) +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) { + const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; ParallelCharDriver *drv; int fd; @@ -1340,8 +1355,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static CharDriverState *qemu_chr_open_pp(const char *filename) +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) { + const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; int fd; @@ -1559,8 +1575,9 @@ static int win_chr_poll(void *opaque) return 0; } -static CharDriverState *qemu_chr_open_win(const char *filename) +static CharDriverState *qemu_chr_open_win(QemuOpts *opts) { + const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; WinCharState *s; @@ -1658,8 +1675,9 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) } -static CharDriverState *qemu_chr_open_win_pipe(const char *filename) +static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) { + const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; WinCharState *s; @@ -1692,13 +1710,14 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) return chr; } -static CharDriverState *qemu_chr_open_win_con(const char *filename) +static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts) { return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } -static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) +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, @@ -1715,7 +1734,6 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) typedef struct { int fd; - struct sockaddr_in daddr; uint8_t buf[1024]; int bufcnt; int bufptr; @@ -1726,8 +1744,7 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { NetCharDriver *s = chr->opaque; - return sendto(s->fd, (const void *)buf, len, 0, - (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in)); + return send(s->fd, (const void *)buf, len, 0); } static int udp_chr_read_poll(void *opaque) @@ -1789,30 +1806,18 @@ static void udp_chr_close(CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_udp(const char *def) +static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; int fd = -1; - struct sockaddr_in saddr; chr = qemu_mallocz(sizeof(CharDriverState)); s = qemu_mallocz(sizeof(NetCharDriver)); - fd = socket(PF_INET, SOCK_DGRAM, 0); + fd = inet_dgram_opts(opts); if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - goto return_err; - } - - if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { - printf("Could not parse: %s\n", def); - goto return_err; - } - - if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) - { - perror("bind"); + fprintf(stderr, "inet_dgram_opts failed\n"); goto return_err; } @@ -2107,67 +2112,39 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_tcp(const char *host_str, - int is_telnet, - int is_unix) +static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; - int fd = -1, offset = 0; - int is_listen = 0; - int is_waitconnect = 1; - int do_nodelay = 0; - const char *ptr; - - ptr = host_str; - while((ptr = strchr(ptr,','))) { - ptr++; - if (!strncmp(ptr,"server",6)) { - is_listen = 1; - } else if (!strncmp(ptr,"nowait",6)) { - is_waitconnect = 0; - } else if (!strncmp(ptr,"nodelay",6)) { - do_nodelay = 1; - } else if (!strncmp(ptr,"to=",3)) { - /* nothing, inet_listen() parses this one */; - } else if (!strncmp(ptr,"ipv4",4)) { - /* nothing, inet_connect() and inet_listen() parse this one */; - } else if (!strncmp(ptr,"ipv6",4)) { - /* nothing, inet_connect() and inet_listen() parse this one */; - } else { - printf("Unknown option: %s\n", ptr); - goto fail; - } - } + int fd = -1; + int is_listen; + int is_waitconnect; + int do_nodelay; + int is_unix; + int is_telnet; + + is_listen = qemu_opt_get_bool(opts, "server", 0); + is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); + is_telnet = qemu_opt_get_bool(opts, "telnet", 0); + do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); + is_unix = qemu_opt_get(opts, "path") != NULL; if (!is_listen) is_waitconnect = 0; chr = qemu_mallocz(sizeof(CharDriverState)); s = qemu_mallocz(sizeof(TCPCharDriver)); - if (is_listen) { - chr->filename = qemu_malloc(256); - if (is_unix) { - pstrcpy(chr->filename, 256, "unix:"); - } else if (is_telnet) { - pstrcpy(chr->filename, 256, "telnet:"); - } else { - pstrcpy(chr->filename, 256, "tcp:"); - } - offset = strlen(chr->filename); - } if (is_unix) { if (is_listen) { - fd = unix_listen(host_str, chr->filename + offset, 256 - offset); + fd = unix_listen_opts(opts); } else { - fd = unix_connect(host_str); + fd = unix_connect_opts(opts); } } else { if (is_listen) { - fd = inet_listen(host_str, chr->filename + offset, 256 - offset, - SOCK_STREAM, 0); + fd = inet_listen_opts(opts, 0); } else { - fd = inet_connect(host_str, SOCK_STREAM); + fd = inet_connect_opts(opts); } } if (fd < 0) @@ -2193,6 +2170,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; + } else { s->connected = 1; s->fd = fd; @@ -2200,14 +2178,30 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, tcp_chr_connect(chr); } + /* for "info chardev" monitor command */ + chr->filename = qemu_malloc(256); + if (is_unix) { + snprintf(chr->filename, 256, "unix:%s%s", + qemu_opt_get(opts, "path"), + qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); + } else if (is_telnet) { + snprintf(chr->filename, 256, "telnet:%s:%s%s", + qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), + qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); + } else { + snprintf(chr->filename, 256, "tcp:%s:%s%s", + qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), + qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); + } + if (is_listen && is_waitconnect) { printf("QEMU waiting for connection on: %s\n", - chr->filename ? chr->filename : host_str); + chr->filename); tcp_chr_accept(chr); socket_set_nonblock(s->listen_fd); } - return chr; + fail: if (fd >= 0) closesocket(fd); @@ -2218,17 +2212,127 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { + char host[65], port[33], width[8], height[8]; + int pos; + const char *p; QemuOpts *opts; opts = qemu_opts_create(&qemu_chardev_opts, label, 1); if (NULL == opts) return NULL; - if (strcmp(filename, "null") == 0) { - qemu_opt_set(opts, "backend", "null"); + if (strstart(filename, "mon:", &p)) { + filename = p; + qemu_opt_set(opts, "mux", "on"); + } + + if (strcmp(filename, "null") == 0 || + strcmp(filename, "pty") == 0 || + strcmp(filename, "msmouse") == 0 || + strcmp(filename, "braille") == 0 || + strcmp(filename, "stdio") == 0) { + qemu_opt_set(opts, "backend", filename); + return opts; + } + if (strstart(filename, "vc", &p)) { + qemu_opt_set(opts, "backend", "vc"); + if (*p == ':') { + if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) { + /* pixels */ + qemu_opt_set(opts, "width", width); + qemu_opt_set(opts, "height", height); + } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) { + /* chars */ + qemu_opt_set(opts, "cols", width); + qemu_opt_set(opts, "rows", height); + } else { + goto fail; + } + } + return opts; + } + if (strcmp(filename, "con:") == 0) { + qemu_opt_set(opts, "backend", "console"); + return opts; + } + if (strstart(filename, "COM", NULL)) { + qemu_opt_set(opts, "backend", "serial"); + qemu_opt_set(opts, "path", filename); + return opts; + } + if (strstart(filename, "file:", &p)) { + qemu_opt_set(opts, "backend", "file"); + qemu_opt_set(opts, "path", p); + return opts; + } + if (strstart(filename, "pipe:", &p)) { + qemu_opt_set(opts, "backend", "pipe"); + qemu_opt_set(opts, "path", p); + return opts; + } + if (strstart(filename, "tcp:", &p) || + strstart(filename, "telnet:", &p)) { + if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { + host[0] = 0; + if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) + goto fail; + } + qemu_opt_set(opts, "backend", "socket"); + qemu_opt_set(opts, "host", host); + qemu_opt_set(opts, "port", port); + if (p[pos] == ',') { + if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0) + goto fail; + } + if (strstart(filename, "telnet:", &p)) + qemu_opt_set(opts, "telnet", "on"); + return opts; + } + if (strstart(filename, "udp:", &p)) { + qemu_opt_set(opts, "backend", "udp"); + if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { + host[0] = 0; + if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { + fprintf(stderr, "udp #1\n"); + goto fail; + } + } + qemu_opt_set(opts, "host", host); + qemu_opt_set(opts, "port", port); + if (p[pos] == '@') { + p += pos + 1; + if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { + host[0] = 0; + if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { + fprintf(stderr, "udp #2\n"); + goto fail; + } + } + qemu_opt_set(opts, "localaddr", host); + qemu_opt_set(opts, "localport", port); + } + return opts; + } + if (strstart(filename, "unix:", &p)) { + qemu_opt_set(opts, "backend", "socket"); + if (qemu_opts_do_parse(opts, p, "path") != 0) + goto fail; + return opts; + } + if (strstart(filename, "/dev/parport", NULL) || + strstart(filename, "/dev/ppi", NULL)) { + qemu_opt_set(opts, "backend", "parport"); + qemu_opt_set(opts, "path", filename); + return opts; + } + if (strstart(filename, "/dev/", NULL)) { + qemu_opt_set(opts, "backend", "tty"); + qemu_opt_set(opts, "path", filename); return opts; } +fail: + fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename); qemu_opts_del(opts); return NULL; } @@ -2238,6 +2342,31 @@ static const struct { CharDriverState *(*open)(QemuOpts *opts); } backend_table[] = { { .name = "null", .open = qemu_chr_open_null }, + { .name = "socket", .open = qemu_chr_open_socket }, + { .name = "udp", .open = qemu_chr_open_udp }, + { .name = "msmouse", .open = qemu_chr_open_msmouse }, + { .name = "vc", .open = text_console_init }, +#ifdef _WIN32 + { .name = "file", .open = qemu_chr_open_win_file_out }, + { .name = "pipe", .open = qemu_chr_open_win_pipe }, + { .name = "console", .open = qemu_chr_open_win_con }, + { .name = "serial", .open = qemu_chr_open_win }, +#else + { .name = "file", .open = qemu_chr_open_file_out }, + { .name = "pipe", .open = qemu_chr_open_pipe }, + { .name = "pty", .open = qemu_chr_open_pty }, + { .name = "stdio", .open = qemu_chr_open_stdio }, +#endif +#ifdef CONFIG_BRLAPI + { .name = "braille", .open = chr_baum_init }, +#endif +#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + { .name = "tty", .open = qemu_chr_open_tty }, +#endif +#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) + { .name = "parport", .open = qemu_chr_open_pp }, +#endif }; CharDriverState *qemu_chr_open_opts(QemuOpts *opts, @@ -2271,8 +2400,18 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, if (!chr->filename) chr->filename = qemu_strdup(qemu_opt_get(opts, "backend")); chr->init = init; + QTAILQ_INSERT_TAIL(&chardevs, chr, next); + + if (qemu_opt_get_bool(opts, "mux", 0)) { + CharDriverState *base = chr; + int len = strlen(qemu_opts_id(opts)) + 6; + base->label = qemu_malloc(len); + snprintf(base->label, len, "%s-base", qemu_opts_id(opts)); + chr = qemu_chr_open_mux(base); + chr->filename = base->filename; + QTAILQ_INSERT_TAIL(&chardevs, chr, next); + } chr->label = qemu_strdup(qemu_opts_id(opts)); - TAILQ_INSERT_TAIL(&chardevs, chr, next); return chr; } @@ -2282,100 +2421,24 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i CharDriverState *chr; QemuOpts *opts; - opts = qemu_chr_parse_compat(label, filename); - if (opts) { - return qemu_chr_open_opts(opts, init); - } - - if (!strcmp(filename, "vc")) { - chr = text_console_init(NULL); - } else - if (strstart(filename, "vc:", &p)) { - chr = text_console_init(p); - } else - if (strstart(filename, "tcp:", &p)) { - chr = qemu_chr_open_tcp(p, 0, 0); - } else - if (strstart(filename, "telnet:", &p)) { - chr = qemu_chr_open_tcp(p, 1, 0); - } else - if (strstart(filename, "udp:", &p)) { - chr = qemu_chr_open_udp(p); - } else - if (strstart(filename, "mon:", &p)) { - chr = qemu_chr_open(label, p, NULL); - if (chr) { - chr = qemu_chr_open_mux(chr); - monitor_init(chr, MONITOR_USE_READLINE); - } else { - printf("Unable to open driver: %s\n", p); - } - } else if (!strcmp(filename, "msmouse")) { - chr = qemu_chr_open_msmouse(); - } else -#ifndef _WIN32 - if (strstart(filename, "unix:", &p)) { - chr = qemu_chr_open_tcp(p, 0, 1); - } else if (strstart(filename, "file:", &p)) { - chr = qemu_chr_open_file_out(p); - } else if (strstart(filename, "pipe:", &p)) { - chr = qemu_chr_open_pipe(p); - } else if (!strcmp(filename, "pty")) { - chr = qemu_chr_open_pty(); - } else if (!strcmp(filename, "stdio")) { - chr = qemu_chr_open_stdio(); - } else -#if defined(__linux__) - if (strstart(filename, "/dev/parport", NULL)) { - chr = qemu_chr_open_pp(filename); - } else -#elif defined(__FreeBSD__) || defined(__DragonFly__) - if (strstart(filename, "/dev/ppi", NULL)) { - chr = qemu_chr_open_pp(filename); - } else -#endif -#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) - if (strstart(filename, "/dev/", NULL)) { - chr = qemu_chr_open_tty(filename); - } else -#endif -#else /* !_WIN32 */ - if (strstart(filename, "COM", NULL)) { - chr = qemu_chr_open_win(filename); - } else - if (strstart(filename, "pipe:", &p)) { - chr = qemu_chr_open_win_pipe(p); - } else - if (strstart(filename, "con:", NULL)) { - chr = qemu_chr_open_win_con(filename); - } else - if (strstart(filename, "file:", &p)) { - chr = qemu_chr_open_win_file_out(p); - } else -#endif -#ifdef CONFIG_BRLAPI - if (!strcmp(filename, "braille")) { - chr = chr_baum_init(); - } else -#endif - { - chr = NULL; + if (strstart(filename, "chardev:", &p)) { + return qemu_chr_find(p); } - if (chr) { - if (!chr->filename) - chr->filename = qemu_strdup(filename); - chr->init = init; - chr->label = qemu_strdup(label); - TAILQ_INSERT_TAIL(&chardevs, chr, next); + opts = qemu_chr_parse_compat(label, filename); + if (!opts) + return NULL; + + chr = qemu_chr_open_opts(opts, init); + if (chr && qemu_opt_get_bool(opts, "mux", 0)) { + monitor_init(chr, MONITOR_USE_READLINE); } return chr; } void qemu_chr_close(CharDriverState *chr) { - TAILQ_REMOVE(&chardevs, chr, next); + QTAILQ_REMOVE(&chardevs, chr, next); if (chr->chr_close) chr->chr_close(chr); qemu_free(chr->filename); @@ -2387,7 +2450,19 @@ void qemu_chr_info(Monitor *mon) { CharDriverState *chr; - TAILQ_FOREACH(chr, &chardevs, next) { + QTAILQ_FOREACH(chr, &chardevs, next) { monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename); } } + +CharDriverState *qemu_chr_find(const char *name) +{ + CharDriverState *chr; + + QTAILQ_FOREACH(chr, &chardevs, next) { + if (strcmp(chr->label, name) != 0) + continue; + return chr; + } + return NULL; +}