1 /* 2 * Copyright 2006-2018, 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 "driver.h" 11 #include "device.h" 12 #include "intel_extreme.h" 13 #include "utility.h" 14 15 #include <OS.h> 16 #include <KernelExport.h> 17 #include <Drivers.h> 18 #include <PCI.h> 19 #include <SupportDefs.h> 20 #include <graphic_driver.h> 21 #include <image.h> 22 23 #include <stdlib.h> 24 #include <string.h> 25 26 27 #define DEBUG_COMMANDS 28 29 #define TRACE_DEVICE 30 #ifdef TRACE_DEVICE 31 # define TRACE(x...) dprintf("intel_extreme: " x) 32 #else 33 # define TRACE(x) ; 34 #endif 35 36 #define ERROR(x...) dprintf("intel_extreme: " x) 37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 38 39 40 /* device hooks prototypes */ 41 42 static status_t device_open(const char* name, uint32 flags, void** _cookie); 43 static status_t device_close(void* data); 44 static status_t device_free(void* data); 45 static status_t device_ioctl(void* data, uint32 opcode, void* buffer, 46 size_t length); 47 static status_t device_read(void* data, off_t offset, void* buffer, 48 size_t* length); 49 static status_t device_write(void* data, off_t offset, const void* buffer, 50 size_t* length); 51 52 53 device_hooks gDeviceHooks = { 54 device_open, 55 device_close, 56 device_free, 57 device_ioctl, 58 device_read, 59 device_write, 60 NULL, 61 NULL, 62 NULL, 63 NULL 64 }; 65 66 67 #ifdef DEBUG_COMMANDS 68 static int 69 getset_register(int argc, char** argv) 70 { 71 if (argc < 2 || argc > 3) { 72 kprintf("usage: %s <register> [set-to-value]\n", argv[0]); 73 return 0; 74 } 75 76 uint32 reg = parse_expression(argv[1]); 77 uint32 value = 0; 78 bool set = argc == 3; 79 if (set) 80 value = parse_expression(argv[2]); 81 82 kprintf("intel_extreme register %#" B_PRIx32 "\n", reg); 83 84 intel_info &info = *gDeviceInfo[0]; 85 uint32 oldValue = read32(info, reg); 86 87 kprintf(" %svalue: %#" B_PRIx32 " (%" B_PRIu32 ")\n", set ? "old " : "", 88 oldValue, oldValue); 89 90 if (set) { 91 write32(info, reg, value); 92 93 value = read32(info, reg); 94 kprintf(" new value: %#" B_PRIx32 " (%" B_PRIu32 ")\n", value, value); 95 } 96 97 return 0; 98 } 99 100 101 static int 102 dump_pipe_info(int argc, char** argv) 103 { 104 int pipeOffset = 0; 105 106 if (argc > 2) { 107 kprintf("usage: %s [pipe index]\n", argv[0]); 108 return 0; 109 } 110 111 if (argc > 1) { 112 uint32 pipe = parse_expression(argv[1]); 113 if (pipe != 0) 114 pipeOffset = INTEL_DISPLAY_OFFSET; // Use pipe B if requested 115 } 116 117 intel_info &info = *gDeviceInfo[0]; 118 uint32 value; 119 120 kprintf("intel_extreme pipe configuration:\n"); 121 122 value = read32(info, INTEL_DISPLAY_A_HTOTAL + pipeOffset); 123 kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", 124 (value & 0xFFFF) + 1, (value >> 16) + 1); 125 value = read32(info, INTEL_DISPLAY_A_HBLANK + pipeOffset); 126 kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", 127 (value & 0xFFFF) + 1, (value >> 16) + 1); 128 value = read32(info, INTEL_DISPLAY_A_HSYNC + pipeOffset); 129 kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", 130 (value & 0xFFFF) + 1, (value >> 16) + 1); 131 value = read32(info, INTEL_DISPLAY_A_VTOTAL + pipeOffset); 132 kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", 133 (value & 0xFFFF) + 1, (value >> 16) + 1); 134 value = read32(info, INTEL_DISPLAY_A_VBLANK + pipeOffset); 135 kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", 136 (value & 0xFFFF) + 1, (value >> 16) + 1); 137 value = read32(info, INTEL_DISPLAY_A_VSYNC + pipeOffset); 138 kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", 139 (value & 0xFFFF) + 1, (value >> 16) + 1); 140 value = read32(info, INTEL_DISPLAY_A_PIPE_SIZE + pipeOffset); 141 kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n", 142 (value & 0xFFFF) + 1, (value >> 16) + 1); 143 144 if (info.pch_info != INTEL_PCH_NONE) { 145 kprintf("intel_extreme transcoder configuration:\n"); 146 147 value = read32(info, INTEL_TRANSCODER_A_HTOTAL + pipeOffset); 148 kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", 149 (value & 0xFFFF) + 1, (value >> 16) + 1); 150 value = read32(info, INTEL_TRANSCODER_A_HBLANK + pipeOffset); 151 kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", 152 (value & 0xFFFF) + 1, (value >> 16) + 1); 153 value = read32(info, INTEL_TRANSCODER_A_HSYNC + pipeOffset); 154 kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", 155 (value & 0xFFFF) + 1, (value >> 16) + 1); 156 value = read32(info, INTEL_TRANSCODER_A_VTOTAL + pipeOffset); 157 kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", 158 (value & 0xFFFF) + 1, (value >> 16) + 1); 159 value = read32(info, INTEL_TRANSCODER_A_VBLANK + pipeOffset); 160 kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", 161 (value & 0xFFFF) + 1, (value >> 16) + 1); 162 value = read32(info, INTEL_TRANSCODER_A_VSYNC + pipeOffset); 163 kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", 164 (value & 0xFFFF) + 1, (value >> 16) + 1); 165 value = read32(info, INTEL_TRANSCODER_A_IMAGE_SIZE + pipeOffset); 166 kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n", 167 (value & 0xFFFF) + 1, (value >> 16) + 1); 168 } 169 170 kprintf("intel_extreme display plane configuration:\n"); 171 172 value = read32(info, INTEL_DISPLAY_A_CONTROL + pipeOffset); 173 kprintf(" CONTROL: %" B_PRIx32 "\n", value); 174 value = read32(info, INTEL_DISPLAY_A_BASE + pipeOffset); 175 kprintf(" BASE: %" B_PRIx32 "\n", value); 176 value = read32(info, INTEL_DISPLAY_A_BYTES_PER_ROW + pipeOffset); 177 kprintf(" BYTES_PER_ROW: %" B_PRIx32 "\n", value); 178 value = read32(info, INTEL_DISPLAY_A_SURFACE + pipeOffset); 179 kprintf(" SURFACE: %" B_PRIx32 "\n", value); 180 181 return 0; 182 } 183 184 #endif // DEBUG_COMMANDS 185 186 187 // #pragma mark - Device Hooks 188 189 190 static status_t 191 device_open(const char* name, uint32 /*flags*/, void** _cookie) 192 { 193 CALLED(); 194 int32 id; 195 196 // find accessed device 197 { 198 char* thisName; 199 200 // search for device name 201 for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { 202 if (!strcmp(name, thisName)) 203 break; 204 } 205 if (!thisName) 206 return B_BAD_VALUE; 207 } 208 209 intel_info* info = gDeviceInfo[id]; 210 211 mutex_lock(&gLock); 212 213 if (info->open_count == 0) { 214 // This device hasn't been initialized yet, so we 215 // allocate needed resources and initialize the structure 216 info->init_status = intel_extreme_init(*info); 217 if (info->init_status == B_OK) { 218 #ifdef DEBUG_COMMANDS 219 add_debugger_command("ie_reg", getset_register, 220 "dumps or sets the specified intel_extreme register"); 221 add_debugger_command("ie_pipe", dump_pipe_info, 222 "show pipe configuration information"); 223 #endif 224 } 225 } 226 227 if (info->init_status == B_OK) { 228 info->open_count++; 229 *_cookie = info; 230 } else 231 ERROR("%s: initialization failed!\n", __func__); 232 233 mutex_unlock(&gLock); 234 235 return info->init_status; 236 } 237 238 239 static status_t 240 device_close(void* /*data*/) 241 { 242 CALLED(); 243 return B_OK; 244 } 245 246 247 static status_t 248 device_free(void* data) 249 { 250 struct intel_info* info = (intel_info*)data; 251 252 mutex_lock(&gLock); 253 254 if (info->open_count-- == 1) { 255 // release info structure 256 info->init_status = B_NO_INIT; 257 intel_extreme_uninit(*info); 258 259 #ifdef DEBUG_COMMANDS 260 remove_debugger_command("ie_reg", getset_register); 261 remove_debugger_command("ie_pipe", dump_pipe_info); 262 #endif 263 } 264 265 mutex_unlock(&gLock); 266 return B_OK; 267 } 268 269 270 static status_t 271 device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength) 272 { 273 struct intel_info* info = (intel_info*)data; 274 275 switch (op) { 276 case B_GET_ACCELERANT_SIGNATURE: 277 TRACE("accelerant: %s\n", INTEL_ACCELERANT_NAME); 278 if (user_strlcpy((char*)buffer, INTEL_ACCELERANT_NAME, 279 bufferLength) < B_OK) 280 return B_BAD_ADDRESS; 281 return B_OK; 282 283 // needed to share data between kernel and accelerant 284 case INTEL_GET_PRIVATE_DATA: 285 { 286 intel_get_private_data data; 287 if (user_memcpy(&data, buffer, sizeof(intel_get_private_data)) < B_OK) 288 return B_BAD_ADDRESS; 289 290 if (data.magic == INTEL_PRIVATE_DATA_MAGIC) { 291 data.shared_info_area = info->shared_area; 292 return user_memcpy(buffer, &data, 293 sizeof(intel_get_private_data)); 294 } 295 break; 296 } 297 298 // needed for cloning 299 case INTEL_GET_DEVICE_NAME: 300 if (user_strlcpy((char* )buffer, gDeviceNames[info->id], 301 bufferLength) < B_OK) 302 return B_BAD_ADDRESS; 303 return B_OK; 304 305 // graphics mem manager 306 case INTEL_ALLOCATE_GRAPHICS_MEMORY: 307 { 308 intel_allocate_graphics_memory allocMemory; 309 if (user_memcpy(&allocMemory, buffer, 310 sizeof(intel_allocate_graphics_memory)) < B_OK) 311 return B_BAD_ADDRESS; 312 313 if (allocMemory.magic != INTEL_PRIVATE_DATA_MAGIC) 314 return B_BAD_VALUE; 315 316 status_t status = intel_allocate_memory(*info, allocMemory.size, 317 allocMemory.alignment, allocMemory.flags, 318 &allocMemory.buffer_base); 319 if (status == B_OK) { 320 // copy result 321 if (user_memcpy(buffer, &allocMemory, 322 sizeof(intel_allocate_graphics_memory)) < B_OK) 323 return B_BAD_ADDRESS; 324 } 325 return status; 326 } 327 328 case INTEL_FREE_GRAPHICS_MEMORY: 329 { 330 intel_free_graphics_memory freeMemory; 331 if (user_memcpy(&freeMemory, buffer, 332 sizeof(intel_free_graphics_memory)) < B_OK) 333 return B_BAD_ADDRESS; 334 335 if (freeMemory.magic == INTEL_PRIVATE_DATA_MAGIC) 336 return intel_free_memory(*info, freeMemory.buffer_base); 337 break; 338 } 339 340 case INTEL_GET_BRIGHTNESS_LEGACY: 341 case INTEL_SET_BRIGHTNESS_LEGACY: 342 { 343 intel_brightness_legacy brightnessLegacy; 344 if (user_memcpy(&brightnessLegacy, buffer, 345 sizeof(brightnessLegacy)) < B_OK) 346 return B_BAD_ADDRESS; 347 348 if (brightnessLegacy.magic != INTEL_PRIVATE_DATA_MAGIC) 349 break; 350 if (op == INTEL_GET_BRIGHTNESS_LEGACY) { 351 brightnessLegacy.lpc = get_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1); 352 // copy result 353 if (user_memcpy(buffer, &brightnessLegacy, sizeof(brightnessLegacy)) < B_OK) 354 return B_BAD_ADDRESS; 355 } else { 356 set_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1, brightnessLegacy.lpc); 357 } 358 return B_OK; 359 } 360 361 default: 362 ERROR("ioctl() unknown message %" B_PRIu32 " (length = %" 363 B_PRIuSIZE ")\n", op, bufferLength); 364 break; 365 } 366 367 return B_DEV_INVALID_IOCTL; 368 } 369 370 371 static status_t 372 device_read(void* /*data*/, off_t /*pos*/, void* /*buffer*/, size_t* _length) 373 { 374 *_length = 0; 375 return B_NOT_ALLOWED; 376 } 377 378 379 static status_t 380 device_write(void* /*data*/, off_t /*pos*/, const void* /*buffer*/, 381 size_t* _length) 382 { 383 *_length = 0; 384 return B_NOT_ALLOWED; 385 } 386 387