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 = 0x12; 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 = 3; 601 call_bios(0x10, ®s); 602 } 603 604 605 // #pragma mark - blit 606 607 608 static void 609 blit32(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 610 uint16 left, uint16 top) 611 { 612 uint32 *start = (uint32 *)(sFrameBuffer 613 + gKernelArgs.frame_buffer.bytes_per_row * top + 4 * left); 614 615 for (int32 y = 0; y < height; y++) { 616 const uint8* src = data; 617 uint32* dst = start; 618 for (int32 x = 0; x < width; x++) { 619 dst[0] = (src[2] << 16) | (src[1] << 8) | (src[0]); 620 dst++; 621 src += 3; 622 } 623 624 data += imageWidth * 3; 625 start = (uint32 *)((addr_t)start 626 + gKernelArgs.frame_buffer.bytes_per_row); 627 } 628 } 629 630 631 static void 632 blit24(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 633 uint16 left, uint16 top) 634 { 635 uint8 *start = (uint8 *)sFrameBuffer 636 + gKernelArgs.frame_buffer.bytes_per_row * top + 3 * left; 637 638 for (int32 y = 0; y < height; y++) { 639 const uint8* src = data; 640 uint8* dst = start; 641 for (int32 x = 0; x < width; x++) { 642 dst[0] = src[0]; 643 dst[1] = src[1]; 644 dst[2] = src[2]; 645 dst += 3; 646 src += 3; 647 } 648 649 data += imageWidth * 3; 650 start = start + gKernelArgs.frame_buffer.bytes_per_row; 651 } 652 } 653 654 655 static void 656 blit16(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 657 uint16 left, uint16 top) 658 { 659 uint16 *start = (uint16 *)(sFrameBuffer 660 + gKernelArgs.frame_buffer.bytes_per_row * top + 2 * left); 661 662 for (int32 y = 0; y < height; y++) { 663 const uint8* src = data; 664 uint16* dst = start; 665 for (int32 x = 0; x < width; x++) { 666 dst[0] = ((src[2] >> 3) << 11) 667 | ((src[1] >> 2) << 5) 668 | ((src[0] >> 3)); 669 dst++; 670 src += 3; 671 } 672 673 data += imageWidth * 3; 674 start = (uint16 *)((addr_t)start 675 + gKernelArgs.frame_buffer.bytes_per_row); 676 } 677 } 678 679 680 static void 681 blit15(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 682 uint16 left, uint16 top) 683 { 684 uint16 *start = (uint16 *)(sFrameBuffer 685 + gKernelArgs.frame_buffer.bytes_per_row * top + 2 * left); 686 687 for (int32 y = 0; y < height; y++) { 688 const uint8* src = data; 689 uint16* dst = start; 690 for (int32 x = 0; x < width; x++) { 691 dst[0] = ((src[2] >> 3) << 10) 692 | ((src[1] >> 3) << 5) 693 | ((src[0] >> 3)); 694 dst++; 695 src += 3; 696 } 697 698 data += imageWidth * 3; 699 start = (uint16 *)((addr_t)start 700 + gKernelArgs.frame_buffer.bytes_per_row); 701 } 702 } 703 704 705 static void 706 blit8(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 707 const uint8 *palette, uint16 left, uint16 top) 708 { 709 if (!data || !palette) 710 return; 711 712 if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK) 713 dprintf("set palette failed!\n"); 714 715 addr_t start = sFrameBuffer + gKernelArgs.frame_buffer.bytes_per_row * top 716 + left; 717 718 for (int32 i = 0; i < height; i++) { 719 memcpy((void *)(start + gKernelArgs.frame_buffer.bytes_per_row * i), 720 &data[i * imageWidth], width); 721 } 722 } 723 724 725 static void 726 blit4(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth, 727 const uint8 *palette, uint16 left, uint16 top) 728 { 729 if (!data || !palette) 730 return; 731 // vga_set_palette((const uint8 *)kPalette16, 0, 16); 732 // ToDo: no boot logo yet in VGA mode 733 #if 1 734 // this draws 16 big rectangles in all the available colors 735 uint8 *bits = (uint8 *)sFrameBuffer; 736 uint32 bytesPerRow = 80; 737 for (int32 i = 0; i < 32; i++) { 738 bits[9 * bytesPerRow + i + 2] = 0x55; 739 bits[30 * bytesPerRow + i + 2] = 0xaa; 740 } 741 742 for (int32 y = 10; y < 30; y++) { 743 for (int32 i = 0; i < 16; i++) { 744 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 745 bits[32 * bytesPerRow + i*2 + 2] = i; 746 747 if (i & 1) { 748 out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX); 749 bits[y * bytesPerRow + i*2 + 2] = 0xff; 750 bits[y * bytesPerRow + i*2 + 3] = 0xff; 751 } 752 if (i & 2) { 753 out16((2 << 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 & 4) { 758 out16((4 << 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 & 8) { 763 out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX); 764 bits[y * bytesPerRow + i*2 + 2] = 0xff; 765 bits[y * bytesPerRow + i*2 + 3] = 0xff; 766 } 767 } 768 } 769 770 // enable all planes again 771 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 772 #endif 773 } 774 775 776 static void 777 blit_image(const uint8 *data, const uint8* indexedData, uint16 width, 778 uint16 height, uint16 imageWidth, const uint8 *palette, uint16 left, 779 uint16 top) 780 { 781 switch (gKernelArgs.frame_buffer.depth) { 782 case 4: 783 return blit4(indexedData, width, height, imageWidth, palette, 784 left, top); 785 case 8: 786 return blit8(indexedData, width, height, imageWidth, palette, 787 left, top); 788 case 15: 789 return blit15(data, width, height, imageWidth, left, top); 790 case 16: 791 return blit16(data, width, height, imageWidth, left, top); 792 case 24: 793 return blit24(data, width, height, imageWidth, left, top); 794 case 32: 795 return blit32(data, width, height, imageWidth, left, top); 796 } 797 } 798 799 800 static void 801 uncompress_RLE(const uint8 compressed[], uint8 *uncompressed) 802 { 803 uint32 cursorUncompressed = 0; 804 uint32 cursorCompressed = 0; 805 uint8 count = 0; 806 uint8 item = 0; 807 int i = 0; 808 for (uint8 c = 0; c < 3; c++) { 809 // for Red channel, then Green, then finally Blue... 810 cursorUncompressed = c; 811 while (compressed[cursorCompressed]) { 812 // at the end of the channel there is a terminating 0, 813 // so the loop will end... (ref: generate_boot_screen.cpp) 814 count = compressed[cursorCompressed++]; 815 if (count < 128) { 816 // regular run, repeat "item" "count" times... 817 item = compressed[cursorCompressed++]; 818 for (i = count - 1; i >= 0; --i) { 819 uncompressed[cursorUncompressed] = item; 820 cursorUncompressed += 3; 821 } 822 } else { 823 // enumeration, just write the next "count" items as is... 824 count = count - 128; 825 for (i = count - 1; i >= 0; --i) { 826 uncompressed[cursorUncompressed] 827 = compressed[cursorCompressed++]; 828 cursorUncompressed += 3; 829 } 830 } 831 } 832 // the current position of compressed[cursor] is the end of channel, 833 // we skip it... 834 cursorCompressed++; 835 } 836 } 837 838 // #pragma mark - 839 840 extern "C" void 841 platform_switch_to_logo(void) 842 { 843 // in debug mode, we'll never show the logo 844 if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) 845 return; 846 847 addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; 848 size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size; 849 850 if (sVesaCompatible && sMode != NULL) { 851 if (!sModeChosen) 852 get_mode_from_settings(); 853 854 // On some BIOS / chipset / monitor combinations, there seems to be a timing issue between 855 // getting the EDID data and setting the video mode. As such we wait here briefly to give 856 // everything enough time to settle. 857 spin(1000); 858 if (vesa_set_mode(sMode->mode) != B_OK) 859 goto fallback; 860 861 struct vbe_mode_info modeInfo; 862 if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK) 863 goto fallback; 864 865 gKernelArgs.frame_buffer.width = modeInfo.width; 866 gKernelArgs.frame_buffer.height = modeInfo.height; 867 gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row; 868 gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel; 869 gKernelArgs.frame_buffer.physical_buffer.size = modeInfo.bytes_per_row 870 * gKernelArgs.frame_buffer.height; 871 gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; 872 } else { 873 fallback: 874 // use standard VGA mode 640x480x4 875 set_vga_mode(); 876 877 gKernelArgs.frame_buffer.width = 640; 878 gKernelArgs.frame_buffer.height = 480; 879 gKernelArgs.frame_buffer.bytes_per_row = 640 / 2; 880 gKernelArgs.frame_buffer.depth = 4; 881 gKernelArgs.frame_buffer.physical_buffer.size 882 = gKernelArgs.frame_buffer.width 883 * gKernelArgs.frame_buffer.height / 2; 884 gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000; 885 } 886 887 dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width, 888 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth); 889 890 gKernelArgs.frame_buffer.enabled = true; 891 892 // If the new frame buffer is either larger than the old one or located at 893 // a different address, we need to remap it, so we first have to throw 894 // away its previous mapping 895 if (lastBase != 0 896 && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start 897 || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) { 898 mmu_free((void *)sFrameBuffer, lastSize); 899 lastBase = 0; 900 } 901 if (lastBase == 0) { 902 // the graphics memory has not been mapped yet! 903 sFrameBuffer = mmu_map_physical_memory( 904 gKernelArgs.frame_buffer.physical_buffer.start, 905 gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags); 906 } 907 908 // clear the video memory 909 memset((void *)sFrameBuffer, 0, 910 gKernelArgs.frame_buffer.physical_buffer.size); 911 912 uint8 *uncompressedLogo = (uint8 *)kernel_args_malloc(kSplashLogoWidth 913 * kSplashLogoHeight * 3); 914 if (uncompressedLogo == NULL) 915 return; 916 uncompress_RLE(kSplashLogoCompressedImage, uncompressedLogo); 917 918 // TODO: support indexed versions of the images! 919 920 // render splash logo 921 uint16 iconsHalfHeight = kSplashIconsHeight / 2; 922 923 int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width); 924 int height = min_c(kSplashLogoHeight + iconsHalfHeight, 925 gKernelArgs.frame_buffer.height); 926 int placementX = max_c(0, min_c(100, kSplashLogoPlacementX)); 927 int placementY = max_c(0, min_c(100, kSplashLogoPlacementY)); 928 929 int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; 930 int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100; 931 932 height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height); 933 blit_image(uncompressedLogo, NULL, width, height, kSplashLogoWidth, 934 NULL, x, y); 935 936 kernel_args_free(uncompressedLogo); 937 938 gKernelArgs.boot_splash = (uint8 *)kernel_args_malloc(kSplashIconsWidth 939 * kSplashIconsHeight * 3); 940 if (gKernelArgs.boot_splash == NULL) 941 return; 942 uncompress_RLE(kSplashIconsCompressedImage, gKernelArgs.boot_splash ); 943 944 // render initial (grayed out) icons 945 // the grayed out version is the lower half of the icons image 946 947 width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width); 948 height = min_c(kSplashLogoHeight + iconsHalfHeight, 949 gKernelArgs.frame_buffer.height); 950 placementX = max_c(0, min_c(100, kSplashIconsPlacementX)); 951 placementY = max_c(0, min_c(100, kSplashIconsPlacementY)); 952 953 x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; 954 y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height) 955 * placementY / 100; 956 957 // pointer into the lower half of the icons image data 958 const uint8* lowerHalfIconImage = gKernelArgs.boot_splash 959 + (kSplashIconsWidth * iconsHalfHeight) * 3; 960 height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height); 961 blit_image(lowerHalfIconImage, NULL, width, height, 962 kSplashIconsWidth, NULL, x, y); 963 } 964 965 966 extern "C" void 967 platform_switch_to_text_mode(void) 968 { 969 if (!gKernelArgs.frame_buffer.enabled) { 970 vga_enable_bright_background_colors(); 971 return; 972 } 973 974 set_text_mode(); 975 gKernelArgs.frame_buffer.enabled = 0; 976 977 vga_enable_bright_background_colors(); 978 } 979 980 981 extern "C" status_t 982 platform_init_video(void) 983 { 984 gKernelArgs.frame_buffer.enabled = 0; 985 list_init(&sModeList); 986 987 set_text_mode(); 988 // You may wonder why we do this here: 989 // Obviously, some graphics card BIOS implementations don't 990 // report all available modes unless you've done this before 991 // getting the VESA information. 992 // One example of those is the SiS 630 chipset in my laptop. 993 994 sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; 995 if (!sVesaCompatible) { 996 TRACE(("No VESA compatible graphics!\n")); 997 return B_ERROR; 998 } 999 1000 TRACE(("VESA compatible graphics!\n")); 1001 1002 // store VESA modes into kernel args 1003 vesa_mode *modes = (vesa_mode *)kernel_args_malloc( 1004 sModeCount * sizeof(vesa_mode)); 1005 if (modes != NULL) { 1006 video_mode *mode = NULL; 1007 uint32 i = 0; 1008 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 1009 != NULL) { 1010 modes[i].width = mode->width; 1011 modes[i].height = mode->height; 1012 modes[i].bits_per_pixel = mode->bits_per_pixel; 1013 i++; 1014 } 1015 1016 gKernelArgs.vesa_modes = modes; 1017 gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode); 1018 } 1019 1020 edid1_info info; 1021 if (vesa_get_edid(&info) == B_OK) { 1022 // we got EDID information from the monitor, try to find a new default 1023 // mode 1024 video_mode *defaultMode = find_edid_mode(info, false); 1025 if (defaultMode == NULL) 1026 find_edid_mode(info, true); 1027 1028 if (defaultMode != NULL) { 1029 // We found a new default mode to use! 1030 sDefaultMode = defaultMode; 1031 } 1032 } 1033 1034 sMode = sDefaultMode; 1035 return B_OK; 1036 } 1037 1038