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