1 /* 2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "framebuffer_private.h" 9 #include "vesa.h" 10 11 #include <string.h> 12 13 #include <drivers/bios.h> 14 15 #include <boot_item.h> 16 #include <frame_buffer_console.h> 17 #include <util/kernel_cpp.h> 18 #include <vm/vm.h> 19 20 #include "driver.h" 21 #include "utility.h" 22 #include "vesa_info.h" 23 24 25 static status_t 26 find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size) 27 { 28 // TODO: when we port this over to the new driver API, this mechanism can be 29 // used to find the right device_node 30 pci_module_info* pci; 31 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK) 32 return B_ERROR; 33 34 pci_info info; 35 for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) { 36 if (info.class_base != PCI_display) 37 continue; 38 39 // check PCI BARs 40 for (uint32 i = 0; i < 6; i++) { 41 if (info.u.h0.base_registers[i] <= frameBuffer 42 && info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i] 43 > frameBuffer) { 44 // found it! 45 base = info.u.h0.base_registers[i]; 46 size = info.u.h0.base_register_sizes[i]; 47 48 put_module(B_PCI_MODULE_NAME); 49 return B_OK; 50 } 51 } 52 } 53 54 put_module(B_PCI_MODULE_NAME); 55 return B_ENTRY_NOT_FOUND; 56 } 57 58 59 static uint32 60 get_color_space_for_depth(uint32 depth) 61 { 62 switch (depth) { 63 case 1: 64 return B_GRAY1; 65 case 4: 66 return B_GRAY8; 67 // the app_server is smart enough to translate this to VGA mode 68 case 8: 69 return B_CMAP8; 70 case 15: 71 return B_RGB15; 72 case 16: 73 return B_RGB16; 74 case 24: 75 return B_RGB24; 76 case 32: 77 return B_RGB32; 78 } 79 80 return 0; 81 } 82 83 84 /*! Remaps the frame buffer if necessary; if we've already mapped the complete 85 frame buffer, there is no need to map it again. 86 */ 87 static status_t 88 remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width, 89 uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) 90 { 91 vesa_shared_info& sharedInfo = *info.shared_info; 92 addr_t frameBuffer = info.frame_buffer; 93 94 if (!info.complete_frame_buffer_mapped) { 95 addr_t base = physicalBase; 96 size_t size = bytesPerRow * height; 97 bool remap = !initializing; 98 99 if (info.physical_frame_buffer_size != 0) { 100 // we can map the complete frame buffer 101 base = info.physical_frame_buffer; 102 size = info.physical_frame_buffer_size; 103 remap = true; 104 } 105 106 if (remap) { 107 area_id area = map_physical_memory("framebuffer buffer", base, 108 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, 109 (void**)&frameBuffer); 110 if (area < 0) 111 return area; 112 113 if (initializing) { 114 // We need to manually update the kernel's frame buffer address, 115 // since this frame buffer remapping has not been issued by the 116 // app_server (which would otherwise take care of this) 117 frame_buffer_update(frameBuffer, width, height, depth, 118 bytesPerRow); 119 } 120 121 delete_area(info.shared_info->frame_buffer_area); 122 123 info.frame_buffer = frameBuffer; 124 sharedInfo.frame_buffer_area = area; 125 126 // Turn on write combining for the area 127 vm_set_area_memory_type(area, base, B_MTR_WC); 128 129 if (info.physical_frame_buffer_size != 0) 130 info.complete_frame_buffer_mapped = true; 131 } 132 } 133 134 if (info.complete_frame_buffer_mapped) 135 frameBuffer += physicalBase - info.physical_frame_buffer; 136 137 // Update shared frame buffer information 138 sharedInfo.frame_buffer = (uint8*)frameBuffer; 139 sharedInfo.physical_frame_buffer = (uint8*)physicalBase; 140 sharedInfo.bytes_per_row = bytesPerRow; 141 142 return B_OK; 143 } 144 145 146 // #pragma mark - 147 148 149 status_t 150 framebuffer_init(framebuffer_info& info) 151 { 152 frame_buffer_boot_info* bufferInfo 153 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 154 if (bufferInfo == NULL) 155 return B_ERROR; 156 157 info.complete_frame_buffer_mapped = false; 158 159 // Find out which PCI device we belong to, so that we know its frame buffer 160 // size 161 find_graphics_card(bufferInfo->physical_frame_buffer, 162 info.physical_frame_buffer, info.physical_frame_buffer_size); 163 164 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 165 166 info.shared_area = create_area("framebuffer shared info", 167 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, 168 ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, 169 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 170 if (info.shared_area < 0) 171 return info.shared_area; 172 173 vesa_shared_info& sharedInfo = *info.shared_info; 174 175 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 176 177 sharedInfo.frame_buffer_area = bufferInfo->area; 178 179 remap_frame_buffer(info, bufferInfo->physical_frame_buffer, 180 bufferInfo->width, bufferInfo->height, bufferInfo->depth, 181 bufferInfo->bytes_per_row, true); 182 // Does not matter if this fails - the frame buffer was already mapped 183 // before. 184 185 sharedInfo.current_mode.virtual_width = bufferInfo->width; 186 sharedInfo.current_mode.virtual_height = bufferInfo->height; 187 sharedInfo.current_mode.space = get_color_space_for_depth( 188 bufferInfo->depth); 189 190 dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n"); 191 return B_OK; 192 } 193 194 195 void 196 framebuffer_uninit(framebuffer_info& info) 197 { 198 dprintf(DEVICE_NAME": framebuffer_uninit()\n"); 199 200 delete_area(info.shared_info->frame_buffer_area); 201 delete_area(info.shared_area); 202 } 203