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 compute_display_timing(initialModes[0].virtual_width, 119 initialModes[0].virtual_height, 60, false, 120 &initialModes[0].timing); 121 fill_display_mode(initialModes[0].virtual_width, 122 initialModes[0].virtual_height, &initialModes[0]); 123 } 124 } 125 126 const color_space *colorSpaces = vesaAvailable ? kVesaSpaces : kUefiSpaces; 127 size_t colorSpaceCount = vesaAvailable ? 128 sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]) : 1; 129 130 gInfo->mode_list_area = create_display_modes("vesa modes", 131 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 132 initialModes, initialModesCount, colorSpaces, colorSpaceCount, 133 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 134 135 free(initialModes); 136 137 if (gInfo->mode_list_area < 0) 138 return gInfo->mode_list_area; 139 140 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 141 return B_OK; 142 } 143 144 145 // #pragma mark - 146 147 148 uint32 149 vesa_accelerant_mode_count(void) 150 { 151 TRACE(("vesa_accelerant_mode_count() = %d\n", gInfo->shared_info->mode_count)); 152 return gInfo->shared_info->mode_count; 153 } 154 155 156 status_t 157 vesa_get_mode_list(display_mode* modeList) 158 { 159 TRACE(("vesa_get_mode_info()\n")); 160 memcpy(modeList, gInfo->mode_list, 161 gInfo->shared_info->mode_count * sizeof(display_mode)); 162 return B_OK; 163 } 164 165 166 status_t 167 vesa_propose_display_mode(display_mode* target, const display_mode* low, 168 const display_mode* high) 169 { 170 TRACE(("vesa_propose_display_mode()\n")); 171 172 // just search for the specified mode in the list 173 174 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 175 display_mode* current = &gInfo->mode_list[i]; 176 177 if (target->virtual_width != current->virtual_width 178 || target->virtual_height != current->virtual_height 179 || target->space != current->space) 180 continue; 181 182 *target = *current; 183 return B_OK; 184 } 185 return B_BAD_VALUE; 186 } 187 188 189 status_t 190 vesa_set_display_mode(display_mode* _mode) 191 { 192 TRACE(("vesa_set_display_mode()\n")); 193 194 display_mode mode = *_mode; 195 if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK) 196 return B_BAD_VALUE; 197 198 vesa_mode* modes = gInfo->vesa_modes; 199 if (modes == NULL) 200 return B_BAD_VALUE; 201 // UEFI has no VESA modes 202 203 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 204 // search mode in VESA mode list 205 // TODO: list is ordered, we could use binary search 206 if (modes[i].width == mode.virtual_width 207 && modes[i].height == mode.virtual_height 208 && get_color_space_for_depth(modes[i].bits_per_pixel) 209 == mode.space) { 210 if (gInfo->current_mode == i) 211 return B_OK; 212 status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); 213 if (result == B_OK) 214 gInfo->current_mode = i; 215 return result; 216 } 217 } 218 219 return B_UNSUPPORTED; 220 } 221 222 223 status_t 224 vesa_get_display_mode(display_mode* _currentMode) 225 { 226 TRACE(("vesa_get_display_mode()\n")); 227 *_currentMode = gInfo->shared_info->current_mode; 228 return B_OK; 229 } 230 231 232 status_t 233 vesa_get_edid_info(void* info, size_t size, uint32* _version) 234 { 235 TRACE(("vesa_get_edid_info()\n")); 236 237 if (!gInfo->shared_info->has_edid) 238 return B_ERROR; 239 if (size < sizeof(struct edid1_info)) 240 return B_BUFFER_OVERFLOW; 241 242 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 243 *_version = EDID_VERSION_1; 244 return B_OK; 245 } 246 247 248 status_t 249 vesa_get_frame_buffer_config(frame_buffer_config* config) 250 { 251 TRACE(("vesa_get_frame_buffer_config()\n")); 252 253 config->frame_buffer = gInfo->shared_info->frame_buffer; 254 config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; 255 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 256 257 return B_OK; 258 } 259 260 261 status_t 262 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 263 { 264 TRACE(("vesa_get_pixel_clock_limits()\n")); 265 266 // TODO: do some real stuff here (taken from radeon driver) 267 uint32 totalPixel = (uint32)mode->timing.h_total 268 * (uint32)mode->timing.v_total; 269 uint32 clockLimit = 2000000; 270 271 // lower limit of about 48Hz vertical refresh 272 *_low = totalPixel * 48L / 1000L; 273 if (*_low > clockLimit) 274 return B_ERROR; 275 276 *_high = clockLimit; 277 return B_OK; 278 } 279 280 281 status_t 282 vesa_move_display(uint16 h_display_start, uint16 v_display_start) 283 { 284 TRACE(("vesa_move_display()\n")); 285 return B_ERROR; 286 } 287 288 289 status_t 290 vesa_get_timing_constraints(display_timing_constraints* constraints) 291 { 292 TRACE(("vesa_get_timing_constraints()\n")); 293 return B_ERROR; 294 } 295 296 297 void 298 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 299 { 300 TRACE(("vesa_set_indexed_colors()\n")); 301 302 vesa_set_indexed_colors_args args; 303 args.first = first; 304 args.count = count; 305 args.colors = colors; 306 ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); 307 } 308 309