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