console.c 55.1 KB
Newer Older
B
bellard 已提交
1 2
/*
 * QEMU graphical console
3
 *
B
bellard 已提交
4
 * Copyright (c) 2004 Fabrice Bellard
5
 *
B
bellard 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
pbrook 已提交
24
#include "qemu-common.h"
25
#include "ui/console.h"
26
#include "hw/qdev-core.h"
27
#include "qemu/timer.h"
L
Luiz Capitulino 已提交
28
#include "qmp-commands.h"
29
#include "sysemu/char.h"
30
#include "trace.h"
B
bellard 已提交
31 32 33

#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
34
#define CONSOLE_CURSOR_PERIOD 500
B
bellard 已提交
35

36 37 38 39 40 41 42 43 44 45
typedef struct TextAttributes {
    uint8_t fgcol:4;
    uint8_t bgcol:4;
    uint8_t bold:1;
    uint8_t uline:1;
    uint8_t blink:1;
    uint8_t invers:1;
    uint8_t unvisible:1;
} TextAttributes;

B
bellard 已提交
46 47
typedef struct TextCell {
    uint8_t ch;
48
    TextAttributes t_attrib;
B
bellard 已提交
49 50 51 52 53 54 55 56 57 58
} TextCell;

#define MAX_ESC_PARAMS 3

enum TTYState {
    TTY_STATE_NORM,
    TTY_STATE_ESC,
    TTY_STATE_CSI,
};

59 60 61 62 63 64
typedef struct QEMUFIFO {
    uint8_t *buf;
    int buf_size;
    int count, wptr, rptr;
} QEMUFIFO;

65
static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
{
    int l, len;

    l = f->buf_size - f->count;
    if (len1 > l)
        len1 = l;
    len = len1;
    while (len > 0) {
        l = f->buf_size - f->wptr;
        if (l > len)
            l = len;
        memcpy(f->buf + f->wptr, buf, l);
        f->wptr += l;
        if (f->wptr >= f->buf_size)
            f->wptr = 0;
        buf += l;
        len -= l;
    }
    f->count += len1;
    return len1;
}

88
static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
{
    int l, len;

    if (len1 > f->count)
        len1 = f->count;
    len = len1;
    while (len > 0) {
        l = f->buf_size - f->rptr;
        if (l > len)
            l = len;
        memcpy(buf, f->buf + f->rptr, l);
        f->rptr += l;
        if (f->rptr >= f->buf_size)
            f->rptr = 0;
        buf += l;
        len -= l;
    }
    f->count -= len1;
    return len1;
}

110 111
typedef enum {
    GRAPHIC_CONSOLE,
112 113
    TEXT_CONSOLE,
    TEXT_CONSOLE_FIXED_SIZE
A
Anthony Liguori 已提交
114
} console_type_t;
115

116
struct QemuConsole {
G
Gerd Hoffmann 已提交
117 118
    Object parent;

119
    int index;
A
Anthony Liguori 已提交
120
    console_type_t console_type;
B
bellard 已提交
121
    DisplayState *ds;
122
    DisplaySurface *surface;
123
    int dcls;
124

P
pbrook 已提交
125
    /* Graphic console state.  */
126
    Object *device;
127
    uint32_t head;
G
Gerd Hoffmann 已提交
128
    QemuUIInfo ui_info;
G
Gerd Hoffmann 已提交
129
    const GraphicHwOps *hw_ops;
P
pbrook 已提交
130
    void *hw;
131 132

    /* Text console state */
B
bellard 已提交
133 134 135 136 137
    int width;
    int height;
    int total_height;
    int backscroll_height;
    int x, y;
138
    int x_saved, y_saved;
B
bellard 已提交
139 140
    int y_displayed;
    int y_base;
141 142
    TextAttributes t_attrib_default; /* default text attributes */
    TextAttributes t_attrib; /* currently active text attributes */
B
bellard 已提交
143
    TextCell *cells;
B
balrog 已提交
144
    int text_x[2], text_y[2], cursor_invalidate;
145
    int echo;
B
bellard 已提交
146

147 148 149 150 151
    int update_x0;
    int update_y0;
    int update_x1;
    int update_y1;

B
bellard 已提交
152 153 154 155
    enum TTYState state;
    int esc_params[MAX_ESC_PARAMS];
    int nb_esc_params;

156
    CharDriverState *chr;
157 158 159 160
    /* fifo for key pressed */
    QEMUFIFO out_fifo;
    uint8_t out_fifo_buf[16];
    QEMUTimer *kbd_timer;
B
bellard 已提交
161 162
};

163
struct DisplayState {
164
    QEMUTimer *gui_timer;
G
Gerd Hoffmann 已提交
165 166 167
    uint64_t last_update;
    uint64_t update_interval;
    bool refreshing;
168 169 170 171 172 173
    bool have_gfx;
    bool have_text;

    QLIST_HEAD(, DisplayChangeListener) listeners;
};

174
static DisplayState *display_state;
175 176
static QemuConsole *active_console;
static QemuConsole *consoles[MAX_CONSOLES];
B
bellard 已提交
177
static int nb_consoles = 0;
178 179
static bool cursor_visible_phase;
static QEMUTimer *cursor_timer;
B
bellard 已提交
180

181
static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
G
Gerd Hoffmann 已提交
182
static void dpy_refresh(DisplayState *s);
183
static DisplayState *get_alloc_displaystate(void);
184 185
static void text_console_update_cursor_timer(void);
static void text_console_update_cursor(void *opaque);
186

187 188
static void gui_update(void *opaque)
{
G
Gerd Hoffmann 已提交
189 190
    uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
    uint64_t dcl_interval;
191 192
    DisplayState *ds = opaque;
    DisplayChangeListener *dcl;
193
    int i;
194

G
Gerd Hoffmann 已提交
195
    ds->refreshing = true;
196
    dpy_refresh(ds);
G
Gerd Hoffmann 已提交
197
    ds->refreshing = false;
198 199

    QLIST_FOREACH(dcl, &ds->listeners, next) {
G
Gerd Hoffmann 已提交
200 201 202 203
        dcl_interval = dcl->update_interval ?
            dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
        if (interval > dcl_interval) {
            interval = dcl_interval;
204 205
        }
    }
G
Gerd Hoffmann 已提交
206 207
    if (ds->update_interval != interval) {
        ds->update_interval = interval;
208 209 210 211 212
        for (i = 0; i < nb_consoles; i++) {
            if (consoles[i]->hw_ops->update_interval) {
                consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
            }
        }
G
Gerd Hoffmann 已提交
213 214
        trace_console_refresh(interval);
    }
215 216
    ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
    timer_mod(ds->gui_timer, ds->last_update + interval);
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
}

static void gui_setup_refresh(DisplayState *ds)
{
    DisplayChangeListener *dcl;
    bool need_timer = false;
    bool have_gfx = false;
    bool have_text = false;

    QLIST_FOREACH(dcl, &ds->listeners, next) {
        if (dcl->ops->dpy_refresh != NULL) {
            need_timer = true;
        }
        if (dcl->ops->dpy_gfx_update != NULL) {
            have_gfx = true;
        }
        if (dcl->ops->dpy_text_update != NULL) {
            have_text = true;
        }
    }

    if (need_timer && ds->gui_timer == NULL) {
239 240
        ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
        timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
241 242
    }
    if (!need_timer && ds->gui_timer != NULL) {
243 244
        timer_del(ds->gui_timer);
        timer_free(ds->gui_timer);
245 246 247 248 249 250 251
        ds->gui_timer = NULL;
    }

    ds->have_gfx = have_gfx;
    ds->have_text = have_text;
}

252
void graphic_hw_update(QemuConsole *con)
P
pbrook 已提交
253
{
254 255 256
    if (!con) {
        con = active_console;
    }
G
Gerd Hoffmann 已提交
257 258
    if (con && con->hw_ops->gfx_update) {
        con->hw_ops->gfx_update(con->hw);
259
    }
P
pbrook 已提交
260 261
}

262
void graphic_hw_invalidate(QemuConsole *con)
P
pbrook 已提交
263
{
264 265 266
    if (!con) {
        con = active_console;
    }
G
Gerd Hoffmann 已提交
267 268
    if (con && con->hw_ops->invalidate) {
        con->hw_ops->invalidate(con->hw);
269
    }
P
pbrook 已提交
270 271
}

G
Gerd Hoffmann 已提交
272 273
static void ppm_save(const char *filename, struct DisplaySurface *ds,
                     Error **errp)
