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