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