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