diff --git a/monitor.c b/monitor.c
index 12a6fe2..3631ef8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -206,6 +206,8 @@ static const mon_cmd_t qmp_cmds[];
 Monitor *cur_mon;
 Monitor *default_mon;
 
+static void monitor_stdio_control_command_cb(Monitor *mon, const char *cmdline,
+                               void *opaque);
 static void monitor_command_cb(Monitor *mon, const char *cmdline,
                                void *opaque);
 
@@ -214,6 +216,11 @@ static inline int qmp_cmd_mode(const Monitor *mon)
     return (mon->mc ? mon->mc->command_mode : 0);
 }
 
+static inline int monitor_readline_mode(const Monitor *mon)
+{
+    return (mon->flags & MONITOR_USE_READLINE);
+}
+
 /* Return true if in control mode, false otherwise */
 static inline int monitor_ctrl_mode(const Monitor *mon)
 {
@@ -226,6 +233,16 @@ int monitor_cur_is_qmp(void)
     return cur_mon && monitor_ctrl_mode(cur_mon);
 }
 
+static void monitor_control_read_command(Monitor *mon, int show_prompt)
+{
+    if (!mon->rs)
+        return;
+
+    readline_start(mon->rs, "", 0, monitor_stdio_control_command_cb, NULL);
+    if (show_prompt)
+        readline_show_prompt(mon->rs);
+}
+
 void monitor_read_command(Monitor *mon, int show_prompt)
 {
     if (!mon->rs)
@@ -287,7 +304,7 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 
     mon_print_count_inc(mon);
 
-    if (monitor_ctrl_mode(mon)) {
+    if (monitor_ctrl_mode(mon) && !monitor_readline_mode(mon)) {
         return;
     }
 
@@ -3975,6 +3992,11 @@ static const char *next_arg_type(const char *typestr)
     return (p != NULL ? ++p : typestr);
 }
 
+static void monitor_control_find_completion(const char *cmdline)
+{
+    /* TODO: to be implemented */
+}
+
 static void monitor_find_completion(const char *cmdline)
 {
     const char *cmdname;
@@ -4431,10 +4453,23 @@ out:
 static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
 {
     Monitor *old_mon = cur_mon;
+    int i;
 
     cur_mon = opaque;
 
-    json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
+    if (monitor_readline_mode(cur_mon)) {
+        if (cur_mon->rs) {
+            for (i = 0; i < size; i++)
+                readline_handle_byte(cur_mon->rs, buf[i]);
+        } else {
+            if (size == 0 || buf[size - 1] != 0)
+                monitor_printf(cur_mon, "corrupted command\n");
+            else
+                json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
+        }
+    } else {
+        json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
+    }
 
     cur_mon = old_mon;
 }
@@ -4459,6 +4494,13 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size)
     cur_mon = old_mon;
 }
 
+static void monitor_stdio_control_command_cb(Monitor *mon, const char *cmdline, void *opaque)
+{
+    monitor_suspend(mon);
+    json_message_parser_feed(&mon->mc->parser, cmdline, strlen(cmdline));
+    monitor_resume(mon);
+}
+
 static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
 {
     monitor_suspend(mon);
@@ -4499,7 +4541,41 @@ static void monitor_control_event(void *opaque, int event)
     Monitor *mon = opaque;
 
     switch (event) {
+    case CHR_EVENT_MUX_IN:
+        if (!monitor_readline_mode(mon))
+            break;
+        mon->mux_out = 0;
+        if (mon->reset_seen) {
+            readline_restart(mon->rs);
+            monitor_resume(mon);
+            monitor_flush(mon);
+        } else {
+            mon->suspend_cnt = 0;
+        }
+        break;
+
+    case CHR_EVENT_MUX_OUT:
+        if (!monitor_readline_mode(mon))
+            break;
+        if (mon->reset_seen) {
+            if (mon->suspend_cnt == 0) {
+                monitor_printf(mon, "\n");
+            }
+            monitor_flush(mon);
+            monitor_suspend(mon);
+        } else {
+            mon->suspend_cnt++;
+        }
+        mon->mux_out = 1;
+        break;
+
     case CHR_EVENT_OPENED:
+        if (monitor_readline_mode(mon)) {
+            mon->reset_seen = 1;
+            if (!mon->mux_out) {
+                readline_show_prompt(mon->rs);
+            }
+        }
         mon->mc->command_mode = 0;
         json_message_parser_init(&mon->mc->parser, handle_qmp_command);
         data = get_qmp_greeting();
@@ -4594,9 +4670,14 @@ void monitor_init(CharDriverState *chr, int flags)
 
     mon->chr = chr;
     mon->flags = flags;
-    if (flags & MONITOR_USE_READLINE) {
-        mon->rs = readline_init(mon, monitor_find_completion);
-        monitor_read_command(mon, 0);
+    if (monitor_readline_mode(mon)) {
+        if (monitor_ctrl_mode(mon)) {
+            mon->rs = readline_init(mon, monitor_control_find_completion);
+            monitor_control_read_command(mon, 0);
+        } else {
+            mon->rs = readline_init(mon, monitor_find_completion);
+            monitor_read_command(mon, 0);
+        }
     }
 
     if (monitor_ctrl_mode(mon)) {
@@ -4604,7 +4685,6 @@ void monitor_init(CharDriverState *chr, int flags)
         /* Control mode requires special handlers */
         qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
                               monitor_control_event, mon);
-        qemu_chr_fe_set_echo(chr, true);
     } else {
         qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
                               monitor_event, mon);
diff --git a/vl.c b/vl.c
index 23ab3a3..5e9c130 100644
--- a/vl.c
+++ b/vl.c
@@ -1894,6 +1894,9 @@ static int mon_init_func(QemuOpts *opts, void *opaque)
         exit(1);
     }
 
+    if ((flags & MONITOR_USE_CONTROL) && strcmp(chr->filename, "stdio") == 0)
+        flags |= MONITOR_USE_READLINE;
+
     monitor_init(chr, flags);
     return 0;
 }
