virtio/vhost: Add support for KVM in-kernel MSI injection
[qemu-kvm.git] / console.c
blob6a463f5918d58d7fc6153e87ec472c6404f445c6
1 /*
2 * QEMU graphical console
4 * Copyright (c) 2004 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include "qemu-common.h"
25 #include "console.h"
26 #include "qemu-timer.h"
28 //#define DEBUG_CONSOLE
29 #define DEFAULT_BACKSCROLL 512
30 #define MAX_CONSOLES 12
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)
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;
45 typedef struct TextCell {
46 uint8_t ch;
47 TextAttributes t_attrib;
48 } TextCell;
50 #define MAX_ESC_PARAMS 3
52 enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
58 typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62 } QEMUFIFO;
64 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 int l, len;
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;
83 f->count += len1;
84 return len1;
87 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 int l, len;
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;
105 f->count -= len1;
106 return len1;
109 typedef enum {
110 GRAPHIC_CONSOLE,
111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
113 } console_type_t;
115 /* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
117 struct TextConsole {
118 int index;
119 console_type_t console_type;
120 DisplayState *ds;
121 /* Graphic console state. */
122 vga_hw_update_ptr hw_update;
123 vga_hw_invalidate_ptr hw_invalidate;
124 vga_hw_screen_dump_ptr hw_screen_dump;
125 vga_hw_text_update_ptr hw_text_update;
126 void *hw;
128 int g_width, g_height;
129 int width;
130 int height;
131 int total_height;
132 int backscroll_height;
133 int x, y;
134 int x_saved, y_saved;
135 int y_displayed;
136 int y_base;
137 TextAttributes t_attrib_default; /* default text attributes */
138 TextAttributes t_attrib; /* currently active text attributes */
139 TextCell *cells;
140 int text_x[2], text_y[2], cursor_invalidate;
141 int echo;
143 int update_x0;
144 int update_y0;
145 int update_x1;
146 int update_y1;
148 enum TTYState state;
149 int esc_params[MAX_ESC_PARAMS];
150 int nb_esc_params;
152 CharDriverState *chr;
153 /* fifo for key pressed */
154 QEMUFIFO out_fifo;
155 uint8_t out_fifo_buf[16];
156 QEMUTimer *kbd_timer;
159 static DisplayState *display_state;
160 static TextConsole *active_console;
161 static TextConsole *consoles[MAX_CONSOLES];
162 static int nb_consoles = 0;
164 void vga_hw_update(void)
166 if (active_console && active_console->hw_update)
167 active_console->hw_update(active_console->hw);
170 void vga_hw_invalidate(void)
172 if (active_console && active_console->hw_invalidate)
173 active_console->hw_invalidate(active_console->hw);
176 void vga_hw_screen_dump(const char *filename)
178 TextConsole *previous_active_console;
179 bool cswitch;
181 previous_active_console = active_console;
182 cswitch = previous_active_console && previous_active_console->index != 0;
184 /* There is currently no way of specifying which screen we want to dump,
185 so always dump the first one. */
186 if (cswitch) {
187 console_select(0);
189 if (consoles[0] && consoles[0]->hw_screen_dump) {
190 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
191 } else {
192 error_report("screen dump not implemented");
195 if (cswitch) {
196 console_select(previous_active_console->index);
200 void vga_hw_text_update(console_ch_t *chardata)
202 if (active_console && active_console->hw_text_update)
203 active_console->hw_text_update(active_console->hw, chardata);
206 /* convert a RGBA color to a color index usable in graphic primitives */
207 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
209 unsigned int r, g, b, color;
211 switch(ds_get_bits_per_pixel(ds)) {
212 #if 0
213 case 8:
214 r = (rgba >> 16) & 0xff;
215 g = (rgba >> 8) & 0xff;
216 b = (rgba) & 0xff;
217 color = (rgb_to_index[r] * 6 * 6) +
218 (rgb_to_index[g] * 6) +
219 (rgb_to_index[b]);
220 break;
221 #endif
222 case 15:
223 r = (rgba >> 16) & 0xff;
224 g = (rgba >> 8) & 0xff;
225 b = (rgba) & 0xff;
226 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
227 break;
228 case 16:
229 r = (rgba >> 16) & 0xff;
230 g = (rgba >> 8) & 0xff;
231 b = (rgba) & 0xff;
232 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
233 break;
234 case 32:
235 default:
236 color = rgba;
237 break;
239 return color;
242 static void vga_fill_rect (DisplayState *ds,
243 int posx, int posy, int width, int height, uint32_t color)
245 uint8_t *d, *d1;
246 int x, y, bpp;
248 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
249 d1 = ds_get_data(ds) +
250 ds_get_linesize(ds) * posy + bpp * posx;
251 for (y = 0; y < height; y++) {
252 d = d1;
253 switch(bpp) {
254 case 1:
255 for (x = 0; x < width; x++) {
256 *((uint8_t *)d) = color;
257 d++;
259 break;
260 case 2:
261 for (x = 0; x < width; x++) {
262 *((uint16_t *)d) = color;
263 d += 2;
265 break;
266 case 4:
267 for (x = 0; x < width; x++) {
268 *((uint32_t *)d) = color;
269 d += 4;
271 break;
273 d1 += ds_get_linesize(ds);
277 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
278 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
280 const uint8_t *s;
281 uint8_t *d;
282 int wb, y, bpp;
284 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
285 wb = w * bpp;
286 if (yd <= ys) {
287 s = ds_get_data(ds) +
288 ds_get_linesize(ds) * ys + bpp * xs;
289 d = ds_get_data(ds) +
290 ds_get_linesize(ds) * yd + bpp * xd;
291 for (y = 0; y < h; y++) {
292 memmove(d, s, wb);
293 d += ds_get_linesize(ds);
294 s += ds_get_linesize(ds);
296 } else {
297 s = ds_get_data(ds) +
298 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
299 d = ds_get_data(ds) +
300 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
301 for (y = 0; y < h; y++) {
302 memmove(d, s, wb);
303 d -= ds_get_linesize(ds);
304 s -= ds_get_linesize(ds);
309 /***********************************************************/
310 /* basic char display */
312 #define FONT_HEIGHT 16
313 #define FONT_WIDTH 8
315 #include "vgafont.h"
317 #define cbswap_32(__x) \
318 ((uint32_t)( \
319 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
320 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
321 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
322 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
324 #ifdef HOST_WORDS_BIGENDIAN
325 #define PAT(x) x
326 #else
327 #define PAT(x) cbswap_32(x)
328 #endif
330 static const uint32_t dmask16[16] = {
331 PAT(0x00000000),
332 PAT(0x000000ff),
333 PAT(0x0000ff00),
334 PAT(0x0000ffff),
335 PAT(0x00ff0000),
336 PAT(0x00ff00ff),
337 PAT(0x00ffff00),
338 PAT(0x00ffffff),
339 PAT(0xff000000),
340 PAT(0xff0000ff),
341 PAT(0xff00ff00),
342 PAT(0xff00ffff),
343 PAT(0xffff0000),
344 PAT(0xffff00ff),
345 PAT(0xffffff00),
346 PAT(0xffffffff),
349 static const uint32_t dmask4[4] = {
350 PAT(0x00000000),
351 PAT(0x0000ffff),
352 PAT(0xffff0000),
353 PAT(0xffffffff),
356 static uint32_t color_table[2][8];
358 #ifndef CONFIG_CURSES
359 enum color_names {
360 COLOR_BLACK = 0,
361 COLOR_RED = 1,
362 COLOR_GREEN = 2,
363 COLOR_YELLOW = 3,
364 COLOR_BLUE = 4,
365 COLOR_MAGENTA = 5,
366 COLOR_CYAN = 6,
367 COLOR_WHITE = 7
369 #endif
371 static const uint32_t color_table_rgb[2][8] = {
372 { /* dark */
373 QEMU_RGB(0x00, 0x00, 0x00), /* black */
374 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
375 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
376 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
377 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
378 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
379 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
380 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
382 { /* bright */
383 QEMU_RGB(0x00, 0x00, 0x00), /* black */
384 QEMU_RGB(0xff, 0x00, 0x00), /* red */
385 QEMU_RGB(0x00, 0xff, 0x00), /* green */
386 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
387 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
388 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
389 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
390 QEMU_RGB(0xff, 0xff, 0xff), /* white */
394 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
396 switch(ds_get_bits_per_pixel(ds)) {
397 case 8:
398 col |= col << 8;
399 col |= col << 16;
400 break;
401 case 15:
402 case 16:
403 col |= col << 16;
404 break;
405 default:
406 break;
409 return col;
411 #ifdef DEBUG_CONSOLE
412 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
414 if (t_attrib->bold) {
415 printf("b");
416 } else {
417 printf(" ");
419 if (t_attrib->uline) {
420 printf("u");
421 } else {
422 printf(" ");
424 if (t_attrib->blink) {
425 printf("l");
426 } else {
427 printf(" ");
429 if (t_attrib->invers) {
430 printf("i");
431 } else {
432 printf(" ");
434 if (t_attrib->unvisible) {
435 printf("n");
436 } else {
437 printf(" ");
440 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
442 #endif
444 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
445 TextAttributes *t_attrib)
447 uint8_t *d;
448 const uint8_t *font_ptr;
449 unsigned int font_data, linesize, xorcol, bpp;
450 int i;
451 unsigned int fgcol, bgcol;
453 #ifdef DEBUG_CONSOLE
454 printf("x: %2i y: %2i", x, y);
455 console_print_text_attributes(t_attrib, ch);
456 #endif
458 if (t_attrib->invers) {
459 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
460 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
461 } else {
462 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
463 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
466 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
467 d = ds_get_data(ds) +
468 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
469 linesize = ds_get_linesize(ds);
470 font_ptr = vgafont16 + FONT_HEIGHT * ch;
471 xorcol = bgcol ^ fgcol;
472 switch(ds_get_bits_per_pixel(ds)) {
473 case 8:
474 for(i = 0; i < FONT_HEIGHT; i++) {
475 font_data = *font_ptr++;
476 if (t_attrib->uline
477 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
478 font_data = 0xFF;
480 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
482 d += linesize;
484 break;
485 case 16:
486 case 15:
487 for(i = 0; i < FONT_HEIGHT; i++) {
488 font_data = *font_ptr++;
489 if (t_attrib->uline
490 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
491 font_data = 0xFF;
493 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
494 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
495 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
496 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
497 d += linesize;
499 break;
500 case 32:
501 for(i = 0; i < FONT_HEIGHT; i++) {
502 font_data = *font_ptr++;
503 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
504 font_data = 0xFF;
506 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
507 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
508 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
509 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
510 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
514 d += linesize;
516 break;
520 static void text_console_resize(TextConsole *s)
522 TextCell *cells, *c, *c1;
523 int w1, x, y, last_width;
525 last_width = s->width;
526 s->width = s->g_width / FONT_WIDTH;
527 s->height = s->g_height / FONT_HEIGHT;
529 w1 = last_width;
530 if (s->width < w1)
531 w1 = s->width;
533 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
534 for(y = 0; y < s->total_height; y++) {
535 c = &cells[y * s->width];
536 if (w1 > 0) {
537 c1 = &s->cells[y * last_width];
538 for(x = 0; x < w1; x++) {
539 *c++ = *c1++;
542 for(x = w1; x < s->width; x++) {
543 c->ch = ' ';
544 c->t_attrib = s->t_attrib_default;
545 c++;
548 g_free(s->cells);
549 s->cells = cells;
552 static inline void text_update_xy(TextConsole *s, int x, int y)
554 s->text_x[0] = MIN(s->text_x[0], x);
555 s->text_x[1] = MAX(s->text_x[1], x);
556 s->text_y[0] = MIN(s->text_y[0], y);
557 s->text_y[1] = MAX(s->text_y[1], y);
560 static void invalidate_xy(TextConsole *s, int x, int y)
562 if (s->update_x0 > x * FONT_WIDTH)
563 s->update_x0 = x * FONT_WIDTH;
564 if (s->update_y0 > y * FONT_HEIGHT)
565 s->update_y0 = y * FONT_HEIGHT;
566 if (s->update_x1 < (x + 1) * FONT_WIDTH)
567 s->update_x1 = (x + 1) * FONT_WIDTH;
568 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
569 s->update_y1 = (y + 1) * FONT_HEIGHT;
572 static void update_xy(TextConsole *s, int x, int y)
574 TextCell *c;
575 int y1, y2;
577 if (s == active_console) {
578 if (!ds_get_bits_per_pixel(s->ds)) {
579 text_update_xy(s, x, y);
580 return;
583 y1 = (s->y_base + y) % s->total_height;
584 y2 = y1 - s->y_displayed;
585 if (y2 < 0)
586 y2 += s->total_height;
587 if (y2 < s->height) {
588 c = &s->cells[y1 * s->width + x];
589 vga_putcharxy(s->ds, x, y2, c->ch,
590 &(c->t_attrib));
591 invalidate_xy(s, x, y2);
596 static void console_show_cursor(TextConsole *s, int show)
598 TextCell *c;
599 int y, y1;
601 if (s == active_console) {
602 int x = s->x;
604 if (!ds_get_bits_per_pixel(s->ds)) {
605 s->cursor_invalidate = 1;
606 return;
609 if (x >= s->width) {
610 x = s->width - 1;
612 y1 = (s->y_base + s->y) % s->total_height;
613 y = y1 - s->y_displayed;
614 if (y < 0)
615 y += s->total_height;
616 if (y < s->height) {
617 c = &s->cells[y1 * s->width + x];
618 if (show) {
619 TextAttributes t_attrib = s->t_attrib_default;
620 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
621 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
622 } else {
623 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
625 invalidate_xy(s, x, y);
630 static void console_refresh(TextConsole *s)
632 TextCell *c;
633 int x, y, y1;
635 if (s != active_console)
636 return;
637 if (!ds_get_bits_per_pixel(s->ds)) {
638 s->text_x[0] = 0;
639 s->text_y[0] = 0;
640 s->text_x[1] = s->width - 1;
641 s->text_y[1] = s->height - 1;
642 s->cursor_invalidate = 1;
643 return;
646 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
647 color_table[0][COLOR_BLACK]);
648 y1 = s->y_displayed;
649 for(y = 0; y < s->height; y++) {
650 c = s->cells + y1 * s->width;
651 for(x = 0; x < s->width; x++) {
652 vga_putcharxy(s->ds, x, y, c->ch,
653 &(c->t_attrib));
654 c++;
656 if (++y1 == s->total_height)
657 y1 = 0;
659 console_show_cursor(s, 1);
660 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
663 static void console_scroll(int ydelta)
665 TextConsole *s;
666 int i, y1;
668 s = active_console;
669 if (!s || (s->console_type == GRAPHIC_CONSOLE))
670 return;
672 if (ydelta > 0) {
673 for(i = 0; i < ydelta; i++) {
674 if (s->y_displayed == s->y_base)
675 break;
676 if (++s->y_displayed == s->total_height)
677 s->y_displayed = 0;
679 } else {
680 ydelta = -ydelta;
681 i = s->backscroll_height;
682 if (i > s->total_height - s->height)
683 i = s->total_height - s->height;
684 y1 = s->y_base - i;
685 if (y1 < 0)
686 y1 += s->total_height;
687 for(i = 0; i < ydelta; i++) {
688 if (s->y_displayed == y1)
689 break;
690 if (--s->y_displayed < 0)
691 s->y_displayed = s->total_height - 1;
694 console_refresh(s);
697 static void console_put_lf(TextConsole *s)
699 TextCell *c;
700 int x, y1;
702 s->y++;
703 if (s->y >= s->height) {
704 s->y = s->height - 1;
706 if (s->y_displayed == s->y_base) {
707 if (++s->y_displayed == s->total_height)
708 s->y_displayed = 0;
710 if (++s->y_base == s->total_height)
711 s->y_base = 0;
712 if (s->backscroll_height < s->total_height)
713 s->backscroll_height++;
714 y1 = (s->y_base + s->height - 1) % s->total_height;
715 c = &s->cells[y1 * s->width];
716 for(x = 0; x < s->width; x++) {
717 c->ch = ' ';
718 c->t_attrib = s->t_attrib_default;
719 c++;
721 if (s == active_console && s->y_displayed == s->y_base) {
722 if (!ds_get_bits_per_pixel(s->ds)) {
723 s->text_x[0] = 0;
724 s->text_y[0] = 0;
725 s->text_x[1] = s->width - 1;
726 s->text_y[1] = s->height - 1;
727 return;
730 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
731 s->width * FONT_WIDTH,
732 (s->height - 1) * FONT_HEIGHT);
733 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
734 s->width * FONT_WIDTH, FONT_HEIGHT,
735 color_table[0][s->t_attrib_default.bgcol]);
736 s->update_x0 = 0;
737 s->update_y0 = 0;
738 s->update_x1 = s->width * FONT_WIDTH;
739 s->update_y1 = s->height * FONT_HEIGHT;
744 /* Set console attributes depending on the current escape codes.
745 * NOTE: I know this code is not very efficient (checking every color for it
746 * self) but it is more readable and better maintainable.
748 static void console_handle_escape(TextConsole *s)
750 int i;
752 for (i=0; i<s->nb_esc_params; i++) {
753 switch (s->esc_params[i]) {
754 case 0: /* reset all console attributes to default */
755 s->t_attrib = s->t_attrib_default;
756 break;
757 case 1:
758 s->t_attrib.bold = 1;
759 break;
760 case 4:
761 s->t_attrib.uline = 1;
762 break;
763 case 5:
764 s->t_attrib.blink = 1;
765 break;
766 case 7:
767 s->t_attrib.invers = 1;
768 break;
769 case 8:
770 s->t_attrib.unvisible = 1;
771 break;
772 case 22:
773 s->t_attrib.bold = 0;
774 break;
775 case 24:
776 s->t_attrib.uline = 0;
777 break;
778 case 25:
779 s->t_attrib.blink = 0;
780 break;
781 case 27:
782 s->t_attrib.invers = 0;
783 break;
784 case 28:
785 s->t_attrib.unvisible = 0;
786 break;
787 /* set foreground color */
788 case 30:
789 s->t_attrib.fgcol=COLOR_BLACK;
790 break;
791 case 31:
792 s->t_attrib.fgcol=COLOR_RED;
793 break;
794 case 32:
795 s->t_attrib.fgcol=COLOR_GREEN;
796 break;
797 case 33:
798 s->t_attrib.fgcol=COLOR_YELLOW;
799 break;
800 case 34:
801 s->t_attrib.fgcol=COLOR_BLUE;
802 break;
803 case 35:
804 s->t_attrib.fgcol=COLOR_MAGENTA;
805 break;
806 case 36:
807 s->t_attrib.fgcol=COLOR_CYAN;
808 break;
809 case 37:
810 s->t_attrib.fgcol=COLOR_WHITE;
811 break;
812 /* set background color */
813 case 40:
814 s->t_attrib.bgcol=COLOR_BLACK;
815 break;
816 case 41:
817 s->t_attrib.bgcol=COLOR_RED;
818 break;
819 case 42:
820 s->t_attrib.bgcol=COLOR_GREEN;
821 break;
822 case 43:
823 s->t_attrib.bgcol=COLOR_YELLOW;
824 break;
825 case 44:
826 s->t_attrib.bgcol=COLOR_BLUE;
827 break;
828 case 45:
829 s->t_attrib.bgcol=COLOR_MAGENTA;
830 break;
831 case 46:
832 s->t_attrib.bgcol=COLOR_CYAN;
833 break;
834 case 47:
835 s->t_attrib.bgcol=COLOR_WHITE;
836 break;
841 static void console_clear_xy(TextConsole *s, int x, int y)
843 int y1 = (s->y_base + y) % s->total_height;
844 TextCell *c = &s->cells[y1 * s->width + x];
845 c->ch = ' ';
846 c->t_attrib = s->t_attrib_default;
847 update_xy(s, x, y);
850 static void console_putchar(TextConsole *s, int ch)
852 TextCell *c;
853 int y1, i;
854 int x, y;
856 switch(s->state) {
857 case TTY_STATE_NORM:
858 switch(ch) {
859 case '\r': /* carriage return */
860 s->x = 0;
861 break;
862 case '\n': /* newline */
863 console_put_lf(s);
864 break;
865 case '\b': /* backspace */
866 if (s->x > 0)
867 s->x--;
868 break;
869 case '\t': /* tabspace */
870 if (s->x + (8 - (s->x % 8)) > s->width) {
871 s->x = 0;
872 console_put_lf(s);
873 } else {
874 s->x = s->x + (8 - (s->x % 8));
876 break;
877 case '\a': /* alert aka. bell */
878 /* TODO: has to be implemented */
879 break;
880 case 14:
881 /* SI (shift in), character set 0 (ignored) */
882 break;
883 case 15:
884 /* SO (shift out), character set 1 (ignored) */
885 break;
886 case 27: /* esc (introducing an escape sequence) */
887 s->state = TTY_STATE_ESC;
888 break;
889 default:
890 if (s->x >= s->width) {
891 /* line wrap */
892 s->x = 0;
893 console_put_lf(s);
895 y1 = (s->y_base + s->y) % s->total_height;
896 c = &s->cells[y1 * s->width + s->x];
897 c->ch = ch;
898 c->t_attrib = s->t_attrib;
899 update_xy(s, s->x, s->y);
900 s->x++;
901 break;
903 break;
904 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
905 if (ch == '[') {
906 for(i=0;i<MAX_ESC_PARAMS;i++)
907 s->esc_params[i] = 0;
908 s->nb_esc_params = 0;
909 s->state = TTY_STATE_CSI;
910 } else {
911 s->state = TTY_STATE_NORM;
913 break;
914 case TTY_STATE_CSI: /* handle escape sequence parameters */
915 if (ch >= '0' && ch <= '9') {
916 if (s->nb_esc_params < MAX_ESC_PARAMS) {
917 s->esc_params[s->nb_esc_params] =
918 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
920 } else {
921 s->nb_esc_params++;
922 if (ch == ';')
923 break;
924 #ifdef DEBUG_CONSOLE
925 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
926 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
927 #endif
928 s->state = TTY_STATE_NORM;
929 switch(ch) {
930 case 'A':
931 /* move cursor up */
932 if (s->esc_params[0] == 0) {
933 s->esc_params[0] = 1;
935 s->y -= s->esc_params[0];
936 if (s->y < 0) {
937 s->y = 0;
939 break;
940 case 'B':
941 /* move cursor down */
942 if (s->esc_params[0] == 0) {
943 s->esc_params[0] = 1;
945 s->y += s->esc_params[0];
946 if (s->y >= s->height) {
947 s->y = s->height - 1;
949 break;
950 case 'C':
951 /* move cursor right */
952 if (s->esc_params[0] == 0) {
953 s->esc_params[0] = 1;
955 s->x += s->esc_params[0];
956 if (s->x >= s->width) {
957 s->x = s->width - 1;
959 break;
960 case 'D':
961 /* move cursor left */
962 if (s->esc_params[0] == 0) {
963 s->esc_params[0] = 1;
965 s->x -= s->esc_params[0];
966 if (s->x < 0) {
967 s->x = 0;
969 break;
970 case 'G':
971 /* move cursor to column */
972 s->x = s->esc_params[0] - 1;
973 if (s->x < 0) {
974 s->x = 0;
976 break;
977 case 'f':
978 case 'H':
979 /* move cursor to row, column */
980 s->x = s->esc_params[1] - 1;
981 if (s->x < 0) {
982 s->x = 0;
984 s->y = s->esc_params[0] - 1;
985 if (s->y < 0) {
986 s->y = 0;
988 break;
989 case 'J':
990 switch (s->esc_params[0]) {
991 case 0:
992 /* clear to end of screen */
993 for (y = s->y; y < s->height; y++) {
994 for (x = 0; x < s->width; x++) {
995 if (y == s->y && x < s->x) {
996 continue;
998 console_clear_xy(s, x, y);
1001 break;
1002 case 1:
1003 /* clear from beginning of screen */
1004 for (y = 0; y <= s->y; y++) {
1005 for (x = 0; x < s->width; x++) {
1006 if (y == s->y && x > s->x) {
1007 break;
1009 console_clear_xy(s, x, y);
1012 break;
1013 case 2:
1014 /* clear entire screen */
1015 for (y = 0; y <= s->height; y++) {
1016 for (x = 0; x < s->width; x++) {
1017 console_clear_xy(s, x, y);
1020 break;
1022 break;
1023 case 'K':
1024 switch (s->esc_params[0]) {
1025 case 0:
1026 /* clear to eol */
1027 for(x = s->x; x < s->width; x++) {
1028 console_clear_xy(s, x, s->y);
1030 break;
1031 case 1:
1032 /* clear from beginning of line */
1033 for (x = 0; x <= s->x; x++) {
1034 console_clear_xy(s, x, s->y);
1036 break;
1037 case 2:
1038 /* clear entire line */
1039 for(x = 0; x < s->width; x++) {
1040 console_clear_xy(s, x, s->y);
1042 break;
1044 break;
1045 case 'm':
1046 console_handle_escape(s);
1047 break;
1048 case 'n':
1049 /* report cursor position */
1050 /* TODO: send ESC[row;colR */
1051 break;
1052 case 's':
1053 /* save cursor position */
1054 s->x_saved = s->x;
1055 s->y_saved = s->y;
1056 break;
1057 case 'u':
1058 /* restore cursor position */
1059 s->x = s->x_saved;
1060 s->y = s->y_saved;
1061 break;
1062 default:
1063 #ifdef DEBUG_CONSOLE
1064 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1065 #endif
1066 break;
1068 break;
1073 void console_select(unsigned int index)
1075 TextConsole *s;
1077 if (index >= MAX_CONSOLES)
1078 return;
1079 if (active_console) {
1080 active_console->g_width = ds_get_width(active_console->ds);
1081 active_console->g_height = ds_get_height(active_console->ds);
1083 s = consoles[index];
1084 if (s) {
1085 DisplayState *ds = s->ds;
1086 active_console = s;
1087 if (ds_get_bits_per_pixel(s->ds)) {
1088 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1089 } else {
1090 s->ds->surface->width = s->width;
1091 s->ds->surface->height = s->height;
1093 dpy_resize(s->ds);
1094 vga_hw_invalidate();
1098 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1100 TextConsole *s = chr->opaque;
1101 int i;
1103 s->update_x0 = s->width * FONT_WIDTH;
1104 s->update_y0 = s->height * FONT_HEIGHT;
1105 s->update_x1 = 0;
1106 s->update_y1 = 0;
1107 console_show_cursor(s, 0);
1108 for(i = 0; i < len; i++) {
1109 console_putchar(s, buf[i]);
1111 console_show_cursor(s, 1);
1112 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1113 dpy_update(s->ds, s->update_x0, s->update_y0,
1114 s->update_x1 - s->update_x0,
1115 s->update_y1 - s->update_y0);
1117 return len;
1120 static void kbd_send_chars(void *opaque)
1122 TextConsole *s = opaque;
1123 int len;
1124 uint8_t buf[16];
1126 len = qemu_chr_be_can_write(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_be_write(s->chr, buf, len);
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_ms(rt_clock) + 1);
1142 /* called when an ascii key is pressed */
1143 void kbd_put_keysym(int keysym)
1145 TextConsole *s;
1146 uint8_t buf[16], *q;
1147 int c;
1149 s = active_console;
1150 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1151 return;
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;
1187 if (s->echo) {
1188 console_puts(s->chr, buf, q - buf);
1190 if (s->chr->chr_read) {
1191 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192 kbd_send_chars(s);
1194 break;
1198 static void text_console_invalidate(void *opaque)
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);
1206 console_refresh(s);
1209 static void text_console_update(void *opaque, console_ch_t *chardata)
1211 TextConsole *s = (TextConsole *) opaque;
1212 int i, j, src;
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;
1230 if (s->cursor_invalidate) {
1231 dpy_cursor(s->ds, s->x, s->y);
1232 s->cursor_invalidate = 0;
1236 static TextConsole *get_graphic_console(DisplayState *ds)
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;
1245 return NULL;
1248 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1250 TextConsole *s;
1251 int i;
1253 if (nb_consoles >= MAX_CONSOLES)
1254 return NULL;
1255 s = g_malloc0(sizeof(TextConsole));
1256 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257 (console_type == GRAPHIC_CONSOLE))) {
1258 active_console = s;
1260 s->ds = ds;
1261 s->console_type = console_type;
1262 if (console_type != GRAPHIC_CONSOLE) {
1263 s->index = nb_consoles;
1264 consoles[nb_consoles++] = s;
1265 } else {
1266 /* HACK: Put graphical consoles before text consoles. */
1267 for (i = nb_consoles; i > 0; i--) {
1268 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1269 break;
1270 consoles[i] = consoles[i - 1];
1271 consoles[i]->index = i;
1273 s->index = i;
1274 consoles[i] = s;
1275 nb_consoles++;
1277 return s;
1280 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1282 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1284 int linesize = width * 4;
1285 qemu_alloc_display(surface, width, height, linesize,
1286 qemu_default_pixelformat(32), 0);
1287 return surface;
1290 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1291 int width, int height)
1293 int linesize = width * 4;
1294 qemu_alloc_display(surface, width, height, linesize,
1295 qemu_default_pixelformat(32), 0);
1296 return surface;
1299 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1300 int linesize, PixelFormat pf, int newflags)
1302 void *data;
1303 surface->width = width;
1304 surface->height = height;
1305 surface->linesize = linesize;
1306 surface->pf = pf;
1307 if (surface->flags & QEMU_ALLOCATED_FLAG) {
1308 data = g_realloc(surface->data,
1309 surface->linesize * surface->height);
1310 } else {
1311 data = g_malloc(surface->linesize * surface->height);
1313 surface->data = (uint8_t *)data;
1314 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1315 #ifdef HOST_WORDS_BIGENDIAN
1316 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1317 #endif
1320 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1321 int linesize, uint8_t *data)
1323 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1325 surface->width = width;
1326 surface->height = height;
1327 surface->linesize = linesize;
1328 surface->pf = qemu_default_pixelformat(bpp);
1329 #ifdef HOST_WORDS_BIGENDIAN
1330 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1331 #endif
1332 surface->data = data;
1334 return surface;
1337 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1339 if (surface == NULL)
1340 return;
1341 if (surface->flags & QEMU_ALLOCATED_FLAG)
1342 g_free(surface->data);
1343 g_free(surface);
1346 static struct DisplayAllocator default_allocator = {
1347 defaultallocator_create_displaysurface,
1348 defaultallocator_resize_displaysurface,
1349 defaultallocator_free_displaysurface
1352 static void dumb_display_init(void)
1354 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1355 int width = 640;
1356 int height = 480;
1358 ds->allocator = &default_allocator;
1359 if (is_fixedsize_console()) {
1360 width = active_console->g_width;
1361 height = active_console->g_height;
1363 ds->surface = qemu_create_displaysurface(ds, width, height);
1364 register_displaystate(ds);
1367 /***********************************************************/
1368 /* register display */
1370 void register_displaystate(DisplayState *ds)
1372 DisplayState **s;
1373 s = &display_state;
1374 while (*s != NULL)
1375 s = &(*s)->next;
1376 ds->next = NULL;
1377 *s = ds;
1380 DisplayState *get_displaystate(void)
1382 if (!display_state) {
1383 dumb_display_init ();
1385 return display_state;
1388 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1390 if(ds->allocator == &default_allocator) {
1391 DisplaySurface *surf;
1392 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1393 defaultallocator_free_displaysurface(ds->surface);
1394 ds->surface = surf;
1395 ds->allocator = da;
1397 return ds->allocator;
1400 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1401 vga_hw_invalidate_ptr invalidate,
1402 vga_hw_screen_dump_ptr screen_dump,
1403 vga_hw_text_update_ptr text_update,
1404 void *opaque)
1406 TextConsole *s;
1407 DisplayState *ds;
1409 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1410 ds->allocator = &default_allocator;
1411 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1413 s = new_console(ds, GRAPHIC_CONSOLE);
1414 if (s == NULL) {
1415 qemu_free_displaysurface(ds);
1416 g_free(ds);
1417 return NULL;
1419 s->hw_update = update;
1420 s->hw_invalidate = invalidate;
1421 s->hw_screen_dump = screen_dump;
1422 s->hw_text_update = text_update;
1423 s->hw = opaque;
1425 register_displaystate(ds);
1426 return ds;
1429 int is_graphic_console(void)
1431 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1434 int is_fixedsize_console(void)
1436 return active_console && active_console->console_type != TEXT_CONSOLE;
1439 void console_color_init(DisplayState *ds)
1441 int i, j;
1442 for (j = 0; j < 2; j++) {
1443 for (i = 0; i < 8; i++) {
1444 color_table[j][i] = col_expand(ds,
1445 vga_get_color(ds, color_table_rgb[j][i]));
1450 static void text_console_set_echo(CharDriverState *chr, bool echo)
1452 TextConsole *s = chr->opaque;
1454 s->echo = echo;
1457 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1459 TextConsole *s;
1460 static int color_inited;
1462 s = chr->opaque;
1464 chr->chr_write = console_puts;
1466 s->out_fifo.buf = s->out_fifo_buf;
1467 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1468 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1469 s->ds = ds;
1471 if (!color_inited) {
1472 color_inited = 1;
1473 console_color_init(s->ds);
1475 s->y_displayed = 0;
1476 s->y_base = 0;
1477 s->total_height = DEFAULT_BACKSCROLL;
1478 s->x = 0;
1479 s->y = 0;
1480 if (s->console_type == TEXT_CONSOLE) {
1481 s->g_width = ds_get_width(s->ds);
1482 s->g_height = ds_get_height(s->ds);
1485 s->hw_invalidate = text_console_invalidate;
1486 s->hw_text_update = text_console_update;
1487 s->hw = s;
1489 /* Set text attribute defaults */
1490 s->t_attrib_default.bold = 0;
1491 s->t_attrib_default.uline = 0;
1492 s->t_attrib_default.blink = 0;
1493 s->t_attrib_default.invers = 0;
1494 s->t_attrib_default.unvisible = 0;
1495 s->t_attrib_default.fgcol = COLOR_WHITE;
1496 s->t_attrib_default.bgcol = COLOR_BLACK;
1497 /* set current text attributes to default */
1498 s->t_attrib = s->t_attrib_default;
1499 text_console_resize(s);
1501 if (chr->label) {
1502 char msg[128];
1503 int len;
1505 s->t_attrib.bgcol = COLOR_BLUE;
1506 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1507 console_puts(chr, (uint8_t*)msg, len);
1508 s->t_attrib = s->t_attrib_default;
1511 qemu_chr_generic_open(chr);
1512 if (chr->init)
1513 chr->init(chr);
1516 CharDriverState *text_console_init(QemuOpts *opts)
1518 CharDriverState *chr;
1519 TextConsole *s;
1520 unsigned width;
1521 unsigned height;
1523 chr = g_malloc0(sizeof(CharDriverState));
1525 width = qemu_opt_get_number(opts, "width", 0);
1526 if (width == 0)
1527 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1529 height = qemu_opt_get_number(opts, "height", 0);
1530 if (height == 0)
1531 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1533 if (width == 0 || height == 0) {
1534 s = new_console(NULL, TEXT_CONSOLE);
1535 } else {
1536 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1539 if (!s) {
1540 g_free(chr);
1541 return NULL;
1544 s->chr = chr;
1545 s->g_width = width;
1546 s->g_height = height;
1547 chr->opaque = s;
1548 chr->chr_set_echo = text_console_set_echo;
1549 return chr;
1552 void text_consoles_set_display(DisplayState *ds)
1554 int i;
1556 for (i = 0; i < nb_consoles; i++) {
1557 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1558 text_console_do_init(consoles[i]->chr, ds);
1563 void qemu_console_resize(DisplayState *ds, int width, int height)
1565 TextConsole *s = get_graphic_console(ds);
1566 if (!s) return;
1568 s->g_width = width;
1569 s->g_height = height;
1570 if (is_graphic_console()) {
1571 ds->surface = qemu_resize_displaysurface(ds, width, height);
1572 dpy_resize(ds);
1576 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1577 int dst_x, int dst_y, int w, int h)
1579 if (is_graphic_console()) {
1580 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1584 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1586 PixelFormat pf;
1588 memset(&pf, 0x00, sizeof(PixelFormat));
1590 pf.bits_per_pixel = bpp;
1591 pf.bytes_per_pixel = bpp / 8;
1592 pf.depth = bpp == 32 ? 24 : bpp;
1594 switch (bpp) {
1595 case 24:
1596 pf.rmask = 0x000000FF;
1597 pf.gmask = 0x0000FF00;
1598 pf.bmask = 0x00FF0000;
1599 pf.rmax = 255;
1600 pf.gmax = 255;
1601 pf.bmax = 255;
1602 pf.rshift = 0;
1603 pf.gshift = 8;
1604 pf.bshift = 16;
1605 pf.rbits = 8;
1606 pf.gbits = 8;
1607 pf.bbits = 8;
1608 break;
1609 case 32:
1610 pf.rmask = 0x0000FF00;
1611 pf.gmask = 0x00FF0000;
1612 pf.bmask = 0xFF000000;
1613 pf.amask = 0x00000000;
1614 pf.amax = 255;
1615 pf.rmax = 255;
1616 pf.gmax = 255;
1617 pf.bmax = 255;
1618 pf.ashift = 0;
1619 pf.rshift = 8;
1620 pf.gshift = 16;
1621 pf.bshift = 24;
1622 pf.rbits = 8;
1623 pf.gbits = 8;
1624 pf.bbits = 8;
1625 pf.abits = 8;
1626 break;
1627 default:
1628 break;
1630 return pf;
1633 PixelFormat qemu_default_pixelformat(int bpp)
1635 PixelFormat pf;
1637 memset(&pf, 0x00, sizeof(PixelFormat));
1639 pf.bits_per_pixel = bpp;
1640 pf.bytes_per_pixel = bpp / 8;
1641 pf.depth = bpp == 32 ? 24 : bpp;
1643 switch (bpp) {
1644 case 15:
1645 pf.bits_per_pixel = 16;
1646 pf.bytes_per_pixel = 2;
1647 pf.rmask = 0x00007c00;
1648 pf.gmask = 0x000003E0;
1649 pf.bmask = 0x0000001F;
1650 pf.rmax = 31;
1651 pf.gmax = 31;
1652 pf.bmax = 31;
1653 pf.rshift = 10;
1654 pf.gshift = 5;
1655 pf.bshift = 0;
1656 pf.rbits = 5;
1657 pf.gbits = 5;
1658 pf.bbits = 5;
1659 break;
1660 case 16:
1661 pf.rmask = 0x0000F800;
1662 pf.gmask = 0x000007E0;
1663 pf.bmask = 0x0000001F;
1664 pf.rmax = 31;
1665 pf.gmax = 63;
1666 pf.bmax = 31;
1667 pf.rshift = 11;
1668 pf.gshift = 5;
1669 pf.bshift = 0;
1670 pf.rbits = 5;
1671 pf.gbits = 6;
1672 pf.bbits = 5;
1673 break;
1674 case 24:
1675 pf.rmask = 0x00FF0000;
1676 pf.gmask = 0x0000FF00;
1677 pf.bmask = 0x000000FF;
1678 pf.rmax = 255;
1679 pf.gmax = 255;
1680 pf.bmax = 255;
1681 pf.rshift = 16;
1682 pf.gshift = 8;
1683 pf.bshift = 0;
1684 pf.rbits = 8;
1685 pf.gbits = 8;
1686 pf.bbits = 8;
1687 break;
1688 case 32:
1689 pf.rmask = 0x00FF0000;
1690 pf.gmask = 0x0000FF00;
1691 pf.bmask = 0x000000FF;
1692 pf.amax = 255;
1693 pf.rmax = 255;
1694 pf.gmax = 255;
1695 pf.bmax = 255;
1696 pf.ashift = 24;
1697 pf.rshift = 16;
1698 pf.gshift = 8;
1699 pf.bshift = 0;
1700 pf.rbits = 8;
1701 pf.gbits = 8;
1702 pf.bbits = 8;
1703 pf.abits = 8;
1704 break;
1705 default:
1706 break;
1708 return pf;