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