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