X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-char.c;h=b13f8d4cf7e119564be6c2b017ae8f54db082c7b;hb=refs%2Fheads%2Fstaging;hp=074fc22d114d0167bb7baa3dd9ce5d43b86e0553;hpb=d6c983cdadb4aec649ef93eefc025235a17ce467;p=qemu.git diff --git a/qemu-char.c b/qemu-char.c index 074fc22d1..b13f8d4cf 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -32,6 +32,7 @@ #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" +#include "qemu-objects.h" #include #include @@ -51,22 +52,19 @@ #include #include #include -#ifdef __NetBSD__ -#include -#endif -#ifdef __linux__ -#include -#endif #include #include #include #include #ifdef CONFIG_BSD #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #include +#if defined(__GLIBC__) +#include +#endif #elif defined(__DragonFly__) #include #include @@ -74,8 +72,6 @@ #else #include #endif -#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) -#include #else #ifdef __linux__ #include @@ -103,12 +99,13 @@ #include "qemu_socket.h" +#define READ_BUF_LEN 4096 + /***********************************************************/ /* character device */ -static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = - TAILQ_HEAD_INITIALIZER(chardevs); -static int initial_reset_issued; +static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = + QTAILQ_HEAD_INITIALIZER(chardevs); static void qemu_chr_event(CharDriverState *s, int event) { @@ -117,33 +114,22 @@ static void qemu_chr_event(CharDriverState *s, int event) s->chr_event(s->handler_opaque, event); } -static void qemu_chr_reset_bh(void *opaque) +static void qemu_chr_generic_open_bh(void *opaque) { CharDriverState *s = opaque; - qemu_chr_event(s, CHR_EVENT_RESET); + qemu_chr_event(s, CHR_EVENT_OPENED); qemu_bh_delete(s->bh); s->bh = NULL; } -void qemu_chr_reset(CharDriverState *s) +void qemu_chr_generic_open(CharDriverState *s) { - if (s->bh == NULL && initial_reset_issued) { - s->bh = qemu_bh_new(qemu_chr_reset_bh, s); + if (s->bh == NULL) { + s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s); qemu_bh_schedule(s->bh); } } -void qemu_chr_initial_reset(void) -{ - CharDriverState *chr; - - initial_reset_issued = 1; - - TAILQ_FOREACH(chr, &chardevs, next) { - qemu_chr_reset(chr); - } -} - int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) { return s->chr_write(s, buf, len); @@ -181,7 +167,7 @@ void qemu_chr_accept_input(CharDriverState *s) void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { - char buf[4096]; + char buf[READ_BUF_LEN]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); @@ -233,6 +219,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 +338,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 +348,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 +371,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 +386,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 +399,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 +443,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 +461,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; @@ -559,7 +550,7 @@ static void fd_chr_read(void *opaque) CharDriverState *chr = opaque; FDCharDriver *s = chr->opaque; int size, len; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; len = sizeof(buf); if (len > s->max_size) @@ -621,7 +612,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) chr->chr_update_read_handler = fd_chr_update_read_handler; chr->chr_close = fd_chr_close; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -630,7 +621,7 @@ static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) { int fd_out; - TFR(fd_out = open(qemu_opt_get(opts, "path"), + 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; @@ -650,8 +641,8 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) snprintf(filename_in, 256, "%s.in", filename); snprintf(filename_out, 256, "%s.out", filename); - TFR(fd_in = open(filename_in, O_RDWR | O_BINARY)); - TFR(fd_out = open(filename_out, O_RDWR | O_BINARY)); + TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY)); + TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY)); if (fd_in < 0 || fd_out < 0) { if (fd_in >= 0) close(fd_in); @@ -722,7 +713,7 @@ static void term_exit(void) fcntl(0, F_SETFL, old_fd0_flags); } -static void term_init(void) +static void term_init(QemuOpts *opts) { struct termios tty; @@ -735,7 +726,7 @@ static void term_init(void) tty.c_oflag |= OPOST; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); /* if graphical mode, we allow Ctrl-C handling */ - if (display_type == DT_NOGRAPHIC) + if (!qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC)) tty.c_lflag &= ~ISIG; tty.c_cflag &= ~(CSIZE|PARENB); tty.c_cflag |= CS8; @@ -768,7 +759,7 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) chr->chr_close = qemu_chr_close_stdio; qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); stdio_nb_clients++; - term_init(); + term_init(opts); return chr; } @@ -831,7 +822,8 @@ static void cfmakeraw (struct termios *termios_p) #endif #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ + || defined(__GLIBC__) typedef struct { int fd; @@ -870,7 +862,7 @@ static void pty_chr_read(void *opaque) CharDriverState *chr = opaque; PtyCharDriver *s = chr->opaque; int size, len; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; len = sizeof(buf); if (len > s->read_bytes) @@ -921,7 +913,7 @@ static void pty_chr_state(CharDriverState *chr, int connected) qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000); } else { if (!s->connected) - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); s->connected = 1; } } @@ -1011,33 +1003,68 @@ static void tty_serial_init(int fd, int speed, #endif tcgetattr (fd, &tty); -#define MARGIN 1.1 - if (speed <= 50 * MARGIN) - spd = B50; - else if (speed <= 75 * MARGIN) - spd = B75; - else if (speed <= 300 * MARGIN) - spd = B300; - else if (speed <= 600 * MARGIN) - spd = B600; - else if (speed <= 1200 * MARGIN) - spd = B1200; - else if (speed <= 2400 * MARGIN) - spd = B2400; - else if (speed <= 4800 * MARGIN) - spd = B4800; - else if (speed <= 9600 * MARGIN) - spd = B9600; - else if (speed <= 19200 * MARGIN) - spd = B19200; - else if (speed <= 38400 * MARGIN) - spd = B38400; - else if (speed <= 57600 * MARGIN) - spd = B57600; - else if (speed <= 115200 * MARGIN) - spd = B115200; - else +#define check_speed(val) if (speed <= val) { spd = B##val; break; } + speed = speed * 10 / 11; + do { + check_speed(50); + check_speed(75); + check_speed(110); + check_speed(134); + check_speed(150); + check_speed(200); + check_speed(300); + check_speed(600); + check_speed(1200); + check_speed(1800); + check_speed(2400); + check_speed(4800); + check_speed(9600); + check_speed(19200); + check_speed(38400); + /* Non-Posix values follow. They may be unsupported on some systems. */ + check_speed(57600); + check_speed(115200); +#ifdef B230400 + check_speed(230400); +#endif +#ifdef B460800 + check_speed(460800); +#endif +#ifdef B500000 + check_speed(500000); +#endif +#ifdef B576000 + check_speed(576000); +#endif +#ifdef B921600 + check_speed(921600); +#endif +#ifdef B1000000 + check_speed(1000000); +#endif +#ifdef B1152000 + check_speed(1152000); +#endif +#ifdef B1500000 + check_speed(1500000); +#endif +#ifdef B2000000 + check_speed(2000000); +#endif +#ifdef B2500000 + check_speed(2500000); +#endif +#ifdef B3000000 + check_speed(3000000); +#endif +#ifdef B3500000 + check_speed(3500000); +#endif +#ifdef B4000000 + check_speed(4000000); +#endif spd = B115200; + } while (0); cfsetispeed(&tty, spd); cfsetospeed(&tty, spd); @@ -1146,8 +1173,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; @@ -1159,7 +1187,7 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) return NULL; } chr->chr_ioctl = tty_serial_ioctl; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } #else /* ! __linux__ && ! __sun__ */ @@ -1279,8 +1307,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; @@ -1304,13 +1333,13 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) chr->chr_close = pp_close; chr->opaque = drv; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) { int fd = (int)chr->opaque; @@ -1348,8 +1377,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; @@ -1520,7 +1550,7 @@ static void win_chr_readfile(CharDriverState *chr) { WinCharState *s = chr->opaque; int ret, err; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; DWORD size; ZeroMemory(&s->orecv, sizeof(s->orecv)); @@ -1567,8 +1597,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; @@ -1583,7 +1614,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) free(chr); return NULL; } - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1683,7 +1714,7 @@ static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) free(chr); return NULL; } - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1697,7 +1728,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1725,8 +1756,7 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) typedef struct { int fd; - struct sockaddr_in daddr; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; int bufcnt; int bufptr; int max_size; @@ -1736,8 +1766,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) @@ -1799,30 +1828,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; } @@ -1999,7 +2016,7 @@ static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; int len, size; if (!s->connected || s->max_size <= 0) @@ -2038,7 +2055,7 @@ static void tcp_chr_connect(void *opaque) s->connected = 1; qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, tcp_chr_read, NULL, chr); - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); } #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; @@ -2085,7 +2102,7 @@ static void tcp_chr_accept(void *opaque) len = sizeof(saddr); addr = (struct sockaddr *)&saddr; } - fd = accept(s->listen_fd, addr, &len); + fd = qemu_accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { @@ -2215,9 +2232,9 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return NULL; } -static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) +QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { - char host[65], port[33]; + char host[65], port[33], width[8], height[8]; int pos; const char *p; QemuOpts *opts; @@ -2226,6 +2243,11 @@ static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (NULL == opts) return 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 || @@ -2234,10 +2256,32 @@ static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) 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); @@ -2266,12 +2310,48 @@ static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) 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); @@ -2285,11 +2365,14 @@ static const struct { } 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 }, @@ -2299,6 +2382,15 @@ static const struct { #ifdef CONFIG_BRLAPI { .name = "braille", .open = chr_baum_init }, #endif +#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ + || defined(__FreeBSD_kernel__) + { .name = "tty", .open = qemu_chr_open_tty }, +#endif +#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \ + || defined(__FreeBSD_kernel__) + { .name = "parport", .open = qemu_chr_open_pp }, +#endif }; CharDriverState *qemu_chr_open_opts(QemuOpts *opts, @@ -2332,8 +2424,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; } @@ -2343,67 +2445,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 (strstart(filename, "chardev:", &p)) { + return qemu_chr_find(p); } - if (!strcmp(filename, "vc")) { - chr = text_console_init(NULL); - } else - if (strstart(filename, "vc:", &p)) { - chr = text_console_init(p); - } 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 -#ifndef _WIN32 -#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 -#endif - { - chr = NULL; - } + opts = qemu_chr_parse_compat(label, filename); + if (!opts) + return NULL; - if (chr) { - if (!chr->filename) - chr->filename = qemu_strdup(filename); - chr->init = init; - chr->label = qemu_strdup(label); - TAILQ_INSERT_TAIL(&chardevs, chr, next); + 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); @@ -2411,11 +2470,61 @@ void qemu_chr_close(CharDriverState *chr) qemu_free(chr); } -void qemu_chr_info(Monitor *mon) +static void qemu_chr_qlist_iter(QObject *obj, void *opaque) +{ + QDict *chr_dict; + Monitor *mon = opaque; + + chr_dict = qobject_to_qdict(obj); + monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"), + qdict_get_str(chr_dict, "filename")); +} + +void qemu_chr_info_print(Monitor *mon, const QObject *ret_data) +{ + qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon); +} + +/** + * qemu_chr_info(): Character devices information + * + * Each device is represented by a QDict. The returned QObject is a QList + * of all devices. + * + * The QDict contains the following: + * + * - "label": device's label + * - "filename": device's file + * + * Example: + * + * [ { "label": "monitor", "filename", "stdio" }, + * { "label": "serial0", "filename": "vc" } ] + */ +void qemu_chr_info(Monitor *mon, QObject **ret_data) +{ + QList *chr_list; + CharDriverState *chr; + + chr_list = qlist_new(); + + QTAILQ_FOREACH(chr, &chardevs, next) { + QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }", + chr->label, chr->filename); + qlist_append_obj(chr_list, obj); + } + + *ret_data = QOBJECT(chr_list); +} + +CharDriverState *qemu_chr_find(const char *name) { CharDriverState *chr; - TAILQ_FOREACH(chr, &chardevs, next) { - monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename); + QTAILQ_FOREACH(chr, &chardevs, next) { + if (strcmp(chr->label, name) != 0) + continue; + return chr; } + return NULL; }