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