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