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