qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

console.c (78628B)


      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 
     25 #include "qemu/osdep.h"
     26 #include "ui/console.h"
     27 #include "hw/qdev-core.h"
     28 #include "qapi/error.h"
     29 #include "qapi/qapi-commands-ui.h"
     30 #include "qemu/fifo8.h"
     31 #include "qemu/main-loop.h"
     32 #include "qemu/module.h"
     33 #include "qemu/option.h"
     34 #include "qemu/timer.h"
     35 #include "chardev/char.h"
     36 #include "trace.h"
     37 #include "exec/memory.h"
     38 #include "io/channel-file.h"
     39 #include "qom/object.h"
     40 #ifdef CONFIG_PNG
     41 #include <png.h>
     42 #endif
     43 
     44 #define DEFAULT_BACKSCROLL 512
     45 #define CONSOLE_CURSOR_PERIOD 500
     46 
     47 typedef struct TextAttributes {
     48     uint8_t fgcol:4;
     49     uint8_t bgcol:4;
     50     uint8_t bold:1;
     51     uint8_t uline:1;
     52     uint8_t blink:1;
     53     uint8_t invers:1;
     54     uint8_t unvisible:1;
     55 } TextAttributes;
     56 
     57 typedef struct TextCell {
     58     uint8_t ch;
     59     TextAttributes t_attrib;
     60 } TextCell;
     61 
     62 #define MAX_ESC_PARAMS 3
     63 
     64 enum TTYState {
     65     TTY_STATE_NORM,
     66     TTY_STATE_ESC,
     67     TTY_STATE_CSI,
     68 };
     69 
     70 typedef enum {
     71     GRAPHIC_CONSOLE,
     72     TEXT_CONSOLE,
     73     TEXT_CONSOLE_FIXED_SIZE
     74 } console_type_t;
     75 
     76 struct QemuConsole {
     77     Object parent;
     78 
     79     int index;
     80     console_type_t console_type;
     81     DisplayState *ds;
     82     DisplaySurface *surface;
     83     DisplayScanout scanout;
     84     int dcls;
     85     DisplayGLCtx *gl;
     86     int gl_block;
     87     QEMUTimer *gl_unblock_timer;
     88     int window_id;
     89 
     90     /* Graphic console state.  */
     91     Object *device;
     92     uint32_t head;
     93     QemuUIInfo ui_info;
     94     QEMUTimer *ui_timer;
     95     const GraphicHwOps *hw_ops;
     96     void *hw;
     97 
     98     /* Text console state */
     99     int width;
    100     int height;
    101     int total_height;
    102     int backscroll_height;
    103     int x, y;
    104     int x_saved, y_saved;
    105     int y_displayed;
    106     int y_base;
    107     TextAttributes t_attrib_default; /* default text attributes */
    108     TextAttributes t_attrib; /* currently active text attributes */
    109     TextCell *cells;
    110     int text_x[2], text_y[2], cursor_invalidate;
    111     int echo;
    112 
    113     int update_x0;
    114     int update_y0;
    115     int update_x1;
    116     int update_y1;
    117 
    118     enum TTYState state;
    119     int esc_params[MAX_ESC_PARAMS];
    120     int nb_esc_params;
    121 
    122     Chardev *chr;
    123     /* fifo for key pressed */
    124     Fifo8 out_fifo;
    125     CoQueue dump_queue;
    126 
    127     QTAILQ_ENTRY(QemuConsole) next;
    128 };
    129 
    130 struct DisplayState {
    131     QEMUTimer *gui_timer;
    132     uint64_t last_update;
    133     uint64_t update_interval;
    134     bool refreshing;
    135     bool have_gfx;
    136     bool have_text;
    137 
    138     QLIST_HEAD(, DisplayChangeListener) listeners;
    139 };
    140 
    141 static DisplayState *display_state;
    142 static QemuConsole *active_console;
    143 static QTAILQ_HEAD(, QemuConsole) consoles =
    144     QTAILQ_HEAD_INITIALIZER(consoles);
    145 static bool cursor_visible_phase;
    146 static QEMUTimer *cursor_timer;
    147 
    148 static void text_console_do_init(Chardev *chr, DisplayState *ds);
    149 static void dpy_refresh(DisplayState *s);
    150 static DisplayState *get_alloc_displaystate(void);
    151 static void text_console_update_cursor_timer(void);
    152 static void text_console_update_cursor(void *opaque);
    153 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
    154 static bool console_compatible_with(QemuConsole *con,
    155                                     DisplayChangeListener *dcl, Error **errp);
    156 
    157 static void gui_update(void *opaque)
    158 {
    159     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
    160     uint64_t dcl_interval;
    161     DisplayState *ds = opaque;
    162     DisplayChangeListener *dcl;
    163 
    164     ds->refreshing = true;
    165     dpy_refresh(ds);
    166     ds->refreshing = false;
    167 
    168     QLIST_FOREACH(dcl, &ds->listeners, next) {
    169         dcl_interval = dcl->update_interval ?
    170             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
    171         if (interval > dcl_interval) {
    172             interval = dcl_interval;
    173         }
    174     }
    175     if (ds->update_interval != interval) {
    176         ds->update_interval = interval;
    177         trace_console_refresh(interval);
    178     }
    179     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
    180     timer_mod(ds->gui_timer, ds->last_update + interval);
    181 }
    182 
    183 static void gui_setup_refresh(DisplayState *ds)
    184 {
    185     DisplayChangeListener *dcl;
    186     bool need_timer = false;
    187     bool have_gfx = false;
    188     bool have_text = false;
    189 
    190     QLIST_FOREACH(dcl, &ds->listeners, next) {
    191         if (dcl->ops->dpy_refresh != NULL) {
    192             need_timer = true;
    193         }
    194         if (dcl->ops->dpy_gfx_update != NULL) {
    195             have_gfx = true;
    196         }
    197         if (dcl->ops->dpy_text_update != NULL) {
    198             have_text = true;
    199         }
    200     }
    201 
    202     if (need_timer && ds->gui_timer == NULL) {
    203         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
    204         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
    205     }
    206     if (!need_timer && ds->gui_timer != NULL) {
    207         timer_free(ds->gui_timer);
    208         ds->gui_timer = NULL;
    209     }
    210 
    211     ds->have_gfx = have_gfx;
    212     ds->have_text = have_text;
    213 }
    214 
    215 void graphic_hw_update_done(QemuConsole *con)
    216 {
    217     if (con) {
    218         qemu_co_enter_all(&con->dump_queue, NULL);
    219     }
    220 }
    221 
    222 void graphic_hw_update(QemuConsole *con)
    223 {
    224     bool async = false;
    225     con = con ? con : active_console;
    226     if (!con) {
    227         return;
    228     }
    229     if (con->hw_ops->gfx_update) {
    230         con->hw_ops->gfx_update(con->hw);
    231         async = con->hw_ops->gfx_update_async;
    232     }
    233     if (!async) {
    234         graphic_hw_update_done(con);
    235     }
    236 }
    237 
    238 static void graphic_hw_gl_unblock_timer(void *opaque)
    239 {
    240     warn_report("console: no gl-unblock within one second");
    241 }
    242 
    243 void graphic_hw_gl_block(QemuConsole *con, bool block)
    244 {
    245     uint64_t timeout;
    246     assert(con != NULL);
    247 
    248     if (block) {
    249         con->gl_block++;
    250     } else {
    251         con->gl_block--;
    252     }
    253     assert(con->gl_block >= 0);
    254     if (!con->hw_ops->gl_block) {
    255         return;
    256     }
    257     if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
    258         return;
    259     }
    260     con->hw_ops->gl_block(con->hw, block);
    261 
    262     if (block) {
    263         timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
    264         timeout += 1000; /* one sec */
    265         timer_mod(con->gl_unblock_timer, timeout);
    266     } else {
    267         timer_del(con->gl_unblock_timer);
    268     }
    269 }
    270 
    271 int qemu_console_get_window_id(QemuConsole *con)
    272 {
    273     return con->window_id;
    274 }
    275 
    276 void qemu_console_set_window_id(QemuConsole *con, int window_id)
    277 {
    278     con->window_id = window_id;
    279 }
    280 
    281 void graphic_hw_invalidate(QemuConsole *con)
    282 {
    283     if (!con) {
    284         con = active_console;
    285     }
    286     if (con && con->hw_ops->invalidate) {
    287         con->hw_ops->invalidate(con->hw);
    288     }
    289 }
    290 
    291 #ifdef CONFIG_PNG
    292 /**
    293  * png_save: Take a screenshot as PNG
    294  *
    295  * Saves screendump as a PNG file
    296  *
    297  * Returns true for success or false for error.
    298  *
    299  * @fd: File descriptor for PNG file.
    300  * @image: Image data in pixman format.
    301  * @errp: Pointer to an error.
    302  */
    303 static bool png_save(int fd, pixman_image_t *image, Error **errp)
    304 {
    305     int width = pixman_image_get_width(image);
    306     int height = pixman_image_get_height(image);
    307     png_struct *png_ptr;
    308     png_info *info_ptr;
    309     g_autoptr(pixman_image_t) linebuf =
    310                             qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width);
    311     uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
    312     FILE *f = fdopen(fd, "wb");
    313     int y;
    314     if (!f) {
    315         error_setg_errno(errp, errno,
    316                          "Failed to create file from file descriptor");
    317         return false;
    318     }
    319 
    320     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
    321                                       NULL, NULL);
    322     if (!png_ptr) {
    323         error_setg(errp, "PNG creation failed. Unable to write struct");
    324         fclose(f);
    325         return false;
    326     }
    327 
    328     info_ptr = png_create_info_struct(png_ptr);
    329 
    330     if (!info_ptr) {
    331         error_setg(errp, "PNG creation failed. Unable to write info");
    332         fclose(f);
    333         png_destroy_write_struct(&png_ptr, &info_ptr);
    334         return false;
    335     }
    336 
    337     png_init_io(png_ptr, f);
    338 
    339     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
    340                  PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
    341                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    342 
    343     png_write_info(png_ptr, info_ptr);
    344 
    345     for (y = 0; y < height; ++y) {
    346         qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
    347         png_write_row(png_ptr, buf);
    348     }
    349 
    350     png_write_end(png_ptr, NULL);
    351 
    352     png_destroy_write_struct(&png_ptr, &info_ptr);
    353 
    354     if (fclose(f) != 0) {
    355         error_setg_errno(errp, errno,
    356                          "PNG creation failed. Unable to close file");
    357         return false;
    358     }
    359 
    360     return true;
    361 }
    362 
    363 #else /* no png support */
    364 
    365 static bool png_save(int fd, pixman_image_t *image, Error **errp)
    366 {
    367     error_setg(errp, "Enable PNG support with libpng for screendump");
    368     return false;
    369 }
    370 
    371 #endif /* CONFIG_PNG */
    372 
    373 static bool ppm_save(int fd, pixman_image_t *image, Error **errp)
    374 {
    375     int width = pixman_image_get_width(image);
    376     int height = pixman_image_get_height(image);
    377     g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
    378     g_autofree char *header = NULL;
    379     g_autoptr(pixman_image_t) linebuf = NULL;
    380     int y;
    381 
    382     trace_ppm_save(fd, image);
    383 
    384     header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
    385     if (qio_channel_write_all(QIO_CHANNEL(ioc),
    386                               header, strlen(header), errp) < 0) {
    387         return false;
    388     }
    389 
    390     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
    391     for (y = 0; y < height; y++) {
    392         qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
    393         if (qio_channel_write_all(QIO_CHANNEL(ioc),
    394                                   (char *)pixman_image_get_data(linebuf),
    395                                   pixman_image_get_stride(linebuf), errp) < 0) {
    396             return false;
    397         }
    398     }
    399 
    400     return true;
    401 }
    402 
    403 static void graphic_hw_update_bh(void *con)
    404 {
    405     graphic_hw_update(con);
    406 }
    407 
    408 /* Safety: coroutine-only, concurrent-coroutine safe, main thread only */
    409 void coroutine_fn
    410 qmp_screendump(const char *filename, bool has_device, const char *device,
    411                bool has_head, int64_t head,
    412                bool has_format, ImageFormat format, Error **errp)
    413 {
    414     g_autoptr(pixman_image_t) image = NULL;
    415     QemuConsole *con;
    416     DisplaySurface *surface;
    417     int fd;
    418 
    419     if (has_device) {
    420         con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
    421                                                  errp);
    422         if (!con) {
    423             return;
    424         }
    425     } else {
    426         if (has_head) {
    427             error_setg(errp, "'head' must be specified together with 'device'");
    428             return;
    429         }
    430         con = qemu_console_lookup_by_index(0);
    431         if (!con) {
    432             error_setg(errp, "There is no console to take a screendump from");
    433             return;
    434         }
    435     }
    436 
    437     if (qemu_co_queue_empty(&con->dump_queue)) {
    438         /* Defer the update, it will restart the pending coroutines */
    439         aio_bh_schedule_oneshot(qemu_get_aio_context(),
    440                                 graphic_hw_update_bh, con);
    441     }
    442     qemu_co_queue_wait(&con->dump_queue, NULL);
    443 
    444     /*
    445      * All pending coroutines are woken up, while the BQL is held.  No
    446      * further graphic update are possible until it is released.  Take
    447      * an image ref before that.
    448      */
    449     surface = qemu_console_surface(con);
    450     if (!surface) {
    451         error_setg(errp, "no surface");
    452         return;
    453     }
    454     image = pixman_image_ref(surface->image);
    455 
    456     fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
    457     if (fd == -1) {
    458         error_setg(errp, "failed to open file '%s': %s", filename,
    459                    strerror(errno));
    460         return;
    461     }
    462 
    463     /*
    464      * The image content could potentially be updated as the coroutine
    465      * yields and releases the BQL. It could produce corrupted dump, but
    466      * it should be otherwise safe.
    467      */
    468     if (has_format && format == IMAGE_FORMAT_PNG) {
    469         /* PNG format specified for screendump */
    470         if (!png_save(fd, image, errp)) {
    471             qemu_unlink(filename);
    472         }
    473     } else {
    474         /* PPM format specified/default for screendump */
    475         if (!ppm_save(fd, image, errp)) {
    476             qemu_unlink(filename);
    477         }
    478     }
    479 }
    480 
    481 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
    482 {
    483     if (!con) {
    484         con = active_console;
    485     }
    486     if (con && con->hw_ops->text_update) {
    487         con->hw_ops->text_update(con->hw, chardata);
    488     }
    489 }
    490 
    491 static void vga_fill_rect(QemuConsole *con,
    492                           int posx, int posy, int width, int height,
    493                           pixman_color_t color)
    494 {
    495     DisplaySurface *surface = qemu_console_surface(con);
    496     pixman_rectangle16_t rect = {
    497         .x = posx, .y = posy, .width = width, .height = height
    498     };
    499 
    500     pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
    501                                  &color, 1, &rect);
    502 }
    503 
    504 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
    505 static void vga_bitblt(QemuConsole *con,
    506                        int xs, int ys, int xd, int yd, int w, int h)
    507 {
    508     DisplaySurface *surface = qemu_console_surface(con);
    509 
    510     pixman_image_composite(PIXMAN_OP_SRC,
    511                            surface->image, NULL, surface->image,
    512                            xs, ys, 0, 0, xd, yd, w, h);
    513 }
    514 
    515 /***********************************************************/
    516 /* basic char display */
    517 
    518 #define FONT_HEIGHT 16
    519 #define FONT_WIDTH 8
    520 
    521 #include "vgafont.h"
    522 
    523 #define QEMU_RGB(r, g, b)                                               \
    524     { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
    525 
    526 static const pixman_color_t color_table_rgb[2][8] = {
    527     {   /* dark */
    528         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
    529         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
    530         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
    531         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
    532         [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
    533         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
    534         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
    535         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
    536     },
    537     {   /* bright */
    538         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
    539         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
    540         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
    541         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
    542         [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
    543         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
    544         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
    545         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
    546     }
    547 };
    548 
    549 static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
    550                           TextAttributes *t_attrib)
    551 {
    552     static pixman_image_t *glyphs[256];
    553     DisplaySurface *surface = qemu_console_surface(s);
    554     pixman_color_t fgcol, bgcol;
    555 
    556     if (t_attrib->invers) {
    557         bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
    558         fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
    559     } else {
    560         fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
    561         bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
    562     }
    563 
    564     if (!glyphs[ch]) {
    565         glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
    566     }
    567     qemu_pixman_glyph_render(glyphs[ch], surface->image,
    568                              &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
    569 }
    570 
    571 static void text_console_resize(QemuConsole *s)
    572 {
    573     TextCell *cells, *c, *c1;
    574     int w1, x, y, last_width;
    575 
    576     assert(s->scanout.kind == SCANOUT_SURFACE);
    577 
    578     last_width = s->width;
    579     s->width = surface_width(s->surface) / FONT_WIDTH;
    580     s->height = surface_height(s->surface) / FONT_HEIGHT;
    581 
    582     w1 = last_width;
    583     if (s->width < w1)
    584         w1 = s->width;
    585 
    586     cells = g_new(TextCell, s->width * s->total_height + 1);
    587     for(y = 0; y < s->total_height; y++) {
    588         c = &cells[y * s->width];
    589         if (w1 > 0) {
    590             c1 = &s->cells[y * last_width];
    591             for(x = 0; x < w1; x++) {
    592                 *c++ = *c1++;
    593             }
    594         }
    595         for(x = w1; x < s->width; x++) {
    596             c->ch = ' ';
    597             c->t_attrib = s->t_attrib_default;
    598             c++;
    599         }
    600     }
    601     g_free(s->cells);
    602     s->cells = cells;
    603 }
    604 
    605 static inline void text_update_xy(QemuConsole *s, int x, int y)
    606 {
    607     s->text_x[0] = MIN(s->text_x[0], x);
    608     s->text_x[1] = MAX(s->text_x[1], x);
    609     s->text_y[0] = MIN(s->text_y[0], y);
    610     s->text_y[1] = MAX(s->text_y[1], y);
    611 }
    612 
    613 static void invalidate_xy(QemuConsole *s, int x, int y)
    614 {
    615     if (!qemu_console_is_visible(s)) {
    616         return;
    617     }
    618     if (s->update_x0 > x * FONT_WIDTH)
    619         s->update_x0 = x * FONT_WIDTH;
    620     if (s->update_y0 > y * FONT_HEIGHT)
    621         s->update_y0 = y * FONT_HEIGHT;
    622     if (s->update_x1 < (x + 1) * FONT_WIDTH)
    623         s->update_x1 = (x + 1) * FONT_WIDTH;
    624     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
    625         s->update_y1 = (y + 1) * FONT_HEIGHT;
    626 }
    627 
    628 static void update_xy(QemuConsole *s, int x, int y)
    629 {
    630     TextCell *c;
    631     int y1, y2;
    632 
    633     if (s->ds->have_text) {
    634         text_update_xy(s, x, y);
    635     }
    636 
    637     y1 = (s->y_base + y) % s->total_height;
    638     y2 = y1 - s->y_displayed;
    639     if (y2 < 0) {
    640         y2 += s->total_height;
    641     }
    642     if (y2 < s->height) {
    643         if (x >= s->width) {
    644             x = s->width - 1;
    645         }
    646         c = &s->cells[y1 * s->width + x];
    647         vga_putcharxy(s, x, y2, c->ch,
    648                       &(c->t_attrib));
    649         invalidate_xy(s, x, y2);
    650     }
    651 }
    652 
    653 static void console_show_cursor(QemuConsole *s, int show)
    654 {
    655     TextCell *c;
    656     int y, y1;
    657     int x = s->x;
    658 
    659     if (s->ds->have_text) {
    660         s->cursor_invalidate = 1;
    661     }
    662 
    663     if (x >= s->width) {
    664         x = s->width - 1;
    665     }
    666     y1 = (s->y_base + s->y) % s->total_height;
    667     y = y1 - s->y_displayed;
    668     if (y < 0) {
    669         y += s->total_height;
    670     }
    671     if (y < s->height) {
    672         c = &s->cells[y1 * s->width + x];
    673         if (show && cursor_visible_phase) {
    674             TextAttributes t_attrib = s->t_attrib_default;
    675             t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
    676             vga_putcharxy(s, x, y, c->ch, &t_attrib);
    677         } else {
    678             vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
    679         }
    680         invalidate_xy(s, x, y);
    681     }
    682 }
    683 
    684 static void console_refresh(QemuConsole *s)
    685 {
    686     DisplaySurface *surface = qemu_console_surface(s);
    687     TextCell *c;
    688     int x, y, y1;
    689 
    690     if (s->ds->have_text) {
    691         s->text_x[0] = 0;
    692         s->text_y[0] = 0;
    693         s->text_x[1] = s->width - 1;
    694         s->text_y[1] = s->height - 1;
    695         s->cursor_invalidate = 1;
    696     }
    697 
    698     vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
    699                   color_table_rgb[0][QEMU_COLOR_BLACK]);
    700     y1 = s->y_displayed;
    701     for (y = 0; y < s->height; y++) {
    702         c = s->cells + y1 * s->width;
    703         for (x = 0; x < s->width; x++) {
    704             vga_putcharxy(s, x, y, c->ch,
    705                           &(c->t_attrib));
    706             c++;
    707         }
    708         if (++y1 == s->total_height) {
    709             y1 = 0;
    710         }
    711     }
    712     console_show_cursor(s, 1);
    713     dpy_gfx_update(s, 0, 0,
    714                    surface_width(surface), surface_height(surface));
    715 }
    716 
    717 static void console_scroll(QemuConsole *s, int ydelta)
    718 {
    719     int i, y1;
    720 
    721     if (ydelta > 0) {
    722         for(i = 0; i < ydelta; i++) {
    723             if (s->y_displayed == s->y_base)
    724                 break;
    725             if (++s->y_displayed == s->total_height)
    726                 s->y_displayed = 0;
    727         }
    728     } else {
    729         ydelta = -ydelta;
    730         i = s->backscroll_height;
    731         if (i > s->total_height - s->height)
    732             i = s->total_height - s->height;
    733         y1 = s->y_base - i;
    734         if (y1 < 0)
    735             y1 += s->total_height;
    736         for(i = 0; i < ydelta; i++) {
    737             if (s->y_displayed == y1)
    738                 break;
    739             if (--s->y_displayed < 0)
    740                 s->y_displayed = s->total_height - 1;
    741         }
    742     }
    743     console_refresh(s);
    744 }
    745 
    746 static void console_put_lf(QemuConsole *s)
    747 {
    748     TextCell *c;
    749     int x, y1;
    750 
    751     s->y++;
    752     if (s->y >= s->height) {
    753         s->y = s->height - 1;
    754 
    755         if (s->y_displayed == s->y_base) {
    756             if (++s->y_displayed == s->total_height)
    757                 s->y_displayed = 0;
    758         }
    759         if (++s->y_base == s->total_height)
    760             s->y_base = 0;
    761         if (s->backscroll_height < s->total_height)
    762             s->backscroll_height++;
    763         y1 = (s->y_base + s->height - 1) % s->total_height;
    764         c = &s->cells[y1 * s->width];
    765         for(x = 0; x < s->width; x++) {
    766             c->ch = ' ';
    767             c->t_attrib = s->t_attrib_default;
    768             c++;
    769         }
    770         if (s->y_displayed == s->y_base) {
    771             if (s->ds->have_text) {
    772                 s->text_x[0] = 0;
    773                 s->text_y[0] = 0;
    774                 s->text_x[1] = s->width - 1;
    775                 s->text_y[1] = s->height - 1;
    776             }
    777 
    778             vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
    779                        s->width * FONT_WIDTH,
    780                        (s->height - 1) * FONT_HEIGHT);
    781             vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
    782                           s->width * FONT_WIDTH, FONT_HEIGHT,
    783                           color_table_rgb[0][s->t_attrib_default.bgcol]);
    784             s->update_x0 = 0;
    785             s->update_y0 = 0;
    786             s->update_x1 = s->width * FONT_WIDTH;
    787             s->update_y1 = s->height * FONT_HEIGHT;
    788         }
    789     }
    790 }
    791 
    792 /* Set console attributes depending on the current escape codes.
    793  * NOTE: I know this code is not very efficient (checking every color for it
    794  * self) but it is more readable and better maintainable.
    795  */
    796 static void console_handle_escape(QemuConsole *s)
    797 {
    798     int i;
    799 
    800     for (i=0; i<s->nb_esc_params; i++) {
    801         switch (s->esc_params[i]) {
    802             case 0: /* reset all console attributes to default */
    803                 s->t_attrib = s->t_attrib_default;
    804                 break;
    805             case 1:
    806                 s->t_attrib.bold = 1;
    807                 break;
    808             case 4:
    809                 s->t_attrib.uline = 1;
    810                 break;
    811             case 5:
    812                 s->t_attrib.blink = 1;
    813                 break;
    814             case 7:
    815                 s->t_attrib.invers = 1;
    816                 break;
    817             case 8:
    818                 s->t_attrib.unvisible = 1;
    819                 break;
    820             case 22:
    821                 s->t_attrib.bold = 0;
    822                 break;
    823             case 24:
    824                 s->t_attrib.uline = 0;
    825                 break;
    826             case 25:
    827                 s->t_attrib.blink = 0;
    828                 break;
    829             case 27:
    830                 s->t_attrib.invers = 0;
    831                 break;
    832             case 28:
    833                 s->t_attrib.unvisible = 0;
    834                 break;
    835             /* set foreground color */
    836             case 30:
    837                 s->t_attrib.fgcol = QEMU_COLOR_BLACK;
    838                 break;
    839             case 31:
    840                 s->t_attrib.fgcol = QEMU_COLOR_RED;
    841                 break;
    842             case 32:
    843                 s->t_attrib.fgcol = QEMU_COLOR_GREEN;
    844                 break;
    845             case 33:
    846                 s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
    847                 break;
    848             case 34:
    849                 s->t_attrib.fgcol = QEMU_COLOR_BLUE;
    850                 break;
    851             case 35:
    852                 s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
    853                 break;
    854             case 36:
    855                 s->t_attrib.fgcol = QEMU_COLOR_CYAN;
    856                 break;
    857             case 37:
    858                 s->t_attrib.fgcol = QEMU_COLOR_WHITE;
    859                 break;
    860             /* set background color */
    861             case 40:
    862                 s->t_attrib.bgcol = QEMU_COLOR_BLACK;
    863                 break;
    864             case 41:
    865                 s->t_attrib.bgcol = QEMU_COLOR_RED;
    866                 break;
    867             case 42:
    868                 s->t_attrib.bgcol = QEMU_COLOR_GREEN;
    869                 break;
    870             case 43:
    871                 s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
    872                 break;
    873             case 44:
    874                 s->t_attrib.bgcol = QEMU_COLOR_BLUE;
    875                 break;
    876             case 45:
    877                 s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
    878                 break;
    879             case 46:
    880                 s->t_attrib.bgcol = QEMU_COLOR_CYAN;
    881                 break;
    882             case 47:
    883                 s->t_attrib.bgcol = QEMU_COLOR_WHITE;
    884                 break;
    885         }
    886     }
    887 }
    888 
    889 static void console_clear_xy(QemuConsole *s, int x, int y)
    890 {
    891     int y1 = (s->y_base + y) % s->total_height;
    892     if (x >= s->width) {
    893         x = s->width - 1;
    894     }
    895     TextCell *c = &s->cells[y1 * s->width + x];
    896     c->ch = ' ';
    897     c->t_attrib = s->t_attrib_default;
    898     update_xy(s, x, y);
    899 }
    900 
    901 static void console_put_one(QemuConsole *s, int ch)
    902 {
    903     TextCell *c;
    904     int y1;
    905     if (s->x >= s->width) {
    906         /* line wrap */
    907         s->x = 0;
    908         console_put_lf(s);
    909     }
    910     y1 = (s->y_base + s->y) % s->total_height;
    911     c = &s->cells[y1 * s->width + s->x];
    912     c->ch = ch;
    913     c->t_attrib = s->t_attrib;
    914     update_xy(s, s->x, s->y);
    915     s->x++;
    916 }
    917 
    918 static void console_respond_str(QemuConsole *s, const char *buf)
    919 {
    920     while (*buf) {
    921         console_put_one(s, *buf);
    922         buf++;
    923     }
    924 }
    925 
    926 /* set cursor, checking bounds */
    927 static void set_cursor(QemuConsole *s, int x, int y)
    928 {
    929     if (x < 0) {
    930         x = 0;
    931     }
    932     if (y < 0) {
    933         y = 0;
    934     }
    935     if (y >= s->height) {
    936         y = s->height - 1;
    937     }
    938     if (x >= s->width) {
    939         x = s->width - 1;
    940     }
    941 
    942     s->x = x;
    943     s->y = y;
    944 }
    945 
    946 static void console_putchar(QemuConsole *s, int ch)
    947 {
    948     int i;
    949     int x, y;
    950     char response[40];
    951 
    952     switch(s->state) {
    953     case TTY_STATE_NORM:
    954         switch(ch) {
    955         case '\r':  /* carriage return */
    956             s->x = 0;
    957             break;
    958         case '\n':  /* newline */
    959             console_put_lf(s);
    960             break;
    961         case '\b':  /* backspace */
    962             if (s->x > 0)
    963                 s->x--;
    964             break;
    965         case '\t':  /* tabspace */
    966             if (s->x + (8 - (s->x % 8)) > s->width) {
    967                 s->x = 0;
    968                 console_put_lf(s);
    969             } else {
    970                 s->x = s->x + (8 - (s->x % 8));
    971             }
    972             break;
    973         case '\a':  /* alert aka. bell */
    974             /* TODO: has to be implemented */
    975             break;
    976         case 14:
    977             /* SI (shift in), character set 0 (ignored) */
    978             break;
    979         case 15:
    980             /* SO (shift out), character set 1 (ignored) */
    981             break;
    982         case 27:    /* esc (introducing an escape sequence) */
    983             s->state = TTY_STATE_ESC;
    984             break;
    985         default:
    986             console_put_one(s, ch);
    987             break;
    988         }
    989         break;
    990     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
    991         if (ch == '[') {
    992             for(i=0;i<MAX_ESC_PARAMS;i++)
    993                 s->esc_params[i] = 0;
    994             s->nb_esc_params = 0;
    995             s->state = TTY_STATE_CSI;
    996         } else {
    997             s->state = TTY_STATE_NORM;
    998         }
    999         break;
   1000     case TTY_STATE_CSI: /* handle escape sequence parameters */
   1001         if (ch >= '0' && ch <= '9') {
   1002             if (s->nb_esc_params < MAX_ESC_PARAMS) {
   1003                 int *param = &s->esc_params[s->nb_esc_params];
   1004                 int digit = (ch - '0');
   1005 
   1006                 *param = (*param <= (INT_MAX - digit) / 10) ?
   1007                          *param * 10 + digit : INT_MAX;
   1008             }
   1009         } else {
   1010             if (s->nb_esc_params < MAX_ESC_PARAMS)
   1011                 s->nb_esc_params++;
   1012             if (ch == ';' || ch == '?') {
   1013                 break;
   1014             }
   1015             trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
   1016                                       ch, s->nb_esc_params);
   1017             s->state = TTY_STATE_NORM;
   1018             switch(ch) {
   1019             case 'A':
   1020                 /* move cursor up */
   1021                 if (s->esc_params[0] == 0) {
   1022                     s->esc_params[0] = 1;
   1023                 }
   1024                 set_cursor(s, s->x, s->y - s->esc_params[0]);
   1025                 break;
   1026             case 'B':
   1027                 /* move cursor down */
   1028                 if (s->esc_params[0] == 0) {
   1029                     s->esc_params[0] = 1;
   1030                 }
   1031                 set_cursor(s, s->x, s->y + s->esc_params[0]);
   1032                 break;
   1033             case 'C':
   1034                 /* move cursor right */
   1035                 if (s->esc_params[0] == 0) {
   1036                     s->esc_params[0] = 1;
   1037                 }
   1038                 set_cursor(s, s->x + s->esc_params[0], s->y);
   1039                 break;
   1040             case 'D':
   1041                 /* move cursor left */
   1042                 if (s->esc_params[0] == 0) {
   1043                     s->esc_params[0] = 1;
   1044                 }
   1045                 set_cursor(s, s->x - s->esc_params[0], s->y);
   1046                 break;
   1047             case 'G':
   1048                 /* move cursor to column */
   1049                 set_cursor(s, s->esc_params[0] - 1, s->y);
   1050                 break;
   1051             case 'f':
   1052             case 'H':
   1053                 /* move cursor to row, column */
   1054                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
   1055                 break;
   1056             case 'J':
   1057                 switch (s->esc_params[0]) {
   1058                 case 0:
   1059                     /* clear to end of screen */
   1060                     for (y = s->y; y < s->height; y++) {
   1061                         for (x = 0; x < s->width; x++) {
   1062                             if (y == s->y && x < s->x) {
   1063                                 continue;
   1064                             }
   1065                             console_clear_xy(s, x, y);
   1066                         }
   1067                     }
   1068                     break;
   1069                 case 1:
   1070                     /* clear from beginning of screen */
   1071                     for (y = 0; y <= s->y; y++) {
   1072                         for (x = 0; x < s->width; x++) {
   1073                             if (y == s->y && x > s->x) {
   1074                                 break;
   1075                             }
   1076                             console_clear_xy(s, x, y);
   1077                         }
   1078                     }
   1079                     break;
   1080                 case 2:
   1081                     /* clear entire screen */
   1082                     for (y = 0; y <= s->height; y++) {
   1083                         for (x = 0; x < s->width; x++) {
   1084                             console_clear_xy(s, x, y);
   1085                         }
   1086                     }
   1087                     break;
   1088                 }
   1089                 break;
   1090             case 'K':
   1091                 switch (s->esc_params[0]) {
   1092                 case 0:
   1093                     /* clear to eol */
   1094                     for(x = s->x; x < s->width; x++) {
   1095                         console_clear_xy(s, x, s->y);
   1096                     }
   1097                     break;
   1098                 case 1:
   1099                     /* clear from beginning of line */
   1100                     for (x = 0; x <= s->x && x < s->width; x++) {
   1101                         console_clear_xy(s, x, s->y);
   1102                     }
   1103                     break;
   1104                 case 2:
   1105                     /* clear entire line */
   1106                     for(x = 0; x < s->width; x++) {
   1107                         console_clear_xy(s, x, s->y);
   1108                     }
   1109                     break;
   1110                 }
   1111                 break;
   1112             case 'm':
   1113                 console_handle_escape(s);
   1114                 break;
   1115             case 'n':
   1116                 switch (s->esc_params[0]) {
   1117                 case 5:
   1118                     /* report console status (always succeed)*/
   1119                     console_respond_str(s, "\033[0n");
   1120                     break;
   1121                 case 6:
   1122                     /* report cursor position */
   1123                     sprintf(response, "\033[%d;%dR",
   1124                            (s->y_base + s->y) % s->total_height + 1,
   1125                             s->x + 1);
   1126                     console_respond_str(s, response);
   1127                     break;
   1128                 }
   1129                 break;
   1130             case 's':
   1131                 /* save cursor position */
   1132                 s->x_saved = s->x;
   1133                 s->y_saved = s->y;
   1134                 break;
   1135             case 'u':
   1136                 /* restore cursor position */
   1137                 s->x = s->x_saved;
   1138                 s->y = s->y_saved;
   1139                 break;
   1140             default:
   1141                 trace_console_putchar_unhandled(ch);
   1142                 break;
   1143             }
   1144             break;
   1145         }
   1146     }
   1147 }
   1148 
   1149 static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
   1150                                              struct DisplaySurface *new_surface,
   1151                                              bool update)
   1152 {
   1153     if (dcl->ops->dpy_gfx_switch) {
   1154         dcl->ops->dpy_gfx_switch(dcl, new_surface);
   1155     }
   1156 
   1157     if (update && dcl->ops->dpy_gfx_update) {
   1158         dcl->ops->dpy_gfx_update(dcl, 0, 0,
   1159                                  surface_width(new_surface),
   1160                                  surface_height(new_surface));
   1161     }
   1162 }
   1163 
   1164 static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface)
   1165 {
   1166     if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) {
   1167         con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface);
   1168     }
   1169 }
   1170 
   1171 static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface)
   1172 {
   1173     if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) {
   1174         con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface);
   1175     }
   1176 }
   1177 
   1178 static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface,
   1179                                    int x, int y, int w, int h)
   1180 {
   1181     if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) {
   1182         con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h);
   1183     }
   1184 }
   1185 
   1186 static void displaychangelistener_display_console(DisplayChangeListener *dcl,
   1187                                                   QemuConsole *con,
   1188                                                   Error **errp)
   1189 {
   1190     static const char nodev[] =
   1191         "This VM has no graphic display device.";
   1192     static DisplaySurface *dummy;
   1193 
   1194     if (!con || !console_compatible_with(con, dcl, errp)) {
   1195         if (!dummy) {
   1196             dummy = qemu_create_placeholder_surface(640, 480, nodev);
   1197         }
   1198         if (con) {
   1199             dpy_gfx_create_texture(con, dummy);
   1200         }
   1201         displaychangelistener_gfx_switch(dcl, dummy, TRUE);
   1202         return;
   1203     }
   1204 
   1205     dpy_gfx_create_texture(con, con->surface);
   1206     displaychangelistener_gfx_switch(dcl, con->surface,
   1207                                      con->scanout.kind == SCANOUT_SURFACE);
   1208 
   1209     if (con->scanout.kind == SCANOUT_DMABUF &&
   1210         displaychangelistener_has_dmabuf(dcl)) {
   1211         dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
   1212     } else if (con->scanout.kind == SCANOUT_TEXTURE &&
   1213                dcl->ops->dpy_gl_scanout_texture) {
   1214         dcl->ops->dpy_gl_scanout_texture(dcl,
   1215                                          con->scanout.texture.backing_id,
   1216                                          con->scanout.texture.backing_y_0_top,
   1217                                          con->scanout.texture.backing_width,
   1218                                          con->scanout.texture.backing_height,
   1219                                          con->scanout.texture.x,
   1220                                          con->scanout.texture.y,
   1221                                          con->scanout.texture.width,
   1222                                          con->scanout.texture.height);
   1223     }
   1224 }
   1225 
   1226 void console_select(unsigned int index)
   1227 {
   1228     DisplayChangeListener *dcl;
   1229     QemuConsole *s;
   1230 
   1231     trace_console_select(index);
   1232     s = qemu_console_lookup_by_index(index);
   1233     if (s) {
   1234         DisplayState *ds = s->ds;
   1235 
   1236         active_console = s;
   1237         if (ds->have_gfx) {
   1238             QLIST_FOREACH(dcl, &ds->listeners, next) {
   1239                 if (dcl->con != NULL) {
   1240                     continue;
   1241                 }
   1242                 displaychangelistener_display_console(dcl, s, NULL);
   1243             }
   1244         }
   1245         if (ds->have_text) {
   1246             dpy_text_resize(s, s->width, s->height);
   1247         }
   1248         text_console_update_cursor(NULL);
   1249     }
   1250 }
   1251 
   1252 struct VCChardev {
   1253     Chardev parent;
   1254     QemuConsole *console;
   1255 };
   1256 typedef struct VCChardev VCChardev;
   1257 
   1258 #define TYPE_CHARDEV_VC "chardev-vc"
   1259 DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
   1260                          TYPE_CHARDEV_VC)
   1261 
   1262 static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
   1263 {
   1264     VCChardev *drv = VC_CHARDEV(chr);
   1265     QemuConsole *s = drv->console;
   1266     int i;
   1267 
   1268     if (!s->ds) {
   1269         return 0;
   1270     }
   1271 
   1272     s->update_x0 = s->width * FONT_WIDTH;
   1273     s->update_y0 = s->height * FONT_HEIGHT;
   1274     s->update_x1 = 0;
   1275     s->update_y1 = 0;
   1276     console_show_cursor(s, 0);
   1277     for(i = 0; i < len; i++) {
   1278         console_putchar(s, buf[i]);
   1279     }
   1280     console_show_cursor(s, 1);
   1281     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
   1282         dpy_gfx_update(s, s->update_x0, s->update_y0,
   1283                        s->update_x1 - s->update_x0,
   1284                        s->update_y1 - s->update_y0);
   1285     }
   1286     return len;
   1287 }
   1288 
   1289 static void kbd_send_chars(QemuConsole *s)
   1290 {
   1291     uint32_t len, avail;
   1292 
   1293     len = qemu_chr_be_can_write(s->chr);
   1294     avail = fifo8_num_used(&s->out_fifo);
   1295     while (len > 0 && avail > 0) {
   1296         const uint8_t *buf;
   1297         uint32_t size;
   1298 
   1299         buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
   1300         qemu_chr_be_write(s->chr, buf, size);
   1301         len = qemu_chr_be_can_write(s->chr);
   1302         avail -= size;
   1303     }
   1304 }
   1305 
   1306 /* called when an ascii key is pressed */
   1307 void kbd_put_keysym_console(QemuConsole *s, int keysym)
   1308 {
   1309     uint8_t buf[16], *q;
   1310     int c;
   1311     uint32_t num_free;
   1312 
   1313     if (!s || (s->console_type == GRAPHIC_CONSOLE))
   1314         return;
   1315 
   1316     switch(keysym) {
   1317     case QEMU_KEY_CTRL_UP:
   1318         console_scroll(s, -1);
   1319         break;
   1320     case QEMU_KEY_CTRL_DOWN:
   1321         console_scroll(s, 1);
   1322         break;
   1323     case QEMU_KEY_CTRL_PAGEUP:
   1324         console_scroll(s, -10);
   1325         break;
   1326     case QEMU_KEY_CTRL_PAGEDOWN:
   1327         console_scroll(s, 10);
   1328         break;
   1329     default:
   1330         /* convert the QEMU keysym to VT100 key string */
   1331         q = buf;
   1332         if (keysym >= 0xe100 && keysym <= 0xe11f) {
   1333             *q++ = '\033';
   1334             *q++ = '[';
   1335             c = keysym - 0xe100;
   1336             if (c >= 10)
   1337                 *q++ = '0' + (c / 10);
   1338             *q++ = '0' + (c % 10);
   1339             *q++ = '~';
   1340         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
   1341             *q++ = '\033';
   1342             *q++ = '[';
   1343             *q++ = keysym & 0xff;
   1344         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
   1345             vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
   1346             *q++ = '\n';
   1347         } else {
   1348             *q++ = keysym;
   1349         }
   1350         if (s->echo) {
   1351             vc_chr_write(s->chr, buf, q - buf);
   1352         }
   1353         num_free = fifo8_num_free(&s->out_fifo);
   1354         fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
   1355         kbd_send_chars(s);
   1356         break;
   1357     }
   1358 }
   1359 
   1360 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
   1361     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
   1362     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
   1363     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
   1364     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
   1365     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
   1366     [Q_KEY_CODE_END]    = QEMU_KEY_END,
   1367     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
   1368     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
   1369     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
   1370     [Q_KEY_CODE_TAB]    = QEMU_KEY_TAB,
   1371     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
   1372 };
   1373 
   1374 static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
   1375     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
   1376     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
   1377     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
   1378     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
   1379     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
   1380     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
   1381     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
   1382     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
   1383 };
   1384 
   1385 bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
   1386 {
   1387     int keysym;
   1388 
   1389     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
   1390     if (keysym == 0) {
   1391         return false;
   1392     }
   1393     kbd_put_keysym_console(s, keysym);
   1394     return true;
   1395 }
   1396 
   1397 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
   1398 {
   1399     int i;
   1400 
   1401     for (i = 0; i < len && str[i]; i++) {
   1402         kbd_put_keysym_console(s, str[i]);
   1403     }
   1404 }
   1405 
   1406 void kbd_put_keysym(int keysym)
   1407 {
   1408     kbd_put_keysym_console(active_console, keysym);
   1409 }
   1410 
   1411 static void text_console_invalidate(void *opaque)
   1412 {
   1413     QemuConsole *s = (QemuConsole *) opaque;
   1414 
   1415     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
   1416         text_console_resize(s);
   1417     }
   1418     console_refresh(s);
   1419 }
   1420 
   1421 static void text_console_update(void *opaque, console_ch_t *chardata)
   1422 {
   1423     QemuConsole *s = (QemuConsole *) opaque;
   1424     int i, j, src;
   1425 
   1426     if (s->text_x[0] <= s->text_x[1]) {
   1427         src = (s->y_base + s->text_y[0]) * s->width;
   1428         chardata += s->text_y[0] * s->width;
   1429         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
   1430             for (j = 0; j < s->width; j++, src++) {
   1431                 console_write_ch(chardata ++,
   1432                                  ATTR2CHTYPE(s->cells[src].ch,
   1433                                              s->cells[src].t_attrib.fgcol,
   1434                                              s->cells[src].t_attrib.bgcol,
   1435                                              s->cells[src].t_attrib.bold));
   1436             }
   1437         dpy_text_update(s, s->text_x[0], s->text_y[0],
   1438                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
   1439         s->text_x[0] = s->width;
   1440         s->text_y[0] = s->height;
   1441         s->text_x[1] = 0;
   1442         s->text_y[1] = 0;
   1443     }
   1444     if (s->cursor_invalidate) {
   1445         dpy_text_cursor(s, s->x, s->y);
   1446         s->cursor_invalidate = 0;
   1447     }
   1448 }
   1449 
   1450 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
   1451                                 uint32_t head)
   1452 {
   1453     Object *obj;
   1454     QemuConsole *s;
   1455     int i;
   1456 
   1457     obj = object_new(TYPE_QEMU_CONSOLE);
   1458     s = QEMU_CONSOLE(obj);
   1459     qemu_co_queue_init(&s->dump_queue);
   1460     s->head = head;
   1461     object_property_add_link(obj, "device", TYPE_DEVICE,
   1462                              (Object **)&s->device,
   1463                              object_property_allow_set_link,
   1464                              OBJ_PROP_LINK_STRONG);
   1465     object_property_add_uint32_ptr(obj, "head", &s->head,
   1466                                    OBJ_PROP_FLAG_READ);
   1467 
   1468     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
   1469         (console_type == GRAPHIC_CONSOLE))) {
   1470         active_console = s;
   1471     }
   1472     s->ds = ds;
   1473     s->console_type = console_type;
   1474     s->window_id = -1;
   1475 
   1476     if (QTAILQ_EMPTY(&consoles)) {
   1477         s->index = 0;
   1478         QTAILQ_INSERT_TAIL(&consoles, s, next);
   1479     } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) {
   1480         QemuConsole *last = QTAILQ_LAST(&consoles);
   1481         s->index = last->index + 1;
   1482         QTAILQ_INSERT_TAIL(&consoles, s, next);
   1483     } else {
   1484         /*
   1485          * HACK: Put graphical consoles before text consoles.
   1486          *
   1487          * Only do that for coldplugged devices.  After initial device
   1488          * initialization we will not renumber the consoles any more.
   1489          */
   1490         QemuConsole *c = QTAILQ_FIRST(&consoles);
   1491 
   1492         while (QTAILQ_NEXT(c, next) != NULL &&
   1493                c->console_type == GRAPHIC_CONSOLE) {
   1494             c = QTAILQ_NEXT(c, next);
   1495         }
   1496         if (c->console_type == GRAPHIC_CONSOLE) {
   1497             /* have no text consoles */
   1498             s->index = c->index + 1;
   1499             QTAILQ_INSERT_AFTER(&consoles, c, s, next);
   1500         } else {
   1501             s->index = c->index;
   1502             QTAILQ_INSERT_BEFORE(c, s, next);
   1503             /* renumber text consoles */
   1504             for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
   1505                 c->index = i;
   1506             }
   1507         }
   1508     }
   1509     return s;
   1510 }
   1511 
   1512 DisplaySurface *qemu_create_displaysurface(int width, int height)
   1513 {
   1514     DisplaySurface *surface = g_new0(DisplaySurface, 1);
   1515 
   1516     trace_displaysurface_create(surface, width, height);
   1517     surface->format = PIXMAN_x8r8g8b8;
   1518     surface->image = pixman_image_create_bits(surface->format,
   1519                                               width, height,
   1520                                               NULL, width * 4);
   1521     assert(surface->image != NULL);
   1522     surface->flags = QEMU_ALLOCATED_FLAG;
   1523 
   1524     return surface;
   1525 }
   1526 
   1527 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
   1528                                                 pixman_format_code_t format,
   1529                                                 int linesize, uint8_t *data)
   1530 {
   1531     DisplaySurface *surface = g_new0(DisplaySurface, 1);
   1532 
   1533     trace_displaysurface_create_from(surface, width, height, format);
   1534     surface->format = format;
   1535     surface->image = pixman_image_create_bits(surface->format,
   1536                                               width, height,
   1537                                               (void *)data, linesize);
   1538     assert(surface->image != NULL);
   1539 
   1540     return surface;
   1541 }
   1542 
   1543 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
   1544 {
   1545     DisplaySurface *surface = g_new0(DisplaySurface, 1);
   1546 
   1547     trace_displaysurface_create_pixman(surface);
   1548     surface->format = pixman_image_get_format(image);
   1549     surface->image = pixman_image_ref(image);
   1550 
   1551     return surface;
   1552 }
   1553 
   1554 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
   1555                                                 const char *msg)
   1556 {
   1557     DisplaySurface *surface = qemu_create_displaysurface(w, h);
   1558     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
   1559     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
   1560     pixman_image_t *glyph;
   1561     int len, x, y, i;
   1562 
   1563     len = strlen(msg);
   1564     x = (w / FONT_WIDTH  - len) / 2;
   1565     y = (h / FONT_HEIGHT - 1)   / 2;
   1566     for (i = 0; i < len; i++) {
   1567         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
   1568         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
   1569                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
   1570         qemu_pixman_image_unref(glyph);
   1571     }
   1572     surface->flags |= QEMU_PLACEHOLDER_FLAG;
   1573     return surface;
   1574 }
   1575 
   1576 void qemu_free_displaysurface(DisplaySurface *surface)
   1577 {
   1578     if (surface == NULL) {
   1579         return;
   1580     }
   1581     trace_displaysurface_free(surface);
   1582     qemu_pixman_image_unref(surface->image);
   1583     g_free(surface);
   1584 }
   1585 
   1586 bool console_has_gl(QemuConsole *con)
   1587 {
   1588     return con->gl != NULL;
   1589 }
   1590 
   1591 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
   1592 {
   1593     if (dcl->ops->dpy_has_dmabuf) {
   1594         return dcl->ops->dpy_has_dmabuf(dcl);
   1595     }
   1596 
   1597     if (dcl->ops->dpy_gl_scanout_dmabuf) {
   1598         return true;
   1599     }
   1600 
   1601     return false;
   1602 }
   1603 
   1604 static bool console_compatible_with(QemuConsole *con,
   1605                                     DisplayChangeListener *dcl, Error **errp)
   1606 {
   1607     int flags;
   1608 
   1609     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
   1610 
   1611     if (console_has_gl(con) &&
   1612         !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
   1613         error_setg(errp, "Display %s is incompatible with the GL context",
   1614                    dcl->ops->dpy_name);
   1615         return false;
   1616     }
   1617 
   1618     if (flags & GRAPHIC_FLAGS_GL &&
   1619         !console_has_gl(con)) {
   1620         error_setg(errp, "The console requires a GL context.");
   1621         return false;
   1622 
   1623     }
   1624 
   1625     if (flags & GRAPHIC_FLAGS_DMABUF &&
   1626         !displaychangelistener_has_dmabuf(dcl)) {
   1627         error_setg(errp, "The console requires display DMABUF support.");
   1628         return false;
   1629     }
   1630 
   1631     return true;
   1632 }
   1633 
   1634 void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
   1635 {
   1636     /* display has opengl support */
   1637     assert(con);
   1638     if (con->gl) {
   1639         error_report("The console already has an OpenGL context.");
   1640         exit(1);
   1641     }
   1642     con->gl = gl;
   1643 }
   1644 
   1645 void register_displaychangelistener(DisplayChangeListener *dcl)
   1646 {
   1647     QemuConsole *con;
   1648 
   1649     assert(!dcl->ds);
   1650 
   1651     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
   1652     dcl->ds = get_alloc_displaystate();
   1653     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
   1654     gui_setup_refresh(dcl->ds);
   1655     if (dcl->con) {
   1656         dcl->con->dcls++;
   1657         con = dcl->con;
   1658     } else {
   1659         con = active_console;
   1660     }
   1661     displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
   1662     text_console_update_cursor(NULL);
   1663 }
   1664 
   1665 void update_displaychangelistener(DisplayChangeListener *dcl,
   1666                                   uint64_t interval)
   1667 {
   1668     DisplayState *ds = dcl->ds;
   1669 
   1670     dcl->update_interval = interval;
   1671     if (!ds->refreshing && ds->update_interval > interval) {
   1672         timer_mod(ds->gui_timer, ds->last_update + interval);
   1673     }
   1674 }
   1675 
   1676 void unregister_displaychangelistener(DisplayChangeListener *dcl)
   1677 {
   1678     DisplayState *ds = dcl->ds;
   1679     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
   1680     if (dcl->con) {
   1681         dcl->con->dcls--;
   1682     }
   1683     QLIST_REMOVE(dcl, next);
   1684     dcl->ds = NULL;
   1685     gui_setup_refresh(ds);
   1686 }
   1687 
   1688 static void dpy_set_ui_info_timer(void *opaque)
   1689 {
   1690     QemuConsole *con = opaque;
   1691 
   1692     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
   1693 }
   1694 
   1695 bool dpy_ui_info_supported(QemuConsole *con)
   1696 {
   1697     if (con == NULL) {
   1698         con = active_console;
   1699     }
   1700 
   1701     return con->hw_ops->ui_info != NULL;
   1702 }
   1703 
   1704 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
   1705 {
   1706     if (con == NULL) {
   1707         con = active_console;
   1708     }
   1709 
   1710     return &con->ui_info;
   1711 }
   1712 
   1713 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
   1714 {
   1715     if (con == NULL) {
   1716         con = active_console;
   1717     }
   1718 
   1719     if (!dpy_ui_info_supported(con)) {
   1720         return -1;
   1721     }
   1722     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
   1723         /* nothing changed -- ignore */
   1724         return 0;
   1725     }
   1726 
   1727     /*
   1728      * Typically we get a flood of these as the user resizes the window.
   1729      * Wait until the dust has settled (one second without updates), then
   1730      * go notify the guest.
   1731      */
   1732     con->ui_info = *info;
   1733     timer_mod(con->ui_timer,
   1734               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
   1735     return 0;
   1736 }
   1737 
   1738 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
   1739 {
   1740     DisplayState *s = con->ds;
   1741     DisplayChangeListener *dcl;
   1742     int width = qemu_console_get_width(con, x + w);
   1743     int height = qemu_console_get_height(con, y + h);
   1744 
   1745     x = MAX(x, 0);
   1746     y = MAX(y, 0);
   1747     x = MIN(x, width);
   1748     y = MIN(y, height);
   1749     w = MIN(w, width - x);
   1750     h = MIN(h, height - y);
   1751 
   1752     if (!qemu_console_is_visible(con)) {
   1753         return;
   1754     }
   1755     dpy_gfx_update_texture(con, con->surface, x, y, w, h);
   1756     QLIST_FOREACH(dcl, &s->listeners, next) {
   1757         if (con != (dcl->con ? dcl->con : active_console)) {
   1758             continue;
   1759         }
   1760         if (dcl->ops->dpy_gfx_update) {
   1761             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
   1762         }
   1763     }
   1764 }
   1765 
   1766 void dpy_gfx_update_full(QemuConsole *con)
   1767 {
   1768     int w = qemu_console_get_width(con, 0);
   1769     int h = qemu_console_get_height(con, 0);
   1770 
   1771     dpy_gfx_update(con, 0, 0, w, h);
   1772 }
   1773 
   1774 void dpy_gfx_replace_surface(QemuConsole *con,
   1775                              DisplaySurface *surface)
   1776 {
   1777     static const char placeholder_msg[] = "Display output is not active.";
   1778     DisplayState *s = con->ds;
   1779     DisplaySurface *old_surface = con->surface;
   1780     DisplayChangeListener *dcl;
   1781     int width;
   1782     int height;
   1783 
   1784     if (!surface) {
   1785         if (old_surface) {
   1786             width = surface_width(old_surface);
   1787             height = surface_height(old_surface);
   1788         } else {
   1789             width = 640;
   1790             height = 480;
   1791         }
   1792 
   1793         surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
   1794     }
   1795 
   1796     assert(old_surface != surface);
   1797 
   1798     con->scanout.kind = SCANOUT_SURFACE;
   1799     con->surface = surface;
   1800     dpy_gfx_create_texture(con, surface);
   1801     QLIST_FOREACH(dcl, &s->listeners, next) {
   1802         if (con != (dcl->con ? dcl->con : active_console)) {
   1803             continue;
   1804         }
   1805         displaychangelistener_gfx_switch(dcl, surface, FALSE);
   1806     }
   1807     dpy_gfx_destroy_texture(con, old_surface);
   1808     qemu_free_displaysurface(old_surface);
   1809 }
   1810 
   1811 bool dpy_gfx_check_format(QemuConsole *con,
   1812                           pixman_format_code_t format)
   1813 {
   1814     DisplayChangeListener *dcl;
   1815     DisplayState *s = con->ds;
   1816 
   1817     QLIST_FOREACH(dcl, &s->listeners, next) {
   1818         if (dcl->con && dcl->con != con) {
   1819             /* dcl bound to another console -> skip */
   1820             continue;
   1821         }
   1822         if (dcl->ops->dpy_gfx_check_format) {
   1823             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
   1824                 return false;
   1825             }
   1826         } else {
   1827             /* default is to allow native 32 bpp only */
   1828             if (format != qemu_default_pixman_format(32, true)) {
   1829                 return false;
   1830             }
   1831         }
   1832     }
   1833     return true;
   1834 }
   1835 
   1836 static void dpy_refresh(DisplayState *s)
   1837 {
   1838     DisplayChangeListener *dcl;
   1839 
   1840     QLIST_FOREACH(dcl, &s->listeners, next) {
   1841         if (dcl->ops->dpy_refresh) {
   1842             dcl->ops->dpy_refresh(dcl);
   1843         }
   1844     }
   1845 }
   1846 
   1847 void dpy_text_cursor(QemuConsole *con, int x, int y)
   1848 {
   1849     DisplayState *s = con->ds;
   1850     DisplayChangeListener *dcl;
   1851 
   1852     if (!qemu_console_is_visible(con)) {
   1853         return;
   1854     }
   1855     QLIST_FOREACH(dcl, &s->listeners, next) {
   1856         if (con != (dcl->con ? dcl->con : active_console)) {
   1857             continue;
   1858         }
   1859         if (dcl->ops->dpy_text_cursor) {
   1860             dcl->ops->dpy_text_cursor(dcl, x, y);
   1861         }
   1862     }
   1863 }
   1864 
   1865 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
   1866 {
   1867     DisplayState *s = con->ds;
   1868     DisplayChangeListener *dcl;
   1869 
   1870     if (!qemu_console_is_visible(con)) {
   1871         return;
   1872     }
   1873     QLIST_FOREACH(dcl, &s->listeners, next) {
   1874         if (con != (dcl->con ? dcl->con : active_console)) {
   1875             continue;
   1876         }
   1877         if (dcl->ops->dpy_text_update) {
   1878             dcl->ops->dpy_text_update(dcl, x, y, w, h);
   1879         }
   1880     }
   1881 }
   1882 
   1883 void dpy_text_resize(QemuConsole *con, int w, int h)
   1884 {
   1885     DisplayState *s = con->ds;
   1886     DisplayChangeListener *dcl;
   1887 
   1888     if (!qemu_console_is_visible(con)) {
   1889         return;
   1890     }
   1891     QLIST_FOREACH(dcl, &s->listeners, next) {
   1892         if (con != (dcl->con ? dcl->con : active_console)) {
   1893             continue;
   1894         }
   1895         if (dcl->ops->dpy_text_resize) {
   1896             dcl->ops->dpy_text_resize(dcl, w, h);
   1897         }
   1898     }
   1899 }
   1900 
   1901 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
   1902 {
   1903     DisplayState *s = con->ds;
   1904     DisplayChangeListener *dcl;
   1905 
   1906     if (!qemu_console_is_visible(con)) {
   1907         return;
   1908     }
   1909     QLIST_FOREACH(dcl, &s->listeners, next) {
   1910         if (con != (dcl->con ? dcl->con : active_console)) {
   1911             continue;
   1912         }
   1913         if (dcl->ops->dpy_mouse_set) {
   1914             dcl->ops->dpy_mouse_set(dcl, x, y, on);
   1915         }
   1916     }
   1917 }
   1918 
   1919 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
   1920 {
   1921     DisplayState *s = con->ds;
   1922     DisplayChangeListener *dcl;
   1923 
   1924     if (!qemu_console_is_visible(con)) {
   1925         return;
   1926     }
   1927     QLIST_FOREACH(dcl, &s->listeners, next) {
   1928         if (con != (dcl->con ? dcl->con : active_console)) {
   1929             continue;
   1930         }
   1931         if (dcl->ops->dpy_cursor_define) {
   1932             dcl->ops->dpy_cursor_define(dcl, cursor);
   1933         }
   1934     }
   1935 }
   1936 
   1937 bool dpy_cursor_define_supported(QemuConsole *con)
   1938 {
   1939     DisplayState *s = con->ds;
   1940     DisplayChangeListener *dcl;
   1941 
   1942     QLIST_FOREACH(dcl, &s->listeners, next) {
   1943         if (dcl->ops->dpy_cursor_define) {
   1944             return true;
   1945         }
   1946     }
   1947     return false;
   1948 }
   1949 
   1950 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
   1951                                 struct QEMUGLParams *qparams)
   1952 {
   1953     assert(con->gl);
   1954     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
   1955 }
   1956 
   1957 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
   1958 {
   1959     assert(con->gl);
   1960     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
   1961 }
   1962 
   1963 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
   1964 {
   1965     assert(con->gl);
   1966     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
   1967 }
   1968 
   1969 void dpy_gl_scanout_disable(QemuConsole *con)
   1970 {
   1971     DisplayState *s = con->ds;
   1972     DisplayChangeListener *dcl;
   1973 
   1974     if (con->scanout.kind != SCANOUT_SURFACE) {
   1975         con->scanout.kind = SCANOUT_NONE;
   1976     }
   1977     QLIST_FOREACH(dcl, &s->listeners, next) {
   1978         if (con != (dcl->con ? dcl->con : active_console)) {
   1979             continue;
   1980         }
   1981         if (dcl->ops->dpy_gl_scanout_disable) {
   1982             dcl->ops->dpy_gl_scanout_disable(dcl);
   1983         }
   1984     }
   1985 }
   1986 
   1987 void dpy_gl_scanout_texture(QemuConsole *con,
   1988                             uint32_t backing_id,
   1989                             bool backing_y_0_top,
   1990                             uint32_t backing_width,
   1991                             uint32_t backing_height,
   1992                             uint32_t x, uint32_t y,
   1993                             uint32_t width, uint32_t height)
   1994 {
   1995     DisplayState *s = con->ds;
   1996     DisplayChangeListener *dcl;
   1997 
   1998     con->scanout.kind = SCANOUT_TEXTURE;
   1999     con->scanout.texture = (ScanoutTexture) {
   2000         backing_id, backing_y_0_top, backing_width, backing_height,
   2001         x, y, width, height
   2002     };
   2003     QLIST_FOREACH(dcl, &s->listeners, next) {
   2004         if (con != (dcl->con ? dcl->con : active_console)) {
   2005             continue;
   2006         }
   2007         if (dcl->ops->dpy_gl_scanout_texture) {
   2008             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
   2009                                              backing_y_0_top,
   2010                                              backing_width, backing_height,
   2011                                              x, y, width, height);
   2012         }
   2013     }
   2014 }
   2015 
   2016 void dpy_gl_scanout_dmabuf(QemuConsole *con,
   2017                            QemuDmaBuf *dmabuf)
   2018 {
   2019     DisplayState *s = con->ds;
   2020     DisplayChangeListener *dcl;
   2021 
   2022     con->scanout.kind = SCANOUT_DMABUF;
   2023     con->scanout.dmabuf = dmabuf;
   2024     QLIST_FOREACH(dcl, &s->listeners, next) {
   2025         if (con != (dcl->con ? dcl->con : active_console)) {
   2026             continue;
   2027         }
   2028         if (dcl->ops->dpy_gl_scanout_dmabuf) {
   2029             dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
   2030         }
   2031     }
   2032 }
   2033 
   2034 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
   2035                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
   2036 {
   2037     DisplayState *s = con->ds;
   2038     DisplayChangeListener *dcl;
   2039 
   2040     QLIST_FOREACH(dcl, &s->listeners, next) {
   2041         if (con != (dcl->con ? dcl->con : active_console)) {
   2042             continue;
   2043         }
   2044         if (dcl->ops->dpy_gl_cursor_dmabuf) {
   2045             dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
   2046                                            have_hot, hot_x, hot_y);
   2047         }
   2048     }
   2049 }
   2050 
   2051 void dpy_gl_cursor_position(QemuConsole *con,
   2052                             uint32_t pos_x, uint32_t pos_y)
   2053 {
   2054     DisplayState *s = con->ds;
   2055     DisplayChangeListener *dcl;
   2056 
   2057     QLIST_FOREACH(dcl, &s->listeners, next) {
   2058         if (con != (dcl->con ? dcl->con : active_console)) {
   2059             continue;
   2060         }
   2061         if (dcl->ops->dpy_gl_cursor_position) {
   2062             dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
   2063         }
   2064     }
   2065 }
   2066 
   2067 void dpy_gl_release_dmabuf(QemuConsole *con,
   2068                           QemuDmaBuf *dmabuf)
   2069 {
   2070     DisplayState *s = con->ds;
   2071     DisplayChangeListener *dcl;
   2072 
   2073     QLIST_FOREACH(dcl, &s->listeners, next) {
   2074         if (con != (dcl->con ? dcl->con : active_console)) {
   2075             continue;
   2076         }
   2077         if (dcl->ops->dpy_gl_release_dmabuf) {
   2078             dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
   2079         }
   2080     }
   2081 }
   2082 
   2083 void dpy_gl_update(QemuConsole *con,
   2084                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
   2085 {
   2086     DisplayState *s = con->ds;
   2087     DisplayChangeListener *dcl;
   2088 
   2089     assert(con->gl);
   2090 
   2091     graphic_hw_gl_block(con, true);
   2092     QLIST_FOREACH(dcl, &s->listeners, next) {
   2093         if (con != (dcl->con ? dcl->con : active_console)) {
   2094             continue;
   2095         }
   2096         if (dcl->ops->dpy_gl_update) {
   2097             dcl->ops->dpy_gl_update(dcl, x, y, w, h);
   2098         }
   2099     }
   2100     graphic_hw_gl_block(con, false);
   2101 }
   2102 
   2103 /***********************************************************/
   2104 /* register display */
   2105 
   2106 /* console.c internal use only */
   2107 static DisplayState *get_alloc_displaystate(void)
   2108 {
   2109     if (!display_state) {
   2110         display_state = g_new0(DisplayState, 1);
   2111         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
   2112                                     text_console_update_cursor, NULL);
   2113     }
   2114     return display_state;
   2115 }
   2116 
   2117 /*
   2118  * Called by main(), after creating QemuConsoles
   2119  * and before initializing ui (sdl/vnc/...).
   2120  */
   2121 DisplayState *init_displaystate(void)
   2122 {
   2123     gchar *name;
   2124     QemuConsole *con;
   2125 
   2126     get_alloc_displaystate();
   2127     QTAILQ_FOREACH(con, &consoles, next) {
   2128         if (con->console_type != GRAPHIC_CONSOLE &&
   2129             con->ds == NULL) {
   2130             text_console_do_init(con->chr, display_state);
   2131         }
   2132 
   2133         /* Hook up into the qom tree here (not in new_console()), once
   2134          * all QemuConsoles are created and the order / numbering
   2135          * doesn't change any more */
   2136         name = g_strdup_printf("console[%d]", con->index);
   2137         object_property_add_child(container_get(object_get_root(), "/backend"),
   2138                                   name, OBJECT(con));
   2139         g_free(name);
   2140     }
   2141 
   2142     return display_state;
   2143 }
   2144 
   2145 void graphic_console_set_hwops(QemuConsole *con,
   2146                                const GraphicHwOps *hw_ops,
   2147                                void *opaque)
   2148 {
   2149     con->hw_ops = hw_ops;
   2150     con->hw = opaque;
   2151 }
   2152 
   2153 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
   2154                                   const GraphicHwOps *hw_ops,
   2155                                   void *opaque)
   2156 {
   2157     static const char noinit[] =
   2158         "Guest has not initialized the display (yet).";
   2159     int width = 640;
   2160     int height = 480;
   2161     QemuConsole *s;
   2162     DisplayState *ds;
   2163     DisplaySurface *surface;
   2164 
   2165     ds = get_alloc_displaystate();
   2166     s = qemu_console_lookup_unused();
   2167     if (s) {
   2168         trace_console_gfx_reuse(s->index);
   2169         width = qemu_console_get_width(s, 0);
   2170         height = qemu_console_get_height(s, 0);
   2171     } else {
   2172         trace_console_gfx_new();
   2173         s = new_console(ds, GRAPHIC_CONSOLE, head);
   2174         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
   2175                                    dpy_set_ui_info_timer, s);
   2176     }
   2177     graphic_console_set_hwops(s, hw_ops, opaque);
   2178     if (dev) {
   2179         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
   2180                                  &error_abort);
   2181     }
   2182 
   2183     surface = qemu_create_placeholder_surface(width, height, noinit);
   2184     dpy_gfx_replace_surface(s, surface);
   2185     s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
   2186                                        graphic_hw_gl_unblock_timer, s);
   2187     return s;
   2188 }
   2189 
   2190 static const GraphicHwOps unused_ops = {
   2191     /* no callbacks */
   2192 };
   2193 
   2194 void graphic_console_close(QemuConsole *con)
   2195 {
   2196     static const char unplugged[] =
   2197         "Guest display has been unplugged";
   2198     DisplaySurface *surface;
   2199     int width = qemu_console_get_width(con, 640);
   2200     int height = qemu_console_get_height(con, 480);
   2201 
   2202     trace_console_gfx_close(con->index);
   2203     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
   2204     graphic_console_set_hwops(con, &unused_ops, NULL);
   2205 
   2206     if (con->gl) {
   2207         dpy_gl_scanout_disable(con);
   2208     }
   2209     surface = qemu_create_placeholder_surface(width, height, unplugged);
   2210     dpy_gfx_replace_surface(con, surface);
   2211 }
   2212 
   2213 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
   2214 {
   2215     QemuConsole *con;
   2216 
   2217     QTAILQ_FOREACH(con, &consoles, next) {
   2218         if (con->index == index) {
   2219             return con;
   2220         }
   2221     }
   2222     return NULL;
   2223 }
   2224 
   2225 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
   2226 {
   2227     QemuConsole *con;
   2228     Object *obj;
   2229     uint32_t h;
   2230 
   2231     QTAILQ_FOREACH(con, &consoles, next) {
   2232         obj = object_property_get_link(OBJECT(con),
   2233                                        "device", &error_abort);
   2234         if (DEVICE(obj) != dev) {
   2235             continue;
   2236         }
   2237         h = object_property_get_uint(OBJECT(con),
   2238                                      "head", &error_abort);
   2239         if (h != head) {
   2240             continue;
   2241         }
   2242         return con;
   2243     }
   2244     return NULL;
   2245 }
   2246 
   2247 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
   2248                                                 uint32_t head, Error **errp)
   2249 {
   2250     DeviceState *dev;
   2251     QemuConsole *con;
   2252 
   2253     dev = qdev_find_recursive(sysbus_get_default(), device_id);
   2254     if (dev == NULL) {
   2255         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
   2256                   "Device '%s' not found", device_id);
   2257         return NULL;
   2258     }
   2259 
   2260     con = qemu_console_lookup_by_device(dev, head);
   2261     if (con == NULL) {
   2262         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
   2263                    device_id, head);
   2264         return NULL;
   2265     }
   2266 
   2267     return con;
   2268 }
   2269 
   2270 QemuConsole *qemu_console_lookup_unused(void)
   2271 {
   2272     QemuConsole *con;
   2273     Object *obj;
   2274 
   2275     QTAILQ_FOREACH(con, &consoles, next) {
   2276         if (con->hw_ops != &unused_ops) {
   2277             continue;
   2278         }
   2279         obj = object_property_get_link(OBJECT(con),
   2280                                        "device", &error_abort);
   2281         if (obj != NULL) {
   2282             continue;
   2283         }
   2284         return con;
   2285     }
   2286     return NULL;
   2287 }
   2288 
   2289 bool qemu_console_is_visible(QemuConsole *con)
   2290 {
   2291     return (con == active_console) || (con->dcls > 0);
   2292 }
   2293 
   2294 bool qemu_console_is_graphic(QemuConsole *con)
   2295 {
   2296     if (con == NULL) {
   2297         con = active_console;
   2298     }
   2299     return con && (con->console_type == GRAPHIC_CONSOLE);
   2300 }
   2301 
   2302 bool qemu_console_is_fixedsize(QemuConsole *con)
   2303 {
   2304     if (con == NULL) {
   2305         con = active_console;
   2306     }
   2307     return con && (con->console_type != TEXT_CONSOLE);
   2308 }
   2309 
   2310 bool qemu_console_is_gl_blocked(QemuConsole *con)
   2311 {
   2312     assert(con != NULL);
   2313     return con->gl_block;
   2314 }
   2315 
   2316 bool qemu_console_is_multihead(DeviceState *dev)
   2317 {
   2318     QemuConsole *con;
   2319     Object *obj;
   2320     uint32_t f = 0xffffffff;
   2321     uint32_t h;
   2322 
   2323     QTAILQ_FOREACH(con, &consoles, next) {
   2324         obj = object_property_get_link(OBJECT(con),
   2325                                        "device", &error_abort);
   2326         if (DEVICE(obj) != dev) {
   2327             continue;
   2328         }
   2329 
   2330         h = object_property_get_uint(OBJECT(con),
   2331                                      "head", &error_abort);
   2332         if (f == 0xffffffff) {
   2333             f = h;
   2334         } else if (h != f) {
   2335             return true;
   2336         }
   2337     }
   2338     return false;
   2339 }
   2340 
   2341 char *qemu_console_get_label(QemuConsole *con)
   2342 {
   2343     if (con->console_type == GRAPHIC_CONSOLE) {
   2344         if (con->device) {
   2345             DeviceState *dev;
   2346             bool multihead;
   2347 
   2348             dev = DEVICE(con->device);
   2349             multihead = qemu_console_is_multihead(dev);
   2350             if (multihead) {
   2351                 return g_strdup_printf("%s.%d", dev->id ?
   2352                                        dev->id :
   2353                                        object_get_typename(con->device),
   2354                                        con->head);
   2355             } else {
   2356                 return g_strdup_printf("%s", dev->id ?
   2357                                        dev->id :
   2358                                        object_get_typename(con->device));
   2359             }
   2360         }
   2361         return g_strdup("VGA");
   2362     } else {
   2363         if (con->chr && con->chr->label) {
   2364             return g_strdup(con->chr->label);
   2365         }
   2366         return g_strdup_printf("vc%d", con->index);
   2367     }
   2368 }
   2369 
   2370 int qemu_console_get_index(QemuConsole *con)
   2371 {
   2372     if (con == NULL) {
   2373         con = active_console;
   2374     }
   2375     return con ? con->index : -1;
   2376 }
   2377 
   2378 uint32_t qemu_console_get_head(QemuConsole *con)
   2379 {
   2380     if (con == NULL) {
   2381         con = active_console;
   2382     }
   2383     return con ? con->head : -1;
   2384 }
   2385 
   2386 int qemu_console_get_width(QemuConsole *con, int fallback)
   2387 {
   2388     if (con == NULL) {
   2389         con = active_console;
   2390     }
   2391     if (con == NULL) {
   2392         return fallback;
   2393     }
   2394     switch (con->scanout.kind) {
   2395     case SCANOUT_DMABUF:
   2396         return con->scanout.dmabuf->width;
   2397     case SCANOUT_TEXTURE:
   2398         return con->scanout.texture.width;
   2399     case SCANOUT_SURFACE:
   2400         return surface_width(con->surface);
   2401     default:
   2402         return fallback;
   2403     }
   2404 }
   2405 
   2406 int qemu_console_get_height(QemuConsole *con, int fallback)
   2407 {
   2408     if (con == NULL) {
   2409         con = active_console;
   2410     }
   2411     if (con == NULL) {
   2412         return fallback;
   2413     }
   2414     switch (con->scanout.kind) {
   2415     case SCANOUT_DMABUF:
   2416         return con->scanout.dmabuf->height;
   2417     case SCANOUT_TEXTURE:
   2418         return con->scanout.texture.height;
   2419     case SCANOUT_SURFACE:
   2420         return surface_height(con->surface);
   2421     default:
   2422         return fallback;
   2423     }
   2424 }
   2425 
   2426 static void vc_chr_accept_input(Chardev *chr)
   2427 {
   2428     VCChardev *drv = VC_CHARDEV(chr);
   2429     QemuConsole *s = drv->console;
   2430 
   2431     kbd_send_chars(s);
   2432 }
   2433 
   2434 static void vc_chr_set_echo(Chardev *chr, bool echo)
   2435 {
   2436     VCChardev *drv = VC_CHARDEV(chr);
   2437     QemuConsole *s = drv->console;
   2438 
   2439     s->echo = echo;
   2440 }
   2441 
   2442 static void text_console_update_cursor_timer(void)
   2443 {
   2444     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
   2445               + CONSOLE_CURSOR_PERIOD / 2);
   2446 }
   2447 
   2448 static void text_console_update_cursor(void *opaque)
   2449 {
   2450     QemuConsole *s;
   2451     int count = 0;
   2452 
   2453     cursor_visible_phase = !cursor_visible_phase;
   2454 
   2455     QTAILQ_FOREACH(s, &consoles, next) {
   2456         if (qemu_console_is_graphic(s) ||
   2457             !qemu_console_is_visible(s)) {
   2458             continue;
   2459         }
   2460         count++;
   2461         graphic_hw_invalidate(s);
   2462     }
   2463 
   2464     if (count) {
   2465         text_console_update_cursor_timer();
   2466     }
   2467 }
   2468 
   2469 static const GraphicHwOps text_console_ops = {
   2470     .invalidate  = text_console_invalidate,
   2471     .text_update = text_console_update,
   2472 };
   2473 
   2474 static void text_console_do_init(Chardev *chr, DisplayState *ds)
   2475 {
   2476     VCChardev *drv = VC_CHARDEV(chr);
   2477     QemuConsole *s = drv->console;
   2478     int g_width = 80 * FONT_WIDTH;
   2479     int g_height = 24 * FONT_HEIGHT;
   2480 
   2481     fifo8_create(&s->out_fifo, 16);
   2482     s->ds = ds;
   2483 
   2484     s->y_displayed = 0;
   2485     s->y_base = 0;
   2486     s->total_height = DEFAULT_BACKSCROLL;
   2487     s->x = 0;
   2488     s->y = 0;
   2489     if (s->scanout.kind != SCANOUT_SURFACE) {
   2490         if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) {
   2491             g_width = qemu_console_get_width(active_console, g_width);
   2492             g_height = qemu_console_get_height(active_console, g_height);
   2493         }
   2494         s->surface = qemu_create_displaysurface(g_width, g_height);
   2495         s->scanout.kind = SCANOUT_SURFACE;
   2496     }
   2497 
   2498     s->hw_ops = &text_console_ops;
   2499     s->hw = s;
   2500 
   2501     /* Set text attribute defaults */
   2502     s->t_attrib_default.bold = 0;
   2503     s->t_attrib_default.uline = 0;
   2504     s->t_attrib_default.blink = 0;
   2505     s->t_attrib_default.invers = 0;
   2506     s->t_attrib_default.unvisible = 0;
   2507     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
   2508     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
   2509     /* set current text attributes to default */
   2510     s->t_attrib = s->t_attrib_default;
   2511     text_console_resize(s);
   2512 
   2513     if (chr->label) {
   2514         char *msg;
   2515 
   2516         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
   2517         msg = g_strdup_printf("%s console\r\n", chr->label);
   2518         vc_chr_write(chr, (uint8_t *)msg, strlen(msg));
   2519         g_free(msg);
   2520         s->t_attrib = s->t_attrib_default;
   2521     }
   2522 
   2523     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
   2524 }
   2525 
   2526 static void vc_chr_open(Chardev *chr,
   2527                         ChardevBackend *backend,
   2528                         bool *be_opened,
   2529                         Error **errp)
   2530 {
   2531     ChardevVC *vc = backend->u.vc.data;
   2532     VCChardev *drv = VC_CHARDEV(chr);
   2533     QemuConsole *s;
   2534     unsigned width = 0;
   2535     unsigned height = 0;
   2536 
   2537     if (vc->has_width) {
   2538         width = vc->width;
   2539     } else if (vc->has_cols) {
   2540         width = vc->cols * FONT_WIDTH;
   2541     }
   2542 
   2543     if (vc->has_height) {
   2544         height = vc->height;
   2545     } else if (vc->has_rows) {
   2546         height = vc->rows * FONT_HEIGHT;
   2547     }
   2548 
   2549     trace_console_txt_new(width, height);
   2550     if (width == 0 || height == 0) {
   2551         s = new_console(NULL, TEXT_CONSOLE, 0);
   2552     } else {
   2553         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
   2554         s->scanout.kind = SCANOUT_SURFACE;
   2555         s->surface = qemu_create_displaysurface(width, height);
   2556     }
   2557 
   2558     if (!s) {
   2559         error_setg(errp, "cannot create text console");
   2560         return;
   2561     }
   2562 
   2563     s->chr = chr;
   2564     drv->console = s;
   2565 
   2566     if (display_state) {
   2567         text_console_do_init(chr, display_state);
   2568     }
   2569 
   2570     /* console/chardev init sometimes completes elsewhere in a 2nd
   2571      * stage, so defer OPENED events until they are fully initialized
   2572      */
   2573     *be_opened = false;
   2574 }
   2575 
   2576 void qemu_console_resize(QemuConsole *s, int width, int height)
   2577 {
   2578     DisplaySurface *surface = qemu_console_surface(s);
   2579 
   2580     assert(s->console_type == GRAPHIC_CONSOLE);
   2581 
   2582     if ((s->scanout.kind != SCANOUT_SURFACE ||
   2583          (surface && surface->flags & QEMU_ALLOCATED_FLAG)) &&
   2584         qemu_console_get_width(s, -1) == width &&
   2585         qemu_console_get_height(s, -1) == height) {
   2586         return;
   2587     }
   2588 
   2589     surface = qemu_create_displaysurface(width, height);
   2590     dpy_gfx_replace_surface(s, surface);
   2591 }
   2592 
   2593 DisplaySurface *qemu_console_surface(QemuConsole *console)
   2594 {
   2595     switch (console->scanout.kind) {
   2596     case SCANOUT_SURFACE:
   2597         return console->surface;
   2598     default:
   2599         return NULL;
   2600     }
   2601 }
   2602 
   2603 PixelFormat qemu_default_pixelformat(int bpp)
   2604 {
   2605     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
   2606     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
   2607     return pf;
   2608 }
   2609 
   2610 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
   2611 
   2612 void qemu_display_register(QemuDisplay *ui)
   2613 {
   2614     assert(ui->type < DISPLAY_TYPE__MAX);
   2615     dpys[ui->type] = ui;
   2616 }
   2617 
   2618 bool qemu_display_find_default(DisplayOptions *opts)
   2619 {
   2620     static DisplayType prio[] = {
   2621 #if defined(CONFIG_GTK)
   2622         DISPLAY_TYPE_GTK,
   2623 #endif
   2624 #if defined(CONFIG_SDL)
   2625         DISPLAY_TYPE_SDL,
   2626 #endif
   2627 #if defined(CONFIG_COCOA)
   2628         DISPLAY_TYPE_COCOA
   2629 #endif
   2630     };
   2631     int i;
   2632 
   2633     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
   2634         if (dpys[prio[i]] == NULL) {
   2635             Error *local_err = NULL;
   2636             int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
   2637             if (rv < 0) {
   2638                 error_report_err(local_err);
   2639             }
   2640         }
   2641         if (dpys[prio[i]] == NULL) {
   2642             continue;
   2643         }
   2644         opts->type = prio[i];
   2645         return true;
   2646     }
   2647     return false;
   2648 }
   2649 
   2650 void qemu_display_early_init(DisplayOptions *opts)
   2651 {
   2652     assert(opts->type < DISPLAY_TYPE__MAX);
   2653     if (opts->type == DISPLAY_TYPE_NONE) {
   2654         return;
   2655     }
   2656     if (dpys[opts->type] == NULL) {
   2657         Error *local_err = NULL;
   2658         int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
   2659         if (rv < 0) {
   2660             error_report_err(local_err);
   2661         }
   2662     }
   2663     if (dpys[opts->type] == NULL) {
   2664         error_report("Display '%s' is not available.",
   2665                      DisplayType_str(opts->type));
   2666         exit(1);
   2667     }
   2668     if (dpys[opts->type]->early_init) {
   2669         dpys[opts->type]->early_init(opts);
   2670     }
   2671 }
   2672 
   2673 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
   2674 {
   2675     assert(opts->type < DISPLAY_TYPE__MAX);
   2676     if (opts->type == DISPLAY_TYPE_NONE) {
   2677         return;
   2678     }
   2679     assert(dpys[opts->type] != NULL);
   2680     dpys[opts->type]->init(ds, opts);
   2681 }
   2682 
   2683 void qemu_display_help(void)
   2684 {
   2685     int idx;
   2686 
   2687     printf("Available display backend types:\n");
   2688     printf("none\n");
   2689     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
   2690         if (!dpys[idx]) {
   2691             Error *local_err = NULL;
   2692             int rv = ui_module_load(DisplayType_str(idx), &local_err);
   2693             if (rv < 0) {
   2694                 error_report_err(local_err);
   2695             }
   2696         }
   2697         if (dpys[idx]) {
   2698             printf("%s\n",  DisplayType_str(dpys[idx]->type));
   2699         }
   2700     }
   2701 }
   2702 
   2703 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
   2704 {
   2705     int val;
   2706     ChardevVC *vc;
   2707 
   2708     backend->type = CHARDEV_BACKEND_KIND_VC;
   2709     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
   2710     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
   2711 
   2712     val = qemu_opt_get_number(opts, "width", 0);
   2713     if (val != 0) {
   2714         vc->has_width = true;
   2715         vc->width = val;
   2716     }
   2717 
   2718     val = qemu_opt_get_number(opts, "height", 0);
   2719     if (val != 0) {
   2720         vc->has_height = true;
   2721         vc->height = val;
   2722     }
   2723 
   2724     val = qemu_opt_get_number(opts, "cols", 0);
   2725     if (val != 0) {
   2726         vc->has_cols = true;
   2727         vc->cols = val;
   2728     }
   2729 
   2730     val = qemu_opt_get_number(opts, "rows", 0);
   2731     if (val != 0) {
   2732         vc->has_rows = true;
   2733         vc->rows = val;
   2734     }
   2735 }
   2736 
   2737 static const TypeInfo qemu_console_info = {
   2738     .name = TYPE_QEMU_CONSOLE,
   2739     .parent = TYPE_OBJECT,
   2740     .instance_size = sizeof(QemuConsole),
   2741     .class_size = sizeof(QemuConsoleClass),
   2742 };
   2743 
   2744 static void char_vc_class_init(ObjectClass *oc, void *data)
   2745 {
   2746     ChardevClass *cc = CHARDEV_CLASS(oc);
   2747 
   2748     cc->parse = qemu_chr_parse_vc;
   2749     cc->open = vc_chr_open;
   2750     cc->chr_write = vc_chr_write;
   2751     cc->chr_accept_input = vc_chr_accept_input;
   2752     cc->chr_set_echo = vc_chr_set_echo;
   2753 }
   2754 
   2755 static const TypeInfo char_vc_type_info = {
   2756     .name = TYPE_CHARDEV_VC,
   2757     .parent = TYPE_CHARDEV,
   2758     .instance_size = sizeof(VCChardev),
   2759     .class_init = char_vc_class_init,
   2760 };
   2761 
   2762 void qemu_console_early_init(void)
   2763 {
   2764     /* set the default vc driver */
   2765     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
   2766         type_register(&char_vc_type_info);
   2767     }
   2768 }
   2769 
   2770 static void register_types(void)
   2771 {
   2772     type_register_static(&qemu_console_info);
   2773 }
   2774 
   2775 type_init(register_types);