avoid name conflicts
[qemu] / console.c
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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.
23  */
24 #include "vl.h"
25
26 //#define DEBUG_CONSOLE
27 #define DEFAULT_BACKSCROLL 512
28 #define MAX_CONSOLES 12
29
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)
32
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;
42
43 typedef struct TextCell {
44     uint8_t ch;
45     TextAttributes t_attrib;
46 } TextCell;
47
48 #define MAX_ESC_PARAMS 3
49
50 enum TTYState {
51     TTY_STATE_NORM,
52     TTY_STATE_ESC,
53     TTY_STATE_CSI,
54 };
55
56 typedef struct QEMUFIFO {
57     uint8_t *buf;
58     int buf_size;
59     int count, wptr, rptr;
60 } QEMUFIFO;
61
62 int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
63 {
64     int l, len;
65
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;
80     }
81     f->count += len1;
82     return len1;
83 }
84
85 int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
86 {
87     int l, len;
88
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;
102     }
103     f->count -= len1;
104     return len1;
105 }
106
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;
117
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;
129
130     enum TTYState state;
131     int esc_params[MAX_ESC_PARAMS];
132     int nb_esc_params;
133
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;
142 };
143
144 static TextConsole *active_console;
145 static TextConsole *consoles[MAX_CONSOLES];
146 static int nb_consoles = 0;
147
148 void vga_hw_update(void)
149 {
150     if (active_console->hw_update)
151         active_console->hw_update(active_console->hw);
152 }
153
154 void vga_hw_invalidate(void)
155 {
156     if (active_console->hw_invalidate)
157         active_console->hw_invalidate(active_console->hw);
158 }
159
160 void vga_hw_screen_dump(const char *filename)
161 {
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);
166 }
167
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)
170 {
171     unsigned int r, g, b, color;
172
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;
200     }
201     return color;
202 }
203
204 static void vga_fill_rect (DisplayState *ds, 
205                            int posx, int posy, int width, int height, uint32_t color)
206 {
207     uint8_t *d, *d1;
208     int x, y, bpp;
209     
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++;
220             }
221             break;
222         case 2:
223             for (x = 0; x < width; x++) {
224                 *((uint16_t *)d) = color;
225                 d += 2;
226             }
227             break;
228         case 4:
229             for (x = 0; x < width; x++) {
230                 *((uint32_t *)d) = color;
231                 d += 4;
232             }
233             break;
234         }
235         d1 += ds->linesize;
236     }
237 }
238
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)
241 {
242     const uint8_t *s;
243     uint8_t *d;
244     int wb, y, bpp;
245
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;
257         }
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;
267         }
268     }
269 }
270
271 /***********************************************************/
272 /* basic char display */
273
274 #define FONT_HEIGHT 16
275 #define FONT_WIDTH 8
276
277 #include "vgafont.h"
278
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) ))
285
286 #ifdef WORDS_BIGENDIAN
287 #define PAT(x) x
288 #else
289 #define PAT(x) cbswap_32(x)
290 #endif
291
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),
309 };
310
311 static const uint32_t dmask4[4] = {
312     PAT(0x00000000),
313     PAT(0x0000ffff),
314     PAT(0xffff0000),
315     PAT(0xffffffff),
316 };
317
318 static uint32_t color_table[2][8];
319
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
329 };
330
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 */
341     },
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 */
351     }
352 };
353
354 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
355 {
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;
367     }
368
369     return col;
370 }
371 #ifdef DEBUG_CONSOLE
372 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
373 {
374     if (t_attrib->bold) {
375         printf("b");
376     } else {
377         printf(" ");
378     }
379     if (t_attrib->uline) {
380         printf("u");
381     } else {
382         printf(" ");
383     }
384     if (t_attrib->blink) {
385         printf("l");
386     } else {
387         printf(" ");
388     }
389     if (t_attrib->invers) {
390         printf("i");
391     } else {
392         printf(" ");
393     }
394     if (t_attrib->unvisible) {
395         printf("n");
396     } else {
397         printf(" ");
398     }
399
400     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
401 }
402 #endif
403
404 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
405                           TextAttributes *t_attrib)
406 {
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;
412
413 #ifdef DEBUG_CONSOLE
414     printf("x: %2i y: %2i", x, y);
415     console_print_text_attributes(t_attrib, ch);
416 #endif
417
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];
424     }
425
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;
439             }
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;
443         }
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;
452             }
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;
458         }
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;
465             }
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;
475         }
476         break;
477     }
478 }
479
480 static void text_console_resize(TextConsole *s)
481 {
482     TextCell *cells, *c, *c1;
483     int w1, x, y, last_width;
484
485     last_width = s->width;
486     s->width = s->g_width / FONT_WIDTH;
487     s->height = s->g_height / FONT_HEIGHT;
488
489     w1 = last_width;
490     if (s->width < w1)
491         w1 = s->width;
492
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++;
500             }
501         }
502         for(x = w1; x < s->width; x++) {
503             c->ch = ' ';
504             c->t_attrib = s->t_attrib_default;
505             c++;
506         }
507     }
508     free(s->cells);
509     s->cells = cells;
510 }
511
512 static void update_xy(TextConsole *s, int x, int y)
513 {
514     TextCell *c;
515     int y1, y2;
516
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);
528         }
529     }
530 }
531
532 static void console_show_cursor(TextConsole *s, int show)
533 {
534     TextCell *c;
535     int y, y1;
536
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));
551             }
552             dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
553                        FONT_WIDTH, FONT_HEIGHT);
554         }
555     }
556 }
557
558 static void console_refresh(TextConsole *s)
559 {
560     TextCell *c;
561     int x, y, y1;
562
563     if (s != active_console) 
564         return;
565
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++;
575         }
576         if (++y1 == s->total_height)
577             y1 = 0;
578     }
579     dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
580     console_show_cursor(s, 1);
581 }
582
583 static void console_scroll(int ydelta)
584 {
585     TextConsole *s;
586     int i, y1;
587     
588     s = active_console;
589     if (!s || !s->text_console)
590         return;
591
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;
598         }
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;
612         }
613     }
614     console_refresh(s);
615 }
616
617 static void console_put_lf(TextConsole *s)
618 {
619     TextCell *c;
620     int x, y1;
621
622     s->x = 0;
623     s->y++;
624     if (s->y >= s->height) {
625         s->y = s->height - 1;
626
627         if (s->y_displayed == s->y_base) {
628             if (++s->y_displayed == s->total_height)
629                 s->y_displayed = 0;
630         }
631         if (++s->y_base == s->total_height)
632             s->y_base = 0;
633         if (s->backscroll_height < s->total_height)
634             s->backscroll_height++;
635         y1 = (s->y_base + s->height - 1) % s->total_height;
636         c = &s->cells[y1 * s->width];
637         for(x = 0; x < s->width; x++) {
638             c->ch = ' ';
639             c->t_attrib = s->t_attrib_default;
640             c++;
641         }
642         if (s == active_console && s->y_displayed == s->y_base) {
643             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
644                        s->width * FONT_WIDTH, 
645                        (s->height - 1) * FONT_HEIGHT);
646             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
647                           s->width * FONT_WIDTH, FONT_HEIGHT, 
648                           color_table[0][s->t_attrib_default.bgcol]);
649             dpy_update(s->ds, 0, 0, 
650                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
651         }
652     }
653 }
654
655 /* Set console attributes depending on the current escape codes.
656  * NOTE: I know this code is not very efficient (checking every color for it
657  * self) but it is more readable and better maintainable.
658  */
659 static void console_handle_escape(TextConsole *s)
660 {
661     int i;
662
663     if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
664         s->t_attrib = s->t_attrib_default;
665         return;
666     }
667     for (i=0; i<s->nb_esc_params; i++) {
668         switch (s->esc_params[i]) {
669             case 0: /* reset all console attributes to default */
670                 s->t_attrib = s->t_attrib_default;
671                 break;
672             case 1:
673                 s->t_attrib.bold = 1;
674                 break;
675             case 4:
676                 s->t_attrib.uline = 1;
677                 break;
678             case 5:
679                 s->t_attrib.blink = 1;
680                 break;
681             case 7:
682                 s->t_attrib.invers = 1;
683                 break;
684             case 8:
685                 s->t_attrib.unvisible = 1;
686                 break;
687             case 22:
688                 s->t_attrib.bold = 0;
689                 break;
690             case 24:
691                 s->t_attrib.uline = 0;
692                 break;
693             case 25:
694                 s->t_attrib.blink = 0;
695                 break;
696             case 27:
697                 s->t_attrib.invers = 0;
698                 break;
699             case 28:
700                 s->t_attrib.unvisible = 0;
701                 break;
702             /* set foreground color */
703             case 30:
704                 s->t_attrib.fgcol=COLOR_BLACK;
705                 break;
706             case 31:
707                 s->t_attrib.fgcol=COLOR_RED;
708                 break;
709             case 32:
710                 s->t_attrib.fgcol=COLOR_GREEN;
711                 break;
712             case 33:
713                 s->t_attrib.fgcol=COLOR_YELLOW;
714                 break;
715             case 34:
716                 s->t_attrib.fgcol=COLOR_BLUE;
717                 break;
718             case 35:
719                 s->t_attrib.fgcol=COLOR_MAGENTA;
720                 break;
721             case 36:
722                 s->t_attrib.fgcol=COLOR_CYAN;
723                 break;
724             case 37:
725                 s->t_attrib.fgcol=COLOR_WHITE;
726                 break;
727             /* set background color */
728             case 40:
729                 s->t_attrib.bgcol=COLOR_BLACK;
730                 break;
731             case 41:
732                 s->t_attrib.bgcol=COLOR_RED;
733                 break;
734             case 42:
735                 s->t_attrib.bgcol=COLOR_GREEN;
736                 break;
737             case 43:
738                 s->t_attrib.bgcol=COLOR_YELLOW;
739                 break;
740             case 44:
741                 s->t_attrib.bgcol=COLOR_BLUE;
742                 break;
743             case 45:
744                 s->t_attrib.bgcol=COLOR_MAGENTA;
745                 break;
746             case 46:
747                 s->t_attrib.bgcol=COLOR_CYAN;
748                 break;
749             case 47:
750                 s->t_attrib.bgcol=COLOR_WHITE;
751                 break;
752         }
753     }
754 }
755
756 static void console_putchar(TextConsole *s, int ch)
757 {
758     TextCell *c;
759     int y1, i, x;
760
761     switch(s->state) {
762     case TTY_STATE_NORM:
763         switch(ch) {
764         case '\r':  /* carriage return */
765             s->x = 0;
766             break;
767         case '\n':  /* newline */
768             console_put_lf(s);
769             break;
770         case '\b':  /* backspace */
771             if (s->x > 0) 
772                 s->x--;
773             break;
774         case '\t':  /* tabspace */
775             if (s->x + (8 - (s->x % 8)) > s->width) {
776                 console_put_lf(s);
777             } else {
778                 s->x = s->x + (8 - (s->x % 8));
779             }
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                 console_put_lf(s);
796             break;
797         }
798         break;
799     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
800         if (ch == '[') {
801             for(i=0;i<MAX_ESC_PARAMS;i++)
802                 s->esc_params[i] = 0;
803             s->nb_esc_params = 0;
804             s->state = TTY_STATE_CSI;
805         } else {
806             s->state = TTY_STATE_NORM;
807         }
808         break;
809     case TTY_STATE_CSI: /* handle escape sequence parameters */
810         if (ch >= '0' && ch <= '9') {
811             if (s->nb_esc_params < MAX_ESC_PARAMS) {
812                 s->esc_params[s->nb_esc_params] = 
813                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
814             }
815         } else {
816             s->nb_esc_params++;
817             if (ch == ';')
818                 break;
819             s->state = TTY_STATE_NORM;
820             switch(ch) {
821             case 'D':
822                 if (s->x > 0)
823                     s->x--;
824                 break;
825             case 'C':
826                 if (s->x < (s->width - 1))
827                     s->x++;
828                 break;
829             case 'K':
830                 /* clear to eol */
831                 y1 = (s->y_base + s->y) % s->total_height;
832                 for(x = s->x; x < s->width; x++) {
833                     c = &s->cells[y1 * s->width + x];
834                     c->ch = ' ';
835                     c->t_attrib = s->t_attrib_default;
836                     c++;
837                     update_xy(s, x, s->y);
838                 }
839                 break;
840             default:
841                 break;
842             }
843             console_handle_escape(s);
844             break;
845         }
846     }
847 }
848
849 void console_select(unsigned int index)
850 {
851     TextConsole *s;
852
853     if (index >= MAX_CONSOLES)
854         return;
855     s = consoles[index];
856     if (s) {
857         active_console = s;
858         if (s->text_console) {
859             if (s->g_width != s->ds->width ||
860                 s->g_height != s->ds->height) {
861                 s->g_width = s->ds->width;
862                 s->g_height = s->ds->height;
863                 text_console_resize(s);
864             }
865             console_refresh(s);
866         } else {
867             vga_hw_invalidate();
868         }
869     }
870 }
871
872 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
873 {
874     TextConsole *s = chr->opaque;
875     int i;
876
877     console_show_cursor(s, 0);
878     for(i = 0; i < len; i++) {
879         console_putchar(s, buf[i]);
880     }
881     console_show_cursor(s, 1);
882     return len;
883 }
884
885 static void console_chr_add_read_handler(CharDriverState *chr, 
886                                          IOCanRWHandler *fd_can_read, 
887                                          IOReadHandler *fd_read, void *opaque)
888 {
889     TextConsole *s = chr->opaque;
890     s->fd_can_read = fd_can_read;
891     s->fd_read = fd_read;
892     s->fd_opaque = opaque;
893 }
894
895 static void console_send_event(CharDriverState *chr, int event)
896 {
897     TextConsole *s = chr->opaque;
898     int i;
899
900     if (event == CHR_EVENT_FOCUS) {
901         for(i = 0; i < nb_consoles; i++) {
902             if (consoles[i] == s) {
903                 console_select(i);
904                 break;
905             }
906         }
907     }
908 }
909
910 static void kbd_send_chars(void *opaque)
911 {
912     TextConsole *s = opaque;
913     int len;
914     uint8_t buf[16];
915     
916     len = s->fd_can_read(s->fd_opaque);
917     if (len > s->out_fifo.count)
918         len = s->out_fifo.count;
919     if (len > 0) {
920         if (len > sizeof(buf))
921             len = sizeof(buf);
922         qemu_fifo_read(&s->out_fifo, buf, len);
923         s->fd_read(s->fd_opaque, buf, len);
924     }
925     /* characters are pending: we send them a bit later (XXX:
926        horrible, should change char device API) */
927     if (s->out_fifo.count > 0) {
928         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
929     }
930 }
931
932 /* called when an ascii key is pressed */
933 void kbd_put_keysym(int keysym)
934 {
935     TextConsole *s;
936     uint8_t buf[16], *q;
937     int c;
938
939     s = active_console;
940     if (!s || !s->text_console)
941         return;
942
943     switch(keysym) {
944     case QEMU_KEY_CTRL_UP:
945         console_scroll(-1);
946         break;
947     case QEMU_KEY_CTRL_DOWN:
948         console_scroll(1);
949         break;
950     case QEMU_KEY_CTRL_PAGEUP:
951         console_scroll(-10);
952         break;
953     case QEMU_KEY_CTRL_PAGEDOWN:
954         console_scroll(10);
955         break;
956     default:
957         /* convert the QEMU keysym to VT100 key string */
958         q = buf;
959         if (keysym >= 0xe100 && keysym <= 0xe11f) {
960             *q++ = '\033';
961             *q++ = '[';
962             c = keysym - 0xe100;
963             if (c >= 10)
964                 *q++ = '0' + (c / 10);
965             *q++ = '0' + (c % 10);
966             *q++ = '~';
967         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
968             *q++ = '\033';
969             *q++ = '[';
970             *q++ = keysym & 0xff;
971         } else {
972                 *q++ = keysym;
973         }
974         if (s->fd_read) {
975             qemu_fifo_write(&s->out_fifo, buf, q - buf);
976             kbd_send_chars(s);
977         }
978         break;
979     }
980 }
981
982 static TextConsole *new_console(DisplayState *ds, int text)
983 {
984     TextConsole *s;
985     int i;
986
987     if (nb_consoles >= MAX_CONSOLES)
988         return NULL;
989     s = qemu_mallocz(sizeof(TextConsole));
990     if (!s) {
991         return NULL;
992     }
993     if (!active_console || (active_console->text_console && !text))
994         active_console = s;
995     s->ds = ds;
996     s->text_console = text;
997     if (text) {
998         consoles[nb_consoles++] = s;
999     } else {
1000         /* HACK: Put graphical consoles before text consoles.  */
1001         for (i = nb_consoles; i > 0; i--) {
1002             if (!consoles[i - 1]->text_console)
1003                 break;
1004             consoles[i] = consoles[i - 1];
1005         }
1006         consoles[i] = s;
1007     }
1008     return s;
1009 }
1010
1011 TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1012                                   vga_hw_invalidate_ptr invalidate,
1013                                   vga_hw_screen_dump_ptr screen_dump,
1014                                   void *opaque)
1015 {
1016     TextConsole *s;
1017
1018     s = new_console(ds, 0);
1019     if (!s)
1020       return NULL;
1021     s->hw_update = update;
1022     s->hw_invalidate = invalidate;
1023     s->hw_screen_dump = screen_dump;
1024     s->hw = opaque;
1025     return s;
1026 }
1027
1028 int is_graphic_console(void)
1029 {
1030     return !active_console->text_console;
1031 }
1032
1033 CharDriverState *text_console_init(DisplayState *ds)
1034 {
1035     CharDriverState *chr;
1036     TextConsole *s;
1037     int i,j;
1038     static int color_inited;
1039
1040     chr = qemu_mallocz(sizeof(CharDriverState));
1041     if (!chr)
1042         return NULL;
1043     s = new_console(ds, 1);
1044     if (!s) {
1045         free(chr);
1046         return NULL;
1047     }
1048     chr->opaque = s;
1049     chr->chr_write = console_puts;
1050     chr->chr_add_read_handler = console_chr_add_read_handler;
1051     chr->chr_send_event = console_send_event;
1052
1053     s->out_fifo.buf = s->out_fifo_buf;
1054     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1055     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1056     
1057     if (!color_inited) {
1058         color_inited = 1;
1059         for(j = 0; j < 2; j++) {
1060             for(i = 0; i < 8; i++) {
1061                 color_table[j][i] = col_expand(s->ds, 
1062                         vga_get_color(s->ds, color_table_rgb[j][i]));
1063             }
1064         }
1065     }
1066     s->y_displayed = 0;
1067     s->y_base = 0;
1068     s->total_height = DEFAULT_BACKSCROLL;
1069     s->x = 0;
1070     s->y = 0;
1071     s->g_width = s->ds->width;
1072     s->g_height = s->ds->height;
1073
1074     /* Set text attribute defaults */
1075     s->t_attrib_default.bold = 0;
1076     s->t_attrib_default.uline = 0;
1077     s->t_attrib_default.blink = 0;
1078     s->t_attrib_default.invers = 0;
1079     s->t_attrib_default.unvisible = 0;
1080     s->t_attrib_default.fgcol = COLOR_WHITE;
1081     s->t_attrib_default.bgcol = COLOR_BLACK;
1082
1083     /* set current text attributes to default */
1084     s->t_attrib = s->t_attrib_default;
1085     text_console_resize(s);
1086
1087     return chr;
1088 }