1 /* 2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "vesa_private.h" 8 #include "vesa.h" 9 10 #include <string.h> 11 12 #include <drivers/bios.h> 13 14 #include <boot_item.h> 15 #include <frame_buffer_console.h> 16 #include <util/kernel_cpp.h> 17 #include <vm/vm.h> 18 19 #include "driver.h" 20 #include "utility.h" 21 #include "vesa_info.h" 22 23 24 static bios_module_info* sBIOSModule; 25 26 27 /*! Loads the BIOS module and sets up a state for it. The BIOS module is only 28 loaded when we need it, as it is quite a large module. 29 */ 30 static status_t 31 vbe_call_prepare(bios_state** state) 32 { 33 status_t status; 34 35 status = get_module(B_BIOS_MODULE_NAME, (module_info**)&sBIOSModule); 36 if (status != B_OK) { 37 dprintf(DEVICE_NAME ": failed to get BIOS module: %s\n", 38 strerror(status)); 39 return status; 40 } 41 42 status = sBIOSModule->prepare(state); 43 if (status != B_OK) { 44 dprintf(DEVICE_NAME ": failed to prepare BIOS state: %s\n", 45 strerror(status)); 46 put_module(B_BIOS_MODULE_NAME); 47 } 48 49 return status; 50 } 51 52 53 static void 54 vbe_call_finish(bios_state* state) 55 { 56 sBIOSModule->finish(state); 57 put_module(B_BIOS_MODULE_NAME); 58 } 59 60 61 static status_t 62 find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size) 63 { 64 // TODO: when we port this over to the new driver API, this mechanism can be 65 // used to find the right device_node 66 pci_module_info* pci; 67 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK) 68 return B_ERROR; 69 70 pci_info info; 71 for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) { 72 if (info.class_base != PCI_display) 73 continue; 74 75 // check PCI BARs 76 for (uint32 i = 0; i < 6; i++) { 77 if (info.u.h0.base_registers[i] <= frameBuffer 78 && info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i] 79 > frameBuffer) { 80 // found it! 81 base = info.u.h0.base_registers[i]; 82 size = info.u.h0.base_register_sizes[i]; 83 84 put_module(B_PCI_MODULE_NAME); 85 return B_OK; 86 } 87 } 88 } 89 90 put_module(B_PCI_MODULE_NAME); 91 return B_ENTRY_NOT_FOUND; 92 } 93 94 95 static uint32 96 get_color_space_for_depth(uint32 depth) 97 { 98 switch (depth) { 99 case 1: 100 return B_GRAY1; 101 case 4: 102 return B_GRAY8; 103 // the app_server is smart enough to translate this to VGA mode 104 case 8: 105 return B_CMAP8; 106 case 15: 107 return B_RGB15; 108 case 16: 109 return B_RGB16; 110 case 24: 111 return B_RGB24; 112 case 32: 113 return B_RGB32; 114 } 115 116 return 0; 117 } 118 119 120 static status_t 121 vbe_get_mode_info(bios_state* state, uint16 mode, struct vbe_mode_info* modeInfo) 122 { 123 void* vbeModeInfo = sBIOSModule->allocate_mem(state, 124 sizeof(struct vbe_mode_info)); 125 if (vbeModeInfo == NULL) 126 return B_NO_MEMORY; 127 memset(vbeModeInfo, 0, sizeof(vbe_mode_info)); 128 129 uint32 physicalAddress = sBIOSModule->physical_address(state, vbeModeInfo); 130 bios_regs regs = {}; 131 regs.eax = 0x4f01; 132 regs.ecx = mode; 133 regs.es = physicalAddress >> 4; 134 regs.edi = physicalAddress - (regs.es << 4); 135 136 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 137 if (status != B_OK) { 138 dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS failed: %s\n", mode, 139 strerror(status)); 140 return status; 141 } 142 143 if ((regs.eax & 0xffff) != 0x4f) { 144 dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS returned " 145 "0x%04" B_PRIx32 "\n", mode, regs.eax & 0xffff); 146 return B_ENTRY_NOT_FOUND; 147 } 148 149 memcpy(modeInfo, vbeModeInfo, sizeof(struct vbe_mode_info)); 150 return B_OK; 151 } 152 153 154 static status_t 155 vbe_set_mode(bios_state* state, uint16 mode) 156 { 157 bios_regs regs = {}; 158 regs.eax = 0x4f02; 159 regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 160 161 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 162 if (status != B_OK) { 163 dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS failed: %s\n", mode, 164 strerror(status)); 165 return status; 166 } 167 168 if ((regs.eax & 0xffff) != 0x4f) { 169 dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS returned 0x%04" B_PRIx32 170 "\n", mode, regs.eax & 0xffff); 171 return B_ERROR; 172 } 173 174 return B_OK; 175 } 176 177 178 static uint32 179 vbe_to_system_dpms(uint8 vbeMode) 180 { 181 uint32 mode = 0; 182 if ((vbeMode & (DPMS_OFF | DPMS_REDUCED_ON)) != 0) 183 mode |= B_DPMS_OFF; 184 if ((vbeMode & DPMS_STANDBY) != 0) 185 mode |= B_DPMS_STAND_BY; 186 if ((vbeMode & DPMS_SUSPEND) != 0) 187 mode |= B_DPMS_SUSPEND; 188 189 return mode; 190 } 191 192 193 static status_t 194 vbe_get_dpms_capabilities(uint32& vbeMode, uint32& mode) 195 { 196 // we always return a valid mode 197 vbeMode = 0; 198 mode = B_DPMS_ON; 199 200 // Prepare BIOS environment 201 bios_state* state; 202 status_t status = vbe_call_prepare(&state); 203 if (status != B_OK) 204 return status; 205 206 bios_regs regs = {}; 207 regs.eax = 0x4f10; 208 regs.ebx = 0; 209 regs.esi = 0; 210 regs.edi = 0; 211 212 status = sBIOSModule->interrupt(state, 0x10, ®s); 213 if (status != B_OK) { 214 dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS failed: %s\n", 215 strerror(status)); 216 goto out; 217 } 218 219 if ((regs.eax & 0xffff) != 0x4f) { 220 dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS returned " 221 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 222 status = B_ERROR; 223 goto out; 224 } 225 226 vbeMode = regs.ebx >> 8; 227 mode = vbe_to_system_dpms(vbeMode); 228 229 out: 230 vbe_call_finish(state); 231 return status; 232 } 233 234 235 static status_t 236 vbe_set_bits_per_gun(bios_state* state, vesa_info& info, uint8 bits) 237 { 238 info.bits_per_gun = 6; 239 240 bios_regs regs = {}; 241 regs.eax = 0x4f08; 242 regs.ebx = (bits << 8) | 1; 243 244 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 245 if (status != B_OK) { 246 dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS failed: %s\n", 247 strerror(status)); 248 return status; 249 } 250 251 if ((regs.eax & 0xffff) != 0x4f) { 252 dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS returned " 253 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 254 return B_ERROR; 255 } 256 257 info.bits_per_gun = regs.ebx >> 8; 258 return B_OK; 259 } 260 261 262 static status_t 263 vbe_set_bits_per_gun(vesa_info& info, uint8 bits) 264 { 265 info.bits_per_gun = 6; 266 267 bios_state* state; 268 status_t status = vbe_call_prepare(&state); 269 if (status != B_OK) 270 return status; 271 272 status = vbe_set_bits_per_gun(state, info, bits); 273 274 vbe_call_finish(state); 275 return status; 276 } 277 278 279 /*! Remaps the frame buffer if necessary; if we've already mapped the complete 280 frame buffer, there is no need to map it again. 281 */ 282 static status_t 283 remap_frame_buffer(vesa_info& info, addr_t physicalBase, uint32 width, 284 uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) 285 { 286 vesa_shared_info& sharedInfo = *info.shared_info; 287 addr_t frameBuffer = info.frame_buffer; 288 289 if (!info.complete_frame_buffer_mapped) { 290 addr_t base = physicalBase; 291 size_t size = bytesPerRow * height; 292 bool remap = !initializing; 293 294 if (info.physical_frame_buffer_size != 0) { 295 // we can map the complete frame buffer 296 base = info.physical_frame_buffer; 297 size = info.physical_frame_buffer_size; 298 remap = true; 299 } 300 301 if (remap) { 302 area_id area = map_physical_memory("vesa frame buffer", base, 303 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, 304 (void**)&frameBuffer); 305 if (area < 0) 306 return area; 307 308 if (initializing) { 309 // We need to manually update the kernel's frame buffer address, 310 // since this frame buffer remapping has not been issued by the 311 // app_server (which would otherwise take care of this) 312 frame_buffer_update(frameBuffer, width, height, depth, 313 bytesPerRow); 314 } 315 316 delete_area(info.shared_info->frame_buffer_area); 317 318 info.frame_buffer = frameBuffer; 319 sharedInfo.frame_buffer_area = area; 320 321 // Turn on write combining for the area 322 vm_set_area_memory_type(area, base, B_MTR_WC); 323 324 if (info.physical_frame_buffer_size != 0) 325 info.complete_frame_buffer_mapped = true; 326 } 327 } 328 329 if (info.complete_frame_buffer_mapped) 330 frameBuffer += physicalBase - info.physical_frame_buffer; 331 332 // Update shared frame buffer information 333 sharedInfo.frame_buffer = (uint8*)frameBuffer; 334 sharedInfo.physical_frame_buffer = (uint8*)physicalBase; 335 sharedInfo.bytes_per_row = bytesPerRow; 336 337 return B_OK; 338 } 339 340 341 // #pragma mark - 342 343 344 status_t 345 vesa_init(vesa_info& info) 346 { 347 frame_buffer_boot_info* bufferInfo 348 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 349 if (bufferInfo == NULL) 350 return B_ERROR; 351 352 info.vbe_capabilities = bufferInfo->vesa_capabilities; 353 info.complete_frame_buffer_mapped = false; 354 355 // Find out which PCI device we belong to, so that we know its frame buffer 356 // size 357 find_graphics_card(bufferInfo->physical_frame_buffer, 358 info.physical_frame_buffer, info.physical_frame_buffer_size); 359 360 size_t modesSize = 0; 361 vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO, 362 &modesSize); 363 info.modes = modes; 364 365 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 366 367 info.shared_area = create_area("vesa shared info", 368 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, 369 ROUND_TO_PAGE_SIZE(sharedSize + modesSize), B_FULL_LOCK, 370 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 371 if (info.shared_area < 0) 372 return info.shared_area; 373 374 vesa_shared_info& sharedInfo = *info.shared_info; 375 376 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 377 378 if (modes != NULL) { 379 sharedInfo.vesa_mode_offset = sharedSize; 380 sharedInfo.vesa_mode_count = modesSize / sizeof(vesa_mode); 381 382 memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize); 383 } 384 385 sharedInfo.frame_buffer_area = bufferInfo->area; 386 387 remap_frame_buffer(info, bufferInfo->physical_frame_buffer, 388 bufferInfo->width, bufferInfo->height, bufferInfo->depth, 389 bufferInfo->bytes_per_row, true); 390 // Does not matter if this fails - the frame buffer was already mapped 391 // before. 392 393 sharedInfo.current_mode.virtual_width = bufferInfo->width; 394 sharedInfo.current_mode.virtual_height = bufferInfo->height; 395 sharedInfo.current_mode.space = get_color_space_for_depth( 396 bufferInfo->depth); 397 398 edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO, 399 NULL); 400 if (edidInfo != NULL) { 401 sharedInfo.has_edid = true; 402 memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info)); 403 } 404 405 vbe_get_dpms_capabilities(info.vbe_dpms_capabilities, 406 sharedInfo.dpms_capabilities); 407 if (bufferInfo->depth <= 8) 408 vbe_set_bits_per_gun(info, 8); 409 410 dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n"); 411 return B_OK; 412 } 413 414 415 void 416 vesa_uninit(vesa_info& info) 417 { 418 dprintf(DEVICE_NAME": vesa_uninit()\n"); 419 420 delete_area(info.shared_info->frame_buffer_area); 421 delete_area(info.shared_area); 422 } 423 424 425 status_t 426 vesa_set_display_mode(vesa_info& info, uint32 mode) 427 { 428 if (mode >= info.shared_info->vesa_mode_count) 429 return B_ENTRY_NOT_FOUND; 430 431 // Prepare BIOS environment 432 bios_state* state; 433 status_t status = vbe_call_prepare(&state); 434 if (status != B_OK) 435 return status; 436 437 // Get mode information 438 struct vbe_mode_info modeInfo; 439 status = vbe_get_mode_info(state, info.modes[mode].mode, &modeInfo); 440 if (status != B_OK) { 441 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n"); 442 goto out; 443 } 444 445 // Set mode 446 status = vbe_set_mode(state, info.modes[mode].mode); 447 if (status != B_OK) { 448 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot set mode\n"); 449 goto out; 450 } 451 452 if (info.modes[mode].bits_per_pixel <= 8) 453 vbe_set_bits_per_gun(state, info, 8); 454 455 // Map new frame buffer if necessary 456 457 status = remap_frame_buffer(info, modeInfo.physical_base, modeInfo.width, 458 modeInfo.height, modeInfo.bits_per_pixel, modeInfo.bytes_per_row, 459 false); 460 if (status == B_OK) { 461 // Update shared frame buffer information 462 info.shared_info->current_mode.virtual_width = modeInfo.width; 463 info.shared_info->current_mode.virtual_height = modeInfo.height; 464 info.shared_info->current_mode.space = get_color_space_for_depth( 465 modeInfo.bits_per_pixel); 466 } 467 468 out: 469 vbe_call_finish(state); 470 return status; 471 } 472 473 474 status_t 475 vesa_get_dpms_mode(vesa_info& info, uint32& mode) 476 { 477 mode = B_DPMS_ON; 478 // we always return a valid mode 479 480 // Prepare BIOS environment 481 bios_state* state; 482 status_t status = vbe_call_prepare(&state); 483 if (status != B_OK) 484 return status; 485 486 bios_regs regs = {}; 487 regs.eax = 0x4f10; 488 regs.ebx = 2; 489 regs.esi = 0; 490 regs.edi = 0; 491 492 status = sBIOSModule->interrupt(state, 0x10, ®s); 493 if (status != B_OK) { 494 dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS failed: %s\n", 495 strerror(status)); 496 goto out; 497 } 498 499 if ((regs.eax & 0xffff) != 0x4f) { 500 dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS returned " 501 "0x%" B_PRIx32 "\n", regs.eax & 0xffff); 502 status = B_ERROR; 503 goto out; 504 } 505 506 mode = vbe_to_system_dpms(regs.ebx >> 8); 507 508 out: 509 vbe_call_finish(state); 510 return status; 511 } 512 513 514 status_t 515 vesa_set_dpms_mode(vesa_info& info, uint32 mode) 516 { 517 // Only let supported modes through 518 mode &= info.shared_info->dpms_capabilities; 519 520 uint8 vbeMode = 0; 521 if ((mode & B_DPMS_OFF) != 0) 522 vbeMode |= DPMS_OFF | DPMS_REDUCED_ON; 523 if ((mode & B_DPMS_STAND_BY) != 0) 524 vbeMode |= DPMS_STANDBY; 525 if ((mode & B_DPMS_SUSPEND) != 0) 526 vbeMode |= DPMS_SUSPEND; 527 528 vbeMode &= info.vbe_dpms_capabilities; 529 530 // Prepare BIOS environment 531 bios_state* state; 532 status_t status = vbe_call_prepare(&state); 533 if (status != B_OK) 534 return status; 535 536 bios_regs regs = {}; 537 regs.eax = 0x4f10; 538 regs.ebx = (vbeMode << 8) | 1; 539 regs.esi = 0; 540 regs.edi = 0; 541 542 status = sBIOSModule->interrupt(state, 0x10, ®s); 543 if (status != B_OK) { 544 dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS failed: %s\n", 545 strerror(status)); 546 goto out; 547 } 548 549 if ((regs.eax & 0xffff) != 0x4f) { 550 dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS returned " 551 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 552 status = B_ERROR; 553 goto out; 554 } 555 556 out: 557 vbe_call_finish(state); 558 return status; 559 } 560 561 562 status_t 563 vesa_set_indexed_colors(vesa_info& info, uint8 first, uint8* colors, 564 uint16 count) 565 { 566 bios_regs regs = {}; 567 uint32 shift, physicalAddress; 568 569 if (first + count > 256) 570 count = 256 - first; 571 572 // Prepare BIOS environment 573 bios_state* state; 574 status_t status = vbe_call_prepare(&state); 575 if (status != B_OK) 576 return status; 577 578 uint8* palette = (uint8*)sBIOSModule->allocate_mem(state, 256 * 4); 579 if (palette == NULL) { 580 status = B_NO_MEMORY; 581 goto out; 582 } 583 584 shift = 8 - info.bits_per_gun; 585 586 // convert colors to VESA palette 587 for (int32 i = first; i < count; i++) { 588 uint8 color[3]; 589 if (user_memcpy(color, &colors[i * 3], 3) < B_OK) { 590 status = B_BAD_ADDRESS; 591 goto out; 592 } 593 594 // order is BGR- 595 palette[i * 4 + 0] = color[2] >> shift; 596 palette[i * 4 + 1] = color[1] >> shift; 597 palette[i * 4 + 2] = color[0] >> shift; 598 palette[i * 4 + 3] = 0; 599 } 600 601 // set palette 602 physicalAddress = sBIOSModule->physical_address(state, palette); 603 regs.eax = 0x4f09; 604 regs.ebx = 0; 605 regs.ecx = count; 606 regs.edx = first; 607 regs.es = physicalAddress >> 4; 608 regs.edi = physicalAddress - (regs.es << 4); 609 610 status = sBIOSModule->interrupt(state, 0x10, ®s); 611 if (status != B_OK) { 612 dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS failed: %s\n", 613 strerror(status)); 614 goto out; 615 } 616 617 if ((regs.eax & 0xffff) != 0x4f) { 618 dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS returned " 619 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 620 status = B_ERROR; 621 } 622 623 out: 624 vbe_call_finish(state); 625 return status; 626 } 627