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 struct vbe_mode_info modeInfo; 457 if (vesa_get_mode_info(mode, &modeInfo) == B_OK) { 458 TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", mode, 459 modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes, 460 modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes, 461 modeInfo.num_banks)); 462 TRACE((" mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n", 463 modeInfo.red_mask_size, modeInfo.red_field_position, 464 modeInfo.green_mask_size, modeInfo.green_field_position, 465 modeInfo.blue_mask_size, modeInfo.blue_field_position, 466 modeInfo.direct_color_mode_info)); 467 468 const uint32 requiredAttributes = MODE_ATTR_AVAILABLE 469 | MODE_ATTR_GRAPHICS_MODE | MODE_ATTR_COLOR_MODE 470 | MODE_ATTR_LINEAR_BUFFER; 471 472 if (modeInfo.width >= 640 473 && modeInfo.physical_base != 0 474 && modeInfo.num_planes == 1 475 && (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL 476 || modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR) 477 && (modeInfo.attributes & requiredAttributes) 478 == requiredAttributes) { 479 // this mode fits our needs 480 video_mode *videoMode = (video_mode *)malloc( 481 sizeof(struct video_mode)); 482 if (videoMode == NULL) 483 continue; 484 485 videoMode->mode = mode; 486 videoMode->bytes_per_row = modeInfo.bytes_per_row; 487 videoMode->width = modeInfo.width; 488 videoMode->height = modeInfo.height; 489 videoMode->bits_per_pixel = modeInfo.bits_per_pixel; 490 videoMode->timing = NULL; 491 492 if (modeInfo.bits_per_pixel == 16 493 && modeInfo.red_mask_size + modeInfo.green_mask_size 494 + modeInfo.blue_mask_size == 15) { 495 // this is really a 15-bit mode 496 videoMode->bits_per_pixel = 15; 497 } 498 499 add_video_mode(videoMode); 500 } 501 } else 502 TRACE((" 0x%03x: (failed)\n", mode)); 503 } 504 505 // Choose default resolution (when no EDID information is available) 506 const uint32 kPreferredWidth = 1024; 507 const uint32 kFallbackWidth = 800; 508 509 standardMode = find_video_mode(kPreferredWidth, -1, false); 510 if (standardMode == NULL) { 511 standardMode = find_video_mode(kFallbackWidth, -1, false); 512 if (standardMode == NULL) { 513 standardMode = find_video_mode(kPreferredWidth, -1, true); 514 if (standardMode == NULL) 515 standardMode = find_video_mode(kFallbackWidth, -1, true); 516 } 517 } 518 if (standardMode == NULL) { 519 // just take any mode 520 standardMode = (video_mode *)list_get_first_item(&sModeList); 521 } 522 523 if (standardMode == NULL) { 524 // no usable VESA mode found... 525 return B_ERROR; 526 } 527 528 TRACE(("Using mode 0x%03x\n", standardMode->mode)); 529 *_standardMode = standardMode; 530 return B_OK; 531 } 532 533 534 #if 0 535 static status_t 536 vesa_get_mode(uint16 *_mode) 537 { 538 struct bios_regs regs; 539 regs.eax = 0x4f03; 540 call_bios(0x10, ®s); 541 542 if ((regs.eax & 0xffff) != 0x4f) 543 return B_ERROR; 544 545 *_mode = regs.ebx & 0xffff; 546 return B_OK; 547 } 548 #endif 549 550 551 static status_t 552 vesa_set_mode(video_mode* mode, bool useTiming) 553 { 554 struct bios_regs regs; 555 regs.eax = 0x4f02; 556 regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 557 558 if (useTiming && mode->timing != NULL) { 559 regs.ebx |= SET_MODE_SPECIFY_CRTC; 560 regs.es = ADDRESS_SEGMENT(mode->timing); 561 regs.edi = ADDRESS_OFFSET(mode->timing); 562 } 563 564 call_bios(0x10, ®s); 565 566 if ((regs.eax & 0xffff) != 0x4f) 567 return B_ERROR; 568 569 #if 0 570 // make sure we have 8 bits per color channel 571 regs.eax = 0x4f08; 572 regs.ebx = 8 << 8; 573 call_bios(0x10, ®s); 574 #endif 575 576 return B_OK; 577 } 578 579 580 static status_t 581 vesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) 582 { 583 // is this an 8 bit indexed color mode? 584 if (gKernelArgs.frame_buffer.depth != 8) 585 return B_BAD_TYPE; 586 587 #if 0 588 struct bios_regs regs; 589 regs.eax = 0x4f09; 590 regs.ebx = 0; 591 regs.ecx = numEntries; 592 regs.edx = firstIndex; 593 regs.es = (addr_t)palette >> 4; 594 regs.edi = (addr_t)palette & 0xf; 595 call_bios(0x10, ®s); 596 597 if ((regs.eax & 0xffff) != 0x4f) { 598 #endif 599 // the VESA call does not work, just try good old VGA mechanism 600 vga_set_palette(palette, firstIndex, numEntries); 601 #if 0 602 return B_ERROR; 603 } 604 #endif 605 return B_OK; 606 } 607 608 609 // #pragma mark - 610 611 612 bool 613 video_mode_hook(Menu *menu, MenuItem *item) 614 { 615 // find selected mode 616 video_mode *mode = NULL; 617 618 menu = item->Submenu(); 619 item = menu->FindMarked(); 620 if (item != NULL) { 621 switch (menu->IndexOf(item)) { 622 case 0: 623 // "Default" mode special 624 sMode = sDefaultMode; 625 sModeChosen = false; 626 return true; 627 case 1: 628 // "Standard VGA" mode special 629 // sets sMode to NULL which triggers VGA mode 630 break; 631 default: 632 mode = (video_mode *)item->Data(); 633 break; 634 } 635 } 636 637 if (mode != sMode) { 638 // update standard mode 639 // ToDo: update fb settings! 640 sMode = mode; 641 } 642 643 sModeChosen = true; 644 return true; 645 } 646 647 648 Menu * 649 video_mode_menu() 650 { 651 Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode"); 652 MenuItem *item; 653 654 menu->AddItem(item = new(nothrow) MenuItem("Default")); 655 item->SetMarked(true); 656 item->Select(true); 657 item->SetHelpText("The Default video mode is the one currently configured " 658 "in the system. If there is no mode configured yet, a viable mode will " 659 "be chosen automatically."); 660 661 menu->AddItem(new(nothrow) MenuItem("Standard VGA")); 662 663 video_mode *mode = NULL; 664 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { 665 char label[64]; 666 sprintf(label, "%ux%u %u bit", mode->width, mode->height, 667 mode->bits_per_pixel); 668 669 menu->AddItem(item = new(nothrow) MenuItem(label)); 670 item->SetData(mode); 671 } 672 673 menu->AddSeparatorItem(); 674 menu->AddItem(item = new(nothrow) MenuItem("Return to main menu")); 675 item->SetType(MENU_ITEM_NO_CHOICE); 676 677 return menu; 678 } 679 680 681 static void 682 set_vga_mode(void) 683 { 684 // sets 640x480 16 colors graphics mode 685 bios_regs regs; 686 regs.eax = 0x0012; 687 call_bios(0x10, ®s); 688 } 689 690 691 static void 692 set_text_mode(void) 693 { 694 // sets 80x25 text console 695 bios_regs regs; 696 regs.eax = 0x0003; 697 call_bios(0x10, ®s); 698 699 // turns off text cursor 700 regs.eax = 0x0100; 701 regs.ecx = 0x2000; 702 call_bios(0x10, ®s); 703 } 704 705 706 // #pragma mark - blit 707 708 709 void 710 platform_blit4(addr_t frameBuffer, const uint8 *data, 711 uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top) 712 { 713 if (!data) 714 return; 715 // ToDo: no boot logo yet in VGA mode 716 #if 1 717 // this draws 16 big rectangles in all the available colors 718 uint8 *bits = (uint8 *)frameBuffer; 719 uint32 bytesPerRow = 80; 720 for (int32 i = 0; i < 32; i++) { 721 bits[9 * bytesPerRow + i + 2] = 0x55; 722 bits[30 * bytesPerRow + i + 2] = 0xaa; 723 } 724 725 for (int32 y = 10; y < 30; y++) { 726 for (int32 i = 0; i < 16; i++) { 727 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 728 bits[32 * bytesPerRow + i*2 + 2] = i; 729 730 if (i & 1) { 731 out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX); 732 bits[y * bytesPerRow + i*2 + 2] = 0xff; 733 bits[y * bytesPerRow + i*2 + 3] = 0xff; 734 } 735 if (i & 2) { 736 out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX); 737 bits[y * bytesPerRow + i*2 + 2] = 0xff; 738 bits[y * bytesPerRow + i*2 + 3] = 0xff; 739 } 740 if (i & 4) { 741 out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX); 742 bits[y * bytesPerRow + i*2 + 2] = 0xff; 743 bits[y * bytesPerRow + i*2 + 3] = 0xff; 744 } 745 if (i & 8) { 746 out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX); 747 bits[y * bytesPerRow + i*2 + 2] = 0xff; 748 bits[y * bytesPerRow + i*2 + 3] = 0xff; 749 } 750 } 751 } 752 753 // enable all planes again 754 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 755 #endif 756 } 757 758 759 extern "C" void 760 platform_set_palette(const uint8 *palette) 761 { 762 switch (gKernelArgs.frame_buffer.depth) { 763 case 4: 764 //vga_set_palette((const uint8 *)kPalette16, 0, 16); 765 break; 766 case 8: 767 if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK) 768 dprintf("set palette failed!\n"); 769 770 break; 771 default: 772 break; 773 } 774 } 775 776 777 // #pragma mark - 778 779 extern "C" void 780 platform_switch_to_logo(void) 781 { 782 // in debug mode, we'll never show the logo 783 if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) 784 return; 785 786 addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; 787 size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size; 788 789 if (sVesaCompatible && sMode != NULL) { 790 if (!sModeChosen) 791 get_mode_from_settings(); 792 793 // On some BIOS / chipset / monitor combinations, there seems to be a 794 // timing issue between getting the EDID data and setting the video 795 // mode. As such we wait here briefly to give everything enough time 796 // to settle. 797 spin(1000); 798 799 if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK) 800 && vesa_set_mode(sMode, false) != B_OK) 801 goto fallback; 802 803 struct vbe_mode_info modeInfo; 804 if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK) 805 goto fallback; 806 807 gKernelArgs.frame_buffer.width = modeInfo.width; 808 gKernelArgs.frame_buffer.height = modeInfo.height; 809 gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row; 810 gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel; 811 gKernelArgs.frame_buffer.physical_buffer.size = modeInfo.bytes_per_row 812 * gKernelArgs.frame_buffer.height; 813 gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; 814 } else { 815 fallback: 816 // use standard VGA mode 640x480x4 817 set_vga_mode(); 818 819 gKernelArgs.frame_buffer.width = 640; 820 gKernelArgs.frame_buffer.height = 480; 821 gKernelArgs.frame_buffer.bytes_per_row = 80; 822 gKernelArgs.frame_buffer.depth = 4; 823 gKernelArgs.frame_buffer.physical_buffer.size 824 = gKernelArgs.frame_buffer.width 825 * gKernelArgs.frame_buffer.height / 2; 826 gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000; 827 } 828 829 dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width, 830 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth); 831 832 gKernelArgs.frame_buffer.enabled = true; 833 834 // If the new frame buffer is either larger than the old one or located at 835 // a different address, we need to remap it, so we first have to throw 836 // away its previous mapping 837 if (lastBase != 0 838 && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start 839 || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) { 840 mmu_free((void *)sFrameBuffer, lastSize); 841 lastBase = 0; 842 } 843 if (lastBase == 0) { 844 // the graphics memory has not been mapped yet! 845 sFrameBuffer = mmu_map_physical_memory( 846 gKernelArgs.frame_buffer.physical_buffer.start, 847 gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags); 848 } 849 850 video_display_splash(sFrameBuffer); 851 } 852 853 854 extern "C" void 855 platform_switch_to_text_mode(void) 856 { 857 if (!gKernelArgs.frame_buffer.enabled) { 858 vga_enable_bright_background_colors(); 859 return; 860 } 861 862 set_text_mode(); 863 gKernelArgs.frame_buffer.enabled = 0; 864 865 vga_enable_bright_background_colors(); 866 } 867 868 869 extern "C" status_t 870 platform_init_video(void) 871 { 872 gKernelArgs.frame_buffer.enabled = 0; 873 list_init(&sModeList); 874 875 set_text_mode(); 876 // You may wonder why we do this here: 877 // Obviously, some graphics card BIOS implementations don't 878 // report all available modes unless you've done this before 879 // getting the VESA information. 880 // One example of those is the SiS 630 chipset in my laptop. 881 882 sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; 883 if (!sVesaCompatible) { 884 TRACE(("No VESA compatible graphics!\n")); 885 gKernelArgs.vesa_capabilities = 0; 886 return B_ERROR; 887 } 888 889 gKernelArgs.vesa_capabilities = sInfo.capabilities; 890 891 TRACE(("VESA compatible graphics!\n")); 892 893 // store VESA modes into kernel args 894 vesa_mode *modes = (vesa_mode *)kernel_args_malloc( 895 sModeCount * sizeof(vesa_mode)); 896 if (modes != NULL) { 897 video_mode *mode = NULL; 898 uint32 i = 0; 899 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 900 != NULL) { 901 modes[i].mode = mode->mode; 902 modes[i].width = mode->width; 903 modes[i].height = mode->height; 904 modes[i].bits_per_pixel = mode->bits_per_pixel; 905 i++; 906 } 907 908 gKernelArgs.vesa_modes = modes; 909 gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode); 910 } 911 912 edid1_info info; 913 // Note, we currently ignore EDID information for VBE2 - while the EDID 914 // information itself seems to be reliable, older chips often seem to 915 // use very strange default timings with higher modes. 916 // TODO: Maybe add a setting to enable it anyway? 917 if (sInfo.version.major >= 3 && vesa_get_edid(&info) == B_OK) { 918 // we got EDID information from the monitor, try to find a new default 919 // mode 920 video_mode *defaultMode = find_edid_mode(info, false); 921 if (defaultMode == NULL) 922 defaultMode = find_edid_mode(info, true); 923 924 if (defaultMode != NULL) { 925 // We found a new default mode to use! 926 sDefaultMode = defaultMode; 927 } 928 929 gKernelArgs.edid_info = kernel_args_malloc(sizeof(edid1_info)); 930 if (gKernelArgs.edid_info != NULL) 931 memcpy(gKernelArgs.edid_info, &info, sizeof(edid1_info)); 932 } 933 934 sMode = sDefaultMode; 935 return B_OK; 936 } 937 938