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 bool remap = !initializing; 107 108 if (info.physical_frame_buffer_size != 0) { 109 // we can map the complete frame buffer 110 base = info.physical_frame_buffer; 111 size = info.physical_frame_buffer_size; 112 remap = true; 113 } 114 115 if (remap) { 116 area_id area = map_physical_memory("framebuffer buffer", base, 117 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, 118 (void**)&frameBuffer); 119 if (area < 0) 120 return area; 121 122 if (initializing) { 123 // We need to manually update the kernel's frame buffer address, 124 // since this frame buffer remapping has not been issued by the 125 // app_server (which would otherwise take care of this) 126 frame_buffer_update(frameBuffer, width, height, depth, 127 bytesPerRow); 128 } 129 130 delete_area(info.shared_info->frame_buffer_area); 131 132 info.frame_buffer = frameBuffer; 133 sharedInfo.frame_buffer_area = area; 134 135 // Turn on write combining for the area 136 vm_set_area_memory_type(area, base, B_MTR_WC); 137 138 if (info.physical_frame_buffer_size != 0) 139 info.complete_frame_buffer_mapped = true; 140 } 141 } 142 143 if (info.complete_frame_buffer_mapped) 144 frameBuffer += physicalBase - info.physical_frame_buffer; 145 146 // Update shared frame buffer information 147 sharedInfo.frame_buffer = (uint8*)frameBuffer; 148 sharedInfo.physical_frame_buffer = (uint8*)physicalBase; 149 sharedInfo.bytes_per_row = bytesPerRow; 150 151 return B_OK; 152 } 153 154 155 // #pragma mark - 156 157 158 status_t 159 framebuffer_init(framebuffer_info& info) 160 { 161 frame_buffer_boot_info* bufferInfo 162 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 163 if (bufferInfo == NULL) 164 return B_ERROR; 165 166 info.complete_frame_buffer_mapped = false; 167 168 // Find out which PCI device we belong to, so that we know its frame buffer 169 // size 170 find_graphics_card(bufferInfo->physical_frame_buffer, 171 info.physical_frame_buffer, info.physical_frame_buffer_size); 172 173 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 174 175 info.shared_area = create_area("framebuffer shared info", 176 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, 177 ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, 178 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 179 if (info.shared_area < 0) 180 return info.shared_area; 181 182 vesa_shared_info& sharedInfo = *info.shared_info; 183 184 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 185 186 sharedInfo.frame_buffer_area = bufferInfo->area; 187 188 remap_frame_buffer(info, bufferInfo->physical_frame_buffer, 189 bufferInfo->width, bufferInfo->height, bufferInfo->depth, 190 bufferInfo->bytes_per_row, true); 191 // Does not matter if this fails - the frame buffer was already mapped 192 // before. 193 194 sharedInfo.current_mode.virtual_width = bufferInfo->width; 195 sharedInfo.current_mode.virtual_height = bufferInfo->height; 196 sharedInfo.current_mode.space = get_color_space_for_depth( 197 bufferInfo->depth); 198 199 dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n"); 200 return B_OK; 201 } 202 203 204 void 205 framebuffer_uninit(framebuffer_info& info) 206 { 207 dprintf(DEVICE_NAME": framebuffer_uninit()\n"); 208 209 delete_area(info.shared_info->frame_buffer_area); 210 delete_area(info.shared_area); 211 } 212