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