P
pbrook 已提交
274
{
G
Gerd Hoffmann 已提交
275 276
    int width = pixman_image_get_width(ds->image);
    int height = pixman_image_get_height(ds->image);
277
    int fd;
G
Gerd Hoffmann 已提交
278 279 280 281 282 283
    FILE *f;
    int y;
    int ret;
    pixman_image_t *linebuf;

    trace_ppm_save(filename, ds);
284 285
    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
    if (fd == -1) {
G
Gerd Hoffmann 已提交
286 287 288
        error_setg(errp, "failed to open file '%s': %s", filename,
                   strerror(errno));
        return;
289
    }
290
    f = fdopen(fd, "wb");
G
Gerd Hoffmann 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
    if (ret < 0) {
        linebuf = NULL;
        goto write_err;
    }
    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
    for (y = 0; y < height; y++) {
        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
        clearerr(f);
        ret = fwrite(pixman_image_get_data(linebuf), 1,
                     pixman_image_get_stride(linebuf), f);
        (void)ret;
        if (ferror(f)) {
            goto write_err;
        }
306 307
    }

G
Gerd Hoffmann 已提交
308 309 310 311 312 313 314 315 316 317 318 319 320 321
out:
    qemu_pixman_image_unref(linebuf);
    fclose(f);
    return;

write_err:
    error_setg(errp, "failed to write to file '%s': %s", filename,
               strerror(errno));
    unlink(filename);
    goto out;
}

void qmp_screendump(const char *filename, Error **errp)
{
322
    QemuConsole *con = qemu_console_lookup_by_index(0);
G
Gerd Hoffmann 已提交
323 324 325 326 327
    DisplaySurface *surface;

    if (con == NULL) {
        error_setg(errp, "There is no QemuConsole I can screendump from.");
        return;
328
    }
G
Gerd Hoffmann 已提交
329 330 331 332

    graphic_hw_update(con);
    surface = qemu_console_surface(con);
    ppm_save(filename, surface, errp);
P
pbrook 已提交
333 334
}

335
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
B
balrog 已提交
336
{
337 338 339
    if (!con) {
        con = active_console;
    }
G
Gerd Hoffmann 已提交
340 341 342
    if (con && con->hw_ops->text_update) {
        con->hw_ops->text_update(con->hw, chardata);
    }
B
balrog 已提交
343 344
}

345 346
static void vga_fill_rect(QemuConsole *con,
                          int posx, int posy, int width, int height,
347
                          pixman_color_t color)
B
bellard 已提交
348
{
349
    DisplaySurface *surface = qemu_console_surface(con);
350 351 352 353 354
    pixman_rectangle16_t rect = {
        .x = posx, .y = posy, .width = width, .height = height
    };

    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
355
                                 &color, 1, &rect);
B
bellard 已提交
356 357 358
}

/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
359 360
static void vga_bitblt(QemuConsole *con,
                       int xs, int ys, int xd, int yd, int w, int h)
B
bellard 已提交
361
{
362
    DisplaySurface *surface = qemu_console_surface(con);
363 364 365 366

    pixman_image_composite(PIXMAN_OP_SRC,
                           surface->image, NULL, surface->image,
                           xs, ys, 0, 0, xd, yd, w, h);
B
bellard 已提交
367 368 369 370 371 372 373 374 375 376
}

/***********************************************************/
/* basic char display */

#define FONT_HEIGHT 16
#define FONT_WIDTH 8

#include "vgafont.h"

377
#ifndef CONFIG_CURSES
378 379 380 381 382 383 384 385 386 387
enum color_names {
    COLOR_BLACK   = 0,
    COLOR_RED     = 1,
    COLOR_GREEN   = 2,
    COLOR_YELLOW  = 3,
    COLOR_BLUE    = 4,
    COLOR_MAGENTA = 5,
    COLOR_CYAN    = 6,
    COLOR_WHITE   = 7
};
388
#endif
389

390 391 392 393
#define QEMU_RGB(r, g, b)                                               \
    { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }

static const pixman_color_t color_table_rgb[2][8] = {
394
    {   /* dark */
B
bellard 已提交
395 396 397 398 399 400 401 402
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
403 404
    },
    {   /* bright */
B
bellard 已提交
405 406 407 408 409 410 411 412
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
413
    }
B
bellard 已提交
414 415
};

416
static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
417
                          TextAttributes *t_attrib)
B
bellard 已提交
418
{
419
    static pixman_image_t *glyphs[256];
420
    DisplaySurface *surface = qemu_console_surface(s);
421
    pixman_color_t fgcol, bgcol;
422 423

    if (t_attrib->invers) {
G
Gerd Hoffmann 已提交
424 425
        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
426
    } else {
G
Gerd Hoffmann 已提交
427 428
        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
429
    }
B
bellard 已提交
430

431 432
    if (!glyphs[ch]) {
        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
B
bellard 已提交
433
    }
434
    qemu_pixman_glyph_render(glyphs[ch], surface->image,
435
                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
B
bellard 已提交
436 437
}

438
static void text_console_resize(QemuConsole *s)
B
bellard 已提交
439 440 441 442 443
{
    TextCell *cells, *c, *c1;
    int w1, x, y, last_width;

    last_width = s->width;
G
Gerd Hoffmann 已提交
444 445
    s->width = surface_width(s->surface) / FONT_WIDTH;
    s->height = surface_height(s->surface) / FONT_HEIGHT;
B
bellard 已提交
446 447 448 449 450

    w1 = last_width;
    if (s->width < w1)
        w1 = s->width;

451
    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
B
bellard 已提交
452 453 454 455 456 457 458 459 460 461
    for(y = 0; y < s->total_height; y++) {
        c = &cells[y * s->width];
        if (w1 > 0) {
            c1 = &s->cells[y * last_width];
            for(x = 0; x < w1; x++) {
                *c++ = *c1++;
            }
        }
        for(x = w1; x < s->width; x++) {
            c->ch = ' ';
462
            c->t_attrib = s->t_attrib_default;
B
bellard 已提交
463 464 465
            c++;
        }
    }
466
    g_free(s->cells);
B
bellard 已提交
467 468 469
    s->cells = cells;
}

470
static inline void text_update_xy(QemuConsole *s, int x, int y)
B
balrog 已提交
471 472 473 474 475 476 477
{
    s->text_x[0] = MIN(s->text_x[0], x);
    s->text_x[1] = MAX(s->text_x[1], x);
    s->text_y[0] = MIN(s->text_y[0], y);
    s->text_y[1] = MAX(s->text_y[1], y);
}

478
static void invalidate_xy(QemuConsole *s, int x, int y)
479
{
480 481 482
    if (!qemu_console_is_visible(s)) {
        return;
    }
483 484 485 486 487 488 489 490 491 492
    if (s->update_x0 > x * FONT_WIDTH)
        s->update_x0 = x * FONT_WIDTH;
    if (s->update_y0 > y * FONT_HEIGHT)
        s->update_y0 = y * FONT_HEIGHT;
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
        s->update_x1 = (x + 1) * FONT_WIDTH;
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
        s->update_y1 = (y + 1) * FONT_HEIGHT;
}

493
static void update_xy(QemuConsole *s, int x, int y)
B
bellard 已提交
494 495 496 497
{
    TextCell *c;
    int y1, y2;

498 499 500
    if (s->ds->have_text) {
        text_update_xy(s, x, y);
    }
B
balrog 已提交
501

502 503 504 505 506 507 508 509 510 511
    y1 = (s->y_base + y) % s->total_height;
    y2 = y1 - s->y_displayed;
    if (y2 < 0) {
        y2 += s->total_height;
    }
    if (y2 < s->height) {
        c = &s->cells[y1 * s->width + x];
        vga_putcharxy(s, x, y2, c->ch,
                      &(c->t_attrib));
        invalidate_xy(s, x, y2);
B
bellard 已提交
512 513 514
    }
}

515
static void console_show_cursor(QemuConsole *s, int show)
B
bellard 已提交
516 517 518
{
    TextCell *c;
    int y, y1;
519
    int x = s->x;
B
bellard 已提交
520

521 522 523
    if (s->ds->have_text) {
        s->cursor_invalidate = 1;
    }
B
balrog 已提交
524

525 526 527 528 529 530 531 532 533 534
    if (x >= s->width) {
        x = s->width - 1;
    }
    y1 = (s->y_base + s->y) % s->total_height;
    y = y1 - s->y_displayed;
    if (y < 0) {
        y += s->total_height;
    }
    if (y < s->height) {
        c = &s->cells[y1 * s->width + x];
535
        if (show && cursor_visible_phase) {
536 537 538 539 540
            TextAttributes t_attrib = s->t_attrib_default;
            t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
            vga_putcharxy(s, x, y, c->ch, &t_attrib);
        } else {
            vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
B
bellard 已提交
541
        }
542
        invalidate_xy(s, x, y);
B
bellard 已提交
543 544 545
    }
}

546
static void console_refresh(QemuConsole *s)
B
bellard 已提交
547
{
548
    DisplaySurface *surface = qemu_console_surface(s);
B
bellard 已提交
549 550 551
    TextCell *c;
    int x, y, y1;

552
    if (s->ds->have_text) {
B
balrog 已提交
553 554 555 556 557 558
        s->text_x[0] = 0;
        s->text_y[0] = 0;
        s->text_x[1] = s->width - 1;
        s->text_y[1] = s->height - 1;
        s->cursor_invalidate = 1;
    }
B
bellard 已提交
559

560 561 562 563 564 565 566 567 568 569 570 571
    vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
                  color_table_rgb[0][COLOR_BLACK]);
    y1 = s->y_displayed;
    for (y = 0; y < s->height; y++) {
        c = s->cells + y1 * s->width;
        for (x = 0; x < s->width; x++) {
            vga_putcharxy(s, x, y, c->ch,
                          &(c->t_attrib));
            c++;
        }
        if (++y1 == s->total_height) {
            y1 = 0;
B
bellard 已提交
572 573
        }
    }
574 575 576
    console_show_cursor(s, 1);
    dpy_gfx_update(s, 0, 0,
                   surface_width(surface), surface_height(surface));
B
bellard 已提交
577 578
}

