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