1/* 2 * Copyright 2005-2015, Axel D��rfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include <stdlib.h> 8#include <string.h> 9 10#include <compute_display_timing.h> 11#include <create_display_modes.h> 12 13#include "accelerant_protos.h" 14#include "accelerant.h" 15#include "utility.h" 16#include "vesa_info.h" 17 18 19//#define TRACE_MODE 20#ifdef TRACE_MODE 21extern "C" void _sPrintf(const char* format, ...); 22# define TRACE(x) _sPrintf x 23#else 24# define TRACE(x) ; 25#endif 26 27 28struct nvidia_resolution { 29 int width; 30 int height; 31}; 32 33static const nvidia_resolution kNVidiaAllowedResolutions[] = { 34 { 1280, 720 }, 35 { 1280, 800 }, 36 { 1360, 768 }, 37 { 1400, 1050 }, 38 { 1440, 900 }, 39 { 1600, 900 }, 40 { 1600, 1200 }, 41 { 1680, 1050 }, 42 { 1920, 1080 }, 43 { 1920, 1200 }, 44 { 2048, 1536 }, 45}; 46 47 48static uint32 49get_color_space_for_depth(uint32 depth) 50{ 51 switch (depth) { 52 case 4: 53 return B_GRAY8; 54 // the app_server is smart enough to translate this to VGA mode 55 case 8: 56 return B_CMAP8; 57 case 15: 58 return B_RGB15; 59 case 16: 60 return B_RGB16; 61 case 24: 62 return B_RGB24; 63 case 32: 64 return B_RGB32; 65 } 66 67 return 0; 68} 69 70 71/*! Checks if the specified \a mode can be set using VESA. */ 72static bool 73is_mode_supported(display_mode* mode) 74{ 75 vesa_mode* modes = gInfo->vesa_modes; 76 77 bool colorspaceSupported = false; 78 79 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 80 // search mode in VESA mode list 81 // TODO: list is ordered, we could use binary search 82 if (modes[i].width == mode->virtual_width 83 && modes[i].height == mode->virtual_height 84 && get_color_space_for_depth(modes[i].bits_per_pixel) 85 == mode->space) 86 return true; 87 88 if (get_color_space_for_depth(modes[i].bits_per_pixel) == mode->space) 89 colorspaceSupported = true; 90 } 91 92 bios_type_enum type = gInfo->shared_info->bios_type; 93 if (type == kIntelBiosType || type == kAtomBiosType1 || type == kAtomBiosType2) { 94 // We know how to patch the BIOS, so we can set any mode we want 95 return colorspaceSupported; 96 } 97 98 if (type == kNVidiaBiosType) { 99 for (size_t i = 0; i < B_COUNT_OF(kNVidiaAllowedResolutions); i++) { 100 if (mode->virtual_width == kNVidiaAllowedResolutions[i].width 101 && mode->virtual_height == kNVidiaAllowedResolutions[i].height) 102 return colorspaceSupported; 103 } 104 } 105 106 return false; 107} 108 109 110/*! Creates the initial mode list of the primary accelerant. 111 It's called from vesa_init_accelerant(). 112*/ 113status_t 114create_mode_list(void) 115{ 116 const color_space kVesaSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 117 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 118 119 uint32 initialModesCount = 0; 120 121 // Add initial VESA modes. 122 display_mode* initialModes = (display_mode*)malloc( 123 sizeof(display_mode) * gInfo->shared_info->vesa_mode_count); 124 if (initialModes != NULL) { 125 initialModesCount = gInfo->shared_info->vesa_mode_count; 126 vesa_mode* vesaModes = gInfo->vesa_modes; 127 128 for (uint32 i = 0; i < initialModesCount; i++) { 129 compute_display_timing(vesaModes[i].width, vesaModes[i].height, 130 60, false, &initialModes[i].timing); 131 fill_display_mode(vesaModes[i].width, vesaModes[i].height, 132 &initialModes[i]); 133 } 134 } 135 136 gInfo->mode_list_area = create_display_modes("vesa modes", 137 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 138 initialModes, initialModesCount, 139 kVesaSpaces, sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]), 140 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 141 142 free(initialModes); 143 144 if (gInfo->mode_list_area < 0) 145 return gInfo->mode_list_area; 146 147 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 148 return B_OK; 149} 150 151 152// #pragma mark - 153 154 155uint32 156vesa_accelerant_mode_count(void) 157{ 158 TRACE(("vesa_accelerant_mode_count() = %d\n", gInfo->shared_info->mode_count)); 159 return gInfo->shared_info->mode_count; 160} 161 162 163status_t 164vesa_get_mode_list(display_mode* modeList) 165{ 166 TRACE(("vesa_get_mode_info()\n")); 167 memcpy(modeList, gInfo->mode_list, 168 gInfo->shared_info->mode_count * sizeof(display_mode)); 169 return B_OK; 170} 171 172 173status_t 174vesa_propose_display_mode(display_mode* target, const display_mode* low, 175 const display_mode* high) 176{ 177 TRACE(("vesa_propose_display_mode()\n")); 178 179 // Search for the specified mode in the list. If it's in there, we don't need a custom mode and 180 // we just normalize it to the info provided by the VESA BIOS. 181 182 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 183 display_mode* current = &gInfo->mode_list[i]; 184 185 if (target->virtual_width != current->virtual_width 186 || target->virtual_height != current->virtual_height 187 || target->space != current->space) 188 continue; 189 190 *target = *current; 191 return B_OK; 192 } 193 194 bios_type_enum type = gInfo->shared_info->bios_type; 195 if (type == kIntelBiosType || type == kAtomBiosType1 || type == kAtomBiosType2) { 196 // The driver says it knows the BIOS type, and therefore how to patch it to apply custom 197 // modes. 198 return B_OK; 199 } 200 201 if (type == kNVidiaBiosType) { 202 // For NVidia there is only a limited set of extra resolutions we know how to set 203 for (size_t i = 0; i < B_COUNT_OF(kNVidiaAllowedResolutions); i++) { 204 if (target->virtual_width == kNVidiaAllowedResolutions[i].width 205 && target->virtual_height == kNVidiaAllowedResolutions[i].height) 206 return B_OK; 207 } 208 } 209 210 return B_BAD_VALUE; 211} 212 213 214status_t 215vesa_set_display_mode(display_mode* _mode) 216{ 217 TRACE(("vesa_set_display_mode()\n")); 218 219 display_mode mode = *_mode; 220 if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK) 221 return B_BAD_VALUE; 222 223 vesa_mode* modes = gInfo->vesa_modes; 224 for (int32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 225 // search mode in VESA mode list 226 // TODO: list is ordered, we could use binary search 227 if (modes[i].width == mode.virtual_width 228 && modes[i].height == mode.virtual_height 229 && get_color_space_for_depth(modes[i].bits_per_pixel) 230 == mode.space) { 231 if (gInfo->current_mode == i) 232 return B_OK; 233 status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); 234 if (result == B_OK) 235 gInfo->current_mode = i; 236 return result; 237 } 238 } 239 240 // If the mode is not found in the list of standard mode, live patch the BIOS to get it anyway 241 status_t result = ioctl(gInfo->device, VESA_SET_CUSTOM_DISPLAY_MODE, 242 &mode, sizeof(display_mode)); 243 if (result == B_OK) { 244 gInfo->current_mode = -1; 245 } 246 247 return result; 248} 249 250 251status_t 252vesa_get_display_mode(display_mode* _currentMode) 253{ 254 TRACE(("vesa_get_display_mode()\n")); 255 *_currentMode = gInfo->shared_info->current_mode; 256 return B_OK; 257} 258 259 260status_t 261vesa_get_edid_info(void* info, size_t size, uint32* _version) 262{ 263 TRACE(("vesa_get_edid_info()\n")); 264 265 if (!gInfo->shared_info->has_edid) 266 return B_ERROR; 267 if (size < sizeof(struct edid1_info)) 268 return B_BUFFER_OVERFLOW; 269 270 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 271 *_version = EDID_VERSION_1; 272 return B_OK; 273} 274 275 276status_t 277vesa_get_frame_buffer_config(frame_buffer_config* config) 278{ 279 TRACE(("vesa_get_frame_buffer_config()\n")); 280 281 config->frame_buffer = gInfo->shared_info->frame_buffer; 282 config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; 283 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 284 285 return B_OK; 286} 287 288 289status_t 290vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 291{ 292 TRACE(("vesa_get_pixel_clock_limits()\n")); 293 294 // TODO: do some real stuff here (taken from radeon driver) 295 uint32 totalPixel = (uint32)mode->timing.h_total 296 * (uint32)mode->timing.v_total; 297 uint32 clockLimit = 2000000; 298 299 // lower limit of about 48Hz vertical refresh 300 *_low = totalPixel * 48L / 1000L; 301 if (*_low > clockLimit) 302 return B_ERROR; 303 304 *_high = clockLimit; 305 return B_OK; 306} 307 308 309status_t 310vesa_move_display(uint16 h_display_start, uint16 v_display_start) 311{ 312 TRACE(("vesa_move_display()\n")); 313 return B_ERROR; 314} 315 316 317status_t 318vesa_get_timing_constraints(display_timing_constraints* constraints) 319{ 320 TRACE(("vesa_get_timing_constraints()\n")); 321 return B_ERROR; 322} 323 324 325void 326vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 327{ 328 TRACE(("vesa_set_indexed_colors()\n")); 329 330 vesa_set_indexed_colors_args args; 331 args.first = first; 332 args.count = count; 333 args.colors = colors; 334 ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); 335} 336 337