qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] add serial port mux for debug monitor support
@ 2006-07-01 20:24 Jason Wessel
  2006-07-02 12:41 ` Jason Wessel
  0 siblings, 1 reply; 2+ messages in thread
From: Jason Wessel @ 2006-07-01 20:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1094 bytes --]

There are two patches attached to show the logical progress of the code 
and in the case that one is not accepted the work is more easily broken 
down.

The serial_mux_driver.patch must be applied first.  It adds a generic 
mux support for the I/O drivers internal to vl.c.  The main purpose is 
to use it for switching on the monitor.  Basically it allows more than 
one driver to register an fd_read and fd_can_read routine.  Of course 
the mux support is generic and could easily be used for other sorts of 
I/O.  This patch also adds the new options:

-echr ascii_value -- Allow you to use a different control character 
other than Control-a
-serial mon:device_string  -- Multiplex the device_string with the 
monitor functionality

The second patch fully abstracts the monitor so that the monitor can be 
used on more than one serial port at the same time as well as having a 
separate dedicated monitor.  I also removed the stdio splitting from the 
stdio driver.  The mux driver can be used to replace any functionality 
that I missed.

signed-off-by: jason.wessel@windriver.com

Jason.

[-- Attachment #2: serial_mux_driver.patch --]
[-- Type: text/plain, Size: 14781 bytes --]

Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -1124,9 +1124,11 @@ void qemu_chr_add_read_handler(CharDrive
     s->chr_add_read_handler(s, fd_can_read, fd_read, opaque);
 }
              
-void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event)
+void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event,
+                                void *event_opaque)
 {
     s->chr_event = chr_event;
+    s->event_opaque = event_opaque;
 }
 
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -1152,6 +1154,166 @@ CharDriverState *qemu_chr_open_null(void
     return chr;
 }
 
+#define MAX_MUX 2
+/* MUX driver for serial I/O splitting */
+typedef struct {
+    IOCanRWHandler *fd_can_read[MAX_MUX];
+    IOReadHandler *fd_read[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    CharDriverState *drv;
+    int idx;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MuxDriver *d = chr->opaque;
+    len = d->drv->chr_write(d->drv, buf, len);
+    return len;
+}
+
+static char *mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+static int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(CharDriverState *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        sprintf(cbuf,"\n\r");
+        sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a');
+    } else {
+        sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char);
+    }
+    chr->chr_write(chr, cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j=0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%')
+                chr->chr_write(chr, ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, &mux_help[i][j], 1);
+        }
+    }
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
+        switch(ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            exit(0);
+            break;
+        case 's':
+            {
+                int i;
+                for (i = 0; i < MAX_DISKS; i++) {
+                    if (bs_table[i])
+                        bdrv_commit(bs_table[i]);
+                }
+            }
+            break;
+        case 'b':
+            if (chr->chr_event)
+                chr->chr_event(chr->event_opaque, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            /* Switch to the next registered device */
+            d->idx++;
+            if (d->idx >= d->mux_cnt)
+                d->idx = 0;
+            break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static int mux_chr_fd_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    return d->fd_can_read[d->idx](d->ext_opaque[d->idx]);
+}
+
+static void mux_chr_fd_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+    for(i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i]))
+            d->fd_read[d->idx](d->ext_opaque[d->idx], &buf[i], 1);
+}
+
+static void mux_chr_add_read_handler(CharDriverState *chr,
+                                    IOCanRWHandler *fd_can_read,
+                                    IOReadHandler *fd_read, void *opaque)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        return;
+    }
+    d->ext_opaque[d->mux_cnt] = opaque;
+    d->fd_can_read[d->mux_cnt] = fd_can_read;
+    d->fd_read[d->mux_cnt] = fd_read;
+    /* Fix up the real driver with mux routines */
+    if (d->drv->chr_add_read_handler && d->mux_cnt == 0)
+        d->drv->chr_add_read_handler(d->drv,
+                                     mux_chr_fd_can_read,
+                                     mux_chr_fd_read, chr);
+    d->idx = d->mux_cnt;
+    d->mux_cnt++;
+}
+
+CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
+    CharDriverState *chr;
+    MuxDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    d = qemu_mallocz(sizeof(MuxDriver));
+    if (!d) {
+        free(chr);
+        return NULL;
+    }
+
+    chr->opaque = d;
+    d->drv = drv;
+    d->idx = -1;
+    chr->chr_write = mux_chr_write;
+    chr->chr_add_read_handler = mux_chr_add_read_handler;
+    return chr;
+}
+
+
 #ifdef _WIN32
 
 static void socket_cleanup(void)
@@ -1348,8 +1510,6 @@ CharDriverState *qemu_chr_open_pipe(cons
 /* for STDIO, we handle the case where several clients use it
    (nographic mode) */
 
-#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-
 #define TERM_FIFO_MAX_SIZE 1
 
 static int term_got_escape, client_index;
@@ -1373,6 +1533,8 @@ static void stdio_received_byte(int ch)
 {
     if (term_got_escape) {
         term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
         switch(ch) {
         case 'h':
             term_print_help();
@@ -1409,10 +1571,8 @@ static void stdio_received_byte(int ch)
                 goto send_char;
             }
             break;
-        case TERM_ESCAPE:
-            goto send_char;
         }
-    } else if (ch == TERM_ESCAPE) {
+    } else if (ch == term_escape_char) {
         term_got_escape = 1;
     } else {
     send_char:
@@ -2564,6 +2724,16 @@ CharDriverState *qemu_chr_open(const cha
     if (strstart(filename, "udp:", &p)) {
         return qemu_chr_open_udp(p);
     } else
+    if (strstart(filename, "mon:", &p)) {
+        CharDriverState *drv = qemu_chr_open(p);
+        if (drv) {
+            drv = qemu_chr_open_mux(drv);
+            monitor_init(drv, !nographic);
+            return drv;
+        }
+        printf("Unable to open driver: %s\n", p);
+        return 0;
+    } else
 #ifndef _WIN32
     if (strstart(filename, "file:", &p)) {
         return qemu_chr_open_file_out(p);
@@ -5305,6 +5475,7 @@ enum {
     QEMU_OPTION_cirrusvga,
     QEMU_OPTION_g,
     QEMU_OPTION_std_vga,
+    QEMU_OPTION_echr,
     QEMU_OPTION_monitor,
     QEMU_OPTION_serial,
     QEMU_OPTION_parallel,
@@ -5380,6 +5551,7 @@ const QEMUOption qemu_options[] = {
 #endif
     { "localtime", 0, QEMU_OPTION_localtime },
     { "std-vga", 0, QEMU_OPTION_std_vga },
+    { "echr", 1, QEMU_OPTION_echr },
     { "monitor", 1, QEMU_OPTION_monitor },
     { "serial", 1, QEMU_OPTION_serial },
     { "parallel", 1, QEMU_OPTION_parallel },
@@ -5947,6 +6119,13 @@ int main(int argc, char **argv)
                     graphic_depth = depth;
                 }
                 break;
+            case QEMU_OPTION_echr:
+                {
+                    char *r;
+                    term_escape_char = strtol(optarg, &r, 0);
+                    if (r == optarg)
+                        printf("Bad argument to echr\n");
+                }
             case QEMU_OPTION_monitor:
                 pstrcpy(monitor_device, sizeof(monitor_device), optarg);
                 break;
@@ -6145,12 +6324,17 @@ int main(int argc, char **argv)
 #endif
     }
 
-    monitor_hd = qemu_chr_open(monitor_device);
-    if (!monitor_hd) {
-        fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
-        exit(1);
+    for (i = 0; i < MAX_SERIAL_PORTS; i++)
+        if (!strncmp(serial_devices[i],"mon:",4))
+            break;
+    if (i >= MAX_SERIAL_PORTS) {
+        monitor_hd = qemu_chr_open(monitor_device);
+        if (!monitor_hd) {
+            fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
+            exit(1);
+        }
+        monitor_init(monitor_hd, !nographic);
     }
-    monitor_init(monitor_hd, !nographic);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_devices[i][0] != '\0') {
Index: qemu/hw/pl011.c
===================================================================
--- qemu.orig/hw/pl011.c
+++ qemu/hw/pl011.c
@@ -244,7 +244,7 @@ void pl011_init(uint32_t base, void *pic
     s->flags = 0x90;
     if (chr){ 
         qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
-        qemu_chr_add_event_handler(chr, pl011_event);
+        qemu_chr_add_event_handler(chr, pl011_event, s);
     }
     /* ??? Save/restore.  */
 }
Index: qemu/hw/serial.c
===================================================================
--- qemu.orig/hw/serial.c
+++ qemu/hw/serial.c
@@ -363,7 +363,7 @@ SerialState *serial_init(SetIRQFunc *set
     register_ioport_read(base, 8, 1, serial_ioport_read, s);
     s->chr = chr;
     qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
-    qemu_chr_add_event_handler(chr, serial_event);
+    qemu_chr_add_event_handler(chr, serial_event, s);
     return s;
 }
 
@@ -451,6 +451,6 @@ SerialState *serial_mm_init (SetIRQFunc 
     cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
     s->chr = chr;
     qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
-    qemu_chr_add_event_handler(chr, serial_event);
+    qemu_chr_add_event_handler(chr, serial_event, s);
     return s;
 }
Index: qemu/hw/sh7750.c
===================================================================
--- qemu.orig/hw/sh7750.c
+++ qemu/hw/sh7750.c
@@ -301,7 +301,7 @@ static void init_serial1(SH7750State * s
     s->serial1 = chr;
     qemu_chr_add_read_handler(chr, serial1_can_receive,
 			      serial1_receive, s);
-    qemu_chr_add_event_handler(chr, serial1_event);
+    qemu_chr_add_event_handler(chr, serial1_event, s);
 }
 
 /**********************************************************************
@@ -417,7 +417,7 @@ static void init_serial2(SH7750State * s
     s->serial2 = chr;
     qemu_chr_add_read_handler(chr, serial2_can_receive,
 			      serial2_receive, s);
-    qemu_chr_add_event_handler(chr, serial2_event);
+    qemu_chr_add_event_handler(chr, serial2_event, s);
 }
 
 static void init_serial_ports(SH7750State * s)
Index: qemu/hw/slavio_serial.c
===================================================================
--- qemu.orig/hw/slavio_serial.c
+++ qemu/hw/slavio_serial.c
@@ -457,7 +457,7 @@ SerialState *slavio_serial_init(int base
 	s->chn[i].type = ser;
 	if (s->chn[i].chr) {
 	    qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
-	    qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
+	    qemu_chr_add_event_handler(s->chn[i].chr, serial_event, &s->chn[i]);
 	}
     }
     s->chn[0].otherchn = &s->chn[1];
Index: qemu/monitor.c
===================================================================
--- qemu.orig/monitor.c
+++ qemu/monitor.c
@@ -84,8 +84,19 @@ void term_puts(const char *str)
             break;
         term_outbuf[term_outbuf_index++] = c;
         if (term_outbuf_index >= sizeof(term_outbuf) ||
-            c == '\n')
+            c == '\n') {
             term_flush();
+            /* Tack on an extra \r when we get \n for correct terminal
+             * emulation mainly for telnet.  Most of the time, the
+             * stdio is attached to some type of controlling terminal
+             * and the xterm and vt1xx emulation will automatically
+             * eat these '\r' chars.
+             */
+            if (c == '\n')
+            {
+                term_outbuf[term_outbuf_index++] = '\r';
+            }
+        }
     }
 }
 
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h
+++ qemu/vl.h
@@ -269,6 +269,7 @@ typedef struct CharDriverState {
     void (*chr_send_event)(struct CharDriverState *chr, int event);
     void (*chr_close)(struct CharDriverState *chr);
     void *opaque;
+    void *event_opaque;
 } CharDriverState;
 
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
@@ -277,7 +278,8 @@ void qemu_chr_send_event(CharDriverState
 void qemu_chr_add_read_handler(CharDriverState *s, 
                                IOCanRWHandler *fd_can_read, 
                                IOReadHandler *fd_read, void *opaque);
-void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event);
+void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event,
+                                void *event_opaque);
 int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
 
 /* consoles */
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi
+++ qemu/qemu-doc.texi
@@ -579,6 +579,18 @@ MAGIC_SYSRQ sequence if you use a telnet
 sequence.  Typically in unix telnet you do it with Control-] and then
 type "send break" followed by pressing the enter key.
 
+@item mon:dev_string
+This is a special option to allow the monitor to be multiplexed onto
+another serial port.  The monitor is accessed with key sequence of
+@key{Control-a} and then pressing @key{c}. See monitor accesc
+@ref{pcsys_keys} in the -nographic section for more keys.
+@var{dev_string} should be any one of the serial devices specified
+above.  An example to multiplex the monitor onto a server telnet server
+listening on port 4444 would be:
+@table @code
+@item -serial mon:telnet::4444,server,nowait
+@end table
+
 @end table
 
 @item -parallel dev
@@ -596,6 +608,19 @@ serial port).
 The default device is @code{vc} in graphical mode and @code{stdio} in
 non graphical mode.
 
+@item -echr numeric_ascii_value
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing.  The default is @code{0x01} when using the
+@code{-nographic} option.  @code{0x01} is equal to pressing
+@code{Control-a}.  You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z.  For
+instance you could use the either of the following to change the escape
+character to Control-t.
+@table @code
+@item -echr 0x14
+@item -echr 20
+@end table
+
 @item -s
 Wait gdb connection to port 1234 (@pxref{gdb_usage}). 
 @item -p port

[-- Attachment #3: qemu_monitor_abstraction.patch --]
[-- Type: text/plain, Size: 10891 bytes --]

Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -1238,9 +1238,9 @@ static int mux_proc_byte(CharDriverState
             break;
         case 'c':
             /* Switch to the next registered device */
-            d->idx++;
-            if (d->idx >= d->mux_cnt)
-                d->idx = 0;
+            chr->focus++;
+            if (chr->focus >= d->mux_cnt)
+                chr->focus = 0;
             break;
         }
     } else if (ch == term_escape_char) {
@@ -1256,7 +1256,7 @@ static int mux_chr_fd_can_read(void *opa
 {
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
-    return d->fd_can_read[d->idx](d->ext_opaque[d->idx]);
+    return d->fd_can_read[chr->focus](d->ext_opaque[chr->focus]);
 }
 
 static void mux_chr_fd_read(void *opaque, const uint8_t *buf, int size)
@@ -1266,7 +1266,7 @@ static void mux_chr_fd_read(void *opaque
     int i;
     for(i = 0; i < size; i++)
         if (mux_proc_byte(chr, d, buf[i]))
-            d->fd_read[d->idx](d->ext_opaque[d->idx], &buf[i], 1);
+            d->fd_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1);
 }
 
 static void mux_chr_add_read_handler(CharDriverState *chr,
@@ -1287,7 +1287,7 @@ static void mux_chr_add_read_handler(Cha
         d->drv->chr_add_read_handler(d->drv,
                                      mux_chr_fd_can_read,
                                      mux_chr_fd_read, chr);
-    d->idx = d->mux_cnt;
+    chr->focus = d->mux_cnt;
     d->mux_cnt++;
 }
 
@@ -1307,7 +1307,7 @@ CharDriverState *qemu_chr_open_mux(CharD
 
     chr->opaque = d;
     d->drv = drv;
-    d->idx = -1;
+    chr->focus = -1;
     chr->chr_write = mux_chr_write;
     chr->chr_add_read_handler = mux_chr_add_read_handler;
     return chr;
@@ -1408,10 +1408,8 @@ typedef struct {
     int max_size;
 } FDCharDriver;
 
-#define STDIO_MAX_CLIENTS 2
-
-static int stdio_nb_clients;
-static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
 
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -1512,118 +1510,41 @@ CharDriverState *qemu_chr_open_pipe(cons
 
 #define TERM_FIFO_MAX_SIZE 1
 
-static int term_got_escape, client_index;
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
 int term_fifo_size;
 
-void term_print_help(void)
-{
-    printf("\n"
-           "C-a h    print this help\n"
-           "C-a x    exit emulator\n"
-           "C-a s    save disk data back to file (if -snapshot)\n"
-           "C-a b    send break (magic sysrq)\n"
-           "C-a c    switch between console and monitor\n"
-           "C-a C-a  send C-a\n"
-           );
-}
-
-/* called when a char is received */
-static void stdio_received_byte(int ch)
-{
-    if (term_got_escape) {
-        term_got_escape = 0;
-        if (ch == term_escape_char)
-            goto send_char;
-        switch(ch) {
-        case 'h':
-            term_print_help();
-            break;
-        case 'x':
-            exit(0);
-            break;
-        case 's': 
-            {
-                int i;
-                for (i = 0; i < MAX_DISKS; i++) {
-                    if (bs_table[i])
-                        bdrv_commit(bs_table[i]);
-                }
-            }
-            break;
-        case 'b':
-            if (client_index < stdio_nb_clients) {
-                CharDriverState *chr;
-                FDCharDriver *s;
-
-                chr = stdio_clients[client_index];
-                s = chr->opaque;
-                chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
-            }
-            break;
-        case 'c':
-            client_index++;
-            if (client_index >= stdio_nb_clients)
-                client_index = 0;
-            if (client_index == 0) {
-                /* send a new line in the monitor to get the prompt */
-                ch = '\r';
-                goto send_char;
-            }
-            break;
-        }
-    } else if (ch == term_escape_char) {
-        term_got_escape = 1;
-    } else {
-    send_char:
-        if (client_index < stdio_nb_clients) {
-            uint8_t buf[1];
-            CharDriverState *chr;
-            FDCharDriver *s;
-            
-            chr = stdio_clients[client_index];
-            s = chr->opaque;
-            if (s->fd_can_read(s->fd_opaque) > 0) {
-                buf[0] = ch;
-                s->fd_read(s->fd_opaque, buf, 1);
-            } else if (term_fifo_size == 0) {
-                term_fifo[term_fifo_size++] = ch;
-            }
-        }
-    }
-}
-
 static int stdio_read_poll(void *opaque)
 {
-    CharDriverState *chr;
-    FDCharDriver *s;
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
 
-    if (client_index < stdio_nb_clients) {
-        chr = stdio_clients[client_index];
-        s = chr->opaque;
-        /* try to flush the queue if needed */
-        if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) {
-            s->fd_read(s->fd_opaque, term_fifo, 1);
-            term_fifo_size = 0;
-        }
-        /* see if we can absorb more chars */
-        if (term_fifo_size == 0)
-            return 1;
-        else
-            return 0;
-    } else {
-        return 1;
+    /* try to flush the queue if needed */
+    if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) {
+        s->fd_read(s->fd_opaque, term_fifo, 1);
+        term_fifo_size = 0;
     }
+    /* see if we can absorb more chars */
+    if (term_fifo_size == 0)
+        return 1;
+    else
+        return 0;
 }
 
 static void stdio_read(void *opaque)
 {
     int size;
     uint8_t buf[1];
-    
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+
     size = read(0, buf, 1);
-    if (size > 0)
-        stdio_received_byte(buf[0]);
+    if (size > 0) {
+        if (s->fd_can_read(s->fd_opaque) > 0) {
+            s->fd_read(s->fd_opaque, buf, 1);
+        } else if (term_fifo_size == 0) {
+            term_fifo[term_fifo_size++] = buf[0];
+        }
+    }
 }
 
 /* init terminal so that we can grab keys */
@@ -1667,23 +1588,13 @@ CharDriverState *qemu_chr_open_stdio(voi
 {
     CharDriverState *chr;
 
-    if (nographic) {
-        if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-            return NULL;
-        chr = qemu_chr_open_fd(0, 1);
-        if (stdio_nb_clients == 0)
-            qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
-        client_index = stdio_nb_clients;
-    } else {
-        if (stdio_nb_clients != 0)
-            return NULL;
-        chr = qemu_chr_open_fd(0, 1);
-    }
-    stdio_clients[stdio_nb_clients++] = chr;
-    if (stdio_nb_clients == 1) {
-        /* set the terminal in raw mode */
-        term_init();
-    }
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+        return NULL;
+    chr = qemu_chr_open_fd(0, 1);
+    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+    stdio_nb_clients++;
+    term_init();
+
     return chr;
 }
 
@@ -5957,8 +5868,8 @@ int main(int argc, char **argv)
                 }
                 break;
             case QEMU_OPTION_nographic:
-                pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
                 pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
+                pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
                 nographic = 1;
                 break;
             case QEMU_OPTION_kernel:
@@ -6324,10 +6235,20 @@ int main(int argc, char **argv)
 #endif
     }
 
-    for (i = 0; i < MAX_SERIAL_PORTS; i++)
-        if (!strncmp(serial_devices[i],"mon:",4))
-            break;
-    if (i >= MAX_SERIAL_PORTS) {
+    /* Maintain compatibility with multiple stdio monitors */
+    if (!strcmp(monitor_device,"stdio")) {
+        for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+            if (!strcmp(serial_devices[i],"mon:stdio")) {
+                monitor_device[0] = '\0';
+                break;
+            } else if (!strcmp(serial_devices[i],"stdio")) {
+                monitor_device[0] = '\0';
+                pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio");
+                break;
+            }
+        }
+    }
+    if (monitor_device[0] != '\0') {
         monitor_hd = qemu_chr_open(monitor_device);
         if (!monitor_hd) {
             fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
Index: qemu/monitor.c
===================================================================
--- qemu.orig/monitor.c
+++ qemu/monitor.c
@@ -54,7 +54,8 @@ typedef struct term_cmd_t {
     const char *help;
 } term_cmd_t;
 
-static CharDriverState *monitor_hd;
+#define MAX_MON 4
+static CharDriverState *monitor_hd[MAX_MON];
 
 static term_cmd_t term_cmds[];
 static term_cmd_t info_cmds[];
@@ -68,8 +69,11 @@ CPUState *mon_cpu = NULL;
 
 void term_flush(void)
 {
+    int i;
     if (term_outbuf_index > 0) {
-        qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
         term_outbuf_index = 0;
     }
 }
@@ -2295,9 +2299,24 @@ static void monitor_start_input(void)
     readline_start("(qemu) ", 0, monitor_handle_command1, NULL);
 }
 
+static int is_first_init = 1;
+
 void monitor_init(CharDriverState *hd, int show_banner)
 {
-    monitor_hd = hd;
+    int i;
+
+    if (is_first_init) {
+        for (i = 0; i < MAX_MON; i++) {
+            monitor_hd[i] = NULL;
+        }
+        is_first_init = 0;
+    }
+    for (i = 0; i < MAX_MON; i++) {
+        if (monitor_hd[i] == NULL) {
+            monitor_hd[i] = hd;
+            break;
+        }
+    }
     if (show_banner) {
         term_printf("QEMU %s monitor - type 'help' for more information\n",
                     QEMU_VERSION);
@@ -2321,8 +2340,12 @@ static void monitor_readline_cb(void *op
 void monitor_readline(const char *prompt, int is_password,
                       char *buf, int buf_size)
 {
+    int i;
+
     if (is_password) {
-        qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS);
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS);
     }
     readline_start(prompt, is_password, monitor_readline_cb, NULL);
     monitor_readline_buf = buf;
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h
+++ qemu/vl.h
@@ -270,6 +270,7 @@ typedef struct CharDriverState {
     void (*chr_close)(struct CharDriverState *chr);
     void *opaque;
     void *event_opaque;
+    int focus;
 } CharDriverState;
 
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Qemu-devel] [PATCH] add serial port mux for debug monitor support
  2006-07-01 20:24 [Qemu-devel] [PATCH] add serial port mux for debug monitor support Jason Wessel
@ 2006-07-02 12:41 ` Jason Wessel
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Wessel @ 2006-07-02 12:41 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1347 bytes --]

