Diff for /qemu/qemu-char.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2018/04/24 17:20:39 version 1.1.1.5, 2018/04/24 17:34:16
Line 32 Line 32
 #include "hw/usb.h"  #include "hw/usb.h"
 #include "hw/baum.h"  #include "hw/baum.h"
 #include "hw/msmouse.h"  #include "hw/msmouse.h"
   #include "qemu-objects.h"
   
 #include <unistd.h>  #include <unistd.h>
 #include <fcntl.h>  #include <fcntl.h>
Line 51 Line 52
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <net/if.h>  #include <net/if.h>
 #ifdef __NetBSD__  
 #include <net/if_tap.h>  
 #endif  
 #ifdef __linux__  
 #include <linux/if_tun.h>  
 #endif  
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <dirent.h>  #include <dirent.h>
 #include <netdb.h>  #include <netdb.h>
 #include <sys/select.h>  #include <sys/select.h>
 #ifdef HOST_BSD  #ifdef CONFIG_BSD
 #include <sys/stat.h>  #include <sys/stat.h>
 #ifdef __FreeBSD__  #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <libutil.h>  #include <libutil.h>
 #include <dev/ppbus/ppi.h>  #include <dev/ppbus/ppi.h>
 #include <dev/ppbus/ppbconf.h>  #include <dev/ppbus/ppbconf.h>
   #if defined(__GLIBC__)
   #include <pty.h>
   #endif
 #elif defined(__DragonFly__)  #elif defined(__DragonFly__)
 #include <libutil.h>  #include <libutil.h>
 #include <dev/misc/ppi/ppi.h>  #include <dev/misc/ppi/ppi.h>
Line 74 Line 72
 #else  #else
 #include <util.h>  #include <util.h>
 #endif  #endif
 #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)  
 #include <freebsd/stdlib.h>  
 #else  #else
 #ifdef __linux__  #ifdef __linux__
 #include <pty.h>  #include <pty.h>
