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 phys_addr_t addr = info.u.h0.base_registers[i]; 42 uint64 barSize = info.u.h0.base_register_sizes[i]; 43 if (i < 5 44 && (info.u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) { 45 addr |= (uint64)info.u.h0.base_registers[i + 1] << 32; 46 barSize |= (uint64)info.u.h0.base_register_sizes[i + 1] << 32; 47 i++; 48 } 49 if (addr <= frameBuffer && addr + barSize > frameBuffer) { 50 // found it! 51 base = addr; 52 size = barSize; 53 dprintf(DEVICE_NAME " find_graphics_card: found base 0x%lx size %" B_PRIuSIZE "\n", 54 base, size); 55 56 put_module(B_PCI_MODULE_NAME); 57 return B_OK; 58 } 59 } 60 } 61 62 dprintf(DEVICE_NAME " find_graphics_card: no entry found for 0x%lx\n", frameBuffer); 63 put_module(B_PCI_MODULE_NAME); 64 return B_ENTRY_NOT_FOUND; 65 } 66 67 68 static uint32 69 get_color_space_for_depth(uint32 depth) 70 { 71 switch (depth) { 72 case 1: 73 return B_GRAY1; 74 case 4: 75 return B_GRAY8; 76 // the app_server is smart enough to translate this to VGA mode 77 case 8: 78 return B_CMAP8; 79 case 15: 80 return B_RGB15; 81 case 16: 82 return B_RGB16; 83 case 24: 84 return B_RGB24; 85 case 32: 86 return B_RGB32; 87 } 88 89 return 0; 90 } 91 92 93 /*! Remaps the frame buffer if necessary; if we've already mapped the complete 94 frame buffer, there is no need to map it again. 95 */ 96 static status_t 97 remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width, 98 uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) 99 { 100 vesa_shared_info& sharedInfo = *info.shared_info; 101 addr_t frameBuffer = info.frame_buffer; 102 103 if (!info.complete_frame_buffer_mapped) { 104 addr_t base = physicalBase; 105 size_t size = bytesPerRow * height; 106 // TODO: this logic looks suspicious and may need refactoring 107 bool remap = !initializing || frameBuffer == 0; 108 109 if (info.physical_frame_buffer_size != 0) { 110 // we can map the complete frame buffer 111 base = info.physical_frame_buffer; 112 size = info.physical_frame_buffer_size; 113 remap = true; 114 } 115 116 if (remap) { 117 area_id area = map_physical_memory("framebuffer buffer", base, 118 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, 119 (void**)&frameBuffer); 120 if (area < 0) 121 return area; 122 123 if (initializing) { 124 // We need to manually update the kernel's frame buffer address, 125 // since this frame buffer remapping has not been issued by the 126 // app_server (which would otherwise take care of this) 127 frame_buffer_update(frameBuffer, width, height, depth, 128 bytesPerRow); 129 } 130 131 delete_area(info.shared_info->frame_buffer_area); 132 133 info.frame_buffer = frameBuffer; 134 sharedInfo.frame_buffer_area = area; 135 136 // Turn on write combining for the area 137 vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY); 138 139 if (info.physical_frame_buffer_size != 0) 140 info.complete_frame_buffer_mapped = true; 141 } 142 } 143 144 if (info.complete_frame_buffer_mapped) 145 frameBuffer += physicalBase - info.physical_frame_buffer; 146 147 // Update shared frame buffer information 148 sharedInfo.frame_buffer = (uint8*)frameBuffer; 149 sharedInfo.physical_frame_buffer = (uint8*)physicalBase; 150 sharedInfo.bytes_per_row = bytesPerRow; 151 152 return B_OK; 153 } 154 155 156 // #pragma mark - 157 158 159 status_t 160 framebuffer_init(framebuffer_info& info) 161 { 162 frame_buffer_boot_info* bufferInfo 163 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 164 if (bufferInfo == NULL) 165 return B_ERROR; 166 167 info.complete_frame_buffer_mapped = false; 168 169 // Find out which PCI device we belong to, so that we know its frame buffer 170 // size 171 find_graphics_card(bufferInfo->physical_frame_buffer, 172 info.physical_frame_buffer, info.physical_frame_buffer_size); 173 174 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 175 176 info.shared_area = create_area("framebuffer shared info", 177 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, 178 ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, 179 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 180 if (info.shared_area < 0) 181 return info.shared_area; 182 183 vesa_shared_info& sharedInfo = *info.shared_info; 184 185 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 186 187 sharedInfo.frame_buffer_area = bufferInfo->area; 188 189 remap_frame_buffer(info, bufferInfo->physical_frame_buffer, 190 bufferInfo->width, bufferInfo->height, bufferInfo->depth, 191 bufferInfo->bytes_per_row, true); 192 // Does not matter if this fails - the frame buffer was already mapped 193 // before. 194 195 sharedInfo.current_mode.virtual_width = bufferInfo->width; 196 sharedInfo.current_mode.virtual_height = bufferInfo->height; 197 sharedInfo.current_mode.space = get_color_space_for_depth( 198 bufferInfo->depth); 199 200 edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO, 201 NULL); 202 if (edidInfo != NULL) { 203 sharedInfo.has_edid = true; 204 memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info)); 205 } 206 207 dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n"); 208 return B_OK; 209 } 210 211 212 void 213 framebuffer_uninit(framebuffer_info& info) 214 { 215 dprintf(DEVICE_NAME": framebuffer_uninit()\n"); 216 217 delete_area(info.shared_info->frame_buffer_area); 218 delete_area(info.shared_area); 219 } 220