ImÃport new 3dfx graphics driver from Gerald Zajac (see #6215.
Supports Banshee, Voodoo3 and Voodoo5 chips. It will be promoted as older tdfx replacement soon, but not until my small changes around phys_addr_t are validated. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37241 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
98d65f5627
commit
a56bc48835
153
headers/private/graphics/3dfx/DriverInterface.h
Normal file
153
headers/private/graphics/3dfx/DriverInterface.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2007-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#ifndef DRIVERINTERFACE_H
|
||||
#define DRIVERINTERFACE_H
|
||||
|
||||
|
||||
#include <Accelerant.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Drivers.h>
|
||||
#include <edid.h>
|
||||
#include <video_overlay.h>
|
||||
|
||||
|
||||
// This file contains info that is shared between the kernel driver and the
|
||||
// accelerant, and info that is shared among the source files of the accelerant.
|
||||
|
||||
|
||||
#define ENABLE_DEBUG_TRACE // if defined, turns on debug output to syslog
|
||||
|
||||
|
||||
#define ARRAY_SIZE(a) (int(sizeof(a) / sizeof(a[0]))) // get number of elements in an array
|
||||
|
||||
|
||||
|
||||
struct Benaphore {
|
||||
sem_id sem;
|
||||
int32 count;
|
||||
|
||||
status_t Init(const char* name)
|
||||
{
|
||||
count = 0;
|
||||
sem = create_sem(0, name);
|
||||
return sem < 0 ? sem : B_OK;
|
||||
}
|
||||
|
||||
status_t Acquire()
|
||||
{
|
||||
if (atomic_add(&count, 1) > 0)
|
||||
return acquire_sem(sem);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t Release()
|
||||
{
|
||||
if (atomic_add(&count, -1) > 1)
|
||||
return release_sem(sem);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Delete() { delete_sem(sem); }
|
||||
};
|
||||
|
||||
|
||||
#define TDFX_PRIVATE_DATA_MAGIC 0x5042
|
||||
|
||||
|
||||
enum {
|
||||
TDFX_GET_SHARED_DATA = B_DEVICE_OP_CODES_END + 123,
|
||||
TDFX_DEVICE_NAME,
|
||||
TDFX_GET_PIO_REG,
|
||||
TDFX_SET_PIO_REG
|
||||
};
|
||||
|
||||
|
||||
// Chip type numbers. These are used to group the chips into related
|
||||
// groups. See table chipTable in driver.c
|
||||
|
||||
enum ChipType {
|
||||
TDFX_NONE = 0,
|
||||
|
||||
BANSHEE,
|
||||
VOODOO_3,
|
||||
VOODOO_5,
|
||||
};
|
||||
|
||||
|
||||
struct PIORegInfo {
|
||||
uint32 magic; // magic number
|
||||
uint32 offset; // offset of register in PIO register area
|
||||
int16 index; // index of value to read/write; < 0 if not indexed reg
|
||||
uint8 value; // value to write or value that was read
|
||||
};
|
||||
|
||||
|
||||
struct DisplayModeEx : display_mode {
|
||||
uint8 bitsPerPixel;
|
||||
uint8 bytesPerPixel;
|
||||
uint16 bytesPerRow; // number of bytes in one line/row
|
||||
};
|
||||
|
||||
|
||||
struct OverlayBuffer : overlay_buffer {
|
||||
OverlayBuffer* nextBuffer; // pointer to next buffer in chain, NULL = none
|
||||
uint32 size; // size of overlay buffer
|
||||
};
|
||||
|
||||
|
||||
struct SharedInfo {
|
||||
// Device ID info.
|
||||
uint16 vendorID; // PCI vendor ID, from pci_info
|
||||
uint16 deviceID; // PCI device ID, from pci_info
|
||||
uint8 revision; // PCI device revsion, from pci_info
|
||||
ChipType chipType; // indicates group in which chip belongs (a group has similar functionality)
|
||||
char chipName[32]; // user recognizable name of chip
|
||||
|
||||
bool bAccelerantInUse; // true = accelerant has been initialized
|
||||
|
||||
// Memory mappings.
|
||||
area_id regsArea; // area_id for the memory mapped registers. It will
|
||||
// be cloned into accelerant's address space.
|
||||
area_id videoMemArea; // video memory area_id. The addresses are shared with all teams.
|
||||
addr_t videoMemAddr; // video memory addr as viewed from virtual memory
|
||||
phys_addr_t videoMemPCI; // video memory addr as viewed from the PCI bus (for DMA)
|
||||
uint32 videoMemSize; // video memory size in bytes.
|
||||
|
||||
uint32 cursorOffset; // offset of cursor in video memory
|
||||
uint32 frameBufferOffset; // offset of frame buffer in video memory
|
||||
uint32 maxFrameBufferSize; // max available video memory for frame buffer
|
||||
|
||||
// Color spaces supported by current video chip/driver.
|
||||
color_space colorSpaces[6];
|
||||
uint32 colorSpaceCount; // number of color spaces in array colorSpaces
|
||||
|
||||
uint32 maxPixelClock; // max pixel clock of current chip in KHz
|
||||
|
||||
// List of screen modes.
|
||||
area_id modeArea; // area containing list of display modes the driver supports
|
||||
uint32 modeCount; // number of display modes in the list
|
||||
|
||||
DisplayModeEx displayMode; // current display mode configuration
|
||||
|
||||
uint16 cursorHotX; // Cursor hot spot. Top left corner of the cursor
|
||||
uint16 cursorHotY; // is 0,0
|
||||
|
||||
edid1_info edidInfo;
|
||||
bool bHaveEDID; // true = EDID info from device is in edidInfo
|
||||
|
||||
Benaphore engineLock; // for access to the acceleration engine
|
||||
Benaphore overlayLock; // for overlay operations
|
||||
|
||||
int32 overlayAllocated; // non-zero if overlay is allocated
|
||||
uint32 overlayToken;
|
||||
OverlayBuffer* overlayBuffer; // pointer to linked list of buffers; NULL = none
|
||||
};
|
||||
|
||||
|
||||
#endif // DRIVERINTERFACE_H
|
116
src/add-ons/accelerants/3dfx/3dfx.h
Normal file
116
src/add-ons/accelerants/3dfx/3dfx.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2010
|
||||
*/
|
||||
|
||||
#ifndef __3DFX_H__
|
||||
#define __3DFX_H__
|
||||
|
||||
|
||||
|
||||
#define BIT(n) (1UL<<(n))
|
||||
|
||||
#define ROP_COPY 0xcc
|
||||
#define ROP_INVERT 0x55
|
||||
#define ROP_XOR 0x66
|
||||
|
||||
#define MEM_TYPE_SGRAM 0
|
||||
#define MEM_TYPE_SDRAM 1
|
||||
|
||||
|
||||
// Base register offsets in MMIO area.
|
||||
#define STATUS 0x0
|
||||
#define MISC_INIT1 0x14
|
||||
#define DRAM_INIT0 0x18
|
||||
#define DRAM_INIT1 0x1C
|
||||
#define VGA_INIT0 0x28
|
||||
#define VGA_INIT1 0x2c
|
||||
#define PLL_CTRL0 0x40
|
||||
#define DAC_MODE 0x4c
|
||||
#define DAC_ADDR 0x50
|
||||
#define DAC_DATA 0x54
|
||||
#define RGB_MAX_DELTA 0x58
|
||||
#define VIDEO_PROC_CONFIG 0x5c
|
||||
#define HW_CURSOR_PAT_ADDR 0x60
|
||||
#define HW_CURSOR_LOC 0x64
|
||||
#define HW_CURSOR_COLOR0 0x68
|
||||
#define HW_CURSOR_COLOR1 0x6c
|
||||
#define VIDEO_SERIAL_PARALLEL_PORT 0x78
|
||||
#define VIDEO_CHROMA_MIN 0x8c
|
||||
#define VIDEO_CHROMA_MAX 0x90
|
||||
#define VIDEO_SCREEN_SIZE 0x98
|
||||
#define VIDEO_OVERLAY_START_COORDS 0x9c
|
||||
#define VIDEO_OVERLAY_END_COORDS 0xa0
|
||||
#define VIDEO_OVERLAY_DUDX 0xa4
|
||||
#define VIDEO_OVERLAY_DUDX_OFFSET_SRC_WIDTH 0xa8
|
||||
#define VIDEO_OVERLAY_DVDY 0xac
|
||||
#define VIDEO_OVERLAY_DVDY_OFFSET 0xe0
|
||||
#define VIDEO_DESKTOP_START_ADDR 0xe4
|
||||
#define VIDEO_DESKTOP_OVERLAY_STRIDE 0xe8
|
||||
#define VIDEO_IN_ADDR0 0xec
|
||||
|
||||
// Offset in MMIO area of registers used for drawing.
|
||||
#define CLIP0_MIN (0x100000 + 0x8)
|
||||
#define CLIP0_MAX (0x100000 + 0xC)
|
||||
#define DST_BASE_ADDR (0x100000 + 0x10)
|
||||
#define DST_FORMAT (0x100000 + 0x14)
|
||||
#define SRC_BASE_ADDR (0x100000 + 0x34)
|
||||
#define CLIP1_MIN (0x100000 + 0x4C)
|
||||
#define CLIP1_MAX (0x100000 + 0x50)
|
||||
#define SRC_FORMAT (0x100000 + 0x54)
|
||||
#define SRC_XY (0x100000 + 0x5C)
|
||||
#define COLOR_BACK (0x100000 + 0x60)
|
||||
#define COLOR_FORE (0x100000 + 0x64)
|
||||
#define DST_SIZE (0x100000 + 0x68)
|
||||
#define DST_XY (0x100000 + 0x6C)
|
||||
#define CMD_2D (0x100000 + 0x70)
|
||||
|
||||
// Offset in MMIO area of 3D registers.
|
||||
#define CMD_3D (0x200000 + 0x120)
|
||||
|
||||
// Flags and register values.
|
||||
#define CMD_2D_GO BIT(8)
|
||||
#define CMD_3D_NOP 0
|
||||
#define SGRAM_TYPE BIT(27)
|
||||
#define SGRAM_NUM_CHIPSETS BIT(26)
|
||||
#define DISABLE_2D_BLOCK_WRITE BIT(15)
|
||||
#define MCTL_TYPE_SDRAM BIT(30)
|
||||
#define DAC_MODE_2X BIT(0)
|
||||
#define VIDEO_2X_MODE_ENABLE BIT(26)
|
||||
#define CLUT_SELECT_8BIT BIT(2)
|
||||
#define VGA0_EXTENSIONS BIT(6)
|
||||
#define WAKEUP_3C3 BIT(8)
|
||||
#define VGA0_LEGACY_DECODE BIT(9)
|
||||
#define ENABLE_ALT_READBACK BIT(10)
|
||||
#define EXT_SHIFT_OUT BIT(12)
|
||||
#define VIDEO_PROCESSOR_ENABLE BIT(0)
|
||||
#define DESKTOP_ENABLE BIT(7)
|
||||
#define DESKTOP_PIXEL_FORMAT_SHIFT 18
|
||||
#define DESKTOP_CLUT_BYPASS BIT(10)
|
||||
#define OVERLAY_CLUT_BYPASS BIT(11)
|
||||
#define CURSOR_ENABLE BIT(27)
|
||||
#define STATUS_BUSY BIT(9)
|
||||
#define X_RIGHT_TO_LEFT BIT(14)
|
||||
#define Y_BOTTOM_TO_TOP BIT(15)
|
||||
|
||||
// 2D Commands
|
||||
#define SCRN_TO_SCRN_BLIT 1
|
||||
#define RECTANGLE_FILL 5
|
||||
|
||||
// Definitions for I2C bus when fetching EDID info.
|
||||
#define VSP_SDA0_IN 0x00400000
|
||||
#define VSP_SCL0_IN 0x00200000
|
||||
#define VSP_SDA0_OUT 0x00100000
|
||||
#define VSP_SCL0_OUT 0x00080000
|
||||
#define VSP_ENABLE_IIC0 0x00040000 // set bit to 1 to enable I2C bus 0
|
||||
|
||||
// Definitions for overlays.
|
||||
#define VIDEO_PROC_CONFIG_MASK 0xa2e3eb6c
|
||||
#define VIDCFG_OVL_FMT_RGB565 (1 << 21)
|
||||
#define VIDCFG_OVL_FMT_YUYV422 (5 << 21)
|
||||
|
||||
|
||||
#endif // __3DFX_H__
|
83
src/add-ons/accelerants/3dfx/3dfx_cursor.cpp
Normal file
83
src/add-ons/accelerants/3dfx/3dfx_cursor.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2010
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
void
|
||||
TDFX_ShowCursor(bool bShow)
|
||||
{
|
||||
// Turn cursor on/off.
|
||||
|
||||
uint32 config = INREG32(VIDEO_PROC_CONFIG);
|
||||
if (bShow)
|
||||
config |= CURSOR_ENABLE;
|
||||
else
|
||||
config &= ~CURSOR_ENABLE;
|
||||
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(VIDEO_PROC_CONFIG, config);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_SetCursorPosition(int x, int y)
|
||||
{
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(HW_CURSOR_LOC, ((y + 63) << 16) | (x + 63));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TDFX_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (andMask == NULL || xorMask == NULL)
|
||||
return false;
|
||||
|
||||
uint64* fbCursor64 = (uint64*)((addr_t)si.videoMemAddr + si.cursorOffset);
|
||||
|
||||
// Initialize the hardware cursor as completely transparent.
|
||||
|
||||
for (int i = 0; i < CURSOR_BYTES; i += 16) {
|
||||
*fbCursor64++ = ~0; // and bits
|
||||
*fbCursor64++ = 0; // xor bits
|
||||
}
|
||||
|
||||
// Now load the AND & XOR masks for the cursor image into the cursor
|
||||
// buffer. Note that a particular bit in these masks will have the
|
||||
// following effect upon the corresponding cursor pixel:
|
||||
// AND XOR Result
|
||||
// 0 0 White pixel
|
||||
// 0 1 Black pixel
|
||||
// 1 0 Screen color (for transparency)
|
||||
// 1 1 Reverse screen color to black or white
|
||||
|
||||
uint8* fbCursor = (uint8*)((addr_t)si.videoMemAddr + si.cursorOffset);
|
||||
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int colByte = 0; colByte < width / 8; colByte++) {
|
||||
fbCursor[row * 16 + colByte] = *andMask++;
|
||||
fbCursor[row * 16 + colByte + 8] = *xorMask++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursor colors which are white background and black foreground.
|
||||
|
||||
TDFX_WaitForFifo(2);
|
||||
OUTREG32(HW_CURSOR_COLOR0, 0xffffff);
|
||||
OUTREG32(HW_CURSOR_COLOR1, 0);
|
||||
|
||||
return true;
|
||||
}
|
87
src/add-ons/accelerants/3dfx/3dfx_dpms.cpp
Normal file
87
src/add-ons/accelerants/3dfx/3dfx_dpms.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2010
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
|
||||
|
||||
#define H_SYNC_OFF BIT(3)
|
||||
#define V_SYNC_OFF BIT(1)
|
||||
|
||||
|
||||
uint32
|
||||
TDFX_DPMSCapabilities(void)
|
||||
{
|
||||
// Return DPMS modes supported by this device.
|
||||
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
TDFX_GetDPMSMode(void)
|
||||
{
|
||||
// Return the current DPMS mode.
|
||||
|
||||
uint32 tmp = INREG32(DAC_MODE) & (H_SYNC_OFF | V_SYNC_OFF);
|
||||
uint32 mode;
|
||||
|
||||
if (tmp == 0 )
|
||||
mode = B_DPMS_ON;
|
||||
else if (tmp == H_SYNC_OFF)
|
||||
mode = B_DPMS_STAND_BY;
|
||||
else if (tmp == V_SYNC_OFF)
|
||||
mode = B_DPMS_SUSPEND;
|
||||
else
|
||||
mode = B_DPMS_OFF;
|
||||
|
||||
TRACE("TDFX_DPMSMode() mode: %d\n", mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TDFX_SetDPMSMode(uint32 dpmsMode)
|
||||
{
|
||||
// Set the display into one of the Display Power Management modes,
|
||||
// and return B_OK if successful, else return B_ERROR.
|
||||
|
||||
TRACE("TDFX_SetDPMSMode() mode: %d\n", dpmsMode);
|
||||
|
||||
uint32 dacMode = INREG32(DAC_MODE) & ~(H_SYNC_OFF | V_SYNC_OFF);
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
// Screen: On; HSync: On, VSync: On.
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
// Screen: Off; HSync: Off, VSync: On.
|
||||
dacMode |= H_SYNC_OFF;
|
||||
break;
|
||||
|
||||
case B_DPMS_SUSPEND:
|
||||
// Screen: Off; HSync: On, VSync: Off.
|
||||
dacMode |= V_SYNC_OFF;
|
||||
break;
|
||||
|
||||
case B_DPMS_OFF:
|
||||
// Screen: Off; HSync: Off, VSync: Off.
|
||||
dacMode |= H_SYNC_OFF | V_SYNC_OFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
OUTREG32(DAC_MODE, dacMode);
|
||||
return B_OK;
|
||||
}
|
152
src/add-ons/accelerants/3dfx/3dfx_draw.cpp
Normal file
152
src/add-ons/accelerants/3dfx/3dfx_draw.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
|
||||
// Constants for the DST_FORMAT register based upon the color depth.
|
||||
|
||||
static const uint32 fmtColorDepth[] = {
|
||||
0x10000, // 1 byte/pixel
|
||||
0x30000, // 2 bytes/pixel
|
||||
0x50000, // 3 bytes/pixel (not used)
|
||||
0x50000 // 4 bytes/pixel
|
||||
};
|
||||
|
||||
|
||||
|
||||
void
|
||||
TDFX_FillRectangle(engine_token *et, uint32 color, fill_rect_params *list, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];
|
||||
|
||||
TDFX_WaitForFifo(3);
|
||||
OUTREG32(DST_FORMAT, fmt);
|
||||
OUTREG32(COLOR_BACK, color);
|
||||
OUTREG32(COLOR_FORE, color);
|
||||
|
||||
while (count--) {
|
||||
int x = list->left;
|
||||
int y = list->top;
|
||||
int w = list->right - x + 1;
|
||||
int h = list->bottom - y + 1;
|
||||
|
||||
TDFX_WaitForFifo(3);
|
||||
OUTREG32(DST_SIZE, w | (h << 16));
|
||||
OUTREG32(DST_XY, x | (y << 16));
|
||||
OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_COPY << 24));
|
||||
|
||||
list++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_FillSpan(engine_token *et, uint32 color, uint16 *list, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];
|
||||
|
||||
TDFX_WaitForFifo(3);
|
||||
OUTREG32(DST_FORMAT, fmt);
|
||||
OUTREG32(COLOR_BACK, color);
|
||||
OUTREG32(COLOR_FORE, color);
|
||||
|
||||
while (count--) {
|
||||
int y = *list++;
|
||||
int x = *list++;
|
||||
int w = *list++ - x + 1;
|
||||
|
||||
if (w <= 0)
|
||||
continue; // discard span with zero or negative width
|
||||
|
||||
TDFX_WaitForFifo(3);
|
||||
OUTREG32(DST_SIZE, w | (1 << 16));
|
||||
OUTREG32(DST_XY, x | (y << 16));
|
||||
OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_COPY << 24));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_InvertRectangle(engine_token *et, fill_rect_params *list, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];
|
||||
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(DST_FORMAT, fmt);
|
||||
|
||||
while (count--) {
|
||||
int x = list->left;
|
||||
int y = list->top;
|
||||
int w = list->right - x + 1;
|
||||
int h = list->bottom - y + 1;
|
||||
|
||||
TDFX_WaitForFifo(3);
|
||||
OUTREG32(DST_SIZE, w | (h << 16));
|
||||
OUTREG32(DST_XY, x | (y << 16));
|
||||
OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_INVERT << 24));
|
||||
|
||||
list++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_ScreenToScreenBlit(engine_token *et, blit_params *list, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];
|
||||
|
||||
TDFX_WaitForFifo(2);
|
||||
OUTREG32(DST_FORMAT, fmt);
|
||||
OUTREG32(SRC_FORMAT, fmt);
|
||||
|
||||
while (count--) {
|
||||
int src_x = list->src_left;
|
||||
int src_y = list->src_top;
|
||||
int dest_x = list->dest_left;
|
||||
int dest_y = list->dest_top;
|
||||
int width = list->width;
|
||||
int height = list->height;
|
||||
|
||||
uint32 cmd = SCRN_TO_SCRN_BLIT | CMD_2D_GO | (ROP_COPY << 24);
|
||||
|
||||
if (src_x <= dest_x) {
|
||||
cmd |= X_RIGHT_TO_LEFT;
|
||||
src_x += width;
|
||||
dest_x += width;
|
||||
}
|
||||
|
||||
if (src_y <= dest_y) {
|
||||
cmd |= Y_BOTTOM_TO_TOP;
|
||||
src_y += height;
|
||||
dest_y += height;
|
||||
}
|
||||
|
||||
TDFX_WaitForFifo(4);
|
||||
OUTREG32(SRC_XY, src_x | (src_y << 16));
|
||||
OUTREG32(DST_SIZE, (width + 1) | ((height + 1) << 16));
|
||||
OUTREG32(DST_XY, dest_x | (dest_y << 16));
|
||||
OUTREG32(CMD_2D, cmd);
|
||||
|
||||
list++;
|
||||
}
|
||||
}
|
64
src/add-ons/accelerants/3dfx/3dfx_edid.cpp
Normal file
64
src/add-ons/accelerants/3dfx/3dfx_edid.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ddc.h>
|
||||
#include <edid.h>
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
GetI2CSignals(void* cookie, int* _clock, int* data)
|
||||
{
|
||||
(void)cookie; // avoid compiler warning for unused arg
|
||||
|
||||
uint32 reg = INREG32(VIDEO_SERIAL_PARALLEL_PORT);
|
||||
*_clock = (reg & VSP_SCL0_IN) ? 1 : 0;;
|
||||
*data = (reg & VSP_SDA0_IN) ? 1 : 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
SetI2CSignals(void* cookie, int _clock, int data)
|
||||
{
|
||||
(void)cookie; // avoid compiler warning for unused arg
|
||||
|
||||
uint32 reg = (INREG32(VIDEO_SERIAL_PARALLEL_PORT)
|
||||
& ~(VSP_SDA0_OUT | VSP_SCL0_OUT));
|
||||
reg = (reg | (_clock ? VSP_SCL0_OUT : 0) | (data ? VSP_SDA0_OUT : 0));
|
||||
OUTREG32(VIDEO_SERIAL_PARALLEL_PORT, reg);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
TDFX_GetEdidInfo(edid1_info& edidInfo)
|
||||
{
|
||||
// Get the EDID info and return true if successful.
|
||||
|
||||
i2c_bus bus;
|
||||
|
||||
bus.cookie = (void*)NULL;
|
||||
bus.set_signals = &SetI2CSignals;
|
||||
bus.get_signals = &GetI2CSignals;
|
||||
ddc2_init_timing(&bus);
|
||||
|
||||
uint32 reg = INREG32(VIDEO_SERIAL_PARALLEL_PORT);
|
||||
OUTREG32(VIDEO_SERIAL_PARALLEL_PORT, reg | VSP_ENABLE_IIC0);
|
||||
|
||||
bool bResult = (ddc2_read_edid1(&bus, &edidInfo, NULL, NULL) == B_OK);
|
||||
|
||||
OUTREG32(VIDEO_SERIAL_PARALLEL_PORT, reg);
|
||||
|
||||
return bResult;
|
||||
}
|
89
src/add-ons/accelerants/3dfx/3dfx_init.cpp
Normal file
89
src/add-ons/accelerants/3dfx/3dfx_init.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
TDFX_GetVideoMemorySize(void)
|
||||
{
|
||||
// Return the number of bytes of video memory.
|
||||
|
||||
uint32 chipSize; // size is in megabytes
|
||||
uint32 dramInit0 = INREG32(DRAM_INIT0);
|
||||
uint32 dramInit1 = INREG32(DRAM_INIT1);
|
||||
uint32 numChips = (dramInit0 & SGRAM_NUM_CHIPSETS) ? 8 : 4;
|
||||
int memType = (dramInit1 & MCTL_TYPE_SDRAM) ? MEM_TYPE_SDRAM : MEM_TYPE_SGRAM;
|
||||
|
||||
if (gInfo.sharedInfo->chipType == VOODOO_5) {
|
||||
chipSize = 1 << ((dramInit0 >> 27) & 0x7);
|
||||
} else {
|
||||
// Banshee or Voodoo3
|
||||
if (memType == MEM_TYPE_SDRAM)
|
||||
chipSize = 2;
|
||||
else
|
||||
chipSize = (dramInit0 & SGRAM_TYPE) ? 2 : 1;
|
||||
}
|
||||
|
||||
// Disable block writes for SDRAM.
|
||||
|
||||
uint32 miscInit1 = INREG32(MISC_INIT1);
|
||||
if (memType == MEM_TYPE_SDRAM) {
|
||||
miscInit1 |= DISABLE_2D_BLOCK_WRITE;
|
||||
}
|
||||
miscInit1 |= 1;
|
||||
OUTREG32(MISC_INIT1, miscInit1);
|
||||
|
||||
return chipSize * numChips * 1024 * 1024;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TDFX_Init(void)
|
||||
{
|
||||
TRACE("TDFX_Init()\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
si.videoMemSize = TDFX_GetVideoMemorySize();
|
||||
|
||||
si.cursorOffset = 0;
|
||||
si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES;
|
||||
si.maxFrameBufferSize = si.videoMemSize - si.frameBufferOffset;
|
||||
|
||||
TRACE("Video Memory size: %d MB\n", si.videoMemSize / 1024 / 1024);
|
||||
TRACE("frameBufferOffset: 0x%x cursorOffset: 0x%x\n", si.frameBufferOffset, si.cursorOffset);
|
||||
|
||||
switch (si.chipType) {
|
||||
case BANSHEE:
|
||||
si.maxPixelClock = 270000;
|
||||
break;
|
||||
case VOODOO_3:
|
||||
si.maxPixelClock = 300000;
|
||||
break;
|
||||
case VOODOO_5:
|
||||
si.maxPixelClock = 350000;
|
||||
break;
|
||||
default:
|
||||
TRACE("Undefined chip type: %d\n", si.chipType);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Set up the array of color spaces supported by the 3dfx chips.
|
||||
|
||||
si.colorSpaces[0] = B_CMAP8;
|
||||
si.colorSpaces[1] = B_RGB16;
|
||||
si.colorSpaces[2] = B_RGB32;
|
||||
si.colorSpaceCount = 3;
|
||||
|
||||
// Setup the mode list.
|
||||
|
||||
return CreateModeList(IsModeUsable);
|
||||
}
|
402
src/add-ons/accelerants/3dfx/3dfx_mode.cpp
Normal file
402
src/add-ons/accelerants/3dfx/3dfx_mode.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
/*
|
||||
Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac
|
||||
*/
|
||||
|
||||
/*
|
||||
Some of the code in this source file was adapted from the X.org tdfx
|
||||
video driver, and was covered by the following copyright and license.
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sub license, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the
|
||||
next paragraph) shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
// Functions to read/write PIO registers.
|
||||
//=======================================
|
||||
|
||||
static void
|
||||
WritePIOReg(uint32 offset, int16 index, uint8 value)
|
||||
{
|
||||
PIORegInfo prInfo;
|
||||
prInfo.magic = TDFX_PRIVATE_DATA_MAGIC;
|
||||
prInfo.offset = offset;
|
||||
prInfo.index = index;
|
||||
prInfo.value = value;
|
||||
|
||||
status_t result = ioctl(gInfo.deviceFileDesc, TDFX_SET_PIO_REG,
|
||||
&prInfo, sizeof(prInfo));
|
||||
if (result != B_OK)
|
||||
TRACE("WritePIOReg() failed, result = 0x%x\n", result);
|
||||
}
|
||||
|
||||
|
||||
static uint8
|
||||
ReadPIOReg(uint32 offset, int16 index)
|
||||
{
|
||||
PIORegInfo prInfo;
|
||||
prInfo.magic = TDFX_PRIVATE_DATA_MAGIC;
|
||||
prInfo.offset = offset;
|
||||
prInfo.index = index;
|
||||
|
||||
status_t result = ioctl(gInfo.deviceFileDesc, TDFX_GET_PIO_REG,
|
||||
&prInfo, sizeof(prInfo));
|
||||
if (result != B_OK)
|
||||
TRACE("ReadPIOReg() failed, result = 0x%x\n", result);
|
||||
|
||||
return prInfo.value;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WriteMiscOutReg(uint8 value)
|
||||
{
|
||||
WritePIOReg(MISC_OUT_W - 0x300, -1, value);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WriteCrtcReg(uint8 index, uint8 value)
|
||||
{
|
||||
WritePIOReg(CRTC_INDEX - 0x300, index, value);
|
||||
}
|
||||
|
||||
|
||||
uint8
|
||||
ReadMiscOutReg()
|
||||
{
|
||||
return ReadPIOReg(MISC_OUT_R - 0x300, -1);
|
||||
}
|
||||
|
||||
|
||||
uint8
|
||||
ReadCrtcReg(uint8 index)
|
||||
{
|
||||
return ReadPIOReg(CRTC_INDEX - 0x300, index);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_WaitForFifo(uint32 entries)
|
||||
{
|
||||
// The FIFO has 32 slots. This routine waits until at least `entries'
|
||||
// of these slots are empty.
|
||||
|
||||
while ((INREG32(STATUS) & 0x1f) < entries) ;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_WaitForIdle()
|
||||
{
|
||||
// Wait for the graphics engine to be completely idle.
|
||||
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(CMD_3D, CMD_3D_NOP);
|
||||
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
i = (INREG32(STATUS) & STATUS_BUSY) ? 0 : i + 1;
|
||||
} while (i < 3);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
TDFX_CalcPLL(int freq)
|
||||
{
|
||||
const int refFreq = 14318;
|
||||
int best_error = freq;
|
||||
int best_k = 0;
|
||||
int best_m = 0;
|
||||
int best_n = 0;
|
||||
|
||||
for (int n = 1; n < 256; n++) {
|
||||
int freqCur = refFreq * (n + 2);
|
||||
if (freqCur < freq) {
|
||||
freqCur = freqCur / 3;
|
||||
if (freq - freqCur < best_error) {
|
||||
best_error = freq - freqCur;
|
||||
best_n = n;
|
||||
best_m = 1;
|
||||
best_k = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (int m = 1; m < 64; m++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
freqCur = refFreq * (n + 2) / (m + 2) / (1 << k);
|
||||
if (abs(freqCur - freq) < best_error) {
|
||||
best_error = abs(freqCur - freq);
|
||||
best_n = n;
|
||||
best_m = m;
|
||||
best_k = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (best_n << 8) | (best_m << 2) | best_k;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TDFX_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel)
|
||||
{
|
||||
// Get parameters for a color space which is supported by the 3dfx chips.
|
||||
// Return true if the color space is supported; else return false.
|
||||
|
||||
switch (colorSpace) {
|
||||
case B_RGB32:
|
||||
bitsPerPixel = 32;
|
||||
break;
|
||||
case B_RGB16:
|
||||
bitsPerPixel = 16;
|
||||
break;
|
||||
case B_RGB15:
|
||||
bitsPerPixel = 15;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color space: 0x%X\n", colorSpace);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TDFX_SetDisplayMode(const DisplayModeEx& mode)
|
||||
{
|
||||
// The code to actually configure the display.
|
||||
// All the error checking must be done in ProposeDisplayMode(),
|
||||
// and assume that the mode values we get here are acceptable.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
bool clock2X = mode.timing.pixel_clock > si.maxPixelClock / 2;
|
||||
|
||||
// Initialize the timing values for CRTC registers cr00 to cr18. Note
|
||||
// that the number following the letters 'cr' is a hexadecimal number.
|
||||
// Argument crtc will contain registers cr00 to cr18; thus, it must
|
||||
// contain at least 25 (0x19) elements.
|
||||
|
||||
// Normally the horizontal timing values are divided by 8; however,
|
||||
// if the clock is above the 2X value, divide by 16 such that the values
|
||||
// are halved.
|
||||
|
||||
int horzDiv = clock2X ? 16 : 8;
|
||||
|
||||
int hTotal = mode.timing.h_total / horzDiv - 5;
|
||||
int hDisp_e = mode.timing.h_display / horzDiv - 1;
|
||||
int hSync_s = mode.timing.h_sync_start / horzDiv;
|
||||
int hSync_e = mode.timing.h_sync_end / horzDiv;
|
||||
int hBlank_s = hDisp_e + 1; // start of horizontal blanking
|
||||
int hBlank_e = hTotal + 3; // end of horizontal blanking
|
||||
|
||||
int vTotal = mode.timing.v_total - 2;
|
||||
int vDisp_e = mode.timing.v_display - 1;
|
||||
int vSync_s = mode.timing.v_sync_start;
|
||||
int vSync_e = mode.timing.v_sync_end;
|
||||
int vBlank_s = vDisp_e + 1; // start of vertical blanking
|
||||
int vBlank_e = vTotal; // end of vertical blanking
|
||||
|
||||
// CRTC Controller values
|
||||
|
||||
uint8 crtc[25];
|
||||
|
||||
crtc[0x00] = hTotal;
|
||||
crtc[0x01] = hDisp_e;
|
||||
crtc[0x02] = hBlank_s;
|
||||
crtc[0x03] = (hBlank_e & 0x1f) | 0x80;
|
||||
crtc[0x04] = hSync_s;
|
||||
crtc[0x05] = ((hSync_e & 0x1f) | ((hBlank_e & 0x20) << 2));
|
||||
crtc[0x06] = vTotal;
|
||||
crtc[0x07] = (((vTotal & 0x100) >> 8)
|
||||
| ((vDisp_e & 0x100) >> 7)
|
||||
| ((vSync_s & 0x100) >> 6)
|
||||
| ((vBlank_s & 0x100) >> 5)
|
||||
| 0x10
|
||||
| ((vTotal & 0x200) >> 4)
|
||||
| ((vDisp_e & 0x200) >> 3)
|
||||
| ((vSync_s & 0x200) >> 2));
|
||||
crtc[0x08] = 0x00;
|
||||
crtc[0x09] = ((vBlank_s & 0x200) >> 4) | 0x40;
|
||||
crtc[0x0a] = 0x00;
|
||||
crtc[0x0b] = 0x00;
|
||||
crtc[0x0c] = 0x00;
|
||||
crtc[0x0d] = 0x00;
|
||||
crtc[0x0e] = 0x00;
|
||||
crtc[0x0f] = 0x00;
|
||||
crtc[0x10] = vSync_s;
|
||||
crtc[0x11] = (vSync_e & 0x0f) | 0x20;
|
||||
crtc[0x12] = vDisp_e;
|
||||
crtc[0x13] = hDisp_e + 1;
|
||||
crtc[0x14] = 0x00;
|
||||
crtc[0x15] = vBlank_s;
|
||||
crtc[0x16] = vBlank_e;
|
||||
crtc[0x17] = 0xc3;
|
||||
crtc[0x18] = 0xff;
|
||||
|
||||
// Set up the extra CR reg's to handle the higher resolution modes.
|
||||
|
||||
uint8 cr1a = (hTotal & 0x100) >> 8
|
||||
| (hDisp_e & 0x100) >> 6
|
||||
| (hBlank_s & 0x100) >> 4
|
||||
| (hBlank_e & 0x40) >> 1
|
||||
| (hSync_s & 0x100) >> 2
|
||||
| (hSync_e & 0x20) << 2;
|
||||
|
||||
uint8 cr1b = (vTotal & 0x400) >> 10
|
||||
| (vDisp_e & 0x400) >> 8
|
||||
| (vBlank_s & 0x400) >> 6
|
||||
| (vBlank_e & 0x400) >> 4;
|
||||
|
||||
uint8 miscOutReg = 0x0f | (mode.timing.v_display < 400 ? 0xa0
|
||||
: mode.timing.v_display < 480 ? 0x60
|
||||
: mode.timing.v_display < 768 ? 0xe0 : 0x20);
|
||||
|
||||
uint32 vgaInit0 = VGA0_EXTENSIONS
|
||||
| WAKEUP_3C3
|
||||
| ENABLE_ALT_READBACK
|
||||
| CLUT_SELECT_8BIT
|
||||
| EXT_SHIFT_OUT;
|
||||
|
||||
uint32 videoConfig = VIDEO_PROCESSOR_ENABLE | DESKTOP_ENABLE
|
||||
| (mode.bytesPerPixel - 1) << DESKTOP_PIXEL_FORMAT_SHIFT
|
||||
| (mode.bytesPerPixel > 1 ? DESKTOP_CLUT_BYPASS : 0);
|
||||
|
||||
uint32 dacMode = INREG32(DAC_MODE) & ~DAC_MODE_2X;
|
||||
|
||||
if (clock2X) {
|
||||
dacMode |= DAC_MODE_2X;
|
||||
videoConfig |= VIDEO_2X_MODE_ENABLE;
|
||||
}
|
||||
|
||||
uint32 pllFreq = TDFX_CalcPLL(mode.timing.pixel_clock);
|
||||
|
||||
// Note that for the Banshee chip, the mode 1280x1024 at 60Hz refresh does
|
||||
// not display properly using the computed PLL frequency; thus, set it to
|
||||
// the value that is computed when set by VESA.
|
||||
|
||||
if (si.chipType == BANSHEE && pllFreq == 45831
|
||||
&& mode.timing.h_display == 1280 && mode.timing.v_display == 1024)
|
||||
pllFreq = 45912;
|
||||
|
||||
uint32 screenSize = mode.timing.h_display | (mode.timing.v_display << 12);
|
||||
|
||||
// Now that the values for the registers have been computed, write the
|
||||
// registers to set the mode.
|
||||
//=====================================================================
|
||||
|
||||
TDFX_WaitForFifo(2);
|
||||
OUTREG32(VIDEO_PROC_CONFIG, 0);
|
||||
OUTREG32(PLL_CTRL0, pllFreq);
|
||||
|
||||
WriteMiscOutReg(miscOutReg);
|
||||
|
||||
for (uint8 j = 0; j < 25; j++)
|
||||
WriteCrtcReg(j, crtc[j]);
|
||||
|
||||
WriteCrtcReg(0x1a, cr1a);
|
||||
WriteCrtcReg(0x1b, cr1b);
|
||||
|
||||
TDFX_WaitForFifo(6);
|
||||
OUTREG32(VGA_INIT0, vgaInit0);
|
||||
OUTREG32(DAC_MODE, dacMode);
|
||||
OUTREG32(VIDEO_DESKTOP_OVERLAY_STRIDE, mode.bytesPerRow);
|
||||
OUTREG32(HW_CURSOR_PAT_ADDR, si.cursorOffset);
|
||||
OUTREG32(VIDEO_SCREEN_SIZE, screenSize);
|
||||
OUTREG32(VIDEO_DESKTOP_START_ADDR, si.frameBufferOffset);
|
||||
|
||||
TDFX_WaitForFifo(7);
|
||||
OUTREG32(CLIP0_MIN, 0);
|
||||
OUTREG32(CLIP0_MAX, 0x0fff0fff);
|
||||
OUTREG32(CLIP1_MIN, 0);
|
||||
OUTREG32(CLIP1_MAX, 0x0fff0fff);
|
||||
OUTREG32(VIDEO_PROC_CONFIG, videoConfig);
|
||||
OUTREG32(SRC_BASE_ADDR, si.frameBufferOffset);
|
||||
OUTREG32(DST_BASE_ADDR, si.frameBufferOffset);
|
||||
|
||||
TDFX_WaitForIdle();
|
||||
|
||||
TDFX_AdjustFrame(mode);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
TDFX_AdjustFrame(const DisplayModeEx& mode)
|
||||
{
|
||||
// Adjust start address in frame buffer.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
int address = (mode.v_display_start * mode.virtual_width
|
||||
+ mode.h_display_start) * mode.bytesPerPixel;
|
||||
|
||||
address &= ~0x07;
|
||||
address += si.frameBufferOffset;
|
||||
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(VIDEO_DESKTOP_START_ADDR, address);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
|
||||
{
|
||||
// Set the indexed color palette for 8-bit color depth mode.
|
||||
|
||||
(void)flags; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
|
||||
return ;
|
||||
|
||||
uint32 index = first;
|
||||
|
||||
while (count--) {
|
||||
uint32 color = ((colorData[0] << 16) | (colorData[1] << 8) | colorData[2]);
|
||||
TDFX_WaitForFifo(2);
|
||||
OUTREG32(DAC_ADDR, index++);
|
||||
INREG32(DAC_ADDR); // color not always set unless we read after write
|
||||
OUTREG32(DAC_DATA, color);
|
||||
|
||||
colorData += 3;
|
||||
}
|
||||
}
|
121
src/add-ons/accelerants/3dfx/3dfx_overlay.cpp
Normal file
121
src/add-ons/accelerants/3dfx/3dfx_overlay.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
|
||||
|
||||
bool
|
||||
TDFX_DisplayOverlay(const overlay_window* window,
|
||||
const overlay_buffer* buffer,
|
||||
const overlay_view* view)
|
||||
{
|
||||
// Return true if setup is successful.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (window == NULL || buffer == NULL || view == NULL)
|
||||
return false;
|
||||
|
||||
if (window->flags & B_OVERLAY_COLOR_KEY) {
|
||||
uint32 color = 0;
|
||||
|
||||
if (si.displayMode.bitsPerPixel == 16) {
|
||||
color = (window->blue.value & window->blue.mask) << 0
|
||||
| (window->green.value & window->green.mask) << 5
|
||||
| (window->red.value & window->red.mask) << 11;
|
||||
// 16 bit color has no alpha bits
|
||||
} else {
|
||||
color = (window->blue.value & window->blue.mask) << 0
|
||||
| (window->green.value & window->green.mask) << 8
|
||||
| (window->red.value & window->red.mask) << 16
|
||||
| (window->alpha.value & window->alpha.mask) << 24;
|
||||
}
|
||||
|
||||
TDFX_WaitForFifo(2);
|
||||
OUTREG32(VIDEO_CHROMA_MIN, color);
|
||||
OUTREG32(VIDEO_CHROMA_MAX, color);
|
||||
}
|
||||
|
||||
uint32 videoConfig = INREG32(VIDEO_PROC_CONFIG);
|
||||
videoConfig &= ~VIDEO_PROC_CONFIG_MASK;
|
||||
videoConfig |= (0x00000320 | OVERLAY_CLUT_BYPASS);
|
||||
|
||||
// Scale image if window dimension is larger than the buffer dimension.
|
||||
// Scaling is not done if window dimension is smaller since the chip only
|
||||
// scales up to a larger dimension, and does not scale down to a smaller
|
||||
// dimension.
|
||||
|
||||
if (window->width > buffer->width)
|
||||
videoConfig |= (1 << 14);
|
||||
if (window->height > buffer->height)
|
||||
videoConfig |= (1 << 15);
|
||||
|
||||
switch (buffer->space) {
|
||||
case B_YCbCr422:
|
||||
videoConfig |= VIDCFG_OVL_FMT_YUYV422;
|
||||
break;
|
||||
case B_RGB16:
|
||||
videoConfig |= VIDCFG_OVL_FMT_RGB565;
|
||||
break;
|
||||
default:
|
||||
return false; // color space not supported
|
||||
}
|
||||
|
||||
// can't do bilinear filtering when in 2X mode
|
||||
if ((videoConfig & VIDEO_2X_MODE_ENABLE) == 0)
|
||||
videoConfig |= (3 << 16);
|
||||
|
||||
TDFX_WaitForFifo(1);
|
||||
OUTREG32(VIDEO_PROC_CONFIG, videoConfig);
|
||||
|
||||
// Subtract 1 from height to eliminate junk on last line of image.
|
||||
int32 dudx = (buffer->width << 20) / window->width;
|
||||
int32 dudy = ((buffer->height - 1) << 20) / window->height;
|
||||
|
||||
int32 x1 = (window->h_start < 0) ? 0 : window->h_start;
|
||||
int32 y1 = (window->v_start < 0) ? 0 : window->v_start;
|
||||
|
||||
int32 x2 = x1 + window->width - 1;
|
||||
int32 y2 = y1 + window->height - 1;
|
||||
|
||||
TDFX_WaitForFifo(6);
|
||||
|
||||
// Set up coordinates of overlay window on screen.
|
||||
OUTREG32(VIDEO_OVERLAY_START_COORDS, x1 | (y1 << 12));
|
||||
OUTREG32(VIDEO_OVERLAY_END_COORDS, x2 | (y2 << 12));
|
||||
// Set up scale and position of overlay in graphics memory.
|
||||
OUTREG32(VIDEO_OVERLAY_DUDX, dudx);
|
||||
OUTREG32(VIDEO_OVERLAY_DUDX_OFFSET_SRC_WIDTH, ((x1 & 0x0001ffff) << 3)
|
||||
| (buffer->width << 20));
|
||||
OUTREG32(VIDEO_OVERLAY_DVDY, dudy);
|
||||
OUTREG32(VIDEO_OVERLAY_DVDY_OFFSET, (y1 & 0x0000ffff) << 3);
|
||||
|
||||
// Add width of overlay buffer to stride.
|
||||
uint32 stride = INREG32(VIDEO_DESKTOP_OVERLAY_STRIDE) & 0x0000ffff;
|
||||
stride |= (buffer->width << 1) << 16;
|
||||
uint32 offset = (uint32)buffer->buffer_dma;
|
||||
|
||||
TDFX_WaitForFifo(2);
|
||||
|
||||
OUTREG32(VIDEO_DESKTOP_OVERLAY_STRIDE, stride);
|
||||
OUTREG32(VIDEO_IN_ADDR0, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TDFX_StopOverlay(void)
|
||||
{
|
||||
// reset the video
|
||||
uint32 videoConfig = INREG32(VIDEO_PROC_CONFIG) & ~VIDEO_PROC_CONFIG_MASK;
|
||||
OUTREG32(VIDEO_PROC_CONFIG, videoConfig);
|
||||
OUTREG32(RGB_MAX_DELTA, 0x0080808);
|
||||
}
|
24
src/add-ons/accelerants/3dfx/Jamfile
Normal file
24
src/add-ons/accelerants/3dfx/Jamfile
Normal file
@ -0,0 +1,24 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants 3dfx ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics 3dfx ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
|
||||
Addon 3dfx.accelerant :
|
||||
accelerant.cpp
|
||||
cursor.cpp
|
||||
engine.cpp
|
||||
hooks.cpp
|
||||
mode.cpp
|
||||
overlay.cpp
|
||||
|
||||
3dfx_cursor.cpp
|
||||
3dfx_dpms.cpp
|
||||
3dfx_draw.cpp
|
||||
3dfx_edid.cpp
|
||||
3dfx_init.cpp
|
||||
3dfx_mode.cpp
|
||||
3dfx_overlay.cpp
|
||||
|
||||
: be libaccelerantscommon.a
|
||||
;
|
196
src/add-ons/accelerants/3dfx/accelerant.cpp
Normal file
196
src/add-ons/accelerants/3dfx/accelerant.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2007-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
AccelerantInfo gInfo; // global data used by various source files of accelerant.
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
InitCommon(int fileDesc)
|
||||
{
|
||||
// Initialization function used by primary and cloned accelerants.
|
||||
|
||||
gInfo.deviceFileDesc = fileDesc;
|
||||
|
||||
// Get area ID of shared data from driver.
|
||||
|
||||
area_id sharedArea;
|
||||
status_t result = ioctl(gInfo.deviceFileDesc, TDFX_GET_SHARED_DATA,
|
||||
&sharedArea, sizeof(sharedArea));
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
gInfo.sharedInfoArea = clone_area("3DFX shared info", (void**)&(gInfo.sharedInfo),
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, sharedArea);
|
||||
if (gInfo.sharedInfoArea < 0)
|
||||
return gInfo.sharedInfoArea; // sharedInfoArea has error code
|
||||
|
||||
gInfo.regsArea = clone_area("3DFX regs area", (void**)&(gInfo.regs),
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gInfo.sharedInfo->regsArea);
|
||||
if (gInfo.regsArea < 0) {
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
return gInfo.regsArea; // regsArea has error code
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
UninitCommon(void)
|
||||
{
|
||||
// This function is used by both primary and cloned accelerants.
|
||||
|
||||
delete_area(gInfo.regsArea);
|
||||
gInfo.regs = 0;
|
||||
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
gInfo.sharedInfo = 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InitAccelerant(int fileDesc)
|
||||
{
|
||||
// Initialize the accelerant. fileDesc is the file handle of the device
|
||||
// (in /dev/graphics) that has been opened by the app_server.
|
||||
|
||||
TRACE("Enter InitAccelerant()\n");
|
||||
|
||||
gInfo.bAccelerantIsClone = false; // indicate this is primary accelerant
|
||||
|
||||
status_t result = InitCommon(fileDesc);
|
||||
if (result == B_OK) {
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("Vendor ID: 0x%X, Device ID: 0x%X\n", si.vendorID, si.deviceID);
|
||||
|
||||
// Ensure that InitAccelerant is executed just once (copies should be clones)
|
||||
|
||||
if (si.bAccelerantInUse) {
|
||||
result = B_NOT_ALLOWED;
|
||||
} else {
|
||||
result = TDFX_Init(); // perform init related to current chip
|
||||
if (result == B_OK) {
|
||||
result = si.engineLock.Init("3DFX engine lock");
|
||||
if (result == B_OK)
|
||||
result = si.overlayLock.Init("3DFX overlay lock");
|
||||
if (result == B_OK) {
|
||||
TDFX_ShowCursor(false);
|
||||
|
||||
// ensure that this function won't be executed again
|
||||
// (copies should be clones)
|
||||
si.bAccelerantInUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result != B_OK)
|
||||
UninitCommon();
|
||||
}
|
||||
|
||||
TRACE("Leave InitAccelerant(), result: 0x%X\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
AccelerantCloneInfoSize(void)
|
||||
{
|
||||
// Return the number of bytes required to hold the information required
|
||||
// to clone the device. The information is merely the name of the device;
|
||||
// thus, return the size of the name buffer.
|
||||
|
||||
return B_OS_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GetAccelerantCloneInfo(void* data)
|
||||
{
|
||||
// Return the info required to clone the device. Argument data points to
|
||||
// a buffer which is the size returned by AccelerantCloneInfoSize().
|
||||
|
||||
ioctl(gInfo.deviceFileDesc, TDFX_DEVICE_NAME, data, B_OS_NAME_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CloneAccelerant(void* data)
|
||||
{
|
||||
// Initialize a copy of the accelerant as a clone. Argument data points to
|
||||
// a copy of the data which was returned by GetAccelerantCloneInfo().
|
||||
|
||||
TRACE("Enter CloneAccelerant()\n");
|
||||
|
||||
char path[MAXPATHLEN] = "/dev/";
|
||||
strcat(path, (const char*)data);
|
||||
|
||||
gInfo.deviceFileDesc = open(path, B_READ_WRITE); // open the device
|
||||
if (gInfo.deviceFileDesc < 0)
|
||||
return errno;
|
||||
|
||||
gInfo.bAccelerantIsClone = true;
|
||||
|
||||
status_t result = InitCommon(gInfo.deviceFileDesc);
|
||||
if (result != B_OK) {
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = gInfo.modeListArea = clone_area("3DFX cloned display_modes",
|
||||
(void**) &gInfo.modeList, B_ANY_ADDRESS, B_READ_AREA,
|
||||
gInfo.sharedInfo->modeArea);
|
||||
if (result < 0) {
|
||||
UninitCommon();
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
TRACE("Leave CloneAccelerant()\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UninitAccelerant(void)
|
||||
{
|
||||
delete_area(gInfo.modeListArea);
|
||||
gInfo.modeList = NULL;
|
||||
|
||||
UninitCommon();
|
||||
|
||||
if (gInfo.bAccelerantIsClone)
|
||||
close(gInfo.deviceFileDesc);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetAccelerantDeviceInfo(accelerant_device_info* adi)
|
||||
{
|
||||
// Get info about the device.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
adi->version = 1;
|
||||
strcpy(adi->name, "3dfx chipset");
|
||||
strcpy(adi->chipset, si.chipName);
|
||||
strcpy(adi->serial_no, "unknown");
|
||||
adi->memory = si.maxFrameBufferSize;
|
||||
adi->dac_speed = 270;
|
||||
|
||||
return B_OK;
|
||||
}
|
186
src/add-ons/accelerants/3dfx/accelerant.h
Normal file
186
src/add-ons/accelerants/3dfx/accelerant.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2007-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#ifndef _ACCELERANT_H
|
||||
#define _ACCELERANT_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
|
||||
|
||||
#undef TRACE
|
||||
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
extern "C" void _sPrintf(const char* format, ...);
|
||||
# define TRACE(x...) _sPrintf("3dfx: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory
|
||||
|
||||
|
||||
// Global data used by various source files of the accelerant.
|
||||
|
||||
struct AccelerantInfo {
|
||||
int deviceFileDesc; // file descriptor of kernel driver
|
||||
|
||||
SharedInfo* sharedInfo; // address of info shared between accelerants & driver
|
||||
area_id sharedInfoArea; // shared info area ID
|
||||
|
||||
uint8* regs; // base address of MMIO register area
|
||||
area_id regsArea; // MMIO register area ID
|
||||
|
||||
display_mode* modeList; // list of standard display modes
|
||||
area_id modeListArea; // mode list area ID
|
||||
|
||||
bool bAccelerantIsClone; // true if this is a cloned accelerant
|
||||
};
|
||||
|
||||
extern AccelerantInfo gInfo;
|
||||
|
||||
|
||||
// Prototypes of the interface functions called by the app_server. Note that
|
||||
// the functions that are unique to a particular chip family, will be prefixed
|
||||
// with the name of the family, and the functions that are applicable to all
|
||||
// chips will have no prefix.
|
||||
//================================================================
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// General
|
||||
status_t InitAccelerant(int fd);
|
||||
ssize_t AccelerantCloneInfoSize(void);
|
||||
void GetAccelerantCloneInfo(void* data);
|
||||
status_t CloneAccelerant(void* data);
|
||||
void UninitAccelerant(void);
|
||||
status_t GetAccelerantDeviceInfo(accelerant_device_info* adi);
|
||||
|
||||
// Mode Configuration
|
||||
uint32 AccelerantModeCount(void);
|
||||
status_t GetModeList(display_mode* dm);
|
||||
status_t ProposeDisplayMode(display_mode* target, const display_mode* low,
|
||||
const display_mode* high);
|
||||
status_t SetDisplayMode(display_mode* mode_to_set);
|
||||
status_t GetDisplayMode(display_mode* current_mode);
|
||||
status_t GetFrameBufferConfig(frame_buffer_config* a_frame_buffer);
|
||||
status_t GetPixelClockLimits(display_mode* dm, uint32* low, uint32* high);
|
||||
status_t MoveDisplay(uint16 h_display_start, uint16 v_display_start);
|
||||
void TDFX_SetIndexedColors(uint count, uint8 first, uint8* color_data,
|
||||
uint32 flags);
|
||||
status_t GetEdidInfo(void* info, size_t size, uint32* _version);
|
||||
|
||||
// DPMS
|
||||
uint32 TDFX_DPMSCapabilities(void);
|
||||
uint32 TDFX_GetDPMSMode(void);
|
||||
status_t TDFX_SetDPMSMode(uint32 dpms_flags);
|
||||
|
||||
// Cursor
|
||||
status_t SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
|
||||
uint8* andMask, uint8* xorMask);
|
||||
void MoveCursor(uint16 x, uint16 y);
|
||||
void TDFX_ShowCursor(bool bShow);
|
||||
|
||||
// Engine Management
|
||||
uint32 AccelerantEngineCount(void);
|
||||
status_t AcquireEngine(uint32 capabilities, uint32 max_wait, sync_token* st,
|
||||
engine_token** et);
|
||||
status_t ReleaseEngine(engine_token* et, sync_token* st);
|
||||
void WaitEngineIdle(void);
|
||||
status_t GetSyncToken(engine_token* et, sync_token* st);
|
||||
status_t SyncToToken(sync_token* st);
|
||||
|
||||
// 2D acceleration
|
||||
void TDFX_FillRectangle(engine_token* et, uint32 color,
|
||||
fill_rect_params* list, uint32 count);
|
||||
void TDFX_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
|
||||
void TDFX_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
|
||||
void TDFX_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
|
||||
|
||||
// Video_overlay
|
||||
uint32 OverlayCount(const display_mode *dm);
|
||||
const uint32* OverlaySupportedSpaces(const display_mode *dm);
|
||||
uint32 OverlaySupportedFeatures(uint32 a_color_space);
|
||||
const overlay_buffer* AllocateOverlayBuffer(color_space cs, uint16 width,
|
||||
uint16 height);
|
||||
status_t ReleaseOverlayBuffer(const overlay_buffer *ob);
|
||||
status_t GetOverlayConstraints(const display_mode *dm,
|
||||
const overlay_buffer *ob, overlay_constraints *oc);
|
||||
overlay_token AllocateOverlay(void);
|
||||
status_t ReleaseOverlay(overlay_token ot);
|
||||
status_t ConfigureOverlay(overlay_token ot, const overlay_buffer *ob,
|
||||
const overlay_window *ow, const overlay_view *ov);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Prototypes for other functions that are called from source files other than
|
||||
// where they are defined.
|
||||
//============================================================================
|
||||
|
||||
status_t CreateModeList(bool (*checkMode)(const display_mode* mode));
|
||||
uint16 GetVesaModeNumber(const display_mode& mode, uint8 bitsPerPixel);
|
||||
bool IsModeUsable(const display_mode* mode);
|
||||
|
||||
// 3dfx functions.
|
||||
|
||||
bool TDFX_DisplayOverlay(const overlay_window* window,
|
||||
const overlay_buffer* buffer, const overlay_view* view);
|
||||
void TDFX_StopOverlay(void);
|
||||
|
||||
status_t TDFX_Init(void);
|
||||
bool TDFX_GetColorSpaceParams(int colorSpace, uint8& bpp);
|
||||
bool TDFX_GetEdidInfo(edid1_info& edidInfo);
|
||||
|
||||
void TDFX_EngineReset(void);
|
||||
void TDFX_EngineInit(const DisplayModeEx& mode);
|
||||
|
||||
bool TDFX_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
|
||||
void TDFX_SetCursorPosition(int x, int y);
|
||||
|
||||
void TDFX_AdjustFrame(const DisplayModeEx& mode);
|
||||
status_t TDFX_SetDisplayMode(const DisplayModeEx& mode);
|
||||
|
||||
void TDFX_WaitForFifo(uint32);
|
||||
void TDFX_WaitForIdle();
|
||||
|
||||
|
||||
// Address of various VGA registers.
|
||||
|
||||
#define MISC_OUT_R 0x3cc // read
|
||||
#define MISC_OUT_W 0x3c2 // write
|
||||
#define CRTC_INDEX 0x3d4
|
||||
#define CRTC_DATA 0x3d5
|
||||
#define SEQ_INDEX 0x3c4
|
||||
#define SEQ_DATA 0x3c5
|
||||
|
||||
|
||||
// Macros for memory mapped I/O.
|
||||
//===============================
|
||||
|
||||
#define INREG8(addr) *((vuint8*)(gInfo.regs + addr))
|
||||
#define INREG16(addr) *((vuint16*)(gInfo.regs + addr))
|
||||
#define INREG32(addr) *((vuint32*)(gInfo.regs + addr))
|
||||
|
||||
#define OUTREG8(addr, val) *((vuint8*)(gInfo.regs + addr)) = val
|
||||
#define OUTREG16(addr, val) *((vuint16*)(gInfo.regs + addr)) = val
|
||||
#define OUTREG32(addr, val) *((vuint32*)(gInfo.regs + addr)) = val
|
||||
|
||||
// Write a value to an 32-bit reg using a mask. The mask selects the
|
||||
// bits to be modified.
|
||||
#define OUTREGM(addr, value, mask) \
|
||||
(OUTREG(addr, (INREG(addr) & ~mask) | (value & mask)))
|
||||
|
||||
|
||||
#endif // _ACCELERANT_H
|
81
src/add-ons/accelerants/3dfx/cursor.cpp
Normal file
81
src/add-ons/accelerants/3dfx/cursor.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Gerald Zajac 2007-2010
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
status_t
|
||||
SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
|
||||
uint8* andMask, uint8* xorMask)
|
||||
{
|
||||
// NOTE: Currently, for BeOS, cursor width and height must be equal to 16.
|
||||
|
||||
if ((width != 16) || (height != 16)) {
|
||||
return B_ERROR;
|
||||
} else if ((hot_x >= width) || (hot_y >= height)) {
|
||||
return B_ERROR;
|
||||
} else {
|
||||
// Update cursor variables appropriately.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
si.cursorHotX = hot_x;
|
||||
si.cursorHotY = hot_y;
|
||||
|
||||
if ( ! TDFX_LoadCursorImage(width, height, andMask, xorMask))
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MoveCursor(uint16 xPos, uint16 yPos)
|
||||
{
|
||||
// Move the cursor to the specified position on the desktop. If we're
|
||||
// using some kind of virtual desktop, adjust the display start position
|
||||
// accordingly and position the cursor in the proper "virtual" location.
|
||||
|
||||
int x = xPos; // use signed int's since chip specific functions
|
||||
int y = yPos; // need signed int to determine if cursor off screen
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
DisplayModeEx& dm = si.displayMode;
|
||||
|
||||
uint16 hds = dm.h_display_start; // current horizontal starting pixel
|
||||
uint16 vds = dm.v_display_start; // current vertical starting line
|
||||
|
||||
// Clamp cursor to virtual display.
|
||||
if (x >= dm.virtual_width)
|
||||
x = dm.virtual_width - 1;
|
||||
if (y >= dm.virtual_height)
|
||||
y = dm.virtual_height - 1;
|
||||
|
||||
// Adjust h/v display start to move cursor onto screen.
|
||||
if (x >= (dm.timing.h_display + hds))
|
||||
hds = x - dm.timing.h_display + 1;
|
||||
else if (x < hds)
|
||||
hds = x;
|
||||
|
||||
if (y >= (dm.timing.v_display + vds))
|
||||
vds = y - dm.timing.v_display + 1;
|
||||
else if (y < vds)
|
||||
vds = y;
|
||||
|
||||
// Reposition the desktop on the display if required.
|
||||
if (hds != dm.h_display_start || vds != dm.v_display_start)
|
||||
MoveDisplay(hds, vds);
|
||||
|
||||
// Put cursor in correct physical position.
|
||||
x -= (hds + si.cursorHotX);
|
||||
y -= (vds + si.cursorHotY);
|
||||
|
||||
// Position the cursor on the display.
|
||||
TDFX_SetCursorPosition(x, y);
|
||||
}
|
||||
|
78
src/add-ons/accelerants/3dfx/engine.cpp
Normal file
78
src/add-ons/accelerants/3dfx/engine.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Gerald Zajac 2007-2010
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
static engine_token engineToken = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantEngineCount(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AcquireEngine(uint32 capabilities, uint32 max_wait,
|
||||
sync_token* st, engine_token** et)
|
||||
{
|
||||
(void)capabilities; // avoid compiler warning for unused arg
|
||||
(void)max_wait; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->engineLock.Acquire() != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Sync if required.
|
||||
if (st)
|
||||
SyncToToken(st);
|
||||
|
||||
// Return an engine token.
|
||||
*et = &engineToken;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReleaseEngine(engine_token* et, sync_token* st)
|
||||
{
|
||||
// Update the sync token, if any.
|
||||
if (st)
|
||||
GetSyncToken(et, st);
|
||||
|
||||
gInfo.sharedInfo->engineLock.Release();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WaitEngineIdle(void)
|
||||
{
|
||||
TDFX_WaitForIdle(); // wait until engine is completely idle
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetSyncToken(engine_token* et, sync_token* st)
|
||||
{
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SyncToToken(sync_token* st)
|
||||
{
|
||||
(void)st; // avoid compiler warning for unused arg
|
||||
|
||||
WaitEngineIdle();
|
||||
return B_OK;
|
||||
}
|
||||
|
124
src/add-ons/accelerants/3dfx/hooks.cpp
Normal file
124
src/add-ons/accelerants/3dfx/hooks.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2008-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
extern "C" void*
|
||||
get_accelerant_hook(uint32 feature, void* data)
|
||||
{
|
||||
(void)data; // avoid compiler warning for unused arg
|
||||
|
||||
switch (feature) {
|
||||
// General
|
||||
case B_INIT_ACCELERANT:
|
||||
return (void*)InitAccelerant;
|
||||
case B_UNINIT_ACCELERANT:
|
||||
return (void*)UninitAccelerant;
|
||||
case B_CLONE_ACCELERANT:
|
||||
return (void*)CloneAccelerant;
|
||||
case B_ACCELERANT_CLONE_INFO_SIZE:
|
||||
return (void*)AccelerantCloneInfoSize;
|
||||
case B_GET_ACCELERANT_CLONE_INFO:
|
||||
return (void*)GetAccelerantCloneInfo;
|
||||
case B_GET_ACCELERANT_DEVICE_INFO:
|
||||
return (void*)GetAccelerantDeviceInfo;
|
||||
case B_ACCELERANT_RETRACE_SEMAPHORE:
|
||||
return NULL;
|
||||
|
||||
// Mode Configuration
|
||||
case B_ACCELERANT_MODE_COUNT:
|
||||
return (void*)AccelerantModeCount;
|
||||
case B_GET_MODE_LIST:
|
||||
return (void*)GetModeList;
|
||||
case B_PROPOSE_DISPLAY_MODE:
|
||||
return (void*)ProposeDisplayMode;
|
||||
case B_SET_DISPLAY_MODE:
|
||||
return (void*)SetDisplayMode;
|
||||
case B_GET_DISPLAY_MODE:
|
||||
return (void*)GetDisplayMode;
|
||||
#ifdef __HAIKU__
|
||||
case B_GET_PREFERRED_DISPLAY_MODE:
|
||||
return NULL;
|
||||
case B_GET_EDID_INFO:
|
||||
return (void*)GetEdidInfo;
|
||||
#endif
|
||||
case B_GET_FRAME_BUFFER_CONFIG:
|
||||
return (void*)GetFrameBufferConfig;
|
||||
case B_GET_PIXEL_CLOCK_LIMITS:
|
||||
return (void*)GetPixelClockLimits;
|
||||
case B_MOVE_DISPLAY:
|
||||
return (void*)MoveDisplay;
|
||||
case B_SET_INDEXED_COLORS:
|
||||
return (void*)(TDFX_SetIndexedColors);
|
||||
case B_GET_TIMING_CONSTRAINTS:
|
||||
return NULL;
|
||||
|
||||
// DPMS
|
||||
case B_DPMS_CAPABILITIES:
|
||||
return (void*)(TDFX_DPMSCapabilities);
|
||||
case B_DPMS_MODE:
|
||||
return (void*)(TDFX_GetDPMSMode);
|
||||
case B_SET_DPMS_MODE:
|
||||
return (void*)(TDFX_SetDPMSMode);
|
||||
|
||||
// Cursor
|
||||
case B_SET_CURSOR_SHAPE:
|
||||
return (void*)SetCursorShape;
|
||||
case B_MOVE_CURSOR:
|
||||
return (void*)MoveCursor;
|
||||
case B_SHOW_CURSOR:
|
||||
return (void*)(TDFX_ShowCursor);
|
||||
|
||||
// Engine Management
|
||||
case B_ACCELERANT_ENGINE_COUNT:
|
||||
return (void*)AccelerantEngineCount;
|
||||
case B_ACQUIRE_ENGINE:
|
||||
return (void*)AcquireEngine;
|
||||
case B_RELEASE_ENGINE:
|
||||
return (void*)ReleaseEngine;
|
||||
case B_WAIT_ENGINE_IDLE:
|
||||
return (void*)WaitEngineIdle;
|
||||
case B_GET_SYNC_TOKEN:
|
||||
return (void*)GetSyncToken;
|
||||
case B_SYNC_TO_TOKEN:
|
||||
return (void*)SyncToToken;
|
||||
|
||||
// 2D acceleration
|
||||
case B_SCREEN_TO_SCREEN_BLIT:
|
||||
return (void*)(TDFX_ScreenToScreenBlit);
|
||||
case B_FILL_RECTANGLE:
|
||||
return (void*)(TDFX_FillRectangle);
|
||||
case B_INVERT_RECTANGLE:
|
||||
return (void*)(TDFX_InvertRectangle);
|
||||
case B_FILL_SPAN:
|
||||
return (void*)(TDFX_FillSpan);
|
||||
|
||||
// Overlay
|
||||
case B_OVERLAY_COUNT:
|
||||
return (void*)OverlayCount;
|
||||
case B_OVERLAY_SUPPORTED_SPACES:
|
||||
return (void*)OverlaySupportedSpaces;
|
||||
case B_OVERLAY_SUPPORTED_FEATURES:
|
||||
return (void*)OverlaySupportedFeatures;
|
||||
case B_ALLOCATE_OVERLAY_BUFFER:
|
||||
return (void*)AllocateOverlayBuffer;
|
||||
case B_RELEASE_OVERLAY_BUFFER:
|
||||
return (void*)ReleaseOverlayBuffer;
|
||||
case B_GET_OVERLAY_CONSTRAINTS:
|
||||
return (void*)GetOverlayConstraints;
|
||||
case B_ALLOCATE_OVERLAY:
|
||||
return (void*)AllocateOverlay;
|
||||
case B_RELEASE_OVERLAY:
|
||||
return (void*)ReleaseOverlay;
|
||||
case B_CONFIGURE_OVERLAY:
|
||||
return (void*)ConfigureOverlay;
|
||||
}
|
||||
|
||||
return NULL; // Return null pointer for any feature not handled above
|
||||
}
|
343
src/add-ons/accelerants/3dfx/mode.cpp
Normal file
343
src/add-ons/accelerants/3dfx/mode.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright 2007-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <create_display_modes.h> // common accelerant header file
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static bool
|
||||
IsThereEnoughFBMemory(const display_mode* mode, uint32 bitsPerPixel)
|
||||
{
|
||||
// Test if there is enough Frame Buffer memory for the mode and color depth
|
||||
// specified by the caller, and return true if there is sufficient memory.
|
||||
|
||||
uint32 maxWidth = mode->virtual_width;
|
||||
if (mode->timing.h_display > maxWidth)
|
||||
maxWidth = mode->timing.h_display;
|
||||
|
||||
uint32 maxHeight = mode->virtual_height;
|
||||
if (mode->timing.v_display > maxHeight)
|
||||
maxHeight = mode->timing.v_display;
|
||||
|
||||
uint32 bytesPerPixel = (bitsPerPixel + 7) / 8;
|
||||
|
||||
return (maxWidth * maxHeight * bytesPerPixel < gInfo.sharedInfo->maxFrameBufferSize);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IsModeUsable(const display_mode* mode)
|
||||
{
|
||||
// Test if the display mode is usable by the current video chip. That is,
|
||||
// does the chip have enough memory for the mode and is the pixel clock
|
||||
// within the chips allowable range, etc.
|
||||
//
|
||||
// Return true if the mode is usable.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
uint8 bitsPerPixel;
|
||||
|
||||
if (!TDFX_GetColorSpaceParams(mode->space, bitsPerPixel))
|
||||
return false;
|
||||
|
||||
// Is there enough frame buffer memory to handle the mode?
|
||||
|
||||
if (!IsThereEnoughFBMemory(mode, bitsPerPixel))
|
||||
return false;
|
||||
|
||||
if (mode->timing.pixel_clock > si.maxPixelClock)
|
||||
return false;
|
||||
|
||||
// Is the color space supported?
|
||||
|
||||
bool colorSpaceSupported = false;
|
||||
for (uint32 j = 0; j < si.colorSpaceCount; j++) {
|
||||
if (mode->space == uint32(si.colorSpaces[j])) {
|
||||
colorSpaceSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colorSpaceSupported)
|
||||
return false;
|
||||
|
||||
// In clock doubled mode for 3DFX chips, widths must be divisible by 16
|
||||
// instead of 8.
|
||||
|
||||
if ((mode->timing.pixel_clock > si.maxPixelClock / 2)
|
||||
&& (mode->timing.h_display % 16) != 0)
|
||||
return false;
|
||||
|
||||
// Reject modes with a width of 640 and a height < 480 since they do not
|
||||
// work properly with the 3DFX chipsets.
|
||||
|
||||
if (mode->timing.h_display == 640 && mode->timing.v_display < 480)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CreateModeList(bool (*checkMode)(const display_mode* mode))
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// Obtain EDID info which is needed for for building the mode list. If
|
||||
// function TDFX_GetEdidInfo() fails, no attempt is made to read the EDID
|
||||
// info from the video BIOS since that always failed when attempted during
|
||||
// the development of this driver.
|
||||
|
||||
si.bHaveEDID = TDFX_GetEdidInfo(si.edidInfo);
|
||||
|
||||
if (si.bHaveEDID) {
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
edid_dump(&(si.edidInfo));
|
||||
#endif
|
||||
} else {
|
||||
TRACE("CreateModeList(); Unable to get EDID info\n");
|
||||
}
|
||||
|
||||
display_mode* list;
|
||||
uint32 count = 0;
|
||||
area_id listArea;
|
||||
|
||||
listArea = create_display_modes("3DFX modes",
|
||||
si.bHaveEDID ? &si.edidInfo : NULL,
|
||||
NULL, 0, si.colorSpaces, si.colorSpaceCount,
|
||||
(check_display_mode_hook)checkMode, &list, &count);
|
||||
|
||||
if (listArea < 0)
|
||||
return listArea; // listArea has error code
|
||||
|
||||
si.modeArea = gInfo.modeListArea = listArea;
|
||||
si.modeCount = count;
|
||||
gInfo.modeList = list;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ProposeDisplayMode(display_mode *target, const display_mode *low,
|
||||
const display_mode *high)
|
||||
{
|
||||
(void)low; // avoid compiler warning for unused arg
|
||||
(void)high; // avoid compiler warning for unused arg
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n",
|
||||
target->timing.h_display, target->timing.v_display,
|
||||
target->timing.pixel_clock, target->space);
|
||||
|
||||
// In clock doubled mode for 3DFX chips, widths must be divisible by 16
|
||||
// instead of 8.
|
||||
|
||||
if ((target->timing.pixel_clock > si.maxPixelClock / 2)
|
||||
&& (target->timing.h_display % 16) != 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// Search the mode list for the specified mode.
|
||||
|
||||
uint32 modeCount = si.modeCount;
|
||||
|
||||
for (uint32 j = 0; j < modeCount; j++) {
|
||||
display_mode& mode = gInfo.modeList[j];
|
||||
|
||||
if (target->timing.h_display == mode.timing.h_display
|
||||
&& target->timing.v_display == mode.timing.v_display
|
||||
&& target->space == mode.space)
|
||||
return B_OK; // mode found in list
|
||||
}
|
||||
|
||||
return B_BAD_VALUE; // mode not found in list
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SetDisplayMode(display_mode* pMode)
|
||||
{
|
||||
// First validate the mode, then call a function to set the registers.
|
||||
|
||||
TRACE("SetDisplayMode() begin\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
DisplayModeEx mode;
|
||||
(display_mode&)mode = *pMode;
|
||||
|
||||
if (!TDFX_GetColorSpaceParams(mode.space, mode.bitsPerPixel))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
mode.bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
|
||||
mode.bytesPerRow = mode.timing.h_display * mode.bytesPerPixel;
|
||||
|
||||
// Is there enough frame buffer memory for this mode?
|
||||
|
||||
if ( ! IsThereEnoughFBMemory(&mode, mode.bitsPerPixel))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE("Set display mode: %dx%d virtual size: %dx%d color depth: %d bits/pixel\n",
|
||||
mode.timing.h_display, mode.timing.v_display,
|
||||
mode.virtual_width, mode.virtual_height, mode.bitsPerPixel);
|
||||
|
||||
TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n",
|
||||
mode.timing.pixel_clock,
|
||||
mode.timing.h_display,
|
||||
mode.timing.h_sync_start, mode.timing.h_sync_end,
|
||||
mode.timing.h_total,
|
||||
mode.timing.v_display,
|
||||
mode.timing.v_sync_start, mode.timing.v_sync_end,
|
||||
mode.timing.v_total);
|
||||
|
||||
TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n",
|
||||
double(mode.timing.pixel_clock) / mode.timing.h_total,
|
||||
((double(mode.timing.pixel_clock) / mode.timing.h_total) * 1000.0)
|
||||
/ mode.timing.v_total,
|
||||
(mode.timing.flags & B_POSITIVE_HSYNC) ? '+' : '-',
|
||||
(mode.timing.flags & B_POSITIVE_VSYNC) ? '+' : '-');
|
||||
|
||||
status_t status = TDFX_SetDisplayMode(mode);
|
||||
if (status != B_OK) {
|
||||
TRACE("SetDisplayMode() failed; status 0x%x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
si.displayMode = mode;
|
||||
|
||||
TRACE("SetDisplayMode() done\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MoveDisplay(uint16 horizontalStart, uint16 verticalStart)
|
||||
{
|
||||
// Set which pixel of the virtual frame buffer will show up in the
|
||||
// top left corner of the display device. Used for page-flipping
|
||||
// games and virtual desktops.
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
|
||||
if (mode.timing.h_display + horizontalStart > mode.virtual_width
|
||||
|| mode.timing.v_display + verticalStart > mode.virtual_height)
|
||||
return B_ERROR;
|
||||
|
||||
mode.h_display_start = horizontalStart;
|
||||
mode.v_display_start = verticalStart;
|
||||
|
||||
TDFX_AdjustFrame(mode);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantModeCount(void)
|
||||
{
|
||||
// Return the number of display modes in the mode list.
|
||||
|
||||
return gInfo.sharedInfo->modeCount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetModeList(display_mode* dmList)
|
||||
{
|
||||
// Copy the list of supported video modes to the location pointed at
|
||||
// by dmList.
|
||||
|
||||
memcpy(dmList, gInfo.modeList, gInfo.sharedInfo->modeCount * sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetDisplayMode(display_mode* current_mode)
|
||||
{
|
||||
*current_mode = gInfo.sharedInfo->displayMode; // return current display mode
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetFrameBufferConfig(frame_buffer_config* pFBC)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
pFBC->frame_buffer = (void*)((addr_t)si.videoMemAddr + si.frameBufferOffset);
|
||||
pFBC->frame_buffer_dma = (void*)((addr_t)si.videoMemPCI + si.frameBufferOffset);
|
||||
pFBC->bytes_per_row = si.displayMode.virtual_width * si.displayMode.bytesPerPixel;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high)
|
||||
{
|
||||
// Return the maximum and minium pixel clock limits for the specified mode.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
uint8 bitsPerPixel;
|
||||
|
||||
if (!TDFX_GetColorSpaceParams(mode->space, bitsPerPixel))
|
||||
return B_ERROR;
|
||||
|
||||
if (low != NULL) {
|
||||
// lower limit of about 48Hz vertical refresh
|
||||
uint32 totalClocks = (uint32)mode->timing.h_total
|
||||
* (uint32)mode->timing.v_total;
|
||||
uint32 lowClock = (totalClocks * 48L) / 1000L;
|
||||
if (lowClock > si.maxPixelClock)
|
||||
return B_ERROR;
|
||||
|
||||
*low = lowClock;
|
||||
}
|
||||
|
||||
if (high != NULL) {
|
||||
// In clock doubled mode for 3DFX chips, widths must be divisible by 16
|
||||
// instead of 8. If width is not divisible by 16, limit pixel clock to
|
||||
// half of max pixel clock since divisor is 8 if pixel clock is < half
|
||||
// max pixel clock.
|
||||
|
||||
if ((mode->timing.h_display % 16) != 0)
|
||||
*high = si.maxPixelClock / 2;
|
||||
else
|
||||
*high = si.maxPixelClock;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
GetEdidInfo(void* info, size_t size, uint32* _version)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if ( ! si.bHaveEDID)
|
||||
return B_ERROR;
|
||||
|
||||
if (size < sizeof(struct edid1_info))
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
memcpy(info, &si.edidInfo, sizeof(struct edid1_info));
|
||||
*_version = EDID_VERSION_1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
#endif // __HAIKU__
|
318
src/add-ons/accelerants/3dfx/overlay.cpp
Normal file
318
src/add-ons/accelerants/3dfx/overlay.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "3dfx.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
OverlayCount(const display_mode *mode)
|
||||
{
|
||||
(void)mode; // avoid compiler warning for unused arg
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
const uint32*
|
||||
OverlaySupportedSpaces(const display_mode* mode)
|
||||
{
|
||||
(void)mode; // avoid compiler warning for unused arg
|
||||
|
||||
static const uint32 kSupportedSpaces[] = {B_RGB16, B_YCbCr422, 0};
|
||||
|
||||
return kSupportedSpaces;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
OverlaySupportedFeatures(uint32 colorSpace)
|
||||
{
|
||||
(void)colorSpace; // avoid compiler warning for unused arg
|
||||
|
||||
return B_OVERLAY_COLOR_KEY
|
||||
| B_OVERLAY_HORIZONTAL_FILTERING
|
||||
| B_OVERLAY_VERTICAL_FILTERING;
|
||||
}
|
||||
|
||||
|
||||
const overlay_buffer*
|
||||
AllocateOverlayBuffer(color_space colorSpace, uint16 width, uint16 height)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n",
|
||||
width, height, colorSpace);
|
||||
|
||||
si.overlayLock.Acquire();
|
||||
|
||||
// Note: When allocating buffers, buffer allocation starts at the end of
|
||||
// video memory, and works backward to the end of the video frame buffer.
|
||||
// The allocated buffers are recorded in a linked list of OverlayBuffer
|
||||
// objects which are ordered by the buffer address with the first object
|
||||
// in the list having the highest buffer address.
|
||||
|
||||
uint32 bytesPerPixel;
|
||||
|
||||
switch (colorSpace) {
|
||||
case B_YCbCr422:
|
||||
case B_RGB16:
|
||||
bytesPerPixel = 2;
|
||||
break;
|
||||
default:
|
||||
si.overlayLock.Release();
|
||||
TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
|
||||
colorSpace);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Calculate required buffer size as a multiple of 1K.
|
||||
uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
|
||||
|
||||
// If the buffer area starts at the end of the video memory, the Voodoo5
|
||||
// chip has the following display problems: displays a pink/red band at
|
||||
// the bottom of the overlay display, leaves some artifacts at the top of
|
||||
// screen, and messes up the displayed cursor when a hardware cursor is
|
||||
// used (cursor image is at beginning of video memory). I don't know
|
||||
// whether the Voodoo5 goes beyond the buffer area or whether this is some
|
||||
// sort of memory mapping problem; nevertheless, adding 4k or 8K to the
|
||||
// buffer size solves the problem. Thus, 16K is added to the buffer size.
|
||||
|
||||
if (si.chipType == VOODOO_5)
|
||||
buffSize += 16 * 1024;
|
||||
|
||||
OverlayBuffer* ovBuff = si.overlayBuffer;
|
||||
OverlayBuffer* prevOvBuff = NULL;
|
||||
|
||||
// If no buffers have been allocated, prevBuffAddr calculated here will be
|
||||
// the address where the buffer area will start.
|
||||
|
||||
uint32 prevBuffAddr = si.videoMemAddr + si.frameBufferOffset
|
||||
+ si.maxFrameBufferSize;
|
||||
|
||||
while (ovBuff != NULL) {
|
||||
// Test if there is sufficient space between the end of the current
|
||||
// buffer and the start of the previous buffer to allocate the new
|
||||
// buffer.
|
||||
|
||||
uint32 currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
|
||||
if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
|
||||
break; // sufficient space for the new buffer
|
||||
|
||||
prevBuffAddr = (uint32)ovBuff->buffer;
|
||||
prevOvBuff = ovBuff;
|
||||
ovBuff = ovBuff->nextBuffer;
|
||||
}
|
||||
|
||||
OverlayBuffer* nextOvBuff = ovBuff;
|
||||
|
||||
if (ovBuff == NULL) {
|
||||
// No space between any current buffers of the required size was found;
|
||||
// thus space must be allocated between the last buffer and the end of
|
||||
// the video frame buffer. Compute where current video frame buffer
|
||||
// ends so that it can be determined if there is sufficient space for
|
||||
// the new buffer to be created.
|
||||
|
||||
uint32 fbEndAddr = si.videoMemAddr + si.frameBufferOffset
|
||||
+ (si.displayMode.virtual_width * si.displayMode.bytesPerPixel
|
||||
* si.displayMode.virtual_height);
|
||||
|
||||
if (buffSize > prevBuffAddr - fbEndAddr) {
|
||||
si.overlayLock.Release();
|
||||
TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) "
|
||||
"byte buffer\n", buffSize, buffSize);
|
||||
return NULL; // insufficient space for buffer
|
||||
}
|
||||
|
||||
nextOvBuff = NULL;
|
||||
}
|
||||
|
||||
ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
|
||||
if (ovBuff == NULL) {
|
||||
si.overlayLock.Release();
|
||||
return NULL; // memory not available for OverlayBuffer struct
|
||||
}
|
||||
|
||||
ovBuff->nextBuffer = nextOvBuff;
|
||||
ovBuff->size = buffSize;
|
||||
ovBuff->space = colorSpace;
|
||||
ovBuff->width = width;
|
||||
ovBuff->height = height;
|
||||
ovBuff->bytes_per_row = width * bytesPerPixel;
|
||||
ovBuff->buffer = (void*)(prevBuffAddr - buffSize);
|
||||
ovBuff->buffer_dma = (void*)(si.videoMemPCI
|
||||
+ ((addr_t)ovBuff->buffer - si.videoMemAddr));
|
||||
|
||||
if (prevOvBuff == NULL)
|
||||
si.overlayBuffer = ovBuff;
|
||||
else
|
||||
prevOvBuff->nextBuffer = ovBuff;
|
||||
|
||||
si.overlayLock.Release();
|
||||
TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n",
|
||||
buffSize, buffSize, ovBuff->buffer);
|
||||
return ovBuff;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReleaseOverlayBuffer(const overlay_buffer* buffer)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("ReleaseOverlayBuffer() called\n");
|
||||
|
||||
if (buffer == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// Find the buffer to be released.
|
||||
|
||||
OverlayBuffer* ovBuff = si.overlayBuffer;
|
||||
OverlayBuffer* prevOvBuff = NULL;
|
||||
|
||||
while (ovBuff != NULL) {
|
||||
if (ovBuff->buffer == buffer->buffer) {
|
||||
// Buffer to be released has been found. Remove the OverlayBuffer
|
||||
// object from the chain of overlay buffers.
|
||||
|
||||
if (prevOvBuff == NULL)
|
||||
si.overlayBuffer = ovBuff->nextBuffer;
|
||||
else
|
||||
prevOvBuff->nextBuffer = ovBuff->nextBuffer;
|
||||
|
||||
free(ovBuff);
|
||||
TRACE("ReleaseOverlayBuffer() return OK\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
prevOvBuff = ovBuff;
|
||||
ovBuff = ovBuff->nextBuffer;
|
||||
}
|
||||
|
||||
return B_ERROR; // buffer to be released not found in chain of buffers
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
|
||||
overlay_constraints *constraints)
|
||||
{
|
||||
if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
|
||||
return B_ERROR;
|
||||
|
||||
// Position (values are in pixels)
|
||||
constraints->view.h_alignment = 0;
|
||||
constraints->view.v_alignment = 0;
|
||||
|
||||
switch (buffer->space) {
|
||||
case B_YCbCr422:
|
||||
case B_RGB16:
|
||||
constraints->view.width_alignment = 7;
|
||||
break;
|
||||
default:
|
||||
TRACE("GetOverlayConstraints() color space 0x%x out of range\n",
|
||||
buffer->space);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
constraints->view.height_alignment = 0;
|
||||
|
||||
//Size
|
||||
constraints->view.width.min = 4;
|
||||
constraints->view.height.min = 4;
|
||||
constraints->view.width.max = buffer->width;
|
||||
constraints->view.height.max = buffer->height;
|
||||
|
||||
// Scaler output restrictions
|
||||
constraints->window.h_alignment = 0;
|
||||
constraints->window.v_alignment = 0;
|
||||
constraints->window.width_alignment = 0;
|
||||
constraints->window.height_alignment = 0;
|
||||
constraints->window.width.min = 2;
|
||||
constraints->window.width.max = mode->virtual_width;
|
||||
constraints->window.height.min = 2;
|
||||
constraints->window.height.max = mode->virtual_height;
|
||||
|
||||
constraints->h_scale.min = 1.0;
|
||||
constraints->h_scale.max = 8.0;
|
||||
constraints->v_scale.min = 1.0;
|
||||
constraints->v_scale.max = 8.0;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
overlay_token
|
||||
AllocateOverlay(void)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("AllocateOverlay() called\n");
|
||||
|
||||
// There is only a single overlay channel; thus, check if it is already
|
||||
// allocated.
|
||||
|
||||
if( atomic_or(&si.overlayAllocated, 1) != 0) {
|
||||
TRACE("AllocateOverlay() overlay channel already in use\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("AllocateOverlay() Overlay allocated, overlayToken: %d\n",
|
||||
si.overlayToken);
|
||||
return (overlay_token)++si.overlayToken;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReleaseOverlay(overlay_token overlayToken)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("ReleaseOverlay() called\n");
|
||||
|
||||
if (overlayToken != (overlay_token)si.overlayToken)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
TDFX_StopOverlay();
|
||||
|
||||
atomic_and(&si.overlayAllocated, 0); // mark overlay as unallocated
|
||||
|
||||
TRACE("ReleaseOverlay() return OK\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConfigureOverlay (overlay_token overlayToken, const overlay_buffer* buffer,
|
||||
const overlay_window* window, const overlay_view* view)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (overlayToken != (overlay_token)si.overlayToken)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (buffer == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (window == NULL || view == NULL) {
|
||||
TDFX_StopOverlay();
|
||||
TRACE("ConfigureOverlay() hide only\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Program the overlay hardware.
|
||||
if (!TDFX_DisplayOverlay(window, buffer, view)) {
|
||||
TRACE("ConfigureOverlay(), call to TDFX_DisplayOverlay() returned error\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons accelerants 3dfx ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants ati ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants common ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants et6x00 ;
|
||||
|
9
src/add-ons/kernel/drivers/graphics/3dfx/Jamfile
Normal file
9
src/add-ons/kernel/drivers/graphics/3dfx/Jamfile
Normal file
@ -0,0 +1,9 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers graphics 3dfx ;
|
||||
|
||||
UsePrivateHeaders [ FDirName graphics 3dfx ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
UsePrivateHeaders graphics kernel ;
|
||||
|
||||
KernelAddon 3dfx :
|
||||
driver.cpp
|
||||
;
|
563
src/add-ons/kernel/drivers/graphics/3dfx/driver.cpp
Normal file
563
src/add-ons/kernel/drivers/graphics/3dfx/driver.cpp
Normal file
@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Copyright 2007-2010 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <PCI.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <graphic_driver.h>
|
||||
#ifdef __HAIKU__
|
||||
#include <boot_item.h>
|
||||
#include <arch/x86/vm86.h>
|
||||
#endif // __HAIKU__
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
|
||||
#undef TRACE
|
||||
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
# define TRACE(x...) dprintf("3dfx: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
#define ACCELERANT_NAME "3dfx.accelerant"
|
||||
|
||||
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
||||
|
||||
#define SKD_HANDLER_INSTALLED 0x80000000
|
||||
#define MAX_DEVICES 4
|
||||
#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X"
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support
|
||||
|
||||
#define VENDOR_ID 0x121A // 3DFX vendor ID
|
||||
|
||||
|
||||
struct ChipInfo {
|
||||
uint16 chipID; // PCI device id of the chip
|
||||
ChipType chipType; // assigned chip type identifier
|
||||
const char* chipName; // user recognizable name for chip (must be < 32 chars)
|
||||
};
|
||||
|
||||
|
||||
// This table maps a PCI device ID to a chip type identifier and the chip name.
|
||||
|
||||
static const ChipInfo chipTable[] = {
|
||||
{ 0x03, BANSHEE, "Banshee" },
|
||||
{ 0x05, VOODOO_3, "Voodoo 3" },
|
||||
{ 0x09, VOODOO_5, "Voodoo 5" },
|
||||
{ 0, TDFX_NONE, NULL }
|
||||
};
|
||||
|
||||
|
||||
struct DeviceInfo {
|
||||
uint32 openCount; // count of how many times device has been opened
|
||||
int32 flags;
|
||||
area_id sharedArea; // area shared between driver and all accelerants
|
||||
SharedInfo* sharedInfo; // pointer to shared info area memory
|
||||
vuint8* regs; // pointer to memory mapped registers
|
||||
const ChipInfo* pChipInfo; // info about the selected chip
|
||||
pci_info pciInfo; // copy of pci info for this device
|
||||
char name[B_OS_NAME_LENGTH]; // name of device
|
||||
};
|
||||
|
||||
|
||||
static Benaphore gLock;
|
||||
static DeviceInfo gDeviceInfo[MAX_DEVICES];
|
||||
static char* gDeviceNames[MAX_DEVICES + 1];
|
||||
static pci_module_info* gPCI;
|
||||
|
||||
|
||||
// Prototypes for device hook functions.
|
||||
|
||||
static status_t device_open(const char* name, uint32 flags, void** cookie);
|
||||
static status_t device_close(void* dev);
|
||||
static status_t device_free(void* dev);
|
||||
static status_t device_read(void* dev, off_t pos, void* buf, size_t* len);
|
||||
static status_t device_write(void* dev, off_t pos, const void* buf, size_t* len);
|
||||
static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len);
|
||||
|
||||
static device_hooks gDeviceHooks =
|
||||
{
|
||||
device_open,
|
||||
device_close,
|
||||
device_free,
|
||||
device_ioctl,
|
||||
device_read,
|
||||
device_write,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline uint32
|
||||
GetPCI(pci_info& info, uint8 offset, uint8 size)
|
||||
{
|
||||
return gPCI->read_pci_config(info.bus, info.device, info.function, offset, size);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
SetPCI(pci_info& info, uint8 offset, uint8 size, uint32 value)
|
||||
{
|
||||
gPCI->write_pci_config(info.bus, info.device, info.function, offset, size, value);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
MapDevice(DeviceInfo& di)
|
||||
{
|
||||
SharedInfo& si = *(di.sharedInfo);
|
||||
pci_info& pciInfo = di.pciInfo;
|
||||
|
||||
TRACE("enter MapDevice()\n");
|
||||
|
||||
// Enable memory mapped IO and bus master.
|
||||
|
||||
SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2)
|
||||
| PCI_command_io | PCI_command_memory | PCI_command_master);
|
||||
|
||||
// Map the video memory.
|
||||
|
||||
phys_addr_t videoRamAddr = pciInfo.u.h0.base_registers[1];
|
||||
uint32 videoRamSize = pciInfo.u.h0.base_register_sizes[1];
|
||||
si.videoMemPCI = videoRamAddr;
|
||||
char frameBufferAreaName[] = "3DFX frame buffer";
|
||||
|
||||
si.videoMemArea = map_physical_memory(
|
||||
frameBufferAreaName,
|
||||
videoRamAddr,
|
||||
videoRamSize,
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
(void**)&si.videoMemAddr);
|
||||
|
||||
TRACE("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si.videoMemArea, (uint32)(si.videoMemAddr), videoRamSize);
|
||||
|
||||
if (si.videoMemArea < 0) {
|
||||
// Try to map this time without write combining.
|
||||
si.videoMemArea = map_physical_memory(
|
||||
frameBufferAreaName,
|
||||
videoRamAddr,
|
||||
videoRamSize,
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
(void**)&si.videoMemAddr);
|
||||
}
|
||||
|
||||
if (si.videoMemArea < 0)
|
||||
return si.videoMemArea;
|
||||
|
||||
// Map the MMIO register area.
|
||||
|
||||
phys_addr_t regsBase = pciInfo.u.h0.base_registers[0];
|
||||
uint32 regAreaSize = pciInfo.u.h0.base_register_sizes[0];
|
||||
|
||||
si.regsArea = map_physical_memory("3DFX mmio registers",
|
||||
regsBase,
|
||||
regAreaSize,
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
0, // neither read nor write, to hide it from user space apps
|
||||
(void**)&di.regs);
|
||||
|
||||
// If there was an error, delete other areas.
|
||||
if (si.regsArea < 0) {
|
||||
delete_area(si.videoMemArea);
|
||||
si.videoMemArea = -1;
|
||||
}
|
||||
|
||||
TRACE("leave MapDevice(); result: %ld\n", si.regsArea);
|
||||
return si.regsArea;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
UnmapDevice(DeviceInfo& di)
|
||||
{
|
||||
SharedInfo& si = *(di.sharedInfo);
|
||||
|
||||
if (si.regsArea >= 0)
|
||||
delete_area(si.regsArea);
|
||||
if (si.videoMemArea >= 0)
|
||||
delete_area(si.videoMemArea);
|
||||
|
||||
si.regsArea = si.videoMemArea = -1;
|
||||
si.videoMemAddr = (addr_t)NULL;
|
||||
di.regs = NULL;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
InitDevice(DeviceInfo& di)
|
||||
{
|
||||
// Perform initialization and mapping of the device, and return B_OK if
|
||||
// sucessful; else, return error code.
|
||||
|
||||
// Create the area for shared info with NO user-space read or write
|
||||
// permissions, to prevent accidental damage.
|
||||
|
||||
TRACE("enter InitDevice()\n");
|
||||
|
||||
size_t sharedSize = (sizeof(SharedInfo) + 7) & ~7;
|
||||
|
||||
di.sharedArea = create_area("3DFX shared info",
|
||||
(void**) &(di.sharedInfo),
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
ROUND_TO_PAGE_SIZE(sharedSize),
|
||||
B_FULL_LOCK, 0);
|
||||
if (di.sharedArea < 0)
|
||||
return di.sharedArea; // return error code
|
||||
|
||||
SharedInfo& si = *(di.sharedInfo);
|
||||
|
||||
memset(&si, 0, sharedSize);
|
||||
|
||||
pci_info& pciInfo = di.pciInfo;
|
||||
|
||||
si.vendorID = pciInfo.vendor_id;
|
||||
si.deviceID = pciInfo.device_id;
|
||||
si.revision = pciInfo.revision;
|
||||
si.chipType = di.pChipInfo->chipType;
|
||||
strcpy(si.chipName, di.pChipInfo->chipName);
|
||||
|
||||
status_t status = MapDevice(di);
|
||||
if (status < 0) {
|
||||
delete_area(di.sharedArea);
|
||||
di.sharedArea = -1;
|
||||
di.sharedInfo = NULL;
|
||||
return status; // return error code
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static const ChipInfo*
|
||||
GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo)
|
||||
{
|
||||
// Search the PCI devices for a device that is supported by this driver.
|
||||
// The search starts at the device specified by argument pciIndex, and
|
||||
// continues until a supported device is found or there are no more devices
|
||||
// to examine. Argument pciIndex is incremented after each device is
|
||||
// examined.
|
||||
|
||||
// If a supported device is found, return a pointer to the struct containing
|
||||
// the chip info; else return NULL.
|
||||
|
||||
while (gPCI->get_nth_pci_info(pciIndex, &pciInfo) == B_OK) {
|
||||
|
||||
if (pciInfo.vendor_id == VENDOR_ID) {
|
||||
|
||||
// Search the table of supported devices to find a chip/device that
|
||||
// matches device ID of the current PCI device.
|
||||
|
||||
const ChipInfo* pDevice = chipTable;
|
||||
|
||||
while (pDevice->chipID != 0) { // end of table?
|
||||
if (pDevice->chipID == pciInfo.device_id)
|
||||
return pDevice; // matching device/chip found
|
||||
|
||||
pDevice++;
|
||||
}
|
||||
}
|
||||
|
||||
pciIndex++;
|
||||
}
|
||||
|
||||
return NULL; // no supported device found
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - Kernel Interface
|
||||
|
||||
|
||||
status_t
|
||||
init_hardware(void)
|
||||
{
|
||||
// Return B_OK if a device supported by this driver is found; otherwise,
|
||||
// return B_ERROR so the driver will be unloaded.
|
||||
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK)
|
||||
return B_ERROR; // unable to access PCI bus
|
||||
|
||||
// Check pci devices for a device supported by this driver.
|
||||
|
||||
uint32 pciIndex = 0;
|
||||
pci_info pciInfo;
|
||||
const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, pciInfo);
|
||||
|
||||
TRACE("init_hardware() - %s\n", pDevice == NULL ? "no supported devices" : "device supported");
|
||||
|
||||
put_module(B_PCI_MODULE_NAME); // put away the module manager
|
||||
|
||||
return (pDevice == NULL ? B_ERROR : B_OK);
|
||||
}
|
||||
|
||||
|
||||
status_t init_driver(void)
|
||||
{
|
||||
// Get handle for the pci bus.
|
||||
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
status_t status = gLock.Init("3DFX driver lock");
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// Get info about all the devices supported by this driver.
|
||||
|
||||
uint32 pciIndex = 0;
|
||||
uint32 count = 0;
|
||||
|
||||
while (count < MAX_DEVICES) {
|
||||
DeviceInfo& di = gDeviceInfo[count];
|
||||
|
||||
const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, di.pciInfo);
|
||||
if (pDevice == NULL)
|
||||
break; // all supported devices have been obtained
|
||||
|
||||
// Compose device name.
|
||||
sprintf(di.name, "graphics/" DEVICE_FORMAT,
|
||||
di.pciInfo.vendor_id, di.pciInfo.device_id,
|
||||
di.pciInfo.bus, di.pciInfo.device, di.pciInfo.function);
|
||||
TRACE("init_driver() match found; name: %s\n", di.name);
|
||||
|
||||
gDeviceNames[count] = di.name;
|
||||
di.openCount = 0; // mark driver as available for R/W open
|
||||
di.sharedArea = -1; // indicate shared area not yet created
|
||||
di.sharedInfo = NULL;
|
||||
di.pChipInfo = pDevice;
|
||||
count++;
|
||||
pciIndex++;
|
||||
}
|
||||
|
||||
gDeviceNames[count] = NULL; // terminate list with null pointer
|
||||
|
||||
TRACE("init_driver() %ld supported devices\n", count);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
// Free the driver data.
|
||||
|
||||
gLock.Delete();
|
||||
put_module(B_PCI_MODULE_NAME); // put the pci module away
|
||||
}
|
||||
|
||||
|
||||
const char**
|
||||
publish_devices(void)
|
||||
{
|
||||
return (const char**)gDeviceNames; // return list of supported devices
|
||||
}
|
||||
|
||||
|
||||
device_hooks*
|
||||
find_device(const char* name)
|
||||
{
|
||||
int i = 0;
|
||||
while (gDeviceNames[i] != NULL) {
|
||||
if (strcmp(name, gDeviceNames[i]) == 0)
|
||||
return &gDeviceHooks;
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - Device Hooks
|
||||
|
||||
|
||||
static status_t
|
||||
device_open(const char* name, uint32 /*flags*/, void** cookie)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
TRACE("device_open() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie);
|
||||
|
||||
// Find the device name in the list of devices.
|
||||
|
||||
int32 i = 0;
|
||||
while (gDeviceNames[i] != NULL && (strcmp(name, gDeviceNames[i]) != 0))
|
||||
i++;
|
||||
|
||||
if (gDeviceNames[i] == NULL)
|
||||
return B_BAD_VALUE; // device name not found in list of devices
|
||||
|
||||
DeviceInfo& di = gDeviceInfo[i];
|
||||
|
||||
gLock.Acquire(); // make sure no one else has write access to common data
|
||||
|
||||
if (di.openCount == 0)
|
||||
status = InitDevice(di);
|
||||
|
||||
gLock.Release();
|
||||
|
||||
if (status == B_OK) {
|
||||
di.openCount++; // mark device open
|
||||
*cookie = &di; // send cookie to opener
|
||||
}
|
||||
|
||||
TRACE("device_open() returning 0x%lx, open count: %ld\n", status, di.openCount);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_read(void* dev, off_t pos, void* buf, size_t* len)
|
||||
{
|
||||
// Following 3 lines of code are here to eliminate "unused parameter" warnings.
|
||||
(void)dev;
|
||||
(void)pos;
|
||||
(void)buf;
|
||||
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_write(void* dev, off_t pos, const void* buf, size_t* len)
|
||||
{
|
||||
// Following 3 lines of code are here to eliminate "unused parameter" warnings.
|
||||
(void)dev;
|
||||
(void)pos;
|
||||
(void)buf;
|
||||
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_close(void* dev)
|
||||
{
|
||||
(void)dev; // avoid compiler warning for unused arg
|
||||
|
||||
TRACE("device_close()\n");
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_free(void* dev)
|
||||
{
|
||||
DeviceInfo& di = *((DeviceInfo*)dev);
|
||||
|
||||
TRACE("enter device_free()\n");
|
||||
|
||||
gLock.Acquire(); // lock driver
|
||||
|
||||
// If opened multiple times, merely decrement the open count and exit.
|
||||
|
||||
if (di.openCount <= 1) {
|
||||
UnmapDevice(di); // free regs and frame buffer areas
|
||||
|
||||
delete_area(di.sharedArea);
|
||||
di.sharedArea = -1;
|
||||
di.sharedInfo = NULL;
|
||||
}
|
||||
|
||||
if (di.openCount > 0)
|
||||
di.openCount--; // mark device available
|
||||
|
||||
gLock.Release(); // unlock driver
|
||||
|
||||
TRACE("exit device_free() openCount: %ld\n", di.openCount);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_ioctl(void* dev, uint32 msg, void* buffer, size_t bufferLength)
|
||||
{
|
||||
DeviceInfo& di = *((DeviceInfo*)dev);
|
||||
|
||||
#ifndef __HAIKU__
|
||||
(void)bufferLength; // avoid compiler warning for unused arg
|
||||
#endif
|
||||
|
||||
switch (msg) {
|
||||
case B_GET_ACCELERANT_SIGNATURE:
|
||||
strcpy((char*)buffer, ACCELERANT_NAME);
|
||||
return B_OK;
|
||||
|
||||
case TDFX_DEVICE_NAME:
|
||||
strncpy((char*)buffer, di.name, B_OS_NAME_LENGTH);
|
||||
((char*)buffer)[B_OS_NAME_LENGTH -1] = '\0';
|
||||
return B_OK;
|
||||
|
||||
case TDFX_GET_SHARED_DATA:
|
||||
#ifdef __HAIKU__
|
||||
if (bufferLength != sizeof(area_id))
|
||||
return B_BAD_DATA;
|
||||
#endif
|
||||
|
||||
*((area_id*)buffer) = di.sharedArea;
|
||||
return B_OK;
|
||||
|
||||
case TDFX_GET_PIO_REG:
|
||||
{
|
||||
#ifdef __HAIKU__
|
||||
if (bufferLength != sizeof(PIORegInfo))
|
||||
return B_BAD_DATA;
|
||||
#endif
|
||||
|
||||
PIORegInfo* regInfo = (PIORegInfo*)buffer;
|
||||
if (regInfo->magic == TDFX_PRIVATE_DATA_MAGIC) {
|
||||
int ioAddr = di.pciInfo.u.h0.base_registers[2] + regInfo->offset;
|
||||
if (regInfo->index >= 0) {
|
||||
gPCI->write_io_8(ioAddr, regInfo->index);
|
||||
regInfo->value = gPCI->read_io_8(ioAddr + 1);
|
||||
} else {
|
||||
regInfo->value = gPCI->read_io_8(ioAddr);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TDFX_SET_PIO_REG:
|
||||
{
|
||||
#ifdef __HAIKU__
|
||||
if (bufferLength != sizeof(PIORegInfo))
|
||||
return B_BAD_DATA;
|
||||
#endif
|
||||
|
||||
PIORegInfo* regInfo = (PIORegInfo*)buffer;
|
||||
if (regInfo->magic == TDFX_PRIVATE_DATA_MAGIC) {
|
||||
int ioAddr = di.pciInfo.u.h0.base_registers[2] + regInfo->offset;
|
||||
if (regInfo->index >= 0) {
|
||||
gPCI->write_io_8(ioAddr, regInfo->index);
|
||||
gPCI->write_io_8(ioAddr + 1, regInfo->value);
|
||||
} else {
|
||||
gPCI->write_io_8(ioAddr, regInfo->value);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return B_DEV_INVALID_IOCTL;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers graphics ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics 3dfx ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics ati ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics common ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics et6x00 ;
|
||||
@ -11,8 +12,8 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia_gpgpu ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon_hd ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics tdfx ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics tdfx ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vesa ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics via ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vmware ;
|
||||
|
Loading…
Reference in New Issue
Block a user