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