G
Gerd Hoffmann 已提交
579
static void console_scroll(QemuConsole *s, int ydelta)
B
bellard 已提交
580 581
{
    int i, y1;
582

B
bellard 已提交
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
    if (ydelta > 0) {
        for(i = 0; i < ydelta; i++) {
            if (s->y_displayed == s->y_base)
                break;
            if (++s->y_displayed == s->total_height)
                s->y_displayed = 0;
        }
    } else {
        ydelta = -ydelta;
        i = s->backscroll_height;
        if (i > s->total_height - s->height)
            i = s->total_height - s->height;
        y1 = s->y_base - i;
        if (y1 < 0)
            y1 += s->total_height;
        for(i = 0; i < ydelta; i++) {
            if (s->y_displayed == y1)
                break;
            if (--s->y_displayed < 0)
                s->y_displayed = s->total_height - 1;
        }
    }
    console_refresh(s);
}

608
static void console_put_lf(QemuConsole *s)
B
bellard 已提交
609 610 611 612 613 614 615
{
    TextCell *c;
    int x, y1;

    s->y++;
    if (s->y >= s->height) {
        s->y = s->height - 1;
616

B
bellard 已提交
617 618 619 620 621 622 623 624 625 626 627 628
        if (s->y_displayed == s->y_base) {
            if (++s->y_displayed == s->total_height)
                s->y_displayed = 0;
        }
        if (++s->y_base == s->total_height)
            s->y_base = 0;
        if (s->backscroll_height < s->total_height)
            s->backscroll_height++;
        y1 = (s->y_base + s->height - 1) % s->total_height;
        c = &s->cells[y1 * s->width];
        for(x = 0; x < s->width; x++) {
            c->ch = ' ';
629
            c->t_attrib = s->t_attrib_default;
B
bellard 已提交
630 631
            c++;
        }
632
        if (s->y_displayed == s->y_base) {
633
            if (s->ds->have_text) {
B
balrog 已提交
634 635 636 637 638 639
                s->text_x[0] = 0;
                s->text_y[0] = 0;
                s->text_x[1] = s->width - 1;
                s->text_y[1] = s->height - 1;
            }

640 641 642 643 644 645 646 647 648 649
            vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
                       s->width * FONT_WIDTH,
                       (s->height - 1) * FONT_HEIGHT);
            vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
                          s->width * FONT_WIDTH, FONT_HEIGHT,
                          color_table_rgb[0][s->t_attrib_default.bgcol]);
            s->update_x0 = 0;
            s->update_y0 = 0;
            s->update_x1 = s->width * FONT_WIDTH;
            s->update_y1 = s->height * FONT_HEIGHT;
B
bellard 已提交
650 651 652 653
        }
    }
}

654 655 656 657
/* Set console attributes depending on the current escape codes.
 * NOTE: I know this code is not very efficient (checking every color for it
 * self) but it is more readable and better maintainable.
 */
658
static void console_handle_escape(QemuConsole *s)
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
{
    int i;

    for (i=0; i<s->nb_esc_params; i++) {
        switch (s->esc_params[i]) {
            case 0: /* reset all console attributes to default */
                s->t_attrib = s->t_attrib_default;
                break;
            case 1:
                s->t_attrib.bold = 1;
                break;
            case 4:
                s->t_attrib.uline = 1;
                break;
            case 5:
                s->t_attrib.blink = 1;
                break;
            case 7:
                s->t_attrib.invers = 1;
                break;
            case 8:
                s->t_attrib.unvisible = 1;
                break;
            case 22:
                s->t_attrib.bold = 0;
                break;
            case 24:
                s->t_attrib.uline = 0;
                break;
            case 25:
                s->t_attrib.blink = 0;
                break;
            case 27:
                s->t_attrib.invers = 0;
                break;
            case 28:
                s->t_attrib.unvisible = 0;
                break;
            /* set foreground color */
            case 30:
                s->t_attrib.fgcol=COLOR_BLACK;
                break;
            case 31:
                s->t_attrib.fgcol=COLOR_RED;
                break;
            case 32:
                s->t_attrib.fgcol=COLOR_GREEN;
                break;
            case 33:
                s->t_attrib.fgcol=COLOR_YELLOW;
                break;
            case 34:
                s->t_attrib.fgcol=COLOR_BLUE;
                break;
            case 35:
                s->t_attrib.fgcol=COLOR_MAGENTA;
                break;
            case 36:
                s->t_attrib.fgcol=COLOR_CYAN;
                break;
            case 37:
                s->t_attrib.fgcol=COLOR_WHITE;
                break;
            /* set background color */
            case 40:
                s->t_attrib.bgcol=COLOR_BLACK;
                break;
            case 41:
                s->t_attrib.bgcol=COLOR_RED;
                break;
            case 42:
                s->t_attrib.bgcol=COLOR_GREEN;
                break;
            case 43:
                s->t_attrib.bgcol=COLOR_YELLOW;
                break;
            case 44:
                s->t_attrib.bgcol=COLOR_BLUE;
                break;
            case 45:
                s->t_attrib.bgcol=COLOR_MAGENTA;
                break;
            case 46:
                s->t_attrib.bgcol=COLOR_CYAN;
                break;
            case 47:
                s->t_attrib.bgcol=COLOR_WHITE;
                break;
        }
    }
}

751
static void console_clear_xy(QemuConsole *s, int x, int y)
752 753 754 755 756 757 758 759
{
    int y1 = (s->y_base + y) % s->total_height;
    TextCell *c = &s->cells[y1 * s->width + x];
    c->ch = ' ';
    c->t_attrib = s->t_attrib_default;
    update_xy(s, x, y);
}

760
/* set cursor, checking bounds */
761
static void set_cursor(QemuConsole *s, int x, int y)
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
{
    if (x < 0) {
        x = 0;
    }
    if (y < 0) {
        y = 0;
    }
    if (y >= s->height) {
        y = s->height - 1;
    }
    if (x >= s->width) {
        x = s->width - 1;
    }

    s->x = x;
    s->y = y;
}

