]> Git Repo - qemu.git/blob - console.c
target-sparc: Fall through from not-taken trap
[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 /* ??? This is mis-named.
118    It is used for both text and graphical consoles.  */
119 struct TextConsole {
120     int index;
121     console_type_t console_type;
122     DisplayState *ds;
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
130     int g_width, g_height;
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 TextConsole *active_console;
165 static TextConsole *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     TextConsole *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(TextConsole *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(TextConsole *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(TextConsole *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(TextConsole *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(TextConsole *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(TextConsole *s)
635 {
636     TextCell *c;
637     int x, y, y1;
638
639     if (s != active_console)
640         return;
641     if (!ds_get_bits_per_pixel(s->ds)) {
642         s->text_x[0] = 0;
643         s->text_y[0] = 0;
644         s->text_x[1] = s->width - 1;
645         s->text_y[1] = s->height - 1;
646         s->cursor_invalidate = 1;
647         return;
648     }
649
650     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
651                   color_table[0][COLOR_BLACK]);
652     y1 = s->y_displayed;
653     for(y = 0; y < s->height; y++) {
654         c = s->cells + y1 * s->width;
655         for(x = 0; x < s->width; x++) {
656             vga_putcharxy(s->ds, x, y, c->ch,
657                           &(c->t_attrib));
658             c++;
659         }
660         if (++y1 == s->total_height)
661             y1 = 0;
662     }
663     console_show_cursor(s, 1);
664     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
665 }
666
667 static void console_scroll(int ydelta)
668 {
669     TextConsole *s;
670     int i, y1;
671
672     s = active_console;
673     if (!s || (s->console_type == GRAPHIC_CONSOLE))
674         return;
675
676     if (ydelta > 0) {
677         for(i = 0; i < ydelta; i++) {
678             if (s->y_displayed == s->y_base)
679                 break;
680             if (++s->y_displayed == s->total_height)
681                 s->y_displayed = 0;
682         }
683     } else {
684         ydelta = -ydelta;
685         i = s->backscroll_height;
686         if (i > s->total_height - s->height)
687             i = s->total_height - s->height;
688         y1 = s->y_base - i;
689         if (y1 < 0)
690             y1 += s->total_height;
691         for(i = 0; i < ydelta; i++) {
692             if (s->y_displayed == y1)
693                 break;
694             if (--s->y_displayed < 0)
695                 s->y_displayed = s->total_height - 1;
696         }
697     }
698     console_refresh(s);
699 }
700
701 static void console_put_lf(TextConsole *s)
702 {
703     TextCell *c;
704     int x, y1;
705
706     s->y++;
707     if (s->y >= s->height) {
708         s->y = s->height - 1;
709
710         if (s->y_displayed == s->y_base) {
711             if (++s->y_displayed == s->total_height)
712                 s->y_displayed = 0;
713         }
714         if (++s->y_base == s->total_height)
715             s->y_base = 0;
716         if (s->backscroll_height < s->total_height)
717             s->backscroll_height++;
718         y1 = (s->y_base + s->height - 1) % s->total_height;
719         c = &s->cells[y1 * s->width];
720         for(x = 0; x < s->width; x++) {
721             c->ch = ' ';
722             c->t_attrib = s->t_attrib_default;
723             c++;
724         }
725         if (s == active_console && s->y_displayed == s->y_base) {
726             if (!ds_get_bits_per_pixel(s->ds)) {
727                 s->text_x[0] = 0;
728                 s->text_y[0] = 0;
729                 s->text_x[1] = s->width - 1;
730                 s->text_y[1] = s->height - 1;
731                 return;
732             }
733
734             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
735                        s->width * FONT_WIDTH,
736                        (s->height - 1) * FONT_HEIGHT);
737             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
738                           s->width * FONT_WIDTH, FONT_HEIGHT,
739                           color_table[0][s->t_attrib_default.bgcol]);
740             s->update_x0 = 0;
741             s->update_y0 = 0;
742             s->update_x1 = s->width * FONT_WIDTH;
743             s->update_y1 = s->height * FONT_HEIGHT;
744         }
745     }
746 }
747
748 /* Set console attributes depending on the current escape codes.
749  * NOTE: I know this code is not very efficient (checking every color for it
750  * self) but it is more readable and better maintainable.
751  */
752 static void console_handle_escape(TextConsole *s)
753 {
754     int i;
755
756     for (i=0; i<s->nb_esc_params; i++) {
757         switch (s->esc_params[i]) {
758             case 0: /* reset all console attributes to default */
759                 s->t_attrib = s->t_attrib_default;
760                 break;
761             case 1:
762                 s->t_attrib.bold = 1;
763                 break;
764             case 4:
765                 s->t_attrib.uline = 1;
766                 break;
767             case 5:
768                 s->t_attrib.blink = 1;
769                 break;
770             case 7:
771                 s->t_attrib.invers = 1;
772                 break;
773             case 8:
774                 s->t_attrib.unvisible = 1;
775                 break;
776             case 22:
777                 s->t_attrib.bold = 0;
778                 break;
779             case 24:
780                 s->t_attrib.uline = 0;
781                 break;
782             case 25:
783                 s->t_attrib.blink = 0;
784                 break;
785             case 27:
786                 s->t_attrib.invers = 0;
787                 break;
788             case 28:
789                 s->t_attrib.unvisible = 0;
790                 break;
791             /* set foreground color */
792             case 30:
793                 s->t_attrib.fgcol=COLOR_BLACK;
794                 break;
795             case 31:
796                 s->t_attrib.fgcol=COLOR_RED;
797                 break;
798             case 32:
799                 s->t_attrib.fgcol=COLOR_GREEN;
800                 break;
801             case 33:
802                 s->t_attrib.fgcol=COLOR_YELLOW;
803                 break;
804             case 34:
805                 s->t_attrib.fgcol=COLOR_BLUE;
806                 break;
807             case 35:
808                 s->t_attrib.fgcol=COLOR_MAGENTA;
809                 break;
810             case 36:
811                 s->t_attrib.fgcol=COLOR_CYAN;
812                 break;
813             case 37:
814                 s->t_attrib.fgcol=COLOR_WHITE;
815                 break;
816             /* set background color */
817             case 40:
818                 s->t_attrib.bgcol=COLOR_BLACK;
819                 break;
820             case 41:
821                 s->t_attrib.bgcol=COLOR_RED;
822                 break;
823             case 42:
824                 s->t_attrib.bgcol=COLOR_GREEN;
825                 break;
826             case 43:
827                 s->t_attrib.bgcol=COLOR_YELLOW;
828                 break;
829             case 44:
830                 s->t_attrib.bgcol=COLOR_BLUE;
831                 break;
832             case 45:
833                 s->t_attrib.bgcol=COLOR_MAGENTA;
834                 break;
835             case 46:
836                 s->t_attrib.bgcol=COLOR_CYAN;
837                 break;
838             case 47:
839                 s->t_attrib.bgcol=COLOR_WHITE;
840                 break;
841         }
842     }
843 }
844
845 static void console_clear_xy(TextConsole *s, int x, int y)
846 {
847     int y1 = (s->y_base + y) % s->total_height;
848     TextCell *c = &s->cells[y1 * s->width + x];
849     c->ch = ' ';
850     c->t_attrib = s->t_attrib_default;
851     update_xy(s, x, y);
852 }
853
854 /* set cursor, checking bounds */
855 static void set_cursor(TextConsole *s, int x, int y)
856 {
857     if (x < 0) {
858         x = 0;
859     }
860     if (y < 0) {
861         y = 0;
862     }
863     if (y >= s->height) {
864         y = s->height - 1;
865     }
866     if (x >= s->width) {
867         x = s->width - 1;
868     }
869
870     s->x = x;
871     s->y = y;
872 }
873
874 static void console_putchar(TextConsole *s, int ch)
875 {
876     TextCell *c;
877     int y1, i;
878     int x, y;
879
880     switch(s->state) {
881     case TTY_STATE_NORM:
882         switch(ch) {
883         case '\r':  /* carriage return */
884             s->x = 0;
885             break;
886         case '\n':  /* newline */
887             console_put_lf(s);
888             break;
889         case '\b':  /* backspace */
890             if (s->x > 0)
891                 s->x--;
892             break;
893         case '\t':  /* tabspace */
894             if (s->x + (8 - (s->x % 8)) > s->width) {
895                 s->x = 0;
896                 console_put_lf(s);
897             } else {
898                 s->x = s->x + (8 - (s->x % 8));
899             }
900             break;
901         case '\a':  /* alert aka. bell */
902             /* TODO: has to be implemented */
903             break;
904         case 14:
905             /* SI (shift in), character set 0 (ignored) */
906             break;
907         case 15:
908             /* SO (shift out), character set 1 (ignored) */
909             break;
910         case 27:    /* esc (introducing an escape sequence) */
911             s->state = TTY_STATE_ESC;
912             break;
913         default:
914             if (s->x >= s->width) {
915                 /* line wrap */
916                 s->x = 0;
917                 console_put_lf(s);
918             }
919             y1 = (s->y_base + s->y) % s->total_height;
920             c = &s->cells[y1 * s->width + s->x];
921             c->ch = ch;
922             c->t_attrib = s->t_attrib;
923             update_xy(s, s->x, s->y);
924             s->x++;
925             break;
926         }
927         break;
928     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
929         if (ch == '[') {
930             for(i=0;i<MAX_ESC_PARAMS;i++)
931                 s->esc_params[i] = 0;
932             s->nb_esc_params = 0;
933             s->state = TTY_STATE_CSI;
934         } else {
935             s->state = TTY_STATE_NORM;
936         }
937         break;
938     case TTY_STATE_CSI: /* handle escape sequence parameters */
939         if (ch >= '0' && ch <= '9') {
940             if (s->nb_esc_params < MAX_ESC_PARAMS) {
941                 int *param = &s->esc_params[s->nb_esc_params];
942                 int digit = (ch - '0');
943
944                 *param = (*param <= (INT_MAX - digit) / 10) ?
945                          *param * 10 + digit : INT_MAX;
946             }
947         } else {
948             if (s->nb_esc_params < MAX_ESC_PARAMS)
949                 s->nb_esc_params++;
950             if (ch == ';')
951                 break;
952 #ifdef DEBUG_CONSOLE
953             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
954                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
955 #endif
956             s->state = TTY_STATE_NORM;
957             switch(ch) {
958             case 'A':
959                 /* move cursor up */
960                 if (s->esc_params[0] == 0) {
961                     s->esc_params[0] = 1;
962                 }
963                 set_cursor(s, s->x, s->y - s->esc_params[0]);
964                 break;
965             case 'B':
966                 /* move cursor down */
967                 if (s->esc_params[0] == 0) {
968                     s->esc_params[0] = 1;
969                 }
970                 set_cursor(s, s->x, s->y + s->esc_params[0]);
971                 break;
972             case 'C':
973                 /* move cursor right */
974                 if (s->esc_params[0] == 0) {
975                     s->esc_params[0] = 1;
976                 }
977                 set_cursor(s, s->x + s->esc_params[0], s->y);
978                 break;
979             case 'D':
980                 /* move cursor left */
981                 if (s->esc_params[0] == 0) {
982                     s->esc_params[0] = 1;
983                 }
984                 set_cursor(s, s->x - s->esc_params[0], s->y);
985                 break;
986             case 'G':
987                 /* move cursor to column */
988                 set_cursor(s, s->esc_params[0] - 1, s->y);
989                 break;
990             case 'f':
991             case 'H':
992                 /* move cursor to row, column */
993                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
994                 break;
995             case 'J':
996                 switch (s->esc_params[0]) {
997                 case 0:
998                     /* clear to end of screen */
999                     for (y = s->y; y < s->height; y++) {
1000                         for (x = 0; x < s->width; x++) {
1001                             if (y == s->y && x < s->x) {
1002                                 continue;
1003                             }
1004                             console_clear_xy(s, x, y);
1005                         }
1006                     }
1007                     break;
1008                 case 1:
1009                     /* clear from beginning of screen */
1010                     for (y = 0; y <= s->y; y++) {
1011                         for (x = 0; x < s->width; x++) {
1012                             if (y == s->y && x > s->x) {
1013                                 break;
1014                             }
1015                             console_clear_xy(s, x, y);
1016                         }
1017                     }
1018                     break;
1019                 case 2:
1020                     /* clear entire screen */
1021                     for (y = 0; y <= s->height; y++) {
1022                         for (x = 0; x < s->width; x++) {
1023                             console_clear_xy(s, x, y);
1024                         }
1025                     }
1026                     break;
1027                 }
1028                 break;
1029             case 'K':
1030                 switch (s->esc_params[0]) {
1031                 case 0:
1032                     /* clear to eol */
1033                     for(x = s->x; x < s->width; x++) {
1034                         console_clear_xy(s, x, s->y);
1035                     }
1036                     break;
1037                 case 1:
1038                     /* clear from beginning of line */
1039                     for (x = 0; x <= s->x; x++) {
1040                         console_clear_xy(s, x, s->y);
1041                     }
1042                     break;
1043                 case 2:
1044                     /* clear entire line */
1045                     for(x = 0; x < s->width; x++) {
1046                         console_clear_xy(s, x, s->y);
1047                     }
1048                     break;
1049                 }
1050                 break;
1051             case 'm':
1052                 console_handle_escape(s);
1053                 break;
1054             case 'n':
1055                 /* report cursor position */
1056                 /* TODO: send ESC[row;colR */
1057                 break;
1058             case 's':
1059                 /* save cursor position */
1060                 s->x_saved = s->x;
1061                 s->y_saved = s->y;
1062                 break;
1063             case 'u':
1064                 /* restore cursor position */
1065                 s->x = s->x_saved;
1066                 s->y = s->y_saved;
1067                 break;
1068             default:
1069 #ifdef DEBUG_CONSOLE
1070                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1071 #endif
1072                 break;
1073             }
1074             break;
1075         }
1076     }
1077 }
1078
1079 void console_select(unsigned int index)
1080 {
1081     TextConsole *s;
1082
1083     if (index >= MAX_CONSOLES)
1084         return;
1085     if (active_console) {
1086         active_console->g_width = ds_get_width(active_console->ds);
1087         active_console->g_height = ds_get_height(active_console->ds);
1088     }
1089     s = consoles[index];
1090     if (s) {
1091         DisplayState *ds = s->ds;
1092
1093         if (active_console && active_console->cursor_timer) {
1094             qemu_del_timer(active_console->cursor_timer);
1095         }
1096         active_console = s;
1097         if (ds_get_bits_per_pixel(s->ds)) {
1098             ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1099         } else {
1100             s->ds->surface->width = s->width;
1101             s->ds->surface->height = s->height;
1102         }
1103         if (s->cursor_timer) {
1104             qemu_mod_timer(s->cursor_timer,
1105                    qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1106         }
1107         dpy_resize(s->ds);
1108         vga_hw_invalidate();
1109     }
1110 }
1111
1112 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1113 {
1114     TextConsole *s = chr->opaque;
1115     int i;
1116
1117     s->update_x0 = s->width * FONT_WIDTH;
1118     s->update_y0 = s->height * FONT_HEIGHT;
1119     s->update_x1 = 0;
1120     s->update_y1 = 0;
1121     console_show_cursor(s, 0);
1122     for(i = 0; i < len; i++) {
1123         console_putchar(s, buf[i]);
1124     }
1125     console_show_cursor(s, 1);
1126     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1127         dpy_update(s->ds, s->update_x0, s->update_y0,
1128                    s->update_x1 - s->update_x0,
1129                    s->update_y1 - s->update_y0);
1130     }
1131     return len;
1132 }
1133
1134 static void kbd_send_chars(void *opaque)
1135 {
1136     TextConsole *s = opaque;
1137     int len;
1138     uint8_t buf[16];
1139
1140     len = qemu_chr_be_can_write(s->chr);
1141     if (len > s->out_fifo.count)
1142         len = s->out_fifo.count;
1143     if (len > 0) {
1144         if (len > sizeof(buf))
1145             len = sizeof(buf);
1146         qemu_fifo_read(&s->out_fifo, buf, len);
1147         qemu_chr_be_write(s->chr, buf, len);
1148     }
1149     /* characters are pending: we send them a bit later (XXX:
1150        horrible, should change char device API) */
1151     if (s->out_fifo.count > 0) {
1152         qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1153     }
1154 }
1155
1156 /* called when an ascii key is pressed */
1157 void kbd_put_keysym(int keysym)
1158 {
1159     TextConsole *s;
1160     uint8_t buf[16], *q;
1161     int c;
1162
1163     s = active_console;
1164     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1165         return;
1166
1167     switch(keysym) {
1168     case QEMU_KEY_CTRL_UP:
1169         console_scroll(-1);
1170         break;
1171     case QEMU_KEY_CTRL_DOWN:
1172         console_scroll(1);
1173         break;
1174     case QEMU_KEY_CTRL_PAGEUP:
1175         console_scroll(-10);
1176         break;
1177     case QEMU_KEY_CTRL_PAGEDOWN:
1178         console_scroll(10);
1179         break;
1180     default:
1181         /* convert the QEMU keysym to VT100 key string */
1182         q = buf;
1183         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1184             *q++ = '\033';
1185             *q++ = '[';
1186             c = keysym - 0xe100;
1187             if (c >= 10)
1188                 *q++ = '0' + (c / 10);
1189             *q++ = '0' + (c % 10);
1190             *q++ = '~';
1191         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1192             *q++ = '\033';
1193             *q++ = '[';
1194             *q++ = keysym & 0xff;
1195         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1196             console_puts(s->chr, (const uint8_t *) "\r", 1);
1197             *q++ = '\n';
1198         } else {
1199             *q++ = keysym;
1200         }
1201         if (s->echo) {
1202             console_puts(s->chr, buf, q - buf);
1203         }
1204         if (s->chr->chr_read) {
1205             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1206             kbd_send_chars(s);
1207         }
1208         break;
1209     }
1210 }
1211
1212 static void text_console_invalidate(void *opaque)
1213 {
1214     TextConsole *s = (TextConsole *) opaque;
1215     if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1216         s->g_width = ds_get_width(s->ds);
1217         s->g_height = ds_get_height(s->ds);
1218         text_console_resize(s);
1219     }
1220     console_refresh(s);
1221 }
1222
1223 static void text_console_update(void *opaque, console_ch_t *chardata)
1224 {
1225     TextConsole *s = (TextConsole *) opaque;
1226     int i, j, src;
1227
1228     if (s->text_x[0] <= s->text_x[1]) {
1229         src = (s->y_base + s->text_y[0]) * s->width;
1230         chardata += s->text_y[0] * s->width;
1231         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1232             for (j = 0; j < s->width; j ++, src ++)
1233                 console_write_ch(chardata ++, s->cells[src].ch |
1234                                 (s->cells[src].t_attrib.fgcol << 12) |
1235                                 (s->cells[src].t_attrib.bgcol << 8) |
1236                                 (s->cells[src].t_attrib.bold << 21));
1237         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1238                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1239         s->text_x[0] = s->width;
1240         s->text_y[0] = s->height;
1241         s->text_x[1] = 0;
1242         s->text_y[1] = 0;
1243     }
1244     if (s->cursor_invalidate) {
1245         dpy_cursor(s->ds, s->x, s->y);
1246         s->cursor_invalidate = 0;
1247     }
1248 }
1249
1250 static TextConsole *get_graphic_console(DisplayState *ds)
1251 {
1252     int i;
1253     TextConsole *s;
1254     for (i = 0; i < nb_consoles; i++) {
1255         s = consoles[i];
1256         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1257             return s;
1258     }
1259     return NULL;
1260 }
1261
1262 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1263 {
1264     TextConsole *s;
1265     int i;
1266
1267     if (nb_consoles >= MAX_CONSOLES)
1268         return NULL;
1269     s = g_malloc0(sizeof(TextConsole));
1270     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1271         (console_type == GRAPHIC_CONSOLE))) {
1272         active_console = s;
1273     }
1274     s->ds = ds;
1275     s->console_type = console_type;
1276     if (console_type != GRAPHIC_CONSOLE) {
1277         s->index = nb_consoles;
1278         consoles[nb_consoles++] = s;
1279     } else {
1280         /* HACK: Put graphical consoles before text consoles.  */
1281         for (i = nb_consoles; i > 0; i--) {
1282             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1283                 break;
1284             consoles[i] = consoles[i - 1];
1285             consoles[i]->index = i;
1286         }
1287         s->index = i;
1288         consoles[i] = s;
1289         nb_consoles++;
1290     }
1291     return s;
1292 }
1293
1294 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1295 {
1296     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1297
1298     int linesize = width * 4;
1299     qemu_alloc_display(surface, width, height, linesize,
1300                        qemu_default_pixelformat(32), 0);
1301     return surface;
1302 }
1303
1304 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1305                                           int width, int height)
1306 {
1307     int linesize = width * 4;
1308     qemu_alloc_display(surface, width, height, linesize,
1309                        qemu_default_pixelformat(32), 0);
1310     return surface;
1311 }
1312
1313 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1314                         int linesize, PixelFormat pf, int newflags)
1315 {
1316     void *data;
1317     surface->width = width;
1318     surface->height = height;
1319     surface->linesize = linesize;
1320     surface->pf = pf;
1321     if (surface->flags & QEMU_ALLOCATED_FLAG) {
1322         data = g_realloc(surface->data,
1323                             surface->linesize * surface->height);
1324     } else {
1325         data = g_malloc(surface->linesize * surface->height);
1326     }
1327     surface->data = (uint8_t *)data;
1328     surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1329 #ifdef HOST_WORDS_BIGENDIAN
1330     surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1331 #endif
1332 }
1333
1334 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1335                                               int linesize, uint8_t *data)
1336 {
1337     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1338
1339     surface->width = width;
1340     surface->height = height;
1341     surface->linesize = linesize;
1342     surface->pf = qemu_default_pixelformat(bpp);
1343 #ifdef HOST_WORDS_BIGENDIAN
1344     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1345 #endif
1346     surface->data = data;
1347
1348     return surface;
1349 }
1350
1351 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1352 {
1353     if (surface == NULL)
1354         return;
1355     if (surface->flags & QEMU_ALLOCATED_FLAG)
1356         g_free(surface->data);
1357     g_free(surface);
1358 }
1359
1360 static struct DisplayAllocator default_allocator = {
1361     defaultallocator_create_displaysurface,
1362     defaultallocator_resize_displaysurface,
1363     defaultallocator_free_displaysurface
1364 };
1365
1366 static void dumb_display_init(void)
1367 {
1368     DisplayState *ds = g_malloc0(sizeof(DisplayState));
1369     int width = 640;
1370     int height = 480;
1371
1372     ds->allocator = &default_allocator;
1373     if (is_fixedsize_console()) {
1374         width = active_console->g_width;
1375         height = active_console->g_height;
1376     }
1377     ds->surface = qemu_create_displaysurface(ds, width, height);
1378     register_displaystate(ds);
1379 }
1380
1381 /***********************************************************/
1382 /* register display */
1383
1384 void register_displaystate(DisplayState *ds)
1385 {
1386     DisplayState **s;
1387     s = &display_state;
1388     while (*s != NULL)
1389         s = &(*s)->next;
1390     ds->next = NULL;
1391     *s = ds;
1392 }
1393
1394 DisplayState *get_displaystate(void)
1395 {
1396     if (!display_state) {
1397         dumb_display_init ();
1398     }
1399     return display_state;
1400 }
1401
1402 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1403 {
1404     if(ds->allocator ==  &default_allocator) {
1405         DisplaySurface *surf;
1406         surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1407         defaultallocator_free_displaysurface(ds->surface);
1408         ds->surface = surf;
1409         ds->allocator = da;
1410     }
1411     return ds->allocator;
1412 }
1413
1414 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1415                                    vga_hw_invalidate_ptr invalidate,
1416                                    vga_hw_screen_dump_ptr screen_dump,
1417                                    vga_hw_text_update_ptr text_update,
1418                                    void *opaque)
1419 {
1420     TextConsole *s;
1421     DisplayState *ds;
1422
1423     ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1424     ds->allocator = &default_allocator; 
1425     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1426
1427     s = new_console(ds, GRAPHIC_CONSOLE);
1428     if (s == NULL) {
1429         qemu_free_displaysurface(ds);
1430         g_free(ds);
1431         return NULL;
1432     }
1433     s->hw_update = update;
1434     s->hw_invalidate = invalidate;
1435     s->hw_screen_dump = screen_dump;
1436     s->hw_text_update = text_update;
1437     s->hw = opaque;
1438
1439     register_displaystate(ds);
1440     return ds;
1441 }
1442
1443 int is_graphic_console(void)
1444 {
1445     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1446 }
1447
1448 int is_fixedsize_console(void)
1449 {
1450     return active_console && active_console->console_type != TEXT_CONSOLE;
1451 }
1452
1453 void console_color_init(DisplayState *ds)
1454 {
1455     int i, j;
1456     for (j = 0; j < 2; j++) {
1457         for (i = 0; i < 8; i++) {
1458             color_table[j][i] = col_expand(ds,
1459                    vga_get_color(ds, color_table_rgb[j][i]));
1460         }
1461     }
1462 }
1463
1464 static void text_console_set_echo(CharDriverState *chr, bool echo)
1465 {
1466     TextConsole *s = chr->opaque;
1467
1468     s->echo = echo;
1469 }
1470
1471 static void text_console_update_cursor(void *opaque)
1472 {
1473     TextConsole *s = opaque;
1474
1475     s->cursor_visible_phase = !s->cursor_visible_phase;
1476     vga_hw_invalidate();
1477     qemu_mod_timer(s->cursor_timer,
1478                    qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1479 }
1480
1481 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1482 {
1483     TextConsole *s;
1484     static int color_inited;
1485
1486     s = chr->opaque;
1487
1488     chr->chr_write = console_puts;
1489
1490     s->out_fifo.buf = s->out_fifo_buf;
1491     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1492     s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1493     s->ds = ds;
1494
1495     if (!color_inited) {
1496         color_inited = 1;
1497         console_color_init(s->ds);
1498     }
1499     s->y_displayed = 0;
1500     s->y_base = 0;
1501     s->total_height = DEFAULT_BACKSCROLL;
1502     s->x = 0;
1503     s->y = 0;
1504     if (s->console_type == TEXT_CONSOLE) {
1505         s->g_width = ds_get_width(s->ds);
1506         s->g_height = ds_get_height(s->ds);
1507     }
1508
1509     s->cursor_timer =
1510         qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1511
1512     s->hw_invalidate = text_console_invalidate;
1513     s->hw_text_update = text_console_update;
1514     s->hw = s;
1515
1516     /* Set text attribute defaults */
1517     s->t_attrib_default.bold = 0;
1518     s->t_attrib_default.uline = 0;
1519     s->t_attrib_default.blink = 0;
1520     s->t_attrib_default.invers = 0;
1521     s->t_attrib_default.unvisible = 0;
1522     s->t_attrib_default.fgcol = COLOR_WHITE;
1523     s->t_attrib_default.bgcol = COLOR_BLACK;
1524     /* set current text attributes to default */
1525     s->t_attrib = s->t_attrib_default;
1526     text_console_resize(s);
1527
1528     if (chr->label) {
1529         char msg[128];
1530         int len;
1531
1532         s->t_attrib.bgcol = COLOR_BLUE;
1533         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1534         console_puts(chr, (uint8_t*)msg, len);
1535         s->t_attrib = s->t_attrib_default;
1536     }
1537
1538     qemu_chr_generic_open(chr);
1539     if (chr->init)
1540         chr->init(chr);
1541 }
1542
1543 CharDriverState *text_console_init(QemuOpts *opts)
1544 {
1545     CharDriverState *chr;
1546     TextConsole *s;
1547     unsigned width;
1548     unsigned height;
1549
1550     chr = g_malloc0(sizeof(CharDriverState));
1551
1552     width = qemu_opt_get_number(opts, "width", 0);
1553     if (width == 0)
1554         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1555
1556     height = qemu_opt_get_number(opts, "height", 0);
1557     if (height == 0)
1558         height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1559
1560     if (width == 0 || height == 0) {
1561         s = new_console(NULL, TEXT_CONSOLE);
1562     } else {
1563         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1564     }
1565
1566     if (!s) {
1567         g_free(chr);
1568         return NULL;
1569     }
1570
1571     s->chr = chr;
1572     s->g_width = width;
1573     s->g_height = height;
1574     chr->opaque = s;
1575     chr->chr_set_echo = text_console_set_echo;
1576     return chr;
1577 }
1578
1579 void text_consoles_set_display(DisplayState *ds)
1580 {
1581     int i;
1582
1583     for (i = 0; i < nb_consoles; i++) {
1584         if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1585             text_console_do_init(consoles[i]->chr, ds);
1586         }
1587     }
1588 }
1589
1590 void qemu_console_resize(DisplayState *ds, int width, int height)
1591 {
1592     TextConsole *s = get_graphic_console(ds);
1593     if (!s) return;
1594
1595     s->g_width = width;
1596     s->g_height = height;
1597     if (is_graphic_console()) {
1598         ds->surface = qemu_resize_displaysurface(ds, width, height);
1599         dpy_resize(ds);
1600     }
1601 }
1602
1603 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1604                        int dst_x, int dst_y, int w, int h)
1605 {
1606     if (is_graphic_console()) {
1607         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1608     }
1609 }
1610
1611 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1612 {
1613     PixelFormat pf;
1614
1615     memset(&pf, 0x00, sizeof(PixelFormat));
1616
1617     pf.bits_per_pixel = bpp;
1618     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1619     pf.depth = bpp == 32 ? 24 : bpp;
1620
1621     switch (bpp) {
1622         case 24:
1623             pf.rmask = 0x000000FF;
1624             pf.gmask = 0x0000FF00;
1625             pf.bmask = 0x00FF0000;
1626             pf.rmax = 255;
1627             pf.gmax = 255;
1628             pf.bmax = 255;
1629             pf.rshift = 0;
1630             pf.gshift = 8;
1631             pf.bshift = 16;
1632             pf.rbits = 8;
1633             pf.gbits = 8;
1634             pf.bbits = 8;
1635             break;
1636         case 32:
1637             pf.rmask = 0x0000FF00;
1638             pf.gmask = 0x00FF0000;
1639             pf.bmask = 0xFF000000;
1640             pf.amask = 0x00000000;
1641             pf.amax = 255;
1642             pf.rmax = 255;
1643             pf.gmax = 255;
1644             pf.bmax = 255;
1645             pf.ashift = 0;
1646             pf.rshift = 8;
1647             pf.gshift = 16;
1648             pf.bshift = 24;
1649             pf.rbits = 8;
1650             pf.gbits = 8;
1651             pf.bbits = 8;
1652             pf.abits = 8;
1653             break;
1654         default:
1655             break;
1656     }
1657     return pf;
1658 }
1659
1660 PixelFormat qemu_default_pixelformat(int bpp)
1661 {
1662     PixelFormat pf;
1663
1664     memset(&pf, 0x00, sizeof(PixelFormat));
1665
1666     pf.bits_per_pixel = bpp;
1667     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1668     pf.depth = bpp == 32 ? 24 : bpp;
1669
1670     switch (bpp) {
1671         case 15:
1672             pf.bits_per_pixel = 16;
1673             pf.rmask = 0x00007c00;
1674             pf.gmask = 0x000003E0;
1675             pf.bmask = 0x0000001F;
1676             pf.rmax = 31;
1677             pf.gmax = 31;
1678             pf.bmax = 31;
1679             pf.rshift = 10;
1680             pf.gshift = 5;
1681             pf.bshift = 0;
1682             pf.rbits = 5;
1683             pf.gbits = 5;
1684             pf.bbits = 5;
1685             break;
1686         case 16:
1687             pf.rmask = 0x0000F800;
1688             pf.gmask = 0x000007E0;
1689             pf.bmask = 0x0000001F;
1690             pf.rmax = 31;
1691             pf.gmax = 63;
1692             pf.bmax = 31;
1693             pf.rshift = 11;
1694             pf.gshift = 5;
1695             pf.bshift = 0;
1696             pf.rbits = 5;
1697             pf.gbits = 6;
1698             pf.bbits = 5;
1699             break;
1700         case 24:
1701             pf.rmask = 0x00FF0000;
1702             pf.gmask = 0x0000FF00;
1703             pf.bmask = 0x000000FF;
1704             pf.rmax = 255;
1705             pf.gmax = 255;
1706             pf.bmax = 255;
1707             pf.rshift = 16;
1708             pf.gshift = 8;
1709             pf.bshift = 0;
1710             pf.rbits = 8;
1711             pf.gbits = 8;
1712             pf.bbits = 8;
1713             break;
1714         case 32:
1715             pf.rmask = 0x00FF0000;
1716             pf.gmask = 0x0000FF00;
1717             pf.bmask = 0x000000FF;
1718             pf.amax = 255;
1719             pf.rmax = 255;
1720             pf.gmax = 255;
1721             pf.bmax = 255;
1722             pf.ashift = 24;
1723             pf.rshift = 16;
1724             pf.gshift = 8;
1725             pf.bshift = 0;
1726             pf.rbits = 8;
1727             pf.gbits = 8;
1728             pf.bbits = 8;
1729             pf.abits = 8;
1730             break;
1731         default:
1732             break;
1733     }
1734     return pf;
1735 }
This page took 0.113646 seconds and 4 git commands to generate.