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