diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 1cf6ca7683..4183b4b3dc 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -81,6 +81,8 @@ struct intel_shared_info { uint32 overlay_token; uint8* physical_overlay_registers; + sem_id vblank_sem; + uint32 device_type; char device_identifier[32]; struct pll_info pll_info; @@ -106,6 +108,8 @@ struct intel_info { // allocated memory beyond the "stolen" amount mem_info *memory_manager; + bool fake_interrupts; + const char *device_identifier; uint32 device_type; }; @@ -166,6 +170,7 @@ struct intel_free_graphics_memory { #define i855_STOLEN_MEMORY_48M 0x60 #define i855_STOLEN_MEMORY_64M 0x70 +// graphics page translation table #define INTEL_PAGE_TABLE_CONTROL 0x02020 #define INTEL_PAGE_TABLE_ERROR 0x02024 #define INTEL_HARDWARE_STATUS_PAGE 0x02080 @@ -173,6 +178,14 @@ struct intel_free_graphics_memory { #define GTT_ENTRY_VALID 0x01 #define GTT_ENTRY_LOCAL_MEMORY 0x02 +// interrupts +#define INTEL_INTERRUPT_ENABLED 0x020a0 +#define INTEL_INTERRUPT_IDENTITY 0x020a4 +#define INTEL_INTERRUPT_MASK 0x020a8 +#define INTEL_INTERRUPT_STATUS 0x020ac +#define INTERRUPT_VBLANK (1 << 7) + +// ring buffer #define INTEL_PRIMARY_RING_BUFFER 0x02030 #define INTEL_SECONDARY_RING_BUFFER_0 0x02100 #define INTEL_SECONDARY_RING_BUFFER_1 0x02110 @@ -185,6 +198,7 @@ struct intel_free_graphics_memory { #define INTEL_RING_BUFFER_HEAD_MASK 0x001ffffc #define INTEL_RING_BUFFER_ENABLED 1 +// display #define INTEL_DISPLAY_HTOTAL 0x60000 #define INTEL_DISPLAY_HBLANK 0x60004 #define INTEL_DISPLAY_HSYNC 0x60008 @@ -207,6 +221,8 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_PIPE_CONTROL 0x70008 #define DISPLAY_PIPE_ENABLED (1UL << 31) +#define INTEL_DISPLAY_PIPE_STATUS 0x70024 +#define DISPLAY_PIPE_VBLANK_ENABLED (1UL << 17) #define INTEL_DISPLAY_PLL 0x06014 #define INTEL_DISPLAY_PLL_DIVISOR_0 0x06040 @@ -238,11 +254,18 @@ struct intel_free_graphics_memory { #define DISPLAY_MONITOR_POSITIVE_HSYNC (1UL << 3) #define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 3) +// cursor #define INTEL_CURSOR_CONTROL 0x70080 #define INTEL_CURSOR_BASE 0x70084 #define INTEL_CURSOR_POSITION 0x70088 #define INTEL_CURSOR_PALETTE 0x70090 // (- 0x7009f) #define INTEL_CURSOR_SIZE 0x700a0 +#define CURSOR_ENABLED (1UL << 31) +#define CURSOR_FORMAT_2_COLORS (0UL << 24) +#define CURSOR_FORMAT_3_COLORS (1UL << 24) +#define CURSOR_FORMAT_4_COLORS (2UL << 24) +#define CURSOR_FORMAT_ARGB (4UL << 24) +#define CURSOR_FORMAT_XRGB (5UL << 24) // ring buffer commands diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index 1141790359..e4c82a48e1 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -298,6 +298,6 @@ sem_id intel_accelerant_retrace_semaphore() { TRACE(("intel_accelerant_retrace_semaphore()\n")); - return -1; + return gInfo->shared_info->vblank_sem; } diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index 303fd98104..371d08b795 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -147,6 +147,96 @@ set_gtt_entry(intel_info &info, uint32 offset, uint8 *physicalAddress) } +static int32 +release_vblank_sem(intel_info &info) +{ + int32 count; + if (get_sem_count(info.shared_info->vblank_sem, &count) == B_OK + && count < 0) { + release_sem_etc(info.shared_info->vblank_sem, -count, B_DO_NOT_RESCHEDULE); + return B_INVOKE_SCHEDULER; + } + + return B_HANDLED_INTERRUPT; +} + + +static int32 +intel_interrupt_handler(void *data) +{ + intel_info &info = *(intel_info *)data; + + uint32 identity = read32(info.registers + INTEL_INTERRUPT_IDENTITY); + if (identity == 0) + return B_UNHANDLED_INTERRUPT; + + int32 handled = B_HANDLED_INTERRUPT; + + if ((identity & INTERRUPT_VBLANK) != 0) { + handled = release_vblank_sem(info); + + // make sure we'll get another one of those + write32(info.registers + INTEL_DISPLAY_PIPE_STATUS, DISPLAY_PIPE_VBLANK_ENABLED); + write32(info.registers + INTEL_INTERRUPT_IDENTITY, 0); + } + + return handled; +} + + +static void +init_interrupt_handler(intel_info &info) +{ + info.shared_info->vblank_sem = create_sem(0, "intel extreme vblank"); + if (info.shared_info->vblank_sem < B_OK) + return; + + status_t status = B_OK; + + // We need to change the owner of the sem to the calling team (usually the + // app_server), because userland apps cannot acquire kernel semaphores + thread_id thread = find_thread(NULL); + thread_info threadInfo; + if (get_thread_info(thread, &threadInfo) != B_OK + || set_sem_owner(info.shared_info->vblank_sem, threadInfo.team) != B_OK) { + status = B_ERROR; + } + + if (status == B_OK + && info.pci->u.h0.interrupt_pin != 0x00 && info.pci->u.h0.interrupt_line != 0xff) { + // we've gotten an interrupt line for us to use + + info.fake_interrupts = false; + + status = install_io_interrupt_handler(info.pci->u.h0.interrupt_line, + intel_interrupt_handler, (void *)&info, 0); + if (status == B_OK) { + // enable interrupts - we only want VBLANK interrupts + write32(info.registers + INTEL_INTERRUPT_ENABLED, INTERRUPT_VBLANK); + write32(info.registers + INTEL_INTERRUPT_MASK, ~INTERRUPT_VBLANK); + + write32(info.registers + INTEL_DISPLAY_PIPE_STATUS, + DISPLAY_PIPE_VBLANK_ENABLED); + write32(info.registers + INTEL_INTERRUPT_IDENTITY, 0); + } + } + if (status < B_OK) { + // there is no interrupt reserved for us, or we couldn't install our interrupt + // handler, let's fake the vblank interrupt for our clients using a timer + // interrupt + info.fake_interrupts = true; + + // TODO: fake interrupts! + status = B_ERROR; + } + + if (status < B_OK) { + delete_sem(info.shared_info->vblank_sem); + info.shared_info->vblank_sem = B_ERROR; + } +} + + // #pragma mark - @@ -330,6 +420,8 @@ intel_extreme_init(intel_info &info) } info.shared_info->cursor_area = info.cursor_area; + init_interrupt_handler(info); + info.cookie_magic = INTEL_COOKIE_MAGIC; // this makes the cookie valid to be used @@ -344,6 +436,15 @@ intel_extreme_uninit(intel_info &info) { dprintf(DEVICE_NAME": intel_extreme_uninit()\n"); + if (!info.fake_interrupts && info.shared_info->vblank_sem > 0) { + // disable interrupt generation + write32(info.registers + INTEL_INTERRUPT_ENABLED, 0); + write32(info.registers + INTEL_INTERRUPT_MASK, ~0); + + remove_io_interrupt_handler(info.pci->u.h0.interrupt_line, + intel_interrupt_handler, &info); + } + mem_destroy(info.memory_manager); delete_area(info.graphics_memory_area);