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 17 18 //#define TRACE_MODE 19 #ifdef TRACE_MODE 20 extern "C" void _sPrintf(const char* format, ...); 21 # define TRACE(x) _sPrintf x 22 #else 23 # define TRACE(x) ; 24 #endif 25 26 27 static uint32 28 get_color_space_for_depth(uint32 depth) 29 { 30 switch (depth) { 31 case 4: 32 return B_GRAY8; 33 // the app_server is smart enough to translate this to VGA mode 34 case 8: 35 return B_CMAP8; 36 case 15: 37 return B_RGB15; 38 case 16: 39 return B_RGB16; 40 case 24: 41 return B_RGB24; 42 case 32: 43 return B_RGB32; 44 } 45 46 return 0; 47 } 48 49 50 /*! Checks if the specified \a mode can be set using VESA. */ 51 static bool 52 is_mode_supported(display_mode* mode) 53 { 54 vesa_mode* modes = gInfo->vesa_modes; 55 56 if (modes == NULL) { 57 // we're a UEFI framebuffer, just confirm it's our current mode 58 const display_mode ¤t = gInfo->shared_info->current_mode; 59 return mode->virtual_width == current.virtual_width 60 && mode->virtual_height == current.virtual_height 61 && mode->h_display_start == current.h_display_start 62 && mode->v_display_start == current.v_display_start 63 && mode->space == current.space; 64 } 65 66 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 67 // search mode in VESA mode list 68 // TODO: list is ordered, we could use binary search 69 if (modes[i].width == mode->virtual_width 70 && modes[i].height == mode->virtual_height 71 && get_color_space_for_depth(modes[i].bits_per_pixel) 72 == mode->space) 73 return true; 74 } 75 76 return false; 77 } 78 79 80 /*! Creates the initial mode list of the primary accelerant. 81 It's called from vesa_init_accelerant(). 82 */ 83 status_t 84 create_mode_list(void) 85 { 86 const color_space kVesaSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 87 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 88 const color_space kUefiSpaces[] = { 89 (color_space)gInfo->shared_info->current_mode.space 90 }; 91 92 uint32 initialModesCount = 0; 93 bool vesaAvailable = gInfo->vesa_modes != NULL; 94 95 // Add initial VESA modes. 96 display_mode* initialModes = NULL; 97 if (vesaAvailable) { 98 initialModes = (display_mode*)malloc( 99 sizeof(display_mode) * gInfo->shared_info->vesa_mode_count); 100 } 101 102 if (initialModes != NULL) { 103 initialModesCount = gInfo->shared_info->vesa_mode_count; 104 vesa_mode* vesaModes = gInfo->vesa_modes; 105 106 for (uint32 i = 0; i < initialModesCount; i++) { 107 compute_display_timing(vesaModes[i].width, vesaModes[i].height, 108 60, false, &initialModes[i].timing); 109 fill_display_mode(vesaModes[i].width, vesaModes[i].height, 110 &initialModes[i]); 111 } 112 } else { 113 // UEFI doesn't give us any VESA modes 114 initialModes = (display_mode*)malloc(sizeof(display_mode)); 115 if (initialModes != NULL) { 116 initialModesCount = 1; 117 118 display_mode &mode = gInfo->shared_info->current_mode; 119 120 compute_display_timing(mode.virtual_width, mode.virtual_height, 121 60, false, &initialModes[0].timing); 122 fill_display_mode(mode.virtual_width, mode.virtual_height, 123 &initialModes[0]); 124 } 125 } 126 127 const color_space *colorSpaces = vesaAvailable ? kVesaSpaces : kUefiSpaces; 128 size_t colorSpaceCount = vesaAvailable ? 129 sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]) : 1; 130 131 gInfo->mode_list_area = create_display_modes("vesa modes", 132 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 133 initialModes, initialModesCount, colorSpaces, colorSpaceCount, 134 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 135 136 free(initialModes); 137 138 if (gInfo->mode_list_area < 0) 139 return gInfo->mode_list_area; 140 141 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 142 return B_OK; 143 } 144 145 146 // #pragma mark - 147 148 149 uint32 150 vesa_accelerant_mode_count(void) 151 { 152 TRACE(("vesa_accelerant_mode_count() = %d\n", gInfo->shared_info->mode_count)); 153 return gInfo->shared_info->mode_count; 154 } 155 156 157 status_t 158 vesa_get_mode_list(display_mode* modeList) 159 { 160 TRACE(("vesa_get_mode_info()\n")); 161 memcpy(modeList, gInfo->mode_list, 162 gInfo->shared_info->mode_count * sizeof(display_mode)); 163 return B_OK; 164 } 165 166 167 status_t 168 vesa_propose_display_mode(display_mode* target, const display_mode* low, 169 const display_mode* high) 170 { 171 TRACE(("vesa_propose_display_mode()\n")); 172 173 // just search for the specified mode in the list 174 175 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 176 display_mode* current = &gInfo->mode_list[i]; 177 178 if (target->virtual_width != current->virtual_width 179 || target->virtual_height != current->virtual_height 180 || target->space != current->space) 181 continue; 182 183 *target = *current; 184 return B_OK; 185 } 186 return B_BAD_VALUE; 187 } 188 189 190 status_t 191 vesa_set_display_mode(display_mode* _mode) 192 { 193 TRACE(("vesa_set_display_mode()\n")); 194 195 display_mode mode = *_mode; 196 if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK) 197 return B_BAD_VALUE; 198 199 vesa_mode* modes = gInfo->vesa_modes; 200 if (modes == NULL) 201 return B_BAD_VALUE; 202 // UEFI has no VESA modes 203 204 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 205 // search mode in VESA mode list 206 // TODO: list is ordered, we could use binary search 207 if (modes[i].width == mode.virtual_width 208 && modes[i].height == mode.virtual_height 209 && get_color_space_for_depth(modes[i].bits_per_pixel) 210 == mode.space) { 211 if (gInfo->current_mode == i) 212 return B_OK; 213 status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); 214 if (result == B_OK) 215 gInfo->current_mode = i; 216 return result; 217 } 218 } 219 220 return B_UNSUPPORTED; 221 } 222 223 224 status_t 225 vesa_get_display_mode(display_mode* _currentMode) 226 { 227 TRACE(("vesa_get_display_mode()\n")); 228 *_currentMode = gInfo->shared_info->current_mode; 229 return B_OK; 230 } 231 232 233 status_t 234 vesa_get_edid_info(void* info, size_t size, uint32* _version) 235 { 236 TRACE(("vesa_get_edid_info()\n")); 237 238 if (!gInfo->shared_info->has_edid) 239 return B_ERROR; 240 if (size < sizeof(struct edid1_info)) 241 return B_BUFFER_OVERFLOW; 242 243 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 244 *_version = EDID_VERSION_1; 245 return B_OK; 246 } 247 248 249 status_t 250 vesa_get_frame_buffer_config(frame_buffer_config* config) 251 { 252 TRACE(("vesa_get_frame_buffer_config()\n")); 253 254 config->frame_buffer = gInfo->shared_info->frame_buffer; 255 config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; 256 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 257 258 return B_OK; 259 } 260 261 262 status_t 263 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 264 { 265 TRACE(("vesa_get_pixel_clock_limits()\n")); 266 267 // TODO: do some real stuff here (taken from radeon driver) 268 uint32 totalPixel = (uint32)mode->timing.h_total 269 * (uint32)mode->timing.v_total; 270 uint32 clockLimit = 2000000; 271 272 // lower limit of about 48Hz vertical refresh 273 *_low = totalPixel * 48L / 1000L; 274 if (*_low > clockLimit) 275 return B_ERROR; 276 277 *_high = clockLimit; 278 return B_OK; 279 } 280 281 282 status_t 283 vesa_move_display(uint16 h_display_start, uint16 v_display_start) 284 { 285 TRACE(("vesa_move_display()\n")); 286 return B_ERROR; 287 } 288 289 290 status_t 291 vesa_get_timing_constraints(display_timing_constraints* constraints) 292 { 293 TRACE(("vesa_get_timing_constraints()\n")); 294 return B_ERROR; 295 } 296 297 298 void 299 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 300 { 301 TRACE(("vesa_set_indexed_colors()\n")); 302 303 vesa_set_indexed_colors_args args; 304 args.first = first; 305 args.count = count; 306 args.colors = colors; 307 ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); 308 } 309 310