780
static void console_putchar(QemuConsole *s, int ch)
B
bellard 已提交
781 782
{
    TextCell *c;
783 784
    int y1, i;
    int x, y;
B
bellard 已提交
785 786 787 788

    switch(s->state) {
    case TTY_STATE_NORM:
        switch(ch) {
789
        case '\r':  /* carriage return */
B
bellard 已提交
790 791
            s->x = 0;
            break;
792
        case '\n':  /* newline */
B
bellard 已提交
793 794
            console_put_lf(s);
            break;
795
        case '\b':  /* backspace */
796
            if (s->x > 0)
797
                s->x--;
798 799 800
            break;
        case '\t':  /* tabspace */
            if (s->x + (8 - (s->x % 8)) > s->width) {
B
bellard 已提交
801
                s->x = 0;
802 803 804 805 806 807 808 809
                console_put_lf(s);
            } else {
                s->x = s->x + (8 - (s->x % 8));
            }
            break;
        case '\a':  /* alert aka. bell */
            /* TODO: has to be implemented */
            break;
810 811 812 813 814 815
        case 14:
            /* SI (shift in), character set 0 (ignored) */
            break;
        case 15:
            /* SO (shift out), character set 1 (ignored) */
            break;
816
        case 27:    /* esc (introducing an escape sequence) */
B
bellard 已提交
817 818 819
            s->state = TTY_STATE_ESC;
            break;
        default:
820 821 822 823
            if (s->x >= s->width) {
                /* line wrap */
                s->x = 0;
                console_put_lf(s);
824
            }
B
bellard 已提交
825 826 827
            y1 = (s->y_base + s->y) % s->total_height;
            c = &s->cells[y1 * s->width + s->x];
            c->ch = ch;
828
            c->t_attrib = s->t_attrib;
B
bellard 已提交
829 830 831 832 833
            update_xy(s, s->x, s->y);
            s->x++;
            break;
        }
        break;
834
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
B
bellard 已提交
835 836 837 838 839 840 841 842 843
        if (ch == '[') {
            for(i=0;i<MAX_ESC_PARAMS;i++)
                s->esc_params[i] = 0;
            s->nb_esc_params = 0;
            s->state = TTY_STATE_CSI;
        } else {
            s->state = TTY_STATE_NORM;
        }
        break;
844
    case TTY_STATE_CSI: /* handle escape sequence parameters */
B
bellard 已提交
845 846
        if (ch >= '0' && ch <= '9') {
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
847 848 849 850 851
                int *param = &s->esc_params[s->nb_esc_params];
                int digit = (ch - '0');

                *param = (*param <= (INT_MAX - digit) / 10) ?
                         *param * 10 + digit : INT_MAX;
B
bellard 已提交
852 853
            }
        } else {
854 855
            if (s->nb_esc_params < MAX_ESC_PARAMS)
                s->nb_esc_params++;
B
bellard 已提交
856 857
            if (ch == ';')
                break;
858 859
            trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
                                      ch, s->nb_esc_params);
B
bellard 已提交
860 861
            s->state = TTY_STATE_NORM;
            switch(ch) {
862 863 864 865 866
            case 'A':
                /* move cursor up */
                if (s->esc_params[0] == 0) {
                    s->esc_params[0] = 1;
                }
867
                set_cursor(s, s->x, s->y - s->esc_params[0]);
868 869 870 871 872 873
                break;
            case 'B':
                /* move cursor down */
                if (s->esc_params[0] == 0) {
                    s->esc_params[0] = 1;
                }
874
                set_cursor(s, s->x, s->y + s->esc_params[0]);
B
bellard 已提交
875 876
                break;
            case 'C':
877 878 879 880
                /* move cursor right */
                if (s->esc_params[0] == 0) {
                    s->esc_params[0] = 1;
                }
881
                set_cursor(s, s->x + s->esc_params[0], s->y);
B
bellard 已提交
882
                break;
883 884 885 886 887
            case 'D':
                /* move cursor left */
                if (s->esc_params[0] == 0) {
                    s->esc_params[0] = 1;
                }
888
                set_cursor(s, s->x - s->esc_params[0], s->y);
889 890 891
                break;
            case 'G':
                /* move cursor to column */
892
                set_cursor(s, s->esc_params[0] - 1, s->y);
893 894 895 896
                break;
            case 'f':
            case 'H':
                /* move cursor to row, column */
897
                set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
                break;
            case 'J':
                switch (s->esc_params[0]) {
                case 0:
                    /* clear to end of screen */
                    for (y = s->y; y < s->height; y++) {
                        for (x = 0; x < s->width; x++) {
                            if (y == s->y && x < s->x) {
                                continue;
                            }
                            console_clear_xy(s, x, y);
                        }
                    }
                    break;
                case 1:
                    /* clear from beginning of screen */
                    for (y = 0; y <= s->y; y++) {
                        for (x = 0; x < s->width; x++) {
                            if (y == s->y && x > s->x) {
                                break;
                            }
                            console_clear_xy(s, x, y);
                        }
                    }
                    break;
                case 2:
                    /* clear entire screen */
                    for (y = 0; y <= s->height; y++) {
                        for (x = 0; x < s->width; x++) {
                            console_clear_xy(s, x, y);
                        }
                    }
930
                    break;
931
                }
932
                break;
B
bellard 已提交
933
            case 'K':
934 935
                switch (s->esc_params[0]) {
                case 0:
936 937
                    /* clear to eol */
                    for(x = s->x; x < s->width; x++) {
938
                        console_clear_xy(s, x, s->y);
939 940
                    }
                    break;
941 942 943 944 945 946 947 948 949 950 951
                case 1:
                    /* clear from beginning of line */
                    for (x = 0; x <= s->x; x++) {
                        console_clear_xy(s, x, s->y);
                    }
                    break;
                case 2:
                    /* clear entire line */
                    for(x = 0; x < s->width; x++) {
                        console_clear_xy(s, x, s->y);
                    }
952 953
                    break;
                }
954 955
                break;
            case 'm':
956 957
                console_handle_escape(s);
                break;
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
            case 'n':
                /* report cursor position */
                /* TODO: send ESC[row;colR */
                break;
            case 's':
                /* save cursor position */
                s->x_saved = s->x;
                s->y_saved = s->y;
                break;
            case 'u':
                /* restore cursor position */
                s->x = s->x_saved;
                s->y = s->y_saved;
                break;
            default:
973
                trace_console_putchar_unhandled(ch);
974 975 976
                break;
            }
            break;
B
bellard 已提交
977 978 979 980 981 982
        }
    }
}

void console_select(unsigned int index)
{
983
    DisplayChangeListener *dcl;
984
    QemuConsole *s;
985

B
bellard 已提交
986 987
    if (index >= MAX_CONSOLES)
        return;
G
Gerd Hoffmann 已提交
988 989

    trace_console_select(index);
990
    s = qemu_console_lookup_by_index(index);
B
bellard 已提交
991
    if (s) {
992
        DisplayState *ds = s->ds;
993

B
bellard 已提交
994
        active_console = s;
995
        if (ds->have_gfx) {
996 997 998 999 1000 1001 1002 1003
            QLIST_FOREACH(dcl, &ds->listeners, next) {
                if (dcl->con != NULL) {
                    continue;
                }
                if (dcl->ops->dpy_gfx_switch) {
                    dcl->ops->dpy_gfx_switch(dcl, s->surface);
                }
            }
1004 1005
            dpy_gfx_update(s, 0, 0, surface_width(s->surface),
                           surface_height(s->surface));
1006 1007
        }
        if (ds->have_text) {
1008
            dpy_text_resize(s, s->width, s->height);
1009
        }
1010
        text_console_update_cursor(NULL);
B
bellard 已提交
1011 1012 1013 1014 1015
    }
}

static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
{
1016
    QemuConsole *s = chr->opaque;
B
bellard 已提交
1017 1018
    int i;

1019 1020 1021 1022
    s->update_x0 = s->width * FONT_WIDTH;
    s->update_y0 = s->height * FONT_HEIGHT;
    s->update_x1 = 0;
    s->update_y1 = 0;
B
bellard 已提交
1023 1024 1025 1026 1027
    console_show_cursor(s, 0);
    for(i = 0; i < len; i++) {
        console_putchar(s, buf[i]);
    }
    console_show_cursor(s, 1);
1028
    if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1029
        dpy_gfx_update(s, s->update_x0, s->update_y0,
1030 1031
                       s->update_x1 - s->update_x0,
                       s->update_y1 - s->update_y0);
1032
    }
B
bellard 已提交
1033 1034 1035
    return len;
}

1036 1037
static void kbd_send_chars(void *opaque)
{
1038
    QemuConsole *s = opaque;
1039 1040
    int len;
    uint8_t buf[16];
1041

1042
    len = qemu_chr_be_can_write(s->chr);
1043 1044 1045 1046 1047 1048
    if (len > s->out_fifo.count)
        len = s->out_fifo.count;
    if (len > 0) {
        if (len > sizeof(buf))
            len = sizeof(buf);
        qemu_fifo_read(&s->out_fifo, buf, len);
1049
        qemu_chr_be_write(s->chr, buf, len);
1050 1051 1052 1053
    }
    /* characters are pending: we send them a bit later (XXX:
       horrible, should change char device API) */
    if (s->out_fifo.count > 0) {
1054
        timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
1055 1056 1057
    }
}

