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