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 vesa_mode* modes = gInfo->vesa_modes; 166 for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { 167 // search mode in VESA mode list 168 // TODO: list is ordered, we could use binary search 169 if (modes[i].width == mode.virtual_width 170 && modes[i].height == mode.virtual_height 171 && get_color_space_for_depth(modes[i].bits_per_pixel) 172 == mode.space) { 173 if (gInfo->current_mode == i) 174 return B_OK; 175 status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); 176 if (result == B_OK) 177 gInfo->current_mode = i; 178 return result; 179 } 180 } 181 182 return B_UNSUPPORTED; 183 } 184 185 186 status_t 187 vesa_get_display_mode(display_mode* _currentMode) 188 { 189 TRACE(("vesa_get_display_mode()\n")); 190 *_currentMode = gInfo->shared_info->current_mode; 191 return B_OK; 192 } 193 194 195 status_t 196 vesa_get_edid_info(void* info, size_t size, uint32* _version) 197 { 198 TRACE(("vesa_get_edid_info()\n")); 199 200 if (!gInfo->shared_info->has_edid) 201 return B_ERROR; 202 if (size < sizeof(struct edid1_info)) 203 return B_BUFFER_OVERFLOW; 204 205 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 206 *_version = EDID_VERSION_1; 207 return B_OK; 208 } 209 210 211 status_t 212 vesa_get_frame_buffer_config(frame_buffer_config* config) 213 { 214 TRACE(("vesa_get_frame_buffer_config()\n")); 215 216 config->frame_buffer = gInfo->shared_info->frame_buffer; 217 config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; 218 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 219 220 return B_OK; 221 } 222 223 224 status_t 225 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 226 { 227 TRACE(("vesa_get_pixel_clock_limits()\n")); 228 229 // TODO: do some real stuff here (taken from radeon driver) 230 uint32 totalPixel = (uint32)mode->timing.h_total 231 * (uint32)mode->timing.v_total; 232 uint32 clockLimit = 2000000; 233 234 // lower limit of about 48Hz vertical refresh 235 *_low = totalPixel * 48L / 1000L; 236 if (*_low > clockLimit) 237 return B_ERROR; 238 239 *_high = clockLimit; 240 return B_OK; 241 } 242 243 244 status_t 245 vesa_move_display(uint16 h_display_start, uint16 v_display_start) 246 { 247 TRACE(("vesa_move_display()\n")); 248 return B_ERROR; 249 } 250 251 252 status_t 253 vesa_get_timing_constraints(display_timing_constraints* constraints) 254 { 255 TRACE(("vesa_get_timing_constraints()\n")); 256 return B_ERROR; 257 } 258 259 260 void 261 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 262 { 263 TRACE(("vesa_set_indexed_colors()\n")); 264 265 vesa_set_indexed_colors_args args; 266 args.first = first; 267 args.count = count; 268 args.colors = colors; 269 ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); 270 } 271 272