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