Commit 20d8a3edb062c96f9a08ccf0637f76ae2563c5e1
1 parent
925fd0f2
Monitor multiplexing, by Jason Wessel.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2434 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
335 additions
and
166 deletions
monitor.c
... | ... | @@ -54,7 +54,8 @@ typedef struct term_cmd_t { |
54 | 54 | const char *help; |
55 | 55 | } term_cmd_t; |
56 | 56 | |
57 | -static CharDriverState *monitor_hd; | |
57 | +#define MAX_MON 4 | |
58 | +static CharDriverState *monitor_hd[MAX_MON]; | |
58 | 59 | static int hide_banner; |
59 | 60 | |
60 | 61 | static term_cmd_t term_cmds[]; |
... | ... | @@ -69,8 +70,11 @@ CPUState *mon_cpu = NULL; |
69 | 70 | |
70 | 71 | void term_flush(void) |
71 | 72 | { |
73 | + int i; | |
72 | 74 | if (term_outbuf_index > 0) { |
73 | - qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); | |
75 | + for (i = 0; i < MAX_MON; i++) | |
76 | + if (monitor_hd[i] && monitor_hd[i]->focus == 0) | |
77 | + qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index); | |
74 | 78 | term_outbuf_index = 0; |
75 | 79 | } |
76 | 80 | } |
... | ... | @@ -2452,9 +2456,25 @@ static void term_event(void *opaque, int event) |
2452 | 2456 | monitor_start_input(); |
2453 | 2457 | } |
2454 | 2458 | |
2459 | +static int is_first_init = 1; | |
2460 | + | |
2455 | 2461 | void monitor_init(CharDriverState *hd, int show_banner) |
2456 | 2462 | { |
2457 | - monitor_hd = hd; | |
2463 | + int i; | |
2464 | + | |
2465 | + if (is_first_init) { | |
2466 | + for (i = 0; i < MAX_MON; i++) { | |
2467 | + monitor_hd[i] = NULL; | |
2468 | + } | |
2469 | + is_first_init = 0; | |
2470 | + } | |
2471 | + for (i = 0; i < MAX_MON; i++) { | |
2472 | + if (monitor_hd[i] == NULL) { | |
2473 | + monitor_hd[i] = hd; | |
2474 | + break; | |
2475 | + } | |
2476 | + } | |
2477 | + | |
2458 | 2478 | hide_banner = !show_banner; |
2459 | 2479 | |
2460 | 2480 | qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); |
... | ... | @@ -2475,8 +2495,12 @@ static void monitor_readline_cb(void *opaque, const char *input) |
2475 | 2495 | void monitor_readline(const char *prompt, int is_password, |
2476 | 2496 | char *buf, int buf_size) |
2477 | 2497 | { |
2498 | + int i; | |
2499 | + | |
2478 | 2500 | if (is_password) { |
2479 | - qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); | |
2501 | + for (i = 0; i < MAX_MON; i++) | |
2502 | + if (monitor_hd[i] && monitor_hd[i]->focus == 0) | |
2503 | + qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS); | |
2480 | 2504 | } |
2481 | 2505 | readline_start(prompt, is_password, monitor_readline_cb, NULL); |
2482 | 2506 | monitor_readline_buf = buf; | ... | ... |
qemu-doc.texi
... | ... | @@ -610,6 +610,18 @@ A unix domain socket is used instead of a tcp socket. The option works the |
610 | 610 | same as if you had specified @code{-serial tcp} except the unix domain socket |
611 | 611 | @var{path} is used for connections. |
612 | 612 | |
613 | +@item mon:dev_string | |
614 | +This is a special option to allow the monitor to be multiplexed onto | |
615 | +another serial port. The monitor is accessed with key sequence of | |
616 | +@key{Control-a} and then pressing @key{c}. See monitor access | |
617 | +@ref{pcsys_keys} in the -nographic section for more keys. | |
618 | +@var{dev_string} should be any one of the serial devices specified | |
619 | +above. An example to multiplex the monitor onto a telnet server | |
620 | +listening on port 4444 would be: | |
621 | +@table @code | |
622 | +@item -serial mon:telnet::4444,server,nowait | |
623 | +@end table | |
624 | + | |
613 | 625 | @end table |
614 | 626 | |
615 | 627 | @item -parallel dev |
... | ... | @@ -629,6 +641,19 @@ serial port). |
629 | 641 | The default device is @code{vc} in graphical mode and @code{stdio} in |
630 | 642 | non graphical mode. |
631 | 643 | |
644 | +@item -echr numeric_ascii_value | |
645 | +Change the escape character used for switching to the monitor when using | |
646 | +monitor and serial sharing. The default is @code{0x01} when using the | |
647 | +@code{-nographic} option. @code{0x01} is equal to pressing | |
648 | +@code{Control-a}. You can select a different character from the ascii | |
649 | +control keys where 1 through 26 map to Control-a through Control-z. For | |
650 | +instance you could use the either of the following to change the escape | |
651 | +character to Control-t. | |
652 | +@table @code | |
653 | +@item -echr 0x14 | |
654 | +@item -echr 20 | |
655 | +@end table | |
656 | + | |
632 | 657 | @item -s |
633 | 658 | Wait gdb connection to port 1234 (@pxref{gdb_usage}). |
634 | 659 | @item -p port |
... | ... | @@ -711,6 +736,8 @@ Print this help |
711 | 736 | Exit emulator |
712 | 737 | @item Ctrl-a s |
713 | 738 | Save disk data back to file (if -snapshot) |
739 | +@item Ctrl-a t | |
740 | +toggle console timestamps | |
714 | 741 | @item Ctrl-a b |
715 | 742 | Send break (magic sysrq in Linux) |
716 | 743 | @item Ctrl-a c | ... | ... |
vl.c
... | ... | @@ -1228,6 +1228,218 @@ static CharDriverState *qemu_chr_open_null(void) |
1228 | 1228 | return chr; |
1229 | 1229 | } |
1230 | 1230 | |
1231 | +/* MUX driver for serial I/O splitting */ | |
1232 | +static int term_timestamps; | |
1233 | +static int64_t term_timestamps_start; | |
1234 | +#define MAX_MUX 2 | |
1235 | +typedef struct { | |
1236 | + IOCanRWHandler *chr_can_read[MAX_MUX]; | |
1237 | + IOReadHandler *chr_read[MAX_MUX]; | |
1238 | + IOEventHandler *chr_event[MAX_MUX]; | |
1239 | + void *ext_opaque[MAX_MUX]; | |
1240 | + CharDriverState *drv; | |
1241 | + int mux_cnt; | |
1242 | + int term_got_escape; | |
1243 | + int max_size; | |
1244 | +} MuxDriver; | |
1245 | + | |
1246 | + | |
1247 | +static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) | |
1248 | +{ | |
1249 | + MuxDriver *d = chr->opaque; | |
1250 | + int ret; | |
1251 | + if (!term_timestamps) { | |
1252 | + ret = d->drv->chr_write(d->drv, buf, len); | |
1253 | + } else { | |
1254 | + int i; | |
1255 | + | |
1256 | + ret = 0; | |
1257 | + for(i = 0; i < len; i++) { | |
1258 | + ret += d->drv->chr_write(d->drv, buf+i, 1); | |
1259 | + if (buf[i] == '\n') { | |
1260 | + char buf1[64]; | |
1261 | + int64_t ti; | |
1262 | + int secs; | |
1263 | + | |
1264 | + ti = get_clock(); | |
1265 | + if (term_timestamps_start == -1) | |
1266 | + term_timestamps_start = ti; | |
1267 | + ti -= term_timestamps_start; | |
1268 | + secs = ti / 1000000000; | |
1269 | + snprintf(buf1, sizeof(buf1), | |
1270 | + "[%02d:%02d:%02d.%03d] ", | |
1271 | + secs / 3600, | |
1272 | + (secs / 60) % 60, | |
1273 | + secs % 60, | |
1274 | + (int)((ti / 1000000) % 1000)); | |
1275 | + d->drv->chr_write(d->drv, buf1, strlen(buf1)); | |
1276 | + } | |
1277 | + } | |
1278 | + } | |
1279 | + return ret; | |
1280 | +} | |
1281 | + | |
1282 | +static char *mux_help[] = { | |
1283 | + "% h print this help\n\r", | |
1284 | + "% x exit emulator\n\r", | |
1285 | + "% s save disk data back to file (if -snapshot)\n\r", | |
1286 | + "% t toggle console timestamps\n\r" | |
1287 | + "% b send break (magic sysrq)\n\r", | |
1288 | + "% c switch between console and monitor\n\r", | |
1289 | + "% % sends %\n\r", | |
1290 | + NULL | |
1291 | +}; | |
1292 | + | |
1293 | +static int term_escape_char = 0x01; /* ctrl-a is used for escape */ | |
1294 | +static void mux_print_help(CharDriverState *chr) | |
1295 | +{ | |
1296 | + int i, j; | |
1297 | + char ebuf[15] = "Escape-Char"; | |
1298 | + char cbuf[50] = "\n\r"; | |
1299 | + | |
1300 | + if (term_escape_char > 0 && term_escape_char < 26) { | |
1301 | + sprintf(cbuf,"\n\r"); | |
1302 | + sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a'); | |
1303 | + } else { | |
1304 | + sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char); | |
1305 | + } | |
1306 | + chr->chr_write(chr, cbuf, strlen(cbuf)); | |
1307 | + for (i = 0; mux_help[i] != NULL; i++) { | |
1308 | + for (j=0; mux_help[i][j] != '\0'; j++) { | |
1309 | + if (mux_help[i][j] == '%') | |
1310 | + chr->chr_write(chr, ebuf, strlen(ebuf)); | |
1311 | + else | |
1312 | + chr->chr_write(chr, &mux_help[i][j], 1); | |
1313 | + } | |
1314 | + } | |
1315 | +} | |
1316 | + | |
1317 | +static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) | |
1318 | +{ | |
1319 | + if (d->term_got_escape) { | |
1320 | + d->term_got_escape = 0; | |
1321 | + if (ch == term_escape_char) | |
1322 | + goto send_char; | |
1323 | + switch(ch) { | |
1324 | + case '?': | |
1325 | + case 'h': | |
1326 | + mux_print_help(chr); | |
1327 | + break; | |
1328 | + case 'x': | |
1329 | + { | |
1330 | + char *term = "QEMU: Terminated\n\r"; | |
1331 | + chr->chr_write(chr,term,strlen(term)); | |
1332 | + exit(0); | |
1333 | + break; | |
1334 | + } | |
1335 | + case 's': | |
1336 | + { | |
1337 | + int i; | |
1338 | + for (i = 0; i < MAX_DISKS; i++) { | |
1339 | + if (bs_table[i]) | |
1340 | + bdrv_commit(bs_table[i]); | |
1341 | + } | |
1342 | + } | |
1343 | + break; | |
1344 | + case 'b': | |
1345 | + if (chr->chr_event) | |
1346 | + chr->chr_event(chr->opaque, CHR_EVENT_BREAK); | |
1347 | + break; | |
1348 | + case 'c': | |
1349 | + /* Switch to the next registered device */ | |
1350 | + chr->focus++; | |
1351 | + if (chr->focus >= d->mux_cnt) | |
1352 | + chr->focus = 0; | |
1353 | + break; | |
1354 | + case 't': | |
1355 | + term_timestamps = !term_timestamps; | |
1356 | + term_timestamps_start = -1; | |
1357 | + break; | |
1358 | + } | |
1359 | + } else if (ch == term_escape_char) { | |
1360 | + d->term_got_escape = 1; | |
1361 | + } else { | |
1362 | + send_char: | |
1363 | + return 1; | |
1364 | + } | |
1365 | + return 0; | |
1366 | +} | |
1367 | + | |
1368 | +static int mux_chr_can_read(void *opaque) | |
1369 | +{ | |
1370 | + CharDriverState *chr = opaque; | |
1371 | + MuxDriver *d = chr->opaque; | |
1372 | + if (d->chr_can_read[chr->focus]) | |
1373 | + return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); | |
1374 | + return 0; | |
1375 | +} | |
1376 | + | |
1377 | +static void mux_chr_read(void *opaque, const uint8_t *buf, int size) | |
1378 | +{ | |
1379 | + CharDriverState *chr = opaque; | |
1380 | + MuxDriver *d = chr->opaque; | |
1381 | + int i; | |
1382 | + for(i = 0; i < size; i++) | |
1383 | + if (mux_proc_byte(chr, d, buf[i])) | |
1384 | + d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1); | |
1385 | +} | |
1386 | + | |
1387 | +static void mux_chr_event(void *opaque, int event) | |
1388 | +{ | |
1389 | + CharDriverState *chr = opaque; | |
1390 | + MuxDriver *d = chr->opaque; | |
1391 | + int i; | |
1392 | + | |
1393 | + /* Send the event to all registered listeners */ | |
1394 | + for (i = 0; i < d->mux_cnt; i++) | |
1395 | + if (d->chr_event[i]) | |
1396 | + d->chr_event[i](d->ext_opaque[i], event); | |
1397 | +} | |
1398 | + | |
1399 | +static void mux_chr_update_read_handler(CharDriverState *chr) | |
1400 | +{ | |
1401 | + MuxDriver *d = chr->opaque; | |
1402 | + | |
1403 | + if (d->mux_cnt >= MAX_MUX) { | |
1404 | + fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); | |
1405 | + return; | |
1406 | + } | |
1407 | + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; | |
1408 | + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; | |
1409 | + d->chr_read[d->mux_cnt] = chr->chr_read; | |
1410 | + d->chr_event[d->mux_cnt] = chr->chr_event; | |
1411 | + /* Fix up the real driver with mux routines */ | |
1412 | + if (d->mux_cnt == 0) { | |
1413 | + qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, | |
1414 | + mux_chr_event, chr); | |
1415 | + } | |
1416 | + chr->focus = d->mux_cnt; | |
1417 | + d->mux_cnt++; | |
1418 | +} | |
1419 | + | |
1420 | +CharDriverState *qemu_chr_open_mux(CharDriverState *drv) | |
1421 | +{ | |
1422 | + CharDriverState *chr; | |
1423 | + MuxDriver *d; | |
1424 | + | |
1425 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
1426 | + if (!chr) | |
1427 | + return NULL; | |
1428 | + d = qemu_mallocz(sizeof(MuxDriver)); | |
1429 | + if (!d) { | |
1430 | + free(chr); | |
1431 | + return NULL; | |
1432 | + } | |
1433 | + | |
1434 | + chr->opaque = d; | |
1435 | + d->drv = drv; | |
1436 | + chr->focus = -1; | |
1437 | + chr->chr_write = mux_chr_write; | |
1438 | + chr->chr_update_read_handler = mux_chr_update_read_handler; | |
1439 | + return chr; | |
1440 | +} | |
1441 | + | |
1442 | + | |
1231 | 1443 | #ifdef _WIN32 |
1232 | 1444 | |
1233 | 1445 | static void socket_cleanup(void) |
... | ... | @@ -1319,10 +1531,8 @@ typedef struct { |
1319 | 1531 | int max_size; |
1320 | 1532 | } FDCharDriver; |
1321 | 1533 | |
1322 | -#define STDIO_MAX_CLIENTS 2 | |
1323 | - | |
1324 | -static int stdio_nb_clients; | |
1325 | -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; | |
1534 | +#define STDIO_MAX_CLIENTS 1 | |
1535 | +static int stdio_nb_clients = 0; | |
1326 | 1536 | |
1327 | 1537 | static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) |
1328 | 1538 | { |
... | ... | @@ -1435,162 +1645,45 @@ static CharDriverState *qemu_chr_open_pipe(const char *filename) |
1435 | 1645 | /* for STDIO, we handle the case where several clients use it |
1436 | 1646 | (nographic mode) */ |
1437 | 1647 | |
1438 | -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ | |
1439 | - | |
1440 | 1648 | #define TERM_FIFO_MAX_SIZE 1 |
1441 | 1649 | |
1442 | -static int term_got_escape, client_index; | |
1443 | 1650 | static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; |
1444 | 1651 | static int term_fifo_size; |
1445 | -static int term_timestamps; | |
1446 | -static int64_t term_timestamps_start; | |
1447 | - | |
1448 | -void term_print_help(void) | |
1449 | -{ | |
1450 | - printf("\n" | |
1451 | - "C-a h print this help\n" | |
1452 | - "C-a x exit emulator\n" | |
1453 | - "C-a s save disk data back to file (if -snapshot)\n" | |
1454 | - "C-a b send break (magic sysrq)\n" | |
1455 | - "C-a t toggle console timestamps\n" | |
1456 | - "C-a c switch between console and monitor\n" | |
1457 | - "C-a C-a send C-a\n" | |
1458 | - ); | |
1459 | -} | |
1460 | - | |
1461 | -/* called when a char is received */ | |
1462 | -static void stdio_received_byte(int ch) | |
1463 | -{ | |
1464 | - if (term_got_escape) { | |
1465 | - term_got_escape = 0; | |
1466 | - switch(ch) { | |
1467 | - case 'h': | |
1468 | - term_print_help(); | |
1469 | - break; | |
1470 | - case 'x': | |
1471 | - exit(0); | |
1472 | - break; | |
1473 | - case 's': | |
1474 | - { | |
1475 | - int i; | |
1476 | - for (i = 0; i < MAX_DISKS; i++) { | |
1477 | - if (bs_table[i]) | |
1478 | - bdrv_commit(bs_table[i]); | |
1479 | - } | |
1480 | - } | |
1481 | - break; | |
1482 | - case 'b': | |
1483 | - if (client_index < stdio_nb_clients) { | |
1484 | - CharDriverState *chr; | |
1485 | - FDCharDriver *s; | |
1486 | - | |
1487 | - chr = stdio_clients[client_index]; | |
1488 | - s = chr->opaque; | |
1489 | - qemu_chr_event(chr, CHR_EVENT_BREAK); | |
1490 | - } | |
1491 | - break; | |
1492 | - case 'c': | |
1493 | - client_index++; | |
1494 | - if (client_index >= stdio_nb_clients) | |
1495 | - client_index = 0; | |
1496 | - if (client_index == 0) { | |
1497 | - /* send a new line in the monitor to get the prompt */ | |
1498 | - ch = '\r'; | |
1499 | - goto send_char; | |
1500 | - } | |
1501 | - break; | |
1502 | - case 't': | |
1503 | - term_timestamps = !term_timestamps; | |
1504 | - term_timestamps_start = -1; | |
1505 | - break; | |
1506 | - case TERM_ESCAPE: | |
1507 | - goto send_char; | |
1508 | - } | |
1509 | - } else if (ch == TERM_ESCAPE) { | |
1510 | - term_got_escape = 1; | |
1511 | - } else { | |
1512 | - send_char: | |
1513 | - if (client_index < stdio_nb_clients) { | |
1514 | - uint8_t buf[1]; | |
1515 | - CharDriverState *chr; | |
1516 | - | |
1517 | - chr = stdio_clients[client_index]; | |
1518 | - if (qemu_chr_can_read(chr) > 0) { | |
1519 | - buf[0] = ch; | |
1520 | - qemu_chr_read(chr, buf, 1); | |
1521 | - } else if (term_fifo_size == 0) { | |
1522 | - term_fifo[term_fifo_size++] = ch; | |
1523 | - } | |
1524 | - } | |
1525 | - } | |
1526 | -} | |
1527 | 1652 | |
1528 | 1653 | static int stdio_read_poll(void *opaque) |
1529 | 1654 | { |
1530 | - CharDriverState *chr; | |
1655 | + CharDriverState *chr = opaque; | |
1531 | 1656 | |
1532 | - if (client_index < stdio_nb_clients) { | |
1533 | - chr = stdio_clients[client_index]; | |
1534 | - /* try to flush the queue if needed */ | |
1535 | - if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { | |
1536 | - qemu_chr_read(chr, term_fifo, 1); | |
1537 | - term_fifo_size = 0; | |
1538 | - } | |
1539 | - /* see if we can absorb more chars */ | |
1540 | - if (term_fifo_size == 0) | |
1541 | - return 1; | |
1542 | - else | |
1543 | - return 0; | |
1544 | - } else { | |
1545 | - return 1; | |
1657 | + /* try to flush the queue if needed */ | |
1658 | + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { | |
1659 | + qemu_chr_read(chr, term_fifo, 1); | |
1660 | + term_fifo_size = 0; | |
1546 | 1661 | } |
1662 | + /* see if we can absorb more chars */ | |
1663 | + if (term_fifo_size == 0) | |
1664 | + return 1; | |
1665 | + else | |
1666 | + return 0; | |
1547 | 1667 | } |
1548 | 1668 | |
1549 | 1669 | static void stdio_read(void *opaque) |
1550 | 1670 | { |
1551 | 1671 | int size; |
1552 | 1672 | uint8_t buf[1]; |
1553 | - | |
1673 | + CharDriverState *chr = opaque; | |
1674 | + | |
1554 | 1675 | size = read(0, buf, 1); |
1555 | 1676 | if (size == 0) { |
1556 | 1677 | /* stdin has been closed. Remove it from the active list. */ |
1557 | 1678 | qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); |
1558 | 1679 | return; |
1559 | 1680 | } |
1560 | - if (size > 0) | |
1561 | - stdio_received_byte(buf[0]); | |
1562 | -} | |
1563 | - | |
1564 | -static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len) | |
1565 | -{ | |
1566 | - FDCharDriver *s = chr->opaque; | |
1567 | - if (!term_timestamps) { | |
1568 | - return unix_write(s->fd_out, buf, len); | |
1569 | - } else { | |
1570 | - int i; | |
1571 | - char buf1[64]; | |
1572 | - | |
1573 | - for(i = 0; i < len; i++) { | |
1574 | - unix_write(s->fd_out, buf + i, 1); | |
1575 | - if (buf[i] == '\n') { | |
1576 | - int64_t ti; | |
1577 | - int secs; | |
1578 | - | |
1579 | - ti = get_clock(); | |
1580 | - if (term_timestamps_start == -1) | |
1581 | - term_timestamps_start = ti; | |
1582 | - ti -= term_timestamps_start; | |
1583 | - secs = ti / 1000000000; | |
1584 | - snprintf(buf1, sizeof(buf1), | |
1585 | - "[%02d:%02d:%02d.%03d] ", | |
1586 | - secs / 3600, | |
1587 | - (secs / 60) % 60, | |
1588 | - secs % 60, | |
1589 | - (int)((ti / 1000000) % 1000)); | |
1590 | - unix_write(s->fd_out, buf1, strlen(buf1)); | |
1591 | - } | |
1681 | + if (size > 0) { | |
1682 | + if (qemu_chr_can_read(chr) > 0) { | |
1683 | + qemu_chr_read(chr, buf, 1); | |
1684 | + } else if (term_fifo_size == 0) { | |
1685 | + term_fifo[term_fifo_size++] = buf[0]; | |
1592 | 1686 | } |
1593 | - return len; | |
1594 | 1687 | } |
1595 | 1688 | } |
1596 | 1689 | |
... | ... | @@ -1635,24 +1728,13 @@ static CharDriverState *qemu_chr_open_stdio(void) |
1635 | 1728 | { |
1636 | 1729 | CharDriverState *chr; |
1637 | 1730 | |
1638 | - if (nographic) { | |
1639 | - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) | |
1640 | - return NULL; | |
1641 | - chr = qemu_chr_open_fd(0, 1); | |
1642 | - chr->chr_write = stdio_write; | |
1643 | - if (stdio_nb_clients == 0) | |
1644 | - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); | |
1645 | - client_index = stdio_nb_clients; | |
1646 | - } else { | |
1647 | - if (stdio_nb_clients != 0) | |
1648 | - return NULL; | |
1649 | - chr = qemu_chr_open_fd(0, 1); | |
1650 | - } | |
1651 | - stdio_clients[stdio_nb_clients++] = chr; | |
1652 | - if (stdio_nb_clients == 1) { | |
1653 | - /* set the terminal in raw mode */ | |
1654 | - term_init(); | |
1655 | - } | |
1731 | + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) | |
1732 | + return NULL; | |
1733 | + chr = qemu_chr_open_fd(0, 1); | |
1734 | + qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); | |
1735 | + stdio_nb_clients++; | |
1736 | + term_init(); | |
1737 | + | |
1656 | 1738 | return chr; |
1657 | 1739 | } |
1658 | 1740 | |
... | ... | @@ -2815,6 +2897,16 @@ CharDriverState *qemu_chr_open(const char *filename) |
2815 | 2897 | if (strstart(filename, "udp:", &p)) { |
2816 | 2898 | return qemu_chr_open_udp(p); |
2817 | 2899 | } else |
2900 | + if (strstart(filename, "mon:", &p)) { | |
2901 | + CharDriverState *drv = qemu_chr_open(p); | |
2902 | + if (drv) { | |
2903 | + drv = qemu_chr_open_mux(drv); | |
2904 | + monitor_init(drv, !nographic); | |
2905 | + return drv; | |
2906 | + } | |
2907 | + printf("Unable to open driver: %s\n", p); | |
2908 | + return 0; | |
2909 | + } else | |
2818 | 2910 | #ifndef _WIN32 |
2819 | 2911 | if (strstart(filename, "unix:", &p)) { |
2820 | 2912 | return qemu_chr_open_tcp(p, 0, 1); |
... | ... | @@ -6416,6 +6508,7 @@ enum { |
6416 | 6508 | QEMU_OPTION_cirrusvga, |
6417 | 6509 | QEMU_OPTION_g, |
6418 | 6510 | QEMU_OPTION_std_vga, |
6511 | + QEMU_OPTION_echr, | |
6419 | 6512 | QEMU_OPTION_monitor, |
6420 | 6513 | QEMU_OPTION_serial, |
6421 | 6514 | QEMU_OPTION_parallel, |
... | ... | @@ -6497,6 +6590,7 @@ const QEMUOption qemu_options[] = { |
6497 | 6590 | #endif |
6498 | 6591 | { "localtime", 0, QEMU_OPTION_localtime }, |
6499 | 6592 | { "std-vga", 0, QEMU_OPTION_std_vga }, |
6593 | + { "echr", 1, QEMU_OPTION_echr }, | |
6500 | 6594 | { "monitor", 1, QEMU_OPTION_monitor }, |
6501 | 6595 | { "serial", 1, QEMU_OPTION_serial }, |
6502 | 6596 | { "parallel", 1, QEMU_OPTION_parallel }, |
... | ... | @@ -6932,8 +7026,8 @@ int main(int argc, char **argv) |
6932 | 7026 | } |
6933 | 7027 | break; |
6934 | 7028 | case QEMU_OPTION_nographic: |
6935 | - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | |
6936 | 7029 | pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); |
7030 | + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | |
6937 | 7031 | nographic = 1; |
6938 | 7032 | break; |
6939 | 7033 | case QEMU_OPTION_kernel: |
... | ... | @@ -7094,6 +7188,14 @@ int main(int argc, char **argv) |
7094 | 7188 | graphic_depth = depth; |
7095 | 7189 | } |
7096 | 7190 | break; |
7191 | + case QEMU_OPTION_echr: | |
7192 | + { | |
7193 | + char *r; | |
7194 | + term_escape_char = strtol(optarg, &r, 0); | |
7195 | + if (r == optarg) | |
7196 | + printf("Bad argument to echr\n"); | |
7197 | + break; | |
7198 | + } | |
7097 | 7199 | case QEMU_OPTION_monitor: |
7098 | 7200 | pstrcpy(monitor_device, sizeof(monitor_device), optarg); |
7099 | 7201 | break; |
... | ... | @@ -7384,12 +7486,27 @@ int main(int argc, char **argv) |
7384 | 7486 | #endif |
7385 | 7487 | } |
7386 | 7488 | |
7387 | - monitor_hd = qemu_chr_open(monitor_device); | |
7388 | - if (!monitor_hd) { | |
7389 | - fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); | |
7390 | - exit(1); | |
7489 | + /* Maintain compatibility with multiple stdio monitors */ | |
7490 | + if (!strcmp(monitor_device,"stdio")) { | |
7491 | + for (i = 0; i < MAX_SERIAL_PORTS; i++) { | |
7492 | + if (!strcmp(serial_devices[i],"mon:stdio")) { | |
7493 | + monitor_device[0] = '\0'; | |
7494 | + break; | |
7495 | + } else if (!strcmp(serial_devices[i],"stdio")) { | |
7496 | + monitor_device[0] = '\0'; | |
7497 | + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio"); | |
7498 | + break; | |
7499 | + } | |
7500 | + } | |
7501 | + } | |
7502 | + if (monitor_device[0] != '\0') { | |
7503 | + monitor_hd = qemu_chr_open(monitor_device); | |
7504 | + if (!monitor_hd) { | |
7505 | + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); | |
7506 | + exit(1); | |
7507 | + } | |
7508 | + monitor_init(monitor_hd, !nographic); | |
7391 | 7509 | } |
7392 | - monitor_init(monitor_hd, !nographic); | |
7393 | 7510 | |
7394 | 7511 | for(i = 0; i < MAX_SERIAL_PORTS; i++) { |
7395 | 7512 | const char *devname = serial_devices[i]; | ... | ... |
vl.h