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