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