1 /* 2 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 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.h> 17 18 #include "driver.h" 19 #include "utility.h" 20 #include "vesa_info.h" 21 22 23 static uint32 24 get_color_space_for_depth(uint32 depth) 25 { 26 switch (depth) { 27 case 4: 28 return B_GRAY8; 29 // the app_server is smart enough to translate this to VGA mode 30 case 8: 31 return B_CMAP8; 32 case 15: 33 return B_RGB15; 34 case 16: 35 return B_RGB16; 36 case 24: 37 return B_RGB24; 38 case 32: 39 return B_RGB32; 40 } 41 42 return 0; 43 } 44 45 46 static status_t 47 vbe_get_mode_info(struct vm86_state *vmState, uint16 mode, 48 struct vbe_mode_info *modeInfo) 49 { 50 struct vbe_mode_info *vbeModeInfo = (struct vbe_mode_info *)0x1000; 51 52 memset(vbeModeInfo, 0, sizeof(vbe_mode_info)); 53 vmState->regs.eax = 0x4f01; 54 vmState->regs.ecx = mode; 55 vmState->regs.es = 0x1000 >> 4; 56 vmState->regs.edi = 0x0000; 57 58 status_t status = vm86_do_int(vmState, 0x10); 59 if (status != B_OK) { 60 dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): vm86 failed\n", mode); 61 return status; 62 } 63 64 if ((vmState->regs.eax & 0xffff) != 0x4f) { 65 dprintf(DEVICE_NAME ": vbe_get_mode_info(): BIOS returned 0x%04lx\n", 66 vmState->regs.eax & 0xffff); 67 return B_ENTRY_NOT_FOUND; 68 } 69 70 memcpy(modeInfo, vbeModeInfo, sizeof(struct vbe_mode_info)); 71 return B_OK; 72 } 73 74 75 static status_t 76 vbe_set_mode(struct vm86_state *vmState, uint16 mode) 77 { 78 vmState->regs.eax = 0x4f02; 79 vmState->regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 80 81 status_t status = vm86_do_int(vmState, 0x10); 82 if (status != B_OK) { 83 dprintf(DEVICE_NAME ": vbe_set_mode(%u): vm86 failed\n", mode); 84 return status; 85 } 86 87 if ((vmState->regs.eax & 0xffff) != 0x4f) { 88 dprintf(DEVICE_NAME ": vbe_set_mode(): BIOS returned 0x%04lx\n", 89 vmState->regs.eax & 0xffff); 90 return B_ERROR; 91 } 92 93 return B_OK; 94 } 95 96 97 // #pragma mark - 98 99 100 status_t 101 vesa_init(vesa_info &info) 102 { 103 frame_buffer_boot_info *bufferInfo 104 = (frame_buffer_boot_info *)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 105 if (bufferInfo == NULL) 106 return B_ERROR; 107 108 size_t modesSize = 0; 109 vesa_mode *modes = (vesa_mode *)get_boot_item(VESA_MODES_BOOT_INFO, 110 &modesSize); 111 info.modes = modes; 112 113 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 114 115 info.shared_area = create_area("vesa shared info", 116 (void **)&info.shared_info, B_ANY_KERNEL_ADDRESS, 117 ROUND_TO_PAGE_SIZE(sharedSize + modesSize), B_FULL_LOCK, 118 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); 119 if (info.shared_area < B_OK) 120 return info.shared_area; 121 122 vesa_shared_info &sharedInfo = *info.shared_info; 123 124 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 125 126 if (modes != NULL) { 127 sharedInfo.vesa_mode_offset = sharedSize; 128 sharedInfo.vesa_mode_count = modesSize / sizeof(vesa_mode); 129 130 memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize); 131 } 132 133 sharedInfo.frame_buffer_area = bufferInfo->area; 134 sharedInfo.frame_buffer = (uint8 *)bufferInfo->frame_buffer; 135 136 sharedInfo.current_mode.virtual_width = bufferInfo->width; 137 sharedInfo.current_mode.virtual_height = bufferInfo->height; 138 sharedInfo.current_mode.space = get_color_space_for_depth( 139 bufferInfo->depth); 140 sharedInfo.bytes_per_row = bufferInfo->bytes_per_row; 141 142 // TODO: we might want to do this via vm86 instead 143 edid1_info *edidInfo = (edid1_info *)get_boot_item(VESA_EDID_BOOT_INFO, 144 NULL); 145 if (edidInfo != NULL) { 146 sharedInfo.has_edid = true; 147 memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info)); 148 } 149 150 physical_entry mapping; 151 get_memory_map((void *)sharedInfo.frame_buffer, B_PAGE_SIZE, 152 &mapping, 1); 153 sharedInfo.physical_frame_buffer = (uint8 *)mapping.address; 154 155 dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n"); 156 return B_OK; 157 } 158 159 160 void 161 vesa_uninit(vesa_info &info) 162 { 163 dprintf(DEVICE_NAME": vesa_uninit()\n"); 164 165 delete_area(info.shared_info->frame_buffer_area); 166 delete_area(info.shared_area); 167 } 168 169 170 status_t 171 vesa_set_display_mode(vesa_info &info, unsigned int mode) 172 { 173 if (mode >= info.shared_info->vesa_mode_count) 174 return B_ENTRY_NOT_FOUND; 175 176 // Prepare vm86 mode environment 177 struct vm86_state vmState; 178 status_t status = vm86_prepare(&vmState, 0x20000); 179 if (status != B_OK) { 180 dprintf(DEVICE_NAME": vesa_set_display_mode(): vm86_prepare failed\n"); 181 return status; 182 } 183 184 area_id newFBArea; 185 frame_buffer_boot_info *bufferInfo; 186 struct vbe_mode_info modeInfo; 187 188 // Get mode information 189 status = vbe_get_mode_info(&vmState, info.modes[mode].mode, &modeInfo); 190 if (status != B_OK) { 191 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n"); 192 goto error; 193 } 194 195 // Set mode 196 status = vbe_set_mode(&vmState, info.modes[mode].mode); 197 if (status != B_OK) { 198 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot set mode\n"); 199 goto error; 200 } 201 202 // Map new frame buffer 203 void *frameBuffer; 204 newFBArea = map_physical_memory("vesa_fb", 205 (void *)modeInfo.physical_base, 206 modeInfo.bytes_per_row * modeInfo.height, B_ANY_KERNEL_ADDRESS, 207 B_READ_AREA | B_WRITE_AREA, &frameBuffer); 208 if (newFBArea < B_OK) { 209 status = (status_t)newFBArea; 210 goto error; 211 } 212 delete_area(info.shared_info->frame_buffer_area); 213 214 // Turn on write combining for the area 215 vm_set_area_memory_type(newFBArea, modeInfo.physical_base, B_MTR_WC); 216 217 // Update shared frame buffer information 218 info.shared_info->frame_buffer_area = newFBArea; 219 info.shared_info->frame_buffer = (uint8 *)frameBuffer; 220 info.shared_info->physical_frame_buffer = (uint8 *)modeInfo.physical_base; 221 info.shared_info->bytes_per_row = modeInfo.bytes_per_row; 222 info.shared_info->current_mode.virtual_width = modeInfo.width; 223 info.shared_info->current_mode.virtual_height = modeInfo.height; 224 info.shared_info->current_mode.space = get_color_space_for_depth( 225 modeInfo.bits_per_pixel); 226 227 // Update boot item as it's used in vesa_init() 228 bufferInfo 229 = (frame_buffer_boot_info *)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 230 bufferInfo->area = newFBArea; 231 bufferInfo->frame_buffer = (addr_t)frameBuffer; 232 bufferInfo->width = modeInfo.width; 233 bufferInfo->height = modeInfo.height; 234 bufferInfo->depth = modeInfo.bits_per_pixel; 235 bufferInfo->bytes_per_row = modeInfo.bytes_per_row; 236 237 error: 238 vm86_cleanup(&vmState); 239 return status; 240 } 241 242