]> Git Repo - qemu.git/blob - console.c
Merge remote-tracking branch 'kwolf/for-anthony' into staging
[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                 s->esc_params[s->nb_esc_params] =
942                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
943             }
944         } else {
945             if (s->nb_esc_params < MAX_ESC_PARAMS)
946                 s->nb_esc_params++;
947             if (ch == ';')
948                 break;
949 #ifdef DEBUG_CONSOLE
950             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
951                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
952 #endif
953             s->state = TTY_STATE_NORM;
954             switch(ch) {
955             case 'A':
956                 /* move cursor up */
957                 if (s->esc_params[0] == 0) {
958                     s->esc_params[0] = 1;
959                 }
960                 set_cursor(s, s->x, s->y - s->esc_params[0]);
961                 break;
962             case 'B':
963                 /* move cursor down */
964                 if (s->esc_params[0] == 0) {
965                     s->esc_params[0] = 1;
966                 }
967                 set_cursor(s, s->x, s->y + s->esc_params[0]);
968                 break;
969             case 'C':
970                 /* move cursor right */
971                 if (s->esc_params[0] == 0) {
972                     s->esc_params[0] = 1;
973                 }
974                 set_cursor(s, s->x + s->esc_params[0], s->y);
975                 break;
976             case 'D':
977                 /* move cursor left */
978                 if (s->esc_params[0] == 0) {
979                     s->esc_params[0] = 1;
980                 }
981                 set_cursor(s, s->x - s->esc_params[0], s->y);
982                 break;
983             case 'G':
984                 /* move cursor to column */
985                 set_cursor(s, s->esc_params[0] - 1, s->y);
986                 break;
987             case 'f':
988             case 'H':
989                 /* move cursor to row, column */
990                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
991                 break;
992             case 'J':
993                 switch (s->esc_params[0]) {
994                 case 0:
995                     /* clear to end of screen */
996                     for (y = s->y; y < s->height; y++) {
997                         for (x = 0; x < s->width; x++) {
998                             if (y == s->y && x < s->x) {
999                                 continue;
1000                             }
1001                             console_clear_xy(s, x, y);
1002                         }
1003                     }
1004                     break;
1005                 case 1:
1006                     /* clear from beginning of screen */
1007                     for (y = 0; y <= s->y; y++) {
1008                         for (x = 0; x < s->width; x++) {
1009                             if (y == s->y && x > s->x) {
1010                                 break;
1011                             }
1012                             console_clear_xy(s, x, y);
1013                         }
1014                     }
1015                     break;
1016                 case 2:
1017                     /* clear entire screen */
1018                     for (y = 0; y <= s->height; y++) {
1019                         for (x = 0; x < s->width; x++) {
1020                             console_clear_xy(s, x, y);
1021                         }
1022                     }
1023                     break;
1024                 }
1025                 break;
1026             case 'K':
1027                 switch (s->esc_params[0]) {
1028                 case 0:
1029                     /* clear to eol */
1030                     for(x = s->x; x < s->width; x++) {
1031                         console_clear_xy(s, x, s->y);
1032                     }
1033                     break;
1034                 case 1:
1035                     /* clear from beginning of line */
1036                     for (x = 0; x <= s->x; x++) {
1037                         console_clear_xy(s, x, s->y);
1038                     }
1039                     break;
1040                 case 2:
1041                     /* clear entire line */
1042                     for(x = 0; x < s->width; x++) {
1043                         console_clear_xy(s, x, s->y);
1044                     }
1045                     break;
1046                 }
1047                 break;
1048             case 'm':
1049                 console_handle_escape(s);
1050                 break;
1051             case 'n':
1052                 /* report cursor position */
1053                 /* TODO: send ESC[row;colR */
1054                 break;
1055             case 's':
1056                 /* save cursor position */
1057                 s->x_saved = s->x;
1058                 s->y_saved = s->y;
1059                 break;
1060             case 'u':
1061                 /* restore cursor position */
1062                 s->x = s->x_saved;
1063                 s->y = s->y_saved;
1064                 break;
1065             default:
1066 #ifdef DEBUG_CONSOLE
1067                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1068 #endif
1069                 break;
1070             }
1071             break;
1072         }
1073     }
1074 }
1075
1076 void console_select(unsigned int index)
1077 {
1078     TextConsole *s;
1079
1080     if (index >= MAX_CONSOLES)
1081         return;
1082     if (active_console) {
1083         active_console->g_width = ds_get_width(active_console->ds);
1084         active_console->g_height = ds_get_height(active_console->ds);
1085     }
1086     s = consoles[index];
1087     if (s) {
1088         DisplayState *ds = s->ds;
1089
1090         if (active_console && active_console->cursor_timer) {
1091             qemu_del_timer(active_console->cursor_timer);
1092         }
1093         active_console = s;
1094         if (ds_get_bits_per_pixel(s->ds)) {
1095             ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1096         } else {
1097             s->ds->surface->width = s->width;
1098             s->ds->surface->height = s->height;
1099         }
1100         if (s->cursor_timer) {
1101             qemu_mod_timer(s->cursor_timer,
1102                    qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1103         }
1104         dpy_resize(s->ds);
1105         vga_hw_invalidate();
1106     }
1107 }
1108
1109 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1110 {
1111     TextConsole *s = chr->opaque;
1112     int i;
1113
1114     s->update_x0 = s->width * FONT_WIDTH;
1115     s->update_y0 = s->height * FONT_HEIGHT;
1116     s->update_x1 = 0;
1117     s->update_y1 = 0;
1118     console_show_cursor(s, 0);
1119     for(i = 0; i < len; i++) {
1120         console_putchar(s, buf[i]);
1121     }
1122     console_show_cursor(s, 1);
1123     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1124         dpy_update(s->ds, s->update_x0, s->update_y0,
1125                    s->update_x1 - s->update_x0,
1126                    s->update_y1 - s->update_y0);
1127     }
1128     return len;
1129 }
1130
1131 static void kbd_send_chars(void *opaque)
1132 {
1133     TextConsole *s = opaque;
1134     int len;
1135     uint8_t buf[16];
1136
1137     len = qemu_chr_be_can_write(s->chr);
1138     if (len > s->out_fifo.count)
1139         len = s->out_fifo.count;
1140     if (len > 0) {
1141         if (len > sizeof(buf))
1142             len = sizeof(buf);
1143         qemu_fifo_read(&s->out_fifo, buf, len);
1144         qemu_chr_be_write(s->chr, buf, len);
1145     }
1146     /* characters are pending: we send them a bit later (XXX:
1147        horrible, should change char device API) */
1148     if (s->out_fifo.count > 0) {
1149         qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1150     }
1151 }
1152
1153 /* called when an ascii key is pressed */
1154 void kbd_put_keysym(int keysym)
1155 {
1156     TextConsole *s;
1157     uint8_t buf[16], *q;
1158     int c;
1159
1160     s = active_console;
1161     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1162         return;
1163
1164     switch(keysym) {
1165     case QEMU_KEY_CTRL_UP:
1166         console_scroll(-1);
1167         break;
1168     case QEMU_KEY_CTRL_DOWN:
1169         console_scroll(1);
1170         break;
1171     case QEMU_KEY_CTRL_PAGEUP:
1172         console_scroll(-10);
1173         break;
1174     case QEMU_KEY_CTRL_PAGEDOWN:
1175         console_scroll(10);
1176         break;
1177     default:
1178         /* convert the QEMU keysym to VT100 key string */
1179         q = buf;
1180         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1181             *q++ = '\033';
1182             *q++ = '[';
1183             c = keysym - 0xe100;
1184             if (c >= 10)
1185                 *q++ = '0' + (c / 10);
1186             *q++ = '0' + (c % 10);
1187             *q++ = '~';
1188         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1189             *q++ = '\033';
1190             *q++ = '[';
1191             *q++ = keysym & 0xff;
1192         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1193             console_puts(s->chr, (const uint8_t *) "\r", 1);
1194             *q++ = '\n';
1195         } else {
1196             *q++ = keysym;
1197         }
1198         if (s->echo) {
1199             console_puts(s->chr, buf, q - buf);
1200         }
1201         if (s->chr->chr_read) {
1202             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1203             kbd_send_chars(s);
1204         }
1205         break;
1206     }
1207 }
1208
1209 static void text_console_invalidate(void *opaque)
1210 {
1211     TextConsole *s = (TextConsole *) opaque;
1212     if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1213         s->g_width = ds_get_width(s->ds);
1214         s->g_height = ds_get_height(s->ds);
1215         text_console_resize(s);
1216     }
1217     console_refresh(s);
1218 }
1219
1220 static void text_console_update(void *opaque, console_ch_t *chardata)
1221 {
1222     TextConsole *s = (TextConsole *) opaque;
1223     int i, j, src;
1224
1225     if (s->text_x[0] <= s->text_x[1]) {
1226         src = (s->y_base + s->text_y[0]) * s->width;
1227         chardata += s->text_y[0] * s->width;
1228         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1229             for (j = 0; j < s->width; j ++, src ++)
1230                 console_write_ch(chardata ++, s->cells[src].ch |
1231                                 (s->cells[src].t_attrib.fgcol << 12) |
1232                                 (s->cells[src].t_attrib.bgcol << 8) |
1233                                 (s->cells[src].t_attrib.bold << 21));
1234         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1235                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1236         s->text_x[0] = s->width;
1237         s->text_y[0] = s->height;
1238         s->text_x[1] = 0;
1239         s->text_y[1] = 0;
1240     }
1241     if (s->cursor_invalidate) {
1242         dpy_cursor(s->ds, s->x, s->y);
1243         s->cursor_invalidate = 0;
1244     }
1245 }
1246
1247 static TextConsole *get_graphic_console(DisplayState *ds)
1248 {
1249     int i;
1250     TextConsole *s;
1251     for (i = 0; i < nb_consoles; i++) {
1252         s = consoles[i];
1253         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1254             return s;
1255     }
1256     return NULL;
1257 }
1258
1259 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1260 {
1261     TextConsole *s;
1262     int i;
1263
1264     if (nb_consoles >= MAX_CONSOLES)
1265         return NULL;
1266     s = g_malloc0(sizeof(TextConsole));
1267     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1268         (console_type == GRAPHIC_CONSOLE))) {
1269         active_console = s;
1270     }
1271     s->ds = ds;
1272     s->console_type = console_type;
1273     if (console_type != GRAPHIC_CONSOLE) {
1274         s->index = nb_consoles;
1275         consoles[nb_consoles++] = s;
1276     } else {
1277         /* HACK: Put graphical consoles before text consoles.  */
1278         for (i = nb_consoles; i > 0; i--) {
1279             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1280                 break;
1281             consoles[i] = consoles[i - 1];
1282             consoles[i]->index = i;
1283         }
1284         s->index = i;
1285         consoles[i] = s;
1286         nb_consoles++;
1287     }
1288     return s;
1289 }
1290
1291 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1292 {
1293     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1294
1295     int linesize = width * 4;
1296     qemu_alloc_display(surface, width, height, linesize,
1297                        qemu_default_pixelformat(32), 0);
1298     return surface;
1299 }
1300
1301 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1302                                           int width, int height)
1303 {
1304     int linesize = width * 4;
1305     qemu_alloc_display(surface, width, height, linesize,
1306                        qemu_default_pixelformat(32), 0);
1307     return surface;
1308 }
1309
1310 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1311                         int linesize, PixelFormat pf, int newflags)
1312 {
1313     void *data;
1314     surface->width = width;
1315     surface->height = height;
1316     surface->linesize = linesize;
1317     surface->pf = pf;
1318     if (surface->flags & QEMU_ALLOCATED_FLAG) {
1319         data = g_realloc(surface->data,
1320                             surface->linesize * surface->height);
1321     } else {
1322         data = g_malloc(surface->linesize * surface->height);
1323     }
1324     surface->data = (uint8_t *)data;
1325     surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1326 #ifdef HOST_WORDS_BIGENDIAN
1327     surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1328 #endif
1329 }
1330
1331 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1332                                               int linesize, uint8_t *data)
1333 {
1334     DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1335
1336     surface->width = width;
1337     surface->height = height;
1338     surface->linesize = linesize;
1339     surface->pf = qemu_default_pixelformat(bpp);
1340 #ifdef HOST_WORDS_BIGENDIAN
1341     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1342 #endif
1343     surface->data = data;
1344
1345     return surface;
1346 }
1347
1348 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1349 {
1350     if (surface == NULL)
1351         return;
1352     if (surface->flags & QEMU_ALLOCATED_FLAG)
1353         g_free(surface->data);
1354     g_free(surface);
1355 }
1356
1357 static struct DisplayAllocator default_allocator = {
1358     defaultallocator_create_displaysurface,
1359     defaultallocator_resize_displaysurface,
1360     defaultallocator_free_displaysurface
1361 };
1362
1363 static void dumb_display_init(void)
1364 {
1365     DisplayState *ds = g_malloc0(sizeof(DisplayState));
1366     int width = 640;
1367     int height = 480;
1368
1369     ds->allocator = &default_allocator;
1370     if (is_fixedsize_console()) {
1371         width = active_console->g_width;
1372         height = active_console->g_height;
1373     }
1374     ds->surface = qemu_create_displaysurface(ds, width, height);
1375     register_displaystate(ds);
1376 }
1377
1378 /***********************************************************/
1379 /* register display */
1380
1381 void register_displaystate(DisplayState *ds)
1382 {
1383     DisplayState **s;
1384     s = &display_state;
1385     while (*s != NULL)
1386         s = &(*s)->next;
1387     ds->next = NULL;
1388     *s = ds;
1389 }
1390
1391 DisplayState *get_displaystate(void)
1392 {
1393     if (!display_state) {
1394         dumb_display_init ();
1395     }
1396     return display_state;
1397 }
1398
1399 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1400 {
1401     if(ds->allocator ==  &default_allocator) {
1402         DisplaySurface *surf;
1403         surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1404         defaultallocator_free_displaysurface(ds->surface);
1405         ds->surface = surf;
1406         ds->allocator = da;
1407     }
1408     return ds->allocator;
1409 }
1410
1411 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1412                                    vga_hw_invalidate_ptr invalidate,
1413                                    vga_hw_screen_dump_ptr screen_dump,
1414                                    vga_hw_text_update_ptr text_update,
1415                                    void *opaque)
1416 {
1417     TextConsole *s;
1418     DisplayState *ds;
1419
1420     ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1421     ds->allocator = &default_allocator; 
1422     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1423
1424     s = new_console(ds, GRAPHIC_CONSOLE);
1425     if (s == NULL) {
1426         qemu_free_displaysurface(ds);
1427         g_free(ds);
1428         return NULL;
1429     }
1430     s->hw_update = update;
1431     s->hw_invalidate = invalidate;
1432     s->hw_screen_dump = screen_dump;
1433     s->hw_text_update = text_update;
1434     s->hw = opaque;
1435
1436     register_displaystate(ds);
1437     return ds;
1438 }
1439
1440 int is_graphic_console(void)
1441 {
1442     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1443 }
1444
1445 int is_fixedsize_console(void)
1446 {
1447     return active_console && active_console->console_type != TEXT_CONSOLE;
1448 }
1449
1450 void console_color_init(DisplayState *ds)
1451 {
1452     int i, j;
1453     for (j = 0; j < 2; j++) {
1454         for (i = 0; i < 8; i++) {
1455             color_table[j][i] = col_expand(ds,
1456                    vga_get_color(ds, color_table_rgb[j][i]));
1457         }
1458     }
1459 }
1460
1461 static void text_console_set_echo(CharDriverState *chr, bool echo)
1462 {
1463     TextConsole *s = chr->opaque;
1464
1465     s->echo = echo;
1466 }
1467
1468 static void text_console_update_cursor(void *opaque)
1469 {
1470     TextConsole *s = opaque;
1471
1472     s->cursor_visible_phase = !s->cursor_visible_phase;
1473     vga_hw_invalidate();
1474     qemu_mod_timer(s->cursor_timer,
1475                    qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1476 }
1477
1478 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1479 {
1480     TextConsole *s;
1481     static int color_inited;
1482
1483     s = chr->opaque;
1484
1485     chr->chr_write = console_puts;
1486
1487     s->out_fifo.buf = s->out_fifo_buf;
1488     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1489     s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1490     s->ds = ds;
1491
1492     if (!color_inited) {
1493         color_inited = 1;
1494         console_color_init(s->ds);
1495     }
1496     s->y_displayed = 0;
1497     s->y_base = 0;
1498     s->total_height = DEFAULT_BACKSCROLL;
1499     s->x = 0;
1500     s->y = 0;
1501     if (s->console_type == TEXT_CONSOLE) {
1502         s->g_width = ds_get_width(s->ds);
1503         s->g_height = ds_get_height(s->ds);
1504     }
1505
1506     s->cursor_timer =
1507         qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1508
1509     s->hw_invalidate = text_console_invalidate;
1510     s->hw_text_update = text_console_update;
1511     s->hw = s;
1512
1513     /* Set text attribute defaults */
1514     s->t_attrib_default.bold = 0;
1515     s->t_attrib_default.uline = 0;
1516     s->t_attrib_default.blink = 0;
1517     s->t_attrib_default.invers = 0;
1518     s->t_attrib_default.unvisible = 0;
1519     s->t_attrib_default.fgcol = COLOR_WHITE;
1520     s->t_attrib_default.bgcol = COLOR_BLACK;
1521     /* set current text attributes to default */
1522     s->t_attrib = s->t_attrib_default;
1523     text_console_resize(s);
1524
1525     if (chr->label) {
1526         char msg[128];
1527         int len;
1528
1529         s->t_attrib.bgcol = COLOR_BLUE;
1530         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1531         console_puts(chr, (uint8_t*)msg, len);
1532         s->t_attrib = s->t_attrib_default;
1533     }
1534
1535     qemu_chr_generic_open(chr);
1536     if (chr->init)
1537         chr->init(chr);
1538 }
1539
1540 CharDriverState *text_console_init(QemuOpts *opts)
1541 {
1542     CharDriverState *chr;
1543     TextConsole *s;
1544     unsigned width;
1545     unsigned height;
1546
1547     chr = g_malloc0(sizeof(CharDriverState));
1548
1549     width = qemu_opt_get_number(opts, "width", 0);
1550     if (width == 0)
1551         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1552
1553     height = qemu_opt_get_number(opts, "height", 0);
1554     if (height == 0)
1555         height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1556
1557     if (width == 0 || height == 0) {
1558         s = new_console(NULL, TEXT_CONSOLE);
1559     } else {
1560         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1561     }
1562
1563     if (!s) {
1564         g_free(chr);
1565         return NULL;
1566     }
1567
1568     s->chr = chr;
1569     s->g_width = width;
1570     s->g_height = height;
1571     chr->opaque = s;
1572     chr->chr_set_echo = text_console_set_echo;
1573     return chr;
1574 }
1575
1576 void text_consoles_set_display(DisplayState *ds)
1577 {
1578     int i;
1579
1580     for (i = 0; i < nb_consoles; i++) {
1581         if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1582             text_console_do_init(consoles[i]->chr, ds);
1583         }
1584     }
1585 }
1586
1587 void qemu_console_resize(DisplayState *ds, int width, int height)
1588 {
1589     TextConsole *s = get_graphic_console(ds);
1590     if (!s) return;
1591
1592     s->g_width = width;
1593     s->g_height = height;
1594     if (is_graphic_console()) {
1595         ds->surface = qemu_resize_displaysurface(ds, width, height);
1596         dpy_resize(ds);
1597     }
1598 }
1599
1600 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1601                        int dst_x, int dst_y, int w, int h)
1602 {
1603     if (is_graphic_console()) {
1604         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1605     }
1606 }
1607
1608 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1609 {
1610     PixelFormat pf;
1611
1612     memset(&pf, 0x00, sizeof(PixelFormat));
1613
1614     pf.bits_per_pixel = bpp;
1615     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1616     pf.depth = bpp == 32 ? 24 : bpp;
1617
1618     switch (bpp) {
1619         case 24:
1620             pf.rmask = 0x000000FF;
1621             pf.gmask = 0x0000FF00;
1622             pf.bmask = 0x00FF0000;
1623             pf.rmax = 255;
1624             pf.gmax = 255;
1625             pf.bmax = 255;
1626             pf.rshift = 0;
1627             pf.gshift = 8;
1628             pf.bshift = 16;
1629             pf.rbits = 8;
1630             pf.gbits = 8;
1631             pf.bbits = 8;
1632             break;
1633         case 32:
1634             pf.rmask = 0x0000FF00;
1635             pf.gmask = 0x00FF0000;
1636             pf.bmask = 0xFF000000;
1637             pf.amask = 0x00000000;
1638             pf.amax = 255;
1639             pf.rmax = 255;
1640             pf.gmax = 255;
1641             pf.bmax = 255;
1642             pf.ashift = 0;
1643             pf.rshift = 8;
1644             pf.gshift = 16;
1645             pf.bshift = 24;
1646             pf.rbits = 8;
1647             pf.gbits = 8;
1648             pf.bbits = 8;
1649             pf.abits = 8;
1650             break;
1651         default:
1652             break;
1653     }
1654     return pf;
1655 }
1656
1657 PixelFormat qemu_default_pixelformat(int bpp)
1658 {
1659     PixelFormat pf;
1660
1661     memset(&pf, 0x00, sizeof(PixelFormat));
1662
1663     pf.bits_per_pixel = bpp;
1664     pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1665     pf.depth = bpp == 32 ? 24 : bpp;
1666
1667     switch (bpp) {
1668         case 15:
1669             pf.bits_per_pixel = 16;
1670             pf.rmask = 0x00007c00;
1671             pf.gmask = 0x000003E0;
1672             pf.bmask = 0x0000001F;
1673             pf.rmax = 31;
1674             pf.gmax = 31;
1675             pf.bmax = 31;
1676             pf.rshift = 10;
1677             pf.gshift = 5;
1678             pf.bshift = 0;
1679             pf.rbits = 5;
1680             pf.gbits = 5;
1681             pf.bbits = 5;
1682             break;
1683         case 16:
1684             pf.rmask = 0x0000F800;
1685             pf.gmask = 0x000007E0;
1686             pf.bmask = 0x0000001F;
1687             pf.rmax = 31;
1688             pf.gmax = 63;
1689             pf.bmax = 31;
1690             pf.rshift = 11;
1691             pf.gshift = 5;
1692             pf.bshift = 0;
1693             pf.rbits = 5;
1694             pf.gbits = 6;
1695             pf.bbits = 5;
1696             break;
1697         case 24:
1698             pf.rmask = 0x00FF0000;
1699             pf.gmask = 0x0000FF00;
1700             pf.bmask = 0x000000FF;
1701             pf.rmax = 255;
1702             pf.gmax = 255;
1703             pf.bmax = 255;
1704             pf.rshift = 16;
1705             pf.gshift = 8;
1706             pf.bshift = 0;
1707             pf.rbits = 8;
1708             pf.gbits = 8;
1709             pf.bbits = 8;
1710             break;
1711         case 32:
1712             pf.rmask = 0x00FF0000;
1713             pf.gmask = 0x0000FF00;
1714             pf.bmask = 0x000000FF;
1715             pf.amax = 255;
1716             pf.rmax = 255;
1717             pf.gmax = 255;
1718             pf.bmax = 255;
1719             pf.ashift = 24;
1720             pf.rshift = 16;
1721             pf.gshift = 8;
1722             pf.bshift = 0;
1723             pf.rbits = 8;
1724             pf.gbits = 8;
1725             pf.bbits = 8;
1726             pf.abits = 8;
1727             break;
1728         default:
1729             break;
1730     }
1731     return pf;
1732 }
This page took 0.135 seconds and 4 git commands to generate.