1 /* 2 * Copyright 2006, 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 86 static status_t 87 init_common(int device, bool isClone) 88 { 89 // initialize global accelerant info structure 90 91 gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); 92 if (gInfo == NULL) 93 return B_NO_MEMORY; 94 95 memset(gInfo, 0, sizeof(accelerant_info)); 96 97 gInfo->is_clone = isClone; 98 gInfo->device = device; 99 100 // get basic info from driver 101 102 intel_get_private_data data; 103 data.magic = INTEL_PRIVATE_DATA_MAGIC; 104 105 if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, 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, 113 B_READ_AREA | B_WRITE_AREA, 114 data.shared_info_area); 115 status_t status = sharedCloner.InitCheck(); 116 if (status < B_OK) { 117 free(gInfo); 118 return status; 119 } 120 121 AreaCloner regsCloner; 122 gInfo->regs_area = regsCloner.Clone("intel extreme regs", 123 (void **)&gInfo->regs, B_ANY_ADDRESS, 124 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 *)((uint8 *)gInfo->shared_info 139 + ROUND_TO_PAGE_SIZE(sizeof(intel_shared_info))); 140 gInfo->status = (hardware_status *)((uint8 *)gInfo->overlay_registers + B_PAGE_SIZE); 141 142 if (gInfo->shared_info->hardware_cursor_enabled) 143 gInfo->cursor_memory = (uint8 *)gInfo->overlay_registers + 2 * B_PAGE_SIZE; 144 145 return B_OK; 146 } 147 148 149 /** Clean up data common to both primary and cloned accelerant */ 150 151 static void 152 uninit_common(void) 153 { 154 delete_area(gInfo->regs_area); 155 delete_area(gInfo->shared_info_area); 156 157 gInfo->regs_area = gInfo->shared_info_area = -1; 158 159 // close the file handle ONLY if we're the clone 160 if (gInfo->is_clone) 161 close(gInfo->device); 162 163 free(gInfo); 164 } 165 166 167 // #pragma mark - public accelerant functions 168 169 170 /** Init primary accelerant */ 171 172 status_t 173 intel_init_accelerant(int device) 174 { 175 TRACE(("intel_init_accelerant()\n")); 176 177 status_t status = init_common(device, false); 178 if (status != B_OK) 179 return status; 180 181 intel_shared_info &info = *gInfo->shared_info; 182 183 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 184 init_lock(&info.engine_lock, "intel extreme engine"); 185 186 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 187 setup_ring_buffer(info.secondary_ring_buffer, "intel secondary ring buffer"); 188 189 // determine head depending on what's already enabled from the BIOS 190 // TODO: it would be nicer to retrieve this data via DDC - else the 191 // display is gone for good if the BIOS decides to only show the 192 // picture on the connected analog monitor! 193 gInfo->head_mode = 0; 194 if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 195 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 196 if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 197 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 198 199 TRACE(("head detected: %d\n", gInfo->head_mode)); 200 TRACE(("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n", 201 read32(INTEL_DISPLAY_A_ANALOG_PORT), read32(INTEL_DISPLAY_A_DIGITAL_PORT), 202 read32(INTEL_DISPLAY_B_DIGITAL_PORT), read32(INTEL_DISPLAY_LVDS_PORT))); 203 204 status = create_mode_list(); 205 if (status != B_OK) { 206 uninit_common(); 207 return status; 208 } 209 210 return B_OK; 211 } 212 213 214 ssize_t 215 intel_accelerant_clone_info_size(void) 216 { 217 TRACE(("intel_accelerant_clone_info_size()\n")); 218 // clone info is device name, so return its maximum size 219 return B_PATH_NAME_LENGTH; 220 } 221 222 223 void 224 intel_get_accelerant_clone_info(void *info) 225 { 226 TRACE(("intel_get_accelerant_clone_info()\n")); 227 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 228 } 229 230 231 status_t 232 intel_clone_accelerant(void *info) 233 { 234 TRACE(("intel_clone_accelerant()\n")); 235 236 // create full device name 237 char path[B_PATH_NAME_LENGTH]; 238 strcpy(path, "/dev/"); 239 #ifdef __HAIKU__ 240 strlcat(path, (const char *)info, sizeof(path)); 241 #else 242 strcat(path, (const char *)info); 243 #endif 244 245 int fd = open(path, B_READ_WRITE); 246 if (fd < 0) 247 return errno; 248 249 status_t status = init_common(fd, true); 250 if (status != B_OK) 251 goto err1; 252 253 // get read-only clone of supported display modes 254 status = gInfo->mode_list_area = clone_area( 255 "intel extreme cloned modes", (void **)&gInfo->mode_list, 256 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 257 if (status < B_OK) 258 goto err2; 259 260 return B_OK; 261 262 err2: 263 uninit_common(); 264 err1: 265 close(fd); 266 return status; 267 } 268 269 270 /** This function is called for both, the primary accelerant and all of 271 * its clones. 272 */ 273 274 void 275 intel_uninit_accelerant(void) 276 { 277 TRACE(("intel_uninit_accelerant()\n")); 278 279 // delete accelerant instance data 280 delete_area(gInfo->mode_list_area); 281 gInfo->mode_list = NULL; 282 283 intel_shared_info &info = *gInfo->shared_info; 284 285 uninit_lock(&info.accelerant_lock); 286 uninit_lock(&info.engine_lock); 287 288 uninit_ring_buffer(info.primary_ring_buffer); 289 uninit_ring_buffer(info.secondary_ring_buffer); 290 291 uninit_common(); 292 } 293 294 295 status_t 296 intel_get_accelerant_device_info(accelerant_device_info *info) 297 { 298 TRACE(("intel_get_accelerant_device_info()\n")); 299 300 info->version = B_ACCELERANT_VERSION; 301 strcpy(info->name, 302 (gInfo->shared_info->device_type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_7xx 303 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); 304 strcpy(info->chipset, gInfo->shared_info->device_identifier); 305 strcpy(info->serial_no, "None"); 306 307 info->memory = gInfo->shared_info->graphics_memory_size; 308 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 309 310 return B_OK; 311 } 312 313 314 sem_id 315 intel_accelerant_retrace_semaphore() 316 { 317 TRACE(("intel_accelerant_retrace_semaphore()\n")); 318 return gInfo->shared_info->vblank_sem; 319 } 320 321