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