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