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