• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
qemu_fifo_write(QEMUFIFO * f,const uint8_t * buf,int len1)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 
qemu_fifo_read(QEMUFIFO * f,uint8_t * buf,int len1)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 TextConsole *active_console;
158 static TextConsole *consoles[MAX_CONSOLES];
159 static int nb_consoles = 0;
160 
vga_hw_update(void)161 void vga_hw_update(void)
162 {
163     if (active_console && active_console->hw_update)
164         active_console->hw_update(active_console->hw);
165 }
166 
vga_hw_invalidate(void)167 void vga_hw_invalidate(void)
168 {
169     if (active_console->hw_invalidate)
170         active_console->hw_invalidate(active_console->hw);
171 }
172 
vga_hw_screen_dump(const char * filename)173 void vga_hw_screen_dump(const char *filename)
174 {
175     TextConsole *previous_active_console;
176 
177     previous_active_console = active_console;
178     active_console = consoles[0];
179     /* There is currently no way of specifying which screen we want to dump,
180        so always dump the first one.  */
181     if (consoles[0]->hw_screen_dump)
182         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
183     active_console = previous_active_console;
184 }
185 
vga_hw_text_update(console_ch_t * chardata)186 void vga_hw_text_update(console_ch_t *chardata)
187 {
188     if (active_console && active_console->hw_text_update)
189         active_console->hw_text_update(active_console->hw, chardata);
190 }
191 
192 /* convert a RGBA color to a color index usable in graphic primitives */
vga_get_color(DisplayState * ds,unsigned int rgba)193 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
194 {
195     unsigned int r, g, b, color;
196 
197     switch(ds_get_bits_per_pixel(ds)) {
198 #if 0
199     case 8:
200         r = (rgba >> 16) & 0xff;
201         g = (rgba >> 8) & 0xff;
202         b = (rgba) & 0xff;
203         color = (rgb_to_index[r] * 6 * 6) +
204             (rgb_to_index[g] * 6) +
205             (rgb_to_index[b]);
206         break;
207 #endif
208     case 15:
209         r = (rgba >> 16) & 0xff;
210         g = (rgba >> 8) & 0xff;
211         b = (rgba) & 0xff;
212         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
213         break;
214     case 16:
215         r = (rgba >> 16) & 0xff;
216         g = (rgba >> 8) & 0xff;
217         b = (rgba) & 0xff;
218         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
219         break;
220     case 32:
221     default:
222         color = rgba;
223         break;
224     }
225     return color;
226 }
227 
vga_fill_rect(DisplayState * ds,int posx,int posy,int width,int height,uint32_t color)228 static void vga_fill_rect (DisplayState *ds,
229                            int posx, int posy, int width, int height, uint32_t color)
230 {
231     uint8_t *d, *d1;
232     int x, y, bpp;
233 
234     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
235     d1 = ds_get_data(ds) +
236         ds_get_linesize(ds) * posy + bpp * posx;
237     for (y = 0; y < height; y++) {
238         d = d1;
239         switch(bpp) {
240         case 1:
241             for (x = 0; x < width; x++) {
242                 *((uint8_t *)d) = color;
243                 d++;
244             }
245             break;
246         case 2:
247             for (x = 0; x < width; x++) {
248                 *((uint16_t *)d) = color;
249                 d += 2;
250             }
251             break;
252         case 4:
253             for (x = 0; x < width; x++) {
254                 *((uint32_t *)d) = color;
255                 d += 4;
256             }
257             break;
258         }
259         d1 += ds_get_linesize(ds);
260     }
261 }
262 
263 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
vga_bitblt(DisplayState * ds,int xs,int ys,int xd,int yd,int w,int h)264 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
265 {
266     const uint8_t *s;
267     uint8_t *d;
268     int wb, y, bpp;
269 
270     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
271     wb = w * bpp;
272     if (yd <= ys) {
273         s = ds_get_data(ds) +
274             ds_get_linesize(ds) * ys + bpp * xs;
275         d = ds_get_data(ds) +
276             ds_get_linesize(ds) * yd + bpp * xd;
277         for (y = 0; y < h; y++) {
278             memmove(d, s, wb);
279             d += ds_get_linesize(ds);
280             s += ds_get_linesize(ds);
281         }
282     } else {
283         s = ds_get_data(ds) +
284             ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
285         d = ds_get_data(ds) +
286             ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
287        for (y = 0; y < h; y++) {
288             memmove(d, s, wb);
289             d -= ds_get_linesize(ds);
290             s -= ds_get_linesize(ds);
291         }
292     }
293 }
294 
295 /***********************************************************/
296 /* basic char display */
297 
298 #define FONT_HEIGHT 16
299 #define FONT_WIDTH 8
300 
301 #include "vgafont.h"
302 
303 #define cbswap_32(__x) \
304 ((uint32_t)( \
305 		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
306 		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
307 		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
308 		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
309 
310 #ifdef HOST_WORDS_BIGENDIAN
311 #define PAT(x) x
312 #else
313 #define PAT(x) cbswap_32(x)
314 #endif
315 
316 static const uint32_t dmask16[16] = {
317     PAT(0x00000000),
318     PAT(0x000000ff),
319     PAT(0x0000ff00),
320     PAT(0x0000ffff),
321     PAT(0x00ff0000),
322     PAT(0x00ff00ff),
323     PAT(0x00ffff00),
324     PAT(0x00ffffff),
325     PAT(0xff000000),
326     PAT(0xff0000ff),
327     PAT(0xff00ff00),
328     PAT(0xff00ffff),
329     PAT(0xffff0000),
330     PAT(0xffff00ff),
331     PAT(0xffffff00),
332     PAT(0xffffffff),
333 };
334 
335 static const uint32_t dmask4[4] = {
336     PAT(0x00000000),
337     PAT(0x0000ffff),
338     PAT(0xffff0000),
339     PAT(0xffffffff),
340 };
341 
342 static uint32_t color_table[2][8];
343 
344 enum color_names {
345     COLOR_BLACK   = 0,
346     COLOR_RED     = 1,
347     COLOR_GREEN   = 2,
348     COLOR_YELLOW  = 3,
349     COLOR_BLUE    = 4,
350     COLOR_MAGENTA = 5,
351     COLOR_CYAN    = 6,
352     COLOR_WHITE   = 7
353 };
354 
355 static const uint32_t color_table_rgb[2][8] = {
356     {   /* dark */
357         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
358         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
359         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
360         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
361         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
362         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
363         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
364         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
365     },
366     {   /* bright */
367         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
368         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
369         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
370         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
371         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
372         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
373         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
374         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
375     }
376 };
377 
col_expand(DisplayState * ds,unsigned int col)378 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
379 {
380     switch(ds_get_bits_per_pixel(ds)) {
381     case 8:
382         col |= col << 8;
383         col |= col << 16;
384         break;
385     case 15:
386     case 16:
387         col |= col << 16;
388         break;
389     default:
390         break;
391     }
392 
393     return col;
394 }
395 #ifdef DEBUG_CONSOLE
console_print_text_attributes(TextAttributes * t_attrib,char ch)396 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
397 {
398     if (t_attrib->bold) {
399         printf("b");
400     } else {
401         printf(" ");
402     }
403     if (t_attrib->uline) {
404         printf("u");
405     } else {
406         printf(" ");
407     }
408     if (t_attrib->blink) {
409         printf("l");
410     } else {
411         printf(" ");
412     }
413     if (t_attrib->invers) {
414         printf("i");
415     } else {
416         printf(" ");
417     }
418     if (t_attrib->unvisible) {
419         printf("n");
420     } else {
421         printf(" ");
422     }
423 
424     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
425 }
426 #endif
427 
vga_putcharxy(DisplayState * ds,int x,int y,int ch,TextAttributes * t_attrib)428 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
429                           TextAttributes *t_attrib)
430 {
431     uint8_t *d;
432     const uint8_t *font_ptr;
433     unsigned int font_data, linesize, xorcol, bpp;
434     int i;
435     unsigned int fgcol, bgcol;
436 
437 #ifdef DEBUG_CONSOLE
438     printf("x: %2i y: %2i", x, y);
439     console_print_text_attributes(t_attrib, ch);
440 #endif
441 
442     if (t_attrib->invers) {
443         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
444         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
445     } else {
446         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
447         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
448     }
449 
450     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
451     d = ds_get_data(ds) +
452         ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
453     linesize = ds_get_linesize(ds);
454     font_ptr = vgafont16 + FONT_HEIGHT * ch;
455     xorcol = bgcol ^ fgcol;
456     switch(ds_get_bits_per_pixel(ds)) {
457     case 8:
458         for(i = 0; i < FONT_HEIGHT; i++) {
459             font_data = *font_ptr++;
460             if (t_attrib->uline
461                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462                 font_data = 0xFFFF;
463             }
464             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
465             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
466             d += linesize;
467         }
468         break;
469     case 16:
470     case 15:
471         for(i = 0; i < FONT_HEIGHT; i++) {
472             font_data = *font_ptr++;
473             if (t_attrib->uline
474                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
475                 font_data = 0xFFFF;
476             }
477             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
478             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
479             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
480             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
481             d += linesize;
482         }
483         break;
484     case 32:
485         for(i = 0; i < FONT_HEIGHT; i++) {
486             font_data = *font_ptr++;
487             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
488                 font_data = 0xFFFF;
489             }
490             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
491             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
492             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
493             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
494             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
495             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
496             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
497             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
498             d += linesize;
499         }
500         break;
501     }
502 }
503 
text_console_resize(TextConsole * s)504 static void text_console_resize(TextConsole *s)
505 {
506     TextCell *cells, *c, *c1;
507     int w1, x, y, last_width;
508 
509     last_width = s->width;
510     s->width = s->g_width / FONT_WIDTH;
511     s->height = s->g_height / FONT_HEIGHT;
512 
513     w1 = last_width;
514     if (s->width < w1)
515         w1 = s->width;
516 
517     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
518     for(y = 0; y < s->total_height; y++) {
519         c = &cells[y * s->width];
520         if (w1 > 0) {
521             c1 = &s->cells[y * last_width];
522             for(x = 0; x < w1; x++) {
523                 *c++ = *c1++;
524             }
525         }
526         for(x = w1; x < s->width; x++) {
527             c->ch = ' ';
528             c->t_attrib = s->t_attrib_default;
529             c++;
530         }
531     }
532     qemu_free(s->cells);
533     s->cells = cells;
534 }
535 
text_update_xy(TextConsole * s,int x,int y)536 static inline void text_update_xy(TextConsole *s, int x, int y)
537 {
538     s->text_x[0] = MIN(s->text_x[0], x);
539     s->text_x[1] = MAX(s->text_x[1], x);
540     s->text_y[0] = MIN(s->text_y[0], y);
541     s->text_y[1] = MAX(s->text_y[1], y);
542 }
543 
invalidate_xy(TextConsole * s,int x,int y)544 static void invalidate_xy(TextConsole *s, int x, int y)
545 {
546     if (s->update_x0 > x * FONT_WIDTH)
547         s->update_x0 = x * FONT_WIDTH;
548     if (s->update_y0 > y * FONT_HEIGHT)
549         s->update_y0 = y * FONT_HEIGHT;
550     if (s->update_x1 < (x + 1) * FONT_WIDTH)
551         s->update_x1 = (x + 1) * FONT_WIDTH;
552     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
553         s->update_y1 = (y + 1) * FONT_HEIGHT;
554 }
555 
update_xy(TextConsole * s,int x,int y)556 static void update_xy(TextConsole *s, int x, int y)
557 {
558     TextCell *c;
559     int y1, y2;
560 
561     if (s == active_console) {
562         if (!ds_get_bits_per_pixel(s->ds)) {
563             text_update_xy(s, x, y);
564             return;
565         }
566 
567         y1 = (s->y_base + y) % s->total_height;
568         y2 = y1 - s->y_displayed;
569         if (y2 < 0)
570             y2 += s->total_height;
571         if (y2 < s->height) {
572             c = &s->cells[y1 * s->width + x];
573             vga_putcharxy(s->ds, x, y2, c->ch,
574                           &(c->t_attrib));
575             invalidate_xy(s, x, y2);
576         }
577     }
578 }
579 
console_show_cursor(TextConsole * s,int show)580 static void console_show_cursor(TextConsole *s, int show)
581 {
582     TextCell *c;
583     int y, y1;
584 
585     if (s == active_console) {
586         int x = s->x;
587 
588         if (!ds_get_bits_per_pixel(s->ds)) {
589             s->cursor_invalidate = 1;
590             return;
591         }
592 
593         if (x >= s->width) {
594             x = s->width - 1;
595         }
596         y1 = (s->y_base + s->y) % s->total_height;
597         y = y1 - s->y_displayed;
598         if (y < 0)
599             y += s->total_height;
600         if (y < s->height) {
601             c = &s->cells[y1 * s->width + x];
602             if (show) {
603                 TextAttributes t_attrib = s->t_attrib_default;
604                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
605                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
606             } else {
607                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
608             }
609             invalidate_xy(s, x, y);
610         }
611     }
612 }
613 
console_refresh(TextConsole * s)614 static void console_refresh(TextConsole *s)
615 {
616     TextCell *c;
617     int x, y, y1;
618 
619     if (s != active_console)
620         return;
621     if (!ds_get_bits_per_pixel(s->ds)) {
622         s->text_x[0] = 0;
623         s->text_y[0] = 0;
624         s->text_x[1] = s->width - 1;
625         s->text_y[1] = s->height - 1;
626         s->cursor_invalidate = 1;
627         return;
628     }
629 
630     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
631                   color_table[0][COLOR_BLACK]);
632     y1 = s->y_displayed;
633     for(y = 0; y < s->height; y++) {
634         c = s->cells + y1 * s->width;
635         for(x = 0; x < s->width; x++) {
636             vga_putcharxy(s->ds, x, y, c->ch,
637                           &(c->t_attrib));
638             c++;
639         }
640         if (++y1 == s->total_height)
641             y1 = 0;
642     }
643     console_show_cursor(s, 1);
644     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
645 }
646 
console_scroll(int ydelta)647 static void console_scroll(int ydelta)
648 {
649     TextConsole *s;
650     int i, y1;
651 
652     s = active_console;
653     if (!s || (s->console_type == GRAPHIC_CONSOLE))
654         return;
655 
656     if (ydelta > 0) {
657         for(i = 0; i < ydelta; i++) {
658             if (s->y_displayed == s->y_base)
659                 break;
660             if (++s->y_displayed == s->total_height)
661                 s->y_displayed = 0;
662         }
663     } else {
664         ydelta = -ydelta;
665         i = s->backscroll_height;
666         if (i > s->total_height - s->height)
667             i = s->total_height - s->height;
668         y1 = s->y_base - i;
669         if (y1 < 0)
670             y1 += s->total_height;
671         for(i = 0; i < ydelta; i++) {
672             if (s->y_displayed == y1)
673                 break;
674             if (--s->y_displayed < 0)
675                 s->y_displayed = s->total_height - 1;
676         }
677     }
678     console_refresh(s);
679 }
680 
console_put_lf(TextConsole * s)681 static void console_put_lf(TextConsole *s)
682 {
683     TextCell *c;
684     int x, y1;
685 
686     s->y++;
687     if (s->y >= s->height) {
688         s->y = s->height - 1;
689 
690         if (s->y_displayed == s->y_base) {
691             if (++s->y_displayed == s->total_height)
692                 s->y_displayed = 0;
693         }
694         if (++s->y_base == s->total_height)
695             s->y_base = 0;
696         if (s->backscroll_height < s->total_height)
697             s->backscroll_height++;
698         y1 = (s->y_base + s->height - 1) % s->total_height;
699         c = &s->cells[y1 * s->width];
700         for(x = 0; x < s->width; x++) {
701             c->ch = ' ';
702             c->t_attrib = s->t_attrib_default;
703             c++;
704         }
705         if (s == active_console && s->y_displayed == s->y_base) {
706             if (!ds_get_bits_per_pixel(s->ds)) {
707                 s->text_x[0] = 0;
708                 s->text_y[0] = 0;
709                 s->text_x[1] = s->width - 1;
710                 s->text_y[1] = s->height - 1;
711                 return;
712             }
713 
714             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
715                        s->width * FONT_WIDTH,
716                        (s->height - 1) * FONT_HEIGHT);
717             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
718                           s->width * FONT_WIDTH, FONT_HEIGHT,
719                           color_table[0][s->t_attrib_default.bgcol]);
720             s->update_x0 = 0;
721             s->update_y0 = 0;
722             s->update_x1 = s->width * FONT_WIDTH;
723             s->update_y1 = s->height * FONT_HEIGHT;
724         }
725     }
726 }
727 
728 /* Set console attributes depending on the current escape codes.
729  * NOTE: I know this code is not very efficient (checking every color for it
730  * self) but it is more readable and better maintainable.
731  */
console_handle_escape(TextConsole * s)732 static void console_handle_escape(TextConsole *s)
733 {
734     int i;
735 
736     for (i=0; i<s->nb_esc_params; i++) {
737         switch (s->esc_params[i]) {
738             case 0: /* reset all console attributes to default */
739                 s->t_attrib = s->t_attrib_default;
740                 break;
741             case 1:
742                 s->t_attrib.bold = 1;
743                 break;
744             case 4:
745                 s->t_attrib.uline = 1;
746                 break;
747             case 5:
748                 s->t_attrib.blink = 1;
749                 break;
750             case 7:
751                 s->t_attrib.invers = 1;
752                 break;
753             case 8:
754                 s->t_attrib.unvisible = 1;
755                 break;
756             case 22:
757                 s->t_attrib.bold = 0;
758                 break;
759             case 24:
760                 s->t_attrib.uline = 0;
761                 break;
762             case 25:
763                 s->t_attrib.blink = 0;
764                 break;
765             case 27:
766                 s->t_attrib.invers = 0;
767                 break;
768             case 28:
769                 s->t_attrib.unvisible = 0;
770                 break;
771             /* set foreground color */
772             case 30:
773                 s->t_attrib.fgcol=COLOR_BLACK;
774                 break;
775             case 31:
776                 s->t_attrib.fgcol=COLOR_RED;
777                 break;
778             case 32:
779                 s->t_attrib.fgcol=COLOR_GREEN;
780                 break;
781             case 33:
782                 s->t_attrib.fgcol=COLOR_YELLOW;
783                 break;
784             case 34:
785                 s->t_attrib.fgcol=COLOR_BLUE;
786                 break;
787             case 35:
788                 s->t_attrib.fgcol=COLOR_MAGENTA;
789                 break;
790             case 36:
791                 s->t_attrib.fgcol=COLOR_CYAN;
792                 break;
793             case 37:
794                 s->t_attrib.fgcol=COLOR_WHITE;
795                 break;
796             /* set background color */
797             case 40:
798                 s->t_attrib.bgcol=COLOR_BLACK;
799                 break;
800             case 41:
801                 s->t_attrib.bgcol=COLOR_RED;
802                 break;
803             case 42:
804                 s->t_attrib.bgcol=COLOR_GREEN;
805                 break;
806             case 43:
807                 s->t_attrib.bgcol=COLOR_YELLOW;
808                 break;
809             case 44:
810                 s->t_attrib.bgcol=COLOR_BLUE;
811                 break;
812             case 45:
813                 s->t_attrib.bgcol=COLOR_MAGENTA;
814                 break;
815             case 46:
816                 s->t_attrib.bgcol=COLOR_CYAN;
817                 break;
818             case 47:
819                 s->t_attrib.bgcol=COLOR_WHITE;
820                 break;
821         }
822     }
823 }
824 
console_clear_xy(TextConsole * s,int x,int y)825 static void console_clear_xy(TextConsole *s, int x, int y)
826 {
827     int y1 = (s->y_base + y) % s->total_height;
828     TextCell *c = &s->cells[y1 * s->width + x];
829     c->ch = ' ';
830     c->t_attrib = s->t_attrib_default;
831     c++;
832     update_xy(s, x, y);
833 }
834 
console_putchar(TextConsole * s,int ch)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 
console_select(unsigned int index)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 
console_puts(CharDriverState * chr,const uint8_t * buf,int len)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 
console_send_event(CharDriverState * chr,int event)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 
kbd_send_chars(void * opaque)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 */
kbd_put_keysym(int keysym)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 
text_console_invalidate(void * opaque)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 
text_console_update(void * opaque,console_ch_t * chardata)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 
get_graphic_console(DisplayState * ds)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 
new_console(DisplayState * ds,console_type_t console_type)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 
graphic_console_init(vga_hw_update_ptr update,vga_hw_invalidate_ptr invalidate,vga_hw_screen_dump_ptr screen_dump,vga_hw_text_update_ptr text_update,void * opaque)1268 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1269                                    vga_hw_invalidate_ptr invalidate,
1270                                    vga_hw_screen_dump_ptr screen_dump,
1271                                    vga_hw_text_update_ptr text_update,
1272                                    void *opaque)
1273 {
1274     TextConsole *s;
1275     DisplayState *ds;
1276 
1277     ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1278     ds->allocator = &default_allocator;
1279     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1280 
1281     s = new_console(ds, GRAPHIC_CONSOLE);
1282     if (s == NULL) {
1283         qemu_free_displaysurface(ds);
1284         qemu_free(ds);
1285         return NULL;
1286     }
1287     s->hw_update = update;
1288     s->hw_invalidate = invalidate;
1289     s->hw_screen_dump = screen_dump;
1290     s->hw_text_update = text_update;
1291     s->hw = opaque;
1292 
1293     register_displaystate(ds);
1294     return ds;
1295 }
1296 
is_graphic_console(void)1297 int is_graphic_console(void)
1298 {
1299     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1300 }
1301 
is_fixedsize_console(void)1302 int is_fixedsize_console(void)
1303 {
1304     return active_console && active_console->console_type != TEXT_CONSOLE;
1305 }
1306 
console_color_init(DisplayState * ds)1307 void console_color_init(DisplayState *ds)
1308 {
1309     int i, j;
1310     for (j = 0; j < 2; j++) {
1311         for (i = 0; i < 8; i++) {
1312             color_table[j][i] = col_expand(ds,
1313                    vga_get_color(ds, color_table_rgb[j][i]));
1314         }
1315     }
1316 }
1317 
1318 static int n_text_consoles;
1319 static CharDriverState *text_consoles[128];
1320 static char *text_console_strs[128];
1321 
text_console_do_init(CharDriverState * chr,DisplayState * ds,const char * p)1322 static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1323 {
1324     TextConsole *s;
1325     unsigned width;
1326     unsigned height;
1327     static int color_inited;
1328 
1329     s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1330     if (!s) {
1331         free(chr);
1332         return;
1333     }
1334     chr->opaque = s;
1335     chr->chr_write = console_puts;
1336     chr->chr_send_event = console_send_event;
1337 
1338     s->chr = chr;
1339     s->out_fifo.buf = s->out_fifo_buf;
1340     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1341     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1342     s->ds = ds;
1343 
1344     if (!color_inited) {
1345         color_inited = 1;
1346         console_color_init(s->ds);
1347     }
1348     s->y_displayed = 0;
1349     s->y_base = 0;
1350     s->total_height = DEFAULT_BACKSCROLL;
1351     s->x = 0;
1352     s->y = 0;
1353     width = ds_get_width(s->ds);
1354     height = ds_get_height(s->ds);
1355     if (p != NULL) {
1356         width = strtoul(p, (char **)&p, 10);
1357         if (*p == 'C') {
1358             p++;
1359             width *= FONT_WIDTH;
1360         }
1361         if (*p == 'x') {
1362             p++;
1363             height = strtoul(p, (char **)&p, 10);
1364             if (*p == 'C') {
1365                 p++;
1366                 height *= FONT_HEIGHT;
1367             }
1368         }
1369     }
1370     s->g_width = width;
1371     s->g_height = height;
1372 
1373     s->hw_invalidate = text_console_invalidate;
1374     s->hw_text_update = text_console_update;
1375     s->hw = s;
1376 
1377     /* Set text attribute defaults */
1378     s->t_attrib_default.bold = 0;
1379     s->t_attrib_default.uline = 0;
1380     s->t_attrib_default.blink = 0;
1381     s->t_attrib_default.invers = 0;
1382     s->t_attrib_default.unvisible = 0;
1383     s->t_attrib_default.fgcol = COLOR_WHITE;
1384     s->t_attrib_default.bgcol = COLOR_BLACK;
1385     /* set current text attributes to default */
1386     s->t_attrib = s->t_attrib_default;
1387     text_console_resize(s);
1388 
1389     qemu_chr_reset(chr);
1390     if (chr->init)
1391         chr->init(chr);
1392 }
1393 
text_console_init(const char * p)1394 CharDriverState *text_console_init(const char *p)
1395 {
1396     CharDriverState *chr;
1397 
1398     chr = qemu_mallocz(sizeof(CharDriverState));
1399 
1400     if (n_text_consoles == 128) {
1401         fprintf(stderr, "Too many text consoles\n");
1402         exit(1);
1403     }
1404     text_consoles[n_text_consoles] = chr;
1405     text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1406     n_text_consoles++;
1407 
1408     return chr;
1409 }
1410 
text_consoles_set_display(DisplayState * ds)1411 void text_consoles_set_display(DisplayState *ds)
1412 {
1413     int i;
1414 
1415     for (i = 0; i < n_text_consoles; i++) {
1416         text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1417         qemu_free(text_console_strs[i]);
1418     }
1419 
1420     n_text_consoles = 0;
1421 }
1422 
qemu_console_resize(DisplayState * ds,int width,int height)1423 void qemu_console_resize(DisplayState *ds, int width, int height)
1424 {
1425     TextConsole *s = get_graphic_console(ds);
1426     if (!s) return;
1427 
1428     s->g_width = width;
1429     s->g_height = height;
1430     if (is_graphic_console()) {
1431         ds->surface = qemu_resize_displaysurface(ds, width, height);
1432         dpy_resize(ds);
1433     }
1434 }
1435 
qemu_console_copy(DisplayState * ds,int src_x,int src_y,int dst_x,int dst_y,int w,int h)1436 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1437                        int dst_x, int dst_y, int w, int h)
1438 {
1439     if (is_graphic_console()) {
1440         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1441     }
1442 }
1443 
qemu_different_endianness_pixelformat(int bpp)1444 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1445 {
1446     PixelFormat pf;
1447 
1448     memset(&pf, 0x00, sizeof(PixelFormat));
1449 
1450     pf.bits_per_pixel = bpp;
1451     pf.bytes_per_pixel = bpp / 8;
1452     pf.depth = bpp == 32 ? 24 : bpp;
1453 
1454     switch (bpp) {
1455         case 24:
1456             pf.rmask = 0x000000FF;
1457             pf.gmask = 0x0000FF00;
1458             pf.bmask = 0x00FF0000;
1459             pf.rmax = 255;
1460             pf.gmax = 255;
1461             pf.bmax = 255;
1462             pf.rshift = 0;
1463             pf.gshift = 8;
1464             pf.bshift = 16;
1465             pf.rbits = 8;
1466             pf.gbits = 8;
1467             pf.bbits = 8;
1468             break;
1469         case 32:
1470             pf.rmask = 0x0000FF00;
1471             pf.gmask = 0x00FF0000;
1472             pf.bmask = 0xFF000000;
1473             pf.amask = 0x00000000;
1474             pf.amax = 255;
1475             pf.rmax = 255;
1476             pf.gmax = 255;
1477             pf.bmax = 255;
1478             pf.ashift = 0;
1479             pf.rshift = 8;
1480             pf.gshift = 16;
1481             pf.bshift = 24;
1482             pf.rbits = 8;
1483             pf.gbits = 8;
1484             pf.bbits = 8;
1485             pf.abits = 8;
1486             break;
1487         default:
1488             break;
1489     }
1490     return pf;
1491 }
1492 
qemu_default_pixelformat(int bpp)1493 PixelFormat qemu_default_pixelformat(int bpp)
1494 {
1495     PixelFormat pf;
1496 
1497     memset(&pf, 0x00, sizeof(PixelFormat));
1498 
1499     pf.bits_per_pixel = bpp;
1500     pf.bytes_per_pixel = bpp / 8;
1501     pf.depth = bpp == 32 ? 24 : bpp;
1502 
1503     switch (bpp) {
1504         case 16:
1505             pf.rmask = 0x0000F800;
1506             pf.gmask = 0x000007E0;
1507             pf.bmask = 0x0000001F;
1508             pf.rmax = 31;
1509             pf.gmax = 63;
1510             pf.bmax = 31;
1511             pf.rshift = 11;
1512             pf.gshift = 5;
1513             pf.bshift = 0;
1514             pf.rbits = 5;
1515             pf.gbits = 6;
1516             pf.bbits = 5;
1517             break;
1518         case 24:
1519             pf.rmask = 0x00FF0000;
1520             pf.gmask = 0x0000FF00;
1521             pf.bmask = 0x000000FF;
1522             pf.rmax = 255;
1523             pf.gmax = 255;
1524             pf.bmax = 255;
1525             pf.rshift = 16;
1526             pf.gshift = 8;
1527             pf.bshift = 0;
1528             pf.rbits = 8;
1529             pf.gbits = 8;
1530             pf.bbits = 8;
1531         case 32:
1532             pf.rmask = 0x00FF0000;
1533             pf.gmask = 0x0000FF00;
1534             pf.bmask = 0x000000FF;
1535             pf.amax = 255;
1536             pf.rmax = 255;
1537             pf.gmax = 255;
1538             pf.bmax = 255;
1539             pf.ashift = 24;
1540             pf.rshift = 16;
1541             pf.gshift = 8;
1542             pf.bshift = 0;
1543             pf.rbits = 8;
1544             pf.gbits = 8;
1545             pf.bbits = 8;
1546             pf.abits = 8;
1547             break;
1548         default:
1549             break;
1550     }
1551     return pf;
1552 }
1553 
defaultallocator_create_displaysurface(int width,int height)1554 DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1555 {
1556     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1557 
1558     surface->width = width;
1559     surface->height = height;
1560     surface->linesize = width * 4;
1561     surface->pf = qemu_default_pixelformat(32);
1562 #ifdef HOST_WORDS_BIGENDIAN
1563     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1564 #else
1565     surface->flags = QEMU_ALLOCATED_FLAG;
1566 #endif
1567     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1568 
1569     return surface;
1570 }
1571 
defaultallocator_resize_displaysurface(DisplaySurface * surface,int width,int height)1572 DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1573                                           int width, int height)
1574 {
1575     surface->width = width;
1576     surface->height = height;
1577     surface->linesize = width * 4;
1578     surface->pf = qemu_default_pixelformat(32);
1579     if (surface->flags & QEMU_ALLOCATED_FLAG)
1580         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1581     else
1582         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1583 #ifdef HOST_WORDS_BIGENDIAN
1584     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1585 #else
1586     surface->flags = QEMU_ALLOCATED_FLAG;
1587 #endif
1588 
1589     return surface;
1590 }
1591 
qemu_create_displaysurface_from(int width,int height,int bpp,int linesize,uint8_t * data)1592 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1593                                               int linesize, uint8_t *data)
1594 {
1595     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1596 
1597     surface->width = width;
1598     surface->height = height;
1599     surface->linesize = linesize;
1600     surface->pf = qemu_default_pixelformat(bpp);
1601 #ifdef HOST_WORDS_BIGENDIAN
1602     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1603 #endif
1604     surface->data = data;
1605 
1606     return surface;
1607 }
1608 
defaultallocator_free_displaysurface(DisplaySurface * surface)1609 void defaultallocator_free_displaysurface(DisplaySurface *surface)
1610 {
1611     if (surface == NULL)
1612         return;
1613     if (surface->flags & QEMU_ALLOCATED_FLAG)
1614         qemu_free(surface->data);
1615     qemu_free(surface);
1616 }
1617