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 void 262 vesa_fixups(void *settings) 263 { 264 const char *oem_string = (const char *)sInfo.oem_string; 265 266 if (!strcmp(oem_string, "NVIDIA")) { 267 const char *arg = NULL; 268 int32 scaling = -1; 269 270 if (settings != NULL) 271 arg = get_driver_parameter(settings, "nvidia_scaling", NULL, "1"); 272 if (arg != NULL) 273 scaling = strtol(arg, NULL, 0); 274 275 if (scaling > -1) { 276 dprintf("Setting nvidia scaling mode to %" B_PRId32 "\n", scaling); 277 struct bios_regs regs; 278 regs.eax = 0x4f14; 279 regs.ebx = 0x0102; 280 regs.ecx = scaling; 281 call_bios(0x10, ®s); 282 } 283 } 284 285 } 286 287 288 static bool 289 get_mode_from_settings(void) 290 { 291 if (sSettingsLoaded) 292 return true; 293 294 void *handle = load_driver_settings("vesa"); 295 if (handle == NULL) 296 return false; 297 298 vesa_fixups(handle); 299 300 bool found = false; 301 302 const driver_settings *settings = get_driver_settings(handle); 303 if (settings == NULL) 304 goto out; 305 306 sSettingsLoaded = true; 307 308 for (int32 i = 0; i < settings->parameter_count; i++) { 309 driver_parameter ¶meter = settings->parameters[i]; 310 311 if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) { 312 // parameter found, now get its values 313 int32 width = strtol(parameter.values[0], NULL, 0); 314 int32 height = strtol(parameter.values[1], NULL, 0); 315 int32 depth = strtol(parameter.values[2], NULL, 0); 316 317 // search mode that fits 318 319 video_mode *mode = closest_video_mode(width, height, depth); 320 if (mode != NULL) { 321 found = true; 322 sMode = mode; 323 } 324 } 325 } 326 327 out: 328 unload_driver_settings(handle); 329 return found; 330 } 331 332 333 // #pragma mark - vga 334 335 336 static void 337 vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) 338 { 339 out8(firstIndex, VGA_COLOR_WRITE_MODE); 340 // write VGA palette 341 for (int32 i = firstIndex; i < numEntries; i++) { 342 // VGA (usually) has only 6 bits per gun 343 out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA); 344 out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA); 345 out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA); 346 } 347 } 348 349 350 static void 351 vga_enable_bright_background_colors(void) 352 { 353 // reset attribute controller 354 in8(VGA_INPUT_STATUS_1); 355 356 // select mode control register 357 out8(0x30, VGA_ATTRIBUTE_WRITE); 358 359 // read mode control register, change it (we need to clear bit 3), and write it back 360 uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7; 361 out8(mode, VGA_ATTRIBUTE_WRITE); 362 } 363 364 365 // #pragma mark - vesa 366 367 368 static status_t 369 vesa_get_edid(edid1_info *info) 370 { 371 struct bios_regs regs; 372 regs.eax = 0x4f15; 373 regs.ebx = 0; 374 // report DDC service 375 regs.ecx = 0; 376 regs.es = 0; 377 regs.edi = 0; 378 call_bios(0x10, ®s); 379 380 TRACE(("EDID1: %lx\n", regs.eax)); 381 // %ah contains the error code 382 // %al determines whether or not the function is supported 383 if (regs.eax != 0x4f) 384 return B_NOT_SUPPORTED; 385 386 TRACE(("EDID2: ebx %lx\n", regs.ebx)); 387 // test if DDC is supported by the monitor 388 if ((regs.ebx & 3) == 0) 389 return B_NOT_SUPPORTED; 390 391 edid1_raw edidRaw; 392 393 regs.eax = 0x4f15; 394 regs.ebx = 1; 395 // read EDID 396 regs.ecx = 0; 397 regs.edx = 0; 398 regs.es = ADDRESS_SEGMENT(&edidRaw); 399 regs.edi = ADDRESS_OFFSET(&edidRaw); 400 call_bios(0x10, ®s); 401 TRACE(("EDID3: %lx\n", regs.eax)); 402 403 if (regs.eax != 0x4f) 404 return B_NOT_SUPPORTED; 405 406 // retrieved EDID - now parse it 407 edid_decode(info, &edidRaw); 408 409 #ifdef TRACE_VIDEO 410 edid_dump(info); 411 #endif 412 return B_OK; 413 } 414 415 416 static status_t 417 vesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo) 418 { 419 memset(modeInfo, 0, sizeof(vbe_mode_info)); 420 421 struct bios_regs regs; 422 regs.eax = 0x4f01; 423 regs.ecx = mode; 424 regs.es = ADDRESS_SEGMENT(modeInfo); 425 regs.edi = ADDRESS_OFFSET(modeInfo); 426 call_bios(0x10, ®s); 427 428 // %ah contains the error code 429 if ((regs.eax & 0xff00) != 0) 430 return B_ENTRY_NOT_FOUND; 431 432 return B_OK; 433 } 434 435 436 static status_t 437 vesa_get_vbe_info_block(vbe_info_block *info) 438 { 439 memset(info, 0, sizeof(vbe_info_block)); 440 info->signature = VBE2_SIGNATURE; 441 442 struct bios_regs regs; 443 regs.eax = 0x4f00; 444 regs.es = ADDRESS_SEGMENT(info); 445 regs.edi = ADDRESS_OFFSET(info); 446 call_bios(0x10, ®s); 447 448 // %ah contains the error code 449 if ((regs.eax & 0xff00) != 0) 450 return B_ERROR; 451 452 if (info->signature != VESA_SIGNATURE) 453 return B_ERROR; 454 455 dprintf("VESA version = %d.%d, capabilities %lx\n", info->version.major, 456 info->version.minor, info->capabilities); 457 458 if (info->version.major < 2) { 459 dprintf("VESA support too old\n"); 460 return B_ERROR; 461 } 462 463 info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string); 464 info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list); 465 dprintf("OEM string: %s\n", (const char *)info->oem_string); 466 467 return B_OK; 468 } 469 470 471 static status_t 472 vesa_init(vbe_info_block *info, video_mode **_standardMode) 473 { 474 if (vesa_get_vbe_info_block(info) != B_OK) 475 return B_ERROR; 476 477 // fill mode list and find standard video mode 478 479 video_mode *standardMode = NULL; 480 481 for (int32 i = 0; true; i++) { 482 uint16 mode = ((uint16 *)info->mode_list)[i]; 483 if (mode == 0xffff) 484 break; 485 486 struct vbe_mode_info modeInfo; 487 if (vesa_get_mode_info(mode, &modeInfo) == B_OK) { 488 TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", mode, 489 modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes, 490 modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes, 491 modeInfo.num_banks)); 492 TRACE((" mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n", 493 modeInfo.red_mask_size, modeInfo.red_field_position, 494 modeInfo.green_mask_size, modeInfo.green_field_position, 495 modeInfo.blue_mask_size, modeInfo.blue_field_position, 496 modeInfo.direct_color_mode_info)); 497 498 const uint32 requiredAttributes = MODE_ATTR_AVAILABLE 499 | MODE_ATTR_GRAPHICS_MODE | MODE_ATTR_COLOR_MODE 500 | MODE_ATTR_LINEAR_BUFFER; 501 502 if (modeInfo.width >= 640 503 && modeInfo.physical_base != 0 504 && modeInfo.num_planes == 1 505 && (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL 506 || modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR) 507 && (modeInfo.attributes & requiredAttributes) 508 == requiredAttributes) { 509 // this mode fits our needs 510 video_mode *videoMode = (video_mode *)malloc( 511 sizeof(struct video_mode)); 512 if (videoMode == NULL) 513 continue; 514 515 videoMode->mode = mode; 516 videoMode->bytes_per_row = modeInfo.bytes_per_row; 517 videoMode->width = modeInfo.width; 518 videoMode->height = modeInfo.height; 519 videoMode->bits_per_pixel = modeInfo.bits_per_pixel; 520 videoMode->timing = NULL; 521 522 if (modeInfo.bits_per_pixel == 16 523 && modeInfo.red_mask_size + modeInfo.green_mask_size 524 + modeInfo.blue_mask_size == 15) { 525 // this is really a 15-bit mode 526 videoMode->bits_per_pixel = 15; 527 } 528 529 add_video_mode(videoMode); 530 } 531 } else 532 TRACE((" 0x%03x: (failed)\n", mode)); 533 } 534 535 // Choose default resolution (when no EDID information is available) 536 const uint32 kPreferredWidth = 1024; 537 const uint32 kFallbackWidth = 800; 538 539 standardMode = find_video_mode(kPreferredWidth, -1, false); 540 if (standardMode == NULL) { 541 standardMode = find_video_mode(kFallbackWidth, -1, false); 542 if (standardMode == NULL) { 543 standardMode = find_video_mode(kPreferredWidth, -1, true); 544 if (standardMode == NULL) 545 standardMode = find_video_mode(kFallbackWidth, -1, true); 546 } 547 } 548 if (standardMode == NULL) { 549 // just take any mode 550 standardMode = (video_mode *)list_get_first_item(&sModeList); 551 } 552 553 if (standardMode == NULL) { 554 // no usable VESA mode found... 555 return B_ERROR; 556 } 557 558 TRACE(("Using mode 0x%03x\n", standardMode->mode)); 559 *_standardMode = standardMode; 560 return B_OK; 561 } 562 563 564 #if 0 565 static status_t 566 vesa_get_mode(uint16 *_mode) 567 { 568 struct bios_regs regs; 569 regs.eax = 0x4f03; 570 call_bios(0x10, ®s); 571 572 if ((regs.eax & 0xffff) != 0x4f) 573 return B_ERROR; 574 575 *_mode = regs.ebx & 0xffff; 576 return B_OK; 577 } 578 #endif 579 580 581 static status_t 582 vesa_set_mode(video_mode* mode, bool useTiming) 583 { 584 struct bios_regs regs; 585 regs.eax = 0x4f02; 586 regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 587 588 if (useTiming && mode->timing != NULL) { 589 regs.ebx |= SET_MODE_SPECIFY_CRTC; 590 regs.es = ADDRESS_SEGMENT(mode->timing); 591 regs.edi = ADDRESS_OFFSET(mode->timing); 592 } 593 594 call_bios(0x10, ®s); 595 596 if ((regs.eax & 0xffff) != 0x4f) 597 return B_ERROR; 598 599 #if 0 600 // make sure we have 8 bits per color channel 601 regs.eax = 0x4f08; 602 regs.ebx = 8 << 8; 603 call_bios(0x10, ®s); 604 #endif 605 606 return B_OK; 607 } 608 609 610 static status_t 611 vesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) 612 { 613 // is this an 8 bit indexed color mode? 614 if (gKernelArgs.frame_buffer.depth != 8) 615 return B_BAD_TYPE; 616 617 #if 0 618 struct bios_regs regs; 619 regs.eax = 0x4f09; 620 regs.ebx = 0; 621 regs.ecx = numEntries; 622 regs.edx = firstIndex; 623 regs.es = (addr_t)palette >> 4; 624 regs.edi = (addr_t)palette & 0xf; 625 call_bios(0x10, ®s); 626 627 if ((regs.eax & 0xffff) != 0x4f) { 628 #endif 629 // the VESA call does not work, just try good old VGA mechanism 630 vga_set_palette(palette, firstIndex, numEntries); 631 #if 0 632 return B_ERROR; 633 } 634 #endif 635 return B_OK; 636 } 637 638 639 // #pragma mark - 640 641 642 bool 643 video_mode_hook(Menu *menu, MenuItem *item) 644 { 645 // find selected mode 646 video_mode *mode = NULL; 647 648 Menu* submenu = item->Submenu(); 649 MenuItem* subitem = submenu->FindMarked(); 650 if (subitem != NULL) { 651 switch (submenu->IndexOf(subitem)) { 652 case 0: 653 // "Default" mode special 654 sMode = sDefaultMode; 655 sModeChosen = false; 656 return true; 657 case 1: 658 // "Standard VGA" mode special 659 // sets sMode to NULL which triggers VGA mode 660 break; 661 default: 662 mode = (video_mode *)subitem->Data(); 663 break; 664 } 665 } 666 667 if (mode != sMode) { 668 // update standard mode 669 // ToDo: update fb settings! 670 sMode = mode; 671 } 672 673 sModeChosen = true; 674 return true; 675 } 676 677 678 Menu * 679 video_mode_menu() 680 { 681 Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode"); 682 MenuItem *item; 683 684 menu->AddItem(item = new(nothrow) MenuItem("Default")); 685 item->SetMarked(true); 686 item->Select(true); 687 item->SetHelpText("The Default video mode is the one currently configured " 688 "in the system. If there is no mode configured yet, a viable mode will " 689 "be chosen automatically."); 690 691 menu->AddItem(new(nothrow) MenuItem("Standard VGA")); 692 693 video_mode *mode = NULL; 694 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { 695 char label[64]; 696 snprintf(label, sizeof(label), "%ux%u %u bit", mode->width, 697 mode->height, mode->bits_per_pixel); 698 699 menu->AddItem(item = new(nothrow) MenuItem(label)); 700 item->SetData(mode); 701 } 702 703 menu->AddSeparatorItem(); 704 menu->AddItem(item = new(nothrow) MenuItem("Return to main menu")); 705 item->SetType(MENU_ITEM_NO_CHOICE); 706 707 return menu; 708 } 709 710 711 static void 712 set_vga_mode(void) 713 { 714 // sets 640x480 16 colors graphics mode 715 bios_regs regs; 716 regs.eax = 0x0012; 717 call_bios(0x10, ®s); 718 } 719 720 721 static void 722 set_text_mode(void) 723 { 724 // sets 80x25 text console 725 bios_regs regs; 726 regs.eax = 0x0003; 727 call_bios(0x10, ®s); 728 729 video_hide_text_cursor(); 730 } 731 732 733 void 734 video_move_text_cursor(int x, int y) 735 { 736 bios_regs regs; 737 regs.eax = 0x0200; 738 regs.ebx = 0; 739 regs.edx = (y << 8) | x; 740 call_bios(0x10, ®s); 741 } 742 743 744 void 745 video_show_text_cursor(void) 746 { 747 bios_regs regs; 748 regs.eax = 0x0100; 749 regs.ecx = 0x0607; 750 call_bios(0x10, ®s); 751 } 752 753 754 void 755 video_hide_text_cursor(void) 756 { 757 bios_regs regs; 758 regs.eax = 0x0100; 759 regs.ecx = 0x2000; 760 call_bios(0x10, ®s); 761 } 762 763 764 // #pragma mark - blit 765 766 767 void 768 platform_blit4(addr_t frameBuffer, const uint8 *data, 769 uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top) 770 { 771 if (!data) 772 return; 773 // ToDo: no boot logo yet in VGA mode 774 #if 1 775 // this draws 16 big rectangles in all the available colors 776 uint8 *bits = (uint8 *)frameBuffer; 777 uint32 bytesPerRow = 80; 778 for (int32 i = 0; i < 32; i++) { 779 bits[9 * bytesPerRow + i + 2] = 0x55; 780 bits[30 * bytesPerRow + i + 2] = 0xaa; 781 } 782 783 for (int32 y = 10; y < 30; y++) { 784 for (int32 i = 0; i < 16; i++) { 785 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 786 bits[32 * bytesPerRow + i*2 + 2] = i; 787 788 if (i & 1) { 789 out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX); 790 bits[y * bytesPerRow + i*2 + 2] = 0xff; 791 bits[y * bytesPerRow + i*2 + 3] = 0xff; 792 } 793 if (i & 2) { 794 out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX); 795 bits[y * bytesPerRow + i*2 + 2] = 0xff; 796 bits[y * bytesPerRow + i*2 + 3] = 0xff; 797 } 798 if (i & 4) { 799 out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX); 800 bits[y * bytesPerRow + i*2 + 2] = 0xff; 801 bits[y * bytesPerRow + i*2 + 3] = 0xff; 802 } 803 if (i & 8) { 804 out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX); 805 bits[y * bytesPerRow + i*2 + 2] = 0xff; 806 bits[y * bytesPerRow + i*2 + 3] = 0xff; 807 } 808 } 809 } 810 811 // enable all planes again 812 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); 813 #endif 814 } 815 816 817 extern "C" void 818 platform_set_palette(const uint8 *palette) 819 { 820 switch (gKernelArgs.frame_buffer.depth) { 821 case 4: 822 //vga_set_palette((const uint8 *)kPalette16, 0, 16); 823 break; 824 case 8: 825 if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK) 826 dprintf("set palette failed!\n"); 827 828 break; 829 default: 830 break; 831 } 832 } 833 834 835 // #pragma mark - 836 837 extern "C" void 838 platform_switch_to_logo(void) 839 { 840 // in debug mode, we'll never show the logo 841 if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) 842 return; 843 844 addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; 845 size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size; 846 847 if (sVesaCompatible && sMode != NULL) { 848 if (!sModeChosen) 849 get_mode_from_settings(); 850 851 // On some BIOS / chipset / monitor combinations, there seems to be a 852 // timing issue between getting the EDID data and setting the video 853 // mode. As such we wait here briefly to give everything enough time 854 // to settle. 855 spin(1000); 856 857 if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK) 858 && vesa_set_mode(sMode, false) != 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 870 = (phys_size_t)modeInfo.bytes_per_row 871 * (phys_size_t)gKernelArgs.frame_buffer.height; 872 gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; 873 } else { 874 fallback: 875 // use standard VGA mode 640x480x4 876 set_vga_mode(); 877 878 gKernelArgs.frame_buffer.width = 640; 879 gKernelArgs.frame_buffer.height = 480; 880 gKernelArgs.frame_buffer.bytes_per_row = 80; 881 gKernelArgs.frame_buffer.depth = 4; 882 gKernelArgs.frame_buffer.physical_buffer.size 883 = (phys_size_t)gKernelArgs.frame_buffer.width 884 * (phys_size_t)gKernelArgs.frame_buffer.height / 2; 885 gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000; 886 } 887 888 dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width, 889 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth); 890 891 gKernelArgs.frame_buffer.enabled = true; 892 893 // If the new frame buffer is either larger than the old one or located at 894 // a different address, we need to remap it, so we first have to throw 895 // away its previous mapping 896 if (lastBase != 0 897 && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start 898 || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) { 899 mmu_free((void *)sFrameBuffer, lastSize); 900 lastBase = 0; 901 } 902 if (lastBase == 0) { 903 // the graphics memory has not been mapped yet! 904 sFrameBuffer = mmu_map_physical_memory( 905 gKernelArgs.frame_buffer.physical_buffer.start, 906 gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags); 907 } 908 909 video_display_splash(sFrameBuffer); 910 } 911 912 913 extern "C" void 914 platform_switch_to_text_mode(void) 915 { 916 if (!gKernelArgs.frame_buffer.enabled) { 917 vga_enable_bright_background_colors(); 918 return; 919 } 920 921 set_text_mode(); 922 gKernelArgs.frame_buffer.enabled = 0; 923 924 vga_enable_bright_background_colors(); 925 } 926 927 928 extern "C" status_t 929 platform_init_video(void) 930 { 931 gKernelArgs.frame_buffer.enabled = 0; 932 list_init(&sModeList); 933 934 set_text_mode(); 935 // You may wonder why we do this here: 936 // Obviously, some graphics card BIOS implementations don't 937 // report all available modes unless you've done this before 938 // getting the VESA information. 939 // One example of those is the SiS 630 chipset in my laptop. 940 941 sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; 942 if (!sVesaCompatible) { 943 TRACE(("No VESA compatible graphics!\n")); 944 gKernelArgs.vesa_capabilities = 0; 945 return B_ERROR; 946 } 947 948 gKernelArgs.vesa_capabilities = sInfo.capabilities; 949 950 TRACE(("VESA compatible graphics!\n")); 951 952 // store VESA modes into kernel args 953 vesa_mode *modes = (vesa_mode *)kernel_args_malloc( 954 sModeCount * sizeof(vesa_mode)); 955 if (modes != NULL) { 956 video_mode *mode = NULL; 957 uint32 i = 0; 958 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) 959 != NULL) { 960 modes[i].mode = mode->mode; 961 modes[i].width = mode->width; 962 modes[i].height = mode->height; 963 modes[i].bits_per_pixel = mode->bits_per_pixel; 964 i++; 965 } 966 967 gKernelArgs.vesa_modes = modes; 968 gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode); 969 } 970 971 edid1_info info; 972 // Note, we currently ignore EDID information for VBE2 - while the EDID 973 // information itself seems to be reliable, older chips often seem to 974 // use very strange default timings with higher modes. 975 // TODO: Maybe add a setting to enable it anyway? 976 if (sInfo.version.major >= 3 && vesa_get_edid(&info) == B_OK) { 977 // we got EDID information from the monitor, try to find a new default 978 // mode 979 video_mode *defaultMode = find_edid_mode(info, false); 980 if (defaultMode == NULL) 981 defaultMode = find_edid_mode(info, true); 982 983 if (defaultMode != NULL) { 984 // We found a new default mode to use! 985 sDefaultMode = defaultMode; 986 } 987 988 gKernelArgs.edid_info = kernel_args_malloc(sizeof(edid1_info)); 989 if (gKernelArgs.edid_info != NULL) 990 memcpy(gKernelArgs.edid_info, &info, sizeof(edid1_info)); 991 } 992 993 sMode = sDefaultMode; 994 return B_OK; 995 } 996 997