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