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