@samitouri / QOSamiQemu / commits / 8fa294482e

ui/console-vc: move VT100 state machine and output FIFO into QemuVT100

Move the terminal escape sequence parser state (TTYState, esc_params, text attributes, saved cursor position) and the output FIFO from VCChardev/QemuTextConsole into QemuVT100. Rename the corresponding functions from vc_* to vt100_* to reflect they now operate on the VT100 layer directly, removing the indirection through vc->console->vt. Add an out_flush callback to QemuVT100 so vt100_write() can flush output without knowing about QemuTextConsole, and move FIFO/VT100 initialization from qemu_text_console_init() to vc_chr_open() where the callback can be wired up. This continues the decoupling of VT100 terminal emulation from the chardev layer, making QemuVT100 a self-contained terminal emulator. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Marc-André Lureau committed Feb 19, 2026 at 15:10 UTC 8fa294482eb8148ef7278d0b01bfb55f2cf3f227
1 file changed +184 -198
ui/console-vc.c
+184 -198
@@ -58,6 +58,7 @@ struct QemuVT100 {
58 pixman_image_t *image;
59 void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height);
60
61 + ChardevVCEncoding encoding;
62 int width;
63 int height;
64 int total_height;
@@ -74,6 +75,18 @@ struct QemuVT100 {
75 int update_x1;
76 int update_y1;
77
78 + enum TTYState state;
79 + int esc_params[MAX_ESC_PARAMS];
80 + int nb_esc_params;
81 + uint32_t utf8_state; /* UTF-8 DFA decoder state */
82 + uint32_t utf8_codepoint; /* accumulated UTF-8 code point */
83 + TextAttributes t_attrib; /* currently active text attributes */
84 + TextAttributes t_attrib_saved;
85 + int x_saved, y_saved;
86 + /* fifo for key pressed */
87 + Fifo8 out_fifo;
88 + void (*out_flush)(QemuVT100 *vt);
89 +
90 QTAILQ_ENTRY(QemuVT100) list;
91 };
92
@@ -85,8 +98,6 @@ typedef struct QemuTextConsole {
98
99 QemuVT100 vt;
100 Chardev *chr;
88 - /* fifo for key pressed */
89 - Fifo8 out_fifo;
101 } QemuTextConsole;
102
103 typedef QemuConsoleClass QemuTextConsoleClass;
@@ -103,17 +114,9 @@ OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEX
114
115 struct VCChardev {
116 Chardev parent;
106 - QemuTextConsole *console;
117
108 - enum TTYState state;
109 - int esc_params[MAX_ESC_PARAMS];
110 - int nb_esc_params;
111 - uint32_t utf8_state; /* UTF-8 DFA decoder state */
112 - uint32_t utf8_codepoint; /* accumulated UTF-8 code point */
113 - TextAttributes t_attrib; /* currently active text attributes */
114 - TextAttributes t_attrib_saved;
115 - int x_saved, y_saved;
118 ChardevVCEncoding encoding;
119 + QemuTextConsole *console;
120 };
121 typedef struct VCChardev VCChardev;
122
@@ -302,36 +305,35 @@ static void vt100_scroll(QemuVT100 *vt, int ydelta)
305 vt100_refresh(vt);
306 }
307
305 -static void qemu_text_console_flush(QemuTextConsole *s)
308 +static void qemu_text_console_out_flush(QemuTextConsole *s)
309 {
310 uint32_t len, avail;
311
312 len = qemu_chr_be_can_write(s->chr);
310 - avail = fifo8_num_used(&s->out_fifo);
313 + avail = fifo8_num_used(&s->vt.out_fifo);
314 while (len > 0 && avail > 0) {
315 const uint8_t *buf;
316 uint32_t size;
317
315 - buf = fifo8_pop_bufptr(&s->out_fifo, MIN(len, avail), &size);
318 + buf = fifo8_pop_bufptr(&s->vt.out_fifo, MIN(len, avail), &size);
319 qemu_chr_be_write(s->chr, buf, size);
320 len = qemu_chr_be_can_write(s->chr);
321 avail -= size;
322 }
323 }
324
322 -static void qemu_text_console_write(QemuTextConsole *s, const void *buf, size_t len)
325 +static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
326 {
327 uint32_t num_free;
328
326 - num_free = fifo8_num_free(&s->out_fifo);
327 - fifo8_push_all(&s->out_fifo, buf, MIN(num_free, len));
328 - qemu_text_console_flush(s);
329 + num_free = fifo8_num_free(&vt->out_fifo);
330 + fifo8_push_all(&vt->out_fifo, buf, MIN(num_free, len));
331 + vt->out_flush(vt);
332 }
333
334 /* called when an ascii key is pressed */
335 void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
336 {
334 - QemuVT100 *vt = &s->vt;
337 uint8_t buf[16], *q;
338 int c;
339
@@ -363,16 +365,16 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
365 *q++ = '\033';
366 *q++ = '[';
367 *q++ = keysym & 0xff;
366 - } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
368 + } else if (s->vt.echo && (keysym == '\r' || keysym == '\n')) {
369 qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
370 *q++ = '\n';
371 } else {
372 *q++ = keysym;
373 }
372 - if (vt->echo) {
374 + if (s->vt.echo) {
375 qemu_chr_write(s->chr, buf, q - buf, true);
376 }
375 - qemu_text_console_write(s, buf, q - buf);
377 + vt100_write(&s->vt, buf, q - buf);
378 break;
379 }
380 }
@@ -380,30 +382,29 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
382 static void text_console_update(void *opaque, console_ch_t *chardata)
383 {
384 QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
383 - QemuVT100 *vt = &s->vt;
385 int i, j, src;
386
386 - if (vt->text_x[0] <= vt->text_x[1]) {
387 - src = (vt->y_base + vt->text_y[0]) * vt->width;
388 - chardata += vt->text_y[0] * vt->width;
389 - for (i = vt->text_y[0]; i <= vt->text_y[1]; i ++)
390 - for (j = 0; j < vt->width; j++, src++) {
387 + if (s->vt.text_x[0] <= s->vt.text_x[1]) {
388 + src = (s->vt.y_base + s->vt.text_y[0]) * s->vt.width;
389 + chardata += s->vt.text_y[0] * s->vt.width;
390 + for (i = s->vt.text_y[0]; i <= s->vt.text_y[1]; i ++)
391 + for (j = 0; j < s->vt.width; j++, src++) {
392 console_write_ch(chardata ++,
392 - ATTR2CHTYPE(vt->cells[src].ch,
393 - vt->cells[src].t_attrib.fgcol,
394 - vt->cells[src].t_attrib.bgcol,
395 - vt->cells[src].t_attrib.bold));
393 + ATTR2CHTYPE(s->vt.cells[src].ch,
394 + s->vt.cells[src].t_attrib.fgcol,
395 + s->vt.cells[src].t_attrib.bgcol,
396 + s->vt.cells[src].t_attrib.bold));
397 }
397 - dpy_text_update(QEMU_CONSOLE(s), vt->text_x[0], vt->text_y[0],
398 - vt->text_x[1] - vt->text_x[0], i - vt->text_y[0]);
399 - vt->text_x[0] = vt->width;
400 - vt->text_y[0] = vt->height;
401 - vt->text_x[1] = 0;
402 - vt->text_y[1] = 0;
398 + dpy_text_update(QEMU_CONSOLE(s), s->vt.text_x[0], s->vt.text_y[0],
399 + s->vt.text_x[1] - s->vt.text_x[0], i - s->vt.text_y[0]);
400 + s->vt.text_x[0] = s->vt.width;
401 + s->vt.text_y[0] = s->vt.height;
402 + s->vt.text_x[1] = 0;
403 + s->vt.text_y[1] = 0;
404 }
404 - if (vt->cursor_invalidate) {
405 - dpy_text_cursor(QEMU_CONSOLE(s), vt->x, vt->y);
406 - vt->cursor_invalidate = 0;
405 + if (s->vt.cursor_invalidate) {
406 + dpy_text_cursor(QEMU_CONSOLE(s), s->vt.x, s->vt.y);
407 + s->vt.cursor_invalidate = 0;
408 }
409 }
410
@@ -492,103 +493,101 @@ static void vt100_put_lf(QemuVT100 *vt)
493 * NOTE: I know this code is not very efficient (checking every color for it
494 * self) but it is more readable and better maintainable.
495 */
495 -static void vc_handle_escape(VCChardev *vc)
496 +static void vt100_handle_escape(QemuVT100 *vt)
497 {
498 int i;
499
499 - for (i = 0; i < vc->nb_esc_params; i++) {
500 - switch (vc->esc_params[i]) {
500 + for (i = 0; i < vt->nb_esc_params; i++) {
501 + switch (vt->esc_params[i]) {
502 case 0: /* reset all console attributes to default */
502 - vc->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
503 + vt->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
504 break;
505 case 1:
505 - vc->t_attrib.bold = 1;
506 + vt->t_attrib.bold = 1;
507 break;
508 case 4:
508 - vc->t_attrib.uline = 1;
509 + vt->t_attrib.uline = 1;
510 break;
511 case 5:
511 - vc->t_attrib.blink = 1;
512 + vt->t_attrib.blink = 1;
513 break;
514 case 7:
514 - vc->t_attrib.invers = 1;
515 + vt->t_attrib.invers = 1;
516 break;
517 case 8:
517 - vc->t_attrib.unvisible = 1;
518 + vt->t_attrib.unvisible = 1;
519 break;
520 case 22:
520 - vc->t_attrib.bold = 0;
521 + vt->t_attrib.bold = 0;
522 break;
523 case 24:
523 - vc->t_attrib.uline = 0;
524 + vt->t_attrib.uline = 0;
525 break;
526 case 25:
526 - vc->t_attrib.blink = 0;
527 + vt->t_attrib.blink = 0;
528 break;
529 case 27:
529 - vc->t_attrib.invers = 0;
530 + vt->t_attrib.invers = 0;
531 break;
532 case 28:
532 - vc->t_attrib.unvisible = 0;
533 + vt->t_attrib.unvisible = 0;
534 break;
535 /* set foreground color */
536 case 30:
536 - vc->t_attrib.fgcol = QEMU_COLOR_BLACK;
537 + vt->t_attrib.fgcol = QEMU_COLOR_BLACK;
538 break;
539 case 31:
539 - vc->t_attrib.fgcol = QEMU_COLOR_RED;
540 + vt->t_attrib.fgcol = QEMU_COLOR_RED;
541 break;
542 case 32:
542 - vc->t_attrib.fgcol = QEMU_COLOR_GREEN;
543 + vt->t_attrib.fgcol = QEMU_COLOR_GREEN;
544 break;
545 case 33:
545 - vc->t_attrib.fgcol = QEMU_COLOR_YELLOW;
546 + vt->t_attrib.fgcol = QEMU_COLOR_YELLOW;
547 break;
548 case 34:
548 - vc->t_attrib.fgcol = QEMU_COLOR_BLUE;
549 + vt->t_attrib.fgcol = QEMU_COLOR_BLUE;
550 break;
551 case 35:
551 - vc->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
552 + vt->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
553 break;
554 case 36:
554 - vc->t_attrib.fgcol = QEMU_COLOR_CYAN;
555 + vt->t_attrib.fgcol = QEMU_COLOR_CYAN;
556 break;
557 case 37:
557 - vc->t_attrib.fgcol = QEMU_COLOR_WHITE;
558 + vt->t_attrib.fgcol = QEMU_COLOR_WHITE;
559 break;
560 /* set background color */
561 case 40:
561 - vc->t_attrib.bgcol = QEMU_COLOR_BLACK;
562 + vt->t_attrib.bgcol = QEMU_COLOR_BLACK;
563 break;
564 case 41:
564 - vc->t_attrib.bgcol = QEMU_COLOR_RED;
565 + vt->t_attrib.bgcol = QEMU_COLOR_RED;
566 break;
567 case 42:
567 - vc->t_attrib.bgcol = QEMU_COLOR_GREEN;
568 + vt->t_attrib.bgcol = QEMU_COLOR_GREEN;
569 break;
570 case 43:
570 - vc->t_attrib.bgcol = QEMU_COLOR_YELLOW;
571 + vt->t_attrib.bgcol = QEMU_COLOR_YELLOW;
572 break;
573 case 44:
573 - vc->t_attrib.bgcol = QEMU_COLOR_BLUE;
574 + vt->t_attrib.bgcol = QEMU_COLOR_BLUE;
575 break;
576 case 45:
576 - vc->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
577 + vt->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
578 break;
579 case 46:
579 - vc->t_attrib.bgcol = QEMU_COLOR_CYAN;
580 + vt->t_attrib.bgcol = QEMU_COLOR_CYAN;
581 break;
582 case 47:
582 - vc->t_attrib.bgcol = QEMU_COLOR_WHITE;
583 + vt->t_attrib.bgcol = QEMU_COLOR_WHITE;
584 break;
585 }
586 }
587 }
588
588 -static void vc_update_xy(VCChardev *vc, int x, int y)
589 +static void vt100_update_xy(QemuVT100 *vt, int x, int y)
590 {
590 - QemuTextConsole *s = vc->console;
591 - QemuVT100 *vt = &s->vt;
591 TextCell *c;
592 int y1, y2;
593
@@ -609,14 +608,12 @@ static void vc_update_xy(VCChardev *vc, int x, int y)
608 c = &vt->cells[y1 * vt->width + x];
609 vt100_putcharxy(vt, x, y2, c->ch,
610 &(c->t_attrib));
612 - vt100_invalidate_xy(&s->vt, x, y2);
611 + vt100_invalidate_xy(vt, x, y2);
612 }
613 }
614
616 -static void vc_clear_xy(VCChardev *vc, int x, int y)
615 +static void vt100_clear_xy(QemuVT100 *vt, int x, int y)
616 {
618 - QemuTextConsole *s = vc->console;
619 - QemuVT100 *vt = &s->vt;
617 int y1 = (vt->y_base + y) % vt->total_height;
618 if (x >= vt->width) {
619 x = vt->width - 1;
@@ -624,7 +621,7 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
621 TextCell *c = &vt->cells[y1 * vt->width + x];
622 c->ch = ' ';
623 c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
627 - vc_update_xy(vc, x, y);
624 + vt100_update_xy(vt, x, y);
625 }
626
627 /*
@@ -667,10 +664,8 @@ static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
664 return *state;
665 }
666
670 -static void vc_put_one(VCChardev *vc, int ch)
667 +static void vt100_put_one(QemuVT100 *vt, int ch)
668 {
672 - QemuTextConsole *s = vc->console;
673 - QemuVT100 *vt = &s->vt;
669 TextCell *c;
670 int y1;
671 if (vt->x >= vt->width) {
@@ -681,17 +676,14 @@ static void vc_put_one(VCChardev *vc, int ch)
676 y1 = (vt->y_base + vt->y) % vt->total_height;
677 c = &vt->cells[y1 * vt->width + vt->x];
678 c->ch = ch;
684 - c->t_attrib = vc->t_attrib;
685 - vc_update_xy(vc, vt->x, vt->y);
679 + c->t_attrib = vt->t_attrib;
680 + vt100_update_xy(vt, vt->x, vt->y);
681 vt->x++;
682 }
683
684 /* set cursor, checking bounds */
690 -static void vc_set_cursor(VCChardev *vc, int x, int y)
685 +static void vt100_set_cursor(QemuVT100 *vt, int x, int y)
686 {
692 - QemuTextConsole *s = vc->console;
693 - QemuVT100 *vt = &s->vt;
694 -
687 if (x < 0) {
688 x = 0;
689 }
@@ -715,10 +707,8 @@ static void vc_set_cursor(VCChardev *vc, int x, int y)
707 * characters between the cursor and right margin move to the
708 * left. Character attributes move with the characters.
709 */
718 -static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
710 +static void vt100_csi_P(QemuVT100 *vt, unsigned int nr)
711 {
720 - QemuTextConsole *s = vc->console;
721 - QemuVT100 *vt = &s->vt;
712 TextCell *c1, *c2;
713 unsigned int x1, x2, y;
714 unsigned int end, len;
@@ -742,12 +732,12 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
732 c2 = &vt->cells[y * vt->width + x2];
733 memmove(c1, c2, len * sizeof(*c1));
734 for (end = x1 + len; x1 < end; x1++) {
745 - vc_update_xy(vc, x1, vt->y);
735 + vt100_update_xy(vt, x1, vt->y);
736 }
737 }
738 /* Clear the rest */
739 for (; x1 < vt->width; x1++) {
750 - vc_clear_xy(vc, x1, vt->y);
740 + vt100_clear_xy(vt, x1, vt->y);
741 }
742 }
743
@@ -757,10 +747,8 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
747 * blank characters. Text between the cursor and right margin moves to
748 * the right. Characters scrolled past the right margin are lost.
749 */
760 -static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
750 +static void vt100_csi_at(QemuVT100 *vt, unsigned int nr)
751 {
762 - QemuTextConsole *s = vc->console;
763 - QemuVT100 *vt = &s->vt;
752 TextCell *c1, *c2;
753 unsigned int x1, x2, y;
754 unsigned int end, len;
@@ -784,59 +772,51 @@ static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
772 c2 = &vt->cells[y * vt->width + x2];
773 memmove(c1, c2, len * sizeof(*c1));
774 for (end = x1 + len; x1 < end; x1++) {
787 - vc_update_xy(vc, x1, vt->y);
775 + vt100_update_xy(vt, x1, vt->y);
776 }
777 }
778 /* Insert blanks */
779 for (x1 = vt->x; x1 < vt->x + nr; x1++) {
792 - vc_clear_xy(vc, x1, vt->y);
780 + vt100_clear_xy(vt, x1, vt->y);
781 }
782 }
783
784 /**
797 - * vc_save_cursor() - saves cursor position and character attributes.
785 + * vt100_save_cursor() - saves cursor position and character attributes.
786 */
799 -static void vc_save_cursor(VCChardev *vc)
787 +static void vt100_save_cursor(QemuVT100 *vt)
788 {
801 - QemuTextConsole *s = vc->console;
802 - QemuVT100 *vt = &s->vt;
803 -
804 - vc->x_saved = vt->x;
805 - vc->y_saved = vt->y;
806 - vc->t_attrib_saved = vc->t_attrib;
789 + vt->x_saved = vt->x;
790 + vt->y_saved = vt->y;
791 + vt->t_attrib_saved = vt->t_attrib;
792 }
793
794 /**
810 - * vc_restore_cursor() - restores cursor position and character
795 + * vt100_restore_cursor() - restores cursor position and character
796 * attributes from saved state.
797 */
813 -static void vc_restore_cursor(VCChardev *vc)
798 +static void vt100_restore_cursor(QemuVT100 *vt)
799 {
815 - QemuTextConsole *s = vc->console;
816 - QemuVT100 *vt = &s->vt;
817 -
818 - vt->x = vc->x_saved;
819 - vt->y = vc->y_saved;
820 - vc->t_attrib = vc->t_attrib_saved;
800 + vt->x = vt->x_saved;
801 + vt->y = vt->y_saved;
802 + vt->t_attrib = vt->t_attrib_saved;
803 }
804
823 -static void vc_putchar(VCChardev *vc, int ch)
805 +static void vt100_putchar(QemuVT100 *vt, int ch)
806 {
825 - QemuTextConsole *s = vc->console;
826 - QemuVT100 *vt = &s->vt;
807 int i;
808 int x, y;
809 g_autofree char *response = NULL;
810
831 - switch(vc->state) {
811 + switch (vt->state) {
812 case TTY_STATE_NORM:
833 - if (ch >= 0x80 && vc->encoding == CHARDEV_VC_ENCODING_UTF8) {
834 - switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
813 + if (ch >= 0x80 && vt->encoding == CHARDEV_VC_ENCODING_UTF8) {
814 + switch (bh_utf8_decode(&vt->utf8_state, &vt->utf8_codepoint, ch)) {
815 case BH_UTF8_ACCEPT:
836 - vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
816 + vt100_put_one(vt, unicode_to_cp437(vt->utf8_codepoint));
817 break;
818 case BH_UTF8_REJECT:
839 - vc->utf8_state = BH_UTF8_ACCEPT;
819 + vt->utf8_state = BH_UTF8_ACCEPT;
820 break;
821 default:
822 /* Need more bytes */
@@ -844,14 +824,13 @@ static void vc_putchar(VCChardev *vc, int ch)
824 }
825 break;
826 }
847 - /* ASCII byte: abort any pending UTF-8 sequence */
848 - vc->utf8_state = BH_UTF8_ACCEPT;
827 + vt->utf8_state = BH_UTF8_ACCEPT;
828 switch(ch) {
829 case '\r': /* carriage return */
830 vt->x = 0;
831 break;
832 case '\n': /* newline */
854 - vt100_put_lf(&s->vt);
833 + vt100_put_lf(vt);
834 break;
835 case '\b': /* backspace */
836 if (vt->x > 0)
@@ -875,95 +854,95 @@ static void vc_putchar(VCChardev *vc, int ch)
854 /* SI (shift in), character set 0 (ignored) */
855 break;
856 case 27: /* esc (introducing an escape sequence) */
878 - vc->state = TTY_STATE_ESC;
857 + vt->state = TTY_STATE_ESC;
858 break;
859 default:
881 - vc_put_one(vc, ch);
860 + vt100_put_one(vt, ch);
861 break;
862 }
863 break;
864 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
865 if (ch == '[') {
866 for(i=0;i<MAX_ESC_PARAMS;i++)
888 - vc->esc_params[i] = 0;
889 - vc->nb_esc_params = 0;
890 - vc->state = TTY_STATE_CSI;
867 + vt->esc_params[i] = 0;
868 + vt->nb_esc_params = 0;
869 + vt->state = TTY_STATE_CSI;
870 } else if (ch == '(') {
892 - vc->state = TTY_STATE_G0;
871 + vt->state = TTY_STATE_G0;
872 } else if (ch == ')') {
894 - vc->state = TTY_STATE_G1;
873 + vt->state = TTY_STATE_G1;
874 } else if (ch == ']' || ch == 'P' || ch == 'X'
875 || ch == '^' || ch == '_') {
876 /* String sequences: OSC, DCS, SOS, PM, APC */
898 - vc->state = TTY_STATE_OSC;
877 + vt->state = TTY_STATE_OSC;
878 } else if (ch == '7') {
900 - vc_save_cursor(vc);
901 - vc->state = TTY_STATE_NORM;
879 + vt100_save_cursor(vt);
880 + vt->state = TTY_STATE_NORM;
881 } else if (ch == '8') {
903 - vc_restore_cursor(vc);
904 - vc->state = TTY_STATE_NORM;
882 + vt100_restore_cursor(vt);
883 + vt->state = TTY_STATE_NORM;
884 } else {
906 - vc->state = TTY_STATE_NORM;
885 + vt->state = TTY_STATE_NORM;
886 }
887 break;
888 case TTY_STATE_CSI: /* handle escape sequence parameters */
889 if (ch >= '0' && ch <= '9') {
911 - if (vc->nb_esc_params < MAX_ESC_PARAMS) {
912 - int *param = &vc->esc_params[vc->nb_esc_params];
890 + if (vt->nb_esc_params < MAX_ESC_PARAMS) {
891 + int *param = &vt->esc_params[vt->nb_esc_params];
892 int digit = (ch - '0');
893
894 *param = (*param <= (INT_MAX - digit) / 10) ?
895 *param * 10 + digit : INT_MAX;
896 }
897 } else {
919 - if (vc->nb_esc_params < MAX_ESC_PARAMS)
920 - vc->nb_esc_params++;
898 + if (vt->nb_esc_params < MAX_ESC_PARAMS)
899 + vt->nb_esc_params++;
900 if (ch == ';' || ch == '?') {
901 break;
902 }
924 - trace_console_putchar_csi(vc->esc_params[0], vc->esc_params[1],
925 - ch, vc->nb_esc_params);
926 - vc->state = TTY_STATE_NORM;
903 + trace_console_putchar_csi(vt->esc_params[0], vt->esc_params[1],
904 + ch, vt->nb_esc_params);
905 + vt->state = TTY_STATE_NORM;
906 switch(ch) {
907 case 'A':
908 /* move cursor up */
930 - if (vc->esc_params[0] == 0) {
931 - vc->esc_params[0] = 1;
909 + if (vt->esc_params[0] == 0) {
910 + vt->esc_params[0] = 1;
911 }
933 - vc_set_cursor(vc, vt->x, vt->y - vc->esc_params[0]);
912 + vt100_set_cursor(vt, vt->x, vt->y - vt->esc_params[0]);
913 break;
914 case 'B':
915 /* move cursor down */
937 - if (vc->esc_params[0] == 0) {
938 - vc->esc_params[0] = 1;
916 + if (vt->esc_params[0] == 0) {
917 + vt->esc_params[0] = 1;
918 }
940 - vc_set_cursor(vc, vt->x, vt->y + vc->esc_params[0]);
919 + vt100_set_cursor(vt, vt->x, vt->y + vt->esc_params[0]);
920 break;
921 case 'C':
922 /* move cursor right */
944 - if (vc->esc_params[0] == 0) {
945 - vc->esc_params[0] = 1;
923 + if (vt->esc_params[0] == 0) {
924 + vt->esc_params[0] = 1;
925 }
947 - vc_set_cursor(vc, vt->x + vc->esc_params[0], vt->y);
926 + vt100_set_cursor(vt, vt->x + vt->esc_params[0], vt->y);
927 break;
928 case 'D':
929 /* move cursor left */
951 - if (vc->esc_params[0] == 0) {
952 - vc->esc_params[0] = 1;
930 + if (vt->esc_params[0] == 0) {
931 + vt->esc_params[0] = 1;
932 }
954 - vc_set_cursor(vc, vt->x - vc->esc_params[0], vt->y);
933 + vt100_set_cursor(vt, vt->x - vt->esc_params[0], vt->y);
934 break;
935 case 'G':
936 /* move cursor to column */
958 - vc_set_cursor(vc, vc->esc_params[0] - 1, vt->y);
937 + vt100_set_cursor(vt, vt->esc_params[0] - 1, vt->y);
938 break;
939 case 'f':
940 case 'H':
941 /* move cursor to row, column */
963 - vc_set_cursor(vc, vc->esc_params[1] - 1, vc->esc_params[0] - 1);
942 + vt100_set_cursor(vt, vt->esc_params[1] - 1, vt->esc_params[0] - 1);
943 break;
944 case 'J':
966 - switch (vc->esc_params[0]) {
945 + switch (vt->esc_params[0]) {
946 case 0:
947 /* clear to end of screen */
948 for (y = vt->y; y < vt->height; y++) {
@@ -971,7 +950,7 @@ static void vc_putchar(VCChardev *vc, int ch)
950 if (y == vt->y && x < vt->x) {
951 continue;
952 }
974 - vc_clear_xy(vc, x, y);
953 + vt100_clear_xy(vt, x, y);
954 }
955 }
956 break;
@@ -982,7 +961,7 @@ static void vc_putchar(VCChardev *vc, int ch)
961 if (y == vt->y && x > vt->x) {
962 break;
963 }
985 - vc_clear_xy(vc, x, y);
964 + vt100_clear_xy(vt, x, y);
965 }
966 }
967 break;
@@ -990,62 +969,62 @@ static void vc_putchar(VCChardev *vc, int ch)
969 /* clear entire screen */
970 for (y = 0; y < vt->height; y++) {
971 for (x = 0; x < vt->width; x++) {
993 - vc_clear_xy(vc, x, y);
972 + vt100_clear_xy(vt, x, y);
973 }
974 }
975 break;
976 }
977 break;
978 case 'K':
1000 - switch (vc->esc_params[0]) {
979 + switch (vt->esc_params[0]) {
980 case 0:
981 /* clear to eol */
982 for(x = vt->x; x < vt->width; x++) {
1004 - vc_clear_xy(vc, x, vt->y);
983 + vt100_clear_xy(vt, x, vt->y);
984 }
985 break;
986 case 1:
987 /* clear from beginning of line */
988 for (x = 0; x <= vt->x && x < vt->width; x++) {
1010 - vc_clear_xy(vc, x, vt->y);
989 + vt100_clear_xy(vt, x, vt->y);
990 }
991 break;
992 case 2:
993 /* clear entire line */
994 for(x = 0; x < vt->width; x++) {
1016 - vc_clear_xy(vc, x, vt->y);
995 + vt100_clear_xy(vt, x, vt->y);
996 }
997 break;
998 }
999 break;
1000 case 'P':
1022 - vc_csi_P(vc, vc->esc_params[0]);
1001 + vt100_csi_P(vt, vt->esc_params[0]);
1002 break;
1003 case 'm':
1025 - vc_handle_escape(vc);
1004 + vt100_handle_escape(vt);
1005 break;
1006 case 'n':
1028 - switch (vc->esc_params[0]) {
1007 + switch (vt->esc_params[0]) {
1008 case 5:
1009 /* report console status (always succeed)*/
1031 - qemu_text_console_write(s, "\033[0n", 4);
1010 + vt100_write(vt, "\033[0n", 4);
1011 break;
1012 case 6:
1013 /* report cursor position */
1014 response = g_strdup_printf("\033[%d;%dR",
1015 vt->y + 1, vt->x + 1);
1037 - qemu_text_console_write(s, response, strlen(response));
1016 + vt100_write(vt, response, strlen(response));
1017 break;
1018 }
1019 break;
1020 case 's':
1042 - vc_save_cursor(vc);
1021 + vt100_save_cursor(vt);
1022 break;
1023 case 'u':
1045 - vc_restore_cursor(vc);
1024 + vt100_restore_cursor(vt);
1025 break;
1026 case '@':
1048 - vc_csi_at(vc, vc->esc_params[0]);
1027 + vt100_csi_at(vt, vt->esc_params[0]);
1028 break;
1029 default:
1030 trace_console_putchar_unhandled(ch);
@@ -1057,10 +1036,10 @@ static void vc_putchar(VCChardev *vc, int ch)
1036 case TTY_STATE_OSC: /* Operating System Command: ESC ] ... BEL/ST */
1037 if (ch == '\a') {
1038 /* BEL terminates OSC */
1060 - vc->state = TTY_STATE_NORM;
1039 + vt->state = TTY_STATE_NORM;
1040 } else if (ch == 27) {
1041 /* ESC might start ST (ESC \) */
1063 - vc->state = TTY_STATE_ESC;
1042 + vt->state = TTY_STATE_ESC;
1043 }
1044 /* All other bytes are silently consumed */
1045 break;
@@ -1071,7 +1050,7 @@ static void vc_putchar(VCChardev *vc, int ch)
1050 /* Latin-1 map */
1051 break;
1052 }
1074 - vc->state = TTY_STATE_NORM;
1053 + vt->state = TTY_STATE_NORM;
1054 break;
1055 }
1056 }
@@ -1084,22 +1063,21 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
1063 {
1064 VCChardev *drv = VC_CHARDEV(chr);
1065 QemuTextConsole *s = drv->console;
1087 - QemuVT100 *vt = &s->vt;
1066 int i;
1067
1090 - vt->update_x0 = vt->width * FONT_WIDTH;
1091 - vt->update_y0 = vt->height * FONT_HEIGHT;
1092 - vt->update_x1 = 0;
1093 - vt->update_y1 = 0;
1094 - vt100_show_cursor(vt, 0);
1068 + s->vt.update_x0 = s->vt.width * FONT_WIDTH;
1069 + s->vt.update_y0 = s->vt.height * FONT_HEIGHT;
1070 + s->vt.update_x1 = 0;
1071 + s->vt.update_y1 = 0;
1072 + vt100_show_cursor(&s->vt, 0);
1073 for(i = 0; i < len; i++) {
1096 - vc_putchar(drv, buf[i]);
1074 + vt100_putchar(&s->vt, buf[i]);
1075 }
1098 - vt100_show_cursor(vt, 1);
1099 - if (vt->update_x0 < vt->update_x1) {
1100 - vt100_image_update(vt, vt->update_x0, vt->update_y0,
1101 - vt->update_x1 - vt->update_x0,
1102 - vt->update_y1 - vt->update_y0);
1076 + vt100_show_cursor(&s->vt, 1);
1077 + if (s->vt.update_x0 < s->vt.update_x1) {
1078 + vt100_image_update(&s->vt, s->vt.update_x0, s->vt.update_y0,
1079 + s->vt.update_x1 - s->vt.update_x0,
1080 + s->vt.update_y1 - s->vt.update_y0);
1081 }
1082 return len;
1083 }
@@ -1168,9 +1146,6 @@ qemu_text_console_init(Object *obj)
1146 {
1147 QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
1148
1171 - QTAILQ_INSERT_HEAD(&vt100s, &c->vt, list);
1172 - fifo8_create(&c->out_fifo, 16);
1173 - c->vt.total_height = DEFAULT_BACKSCROLL;
1149 QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
1150 QEMU_CONSOLE(c)->hw = c;
1151 }
@@ -1194,7 +1169,7 @@ static void vc_chr_accept_input(Chardev *chr)
1169 {
1170 VCChardev *drv = VC_CHARDEV(chr);
1171
1197 - qemu_text_console_flush(drv->console);
1172 + qemu_text_console_out_flush(drv->console);
1173 }
1174
1175 static void vc_chr_set_echo(Chardev *chr, bool echo)
@@ -1216,6 +1191,13 @@ static void text_console_image_update(QemuVT100 *vt, int x, int y, int width, in
1191 dpy_gfx_update(QEMU_CONSOLE(console), x, y, width, height);
1192 }
1193
1194 +static void text_console_out_flush(QemuVT100 *vt)
1195 +{
1196 + QemuTextConsole *console = container_of(vt, QemuTextConsole, vt);
1197 +
1198 + qemu_text_console_out_flush(console);
1199 +}
1200 +
1201 static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
1202 {
1203 ChardevVC *vc = backend->u.vc.data;
@@ -1245,27 +1227,31 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
1227 s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
1228 }
1229
1230 + QTAILQ_INSERT_HEAD(&vt100s, &s->vt, list);
1231 + fifo8_create(&s->vt.out_fifo, 16);
1232 + s->vt.total_height = DEFAULT_BACKSCROLL;
1233 dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
1234 s->vt.image_update = text_console_image_update;
1235 + s->vt.out_flush = text_console_out_flush;
1236
1237 s->chr = chr;
1238 drv->console = s;
1239 if (vc->has_encoding) {
1254 - drv->encoding = vc->encoding;
1240 + drv->encoding = s->vt.encoding = vc->encoding;
1241 }
1242
1243 /* set current text attributes to default */
1258 - drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
1244 + s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
1245 vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
1246
1247 if (chr->label) {
1248 char *msg;
1249
1264 - drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
1250 + s->vt.t_attrib.bgcol = QEMU_COLOR_BLUE;
1251 msg = g_strdup_printf("%s console\r\n", chr->label);
1252 qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
1253 g_free(msg);
1268 - drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
1254 + s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
1255 }
1256
1257 qemu_chr_be_event(chr, CHR_EVENT_OPENED);