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