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