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