gdbserver fix
[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 x_saved, y_saved;
125     int y_displayed;
126     int y_base;
127     TextAttributes t_attrib_default; /* default text attributes */
128     TextAttributes t_attrib; /* currently active text attributes */
129     TextCell *cells;
130
131     enum TTYState state;
132     int esc_params[MAX_ESC_PARAMS];
133     int nb_esc_params;
134
135     CharDriverState *chr;
136     /* fifo for key pressed */
137     QEMUFIFO out_fifo;
138     uint8_t out_fifo_buf[16];
139     QEMUTimer *kbd_timer;
140 };
141
142 static TextConsole *active_console;
143 static TextConsole *consoles[MAX_CONSOLES];
144 static int nb_consoles = 0;
145
146 void vga_hw_update(void)
147 {
148     if (active_console && active_console->hw_update)
149         active_console->hw_update(active_console->hw);
150 }
151
152 void vga_hw_invalidate(void)
153 {
154     if (active_console->hw_invalidate)
155         active_console->hw_invalidate(active_console->hw);
156 }
157
158 void vga_hw_screen_dump(const char *filename)
159 {
160     /* There is currently no was of specifying which screen we want to dump,
161        so always dump the dirst one.  */
162     if (consoles[0]->hw_screen_dump)
163         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
164 }
165
166 /* convert a RGBA color to a color index usable in graphic primitives */
167 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
168 {
169     unsigned int r, g, b, color;
170
171     switch(ds->depth) {
172 #if 0
173     case 8:
174         r = (rgba >> 16) & 0xff;
175         g = (rgba >> 8) & 0xff;
176         b = (rgba) & 0xff;
177         color = (rgb_to_index[r] * 6 * 6) + 
178             (rgb_to_index[g] * 6) + 
179             (rgb_to_index[b]);
180         break;
181 #endif
182     case 15:
183         r = (rgba >> 16) & 0xff;
184         g = (rgba >> 8) & 0xff;
185         b = (rgba) & 0xff;
186         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
187         break;
188     case 16:
189         r = (rgba >> 16) & 0xff;
190         g = (rgba >> 8) & 0xff;
191         b = (rgba) & 0xff;
192         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
193         break;
194     case 32:
195     default:
196         color = rgba;
197         break;
198     }
199     return color;
200 }
201
202 static void vga_fill_rect (DisplayState *ds, 
203                            int posx, int posy, int width, int height, uint32_t color)
204 {
205     uint8_t *d, *d1;
206     int x, y, bpp;
207     
208     bpp = (ds->depth + 7) >> 3;
209     d1 = ds->data + 
210         ds->linesize * posy + bpp * posx;
211     for (y = 0; y < height; y++) {
212         d = d1;
213         switch(bpp) {
214         case 1:
215             for (x = 0; x < width; x++) {
216                 *((uint8_t *)d) = color;
217                 d++;
218             }
219             break;
220         case 2:
221             for (x = 0; x < width; x++) {
222                 *((uint16_t *)d) = color;
223                 d += 2;
224             }
225             break;
226         case 4:
227             for (x = 0; x < width; x++) {
228                 *((uint32_t *)d) = color;
229                 d += 4;
230             }
231             break;
232         }
233         d1 += ds->linesize;
234     }
235 }
236
237 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
238 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
239 {
240     const uint8_t *s;
241     uint8_t *d;
242     int wb, y, bpp;
243
244     bpp = (ds->depth + 7) >> 3;
245     wb = w * bpp;
246     if (yd <= ys) {
247         s = ds->data + 
248             ds->linesize * ys + bpp * xs;
249         d = ds->data + 
250             ds->linesize * yd + bpp * xd;
251         for (y = 0; y < h; y++) {
252             memmove(d, s, wb);
253             d += ds->linesize;
254             s += ds->linesize;
255         }
256     } else {
257         s = ds->data + 
258             ds->linesize * (ys + h - 1) + bpp * xs;
259         d = ds->data + 
260             ds->linesize * (yd + h - 1) + bpp * xd;
261        for (y = 0; y < h; y++) {
262             memmove(d, s, wb);
263             d -= ds->linesize;
264             s -= ds->linesize;
265         }
266     }
267 }
268
269 /***********************************************************/
270 /* basic char display */
271
272 #define FONT_HEIGHT 16
273 #define FONT_WIDTH 8
274
275 #include "vgafont.h"
276
277 #define cbswap_32(__x) \
278 ((uint32_t)( \
279                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
280                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
281                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
282                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
283
284 #ifdef WORDS_BIGENDIAN
285 #define PAT(x) x
286 #else
287 #define PAT(x) cbswap_32(x)
288 #endif
289
290 static const uint32_t dmask16[16] = {
291     PAT(0x00000000),
292     PAT(0x000000ff),
293     PAT(0x0000ff00),
294     PAT(0x0000ffff),
295     PAT(0x00ff0000),
296     PAT(0x00ff00ff),
297     PAT(0x00ffff00),
298     PAT(0x00ffffff),
299     PAT(0xff000000),
300     PAT(0xff0000ff),
301     PAT(0xff00ff00),
302     PAT(0xff00ffff),
303     PAT(0xffff0000),
304     PAT(0xffff00ff),
305     PAT(0xffffff00),
306     PAT(0xffffffff),
307 };
308
309 static const uint32_t dmask4[4] = {
310     PAT(0x00000000),
311     PAT(0x0000ffff),
312     PAT(0xffff0000),
313     PAT(0xffffffff),
314 };
315
316 static uint32_t color_table[2][8];
317
318 enum color_names {
319     COLOR_BLACK   = 0,
320     COLOR_RED     = 1,
321     COLOR_GREEN   = 2,
322     COLOR_YELLOW  = 3,
323     COLOR_BLUE    = 4,
324     COLOR_MAGENTA = 5,
325     COLOR_CYAN    = 6,
326     COLOR_WHITE   = 7
327 };
328
329 static const uint32_t color_table_rgb[2][8] = {
330     {   /* dark */
331         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
332         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
333         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
334         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
335         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
336         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
337         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
338         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
339     },
340     {   /* bright */
341         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
342         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
343         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
344         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
345         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
346         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
347         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
348         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
349     }
350 };
351
352 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
353 {
354     switch(ds->depth) {
355     case 8:
356         col |= col << 8;
357         col |= col << 16;
358         break;
359     case 15:
360     case 16:
361         col |= col << 16;
362         break;
363     default:
364         break;
365     }
366
367     return col;
368 }
369 #ifdef DEBUG_CONSOLE
370 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
371 {
372     if (t_attrib->bold) {
373         printf("b");
374     } else {
375         printf(" ");
376     }
377     if (t_attrib->uline) {
378         printf("u");
379     } else {
380         printf(" ");
381     }
382     if (t_attrib->blink) {
383         printf("l");
384     } else {
385         printf(" ");
386     }
387     if (t_attrib->invers) {
388         printf("i");
389     } else {
390         printf(" ");
391     }
392     if (t_attrib->unvisible) {
393         printf("n");
394     } else {
395         printf(" ");
396     }
397
398     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
399 }
400 #endif
401
402 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
403                           TextAttributes *t_attrib)
404 {
405     uint8_t *d;
406     const uint8_t *font_ptr;
407     unsigned int font_data, linesize, xorcol, bpp;
408     int i;
409     unsigned int fgcol, bgcol;
410
411 #ifdef DEBUG_CONSOLE
412     printf("x: %2i y: %2i", x, y);
413     console_print_text_attributes(t_attrib, ch);
414 #endif
415
416     if (t_attrib->invers) {
417         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
418         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
419     } else {
420         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
421         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
422     }
423
424     bpp = (ds->depth + 7) >> 3;
425     d = ds->data + 
426         ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
427     linesize = ds->linesize;
428     font_ptr = vgafont16 + FONT_HEIGHT * ch;
429     xorcol = bgcol ^ fgcol;
430     switch(ds->depth) {
431     case 8:
432         for(i = 0; i < FONT_HEIGHT; i++) {
433             font_data = *font_ptr++;
434             if (t_attrib->uline
435                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
436                 font_data = 0xFFFF;
437             }
438             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
439             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
440             d += linesize;
441         }
442         break;
443     case 16:
444     case 15:
445         for(i = 0; i < FONT_HEIGHT; i++) {
446             font_data = *font_ptr++;
447             if (t_attrib->uline
448                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
449                 font_data = 0xFFFF;
450             }
451             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
452             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
453             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
454             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
455             d += linesize;
456         }
457         break;
458     case 32:
459         for(i = 0; i < FONT_HEIGHT; i++) {
460             font_data = *font_ptr++;
461             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462                 font_data = 0xFFFF;
463             }
464             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
465             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
466             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
467             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
468             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
469             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
470             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
471             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
472             d += linesize;
473         }
474         break;
475     }
476 }
477
478 static void text_console_resize(TextConsole *s)
479 {
480     TextCell *cells, *c, *c1;
481     int w1, x, y, last_width;
482
483     last_width = s->width;
484     s->width = s->g_width / FONT_WIDTH;
485     s->height = s->g_height / FONT_HEIGHT;
486
487     w1 = last_width;
488     if (s->width < w1)
489         w1 = s->width;
490
491     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
492     for(y = 0; y < s->total_height; y++) {
493         c = &cells[y * s->width];
494         if (w1 > 0) {
495             c1 = &s->cells[y * last_width];
496             for(x = 0; x < w1; x++) {
497                 *c++ = *c1++;
498             }
499         }
500         for(x = w1; x < s->width; x++) {
501             c->ch = ' ';
502             c->t_attrib = s->t_attrib_default;
503             c++;
504         }
505     }
506     free(s->cells);
507     s->cells = cells;
508 }
509
510 static void update_xy(TextConsole *s, int x, int y)
511 {
512     TextCell *c;
513     int y1, y2;
514
515     if (s == active_console) {
516         y1 = (s->y_base + y) % s->total_height;
517         y2 = y1 - s->y_displayed;
518         if (y2 < 0)
519             y2 += s->total_height;
520         if (y2 < s->height) {
521             c = &s->cells[y1 * s->width + x];
522             vga_putcharxy(s->ds, x, y2, c->ch, 
523                           &(c->t_attrib));
524             dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
525                        FONT_WIDTH, FONT_HEIGHT);
526         }
527     }
528 }
529
530 static void console_show_cursor(TextConsole *s, int show)
531 {
532     TextCell *c;
533     int y, y1;
534
535     if (s == active_console) {
536         y1 = (s->y_base + s->y) % s->total_height;
537         y = y1 - s->y_displayed;
538         if (y < 0)
539             y += s->total_height;
540         if (y < s->height) {
541             c = &s->cells[y1 * s->width + s->x];
542             if (show) {
543                 TextAttributes t_attrib = s->t_attrib_default;
544                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
545                 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
546             } else {
547                 vga_putcharxy(s->ds, s->x, y, c->ch, 
548                               &(c->t_attrib));
549             }
550             dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
551                        FONT_WIDTH, FONT_HEIGHT);
552         }
553     }
554 }
555
556 static void console_refresh(TextConsole *s)
557 {
558     TextCell *c;
559     int x, y, y1;
560
561     if (s != active_console) 
562         return;
563
564     vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
565                   color_table[0][COLOR_BLACK]);
566     y1 = s->y_displayed;
567     for(y = 0; y < s->height; y++) {
568         c = s->cells + y1 * s->width;
569         for(x = 0; x < s->width; x++) {
570             vga_putcharxy(s->ds, x, y, c->ch, 
571                           &(c->t_attrib));
572             c++;
573         }
574         if (++y1 == s->total_height)
575             y1 = 0;
576     }
577     dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
578     console_show_cursor(s, 1);
579 }
580
581 static void console_scroll(int ydelta)
582 {
583     TextConsole *s;
584     int i, y1;
585     
586     s = active_console;
587     if (!s || !s->text_console)
588         return;
589
590     if (ydelta > 0) {
591         for(i = 0; i < ydelta; i++) {
592             if (s->y_displayed == s->y_base)
593                 break;
594             if (++s->y_displayed == s->total_height)
595                 s->y_displayed = 0;
596         }
597     } else {
598         ydelta = -ydelta;
599         i = s->backscroll_height;
600         if (i > s->total_height - s->height)
601             i = s->total_height - s->height;
602         y1 = s->y_base - i;
603         if (y1 < 0)
604             y1 += s->total_height;
605         for(i = 0; i < ydelta; i++) {
606             if (s->y_displayed == y1)
607                 break;
608             if (--s->y_displayed < 0)
609                 s->y_displayed = s->total_height - 1;
610         }
611     }
612     console_refresh(s);
613 }
614
615 static void console_put_lf(TextConsole *s)
616 {
617     TextCell *c;
618     int x, y1;
619
620     s->y++;
621     if (s->y >= s->height) {
622         s->y = s->height - 1;
623
624         if (s->y_displayed == s->y_base) {
625             if (++s->y_displayed == s->total_height)
626                 s->y_displayed = 0;
627         }
628         if (++s->y_base == s->total_height)
629             s->y_base = 0;
630         if (s->backscroll_height < s->total_height)
631             s->backscroll_height++;
632         y1 = (s->y_base + s->height - 1) % s->total_height;
633         c = &s->cells[y1 * s->width];
634         for(x = 0; x < s->width; x++) {
635             c->ch = ' ';
636             c->t_attrib = s->t_attrib_default;
637             c++;
638         }
639         if (s == active_console && s->y_displayed == s->y_base) {
640             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
641                        s->width * FONT_WIDTH, 
642                        (s->height - 1) * FONT_HEIGHT);
643             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
644                           s->width * FONT_WIDTH, FONT_HEIGHT, 
645                           color_table[0][s->t_attrib_default.bgcol]);
646             dpy_update(s->ds, 0, 0, 
647                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
648         }
649     }
650 }
651
652 /* Set console attributes depending on the current escape codes.
653  * NOTE: I know this code is not very efficient (checking every color for it
654  * self) but it is more readable and better maintainable.
655  */
656 static void console_handle_escape(TextConsole *s)
657 {
658     int i;
659
660     for (i=0; i<s->nb_esc_params; i++) {
661         switch (s->esc_params[i]) {
662             case 0: /* reset all console attributes to default */
663                 s->t_attrib = s->t_attrib_default;
664                 break;
665             case 1:
666                 s->t_attrib.bold = 1;
667                 break;
668             case 4:
669                 s->t_attrib.uline = 1;
670                 break;
671             case 5:
672                 s->t_attrib.blink = 1;
673                 break;
674             case 7:
675                 s->t_attrib.invers = 1;
676                 break;
677             case 8:
678                 s->t_attrib.unvisible = 1;
679                 break;
680             case 22:
681                 s->t_attrib.bold = 0;
682                 break;
683             case 24:
684                 s->t_attrib.uline = 0;
685                 break;
686             case 25:
687                 s->t_attrib.blink = 0;
688                 break;
689             case 27:
690                 s->t_attrib.invers = 0;
691                 break;
692             case 28:
693                 s->t_attrib.unvisible = 0;
694                 break;
695             /* set foreground color */
696             case 30:
697                 s->t_attrib.fgcol=COLOR_BLACK;
698                 break;
699             case 31:
700                 s->t_attrib.fgcol=COLOR_RED;
701                 break;
702             case 32:
703                 s->t_attrib.fgcol=COLOR_GREEN;
704                 break;
705             case 33:
706                 s->t_attrib.fgcol=COLOR_YELLOW;
707                 break;
708             case 34:
709                 s->t_attrib.fgcol=COLOR_BLUE;
710                 break;
711             case 35:
712                 s->t_attrib.fgcol=COLOR_MAGENTA;
713                 break;
714             case 36:
715                 s->t_attrib.fgcol=COLOR_CYAN;
716                 break;
717             case 37:
718                 s->t_attrib.fgcol=COLOR_WHITE;
719                 break;
720             /* set background color */
721             case 40:
722                 s->t_attrib.bgcol=COLOR_BLACK;
723                 break;
724             case 41:
725                 s->t_attrib.bgcol=COLOR_RED;
726                 break;
727             case 42:
728                 s->t_attrib.bgcol=COLOR_GREEN;
729                 break;
730             case 43:
731                 s->t_attrib.bgcol=COLOR_YELLOW;
732                 break;
733             case 44:
734                 s->t_attrib.bgcol=COLOR_BLUE;
735                 break;
736             case 45:
737                 s->t_attrib.bgcol=COLOR_MAGENTA;
738                 break;
739             case 46:
740                 s->t_attrib.bgcol=COLOR_CYAN;
741                 break;
742             case 47:
743                 s->t_attrib.bgcol=COLOR_WHITE;
744                 break;
745         }
746     }
747 }
748
749 static void console_clear_xy(TextConsole *s, int x, int y)
750 {
751     int y1 = (s->y_base + y) % s->total_height;
752     TextCell *c = &s->cells[y1 * s->width + x];
753     c->ch = ' ';
754     c->t_attrib = s->t_attrib_default;
755     c++;
756     update_xy(s, x, y);
757 }
758
759 static void console_putchar(TextConsole *s, int ch)
760 {
761     TextCell *c;
762     int y1, i;
763     int x, y;
764
765     switch(s->state) {
766     case TTY_STATE_NORM:
767         switch(ch) {
768         case '\r':  /* carriage return */
769             s->x = 0;
770             break;
771         case '\n':  /* newline */
772             console_put_lf(s);
773             break;
774         case '\b':  /* backspace */
775             if (s->x > 0) 
776                 s->x--;
777             break;
778         case '\t':  /* tabspace */
779             if (s->x + (8 - (s->x % 8)) > s->width) {
780                 s->x = 0;
781                 console_put_lf(s);
782             } else {
783                 s->x = s->x + (8 - (s->x % 8));
784             }
785             break;
786         case '\a':  /* alert aka. bell */
787             /* TODO: has to be implemented */
788             break;
789         case 14:
790             /* SI (shift in), character set 0 (ignored) */
791             break;
792         case 15:
793             /* SO (shift out), character set 1 (ignored) */
794             break;
795         case 27:    /* esc (introducing an escape sequence) */
796             s->state = TTY_STATE_ESC;
797             break;
798         default:
799             if (s->x >= s->width - 1) {
800                 break;
801             }
802             y1 = (s->y_base + s->y) % s->total_height;
803             c = &s->cells[y1 * s->width + s->x];
804             c->ch = ch;
805             c->t_attrib = s->t_attrib;
806             update_xy(s, s->x, s->y);
807             s->x++;
808 #if 0 /* line wrap disabled */
809             if (s->x >= s->width) {
810                 s->x = 0;
811                 console_put_lf(s);
812             }
813 #endif
814             break;
815         }
816         break;
817     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
818         if (ch == '[') {
819             for(i=0;i<MAX_ESC_PARAMS;i++)
820                 s->esc_params[i] = 0;
821             s->nb_esc_params = 0;
822             s->state = TTY_STATE_CSI;
823         } else {
824             s->state = TTY_STATE_NORM;
825         }
826         break;
827     case TTY_STATE_CSI: /* handle escape sequence parameters */
828         if (ch >= '0' && ch <= '9') {
829             if (s->nb_esc_params < MAX_ESC_PARAMS) {
830                 s->esc_params[s->nb_esc_params] = 
831                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
832             }
833         } else {
834             s->nb_esc_params++;
835             if (ch == ';')
836                 break;
837 #ifdef DEBUG_CONSOLE
838             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
839                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
840 #endif
841             s->state = TTY_STATE_NORM;
842             switch(ch) {
843             case 'A':
844                 /* move cursor up */
845                 if (s->esc_params[0] == 0) {
846                     s->esc_params[0] = 1;
847                 }
848                 s->y -= s->esc_params[0];
849                 if (s->y < 0) {
850                     s->y = 0;
851                 }
852                 break;
853             case 'B':
854                 /* move cursor down */
855                 if (s->esc_params[0] == 0) {
856                     s->esc_params[0] = 1;
857                 }
858                 s->y += s->esc_params[0];
859                 if (s->y >= s->height) {
860                     s->y = s->height - 1;
861                 }
862                 break;
863             case 'C':
864                 /* move cursor right */
865                 if (s->esc_params[0] == 0) {
866                     s->esc_params[0] = 1;
867                 }
868                 s->x += s->esc_params[0];
869                 if (s->x >= s->width) {
870                     s->x = s->width - 1;
871                 }
872                 break;
873             case 'D':
874                 /* move cursor left */
875                 if (s->esc_params[0] == 0) {
876                     s->esc_params[0] = 1;
877                 }
878                 s->x -= s->esc_params[0];
879                 if (s->x < 0) {
880                     s->x = 0;
881                 }
882                 break;
883             case 'G':
884                 /* move cursor to column */
885                 s->x = s->esc_params[0] - 1;
886                 if (s->x < 0) {
887                     s->x = 0;
888                 }
889                 break;
890             case 'f':
891             case 'H':
892                 /* move cursor to row, column */
893                 s->x = s->esc_params[1] - 1;
894                 if (s->x < 0) {
895                     s->x = 0;
896                 }
897                 s->y = s->esc_params[0] - 1;
898                 if (s->y < 0) {
899                     s->y = 0;
900                 }
901                 break;
902             case 'J':
903                 switch (s->esc_params[0]) {
904                 case 0:
905                     /* clear to end of screen */
906                     for (y = s->y; y < s->height; y++) {
907                         for (x = 0; x < s->width; x++) {
908                             if (y == s->y && x < s->x) {
909                                 continue;
910                             }
911                             console_clear_xy(s, x, y);
912                         }
913                     }
914                     break;
915                 case 1:
916                     /* clear from beginning of screen */
917                     for (y = 0; y <= s->y; y++) {
918                         for (x = 0; x < s->width; x++) {
919                             if (y == s->y && x > s->x) {
920                                 break;
921                             }
922                             console_clear_xy(s, x, y);
923                         }
924                     }
925                     break;
926                 case 2:
927                     /* clear entire screen */
928                     for (y = 0; y <= s->height; y++) {
929                         for (x = 0; x < s->width; x++) {
930                             console_clear_xy(s, x, y);
931                         }
932                     }
933                 break;
934                 }
935             case 'K':
936                 switch (s->esc_params[0]) {
937                 case 0:
938                 /* clear to eol */
939                 for(x = s->x; x < s->width; x++) {
940                         console_clear_xy(s, x, s->y);
941                 }
942                 break;
943                 case 1:
944                     /* clear from beginning of line */
945                     for (x = 0; x <= s->x; x++) {
946                         console_clear_xy(s, x, s->y);
947                     }
948                     break;
949                 case 2:
950                     /* clear entire line */
951                     for(x = 0; x < s->width; x++) {
952                         console_clear_xy(s, x, s->y);
953                     }
954                 break;
955             }
956                 break;
957             case 'm':
958             console_handle_escape(s);
959             break;
960             case 'n':
961                 /* report cursor position */
962                 /* TODO: send ESC[row;colR */
963                 break;
964             case 's':
965                 /* save cursor position */
966                 s->x_saved = s->x;
967                 s->y_saved = s->y;
968                 break;
969             case 'u':
970                 /* restore cursor position */
971                 s->x = s->x_saved;
972                 s->y = s->y_saved;
973                 break;
974             default:
975 #ifdef DEBUG_CONSOLE
976                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
977 #endif
978                 break;
979             }
980             break;
981         }
982     }
983 }
984
985 void console_select(unsigned int index)
986 {
987     TextConsole *s;
988
989     if (index >= MAX_CONSOLES)
990         return;
991     s = consoles[index];
992     if (s) {
993         active_console = s;
994         if (s->text_console) {
995             if (s->g_width != s->ds->width ||
996                 s->g_height != s->ds->height) {
997                 s->g_width = s->ds->width;
998                 s->g_height = s->ds->height;
999                 text_console_resize(s);
1000             }
1001             console_refresh(s);
1002         } else {
1003             vga_hw_invalidate();
1004         }
1005     }
1006 }
1007
1008 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1009 {
1010     TextConsole *s = chr->opaque;
1011     int i;
1012
1013     console_show_cursor(s, 0);
1014     for(i = 0; i < len; i++) {
1015         console_putchar(s, buf[i]);
1016     }
1017     console_show_cursor(s, 1);
1018     return len;
1019 }
1020
1021 static void console_send_event(CharDriverState *chr, int event)
1022 {
1023     TextConsole *s = chr->opaque;
1024     int i;
1025
1026     if (event == CHR_EVENT_FOCUS) {
1027         for(i = 0; i < nb_consoles; i++) {
1028             if (consoles[i] == s) {
1029                 console_select(i);
1030                 break;
1031             }
1032         }
1033     }
1034 }
1035
1036 static void kbd_send_chars(void *opaque)
1037 {
1038     TextConsole *s = opaque;
1039     int len;
1040     uint8_t buf[16];
1041     
1042     len = qemu_chr_can_read(s->chr);
1043     if (len > s->out_fifo.count)
1044         len = s->out_fifo.count;
1045     if (len > 0) {
1046         if (len > sizeof(buf))
1047             len = sizeof(buf);
1048         qemu_fifo_read(&s->out_fifo, buf, len);
1049         qemu_chr_read(s->chr, buf, len);
1050     }
1051     /* characters are pending: we send them a bit later (XXX:
1052        horrible, should change char device API) */
1053     if (s->out_fifo.count > 0) {
1054         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1055     }
1056 }
1057
1058 /* called when an ascii key is pressed */
1059 void kbd_put_keysym(int keysym)
1060 {
1061     TextConsole *s;
1062     uint8_t buf[16], *q;
1063     int c;
1064
1065     s = active_console;
1066     if (!s || !s->text_console)
1067         return;
1068
1069     switch(keysym) {
1070     case QEMU_KEY_CTRL_UP:
1071         console_scroll(-1);
1072         break;
1073     case QEMU_KEY_CTRL_DOWN:
1074         console_scroll(1);
1075         break;
1076     case QEMU_KEY_CTRL_PAGEUP:
1077         console_scroll(-10);
1078         break;
1079     case QEMU_KEY_CTRL_PAGEDOWN:
1080         console_scroll(10);
1081         break;
1082     default:
1083         /* convert the QEMU keysym to VT100 key string */
1084         q = buf;
1085         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1086             *q++ = '\033';
1087             *q++ = '[';
1088             c = keysym - 0xe100;
1089             if (c >= 10)
1090                 *q++ = '0' + (c / 10);
1091             *q++ = '0' + (c % 10);
1092             *q++ = '~';
1093         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1094             *q++ = '\033';
1095             *q++ = '[';
1096             *q++ = keysym & 0xff;
1097         } else {
1098                 *q++ = keysym;
1099         }
1100         if (s->chr->chr_read) {
1101             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1102             kbd_send_chars(s);
1103         }
1104         break;
1105     }
1106 }
1107
1108 static TextConsole *new_console(DisplayState *ds, int text)
1109 {
1110     TextConsole *s;
1111     int i;
1112
1113     if (nb_consoles >= MAX_CONSOLES)
1114         return NULL;
1115     s = qemu_mallocz(sizeof(TextConsole));
1116     if (!s) {
1117         return NULL;
1118     }
1119     if (!active_console || (active_console->text_console && !text))
1120         active_console = s;
1121     s->ds = ds;
1122     s->text_console = text;
1123     if (text) {
1124         consoles[nb_consoles++] = s;
1125     } else {
1126         /* HACK: Put graphical consoles before text consoles.  */
1127         for (i = nb_consoles; i > 0; i--) {
1128             if (!consoles[i - 1]->text_console)
1129                 break;
1130             consoles[i] = consoles[i - 1];
1131         }
1132         consoles[i] = s;
1133     }
1134     return s;
1135 }
1136
1137 TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1138                                   vga_hw_invalidate_ptr invalidate,
1139                                   vga_hw_screen_dump_ptr screen_dump,
1140                                   void *opaque)
1141 {
1142     TextConsole *s;
1143
1144     s = new_console(ds, 0);
1145     if (!s)
1146       return NULL;
1147     s->hw_update = update;
1148     s->hw_invalidate = invalidate;
1149     s->hw_screen_dump = screen_dump;
1150     s->hw = opaque;
1151     return s;
1152 }
1153
1154 int is_graphic_console(void)
1155 {
1156     return !active_console->text_console;
1157 }
1158
1159 CharDriverState *text_console_init(DisplayState *ds)
1160 {
1161     CharDriverState *chr;
1162     TextConsole *s;
1163     int i,j;
1164     static int color_inited;
1165
1166     chr = qemu_mallocz(sizeof(CharDriverState));
1167     if (!chr)
1168         return NULL;
1169     s = new_console(ds, 1);
1170     if (!s) {
1171         free(chr);
1172         return NULL;
1173     }
1174     chr->opaque = s;
1175     chr->chr_write = console_puts;
1176     chr->chr_send_event = console_send_event;
1177
1178     s->chr = chr;
1179     s->out_fifo.buf = s->out_fifo_buf;
1180     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1181     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1182     
1183     if (!color_inited) {
1184         color_inited = 1;
1185         for(j = 0; j < 2; j++) {
1186             for(i = 0; i < 8; i++) {
1187                 color_table[j][i] = col_expand(s->ds, 
1188                         vga_get_color(s->ds, color_table_rgb[j][i]));
1189             }
1190         }
1191     }
1192     s->y_displayed = 0;
1193     s->y_base = 0;
1194     s->total_height = DEFAULT_BACKSCROLL;
1195     s->x = 0;
1196     s->y = 0;
1197     s->g_width = s->ds->width;
1198     s->g_height = s->ds->height;
1199
1200     /* Set text attribute defaults */
1201     s->t_attrib_default.bold = 0;
1202     s->t_attrib_default.uline = 0;
1203     s->t_attrib_default.blink = 0;
1204     s->t_attrib_default.invers = 0;
1205     s->t_attrib_default.unvisible = 0;
1206     s->t_attrib_default.fgcol = COLOR_WHITE;
1207     s->t_attrib_default.bgcol = COLOR_BLACK;
1208
1209     /* set current text attributes to default */
1210     s->t_attrib = s->t_attrib_default;
1211     text_console_resize(s);
1212
1213     qemu_chr_reset(chr);
1214
1215     return chr;
1216 }