B
bellard 已提交
1058
/* called when an ascii key is pressed */
1059
void kbd_put_keysym_console(QemuConsole *s, int keysym)
B
bellard 已提交
1060 1061 1062 1063
{
    uint8_t buf[16], *q;
    int c;

1064
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
B
bellard 已提交
1065 1066 1067 1068
        return;

    switch(keysym) {
    case QEMU_KEY_CTRL_UP:
G
Gerd Hoffmann 已提交
1069
        console_scroll(s, -1);
B
bellard 已提交
1070 1071
        break;
    case QEMU_KEY_CTRL_DOWN:
G
Gerd Hoffmann 已提交
1072
        console_scroll(s, 1);
B
bellard 已提交
1073 1074
        break;
    case QEMU_KEY_CTRL_PAGEUP:
G
Gerd Hoffmann 已提交
1075
        console_scroll(s, -10);
B
bellard 已提交
1076 1077
        break;
    case QEMU_KEY_CTRL_PAGEDOWN:
G
Gerd Hoffmann 已提交
1078
        console_scroll(s, 10);
B
bellard 已提交
1079 1080
        break;
    default:
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
        /* convert the QEMU keysym to VT100 key string */
        q = buf;
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
            *q++ = '\033';
            *q++ = '[';
            c = keysym - 0xe100;
            if (c >= 10)
                *q++ = '0' + (c / 10);
            *q++ = '0' + (c % 10);
            *q++ = '~';
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
            *q++ = '\033';
            *q++ = '[';
            *q++ = keysym & 0xff;
1095 1096 1097
        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
            console_puts(s->chr, (const uint8_t *) "\r", 1);
            *q++ = '\n';
1098
        } else {
1099 1100 1101 1102
            *q++ = keysym;
        }
        if (s->echo) {
            console_puts(s->chr, buf, q - buf);
1103
        }
1104
        if (s->chr->chr_read) {
1105 1106
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
            kbd_send_chars(s);
B
bellard 已提交
1107 1108 1109 1110 1111
        }
        break;
    }
}

1112 1113 1114 1115 1116
void kbd_put_keysym(int keysym)
{
    kbd_put_keysym_console(active_console, keysym);
}

B
balrog 已提交
1117 1118
static void text_console_invalidate(void *opaque)
{
1119
    QemuConsole *s = (QemuConsole *) opaque;
1120 1121

    if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1122 1123
        text_console_resize(s);
    }
B
balrog 已提交
1124 1125 1126
    console_refresh(s);
}

A
Anthony Liguori 已提交
1127
static void text_console_update(void *opaque, console_ch_t *chardata)
B
balrog 已提交
1128
{
1129
    QemuConsole *s = (QemuConsole *) opaque;
B
balrog 已提交
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
    int i, j, src;

    if (s->text_x[0] <= s->text_x[1]) {
        src = (s->y_base + s->text_y[0]) * s->width;
        chardata += s->text_y[0] * s->width;
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
            for (j = 0; j < s->width; j ++, src ++)
                console_write_ch(chardata ++, s->cells[src].ch |
                                (s->cells[src].t_attrib.fgcol << 12) |
                                (s->cells[src].t_attrib.bgcol << 8) |
                                (s->cells[src].t_attrib.bold << 21));
1141
        dpy_text_update(s, s->text_x[0], s->text_y[0],
1142
                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
B
balrog 已提交
1143 1144 1145 1146 1147 1148
        s->text_x[0] = s->width;
        s->text_y[0] = s->height;
        s->text_x[1] = 0;
        s->text_y[1] = 0;
    }
    if (s->cursor_invalidate) {
1149
        dpy_text_cursor(s, s->x, s->y);
B
balrog 已提交
1150 1151 1152 1153
        s->cursor_invalidate = 0;
    }
}

1154 1155
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
                                uint32_t head)
B
bellard 已提交
1156
{
G
Gerd Hoffmann 已提交
1157
    Object *obj;
1158
    QemuConsole *s;
P
pbrook 已提交
1159
    int i;
B
bellard 已提交
1160 1161 1162

    if (nb_consoles >= MAX_CONSOLES)
        return NULL;
1163

G
Gerd Hoffmann 已提交
1164 1165
    obj = object_new(TYPE_QEMU_CONSOLE);
    s = QEMU_CONSOLE(obj);
1166
    s->head = head;
1167
    object_property_add_link(obj, "device", TYPE_DEVICE,
1168
                             (Object **)&s->device,
1169
                             object_property_allow_set_link,
1170
                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
1171
                             &error_abort);
1172
    object_property_add_uint32_ptr(obj, "head",
1173
                                   &s->head, &error_abort);
1174

1175 1176
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
        (console_type == GRAPHIC_CONSOLE))) {
B
bellard 已提交
1177
        active_console = s;
1178
    }
B
bellard 已提交
1179
    s->ds = ds;
1180 1181
    s->console_type = console_type;
    if (console_type != GRAPHIC_CONSOLE) {
1182
        s->index = nb_consoles;
P
pbrook 已提交
1183 1184 1185 1186
        consoles[nb_consoles++] = s;
    } else {
        /* HACK: Put graphical consoles before text consoles.  */
        for (i = nb_consoles; i > 0; i--) {
1187
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
P
pbrook 已提交
1188 1189
                break;
            consoles[i] = consoles[i - 1];
1190
            consoles[i]->index = i;
P
pbrook 已提交
1191
        }
1192
        s->index = i;
P
pbrook 已提交
1193
        consoles[i] = s;
1194
        nb_consoles++;
P
pbrook 已提交
1195 1196 1197 1198
    }
    return s;
}

1199 1200
static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
                               int linesize, PixelFormat pf, int newflags)
1201 1202
{
    surface->pf = pf;
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213

    qemu_pixman_image_unref(surface->image);
    surface->image = NULL;

    surface->format = qemu_pixman_get_format(&pf);
    assert(surface->format != 0);
    surface->image = pixman_image_create_bits(surface->format,
                                              width, height,
                                              NULL, linesize);
    assert(surface->image != NULL);

1214
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1215
#ifdef HOST_WORDS_BIGENDIAN
1216
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1217 1218 1219
#endif
}

1220
DisplaySurface *qemu_create_displaysurface(int width, int height)
1221 1222 1223
{
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
    int linesize = width * 4;
1224 1225

    trace_displaysurface_create(surface, width, height);
1226 1227 1228 1229 1230
    qemu_alloc_display(surface, width, height, linesize,
                       qemu_default_pixelformat(32), 0);
    return surface;
}

G
Gerd Hoffmann 已提交
1231
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
G
Gerd Hoffmann 已提交
1232 1233
                                                int linesize, uint8_t *data,
                                                bool byteswap)
1234
{
1235
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1236

1237
    trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
G
Gerd Hoffmann 已提交
1238 1239 1240 1241 1242
    if (byteswap) {
        surface->pf = qemu_different_endianness_pixelformat(bpp);
    } else {
        surface->pf = qemu_default_pixelformat(bpp);
    }
1243 1244 1245 1246 1247 1248 1249 1250

    surface->format = qemu_pixman_get_format(&surface->pf);
    assert(surface->format != 0);
    surface->image = pixman_image_create_bits(surface->format,
                                              width, height,
                                              (void *)data, linesize);
    assert(surface->image != NULL);

1251 1252 1253 1254 1255 1256 1257
#ifdef HOST_WORDS_BIGENDIAN
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
#endif

    return surface;
}

G
Gerd Hoffmann 已提交
1258 1259
static DisplaySurface *qemu_create_message_surface(int w, int h,
                                                   const char *msg)
1260
{
G
Gerd Hoffmann 已提交
1261
    DisplaySurface *surface = qemu_create_displaysurface(w, h);
1262 1263 1264 1265 1266 1267
    pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
    pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
    pixman_image_t *glyph;
    int len, x, y, i;

    len = strlen(msg);
G
Gerd Hoffmann 已提交
1268 1269
    x = (w / FONT_WIDTH  - len) / 2;
    y = (h / FONT_HEIGHT - 1)   / 2;
1270 1271 1272 1273 1274 1275 1276 1277 1278
    for (i = 0; i < len; i++) {
        glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
        qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
                                 x+i, y, FONT_WIDTH, FONT_HEIGHT);
        qemu_pixman_image_unref(glyph);
    }
    return surface;
}

