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 TextConsole *active_console;
 158static TextConsole *consoles[MAX_CONSOLES];
 159static int nb_consoles = 0;
 160
 161void vga_hw_update(void)
 162{
 163    if (active_console && active_console->hw_update)
 164        active_console->hw_update(active_console->hw);
 165}
 166
 167void vga_hw_invalidate(void)
 168{
 169    if (active_console->hw_invalidate)
 170        active_console->hw_invalidate(active_console->hw);
 171}
 172
 173void vga_hw_screen_dump(const char *filename)
 174{
 175    TextConsole *previous_active_console;
 176
 177    previous_active_console = active_console;
 178    active_console = consoles[0];
 179    /* There is currently no way of specifying which screen we want to dump,
 180       so always dump the first one.  */
 181    if (consoles[0]->hw_screen_dump)
 182        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
 183    active_console = previous_active_console;
 184}
 185
 186void vga_hw_text_update(console_ch_t *chardata)
 187{
 188    if (active_console && active_console->hw_text_update)
 189        active_console->hw_text_update(active_console->hw, chardata);
 190}
 191
 192/* convert a RGBA color to a color index usable in graphic primitives */
 193static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
 194{
 195    unsigned int r, g, b, color;
 196
 197    switch(ds_get_bits_per_pixel(ds)) {
 198#if 0
 199    case 8:
 200        r = (rgba >> 16) & 0xff;
 201        g = (rgba >> 8) & 0xff;
 202        b = (rgba) & 0xff;
 203        color = (rgb_to_index[r] * 6 * 6) +
 204            (rgb_to_index[g] * 6) +
 205            (rgb_to_index[b]);
 206        break;
 207#endif
 208    case 15:
 209        r = (rgba >> 16) & 0xff;
 210        g = (rgba >> 8) & 0xff;
 211        b = (rgba) & 0xff;
 212        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
 213        break;
 214    case 16:
 215        r = (rgba >> 16) & 0xff;
 216        g = (rgba >> 8) & 0xff;
 217        b = (rgba) & 0xff;
 218        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
 219        break;
 220    case 32:
 221    default:
 222        color = rgba;
 223        break;
 224    }
 225    return color;
 226}
 227
 228static void vga_fill_rect (DisplayState *ds,
 229                           int posx, int posy, int width, int height, uint32_t color)
 230{
 231    uint8_t *d, *d1;
 232    int x, y, bpp;
 233
 234    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 235    d1 = ds_get_data(ds) +
 236        ds_get_linesize(ds) * posy + bpp * posx;
 237    for (y = 0; y < height; y++) {
 238        d = d1;
 239        switch(bpp) {
 240        case 1:
 241            for (x = 0; x < width; x++) {
 242                *((uint8_t *)d) = color;
 243                d++;
 244            }
 245            break;
 246        case 2:
 247            for (x = 0; x < width; x++) {
 248                *((uint16_t *)d) = color;
 249                d += 2;
 250            }
 251            break;
 252        case 4:
 253            for (x = 0; x < width; x++) {
 254                *((uint32_t *)d) = color;
 255                d += 4;
 256            }
 257            break;
 258        }
 259        d1 += ds_get_linesize(ds);
 260    }
 261}
 262
 263/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
 264static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
 265{
 266    const uint8_t *s;
 267    uint8_t *d;
 268    int wb, y, bpp;
 269
 270    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 271    wb = w * bpp;
 272    if (yd <= ys) {
 273        s = ds_get_data(ds) +
 274            ds_get_linesize(ds) * ys + bpp * xs;
 275        d = ds_get_data(ds) +
 276            ds_get_linesize(ds) * yd + bpp * xd;
 277        for (y = 0; y < h; y++) {
 278            memmove(d, s, wb);
 279            d += ds_get_linesize(ds);
 280            s += ds_get_linesize(ds);
 281        }
 282    } else {
 283        s = ds_get_data(ds) +
 284            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
 285        d = ds_get_data(ds) +
 286            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
 287       for (y = 0; y < h; y++) {
 288            memmove(d, s, wb);
 289            d -= ds_get_linesize(ds);
 290            s -= ds_get_linesize(ds);
 291        }
 292    }
 293}
 294
 295/***********************************************************/
 296/* basic char display */
 297
 298#define FONT_HEIGHT 16
 299#define FONT_WIDTH 8
 300
 301#include "vgafont.h"
 302
 303#define cbswap_32(__x) \
 304((uint32_t)( \
 305                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
 306                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
 307                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
 308                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
 309
 310#ifdef WORDS_BIGENDIAN
 311#define PAT(x) x
 312#else
 313#define PAT(x) cbswap_32(x)
 314#endif
 315
 316static const uint32_t dmask16[16] = {
 317    PAT(0x00000000),
 318    PAT(0x000000ff),
 319    PAT(0x0000ff00),
 320    PAT(0x0000ffff),
 321    PAT(0x00ff0000),
 322    PAT(0x00ff00ff),
 323    PAT(0x00ffff00),
 324    PAT(0x00ffffff),
 325    PAT(0xff000000),
 326    PAT(0xff0000ff),
 327    PAT(0xff00ff00),
 328    PAT(0xff00ffff),
 329    PAT(0xffff0000),
 330    PAT(0xffff00ff),
 331    PAT(0xffffff00),
 332    PAT(0xffffffff),
 333};
 334
 335static const uint32_t dmask4[4] = {
 336    PAT(0x00000000),
 337    PAT(0x0000ffff),
 338    PAT(0xffff0000),
 339    PAT(0xffffffff),
 340};
 341
 342static uint32_t color_table[2][8];
 343
 344enum color_names {
 345    COLOR_BLACK   = 0,
 346    COLOR_RED     = 1,
 347    COLOR_GREEN   = 2,
 348    COLOR_YELLOW  = 3,
 349    COLOR_BLUE    = 4,
 350    COLOR_MAGENTA = 5,
 351    COLOR_CYAN    = 6,
 352    COLOR_WHITE   = 7
 353};
 354
 355static const uint32_t color_table_rgb[2][8] = {
 356    {   /* dark */
 357        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 358        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
 359        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
 360        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
 361        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
 362        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
 363        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
 364        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
 365    },
 366    {   /* bright */
 367        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 368        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
 369        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
 370        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
 371        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
 372        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
 373        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
 374        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
 375    }
 376};
 377
 378static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
 379{
 380    switch(ds_get_bits_per_pixel(ds)) {
 381    case 8:
 382        col |= col << 8;
 383        col |= col << 16;
 384        break;
 385    case 15:
 386    case 16:
 387        col |= col << 16;
 388        break;
 389    default:
 390        break;
 391    }
 392
 393    return col;
 394}
 395#ifdef DEBUG_CONSOLE
 396static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
 397{
 398    if (t_attrib->bold) {
 399        printf("b");
 400    } else {
 401        printf(" ");
 402    }
 403    if (t_attrib->uline) {
 404        printf("u");
 405    } else {
 406        printf(" ");
 407    }
 408    if (t_attrib->blink) {
 409        printf("l");
 410    } else {
 411        printf(" ");
 412    }
 413    if (t_attrib->invers) {
 414        printf("i");
 415    } else {
 416        printf(" ");
 417    }
 418    if (t_attrib->unvisible) {
 419        printf("n");
 420    } else {
 421        printf(" ");
 422    }
 423
 424    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
 425}
 426#endif
 427
 428static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
 429                          TextAttributes *t_attrib)
 430{
 431    uint8_t *d;
 432    const uint8_t *font_ptr;
 433    unsigned int font_data, linesize, xorcol, bpp;
 434    int i;
 435    unsigned int fgcol, bgcol;
 436
 437#ifdef DEBUG_CONSOLE
 438    printf("x: %2i y: %2i", x, y);
 439    console_print_text_attributes(t_attrib, ch);
 440#endif
 441
 442    if (t_attrib->invers) {
 443        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
 444        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
 445    } else {
 446        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
 447        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
 448    }
 449
 450    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 451    d = ds_get_data(ds) +
 452        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
 453    linesize = ds_get_linesize(ds);
 454    font_ptr = vgafont16 + FONT_HEIGHT * ch;
 455    xorcol = bgcol ^ fgcol;
 456    switch(ds_get_bits_per_pixel(ds)) {
 457    case 8:
 458        for(i = 0; i < FONT_HEIGHT; i++) {
 459            font_data = *font_ptr++;
 460            if (t_attrib->uline
 461                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 462                font_data = 0xFFFF;
 463            }
 464            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
 465            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
 466            d += linesize;
 467        }
 468        break;
 469    case 16:
 470    case 15:
 471        for(i = 0; i < FONT_HEIGHT; i++) {
 472            font_data = *font_ptr++;
 473            if (t_attrib->uline
 474                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 475                font_data = 0xFFFF;
 476            }
 477            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
 478            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
 479            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
 480            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
 481            d += linesize;
 482        }
 483        break;
 484    case 32:
 485        for(i = 0; i < FONT_HEIGHT; i++) {
 486            font_data = *font_ptr++;
 487            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 488                font_data = 0xFFFF;
 489            }
 490            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
 491            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
 492            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
 493            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
 494            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
 495            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
 496            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
 497            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
 498            d += linesize;
 499        }
 500        break;
 501    }
 502}
 503
 504static void text_console_resize(TextConsole *s)
 505{
 506    TextCell *cells, *c, *c1;
 507    int w1, x, y, last_width;
 508
 509    last_width = s->width;
 510    s->width = s->g_width / FONT_WIDTH;
 511    s->height = s->g_height / FONT_HEIGHT;
 512
 513    w1 = last_width;
 514    if (s->width < w1)
 515        w1 = s->width;
 516
 517    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
 518    for(y = 0; y < s->total_height; y++) {
 519        c = &cells[y * s->width];
 520        if (w1 > 0) {
 521            c1 = &s->cells[y * last_width];
 522            for(x = 0; x < w1; x++) {
 523                *c++ = *c1++;
 524            }
 525        }
 526        for(x = w1; x < s->width; x++) {
 527            c->ch = ' ';
 528            c->t_attrib = s->t_attrib_default;
 529            c++;
 530        }
 531    }
 532    qemu_free(s->cells);
 533    s->cells = cells;
 534}
 535
 536static inline void text_update_xy(TextConsole *s, int x, int y)
 537{
 538    s->text_x[0] = MIN(s->text_x[0], x);
 539    s->text_x[1] = MAX(s->text_x[1], x);
 540    s->text_y[0] = MIN(s->text_y[0], y);
 541    s->text_y[1] = MAX(s->text_y[1], y);
 542}
 543
 544static void invalidate_xy(TextConsole *s, int x, int y)
 545{
 546    if (s->update_x0 > x * FONT_WIDTH)
 547        s->update_x0 = x * FONT_WIDTH;
 548    if (s->update_y0 > y * FONT_HEIGHT)
 549        s->update_y0 = y * FONT_HEIGHT;
 550    if (s->update_x1 < (x + 1) * FONT_WIDTH)
 551        s->update_x1 = (x + 1) * FONT_WIDTH;
 552    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
 553        s->update_y1 = (y + 1) * FONT_HEIGHT;
 554}
 555
 556static void update_xy(TextConsole *s, int x, int y)
 557{
 558    TextCell *c;
 559    int y1, y2;
 560
 561    if (s == active_console) {
 562        if (!ds_get_bits_per_pixel(s->ds)) {
 563            text_update_xy(s, x, y);
 564            return;
 565        }
 566
 567        y1 = (s->y_base + y) % s->total_height;
 568        y2 = y1 - s->y_displayed;
 569        if (y2 < 0)
 570            y2 += s->total_height;
 571        if (y2 < s->height) {
 572            c = &s->cells[y1 * s->width + x];
 573            vga_putcharxy(s->ds, x, y2, c->ch,
 574                          &(c->t_attrib));
 575            invalidate_xy(s, x, y2);
 576        }
 577    }
 578}
 579
 580static void console_show_cursor(TextConsole *s, int show)
 581{
 582    TextCell *c;
 583    int y, y1;
 584
 585    if (s == active_console) {
 586        int x = s->x;
 587
 588        if (!ds_get_bits_per_pixel(s->ds)) {
 589            s->cursor_invalidate = 1;
 590            return;
 591        }
 592
 593        if (x >= s->width) {
 594            x = s->width - 1;
 595        }
 596        y1 = (s->y_base + s->y) % s->total_height;
 597        y = y1 - s->y_displayed;
 598        if (y < 0)
 599            y += s->total_height;
 600        if (y < s->height) {
 601            c = &s->cells[y1 * s->width + x];
 602            if (show) {
 603                TextAttributes t_attrib = s->t_attrib_default;
 604                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
 605                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
 606            } else {
 607                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
 608            }
 609            invalidate_xy(s, x, y);
 610        }
 611    }
 612}
 613
 614static void console_refresh(TextConsole *s)
 615{
 616    TextCell *c;
 617    int x, y, y1;
 618
 619    if (s != active_console)
 620        return;
 621    if (!ds_get_bits_per_pixel(s->ds)) {
 622        s->text_x[0] = 0;
 623        s->text_y[0] = 0;
 624        s->text_x[1] = s->width - 1;
 625        s->text_y[1] = s->height - 1;
 626        s->cursor_invalidate = 1;
 627        return;
 628    }
 629
 630    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
 631                  color_table[0][COLOR_BLACK]);
 632    y1 = s->y_displayed;
 633    for(y = 0; y < s->height; y++) {
 634        c = s->cells + y1 * s->width;
 635        for(x = 0; x < s->width; x++) {
 636            vga_putcharxy(s->ds, x, y, c->ch,
 637                          &(c->t_attrib));
 638            c++;
 639        }
 640        if (++y1 == s->total_height)
 641            y1 = 0;
 642    }
 643    console_show_cursor(s, 1);
 644    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
 645}
 646
 647static void console_scroll(int ydelta)
 648{
 649    TextConsole *s;
 650    int i, y1;
 651
 652    s = active_console;
 653    if (!s || (s->console_type == GRAPHIC_CONSOLE))
 654        return;
 655
 656    if (ydelta > 0) {
 657        for(i = 0; i < ydelta; i++) {
 658            if (s->y_displayed == s->y_base)
 659                break;
 660            if (++s->y_displayed == s->total_height)
 661                s->y_displayed = 0;
 662        }
 663    } else {
 664        ydelta = -ydelta;
 665        i = s->backscroll_height;
 666        if (i > s->total_height - s->height)
 667            i = s->total_height - s->height;
 668        y1 = s->y_base - i;
 669        if (y1 < 0)
 670            y1 += s->total_height;
 671        for(i = 0; i < ydelta; i++) {
 672            if (s->y_displayed == y1)
 673                break;
 674            if (--s->y_displayed < 0)
 675                s->y_displayed = s->total_height - 1;
 676        }
 677    }
 678    console_refresh(s);
 679}
 680
 681static void console_put_lf(TextConsole *s)
 682{
 683    TextCell *c;
 684    int x, y1;
 685
 686    s->y++;
 687    if (s->y >= s->height) {
 688        s->y = s->height - 1;
 689
 690        if (s->y_displayed == s->y_base) {
 691            if (++s->y_displayed == s->total_height)
 692                s->y_displayed = 0;
 693        }
 694        if (++s->y_base == s->total_height)
 695            s->y_base = 0;
 696        if (s->backscroll_height < s->total_height)
 697            s->backscroll_height++;
 698        y1 = (s->y_base + s->height - 1) % s->total_height;
 699        c = &s->cells[y1 * s->width];
 700        for(x = 0; x < s->width; x++) {
 701            c->ch = ' ';
 702            c->t_attrib = s->t_attrib_default;
 703            c++;
 704        }
 705        if (s == active_console && s->y_displayed == s->y_base) {
 706            if (!ds_get_bits_per_pixel(s->ds)) {
 707                s->text_x[0] = 0;
 708                s->text_y[0] = 0;
 709                s->text_x[1] = s->width - 1;
 710                s->text_y[1] = s->height - 1;
 711                return;
 712            }
 713
 714            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
 715                       s->width * FONT_WIDTH,
 716                       (s->height - 1) * FONT_HEIGHT);
 717            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
 718                          s->width * FONT_WIDTH, FONT_HEIGHT,
 719                          color_table[0][s->t_attrib_default.bgcol]);
 720            s->update_x0 = 0;
 721            s->update_y0 = 0;
 722            s->update_x1 = s->width * FONT_WIDTH;
 723            s->update_y1 = s->height * FONT_HEIGHT;
 724        }
 725    }
 726}
 727
 728/* Set console attributes depending on the current escape codes.
 729 * NOTE: I know this code is not very efficient (checking every color for it
 730 * self) but it is more readable and better maintainable.
 731 */
 732static void console_handle_escape(TextConsole *s)
 733{
 734    int i;
 735
 736    for (i=0; i<s->nb_esc_params; i++) {
 737        switch (s->esc_params[i]) {
 738            case 0: /* reset all console attributes to default */
 739                s->t_attrib = s->t_attrib_default;
 740                break;
 741            case 1:
 742                s->t_attrib.bold = 1;
 743                break;
 744            case 4:
 745                s->t_attrib.uline = 1;
 746                break;
 747            case 5:
 748                s->t_attrib.blink = 1;
 749                break;
 750            case 7:
 751                s->t_attrib.invers = 1;
 752                break;
 753            case 8:
 754                s->t_attrib.unvisible = 1;
 755                break;
 756            case 22:
 757                s->t_attrib.bold = 0;
 758                break;
 759            case 24:
 760                s->t_attrib.uline = 0;
 761                break;
 762            case 25:
 763                s->t_attrib.blink = 0;
 764                break;
 765            case 27:
 766                s->t_attrib.invers = 0;
 767                break;
 768            case 28:
 769                s->t_attrib.unvisible = 0;
 770                break;
 771            /* set foreground color */
 772            case 30:
 773                s->t_attrib.fgcol=COLOR_BLACK;
 774                break;
 775            case 31:
 776                s->t_attrib.fgcol=COLOR_RED;
 777                break;
 778            case 32:
 779                s->t_attrib.fgcol=COLOR_GREEN;
 780                break;
 781            case 33:
 782                s->t_attrib.fgcol=COLOR_YELLOW;
 783                break;
 784            case 34:
 785                s->t_attrib.fgcol=COLOR_BLUE;
 786                break;
 787            case 35:
 788                s->t_attrib.fgcol=COLOR_MAGENTA;
 789                break;
 790            case 36:
 791                s->t_attrib.fgcol=COLOR_CYAN;
 792                break;
 793            case 37:
 794                s->t_attrib.fgcol=COLOR_WHITE;
 795                break;
 796            /* set background color */
 797            case 40:
 798                s->t_attrib.bgcol=COLOR_BLACK;
 799                break;
 800            case 41:
 801                s->t_attrib.bgcol=COLOR_RED;
 802                break;
 803            case 42:
 804                s->t_attrib.bgcol=COLOR_GREEN;
 805                break;
 806            case 43:
 807                s->t_attrib.bgcol=COLOR_YELLOW;
 808                break;
 809            case 44:
 810                s->t_attrib.bgcol=COLOR_BLUE;
 811                break;
 812            case 45:
 813                s->t_attrib.bgcol=COLOR_MAGENTA;
 814                break;
 815            case 46:
 816                s->t_attrib.bgcol=COLOR_CYAN;
 817                break;
 818            case 47:
 819                s->t_attrib.bgcol=COLOR_WHITE;
 820                break;
 821        }
 822    }
 823}
 824
 825static void console_clear_xy(TextConsole *s, int x, int y)
 826{
 827    int y1 = (s->y_base + y) % s->total_height;
 828    TextCell *c = &s->cells[y1 * s->width + x];
 829    c->ch = ' ';
 830    c->t_attrib = s->t_attrib_default;
 831    c++;
 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
1268DisplayState *graphic_console_init(vga_hw_update_ptr update,
1269                                   vga_hw_invalidate_ptr invalidate,
1270                                   vga_hw_screen_dump_ptr screen_dump,
1271                                   vga_hw_text_update_ptr text_update,
1272                                   void *opaque)
1273{
1274    TextConsole *s;
1275    DisplayState *ds;
1276
1277    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1278    ds->allocator = &default_allocator; 
1279    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1280
1281    s = new_console(ds, GRAPHIC_CONSOLE);
1282    if (s == NULL) {
1283        qemu_free_displaysurface(ds);
1284        qemu_free(ds);
1285        return NULL;
1286    }
1287    s->hw_update = update;
1288    s->hw_invalidate = invalidate;
1289    s->hw_screen_dump = screen_dump;
1290    s->hw_text_update = text_update;
1291    s->hw = opaque;
1292
1293    register_displaystate(ds);
1294    return ds;
1295}
1296
1297int is_graphic_console(void)
1298{
1299    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1300}
1301
1302int is_fixedsize_console(void)
1303{
1304    return active_console && active_console->console_type != TEXT_CONSOLE;
1305}
1306
1307void console_color_init(DisplayState *ds)
1308{
1309    int i, j;
1310    for (j = 0; j < 2; j++) {
1311        for (i = 0; i < 8; i++) {
1312            color_table[j][i] = col_expand(ds,
1313                   vga_get_color(ds, color_table_rgb[j][i]));
1314        }
1315    }
1316}
1317
1318static int n_text_consoles;
1319static CharDriverState *text_consoles[128];
1320static char *text_console_strs[128];
1321
1322static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1323{
1324    TextConsole *s;
1325    unsigned width;
1326    unsigned height;
1327    static int color_inited;
1328
1329    s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1330    if (!s) {
1331        free(chr);
1332        return;
1333    }
1334    chr->opaque = s;
1335    chr->chr_write = console_puts;
1336    chr->chr_send_event = console_send_event;
1337
1338    s->chr = chr;
1339    s->out_fifo.buf = s->out_fifo_buf;
1340    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1341    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1342    s->ds = ds;
1343
1344    if (!color_inited) {
1345        color_inited = 1;
1346        console_color_init(s->ds);
1347    }
1348    s->y_displayed = 0;
1349    s->y_base = 0;
1350    s->total_height = DEFAULT_BACKSCROLL;
1351    s->x = 0;
1352    s->y = 0;
1353    width = ds_get_width(s->ds);
1354    height = ds_get_height(s->ds);
1355    if (p != NULL) {
1356        width = strtoul(p, (char **)&p, 10);
1357        if (*p == 'C') {
1358            p++;
1359            width *= FONT_WIDTH;
1360        }
1361        if (*p == 'x') {
1362            p++;
1363            height = strtoul(p, (char **)&p, 10);
1364            if (*p == 'C') {
1365                p++;
1366                height *= FONT_HEIGHT;
1367            }
1368        }
1369    }
1370    s->g_width = width;
1371    s->g_height = height;
1372
1373    s->hw_invalidate = text_console_invalidate;
1374    s->hw_text_update = text_console_update;
1375    s->hw = s;
1376
1377    /* Set text attribute defaults */
1378    s->t_attrib_default.bold = 0;
1379    s->t_attrib_default.uline = 0;
1380    s->t_attrib_default.blink = 0;
1381    s->t_attrib_default.invers = 0;
1382    s->t_attrib_default.unvisible = 0;
1383    s->t_attrib_default.fgcol = COLOR_WHITE;
1384    s->t_attrib_default.bgcol = COLOR_BLACK;
1385    /* set current text attributes to default */
1386    s->t_attrib = s->t_attrib_default;
1387    text_console_resize(s);
1388
1389    qemu_chr_reset(chr);
1390    if (chr->init)
1391        chr->init(chr);
1392}
1393
1394CharDriverState *text_console_init(const char *p)
1395{
1396    CharDriverState *chr;
1397
1398    chr = qemu_mallocz(sizeof(CharDriverState));
1399
1400    if (n_text_consoles == 128) {
1401        fprintf(stderr, "Too many text consoles\n");
1402        exit(1);
1403    }
1404    text_consoles[n_text_consoles] = chr;
1405    text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1406    n_text_consoles++;
1407
1408    return chr;
1409}
1410
1411void text_consoles_set_display(DisplayState *ds)
1412{
1413    int i;
1414
1415    for (i = 0; i < n_text_consoles; i++) {
1416        text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1417        qemu_free(text_console_strs[i]);
1418    }
1419
1420    n_text_consoles = 0;
1421}
1422
1423void qemu_console_resize(DisplayState *ds, int width, int height)
1424{
1425    TextConsole *s = get_graphic_console(ds);
1426    if (!s) return;
1427
1428    s->g_width = width;
1429    s->g_height = height;
1430    if (is_graphic_console()) {
1431        ds->surface = qemu_resize_displaysurface(ds, width, height);
1432        dpy_resize(ds);
1433    }
1434}
1435
1436void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1437                       int dst_x, int dst_y, int w, int h)
1438{
1439    if (is_graphic_console()) {
1440        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1441    }
1442}
1443
1444PixelFormat qemu_different_endianness_pixelformat(int bpp)
1445{
1446    PixelFormat pf;
1447
1448    memset(&pf, 0x00, sizeof(PixelFormat));
1449
1450    pf.bits_per_pixel = bpp;
1451    pf.bytes_per_pixel = bpp / 8;
1452    pf.depth = bpp == 32 ? 24 : bpp;
1453
1454    switch (bpp) {
1455        case 24:
1456            pf.rmask = 0x000000FF;
1457            pf.gmask = 0x0000FF00;
1458            pf.bmask = 0x00FF0000;
1459            pf.rmax = 255;
1460            pf.gmax = 255;
1461            pf.bmax = 255;
1462            pf.rshift = 0;
1463            pf.gshift = 8;
1464            pf.bshift = 16;
1465            pf.rbits = 8;
1466            pf.gbits = 8;
1467            pf.bbits = 8;
1468            break;
1469        case 32:
1470            pf.rmask = 0x0000FF00;
1471            pf.gmask = 0x00FF0000;
1472            pf.bmask = 0xFF000000;
1473            pf.amask = 0x00000000;
1474            pf.amax = 255;
1475            pf.rmax = 255;
1476            pf.gmax = 255;
1477            pf.bmax = 255;
1478            pf.ashift = 0;
1479            pf.rshift = 8;
1480            pf.gshift = 16;
1481            pf.bshift = 24;
1482            pf.rbits = 8;
1483            pf.gbits = 8;
1484            pf.bbits = 8;
1485            pf.abits = 8;
1486            break;
1487        default:
1488            break;
1489    }
1490    return pf;
1491}
1492
1493PixelFormat qemu_default_pixelformat(int bpp)
1494{
1495    PixelFormat pf;
1496
1497    memset(&pf, 0x00, sizeof(PixelFormat));
1498
1499    pf.bits_per_pixel = bpp;
1500    pf.bytes_per_pixel = bpp / 8;
1501    pf.depth = bpp == 32 ? 24 : bpp;
1502
1503    switch (bpp) {
1504        case 16:
1505            pf.rmask = 0x0000F800;
1506            pf.gmask = 0x000007E0;
1507            pf.bmask = 0x0000001F;
1508            pf.rmax = 31;
1509            pf.gmax = 63;
1510            pf.bmax = 31;
1511            pf.rshift = 11;
1512            pf.gshift = 5;
1513            pf.bshift = 0;
1514            pf.rbits = 5;
1515            pf.gbits = 6;
1516            pf.bbits = 5;
1517            break;
1518        case 24:
1519            pf.rmask = 0x00FF0000;
1520            pf.gmask = 0x0000FF00;
1521            pf.bmask = 0x000000FF;
1522            pf.rmax = 255;
1523            pf.gmax = 255;
1524            pf.bmax = 255;
1525            pf.rshift = 16;
1526            pf.gshift = 8;
1527            pf.bshift = 0;
1528            pf.rbits = 8;
1529            pf.gbits = 8;
1530            pf.bbits = 8;
1531        case 32:
1532            pf.rmask = 0x00FF0000;
1533            pf.gmask = 0x0000FF00;
1534            pf.bmask = 0x000000FF;
1535            pf.amax = 255;
1536            pf.rmax = 255;
1537            pf.gmax = 255;
1538            pf.bmax = 255;
1539            pf.ashift = 24;
1540            pf.rshift = 16;
1541            pf.gshift = 8;
1542            pf.bshift = 0;
1543            pf.rbits = 8;
1544            pf.gbits = 8;
1545            pf.bbits = 8;
1546            pf.abits = 8;
1547            break;
1548        default:
1549            break;
1550    }
1551    return pf;
1552}
1553
1554DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1555{
1556    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1557
1558    surface->width = width;
1559    surface->height = height;
1560    surface->linesize = width * 4;
1561    surface->pf = qemu_default_pixelformat(32);
1562#ifdef WORDS_BIGENDIAN
1563    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1564#else
1565    surface->flags = QEMU_ALLOCATED_FLAG;
1566#endif
1567    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1568
1569    return surface;
1570}
1571
1572DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1573                                          int width, int height)
1574{
1575    surface->width = width;
1576    surface->height = height;
1577    surface->linesize = width * 4;
1578    surface->pf = qemu_default_pixelformat(32);
1579    if (surface->flags & QEMU_ALLOCATED_FLAG)
1580        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1581    else
1582        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1583#ifdef WORDS_BIGENDIAN
1584    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1585#else
1586    surface->flags = QEMU_ALLOCATED_FLAG;
1587#endif
1588
1589    return surface;
1590}
1591
1592DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1593                                              int linesize, uint8_t *data)
1594{
1595    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1596
1597    surface->width = width;
1598    surface->height = height;
1599    surface->linesize = linesize;
1600    surface->pf = qemu_default_pixelformat(bpp);
1601#ifdef WORDS_BIGENDIAN
1602    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1603#endif
1604    surface->data = data;
1605
1606    return surface;
1607}
1608
1609void defaultallocator_free_displaysurface(DisplaySurface *surface)
1610{
1611    if (surface == NULL)
1612        return;
1613    if (surface->flags & QEMU_ALLOCATED_FLAG)
1614        qemu_free(surface->data);
1615    qemu_free(surface);
1616}
1617