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