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