Don't look up pid/tid on YAGL_LOG_FUNC_SET
[sdk/emulator/qemu.git] / ui / console.c
1 /*
2  * QEMU graphical console
3  *
4  * Copyright (c) 2004 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "qemu/osdep.h"
25 #include "qemu-common.h"
26 #include "ui/console.h"
27 #include "hw/qdev-core.h"
28 #include "qemu/timer.h"
29 #include "qmp-commands.h"
30 #include "sysemu/char.h"
31 #include "trace.h"
32 #include "exec/memory.h"
33
34 #ifdef CONFIG_MARU
35 #include "sysemu/sysemu.h"
36
37 extern int initial_resolution_width;
38 extern int initial_resolution_height;
39 #endif
40
41 #define DEFAULT_BACKSCROLL 512
42 #define CONSOLE_CURSOR_PERIOD 500
43
44 typedef struct TextAttributes {
45     uint8_t fgcol:4;
46     uint8_t bgcol:4;
47     uint8_t bold:1;
48     uint8_t uline:1;
49     uint8_t blink:1;
50     uint8_t invers:1;
51     uint8_t unvisible:1;
52 } TextAttributes;
53
54 typedef struct TextCell {
55     uint8_t ch;
56     TextAttributes t_attrib;
57 } TextCell;
58
59 #define MAX_ESC_PARAMS 3
60
61 enum TTYState {
62     TTY_STATE_NORM,
63     TTY_STATE_ESC,
64     TTY_STATE_CSI,
65 };
66
67 typedef struct QEMUFIFO {
68     uint8_t *buf;
69     int buf_size;
70     int count, wptr, rptr;
71 } QEMUFIFO;
72
73 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
74 {
75     int l, len;
76
77     l = f->buf_size - f->count;
78     if (len1 > l)
79         len1 = l;
80     len = len1;
81     while (len > 0) {
82         l = f->buf_size - f->wptr;
83         if (l > len)
84             l = len;
85         memcpy(f->buf + f->wptr, buf, l);
86         f->wptr += l;
87         if (f->wptr >= f->buf_size)
88             f->wptr = 0;
89         buf += l;
90         len -= l;
91     }
92     f->count += len1;
93     return len1;
94 }
95
96 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
97 {
98     int l, len;
99
100     if (len1 > f->count)
101         len1 = f->count;
102     len = len1;
103     while (len > 0) {
104         l = f->buf_size - f->rptr;
105         if (l > len)
106             l = len;
107         memcpy(buf, f->buf + f->rptr, l);
108         f->rptr += l;
109         if (f->rptr >= f->buf_size)
110             f->rptr = 0;
111         buf += l;
112         len -= l;
113     }
114     f->count -= len1;
115     return len1;
116 }
117
118 typedef enum {
119     GRAPHIC_CONSOLE,
120     TEXT_CONSOLE,
121     TEXT_CONSOLE_FIXED_SIZE
122 } console_type_t;
123
124 struct QemuConsole {
125     Object parent;
126
127     int index;
128     console_type_t console_type;
129     DisplayState *ds;
130     DisplaySurface *surface;
131     int dcls;
132     DisplayChangeListener *gl;
133     bool gl_block;
134
135     /* Graphic console state.  */
136     Object *device;
137     uint32_t head;
138     QemuUIInfo ui_info;
139     QEMUTimer *ui_timer;
140     const GraphicHwOps *hw_ops;
141     void *hw;
142
143     /* Text console state */
144     int width;
145     int height;
146     int total_height;
147     int backscroll_height;
148     int x, y;
149     int x_saved, y_saved;
150     int y_displayed;
151     int y_base;
152     TextAttributes t_attrib_default; /* default text attributes */
153     TextAttributes t_attrib; /* currently active text attributes */
154     TextCell *cells;
155     int text_x[2], text_y[2], cursor_invalidate;
156     int echo;
157
158     int update_x0;
159     int update_y0;
160     int update_x1;
161     int update_y1;
162
163     enum TTYState state;
164     int esc_params[MAX_ESC_PARAMS];
165     int nb_esc_params;
166
167     CharDriverState *chr;
168     /* fifo for key pressed */
169     QEMUFIFO out_fifo;
170     uint8_t out_fifo_buf[16];
171     QEMUTimer *kbd_timer;
172 };
173
174 struct DisplayState {
175     QEMUTimer *gui_timer;
176     uint64_t last_update;
177     uint64_t update_interval;
178     bool refreshing;
179     bool have_gfx;
180     bool have_text;
181
182     QLIST_HEAD(, DisplayChangeListener) listeners;
183 };
184
185 static DisplayState *display_state;
186 static QemuConsole *active_console;
187 static QemuConsole **consoles;
188 static int nb_consoles = 0;
189 static bool cursor_visible_phase;
190 static QEMUTimer *cursor_timer;
191
192 static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
193 static void dpy_refresh(DisplayState *s);
194 static DisplayState *get_alloc_displaystate(void);
195 static void text_console_update_cursor_timer(void);
196 static void text_console_update_cursor(void *opaque);
197
198 static void gui_update(void *opaque)
199 {
200     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
201     uint64_t dcl_interval;
202     DisplayState *ds = opaque;
203     DisplayChangeListener *dcl;
204     int i;
205
206     ds->refreshing = true;
207     dpy_refresh(ds);
208     ds->refreshing = false;
209
210     QLIST_FOREACH(dcl, &ds->listeners, next) {
211         dcl_interval = dcl->update_interval ?
212             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
213         if (interval > dcl_interval) {
214             interval = dcl_interval;
215         }
216     }
217     if (ds->update_interval != interval) {
218         ds->update_interval = interval;
219         for (i = 0; i < nb_consoles; i++) {
220             if (consoles[i]->hw_ops->update_interval) {
221                 consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
222             }
223         }
224         trace_console_refresh(interval);
225     }
226     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
227     timer_mod(ds->gui_timer, ds->last_update + interval);
228 }
229
230 static void gui_setup_refresh(DisplayState *ds)
231 {
232     DisplayChangeListener *dcl;
233     bool need_timer = false;
234     bool have_gfx = false;
235     bool have_text = false;
236
237     QLIST_FOREACH(dcl, &ds->listeners, next) {
238         if (dcl->ops->dpy_refresh != NULL) {
239             need_timer = true;
240         }
241         if (dcl->ops->dpy_gfx_update != NULL) {
242             have_gfx = true;
243         }
244         if (dcl->ops->dpy_text_update != NULL) {
245             have_text = true;
246         }
247     }
248
249     if (need_timer && ds->gui_timer == NULL) {
250         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
251         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
252     }
253     if (!need_timer && ds->gui_timer != NULL) {
254         timer_del(ds->gui_timer);
255         timer_free(ds->gui_timer);
256         ds->gui_timer = NULL;
257     }
258
259     ds->have_gfx = have_gfx;
260     ds->have_text = have_text;
261 }
262
263 void graphic_hw_update(QemuConsole *con)
264 {
265     if (!con) {
266         con = active_console;
267     }
268     if (con && con->hw_ops->gfx_update) {
269         con->hw_ops->gfx_update(con->hw);
270     }
271 }
272
273 void graphic_hw_gl_block(QemuConsole *con, bool block)
274 {
275     assert(con != NULL);
276
277     con->gl_block = block;
278     if (con->hw_ops->gl_block) {
279         con->hw_ops->gl_block(con->hw, block);
280     }
281 }
282
283 void graphic_hw_invalidate(QemuConsole *con)
284 {
285     if (!con) {
286         con = active_console;
287     }
288     if (con && con->hw_ops->invalidate) {
289         con->hw_ops->invalidate(con->hw);
290     }
291 }
292
293 static void ppm_save(const char *filename, DisplaySurface *ds,
294                      Error **errp)
295 {
296     int width = pixman_image_get_width(ds->image);
297     int height = pixman_image_get_height(ds->image);
298     int fd;
299     FILE *f;
300     int y;
301     int ret;
302     pixman_image_t *linebuf;
303
304     trace_ppm_save(filename, ds);
305     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
306     if (fd == -1) {
307         error_setg(errp, "failed to open file '%s': %s", filename,
308                    strerror(errno));
309         return;
310     }
311     f = fdopen(fd, "wb");
312     ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
313     if (ret < 0) {
314         linebuf = NULL;
315         goto write_err;
316     }
317     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
318     for (y = 0; y < height; y++) {
319         qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
320         clearerr(f);
321         ret = fwrite(pixman_image_get_data(linebuf), 1,
322                      pixman_image_get_stride(linebuf), f);
323         (void)ret;
324         if (ferror(f)) {
325             goto write_err;
326         }
327     }
328
329 out:
330     qemu_pixman_image_unref(linebuf);
331     fclose(f);
332     return;
333
334 write_err:
335     error_setg(errp, "failed to write to file '%s': %s", filename,
336                strerror(errno));
337     unlink(filename);
338     goto out;
339 }
340
341 void qmp_screendump(const char *filename, Error **errp)
342 {
343     QemuConsole *con = qemu_console_lookup_by_index(0);
344     DisplaySurface *surface;
345
346     if (con == NULL) {
347         error_setg(errp, "There is no QemuConsole I can screendump from.");
348         return;
349     }
350
351     graphic_hw_update(con);
352     surface = qemu_console_surface(con);
353     ppm_save(filename, surface, errp);
354 }
355
356 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
357 {
358     if (!con) {
359         con = active_console;
360     }
361     if (con && con->hw_ops->text_update) {
362         con->hw_ops->text_update(con->hw, chardata);
363     }
364 }
365
366 static void vga_fill_rect(QemuConsole *con,
367                           int posx, int posy, int width, int height,
368                           pixman_color_t color)
369 {
370     DisplaySurface *surface = qemu_console_surface(con);
371     pixman_rectangle16_t rect = {
372         .x = posx, .y = posy, .width = width, .height = height
373     };
374
375     pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
376                                  &color, 1, &rect);
377 }
378
379 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
380 static void vga_bitblt(QemuConsole *con,
381                        int xs, int ys, int xd, int yd, int w, int h)
382 {
383     DisplaySurface *surface = qemu_console_surface(con);
384
385     pixman_image_composite(PIXMAN_OP_SRC,
386                            surface->image, NULL, surface->image,
387                            xs, ys, 0, 0, xd, yd, w, h);
388 }
389
390 /***********************************************************/
391 /* basic char display */
392
393 #define FONT_HEIGHT 16
394 #define FONT_WIDTH 8
395
396 #include "vgafont.h"
397
398 #define QEMU_RGB(r, g, b)                                               \
399     { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
400
401 static const pixman_color_t color_table_rgb[2][8] = {
402     {   /* dark */
403         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
404         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
405         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
406         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
407         [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
408         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
409         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
410         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
411     },
412     {   /* bright */
413         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
414         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
415         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
416         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
417         [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
418         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
419         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
420         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
421     }
422 };
423
424 static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
425                           TextAttributes *t_attrib)
426 {
427     static pixman_image_t *glyphs[256];
428     DisplaySurface *surface = qemu_console_surface(s);
429     pixman_color_t fgcol, bgcol;
430
431     if (t_attrib->invers) {
432         bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
433         fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
434     } else {
435         fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
436         bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
437     }
438
439     if (!glyphs[ch]) {
440         glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
441     }
442     qemu_pixman_glyph_render(glyphs[ch], surface->image,
443                              &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
444 }
445
446 static void text_console_resize(QemuConsole *s)
447 {
448     TextCell *cells, *c, *c1;
449     int w1, x, y, last_width;
450
451     last_width = s->width;
452     s->width = surface_width(s->surface) / FONT_WIDTH;
453     s->height = surface_height(s->surface) / FONT_HEIGHT;
454
455     w1 = last_width;
456     if (s->width < w1)
457         w1 = s->width;
458
459     cells = g_new(TextCell, s->width * s->total_height);
460     for(y = 0; y < s->total_height; y++) {
461         c = &cells[y * s->width];
462         if (w1 > 0) {
463             c1 = &s->cells[y * last_width];
464             for(x = 0; x < w1; x++) {
465                 *c++ = *c1++;
466             }
467         }
468         for(x = w1; x < s->width; x++) {
469             c->ch = ' ';
470             c->t_attrib = s->t_attrib_default;
471             c++;
472         }
473     }
474     g_free(s->cells);
475     s->cells = cells;
476 }
477
478 static inline void text_update_xy(QemuConsole *s, int x, int y)
479 {
480     s->text_x[0] = MIN(s->text_x[0], x);
481     s->text_x[1] = MAX(s->text_x[1], x);
482     s->text_y[0] = MIN(s->text_y[0], y);
483     s->text_y[1] = MAX(s->text_y[1], y);
484 }
485
486 static void invalidate_xy(QemuConsole *s, int x, int y)
487 {
488     if (!qemu_console_is_visible(s)) {
489         return;
490     }
491     if (s->update_x0 > x * FONT_WIDTH)
492         s->update_x0 = x * FONT_WIDTH;
493     if (s->update_y0 > y * FONT_HEIGHT)
494         s->update_y0 = y * FONT_HEIGHT;
495     if (s->update_x1 < (x + 1) * FONT_WIDTH)
496         s->update_x1 = (x + 1) * FONT_WIDTH;
497     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
498         s->update_y1 = (y + 1) * FONT_HEIGHT;
499 }
500
501 static void update_xy(QemuConsole *s, int x, int y)
502 {
503     TextCell *c;
504     int y1, y2;
505
506     if (s->ds->have_text) {
507         text_update_xy(s, x, y);
508     }
509
510     y1 = (s->y_base + y) % s->total_height;
511     y2 = y1 - s->y_displayed;
512     if (y2 < 0) {
513         y2 += s->total_height;
514     }
515     if (y2 < s->height) {
516         c = &s->cells[y1 * s->width + x];
517         vga_putcharxy(s, x, y2, c->ch,
518                       &(c->t_attrib));
519         invalidate_xy(s, x, y2);
520     }
521 }
522
523 static void console_show_cursor(QemuConsole *s, int show)
524 {
525     TextCell *c;
526     int y, y1;
527     int x = s->x;
528
529     if (s->ds->have_text) {
530         s->cursor_invalidate = 1;
531     }
532
533     if (x >= s->width) {
534         x = s->width - 1;
535     }
536     y1 = (s->y_base + s->y) % s->total_height;
537     y = y1 - s->y_displayed;
538     if (y < 0) {
539         y += s->total_height;
540     }
541     if (y < s->height) {
542         c = &s->cells[y1 * s->width + x];
543         if (show && cursor_visible_phase) {
544             TextAttributes t_attrib = s->t_attrib_default;
545             t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
546             vga_putcharxy(s, x, y, c->ch, &t_attrib);
547         } else {
548             vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
549         }
550         invalidate_xy(s, x, y);
551     }
552 }
553
554 static void console_refresh(QemuConsole *s)
555 {
556     DisplaySurface *surface = qemu_console_surface(s);
557     TextCell *c;
558     int x, y, y1;
559
560     if (s->ds->have_text) {
561         s->text_x[0] = 0;
562         s->text_y[0] = 0;
563         s->text_x[1] = s->width - 1;
564         s->text_y[1] = s->height - 1;
565         s->cursor_invalidate = 1;
566     }
567
568     vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
569                   color_table_rgb[0][QEMU_COLOR_BLACK]);
570     y1 = s->y_displayed;
571     for (y = 0; y < s->height; y++) {
572         c = s->cells + y1 * s->width;
573         for (x = 0; x < s->width; x++) {
574             vga_putcharxy(s, x, y, c->ch,
575                           &(c->t_attrib));
576             c++;
577         }
578         if (++y1 == s->total_height) {
579             y1 = 0;
580         }
581     }
582     console_show_cursor(s, 1);
583     dpy_gfx_update(s, 0, 0,
584                    surface_width(surface), surface_height(surface));
585 }
586
587 static void console_scroll(QemuConsole *s, int ydelta)
588 {
589     int i, y1;
590
591     if (ydelta > 0) {
592         for(i = 0; i < ydelta; i++) {
593             if (s->y_displayed == s->y_base)
594                 break;
595             if (++s->y_displayed == s->total_height)
596                 s->y_displayed = 0;
597         }
598     } else {
599         ydelta = -ydelta;
600         i = s->backscroll_height;
601         if (i > s->total_height - s->height)
602             i = s->total_height - s->height;
603         y1 = s->y_base - i;
604         if (y1 < 0)
605             y1 += s->total_height;
606         for(i = 0; i < ydelta; i++) {
607             if (s->y_displayed == y1)
608                 break;
609             if (--s->y_displayed < 0)
610                 s->y_displayed = s->total_height - 1;
611         }
612     }
613     console_refresh(s);
614 }
615
616 static void console_put_lf(QemuConsole *s)
617 {
618     TextCell *c;
619     int x, y1;
620
621     s->y++;
622     if (s->y >= s->height) {
623         s->y = s->height - 1;
624
625         if (s->y_displayed == s->y_base) {
626             if (++s->y_displayed == s->total_height)
627                 s->y_displayed = 0;
628         }
629         if (++s->y_base == s->total_height)
630             s->y_base = 0;
631         if (s->backscroll_height < s->total_height)
632             s->backscroll_height++;
633         y1 = (s->y_base + s->height - 1) % s->total_height;
634         c = &s->cells[y1 * s->width];
635         for(x = 0; x < s->width; x++) {
636             c->ch = ' ';
637             c->t_attrib = s->t_attrib_default;
638             c++;
639         }
640         if (s->y_displayed == s->y_base) {
641             if (s->ds->have_text) {
642                 s->text_x[0] = 0;
643                 s->text_y[0] = 0;
644                 s->text_x[1] = s->width - 1;
645                 s->text_y[1] = s->height - 1;
646             }
647
648             vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
649                        s->width * FONT_WIDTH,
650                        (s->height - 1) * FONT_HEIGHT);
651             vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
652                           s->width * FONT_WIDTH, FONT_HEIGHT,
653                           color_table_rgb[0][s->t_attrib_default.bgcol]);
654             s->update_x0 = 0;
655             s->update_y0 = 0;
656             s->update_x1 = s->width * FONT_WIDTH;
657             s->update_y1 = s->height * FONT_HEIGHT;
658         }
659     }
660 }
661
662 /* Set console attributes depending on the current escape codes.
663  * NOTE: I know this code is not very efficient (checking every color for it
664  * self) but it is more readable and better maintainable.
665  */
666 static void console_handle_escape(QemuConsole *s)
667 {
668     int i;
669
670     for (i=0; i<s->nb_esc_params; i++) {
671         switch (s->esc_params[i]) {
672             case 0: /* reset all console attributes to default */
673                 s->t_attrib = s->t_attrib_default;
674                 break;
675             case 1:
676                 s->t_attrib.bold = 1;
677                 break;
678             case 4:
679                 s->t_attrib.uline = 1;
680                 break;
681             case 5:
682                 s->t_attrib.blink = 1;
683                 break;
684             case 7:
685                 s->t_attrib.invers = 1;
686                 break;
687             case 8:
688                 s->t_attrib.unvisible = 1;
689                 break;
690             case 22:
691                 s->t_attrib.bold = 0;
692                 break;
693             case 24:
694                 s->t_attrib.uline = 0;
695                 break;
696             case 25:
697                 s->t_attrib.blink = 0;
698                 break;
699             case 27:
700                 s->t_attrib.invers = 0;
701                 break;
702             case 28:
703                 s->t_attrib.unvisible = 0;
704                 break;
705             /* set foreground color */
706             case 30:
707                 s->t_attrib.fgcol = QEMU_COLOR_BLACK;
708                 break;
709             case 31:
710                 s->t_attrib.fgcol = QEMU_COLOR_RED;
711                 break;
712             case 32:
713                 s->t_attrib.fgcol = QEMU_COLOR_GREEN;
714                 break;
715             case 33:
716                 s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
717                 break;
718             case 34:
719                 s->t_attrib.fgcol = QEMU_COLOR_BLUE;
720                 break;
721             case 35:
722                 s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
723                 break;
724             case 36:
725                 s->t_attrib.fgcol = QEMU_COLOR_CYAN;
726                 break;
727             case 37:
728                 s->t_attrib.fgcol = QEMU_COLOR_WHITE;
729                 break;
730             /* set background color */
731             case 40:
732                 s->t_attrib.bgcol = QEMU_COLOR_BLACK;
733                 break;
734             case 41:
735                 s->t_attrib.bgcol = QEMU_COLOR_RED;
736                 break;
737             case 42:
738                 s->t_attrib.bgcol = QEMU_COLOR_GREEN;
739                 break;
740             case 43:
741                 s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
742                 break;
743             case 44:
744                 s->t_attrib.bgcol = QEMU_COLOR_BLUE;
745                 break;
746             case 45:
747                 s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
748                 break;
749             case 46:
750                 s->t_attrib.bgcol = QEMU_COLOR_CYAN;
751                 break;
752             case 47:
753                 s->t_attrib.bgcol = QEMU_COLOR_WHITE;
754                 break;
755         }
756     }
757 }
758
759 static void console_clear_xy(QemuConsole *s, int x, int y)
760 {
761     int y1 = (s->y_base + y) % s->total_height;
762     TextCell *c = &s->cells[y1 * s->width + x];
763     c->ch = ' ';
764     c->t_attrib = s->t_attrib_default;
765     update_xy(s, x, y);
766 }
767
768 static void console_put_one(QemuConsole *s, int ch)
769 {
770     TextCell *c;
771     int y1;
772     if (s->x >= s->width) {
773         /* line wrap */
774         s->x = 0;
775         console_put_lf(s);
776     }
777     y1 = (s->y_base + s->y) % s->total_height;
778     c = &s->cells[y1 * s->width + s->x];
779     c->ch = ch;
780     c->t_attrib = s->t_attrib;
781     update_xy(s, s->x, s->y);
782     s->x++;
783 }
784
785 static void console_respond_str(QemuConsole *s, const char *buf)
786 {
787     while (*buf) {
788         console_put_one(s, *buf);
789         buf++;
790     }
791 }
792
793 /* set cursor, checking bounds */
794 static void set_cursor(QemuConsole *s, int x, int y)
795 {
796     if (x < 0) {
797         x = 0;
798     }
799     if (y < 0) {
800         y = 0;
801     }
802     if (y >= s->height) {
803         y = s->height - 1;
804     }
805     if (x >= s->width) {
806         x = s->width - 1;
807     }
808
809     s->x = x;
810     s->y = y;
811 }
812
813 static void console_putchar(QemuConsole *s, int ch)
814 {
815     int i;
816     int x, y;
817     char response[40];
818
819     switch(s->state) {
820     case TTY_STATE_NORM:
821         switch(ch) {
822         case '\r':  /* carriage return */
823             s->x = 0;
824             break;
825         case '\n':  /* newline */
826             console_put_lf(s);
827             break;
828         case '\b':  /* backspace */
829             if (s->x > 0)
830                 s->x--;
831             break;
832         case '\t':  /* tabspace */
833             if (s->x + (8 - (s->x % 8)) > s->width) {
834                 s->x = 0;
835                 console_put_lf(s);
836             } else {
837                 s->x = s->x + (8 - (s->x % 8));
838             }
839             break;
840         case '\a':  /* alert aka. bell */
841             /* TODO: has to be implemented */
842             break;
843         case 14:
844             /* SI (shift in), character set 0 (ignored) */
845             break;
846         case 15:
847             /* SO (shift out), character set 1 (ignored) */
848             break;
849         case 27:    /* esc (introducing an escape sequence) */
850             s->state = TTY_STATE_ESC;
851             break;
852         default:
853             console_put_one(s, ch);
854             break;
855         }
856         break;
857     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
858         if (ch == '[') {
859             for(i=0;i<MAX_ESC_PARAMS;i++)
860                 s->esc_params[i] = 0;
861             s->nb_esc_params = 0;
862             s->state = TTY_STATE_CSI;
863         } else {
864             s->state = TTY_STATE_NORM;
865         }
866         break;
867     case TTY_STATE_CSI: /* handle escape sequence parameters */
868         if (ch >= '0' && ch <= '9') {
869             if (s->nb_esc_params < MAX_ESC_PARAMS) {
870                 int *param = &s->esc_params[s->nb_esc_params];
871                 int digit = (ch - '0');
872
873                 *param = (*param <= (INT_MAX - digit) / 10) ?
874                          *param * 10 + digit : INT_MAX;
875             }
876         } else {
877             if (s->nb_esc_params < MAX_ESC_PARAMS)
878                 s->nb_esc_params++;
879             if (ch == ';')
880                 break;
881             trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
882                                       ch, s->nb_esc_params);
883             s->state = TTY_STATE_NORM;
884             switch(ch) {
885             case 'A':
886                 /* move cursor up */
887                 if (s->esc_params[0] == 0) {
888                     s->esc_params[0] = 1;
889                 }
890                 set_cursor(s, s->x, s->y - s->esc_params[0]);
891                 break;
892             case 'B':
893                 /* move cursor down */
894                 if (s->esc_params[0] == 0) {
895                     s->esc_params[0] = 1;
896                 }
897                 set_cursor(s, s->x, s->y + s->esc_params[0]);
898                 break;
899             case 'C':
900                 /* move cursor right */
901                 if (s->esc_params[0] == 0) {
902                     s->esc_params[0] = 1;
903                 }
904                 set_cursor(s, s->x + s->esc_params[0], s->y);
905                 break;
906             case 'D':
907                 /* move cursor left */
908                 if (s->esc_params[0] == 0) {
909                     s->esc_params[0] = 1;
910                 }
911                 set_cursor(s, s->x - s->esc_params[0], s->y);
912                 break;
913             case 'G':
914                 /* move cursor to column */
915                 set_cursor(s, s->esc_params[0] - 1, s->y);
916                 break;
917             case 'f':
918             case 'H':
919                 /* move cursor to row, column */
920                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
921                 break;
922             case 'J':
923                 switch (s->esc_params[0]) {
924                 case 0:
925                     /* clear to end of screen */
926                     for (y = s->y; y < s->height; y++) {
927                         for (x = 0; x < s->width; x++) {
928                             if (y == s->y && x < s->x) {
929                                 continue;
930                             }
931                             console_clear_xy(s, x, y);
932                         }
933                     }
934                     break;
935                 case 1:
936                     /* clear from beginning of screen */
937                     for (y = 0; y <= s->y; y++) {
938                         for (x = 0; x < s->width; x++) {
939                             if (y == s->y && x > s->x) {
940                                 break;
941                             }
942                             console_clear_xy(s, x, y);
943                         }
944                     }
945                     break;
946                 case 2:
947                     /* clear entire screen */
948                     for (y = 0; y <= s->height; y++) {
949                         for (x = 0; x < s->width; x++) {
950                             console_clear_xy(s, x, y);
951                         }
952                     }
953                     break;
954                 }
955                 break;
956             case 'K':
957                 switch (s->esc_params[0]) {
958                 case 0:
959                     /* clear to eol */
960                     for(x = s->x; x < s->width; x++) {
961                         console_clear_xy(s, x, s->y);
962                     }
963                     break;
964                 case 1:
965                     /* clear from beginning of line */
966                     for (x = 0; x <= s->x; x++) {
967                         console_clear_xy(s, x, s->y);
968                     }
969                     break;
970                 case 2:
971                     /* clear entire line */
972                     for(x = 0; x < s->width; x++) {
973                         console_clear_xy(s, x, s->y);
974                     }
975                     break;
976                 }
977                 break;
978             case 'm':
979                 console_handle_escape(s);
980                 break;
981             case 'n':
982                 switch (s->esc_params[0]) {
983                 case 5:
984                     /* report console status (always succeed)*/
985                     console_respond_str(s, "\033[0n");
986                     break;
987                 case 6:
988                     /* report cursor position */
989                     sprintf(response, "\033[%d;%dR",
990                            (s->y_base + s->y) % s->total_height + 1,
991                             s->x + 1);
992                     console_respond_str(s, response);
993                     break;
994                 }
995                 break;
996             case 's':
997                 /* save cursor position */
998                 s->x_saved = s->x;
999                 s->y_saved = s->y;
1000                 break;
1001             case 'u':
1002                 /* restore cursor position */
1003                 s->x = s->x_saved;
1004                 s->y = s->y_saved;
1005                 break;
1006             default:
1007                 trace_console_putchar_unhandled(ch);
1008                 break;
1009             }
1010             break;
1011         }
1012     }
1013 }
1014
1015 void console_select(unsigned int index)
1016 {
1017     DisplayChangeListener *dcl;
1018     QemuConsole *s;
1019
1020     trace_console_select(index);
1021     s = qemu_console_lookup_by_index(index);
1022     if (s) {
1023         DisplayState *ds = s->ds;
1024
1025         active_console = s;
1026         if (ds->have_gfx) {
1027             QLIST_FOREACH(dcl, &ds->listeners, next) {
1028                 if (dcl->con != NULL) {
1029                     continue;
1030                 }
1031                 if (dcl->ops->dpy_gfx_switch) {
1032                     dcl->ops->dpy_gfx_switch(dcl, s->surface);
1033                 }
1034             }
1035             dpy_gfx_update(s, 0, 0, surface_width(s->surface),
1036                            surface_height(s->surface));
1037         }
1038         if (ds->have_text) {
1039             dpy_text_resize(s, s->width, s->height);
1040         }
1041         text_console_update_cursor(NULL);
1042     }
1043 }
1044
1045 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1046 {
1047     QemuConsole *s = chr->opaque;
1048     int i;
1049
1050     s->update_x0 = s->width * FONT_WIDTH;
1051     s->update_y0 = s->height * FONT_HEIGHT;
1052     s->update_x1 = 0;
1053     s->update_y1 = 0;
1054     console_show_cursor(s, 0);
1055     for(i = 0; i < len; i++) {
1056         console_putchar(s, buf[i]);
1057     }
1058     console_show_cursor(s, 1);
1059     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1060         dpy_gfx_update(s, s->update_x0, s->update_y0,
1061                        s->update_x1 - s->update_x0,
1062                        s->update_y1 - s->update_y0);
1063     }
1064     return len;
1065 }
1066
1067 static void kbd_send_chars(void *opaque)
1068 {
1069     QemuConsole *s = opaque;
1070     int len;
1071     uint8_t buf[16];
1072
1073     len = qemu_chr_be_can_write(s->chr);
1074     if (len > s->out_fifo.count)
1075         len = s->out_fifo.count;
1076     if (len > 0) {
1077         if (len > sizeof(buf))
1078             len = sizeof(buf);
1079         qemu_fifo_read(&s->out_fifo, buf, len);
1080         qemu_chr_be_write(s->chr, buf, len);
1081     }
1082     /* characters are pending: we send them a bit later (XXX:
1083        horrible, should change char device API) */
1084     if (s->out_fifo.count > 0) {
1085         timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
1086     }
1087 }
1088
1089 /* called when an ascii key is pressed */
1090 void kbd_put_keysym_console(QemuConsole *s, int keysym)
1091 {
1092     uint8_t buf[16], *q;
1093     CharBackend *be;
1094     int c;
1095
1096     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1097         return;
1098
1099     switch(keysym) {
1100     case QEMU_KEY_CTRL_UP:
1101         console_scroll(s, -1);
1102         break;
1103     case QEMU_KEY_CTRL_DOWN:
1104         console_scroll(s, 1);
1105         break;
1106     case QEMU_KEY_CTRL_PAGEUP:
1107         console_scroll(s, -10);
1108         break;
1109     case QEMU_KEY_CTRL_PAGEDOWN:
1110         console_scroll(s, 10);
1111         break;
1112     default:
1113         /* convert the QEMU keysym to VT100 key string */
1114         q = buf;
1115         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1116             *q++ = '\033';
1117             *q++ = '[';
1118             c = keysym - 0xe100;
1119             if (c >= 10)
1120                 *q++ = '0' + (c / 10);
1121             *q++ = '0' + (c % 10);
1122             *q++ = '~';
1123         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1124             *q++ = '\033';
1125             *q++ = '[';
1126             *q++ = keysym & 0xff;
1127         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1128             console_puts(s->chr, (const uint8_t *) "\r", 1);
1129             *q++ = '\n';
1130         } else {
1131             *q++ = keysym;
1132         }
1133         if (s->echo) {
1134             console_puts(s->chr, buf, q - buf);
1135         }
1136         be = s->chr->be;
1137         if (be && be->chr_read) {
1138             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1139             kbd_send_chars(s);
1140         }
1141         break;
1142     }
1143 }
1144
1145 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
1146     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
1147     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
1148     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
1149     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
1150     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
1151     [Q_KEY_CODE_END]    = QEMU_KEY_END,
1152     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
1153     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
1154     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
1155     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
1156 };
1157
1158 bool kbd_put_qcode_console(QemuConsole *s, int qcode)
1159 {
1160     int keysym;
1161
1162     keysym = qcode_to_keysym[qcode];
1163     if (keysym == 0) {
1164         return false;
1165     }
1166     kbd_put_keysym_console(s, keysym);
1167     return true;
1168 }
1169
1170 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1171 {
1172     int i;
1173
1174     for (i = 0; i < len && str[i]; i++) {
1175         kbd_put_keysym_console(s, str[i]);
1176     }
1177 }
1178
1179 void kbd_put_keysym(int keysym)
1180 {
1181     kbd_put_keysym_console(active_console, keysym);
1182 }
1183
1184 static void text_console_invalidate(void *opaque)
1185 {
1186     QemuConsole *s = (QemuConsole *) opaque;
1187
1188     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1189         text_console_resize(s);
1190     }
1191     console_refresh(s);
1192 }
1193
1194 static void text_console_update(void *opaque, console_ch_t *chardata)
1195 {
1196     QemuConsole *s = (QemuConsole *) opaque;
1197     int i, j, src;
1198
1199     if (s->text_x[0] <= s->text_x[1]) {
1200         src = (s->y_base + s->text_y[0]) * s->width;
1201         chardata += s->text_y[0] * s->width;
1202         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1203             for (j = 0; j < s->width; j++, src++) {
1204                 console_write_ch(chardata ++,
1205                                  ATTR2CHTYPE(s->cells[src].ch,
1206                                              s->cells[src].t_attrib.fgcol,
1207                                              s->cells[src].t_attrib.bgcol,
1208                                              s->cells[src].t_attrib.bold));
1209             }
1210         dpy_text_update(s, s->text_x[0], s->text_y[0],
1211                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1212         s->text_x[0] = s->width;
1213         s->text_y[0] = s->height;
1214         s->text_x[1] = 0;
1215         s->text_y[1] = 0;
1216     }
1217     if (s->cursor_invalidate) {
1218         dpy_text_cursor(s, s->x, s->y);
1219         s->cursor_invalidate = 0;
1220     }
1221 }
1222
1223 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1224                                 uint32_t head)
1225 {
1226     Object *obj;
1227     QemuConsole *s;
1228     int i;
1229
1230     obj = object_new(TYPE_QEMU_CONSOLE);
1231     s = QEMU_CONSOLE(obj);
1232     s->head = head;
1233     object_property_add_link(obj, "device", TYPE_DEVICE,
1234                              (Object **)&s->device,
1235                              object_property_allow_set_link,
1236                              OBJ_PROP_LINK_UNREF_ON_RELEASE,
1237                              &error_abort);
1238     object_property_add_uint32_ptr(obj, "head",
1239                                    &s->head, &error_abort);
1240
1241     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1242         (console_type == GRAPHIC_CONSOLE))) {
1243         active_console = s;
1244     }
1245     s->ds = ds;
1246     s->console_type = console_type;
1247
1248     consoles = g_realloc(consoles, sizeof(*consoles) * (nb_consoles+1));
1249     if (console_type != GRAPHIC_CONSOLE) {
1250         s->index = nb_consoles;
1251         consoles[nb_consoles++] = s;
1252     } else {
1253         /* HACK: Put graphical consoles before text consoles.  */
1254         for (i = nb_consoles; i > 0; i--) {
1255             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1256                 break;
1257             consoles[i] = consoles[i - 1];
1258             consoles[i]->index = i;
1259         }
1260         s->index = i;
1261         consoles[i] = s;
1262         nb_consoles++;
1263     }
1264     return s;
1265 }
1266
1267 static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
1268 {
1269     qemu_pixman_image_unref(surface->image);
1270     surface->image = NULL;
1271
1272     surface->format = PIXMAN_x8r8g8b8;
1273     surface->image = pixman_image_create_bits(surface->format,
1274                                               width, height,
1275                                               NULL, width * 4);
1276     assert(surface->image != NULL);
1277
1278     surface->flags = QEMU_ALLOCATED_FLAG;
1279 }
1280
1281 DisplaySurface *qemu_create_displaysurface(int width, int height)
1282 {
1283     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1284
1285     trace_displaysurface_create(surface, width, height);
1286     qemu_alloc_display(surface, width, height);
1287     return surface;
1288 }
1289
1290 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1291                                                 pixman_format_code_t format,
1292                                                 int linesize, uint8_t *data)
1293 {
1294     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1295
1296     trace_displaysurface_create_from(surface, width, height, format);
1297     surface->format = format;
1298     surface->image = pixman_image_create_bits(surface->format,
1299                                               width, height,
1300                                               (void *)data, linesize);
1301     assert(surface->image != NULL);
1302
1303     return surface;
1304 }
1305
1306 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1307 {
1308     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1309
1310     trace_displaysurface_create_pixman(surface);
1311     surface->format = pixman_image_get_format(image);
1312     surface->image = pixman_image_ref(image);
1313
1314     return surface;
1315 }
1316
1317 static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
1318                                                void *unused)
1319 {
1320     void *data = pixman_image_get_data(image);
1321     uint32_t size = pixman_image_get_stride(image) *
1322         pixman_image_get_height(image);
1323     cpu_physical_memory_unmap(data, size, 0, 0);
1324 }
1325
1326 DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
1327                                                     pixman_format_code_t format,
1328                                                     int linesize, uint64_t addr)
1329 {
1330     DisplaySurface *surface;
1331     hwaddr size;
1332     void *data;
1333
1334     if (linesize == 0) {
1335         linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
1336     }
1337
1338     size = (hwaddr)linesize * height;
1339     data = cpu_physical_memory_map(addr, &size, 0);
1340     if (size != (hwaddr)linesize * height) {
1341         cpu_physical_memory_unmap(data, size, 0, 0);
1342         return NULL;
1343     }
1344
1345     surface = qemu_create_displaysurface_from
1346         (width, height, format, linesize, data);
1347     pixman_image_set_destroy_function
1348         (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
1349
1350     return surface;
1351 }
1352
1353 static DisplaySurface *qemu_create_message_surface(int w, int h,
1354                                                    const char *msg)
1355 {
1356     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1357     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1358     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1359     pixman_image_t *glyph;
1360     int len, x, y, i;
1361
1362     len = strlen(msg);
1363     x = (w / FONT_WIDTH  - len) / 2;
1364     y = (h / FONT_HEIGHT - 1)   / 2;
1365     for (i = 0; i < len; i++) {
1366         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1367         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1368                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1369         qemu_pixman_image_unref(glyph);
1370     }
1371     return surface;
1372 }
1373
1374 void qemu_free_displaysurface(DisplaySurface *surface)
1375 {
1376     if (surface == NULL) {
1377         return;
1378     }
1379     trace_displaysurface_free(surface);
1380     qemu_pixman_image_unref(surface->image);
1381     g_free(surface);
1382 }
1383
1384 bool console_has_gl(QemuConsole *con)
1385 {
1386     return con->gl != NULL;
1387 }
1388
1389 void register_displaychangelistener(DisplayChangeListener *dcl)
1390 {
1391     static const char nodev[] =
1392         "This VM has no graphic display device.";
1393     static DisplaySurface *dummy;
1394     QemuConsole *con;
1395
1396     if (dcl->ops->dpy_gl_ctx_create) {
1397         /* display has opengl support */
1398         assert(dcl->con);
1399         if (dcl->con->gl) {
1400             fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1401                     dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1402             exit(1);
1403         }
1404         dcl->con->gl = dcl;
1405     }
1406
1407     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1408     dcl->ds = get_alloc_displaystate();
1409     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1410     gui_setup_refresh(dcl->ds);
1411     if (dcl->con) {
1412         dcl->con->dcls++;
1413         con = dcl->con;
1414     } else {
1415         con = active_console;
1416     }
1417     if (dcl->ops->dpy_gfx_switch) {
1418         if (con) {
1419             dcl->ops->dpy_gfx_switch(dcl, con->surface);
1420         } else {
1421             if (!dummy) {
1422                 dummy = qemu_create_message_surface(640, 480, nodev);
1423             }
1424             dcl->ops->dpy_gfx_switch(dcl, dummy);
1425         }
1426     }
1427     text_console_update_cursor(NULL);
1428 }
1429
1430 void update_displaychangelistener(DisplayChangeListener *dcl,
1431                                   uint64_t interval)
1432 {
1433     DisplayState *ds = dcl->ds;
1434
1435     dcl->update_interval = interval;
1436     if (!ds->refreshing && ds->update_interval > interval) {
1437         timer_mod(ds->gui_timer, ds->last_update + interval);
1438     }
1439 }
1440
1441 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1442 {
1443     DisplayState *ds = dcl->ds;
1444     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1445     if (dcl->con) {
1446         dcl->con->dcls--;
1447     }
1448     QLIST_REMOVE(dcl, next);
1449     gui_setup_refresh(ds);
1450 }
1451
1452 static void dpy_set_ui_info_timer(void *opaque)
1453 {
1454     QemuConsole *con = opaque;
1455
1456     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1457 }
1458
1459 bool dpy_ui_info_supported(QemuConsole *con)
1460 {
1461     return con->hw_ops->ui_info != NULL;
1462 }
1463
1464 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1465 {
1466     assert(con != NULL);
1467
1468     if (!dpy_ui_info_supported(con)) {
1469         return -1;
1470     }
1471     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1472         /* nothing changed -- ignore */
1473         return 0;
1474     }
1475
1476     /*
1477      * Typically we get a flood of these as the user resizes the window.
1478      * Wait until the dust has settled (one second without updates), then
1479      * go notify the guest.
1480      */
1481     con->ui_info = *info;
1482     timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1483     return 0;
1484 }
1485
1486 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1487 {
1488     DisplayState *s = con->ds;
1489     DisplayChangeListener *dcl;
1490     int width = w;
1491     int height = h;
1492
1493     if (con->surface) {
1494         width = surface_width(con->surface);
1495         height = surface_height(con->surface);
1496     }
1497     x = MAX(x, 0);
1498     y = MAX(y, 0);
1499     x = MIN(x, width);
1500     y = MIN(y, height);
1501     w = MIN(w, width - x);
1502     h = MIN(h, height - y);
1503
1504     if (!qemu_console_is_visible(con)) {
1505         return;
1506     }
1507     QLIST_FOREACH(dcl, &s->listeners, next) {
1508         if (con != (dcl->con ? dcl->con : active_console)) {
1509             continue;
1510         }
1511         if (dcl->ops->dpy_gfx_update) {
1512             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1513         }
1514     }
1515 }
1516
1517 void dpy_gfx_replace_surface(QemuConsole *con,
1518                              DisplaySurface *surface)
1519 {
1520     DisplayState *s = con->ds;
1521     DisplaySurface *old_surface = con->surface;
1522     DisplayChangeListener *dcl;
1523
1524     con->surface = surface;
1525     QLIST_FOREACH(dcl, &s->listeners, next) {
1526         if (con != (dcl->con ? dcl->con : active_console)) {
1527             continue;
1528         }
1529         if (dcl->ops->dpy_gfx_switch) {
1530             dcl->ops->dpy_gfx_switch(dcl, surface);
1531         }
1532     }
1533     qemu_free_displaysurface(old_surface);
1534 }
1535
1536 bool dpy_gfx_check_format(QemuConsole *con,
1537                           pixman_format_code_t format)
1538 {
1539     DisplayChangeListener *dcl;
1540     DisplayState *s = con->ds;
1541
1542     QLIST_FOREACH(dcl, &s->listeners, next) {
1543         if (dcl->con && dcl->con != con) {
1544             /* dcl bound to another console -> skip */
1545             continue;
1546         }
1547         if (dcl->ops->dpy_gfx_check_format) {
1548             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1549                 return false;
1550             }
1551         } else {
1552             /* default is to whitelist native 32 bpp only */
1553             if (format != qemu_default_pixman_format(32, true)) {
1554                 return false;
1555             }
1556         }
1557     }
1558     return true;
1559 }
1560
1561 static void dpy_refresh(DisplayState *s)
1562 {
1563     DisplayChangeListener *dcl;
1564
1565     QLIST_FOREACH(dcl, &s->listeners, next) {
1566         if (dcl->ops->dpy_refresh) {
1567             dcl->ops->dpy_refresh(dcl);
1568         }
1569     }
1570 }
1571
1572 void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1573                   int dst_x, int dst_y, int w, int h)
1574 {
1575     DisplayState *s = con->ds;
1576     DisplayChangeListener *dcl;
1577
1578     if (!qemu_console_is_visible(con)) {
1579         return;
1580     }
1581     QLIST_FOREACH(dcl, &s->listeners, next) {
1582         if (con != (dcl->con ? dcl->con : active_console)) {
1583             continue;
1584         }
1585         if (dcl->ops->dpy_gfx_copy) {
1586             dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
1587         } else { /* TODO */
1588             dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
1589         }
1590     }
1591 }
1592
1593 void dpy_text_cursor(QemuConsole *con, int x, int y)
1594 {
1595     DisplayState *s = con->ds;
1596     DisplayChangeListener *dcl;
1597
1598     if (!qemu_console_is_visible(con)) {
1599         return;
1600     }
1601     QLIST_FOREACH(dcl, &s->listeners, next) {
1602         if (con != (dcl->con ? dcl->con : active_console)) {
1603             continue;
1604         }
1605         if (dcl->ops->dpy_text_cursor) {
1606             dcl->ops->dpy_text_cursor(dcl, x, y);
1607         }
1608     }
1609 }
1610
1611 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1612 {
1613     DisplayState *s = con->ds;
1614     DisplayChangeListener *dcl;
1615
1616     if (!qemu_console_is_visible(con)) {
1617         return;
1618     }
1619     QLIST_FOREACH(dcl, &s->listeners, next) {
1620         if (con != (dcl->con ? dcl->con : active_console)) {
1621             continue;
1622         }
1623         if (dcl->ops->dpy_text_update) {
1624             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1625         }
1626     }
1627 }
1628
1629 void dpy_text_resize(QemuConsole *con, int w, int h)
1630 {
1631     DisplayState *s = con->ds;
1632     DisplayChangeListener *dcl;
1633
1634     if (!qemu_console_is_visible(con)) {
1635         return;
1636     }
1637     QLIST_FOREACH(dcl, &s->listeners, next) {
1638         if (con != (dcl->con ? dcl->con : active_console)) {
1639             continue;
1640         }
1641         if (dcl->ops->dpy_text_resize) {
1642             dcl->ops->dpy_text_resize(dcl, w, h);
1643         }
1644     }
1645 }
1646
1647 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1648 {
1649     DisplayState *s = con->ds;
1650     DisplayChangeListener *dcl;
1651
1652     if (!qemu_console_is_visible(con)) {
1653         return;
1654     }
1655     QLIST_FOREACH(dcl, &s->listeners, next) {
1656         if (con != (dcl->con ? dcl->con : active_console)) {
1657             continue;
1658         }
1659         if (dcl->ops->dpy_mouse_set) {
1660             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1661         }
1662     }
1663 }
1664
1665 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1666 {
1667     DisplayState *s = con->ds;
1668     DisplayChangeListener *dcl;
1669
1670     if (!qemu_console_is_visible(con)) {
1671         return;
1672     }
1673     QLIST_FOREACH(dcl, &s->listeners, next) {
1674         if (con != (dcl->con ? dcl->con : active_console)) {
1675             continue;
1676         }
1677         if (dcl->ops->dpy_cursor_define) {
1678             dcl->ops->dpy_cursor_define(dcl, cursor);
1679         }
1680     }
1681 }
1682
1683 bool dpy_cursor_define_supported(QemuConsole *con)
1684 {
1685     DisplayState *s = con->ds;
1686     DisplayChangeListener *dcl;
1687
1688     QLIST_FOREACH(dcl, &s->listeners, next) {
1689         if (dcl->ops->dpy_cursor_define) {
1690             return true;
1691         }
1692     }
1693     return false;
1694 }
1695
1696 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1697                                 struct QEMUGLParams *qparams)
1698 {
1699     assert(con->gl);
1700     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1701 }
1702
1703 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1704 {
1705     assert(con->gl);
1706     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1707 }
1708
1709 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1710 {
1711     assert(con->gl);
1712     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1713 }
1714
1715 QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
1716 {
1717     assert(con->gl);
1718     return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
1719 }
1720
1721 void dpy_gl_scanout(QemuConsole *con,
1722                     uint32_t backing_id, bool backing_y_0_top,
1723                     uint32_t backing_width, uint32_t backing_height,
1724                     uint32_t x, uint32_t y, uint32_t width, uint32_t height)
1725 {
1726     assert(con->gl);
1727     con->gl->ops->dpy_gl_scanout(con->gl, backing_id,
1728                                  backing_y_0_top,
1729                                  backing_width, backing_height,
1730                                  x, y, width, height);
1731 }
1732
1733 void dpy_gl_update(QemuConsole *con,
1734                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1735 {
1736     assert(con->gl);
1737     con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1738 }
1739
1740 /***********************************************************/
1741 /* register display */
1742
1743 /* console.c internal use only */
1744 static DisplayState *get_alloc_displaystate(void)
1745 {
1746     if (!display_state) {
1747         display_state = g_new0(DisplayState, 1);
1748         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1749                                     text_console_update_cursor, NULL);
1750     }
1751     return display_state;
1752 }
1753
1754 /*
1755  * Called by main(), after creating QemuConsoles
1756  * and before initializing ui (sdl/vnc/...).
1757  */
1758 DisplayState *init_displaystate(void)
1759 {
1760     gchar *name;
1761     int i;
1762
1763     get_alloc_displaystate();
1764     for (i = 0; i < nb_consoles; i++) {
1765         if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
1766             consoles[i]->ds == NULL) {
1767             text_console_do_init(consoles[i]->chr, display_state);
1768         }
1769
1770         /* Hook up into the qom tree here (not in new_console()), once
1771          * all QemuConsoles are created and the order / numbering
1772          * doesn't change any more */
1773         name = g_strdup_printf("console[%d]", i);
1774         object_property_add_child(container_get(object_get_root(), "/backend"),
1775                                   name, OBJECT(consoles[i]), &error_abort);
1776         g_free(name);
1777     }
1778
1779     return display_state;
1780 }
1781
1782 void graphic_console_set_hwops(QemuConsole *con,
1783                                const GraphicHwOps *hw_ops,
1784                                void *opaque)
1785 {
1786     con->hw_ops = hw_ops;
1787     con->hw = opaque;
1788 }
1789
1790 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1791                                   const GraphicHwOps *hw_ops,
1792                                   void *opaque)
1793 {
1794     static const char noinit[] =
1795         "Guest has not initialized the display (yet).";
1796     int width = 640;
1797     int height = 480;
1798 #ifdef CONFIG_MARU
1799     if (initial_resolution_width > 0 &&
1800             initial_resolution_height > 0) {
1801         width = initial_resolution_width;
1802         height = initial_resolution_height;
1803     }
1804 #endif
1805     QemuConsole *s;
1806     DisplayState *ds;
1807
1808     ds = get_alloc_displaystate();
1809     trace_console_gfx_new();
1810     s = new_console(ds, GRAPHIC_CONSOLE, head);
1811     s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s);
1812     graphic_console_set_hwops(s, hw_ops, opaque);
1813     if (dev) {
1814         object_property_set_link(OBJECT(s), OBJECT(dev), "device",
1815                                  &error_abort);
1816     }
1817
1818     s->surface = qemu_create_message_surface(width, height, noinit);
1819     return s;
1820 }
1821
1822 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1823 {
1824     if (index >= nb_consoles) {
1825         return NULL;
1826     }
1827     return consoles[index];
1828 }
1829
1830 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1831 {
1832     Object *obj;
1833     uint32_t h;
1834     int i;
1835
1836     for (i = 0; i < nb_consoles; i++) {
1837         if (!consoles[i]) {
1838             continue;
1839         }
1840         obj = object_property_get_link(OBJECT(consoles[i]),
1841                                        "device", &error_abort);
1842         if (DEVICE(obj) != dev) {
1843             continue;
1844         }
1845         h = object_property_get_int(OBJECT(consoles[i]),
1846                                     "head", &error_abort);
1847         if (h != head) {
1848             continue;
1849         }
1850         return consoles[i];
1851     }
1852     return NULL;
1853 }
1854
1855 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
1856                                                 uint32_t head, Error **errp)
1857 {
1858     DeviceState *dev;
1859     QemuConsole *con;
1860
1861     dev = qdev_find_recursive(sysbus_get_default(), device_id);
1862     if (dev == NULL) {
1863         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
1864                   "Device '%s' not found", device_id);
1865         return NULL;
1866     }
1867
1868     con = qemu_console_lookup_by_device(dev, head);
1869     if (con == NULL) {
1870         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
1871                    device_id, head);
1872         return NULL;
1873     }
1874
1875     return con;
1876 }
1877
1878 bool qemu_console_is_visible(QemuConsole *con)
1879 {
1880     return (con == active_console) || (con->dcls > 0);
1881 }
1882
1883 bool qemu_console_is_graphic(QemuConsole *con)
1884 {
1885     if (con == NULL) {
1886         con = active_console;
1887     }
1888     return con && (con->console_type == GRAPHIC_CONSOLE);
1889 }
1890
1891 bool qemu_console_is_fixedsize(QemuConsole *con)
1892 {
1893     if (con == NULL) {
1894         con = active_console;
1895     }
1896     return con && (con->console_type != TEXT_CONSOLE);
1897 }
1898
1899 bool qemu_console_is_gl_blocked(QemuConsole *con)
1900 {
1901     assert(con != NULL);
1902     return con->gl_block;
1903 }
1904
1905 char *qemu_console_get_label(QemuConsole *con)
1906 {
1907     if (con->console_type == GRAPHIC_CONSOLE) {
1908         if (con->device) {
1909             return g_strdup(object_get_typename(con->device));
1910         }
1911         return g_strdup("VGA");
1912     } else {
1913         if (con->chr && con->chr->label) {
1914             return g_strdup(con->chr->label);
1915         }
1916         return g_strdup_printf("vc%d", con->index);
1917     }
1918 }
1919
1920 int qemu_console_get_index(QemuConsole *con)
1921 {
1922     if (con == NULL) {
1923         con = active_console;
1924     }
1925     return con ? con->index : -1;
1926 }
1927
1928 uint32_t qemu_console_get_head(QemuConsole *con)
1929 {
1930     if (con == NULL) {
1931         con = active_console;
1932     }
1933     return con ? con->head : -1;
1934 }
1935
1936 QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
1937 {
1938     assert(con != NULL);
1939     return &con->ui_info;
1940 }
1941
1942 int qemu_console_get_width(QemuConsole *con, int fallback)
1943 {
1944     if (con == NULL) {
1945         con = active_console;
1946     }
1947     return con ? surface_width(con->surface) : fallback;
1948 }
1949
1950 int qemu_console_get_height(QemuConsole *con, int fallback)
1951 {
1952     if (con == NULL) {
1953         con = active_console;
1954     }
1955     return con ? surface_height(con->surface) : fallback;
1956 }
1957
1958 static void text_console_set_echo(CharDriverState *chr, bool echo)
1959 {
1960     QemuConsole *s = chr->opaque;
1961
1962     s->echo = echo;
1963 }
1964
1965 static void text_console_update_cursor_timer(void)
1966 {
1967     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
1968               + CONSOLE_CURSOR_PERIOD / 2);
1969 }
1970
1971 static void text_console_update_cursor(void *opaque)
1972 {
1973     QemuConsole *s;
1974     int i, count = 0;
1975
1976     cursor_visible_phase = !cursor_visible_phase;
1977
1978     for (i = 0; i < nb_consoles; i++) {
1979         s = consoles[i];
1980         if (qemu_console_is_graphic(s) ||
1981             !qemu_console_is_visible(s)) {
1982             continue;
1983         }
1984         count++;
1985         graphic_hw_invalidate(s);
1986     }
1987
1988     if (count) {
1989         text_console_update_cursor_timer();
1990     }
1991 }
1992
1993 static const GraphicHwOps text_console_ops = {
1994     .invalidate  = text_console_invalidate,
1995     .text_update = text_console_update,
1996 };
1997
1998 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1999 {
2000     QemuConsole *s;
2001     int g_width = 80 * FONT_WIDTH;
2002     int g_height = 24 * FONT_HEIGHT;
2003
2004     s = chr->opaque;
2005
2006     chr->chr_write = console_puts;
2007
2008     s->out_fifo.buf = s->out_fifo_buf;
2009     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
2010     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
2011     s->ds = ds;
2012
2013     s->y_displayed = 0;
2014     s->y_base = 0;
2015     s->total_height = DEFAULT_BACKSCROLL;
2016     s->x = 0;
2017     s->y = 0;
2018     if (!s->surface) {
2019         if (active_console && active_console->surface) {
2020             g_width = surface_width(active_console->surface);
2021             g_height = surface_height(active_console->surface);
2022         }
2023         s->surface = qemu_create_displaysurface(g_width, g_height);
2024     }
2025
2026     s->hw_ops = &text_console_ops;
2027     s->hw = s;
2028
2029     /* Set text attribute defaults */
2030     s->t_attrib_default.bold = 0;
2031     s->t_attrib_default.uline = 0;
2032     s->t_attrib_default.blink = 0;
2033     s->t_attrib_default.invers = 0;
2034     s->t_attrib_default.unvisible = 0;
2035     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2036     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2037     /* set current text attributes to default */
2038     s->t_attrib = s->t_attrib_default;
2039     text_console_resize(s);
2040
2041     if (chr->label) {
2042         char msg[128];
2043         int len;
2044
2045         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2046         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
2047         console_puts(chr, (uint8_t*)msg, len);
2048         s->t_attrib = s->t_attrib_default;
2049     }
2050
2051     qemu_chr_be_generic_open(chr);
2052 }
2053
2054 static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
2055 {
2056     ChardevCommon *common = qapi_ChardevVC_base(vc);
2057     CharDriverState *chr;
2058     QemuConsole *s;
2059     unsigned width = 0;
2060     unsigned height = 0;
2061
2062     chr = qemu_chr_alloc(common, errp);
2063     if (!chr) {
2064         return NULL;
2065     }
2066
2067     if (vc->has_width) {
2068         width = vc->width;
2069     } else if (vc->has_cols) {
2070         width = vc->cols * FONT_WIDTH;
2071     }
2072
2073     if (vc->has_height) {
2074         height = vc->height;
2075     } else if (vc->has_rows) {
2076         height = vc->rows * FONT_HEIGHT;
2077     }
2078
2079     trace_console_txt_new(width, height);
2080     if (width == 0 || height == 0) {
2081         s = new_console(NULL, TEXT_CONSOLE, 0);
2082     } else {
2083         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2084         s->surface = qemu_create_displaysurface(width, height);
2085     }
2086
2087     if (!s) {
2088         g_free(chr);
2089         error_setg(errp, "cannot create text console");
2090         return NULL;
2091     }
2092
2093     s->chr = chr;
2094     chr->opaque = s;
2095     chr->chr_set_echo = text_console_set_echo;
2096
2097     if (display_state) {
2098         text_console_do_init(chr, display_state);
2099     }
2100     return chr;
2101 }
2102
2103 static VcHandler *vc_handler = text_console_init;
2104
2105 static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
2106                                 ChardevReturn *ret, bool *be_opened,
2107                                 Error **errp)
2108 {
2109     /* console/chardev init sometimes completes elsewhere in a 2nd
2110      * stage, so defer OPENED events until they are fully initialized
2111      */
2112     *be_opened = false;
2113     return vc_handler(backend->u.vc.data, errp);
2114 }
2115
2116 void register_vc_handler(VcHandler *handler)
2117 {
2118     vc_handler = handler;
2119 }
2120
2121 void qemu_console_resize(QemuConsole *s, int width, int height)
2122 {
2123     DisplaySurface *surface;
2124
2125     assert(s->console_type == GRAPHIC_CONSOLE);
2126
2127     if (s->surface &&
2128         pixman_image_get_width(s->surface->image) == width &&
2129         pixman_image_get_height(s->surface->image) == height) {
2130         return;
2131     }
2132
2133     surface = qemu_create_displaysurface(width, height);
2134     dpy_gfx_replace_surface(s, surface);
2135 }
2136
2137 void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
2138                        int dst_x, int dst_y, int w, int h)
2139 {
2140     assert(con->console_type == GRAPHIC_CONSOLE);
2141     dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
2142 }
2143
2144 DisplaySurface *qemu_console_surface(QemuConsole *console)
2145 {
2146     return console->surface;
2147 }
2148
2149 PixelFormat qemu_default_pixelformat(int bpp)
2150 {
2151     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2152     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2153     return pf;
2154 }
2155
2156 static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
2157                               Error **errp)
2158 {
2159     int val;
2160     ChardevVC *vc;
2161
2162     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2163     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2164
2165     val = qemu_opt_get_number(opts, "width", 0);
2166     if (val != 0) {
2167         vc->has_width = true;
2168         vc->width = val;
2169     }
2170
2171     val = qemu_opt_get_number(opts, "height", 0);
2172     if (val != 0) {
2173         vc->has_height = true;
2174         vc->height = val;
2175     }
2176
2177     val = qemu_opt_get_number(opts, "cols", 0);
2178     if (val != 0) {
2179         vc->has_cols = true;
2180         vc->cols = val;
2181     }
2182
2183     val = qemu_opt_get_number(opts, "rows", 0);
2184     if (val != 0) {
2185         vc->has_rows = true;
2186         vc->rows = val;
2187     }
2188 }
2189
2190 static const TypeInfo qemu_console_info = {
2191     .name = TYPE_QEMU_CONSOLE,
2192     .parent = TYPE_OBJECT,
2193     .instance_size = sizeof(QemuConsole),
2194     .class_size = sizeof(QemuConsoleClass),
2195 };
2196
2197
2198 static void register_types(void)
2199 {
2200     type_register_static(&qemu_console_info);
2201     register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc,
2202                          vc_init);
2203 }
2204
2205 type_init(register_types);