1279
void qemu_free_displaysurface(DisplaySurface *surface)
1280
{
1281
    if (surface == NULL) {
1282
        return;
G
Gerd Hoffmann 已提交
1283
    }
1284 1285 1286
    trace_displaysurface_free(surface);
    qemu_pixman_image_unref(surface->image);
    g_free(surface);
1287 1288
}

1289
void register_displaychangelistener(DisplayChangeListener *dcl)
1290
{
G
Gerd Hoffmann 已提交
1291 1292
    static const char nodev[] =
        "This VM has no graphic display device.";
1293
    static DisplaySurface *dummy;
1294 1295
    QemuConsole *con;

1296
    trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1297 1298 1299
    dcl->ds = get_alloc_displaystate();
    QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
    gui_setup_refresh(dcl->ds);
1300 1301 1302 1303 1304 1305
    if (dcl->con) {
        dcl->con->dcls++;
        con = dcl->con;
    } else {
        con = active_console;
    }
1306 1307 1308 1309 1310
    if (dcl->ops->dpy_gfx_switch) {
        if (con) {
            dcl->ops->dpy_gfx_switch(dcl, con->surface);
        } else {
            if (!dummy) {
G
Gerd Hoffmann 已提交
1311
                dummy = qemu_create_message_surface(640, 480, nodev);
1312 1313 1314
            }
            dcl->ops->dpy_gfx_switch(dcl, dummy);
        }
1315
    }
1316
    text_console_update_cursor(NULL);
1317 1318
}

G
Gerd Hoffmann 已提交
1319 1320 1321 1322 1323 1324 1325
void update_displaychangelistener(DisplayChangeListener *dcl,
                                  uint64_t interval)
{
    DisplayState *ds = dcl->ds;

    dcl->update_interval = interval;
    if (!ds->refreshing && ds->update_interval > interval) {
1326
        timer_mod(ds->gui_timer, ds->last_update + interval);
G
Gerd Hoffmann 已提交
1327 1328 1329
    }
}

1330 1331 1332 1333
void unregister_displaychangelistener(DisplayChangeListener *dcl)
{
    DisplayState *ds = dcl->ds;
    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1334 1335 1336
    if (dcl->con) {
        dcl->con->dcls--;
    }
1337 1338 1339 1340
    QLIST_REMOVE(dcl, next);
    gui_setup_refresh(ds);
}

G
Gerd Hoffmann 已提交
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
{
    assert(con != NULL);
    con->ui_info = *info;
    if (con->hw_ops->ui_info) {
        return con->hw_ops->ui_info(con->hw, con->head, info);
    }
    return -1;
}

1351
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1352
{
1353
    DisplayState *s = con->ds;
1354
    DisplayChangeListener *dcl;
1355 1356
    int width = surface_width(con->surface);
    int height = surface_height(con->surface);
1357 1358 1359 1360 1361 1362 1363 1364

    x = MAX(x, 0);
    y = MAX(y, 0);
    x = MIN(x, width);
    y = MIN(y, height);
    w = MIN(w, width - x);
    h = MIN(h, height - y);

G
Gerd Hoffmann 已提交
1365
    if (!qemu_console_is_visible(con)) {
1366 1367
        return;
    }
1368
    QLIST_FOREACH(dcl, &s->listeners, next) {
1369 1370 1371
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1372
        if (dcl->ops->dpy_gfx_update) {
1373
            dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1374 1375 1376 1377
        }
    }
}

1378 1379 1380 1381 1382
void dpy_gfx_replace_surface(QemuConsole *con,
                             DisplaySurface *surface)
{
    DisplayState *s = con->ds;
    DisplaySurface *old_surface = con->surface;
1383
    DisplayChangeListener *dcl;
1384 1385

    con->surface = surface;
1386 1387 1388 1389 1390 1391 1392
    QLIST_FOREACH(dcl, &s->listeners, next) {
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
        if (dcl->ops->dpy_gfx_switch) {
            dcl->ops->dpy_gfx_switch(dcl, surface);
        }
1393
    }
1394
    qemu_free_displaysurface(old_surface);
1395 1396
}

S
Stefan Weil 已提交
1397
static void dpy_refresh(DisplayState *s)
1398
{
1399 1400
    DisplayChangeListener *dcl;

1401 1402
    QLIST_FOREACH(dcl, &s->listeners, next) {
        if (dcl->ops->dpy_refresh) {
1403
            dcl->ops->dpy_refresh(dcl);
1404 1405 1406 1407
        }
    }
}

1408 1409
void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
                  int dst_x, int dst_y, int w, int h)
1410
{
1411
    DisplayState *s = con->ds;
1412
    DisplayChangeListener *dcl;
1413

G
Gerd Hoffmann 已提交
1414
    if (!qemu_console_is_visible(con)) {
1415 1416
        return;
    }
1417
    QLIST_FOREACH(dcl, &s->listeners, next) {
1418 1419 1420
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1421
        if (dcl->ops->dpy_gfx_copy) {
1422
            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
1423
        } else { /* TODO */
1424
            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
1425 1426 1427 1428
        }
    }
}

1429
void dpy_text_cursor(QemuConsole *con, int x, int y)
1430
{
1431
    DisplayState *s = con->ds;
1432
    DisplayChangeListener *dcl;
1433

G
Gerd Hoffmann 已提交
1434
    if (!qemu_console_is_visible(con)) {
1435 1436
        return;
    }
1437
    QLIST_FOREACH(dcl, &s->listeners, next) {
1438 1439 1440
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1441
        if (dcl->ops->dpy_text_cursor) {
1442
            dcl->ops->dpy_text_cursor(dcl, x, y);
1443 1444 1445 1446
        }
    }
}

1447
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1448
{
1449
    DisplayState *s = con->ds;
1450
    DisplayChangeListener *dcl;
1451

G
Gerd Hoffmann 已提交
1452
    if (!qemu_console_is_visible(con)) {
1453 1454
        return;
    }
1455
    QLIST_FOREACH(dcl, &s->listeners, next) {
1456 1457 1458
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1459
        if (dcl->ops->dpy_text_update) {
1460
            dcl->ops->dpy_text_update(dcl, x, y, w, h);
1461 1462 1463 1464
        }
    }
}

1465
void dpy_text_resize(QemuConsole *con, int w, int h)
1466
{
1467
    DisplayState *s = con->ds;
1468
    struct DisplayChangeListener *dcl;
1469

G
Gerd Hoffmann 已提交
1470
    if (!qemu_console_is_visible(con)) {
1471 1472
        return;
    }
1473
    QLIST_FOREACH(dcl, &s->listeners, next) {
1474 1475 1476
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1477
        if (dcl->ops->dpy_text_resize) {
1478
            dcl->ops->dpy_text_resize(dcl, w, h);
1479 1480 1481 1482
        }
    }
}

1483
void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1484
{
1485
    DisplayState *s = con->ds;
1486
    DisplayChangeListener *dcl;
1487

G
Gerd Hoffmann 已提交
1488
    if (!qemu_console_is_visible(con)) {
1489 1490
        return;
    }
1491
    QLIST_FOREACH(dcl, &s->listeners, next) {
1492 1493 1494
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1495
        if (dcl->ops->dpy_mouse_set) {
1496
            dcl->ops->dpy_mouse_set(dcl, x, y, on);
1497 1498 1499 1500
        }
    }
}

1501
void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1502
{
1503
    DisplayState *s = con->ds;
1504
    DisplayChangeListener *dcl;
1505

G
Gerd Hoffmann 已提交
1506
    if (!qemu_console_is_visible(con)) {
1507 1508
        return;
    }
1509
    QLIST_FOREACH(dcl, &s->listeners, next) {
1510 1511 1512
        if (con != (dcl->con ? dcl->con : active_console)) {
            continue;
        }
1513
        if (dcl->ops->dpy_cursor_define) {
1514
            dcl->ops->dpy_cursor_define(dcl, cursor);
1515 1516 1517 1518
        }
    }
}

1519
bool dpy_cursor_define_supported(QemuConsole *con)
1520
{
1521
    DisplayState *s = con->ds;
1522 1523
    DisplayChangeListener *dcl;

1524 1525 1526 1527 1528 1529 1530 1531
    QLIST_FOREACH(dcl, &s->listeners, next) {
        if (dcl->ops->dpy_cursor_define) {
            return true;
        }
    }
    return false;
}

1532 1533 1534
/***********************************************************/
/* register display */

