1 /* 2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2008, Stephan Aßmus <superstippi@gmx.de> 4 * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com> 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "video.h" 10 #include "bios.h" 11 #include "vesa.h" 12 #include "vesa_info.h" 13 #include "vga.h" 14 #include "mmu.h" 15 16 #include <edid.h> 17 18 #include <arch/cpu.h> 19 #include <boot/stage2.h> 20 #include <boot/platform.h> 21 #include <boot/menu.h> 22 #include <boot/kernel_args.h> 23 #include <boot/images.h> 24 #include <util/list.h> 25 #include <drivers/driver_settings.h> 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 32 #define TRACE_VIDEO 33 #ifdef TRACE_VIDEO 34 # define TRACE(x) dprintf x 35 #else 36 # define TRACE(x) ; 37 #endif 38 39 40 struct video_mode { 41 list_link link; 42 uint16 mode; 43 uint16 width, height, bits_per_pixel; 44 uint32 bytes_per_row; 45 }; 46 47 static vbe_info_block sInfo; 48 static video_mode *sMode, *sDefaultMode; 49 static bool sVesaCompatible; 50 static struct list sModeList; 51 static uint32 sModeCount; 52 static addr_t sFrameBuffer; 53 static bool sModeChosen; 54 static bool sSettingsLoaded; 55 56 57 static int 58 compare_video_modes(video_mode *a, video_mode *b) 59 { 60 int compare = a->width - b->width; 61 if (compare != 0) 62 return compare; 63 64 compare = a->height - b->height; 65 if (compare != 0) 66 return compare; 67 68 // TODO: compare video_mode::mode? 69 return a->bits_per_pixel - b->bits_per_pixel; 70 } 71 72 73 /*! Insert the video mode into the list, sorted by resolution and bit depth. 74 Higher resolutions/depths come first. 75 */ 76 static void 77 add_video_mode(video_mode *videoMode) 78 { 79 video_mode *mode = NULL; 80 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 81 != NULL) { 82 int compare = compare_video_modes(videoMode, mode); 83 if (compare == 0) { 84 // mode already exists 85 return; 86 } 87 88 if (compare > 0) 89 break; 90 } 91 92 list_insert_item_before(&sModeList, mode, videoMode); 93 sModeCount++; 94 } 95 96 97 /*! \brief Finds a video mode with the given resolution. 98 If \a allowPalette is true, 8-bit modes are considered, too. 99 If \a height is \c -1, the height is ignored, and only the width 100 matters. 101 */ 102 static video_mode * 103 find_video_mode(int32 width, int32 height, bool allowPalette) 104 { 105 video_mode *found = NULL; 106 video_mode *mode = NULL; 107 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 108 != NULL) { 109 if (mode->width == width && (height == -1 || mode->height == height) 110 && (mode->bits_per_pixel > 8 || allowPalette)) { 111 if (found == NULL || found->bits_per_pixel < mode->bits_per_pixel) 112 found = mode; 113 } 114 } 115 116 return found; 117 } 118 119 120 static video_mode * 121 closest_video_mode(int32 width, int32 height, int32 depth) 122 { 123 video_mode *bestMode = NULL; 124 uint32 bestDiff = 0; 125 126 video_mode *mode = NULL; 127 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 128 != NULL) { 129 uint32 diff = 2 * abs(mode->width - width) + abs(mode->height - height) 130 + abs(mode->bits_per_pixel - depth); 131 132 if (bestMode == NULL || bestDiff > diff) { 133 bestMode = mode; 134 bestDiff = diff; 135 } 136 } 137 138 return bestMode; 139 } 140 141 142 static video_mode * 143 find_edid_mode(edid1_info &info, bool allowPalette) 144 { 145 video_mode *mode = NULL; 146 147 // try detailed timing first 148 for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) { 149 edid1_detailed_monitor &monitor = info.detailed_monitor[i]; 150 151 if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) { 152 mode = find_video_mode(monitor.data.detailed_timing.h_active, 153 monitor.data.detailed_timing.v_active, allowPalette); 154 if (mode != NULL) 155 return mode; 156 } 157 } 158 159 // try standard timings next 160 for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) { 161 if (info.std_timing[i].h_size <= 256) 162 continue; 163 164 video_mode *found = find_video_mode(info.std_timing[i].h_size, 165 info.std_timing[i].v_size, allowPalette); 166 if (found != NULL) { 167 if (mode != NULL) { 168 // prefer higher resolutions 169 if (found->width > mode->width) 170 mode = found; 171 } else 172 mode = found; 173 } 174 } 175 176 return NULL; 177 } 178 179 180 static bool 181 get_mode_from_settings(void) 182 { 183 if (sSettingsLoaded) 184 return true; 185 186 void *handle = load_driver_settings("vesa"); 187 if (handle == NULL) 188 return false; 189 190 bool found = false; 191 192 const driver_settings *settings = get_driver_settings(handle); 193 if (settings == NULL) 194 goto out; 195 196 sSettingsLoaded = true; 197 198 for (int32 i = 0; i < settings->parameter_count; i++) { 199 driver_parameter ¶meter = settings->parameters[i]; 200 201 if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) { 202 // parameter found, now get its values 203 int32 width = strtol(parameter.values[0], NULL, 0); 204 int32 height = strtol(parameter.values[1], NULL, 0); 205 int32 depth = strtol(parameter.values[2], NULL, 0); 206 207 // search mode that fits 208 209 video_mode *mode = closest_video_mode(width, height, depth); 210 if (mode != NULL) { 211 found = true; 212 sMode = mode; 213 } 214 } 215 } 216 217 out: 218 unload_driver_settings(handle); 219 return found; 220 } 221 222 223 // #pragma mark - vga 224 225 226 static void 227 vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) 228 { 229 out8(firstIndex, VGA_COLOR_WRITE_MODE); 230 // write VGA palette 231 for (int32 i = firstIndex; i < numEntries; i++) { 232 // VGA (usually) has only 6 bits per gun 233 out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA); 234 out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA); 235 out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA); 236 } 237 } 238 239 240 static void 241 vga_enable_bright_background_colors(void) 242 { 243 // reset attribute controller 244 in8(VGA_INPUT_STATUS_1); 245 246 // select mode control register 247 out8(0x30, VGA_ATTRIBUTE_WRITE); 248 249 // read mode control register, change it (we need to clear bit 3), and write it back 250 uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7; 251 out8(mode, VGA_ATTRIBUTE_WRITE); 252 } 253 254 255 // #pragma mark - vesa 256 257 258 static status_t 259 vesa_get_edid(edid1_info *info) 260 { 261 struct bios_regs regs; 262 regs.eax = 0x4f15; 263 regs.ebx = 0; 264 // report DDC service 265 regs.ecx = 0; 266 regs.es = 0; 267 regs.edi = 0; 268 call_bios(0x10, ®s); 269 270 dprintf("EDID1: %lx\n", regs.eax); 271 // %ah contains the error code 272 // %al determines wether or not the function is supported 273 if (regs.eax != 0x4f) 274 return B_NOT_SUPPORTED; 275 276 dprintf("EDID2: ebx %lx\n", regs.ebx); 277 // test if DDC is supported by the monitor 278 if ((regs.ebx & 3) == 0) 279 return B_NOT_SUPPORTED; 280 281 edid1_raw edidRaw; 282 283 regs.eax = 0x4f15; 284 regs.ebx = 1; 285 // read EDID 286 regs.ecx = 0; 287 regs.edx = 0; 288 regs.es = ADDRESS_SEGMENT(&edidRaw); 289 regs.edi = ADDRESS_OFFSET(&edidRaw); 290 call_bios(0x10, ®s); 291 dprintf("EDID3: %lx\n", regs.eax); 292 293 if (regs.eax != 0x4f) 294 return B_NOT_SUPPORTED; 295 296 // retrieved EDID - now parse it 297 dprintf("Got EDID!\n"); 298 edid_decode(info, &edidRaw); 299 edid_dump(info); 300 return B_OK; 301 } 302 303 304 static status_t 305 vesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo) 306 { 307 memset(modeInfo, 0, sizeof(vbe_mode_info)); 308 309 struct bios_regs regs; 310 regs.eax = 0x4f01; 311 regs.ecx = mode; 312 regs.es = ADDRESS_SEGMENT(modeInfo); 313 regs.edi = ADDRESS_OFFSET(modeInfo); 314 call_bios(0x10, ®s); 315 316 // %ah contains the error code 317 if ((regs.eax & 0xff00) != 0) 318 return B_ENTRY_NOT_FOUND; 319 320 return B_OK; 321 } 322 323 324 static status_t 325 vesa_get_vbe_info_block(vbe_info_block *info) 326 { 327 memset(info, 0, sizeof(vbe_info_block)); 328 info->signature = VBE2_SIGNATURE; 329 330 struct bios_regs regs; 331 regs.eax = 0x4f00; 332 regs.es = ADDRESS_SEGMENT(info); 333 regs.edi = ADDRESS_OFFSET(info); 334 call_bios(0x10, ®s); 335 336 // %ah contains the error code 337 if ((regs.eax & 0xff00) != 0) 338 return B_ERROR; 339 340 if (info->signature != VESA_SIGNATURE) 341 return B_ERROR; 342 343 dprintf("VESA version = %d.%d\n", info->version.major, info->version.minor); 344 345 if (info->version.major < 2) { 346 dprintf("VESA support too old\n"); 347 return B_ERROR; 348 } 349 350 info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string); 351 info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list); 352 dprintf("oem string: %s\n", (const char *)info->oem_string); 353 354 return B_OK; 355 } 356 357 358 static status_t 359 vesa_init(vbe_info_block *info, video_mode **_standardMode) 360 { 361 if (vesa_get_vbe_info_block(info) != B_OK) 362 return B_ERROR; 363 364 // fill mode list and find standard video mode 365 366 video_mode *standardMode = NULL; 367 368 for (int32 i = 0; true; i++) { 369 uint16 mode = ((uint16 *)info->mode_list)[i]; 370 if (mode == 0xffff) 371 break; 372 373 TRACE((" %x: ", mode)); 374 375 struct vbe_mode_info modeInfo; 376 if (vesa_get_mode_info(mode, &modeInfo) == B_OK) { 377 TRACE(("%u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", 378 modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes, 379 modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes, 380 modeInfo.num_banks)); 381 382 const uint32 requiredAttributes = MODE_ATTR_AVAILABLE 383 | MODE_ATTR_GRAPHICS_MODE | MODE_ATTR_COLOR_MODE 384 | MODE_ATTR_LINEAR_BUFFER; 385 386 if (modeInfo.width >= 640 387 && modeInfo.physical_base != 0 388 && modeInfo.num_planes == 1 389 && (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL 390 || modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR) 391 && (modeInfo.attributes & requiredAttributes) 392 == requiredAttributes) { 393 // this mode fits our needs 394 video_mode *videoMode = (video_mode *)malloc( 395 sizeof(struct video_mode)); 396 if (videoMode == NULL) 397 continue; 398 399 videoMode->mode = mode; 400 videoMode->bytes_per_row = modeInfo.bytes_per_row; 401 videoMode->width = modeInfo.width; 402 videoMode->height = modeInfo.height; 403 videoMode->bits_per_pixel = modeInfo.bits_per_pixel; 404 if (modeInfo.bits_per_pixel == 16 405 && modeInfo.red_mask_size + modeInfo.green_mask_size 406 + modeInfo.blue_mask_size == 15) { 407 // this is really a 15-bit mode 408 videoMode->bits_per_pixel = 15; 409 } 410 411 add_video_mode(videoMode); 412 } 413 } else 414 TRACE(("(failed)\n")); 415 } 416 417 // Choose default resolution (when no EDID information is available) 418 const uint32 kPreferredWidth = 1024; 419 const uint32 kFallbackWidth = 800; 420 421 standardMode = find_video_mode(kPreferredWidth, -1, false); 422 if (standardMode == NULL) { 423 standardMode = find_video_mode(kFallbackWidth, -1, false); 424 if (standardMode == NULL) { 425 standardMode = find_video_mode(kPreferredWidth, -1, true); 426 if (standardMode == NULL) 427 standardMode = find_video_mode(kFallbackWidth, -1, true); 428 } 429 } 430 if (standardMode == NULL) { 431 // just take any mode 432 standardMode = (video_mode *)list_get_first_item(&sModeList); 433 } 434 435 if (standardMode == NULL) { 436 // no usable VESA mode found... 437 return B_ERROR; 438 } 439 440 *_standardMode = standardMode; 441 return B_OK; 442 } 443 444 445 #if 0 446 static status_t 447 vesa_get_mode(uint16 *_mode) 448 { 449 struct bios_regs regs; 450 regs.eax = 0x4f03; 451 call_bios(0x10, ®s); 452 453 if ((regs.eax & 0xffff) != 0x4f) 454 return B_ERROR; 455 456 *_mode = regs.ebx & 0xffff; 457 return B_OK; 458 } 459 #endif 460 461 462 static status_t 463 vesa_set_mode(uint16 mode) 464 { 465 struct bios_regs regs; 466 regs.eax = 0x4f02; 467 regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 468 call_bios(0x10, ®s); 469 470 if ((regs.eax & 0xffff) != 0x4f) 471 return B_ERROR; 472 473 #if 0 474 // make sure we have 8 bits per color channel 475 regs.eax = 0x4f08; 476 regs.ebx = 8 << 8; 477 call_bios(0x10, ®s); 478 #endif 479 480 return B_OK; 481 } 482 483 484 static status_t 485 vesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) 486 { 487 // is this an 8 bit indexed color mode? 488 if (gKernelArgs.frame_buffer.depth != 8) 489 return B_BAD_TYPE; 490 491 #if 0 492 struct bios_regs regs; 493 regs.eax = 0x4f09; 494 regs.ebx = 0; 495 regs.ecx = numEntries; 496 regs.edx = firstIndex; 497 regs.es = (addr_t)palette >> 4; 498 regs.edi = (addr_t)palette & 0xf; 499 call_bios(0x10, ®s); 500 501 if ((regs.eax & 0xffff) != 0x4f) { 502 #endif 503 // the VESA call does not work, just try good old VGA mechanism 504 vga_set_palette(palette, firstIndex, numEntries); 505 #if 0 506 return B_ERROR; 507 } 508 #endif 509 return B_OK; 510 } 511 512 513 // #pragma mark - 514 515 516 bool 517 video_mode_hook(Menu *menu, MenuItem *item) 518 { 519 // find selected mode 520 video_mode *mode = NULL; 521 522 menu = item->Submenu(); 523 item = menu->FindMarked(); 524 if (item != NULL) { 525 switch (menu->IndexOf(item)) { 526 case 0: 527 // "Default" mode special 528 sMode = sDefaultMode; 529 sModeChosen = false; 530 return true; 531 case 1: 532 // "Standard VGA" mode special 533 // sets sMode to NULL which triggers VGA mode 534 break; 535 default: 536 mode = (video_mode *)item->Data(); 537 break; 538 } 539 } 540 541 if (mode != sMode) { 542 // update standard mode 543 // ToDo: update fb settings! 544 sMode = mode; 545 } 546 547 sModeChosen = true; 548 return true; 549 } 550 551 552 Menu * 553 video_mode_menu() 554 { 555 Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode"); 556 MenuItem *item; 557 558 menu->AddItem(item = new(nothrow) MenuItem("Default")); 559 item->SetMarked(true); 560 item->Select(true); 561 item->SetHelpText("The Default video mode is the one currently configured " 562 "in the system. If there is no mode configured yet, a viable mode will " 563 "be chosen automatically."); 564 565 menu->AddItem(new(nothrow) MenuItem("Standard VGA")); 566 567 video_mode *mode = NULL; 568 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { 569 char label[64]; 570 sprintf(label, "%ux%u %u bit", mode->width, mode->height, 571 mode->bits_per_pixel); 572 573 menu->AddItem(item = new(nothrow) MenuItem(label)); 574 item->SetData(mode); 575 } 576 577 menu->AddSeparatorItem(); 578 menu->AddItem(item = new(nothrow) MenuItem("Return to main menu")); 579 item->SetType(MENU_ITEM_NO_CHOICE); 580 581 return menu; 582 } 583 584 585 static void 586 set_vga_mode(void) 587 { 588 // sets 640x480 16 colors graphics mode 589 bios_regs regs; 590 regs.eax = 0x0012; 591 call_bios(0x10, ®s); 592 } 593 594 595 static void 596 set_text_mode(void) 597 { 598 // sets 80x25 text console 599 bios_regs regs; 600 regs.eax = 0x0003; 601 call_bios(0x10, ®s); 602 603 // turns off text cursor 604 regs.eax = 0x0100; 605 regs.ecx = 0x2000; 606 call_bios(0x10, ®s); 607 } 608 609 610 // #pragma mark - blit 611 612 613 static void 614 blit32(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 615 uint16 left, uint16 top) 616 { 617 uint32 *start = (uint32 *)(sFrameBuffer 618 + gKernelArgs.frame_buffer.bytes_per_row * top + 4 * left); 619 620 for (int32 y = 0; y < height; y++) { 621 const uint8* src = data; 622 uint32* dst = start; 623 for (int32 x = 0; x < width; x++) { 624 dst[0] = (src[2] << 16) | (src[1] << 8) | (src[0]); 625 dst++; 626 src += 3; 627 } 628 629 data += imageWidth * 3; 630 start = (uint32 *)((addr_t)start 631 + gKernelArgs.frame_buffer.bytes_per_row); 632 } 633 } 634 635 636 static void 637 blit24(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 638 uint16 left, uint16 top) 639 { 640 uint8 *start = (uint8 *)sFrameBuffer 641 + gKernelArgs.frame_buffer.bytes_per_row * top + 3 * left; 642 643 for (int32 y = 0; y < height; y++) { 644 const uint8* src = data; 645 uint8* dst = start; 646 for (int32 x = 0; x < width; x++) { 647 dst[0] = src[0]; 648 dst[1] = src[1]; 649 dst[2] = src[2]; 650 dst += 3; 651 src += 3; 652 } 653 654 data += imageWidth * 3; 655 start = start + gKernelArgs.frame_buffer.bytes_per_row; 656 } 657 } 658 659 660 static void 661 blit16(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 662 uint16 left, uint16 top) 663 { 664 uint16 *start = (uint16 *)(sFrameBuffer 665 + gKernelArgs.frame_buffer.bytes_per_row * top + 2 * left); 666 667 for (int32 y = 0; y < height; y++) { 668 const uint8* src = data; 669 uint16* dst = start; 670 for (int32 x = 0; x < width; x++) { 671 dst[0] = ((src[2] >> 3) << 11) 672 | ((src[1] >> 2) << 5) 673 | ((src[0] >> 3)); 674 dst++; 675 src += 3; 676 } 677 678 data += imageWidth * 3; 679 start = (uint16 *)((addr_t)start 680 + gKernelArgs.frame_buffer.bytes_per_row); 681 } 682 } 683 684 685 static void 686 blit15(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 687 uint16 left, uint16 top) 688 { 689 uint16 *start = (uint16 *)(sFrameBuffer 690 + gKernelArgs.frame_buffer.bytes_per_row * top + 2 * left); 691 692 for (int32 y = 0; y < height; y++) { 693 const uint8* src = data; 694 uint16* dst = start; 695 for (int32 x = 0; x < width; x++) { 696 dst[0] = ((src[2] >> 3) << 10) 697 | ((src[1] >> 3) << 5) 698 | ((src[0] >> 3)); 699 dst++; 700 src += 3; 701 } 702 703 data += imageWidth * 3; 704 start = (uint16 *)((addr_t)start 705 + gKernelArgs.frame_buffer.bytes_per_row); 706 } 707 } 708 709 710 static void 711 blit8(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 712 const uint8 *palette, uint16 left, uint16 top) 713 { 714 if (!data || !palette) 715 return; 716 717 if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK) 718 dprintf("set palette failed!\n"); 719 720 addr_t start = sFrameBuffer + gKernelArgs.frame_buffer.bytes_per_row * top 721 + left; 722 723 for (int32 i = 0; i < height; i++) { 724 memcpy((void *)(start + gKernelArgs.frame_buffer.bytes_per_row * i), 725 &data[i * imageWidth], width); 726 } 727 } 728 729 730 static void 731 blit4(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 732 const uint8 *palette, uint16 left, uint16 top) 733 { 734 if (!data || !palette) 735 return; 736 // vga_set_palette((const uint8 *)kPalette16, 0, 16); 737 // ToDo: no boot logo yet in VGA mode 738 #if 1 739 // this draws 16 big rectangles in all the available colors 740 uint8 *bits = (uint8 *)sFrameBuffer; 741 uint32 bytesPerRow = 80; 742 for (int32 i = 0; i < 32; i++) { 743 bits[9 * bytesPerRow + i + 2] = 0x55; 744 bits[30 * bytesPerRow + i + 2] = 0xaa; 745 } 746 747 for (int32 y = 10; y < 30; y++) { 748 for (int32 i = 0; i < 16; i++) { 749 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 750 bits[32 * bytesPerRow + i*2 + 2] = i; 751 752 if (i & 1) { 753 out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX); 754 bits[y * bytesPerRow + i*2 + 2] = 0xff; 755 bits[y * bytesPerRow + i*2 + 3] = 0xff; 756 } 757 if (i & 2) { 758 out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX); 759 bits[y * bytesPerRow + i*2 + 2] = 0xff; 760 bits[y * bytesPerRow + i*2 + 3] = 0xff; 761 } 762 if (i & 4) { 763 out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX); 764 bits[y * bytesPerRow + i*2 + 2] = 0xff; 765 bits[y * bytesPerRow + i*2 + 3] = 0xff; 766 } 767 if (i & 8) { 768 out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX); 769 bits[y * bytesPerRow + i*2 + 2] = 0xff; 770 bits[y * bytesPerRow + i*2 + 3] = 0xff; 771 } 772 } 773 } 774 775 // enable all planes again 776 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 777 #endif 778 } 779 780 781 static void 782 blit_image(const uint8 *data, const uint8* indexedData, uint16 width, 783 uint16 height, uint16 imageWidth, const uint8 *palette, uint16 left, 784 uint16 top) 785 { 786 switch (gKernelArgs.frame_buffer.depth) { 787 case 4: 788 return blit4(indexedData, width, height, imageWidth, palette, 789 left, top); 790 case 8: 791 return blit8(indexedData, width, height, imageWidth, palette, 792 left, top); 793 case 15: 794 return blit15(data, width, height, imageWidth, left, top); 795 case 16: 796 return blit16(data, width, height, imageWidth, left, top); 797 case 24: 798 return blit24(data, width, height, imageWidth, left, top); 799 case 32: 800 return blit32(data, width, height, imageWidth, left, top); 801 } 802 } 803 804 805 static void 806 uncompress_RLE(const uint8 compressed[], uint8 *uncompressed) 807 { 808 uint32 cursorUncompressed = 0; 809 uint32 cursorCompressed = 0; 810 uint8 count = 0; 811 uint8 item = 0; 812 int i = 0; 813 for (uint8 c = 0; c < 3; c++) { 814 // for Red channel, then Green, then finally Blue... 815 cursorUncompressed = c; 816 while (compressed[cursorCompressed]) { 817 // at the end of the channel there is a terminating 0, 818 // so the loop will end... (ref: generate_boot_screen.cpp) 819 count = compressed[cursorCompressed++]; 820 if (count < 128) { 821 // regular run, repeat "item" "count" times... 822 item = compressed[cursorCompressed++]; 823 for (i = count - 1; i >= 0; --i) { 824 uncompressed[cursorUncompressed] = item; 825 cursorUncompressed += 3; 826 } 827 } else { 828 // enumeration, just write the next "count" items as is... 829 count = count - 128; 830 for (i = count - 1; i >= 0; --i) { 831 uncompressed[cursorUncompressed] 832 = compressed[cursorCompressed++]; 833 cursorUncompressed += 3; 834 } 835 } 836 } 837 // the current position of compressed[cursor] is the end of channel, 838 // we skip it... 839 cursorCompressed++; 840 } 841 } 842 843 // #pragma mark - 844 845 extern "C" void 846 platform_switch_to_logo(void) 847 { 848 // in debug mode, we'll never show the logo 849 if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) 850 return; 851 852 addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; 853 size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size; 854 855 if (sVesaCompatible && sMode != NULL) { 856 if (!sModeChosen) 857 get_mode_from_settings(); 858 859 // On some BIOS / chipset / monitor combinations, there seems to be a timing issue between 860 // getting the EDID data and setting the video mode. As such we wait here briefly to give 861 // everything enough time to settle. 862 spin(1000); 863 if (vesa_set_mode(sMode->mode) != B_OK) 864 goto fallback; 865 866 struct vbe_mode_info modeInfo; 867 if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK) 868 goto fallback; 869 870 gKernelArgs.frame_buffer.width = modeInfo.width; 871 gKernelArgs.frame_buffer.height = modeInfo.height; 872 gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row; 873 gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel; 874 gKernelArgs.frame_buffer.physical_buffer.size = modeInfo.bytes_per_row 875 * gKernelArgs.frame_buffer.height; 876 gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; 877 } else { 878 fallback: 879 // use standard VGA mode 640x480x4 880 set_vga_mode(); 881 882 gKernelArgs.frame_buffer.width = 640; 883 gKernelArgs.frame_buffer.height = 480; 884 gKernelArgs.frame_buffer.bytes_per_row = 640 / 2; 885 gKernelArgs.frame_buffer.depth = 4; 886 gKernelArgs.frame_buffer.physical_buffer.size 887 = gKernelArgs.frame_buffer.width 888 * gKernelArgs.frame_buffer.height / 2; 889 gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000; 890 } 891 892 dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width, 893 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth); 894 895 gKernelArgs.frame_buffer.enabled = true; 896 897 // If the new frame buffer is either larger than the old one or located at 898 // a different address, we need to remap it, so we first have to throw 899 // away its previous mapping 900 if (lastBase != 0 901 && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start 902 || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) { 903 mmu_free((void *)sFrameBuffer, lastSize); 904 lastBase = 0; 905 } 906 if (lastBase == 0) { 907 // the graphics memory has not been mapped yet! 908 sFrameBuffer = mmu_map_physical_memory( 909 gKernelArgs.frame_buffer.physical_buffer.start, 910 gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags); 911 } 912 913 // clear the video memory 914 memset((void *)sFrameBuffer, 0, 915 gKernelArgs.frame_buffer.physical_buffer.size); 916 917 uint8 *uncompressedLogo = (uint8 *)kernel_args_malloc(kSplashLogoWidth 918 * kSplashLogoHeight * 3); 919 if (uncompressedLogo == NULL) 920 return; 921 uncompress_RLE(kSplashLogoCompressedImage, uncompressedLogo); 922 923 // TODO: support indexed versions of the images! 924 925 // render splash logo 926 uint16 iconsHalfHeight = kSplashIconsHeight / 2; 927 928 int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width); 929 int height = min_c(kSplashLogoHeight + iconsHalfHeight, 930 gKernelArgs.frame_buffer.height); 931 int placementX = max_c(0, min_c(100, kSplashLogoPlacementX)); 932 int placementY = max_c(0, min_c(100, kSplashLogoPlacementY)); 933 934 int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; 935 int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100; 936 937 height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height); 938 blit_image(uncompressedLogo, NULL, width, height, kSplashLogoWidth, 939 NULL, x, y); 940 941 kernel_args_free(uncompressedLogo); 942 943 gKernelArgs.boot_splash = (uint8 *)kernel_args_malloc(kSplashIconsWidth 944 * kSplashIconsHeight * 3); 945 if (gKernelArgs.boot_splash == NULL) 946 return; 947 uncompress_RLE(kSplashIconsCompressedImage, gKernelArgs.boot_splash ); 948 949 // render initial (grayed out) icons 950 // the grayed out version is the lower half of the icons image 951 952 width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width); 953 height = min_c(kSplashLogoHeight + iconsHalfHeight, 954 gKernelArgs.frame_buffer.height); 955 placementX = max_c(0, min_c(100, kSplashIconsPlacementX)); 956 placementY = max_c(0, min_c(100, kSplashIconsPlacementY)); 957 958 x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; 959 y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height) 960 * placementY / 100; 961 962 // pointer into the lower half of the icons image data 963 const uint8* lowerHalfIconImage = gKernelArgs.boot_splash 964 + (kSplashIconsWidth * iconsHalfHeight) * 3; 965 height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height); 966 blit_image(lowerHalfIconImage, NULL, width, height, 967 kSplashIconsWidth, NULL, x, y); 968 } 969 970 971 extern "C" void 972 platform_switch_to_text_mode(void) 973 { 974 if (!gKernelArgs.frame_buffer.enabled) { 975 vga_enable_bright_background_colors(); 976 return; 977 } 978 979 set_text_mode(); 980 gKernelArgs.frame_buffer.enabled = 0; 981 982 vga_enable_bright_background_colors(); 983 } 984 985 986 extern "C" status_t 987 platform_init_video(void) 988 { 989 gKernelArgs.frame_buffer.enabled = 0; 990 list_init(&sModeList); 991 992 set_text_mode(); 993 // You may wonder why we do this here: 994 // Obviously, some graphics card BIOS implementations don't 995 // report all available modes unless you've done this before 996 // getting the VESA information. 997 // One example of those is the SiS 630 chipset in my laptop. 998 999 sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; 1000 if (!sVesaCompatible) { 1001 TRACE(("No VESA compatible graphics!\n")); 1002 return B_ERROR; 1003 } 1004 1005 TRACE(("VESA compatible graphics!\n")); 1006 1007 // store VESA modes into kernel args 1008 vesa_mode *modes = (vesa_mode *)kernel_args_malloc( 1009 sModeCount * sizeof(vesa_mode)); 1010 if (modes != NULL) { 1011 video_mode *mode = NULL; 1012 uint32 i = 0; 1013 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 1014 != NULL) { 1015 modes[i].mode = mode->mode; 1016 modes[i].width = mode->width; 1017 modes[i].height = mode->height; 1018 modes[i].bits_per_pixel = mode->bits_per_pixel; 1019 i++; 1020 } 1021 1022 gKernelArgs.vesa_modes = modes; 1023 gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode); 1024 } 1025 1026 edid1_info info; 1027 if (vesa_get_edid(&info) == B_OK) { 1028 // we got EDID information from the monitor, try to find a new default 1029 // mode 1030 video_mode *defaultMode = find_edid_mode(info, false); 1031 if (defaultMode == NULL) 1032 find_edid_mode(info, true); 1033 1034 if (defaultMode != NULL) { 1035 // We found a new default mode to use! 1036 sDefaultMode = defaultMode; 1037 } 1038 1039 gKernelArgs.edid_info = kernel_args_malloc(sizeof(edid1_info)); 1040 if (gKernelArgs.edid_info != NULL) 1041 memcpy(gKernelArgs.edid_info, &info, sizeof(edid1_info)); 1042 } 1043 1044 sMode = sDefaultMode; 1045 return B_OK; 1046 } 1047 1048