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