1535 1536
/* console.c internal use only */
static DisplayState *get_alloc_displaystate(void)
1537
{
1538 1539
    if (!display_state) {
        display_state = g_new0(DisplayState, 1);
1540 1541
        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
                                    text_console_update_cursor, NULL);
1542 1543
    }
    return display_state;
1544 1545
}

1546 1547 1548 1549 1550
/*
 * Called by main(), after creating QemuConsoles
 * and before initializing ui (sdl/vnc/...).
 */
DisplayState *init_displaystate(void)
1551
{
1552
    gchar *name;
1553 1554
    int i;

1555
    if (!display_state) {
1556
        display_state = g_new0(DisplayState, 1);
1557
    }
1558 1559 1560 1561 1562 1563

    for (i = 0; i < nb_consoles; i++) {
        if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
            consoles[i]->ds == NULL) {
            text_console_do_init(consoles[i]->chr, display_state);
        }
1564 1565 1566 1567 1568 1569

        /* Hook up into the qom tree here (not in new_console()), once
         * all QemuConsoles are created and the order / numbering
         * doesn't change any more */
        name = g_strdup_printf("console[%d]", i);
        object_property_add_child(container_get(object_get_root(), "/backend"),
1570
                                  name, OBJECT(consoles[i]), &error_abort);
1571
        g_free(name);
1572 1573
    }

1574 1575 1576
    return display_state;
}

1577
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1578
                                  const GraphicHwOps *hw_ops,
1579
                                  void *opaque)
P
pbrook 已提交
1580
{
G
Gerd Hoffmann 已提交
1581 1582
    static const char noinit[] =
        "Guest has not initialized the display (yet).";
1583 1584
    int width = 640;
    int height = 480;
1585
    QemuConsole *s;
1586
    DisplayState *ds;
A
aurel32 已提交
1587

1588
    ds = get_alloc_displaystate();
G
Gerd Hoffmann 已提交
1589
    trace_console_gfx_new();
1590
    s = new_console(ds, GRAPHIC_CONSOLE, head);
G
Gerd Hoffmann 已提交
1591
    s->hw_ops = hw_ops;
P
pbrook 已提交
1592
    s->hw = opaque;
1593
    if (dev) {
1594 1595
        object_property_set_link(OBJECT(s), OBJECT(dev), "device",
                                 &error_abort);
1596
    }
1597

G
Gerd Hoffmann 已提交
1598
    s->surface = qemu_create_message_surface(width, height, noinit);
1599
    return s;
B
bellard 已提交
1600 1601
}

1602 1603 1604 1605 1606 1607 1608 1609
QemuConsole *qemu_console_lookup_by_index(unsigned int index)
{
    if (index >= MAX_CONSOLES) {
        return NULL;
    }
    return consoles[index];
}

1610
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1611 1612
{
    Object *obj;
1613
    uint32_t h;
1614 1615 1616 1617 1618 1619 1620
    int i;

    for (i = 0; i < nb_consoles; i++) {
        if (!consoles[i]) {
            continue;
        }
        obj = object_property_get_link(OBJECT(consoles[i]),
1621
                                       "device", &error_abort);
1622 1623 1624 1625
        if (DEVICE(obj) != dev) {
            continue;
        }
        h = object_property_get_int(OBJECT(consoles[i]),
1626
                                    "head", &error_abort);
1627 1628
        if (h != head) {
            continue;
1629
        }
1630
        return consoles[i];
1631 1632 1633 1634
    }
    return NULL;
}

G
Gerd Hoffmann 已提交
1635
bool qemu_console_is_visible(QemuConsole *con)
B
bellard 已提交
1636
{
1637
    return (con == active_console) || (con->dcls > 0);
B
bellard 已提交
1638 1639
}

G
Gerd Hoffmann 已提交
1640
bool qemu_console_is_graphic(QemuConsole *con)
1641
{
G
Gerd Hoffmann 已提交
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
    if (con == NULL) {
        con = active_console;
    }
    return con && (con->console_type == GRAPHIC_CONSOLE);
}

bool qemu_console_is_fixedsize(QemuConsole *con)
{
    if (con == NULL) {
        con = active_console;
    }
    return con && (con->console_type != TEXT_CONSOLE);
1654 1655
}

1656 1657 1658 1659 1660 1661 1662 1663
int qemu_console_get_index(QemuConsole *con)
{
    if (con == NULL) {
        con = active_console;
    }
    return con ? con->index : -1;
}

1664 1665 1666 1667 1668 1669 1670 1671
uint32_t qemu_console_get_head(QemuConsole *con)
{
    if (con == NULL) {
        con = active_console;
    }
    return con ? con->head : -1;
}

G
Gerd Hoffmann 已提交
1672 1673 1674 1675 1676 1677
QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
{
    assert(con != NULL);
    return &con->ui_info;
}

1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693
int qemu_console_get_width(QemuConsole *con, int fallback)
{
    if (con == NULL) {
        con = active_console;
    }
    return con ? surface_width(con->surface) : fallback;
}

int qemu_console_get_height(QemuConsole *con, int fallback)
{
    if (con == NULL) {
        con = active_console;
    }
    return con ? surface_height(con->surface) : fallback;
}

1694 1695
static void text_console_set_echo(CharDriverState *chr, bool echo)
{
1696
    QemuConsole *s = chr->opaque;
1697 1698 1699 1700

    s->echo = echo;
}

1701 1702 1703 1704 1705 1706
static void text_console_update_cursor_timer(void)
{
    timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
              + CONSOLE_CURSOR_PERIOD / 2);
}

1707 1708
static void text_console_update_cursor(void *opaque)
{
1709 1710 1711 1712
    QemuConsole *s;
    int i, count = 0;

    cursor_visible_phase = !cursor_visible_phase;
1713

1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
    for (i = 0; i < nb_consoles; i++) {
        s = consoles[i];
        if (qemu_console_is_graphic(s) ||
            !qemu_console_is_visible(s)) {
            continue;
        }
        count++;
        graphic_hw_invalidate(s);
    }

    if (count) {
        text_console_update_cursor_timer();
    }
1727 1728
}

G
Gerd Hoffmann 已提交
1729 1730 1731 1732 1733
static const GraphicHwOps text_console_ops = {
    .invalidate  = text_console_invalidate,
    .text_update = text_console_update,
};

P
Paolo Bonzini 已提交
1734
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
B
bellard 已提交
1735
{
1736
    QemuConsole *s;
G
Gerd Hoffmann 已提交
1737 1738
    int g_width = 80 * FONT_WIDTH;
    int g_height = 24 * FONT_HEIGHT;
1739

1740
    s = chr->opaque;
G
Gerd Hoffmann 已提交
1741

B
bellard 已提交
1742
    chr->chr_write = console_puts;
B
bellard 已提交
1743

1744 1745
    s->out_fifo.buf = s->out_fifo_buf;
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1746
    s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
1747
    s->ds = ds;
1748

B
bellard 已提交
1749 1750 1751 1752 1753
    s->y_displayed = 0;
    s->y_base = 0;
    s->total_height = DEFAULT_BACKSCROLL;
    s->x = 0;
    s->y = 0;
G
Gerd Hoffmann 已提交
1754
    if (!s->surface) {
1755
        if (active_console && active_console->surface) {
G
Gerd Hoffmann 已提交
1756 1757
            g_width = surface_width(active_console->surface);
            g_height = surface_height(active_console->surface);
1758
        }
G
Gerd Hoffmann 已提交
1759
        s->surface = qemu_create_displaysurface(g_width, g_height);
1760
    }
1761

G
Gerd Hoffmann 已提交
1762
    s->hw_ops = &text_console_ops;
B
balrog 已提交
1763 1764
    s->hw = s;

1765 1766 1767 1768 1769 1770 1771 1772 1773 1774
    /* Set text attribute defaults */
    s->t_attrib_default.bold = 0;
    s->t_attrib_default.uline = 0;
    s->t_attrib_default.blink = 0;
    s->t_attrib_default.invers = 0;
    s->t_attrib_default.unvisible = 0;
    s->t_attrib_default.fgcol = COLOR_WHITE;
    s->t_attrib_default.bgcol = COLOR_BLACK;
    /* set current text attributes to default */
    s->t_attrib = s->t_attrib_default;
B
bellard 已提交
1775 1776
    text_console_resize(s);

1777 1778 1779 1780
    if (chr->label) {
        char msg[128];
        int len;

1781
        s->t_attrib.bgcol = COLOR_BLUE;
1782 1783
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
        console_puts(chr, (uint8_t*)msg, len);
1784
        s->t_attrib = s->t_attrib_default;
1785 1786
    }

1787
    qemu_chr_be_generic_open(chr);
1788 1789
    if (chr->init)
        chr->init(chr);
B
bellard 已提交
1790
}
1791

