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