1 /* 2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "accelerant_protos.h" 11 #include "accelerant.h" 12 13 #include "utility.h" 14 15 #include <errno.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <syslog.h> 20 21 #include <AGP.h> 22 23 24 #define TRACE_ACCELERANT 25 #ifdef TRACE_ACCELERANT 26 extern "C" void _sPrintf(const char* format, ...); 27 # define TRACE(x) _sPrintf x 28 #else 29 # define TRACE(x) ; 30 #endif 31 32 33 struct accelerant_info* gInfo; 34 35 36 class AreaCloner { 37 public: 38 AreaCloner(); 39 ~AreaCloner(); 40 41 area_id Clone(const char* name, void** _address, 42 uint32 spec, uint32 protection, 43 area_id sourceArea); 44 status_t InitCheck() 45 { return fArea < 0 ? (status_t)fArea : B_OK; } 46 void Keep(); 47 48 private: 49 area_id fArea; 50 }; 51 52 53 AreaCloner::AreaCloner() 54 : 55 fArea(-1) 56 { 57 } 58 59 60 AreaCloner::~AreaCloner() 61 { 62 if (fArea >= 0) 63 delete_area(fArea); 64 } 65 66 67 area_id 68 AreaCloner::Clone(const char* name, void** _address, uint32 spec, 69 uint32 protection, area_id sourceArea) 70 { 71 fArea = clone_area(name, _address, spec, protection, sourceArea); 72 return fArea; 73 } 74 75 76 void 77 AreaCloner::Keep() 78 { 79 fArea = -1; 80 } 81 82 83 // #pragma mark - 84 85 86 /*! This is the common accelerant_info initializer. It is called by 87 both, the first accelerant and all clones. 88 */ 89 static status_t 90 init_common(int device, bool isClone) 91 { 92 // initialize global accelerant info structure 93 94 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info)); 95 if (gInfo == NULL) 96 return B_NO_MEMORY; 97 98 memset(gInfo, 0, sizeof(accelerant_info)); 99 100 gInfo->is_clone = isClone; 101 gInfo->device = device; 102 103 // get basic info from driver 104 105 intel_get_private_data data; 106 data.magic = INTEL_PRIVATE_DATA_MAGIC; 107 108 if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, 109 sizeof(intel_get_private_data)) != 0) { 110 free(gInfo); 111 return B_ERROR; 112 } 113 114 AreaCloner sharedCloner; 115 gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info", 116 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 117 data.shared_info_area); 118 status_t status = sharedCloner.InitCheck(); 119 if (status < B_OK) { 120 free(gInfo); 121 return status; 122 } 123 124 AreaCloner regsCloner; 125 gInfo->regs_area = regsCloner.Clone("intel extreme regs", 126 (void**)&gInfo->registers, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 127 gInfo->shared_info->registers_area); 128 status = regsCloner.InitCheck(); 129 if (status < B_OK) { 130 free(gInfo); 131 return status; 132 } 133 134 sharedCloner.Keep(); 135 regsCloner.Keep(); 136 137 // The overlay registers, hardware status, and cursor memory share 138 // a single area with the shared_info 139 140 gInfo->overlay_registers = (struct overlay_registers*) 141 (gInfo->shared_info->graphics_memory 142 + gInfo->shared_info->overlay_offset); 143 144 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { 145 // allocate some extra memory for the 3D context 146 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE, 147 B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) { 148 gInfo->context_offset = gInfo->context_base 149 - (addr_t)gInfo->shared_info->graphics_memory; 150 } 151 } 152 153 return B_OK; 154 } 155 156 157 /*! Clean up data common to both primary and cloned accelerant */ 158 static void 159 uninit_common(void) 160 { 161 intel_free_memory(gInfo->context_base); 162 163 delete_area(gInfo->regs_area); 164 delete_area(gInfo->shared_info_area); 165 166 gInfo->regs_area = gInfo->shared_info_area = -1; 167 168 // close the file handle ONLY if we're the clone 169 if (gInfo->is_clone) 170 close(gInfo->device); 171 172 free(gInfo); 173 } 174 175 176 // #pragma mark - public accelerant functions 177 178 179 /*! Init primary accelerant */ 180 status_t 181 intel_init_accelerant(int device) 182 { 183 TRACE(("intel_init_accelerant()\n")); 184 185 status_t status = init_common(device, false); 186 if (status != B_OK) 187 return status; 188 189 intel_shared_info &info = *gInfo->shared_info; 190 191 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 192 init_lock(&info.engine_lock, "intel extreme engine"); 193 194 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 195 196 // determine head depending on what's already enabled from the BIOS 197 // TODO: it would be nicer to retrieve this data via DDC - else the 198 // display is gone for good if the BIOS decides to only show the 199 // picture on the connected analog monitor! 200 gInfo->head_mode = 0; 201 if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 202 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 203 if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 204 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 205 206 uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT); 207 208 // If we have an enabled display pipe we save the passed information and 209 // assume it is the valid panel size.. 210 // Later we query for proper EDID info if it exists, or figure something 211 // else out. (Default modes, etc.) 212 bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); 213 if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0) 214 || (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) { 215 save_lvds_mode(); 216 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 217 } 218 219 TRACE(("head detected: %#x\n", gInfo->head_mode)); 220 TRACE(("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n", 221 read32(INTEL_DISPLAY_A_ANALOG_PORT), 222 read32(INTEL_DISPLAY_A_DIGITAL_PORT), 223 read32(INTEL_DISPLAY_B_DIGITAL_PORT), read32(INTEL_DISPLAY_LVDS_PORT))); 224 225 status = create_mode_list(); 226 if (status != B_OK) { 227 uninit_common(); 228 return status; 229 } 230 231 return B_OK; 232 } 233 234 235 ssize_t 236 intel_accelerant_clone_info_size(void) 237 { 238 TRACE(("intel_accelerant_clone_info_size()\n")); 239 // clone info is device name, so return its maximum size 240 return B_PATH_NAME_LENGTH; 241 } 242 243 244 void 245 intel_get_accelerant_clone_info(void* info) 246 { 247 TRACE(("intel_get_accelerant_clone_info()\n")); 248 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 249 } 250 251 252 status_t 253 intel_clone_accelerant(void* info) 254 { 255 TRACE(("intel_clone_accelerant()\n")); 256 257 // create full device name 258 char path[B_PATH_NAME_LENGTH]; 259 strcpy(path, "/dev/"); 260 #ifdef __HAIKU__ 261 strlcat(path, (const char*)info, sizeof(path)); 262 #else 263 strcat(path, (const char*)info); 264 #endif 265 266 int fd = open(path, B_READ_WRITE); 267 if (fd < 0) 268 return errno; 269 270 status_t status = init_common(fd, true); 271 if (status != B_OK) 272 goto err1; 273 274 // get read-only clone of supported display modes 275 status = gInfo->mode_list_area = clone_area( 276 "intel extreme cloned modes", (void**)&gInfo->mode_list, 277 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 278 if (status < B_OK) 279 goto err2; 280 281 return B_OK; 282 283 err2: 284 uninit_common(); 285 err1: 286 close(fd); 287 return status; 288 } 289 290 291 /*! This function is called for both, the primary accelerant and all of 292 its clones. 293 */ 294 void 295 intel_uninit_accelerant(void) 296 { 297 TRACE(("intel_uninit_accelerant()\n")); 298 299 // delete accelerant instance data 300 delete_area(gInfo->mode_list_area); 301 gInfo->mode_list = NULL; 302 303 intel_shared_info &info = *gInfo->shared_info; 304 305 uninit_lock(&info.accelerant_lock); 306 uninit_lock(&info.engine_lock); 307 308 uninit_ring_buffer(info.primary_ring_buffer); 309 310 uninit_common(); 311 } 312 313 314 status_t 315 intel_get_accelerant_device_info(accelerant_device_info* info) 316 { 317 TRACE(("intel_get_accelerant_device_info()\n")); 318 319 info->version = B_ACCELERANT_VERSION; 320 strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx) 321 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); 322 strcpy(info->chipset, gInfo->shared_info->device_identifier); 323 strcpy(info->serial_no, "None"); 324 325 info->memory = gInfo->shared_info->graphics_memory_size; 326 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 327 328 return B_OK; 329 } 330 331 332 sem_id 333 intel_accelerant_retrace_semaphore() 334 { 335 TRACE(("intel_accelerant_retrace_semaphore()\n")); 336 return gInfo->shared_info->vblank_sem; 337 } 338 339