G
Gerd Hoffmann 已提交
1792
static CharDriverState *text_console_init(ChardevVC *vc)
1793 1794
{
    CharDriverState *chr;
1795
    QemuConsole *s;
G
Gerd Hoffmann 已提交
1796 1797
    unsigned width = 0;
    unsigned height = 0;
1798

1799
    chr = g_malloc0(sizeof(CharDriverState));
1800

G
Gerd Hoffmann 已提交
1801 1802 1803 1804 1805
    if (vc->has_width) {
        width = vc->width;
    } else if (vc->has_cols) {
        width = vc->cols * FONT_WIDTH;
    }
1806

G
Gerd Hoffmann 已提交
1807 1808 1809 1810 1811
    if (vc->has_height) {
        height = vc->height;
    } else if (vc->has_rows) {
        height = vc->rows * FONT_HEIGHT;
    }
1812

G
Gerd Hoffmann 已提交
1813
    trace_console_txt_new(width, height);
1814
    if (width == 0 || height == 0) {
1815
        s = new_console(NULL, TEXT_CONSOLE, 0);
1816
    } else {
1817
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
G
Gerd Hoffmann 已提交
1818
        s->surface = qemu_create_displaysurface(width, height);
1819 1820 1821
    }

    if (!s) {
1822
        g_free(chr);
1823
        return NULL;
1824 1825 1826 1827
    }

    s->chr = chr;
    chr->opaque = s;
1828
    chr->chr_set_echo = text_console_set_echo;
1829 1830 1831 1832
    /* console/chardev init sometimes completes elsewhere in a 2nd
     * stage, so defer OPENED events until they are fully initialized
     */
    chr->explicit_be_open = true;
1833 1834 1835 1836

    if (display_state) {
        text_console_do_init(chr, display_state);
    }
1837
    return chr;
1838 1839
}

1840 1841
static VcHandler *vc_handler = text_console_init;

G
Gerd Hoffmann 已提交
1842
CharDriverState *vc_init(ChardevVC *vc)
1843
{
G
Gerd Hoffmann 已提交
1844
    return vc_handler(vc);
1845 1846 1847 1848 1849 1850 1851
}

void register_vc_handler(VcHandler *handler)
{
    vc_handler = handler;
}

1852
void qemu_console_resize(QemuConsole *s, int width, int height)
1853
{
1854 1855 1856 1857 1858
    DisplaySurface *surface;

    assert(s->console_type == GRAPHIC_CONSOLE);
    surface = qemu_create_displaysurface(width, height);
    dpy_gfx_replace_surface(s, surface);
1859
}
1860

1861
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
1862
                       int dst_x, int dst_y, int w, int h)
1863
{
1864 1865
    assert(con->console_type == GRAPHIC_CONSOLE);
    dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
1866
}
1867

1868 1869
DisplaySurface *qemu_console_surface(QemuConsole *console)
{
1870
    return console->surface;
1871 1872 1873 1874 1875 1876 1877
}

DisplayState *qemu_console_displaystate(QemuConsole *console)
{
    return console->ds;
}

1878
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1879 1880 1881 1882 1883 1884
{
    PixelFormat pf;

    memset(&pf, 0x00, sizeof(PixelFormat));

    pf.bits_per_pixel = bpp;
1885
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1886 1887 1888
    pf.depth = bpp == 32 ? 24 : bpp;

    switch (bpp) {
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898
        case 24:
            pf.rmask = 0x000000FF;
            pf.gmask = 0x0000FF00;
            pf.bmask = 0x00FF0000;
            pf.rmax = 255;
            pf.gmax = 255;
            pf.bmax = 255;
            pf.rshift = 0;
            pf.gshift = 8;
            pf.bshift = 16;
1899 1900 1901
            pf.rbits = 8;
            pf.gbits = 8;
            pf.bbits = 8;
1902
            break;
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
        case 32:
            pf.rmask = 0x0000FF00;
            pf.gmask = 0x00FF0000;
            pf.bmask = 0xFF000000;
            pf.amask = 0x00000000;
            pf.amax = 255;
            pf.rmax = 255;
            pf.gmax = 255;
            pf.bmax = 255;
            pf.ashift = 0;
            pf.rshift = 8;
            pf.gshift = 16;
            pf.bshift = 24;
1916 1917 1918 1919
            pf.rbits = 8;
            pf.gbits = 8;
            pf.bbits = 8;
            pf.abits = 8;
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
            break;
        default:
            break;
    }
    return pf;
}

PixelFormat qemu_default_pixelformat(int bpp)
{
    PixelFormat pf;

    memset(&pf, 0x00, sizeof(PixelFormat));

    pf.bits_per_pixel = bpp;
1934
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1935 1936 1937
    pf.depth = bpp == 32 ? 24 : bpp;

    switch (bpp) {
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
        case 15:
            pf.bits_per_pixel = 16;
            pf.rmask = 0x00007c00;
            pf.gmask = 0x000003E0;
            pf.bmask = 0x0000001F;
            pf.rmax = 31;
            pf.gmax = 31;
            pf.bmax = 31;
            pf.rshift = 10;
            pf.gshift = 5;
            pf.bshift = 0;
            pf.rbits = 5;
            pf.gbits = 5;
            pf.bbits = 5;
            break;
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
        case 16:
            pf.rmask = 0x0000F800;
            pf.gmask = 0x000007E0;
            pf.bmask = 0x0000001F;
            pf.rmax = 31;
            pf.gmax = 63;
            pf.bmax = 31;
            pf.rshift = 11;
            pf.gshift = 5;
            pf.bshift = 0;
1963 1964 1965
            pf.rbits = 5;
            pf.gbits = 6;
            pf.bbits = 5;
1966 1967
            break;
        case 24:
1968 1969 1970 1971 1972 1973 1974 1975 1976
            pf.rmask = 0x00FF0000;
            pf.gmask = 0x0000FF00;
            pf.bmask = 0x000000FF;
            pf.rmax = 255;
            pf.gmax = 255;
            pf.bmax = 255;
            pf.rshift = 16;
            pf.gshift = 8;
            pf.bshift = 0;
1977 1978 1979
            pf.rbits = 8;
            pf.gbits = 8;
            pf.bbits = 8;
1980
            break;
1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
        case 32:
            pf.rmask = 0x00FF0000;
            pf.gmask = 0x0000FF00;
            pf.bmask = 0x000000FF;
            pf.rmax = 255;
            pf.gmax = 255;
            pf.bmax = 255;
            pf.rshift = 16;
            pf.gshift = 8;
            pf.bshift = 0;
1991 1992 1993
            pf.rbits = 8;
            pf.gbits = 8;
            pf.bbits = 8;
1994 1995 1996 1997 1998 1999
            break;
        default:
            break;
    }
    return pf;
}
2000

G
Gerd Hoffmann 已提交
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
                              Error **errp)
{
    int val;

    backend->vc = g_new0(ChardevVC, 1);

    val = qemu_opt_get_number(opts, "width", 0);
    if (val != 0) {
        backend->vc->has_width = true;
        backend->vc->width = val;
    }

    val = qemu_opt_get_number(opts, "height", 0);
    if (val != 0) {
        backend->vc->has_height = true;
        backend->vc->height = val;
    }

    val = qemu_opt_get_number(opts, "cols", 0);
    if (val != 0) {
        backend->vc->has_cols = true;
        backend->vc->cols = val;
    }

    val = qemu_opt_get_number(opts, "rows", 0);
    if (val != 0) {
        backend->vc->has_rows = true;
        backend->vc->rows = val;
    }
}

G
Gerd Hoffmann 已提交
2033 2034 2035 2036 2037 2038 2039 2040
static const TypeInfo qemu_console_info = {
    .name = TYPE_QEMU_CONSOLE,
    .parent = TYPE_OBJECT,
    .instance_size = sizeof(QemuConsole),
    .class_size = sizeof(QemuConsoleClass),
};


2041 2042
static void register_types(void)
{
G
Gerd Hoffmann 已提交
2043
    type_register_static(&qemu_console_info);
G
Gerd Hoffmann 已提交
2044 2045
    register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
                              qemu_chr_parse_vc);
2046 2047 2048
}

type_init(register_types);