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 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 57 // search mode in VESA mode list 58 // TODO: list is ordered, we could use binary search 59 if (modes[i].width == mode->virtual_width 60 && modes[i].height == mode->virtual_height 61 && get_color_space_for_depth(modes[i].bits_per_pixel) 62 == mode->space) 63 return true; 64 } 65 66 return false; 67 } 68 69 70 /*! Creates the initial mode list of the primary accelerant. 71 It's called from vesa_init_accelerant(). 72 */ 73 status_t 74 create_mode_list(void) 75 { 76 const color_space kVesaSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 77 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 78 79 uint32 initialModesCount = 0; 80 81 // Add initial VESA modes. 82 display_mode* initialModes = (display_mode*)malloc( 83 sizeof(display_mode) * gInfo->shared_info->vesa_mode_count); 84 if (initialModes != NULL) { 85 initialModesCount = gInfo->shared_info->vesa_mode_count; 86 vesa_mode* vesaModes = gInfo->vesa_modes; 87 88 for (uint32 i = 0; i < initialModesCount; i++) { 89 compute_display_timing(vesaModes[i].width, vesaModes[i].height, 90 60, false, &initialModes[i].timing); 91 fill_display_mode(vesaModes[i].width, vesaModes[i].height, 92 &initialModes[i]); 93 } 94 } 95 96 gInfo->mode_list_area = create_display_modes("vesa modes", 97 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 98 initialModes, initialModesCount, 99 kVesaSpaces, sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]), 100 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 101 102 free(initialModes); 103 104 if (gInfo->mode_list_area < 0) 105 return gInfo->mode_list_area; 106 107 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 108 return B_OK; 109 } 110 111 112 // #pragma mark - 113 114 115 uint32 116 vesa_accelerant_mode_count(void) 117 { 118 TRACE(("vesa_accelerant_mode_count() = %d\n", gInfo->shared_info->mode_count)); 119 return gInfo->shared_info->mode_count; 120 } 121 122 123 status_t 124 vesa_get_mode_list(display_mode* modeList) 125 { 126 TRACE(("vesa_get_mode_info()\n")); 127 memcpy(modeList, gInfo->mode_list, 128 gInfo->shared_info->mode_count * sizeof(display_mode)); 129 return B_OK; 130 } 131 132 133 status_t 134 vesa_propose_display_mode(display_mode* target, const display_mode* low, 135 const display_mode* high) 136 { 137 TRACE(("vesa_propose_display_mode()\n")); 138 139 // just search for the specified mode in the list 140 141 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 142 display_mode* current = &gInfo->mode_list[i]; 143 144 if (target->virtual_width != current->virtual_width 145 || target->virtual_height != current->virtual_height 146 || target->space != current->space) 147 continue; 148 149 *target = *current; 150 return B_OK; 151 } 152 return B_BAD_VALUE; 153 } 154 155 156 status_t 157 vesa_set_display_mode(display_mode* _mode) 158 { 159 TRACE(("vesa_set_display_mode()\n")); 160 161 display_mode mode = *_mode; 162 if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK) 163 return B_BAD_VALUE; 164 165 if (gInfo->shared_info->current_mode.virtual_width == mode.virtual_width 166 && gInfo->shared_info->current_mode.virtual_height 167 == mode.virtual_height 168 && gInfo->shared_info->current_mode.space == mode.space) { 169 return B_OK; 170 } 171 172 vesa_mode* modes = gInfo->vesa_modes; 173 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 174 // search mode in VESA mode list 175 // TODO: list is ordered, we could use binary search 176 if (modes[i].width == mode.virtual_width 177 && modes[i].height == mode.virtual_height 178 && get_color_space_for_depth(modes[i].bits_per_pixel) 179 == mode.space) { 180 return ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); 181 } 182 } 183 184 return B_UNSUPPORTED; 185 } 186 187 188 status_t 189 vesa_get_display_mode(display_mode* _currentMode) 190 { 191 TRACE(("vesa_get_display_mode()\n")); 192 *_currentMode = gInfo->shared_info->current_mode; 193 return B_OK; 194 } 195 196 197 status_t 198 vesa_get_edid_info(void* info, size_t size, uint32* _version) 199 { 200 TRACE(("vesa_get_edid_info()\n")); 201 202 if (!gInfo->shared_info->has_edid) 203 return B_ERROR; 204 if (size < sizeof(struct edid1_info)) 205 return B_BUFFER_OVERFLOW; 206 207 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 208 *_version = EDID_VERSION_1; 209 return B_OK; 210 } 211 212 213 status_t 214 vesa_get_frame_buffer_config(frame_buffer_config* config) 215 { 216 TRACE(("vesa_get_frame_buffer_config()\n")); 217 218 config->frame_buffer = gInfo->shared_info->frame_buffer; 219 config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; 220 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 221 222 return B_OK; 223 } 224 225 226 status_t 227 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 228 { 229 TRACE(("vesa_get_pixel_clock_limits()\n")); 230 231 // TODO: do some real stuff here (taken from radeon driver) 232 uint32 totalPixel = (uint32)mode->timing.h_total 233 * (uint32)mode->timing.v_total; 234 uint32 clockLimit = 2000000; 235 236 // lower limit of about 48Hz vertical refresh 237 *_low = totalPixel * 48L / 1000L; 238 if (*_low > clockLimit) 239 return B_ERROR; 240 241 *_high = clockLimit; 242 return B_OK; 243 } 244 245 246 status_t 247 vesa_move_display(uint16 h_display_start, uint16 v_display_start) 248 { 249 TRACE(("vesa_move_display()\n")); 250 return B_ERROR; 251 } 252 253 254 status_t 255 vesa_get_timing_constraints(display_timing_constraints* constraints) 256 { 257 TRACE(("vesa_get_timing_constraints()\n")); 258 return B_ERROR; 259 } 260 261 262 void 263 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 264 { 265 TRACE(("vesa_set_indexed_colors()\n")); 266 267 vesa_set_indexed_colors_args args; 268 args.first = first; 269 args.count = count; 270 args.colors = colors; 271 ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); 272 } 273 274