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->regs, 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 if ((lvds & DISPLAY_PIPE_ENABLED) != 0) { 213 save_lvds_mode(); 214 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 215 } 216 217 TRACE(("head detected: %#x\n", gInfo->head_mode)); 218 TRACE(("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n", 219 read32(INTEL_DISPLAY_A_ANALOG_PORT), 220 read32(INTEL_DISPLAY_A_DIGITAL_PORT), 221 read32(INTEL_DISPLAY_B_DIGITAL_PORT), read32(INTEL_DISPLAY_LVDS_PORT))); 222 223 status = create_mode_list(); 224 if (status != B_OK) { 225 uninit_common(); 226 return status; 227 } 228 229 return B_OK; 230 } 231 232 233 ssize_t 234 intel_accelerant_clone_info_size(void) 235 { 236 TRACE(("intel_accelerant_clone_info_size()\n")); 237 // clone info is device name, so return its maximum size 238 return B_PATH_NAME_LENGTH; 239 } 240 241 242 void 243 intel_get_accelerant_clone_info(void *info) 244 { 245 TRACE(("intel_get_accelerant_clone_info()\n")); 246 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 247 } 248 249 250 status_t 251 intel_clone_accelerant(void *info) 252 { 253 TRACE(("intel_clone_accelerant()\n")); 254 255 // create full device name 256 char path[B_PATH_NAME_LENGTH]; 257 strcpy(path, "/dev/"); 258 #ifdef __HAIKU__ 259 strlcat(path, (const char *)info, sizeof(path)); 260 #else 261 strcat(path, (const char *)info); 262 #endif 263 264 int fd = open(path, B_READ_WRITE); 265 if (fd < 0) 266 return errno; 267 268 status_t status = init_common(fd, true); 269 if (status != B_OK) 270 goto err1; 271 272 // get read-only clone of supported display modes 273 status = gInfo->mode_list_area = clone_area( 274 "intel extreme cloned modes", (void **)&gInfo->mode_list, 275 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 276 if (status < B_OK) 277 goto err2; 278 279 return B_OK; 280 281 err2: 282 uninit_common(); 283 err1: 284 close(fd); 285 return status; 286 } 287 288 289 /*! This function is called for both, the primary accelerant and all of 290 its clones. 291 */ 292 void 293 intel_uninit_accelerant(void) 294 { 295 TRACE(("intel_uninit_accelerant()\n")); 296 297 // delete accelerant instance data 298 delete_area(gInfo->mode_list_area); 299 gInfo->mode_list = NULL; 300 301 intel_shared_info &info = *gInfo->shared_info; 302 303 uninit_lock(&info.accelerant_lock); 304 uninit_lock(&info.engine_lock); 305 306 uninit_ring_buffer(info.primary_ring_buffer); 307 308 uninit_common(); 309 } 310 311 312 status_t 313 intel_get_accelerant_device_info(accelerant_device_info *info) 314 { 315 TRACE(("intel_get_accelerant_device_info()\n")); 316 317 info->version = B_ACCELERANT_VERSION; 318 strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx) 319 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); 320 strcpy(info->chipset, gInfo->shared_info->device_identifier); 321 strcpy(info->serial_no, "None"); 322 323 info->memory = gInfo->shared_info->graphics_memory_size; 324 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 325 326 return B_OK; 327 } 328 329 330 sem_id 331 intel_accelerant_retrace_semaphore() 332 { 333 TRACE(("intel_accelerant_retrace_semaphore()\n")); 334 return gInfo->shared_info->vblank_sem; 335 } 336 337