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 DEFAULT_MONITOR_SIZE "800x600"
  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    console_type_t console_type;
 120    DisplayState *ds;
 121    /* Graphic console state.  */
 122    vga_hw_update_ptr hw_update;
 123    vga_hw_invalidate_ptr hw_invalidate;
 124    vga_hw_screen_dump_ptr hw_screen_dump;
 125    vga_hw_text_update_ptr hw_text_update;
 126    void *hw;
 127
 128    int g_width, g_height;
 129    int width;
 130    int height;
 131    int total_height;
 132    int backscroll_height;
 133    int x, y;
 134    int x_saved, y_saved;
 135    int y_displayed;
 136    int y_base;
 137    TextAttributes t_attrib_default; /* default text attributes */
 138    TextAttributes t_attrib; /* currently active text attributes */
 139    TextCell *cells;
 140    int text_x[2], text_y[2], cursor_invalidate;
 141
 142    int update_x0;
 143    int update_y0;
 144    int update_x1;
 145    int update_y1;
 146
 147    enum TTYState state;
 148    int esc_params[MAX_ESC_PARAMS];
 149    int nb_esc_params;
 150
 151    CharDriverState *chr;
 152    /* fifo for key pressed */
 153    QEMUFIFO out_fifo;
 154    uint8_t out_fifo_buf[16];
 155    QEMUTimer *kbd_timer;
 156};
 157
 158static 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->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 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    c++;
 833    update_xy(s, x, y);
 834}
 835
 836static void console_putchar(TextConsole *s, int ch)
 837{
 838    TextCell *c;
 839    int y1, i;
 840    int x, y;
 841
 842    switch(s->state) {
 843    case TTY_STATE_NORM:
 844        switch(ch) {
 845        case '\r':  /* carriage return */
 846            s->x = 0;
 847            break;
 848        case '\n':  /* newline */
 849            console_put_lf(s);
 850            break;
 851        case '\b':  /* backspace */
 852            if (s->x > 0)
 853                s->x--;
 854            break;
 855        case '\t':  /* tabspace */
 856            if (s->x + (8 - (s->x % 8)) > s->width) {
 857                s->x = 0;
 858                console_put_lf(s);
 859            } else {
 860                s->x = s->x + (8 - (s->x % 8));
 861            }
 862            break;
 863        case '\a':  /* alert aka. bell */
 864            /* TODO: has to be implemented */
 865            break;
 866        case 14:
 867            /* SI (shift in), character set 0 (ignored) */
 868            break;
 869        case 15:
 870            /* SO (shift out), character set 1 (ignored) */
 871            break;
 872        case 27:    /* esc (introducing an escape sequence) */
 873            s->state = TTY_STATE_ESC;
 874            break;
 875        default:
 876            if (s->x >= s->width) {
 877                /* line wrap */
 878                s->x = 0;
 879                console_put_lf(s);
 880            }
 881            y1 = (s->y_base + s->y) % s->total_height;
 882            c = &s->cells[y1 * s->width + s->x];
 883            c->ch = ch;
 884            c->t_attrib = s->t_attrib;
 885            update_xy(s, s->x, s->y);
 886            s->x++;
 887            break;
 888        }
 889        break;
 890    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
 891        if (ch == '[') {
 892            for(i=0;i<MAX_ESC_PARAMS;i++)
 893                s->esc_params[i] = 0;
 894            s->nb_esc_params = 0;
 895            s->state = TTY_STATE_CSI;
 896        } else {
 897            s->state = TTY_STATE_NORM;
 898        }
 899        break;
 900    case TTY_STATE_CSI: /* handle escape sequence parameters */
 901        if (ch >= '0' && ch <= '9') {
 902            if (s->nb_esc_params < MAX_ESC_PARAMS) {
 903                s->esc_params[s->nb_esc_params] =
 904                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
 905            }
 906        } else {
 907            s->nb_esc_params++;
 908            if (ch == ';')
 909                break;
 910#ifdef DEBUG_CONSOLE
 911            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
 912                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
 913#endif
 914            s->state = TTY_STATE_NORM;
 915            switch(ch) {
 916            case 'A':
 917                /* move cursor up */
 918                if (s->esc_params[0] == 0) {
 919                    s->esc_params[0] = 1;
 920                }
 921                s->y -= s->esc_params[0];
 922                if (s->y < 0) {
 923                    s->y = 0;
 924                }
 925                break;
 926            case 'B':
 927                /* move cursor down */
 928                if (s->esc_params[0] == 0) {
 929                    s->esc_params[0] = 1;
 930                }
 931                s->y += s->esc_params[0];
 932                if (s->y >= s->height) {
 933                    s->y = s->height - 1;
 934                }
 935                break;
 936            case 'C':
 937                /* move cursor right */
 938                if (s->esc_params[0] == 0) {
 939                    s->esc_params[0] = 1;
 940                }
 941                s->x += s->esc_params[0];
 942                if (s->x >= s->width) {
 943                    s->x = s->width - 1;
 944                }
 945                break;
 946            case 'D':
 947                /* move cursor left */
 948                if (s->esc_params[0] == 0) {
 949                    s->esc_params[0] = 1;
 950                }
 951                s->x -= s->esc_params[0];
 952                if (s->x < 0) {
 953                    s->x = 0;
 954                }
 955                break;
 956            case 'G':
 957                /* move cursor to column */
 958                s->x = s->esc_params[0] - 1;
 959                if (s->x < 0) {
 960                    s->x = 0;
 961                }
 962                break;
 963            case 'f':
 964            case 'H':
 965                /* move cursor to row, column */
 966                s->x = s->esc_params[1] - 1;
 967                if (s->x < 0) {
 968                    s->x = 0;
 969                }
 970                s->y = s->esc_params[0] - 1;
 971                if (s->y < 0) {
 972                    s->y = 0;
 973                }
 974                break;
 975            case 'J':
 976                switch (s->esc_params[0]) {
 977                case 0:
 978                    /* clear to end of screen */
 979                    for (y = s->y; y < s->height; y++) {
 980                        for (x = 0; x < s->width; x++) {
 981                            if (y == s->y && x < s->x) {
 982                                continue;
 983                            }
 984                            console_clear_xy(s, x, y);
 985                        }
 986                    }
 987                    break;
 988                case 1:
 989                    /* clear from beginning of screen */
 990                    for (y = 0; y <= s->y; y++) {
 991                        for (x = 0; x < s->width; x++) {
 992                            if (y == s->y && x > s->x) {
 993                                break;
 994                            }
 995                            console_clear_xy(s, x, y);
 996                        }
 997                    }
 998                    break;
 999                case 2:
1000                    /* clear entire screen */
1001                    for (y = 0; y <= s->height; y++) {
1002                        for (x = 0; x < s->width; x++) {
1003                            console_clear_xy(s, x, y);
1004                        }
1005                    }
1006                break;
1007                }
1008            case 'K':
1009                switch (s->esc_params[0]) {
1010                case 0:
1011                /* clear to eol */
1012                for(x = s->x; x < s->width; x++) {
1013                        console_clear_xy(s, x, s->y);
1014                }
1015                break;
1016                case 1:
1017                    /* clear from beginning of line */
1018                    for (x = 0; x <= s->x; x++) {
1019                        console_clear_xy(s, x, s->y);
1020                    }
1021                    break;
1022                case 2:
1023                    /* clear entire line */
1024                    for(x = 0; x < s->width; x++) {
1025                        console_clear_xy(s, x, s->y);
1026                    }
1027                break;
1028            }
1029                break;
1030            case 'm':
1031            console_handle_escape(s);
1032            break;
1033            case 'n':
1034                /* report cursor position */
1035                /* TODO: send ESC[row;colR */
1036                break;
1037            case 's':
1038                /* save cursor position */
1039                s->x_saved = s->x;
1040                s->y_saved = s->y;
1041                break;
1042            case 'u':
1043                /* restore cursor position */
1044                s->x = s->x_saved;
1045                s->y = s->y_saved;
1046                break;
1047            default:
1048#ifdef DEBUG_CONSOLE
1049                fprintf(stderr, "unhandled escape character '%c'\n", ch);
1050#endif
1051                break;
1052            }
1053            break;
1054        }
1055    }
1056}
1057
1058void console_select(unsigned int index)
1059{
1060    TextConsole *s;
1061
1062    if (index >= MAX_CONSOLES)
1063        return;
1064    active_console->g_width = ds_get_width(active_console->ds);
1065    active_console->g_height = ds_get_height(active_console->ds);
1066    s = consoles[index];
1067    if (s) {
1068        DisplayState *ds = s->ds;
1069        active_console = s;
1070        if (ds_get_bits_per_pixel(s->ds)) {
1071            ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
1072                    s->g_height, 32, 4 * s->g_width);
1073        } else {
1074            s->ds->surface->width = s->width;
1075            s->ds->surface->height = s->height;
1076        }
1077        dpy_resize(s->ds);
1078        vga_hw_invalidate();
1079    }
1080}
1081
1082static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1083{
1084    TextConsole *s = chr->opaque;
1085    int i;
1086
1087    s->update_x0 = s->width * FONT_WIDTH;
1088    s->update_y0 = s->height * FONT_HEIGHT;
1089    s->update_x1 = 0;
1090    s->update_y1 = 0;
1091    console_show_cursor(s, 0);
1092    for(i = 0; i < len; i++) {
1093        console_putchar(s, buf[i]);
1094    }
1095    console_show_cursor(s, 1);
1096    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1097        dpy_update(s->ds, s->update_x0, s->update_y0,
1098                   s->update_x1 - s->update_x0,
1099                   s->update_y1 - s->update_y0);
1100    }
1101    return len;
1102}
1103
1104static void console_send_event(CharDriverState *chr, int event)
1105{
1106    TextConsole *s = chr->opaque;
1107    int i;
1108
1109    if (event == CHR_EVENT_FOCUS) {
1110        for(i = 0; i < nb_consoles; i++) {
1111            if (consoles[i] == s) {
1112                console_select(i);
1113                break;
1114            }
1115        }
1116    }
1117}
1118
1119static void kbd_send_chars(void *opaque)
1120{
1121    TextConsole *s = opaque;
1122    int len;
1123    uint8_t buf[16];
1124
1125    len = qemu_chr_can_read(s->chr);
1126    if (len > s->out_fifo.count)
1127        len = s->out_fifo.count;
1128    if (len > 0) {
1129        if (len > sizeof(buf))
1130            len = sizeof(buf);
1131        qemu_fifo_read(&s->out_fifo, buf, len);
1132        qemu_chr_read(s->chr, buf, len);
1133    }
1134    /* characters are pending: we send them a bit later (XXX:
1135       horrible, should change char device API) */
1136    if (s->out_fifo.count > 0) {
1137        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1138    }
1139}
1140
1141/* called when an ascii key is pressed */
1142void kbd_put_keysym(int keysym)
1143{
1144    TextConsole *s;
1145    uint8_t buf[16], *q;
1146    int c;
1147
1148    s = active_console;
1149    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1150        return;
1151
1152    switch(keysym) {
1153    case QEMU_KEY_CTRL_UP:
1154        console_scroll(-1);
1155        break;
1156    case QEMU_KEY_CTRL_DOWN:
1157        console_scroll(1);
1158        break;
1159    case QEMU_KEY_CTRL_PAGEUP:
1160        console_scroll(-10);
1161        break;
1162    case QEMU_KEY_CTRL_PAGEDOWN:
1163        console_scroll(10);
1164        break;
1165    default:
1166        /* convert the QEMU keysym to VT100 key string */
1167        q = buf;
1168        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1169            *q++ = '\033';
1170            *q++ = '[';
1171            c = keysym - 0xe100;
1172            if (c >= 10)
1173                *q++ = '0' + (c / 10);
1174            *q++ = '0' + (c % 10);
1175            *q++ = '~';
1176        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1177            *q++ = '\033';
1178            *q++ = '[';
1179            *q++ = keysym & 0xff;
1180        } else {
1181                *q++ = keysym;
1182        }
1183        if (s->chr->chr_read) {
1184            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1185            kbd_send_chars(s);
1186        }
1187        break;
1188    }
1189}
1190
1191static void text_console_invalidate(void *opaque)
1192{
1193    TextConsole *s = (TextConsole *) opaque;
1194    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1195        s->g_width = ds_get_width(s->ds);
1196        s->g_height = ds_get_height(s->ds);
1197        text_console_resize(s);
1198    }
1199    console_refresh(s);
1200}
1201
1202static void text_console_update(void *opaque, console_ch_t *chardata)
1203{
1204    TextConsole *s = (TextConsole *) opaque;
1205    int i, j, src;
1206
1207    if (s->text_x[0] <= s->text_x[1]) {
1208        src = (s->y_base + s->text_y[0]) * s->width;
1209        chardata += s->text_y[0] * s->width;
1210        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1211            for (j = 0; j < s->width; j ++, src ++)
1212                console_write_ch(chardata ++, s->cells[src].ch |
1213                                (s->cells[src].t_attrib.fgcol << 12) |
1214                                (s->cells[src].t_attrib.bgcol << 8) |
1215                                (s->cells[src].t_attrib.bold << 21));
1216        dpy_update(s->ds, s->text_x[0], s->text_y[0],
1217                   s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1218        s->text_x[0] = s->width;
1219        s->text_y[0] = s->height;
1220        s->text_x[1] = 0;
1221        s->text_y[1] = 0;
1222    }
1223    if (s->cursor_invalidate) {
1224        dpy_cursor(s->ds, s->x, s->y);
1225        s->cursor_invalidate = 0;
1226    }
1227}
1228
1229static TextConsole *get_graphic_console(DisplayState *ds)
1230{
1231    int i;
1232    TextConsole *s;
1233    for (i = 0; i < nb_consoles; i++) {
1234        s = consoles[i];
1235        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1236            return s;
1237    }
1238    return NULL;
1239}
1240
1241static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1242{
1243    TextConsole *s;
1244    int i;
1245
1246    if (nb_consoles >= MAX_CONSOLES)
1247        return NULL;
1248    s = qemu_mallocz(sizeof(TextConsole));
1249    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1250        (console_type == GRAPHIC_CONSOLE))) {
1251        active_console = s;
1252    }
1253    s->ds = ds;
1254    s->console_type = console_type;
1255    if (console_type != GRAPHIC_CONSOLE) {
1256        consoles[nb_consoles++] = s;
1257    } else {
1258        /* HACK: Put graphical consoles before text consoles.  */
1259        for (i = nb_consoles; i > 0; i--) {
1260            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1261                break;
1262            consoles[i] = consoles[i - 1];
1263        }
1264        consoles[i] = s;
1265        nb_consoles++;
1266    }
1267    return s;
1268}
1269
1270DisplayState *graphic_console_init(vga_hw_update_ptr update,
1271                                   vga_hw_invalidate_ptr invalidate,
1272                                   vga_hw_screen_dump_ptr screen_dump,
1273                                   vga_hw_text_update_ptr text_update,
1274                                   void *opaque)
1275{
1276    TextConsole *s;
1277    DisplayState *ds;
1278
1279    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1280    ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
1281
1282    s = new_console(ds, GRAPHIC_CONSOLE);
1283    if (s == NULL) {
1284        qemu_free_displaysurface(ds->surface);
1285        qemu_free(ds);
1286        return NULL;
1287    }
1288    s->hw_update = update;
1289    s->hw_invalidate = invalidate;
1290    s->hw_screen_dump = screen_dump;
1291    s->hw_text_update = text_update;
1292    s->hw = opaque;
1293
1294    register_displaystate(ds);
1295    return ds;
1296}
1297
1298int is_graphic_console(void)
1299{
1300    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1301}
1302
1303int is_fixedsize_console(void)
1304{
1305    return active_console && active_console->console_type != TEXT_CONSOLE;
1306}
1307
1308void console_color_init(DisplayState *ds)
1309{
1310    int i, j;
1311    for (j = 0; j < 2; j++) {
1312        for (i = 0; i < 8; i++) {
1313            color_table[j][i] = col_expand(ds,
1314                   vga_get_color(ds, color_table_rgb[j][i]));
1315        }
1316    }
1317}
1318
1319static int n_text_consoles;
1320static CharDriverState *text_consoles[128];
1321static char *text_console_strs[128];
1322
1323static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1324{
1325    TextConsole *s;
1326    unsigned width;
1327    unsigned height;
1328    static int color_inited;
1329
1330    s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1331    if (!s) {
1332        free(chr);
1333        return;
1334    }
1335    chr->opaque = s;
1336    chr->chr_write = console_puts;
1337    chr->chr_send_event = console_send_event;
1338
1339    s->chr = chr;
1340    s->out_fifo.buf = s->out_fifo_buf;
1341    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1342    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1343    s->ds = ds;
1344
1345    if (!color_inited) {
1346        color_inited = 1;
1347        console_color_init(s->ds);
1348    }
1349    s->y_displayed = 0;
1350    s->y_base = 0;
1351    s->total_height = DEFAULT_BACKSCROLL;
1352    s->x = 0;
1353    s->y = 0;
1354    width = ds_get_width(s->ds);
1355    height = ds_get_height(s->ds);
1356    if (p != 0) {
1357        width = strtoul(p, (char **)&p, 10);
1358        if (*p == 'C') {
1359            p++;
1360            width *= FONT_WIDTH;
1361        }
1362        if (*p == 'x') {
1363            p++;
1364            height = strtoul(p, (char **)&p, 10);
1365            if (*p == 'C') {
1366                p++;
1367                height *= FONT_HEIGHT;
1368            }
1369        }
1370    }
1371    s->g_width = width;
1372    s->g_height = height;
1373
1374    s->hw_invalidate = text_console_invalidate;
1375    s->hw_text_update = text_console_update;
1376    s->hw = s;
1377
1378    /* Set text attribute defaults */
1379    s->t_attrib_default.bold = 0;
1380    s->t_attrib_default.uline = 0;
1381    s->t_attrib_default.blink = 0;
1382    s->t_attrib_default.invers = 0;
1383    s->t_attrib_default.unvisible = 0;
1384    s->t_attrib_default.fgcol = COLOR_WHITE;
1385    s->t_attrib_default.bgcol = COLOR_BLACK;
1386    /* set current text attributes to default */
1387    s->t_attrib = s->t_attrib_default;
1388    text_console_resize(s);
1389
1390    qemu_chr_reset(chr);
1391    if (chr->init)
1392        chr->init(chr);
1393}
1394
1395CharDriverState *text_console_init(const char *p)
1396{
1397    CharDriverState *chr;
1398
1399    chr = qemu_mallocz(sizeof(CharDriverState));
1400
1401    if (n_text_consoles == 128) {
1402        fprintf(stderr, "Too many text consoles\n");
1403        exit(1);
1404    }
1405    text_consoles[n_text_consoles] = chr;
1406    text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1407    n_text_consoles++;
1408
1409    return chr;
1410}
1411
1412void text_consoles_set_display(DisplayState *ds)
1413{
1414    int i;
1415
1416    for (i = 0; i < n_text_consoles; i++) {
1417        text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1418        qemu_free(text_console_strs[i]);
1419    }
1420
1421    n_text_consoles = 0;
1422}
1423
1424void qemu_console_resize(DisplayState *ds, int width, int height)
1425{
1426    TextConsole *s = get_graphic_console(ds);
1427    if (!s) return;
1428
1429    s->g_width = width;
1430    s->g_height = height;
1431    if (is_graphic_console()) {
1432        ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1433        dpy_resize(ds);
1434    }
1435}
1436
1437void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1438                       int dst_x, int dst_y, int w, int h)
1439{
1440    if (is_graphic_console()) {
1441        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1442    }
1443}
1444
1445PixelFormat qemu_different_endianness_pixelformat(int bpp)
1446{
1447    PixelFormat pf;
1448
1449    memset(&pf, 0x00, sizeof(PixelFormat));
1450
1451    pf.bits_per_pixel = bpp;
1452    pf.bytes_per_pixel = bpp / 8;
1453    pf.depth = bpp == 32 ? 24 : bpp;
1454
1455    switch (bpp) {
1456        case 24:
1457            pf.rmask = 0x000000FF;
1458            pf.gmask = 0x0000FF00;
1459            pf.bmask = 0x00FF0000;
1460            pf.rmax = 255;
1461            pf.gmax = 255;
1462            pf.bmax = 255;
1463            pf.rshift = 0;
1464            pf.gshift = 8;
1465            pf.bshift = 16;
1466            pf.rbits = 8;
1467            pf.gbits = 8;
1468            pf.bbits = 8;
1469            break;
1470        case 32:
1471            pf.rmask = 0x0000FF00;
1472            pf.gmask = 0x00FF0000;
1473            pf.bmask = 0xFF000000;
1474            pf.amask = 0x00000000;
1475            pf.amax = 255;
1476            pf.rmax = 255;
1477            pf.gmax = 255;
1478            pf.bmax = 255;
1479            pf.ashift = 0;
1480            pf.rshift = 8;
1481            pf.gshift = 16;
1482            pf.bshift = 24;
1483            pf.rbits = 8;
1484            pf.gbits = 8;
1485            pf.bbits = 8;
1486            pf.abits = 8;
1487            break;
1488        default:
1489            break;
1490    }
1491    return pf;
1492}
1493
1494PixelFormat qemu_default_pixelformat(int bpp)
1495{
1496    PixelFormat pf;
1497
1498    memset(&pf, 0x00, sizeof(PixelFormat));
1499
1500    pf.bits_per_pixel = bpp;
1501    pf.bytes_per_pixel = bpp / 8;
1502    pf.depth = bpp == 32 ? 24 : bpp;
1503
1504    switch (bpp) {
1505        case 16:
1506            pf.rmask = 0x0000F800;
1507            pf.gmask = 0x000007E0;
1508            pf.bmask = 0x0000001F;
1509            pf.rmax = 31;
1510            pf.gmax = 63;
1511            pf.bmax = 31;
1512            pf.rshift = 11;
1513            pf.gshift = 5;
1514            pf.bshift = 0;
1515            pf.rbits = 5;
1516            pf.gbits = 6;
1517            pf.bbits = 5;
1518            break;
1519        case 24:
1520            pf.rmask = 0x00FF0000;
1521            pf.gmask = 0x0000FF00;
1522            pf.bmask = 0x000000FF;
1523            pf.rmax = 255;
1524            pf.gmax = 255;
1525            pf.bmax = 255;
1526            pf.rshift = 16;
1527            pf.gshift = 8;
1528            pf.bshift = 0;
1529            pf.rbits = 8;
1530            pf.gbits = 8;
1531            pf.bbits = 8;
1532        case 32:
1533            pf.rmask = 0x00FF0000;
1534            pf.gmask = 0x0000FF00;
1535            pf.bmask = 0x000000FF;
1536            pf.amax = 255;
1537            pf.rmax = 255;
1538            pf.gmax = 255;
1539            pf.bmax = 255;
1540            pf.ashift = 24;
1541            pf.rshift = 16;
1542            pf.gshift = 8;
1543            pf.bshift = 0;
1544            pf.rbits = 8;
1545            pf.gbits = 8;
1546            pf.bbits = 8;
1547            pf.abits = 8;
1548            break;
1549        default:
1550            break;
1551    }
1552    return pf;
1553}
1554
1555DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1556{
1557    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1558
1559    surface->width = width;
1560    surface->height = height;
1561    surface->linesize = linesize;
1562    surface->pf = qemu_default_pixelformat(bpp);
1563#ifdef WORDS_BIGENDIAN
1564    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1565#else
1566    surface->flags = QEMU_ALLOCATED_FLAG;
1567#endif
1568    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1569
1570    return surface;
1571}
1572
1573DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1574                                          int width, int height, int bpp, int linesize)
1575{
1576    surface->width = width;
1577    surface->height = height;
1578    surface->linesize = linesize;
1579    surface->pf = qemu_default_pixelformat(bpp);
1580    if (surface->flags & QEMU_ALLOCATED_FLAG)
1581        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1582    else
1583        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1584#ifdef WORDS_BIGENDIAN
1585    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1586#else
1587    surface->flags = QEMU_ALLOCATED_FLAG;
1588#endif
1589
1590    return surface;
1591}
1592
1593DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1594                                              int linesize, uint8_t *data)
1595{
1596    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1597
1598    surface->width = width;
1599    surface->height = height;
1600    surface->linesize = linesize;
1601    surface->pf = qemu_default_pixelformat(bpp);
1602#ifdef WORDS_BIGENDIAN
1603    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1604#endif
1605    surface->data = data;
1606
1607    return surface;
1608}
1609
1610void qemu_free_displaysurface(DisplaySurface *surface)
1611{
1612    if (surface == NULL)
1613        return;
1614    if (surface->flags & QEMU_ALLOCATED_FLAG)
1615        qemu_free(surface->data);
1616    qemu_free(surface);
1617}
1618