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