xref: /openbmc/qemu/ui/console.c (revision c71c3e99)
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 "ui/console.h"
26 #include "qemu/timer.h"
27 #include "qmp-commands.h"
28 #include "char/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");
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                                                 bool byteswap)
1344 {
1345     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1346 
1347     if (byteswap) {
1348         surface->pf = qemu_different_endianness_pixelformat(bpp);
1349     } else {
1350         surface->pf = qemu_default_pixelformat(bpp);
1351     }
1352 
1353     surface->format = qemu_pixman_get_format(&surface->pf);
1354     assert(surface->format != 0);
1355     surface->image = pixman_image_create_bits(surface->format,
1356                                               width, height,
1357                                               (void *)data, linesize);
1358     assert(surface->image != NULL);
1359 
1360 #ifdef HOST_WORDS_BIGENDIAN
1361     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1362 #endif
1363 
1364     return surface;
1365 }
1366 
1367 void qemu_free_displaysurface(DisplayState *ds)
1368 {
1369     trace_displaysurface_free(ds, ds->surface);
1370     if (ds->surface == NULL) {
1371         return;
1372     }
1373     qemu_pixman_image_unref(ds->surface->image);
1374     g_free(ds->surface);
1375 }
1376 
1377 static void dumb_display_init(void)
1378 {
1379     DisplayState *ds = g_malloc0(sizeof(DisplayState));
1380     int width = 640;
1381     int height = 480;
1382 
1383     if (is_fixedsize_console()) {
1384         width = active_console->g_width;
1385         height = active_console->g_height;
1386     }
1387     ds->surface = qemu_create_displaysurface(ds, width, height);
1388     register_displaystate(ds);
1389 }
1390 
1391 /***********************************************************/
1392 /* register display */
1393 
1394 void register_displaystate(DisplayState *ds)
1395 {
1396     DisplayState **s;
1397     s = &display_state;
1398     while (*s != NULL)
1399         s = &(*s)->next;
1400     ds->next = NULL;
1401     *s = ds;
1402 }
1403 
1404 DisplayState *get_displaystate(void)
1405 {
1406     if (!display_state) {
1407         dumb_display_init ();
1408     }
1409     return display_state;
1410 }
1411 
1412 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1413                                    vga_hw_invalidate_ptr invalidate,
1414                                    vga_hw_screen_dump_ptr screen_dump,
1415                                    vga_hw_text_update_ptr text_update,
1416                                    void *opaque)
1417 {
1418     QemuConsole *s;
1419     DisplayState *ds;
1420 
1421     ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1422     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1423 
1424     s = new_console(ds, GRAPHIC_CONSOLE);
1425     if (s == NULL) {
1426         qemu_free_displaysurface(ds);
1427         g_free(ds);
1428         return NULL;
1429     }
1430     s->hw_update = update;
1431     s->hw_invalidate = invalidate;
1432     s->hw_screen_dump = screen_dump;
1433     s->hw_text_update = text_update;
1434     s->hw = opaque;
1435 
1436     register_displaystate(ds);
1437     return ds;
1438 }
1439 
1440 int is_graphic_console(void)
1441 {
1442     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1443 }
1444 
1445 int is_fixedsize_console(void)
1446 {
1447     return active_console && active_console->console_type != TEXT_CONSOLE;
1448 }
1449 
1450 void console_color_init(DisplayState *ds)
1451 {
1452     int i, j;
1453     for (j = 0; j < 2; j++) {
1454         for (i = 0; i < 8; i++) {
1455             color_table[j][i] = col_expand(ds,
1456                    vga_get_color(ds, color_table_rgb[j][i]));
1457         }
1458     }
1459 }
1460 
1461 static void text_console_set_echo(CharDriverState *chr, bool echo)
1462 {
1463     QemuConsole *s = chr->opaque;
1464 
1465     s->echo = echo;
1466 }
1467 
1468 static void text_console_update_cursor(void *opaque)
1469 {
1470     QemuConsole *s = opaque;
1471 
1472     s->cursor_visible_phase = !s->cursor_visible_phase;
1473     vga_hw_invalidate();
1474     qemu_mod_timer(s->cursor_timer,
1475                    qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1476 }
1477 
1478 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1479 {
1480     QemuConsole *s;
1481     static int color_inited;
1482 
1483     s = chr->opaque;
1484 
1485     chr->chr_write = console_puts;
1486 
1487     s->out_fifo.buf = s->out_fifo_buf;
1488     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1489     s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1490     s->ds = ds;
1491 
1492     if (!color_inited) {
1493         color_inited = 1;
1494         console_color_init(s->ds);
1495     }
1496     s->y_displayed = 0;
1497     s->y_base = 0;
1498     s->total_height = DEFAULT_BACKSCROLL;
1499     s->x = 0;
1500     s->y = 0;
1501     if (s->console_type == TEXT_CONSOLE) {
1502         s->g_width = ds_get_width(s->ds);
1503         s->g_height = ds_get_height(s->ds);
1504     }
1505 
1506     s->cursor_timer =
1507         qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1508 
1509     s->hw_invalidate = text_console_invalidate;
1510     s->hw_text_update = text_console_update;
1511     s->hw = s;
1512 
1513     /* Set text attribute defaults */
1514     s->t_attrib_default.bold = 0;
1515     s->t_attrib_default.uline = 0;
1516     s->t_attrib_default.blink = 0;
1517     s->t_attrib_default.invers = 0;
1518     s->t_attrib_default.unvisible = 0;
1519     s->t_attrib_default.fgcol = COLOR_WHITE;
1520     s->t_attrib_default.bgcol = COLOR_BLACK;
1521     /* set current text attributes to default */
1522     s->t_attrib = s->t_attrib_default;
1523     text_console_resize(s);
1524 
1525     if (chr->label) {
1526         char msg[128];
1527         int len;
1528 
1529         s->t_attrib.bgcol = COLOR_BLUE;
1530         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1531         console_puts(chr, (uint8_t*)msg, len);
1532         s->t_attrib = s->t_attrib_default;
1533     }
1534 
1535     qemu_chr_generic_open(chr);
1536     if (chr->init)
1537         chr->init(chr);
1538 }
1539 
1540 static CharDriverState *text_console_init(QemuOpts *opts)
1541 {
1542     CharDriverState *chr;
1543     QemuConsole *s;
1544     unsigned width;
1545     unsigned height;
1546 
1547     chr = g_malloc0(sizeof(CharDriverState));
1548 
1549     width = qemu_opt_get_number(opts, "width", 0);
1550     if (width == 0)
1551         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1552 
1553     height = qemu_opt_get_number(opts, "height", 0);
1554     if (height == 0)
1555         height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1556 
1557     if (width == 0 || height == 0) {
1558         s = new_console(NULL, TEXT_CONSOLE);
1559     } else {
1560         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1561     }
1562 
1563     if (!s) {
1564         g_free(chr);
1565         return NULL;
1566     }
1567 
1568     s->chr = chr;
1569     s->g_width = width;
1570     s->g_height = height;
1571     chr->opaque = s;
1572     chr->chr_set_echo = text_console_set_echo;
1573     return chr;
1574 }
1575 
1576 static VcHandler *vc_handler = text_console_init;
1577 
1578 CharDriverState *vc_init(QemuOpts *opts)
1579 {
1580     return vc_handler(opts);
1581 }
1582 
1583 void register_vc_handler(VcHandler *handler)
1584 {
1585     vc_handler = handler;
1586 }
1587 
1588 void text_consoles_set_display(DisplayState *ds)
1589 {
1590     int i;
1591 
1592     for (i = 0; i < nb_consoles; i++) {
1593         if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1594             text_console_do_init(consoles[i]->chr, ds);
1595         }
1596     }
1597 }
1598 
1599 void qemu_console_resize(DisplayState *ds, int width, int height)
1600 {
1601     QemuConsole *s = get_graphic_console(ds);
1602     if (!s) return;
1603 
1604     s->g_width = width;
1605     s->g_height = height;
1606     if (is_graphic_console()) {
1607         ds->surface = qemu_resize_displaysurface(ds, width, height);
1608         dpy_gfx_resize(ds);
1609     }
1610 }
1611 
1612 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1613                        int dst_x, int dst_y, int w, int h)
1614 {
1615     if (is_graphic_console()) {
1616         dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1617     }
1618 }
1619 
1620 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1621 {
1622     PixelFormat pf;
1623 
1624     memset(&pf, 0x00, sizeof(PixelFormat));
1625 
1626     pf.bits_per_pixel = bpp;
1627     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1628     pf.depth = bpp == 32 ? 24 : bpp;
1629 
1630     switch (bpp) {
1631         case 24:
1632             pf.rmask = 0x000000FF;
1633             pf.gmask = 0x0000FF00;
1634             pf.bmask = 0x00FF0000;
1635             pf.rmax = 255;
1636             pf.gmax = 255;
1637             pf.bmax = 255;
1638             pf.rshift = 0;
1639             pf.gshift = 8;
1640             pf.bshift = 16;
1641             pf.rbits = 8;
1642             pf.gbits = 8;
1643             pf.bbits = 8;
1644             break;
1645         case 32:
1646             pf.rmask = 0x0000FF00;
1647             pf.gmask = 0x00FF0000;
1648             pf.bmask = 0xFF000000;
1649             pf.amask = 0x00000000;
1650             pf.amax = 255;
1651             pf.rmax = 255;
1652             pf.gmax = 255;
1653             pf.bmax = 255;
1654             pf.ashift = 0;
1655             pf.rshift = 8;
1656             pf.gshift = 16;
1657             pf.bshift = 24;
1658             pf.rbits = 8;
1659             pf.gbits = 8;
1660             pf.bbits = 8;
1661             pf.abits = 8;
1662             break;
1663         default:
1664             break;
1665     }
1666     return pf;
1667 }
1668 
1669 PixelFormat qemu_default_pixelformat(int bpp)
1670 {
1671     PixelFormat pf;
1672 
1673     memset(&pf, 0x00, sizeof(PixelFormat));
1674 
1675     pf.bits_per_pixel = bpp;
1676     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1677     pf.depth = bpp == 32 ? 24 : bpp;
1678 
1679     switch (bpp) {
1680         case 15:
1681             pf.bits_per_pixel = 16;
1682             pf.rmask = 0x00007c00;
1683             pf.gmask = 0x000003E0;
1684             pf.bmask = 0x0000001F;
1685             pf.rmax = 31;
1686             pf.gmax = 31;
1687             pf.bmax = 31;
1688             pf.rshift = 10;
1689             pf.gshift = 5;
1690             pf.bshift = 0;
1691             pf.rbits = 5;
1692             pf.gbits = 5;
1693             pf.bbits = 5;
1694             break;
1695         case 16:
1696             pf.rmask = 0x0000F800;
1697             pf.gmask = 0x000007E0;
1698             pf.bmask = 0x0000001F;
1699             pf.rmax = 31;
1700             pf.gmax = 63;
1701             pf.bmax = 31;
1702             pf.rshift = 11;
1703             pf.gshift = 5;
1704             pf.bshift = 0;
1705             pf.rbits = 5;
1706             pf.gbits = 6;
1707             pf.bbits = 5;
1708             break;
1709         case 24:
1710             pf.rmask = 0x00FF0000;
1711             pf.gmask = 0x0000FF00;
1712             pf.bmask = 0x000000FF;
1713             pf.rmax = 255;
1714             pf.gmax = 255;
1715             pf.bmax = 255;
1716             pf.rshift = 16;
1717             pf.gshift = 8;
1718             pf.bshift = 0;
1719             pf.rbits = 8;
1720             pf.gbits = 8;
1721             pf.bbits = 8;
1722             break;
1723         case 32:
1724             pf.rmask = 0x00FF0000;
1725             pf.gmask = 0x0000FF00;
1726             pf.bmask = 0x000000FF;
1727             pf.rmax = 255;
1728             pf.gmax = 255;
1729             pf.bmax = 255;
1730             pf.rshift = 16;
1731             pf.gshift = 8;
1732             pf.bshift = 0;
1733             pf.rbits = 8;
1734             pf.gbits = 8;
1735             pf.bbits = 8;
1736             break;
1737         default:
1738             break;
1739     }
1740     return pf;
1741 }
1742 
1743 static void register_types(void)
1744 {
1745     register_char_driver("vc", text_console_init);
1746 }
1747 
1748 type_init(register_types);
1749