/* * Copyright 2006-2018, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler, axeld@pinc-software.de */ #include "driver.h" #include "device.h" #include "intel_extreme.h" #include "utility.h" #include #include #include #include #include #include #include #include #include #define DEBUG_COMMANDS #define TRACE_DEVICE #ifdef TRACE_DEVICE # define TRACE(x...) dprintf("intel_extreme: " x) #else # define TRACE(x) ; #endif #define ERROR(x...) dprintf("intel_extreme: " x) #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) /* device hooks prototypes */ static status_t device_open(const char* name, uint32 flags, void** _cookie); static status_t device_close(void* data); static status_t device_free(void* data); static status_t device_ioctl(void* data, uint32 opcode, void* buffer, size_t length); static status_t device_read(void* data, off_t offset, void* buffer, size_t* length); static status_t device_write(void* data, off_t offset, const void* buffer, size_t* length); device_hooks gDeviceHooks = { device_open, device_close, device_free, device_ioctl, device_read, device_write, NULL, NULL, NULL, NULL }; #ifdef DEBUG_COMMANDS static int getset_register(int argc, char** argv) { if (argc < 2 || argc > 3) { kprintf("usage: %s [set-to-value]\n", argv[0]); return 0; } uint32 reg = parse_expression(argv[1]); uint32 value = 0; bool set = argc == 3; if (set) value = parse_expression(argv[2]); kprintf("intel_extreme register %#" B_PRIx32 "\n", reg); intel_info &info = *gDeviceInfo[0]; uint32 oldValue = read32(info, reg); kprintf(" %svalue: %#" B_PRIx32 " (%" B_PRIu32 ")\n", set ? "old " : "", oldValue, oldValue); if (set) { write32(info, reg, value); value = read32(info, reg); kprintf(" new value: %#" B_PRIx32 " (%" B_PRIu32 ")\n", value, value); } return 0; } static int dump_pipe_info(int argc, char** argv) { int pipeOffset = 0; if (argc > 2) { kprintf("usage: %s [pipe index]\n", argv[0]); return 0; } if (argc > 1) { uint32 pipe = parse_expression(argv[1]); if (pipe != 0) pipeOffset = INTEL_DISPLAY_OFFSET; // Use pipe B if requested } intel_info &info = *gDeviceInfo[0]; uint32 value; kprintf("intel_extreme pipe configuration:\n"); value = read32(info, INTEL_DISPLAY_A_HTOTAL + pipeOffset); kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_HBLANK + pipeOffset); kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_HSYNC + pipeOffset); kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_VTOTAL + pipeOffset); kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_VBLANK + pipeOffset); kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_VSYNC + pipeOffset); kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_DISPLAY_A_PIPE_SIZE + pipeOffset); kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); if (info.pch_info != INTEL_PCH_NONE) { kprintf("intel_extreme transcoder configuration:\n"); value = read32(info, INTEL_TRANSCODER_A_HTOTAL + pipeOffset); kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_HBLANK + pipeOffset); kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_HSYNC + pipeOffset); kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_VTOTAL + pipeOffset); kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_VBLANK + pipeOffset); kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_VSYNC + pipeOffset); kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); value = read32(info, INTEL_TRANSCODER_A_IMAGE_SIZE + pipeOffset); kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n", (value & 0xFFFF) + 1, (value >> 16) + 1); } kprintf("intel_extreme display plane configuration:\n"); value = read32(info, INTEL_DISPLAY_A_CONTROL + pipeOffset); kprintf(" CONTROL: %" B_PRIx32 "\n", value); value = read32(info, INTEL_DISPLAY_A_BASE + pipeOffset); kprintf(" BASE: %" B_PRIx32 "\n", value); value = read32(info, INTEL_DISPLAY_A_BYTES_PER_ROW + pipeOffset); kprintf(" BYTES_PER_ROW: %" B_PRIx32 "\n", value); value = read32(info, INTEL_DISPLAY_A_SURFACE + pipeOffset); kprintf(" SURFACE: %" B_PRIx32 "\n", value); return 0; } #endif // DEBUG_COMMANDS // #pragma mark - Device Hooks static status_t device_open(const char* name, uint32 /*flags*/, void** _cookie) { CALLED(); int32 id; // find accessed device { char* thisName; // search for device name for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { if (!strcmp(name, thisName)) break; } if (!thisName) return B_BAD_VALUE; } intel_info* info = gDeviceInfo[id]; mutex_lock(&gLock); if (info->open_count == 0) { // This device hasn't been initialized yet, so we // allocate needed resources and initialize the structure info->init_status = intel_extreme_init(*info); if (info->init_status == B_OK) { #ifdef DEBUG_COMMANDS add_debugger_command("ie_reg", getset_register, "dumps or sets the specified intel_extreme register"); add_debugger_command("ie_pipe", dump_pipe_info, "show pipe configuration information"); #endif } } if (info->init_status == B_OK) { info->open_count++; *_cookie = info; } else ERROR("%s: initialization failed!\n", __func__); mutex_unlock(&gLock); return info->init_status; } static status_t device_close(void* /*data*/) { CALLED(); return B_OK; } static status_t device_free(void* data) { struct intel_info* info = (intel_info*)data; mutex_lock(&gLock); if (info->open_count-- == 1) { // release info structure info->init_status = B_NO_INIT; intel_extreme_uninit(*info); #ifdef DEBUG_COMMANDS remove_debugger_command("ie_reg", getset_register); remove_debugger_command("ie_pipe", dump_pipe_info); #endif } mutex_unlock(&gLock); return B_OK; } static status_t device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength) { struct intel_info* info = (intel_info*)data; switch (op) { case B_GET_ACCELERANT_SIGNATURE: TRACE("accelerant: %s\n", INTEL_ACCELERANT_NAME); if (user_strlcpy((char*)buffer, INTEL_ACCELERANT_NAME, bufferLength) < B_OK) return B_BAD_ADDRESS; return B_OK; // needed to share data between kernel and accelerant case INTEL_GET_PRIVATE_DATA: { intel_get_private_data data; if (user_memcpy(&data, buffer, sizeof(intel_get_private_data)) < B_OK) return B_BAD_ADDRESS; if (data.magic == INTEL_PRIVATE_DATA_MAGIC) { data.shared_info_area = info->shared_area; return user_memcpy(buffer, &data, sizeof(intel_get_private_data)); } break; } // needed for cloning case INTEL_GET_DEVICE_NAME: if (user_strlcpy((char* )buffer, gDeviceNames[info->id], bufferLength) < B_OK) return B_BAD_ADDRESS; return B_OK; // graphics mem manager case INTEL_ALLOCATE_GRAPHICS_MEMORY: { intel_allocate_graphics_memory allocMemory; if (user_memcpy(&allocMemory, buffer, sizeof(intel_allocate_graphics_memory)) < B_OK) return B_BAD_ADDRESS; if (allocMemory.magic != INTEL_PRIVATE_DATA_MAGIC) return B_BAD_VALUE; status_t status = intel_allocate_memory(*info, allocMemory.size, allocMemory.alignment, allocMemory.flags, &allocMemory.buffer_base); if (status == B_OK) { // copy result if (user_memcpy(buffer, &allocMemory, sizeof(intel_allocate_graphics_memory)) < B_OK) return B_BAD_ADDRESS; } return status; } case INTEL_FREE_GRAPHICS_MEMORY: { intel_free_graphics_memory freeMemory; if (user_memcpy(&freeMemory, buffer, sizeof(intel_free_graphics_memory)) < B_OK) return B_BAD_ADDRESS; if (freeMemory.magic == INTEL_PRIVATE_DATA_MAGIC) return intel_free_memory(*info, freeMemory.buffer_base); break; } case INTEL_GET_BRIGHTNESS_LEGACY: case INTEL_SET_BRIGHTNESS_LEGACY: { intel_brightness_legacy brightnessLegacy; if (user_memcpy(&brightnessLegacy, buffer, sizeof(brightnessLegacy)) < B_OK) return B_BAD_ADDRESS; if (brightnessLegacy.magic != INTEL_PRIVATE_DATA_MAGIC) break; if (op == INTEL_GET_BRIGHTNESS_LEGACY) { brightnessLegacy.lpc = get_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1); // copy result if (user_memcpy(buffer, &brightnessLegacy, sizeof(brightnessLegacy)) < B_OK) return B_BAD_ADDRESS; } else { set_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1, brightnessLegacy.lpc); } return B_OK; } default: ERROR("ioctl() unknown message %" B_PRIu32 " (length = %" B_PRIuSIZE ")\n", op, bufferLength); break; } return B_DEV_INVALID_IOCTL; } static status_t device_read(void* /*data*/, off_t /*pos*/, void* /*buffer*/, size_t* _length) { *_length = 0; return B_NOT_ALLOWED; } static status_t device_write(void* /*data*/, off_t /*pos*/, const void* /*buffer*/, size_t* _length) { *_length = 0; return B_NOT_ALLOWED; }