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