Following up to my last patch, I noticed a break; statement was missing 
and cause a bit of a problem with the -echr option.

Fix is attached.

signed-off-by: jason.wessel@windriver.com

Jason Wessel wrote:
> There are two patches attached to show the logical progress of the 
> code and in the case that one is not accepted the work is more easily 
> broken down.
>
> The serial_mux_driver.patch must be applied first.  It adds a generic 
> mux support for the I/O drivers internal to vl.c.  The main purpose is 
> to use it for switching on the monitor.  Basically it allows more than 
> one driver to register an fd_read and fd_can_read routine.  Of course 
> the mux support is generic and could easily be used for other sorts of 
> I/O.  This patch also adds the new options:
>
> -echr ascii_value -- Allow you to use a different control character 
> other than Control-a
> -serial mon:device_string  -- Multiplex the device_string with the 
> monitor functionality
>
> The second patch fully abstracts the monitor so that the monitor can 
> be used on more than one serial port at the same time as well as 
> having a separate dedicated monitor.  I also removed the stdio 
> splitting from the stdio driver.  The mux driver can be used to 
> replace any functionality that I missed.
>
> signed-off-by: jason.wessel@windriver.com
>
> Jason.


[-- Attachment #2: missing_break.patch --]
[-- Type: text/plain, Size: 492 bytes --]

Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -6036,6 +6036,7 @@ int main(int argc, char **argv)
                     term_escape_char = strtol(optarg, &r, 0);
                     if (r == optarg)
                         printf("Bad argument to echr\n");
+                    break;
                 }
             case QEMU_OPTION_monitor:
                 pstrcpy(monitor_device, sizeof(monitor_device), optarg);

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-07-02 12:42 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-01 20:24 [Qemu-devel] [PATCH] add serial port mux for debug monitor support Jason Wessel
2006-07-02 12:41 ` Jason Wessel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).