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