Update sparc bios image (Blue Swirl).
[qemu/mini2440.git] / console.c
blobf039dfcb3909467c7d660fbe701500305d9695f9
1 /*
2 * QEMU graphical console
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "vl.h"
26 //#define DEBUG_CONSOLE
27 #define DEFAULT_BACKSCROLL 512
28 #define MAX_CONSOLES 12
30 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
31 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
33 typedef struct TextAttributes {
34 uint8_t fgcol:4;
35 uint8_t bgcol:4;
36 uint8_t bold:1;
37 uint8_t uline:1;
38 uint8_t blink:1;
39 uint8_t invers:1;
40 uint8_t unvisible:1;
41 } TextAttributes;
43 typedef struct TextCell {
44 uint8_t ch;
45 TextAttributes t_attrib;
46 } TextCell;
48 #define MAX_ESC_PARAMS 3
50 enum TTYState {
51 TTY_STATE_NORM,
52 TTY_STATE_ESC,
53 TTY_STATE_CSI,
56 typedef struct QEMUFIFO {
57 uint8_t *buf;
58 int buf_size;
59 int count, wptr, rptr;
60 } QEMUFIFO;
62 int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
64 int l, len;
66 l = f->buf_size - f->count;
67 if (len1 > l)
68 len1 = l;
69 len = len1;
70 while (len > 0) {
71 l = f->buf_size - f->wptr;
72 if (l > len)
73 l = len;
74 memcpy(f->buf + f->wptr, buf, l);
75 f->wptr += l;
76 if (f->wptr >= f->buf_size)
77 f->wptr = 0;
78 buf += l;
79 len -= l;
81 f->count += len1;
82 return len1;
85 int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
87 int l, len;
89 if (len1 > f->count)
90 len1 = f->count;
91 len = len1;
92 while (len > 0) {
93 l = f->buf_size - f->rptr;
94 if (l > len)
95 l = len;
96 memcpy(buf, f->buf + f->rptr, l);
97 f->rptr += l;
98 if (f->rptr >= f->buf_size)
99 f->rptr = 0;
100 buf += l;
101 len -= l;
103 f->count -= len1;
104 return len1;
107 /* ??? This is mis-named.
108 It is used for both text and graphical consoles. */
109 struct TextConsole {
110 int text_console; /* true if text console */
111 DisplayState *ds;
112 /* Graphic console state. */
113 vga_hw_update_ptr hw_update;
114 vga_hw_invalidate_ptr hw_invalidate;
115 vga_hw_screen_dump_ptr hw_screen_dump;
116 void *hw;
118 int g_width, g_height;
119 int width;
120 int height;
121 int total_height;
122 int backscroll_height;
123 int x, y;
124 int y_displayed;
125 int y_base;
126 TextAttributes t_attrib_default; /* default text attributes */
127 TextAttributes t_attrib; /* currently active text attributes */
128 TextCell *cells;
130 enum TTYState state;
131 int esc_params[MAX_ESC_PARAMS];
132 int nb_esc_params;
134 /* kbd read handler */
135 IOCanRWHandler *fd_can_read;
136 IOReadHandler *fd_read;
137 void *fd_opaque;
138 /* fifo for key pressed */
139 QEMUFIFO out_fifo;
140 uint8_t out_fifo_buf[16];
141 QEMUTimer *kbd_timer;
144 static TextConsole *active_console;
145 static TextConsole *consoles[MAX_CONSOLES];
146 static int nb_consoles = 0;
148 void vga_hw_update(void)
150 if (active_console->hw_update)
151 active_console->hw_update(active_console->hw);
154 void vga_hw_invalidate(void)
156 if (active_console->hw_invalidate)
157 active_console->hw_invalidate(active_console->hw);
160 void vga_hw_screen_dump(const char *filename)
162 /* There is currently no was of specifying which screen we want to dump,
163 so always dump the dirst one. */
164 if (consoles[0]->hw_screen_dump)
165 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
168 /* convert a RGBA color to a color index usable in graphic primitives */
169 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
171 unsigned int r, g, b, color;
173 switch(ds->depth) {
174 #if 0
175 case 8:
176 r = (rgba >> 16) & 0xff;
177 g = (rgba >> 8) & 0xff;
178 b = (rgba) & 0xff;
179 color = (rgb_to_index[r] * 6 * 6) +
180 (rgb_to_index[g] * 6) +
181 (rgb_to_index[b]);
182 break;
183 #endif
184 case 15:
185 r = (rgba >> 16) & 0xff;
186 g = (rgba >> 8) & 0xff;
187 b = (rgba) & 0xff;
188 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
189 break;
190 case 16:
191 r = (rgba >> 16) & 0xff;
192 g = (rgba >> 8) & 0xff;
193 b = (rgba) & 0xff;
194 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
195 break;
196 case 32:
197 default:
198 color = rgba;
199 break;
201 return color;
204 static void vga_fill_rect (DisplayState *ds,
205 int posx, int posy, int width, int height, uint32_t color)
207 uint8_t *d, *d1;
208 int x, y, bpp;
210 bpp = (ds->depth + 7) >> 3;
211 d1 = ds->data +
212 ds->linesize * posy + bpp * posx;
213 for (y = 0; y < height; y++) {
214 d = d1;
215 switch(bpp) {
216 case 1:
217 for (x = 0; x < width; x++) {
218 *((uint8_t *)d) = color;
219 d++;
221 break;
222 case 2:
223 for (x = 0; x < width; x++) {
224 *((uint16_t *)d) = color;
225 d += 2;
227 break;
228 case 4:
229 for (x = 0; x < width; x++) {
230 *((uint32_t *)d) = color;
231 d += 4;
233 break;
235 d1 += ds->linesize;
239 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
240 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
242 const uint8_t *s;
243 uint8_t *d;
244 int wb, y, bpp;
246 bpp = (ds->depth + 7) >> 3;
247 wb = w * bpp;
248 if (yd <= ys) {
249 s = ds->data +
250 ds->linesize * ys + bpp * xs;
251 d = ds->data +
252 ds->linesize * yd + bpp * xd;
253 for (y = 0; y < h; y++) {
254 memmove(d, s, wb);
255 d += ds->linesize;
256 s += ds->linesize;
258 } else {
259 s = ds->data +
260 ds->linesize * (ys + h - 1) + bpp * xs;
261 d = ds->data +
262 ds->linesize * (yd + h - 1) + bpp * xd;
263 for (y = 0; y < h; y++) {
264 memmove(d, s, wb);
265 d -= ds->linesize;
266 s -= ds->linesize;
271 /***********************************************************/
272 /* basic char display */
274 #define FONT_HEIGHT 16
275 #define FONT_WIDTH 8
277 #include "vgafont.h"
279 #define cbswap_32(__x) \
280 ((uint32_t)( \
281 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
282 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
283 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
284 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
286 #ifdef WORDS_BIGENDIAN
287 #define PAT(x) x
288 #else
289 #define PAT(x) cbswap_32(x)
290 #endif
292 static const uint32_t dmask16[16] = {
293 PAT(0x00000000),
294 PAT(0x000000ff),
295 PAT(0x0000ff00),
296 PAT(0x0000ffff),
297 PAT(0x00ff0000),
298 PAT(0x00ff00ff),
299 PAT(0x00ffff00),
300 PAT(0x00ffffff),
301 PAT(0xff000000),
302 PAT(0xff0000ff),
303 PAT(0xff00ff00),
304 PAT(0xff00ffff),
305 PAT(0xffff0000),
306 PAT(0xffff00ff),
307 PAT(0xffffff00),
308 PAT(0xffffffff),
311 static const uint32_t dmask4[4] = {
312 PAT(0x00000000),
313 PAT(0x0000ffff),
314 PAT(0xffff0000),
315 PAT(0xffffffff),
318 static uint32_t color_table[2][8];
320 enum color_names {
321 COLOR_BLACK = 0,
322 COLOR_RED = 1,
323 COLOR_GREEN = 2,
324 COLOR_YELLOW = 3,
325 COLOR_BLUE = 4,
326 COLOR_MAGENTA = 5,
327 COLOR_CYAN = 6,
328 COLOR_WHITE = 7
331 static const uint32_t color_table_rgb[2][8] = {
332 { /* dark */
333 QEMU_RGB(0x00, 0x00, 0x00), /* black */
334 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
335 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
336 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
337 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
338 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
339 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
340 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
342 { /* bright */
343 QEMU_RGB(0x00, 0x00, 0x00), /* black */
344 QEMU_RGB(0xff, 0x00, 0x00), /* red */
345 QEMU_RGB(0x00, 0xff, 0x00), /* green */
346 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
347 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
348 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
349 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
350 QEMU_RGB(0xff, 0xff, 0xff), /* white */
354 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
356 switch(ds->depth) {
357 case 8:
358 col |= col << 8;
359 col |= col << 16;
360 break;
361 case 15:
362 case 16:
363 col |= col << 16;
364 break;
365 default:
366 break;
369 return col;
371 #ifdef DEBUG_CONSOLE
372 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
374 if (t_attrib->bold) {
375 printf("b");
376 } else {
377 printf(" ");
379 if (t_attrib->uline) {
380 printf("u");
381 } else {
382 printf(" ");
384 if (t_attrib->blink) {
385 printf("l");
386 } else {
387 printf(" ");
389 if (t_attrib->invers) {
390 printf("i");
391 } else {
392 printf(" ");
394 if (t_attrib->unvisible) {
395 printf("n");
396 } else {
397 printf(" ");
400 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
402 #endif
404 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
405 TextAttributes *t_attrib)
407 uint8_t *d;
408 const uint8_t *font_ptr;
409 unsigned int font_data, linesize, xorcol, bpp;
410 int i;
411 unsigned int fgcol, bgcol;
413 #ifdef DEBUG_CONSOLE
414 printf("x: %2i y: %2i", x, y);
415 console_print_text_attributes(t_attrib, ch);
416 #endif
418 if (t_attrib->invers) {
419 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
420 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
421 } else {
422 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
423 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
426 bpp = (ds->depth + 7) >> 3;
427 d = ds->data +
428 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
429 linesize = ds->linesize;
430 font_ptr = vgafont16 + FONT_HEIGHT * ch;
431 xorcol = bgcol ^ fgcol;
432 switch(ds->depth) {
433 case 8:
434 for(i = 0; i < FONT_HEIGHT; i++) {
435 font_data = *font_ptr++;
436 if (t_attrib->uline
437 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
438 font_data = 0xFFFF;
440 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
441 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
442 d += linesize;
444 break;
445 case 16:
446 case 15:
447 for(i = 0; i < FONT_HEIGHT; i++) {
448 font_data = *font_ptr++;
449 if (t_attrib->uline
450 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
451 font_data = 0xFFFF;
453 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
454 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
455 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
456 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
457 d += linesize;
459 break;
460 case 32:
461 for(i = 0; i < FONT_HEIGHT; i++) {
462 font_data = *font_ptr++;
463 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464 font_data = 0xFFFF;
466 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
467 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
468 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
469 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
470 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
471 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
472 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
473 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
474 d += linesize;
476 break;
480 static void text_console_resize(TextConsole *s)
482 TextCell *cells, *c, *c1;
483 int w1, x, y, last_width;
485 last_width = s->width;
486 s->width = s->g_width / FONT_WIDTH;
487 s->height = s->g_height / FONT_HEIGHT;
489 w1 = last_width;
490 if (s->width < w1)
491 w1 = s->width;
493 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
494 for(y = 0; y < s->total_height; y++) {
495 c = &cells[y * s->width];
496 if (w1 > 0) {
497 c1 = &s->cells[y * last_width];
498 for(x = 0; x < w1; x++) {
499 *c++ = *c1++;
502 for(x = w1; x < s->width; x++) {
503 c->ch = ' ';
504 c->t_attrib = s->t_attrib_default;
505 c++;
508 free(s->cells);
509 s->cells = cells;
512 static void update_xy(TextConsole *s, int x, int y)
514 TextCell *c;
515 int y1, y2;
517 if (s == active_console) {
518 y1 = (s->y_base + y) % s->total_height;
519 y2 = y1 - s->y_displayed;
520 if (y2 < 0)
521 y2 += s->total_height;
522 if (y2 < s->height) {
523 c = &s->cells[y1 * s->width + x];
524 vga_putcharxy(s->ds, x, y2, c->ch,
525 &(c->t_attrib));
526 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
527 FONT_WIDTH, FONT_HEIGHT);
532 static void console_show_cursor(TextConsole *s, int show)
534 TextCell *c;
535 int y, y1;
537 if (s == active_console) {
538 y1 = (s->y_base + s->y) % s->total_height;
539 y = y1 - s->y_displayed;
540 if (y < 0)
541 y += s->total_height;
542 if (y < s->height) {
543 c = &s->cells[y1 * s->width + s->x];
544 if (show) {
545 TextAttributes t_attrib = s->t_attrib_default;
546 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
547 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
548 } else {
549 vga_putcharxy(s->ds, s->x, y, c->ch,
550 &(c->t_attrib));
552 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
553 FONT_WIDTH, FONT_HEIGHT);
558 static void console_refresh(TextConsole *s)
560 TextCell *c;
561 int x, y, y1;
563 if (s != active_console)
564 return;
566 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
567 color_table[0][COLOR_BLACK]);
568 y1 = s->y_displayed;
569 for(y = 0; y < s->height; y++) {
570 c = s->cells + y1 * s->width;
571 for(x = 0; x < s->width; x++) {
572 vga_putcharxy(s->ds, x, y, c->ch,
573 &(c->t_attrib));
574 c++;
576 if (++y1 == s->total_height)
577 y1 = 0;
579 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
580 console_show_cursor(s, 1);
583 static void console_scroll(int ydelta)
585 TextConsole *s;
586 int i, y1;
588 s = active_console;
589 if (!s || !s->text_console)
590 return;
592 if (ydelta > 0) {
593 for(i = 0; i < ydelta; i++) {
594 if (s->y_displayed == s->y_base)
595 break;
596 if (++s->y_displayed == s->total_height)
597 s->y_displayed = 0;
599 } else {
600 ydelta = -ydelta;
601 i = s->backscroll_height;
602 if (i > s->total_height - s->height)
603 i = s->total_height - s->height;
604 y1 = s->y_base - i;
605 if (y1 < 0)
606 y1 += s->total_height;
607 for(i = 0; i < ydelta; i++) {
608 if (s->y_displayed == y1)
609 break;
610 if (--s->y_displayed < 0)
611 s->y_displayed = s->total_height - 1;
614 console_refresh(s);
617 static void console_put_lf(TextConsole *s)
619 TextCell *c;
620 int x, y1;
622 s->y++;
623 if (s->y >= s->height) {
624 s->y = s->height - 1;
626 if (s->y_displayed == s->y_base) {
627 if (++s->y_displayed == s->total_height)
628 s->y_displayed = 0;
630 if (++s->y_base == s->total_height)
631 s->y_base = 0;
632 if (s->backscroll_height < s->total_height)
633 s->backscroll_height++;
634 y1 = (s->y_base + s->height - 1) % s->total_height;
635 c = &s->cells[y1 * s->width];
636 for(x = 0; x < s->width; x++) {
637 c->ch = ' ';
638 c->t_attrib = s->t_attrib_default;
639 c++;
641 if (s == active_console && s->y_displayed == s->y_base) {
642 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
643 s->width * FONT_WIDTH,
644 (s->height - 1) * FONT_HEIGHT);
645 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
646 s->width * FONT_WIDTH, FONT_HEIGHT,
647 color_table[0][s->t_attrib_default.bgcol]);
648 dpy_update(s->ds, 0, 0,
649 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
654 /* Set console attributes depending on the current escape codes.
655 * NOTE: I know this code is not very efficient (checking every color for it
656 * self) but it is more readable and better maintainable.
658 static void console_handle_escape(TextConsole *s)
660 int i;
662 if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
663 s->t_attrib = s->t_attrib_default;
664 return;
666 for (i=0; i<s->nb_esc_params; i++) {
667 switch (s->esc_params[i]) {
668 case 0: /* reset all console attributes to default */
669 s->t_attrib = s->t_attrib_default;
670 break;
671 case 1:
672 s->t_attrib.bold = 1;
673 break;
674 case 4:
675 s->t_attrib.uline = 1;
676 break;
677 case 5:
678 s->t_attrib.blink = 1;
679 break;
680 case 7:
681 s->t_attrib.invers = 1;
682 break;
683 case 8:
684 s->t_attrib.unvisible = 1;
685 break;
686 case 22:
687 s->t_attrib.bold = 0;
688 break;
689 case 24:
690 s->t_attrib.uline = 0;
691 break;
692 case 25:
693 s->t_attrib.blink = 0;
694 break;
695 case 27:
696 s->t_attrib.invers = 0;
697 break;
698 case 28:
699 s->t_attrib.unvisible = 0;
700 break;
701 /* set foreground color */
702 case 30:
703 s->t_attrib.fgcol=COLOR_BLACK;
704 break;
705 case 31:
706 s->t_attrib.fgcol=COLOR_RED;
707 break;
708 case 32:
709 s->t_attrib.fgcol=COLOR_GREEN;
710 break;
711 case 33:
712 s->t_attrib.fgcol=COLOR_YELLOW;
713 break;
714 case 34:
715 s->t_attrib.fgcol=COLOR_BLUE;
716 break;
717 case 35:
718 s->t_attrib.fgcol=COLOR_MAGENTA;
719 break;
720 case 36:
721 s->t_attrib.fgcol=COLOR_CYAN;
722 break;
723 case 37:
724 s->t_attrib.fgcol=COLOR_WHITE;
725 break;
726 /* set background color */
727 case 40:
728 s->t_attrib.bgcol=COLOR_BLACK;
729 break;
730 case 41:
731 s->t_attrib.bgcol=COLOR_RED;
732 break;
733 case 42:
734 s->t_attrib.bgcol=COLOR_GREEN;
735 break;
736 case 43:
737 s->t_attrib.bgcol=COLOR_YELLOW;
738 break;
739 case 44:
740 s->t_attrib.bgcol=COLOR_BLUE;
741 break;
742 case 45:
743 s->t_attrib.bgcol=COLOR_MAGENTA;
744 break;
745 case 46:
746 s->t_attrib.bgcol=COLOR_CYAN;
747 break;
748 case 47:
749 s->t_attrib.bgcol=COLOR_WHITE;
750 break;
755 static void console_putchar(TextConsole *s, int ch)
757 TextCell *c;
758 int y1, i, x;
760 switch(s->state) {
761 case TTY_STATE_NORM:
762 switch(ch) {
763 case '\r': /* carriage return */
764 s->x = 0;
765 break;
766 case '\n': /* newline */
767 console_put_lf(s);
768 break;
769 case '\b': /* backspace */
770 if (s->x > 0)
771 s->x--;
772 break;
773 case '\t': /* tabspace */
774 if (s->x + (8 - (s->x % 8)) > s->width) {
775 s->x = 0;
776 console_put_lf(s);
777 } else {
778 s->x = s->x + (8 - (s->x % 8));
780 break;
781 case '\a': /* alert aka. bell */
782 /* TODO: has to be implemented */
783 break;
784 case 27: /* esc (introducing an escape sequence) */
785 s->state = TTY_STATE_ESC;
786 break;
787 default:
788 y1 = (s->y_base + s->y) % s->total_height;
789 c = &s->cells[y1 * s->width + s->x];
790 c->ch = ch;
791 c->t_attrib = s->t_attrib;
792 update_xy(s, s->x, s->y);
793 s->x++;
794 if (s->x >= s->width) {
795 s->x = 0;
796 console_put_lf(s);
798 break;
800 break;
801 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
802 if (ch == '[') {
803 for(i=0;i<MAX_ESC_PARAMS;i++)
804 s->esc_params[i] = 0;
805 s->nb_esc_params = 0;
806 s->state = TTY_STATE_CSI;
807 } else {
808 s->state = TTY_STATE_NORM;
810 break;
811 case TTY_STATE_CSI: /* handle escape sequence parameters */
812 if (ch >= '0' && ch <= '9') {
813 if (s->nb_esc_params < MAX_ESC_PARAMS) {
814 s->esc_params[s->nb_esc_params] =
815 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
817 } else {
818 s->nb_esc_params++;
819 if (ch == ';')
820 break;
821 s->state = TTY_STATE_NORM;
822 switch(ch) {
823 case 'D':
824 if (s->x > 0)
825 s->x--;
826 break;
827 case 'C':
828 if (s->x < (s->width - 1))
829 s->x++;
830 break;
831 case 'K':
832 /* clear to eol */
833 y1 = (s->y_base + s->y) % s->total_height;
834 for(x = s->x; x < s->width; x++) {
835 c = &s->cells[y1 * s->width + x];
836 c->ch = ' ';
837 c->t_attrib = s->t_attrib_default;
838 c++;
839 update_xy(s, x, s->y);
841 break;
842 default:
843 break;
845 console_handle_escape(s);
846 break;
851 void console_select(unsigned int index)
853 TextConsole *s;
855 if (index >= MAX_CONSOLES)
856 return;
857 s = consoles[index];
858 if (s) {
859 active_console = s;
860 if (s->text_console) {
861 if (s->g_width != s->ds->width ||
862 s->g_height != s->ds->height) {
863 s->g_width = s->ds->width;
864 s->g_height = s->ds->height;
865 text_console_resize(s);
867 console_refresh(s);
868 } else {
869 vga_hw_invalidate();
874 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
876 TextConsole *s = chr->opaque;
877 int i;
879 console_show_cursor(s, 0);
880 for(i = 0; i < len; i++) {
881 console_putchar(s, buf[i]);
883 console_show_cursor(s, 1);
884 return len;
887 static void console_chr_add_read_handler(CharDriverState *chr,
888 IOCanRWHandler *fd_can_read,
889 IOReadHandler *fd_read, void *opaque)
891 TextConsole *s = chr->opaque;
892 s->fd_can_read = fd_can_read;
893 s->fd_read = fd_read;
894 s->fd_opaque = opaque;
897 static void console_send_event(CharDriverState *chr, int event)
899 TextConsole *s = chr->opaque;
900 int i;
902 if (event == CHR_EVENT_FOCUS) {
903 for(i = 0; i < nb_consoles; i++) {
904 if (consoles[i] == s) {
905 console_select(i);
906 break;
912 static void kbd_send_chars(void *opaque)
914 TextConsole *s = opaque;
915 int len;
916 uint8_t buf[16];
918 len = s->fd_can_read(s->fd_opaque);
919 if (len > s->out_fifo.count)
920 len = s->out_fifo.count;
921 if (len > 0) {
922 if (len > sizeof(buf))
923 len = sizeof(buf);
924 qemu_fifo_read(&s->out_fifo, buf, len);
925 s->fd_read(s->fd_opaque, buf, len);
927 /* characters are pending: we send them a bit later (XXX:
928 horrible, should change char device API) */
929 if (s->out_fifo.count > 0) {
930 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
934 /* called when an ascii key is pressed */
935 void kbd_put_keysym(int keysym)
937 TextConsole *s;
938 uint8_t buf[16], *q;
939 int c;
941 s = active_console;
942 if (!s || !s->text_console)
943 return;
945 switch(keysym) {
946 case QEMU_KEY_CTRL_UP:
947 console_scroll(-1);
948 break;
949 case QEMU_KEY_CTRL_DOWN:
950 console_scroll(1);
951 break;
952 case QEMU_KEY_CTRL_PAGEUP:
953 console_scroll(-10);
954 break;
955 case QEMU_KEY_CTRL_PAGEDOWN:
956 console_scroll(10);
957 break;
958 default:
959 /* convert the QEMU keysym to VT100 key string */
960 q = buf;
961 if (keysym >= 0xe100 && keysym <= 0xe11f) {
962 *q++ = '\033';
963 *q++ = '[';
964 c = keysym - 0xe100;
965 if (c >= 10)
966 *q++ = '0' + (c / 10);
967 *q++ = '0' + (c % 10);
968 *q++ = '~';
969 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
970 *q++ = '\033';
971 *q++ = '[';
972 *q++ = keysym & 0xff;
973 } else {
974 *q++ = keysym;
976 if (s->fd_read) {
977 qemu_fifo_write(&s->out_fifo, buf, q - buf);
978 kbd_send_chars(s);
980 break;
984 static TextConsole *new_console(DisplayState *ds, int text)
986 TextConsole *s;
987 int i;
989 if (nb_consoles >= MAX_CONSOLES)
990 return NULL;
991 s = qemu_mallocz(sizeof(TextConsole));
992 if (!s) {
993 return NULL;
995 if (!active_console || (active_console->text_console && !text))
996 active_console = s;
997 s->ds = ds;
998 s->text_console = text;
999 if (text) {
1000 consoles[nb_consoles++] = s;
1001 } else {
1002 /* HACK: Put graphical consoles before text consoles. */
1003 for (i = nb_consoles; i > 0; i--) {
1004 if (!consoles[i - 1]->text_console)
1005 break;
1006 consoles[i] = consoles[i - 1];
1008 consoles[i] = s;
1010 return s;
1013 TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1014 vga_hw_invalidate_ptr invalidate,
1015 vga_hw_screen_dump_ptr screen_dump,
1016 void *opaque)
1018 TextConsole *s;
1020 s = new_console(ds, 0);
1021 if (!s)
1022 return NULL;
1023 s->hw_update = update;
1024 s->hw_invalidate = invalidate;
1025 s->hw_screen_dump = screen_dump;
1026 s->hw = opaque;
1027 return s;
1030 int is_graphic_console(void)
1032 return !active_console->text_console;
1035 CharDriverState *text_console_init(DisplayState *ds)
1037 CharDriverState *chr;
1038 TextConsole *s;
1039 int i,j;
1040 static int color_inited;
1042 chr = qemu_mallocz(sizeof(CharDriverState));
1043 if (!chr)
1044 return NULL;
1045 s = new_console(ds, 1);
1046 if (!s) {
1047 free(chr);
1048 return NULL;
1050 chr->opaque = s;
1051 chr->chr_write = console_puts;
1052 chr->chr_add_read_handler = console_chr_add_read_handler;
1053 chr->chr_send_event = console_send_event;
1055 s->out_fifo.buf = s->out_fifo_buf;
1056 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1057 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1059 if (!color_inited) {
1060 color_inited = 1;
1061 for(j = 0; j < 2; j++) {
1062 for(i = 0; i < 8; i++) {
1063 color_table[j][i] = col_expand(s->ds,
1064 vga_get_color(s->ds, color_table_rgb[j][i]));
1068 s->y_displayed = 0;
1069 s->y_base = 0;
1070 s->total_height = DEFAULT_BACKSCROLL;
1071 s->x = 0;
1072 s->y = 0;
1073 s->g_width = s->ds->width;
1074 s->g_height = s->ds->height;
1076 /* Set text attribute defaults */
1077 s->t_attrib_default.bold = 0;
1078 s->t_attrib_default.uline = 0;
1079 s->t_attrib_default.blink = 0;
1080 s->t_attrib_default.invers = 0;
1081 s->t_attrib_default.unvisible = 0;
1082 s->t_attrib_default.fgcol = COLOR_WHITE;
1083 s->t_attrib_default.bgcol = COLOR_BLACK;
1085 /* set current text attributes to default */
1086 s->t_attrib = s->t_attrib_default;
1087 text_console_resize(s);
1089 return chr;