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