Line 103 Line 99
   
 #include "qemu_socket.h"  #include "qemu_socket.h"
   
   #define READ_BUF_LEN 4096
   
 /***********************************************************/  /***********************************************************/
 /* character device */  /* character device */
   
 static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =  static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
     TAILQ_HEAD_INITIALIZER(chardevs);      QTAILQ_HEAD_INITIALIZER(chardevs);
 static int initial_reset_issued;  
   
 static void qemu_chr_event(CharDriverState *s, int event)  static void qemu_chr_event(CharDriverState *s, int event)
 {  {
Line 117  static void qemu_chr_event(CharDriverSta Line 114  static void qemu_chr_event(CharDriverSta
     s->chr_event(s->handler_opaque, 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;      CharDriverState *s = opaque;
     qemu_chr_event(s, CHR_EVENT_RESET);      qemu_chr_event(s, CHR_EVENT_OPENED);
     qemu_bh_delete(s->bh);      qemu_bh_delete(s->bh);
     s->bh = NULL;      s->bh = NULL;
 }  }
   
 void qemu_chr_reset(CharDriverState *s)  void qemu_chr_generic_open(CharDriverState *s)
 {  {
     if (s->bh == NULL && initial_reset_issued) {      if (s->bh == NULL) {
         s->bh = qemu_bh_new(qemu_chr_reset_bh, s);          s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
         qemu_bh_schedule(s->bh);          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)  int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
 {  {
     return s->chr_write(s, buf, len);      return s->chr_write(s, buf, len);
Line 181  void qemu_chr_accept_input(CharDriverSta Line 167  void qemu_chr_accept_input(CharDriverSta
   
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)  void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
 {  {
     char buf[4096];      char buf[READ_BUF_LEN];
     va_list ap;      va_list ap;
     va_start(ap, fmt);      va_start(ap, fmt);
     vsnprintf(buf, sizeof(buf), fmt, ap);      vsnprintf(buf, sizeof(buf), fmt, ap);
Line 214  static int null_chr_write(CharDriverStat Line 200  static int null_chr_write(CharDriverStat
     return len;      return len;
 }  }
   
 static CharDriverState *qemu_chr_open_null(void)  static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
 {  {
     CharDriverState *chr;      CharDriverState *chr;
   
Line 233  typedef struct { Line 219  typedef struct {
     IOEventHandler *chr_event[MAX_MUX];      IOEventHandler *chr_event[MAX_MUX];
     void *ext_opaque[MAX_MUX];      void *ext_opaque[MAX_MUX];
     CharDriverState *drv;      CharDriverState *drv;
       int focus;
     int mux_cnt;      int mux_cnt;
     int term_got_escape;      int term_got_escape;
     int max_size;      int max_size;
Line 350  static int mux_proc_byte(CharDriverState Line 337  static int mux_proc_byte(CharDriverState
             }              }
         case 's':          case 's':
             {              {
                 int i;                  DriveInfo *dinfo;
                 for (i = 0; i < nb_drives; i++) {                  QTAILQ_FOREACH(dinfo, &drives, next) {
                         bdrv_commit(drives_table[i].bdrv);                      bdrv_commit(dinfo->bdrv);
                 }                  }
             }              }
             break;              break;
Line 361  static int mux_proc_byte(CharDriverState Line 348  static int mux_proc_byte(CharDriverState
             break;              break;
         case 'c':          case 'c':
             /* Switch to the next registered device */              /* Switch to the next registered device */
             mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);              mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
             chr->focus++;              d->focus++;
             if (chr->focus >= d->mux_cnt)              if (d->focus >= d->mux_cnt)
                 chr->focus = 0;                  d->focus = 0;
             mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);              mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
             break;              break;
         case 't':          case 't':
             d->timestamps = !d->timestamps;              d->timestamps = !d->timestamps;
Line 384  static int mux_proc_byte(CharDriverState Line 371  static int mux_proc_byte(CharDriverState
   
 static void mux_chr_accept_input(CharDriverState *chr)  static void mux_chr_accept_input(CharDriverState *chr)
 {  {
     int m = chr->focus;  
     MuxDriver *d = chr->opaque;      MuxDriver *d = chr->opaque;
       int m = d->focus;
   
     while (d->prod[m] != d->cons[m] &&      while (d->prod[m] != d->cons[m] &&
            d->chr_can_read[m] &&             d->chr_can_read[m] &&
Line 399  static int mux_chr_can_read(void *opaque Line 386  static int mux_chr_can_read(void *opaque
 {  {
     CharDriverState *chr = opaque;      CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;      MuxDriver *d = chr->opaque;
     int m = chr->focus;      int m = d->focus;
   
     if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)      if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
         return 1;          return 1;
Line 412  static void mux_chr_read(void *opaque, c Line 399  static void mux_chr_read(void *opaque, c
 {  {
     CharDriverState *chr = opaque;      CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;      MuxDriver *d = chr->opaque;
     int m = chr->focus;      int m = d->focus;
     int i;      int i;
   
     mux_chr_accept_input (opaque);      mux_chr_accept_input (opaque);
Line 456  static void mux_chr_update_read_handler( Line 443  static void mux_chr_update_read_handler(
         qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,          qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
                               mux_chr_event, chr);                                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++;      d->mux_cnt++;
       mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
 }  }
   
 static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)  static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
Line 470  static CharDriverState *qemu_chr_open_mu Line 461  static CharDriverState *qemu_chr_open_mu
   
     chr->opaque = d;      chr->opaque = d;
     d->drv = drv;      d->drv = drv;
     chr->focus = -1;      d->focus = -1;
     chr->chr_write = mux_chr_write;      chr->chr_write = mux_chr_write;
     chr->chr_update_read_handler = mux_chr_update_read_handler;      chr->chr_update_read_handler = mux_chr_update_read_handler;
     chr->chr_accept_input = mux_chr_accept_input;      chr->chr_accept_input = mux_chr_accept_input;
Line 559  static void fd_chr_read(void *opaque) Line 550  static void fd_chr_read(void *opaque)
     CharDriverState *chr = opaque;      CharDriverState *chr = opaque;
     FDCharDriver *s = chr->opaque;      FDCharDriver *s = chr->opaque;
     int size, len;      int size, len;
     uint8_t buf[1024];      uint8_t buf[READ_BUF_LEN];
   
     len = sizeof(buf);      len = sizeof(buf);
     if (len > s->max_size)      if (len > s->max_size)
Line 570  static void fd_chr_read(void *opaque) Line 561  static void fd_chr_read(void *opaque)
     if (size == 0) {      if (size == 0) {
         /* FD has been closed. Remove it from the active list.  */          /* FD has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);          qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
           qemu_chr_event(chr, CHR_EVENT_CLOSED);
         return;          return;
     }      }
     if (size > 0) {      if (size > 0) {
Line 602  static void fd_chr_close(struct CharDriv Line 594  static void fd_chr_close(struct CharDriv
     }      }
   
     qemu_free(s);      qemu_free(s);
       qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }  }
   
 /* open a character device to a unix fd */  /* open a character device to a unix fd */
Line 619  static CharDriverState *qemu_chr_open_fd Line 612  static CharDriverState *qemu_chr_open_fd
     chr->chr_update_read_handler = fd_chr_update_read_handler;      chr->chr_update_read_handler = fd_chr_update_read_handler;
     chr->chr_close = fd_chr_close;      chr->chr_close = fd_chr_close;
   
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
   
     return chr;      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;      int fd_out;
   
     TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));      TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
                         O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
     if (fd_out < 0)      if (fd_out < 0)
         return NULL;          return NULL;
     return qemu_chr_open_fd(-1, fd_out);      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;      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");
   
       if (filename == NULL) {
           fprintf(stderr, "chardev: pipe: no filename given\n");
           return NULL;
       }
   
     snprintf(filename_in, 256, "%s.in", filename);      snprintf(filename_in, 256, "%s.in", filename);
     snprintf(filename_out, 256, "%s.out", filename);      snprintf(filename_out, 256, "%s.out", filename);
     TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));      TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
     TFR(fd_out = open(filename_out, 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 || fd_out < 0) {
         if (fd_in >= 0)          if (fd_in >= 0)
             close(fd_in);              close(fd_in);
Line 690  static void stdio_read(void *opaque) Line 690  static void stdio_read(void *opaque)
     if (size == 0) {      if (size == 0) {
         /* stdin has been closed. Remove it from the active list.  */          /* stdin has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);          qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
           qemu_chr_event(chr, CHR_EVENT_CLOSED);
         return;          return;
     }      }
     if (size > 0) {      if (size > 0) {
Line 712  static void term_exit(void) Line 713  static void term_exit(void)
     fcntl(0, F_SETFL, old_fd0_flags);      fcntl(0, F_SETFL, old_fd0_flags);
 }  }
   
 static void term_init(void)  static void term_init(QemuOpts *opts)
 {  {
     struct termios tty;      struct termios tty;
   
Line 725  static void term_init(void) Line 726  static void term_init(void)
     tty.c_oflag |= OPOST;      tty.c_oflag |= OPOST;
     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);      tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
     /* if graphical mode, we allow Ctrl-C handling */      /* 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_lflag &= ~ISIG;
     tty.c_cflag &= ~(CSIZE|PARENB);      tty.c_cflag &= ~(CSIZE|PARENB);
     tty.c_cflag |= CS8;      tty.c_cflag |= CS8;
Line 748  static void qemu_chr_close_stdio(struct  Line 749  static void qemu_chr_close_stdio(struct 
     fd_chr_close(chr);      fd_chr_close(chr);
 }  }
   
 static CharDriverState *qemu_chr_open_stdio(void)  static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
 {  {
     CharDriverState *chr;      CharDriverState *chr;
   
Line 758  static CharDriverState *qemu_chr_open_st Line 759  static CharDriverState *qemu_chr_open_st
     chr->chr_close = qemu_chr_close_stdio;      chr->chr_close = qemu_chr_close_stdio;
     qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);      qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
     stdio_nb_clients++;      stdio_nb_clients++;
     term_init();      term_init(opts);
   
     return chr;      return chr;
 }  }
Line 821  static void cfmakeraw (struct termios *t Line 822  static void cfmakeraw (struct termios *t
 #endif  #endif
   
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \  #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)      || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
       || defined(__GLIBC__)
   
 typedef struct {  typedef struct {
     int fd;      int fd;
Line 860  static void pty_chr_read(void *opaque) Line 862  static void pty_chr_read(void *opaque)
     CharDriverState *chr = opaque;      CharDriverState *chr = opaque;
     PtyCharDriver *s = chr->opaque;      PtyCharDriver *s = chr->opaque;
     int size, len;      int size, len;
     uint8_t buf[1024];      uint8_t buf[READ_BUF_LEN];
   
     len = sizeof(buf);      len = sizeof(buf);
     if (len > s->read_bytes)      if (len > s->read_bytes)
Line 911  static void pty_chr_state(CharDriverStat Line 913  static void pty_chr_state(CharDriverStat
         qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);          qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
     } else {      } else {
         if (!s->connected)          if (!s->connected)
             qemu_chr_reset(chr);              qemu_chr_generic_open(chr);
         s->connected = 1;          s->connected = 1;
     }      }
 }  }
Line 943  static void pty_chr_close(struct CharDri Line 945  static void pty_chr_close(struct CharDri
     qemu_del_timer(s->timer);      qemu_del_timer(s->timer);
     qemu_free_timer(s->timer);      qemu_free_timer(s->timer);
     qemu_free(s);      qemu_free(s);
       qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }  }
   
 static CharDriverState *qemu_chr_open_pty(void)  static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 {  {
     CharDriverState *chr;      CharDriverState *chr;
     PtyCharDriver *s;      PtyCharDriver *s;
Line 975  static CharDriverState *qemu_chr_open_pt Line 978  static CharDriverState *qemu_chr_open_pt
     len = strlen(q_ptsname(s->fd)) + 5;      len = strlen(q_ptsname(s->fd)) + 5;
     chr->filename = qemu_malloc(len);      chr->filename = qemu_malloc(len);
     snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));      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));      fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
   
     chr->opaque = s;      chr->opaque = s;
Line 999  static void tty_serial_init(int fd, int  Line 1003  static void tty_serial_init(int fd, int 
 #endif  #endif
     tcgetattr (fd, &tty);      tcgetattr (fd, &tty);
   
 #define MARGIN 1.1  #define check_speed(val) if (speed <= val) { spd = B##val; break; }
     if (speed <= 50 * MARGIN)      speed = speed * 10 / 11;
         spd = B50;      do {
     else if (speed <= 75 * MARGIN)          check_speed(50);
         spd = B75;          check_speed(75);
     else if (speed <= 300 * MARGIN)          check_speed(110);
         spd = B300;          check_speed(134);
     else if (speed <= 600 * MARGIN)          check_speed(150);
         spd = B600;          check_speed(200);
     else if (speed <= 1200 * MARGIN)          check_speed(300);
         spd = B1200;          check_speed(600);
     else if (speed <= 2400 * MARGIN)          check_speed(1200);
         spd = B2400;          check_speed(1800);
     else if (speed <= 4800 * MARGIN)          check_speed(2400);
         spd = B4800;          check_speed(4800);
     else if (speed <= 9600 * MARGIN)          check_speed(9600);
         spd = B9600;          check_speed(19200);
     else if (speed <= 19200 * MARGIN)          check_speed(38400);
         spd = B19200;          /* Non-Posix values follow. They may be unsupported on some systems. */
     else if (speed <= 38400 * MARGIN)          check_speed(57600);
         spd = B38400;          check_speed(115200);
     else if (speed <= 57600 * MARGIN)  #ifdef B230400
         spd = B57600;          check_speed(230400);
     else if (speed <= 115200 * MARGIN)  #endif
         spd = B115200;  #ifdef B460800
     else          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;          spd = B115200;
       } while (0);
   
     cfsetispeed(&tty, spd);      cfsetispeed(&tty, spd);
     cfsetospeed(&tty, spd);      cfsetospeed(&tty, spd);
Line 1134  static int tty_serial_ioctl(CharDriverSt Line 1173  static int tty_serial_ioctl(CharDriverSt
     return 0;      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;      CharDriverState *chr;
     int fd;      int fd;
   
Line 1147  static CharDriverState *qemu_chr_open_tt Line 1187  static CharDriverState *qemu_chr_open_tt
         return NULL;          return NULL;
     }      }
     chr->chr_ioctl = tty_serial_ioctl;      chr->chr_ioctl = tty_serial_ioctl;
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
     return chr;      return chr;
 }  }
 #else  /* ! __linux__ && ! __sun__ */  #else  /* ! __linux__ && ! __sun__ */
Line 1264  static void pp_close(CharDriverState *ch Line 1304  static void pp_close(CharDriverState *ch
     ioctl(fd, PPRELEASE);      ioctl(fd, PPRELEASE);
     close(fd);      close(fd);
     qemu_free(drv);      qemu_free(drv);
       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;      CharDriverState *chr;
     ParallelCharDriver *drv;      ParallelCharDriver *drv;
     int fd;      int fd;
Line 1291  static CharDriverState *qemu_chr_open_pp Line 1333  static CharDriverState *qemu_chr_open_pp
     chr->chr_close = pp_close;      chr->chr_close = pp_close;
     chr->opaque = drv;      chr->opaque = drv;
   
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
   
     return chr;      return chr;
 }  }
 #endif /* __linux__ */  #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)  static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {  {
     int fd = (int)chr->opaque;      int fd = (int)chr->opaque;
Line 1335  static int pp_ioctl(CharDriverState *chr Line 1377  static int pp_ioctl(CharDriverState *chr
     return 0;      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;      CharDriverState *chr;
     int fd;      int fd;
   
Line 1390  static void win_chr_close(CharDriverStat Line 1433  static void win_chr_close(CharDriverStat
         qemu_del_polling_cb(win_chr_pipe_poll, chr);          qemu_del_polling_cb(win_chr_pipe_poll, chr);
     else      else
         qemu_del_polling_cb(win_chr_poll, chr);          qemu_del_polling_cb(win_chr_poll, chr);
   
       qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }  }
   
 static int win_chr_init(CharDriverState *chr, const char *filename)  static int win_chr_init(CharDriverState *chr, const char *filename)
Line 1505  static void win_chr_readfile(CharDriverS Line 1550  static void win_chr_readfile(CharDriverS
 {  {
     WinCharState *s = chr->opaque;      WinCharState *s = chr->opaque;
     int ret, err;      int ret, err;
     uint8_t buf[1024];      uint8_t buf[READ_BUF_LEN];
     DWORD size;      DWORD size;
   
     ZeroMemory(&s->orecv, sizeof(s->orecv));      ZeroMemory(&s->orecv, sizeof(s->orecv));
Line 1552  static int win_chr_poll(void *opaque) Line 1597  static int win_chr_poll(void *opaque)
     return 0;      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;      CharDriverState *chr;
     WinCharState *s;      WinCharState *s;
   
Line 1568  static CharDriverState *qemu_chr_open_wi Line 1614  static CharDriverState *qemu_chr_open_wi
         free(chr);          free(chr);
         return NULL;          return NULL;
     }      }
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
     return chr;      return chr;
 }  }
   
Line 1651  static int win_chr_pipe_init(CharDriverS Line 1697  static int win_chr_pipe_init(CharDriverS
 }  }
   
   
 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;      CharDriverState *chr;
     WinCharState *s;      WinCharState *s;
   
Line 1667  static CharDriverState *qemu_chr_open_wi Line 1714  static CharDriverState *qemu_chr_open_wi
         free(chr);          free(chr);
         return NULL;          return NULL;
     }      }
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
     return chr;      return chr;
 }  }
   
Line 1681  static CharDriverState *qemu_chr_open_wi Line 1728  static CharDriverState *qemu_chr_open_wi
     s->hcom = fd_out;      s->hcom = fd_out;
     chr->opaque = s;      chr->opaque = s;
     chr->chr_write = win_chr_write;      chr->chr_write = win_chr_write;
     qemu_chr_reset(chr);      qemu_chr_generic_open(chr);
     return chr;      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));      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;      HANDLE fd_out;
   
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,      fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
Line 1708  static CharDriverState *qemu_chr_open_wi Line 1756  static CharDriverState *qemu_chr_open_wi
   
 typedef struct {  typedef struct {
     int fd;      int fd;
     struct sockaddr_in daddr;      uint8_t buf[READ_BUF_LEN];
     uint8_t buf[1024];  
     int bufcnt;      int bufcnt;
     int bufptr;      int bufptr;
     int max_size;      int max_size;
Line 1719  static int udp_chr_write(CharDriverState Line 1766  static int udp_chr_write(CharDriverState
 {  {
     NetCharDriver *s = chr->opaque;      NetCharDriver *s = chr->opaque;
   
     return sendto(s->fd, (const void *)buf, len, 0,      return send(s->fd, (const void *)buf, len, 0);
                   (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));  
 }  }
   
 static int udp_chr_read_poll(void *opaque)  static int udp_chr_read_poll(void *opaque)
Line 1779  static void udp_chr_close(CharDriverStat Line 1825  static void udp_chr_close(CharDriverStat
         closesocket(s->fd);          closesocket(s->fd);
     }      }
     qemu_free(s);      qemu_free(s);
       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;      CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;      NetCharDriver *s = NULL;
     int fd = -1;      int fd = -1;
     struct sockaddr_in saddr;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));      chr = qemu_mallocz(sizeof(CharDriverState));
     s = qemu_mallocz(sizeof(NetCharDriver));      s = qemu_mallocz(sizeof(NetCharDriver));
   
     fd = socket(PF_INET, SOCK_DGRAM, 0);      fd = inet_dgram_opts(opts);
     if (fd < 0) {      if (fd < 0) {
         perror("socket(PF_INET, SOCK_DGRAM)");          fprintf(stderr, "inet_dgram_opts failed\n");
         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");  
         goto return_err;          goto return_err;
     }      }
   
Line 1920  static int tcp_get_msgfd(CharDriverState Line 1955  static int tcp_get_msgfd(CharDriverState
     return s->msgfd;      return s->msgfd;
 }  }
   
 #ifndef WIN32  #ifndef _WIN32
 static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)  static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
 {  {
     TCPCharDriver *s = chr->opaque;      TCPCharDriver *s = chr->opaque;
Line 1981  static void tcp_chr_read(void *opaque) Line 2016  static void tcp_chr_read(void *opaque)
 {  {
     CharDriverState *chr = opaque;      CharDriverState *chr = opaque;
     TCPCharDriver *s = chr->opaque;      TCPCharDriver *s = chr->opaque;
     uint8_t buf[1024];      uint8_t buf[READ_BUF_LEN];
     int len, size;      int len, size;
   
     if (!s->connected || s->max_size <= 0)      if (!s->connected || s->max_size <= 0)
Line 1999  static void tcp_chr_read(void *opaque) Line 2034  static void tcp_chr_read(void *opaque)
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);          qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
         closesocket(s->fd);          closesocket(s->fd);
         s->fd = -1;          s->fd = -1;
           qemu_chr_event(chr, CHR_EVENT_CLOSED);
     } else if (size > 0) {      } else if (size > 0) {
         if (s->do_telnetopt)          if (s->do_telnetopt)
             tcp_chr_process_IAC_bytes(chr, s, buf, &size);              tcp_chr_process_IAC_bytes(chr, s, buf, &size);
Line 2019  static void tcp_chr_connect(void *opaque Line 2055  static void tcp_chr_connect(void *opaque
     s->connected = 1;      s->connected = 1;
     qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,      qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
                          tcp_chr_read, NULL, chr);                           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;  #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
Line 2066  static void tcp_chr_accept(void *opaque) Line 2102  static void tcp_chr_accept(void *opaque)
             len = sizeof(saddr);              len = sizeof(saddr);
             addr = (struct sockaddr *)&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) {          if (fd < 0 && errno != EINTR) {
             return;              return;
         } else if (fd >= 0) {          } else if (fd >= 0) {
Line 2095  static void tcp_chr_close(CharDriverStat Line 2131  static void tcp_chr_close(CharDriverStat
         closesocket(s->listen_fd);          closesocket(s->listen_fd);
     }      }
     qemu_free(s);      qemu_free(s);
       qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }  }
   
 static CharDriverState *qemu_chr_open_tcp(const char *host_str,  static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
                                           int is_telnet,  
                                           int is_unix)  
 {  {
     CharDriverState *chr = NULL;      CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;      TCPCharDriver *s = NULL;
     int fd = -1, offset = 0;      int fd = -1;
     int is_listen = 0;      int is_listen;
     int is_waitconnect = 1;      int is_waitconnect;
     int do_nodelay = 0;      int do_nodelay;
     const char *ptr;      int is_unix;
       int is_telnet;
     ptr = host_str;  
     while((ptr = strchr(ptr,','))) {      is_listen      = qemu_opt_get_bool(opts, "server", 0);
         ptr++;      is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
         if (!strncmp(ptr,"server",6)) {      is_telnet      = qemu_opt_get_bool(opts, "telnet", 0);
             is_listen = 1;      do_nodelay     = !qemu_opt_get_bool(opts, "delay", 1);
         } else if (!strncmp(ptr,"nowait",6)) {      is_unix        = qemu_opt_get(opts, "path") != NULL;
             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;  
         }  
     }  
     if (!is_listen)      if (!is_listen)
         is_waitconnect = 0;          is_waitconnect = 0;
   
     chr = qemu_mallocz(sizeof(CharDriverState));      chr = qemu_mallocz(sizeof(CharDriverState));
     s = qemu_mallocz(sizeof(TCPCharDriver));      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_unix) {
         if (is_listen) {          if (is_listen) {
             fd = unix_listen(host_str, chr->filename + offset, 256 - offset);              fd = unix_listen_opts(opts);
         } else {          } else {
             fd = unix_connect(host_str);              fd = unix_connect_opts(opts);
         }          }
     } else {      } else {
         if (is_listen) {          if (is_listen) {
             fd = inet_listen(host_str, chr->filename + offset, 256 - offset,              fd = inet_listen_opts(opts, 0);
                              SOCK_STREAM, 0);  
         } else {          } else {
             fd = inet_connect(host_str, SOCK_STREAM);              fd = inet_connect_opts(opts);
         }          }
     }      }
     if (fd < 0)      if (fd < 0)
Line 2183  static CharDriverState *qemu_chr_open_tc Line 2192  static CharDriverState *qemu_chr_open_tc
         qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);          qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
         if (is_telnet)          if (is_telnet)
             s->do_telnetopt = 1;              s->do_telnetopt = 1;
   
     } else {      } else {
         s->connected = 1;          s->connected = 1;
         s->fd = fd;          s->fd = fd;
Line 2190  static CharDriverState *qemu_chr_open_tc Line 2200  static CharDriverState *qemu_chr_open_tc
         tcp_chr_connect(chr);          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) {      if (is_listen && is_waitconnect) {
         printf("QEMU waiting for connection on: %s\n",          printf("QEMU waiting for connection on: %s\n",
                chr->filename ? chr->filename : host_str);                 chr->filename);
         tcp_chr_accept(chr);          tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);          socket_set_nonblock(s->listen_fd);
     }      }
   
     return chr;      return chr;
   
  fail:   fail:
     if (fd >= 0)      if (fd >= 0)
         closesocket(fd);          closesocket(fd);
Line 2206  static CharDriverState *qemu_chr_open_tc Line 2232  static CharDriverState *qemu_chr_open_tc
     return NULL;      return NULL;
 }  }
   
 CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))  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;      const char *p;
     CharDriverState *chr;      QemuOpts *opts;
   
       opts = qemu_opts_create(&qemu_chardev_opts, label, 1);
       if (NULL == opts)
           return NULL;
   
     if (!strcmp(filename, "vc")) {  
         chr = text_console_init(NULL);  
     } else  
     if (strstart(filename, "vc:", &p)) {  
         chr = text_console_init(p);  
     } else  
     if (!strcmp(filename, "null")) {  
         chr = qemu_chr_open_null();  
     } 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)) {      if (strstart(filename, "mon:", &p)) {
         chr = qemu_chr_open(label, p, NULL);          filename = p;
         if (chr) {          qemu_opt_set(opts, "mux", "on");
             chr = qemu_chr_open_mux(chr);      }
             monitor_init(chr, MONITOR_USE_READLINE);  
         } else {      if (strcmp(filename, "null")    == 0 ||
             printf("Unable to open driver: %s\n", p);          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;
               }
         }          }
     } else if (!strcmp(filename, "msmouse")) {          return opts;
         chr = qemu_chr_open_msmouse();      }
     } else      if (strcmp(filename, "con:") == 0) {
 #ifndef _WIN32          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)) {      if (strstart(filename, "unix:", &p)) {
         chr = qemu_chr_open_tcp(p, 0, 1);          qemu_opt_set(opts, "backend", "socket");
     } else if (strstart(filename, "file:", &p)) {          if (qemu_opts_do_parse(opts, p, "path") != 0)
         chr = qemu_chr_open_file_out(p);              goto fail;
     } else if (strstart(filename, "pipe:", &p)) {          return opts;
         chr = qemu_chr_open_pipe(p);      }
     } else if (!strcmp(filename, "pty")) {      if (strstart(filename, "/dev/parport", NULL) ||
         chr = qemu_chr_open_pty();          strstart(filename, "/dev/ppi", NULL)) {
     } else if (!strcmp(filename, "stdio")) {          qemu_opt_set(opts, "backend", "parport");
         chr = qemu_chr_open_stdio();          qemu_opt_set(opts, "path", filename);
     } else          return opts;
 #if defined(__linux__)      }
     if (strstart(filename, "/dev/parport", NULL)) {      if (strstart(filename, "/dev/", NULL)) {
         chr = qemu_chr_open_pp(filename);          qemu_opt_set(opts, "backend", "tty");
     } else          qemu_opt_set(opts, "path", filename);
 #elif defined(__FreeBSD__) || defined(__DragonFly__)          return opts;
     if (strstart(filename, "/dev/ppi", NULL)) {      }
         chr = qemu_chr_open_pp(filename);  
     } else  fail:
       fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename);
       qemu_opts_del(opts);
       return NULL;
   }
   
   static const struct {
       const char *name;
       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  #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \  #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)      || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
     if (strstart(filename, "/dev/", NULL)) {      || defined(__FreeBSD_kernel__)
         chr = qemu_chr_open_tty(filename);      { .name = "tty",       .open = qemu_chr_open_tty },
     } else  
 #endif  #endif
 #else /* !_WIN32 */  #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \
     if (strstart(filename, "COM", NULL)) {      || defined(__FreeBSD_kernel__)
         chr = qemu_chr_open_win(filename);      { .name = "parport",   .open = qemu_chr_open_pp },
     } 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  #endif
 #ifdef CONFIG_BRLAPI  };
     if (!strcmp(filename, "braille")) {  
         chr = chr_baum_init();  CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
     } else                                      void (*init)(struct CharDriverState *s))
 #endif  {
     {      CharDriverState *chr;
         chr = NULL;      int i;
   
       if (qemu_opts_id(opts) == NULL) {
           fprintf(stderr, "chardev: no id specified\n");
           return NULL;
       }
   
       for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
           if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
               break;
       }
       if (i == ARRAY_SIZE(backend_table)) {
           fprintf(stderr, "chardev: backend \"%s\" not found\n",
                   qemu_opt_get(opts, "backend"));
           return NULL;
       }
   
       chr = backend_table[i].open(opts);
       if (!chr) {
           fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
                   qemu_opt_get(opts, "backend"));
           return NULL;
       }
   
       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));
       return chr;
   }
   
   CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
   {
       const char *p;
       CharDriverState *chr;
       QemuOpts *opts;
   
       if (strstart(filename, "chardev:", &p)) {
           return qemu_chr_find(p);
     }      }
   
     if (chr) {      opts = qemu_chr_parse_compat(label, filename);
         if (!chr->filename)      if (!opts)
             chr->filename = qemu_strdup(filename);          return NULL;
         chr->init = init;  
         chr->label = qemu_strdup(label);      chr = qemu_chr_open_opts(opts, init);
         TAILQ_INSERT_TAIL(&chardevs, chr, next);      if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
           monitor_init(chr, MONITOR_USE_READLINE);
     }      }
     return chr;      return chr;
 }  }
   
 void qemu_chr_close(CharDriverState *chr)  void qemu_chr_close(CharDriverState *chr)
 {  {
     TAILQ_REMOVE(&chardevs, chr, next);      QTAILQ_REMOVE(&chardevs, chr, next);
     if (chr->chr_close)      if (chr->chr_close)
         chr->chr_close(chr);          chr->chr_close(chr);
     qemu_free(chr->filename);      qemu_free(chr->filename);
Line 2310  void qemu_chr_close(CharDriverState *chr Line 2470  void qemu_chr_close(CharDriverState *chr
     qemu_free(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;      CharDriverState *chr;
   
     TAILQ_FOREACH(chr, &chardevs, next) {      QTAILQ_FOREACH(chr, &chardevs, next) {
         monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);          if (strcmp(chr->label, name) != 0)
               continue;
           return chr;
     }      }
       return NULL;
 }  }

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


unix.superglobalmegacorp.com