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