ec529ae6e20080a2603c05fd63531be13438b170
[sdk/emulator/qemu.git] / 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 "qemu-common.h"
25 #include "console.h"
26 #include "qemu-timer.h"
27
28 //#define DEBUG_CONSOLE
29 #define DEFAULT_BACKSCROLL 512
30 #define MAX_CONSOLES 12
31
32 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
34
35 typedef struct TextAttributes {
36     uint8_t fgcol:4;
37     uint8_t bgcol:4;
38     uint8_t bold:1;
39     uint8_t uline:1;
40     uint8_t blink:1;
41     uint8_t invers:1;
42     uint8_t unvisible:1;
43 } TextAttributes;
44
45 typedef struct TextCell {
46     uint8_t ch;
47     TextAttributes t_attrib;
48 } TextCell;
49
50 #define MAX_ESC_PARAMS 3
51
52 enum TTYState {
53     TTY_STATE_NORM,
54     TTY_STATE_ESC,
55     TTY_STATE_CSI,
56 };
57
58 typedef struct QEMUFIFO {
59     uint8_t *buf;
60     int buf_size;
61     int count, wptr, rptr;
62 } QEMUFIFO;
63
64 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
65 {
66     int l, len;
67
68     l = f->buf_size - f->count;
69     if (len1 > l)
70         len1 = l;
71     len = len1;
72     while (len > 0) {
73         l = f->buf_size - f->wptr;
74         if (l > len)
75             l = len;
76         memcpy(f->buf + f->wptr, buf, l);
77         f->wptr += l;
78         if (f->wptr >= f->buf_size)
79             f->wptr = 0;
80         buf += l;
81         len -= l;
82     }
83     f->count += len1;
84     return len1;
85 }
86
87 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
88 {
89     int l, len;
90
91     if (len1 > f->count)
92         len1 = f->count;
93     len = len1;
94     while (len > 0) {
95         l = f->buf_size - f->rptr;
96         if (l > len)
97             l = len;
98         memcpy(buf, f->buf + f->rptr, l);
99         f->rptr += l;
100         if (f->rptr >= f->buf_size)
101             f->rptr = 0;
102         buf += l;
103         len -= l;
104     }
105     f->count -= len1;
106     return len1;
107 }
108
109 typedef enum {
110     GRAPHIC_CONSOLE,
111     TEXT_CONSOLE,
112     TEXT_CONSOLE_FIXED_SIZE
113 } console_type_t;
114
115 /* ??? This is mis-named.
116    It is used for both text and graphical consoles.  */
117 struct TextConsole {
118     console_type_t console_type;
119     DisplayState *ds;
120     /* Graphic console state.  */
121     vga_hw_update_ptr hw_update;
122     vga_hw_invalidate_ptr hw_invalidate;
123     vga_hw_screen_dump_ptr hw_screen_dump;
124     vga_hw_text_update_ptr hw_text_update;
125     void *hw;
126
127     int g_width, g_height;
128     int width;
129     int height;
130     int total_height;
131     int backscroll_height;
132     int x, y;
133     int x_saved, y_saved;
134     int y_displayed;
135     int y_base;
136     TextAttributes t_attrib_default; /* default text attributes */
137     TextAttributes t_attrib; /* currently active text attributes */
138     TextCell *cells;
139     int text_x[2], text_y[2], cursor_invalidate;
140     int echo;
141
142     int update_x0;
143     int update_y0;
144     int update_x1;
145     int update_y1;
146
147     enum TTYState state;
148     int esc_params[MAX_ESC_PARAMS];
149     int nb_esc_params;
150
151     CharDriverState *chr;
152     /* fifo for key pressed */
153     QEMUFIFO out_fifo;
154     uint8_t out_fifo_buf[16];
155     QEMUTimer *kbd_timer;
156 };
157
158 static DisplayState *display_state;
159 static TextConsole *active_console;
160 static TextConsole *consoles[MAX_CONSOLES];
161 static int nb_consoles = 0;
162
163 void vga_hw_update(void)
164 {
165     if (active_console && active_console->hw_update)
166         active_console->hw_update(active_console->hw);
167 }
168
169 void vga_hw_invalidate(void)
170 {
171     if (active_console && active_console->hw_invalidate)
172         active_console->hw_invalidate(active_console->hw);
173 }
174
175 void vga_hw_screen_dump(const char *filename)
176 {
177     TextConsole *previous_active_console;
178
179     previous_active_console = active_console;
180     active_console = consoles[0];
181     /* There is currently no way of specifying which screen we want to dump,
182        so always dump the first one.  */
183     if (consoles[0] && consoles[0]->hw_screen_dump)
184         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
185     active_console = previous_active_console;
186 }
187
188 void vga_hw_text_update(console_ch_t *chardata)
189 {
190     if (active_console && active_console->hw_text_update)
191         active_console->hw_text_update(active_console->hw, chardata);
192 }
193
194 /* convert a RGBA color to a color index usable in graphic primitives */
195 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
196 {
197     unsigned int r, g, b, color;
198
199     switch(ds_get_bits_per_pixel(ds)) {
200 #if 0
201     case 8:
202         r = (rgba >> 16) & 0xff;
203         g = (rgba >> 8) & 0xff;
204         b = (rgba) & 0xff;
205         color = (rgb_to_index[r] * 6 * 6) +
206             (rgb_to_index[g] * 6) +
207             (rgb_to_index[b]);
208         break;
209 #endif
210     case 15:
211         r = (rgba >> 16) & 0xff;
212         g = (rgba >> 8) & 0xff;
213         b = (rgba) & 0xff;
214         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
215         break;
216     case 16:
217         r = (rgba >> 16) & 0xff;
218         g = (rgba >> 8) & 0xff;
219         b = (rgba) & 0xff;
220         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
221         break;
222     case 32:
223     default:
224         color = rgba;
225         break;
226     }
227     return color;
228 }
229
230 static void vga_fill_rect (DisplayState *ds,
231                            int posx, int posy, int width, int height, uint32_t color)
232 {
233     uint8_t *d, *d1;
234     int x, y, bpp;
235
236     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
237     d1 = ds_get_data(ds) +
238         ds_get_linesize(ds) * posy + bpp * posx;
239     for (y = 0; y < height; y++) {
240         d = d1;
241         switch(bpp) {
242         case 1:
243             for (x = 0; x < width; x++) {
244                 *((uint8_t *)d) = color;
245                 d++;
246             }
247             break;
248         case 2:
249             for (x = 0; x < width; x++) {
250                 *((uint16_t *)d) = color;
251                 d += 2;
252             }
253             break;
254         case 4:
255             for (x = 0; x < width; x++) {
256                 *((uint32_t *)d) = color;
257                 d += 4;
258             }
259             break;
260         }
261         d1 += ds_get_linesize(ds);
262     }
263 }
264
265 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
266 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
267 {
268     const uint8_t *s;
269     uint8_t *d;
270     int wb, y, bpp;
271
272     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
273     wb = w * bpp;
274     if (yd <= ys) {
275         s = ds_get_data(ds) +
276             ds_get_linesize(ds) * ys + bpp * xs;
277         d = ds_get_data(ds) +
278             ds_get_linesize(ds) * yd + bpp * xd;
279         for (y = 0; y < h; y++) {
280             memmove(d, s, wb);
281             d += ds_get_linesize(ds);
282             s += ds_get_linesize(ds);
283         }
284     } else {
285         s = ds_get_data(ds) +
286             ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
287         d = ds_get_data(ds) +
288             ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
289        for (y = 0; y < h; y++) {
290             memmove(d, s, wb);
291             d -= ds_get_linesize(ds);
292             s -= ds_get_linesize(ds);
293         }
294     }
295 }
296
297 /***********************************************************/
298 /* basic char display */
299
300 #define FONT_HEIGHT 16
301 #define FONT_WIDTH 8
302
303 #include "vgafont.h"
304
305 #define cbswap_32(__x) \
306 ((uint32_t)( \
307                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
308                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
309                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
310                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
311
312 #ifdef HOST_WORDS_BIGENDIAN
313 #define PAT(x) x
314 #else
315 #define PAT(x) cbswap_32(x)
316 #endif
317
318 static const uint32_t dmask16[16] = {
319     PAT(0x00000000),
320     PAT(0x000000ff),
321     PAT(0x0000ff00),
322     PAT(0x0000ffff),
323     PAT(0x00ff0000),
324     PAT(0x00ff00ff),
325     PAT(0x00ffff00),
326     PAT(0x00ffffff),
327     PAT(0xff000000),
328     PAT(0xff0000ff),
329     PAT(0xff00ff00),
330     PAT(0xff00ffff),
331     PAT(0xffff0000),
332     PAT(0xffff00ff),
333     PAT(0xffffff00),
334     PAT(0xffffffff),
335 };
336
337 static const uint32_t dmask4[4] = {
338     PAT(0x00000000),
339     PAT(0x0000ffff),
340     PAT(0xffff0000),
341     PAT(0xffffffff),
342 };
343
344 static uint32_t color_table[2][8];
345
346 enum color_names {
347     COLOR_BLACK   = 0,
348     COLOR_RED     = 1,
349     COLOR_GREEN   = 2,
350     COLOR_YELLOW  = 3,
351     COLOR_BLUE    = 4,
352     COLOR_MAGENTA = 5,
353     COLOR_CYAN    = 6,
354     COLOR_WHITE   = 7
355 };
356
357 static const uint32_t color_table_rgb[2][8] = {
358     {   /* dark */
359         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
360         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
361         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
362         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
363         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
364         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
365         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
366         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
367     },
368     {   /* bright */
369         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
370         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
371         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
372         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
373         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
374         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
375         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
376         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
377     }
378 };
379
380 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
381 {
382     switch(ds_get_bits_per_pixel(ds)) {
383     case 8:
384         col |= col << 8;
385         col |= col << 16;
386         break;
387     case 15:
388     case 16:
389         col |= col << 16;
390         break;
391     default:
392         break;
393     }
394
395     return col;
396 }
397 #ifdef DEBUG_CONSOLE
398 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
399 {
400     if (t_attrib->bold) {
401         printf("b");
402     } else {
403         printf(" ");
404     }
405     if (t_attrib->uline) {
406         printf("u");
407     } else {
408         printf(" ");
409     }
410     if (t_attrib->blink) {
411         printf("l");
412     } else {
413         printf(" ");
414     }
415     if (t_attrib->invers) {
416         printf("i");
417     } else {
418         printf(" ");
419     }
420     if (t_attrib->unvisible) {
421         printf("n");
422     } else {
423         printf(" ");
424     }
425
426     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
427 }
428 #endif
429
430 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
431                           TextAttributes *t_attrib)
432 {
433     uint8_t *d;
434     const uint8_t *font_ptr;
435     unsigned int font_data, linesize, xorcol, bpp;
436     int i;
437     unsigned int fgcol, bgcol;
438
439 #ifdef DEBUG_CONSOLE
440     printf("x: %2i y: %2i", x, y);
441     console_print_text_attributes(t_attrib, ch);
442 #endif
443
444     if (t_attrib->invers) {
445         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
446         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
447     } else {
448         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
449         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
450     }
451
452     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
453     d = ds_get_data(ds) +
454         ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
455     linesize = ds_get_linesize(ds);
456     font_ptr = vgafont16 + FONT_HEIGHT * ch;
457     xorcol = bgcol ^ fgcol;
458     switch(ds_get_bits_per_pixel(ds)) {
459     case 8:
460         for(i = 0; i < FONT_HEIGHT; i++) {
461             font_data = *font_ptr++;
462             if (t_attrib->uline
463                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464                 font_data = 0xFFFF;
465             }
466             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
467             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
468             d += linesize;
469         }
470         break;
471     case 16:
472     case 15:
473         for(i = 0; i < FONT_HEIGHT; i++) {
474             font_data = *font_ptr++;
475             if (t_attrib->uline
476                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
477                 font_data = 0xFFFF;
478             }
479             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
480             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
481             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
482             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
483             d += linesize;
484         }
485         break;
486     case 32:
487         for(i = 0; i < FONT_HEIGHT; i++) {
488             font_data = *font_ptr++;
489             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
490                 font_data = 0xFFFF;
491             }
492             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
493             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
494             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
495             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
496             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
497             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
498             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
499             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
500             d += linesize;
501         }
502         break;
503     }
504 }
505
506 static void text_console_resize(TextConsole *s)
507 {
508     TextCell *cells, *c, *c1;
509     int w1, x, y, last_width;
510
511     last_width = s->width;
512     s->width = s->g_width / FONT_WIDTH;
513     s->height = s->g_height / FONT_HEIGHT;
514
515     w1 = last_width;
516     if (s->width < w1)
517         w1 = s->width;
518
519     cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
520     for(y = 0; y < s->total_height; y++) {
521         c = &cells[y * s->width];
522         if (w1 > 0) {
523             c1 = &s->cells[y * last_width];
524             for(x = 0; x < w1; x++) {
525                 *c++ = *c1++;
526             }
527         }
528         for(x = w1; x < s->width; x++) {
529             c->ch = ' ';
530             c->t_attrib = s->t_attrib_default;
531             c++;
532         }
533     }
534     g_free(s->cells);
535     s->cells = cells;
536 }
537
538 static inline void text_update_xy(TextConsole *s, int x, int y)
539 {
540     s->text_x[0] = MIN(s->text_x[0], x);
541     s->text_x[1] = MAX(s->text_x[1], x);
542     s->text_y[0] = MIN(s->text_y[0], y);
543     s->text_y[1] = MAX(s->text_y[1], y);
544 }
545
546 static void invalidate_xy(TextConsole *s, int x, int y)
547 {
548     if (s->update_x0 > x * FONT_WIDTH)
549         s->update_x0 = x * FONT_WIDTH;
550     if (s->update_y0 > y * FONT_HEIGHT)
551         s->update_y0 = y * FONT_HEIGHT;
552     if (s->update_x1 < (x + 1) * FONT_WIDTH)
553         s->update_x1 = (x + 1) * FONT_WIDTH;
554     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
555         s->update_y1 = (y + 1) * FONT_HEIGHT;
556 }
557
558 static void update_xy(TextConsole *s, int x, int y)
559 {
560     TextCell *c;
561     int y1, y2;
562
563     if (s == active_console) {
564         if (!ds_get_bits_per_pixel(s->ds)) {
565             text_update_xy(s, x, y);
566             return;
567         }
568
569         y1 = (s->y_base + y) % s->total_height;
570         y2 = y1 - s->y_displayed;
571         if (y2 < 0)
572             y2 += s->total_height;
573         if (y2 < s->height) {
574             c = &s->cells[y1 * s->width + x];
575             vga_putcharxy(s->ds, x, y2, c->ch,
576                           &(c->t_attrib));
577             invalidate_xy(s, x, y2);
578         }
579     }
580 }
581
582 static void console_show_cursor(TextConsole *s, int show)
583 {
584     TextCell *c;
585     int y, y1;
586
587     if (s == active_console) {
588         int x = s->x;
589
590         if (!ds_get_bits_per_pixel(s->ds)) {
591             s->cursor_invalidate = 1;
592             return;
593         }
594
595         if (x >= s->width) {
596             x = s->width - 1;
597         }
598         y1 = (s->y_base + s->y) % s->total_height;
599         y = y1 - s->y_displayed;
600         if (y < 0)
601             y += s->total_height;
602         if (y < s->height) {
603             c = &s->cells[y1 * s->width + x];
604             if (show) {
605                 TextAttributes t_attrib = s->t_attrib_default;
606                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
607                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
608             } else {
609                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
610             }
611             invalidate_xy(s, x, y);
612         }
613     }
614 }
615
616 static void console_refresh(TextConsole *s)
617 {
618     TextCell *c;
619     int x, y, y1;
620
621     if (s != active_console)
622         return;
623     if (!ds_get_bits_per_pixel(s->ds)) {
624         s->text_x[0] = 0;
625         s->text_y[0] = 0;
626         s->text_x[1] = s->width - 1;
627         s->text_y[1] = s->height - 1;
628         s->cursor_invalidate = 1;
629         return;
630     }
631
632     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
633                   color_table[0][COLOR_BLACK]);
634     y1 = s->y_displayed;
635     for(y = 0; y < s->height; y++) {
636         c = s->cells + y1 * s->width;
637         for(x = 0; x < s->width; x++) {
638             vga_putcharxy(s->ds, x, y, c->ch,
639                           &(c->t_attrib));
640             c++;
641         }
642         if (++y1 == s->total_height)
643             y1 = 0;
644     }
645     console_show_cursor(s, 1);
646     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
647 }
648
649 static void console_scroll(int ydelta)
650 {
651     TextConsole *s;
652     int i, y1;
653
654     s = active_console;
655     if (!s || (s->console_type == GRAPHIC_CONSOLE))
656         return;
657
658     if (ydelta > 0) {
659         for(i = 0; i < ydelta; i++) {
660             if (s->y_displayed == s->y_base)
661                 break;
662             if (++s->y_displayed == s->total_height)
663                 s->y_displayed = 0;
664         }
665     } else {
666         ydelta = -ydelta;
667         i = s->backscroll_height;
668         if (i > s->total_height - s->height)
669             i = s->total_height - s->height;
670         y1 = s->y_base - i;
671         if (y1 < 0)
672             y1 += s->total_height;
673         for(i = 0; i < ydelta; i++) {
674             if (s->y_displayed == y1)
675                 break;
676             if (--s->y_displayed < 0)
677                 s->y_displayed = s->total_height - 1;
678         }
679     }
680     console_refresh(s);
681 }
682
683 static void console_put_lf(TextConsole *s)
684 {
685     TextCell *c;
686     int x, y1;
687
688     s->y++;
689     if (s->y >= s->height) {
690         s->y = s->height - 1;
691
692         if (s->y_displayed == s->y_base) {
693             if (++s->y_displayed == s->total_height)
694                 s->y_displayed = 0;
695         }
696         if (++s->y_base == s->total_height)
697             s->y_base = 0;
698         if (s->backscroll_height < s->total_height)
699             s->backscroll_height++;
700         y1 = (s->y_base + s->height - 1) % s->total_height;
701         c = &s->cells[y1 * s->width];
702         for(x = 0; x < s->width; x++) {
703             c->ch = ' ';
704             c->t_attrib = s->t_attrib_default;
705             c++;
706         }
707         if (s == active_console && s->y_displayed == s->y_base) {
708             if (!ds_get_bits_per_pixel(s->ds)) {
709                 s->text_x[0] = 0;
710                 s->text_y[0] = 0;
711                 s->text_x[1] = s->width - 1;
712                 s->text_y[1] = s->height - 1;
713                 return;
714             }
715
716             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
717                        s->width * FONT_WIDTH,
718                        (s->height - 1) * FONT_HEIGHT);
719             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
720                           s->width * FONT_WIDTH, FONT_HEIGHT,
721                           color_table[0][s->t_attrib_default.bgcol]);
722             s->update_x0 = 0;
723             s->update_y0 = 0;
724             s->update_x1 = s->width * FONT_WIDTH;
725             s->update_y1 = s->height * FONT_HEIGHT;
726         }
727     }
728 }
729
730 /* Set console attributes depending on the current escape codes.
731  * NOTE: I know this code is not very efficient (checking every color for it
732  * self) but it is more readable and better maintainable.
733  */
734 static void console_handle_escape(TextConsole *s)
735 {
736     int i;
737
738     for (i=0; i<s->nb_esc_params; i++) {
739         switch (s->esc_params[i]) {
740             case 0: /* reset all console attributes to default */
741                 s->t_attrib = s->t_attrib_default;
742                 break;
743             case 1:
744                 s->t_attrib.bold = 1;
745                 break;
746             case 4:
747                 s->t_attrib.uline = 1;
748                 break;
749             case 5:
750                 s->t_attrib.blink = 1;
751                 break;
752             case 7:
753                 s->t_attrib.invers = 1;
754                 break;
755             case 8:
756                 s->t_attrib.unvisible = 1;
757                 break;
758             case 22:
759                 s->t_attrib.bold = 0;
760                 break;
761             case 24:
762                 s->t_attrib.uline = 0;
763                 break;
764             case 25:
765                 s->t_attrib.blink = 0;
766                 break;
767             case 27:
768                 s->t_attrib.invers = 0;
769                 break;
770             case 28:
771                 s->t_attrib.unvisible = 0;
772                 break;
773             /* set foreground color */
774             case 30:
775                 s->t_attrib.fgcol=COLOR_BLACK;
776                 break;
777             case 31:
778                 s->t_attrib.fgcol=COLOR_RED;
779                 break;
780             case 32:
781                 s->t_attrib.fgcol=COLOR_GREEN;
782                 break;
783             case 33:
784                 s->t_attrib.fgcol=COLOR_YELLOW;
785                 break;
786             case 34:
787                 s->t_attrib.fgcol=COLOR_BLUE;
788                 break;
789             case 35:
790                 s->t_attrib.fgcol=COLOR_MAGENTA;
791                 break;
792             case 36:
793                 s->t_attrib.fgcol=COLOR_CYAN;
794                 break;
795             case 37:
796                 s->t_attrib.fgcol=COLOR_WHITE;
797                 break;
798             /* set background color */
799             case 40:
800                 s->t_attrib.bgcol=COLOR_BLACK;
801                 break;
802             case 41:
803                 s->t_attrib.bgcol=COLOR_RED;
804                 break;
805             case 42:
806                 s->t_attrib.bgcol=COLOR_GREEN;
807                 break;
808             case 43:
809                 s->t_attrib.bgcol=COLOR_YELLOW;
810                 break;
811             case 44:
812                 s->t_attrib.bgcol=COLOR_BLUE;
813                 break;
814             case 45:
815                 s->t_attrib.bgcol=COLOR_MAGENTA;
816                 break;
817             case 46:
818                 s->t_attrib.bgcol=COLOR_CYAN;
819                 break;
820             case 47:
821                 s->t_attrib.bgcol=COLOR_WHITE;
822                 break;
823         }
824     }
825 }
826
827 static void console_clear_xy(TextConsole *s, int x, int y)
828 {
829     int y1 = (s->y_base + y) % s->total_height;
830     TextCell *c = &s->cells[y1 * s->width + x];
831     c->ch = ' ';
832     c->t_attrib = s->t_attrib_default;
833     update_xy(s, x, y);
834 }
835
836 static void console_putchar(TextConsole *s, int ch)
837 {
838     TextCell *c;
839     int y1, i;
840     int x, y;
841
842     switch(s->state) {
843     case TTY_STATE_NORM:
844         switch(ch) {
845         case '\r':  /* carriage return */
846             s->x = 0;
847             break;
848         case '\n':  /* newline */
849             console_put_lf(s);
850             break;
851         case '\b':  /* backspace */
852             if (s->x > 0)
853                 s->x--;
854             break;
855         case '\t':  /* tabspace */
856             if (s->x + (8 - (s->x % 8)) > s->width) {
857                 s->x = 0;
858                 console_put_lf(s);
859             } else {
860                 s->x = s->x + (8 - (s->x % 8));
861             }
862             break;
863         case '\a':  /* alert aka. bell */
864             /* TODO: has to be implemented */
865             break;
866         case 14:
867             /* SI (shift in), character set 0 (ignored) */
868             break;
869         case 15:
870             /* SO (shift out), character set 1 (ignored) */
871             break;
872         case 27:    /* esc (introducing an escape sequence) */
873             s->state = TTY_STATE_ESC;
874             break;
875         default:
876             if (s->x >= s->width) {
877                 /* line wrap */
878                 s->x = 0;
879                 console_put_lf(s);
880             }
881             y1 = (s->y_base + s->y) % s->total_height;
882             c = &s->cells[y1 * s->width + s->x];
883             c->ch = ch;
884             c->t_attrib = s->t_attrib;
885             update_xy(s, s->x, s->y);
886             s->x++;
887             break;
888         }
889         break;
890     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
891         if (ch == '[') {
892             for(i=0;i<MAX_ESC_PARAMS;i++)
893                 s->esc_params[i] = 0;
894             s->nb_esc_params = 0;
895             s->state = TTY_STATE_CSI;
896         } else {
897             s->state = TTY_STATE_NORM;
898         }
899         break;
900     case TTY_STATE_CSI: /* handle escape sequence parameters */
901         if (ch >= '0' && ch <= '9') {
902             if (s->nb_esc_params < MAX_ESC_PARAMS) {
903                 s->esc_params[s->nb_esc_params] =
904                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
905             }
906         } else {
907             s->nb_esc_params++;
908             if (ch == ';')
909                 break;
910 #ifdef DEBUG_CONSOLE
911             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
912                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
913 #endif
914             s->state = TTY_STATE_NORM;
915             switch(ch) {
916             case 'A':
917                 /* move cursor up */
918                 if (s->esc_params[0] == 0) {
919                     s->esc_params[0] = 1;
920                 }
921                 s->y -= s->esc_params[0];
922                 if (s->y < 0) {
923                     s->y = 0;
924                 }
925                 break;
926             case 'B':
927                 /* move cursor down */
928                 if (s->esc_params[0] == 0) {
929                     s->esc_params[0] = 1;
930                 }
931                 s->y += s->esc_params[0];
932                 if (s->y >= s->height) {
933                     s->y = s->height - 1;
934                 }
935                 break;
936             case 'C':
937                 /* move cursor right */
938                 if (s->esc_params[0] == 0) {
939                     s->esc_params[0] = 1;
940                 }
941                 s->x += s->esc_params[0];
942                 if (s->x >= s->width) {
943                     s->x = s->width - 1;
944                 }
945                 break;
946             case 'D':
947                 /* move cursor left */
948                 if (s->esc_params[0] == 0) {
949                     s->esc_params[0] = 1;
950                 }
951                 s->x -= s->esc_params[0];
952                 if (s->x < 0) {
953                     s->x = 0;
954                 }
955                 break;
956             case 'G':
957                 /* move cursor to column */
958                 s->x = s->esc_params[0] - 1;
959                 if (s->x < 0) {
960                     s->x = 0;
961                 }
962                 break;
963             case 'f':
964             case 'H':
965                 /* move cursor to row, column */
966                 s->x = s->esc_params[1] - 1;
967                 if (s->x < 0) {
968                     s->x = 0;
969                 }
970                 s->y = s->esc_params[0] - 1;
971                 if (s->y < 0) {
972                     s->y = 0;
973                 }
974                 break;
975             case 'J':
976                 switch (s->esc_params[0]) {
977                 case 0:
978                     /* clear to end of screen */
979                     for (y = s->y; y < s->height; y++) {
980                         for (x = 0; x < s->width; x++) {
981                             if (y == s->y && x < s->x) {
982                                 continue;
983                             }
984                             console_clear_xy(s, x, y);
985                         }
986                     }
987                     break;
988                 case 1:
989                     /* clear from beginning of screen */
990                     for (y = 0; y <= s->y; y++) {
991                         for (x = 0; x < s->width; x++) {
992                             if (y == s->y && x > s->x) {
993                                 break;
994                             }
995                             console_clear_xy(s, x, y);
996                         }
997                     }
998                     break;
999                 case 2:
1000                     /* clear entire screen */
1001                     for (y = 0; y <= s->height; y++) {
1002                         for (x = 0; x < s->width; x++) {
1003                             console_clear_xy(s, x, y);
1004                         }
1005                     }
1006                 break;
1007                 }
1008             case 'K':
1009                 switch (s->esc_params[0]) {
1010                 case 0:
1011                 /* clear to eol */
1012                 for(x = s->x; x < s->width; x++) {
1013                         console_clear_xy(s, x, s->y);
1014                 }
1015                 break;
1016                 case 1:
1017                     /* clear from beginning of line */
1018                     for (x = 0; x <= s->x; x++) {
1019                         console_clear_xy(s, x, s->y);
1020                     }
1021                     break;
1022                 case 2:
1023                     /* clear entire line */
1024                     for(x = 0; x < s->width; x++) {
1025                         console_clear_xy(s, x, s->y);
1026                     }
1027                 break;
1028             }
1029                 break;
1030             case 'm':
1031             console_handle_escape(s);
1032             break;
1033             case 'n':
1034                 /* report cursor position */
1035                 /* TODO: send ESC[row;colR */
1036                 break;
1037             case 's':
1038                 /* save cursor position */
1039                 s->x_saved = s->x;
1040                 s->y_saved = s->y;
1041                 break;
1042             case 'u':
1043                 /* restore cursor position */
1044                 s->x = s->x_saved;
1045                 s->y = s->y_saved;
1046                 break;
1047             default:
1048 #ifdef DEBUG_CONSOLE
1049                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1050 #endif
1051                 break;
1052             }
1053             break;
1054         }
1055     }
1056 }
1057
1058 void console_select(unsigned int index)
1059 {
1060     TextConsole *s;
1061
1062     if (index >= MAX_CONSOLES)
1063         return;
1064     if (active_console) {
1065         active_console->g_width = ds_get_width(active_console->ds);
1066         active_console->g_height = ds_get_height(active_console->ds);
1067     }
1068     s = consoles[index];
1069     if (s) {
1070         DisplayState *ds = s->ds;
1071         active_console = s;
1072         if (ds_get_bits_per_pixel(s->ds)) {
1073             ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1074         } else {
1075             s->ds->surface->width = s->width;
1076             s->ds->surface->height = s->height;
1077         }
1078         dpy_resize(s->ds);
1079         vga_hw_invalidate();
1080     }
1081 }
1082
1083 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1084 {
1085     TextConsole *s = chr->opaque;
1086     int i;
1087
1088     s->update_x0 = s->width * FONT_WIDTH;
1089     s->update_y0 = s->height * FONT_HEIGHT;
1090     s->update_x1 = 0;
1091     s->update_y1 = 0;
1092     console_show_cursor(s, 0);
1093     for(i = 0; i < len; i++) {
1094         console_putchar(s, buf[i]);
1095     }
1096     console_show_cursor(s, 1);
1097     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1098         dpy_update(s->ds, s->update_x0, s->update_y0,
1099                    s->update_x1 - s->update_x0,
1100                    s->update_y1 - s->update_y0);
1101     }
1102     return len;
1103 }
1104
1105 static void console_send_event(CharDriverState *chr, int event)
1106 {
1107     TextConsole *s = chr->opaque;
1108     int i;
1109
1110     if (event == CHR_EVENT_FOCUS) {
1111         for(i = 0; i < nb_consoles; i++) {
1112             if (consoles[i] == s) {
1113                 console_select(i);
1114                 break;
1115             }
1116         }
1117     }
1118 }
1119
1120 static void kbd_send_chars(void *opaque)
1121 {
1122     TextConsole *s = opaque;
1123     int len;
1124     uint8_t buf[16];
1125
1126     len = qemu_chr_can_read(s->chr);
1127     if (len > s->out_fifo.count)
1128         len = s->out_fifo.count;
1129     if (len > 0) {
1130         if (len > sizeof(buf))
1131             len = sizeof(buf);
1132         qemu_fifo_read(&s->out_fifo, buf, len);
1133         qemu_chr_read(s->chr, buf, len);
1134     }
1135     /* characters are pending: we send them a bit later (XXX:
1136        horrible, should change char device API) */
1137     if (s->out_fifo.count > 0) {
1138         qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1139     }
1140 }
1141
1142 /* called when an ascii key is pressed */
1143 void kbd_put_keysym(int keysym)
1144 {
1145     TextConsole *s;
1146     uint8_t buf[16], *q;
1147     int c;
1148
1149     s = active_console;
1150     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1151         return;
1152
1153     switch(keysym) {
1154     case QEMU_KEY_CTRL_UP:
1155         console_scroll(-1);
1156         break;
1157     case QEMU_KEY_CTRL_DOWN:
1158         console_scroll(1);
1159         break;
1160     case QEMU_KEY_CTRL_PAGEUP:
1161         console_scroll(-10);
1162         break;
1163     case QEMU_KEY_CTRL_PAGEDOWN:
1164         console_scroll(10);
1165         break;
1166     default:
1167         /* convert the QEMU keysym to VT100 key string */
1168         q = buf;
1169         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1170             *q++ = '\033';
1171             *q++ = '[';
1172             c = keysym - 0xe100;
1173             if (c >= 10)
1174                 *q++ = '0' + (c / 10);
1175             *q++ = '0' + (c % 10);
1176             *q++ = '~';
1177         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1178             *q++ = '\033';
1179             *q++ = '[';
1180             *q++ = keysym & 0xff;
1181         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1182             console_puts(s->chr, (const uint8_t *) "\r", 1);
1183             *q++ = '\n';
1184         } else {
1185             *q++ = keysym;
1186         }
1187         if (s->echo) {
1188             console_puts(s->chr, buf, q - buf);
1189         }
1190         if (s->chr->chr_read) {
1191             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192             kbd_send_chars(s);
1193         }
1194         break;
1195     }
1196 }
1197
1198 static void text_console_invalidate(void *opaque)
1199 {
1200     TextConsole *s = (TextConsole *) opaque;
1201     if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1202         s->g_width = ds_get_width(s->ds);
1203         s->g_height = ds_get_height(s->ds);
1204         text_console_resize(s);
1205     }
1206     console_refresh(s);
1207 }
1208
1209 static void text_console_update(void *opaque, console_ch_t *chardata)
1210 {
1211     TextConsole *s = (TextConsole *) opaque;
1212     int i, j, src;
1213
1214     if (s->text_x[0] <= s->text_x[1]) {
1215         src = (s->y_base + s->text_y[0]) * s->width;
1216         chardata += s->text_y[0] * s->width;
1217         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1218             for (j = 0; j < s->width; j ++, src ++)
1219                 console_write_ch(chardata ++, s->cells[src].ch |
1220                                 (s->cells[src].t_attrib.fgcol << 12) |
1221                                 (s->cells[src].t_attrib.bgcol << 8) |
1222                                 (s->cells[src].t_attrib.bold << 21));
1223         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1224                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1225         s->text_x[0] = s->width;
1226         s->text_y[0] = s->height;
1227         s->text_x[1] = 0;
1228         s->text_y[1] = 0;
1229     }
1230     if (s->cursor_invalidate) {
1231         dpy_cursor(s->ds, s->x, s->y);
1232         s->cursor_invalidate = 0;
1233     }
1234 }
1235
1236 static TextConsole *get_graphic_console(DisplayState *ds)
1237 {
1238     int i;
1239     TextConsole *s;
1240     for (i = 0; i < nb_consoles; i++) {
1241         s = consoles[i];
1242         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1243             return s;
1244     }
1245     return NULL;
1246 }
1247
1248 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1249 {
1250     TextConsole *s;
1251     int i;
1252
1253     if (nb_consoles >= MAX_CONSOLES)
1254         return NULL;
1255     s = g_malloc0(sizeof(TextConsole));
1256     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257         (console_type == GRAPHIC_CONSOLE))) {
1258         active_console = s;
1259     }
1260     s->ds = ds;
1261     s->console_type = console_type;
1262     if (console_type != GRAPHIC_CONSOLE) {
1263         consoles[nb_consoles++] = s;
1264     } else {
1265         /* HACK: Put graphical consoles before text consoles.  */
1266         for (i = nb_consoles; i > 0; i--) {
1267             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1268                 break;
1269             consoles[i] = consoles[i - 1];
1270         }
1271         consoles[i] = s;
1272         nb_consoles++;
1273     }
1274     return s;
1275 }
1276
1277 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1278 {
1279     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1280
1281     int linesize = width * 4;
1282     qemu_alloc_display(surface, width, height, linesize,
1283                        qemu_default_pixelformat(32), 0);
1284     return surface;
1285 }
1286
1287 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1288                                           int width, int height)
1289 {
1290     int linesize = width * 4;
1291     qemu_alloc_display(surface, width, height, linesize,
1292                        qemu_default_pixelformat(32), 0);
1293     return surface;
1294 }
1295
1296 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1297                         int linesize, PixelFormat pf, int newflags)
1298 {
1299     void *data;
1300     surface->width = width;
1301     surface->height = height;
1302     surface->linesize = linesize;
1303     surface->pf = pf;
1304     if (surface->flags & QEMU_ALLOCATED_FLAG) {
1305         data = g_realloc(surface->data,
1306                             surface->linesize * surface->height);
1307     } else {
1308         data = g_malloc(surface->linesize * surface->height);
1309     }
1310     surface->data = (uint8_t *)data;
1311     surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1312 #ifdef HOST_WORDS_BIGENDIAN
1313     surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1314 #endif
1315 }
1316
1317 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1318                                               int linesize, uint8_t *data)
1319 {
1320     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1321
1322     surface->width = width;
1323     surface->height = height;
1324     surface->linesize = linesize;
1325     surface->pf = qemu_default_pixelformat(bpp);
1326 #ifdef HOST_WORDS_BIGENDIAN
1327     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1328 #endif
1329     surface->data = data;
1330
1331     return surface;
1332 }
1333
1334 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1335 {
1336     if (surface == NULL)
1337         return;
1338     if (surface->flags & QEMU_ALLOCATED_FLAG)
1339         g_free(surface->data);
1340     g_free(surface);
1341 }
1342
1343 static struct DisplayAllocator default_allocator = {
1344     defaultallocator_create_displaysurface,
1345     defaultallocator_resize_displaysurface,
1346     defaultallocator_free_displaysurface
1347 };
1348
1349 static void dumb_display_init(void)
1350 {
1351     DisplayState *ds = g_malloc0(sizeof(DisplayState));
1352     int width = 640;
1353     int height = 480;
1354
1355     ds->allocator = &default_allocator;
1356     if (is_fixedsize_console()) {
1357         width = active_console->g_width;
1358         height = active_console->g_height;
1359     }
1360     ds->surface = qemu_create_displaysurface(ds, width, height);
1361     register_displaystate(ds);
1362 }
1363
1364 /***********************************************************/
1365 /* register display */
1366
1367 void register_displaystate(DisplayState *ds)
1368 {
1369     DisplayState **s;
1370     s = &display_state;
1371     while (*s != NULL)
1372         s = &(*s)->next;
1373     ds->next = NULL;
1374     *s = ds;
1375 }
1376
1377 DisplayState *get_displaystate(void)
1378 {
1379     if (!display_state) {
1380         dumb_display_init ();
1381     }
1382     return display_state;
1383 }
1384
1385 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1386 {
1387     if(ds->allocator ==  &default_allocator) {
1388         DisplaySurface *surf;
1389         surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1390         defaultallocator_free_displaysurface(ds->surface);
1391         ds->surface = surf;
1392         ds->allocator = da;
1393     }
1394     return ds->allocator;
1395 }
1396
1397 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1398                                    vga_hw_invalidate_ptr invalidate,
1399                                    vga_hw_screen_dump_ptr screen_dump,
1400                                    vga_hw_text_update_ptr text_update,
1401                                    void *opaque)
1402 {
1403     TextConsole *s;
1404     DisplayState *ds;
1405
1406     ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1407     ds->allocator = &default_allocator; 
1408     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1409
1410     s = new_console(ds, GRAPHIC_CONSOLE);
1411     if (s == NULL) {
1412         qemu_free_displaysurface(ds);
1413         g_free(ds);
1414         return NULL;
1415     }
1416     s->hw_update = update;
1417     s->hw_invalidate = invalidate;
1418     s->hw_screen_dump = screen_dump;
1419     s->hw_text_update = text_update;
1420     s->hw = opaque;
1421
1422     register_displaystate(ds);
1423     return ds;
1424 }
1425
1426 int is_graphic_console(void)
1427 {
1428     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1429 }
1430
1431 int is_fixedsize_console(void)
1432 {
1433     return active_console && active_console->console_type != TEXT_CONSOLE;
1434 }
1435
1436 void console_color_init(DisplayState *ds)
1437 {
1438     int i, j;
1439     for (j = 0; j < 2; j++) {
1440         for (i = 0; i < 8; i++) {
1441             color_table[j][i] = col_expand(ds,
1442                    vga_get_color(ds, color_table_rgb[j][i]));
1443         }
1444     }
1445 }
1446
1447 static int n_text_consoles;
1448 static CharDriverState *text_consoles[128];
1449
1450 static void text_console_set_echo(CharDriverState *chr, bool echo)
1451 {
1452     TextConsole *s = chr->opaque;
1453
1454     s->echo = echo;
1455 }
1456
1457 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1458 {
1459     TextConsole *s;
1460     static int color_inited;
1461
1462     s = chr->opaque;
1463
1464     chr->chr_write = console_puts;
1465     chr->chr_send_event = console_send_event;
1466
1467     s->out_fifo.buf = s->out_fifo_buf;
1468     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1469     s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1470     s->ds = ds;
1471
1472     if (!color_inited) {
1473         color_inited = 1;
1474         console_color_init(s->ds);
1475     }
1476     s->y_displayed = 0;
1477     s->y_base = 0;
1478     s->total_height = DEFAULT_BACKSCROLL;
1479     s->x = 0;
1480     s->y = 0;
1481     if (s->console_type == TEXT_CONSOLE) {
1482         s->g_width = ds_get_width(s->ds);
1483         s->g_height = ds_get_height(s->ds);
1484     }
1485
1486     s->hw_invalidate = text_console_invalidate;
1487     s->hw_text_update = text_console_update;
1488     s->hw = s;
1489
1490     /* Set text attribute defaults */
1491     s->t_attrib_default.bold = 0;
1492     s->t_attrib_default.uline = 0;
1493     s->t_attrib_default.blink = 0;
1494     s->t_attrib_default.invers = 0;
1495     s->t_attrib_default.unvisible = 0;
1496     s->t_attrib_default.fgcol = COLOR_WHITE;
1497     s->t_attrib_default.bgcol = COLOR_BLACK;
1498     /* set current text attributes to default */
1499     s->t_attrib = s->t_attrib_default;
1500     text_console_resize(s);
1501
1502     if (chr->label) {
1503         char msg[128];
1504         int len;
1505
1506         s->t_attrib.bgcol = COLOR_BLUE;
1507         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1508         console_puts(chr, (uint8_t*)msg, len);
1509         s->t_attrib = s->t_attrib_default;
1510     }
1511
1512     qemu_chr_generic_open(chr);
1513     if (chr->init)
1514         chr->init(chr);
1515 }
1516
1517 int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1518 {
1519     CharDriverState *chr;
1520     TextConsole *s;
1521     unsigned width;
1522     unsigned height;
1523
1524     chr = g_malloc0(sizeof(CharDriverState));
1525
1526     if (n_text_consoles == 128) {
1527         fprintf(stderr, "Too many text consoles\n");
1528         exit(1);
1529     }
1530     text_consoles[n_text_consoles] = chr;
1531     n_text_consoles++;
1532
1533     width = qemu_opt_get_number(opts, "width", 0);
1534     if (width == 0)
1535         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1536
1537     height = qemu_opt_get_number(opts, "height", 0);
1538     if (height == 0)
1539         height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1540
1541     if (width == 0 || height == 0) {
1542         s = new_console(NULL, TEXT_CONSOLE);
1543     } else {
1544         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1545     }
1546
1547     if (!s) {
1548         free(chr);
1549         return -EBUSY;
1550     }
1551
1552     s->chr = chr;
1553     s->g_width = width;
1554     s->g_height = height;
1555     chr->opaque = s;
1556     chr->chr_set_echo = text_console_set_echo;
1557
1558     *_chr = chr;
1559     return 0;
1560 }
1561
1562 void text_consoles_set_display(DisplayState *ds)
1563 {
1564     int i;
1565
1566     for (i = 0; i < n_text_consoles; i++) {
1567         text_console_do_init(text_consoles[i], ds);
1568     }
1569
1570     n_text_consoles = 0;
1571 }
1572
1573 void qemu_console_resize(DisplayState *ds, int width, int height)
1574 {
1575     TextConsole *s = get_graphic_console(ds);
1576     if (!s) return;
1577
1578     s->g_width = width;
1579     s->g_height = height;
1580     if (is_graphic_console()) {
1581         ds->surface = qemu_resize_displaysurface(ds, width, height);
1582         dpy_resize(ds);
1583     }
1584 }
1585
1586 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1587                        int dst_x, int dst_y, int w, int h)
1588 {
1589     if (is_graphic_console()) {
1590         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1591     }
1592 }
1593
1594 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1595 {
1596     PixelFormat pf;
1597
1598     memset(&pf, 0x00, sizeof(PixelFormat));
1599
1600     pf.bits_per_pixel = bpp;
1601     pf.bytes_per_pixel = bpp / 8;
1602     pf.depth = bpp == 32 ? 24 : bpp;
1603
1604     switch (bpp) {
1605         case 24:
1606             pf.rmask = 0x000000FF;
1607             pf.gmask = 0x0000FF00;
1608             pf.bmask = 0x00FF0000;
1609             pf.rmax = 255;
1610             pf.gmax = 255;
1611             pf.bmax = 255;
1612             pf.rshift = 0;
1613             pf.gshift = 8;
1614             pf.bshift = 16;
1615             pf.rbits = 8;
1616             pf.gbits = 8;
1617             pf.bbits = 8;
1618             break;
1619         case 32:
1620             pf.rmask = 0x0000FF00;
1621             pf.gmask = 0x00FF0000;
1622             pf.bmask = 0xFF000000;
1623             pf.amask = 0x00000000;
1624             pf.amax = 255;
1625             pf.rmax = 255;
1626             pf.gmax = 255;
1627             pf.bmax = 255;
1628             pf.ashift = 0;
1629             pf.rshift = 8;
1630             pf.gshift = 16;
1631             pf.bshift = 24;
1632             pf.rbits = 8;
1633             pf.gbits = 8;
1634             pf.bbits = 8;
1635             pf.abits = 8;
1636             break;
1637         default:
1638             break;
1639     }
1640     return pf;
1641 }
1642
1643 PixelFormat qemu_default_pixelformat(int bpp)
1644 {
1645     PixelFormat pf;
1646
1647     memset(&pf, 0x00, sizeof(PixelFormat));
1648
1649     pf.bits_per_pixel = bpp;
1650     pf.bytes_per_pixel = bpp / 8;
1651     pf.depth = bpp == 32 ? 24 : bpp;
1652
1653     switch (bpp) {
1654         case 15:
1655             pf.bits_per_pixel = 16;
1656             pf.bytes_per_pixel = 2;
1657             pf.rmask = 0x00007c00;
1658             pf.gmask = 0x000003E0;
1659             pf.bmask = 0x0000001F;
1660             pf.rmax = 31;
1661             pf.gmax = 31;
1662             pf.bmax = 31;
1663             pf.rshift = 10;
1664             pf.gshift = 5;
1665             pf.bshift = 0;
1666             pf.rbits = 5;
1667             pf.gbits = 5;
1668             pf.bbits = 5;
1669             break;
1670         case 16:
1671             pf.rmask = 0x0000F800;
1672             pf.gmask = 0x000007E0;
1673             pf.bmask = 0x0000001F;
1674             pf.rmax = 31;
1675             pf.gmax = 63;
1676             pf.bmax = 31;
1677             pf.rshift = 11;
1678             pf.gshift = 5;
1679             pf.bshift = 0;
1680             pf.rbits = 5;
1681             pf.gbits = 6;
1682             pf.bbits = 5;
1683             break;
1684         case 24:
1685             pf.rmask = 0x00FF0000;
1686             pf.gmask = 0x0000FF00;
1687             pf.bmask = 0x000000FF;
1688             pf.rmax = 255;
1689             pf.gmax = 255;
1690             pf.bmax = 255;
1691             pf.rshift = 16;
1692             pf.gshift = 8;
1693             pf.bshift = 0;
1694             pf.rbits = 8;
1695             pf.gbits = 8;
1696             pf.bbits = 8;
1697         case 32:
1698             pf.rmask = 0x00FF0000;
1699             pf.gmask = 0x0000FF00;
1700             pf.bmask = 0x000000FF;
1701             pf.amax = 255;
1702             pf.rmax = 255;
1703             pf.gmax = 255;
1704             pf.bmax = 255;
1705             pf.ashift = 24;
1706             pf.rshift = 16;
1707             pf.gshift = 8;
1708             pf.bshift = 0;
1709             pf.rbits = 8;
1710             pf.gbits = 8;
1711             pf.bbits = 8;
1712             pf.abits = 8;
1713             break;
1714         default:
1715             break;
1716     }
1717     return pf;
1718 }