* Replaced the old s3savage driver with the new s3 driver, both written by

Gerald Zajac. Thanks a lot!
* Also put it on the image by default.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25583 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-05-20 21:09:49 +00:00
parent a8af2b6dda
commit 35db13ea5a
55 changed files with 7052 additions and 5124 deletions

View File

@ -83,7 +83,7 @@ BEOS_NETWORK_PROTOCOLS = ipv4 tcp udp icmp unix ;
BEOS_ADD_ONS_ACCELERANTS = $(X86_ONLY)radeon.accelerant $(X86_ONLY)nvidia.accelerant
$(X86_ONLY)matrox.accelerant $(X86_ONLY)neomagic.accelerant
$(X86_ONLY)intel_extreme.accelerant $(X86_ONLY)s3savage.accelerant vesa.accelerant
$(X86_ONLY)intel_extreme.accelerant $(X86_ONLY)s3.accelerant vesa.accelerant
#$(X86_ONLY)via.accelerant
#$(X86_ONLY)vmware.accelerant
;
@ -122,7 +122,7 @@ BEOS_ADD_ONS_SCREENSAVERS = Haiku IFS Spider ;
BEOS_ADD_ONS_DRIVERS_AUDIO = auich auvia emuxki ; #hda
BEOS_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon $(X86_ONLY)nvidia
$(X86_ONLY)neomagic $(X86_ONLY)matrox $(X86_ONLY)intel_extreme
$(X86_ONLY)s3savage vesa #$(X86_ONLY)via #$(X86_ONLY)vmware
$(X86_ONLY)s3 vesa #$(X86_ONLY)via #$(X86_ONLY)vmware
;
BEOS_ADD_ONS_DRIVERS_MIDI = emuxki ;
BEOS_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com etherpci $(X86_ONLY)ipro1000

View File

@ -0,0 +1,238 @@
/*
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Other authors:
Gerald Zajac 2007-2008
*/
#ifndef DRIVERINTERFACE_H
#define DRIVERINTERFACE_H
#include <Accelerant.h>
#include <GraphicsDefs.h>
#include <Drivers.h>
#include <edid.h>
// This is the info that needs to be shared between the kernel driver and
// the accelerant for the sample driver.
#if defined(__cplusplus)
extern "C" {
#endif
#define ENABLE_DEBUG_TRACE // if defined, turns on debug output to syslog
#define NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array
struct benaphore {
sem_id sem;
int32 ben;
};
#define INIT_BEN(x) x.sem = create_sem(0, "S3 "#x" benaphore"); x.ben = 0;
#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem);
#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem);
#define DELETE_BEN(x) delete_sem(x.sem);
#define S3_PRIVATE_DATA_MAGIC 0x4521 // a private driver rev, of sorts
enum {
S3_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
S3_DEVICE_NAME,
S3_GET_PIO,
S3_SET_PIO,
S3_RUN_INTERRUPTS,
};
// Chip type numbers. These are used to group the chips into related
// groups. See table S3_ChipTable in driver.c
enum S3_ChipType {
S3_TRIO64 = 1,
S3_TRIO64_VP, // Trio64V+ has same ID as Trio64 but different revision number
S3_TRIO64_UVP,
S3_TRIO64_V2,
Trio64ChipsEnd,
S3_VIRGE,
S3_VIRGE_VX,
S3_VIRGE_DXGX,
S3_VIRGE_GX2,
S3_VIRGE_MX,
S3_VIRGE_MXP,
S3_TRIO_3D,
S3_TRIO_3D_2X,
VirgeChipsEnd,
S3_SAVAGE_3D,
S3_SAVAGE_MX,
S3_SAVAGE4,
S3_PROSAVAGE,
S3_TWISTER,
S3_PROSAVAGE_DDR,
S3_SUPERSAVAGE,
S3_SAVAGE2000,
};
#define S3_TRIO64_FAMILY(chip) (chip < Trio64ChipsEnd)
#define S3_VIRGE_FAMILY(chip) (chip > Trio64ChipsEnd && chip < VirgeChipsEnd)
#define S3_SAVAGE_FAMILY(chip) (chip > VirgeChipsEnd)
#define S3_VIRGE_GX2_SERIES(chip) (chip == S3_VIRGE_GX2 || chip == S3_TRIO_3D_2X)
#define S3_VIRGE_MX_SERIES(chip) (chip == S3_VIRGE_MX || chip == S3_VIRGE_MXP)
#define S3_SAVAGE_3D_SERIES(chip) ((chip == S3_SAVAGE_3D) || (chip == S3_SAVAGE_MX))
#define S3_SAVAGE4_SERIES(chip) ((chip == S3_SAVAGE4) \
|| (chip == S3_PROSAVAGE) \
|| (chip == S3_TWISTER) \
|| (chip == S3_PROSAVAGE_DDR))
#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip == S3_SAVAGE_MX) \
|| (chip == S3_SUPERSAVAGE))
#define S3_MOBILE_TWISTER_SERIES(chip) ((chip == S3_TWISTER) \
|| (chip == S3_PROSAVAGE_DDR))
enum MonitorType {
MT_CRT,
MT_LCD, // laptop LCD display
MT_DFP // DVI display
};
// Bitmap descriptor structures for BCI (for Savage chips)
struct HIGH {
unsigned short Stride;
unsigned char Bpp;
unsigned char ResBWTile;
};
struct BMPDESC1 {
unsigned long Offset;
HIGH HighPart;
};
struct BMPDESC2 {
unsigned long LoPart;
unsigned long HiPart;
};
union BMPDESC {
BMPDESC1 bd1;
BMPDESC2 bd2;
};
struct DisplayModeEx : display_mode {
uint32 bpp; // bits/pixel
uint32 bytesPerRow; // number of bytes in one line/row
};
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
uint32 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
bool bInterruptAssigned; // card has a useable interrupt assigned to it
sem_id vertBlankSem; // vertical blank semaphore; if < 0, there is no semaphore
// 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.
void* videoMemAddr; // video memory addr as viewed from virtual memory
void* 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
// 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
// Cursor info.
struct {
uint16 hot_x; // Cursor hot spot. Top left corner of the cursor
uint16 hot_y; // is 0,0
} cursor;
// Current display mode configuration, and other parameters related to
// current display mode.
DisplayModeEx displayMode; // current display mode configuration
int32 commonCmd; // flags common to drawing commands of current display mode
edid1_info edidInfo;
bool bHaveEDID; // true = EDID info from device is in edidInfo
// Acceleration engine.
struct {
uint64 count; // last fifo slot used
uint64 lastIdle; // last fifo slot we *know* the engine was idle after
benaphore lock; // for serializing access to the acceleration engine
} engine;
int mclk;
MonitorType displayType;
uint16 panelX; // laptop LCD width
uint16 panelY; // laptop LCD height
// Command Overflow Buffer (COB) parameters for Savage chips.
bool bDisableCOB; // enable/disable COB for Savage 4 & ProSavage
uint32 cobIndex; // size index
uint32 cobSize; // size in bytes
uint32 cobOffset; // offset in video memory
uint32 bciThresholdLo; // low and high thresholds for
uint32 bciThresholdHi; // shadow status update (32bit words)
BMPDESC GlobalBD; // Bitmap Descriptor for BCI
};
// Set some boolean condition (like enabling or disabling interrupts)
struct S3SetBoolState {
uint32 magic; // magic number to make sure the caller groks us
bool bEnable; // state to set
};
// Retrieve the area_id of the kernel/accelerant shared info
struct S3GetPrivateData {
uint32 magic; // magic number to make sure the caller groks us
area_id sharedInfoArea; // ID of area containing shared information
};
struct S3GetSetPIO {
uint32 magic; // magic number to make sure the caller groks us
uint32 offset; // offset of PIO register to read/write
uint32 size; // number of bytes to transfer
uint32 value; // value to write or value that was read
};
#if defined(__cplusplus)
}
#endif
#endif // DRIVERINTERFACE_H

View File

@ -1,236 +0,0 @@
/*
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 2006-2007
*/
#ifndef DRIVERINTERFACE_H
#define DRIVERINTERFACE_H
#include <Accelerant.h>
#include <GraphicsDefs.h>
#include <Drivers.h>
#include <PCI.h>
#include <OS.h>
/*
This is the info that needs to be shared between the kernel driver and
the accelerant for the sample driver.
*/
#if defined(__cplusplus)
extern "C" {
#endif
#if 1 /* DEBUG */
# define TRACE_S3SAVAGE
// turns on debug output
#endif
#define NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array
typedef struct {
sem_id sem;
int32 ben;
} benaphore;
#define INIT_BEN(x) x.sem = create_sem(0, "SAVAGE "#x" benaphore"); x.ben = 0;
#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem);
#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem);
#define DELETE_BEN(x) delete_sem(x.sem);
#define SAVAGE_PRIVATE_DATA_MAGIC 0x5791 // a private driver rev, of sorts
enum {
SAVAGE_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
SAVAGE_GET_PCI,
SAVAGE_SET_PCI,
SAVAGE_DEVICE_NAME,
SAVAGE_RUN_INTERRUPTS,
};
// Chip tags. These are used to group the adapters into related
// families. See table SavageChipsetTable in driver.c
enum S3ChipTags {
S3_UNKNOWN = 0,
S3_SAVAGE3D,
S3_SAVAGE_MX,
S3_SAVAGE4,
S3_PROSAVAGE,
S3_TWISTER,
S3_PROSAVAGEDDR,
S3_SUPERSAVAGE,
S3_SAVAGE2000,
};
#define S3_SAVAGE3D_SERIES(chip) ((chip==S3_SAVAGE3D) || (chip==S3_SAVAGE_MX))
#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) \
|| (chip==S3_PROSAVAGE) \
|| (chip==S3_TWISTER) \
|| (chip==S3_PROSAVAGEDDR))
#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip==S3_PROSAVAGEDDR))
typedef enum {
MT_NONE,
MT_CRT,
MT_LCD,
MT_DFP,
MT_TV
} SavageMonitorType;
// Bitmap descriptor structures for BCI
typedef struct _HIGH {
unsigned short Stride;
unsigned char Bpp;
unsigned char ResBWTile;
} HIGH;
typedef struct _BMPDESC1 {
unsigned long Offset;
HIGH HighPart;
} BMPDESC1;
typedef struct _BMPDESC2 {
unsigned long LoPart;
unsigned long HiPart;
} BMPDESC2;
typedef union _BMPDESC {
BMPDESC1 bd1;
BMPDESC2 bd2;
} BMPDESC;
typedef struct {
// 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
uint32 chipset; // indicates family in which chipset belongs (a family has similar functionality)
char chipsetName[32]; // user recognizable name of chipset
bool bAccelerantInUse; // true = accelerant has been initialized
bool bInterruptAssigned; // card has a useable interrupt assigned to it
// 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.
void* videoMemAddr; // video memory addr as viewed from virtual memory
void* 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
// List of screen modes.
area_id modeArea; // Contains the list of display modes the driver supports
uint32 modeCount; // Number of display modes in the list
// Vertical blank semaphore.
sem_id vblank; // vertical blank semaphore; if < 0, there is no semaphore
// Ownership will be transfered to team opening device first
// Flags used by driver.
int32 flags;
// Cursor info.
struct {
uint16 hot_x; // Cursor hot spot. The top left corner of the cursor
uint16 hot_y; // is 0,0
uint16 x; // The location of the cursor hot spot on the
uint16 y; // display (or desktop?)
uint16 width; // Width and height of the cursor shape
uint16 height;
bool bIsVisible; // Is the cursor currently displayed?
} cursor;
display_mode dm; // current display mode configuration
int bitsPerPixel; // bits per pixel of current display mode
frame_buffer_config fbc; // frame buffer addresses and bytes_per_row
// Acceleration engine.
struct {
uint64 count; // last fifo slot used
uint64 lastIdle; // last fifo slot we *know* the engine was idle after
benaphore lock; // for serializing access to the acceleration engine
} engine;
int mclk;
uint32 pix_clk_max8; // The maximum speed the pixel clock should run
uint32 pix_clk_max16; // at for a given pixel width. Usually a function
uint32 pix_clk_max32; // of memory and DAC bandwidths.
// Command Overflow Buffer (COB) parameters.
bool bDisableCOB; // enable/disable COB for Savage 4 & ProSavage
uint32 cobIndex; // size index
uint32 cobSize; // size in bytes
uint32 cobOffset; // offset in video memory
uint32 bciThresholdLo; // low and high thresholds for
uint32 bciThresholdHi; // shadow status update (32bit words)
BMPDESC GlobalBD; // Bitmap Descriptor for BCI
int panelX; // LCD panel width
int panelY; // LCD panel height
int frameX0; // viewport position
int frameY0;
// The various Savage wait handlers.
bool (*WaitQueue)(int);
bool (*WaitIdleEmpty)();
SavageMonitorType displayType;
} SharedInfo;
// Read or write a value in PCI configuration space
typedef struct {
uint32 magic; // magic number to make sure the caller groks us
uint32 offset; // Offset to read/write
uint32 size; // Number of bytes to transfer
uint32 value; // The value read or written
} SavageGetSetPci;
// Set some boolean condition (like enabling or disabling interrupts)
typedef struct {
uint32 magic; // magic number to make sure the caller groks us
bool bEnable; // state to set
} SavageSetBoolState;
// Retrieve the area_id of the kernel/accelerant shared info
typedef struct {
uint32 magic; // magic number to make sure the caller groks us
area_id sharedInfoArea; // ID of area containing shared information
} SavageGetPrivateData;
// Retrieve the device name. Usefull for when we have a file handle, but want
// to know the device name (like when we are cloning the accelerant)
typedef struct {
uint32 magic; // magic number to make sure the caller groks us
char *name; // The name of the device, less the /dev root
} SavageDeviceName;
#if defined(__cplusplus)
}
#endif
#endif /* DRIVERINTERFACE_H */

View File

@ -7,7 +7,7 @@ SubInclude HAIKU_TOP src add-ons accelerants matrox ;
SubInclude HAIKU_TOP src add-ons accelerants neomagic ;
SubInclude HAIKU_TOP src add-ons accelerants nvidia ;
SubInclude HAIKU_TOP src add-ons accelerants radeon ;
SubInclude HAIKU_TOP src add-ons accelerants s3savage ;
SubInclude HAIKU_TOP src add-ons accelerants s3 ;
SubInclude HAIKU_TOP src add-ons accelerants tdfx ;
SubInclude HAIKU_TOP src add-ons accelerants vesa ;
SubInclude HAIKU_TOP src add-ons accelerants via ;

View File

@ -0,0 +1,43 @@
SubDir HAIKU_TOP src add-ons accelerants s3 ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics s3 ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
Addon s3.accelerant :
accel.cpp
cursor.cpp
engine.cpp
hooks.cpp
mode.cpp
register_io.cpp
savage_cursor.cpp
savage_dpms.cpp
savage_draw.cpp
savage_edid.cpp
savage_init.cpp
savage_mode.cpp
trio64_cursor.cpp
trio64_dpms.cpp
trio64_draw.cpp
trio64_init.cpp
trio64_mode.cpp
virge_cursor.cpp
virge_dpms.cpp
virge_draw.cpp
virge_edid.cpp
virge_init.cpp
virge_mode.cpp
: be libaccelerantscommon.a
;
Package haiku-s3-cvs :
s3.accelerant :
boot home config add-ons accelerants ;

View File

@ -0,0 +1,217 @@
/*
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.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 pointer to registers and shared data from driver.
S3GetPrivateData gpd;
gpd.magic = S3_PRIVATE_DATA_MAGIC;
status_t result = ioctl(gInfo.deviceFileDesc, S3_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK)
return result;
gInfo.sharedInfoArea = clone_area("S3 shared info", (void**)&(gInfo.sharedInfo),
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gpd.sharedInfoArea);
if (gInfo.sharedInfoArea < 0)
return gInfo.sharedInfoArea; // sharedInfoArea has error code
gInfo.regsArea = clone_area("S3 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
}
// Set pointers to various device specific functions.
if (S3_SAVAGE_FAMILY(gInfo.sharedInfo->chipType))
Savage_SetFunctionPointers();
else if (S3_TRIO64_FAMILY(gInfo.sharedInfo->chipType))
Trio64_SetFunctionPointers();
else if (S3_VIRGE_FAMILY(gInfo.sharedInfo->chipType))
Virge_SetFunctionPointers();
else
return B_ERROR; // undefined chip type 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 = gInfo.ChipInit(); // perform init related to current chip
if (result == B_OK) {
INIT_BEN(si.engine.lock);
si.engine.lastIdle = 0;
si.engine.count = 0;
gInfo.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, S3_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("S3 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);
}
sem_id
AccelerantRetraceSemaphore(void)
{
// Return the semaphore id that will be used to signal that a vertical
// retrace occured.
return B_ERROR;
}
status_t
GetAccelerantDeviceInfo(accelerant_device_info* adi)
{
// Get info about the device.
SharedInfo& si = *gInfo.sharedInfo;
adi->version = 1;
strcpy(adi->name, "S3 chipset");
strcpy(adi->chipset, si.chipName);
strcpy(adi->serial_no, "unknown");
adi->memory = si.maxFrameBufferSize;
adi->dac_speed = 270;
return B_OK;
}

View File

@ -0,0 +1,202 @@
/*
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#ifndef _ACCEL_H
#define _ACCEL_H
#include "DriverInterface.h"
#include "register_io.h"
#if defined(__cplusplus)
extern "C" {
#endif
#undef TRACE
#ifdef ENABLE_DEBUG_TRACE
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x...) _sPrintf("S3: " x)
#else
# define TRACE(x...) ;
#endif
// 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
// Pointers to wait handlers.
void (*WaitQueue)(uint32);
void (*WaitIdleEmpty)();
// Pointers to DPMS functions.
uint32 (*DPMSCapabilities)(void);
uint32 (*DPMSMode)(void);
status_t (*SetDPMSMode)(uint32 dpms_flags);
// Pointers to cursor functions.
bool (*LoadCursorImage)(int width, int height, uint8* and_mask, uint8* xor_mask);
void (*SetCursorPosition)(int x, int y);
void (*ShowCursor)(bool bShow);
// Pointers to 2D acceleration functions.
void (*FillRectangle)(engine_token*, uint32 color, fill_rect_params*, uint32 count);
void (*FillSpan)(engine_token*, uint32 color, uint16* list, uint32 count);
void (*InvertRectangle)(engine_token*, fill_rect_params*, uint32 count);
void (*ScreenToScreenBlit)(engine_token*, blit_params*, uint32 count);
// Pointers to other functions.
void (*AdjustFrame)(const DisplayModeEx& mode);
status_t (*ChipInit)(void);
bool (*GetColorSpaceParams)(int colorSpace, uint32& bpp, uint32& maxPixelClk);
bool (*SetDisplayMode)(const DisplayModeEx& mode);
void (*SetIndexedColors)(uint count, uint8 first, uint8* color_data, uint32 flags);
};
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.
//================================================================
// 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);
sem_id AccelerantRetraceSemaphore(void);
// 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);
status_t GetTimingConstraints(display_timing_constraints* dtc);
void Savage_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags);
void Trio64_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags);
void Virge_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags);
status_t GetPreferredDisplayMode(display_mode* preferredMode);
status_t GetEdidInfo(void* info, size_t size, uint32* _version);
// DPMS
uint32 Savage_DPMSCapabilities(void);
uint32 Savage_DPMSMode(void);
status_t Savage_SetDPMSMode(uint32 dpms_flags);
uint32 Trio64_DPMSCapabilities(void);
uint32 Trio64_DPMSMode(void);
status_t Trio64_SetDPMSMode(uint32 dpms_flags);
uint32 Virge_DPMSCapabilities(void);
uint32 Virge_DPMSMode(void);
status_t Virge_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 Savage_ShowCursor(bool bShow);
void Trio64_ShowCursor(bool bShow);
void Virge_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 Savage_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count);
void Savage_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
void Savage_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
void Savage_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
void Trio64_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count);
void Trio64_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
void Trio64_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
void Trio64_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
void Virge_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count);
void Virge_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
void Virge_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
void Virge_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
// 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));
void InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[],
uint8& cr3b, uint8& cr3c, uint8& cr5d, uint8& cr5e);
bool IsModeUsable(const display_mode* mode);
// Savage functions.
bool Savage_GetEdidInfo(void);
bool Savage_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
void Savage_SetCursorPosition(int x, int y);
void Savage_AdjustFrame(const DisplayModeEx& mode);
bool Savage_SetDisplayMode(const DisplayModeEx& mode);
void Savage_SetFunctionPointers(void);
// Trio64 functions.
bool Trio64_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
void Trio64_SetCursorPosition(int x, int y);
void Trio64_AdjustFrame(const DisplayModeEx& mode);
bool Trio64_SetDisplayMode(const DisplayModeEx& mode);
void Trio64_SetFunctionPointers(void);
// Virge functions.
bool Virge_GetEdidInfo(void);
bool Virge_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
void Virge_SetCursorPosition(int x, int y);
void Virge_AdjustFrame(const DisplayModeEx& mode);
bool Virge_SetDisplayMode(const DisplayModeEx& mode);
void Virge_SetFunctionPointers(void);
#if defined(__cplusplus)
}
#endif
#endif // _ACCEL_H

View 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-2008
*/
#include "accel.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.cursor.hot_x = hot_x;
si.cursor.hot_y = hot_y;
if ( ! gInfo.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.cursor.hot_x);
y -= (vds + si.cursor.hot_y);
// Position the cursor on the display.
gInfo.SetCursorPosition(x, y);
}

View File

@ -0,0 +1,79 @@
/*
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
*/
#include "accel.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
// Acquire the shared benaphore.
AQUIRE_BEN(gInfo.sharedInfo->engine.lock)
// 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);
// Release the shared benaphore.
RELEASE_BEN(gInfo.sharedInfo->engine.lock)
return B_OK;
}
void
WaitEngineIdle(void)
{
gInfo.WaitIdleEmpty(); // wait until engine is completely idle
}
status_t
GetSyncToken(engine_token* et, sync_token* st)
{
// Engine count will always be zero: we don't support syncing to token (yet).
st->engine_id = et->engine_id;
st->counter = gInfo.sharedInfo->engine.count;
return B_OK;
}
status_t
SyncToToken(sync_token* st)
{
(void)st; // avoid compiler warning for unused arg
WaitEngineIdle();
return B_OK;
}

View File

@ -0,0 +1,69 @@
/*
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#include "accel.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 (void*)AccelerantRetraceSemaphore;
// 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 (void*)GetPreferredDisplayMode;
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*)(gInfo.SetIndexedColors);
case B_GET_TIMING_CONSTRAINTS: return (void*)GetTimingConstraints;
// DPMS
case B_DPMS_CAPABILITIES: return (void*)(gInfo.DPMSCapabilities);
case B_DPMS_MODE: return (void*)(gInfo.DPMSMode);
case B_SET_DPMS_MODE: return (void*)(gInfo.SetDPMSMode);
// Cursor
case B_SET_CURSOR_SHAPE: return (void*)SetCursorShape;
case B_MOVE_CURSOR: return (void*)MoveCursor;
case B_SHOW_CURSOR: return (void*)(gInfo.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*)(gInfo.ScreenToScreenBlit);
case B_FILL_RECTANGLE: return (void*)(gInfo.FillRectangle);
case B_INVERT_RECTANGLE: return (void*)(gInfo.InvertRectangle);
case B_FILL_SPAN: return (void*)(gInfo.FillSpan);
}
return NULL; // Return null pointer for any feature not handled above
}

View File

@ -0,0 +1,470 @@
/*
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include <create_display_modes.h>
void
InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[],
uint8& cr3b, uint8& cr3c, uint8& cr5d, uint8& cr5e)
{
// Initialize the timing values for CRTC registers cr00 to cr18 and cr3a,
// cr3b, cr5d, and cr5e. 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, some
// chips require the horizontal timings to be doubled when the color depth
// is 16 bpp. The horizontal scale factor is used for this purpose.
int hTotal = (mode.timing.h_total * horzScaleFactor) / 8 - 5;
int hDisp_e = (mode.timing.h_display * horzScaleFactor) / 8 - 1;
int hSync_s = (mode.timing.h_sync_start * horzScaleFactor) / 8;
int hSync_e = (mode.timing.h_sync_end * horzScaleFactor) / 8;
int hBlank_s = hDisp_e; // start of horizontal blanking
int hBlank_e = hTotal; // 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; // start of vertical blanking
int vBlank_e = vTotal; // end of vertical blanking
TRACE("InitCrtcTimingValues()\n");
// CRTC Controller values
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] = mode.bytesPerRow / 8;
crtc[0x14] = 0x00;
crtc[0x15] = vBlank_s;
crtc[0x16] = vBlank_e;
crtc[0x17] = 0xc3;
crtc[0x18] = 0xff;
int i = ((hTotal & 0x100) >> 8) |
((hDisp_e & 0x100) >> 7) |
((hBlank_s & 0x100) >> 6) |
((hSync_s & 0x100) >> 4);
if (hSync_e - hSync_s > 64)
i |= 0x08; // add another 64 DCLKs to blank pulse width
if (hSync_e - hSync_s > 32)
i |= 0x20; // add another 32 DCLKs to hsync pulse width
int j = (crtc[0] + ((i & 0x01) << 8) + crtc[4] + ((i & 0x10) << 4) + 1) / 2;
if (j - (crtc[4] + ((i & 0x10) << 4)) < 4) {
if (crtc[4] + ((i & 0x10) << 4) + 4 <= crtc[0] + ((i & 0x01) << 8))
j = crtc[4] + ((i & 0x10) << 4) + 4;
else
j = crtc[0] + ((i & 0x01) << 8) + 1;
}
cr3b = j & 0xff;
i |= (j & 0x100) >> 2;
cr3c = (crtc[0] + ((i & 0x01) << 8)) / 2;
cr5d = i;
cr5e = ((vTotal & 0x400) >> 10) |
((vDisp_e & 0x400) >> 9) |
((vBlank_s & 0x400) >> 8) |
((vSync_s & 0x400) >> 6) | 0x40;
}
static display_mode*
FindDisplayMode(int width, int height, int refreshRate, uint32 colorDepth)
{
// Search the mode list for the mode with specified width, height,
// refresh rate, and color depth. If argument colorDepth is zero, this
// function will search for a mode satisfying the other 3 arguments, and
// if more than one matching mode is found, the one with the greatest color
// depth will be selected.
//
// If successful, return a pointer to the selected display_mode object;
// else return NULL.
display_mode* selectedMode = NULL;
uint32 modeCount = gInfo.sharedInfo->modeCount;
for (uint32 j = 0; j < modeCount; j++) {
display_mode& mode = gInfo.modeList[j];
if (mode.timing.h_display == width && mode.timing.v_display == height) {
int modeRefreshRate = int(((mode.timing.pixel_clock * 1000.0 /
mode.timing.h_total) / mode.timing.v_total) + 0.5);
if (modeRefreshRate == refreshRate) {
if (colorDepth == 0) {
if (selectedMode == NULL || mode.space > selectedMode->space)
selectedMode = &mode;
} else {
if (mode.space == colorDepth)
return &mode;
}
}
}
}
return selectedMode;
}
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;
uint32 bitsPerPixel;
uint32 maxPixelClock;
if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
return false;
// Is there enough memory to handle the mode?
if (mode->virtual_width * mode->virtual_height * ((bitsPerPixel + 7) / 8)
> si.maxFrameBufferSize)
return false;
if (mode->timing.pixel_clock > maxPixelClock)
return false;
// Is the color space supported?
bool bColorSpaceSupported = false;
for (uint32 j = 0; j < si.colorSpaceCount; j++) {
if (mode->space == uint32(si.colorSpaces[j])) {
bColorSpaceSupported = true;
break;
}
}
if ( ! bColorSpaceSupported)
return false;
// Reject modes with a width of 640 and a height < 480 since they do not
// work properly with the S3 chipsets.
if (mode->timing.h_display == 640 && mode->timing.v_display < 480)
return false;
// In most mode lists, there are three entries for 640 x 480 which have a
// refresh rate of 60 Hz. The one with a pixel clock of 25175 works fine
// with the S3 chips; however, the other two with higher clock rates
// cause the display to be offset down and to the right; thus, reject them.
if (mode->timing.h_display == 640 && mode->timing.v_display == 480) {
int modeRefreshRate = int(((mode->timing.pixel_clock * 1000.0 /
mode->timing.h_total) / mode->timing.v_total) + 0.5);
if (modeRefreshRate == 60 && mode->timing.pixel_clock > 26000)
return false;
}
// If the video is connected directly to an LCD display (ie, laptop
// computer), restrict the display mode to resolutions where the width and
// height of the mode are less than or equal to the width and height of the
// LCD display. Note that this code is not needed under Haiku since it can
// get the preferred mode which should be the resolution of the LCD display.
#ifndef __HAIKU__
if (si.displayType == MT_LCD && si.panelX > 0 && si.panelY > 0 &&
(mode->timing.h_display > si.panelX
|| mode->timing.v_display > si.panelY)) {
return false;
}
#endif // __HAIKU__
return true;
}
status_t
CreateModeList(bool (*checkMode)(const display_mode* mode))
{
SharedInfo& si = *gInfo.sharedInfo;
display_mode* list;
uint32 count = 0;
area_id listArea;
listArea = create_display_modes("S3 modes",
si.bHaveEDID ? &si.edidInfo : NULL,
NULL, 0, si.colorSpaces, si.colorSpaceCount, 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
TRACE("ProposeDisplayMode() clock: %d, width: %d, height: %d, space: 0x%X\n",
target->timing.pixel_clock, target->virtual_width, target->virtual_height,
target->space);
// Search the mode list for the specified mode.
uint32 modeCount = gInfo.sharedInfo->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;
uint32 maxPixelClock;
if ( ! gInfo.GetColorSpaceParams(mode.space, mode.bpp, maxPixelClock))
return B_ERROR;
mode.bytesPerRow = mode.virtual_width * ((mode.bpp + 7) / 8); // use virtual width
if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK)
return B_ERROR;
// Test if there is sufficient memory for this mode. Use the virtual width
// and height for this calculation since one or both might be greater than
// the actual dimensions of the mode.
if (mode.bytesPerRow * mode.virtual_height > si.maxFrameBufferSize)
return B_ERROR;
TRACE("Display Mode: width = %d, height = %d, depth = %d\n",
mode.virtual_width, mode.virtual_height, mode.bpp);
TRACE("Mode Timing = { %d %d %d %d %d %d %d %d %d 0x%x }\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, mode.timing.flags);
if ( ! gInfo.SetDisplayMode(mode))
return B_ERROR;
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;
gInfo.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.bytesPerRow;
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.
uint32 bitsPerPixel;
uint32 maxPixelClock;
if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
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 > maxPixelClock)
return B_ERROR;
*low = lowClock;
}
if (high != NULL)
*high = maxPixelClock;
return B_OK;
}
status_t
GetTimingConstraints(display_timing_constraints *constraints)
{
(void)constraints; // avoid compiler warning for unused arg
TRACE("GetTimingConstraints() called\n");
return B_ERROR;
}
status_t
GetPreferredDisplayMode(display_mode* preferredMode)
{
// If the chip is connected to a laptop LCD panel, find the mode with
// matching width and height, 60 Hz refresh rate, and greatest color depth.
TRACE("GetPreferredDisplayMode()\n");
SharedInfo& si = *gInfo.sharedInfo;
if (si.displayType == MT_LCD) {
display_mode* mode = FindDisplayMode(si.panelX, si.panelY, 60, 0);
if (mode != NULL) {
*preferredMode = *mode;
return B_OK;
}
}
return B_ERROR;
}
#ifdef __HAIKU__
status_t
GetEdidInfo(void* info, size_t size, uint32* _version)
{
TRACE("GetEdidInfo()\n");
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__

View File

@ -0,0 +1,245 @@
/*
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#include "accel.h"
#include <unistd.h>
// 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
// Functions for PIO.
//===================
uint32 ReadPIO(uint32 addr, uint8 numBytes)
{
S3GetSetPIO gsp;
gsp.magic = S3_PRIVATE_DATA_MAGIC;
gsp.offset = addr;
gsp.size = numBytes;
gsp.value = 0;
status_t result = ioctl(gInfo.deviceFileDesc, S3_GET_PIO, &gsp, sizeof(gsp));
if (result != B_OK)
TRACE("ReadPIO() failed, result = 0x%x\n", result);
return gsp.value;
}
void WritePIO(uint32 addr, uint8 numBytes, uint32 value)
{
S3GetSetPIO gsp;
gsp.magic = S3_PRIVATE_DATA_MAGIC;
gsp.offset = addr;
gsp.size = numBytes;
gsp.value = value;
status_t result = ioctl(gInfo.deviceFileDesc, S3_SET_PIO, &gsp, sizeof(gsp));
if (result != B_OK)
TRACE("WritePIO() failed, result = 0x%x\n", result);
}
// Functions to read 8/16/32 bit registers.
//=========================================
uint8 ReadReg8(uint32 addr)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
return ReadPIO(addr, 1);
return INREG8(addr);
}
uint16 ReadReg16(uint32 addr)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
return ReadPIO(addr, 2);
return INREG16(addr);
}
uint32 ReadReg32(uint32 addr)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
return ReadPIO(addr, 4);
return INREG32(addr);
}
// Functions to write 8/16/32 bit registers.
//=========================================
void WriteReg8(uint32 addr, uint8 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
WritePIO(addr, 1, value);
else
OUTREG8(addr, value);
}
void WriteReg16(uint32 addr, uint16 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
WritePIO(addr, 2, value);
else
OUTREG16(addr, value);
}
void WriteReg32(uint32 addr, uint32 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
WritePIO(addr, 4, value);
else
OUTREG32(addr, value);
}
// Functions to read/write CRTC registers.
//========================================
uint8 ReadCrtcReg(uint8 index)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3d4, index);
return ReadPIO_8(0x3d5);
}
OUTREG8(0x83d4, index);
return INREG8(0x83d5);
}
void WriteCrtcReg(uint8 index, uint8 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3d4, index);
WritePIO_8(0x3d5, value);
} else {
OUTREG8(0x83d4, index);
OUTREG8(0x83d5, value);
}
}
void WriteCrtcReg(uint8 index, uint8 value, uint8 mask)
{
// Write a value to a CRTC reg using a mask. The mask selects the
// bits to be modified.
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3d4, index);
WritePIO_8(0x3d5, (ReadPIO_8(0x3d5) & ~mask) | (value & mask));
} else {
OUTREG8(0x83d4, index);
OUTREG8(0x83d5, (INREG8(0x83d5) & ~mask) | (value & mask));
}
}
// Functions to read/write Sequence registers.
//============================================
uint8 ReadSeqReg(uint8 index)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3c4, index);
return ReadPIO_8(0x3c5);
}
OUTREG8(0x83c4, index);
return INREG8(0x83c5);
}
void WriteSeqReg(uint8 index, uint8 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3c4, index);
WritePIO_8(0x3c5, value);
} else {
OUTREG8(0x83c4, index);
OUTREG8(0x83c5, value);
}
}
void WriteSeqReg(uint8 index, uint8 value, uint8 mask)
{
// Write a value to a Sequencer reg using a mask. The mask selects the
// bits to be modified.
if (gInfo.sharedInfo->chipType == S3_TRIO64) {
WritePIO_8(0x3c4, index);
WritePIO_8(0x3c5, (ReadPIO_8(0x3c5) & ~mask) | (value & mask));
} else {
OUTREG8(0x83c4, index);
OUTREG8(0x83c5, (INREG8(0x83c5) & ~mask) | (value & mask));
}
}
// Functions to read/write the misc output register.
//==================================================
uint8 ReadMiscOutReg()
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
return ReadPIO_8(0x3cc);
return INREG8(0x83cc);
}
void WriteMiscOutReg(uint8 value)
{
if (gInfo.sharedInfo->chipType == S3_TRIO64)
WritePIO_8(0x3c2, value);
else
OUTREG8(0x83c2, value);
}
void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue)
{
// Write an indexed color. Argument index is the index (0-255) of the
// color, and arguments red, green, & blue are the components of the color.
// Note that although the Trio64V+ chip supports MMIO in nearly all areas,
// it does not support MMIO for setting indexed colors; thus, use PIO to
// set the indexed color.
if (gInfo.sharedInfo->chipType == S3_TRIO64
|| gInfo.sharedInfo->chipType == S3_TRIO64_VP) {
WritePIO_8(0x3c8, index); // color index
WritePIO_8(0x3c9, red);
WritePIO_8(0x3c9, green);
WritePIO_8(0x3c9, blue);
} else {
OUTREG8(0x83c8, index); // color index
OUTREG8(0x83c9, red);
OUTREG8(0x83c9, green);
OUTREG8(0x83c9, blue);
}
}

View File

@ -0,0 +1,59 @@
/*
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#ifndef __REGISTER_IO_H__
#define __REGISTER_IO_H__
// PIO address of various VGA registers. If accessing these registers using
// MMIO, add 0x8000 to thses addresses.
#define VGA_ENABLE 0x3c3
#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
// Prototypes of I/O functions for accessing registers using PIO.
uint32 ReadPIO(uint32 addr, uint8 numBytes);
void WritePIO(uint32 addr, uint8 numBytes, uint32 value);
inline uint8 ReadPIO_8(uint32 addr) { return ReadPIO(addr, 1); }
inline void WritePIO_8(uint32 addr, uint8 value) { WritePIO(addr, 1, value); }
// Prototypes of I/O functions for accessing registers using PIO or MMIO
// depending upon the type of S3 chip.
uint8 ReadReg8(uint32 addr);
uint16 ReadReg16(uint32 addr);
uint32 ReadReg32(uint32 addr);
void WriteReg8(uint32 addr, uint8 value);
void WriteReg16(uint32 addr, uint16 value);
void WriteReg32(uint32 addr, uint32 value);
uint8 ReadCrtcReg(uint8 index);
void WriteCrtcReg(uint8 index, uint8 value);
void WriteCrtcReg(uint8 index, uint8 value, uint8 mask);
uint8 ReadSeqReg(uint8 index);
void WriteSeqReg(uint8 index, uint8 value);
void WriteSeqReg(uint8 index, uint8 value, uint8 mask);
uint8 ReadMiscOutReg();
void WriteMiscOutReg(uint8 value);
void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue);
#endif // __REGISTER_IO_H__

View File

@ -0,0 +1,116 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2008
*/
#ifndef __SAVAGE_H__
#define __SAVAGE_H__
#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory
#define ADVANCED_FUNC_CTRL 0x850C
#define SYSTEM_CONTROL_REG 0x83DA
// Stream Processor 1.
// Primary Stream 1 Frame Buffer Address 0.
#define PRI_STREAM_FBUF_ADDR0 0x81c0
// Primary Stream 1 Frame Buffer Address 1.
#define PRI_STREAM_FBUF_ADDR1 0x81c4
// Primary Stream 1 Stride.
#define PRI_STREAM_STRIDE 0x81c8
// Stream Processor 2.
// Primary Stream 2 Frame Buffer Address 0.
#define PRI_STREAM2_FBUF_ADDR0 0x81b0
// Primary Stream 2 Frame Buffer Address 1.
#define PRI_STREAM2_FBUF_ADDR1 0x81b4
// Primary Stream 2 Stride.
#define PRI_STREAM2_STRIDE 0x81b8
#define MEMORY_CTRL0_REG 0xCA
#define MEMORY_CONFIG_REG 0x31
// Bitmap descriptor register.
#define S3_GLB_BD_LOW 0x8168
#define S3_GLB_BD_HIGH 0x816C
#define S3_PRI_BD_LOW 0x8170
#define S3_PRI_BD_HIGH 0x8174
#define S3_SEC_BD_LOW 0x8178
#define S3_SEC_BD_HIGH 0x817c
#define MEM_PS1 0x10 // CRCA_4 :Primary stream 1
#define MEM_PS2 0x20 // CRCA_5 :Primary stream 2
#define SRC_BASE 0xa4d4
#define DEST_BASE 0xa4d8
#define CLIP_L_R 0xa4dc
#define CLIP_T_B 0xa4e0
#define DEST_SRC_STR 0xa4e4
#define MONO_PAT_0 0xa4e8
#define MONO_PAT_1 0xa4ec
#define DISABLE_BLOCK_WRITE_2D 0x10 // CR88_4 =1 : disable block write
#define STATUS_WORD0 (ReadReg32(0x48C00))
#define ALT_STATUS_WORD0 (ReadReg32(0x48C60))
#define MAXFIFO 0x7f00
// BCI definitions.
//=================
#define TILE_FORMAT_LINEAR 0
// BD - BCI enable.
#define BCI_ENABLE 8 // savage4, MX, IX, 3D
#define BCI_ENABLE_TWISTER 0 // twister, prosavage, DDR, supersavage, 2000
#define S3_BIG_ENDIAN 4
#define S3_LITTLE_ENDIAN 0
#define S3_BD64 1
#define BCI_BUFFER_OFFSET 0x10000
#define BCI_GET_PTR vuint32* bci_ptr = ((uint32*)(gInfo.regs + BCI_BUFFER_OFFSET))
#define BCI_SEND(dw) (*bci_ptr++ = ((uint32)(dw)))
#define BCI_CMD_NOP 0x40000000
#define BCI_CMD_RECT 0x48000000
#define BCI_CMD_RECT_XP 0x01000000
#define BCI_CMD_RECT_YP 0x02000000
#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
#define BCI_CMD_SEND_COLOR 0x00008000
#define BCI_CMD_DEST_PBD_NEW 0x00000C00
#define BCI_CMD_SRC_SOLID 0x00000000
#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140
#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF)
#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF)
static inline void VerticalRetraceWait()
{
if (ReadCrtcReg(0x17) & 0x80) {
int i = 0x10000;
while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ;
i = 0x10000;
while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ;
}
}
#endif // __SAVAGE_H__

View File

@ -0,0 +1,144 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2008
*/
#include "accel.h"
#include "savage.h"
// Certain HW cursor operations seem to require a delay to prevent lockups.
static void
WaitHSync(int n)
{
while (n--) {
while (ReadReg8(SYSTEM_CONTROL_REG) & 0x01) {};
while ( ! ReadReg8(SYSTEM_CONTROL_REG) & 0x01) {};
}
}
void
Savage_ShowCursor(bool bShow)
{
// Turn cursor on/off.
if ( ! bShow && S3_SAVAGE4_SERIES(gInfo.sharedInfo->chipType))
WaitHSync(5);
WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01);
}
void
Savage_SetCursorPosition(int x, int y)
{
SharedInfo& si = *gInfo.sharedInfo;
if (S3_SAVAGE4_SERIES(si.chipType))
WaitHSync(5);
// xOffset & yOffset are used for displaying partial cursors on screen edges.
uint8 xOffset = 0;
uint8 yOffset = 0;
if (x < 0) {
xOffset = (( -x) & 0xFE);
x = 0;
}
if (y < 0) {
yOffset = (( -y) & 0xFE);
y = 0;
}
// Note: when setting the cursor position, register 48 must be set last
// since setting register 48 activates the new cursor position.
WriteCrtcReg( 0x4e, xOffset );
WriteCrtcReg( 0x4f, yOffset );
WriteCrtcReg( 0x47, (x & 0xff) );
WriteCrtcReg( 0x46, (x & 0x0700) >> 8 );
WriteCrtcReg( 0x49, (y & 0xff) );
WriteCrtcReg( 0x48, (y & 0x0700) >> 8 );
}
bool
Savage_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
{
SharedInfo& si = *gInfo.sharedInfo;
if (andMask == NULL || xorMask == NULL)
return false;
// Initialize the hardware cursor as completely transparent.
uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset);
for (int i = 0; i < CURSOR_BYTES; i += 4) {
*fbCursor16++ = ~0; // and bits
*fbCursor16++ = 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 + 2] = *xorMask++;
}
}
if (S3_SAVAGE4_SERIES(si.chipType)) {
// Bug in Savage4 Rev B requires us to do an MMIO read after
// loading the cursor.
volatile unsigned int k = ALT_STATUS_WORD0;
(void)k++; // Not to be optimised out
}
// Set cursor location in video memory.
WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024));
WriteCrtcReg(0x4c, (0xff00 & si.cursorOffset / 1024) >> 8);
// Set the cursor colors which are black foreground and white background.
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes
WriteCrtcReg(0x4a, 0);
WriteCrtcReg(0x4a, 0);
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes
WriteCrtcReg(0x4b, ~0);
WriteCrtcReg(0x4b, ~0);
return true;
}

View File

@ -0,0 +1,118 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2008
*/
#include "accel.h"
#include "savage.h"
uint32
Savage_DPMSCapabilities(void)
{
// Return DPMS modes supported by this device.
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
}
uint32
Savage_DPMSMode(void)
{
// Return the current DPMS mode.
// Note: I do not know whether the following code is correctly reading
// the current DPMS mode. I'm assuming that reading back the bits that
// were set by function SET_DPMS_MODE will give the current DPMS mode.
SharedInfo& si = *gInfo.sharedInfo;
uint32 mode = B_DPMS_ON;
if (si.displayType == MT_CRT) {
switch (ReadSeqReg(0x0d) & 0x70) {
case 0:
mode = B_DPMS_ON;
break;
case 0x10:
mode = B_DPMS_STAND_BY;
break;
case 0x40:
mode = B_DPMS_SUSPEND;
break;
case 0x50:
mode = B_DPMS_OFF;
break;
default:
TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d));
}
} else if (si.displayType == MT_LCD || si.displayType == MT_DFP) {
mode = ((ReadSeqReg(0x31) & 0x10) ? B_DPMS_ON : B_DPMS_OFF);
}
TRACE("Savage_DPMSMode() mode: %d\n", mode);
return mode;
}
status_t
Savage_SetDPMSMode(uint32 dpmsMode)
{
// Set the display into one of the Display Power Management modes,
// and return B_OK if successful, else return B_ERROR.
SharedInfo& si = *gInfo.sharedInfo;
TRACE("Savage_SetDPMSMode() mode: %d, display type: %d\n", dpmsMode, si.displayType);
if (si.displayType == MT_CRT) {
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 sr0D = ReadSeqReg(0x0d) & 0x03;
switch (dpmsMode) {
case B_DPMS_ON:
break;
case B_DPMS_STAND_BY:
sr0D |= 0x10;
break;
case B_DPMS_SUSPEND:
sr0D |= 0x40;
break;
case B_DPMS_OFF:
sr0D |= 0x50;
break;
default:
TRACE("Invalid DPMS mode %d\n", dpmsMode);
return B_ERROR;
}
WriteSeqReg(0x0d, sr0D);
} else if (si.displayType == MT_LCD || si.displayType == MT_DFP) {
switch (dpmsMode) {
case B_DPMS_ON:
WriteSeqReg(0x31, 0x10, 0x10); // SR31 bit 4 - FP enable
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
WriteSeqReg(0x31, 0x00, 0x10); // SR31 bit 4 - FP enable
break;
default:
TRACE("Invalid DPMS mode %d\n", dpmsMode);
return B_ERROR;
}
}
return B_OK;
}

View File

@ -4,30 +4,27 @@
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007 Haiku, Inc. All rights reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2007
Gerald Zajac 2006-2008
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "accel.h"
#include "savage.h"
void
FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32 count)
Savage_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, uint32 count)
{
int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
| BCI_CMD_DEST_PBD_NEW | BCI_CMD_SRC_SOLID | BCI_CMD_SEND_COLOR;
(void)et; // avoid compiler warning for unused arg
// TRACE(("FILL_RECTANGLE, color: %X count: %d\n", color, count));
BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop
while (count--) {
@ -38,11 +35,11 @@ FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32
BCI_GET_PTR;
si->WaitQueue(7);
gInfo.WaitQueue(7);
BCI_SEND(cmd);
BCI_SEND(si->GlobalBD.bd2.LoPart);
BCI_SEND(si->GlobalBD.bd2.HiPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart);
BCI_SEND(color);
BCI_SEND(BCI_X_Y(x, y));
@ -54,15 +51,13 @@ FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32
void
FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count)
Savage_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count)
{
int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
| BCI_CMD_DEST_PBD_NEW | BCI_CMD_SRC_SOLID | BCI_CMD_SEND_COLOR;
(void)et; // avoid compiler warning for unused arg
// TRACE(("FILL_SPAN, count: %d\n", count));
BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop
while (count--) {
@ -76,15 +71,15 @@ FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count)
// spans which the Savage chips display as a line completely across the
// screen; thus, the following if statement discards any span with zero
// or negative width.
if (w <= 0)
continue;
si->WaitQueue(7);
gInfo.WaitQueue(7);
BCI_SEND(cmd);
BCI_SEND(si->GlobalBD.bd2.LoPart);
BCI_SEND(si->GlobalBD.bd2.HiPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart);
BCI_SEND(color);
BCI_SEND(BCI_X_Y(x, y));
@ -94,15 +89,13 @@ FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count)
void
INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count)
Savage_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count)
{
int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
| BCI_CMD_DEST_PBD_NEW;
(void)et; // avoid compiler warning for unused arg
// TRACE(("INVERT_RECTANGLE, count: %d\n", count));
BCI_CMD_SET_ROP(cmd, 0x55); // use GXinvert for rop
while (count--) {
@ -113,11 +106,11 @@ INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count)
BCI_GET_PTR;
si->WaitQueue(7);
gInfo.WaitQueue(7);
BCI_SEND(cmd);
BCI_SEND(si->GlobalBD.bd2.LoPart);
BCI_SEND(si->GlobalBD.bd2.HiPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart);
BCI_SEND(BCI_X_Y(x, y));
BCI_SEND(BCI_W_H(w, h));
@ -128,10 +121,8 @@ INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count)
void
SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *pList, uint32 count)
Savage_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count)
{
// TRACE(("SCREEN_TO_SCREEN_BLIT\n"));
(void)et; // avoid compiler warning for unused arg
while (count--) {
@ -162,15 +153,15 @@ SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *pList, uint32 count)
dest_y += height;
}
si->WaitQueue(9);
gInfo.WaitQueue(9);
BCI_SEND(cmd);
BCI_SEND(si->GlobalBD.bd2.LoPart);
BCI_SEND(si->GlobalBD.bd2.HiPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart);
BCI_SEND(si->GlobalBD.bd2.LoPart);
BCI_SEND(si->GlobalBD.bd2.HiPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart);
BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart);
BCI_SEND(BCI_X_Y(src_x, src_y));
BCI_SEND(BCI_X_Y(dest_x, dest_y));

View File

@ -0,0 +1,99 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "savage.h"
#include <string.h>
#include <ddc.h>
#include <edid.h>
static status_t
GetI2CSignals(void* cookie, int* _clock, int* data)
{
uint32 index = (uint32)cookie;
uint8 value = ReadCrtcReg(index);
*_clock = (value & 0x4) != 0;
*data = (value & 0x8) != 0;
return B_OK;
}
static status_t
SetI2CSignals(void* cookie, int _clock, int data)
{
uint32 index = (uint32)cookie;
uint8 value = 0x10;
if (_clock)
value |= 0x1;
if (data)
value |= 0x2;
WriteCrtcReg(index, value);
return B_OK;
}
bool
Savage_GetEdidInfo(void)
{
// Get the EDID info and return true if successful.
SharedInfo& si = *gInfo.sharedInfo;
uint32 DDCPort = 0;
switch (si.chipType) {
case S3_SAVAGE_3D:
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
case S3_SAVAGE2000:
DDCPort = 0xAA;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_TWISTER:
case S3_PROSAVAGE_DDR:
DDCPort = 0xB1;
break;
}
i2c_bus bus;
bus.cookie = (void*)DDCPort;
bus.set_signals = &SetI2CSignals;
bus.get_signals = &GetI2CSignals;
ddc2_init_timing(&bus);
uint8 tmp = ReadCrtcReg(DDCPort);
WriteCrtcReg(DDCPort, tmp | 0x13);
si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK);
WriteCrtcReg(DDCPort, tmp);
if (si.bHaveEDID) {
#ifdef ENABLE_DEBUG_TRACE
edid_dump(&(si.edidInfo));
#endif
} else {
TRACE("Savage_GetEdidInfo() failed!\n");
}
return si.bHaveEDID;
}

View File

@ -0,0 +1,400 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2008
*/
#include "accel.h"
#include "savage.h"
static bool
Savage_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
{
// Get parameters for a color space which is supported by the Savage chips.
// Argument maxPixelClock is in KHz.
// Return true if the color space is supported; else return false.
switch (colorSpace) {
case B_RGB32:
bitsPerPixel = 32;
maxPixelClock = 220000;
break;
case B_RGB16:
bitsPerPixel = 16;
maxPixelClock = 250000;
break;
case B_CMAP8:
bitsPerPixel = 8;
maxPixelClock = 250000;
break;
default:
TRACE("Unsupported color space: 0x%X\n", colorSpace);
return false;
}
return true;
}
// Wait until "v" queue entries are free.
static void
WaitQueue3D(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((STATUS_WORD0 & 0x0000ffff) > slots);
}
static void
WaitQueue4(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((ALT_STATUS_WORD0 & 0x001fffff) > slots);
}
static void
WaitQueue2K(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((ALT_STATUS_WORD0 & 0x000fffff) > slots);
}
// Wait until GP is idle and queue is empty.
static void
WaitIdleEmpty3D()
{
while ((STATUS_WORD0 & 0x0008ffff) != 0x80000);
}
static void
WaitIdleEmpty4()
{
while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ;
}
static void
WaitIdleEmpty2K()
{
while ((ALT_STATUS_WORD0 & 0x009fffff) != 0);
}
static bool
IsLCDWidthValid(int width)
{
// Search the array of valid LCD widths to find a width that matches the
// width by the caller, and return true if a match is found.
const int lcdWidths[] = { 640, 800, 1024, 1152, 1280, 1400, 1440, 1600, 1680 };
for (int i = 0; i < NUM_ELEMENTS(lcdWidths); i++) {
if (lcdWidths[i] == width)
return true;
}
return false; // match not found
}
static void
Savage_GetPanelInfo()
{
SharedInfo& si = *gInfo.sharedInfo;
enum ACTIVE_DISPLAYS { // these are the bits in CR6B
ActiveCRT = 0x01,
ActiveLCD = 0x02,
ActiveTV = 0x04,
ActiveCRT2 = 0x20,
ActiveDUO = 0x80
};
// Check LCD panel information.
uint8 cr6b = ReadCrtcReg(0x6b);
int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
if ( ! IsLCDWidthValid(panelX)) {
// Some chips such as the Savage IX/MV in a Thinkpad T-22 will return
// a width that is 8 pixels too wide probably because reg SR61 is set
// to a value +1 higher than it should be. Subtract 8 from the width,
// and check if that is a valid width.
panelX -= 8;
if ( ! IsLCDWidthValid(panelX)) {
TRACE("%dx%d LCD panel width invalid.\n", panelX + 8, panelY);
si.displayType = MT_CRT;
return;
}
}
char* sTechnology;
if ((ReadSeqReg(0x39) & 0x03) == 0)
sTechnology = "TFT";
else if ((ReadSeqReg(0x30) & 0x01) == 0)
sTechnology = "DSTN";
else
sTechnology = "STN";
TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology,
cr6b & ActiveLCD ? "and active" : "but not active");
if (cr6b & ActiveLCD) {
TRACE("Limiting max video mode to %dx%d\n", panelX, panelY);
si.panelX = panelX;
si.panelY = panelY;
} else {
si.displayType = MT_CRT;
}
}
status_t
Savage_Init(void)
{
TRACE("Savage_Init()\n");
SharedInfo& si = *gInfo.sharedInfo;
// MMIO should be automatically enabled for Savage chips; thus, use MMIO
// to enable VGA and turn color on.
WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01);
WriteMiscOutReg(ReadMiscOutReg() | 0x01); // turn color on
if (si.chipType >= S3_SAVAGE4)
WriteCrtcReg(0x40, 0x01, 0x01);
WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11
WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F
WriteCrtcReg(0x39, 0xa0); // unlock sys regs CR40~CRFF
WriteSeqReg(0x08, 0x06); // unlock sequencer regs SR09~SRFF
WriteCrtcReg(0x40, 0x00, 0x01);
WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F
// Compute the amount of video memory and offscreen memory.
static const uint8 RamSavage3D[] = { 8, 4, 4, 2 };
static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
int ramSizeMB = 0; // memory size in megabytes
uint8 cr36 = ReadCrtcReg(0x36); // get amount of video ram
switch (si.chipType) {
case S3_SAVAGE_3D:
ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ];
break;
case S3_SAVAGE4:
// The Savage4 has one ugly special case to consider. On
// systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
// when it really means 8MB. Why do it the same when you
// can do it different...
if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6))
RamSavage4[1] = 8;
// FALL THROUGH
case S3_SAVAGE2000:
ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ];
break;
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ];
break;
case S3_PROSAVAGE:
case S3_PROSAVAGE_DDR:
case S3_TWISTER:
ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ];
break;
default:
// How did we get here?
ramSizeMB = 0;
break;
}
TRACE("Savage_Init() memory size: %d MB\n", ramSizeMB);
if (ramSizeMB <= 0)
return B_ERROR;
si.videoMemSize = ramSizeMB * 1024 * 1024;
// Certain Savage4 and ProSavage chips can have coherency problems
// with respect to the Command Overflow Buffer (COB); thus, to avoid
// problems with these chips, set bDisableCOB to true.
si.bDisableCOB = false;
// Compute the Command Overflow Buffer (COB) location.
if ((S3_SAVAGE4_SERIES(si.chipType) || S3_SUPERSAVAGE == si.chipType)
&& si.bDisableCOB) {
// The Savage4 and ProSavage have COB coherency bugs which render
// the buffer useless.
si.cobIndex = 0;
si.cobSize = 0;
si.bciThresholdHi = 32;
si.bciThresholdLo = 0;
} else {
// We use 128kB for the COB on all other chips.
si.cobSize = 0x20000;
if (S3_SAVAGE_3D_SERIES(si.chipType) || si.chipType == S3_SAVAGE2000)
si.cobIndex = 7; // rev.A savage4 apparently also uses 7
else
si.cobIndex = 2;
// Max command size: 2560 entries.
si.bciThresholdHi = si.cobSize / 4 + 32 - 2560;
si.bciThresholdLo = si.bciThresholdHi - 2560;
}
// Note that the X.org developers stated that the command overflow buffer
// (COB) must END at a 4MB boundary which for all practical purposes means
// the very end of the video memory. The cursor must be at the beginning
// of the video memory. It had been tried immediately preceding the COB,
// but the Savage MX chip screws up the cursor in that case.
si.cobOffset = (si.videoMemSize - si.cobSize) & ~0x1ffff; // align cob to 128k
si.cursorOffset = 0;
si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES;
si.maxFrameBufferSize = si.cobOffset - si.frameBufferOffset;
TRACE("cobIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobIndex, si.cobSize, si.cobOffset);
TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset);
// Reset graphics engine to avoid memory corruption.
WriteCrtcReg(0x66, 0x02, 0x02); // set reset flag
snooze(10000);
WriteCrtcReg(0x66, 0x00, 0x02); // clear reset flag
snooze(10000);
// Check for DVI/flat panel.
bool bDvi = false;
if (si.chipType == S3_SAVAGE4) {
WriteSeqReg(0x30, 0x00, 0x02); // clear bit 1
if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) {
bDvi = true;
TRACE("Digital Flat Panel Detected\n");
}
}
if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) {
si.displayType = MT_LCD;
Savage_GetPanelInfo();
}
else if (bDvi)
si.displayType = MT_DFP;
else
si.displayType = MT_CRT;
TRACE("Display Type: %d\n", si.displayType);
// Detect current mclk.
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 m = ReadSeqReg(0x11) & 0x7f;
uint8 n = ReadSeqReg(0x10);
uint8 n1 = n & 0x1f;
uint8 n2 = (n >> 5) & 0x03;
si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
// Set up the array of color spaces supported by the Savage chips.
si.colorSpaces[0] = B_CMAP8;
si.colorSpaces[1] = B_RGB16;
si.colorSpaces[2] = B_RGB32;
si.colorSpaceCount = 3;
// Get info about the display capabilities (EDID).
Savage_GetEdidInfo();
// Setup the mode list.
return CreateModeList(IsModeUsable);
}
void
Savage_SetFunctionPointers(void)
{
// Setting the function pointers must be done prior to first ModeInit call
// or any accel activity.
switch (gInfo.sharedInfo->chipType) {
case S3_SAVAGE_3D:
case S3_SAVAGE_MX:
gInfo.WaitQueue = WaitQueue3D;
gInfo.WaitIdleEmpty = WaitIdleEmpty3D;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_SUPERSAVAGE:
case S3_PROSAVAGE_DDR:
case S3_TWISTER:
gInfo.WaitQueue = WaitQueue4;
gInfo.WaitIdleEmpty = WaitIdleEmpty4;
break;
case S3_SAVAGE2000:
gInfo.WaitQueue = WaitQueue2K;
gInfo.WaitIdleEmpty = WaitIdleEmpty2K;
break;
}
gInfo.DPMSCapabilities = Savage_DPMSCapabilities;
gInfo.DPMSMode = Savage_DPMSMode;
gInfo.SetDPMSMode = Savage_SetDPMSMode;
gInfo.LoadCursorImage = Savage_LoadCursorImage;
gInfo.SetCursorPosition = Savage_SetCursorPosition;
gInfo.ShowCursor = Savage_ShowCursor;
gInfo.FillRectangle = Savage_FillRectangle;
gInfo.FillSpan = Savage_FillSpan;
gInfo.InvertRectangle = Savage_InvertRectangle;
gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit;
gInfo.AdjustFrame = Savage_AdjustFrame;
gInfo.ChipInit = Savage_Init;
gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams;
gInfo.SetDisplayMode = Savage_SetDisplayMode;
gInfo.SetIndexedColors = Savage_SetIndexedColors;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
/*
Haiku S3 Trio64 driver adapted from the X.org S3 driver.
Copyright 2001 Ani Joshi <ajoshi@unixbox.com>
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#ifndef __TRIO64_H__
#define __TRIO64_H__
// Note that the cursor normally needs only 1024 bytes; however, if 1024 bytes
// are used, some of the Trio64 chips draw a short white horizontal line below
// and to the right of the cursor. Setting the number of bytes to 2048 solves
// the problem.
#define CURSOR_BYTES 2048 // see comment above
// Command Registers.
#define ADVFUNC_CNTL 0x4ae8
#define SUBSYS_STAT 0x42e8
#define SUBSYS_CNTL 0x42e8
#define CUR_Y 0x82e8
#define CUR_X 0x86e8
#define DESTY_AXSTP 0x8ae8
#define DESTX_DIASTP 0x8ee8
#define CUR_WIDTH 0x96e8
#define CMD 0x9ae8
#define GP_STAT 0x9ae8
#define FRGD_COLOR 0xa6e8
#define WRT_MASK 0xaae8
#define FRGD_MIX 0xbae8
#define MULTIFUNC_CNTL 0xbee8
// Command register bits.
#define CMD_RECT 0x4000
#define CMD_BITBLT 0xc000
#define INC_Y 0x0080
#define INC_X 0x0020
#define DRAW 0x0010
#define WRTDATA 0x0001
// Foreground mix register.
#define FSS_FRGDCOL 0x0020
#define FSS_BITBLT 0x0060
#define GP_BUSY 0x0200
#define SCISSORS_T 0x1000
#define SCISSORS_L 0x2000
#define SCISSORS_B 0x3000
#define SCISSORS_R 0x4000
#endif // __TRIO64_H__

View File

@ -0,0 +1,112 @@
/*
Haiku S3 Trio64 driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "trio64.h"
void
Trio64_ShowCursor(bool bShow)
{
// Turn cursor on/off.
WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01);
}
void
Trio64_SetCursorPosition(int x, int y)
{
uint8 xOffset = 0;
uint8 yOffset = 0;
// xOffset & yOffset are used for displaying partial cursors on screen edges.
if (x < 0) {
xOffset = (( -x) & 0xfe);
x = 0;
}
if (y < 0) {
yOffset = (( -y) & 0xfe);
y = 0;
}
// Note: when setting the cursor position, register 48 must be set last
// since setting register 48 activates the new cursor position.
WriteCrtcReg( 0x4e, xOffset );
WriteCrtcReg( 0x4f, yOffset );
WriteCrtcReg( 0x47, (x & 0xff) );
WriteCrtcReg( 0x46, (x & 0x0700) >> 8 );
WriteCrtcReg( 0x49, (y & 0xff) );
WriteCrtcReg( 0x48, (y & 0x0700) >> 8 );
}
bool
Trio64_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
{
SharedInfo& si = *gInfo.sharedInfo;
if (andMask == NULL || xorMask == NULL)
return false;
// Initialize hardware cursor to be completely transparent.
uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset);
for (int i = 0; i < CURSOR_BYTES; i += 4) {
*fbCursor16++ = ~0; // and bits
*fbCursor16++ = 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 + 2] = *xorMask++;
}
}
// Set cursor location in video memory.
WriteCrtcReg(0x4c, (0x0f00 & si.cursorOffset / 1024) >> 8);
WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024));
// Set the cursor colors which are black foreground and white background.
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes
WriteCrtcReg(0x4a, 0);
WriteCrtcReg(0x4a, 0);
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes
WriteCrtcReg(0x4b, ~0);
WriteCrtcReg(0x4b, ~0);
return true;
}

View File

@ -0,0 +1,93 @@
/*
Haiku S3 Trio64 DPMS functions adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "trio64.h"
uint32
Trio64_DPMSCapabilities(void)
{
// Return DPMS modes supported by this device.
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
}
uint32
Trio64_DPMSMode(void)
{
// Return the current DPMS mode.
// Note: I do not know whether the following code is correctly reading
// the current DPMS mode. I'm assuming that reading back the bits that
// were set by function Trio64_SetDPMSMode will give the current DPMS mode.
uint32 mode = B_DPMS_ON;
switch (ReadSeqReg(0x0d) & 0x70) {
case 0:
mode = B_DPMS_ON;
break;
case 0x10:
mode = B_DPMS_STAND_BY;
break;
case 0x40:
mode = B_DPMS_SUSPEND;
break;
case 0x50:
mode = B_DPMS_OFF;
break;
default:
TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d));
}
TRACE("Trio64_DPMSMode() mode: %d\n", mode);
return mode;
}
status_t
Trio64_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("Trio64_SetDPMSMode() mode: %d\n", dpmsMode);
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 sr0D = ReadSeqReg(0x0d) & 0x03;
switch (dpmsMode) {
case B_DPMS_ON:
break;
case B_DPMS_STAND_BY:
sr0D |= 0x10;
break;
case B_DPMS_SUSPEND:
sr0D |= 0x40;
break;
case B_DPMS_OFF:
sr0D |= 0x50;
break;
default:
TRACE("Invalid DPMS mode %d\n", dpmsMode);
return B_ERROR;
}
WriteSeqReg(0x0d, sr0D);
return B_OK;
}

View File

@ -0,0 +1,155 @@
/*
Haiku S3 Trio64 driver adapted from the X.org S3 driver.
Copyright 2001 Ani Joshi <ajoshi@unixbox.com>
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#include "accel.h"
#include "trio64.h"
void
Trio64_FillRectangle(engine_token* et, uint32 color, fill_rect_params* pList,
uint32 count)
{
(void)et; // avoid compiler warning for unused arg
gInfo.WaitQueue(3);
WriteReg16(MULTIFUNC_CNTL, 0xa000);
WriteReg32(FRGD_COLOR, color);
WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x07); // 7 = GXcopy rop
while (count--) {
int x = pList->left;
int y = pList->top;
int w = pList->right - x;
int h = pList->bottom - y;
gInfo.WaitQueue(5);
WriteReg16(CUR_X, x);
WriteReg16(CUR_Y, y);
WriteReg16(CUR_WIDTH, w);
WriteReg16(MULTIFUNC_CNTL, h);
WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA);
pList++;
}
}
void
Trio64_FillSpan(engine_token* et, uint32 color, uint16* pList, uint32 count)
{
(void)et; // avoid compiler warning for unused arg
gInfo.WaitQueue(3);
WriteReg16(MULTIFUNC_CNTL, 0xa000);
WriteReg32(FRGD_COLOR, color);
WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x07); // 7 = GXcopy rop
while (count--) {
int y = *pList++;
int x = *pList++;
int w = *pList++ - x;
// Some S3 chips display a line completely across the screen when a
// span has zero width; thus, the following if statement discards any
// span with zero or negative width.
if (w < 0)
continue;
// Draw the span as a rectangle with a height of 1 to avoid the
// extra complexity of drawing a line.
gInfo.WaitQueue(5);
WriteReg16(CUR_X, x);
WriteReg16(CUR_Y, y);
WriteReg16(CUR_WIDTH, w);
WriteReg16(MULTIFUNC_CNTL, 0); // height is 1; but as computed it is 0
WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA);
}
}
void
Trio64_InvertRectangle(engine_token* et, fill_rect_params* pList, uint32 count)
{
(void)et; // avoid compiler warning for unused arg
gInfo.WaitQueue(2);
WriteReg16(MULTIFUNC_CNTL, 0xa000);
WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x00); // 0 = GXinvert rop
while (count--) {
int x = pList->left;
int y = pList->top;
int w = pList->right - x;
int h = pList->bottom - y;
gInfo.WaitQueue(5);
WriteReg16(CUR_X, x);
WriteReg16(CUR_Y, y);
WriteReg16(CUR_WIDTH, w);
WriteReg16(MULTIFUNC_CNTL, h);
WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA);
pList++;
}
}
void
Trio64_ScreenToScreenBlit(engine_token* et, blit_params* pList, uint32 count)
{
(void)et; // avoid compiler warning for unused arg
gInfo.WaitQueue(2);
WriteReg16(MULTIFUNC_CNTL, 0xa000);
WriteReg16(FRGD_MIX, FSS_BITBLT | 0x07); // 7 = GXcopy rop
while (count--) {
int src_x = pList->src_left;
int src_y = pList->src_top;
int dest_x = pList->dest_left;
int dest_y = pList->dest_top;
int width = pList->width;
int height = pList->height;
if (src_x == dest_x && src_y == dest_y)
continue;
int cmd = CMD_BITBLT | DRAW | INC_X | INC_Y | WRTDATA;
if (src_x < dest_x) {
src_x += width;
dest_x += width;
cmd &= ~INC_X;
}
if (src_y < dest_y) {
src_y += height;
dest_y += height;
cmd &= ~INC_Y;
}
gInfo.WaitQueue(7);
WriteReg16(CUR_X, src_x);
WriteReg16(CUR_Y, src_y);
WriteReg16(DESTX_DIASTP, dest_x);
WriteReg16(DESTY_AXSTP, dest_y);
WriteReg16(CUR_WIDTH, width);
WriteReg16(MULTIFUNC_CNTL, height);
WriteReg16(CMD, cmd);
pList ++;
}
}

View File

@ -0,0 +1,176 @@
/*
Haiku S3 Trio64 driver adapted from the X.org S3 driver.
Copyright 2001 Ani Joshi <ajoshi@unixbox.com>
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#include "accel.h"
#include "trio64.h"
static void
WaitQueue(uint32 slots )
{
// Wait until the requested number of queue slots are available.
while (ReadReg16(GP_STAT) & (0x0100 >> slots)) {}
}
static void
WaitIdle()
{
// Wait until Graphics Processor is idle.
while (ReadReg16(GP_STAT) & GP_BUSY);
}
static bool
Trio64_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
{
// Get parameters for a color space which is supported by the Trio64 chips.
// Argument maxPixelClock is in KHz.
// Return true if the color space is supported; else return false.
switch (colorSpace) {
case B_RGB16:
bitsPerPixel = 16;
maxPixelClock = 110000;
break;
case B_CMAP8:
bitsPerPixel = 8;
maxPixelClock = 180000;
break;
default:
TRACE("Unsupported color space: 0x%X\n", colorSpace);
return false;
}
return true;
}
static bool
Trio64_IsModeUsable(const display_mode* mode)
{
// Test if the display mode is usable by the current video chip.
// Return true if the mode is usable.
SharedInfo& si = *gInfo.sharedInfo;
if (si.chipType == S3_TRIO64 && mode->timing.h_display >= 1600)
return false;
return IsModeUsable(mode);
}
static status_t
Trio64_Init(void)
{
TRACE("Trio64_Init()\n");
SharedInfo& si = *gInfo.sharedInfo;
// Use PIO to enable VGA, enable color instead of monochrome, and
// enable MMIO.
WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01);
WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01); // enable color
WritePIO_8(CRTC_INDEX, 0x53);
WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8); // enable MMIO
WriteCrtcReg(0x38, 0x48); // unlock sys regs
WriteCrtcReg(0x39, 0xa5); // unlock sys regs
WriteCrtcReg(0x40, 0x01, 0x01);
WriteCrtcReg(0x35, 0x00, 0x30);
WriteCrtcReg(0x33, 0x20, 0x72);
if (si.chipType == S3_TRIO64_V2) {
WriteCrtcReg(0x86, 0x80);
WriteCrtcReg(0x90, 0x00);
}
// Detect number of megabytes of installed ram.
static const uint8 ramSizes[] = { 4, 0, 3, 8, 2, 6, 1, 0 };
int ramSizeMB = ramSizes[(ReadCrtcReg(0x36) >> 5) & 0x7];
TRACE("memory size: %d MB\n", ramSizeMB);
if (ramSizeMB <= 0)
return B_ERROR;
si.videoMemSize = ramSizeMB * 1024 * 1024;
si.cursorOffset = si.videoMemSize - CURSOR_BYTES; // put cursor at end of video memory
si.frameBufferOffset = 0;
si.maxFrameBufferSize = si.videoMemSize - CURSOR_BYTES;
// Detect current mclk.
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 m = ReadSeqReg(0x11) & 0x7f;
uint8 n = ReadSeqReg(0x10);
uint8 n1 = n & 0x1f;
uint8 n2 = (n >> 5) & 0x03;
si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
TRACE("MCLK value: %1.3f MHz\n", si.mclk / 1000.0);
// Set up the array of color spaces supported by the Trio64 chips.
si.colorSpaces[0] = B_CMAP8;
si.colorSpaces[1] = B_RGB16;
si.colorSpaceCount = 2;
// Setup the mode list.
return CreateModeList(Trio64_IsModeUsable);
}
void
Trio64_SetFunctionPointers(void)
{
// Setting the function pointers must be done prior to first ModeInit call
// or any accel activity.
gInfo.WaitQueue = WaitQueue;
gInfo.WaitIdleEmpty = WaitIdle;
gInfo.DPMSCapabilities = Trio64_DPMSCapabilities;
gInfo.DPMSMode = Trio64_DPMSMode;
gInfo.SetDPMSMode = Trio64_SetDPMSMode;
gInfo.LoadCursorImage = Trio64_LoadCursorImage;
gInfo.SetCursorPosition = Trio64_SetCursorPosition;
gInfo.ShowCursor = Trio64_ShowCursor;
// Note that the 2D accel functions set below do not work with all display
// modes; thus, when a mode is set, the function setting the mode will
// adjust the pointers according to the mode that is set.
gInfo.FillRectangle = Trio64_FillRectangle;
gInfo.FillSpan = Trio64_FillSpan;
gInfo.InvertRectangle = Trio64_InvertRectangle;
gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit;
gInfo.AdjustFrame = Trio64_AdjustFrame;
gInfo.ChipInit = Trio64_Init;
gInfo.GetColorSpaceParams = Trio64_GetColorSpaceParams;
gInfo.SetDisplayMode = Trio64_SetDisplayMode;
gInfo.SetIndexedColors = Trio64_SetIndexedColors;
}

View File

@ -0,0 +1,333 @@
/*
Haiku S3 Trio64 driver adapted from the X.org S3 driver.
Copyright 2001 Ani Joshi <ajoshi@unixbox.com>
Copyright 2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2008
*/
#include "accel.h"
#include "trio64.h"
#define BASE_FREQ 14.31818 // MHz
static void
Trio64_CalcClock(long freq, int min_m, int min_n1, int max_n1,
int min_n2, int max_n2, long freq_min, long freq_max,
uint8* mdiv, uint8* ndiv)
{
uint8 best_n1 = 18, best_n2 = 2, best_m = 127;
double ffreq = freq / 1000.0 / BASE_FREQ;
double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
if (ffreq < ffreq_min / (1 << max_n2)) {
TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n",
ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1 << max_n2));
ffreq = ffreq_min / (1 << max_n2);
}
if (ffreq > ffreq_max / (1 << min_n2)) {
TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n",
ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1 << min_n2));
ffreq = ffreq_max / (1 << min_n2);
}
double best_diff = ffreq;
for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
int m = (int)(ffreq * n1 * (1 << n2) + 0.5);
if (m < min_m + 2 || m > 127 + 2)
continue;
double div = (double)(m) / (double)(n1);
if ((div >= ffreq_min) && (div <= ffreq_max)) {
double diff = ffreq - div / (1 << n2);
if (diff < 0.0)
diff = -diff;
if (diff < best_diff) {
best_diff = diff;
best_m = m;
best_n1 = n1;
best_n2 = n2;
}
}
}
}
if (max_n1 == 63)
*ndiv = (best_n1 - 2) | (best_n2 << 6);
else
*ndiv = (best_n1 - 2) | (best_n2 << 5);
*mdiv = best_m - 2;
}
static bool
Trio64_ModeInit(const DisplayModeEx& mode)
{
SharedInfo& si = *gInfo.sharedInfo;
TRACE("Trio64_ModeInit(%d x %d, %d KHz)\n",
mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
uint32 videoRamMB = si.videoMemSize / (1024 * 1024); // MB's of video RAM
WriteCrtcReg(0x38, 0x48); // unlock sys regs
WriteCrtcReg(0x39, 0xa5); // unlock sys regs
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
WriteCrtcReg(0x45, 0x00, 0x01); // turn off hardware cursor
uint8 sr12, sr13;
Trio64_CalcClock(mode.timing.pixel_clock, 1, 1, 31, 0, 3, 135000, 270000,
&sr13, &sr12);
// Set clock registers.
WriteSeqReg(0x12, sr12);
WriteSeqReg(0x13, sr13);
// Activate clock
uint8 tmp = ReadSeqReg(0x15) & ~0x21;
WriteSeqReg(0x15, tmp | 0x02);
WriteSeqReg(0x15, tmp | 0x22);
WriteSeqReg(0x15, tmp | 0x02);
uint8 cr33 = ReadCrtcReg(0x33) & ~0x28;
uint8 cr50 = 0;
uint8 pixmux = 0;
if (si.chipType == S3_TRIO64_V2)
cr33 |= 0x20;
switch (mode.bpp) {
case 8:
break;
case 15:
cr33 |= 0x08;
cr50 = 0x10;
pixmux = 0x30;
break;
case 16:
cr33 |= 0x08;
cr50 = 0x10;
pixmux = 0x50;
break;
case 32:
cr50 = 0x30;
pixmux = 0xd0;
break;
}
bool bEnableAccelFuncs = true;
switch (mode.timing.h_display) {
case 640:
cr50 |= 0x40;
break;
case 800:
cr50 |= 0x80;
break;
case 1024:
cr50 |= 0x00;
break;
case 1152:
cr50 |= 0x01;
break;
case 1280:
cr50 |= 0xc0;
break;
case 1600:
cr50 |= 0x81;
break;
default:
bEnableAccelFuncs = false; // use app_server default accel functions
break;
}
WriteCrtcReg(0x33, cr33);
WriteCrtcReg(0x50, cr50); // set number of bits per pixel & display width
WriteCrtcReg(0x67, pixmux); // set pixel format
WriteSeqReg(0x15, 0x00, 0x10); // turn off pixel multiplex
WriteSeqReg(0x18, 0x00, 0x80);
// Note that the 2D acceleration (drawing) functions in this accelerant work
// only with the display widths defined in the above switch statement. For
// the other widths, the default functions in the app_server will be used.
if (bEnableAccelFuncs)
{
gInfo.FillRectangle = Trio64_FillRectangle;
gInfo.FillSpan = Trio64_FillSpan;
gInfo.InvertRectangle = Trio64_InvertRectangle;
gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit;
}
else
{
gInfo.FillRectangle = NULL;
gInfo.FillSpan = NULL;
gInfo.InvertRectangle = NULL;
gInfo.ScreenToScreenBlit = NULL;
}
// Set the standard CRTC vga regs.
uint8 crtc[25], cr3b, cr3c, cr5d, cr5e;
InitCrtcTimingValues(mode, (mode.bpp > 8) ? 2 : 1, crtc, cr3b, cr3c, cr5d, cr5e);
crtc[0x17] = 0xe3;
WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11
for (int k = 0; k < NUM_ELEMENTS(crtc); k++) {
WriteCrtcReg(k, crtc[k]);
}
WriteCrtcReg(0x3b, cr3b);
WriteCrtcReg(0x3c, cr3c);
WriteCrtcReg(0x5d, cr5d);
WriteCrtcReg(0x5e, cr5e);
uint8 miscOutReg = 0x2f;
if ( ! (mode.timing.flags & B_POSITIVE_HSYNC))
miscOutReg |= 0x40;
if ( ! (mode.timing.flags & B_POSITIVE_VSYNC))
miscOutReg |= 0x80;
WriteMiscOutReg(miscOutReg);
uint8 cr58;
if (videoRamMB <= 1)
cr58 = 0x01;
else if (videoRamMB <= 2)
cr58 = 0x02;
else
cr58 = 0x03;
WriteCrtcReg(0x58, cr58 | 0x10, 0x13); // enable linear addressing & set memory size
WriteCrtcReg(0x31, 0x08);
WriteCrtcReg(0x32, 0x00);
WriteCrtcReg(0x34, 0x10);
WriteCrtcReg(0x3a, 0x15);
WriteCrtcReg(0x51, mode.bytesPerRow >> 7, 0x30);
WriteCrtcReg(0x53, 0x18, 0x18);
int n = 255;
int clock2 = mode.timing.pixel_clock * (mode.bpp / 8);
if (videoRamMB < 2)
clock2 *= 2;
int m = (int)((gInfo.sharedInfo->mclk / 1000.0 * .72 + 16.867) * 89.736
/ (clock2 / 1000.0 + 39) - 21.1543);
if (videoRamMB < 2)
m /= 2;
if (m > 31)
m = 31;
else if (m < 0) {
m = 0;
n = 16;
}
if (n < 0)
n = 0;
else if (n > 255)
n = 255;
WriteCrtcReg(0x54, m << 3);
WriteCrtcReg(0x60, n);
WriteCrtcReg(0x42, 0x00, 0x20); // disable interlace mode
WriteCrtcReg(0x66, 0x89, 0x8f);
WriteReg16(ADVFUNC_CNTL, 0x0001); // enable enhanced functions
WriteReg16(SUBSYS_CNTL, 0x8000); // reset graphics engine
WriteReg16(SUBSYS_CNTL, 0x4000); // enable graphics engine
ReadReg16(SUBSYS_STAT);
WriteReg16(MULTIFUNC_CNTL, 0x5000 | 0x0004 | 0x000c);
gInfo.WaitQueue(5);
WriteReg16(MULTIFUNC_CNTL, SCISSORS_L | 0);
WriteReg16(MULTIFUNC_CNTL, SCISSORS_T | 0);
WriteReg16(MULTIFUNC_CNTL, SCISSORS_R | (mode.timing.h_display - 1));
WriteReg16(MULTIFUNC_CNTL, SCISSORS_B | ((si.maxFrameBufferSize / mode.bytesPerRow) - 1));
WriteReg32(WRT_MASK, ~0); // enable all planes
TRACE("Trio64_ModeInit() exit\n");
return true;
}
bool
Trio64_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.
WriteSeqReg(0x01, 0x20, 0x20); // blank the screen
if ( ! Trio64_ModeInit(mode)) {
TRACE("Trio64_ModeInit() failed\n");
return false;
}
Trio64_AdjustFrame(mode);
WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen
return true;
}
void
Trio64_AdjustFrame(const DisplayModeEx& mode)
{
// Adjust start address in frame buffer.
int base = (((mode.v_display_start * mode.virtual_width + mode.h_display_start)
* (mode.bpp / 8)) >> 2) & ~1;
base += gInfo.sharedInfo->frameBufferOffset;
WriteCrtcReg(0x0c, (base >> 8) & 0xff);
WriteCrtcReg(0x0d, base & 0xff);
WriteCrtcReg(0x31, base >> 12, 0x30); // put bits 16-17 in bits 4-5 of CR31
WriteCrtcReg(0x51, base >> 18, 0x03); // put bits 18-19 in bits 0-1 of CR51
}
void
Trio64_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 ;
while (count--) {
WriteIndexedColor(first++, // color index
colorData[0] >> 2, // red
colorData[1] >> 2, // green
colorData[2] >> 2); // blue
colorData += 3;
}
}

View File

@ -0,0 +1,78 @@
/*
Haiku S3 Virge driver adapted from the X.org S3 Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#ifndef __VIRGE_H__
#define __VIRGE_H__
#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory
// Miscellaneous registers.
#define SUBSYS_STAT_REG 0x8504
#define SYSTEM_CONTROL_REG 0x83DA
#define DDC_REG 0xFF20
// Memory port controller registers.
#define FIFO_CONTROL_REG 0x8200
// Image write stuff.
#define SRC_BASE 0xA4D4
#define DEST_BASE 0xA4D8
#define CLIP_L_R 0xA4DC
#define CLIP_T_B 0xA4E0
#define DEST_SRC_STR 0xA4E4
#define MONO_PAT_0 0xA4E8
#define MONO_PAT_1 0xA4EC
#define PAT_BG_CLR 0xA4F0
#define PAT_FG_CLR 0xA4F4
#define CMD_SET 0xA500
#define RWIDTH_HEIGHT 0xA504
#define RSRC_XY 0xA508
#define RDEST_XY 0xA50C
// Command Register.
#define CMD_OP_MSK (0xf << 27)
#define CMD_BITBLT (0x0 << 27)
#define CMD_RECT ((0x2 << 27) | 0x0100)
#define CMD_LINE (0x3 << 27)
#define CMD_POLYFILL (0x5 << 27)
#define CMD_NOP (0xf << 27)
#define DRAW 0x0020
// Destination Color Format.
#define DST_8BPP 0x00
#define DST_16BPP 0x04
#define DST_24BPP 0x08
// X Positive, Y Positive (Bit BLT).
#define CMD_XP 0x02000000
#define CMD_YP 0x04000000
#define IN_SUBSYS_STAT() (ReadReg32(SUBSYS_STAT_REG))
static inline void VerticalRetraceWait()
{
if (ReadCrtcReg(0x17) & 0x80) {
int i = 0x10000;
while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ;
i = 0x10000;
while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ;
}
}
#endif // __VIRGE_H__

View File

@ -0,0 +1,112 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "virge.h"
void
Virge_ShowCursor(bool bShow)
{
// Turn cursor on/off.
WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01);
}
void
Virge_SetCursorPosition(int x, int y)
{
uint8 xOffset = 0;
uint8 yOffset = 0;
// xOffset & yOffset are used for displaying partial cursors on screen edges.
if (x < 0) {
xOffset = (( -x) & 0xfe);
x = 0;
}
if (y < 0) {
yOffset = (( -y) & 0xfe);
y = 0;
}
// Note: when setting the cursor position, register 48 must be set last
// since setting register 48 activates the new cursor position.
WriteCrtcReg( 0x4e, xOffset );
WriteCrtcReg( 0x4f, yOffset );
WriteCrtcReg( 0x47, (x & 0xff) );
WriteCrtcReg( 0x46, (x & 0x0700) >> 8 );
WriteCrtcReg( 0x49, (y & 0xff) );
WriteCrtcReg( 0x48, (y & 0x0700) >> 8 );
}
bool
Virge_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
{
SharedInfo& si = *gInfo.sharedInfo;
if (andMask == NULL || xorMask == NULL)
return false;
// Initialize hardware cursor to be completely transparent.
uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset);
for (int i = 0; i < CURSOR_BYTES; i += 4) {
*fbCursor16++ = ~0; // and bits
*fbCursor16++ = 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 + 2] = *xorMask++;
}
}
// Set cursor location in video memory.
WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024));
WriteCrtcReg(0x4c, (0x0f00 & si.cursorOffset / 1024) >> 8);
// Set the cursor colors which are black foreground and white background.
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes
WriteCrtcReg(0x4a, 0);
WriteCrtcReg(0x4a, 0);
ReadCrtcReg(0x45); // reset cursor color stack pointer
WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes
WriteCrtcReg(0x4b, ~0);
WriteCrtcReg(0x4b, ~0);
return true;
}

View File

@ -0,0 +1,93 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "virge.h"
uint32
Virge_DPMSCapabilities(void)
{
// Return DPMS modes supported by this device.
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
}
uint32
Virge_DPMSMode(void)
{
// Return the current DPMS mode.
// Note: I do not know whether the following code is correctly reading
// the current DPMS mode. I'm assuming that reading back the bits that
// were set by function Virge_SetDPMSMode will give the current DPMS mode.
uint32 mode = B_DPMS_ON;
switch (ReadSeqReg(0x0d) & 0x70) {
case 0:
mode = B_DPMS_ON;
break;
case 0x10:
mode = B_DPMS_STAND_BY;
break;
case 0x40:
mode = B_DPMS_SUSPEND;
break;
case 0x50:
mode = B_DPMS_OFF;
break;
default:
TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d));
}
TRACE("Virge_DPMSMode() mode: %d\n", mode);
return mode;
}
status_t
Virge_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("Virge_SetDPMSMode() mode: %d\n", dpmsMode);
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 sr0D = ReadSeqReg(0x0d) & 0x03;
switch (dpmsMode) {
case B_DPMS_ON:
break;
case B_DPMS_STAND_BY:
sr0D |= 0x10;
break;
case B_DPMS_SUSPEND:
sr0D |= 0x40;
break;
case B_DPMS_OFF:
sr0D |= 0x50;
break;
default:
TRACE("Invalid DPMS mode %d\n", dpmsMode);
return B_ERROR;
}
WriteSeqReg(0x0d, sr0D);
return B_OK;
}

View File

@ -0,0 +1,161 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007
*/
#include "accel.h"
#include "virge.h"
static inline void WaitForSync()
{
while ((IN_SUBSYS_STAT() & 0x2000) == 0) ;
}
void
Virge_FillRectangle(engine_token* et, uint32 color, fill_rect_params* pList, uint32 count)
{
int rop = 0xF0;
int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP ;
(void)et; // avoid compiler warning for unused arg
cmd |= gInfo.sharedInfo->commonCmd;
while (count--) {
int x = pList->left;
int y = pList->top;
int w = pList->right - x + 1;
int h = pList->bottom - y + 1;
gInfo.WaitQueue(4);
WriteReg32(PAT_FG_CLR, color);
WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) | h);
WriteReg32(RDEST_XY, (x << 16) | y);
WriteReg32(CMD_SET, cmd);
WaitForSync();
pList++;
}
}
void
Virge_FillSpan(engine_token* et, uint32 color, uint16* pList, uint32 count)
{
int rop = 0xF0;
int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP ;
(void)et; // avoid compiler warning for unused arg
cmd |= gInfo.sharedInfo->commonCmd;
while (count--) {
int y = *pList++;
int x = *pList++;
int w = *pList++ - x + 1;
// The MediaPlayer in Zeta 1.21 displays a window which has 2 zero width
// spans which the Virge chips display as a line completely across the
// screen; thus, the following if statement discards any span with zero
// or negative width.
if (w <= 0)
continue;
// Draw the span as a rectangle with a height of 1 to avoid the
// extra complexity of drawing a line.
gInfo.WaitQueue(4);
WriteReg32(PAT_FG_CLR, color);
WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) | 1);
WriteReg32(RDEST_XY, (x << 16) | y);
WriteReg32(CMD_SET, cmd);
WaitForSync();
}
}
void
Virge_InvertRectangle(engine_token* et, fill_rect_params* pList, uint32 count)
{
int rop = 0x55; // use GXinvert for rop
int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP;
(void)et; // avoid compiler warning for unused arg
cmd |= gInfo.sharedInfo->commonCmd;
while (count--) {
int x = pList->left;
int y = pList->top;
int w = pList->right - x + 1;
int h = pList->bottom - y + 1;
gInfo.WaitQueue(3);
WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) + h);
WriteReg32(RDEST_XY, (x << 16) | y);
WriteReg32(CMD_SET, cmd);
WaitForSync();
pList++;
}
}
void
Virge_ScreenToScreenBlit(engine_token* et, blit_params* pList, uint32 count)
{
int rop = 0xCC; // use GXcopy for rop
int cmd = DRAW | rop << 17 | CMD_BITBLT | CMD_XP | CMD_YP;
(void)et; // avoid compiler warning for unused arg
cmd |= gInfo.sharedInfo->commonCmd;
while (count--) {
int src_x = pList->src_left;
int src_y = pList->src_top;
int dest_x = pList->dest_left;
int dest_y = pList->dest_top;
int width = pList->width;
int height = pList->height;
if (src_x == dest_x && src_y == dest_y)
continue;
cmd |= CMD_XP | CMD_YP; // restore these flags in case removed on last iteration
if (src_x < dest_x) {
src_x += width;
dest_x += width;
cmd &= ~CMD_XP;
}
if (src_y < dest_y) {
src_y += height;
dest_y += height;
cmd &= ~CMD_YP;
}
gInfo.WaitQueue(4);
WriteReg32(RWIDTH_HEIGHT, ((width) << 16) | (height + 1));
WriteReg32(RSRC_XY, (src_x << 16) | src_y);
WriteReg32(RDEST_XY, (dest_x << 16) | dest_y);
WriteReg32(CMD_SET, cmd);
WaitForSync();
pList ++;
}
}

View File

@ -0,0 +1,130 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge and Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "virge.h"
#include <string.h>
#include <ddc.h>
#include <edid.h>
static status_t
GetI2CSignals_Alt(void* cookie, int* _clock, int* data)
{
uint32 index = (uint32)cookie;
uint8 value = ReadCrtcReg(index);
*_clock = (value & 0x4) != 0;
*data = (value & 0x8) != 0;
return B_OK;
}
static status_t
SetI2CSignals_Alt(void* cookie, int _clock, int data)
{
uint32 index = (uint32)cookie;
uint8 value = 0x10;
if (_clock)
value |= 0x1;
if (data)
value |= 0x2;
WriteCrtcReg(index, value);
return B_OK;
}
static status_t
GetI2CSignals(void* cookie, int* _clock, int* data)
{
(void)cookie; // avoid compiler warning for unused arg
uint8 reg = ReadReg8(DDC_REG);
*_clock = (reg & 0x4) != 0;
*data = (reg & 0x8) != 0;
return B_OK;
}
static status_t
SetI2CSignals(void* cookie, int _clock, int data)
{
(void)cookie; // avoid compiler warning for unused arg
uint8 reg = 0x10;
if (_clock)
reg |= 0x1;
if (data)
reg |= 0x2;
WriteReg8(DDC_REG, reg);
return B_OK;
}
bool
Virge_GetEdidInfo(void)
{
// Get the EDID info and return true if successful.
SharedInfo& si = *gInfo.sharedInfo;
si.bHaveEDID = false;
if (si.chipType == S3_TRIO_3D_2X) {
uint32 DDCPort = 0xAA;
i2c_bus bus;
bus.cookie = (void*)DDCPort;
bus.set_signals = &SetI2CSignals_Alt;
bus.get_signals = &GetI2CSignals_Alt;
ddc2_init_timing(&bus);
uint8 tmp = ReadCrtcReg(DDCPort);
WriteCrtcReg(DDCPort, tmp | 0x13);
si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK);
WriteCrtcReg(DDCPort, tmp);
} else {
i2c_bus bus;
bus.cookie = (void*)DDC_REG;
bus.set_signals = &SetI2CSignals;
bus.get_signals = &GetI2CSignals;
ddc2_init_timing(&bus);
uint8 tmp = ReadReg8(DDC_REG);
WriteReg8(DDC_REG, tmp | 0x13);
si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK);
WriteReg8(DDC_REG, tmp);
}
if (si.bHaveEDID) {
#ifdef ENABLE_DEBUG_TRACE
edid_dump(&(si.edidInfo));
#endif
} else {
TRACE("Virge_GetEdidInfo() failed!\n");
}
return si.bHaveEDID;
}

View File

@ -0,0 +1,271 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "virge.h"
static void
VirgeWaitFifoGX2(uint32 slots )
{
while (((ReadReg32(SUBSYS_STAT_REG) >> 9) & 0x60) < slots) {}
}
static void
VirgeWaitFifoMain(uint32 slots )
{
while (((ReadReg32(SUBSYS_STAT_REG) >> 8) & 0x1f) < slots) {}
}
static void
VirgeWaitIdleEmpty()
{
// Wait until GP is idle and queue is empty.
if(gInfo.sharedInfo->chipType == S3_TRIO_3D)
while ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000);
else
while ((IN_SUBSYS_STAT() & 0x3f00) != 0x3000);
}
static bool
Virge_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
{
// Get parameters for a color space which is supported by the Virge chips.
// Argument maxPixelClock is in KHz.
// Return true if the color space is supported; else return false.
// Note that the X.org code set the max clock to 440000 for a Virge VX chip
// and 270000 for all other chips. 440000 seems rather high for a chip that
// old; thus, 270000 is used for all chips.
switch (colorSpace) {
case B_RGB16:
bitsPerPixel = 16;
maxPixelClock = 270000;
break;
case B_CMAP8:
bitsPerPixel = 8;
maxPixelClock = 270000;
break;
default:
TRACE("Unsupported color space: 0x%X\n", colorSpace);
return false;
}
return true;
}
status_t
Virge_Init(void)
{
TRACE("Virge_Init()\n");
SharedInfo& si = *gInfo.sharedInfo;
// Use PIO for following operations since MMIO may not be currently enabled.
WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01); // enable VGA
WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01); // enable color
// Set linear base register to the PCI register value;
// some DX chipsets don't seem to do it automatically.
WritePIO_8(CRTC_INDEX, 0x59);
WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 24);
WritePIO_8(CRTC_INDEX, 0x5A);
WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 16);
// Enable MMIO.
WritePIO_8(CRTC_INDEX, 0x53);
WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8);
if (si.chipType == S3_TRIO_3D)
WriteCrtcReg(0x40, 0x01, 0x01);
// Detect amount of installed ram.
uint8 config1 = ReadCrtcReg(0x36); // get amount of vram installed
uint8 config2 = ReadCrtcReg(0x37); // get amount of off-screen ram
// Compute the amount of video memory and offscreen memory.
int ramOffScreenMB = 0; // off screen memory size in megabytes
int ramSizeMB = 0; // memory size in megabytes
if (si.chipType == S3_VIRGE_VX) {
switch ((config2 & 0x60) >> 5) {
case 1:
ramOffScreenMB = 4;
break;
case 2:
ramOffScreenMB = 2;
break;
}
switch ((config1 & 0x60) >> 5) {
case 0:
ramSizeMB = 2;
break;
case 1:
ramSizeMB = 4;
break;
case 2:
ramSizeMB = 6;
break;
case 3:
ramSizeMB = 8;
break;
}
ramSizeMB -= ramOffScreenMB;
} else if (si.chipType == S3_TRIO_3D_2X) {
switch ((config1 & 0xE0) >> 5) {
case 0: // 8MB -- only 4MB usable for display/cursor
ramSizeMB = 4;
ramOffScreenMB = 4;
break;
case 1: // 32 bit interface -- yuck
TRACE("Undefined video memory size on S3 Trio 3D/2X\n");
case 2:
ramSizeMB = 4;
break;
case 6:
ramSizeMB = 2;
break;
}
} else if (si.chipType == S3_TRIO_3D) {
switch ((config1 & 0xE0) >> 5) {
case 0:
case 2:
ramSizeMB = 4;
break;
case 4:
ramSizeMB = 2;
break;
}
} else if (si.chipType == S3_VIRGE_GX2 || S3_VIRGE_MX_SERIES(si.chipType)) {
switch ((config1 & 0xC0) >> 6) {
case 1:
ramSizeMB = 4;
break;
case 3:
ramSizeMB = 2;
break;
}
} else {
switch ((config1 & 0xE0) >> 5) {
case 0:
ramSizeMB = 4;
break;
case 4:
ramSizeMB = 2;
break;
case 6:
ramSizeMB = 1;
break;
}
}
TRACE("usable memory: %d MB, off-screen memory: %d MB\n", ramSizeMB, ramOffScreenMB);
if (ramSizeMB <= 0)
return B_ERROR;
si.videoMemSize = ramSizeMB * 1024 * 1024;
si.cursorOffset = si.videoMemSize - CURSOR_BYTES; // put cursor at end of video memory
si.frameBufferOffset = 0;
si.maxFrameBufferSize = si.videoMemSize - CURSOR_BYTES;
// Detect current mclk.
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
uint8 m = ReadSeqReg(0x11) & 0x7f;
uint8 n = ReadSeqReg(0x10);
uint8 n1 = n & 0x1f;
uint8 n2 = (n >> 5) & 0x03;
si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
if (S3_VIRGE_MX_SERIES(si.chipType)) {
si.displayType = ((ReadSeqReg(0x31) & 0x10) ? MT_LCD : MT_CRT);
si.panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
si.panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
TRACE("%dx%d LCD panel detected %s\n", si.panelX, si.panelY,
si.displayType == MT_LCD ? "and active" : "but not active");
} else {
si.displayType = MT_CRT;
si.panelX = 0;
si.panelY = 0;
}
// Set up the array of color spaces supported by the Virge/Trio3D chips.
si.colorSpaces[0] = B_CMAP8;
si.colorSpaces[1] = B_RGB16;
si.colorSpaceCount = 2;
// Get info about the display capabilities (EDID).
Virge_GetEdidInfo();
// Setup the mode list.
return CreateModeList(IsModeUsable);
}
void
Virge_SetFunctionPointers(void)
{
// Setting the function pointers must be done prior to first ModeInit call
// or any accel activity.
if (S3_VIRGE_GX2_SERIES(gInfo.sharedInfo->chipType)) {
gInfo.WaitQueue = VirgeWaitFifoGX2;
} else {
gInfo.WaitQueue = VirgeWaitFifoMain;
}
gInfo.WaitIdleEmpty = VirgeWaitIdleEmpty;
gInfo.DPMSCapabilities = Virge_DPMSCapabilities;
gInfo.DPMSMode = Virge_DPMSMode;
gInfo.SetDPMSMode = Virge_SetDPMSMode;
gInfo.LoadCursorImage = Virge_LoadCursorImage;
gInfo.SetCursorPosition = Virge_SetCursorPosition;
gInfo.ShowCursor = Virge_ShowCursor;
gInfo.FillRectangle = Virge_FillRectangle;
gInfo.FillSpan = Virge_FillSpan;
gInfo.InvertRectangle = Virge_InvertRectangle;
gInfo.ScreenToScreenBlit = Virge_ScreenToScreenBlit;
gInfo.AdjustFrame = Virge_AdjustFrame;
gInfo.ChipInit = Virge_Init;
gInfo.GetColorSpaceParams = Virge_GetColorSpaceParams;
gInfo.SetDisplayMode = Virge_SetDisplayMode;
gInfo.SetIndexedColors = Virge_SetIndexedColors;
}

View File

@ -0,0 +1,767 @@
/*
Haiku S3 Virge driver adapted from the X.org Virge driver.
Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
Copyright 2007-2008 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007-2008
*/
#include "accel.h"
#include "virge.h"
#define BASE_FREQ 14.31818 // MHz
struct VirgeRegRec {
uint8 CRTC[25]; // Crtc Controller reg's
uint8 SR0A, SR0F;
uint8 SR12, SR13, SR15, SR18; // SR9-SR1C, ext seq.
uint8 SR29;
uint8 SR54, SR55, SR56, SR57;
uint8 CR31, CR33, CR34, CR3A, CR3B, CR3C;
uint8 CR40, CR41, CR42, CR43, CR45;
uint8 CR51, CR53, CR54, CR58, CR5D, CR5E;
uint8 CR63, CR65, CR66, CR67, CR68, CR69, CR6D; // Video attrib.
uint8 CR7B, CR7D;
uint8 CR85, CR86, CR87;
uint8 CR90, CR91, CR92, CR93;
};
static void
Virge_EngineReset(const DisplayModeEx& mode)
{
SharedInfo& si = *gInfo.sharedInfo;
switch (mode.bpp) {
case 8:
si.commonCmd = DRAW | DST_8BPP;
break;
case 16:
si.commonCmd = DRAW | DST_16BPP;
break;
case 24:
si.commonCmd = DRAW | DST_24BPP;
break;
}
gInfo.WaitQueue(6);
WriteReg32(CMD_SET, CMD_NOP); // turn off auto-execute
WriteReg32(SRC_BASE, 0);
WriteReg32(DEST_BASE, 0);
WriteReg32(DEST_SRC_STR, mode.bytesPerRow | (mode.bytesPerRow << 16));
WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display);
WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display);
}
static void
Virge_NopAllCmdSets()
{
// This function should be called only for the Trio 3D chip.
for (int i = 0; i < 1000; i++) {
if ( (IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) == 0x20002000) {
break;
}
}
gInfo.WaitQueue(7);
WriteReg32(CMD_SET, CMD_NOP);
}
static void
Virge_GEReset(const DisplayModeEx& mode)
{
SharedInfo& si = *gInfo.sharedInfo;
if (si.chipType == S3_TRIO_3D)
Virge_NopAllCmdSets();
gInfo.WaitIdleEmpty();
if (si.chipType == S3_TRIO_3D) {
bool ge_was_on = false;
snooze(10000);
for (int r = 1; r < 10; r++) {
uint8 resetidx = 0x66;
VerticalRetraceWait();
uint8 tmp = ReadCrtcReg(resetidx);
VerticalRetraceWait();
IN_SUBSYS_STAT();
// turn off the GE
if (tmp & 0x01) {
WriteCrtcReg(resetidx, tmp);
ge_was_on = true;
snooze(10000);
}
IN_SUBSYS_STAT();
WriteCrtcReg(resetidx, tmp | 0x02);
snooze(10000);
VerticalRetraceWait();
WriteCrtcReg(resetidx, tmp & ~0x02);
snooze(10000);
if (ge_was_on) {
tmp |= 0x01;
WriteCrtcReg(resetidx, tmp);
snooze(10000);
}
VerticalRetraceWait();
Virge_NopAllCmdSets();
gInfo.WaitIdleEmpty();
WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
snooze(10000);
if ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000) {
TRACE("Restarting S3 graphics engine reset %2d ...%lx\n",
r, IN_SUBSYS_STAT() );
} else
break;
}
} else {
uint8 regIndex = (si.chipType == S3_VIRGE_VX ? 0x63 : 0x66);
uint8 tmp = ReadCrtcReg(regIndex);
snooze(10000);
// try multiple times to avoid lockup of VIRGE/MX
for (int r = 1; r < 10; r++) {
WriteCrtcReg(regIndex, tmp | 0x02);
snooze(10000);
WriteCrtcReg(regIndex, tmp & ~0x02);
snooze(10000);
gInfo.WaitIdleEmpty();
WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
snooze(10000);
if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) {
TRACE("Restarting S3 graphics engine reset %2d ...\n", r);
} else
break;
}
}
gInfo.WaitQueue(2);
WriteReg32(SRC_BASE, 0);
WriteReg32(DEST_BASE, 0);
gInfo.WaitQueue(4);
WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display);
WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display);
WriteReg32(MONO_PAT_0, ~0);
WriteReg32(MONO_PAT_1, ~0);
if (si.chipType == S3_TRIO_3D)
Virge_NopAllCmdSets();
}
static void
Virge_CalcClock(long freq, int min_m,
int min_n1, int max_n1,
int min_n2, int max_n2,
long freq_min, long freq_max,
uint8* mdiv, uint8* ndiv)
{
uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
double ffreq = freq / 1000.0 / BASE_FREQ;
double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
if (ffreq < ffreq_min / (1 << max_n2)) {
TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f MHz]\n",
ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2) );
ffreq = ffreq_min / (1 << max_n2);
}
if (ffreq > ffreq_max / (1 << min_n2)) {
TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f MHz]\n",
ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2) );
ffreq = ffreq_max / (1 << min_n2);
}
// Work out suitable timings.
double best_diff = ffreq;
for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
int m = (int)(ffreq * n1 * (1 << n2) + 0.5) ;
if (m < min_m + 2 || m > 127 + 2)
continue;
double div = (double)(m) / (double)(n1);
if ((div >= ffreq_min) && (div <= ffreq_max)) {
double diff = ffreq - div / (1 << n2);
if (diff < 0.0)
diff = -diff;
if (diff < best_diff) {
best_diff = diff;
best_m = m;
best_n1 = n1;
best_n2 = n2;
}
}
}
}
if (max_n1 == 63)
*ndiv = (best_n1 - 2) | (best_n2 << 6);
else
*ndiv = (best_n1 - 2) | (best_n2 << 5);
*mdiv = best_m - 2;
}
static void
Virge_WriteMode(const DisplayModeEx& mode, VirgeRegRec& regRec)
{
// This function writes out all of the standard VGA and extended S3 registers
// needed to setup a video mode.
TRACE("Virge_WriteMode()\n");
SharedInfo& si = *gInfo.sharedInfo;
// First reset GE to make sure nothing is going on.
if (ReadCrtcReg(si.chipType == S3_VIRGE_VX ? 0x63 : 0x66) & 0x01)
Virge_GEReset(mode);
// As per databook, always disable STREAMS before changing modes.
if ((ReadCrtcReg(0x67) & 0x0c) == 0x0c) {
// STREAMS running, disable it
VerticalRetraceWait();
WriteReg32(FIFO_CONTROL_REG, 0xC000);
WriteCrtcReg(0x67, 0x00, 0x0c); // disable STREAMS processor
}
// Restore S3 extended regs.
WriteCrtcReg(0x63, regRec.CR63);
WriteCrtcReg(0x66, regRec.CR66);
WriteCrtcReg(0x3a, regRec.CR3A);
WriteCrtcReg(0x31, regRec.CR31);
WriteCrtcReg(0x58, regRec.CR58);
// Extended mode timings registers.
WriteCrtcReg(0x53, regRec.CR53);
WriteCrtcReg(0x5d, regRec.CR5D);
WriteCrtcReg(0x5e, regRec.CR5E);
WriteCrtcReg(0x3b, regRec.CR3B);
WriteCrtcReg(0x3c, regRec.CR3C);
WriteCrtcReg(0x43, regRec.CR43);
WriteCrtcReg(0x65, regRec.CR65);
WriteCrtcReg(0x6d, regRec.CR6D);
// Restore the desired video mode with CR67.
WriteCrtcReg(0x67, 0x50, 0xf0); // possible hardware bug on VX?
snooze(10000);
WriteCrtcReg(0x67, regRec.CR67 & ~0x0c); // Don't enable STREAMS
// Other mode timing and extended regs.
WriteCrtcReg(0x34, regRec.CR34);
if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) {
WriteCrtcReg(0x40, regRec.CR40);
}
if (S3_VIRGE_MX_SERIES(si.chipType)) {
WriteCrtcReg(0x41, regRec.CR41);
}
WriteCrtcReg(0x42, regRec.CR42);
WriteCrtcReg(0x45, regRec.CR45);
WriteCrtcReg(0x51, regRec.CR51);
WriteCrtcReg(0x54, regRec.CR54);
// Memory timings.
WriteCrtcReg(0x68, regRec.CR68);
WriteCrtcReg(0x69, regRec.CR69);
WriteCrtcReg(0x33, regRec.CR33);
if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType)
/* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) {
WriteCrtcReg(0x85, regRec.CR85);
}
if (si.chipType == S3_VIRGE_DXGX) {
WriteCrtcReg(0x86, regRec.CR86);
}
if ( (si.chipType == S3_VIRGE_GX2) || S3_VIRGE_MX_SERIES(si.chipType) ) {
WriteCrtcReg(0x7b, regRec.CR7B);
WriteCrtcReg(0x7d, regRec.CR7D);
WriteCrtcReg(0x87, regRec.CR87);
WriteCrtcReg(0x92, regRec.CR92);
WriteCrtcReg(0x93, regRec.CR93);
}
if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) ||
S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) {
WriteCrtcReg(0x90, regRec.CR90);
WriteCrtcReg(0x91, regRec.CR91);
}
WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
// Restore extended sequencer regs for DCLK.
WriteSeqReg(0x12, regRec.SR12);
WriteSeqReg(0x13, regRec.SR13);
if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) {
WriteSeqReg(0x29, regRec.SR29);
}
if (S3_VIRGE_MX_SERIES(si.chipType)) {
WriteSeqReg(0x54, regRec.SR54);
WriteSeqReg(0x55, regRec.SR55);
WriteSeqReg(0x56, regRec.SR56);
WriteSeqReg(0x57, regRec.SR57);
}
WriteSeqReg(0x18, regRec.SR18);
// Load new m,n PLL values for DCLK & MCLK.
uint8 tmp = ReadSeqReg(0x15) & ~0x21;
WriteSeqReg(0x15, tmp | 0x03);
WriteSeqReg(0x15, tmp | 0x23);
WriteSeqReg(0x15, tmp | 0x03);
WriteSeqReg(0x15, regRec.SR15);
if (si.chipType == S3_TRIO_3D) {
WriteSeqReg(0x0a, regRec.SR0A);
WriteSeqReg(0x0f, regRec.SR0F);
}
// Now write out CR67 in full, possibly starting STREAMS.
VerticalRetraceWait();
WriteCrtcReg(0x67, 0x50); // For possible bug on VX?!
snooze(10000);
WriteCrtcReg(0x67, regRec.CR67);
uint8 cr66 = ReadCrtcReg(0x66);
WriteCrtcReg(0x66, cr66 | 0x80);
WriteCrtcReg(0x3a, regRec.CR3A | 0x80);
// Now, before we continue, check if this mode has the graphic engine ON.
// If yes, then we reset it.
if (si.chipType == S3_VIRGE_VX) {
if (regRec.CR63 & 0x01)
Virge_GEReset(mode);
} else {
if (regRec.CR66 & 0x01)
Virge_GEReset(mode);
}
VerticalRetraceWait();
if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) {
WriteCrtcReg(0x85, 0x1f); // primary stream threshold
}
// Set the standard CRTC vga regs.
WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11
for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++) {
WriteCrtcReg(j, regRec.CRTC[j]);
}
// Setup HSYNC & VSYNC polarity and select clock source 2 (0x0c) for
// programmable PLL.
uint8 miscOutReg = 0x23 | 0x0c;
if (!(mode.timing.flags & B_POSITIVE_HSYNC))
miscOutReg |= 0x40;
if (!(mode.timing.flags & B_POSITIVE_VSYNC))
miscOutReg |= 0x80;
WriteMiscOutReg(miscOutReg);
WriteCrtcReg(0x66, cr66);
WriteCrtcReg(0x3a, regRec.CR3A);
return ;
}
static bool
Virge_ModeInit(const DisplayModeEx& mode)
{
SharedInfo& si = *gInfo.sharedInfo;
VirgeRegRec regRec;
TRACE("Virge_ModeInit(%d x %d, %d KHz)\n",
mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
// Set scale factors for mode timings.
int horizScaleFactor = 1;
if (si.chipType == S3_VIRGE_VX || S3_VIRGE_GX2_SERIES(si.chipType) ||
S3_VIRGE_MX_SERIES(si.chipType)) {
horizScaleFactor = 1;
} else if (mode.bpp == 8) {
horizScaleFactor = 1;
} else if (mode.bpp == 16) {
if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000)
horizScaleFactor = 1;
else
horizScaleFactor = 2;
} else {
horizScaleFactor = 1;
}
InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC,
regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E);
// Now we fill in the rest of the stuff we need for the Virge.
// Start with MMIO, linear address regs.
uint8 temp = ReadCrtcReg(0x3a);
if ( S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) )
regRec.CR3A = (temp & 0x7f) | 0x10; // ENH 256, PCI burst
else
regRec.CR3A = (temp & 0x7f) | 0x15; // ENH 256, PCI burst
regRec.CR53 = ReadCrtcReg(0x53);
if (si.chipType == S3_TRIO_3D) {
regRec.CR31 = 0x0c; // [trio3d] page 54
} else {
regRec.CR53 = 0x08; // Enables MMIO
regRec.CR31 = 0x8c; // Dis. 64k window, en. ENH maps
}
// Enables S3D graphic engine and PCI disconnects.
if (si.chipType == S3_VIRGE_VX) {
regRec.CR66 = 0x90;
regRec.CR63 = 0x09;
} else {
regRec.CR66 = 0x89;
// Set display fifo.
if ( S3_VIRGE_GX2_SERIES(si.chipType) ||
S3_VIRGE_MX_SERIES(si.chipType) ) {
// Changed from 0x08 based on reports that this
// prevents MX from running properly below 1024x768.
regRec.CR63 = 0x10;
} else {
regRec.CR63 = 0;
}
}
// Now set linear address registers.
// LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX.
regRec.CR58 = ReadCrtcReg(0x58) & 0x80;
if (si.videoMemSize == 1 * 1024 * 1024)
regRec.CR58 |= 0x01 | 0x10;
else if (si.videoMemSize == 2 * 1024 * 1024)
regRec.CR58 |= 0x02 | 0x10;
else {
if (si.chipType == S3_TRIO_3D_2X && si.videoMemSize == 8 * 1024 * 1024)
regRec.CR58 |= 0x07 | 0x10; // 8MB window on Trio3D/2X
else
regRec.CR58 |= 0x03 | 0x10; // 4MB window on virge, 8MB on VX
}
if (si.chipType == S3_VIRGE_VX)
regRec.CR58 |= 0x40;
// ** On PCI bus, no need to reprogram the linear window base address.
// Now do clock PLL programming. Use the s3gendac function to get m,n.
// Also determine if we need doubling etc.
int dclk = mode.timing.pixel_clock;
if (si.chipType == S3_TRIO_3D) {
regRec.SR15 = (ReadSeqReg(0x15) & 0x80) | 0x03; // keep BIOS init defaults
regRec.SR0A = ReadSeqReg(0x0a);
} else
regRec.SR15 = 0x03 | 0x80;
regRec.SR18 = 0x00;
regRec.CR43 = 0x00;
regRec.CR45 = 0x00;
// Enable MMIO to RAMDAC registers.
regRec.CR65 = 0x00; // CR65_2 must be zero, doc seems to be wrong
regRec.CR54 = 0x00;
if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) {
regRec.CR40 = ReadCrtcReg(0x40) & ~0x01;
}
if (S3_VIRGE_MX_SERIES(si.chipType)) {
// Fix problems with APM suspend/resume trashing CR90/91.
switch (mode.bpp) {
case 8:
regRec.CR41 = 0x38;
break;
case 16:
regRec.CR41 = 0x48;
break;
default:
regRec.CR41 = 0x77;
}
}
regRec.CR67 = 0x00; // defaults
if (si.chipType == S3_VIRGE_VX) {
if (mode.bpp == 8) {
if (dclk <= 110000)
regRec.CR67 = 0x00; // 8bpp, 135MHz
else
regRec.CR67 = 0x10; // 8bpp, 220MHz
} else if (mode.bpp == 16) {
if (dclk <= 110000)
regRec.CR67 = 0x40; // 16bpp, 135MHz
else
regRec.CR67 = 0x50; // 16bpp, 220MHz
}
Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 220000, 440000,
&regRec.SR13, &regRec.SR12);
} // end VX if()
else if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) {
uint8 ndiv;
if (mode.bpp == 8)
regRec.CR67 = 0x00;
else if (mode.bpp == 16)
regRec.CR67 = 0x50;
// X.org code had a somewhat convuluted way of computing the clock for
// MX chips. I hope this simpler method works for most MX cases.
Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 170000, 340000,
&regRec.SR13, &ndiv);
regRec.SR29 = ndiv >> 7;
regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1);
} // end GX2 or MX if()
else if (si.chipType == S3_TRIO_3D) {
regRec.SR0F = 0x00;
if (mode.bpp == 8) {
if (dclk > 115000) { // We need pixmux
regRec.CR67 = 0x10;
regRec.SR15 |= 0x10; // Set DCLK/2 bit
regRec.SR18 = 0x80; // Enable pixmux
}
} else if (mode.bpp == 16) {
if (dclk > 115000) {
regRec.CR67 = 0x40;
regRec.SR15 |= 0x10;
regRec.SR18 = 0x80;
regRec.SR0F = 0x10;
} else {
regRec.CR67 = 0x50;
}
}
Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 230000, 460000,
&regRec.SR13, &regRec.SR12);
} // end TRIO_3D if()
else { // Everything else ... (only VIRGE & VIRGE DX/GX).
if (mode.bpp == 8) {
if (dclk > 80000) { // We need pixmux
regRec.CR67 = 0x10;
regRec.SR15 |= 0x10; // Set DCLK/2 bit
regRec.SR18 = 0x80; // Enable pixmux
}
} else if (mode.bpp == 16) {
regRec.CR67 = 0x50;
}
Virge_CalcClock(dclk, 1, 1, 31, 0, 3, 135000, 270000,
&regRec.SR13, &regRec.SR12);
} // end great big if()...
regRec.CR42 = 0x00;
if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) {
regRec.CR34 = 0;
} else {
regRec.CR34 = 0x10; // set display fifo
}
int width = mode.bytesPerRow >> 3;
regRec.CRTC[19] = 0xFF & width;
regRec.CR51 = (0x300 & width) >> 4; // Extension bits
regRec.CR33 = 0x20;
if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType)
/* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) {
regRec.CR85 = 0x12; // avoid sreen flickering
// by increasing FIFO filling, larger # fills FIFO from memory earlier
// on GX2 this affects all depths, not just those running STREAMS.
// new, secondary stream settings.
regRec.CR87 = 0x10;
// gx2 - set up in XV init code
regRec.CR92 = 0x00;
regRec.CR93 = 0x00;
// gx2 primary mclk timeout, def=0xb
regRec.CR7B = 0xb;
// gx2 secondary mclk timeout, def=0xb
regRec.CR7D = 0xb;
}
if (si.chipType == S3_VIRGE_DXGX || si.chipType == S3_TRIO_3D) {
regRec.CR86 = 0x80; // disable DAC power saving to avoid bright left edge
}
if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) ||
S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) {
int dbytes = mode.bytesPerRow;
regRec.CR91 = (dbytes + 7) / 8;
regRec.CR90 = (((dbytes + 7) / 8) >> 8) | 0x80;
}
// S3_BLANK_DELAY settings based on defaults only. From 3.3.3.
int blank_delay;
if (si.chipType == S3_VIRGE_VX) {
// These values need to be changed once CR67_1 is set
// for gamma correction (see S3V server)!
if (mode.bpp == 8)
blank_delay = 0x00;
else if (mode.bpp == 16)
blank_delay = 0x00;
else
blank_delay = 0x51;
} else {
if (mode.bpp == 8)
blank_delay = 0x00;
else if (mode.bpp == 16)
blank_delay = 0x02;
else
blank_delay = 0x04;
}
if (si.chipType == S3_VIRGE_VX) {
regRec.CR6D = blank_delay;
} else {
regRec.CR65 = (regRec.CR65 & ~0x38) | (blank_delay & 0x07) << 3;
regRec.CR6D = ReadCrtcReg(0x6d);
}
regRec.CR68 = ReadCrtcReg(0x68);
regRec.CR69 = 0;
// Flat panel centering and expansion registers.
regRec.SR54 = 0x1f ;
regRec.SR55 = 0x9f ;
regRec.SR56 = 0x1f ;
regRec.SR57 = 0xff ;
Virge_WriteMode(mode, regRec); // write mode registers to hardware
return true;
}
bool
Virge_SetDisplayMode(const DisplayModeEx& mode)
{
// The code to actually configure the display.
// All the error checking must be done in PROPOSE_DISPLAY_MODE(),
// and assume that the mode values we get here are acceptable.
WriteSeqReg(0x01, 0x20, 0x20); // blank the screen
if ( ! Virge_ModeInit(mode)) {
TRACE("Virge_ModeInit() failed\n");
return false;
}
Virge_AdjustFrame(mode);
Virge_EngineReset(mode);
WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen
return true;
}
void
Virge_AdjustFrame(const DisplayModeEx& mode)
{
// Adjust start address in frame buffer. We use the new CR69 reg
// for this purpose instead of the older CR31/CR51 combo.
SharedInfo& si = *gInfo.sharedInfo;
int base = ((mode.v_display_start * mode.virtual_width + mode.h_display_start)
* (mode.bpp / 8)) >> 2;
if (mode.bpp == 16)
if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000)
base &= ~1;
base += si.frameBufferOffset;
// Now program the start address registers.
WriteCrtcReg(0x0c, (base >> 8) & 0xff);
WriteCrtcReg(0x0d, base & 0xff);
WriteCrtcReg(0x69, (base & 0x0F0000) >> 16);
}
void
Virge_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 ;
while (count--) {
WriteIndexedColor(first++, // color index
colorData[0] >> 2, // red
colorData[1] >> 2, // green
colorData[2] >> 2); // blue
colorData += 3;
}
}

View File

@ -1,56 +0,0 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef ACCELERANT_PROTOTYPES_H
#define ACCELERANT_PROTOTYPES_H
#include <Accelerant.h>
status_t INIT_ACCELERANT(int fd);
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
void GET_ACCELERANT_CLONE_INFO(void *data);
status_t CLONE_ACCELERANT(void *data);
void UNINIT_ACCELERANT(void);
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
uint32 ACCELERANT_MODE_COUNT(void);
status_t GET_MODE_LIST(display_mode *dm);
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
status_t GET_DISPLAY_MODE(display_mode *current_mode);
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
uint32 DPMS_CAPABILITIES(void);
uint32 DPMS_MODE(void);
status_t SET_DPMS_MODE(uint32 dpms_flags);
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
void MOVE_CURSOR(uint16 x, uint16 y);
void SHOW_CURSOR(bool is_visible);
uint32 ACCELERANT_ENGINE_COUNT(void);
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
void WAIT_ENGINE_IDLE(void);
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
status_t SYNC_TO_TOKEN(sync_token *st);
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
// Prototype for other functions that are called from source files
// other than where they are defined.
status_t create_mode_list(void);
#endif

View File

@ -1,90 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
status_t
SET_CURSOR_SHAPE(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. */
si->cursor.width = width;
si->cursor.height = height;
si->cursor.hot_x = hot_x;
si->cursor.hot_y = hot_y;
if (!SavageLoadCursorImage(width, height, andMask, xorMask))
return B_ERROR;
}
return B_OK;
}
/*
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.
*/
void
MOVE_CURSOR(uint16 xPos, uint16 yPos)
{
int x = xPos; // use signed int's since SavageSetCursorPosition()
int y = yPos; // needs signed int to determine if cursor off screen
uint16 hds = si->dm.h_display_start; /* current horizontal starting pixel */
uint16 vds = si->dm.v_display_start; /* current vertical starting line */
/* clamp cursor to virtual display */
if (x >= si->dm.virtual_width)
x = si->dm.virtual_width - 1;
if (y >= si->dm.virtual_height)
y = si->dm.virtual_height - 1;
/* adjust h/v display start to move cursor onto screen */
if (x >= (si->dm.timing.h_display + hds))
hds = x - si->dm.timing.h_display + 1;
else if (x < hds)
hds = x;
if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1;
else if (y < vds)
vds = y;
/* reposition the desktop on the display if required */
if (hds != si->dm.h_display_start || vds != si->dm.v_display_start)
MOVE_DISPLAY(hds, vds);
/* put cursor in correct physical position */
x -= (hds + si->cursor.hot_x);
y -= (vds + si->cursor.hot_y);
/* position the cursor on the display */
SavageSetCursorPosition(x, y);
}
void
SHOW_CURSOR(bool bShow)
{
if (bShow)
SavageShowCursor();
else
SavageHideCursor();
}

View File

@ -1,80 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
static engine_token savage_engine_token = { 1, B_2D_ACCELERATION, NULL };
uint32
ACCELERANT_ENGINE_COUNT(void)
{
return 1;
}
status_t
ACQUIRE_ENGINE(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
/* acquire the shared benaphore */
AQUIRE_BEN(si->engine.lock)
/* sync if required */
if (st)
SYNC_TO_TOKEN(st);
/* return an engine token */
*et = &savage_engine_token;
return B_OK;
}
status_t
RELEASE_ENGINE(engine_token *et, sync_token *st)
{
/* update the sync token, if any */
if (st)
GET_SYNC_TOKEN(et, st);
/* release the shared benaphore */
RELEASE_BEN(si->engine.lock)
return B_OK;
}
void
WAIT_ENGINE_IDLE(void)
{
si->WaitIdleEmpty(); // wait until engine is completely idle
}
status_t
GET_SYNC_TOKEN(engine_token *et, sync_token *st)
{
/* engine count will always be zero: we don't support syncing to token (yet) */
st->engine_id = et->engine_id;
st->counter = si->engine.count;
return B_OK;
}
status_t
SYNC_TO_TOKEN(sync_token *st)
{
(void)st; // avoid compiler warning for unused arg
WAIT_ENGINE_IDLE();
return B_OK;
}

View File

@ -1,100 +0,0 @@
/*
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 2006-2007
*/
#include "AccelerantPrototypes.h"
/*
The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper
function. The extra information (which is specific to the feature) is
pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be
noted on a case by case below.
*/
void *
get_accelerant_hook(uint32 feature, void *data)
{
(void)data; // avoid compiler warning for unused arg
switch (feature) {
/*
These definitions are out of pure lazyness.
*/
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
/* initialization */
HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT);
HOOK(ACCELERANT_CLONE_INFO_SIZE);
HOOK(GET_ACCELERANT_CLONE_INFO);
HOOK(UNINIT_ACCELERANT);
HOOK(GET_ACCELERANT_DEVICE_INFO);
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
/* mode configuration */
HOOK(ACCELERANT_MODE_COUNT);
HOOK(GET_MODE_LIST);
HOOK(PROPOSE_DISPLAY_MODE);
HOOK(SET_DISPLAY_MODE);
HOOK(GET_DISPLAY_MODE);
HOOK(GET_FRAME_BUFFER_CONFIG);
HOOK(GET_PIXEL_CLOCK_LIMITS);
HOOK(MOVE_DISPLAY);
HOOK(SET_INDEXED_COLORS);
//HOOK(GET_TIMING_CONSTRAINTS);
HOOK(DPMS_CAPABILITIES);
HOOK(DPMS_MODE);
HOOK(SET_DPMS_MODE);
/* cursor managment */
HOOK(SET_CURSOR_SHAPE);
HOOK(MOVE_CURSOR);
HOOK(SHOW_CURSOR);
/* synchronization */
HOOK(ACCELERANT_ENGINE_COUNT);
HOOK(ACQUIRE_ENGINE);
HOOK(RELEASE_ENGINE);
HOOK(WAIT_ENGINE_IDLE);
HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_TOKEN);
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
*/
/* 2D acceleration */
HOOK(SCREEN_TO_SCREEN_BLIT);
HOOK(FILL_RECTANGLE);
HOOK(INVERT_RECTANGLE);
HOOK(FILL_SPAN);
#undef HOOK
#undef ZERO
}
/*
Return a null pointer for any feature we don't understand.
*/
return 0;
}

View File

@ -1,28 +0,0 @@
/*
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2007
*/
#include "AccelerantPrototypes.h"
#include "GlobalData.h"
#include <string.h>
// Get info about the device.
status_t
GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi)
{
adi->version = 1;
strcpy(adi->name, "S3 Savage chipset");
strcpy(adi->chipset, si->chipsetName);
strcpy(adi->serial_no, "unknown");
adi->memory = si->videoMemSize;
adi->dac_speed = 250;
return B_OK;
}

View File

@ -1,90 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
/*
Return the current display mode. The only time you might return an
error is if a mode hasn't been set.
*/
status_t
GET_DISPLAY_MODE (display_mode *current_mode)
{
/* easy for us, we return the last mode we set */
*current_mode = si->dm;
return B_OK;
}
/*
Return the frame buffer configuration information.
*/
status_t
GET_FRAME_BUFFER_CONFIG(frame_buffer_config *pFBC)
{
// TRACE(("GET_FRAME_BUFFER_CONFIG called\n"));
*pFBC = si->fbc;
return B_OK;
}
/*
Return the maximum and minium pixel clock limits for the specified mode.
*/
status_t
GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
{
/*
Note that we're not making any guarantees about the ability of the attached
display to handle pixel clocks within the limits we return. A future monitor
capablilities database will post-process this information.
*/
uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total;
uint32 clock_limit;
/* max pixel clock is pixel depth dependant */
switch (dm->space & ~0x3000) {
case B_RGB32:
clock_limit = si->pix_clk_max32;
break;
case B_RGB15:
case B_RGB16:
clock_limit = si->pix_clk_max16;
break;
case B_CMAP8:
clock_limit = si->pix_clk_max8;
break;
default:
clock_limit = 0;
}
/* lower limit of about 48Hz vertical refresh */
*low = (total_pix * 48L) / 1000L;
if (*low > clock_limit)
return B_ERROR;
*high = clock_limit;
return B_OK;
}
/*
Return the semaphore id that will be used to signal a vertical retrace
occured.
*/
sem_id
ACCELERANT_RETRACE_SEMAPHORE(void)
{
// TRACE(("ACCELERANT_RETRACE_SEMAPHORE() called\n"));
// if (si->bInterruptAssigned && si->vblank >= 0)
// return si->vblank;
// else
return B_ERROR;
}

View File

@ -1,19 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
int driverFileDesc;
SharedInfo* si;
area_id sharedInfoArea;
uint8* regs;
area_id regsArea;
display_mode* modeList;
area_id modeListArea;
bool bAccelerantIsClone;

View File

@ -1,32 +0,0 @@
/*
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 2006-2007
*/
#ifndef GLOBALDATA_H
#define GLOBALDATA_H
#include "DriverInterface.h"
extern int driverFileDesc; // file descriptor of kernel driver
extern SharedInfo* si; // address of info shared between accelerants
extern area_id sharedInfoArea; // shared info area ID
extern uint8* regs; // base address of MMIO register area
extern area_id regsArea; // MMIO register area ID
extern display_mode* modeList; // list of standard display modes
extern area_id modeListArea; // mode list area ID
extern bool bAccelerantIsClone;// true if this is a cloned accelerant
void TraceLog(const char* fmt, ...);
#ifdef TRACE_S3SAVAGE
# define TRACE(a) TraceLog a
#else
# define TRACE(a)
#endif
#endif // GLOBALDATA_H

View File

@ -1,284 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
#include "errno.h"
#include "fcntl.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include <sys/ioctl.h>
/* Initialization code shared between primary and cloned accelerants */
static status_t
init_common(int the_fd)
{
status_t result;
SavageGetPrivateData gpd;
/* memorize the file descriptor */
driverFileDesc = the_fd;
/* set the magic number so the driver knows we're for real */
gpd.magic = SAVAGE_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(driverFileDesc, SAVAGE_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK)
goto error0;
/* clone the shared area for our use */
sharedInfoArea = clone_area("SAVAGE shared info", (void**)&si, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, gpd.sharedInfoArea);
if (sharedInfoArea < 0) {
result = sharedInfoArea;
goto error0;
}
/* clone the memory mapped registers for our use */
regsArea = clone_area("SAVAGE regs area", (void**)&regs, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, si->regsArea);
if (regsArea < 0) {
result = regsArea;
goto error1;
}
/* all done */
goto error0;
error1:
delete_area(sharedInfoArea);
error0:
return result;
}
/* Clean up code shared between primary and cloned accelrants */
static void
uninit_common(void)
{
/* release the memory mapped registers */
delete_area(regsArea);
regs = 0;
/* release our copy of the shared info from the kernel driver */
delete_area(sharedInfoArea);
si = 0;
}
/*
Initialize the accelerant. the_fd is the file handle of the device (in
/dev/graphics) that has been opened by the app_server (or some test harness).
We need to determine if the kernel driver and the accelerant are compatible.
If they are, get the accelerant ready to handle other hook functions and
report success or failure.
*/
status_t
INIT_ACCELERANT(int the_fd)
{
status_t result;
TRACE(("Enter INIT_ACCELERANT\n"));
/* note that we're the primary accelerant (bAccelerantIsClone is global) */
bAccelerantIsClone = false;
/* do the initialization common to both the primary and the clones */
result = init_common(the_fd);
if (result != B_OK)
goto error0; // common initialization failed
TRACE(("Vendor ID: 0x%X, Device ID: 0x%X\n", si->vendorID, si->deviceID));
/* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */
if (si->bAccelerantInUse) {
result = B_NOT_ALLOWED;
goto error1;
}
/* call the device specific init code */
if (!SavagePreInit())
goto error1;
/*
Now would be a good time to figure out what video modes your card supports.
We'll place the list of modes in another shared area so all of the copies
of the driver can see them. The primary copy of the accelerant (ie the one
initialized with this routine) will own the "one true copy" of the list.
Everybody else get's a read-only clone.
*/
result = create_mode_list();
if (result != B_OK)
goto error1;
/* Initialize the cursor information */
si->cursor.width = 0;
si->cursor.height = 0;
si->cursor.hot_x = 0;
si->cursor.hot_y = 0;
si->cursor.x = 0;
si->cursor.y = 0;
si->fbc.frame_buffer = (void *)((addr_t)si->videoMemAddr + si->frameBufferOffset);
si->fbc.frame_buffer_dma = (void *)((addr_t)si->videoMemPCI + si->frameBufferOffset);
/* init the shared semaphore */
INIT_BEN(si->engine.lock);
/* initialize the engine synchronization variables */
/* count of issued parameters or commands */
si->engine.lastIdle = si->engine.count = 0;
/* ensure cursor state */
SHOW_CURSOR(false);
/* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */
si->bAccelerantInUse = true;
result = B_OK;
goto error0;
error1:
/*
Initialization failed after init_common() succeeded, so we need to clean
up before quiting.
*/
uninit_common();
error0:
TRACE(("Exit INIT_ACCELERANT, result: 0x%X\n", result));
return result;
}
/*
Return the number of bytes required to hold the information required
to clone the device.
*/
ssize_t
ACCELERANT_CLONE_INFO_SIZE(void)
{
/*
Since we're passing the name of the device as the only required
info, return the size of the name buffer
*/
return B_OS_NAME_LENGTH;
}
/*
Return the info required to clone the device. void* data points to
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
*/
void
GET_ACCELERANT_CLONE_INFO(void* data)
{
SavageDeviceName dn;
status_t result;
/* call the kernel driver to get the device name */
dn.magic = SAVAGE_PRIVATE_DATA_MAGIC;
/* store the returned info directly into the passed buffer */
dn.name = (char*)data;
result = ioctl(driverFileDesc, SAVAGE_DEVICE_NAME, &dn, sizeof(dn));
}
/*
Initialize a copy of the accelerant as a clone. void* data points to
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
*/
status_t
CLONE_ACCELERANT(void* data)
{
status_t result;
char path[MAXPATHLEN];
/* the data is the device name */
strcpy(path, "/dev/");
strcat(path, (const char*)data);
/* open the device, the permissions aren't important */
driverFileDesc = open(path, B_READ_WRITE);
if (driverFileDesc < 0)
return errno;
/* note that we're a clone accelerant */
bAccelerantIsClone = true;
/* call the shared initialization code */
result = init_common(driverFileDesc);
/* bail out if the common initialization failed */
if (result != B_OK)
goto error1;
/* get shared area for display modes */
result = modeListArea = clone_area(
"SAVAGE cloned display_modes",
(void**) &modeList,
B_ANY_ADDRESS,
B_READ_AREA,
si->modeArea
);
if (result < B_OK)
goto error2;
/* all done */
result = B_OK;
goto error0;
error2:
/* free up the areas we cloned */
uninit_common();
error1:
/* close the device we opened */
close(driverFileDesc);
error0:
return result;
}
void
UNINIT_ACCELERANT(void)
{
/* free our mode list area */
delete_area(modeListArea);
modeList = 0;
/* release our cloned data */
uninit_common();
/* close file handle ONLY if we're the clone */
if (bAccelerantIsClone)
close(driverFileDesc);
}
// Kernel function dprintf() is not available in user space; however,
// _sPrintf performs the same function in user space but is undefined
// in the OS header files. Thus, it is defined here.
void _sPrintf(const char *format, ...);
void
TraceLog(const char* fmt, ...)
{
char string[1024];
va_list args;
strcpy(string, "savage: ");
va_start(args, fmt);
vsprintf(&string[strlen(string)], fmt, args);
_sPrintf(string);
}

View File

@ -1,31 +0,0 @@
SubDir HAIKU_TOP src add-ons accelerants s3savage ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics s3savage ] ;
Addon s3savage.accelerant :
Acceleration.c
Cursor.c
EngineManagement.c
GetAccelerantHook.c
GetDeviceInfo.c
GetModeInfo.c
GlobalData.c
InitAccelerant.c
ProposeDisplayMode.c
SetDisplayMode.c
savage_accel.c
savage_cursor.c
savage_dpms.c
savage_driver.c
: be
;
Package haiku-s3savage-cvs :
s3savage.accelerant :
boot home config add-ons accelerants ;

View File

@ -1,418 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
#include <string.h>
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS)
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
static const display_mode mode_list[] = {
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
{ { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) */
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
{ { 81642, 1152, 1216, 1336, 1520, 864, 865, 868, 895, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, // 1152x864x60Hz
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
{ { 155800, 1400, 1464, 1784, 1912, 1050, 1052, 1064, 1090, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1400X1050) */
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
{ { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) */
{ { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) */
{ { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) */
{ { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) */
// widescreen resolutions, 16:10
{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */
{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
// widescreen resolutions, 16:9
{ { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@60Hz_(1280X720) */
};
/* create a mask of one "bits" bits wide */
#define MASKFROMWIDTH(bits) ((1 << bits) - 1)
/*
Validate a target display mode is both
a) a valid display mode for this device and
b) falls between the contraints imposed by "low" and "high"
Return values:
B_ERROR - mode is not (or cannot) be made valid for this device.
B_BAD_VALUE - valid mode can be constructed, but it is not within limits.
B_OK - mode is both valid AND is within the limits.
*/
status_t
PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
const uint16 h_sync_bits = MASKFROMWIDTH(5);
const uint16 h_total_bits = MASKFROMWIDTH(9);
const uint16 v_display_bits = MASKFROMWIDTH(11);
const uint16 v_sync_bits = MASKFROMWIDTH(5);
status_t result = B_OK;
uint32 row_bytes, limit_clock;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0)
/ ((double)target->timing.h_total
* (double)target->timing.v_total);
bool want_same_width = (target->timing.h_display == target->virtual_width);
bool want_same_height = (target->timing.v_display == target->virtual_height);
/*
NOTE:
Different devices provide different levels of control over the
various CRTC values. This code should be used as a *GUIDELINE ONLY*.
The device you're controling may have very different constraints,
and the code below may be insufficient to insure that a particular
display_mode is valid for your device. You would do well to spend
quite a bit of time ensuring that you understand the limitations of
your device, as setting these values incorrectly can create a
display_mode that could turn your monitor into a useless slag of
molten components, burn up your card, lock up the PCI bus, cause
partialy or multiply repeating display images, or otherwise look
just plain wierd. Honest.
*/
/*
NOTE:
This code doesn't explicitly support interlaced video modes.
*/
// TRACE(("ProposeDisplayMode; clock = %d, width = %d, height = %d\n",
// target->timing.pixel_clock, target->virtual_width, target->virtual_height));
/* validate horizontal timings */
{
/* for most devices, horizontal parameters must be multiples of 8 */
uint16 h_display = target->timing.h_display >> 3;
uint16 h_sync_start = target->timing.h_sync_start >> 3;
uint16 h_sync_end = target->timing.h_sync_end >> 3;
uint16 h_total = target->timing.h_total >> 3;
/* ensure reasonable minimum display and sequential order of parms */
if (h_display < (320 >> 3))
h_display = 320 >> 3;
if (h_display > (2048 >> 3))
h_display = 2048 >> 3;
if (h_sync_start < (h_display + 2))
h_sync_start = h_display + 2;
if (h_sync_end < (h_sync_start + 3))
h_sync_end = h_sync_start + 3; /*(0x001f >> 2);*/
if (h_total < (h_sync_end + 1))
h_total = h_sync_end + 1;
/* adjust for register limitations: */
/* h_total is 9 bits */
if (h_total > h_total_bits)
h_total = h_total_bits;
/* h_display is 8 bits - handled above */
/* h_sync_start is 9 bits */
/* h_sync_width is 5 bits */
if ((h_sync_end - h_sync_start) > h_sync_bits)
h_sync_end = h_sync_start + h_sync_bits;
/* shift back to the full width values */
target->timing.h_display = h_display << 3;
target->timing.h_sync_start = h_sync_start << 3;
target->timing.h_sync_end = h_sync_end << 3;
target->timing.h_total = h_total << 3;
}
/* did we fall out of one of the limits? */
if ((target->timing.h_display < low->timing.h_display)
|| (target->timing.h_display > high->timing.h_display)
|| (target->timing.h_sync_start < low->timing.h_sync_start)
|| (target->timing.h_sync_start > high->timing.h_sync_start)
|| (target->timing.h_sync_end < low->timing.h_sync_end)
|| (target->timing.h_sync_end > high->timing.h_sync_end)
|| (target->timing.h_total < low->timing.h_total)
|| (target->timing.h_total > high->timing.h_total))
result = B_BAD_VALUE;
/* validate vertical timings */
{
uint16 v_display = target->timing.v_display;
uint16 v_sync_start = target->timing.v_sync_start;
uint16 v_sync_end = target->timing.v_sync_end;
uint16 v_total = target->timing.v_total;
/* ensure reasonable minium display and sequential order of parms */
/* v_display is 11 bits */
/* v_total is 11 bits */
/* v_sync_start is 11 bits */
/* v_sync_width is 5 bits */
if (v_display < 200)
v_display = 200;
if (v_display > (v_display_bits - 5))
v_display = (v_display_bits - 5); /* leave room for the sync pulse */
if (v_sync_start < (v_display + 1))
v_sync_start = v_display + 1;
if (v_sync_end < v_sync_start)
v_sync_end = v_sync_start + 3;
if (v_total < (v_sync_end + 1))
v_total = v_sync_end + 1;
/* adjust for register limitations */
if ((v_sync_end - v_sync_start) > v_sync_bits)
v_sync_end = v_sync_start + v_sync_bits;
target->timing.v_display = v_display;
target->timing.v_sync_start = v_sync_start;
target->timing.v_sync_end = v_sync_end;
target->timing.v_total = v_total;
}
/* did we fall out of one of the limits? */
if ((target->timing.v_display < low->timing.v_display)
|| (target->timing.v_display > high->timing.v_display)
|| (target->timing.v_sync_start < low->timing.v_sync_start)
|| (target->timing.v_sync_start > high->timing.h_sync_start)
|| (target->timing.v_sync_end < low->timing.v_sync_end)
|| (target->timing.v_sync_end > high->timing.v_sync_end)
|| (target->timing.v_total < low->timing.v_total)
|| (target->timing.v_total > high->timing.v_total))
result = B_BAD_VALUE;
// If the video is connected directly to an LCD display (ie, notebook
// computer), restrict the display mode to resolutions where the width and
// height of the mode are less than or equal to the width and height of the
// LCD display.
if (MT_LCD == si->displayType && si->panelX > 0 && si->panelY > 0 &&
(target->timing.h_display > si->panelX
|| target->timing.v_display > si->panelY)) {
return B_ERROR;
}
/* adjust pixel clock for DAC limits and target refresh rate */
/*
We're re-calcuating the pixel_clock here because we might have
changed the h/v totals above. If we didn't change anything
the calculation is wasted, but it's no big deal.
*/
target->timing.pixel_clock = target_refresh
* ((double)target->timing.h_total)
* ((double)target->timing.v_total) / 1000.0;
/*
Select the maximum pixel clock based on the color space. Your
device may have other constraints. In this sample driver, we
calculated the maximum pixel clock for this device in the
initialization code.
This is also a convienient place to determine the number of bytes
per pixel for a later display pitch calculation.
*/
switch (target->space & 0x0fff) {
case B_CMAP8:
limit_clock = si->pix_clk_max8;
row_bytes = 1;
break;
//case B_RGB15:
case B_RGB16:
limit_clock = si->pix_clk_max16;
row_bytes = 2;
break;
case B_RGB32:
limit_clock = si->pix_clk_max32;
row_bytes = 4;
break;
default:
/* no amount of adjusting will fix not being able to support
the pixel format */
return B_ERROR;
}
/* make sure we don't generate more pixel bandwidth than the device
can handle */
if (target->timing.pixel_clock > limit_clock)
target->timing.pixel_clock = limit_clock;
/* we probably ought to check against too low of a pixel rate,
but I'm lazy */
/* note if we fell outside the limits */
if ((target->timing.pixel_clock < low->timing.pixel_clock)
|| (target->timing.pixel_clock > high->timing.pixel_clock))
result = B_BAD_VALUE;
/* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
if (target->virtual_width > 2048)
target->virtual_width = 2048;
/* adjust virtual width for engine limitations */
target->virtual_width = (target->virtual_width + 7) & ~7;
if ( (target->virtual_width < low->virtual_width)
|| (target->virtual_width > high->virtual_width))
result = B_BAD_VALUE;
/* calculate rowbytes after we've nailed the virtual width */
row_bytes *= target->virtual_width;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) > si->maxFrameBufferSize)
target->virtual_height = si->maxFrameBufferSize / row_bytes;
if (target->virtual_height > 2048)
target->virtual_height = 2048;
if (target->virtual_height < target->timing.v_display)
/* not enough frame buffer memory for the mode */
return B_ERROR;
else if ((target->virtual_height < low->virtual_height)
|| (target->virtual_height > high->virtual_height))
result = B_BAD_VALUE;
return result;
}
/*
Return the number of modes this device will return from GET_MODE_LIST().
*/
uint32
ACCELERANT_MODE_COUNT(void)
{
/* return the number of 'built-in' display modes */
return si->modeCount;
}
/*
Copy the list of guaranteed supported video modes to the location
provided.
*/
status_t
GET_MODE_LIST(display_mode *dm)
{
/* copy them to the buffer pointed at by *dm */
memcpy(dm, modeList, si->modeCount * sizeof(display_mode));
return B_OK;
}
/*
Create a list of display_modes to pass back to the caller.
*/
status_t
create_mode_list(void)
{
size_t max_size;
uint32 i;
uint32 pix_clk_range;
const display_mode *src;
display_mode *dst, low, high;
/*
We prefer frame buffers to have the same endianness as the host
CPU, but it's not required. You can even return both, although
there isn't a way for the current Screen preferences panel to
allow the user to choose which one to use.
*/
#if defined(__INTEL__)
color_space colorSpaces[] = { B_CMAP8, B_RGB16_LITTLE, B_RGB32_LITTLE };
#else
color_space colorSpaces[] = { B_CMAP8, B_RGB16_BIG, B_RGB32_BIG };
#endif
int numColorSpaces = sizeof(colorSpaces) / sizeof(colorSpaces[0]);
/* figure out how big the list could be, and adjust up to nearest
multiple of B_PAGE_SIZE */
max_size = ((MODE_COUNT * numColorSpaces * sizeof(display_mode))
+ (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
/* create an area to hold the info */
si->modeArea = modeListArea = create_area("SAVAGE accelerant mode info",
(void **) &modeList, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (modeListArea < B_OK)
return modeListArea;
/* walk through our predefined list and see which modes fit this device */
src = mode_list;
dst = modeList;
si->modeCount = 0;
for (i = 0; i < MODE_COUNT; i++) {
int j;
/* set ranges for acceptable values */
low = high = *src;
/* Expand range of default clock by 3.1% on each end: arbitrarily picked */
pix_clk_range = low.timing.pixel_clock >> 5; // divide by 32 to get ~3.1%
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
/* do it once for each depth we want to support */
for (j = 0; j < numColorSpaces; j++) {
/* set target values */
*dst = *src;
/* poke the specific space */
dst->space = low.space = high.space = colorSpaces[j];
/* ask for a compatible mode */
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
/* count it, and move on to next mode */
dst++;
si->modeCount++;
}
}
/* advance to next mode */
src++;
}
return B_OK;
}
bool
IsDisplaySizeValid(int width, int height)
{
// Search the mode list for a mode which has the width and height passed
// by the caller, and return true if a match is found.
uint32 i;
for (i = 0; i < MODE_COUNT; i++) {
if (mode_list[i].virtual_width == width && mode_list[i].virtual_height == height)
return true;
}
return false; // match not found
}

View File

@ -1,204 +0,0 @@
/*
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 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
#include <sys/ioctl.h>
#include <stdio.h>
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
*/
static void
interrupt_enable(bool bEnable)
{
status_t result;
SavageSetBoolState sbs;
if (si->bInterruptAssigned) {
/* set the magic number so the driver knows we're for real */
sbs.magic = SAVAGE_PRIVATE_DATA_MAGIC;
sbs.bEnable = bEnable;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(driverFileDesc, SAVAGE_RUN_INTERRUPTS, &sbs, sizeof(sbs));
}
}
/*
Calculates the number of bits for a given color_space.
Usefull for mode setup routines, etc.
*/
static uint32
CalcBitsPerPixel(uint32 cs)
{
uint32 bpp = 0;
switch (cs) {
case B_RGB32_BIG:
case B_RGBA32_BIG:
case B_RGB32_LITTLE:
case B_RGBA32_LITTLE:
bpp = 32;
break;
case B_RGB24_BIG:
case B_RGB24_LITTLE:
bpp = 24;
break;
case B_RGB16_BIG:
case B_RGB16_LITTLE:
bpp = 16;
break;
case B_RGB15_BIG:
case B_RGBA15_BIG:
case B_RGB15_LITTLE:
case B_RGBA15_LITTLE:
bpp = 15;
break;
case B_CMAP8:
bpp = 8;
break;
}
return bpp;
}
/*
The code to actually configure the display.
Do all of the error checking in PROPOSE_DISPLAY_MODE(),
and just assume that the values I get here are acceptable.
*/
static void
SetDisplayMode(display_mode* dm)
{
// The code to actually configure the display.
// All the error checking must be done in PROPOSE_DISPLAY_MODE(),
// and assume that the mode values we get here are acceptable.
uint bpp = CalcBitsPerPixel(dm->space);
DisplayMode mode;
TRACE(("SetDisplayMode begin; depth = %d, width = %d, height = %d\n",
bpp, dm->virtual_width, dm->virtual_height));
interrupt_enable(false); // disable interrupts using kernel driver
mode.timing = dm->timing;
mode.bpp = bpp;
mode.width = dm->virtual_width;
mode.bytesPerRow = dm->virtual_width * ((bpp + 7) / 8);
TRACE(("TIMING = { %d %d %d %d %d %d %d %d %d 0x%x }\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, mode.timing.flags));
if (SavageModeInit(&mode)) {
TRACE(("SavageModeInit succeeded\n"));
} else {
TRACE(("SavageModeInit failed\n"));
}
interrupt_enable(true); // enable interrupts using kernel driver
si->fbc.bytes_per_row = dm->virtual_width * ((bpp + 7) / 8);
si->bitsPerPixel = bpp;
SavageAdjustFrame(dm->h_display_start, dm->v_display_start);
TRACE(("SetDisplayMode done\n"));
}
status_t
SET_DISPLAY_MODE (display_mode* mode_to_set)
{
// The exported mode setting routine. First validate the mode,
// then call our private routine to hammer the registers.
display_mode bounds, target;
/* ask for the specific mode */
target = bounds = *mode_to_set;
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR)
return B_ERROR;
SetDisplayMode(&target);
si->dm = target;
return B_OK;
}
/*
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.
*/
status_t
MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start)
{
/*
Many devices have limitations on the granularity of the horizontal offset.
Make any checks for this here. A future revision of the driver API will
add a hook to return the granularity for a given display mode.
*/
/* most cards can handle multiples of 8 */
if (h_display_start & 0x07)
return B_ERROR;
/* do not run past end of display */
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR;
/* everybody remember where we parked... */
si->dm.h_display_start = h_display_start;
si->dm.v_display_start = v_display_start;
/* actually set the registers */
SavageAdjustFrame(h_display_start, v_display_start);
return B_OK;
}
/*
Set the indexed color palette.
*/
void
SET_INDEXED_COLORS(uint count, uint8 first, uint8* colorData, uint32 flags)
{
(void)flags; // avoid compiler warning for unused arg
/*
Some cards use the indexed color regisers in the DAC for gamma correction.
If this is true with your device (and it probably is), you need to protect
against setting these registers when not in an indexed mode.
*/
if (si->dm.space != B_CMAP8)
return ;
/*
There isn't any need to keep a copy of the data being stored,
as the app_server will set the colors each time it switches to
an 8bpp mode, or takes ownership of an 8bpp mode after a GameKit
app has used it.
*/
OUTREG16(VGA_SEQ_INDEX, 0x101b);
while (count--) {
OUTREG8(0x83c8, first++); // color index
OUTREG8(0x83c9, colorData[0]); // red
OUTREG8(0x83c9, colorData[1]); // green
OUTREG8(0x83c9, colorData[2]); // blue
colorData += 3;
}
}

View File

@ -1,264 +0,0 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2007
*/
#ifndef __SAVAGE_H__
#define __SAVAGE_H__
#define BASE_FREQ 14.31818
#define FIFO_CONTROL_REG 0x8200
#define MIU_CONTROL_REG 0x8204
#define STREAMS_TIMEOUT_REG 0x8208
#define MISC_TIMEOUT_REG 0x820c
#define ADVANCED_FUNC_CTRL 0x850C
#define SYSTEM_CONTROL_REG 0x83DA
#define VGA_ATTR_INDEX 0x83C0
#define VGA_ATTR_DATA_W 0x83C0
#define VGA_MISC_OUT_R 0x83CC /* read */
#define VGA_MISC_OUT_W 0x83C2 /* write */
#define VGA_SEQ_INDEX 0x83C4
#define VGA_SEQ_DATA 0x83C5
#define VGA_GRAPH_INDEX 0x83CE
#define VGA_GRAPH_DATA 0x83CF
#define VGA_CRTC_INDEX 0x83D4
#define VGA_CRTC_DATA 0x83D5
#define VGA_IN_STAT_1 SYSTEM_CONTROL_REG
/* Stream Processor 1 */
/* Primary Stream 1 Frame Buffer Address 0 */
#define PRI_STREAM_FBUF_ADDR0 0x81c0
/* Primary Stream 1 Frame Buffer Address 1 */
#define PRI_STREAM_FBUF_ADDR1 0x81c4
/* Primary Stream 1 Stride */
#define PRI_STREAM_STRIDE 0x81c8
/* Stream Processor 2 */
/* Primary Stream 2 Frame Buffer Address 0 */
#define PRI_STREAM2_FBUF_ADDR0 0x81b0
/* Primary Stream 2 Frame Buffer Address 1 */
#define PRI_STREAM2_FBUF_ADDR1 0x81b4
/* Primary Stream 2 Stride */
#define PRI_STREAM2_STRIDE 0x81b8
/* GX-3 Configuration/Status Registers */
#define S3_BUFFER_THRESHOLD 0x48C10
#define S3_OVERFLOW_BUFFER 0x48C14
#define S3_OVERFLOW_BUFFER_PTR 0x48C18
#define MEMORY_CTRL0_REG 0xCA
#define MEMORY_CONFIG_REG 0x31
/* bitmap descriptor register */
#define S3_GLB_BD_LOW 0x8168
#define S3_GLB_BD_HIGH 0x816C
#define S3_PRI_BD_LOW 0x8170
#define S3_PRI_BD_HIGH 0x8174
#define S3_SEC_BD_LOW 0x8178
#define S3_SEC_BD_HIGH 0x817c
/* duoview */
#define SELECT_IGA1 0x4026
#define SELECT_IGA2_READS_WRITES 0x4f26
#define MEM_PS1 0x10 /*CRCA_4 :Primary stream 1*/
#define MEM_PS2 0x20 /*CRCA_5 :Primary stream 2*/
#define MEM_SS1 0x40 /*CRCA_6 :Secondary stream 1*/
#define MEM_SS2 0x80 /*CRCA_7 :Secondary stream 2*/
#define SRC_BASE 0xa4d4
#define DEST_BASE 0xa4d8
#define CLIP_L_R 0xa4dc
#define CLIP_T_B 0xa4e0
#define DEST_SRC_STR 0xa4e4
#define MONO_PAT_0 0xa4e8
#define MONO_PAT_1 0xa4ec
/*
* CR88_4 =1 : disable block write
* the "2D" is partly to set this apart from "BLOCK_WRITE_DISABLE"
* constant used for bitmap descriptor
*/
#define DISABLE_BLOCK_WRITE_2D 0x10
#define BLOCK_WRITE_DISABLE 0x0
/* CR31[0] set = Enable 8MB display memory through 64K window at A0000H. */
#define ENABLE_CPUA_BASE_A0000 0x01
/*
* reads from SUBSYS_STAT
*/
#define STATUS_WORD0 (INREG(0x48C00))
#define ALT_STATUS_WORD0 (INREG(0x48C60))
#define MAXLOOP 0xffffff
#define MAXFIFO 0x7f00
// BCI definitions.
//=================
#define TILE_FORMAT_LINEAR 0
/* BD - BCI enable */
#define BCI_ENABLE 8 // savage4, MX, IX, 3D
#define BCI_ENABLE_TWISTER 0 // twister, prosavage, DDR, supersavage, 2000
#define S3_BIG_ENDIAN 4
#define S3_LITTLE_ENDIAN 0
#define S3_BD64 1
#define BCI_BUFFER_OFFSET 0x10000
#define BCI_GET_PTR vuint32* bci_ptr = ((uint32*)(regs + BCI_BUFFER_OFFSET))
#define BCI_SEND(dw) (*bci_ptr++ = ((uint32)(dw)))
#define BCI_CMD_NOP 0x40000000
#define BCI_CMD_RECT 0x48000000
#define BCI_CMD_RECT_XP 0x01000000
#define BCI_CMD_RECT_YP 0x02000000
#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
#define BCI_CMD_SEND_COLOR 0x00008000
#define BCI_CMD_DEST_PBD_NEW 0x00000C00
#define BCI_CMD_SRC_SOLID 0x00000000
#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140
#define BCI_BD_BW_DISABLE 0x10000000
#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16))
#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF))
#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF)
#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF)
// Macros for memory mapped I/O.
//==============================
#define INREG8(addr) *((vuint8*)(regs + addr))
#define INREG16(addr) *((vuint16*)(regs + addr))
#define INREG32(addr) *((vuint32*)(regs + addr))
#define OUTREG8(addr, val) *((vuint8*)(regs + addr)) = val
#define OUTREG16(addr, val) *((vuint16*)(regs + addr)) = val
#define OUTREG32(addr, val) *((vuint32*)(regs + addr)) = val
#define INREG(addr) INREG32(addr)
#define OUTREG(addr, val) OUTREG32(addr, val)
static inline uint8 ReadCrtc(uint8 index)
{
OUTREG8(VGA_CRTC_INDEX, index);
return INREG8(VGA_CRTC_DATA);
}
static inline void WriteCrtc(uint8 index, uint8 value)
{
OUTREG8(VGA_CRTC_INDEX, index);
OUTREG8(VGA_CRTC_DATA, value);
}
static inline uint8 ReadSeq(uint8 index)
{
OUTREG8(VGA_SEQ_INDEX, index);
return INREG8(VGA_SEQ_DATA);
}
static inline void WriteSeq(uint8 index, uint8 value)
{
OUTREG8(VGA_SEQ_INDEX, index);
OUTREG8(VGA_SEQ_DATA, value);
}
static inline uint8 ReadST01()
{
return INREG8(VGA_IN_STAT_1);
}
/*
* unprotect CRTC[0-7]
* CR11_7 = 0: Writing to all CRT Controller registers enabled
* = 1: Writing to all bits of CR0~CR7 except CR7_4 disabled
*/
static inline void UnProtectCRTC()
{
unsigned char byte;
OUTREG8(VGA_CRTC_INDEX, 0x11);
byte = INREG8(VGA_CRTC_DATA) & 0x7F;
OUTREG16(VGA_CRTC_INDEX, byte << 8 | 0x11);
}
/*
* unlock extended regs
* CR38:unlock CR20~CR3F
* CR39:unlock CR40~CRFF
* SR08:unlock SR09~SRFF
*/
static inline void UnLockExtRegs()
{
OUTREG16(VGA_CRTC_INDEX, 0x4838);
OUTREG16(VGA_CRTC_INDEX, 0xA039);
OUTREG16(VGA_SEQ_INDEX, 0x0608);
}
static inline void VerticalRetraceWait()
{
INREG8(VGA_CRTC_INDEX);
OUTREG8(VGA_CRTC_INDEX, 0x17);
if (INREG8(VGA_CRTC_DATA) & 0x80)
{
int i = 0x10000;
while ((INREG8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ;
i = 0x10000;
while ((INREG8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ;
}
}
typedef struct
{
display_timing timing; // CRTC info
int bpp; // bits/pixel
int width; // screen width in pixels
int bytesPerRow; // number of bytes in one line/row
} DisplayMode;
bool IsDisplaySizeValid(int width, int height);
bool SavageLoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
void SavageSetCursorPosition(int x, int y);
void SavageShowCursor(void);
void SavageHideCursor(void);
bool SavageDPMS(int mode);
bool SavagePreInit(void);
bool SavageModeInit(DisplayMode* pMode);
void SavageInitialize2DEngine(DisplayMode* pMode);
void SavageSetGBD(DisplayMode* pMode);
void SavageAdjustFrame(int x, int y);
#endif // __SAVAGE_H__

View File

@ -1,768 +0,0 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright 1995-1997 The XFree86 Project, Inc.
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
static void
SavageSetGBD_Twister(DisplayMode* pMode)
{
uint32 ulTmp;
uint8 byte;
int bci_enable;
TRACE(("SavageSetGBD_Twister\n"));
if (si->chipset == S3_SAVAGE4)
bci_enable = BCI_ENABLE;
else
bci_enable = BCI_ENABLE_TWISTER;
/* MM81C0 and 81C4 are used to control primary stream. */
OUTREG32(PRI_STREAM_FBUF_ADDR0, 0);
OUTREG32(PRI_STREAM_FBUF_ADDR1, 0);
/*
* Program Primary Stream Stride Register.
*
* Tell engine if tiling on or off, set primary stream stride, and
* if tiling, set tiling bits/pixel and primary stream tile offset.
* Note that tile offset (bits 16 - 29) must be scanline width in
* bytes/128bytespertile * 256 Qwords/tile. This is equivalent to
* lDelta * 2. Remember that if tiling, lDelta is screenwidth in
* bytes padded up to an even number of tilewidths.
*/
OUTREG32(PRI_STREAM_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFFE000) |
(pMode->bytesPerRow & 0x00001fff));
/*
* CR69, bit 7 = 1
* to use MM streams processor registers to control primary stream.
*/
OUTREG8(VGA_CRTC_INDEX, 0x69);
byte = INREG8(VGA_CRTC_DATA) | 0x80;
OUTREG8(VGA_CRTC_DATA, byte);
OUTREG32(0x8128, 0xFFFFFFFFL);
OUTREG32(0x812C, 0xFFFFFFFFL);
OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
/* CR50, bit 7,6,0 = 111, Use GBD.*/
OUTREG8(VGA_CRTC_INDEX, 0x50);
byte = INREG8(VGA_CRTC_DATA) | 0xC1;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* if MS1NB style linear tiling mode.
* bit MM850C[15] = 0 select NB linear tile mode.
* bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
*/
ulTmp = INREG32(ADVANCED_FUNC_CTRL) | 0x8000; /* use MS-s style tile mode*/
OUTREG32(ADVANCED_FUNC_CTRL, ulTmp);
/*
* Set up Tiled Surface Registers
* Bit 25:20 - Surface width in tiles.
* Bit 29 - Y Range Flag.
* Bit 31:30 = 00, 4 bpp.
* = 01, 8 bpp.
* = 10, 16 bpp.
* = 11, 32 bpp.
*/
/*
* Global Bitmap Descriptor Register MM816C - twister/prosavage
* bit 24~25: tile format
* 00: linear
* 01: destination tiling format
* 10: texture tiling format
* 11: reserved
* bit 28: block write disble/enable
* 0: disable
* 1: enable
*/
/*
* Global Bitmap Descriptor Register MM816C - savage4
* bit 24~25: tile format
* 00: linear
* 01: reserved
* 10: 16 bpp tiles
* 11: 32 bpp tiles
* bit 28: block write disable/enable
* 0: enable
* 1: disable
*/
/*
* Do not enable block_write even for non-tiling modes, because
* the driver cannot determine if the memory type is the certain
* type of SGRAM for which block_write can be used.
*/
si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */
si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */
/* HW uses width */
si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line
si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp);
si->GlobalBD.bd1.Offset = si->frameBufferOffset;
/*
* CR88, bit 4 - Block write enabled/disabled.
*
* Note: Block write must be disabled when writing to tiled
* memory. Even when writing to non-tiled memory, block
* write should only be enabled for certain types of SGRAM.
*/
OUTREG8(VGA_CRTC_INDEX, 0x88);
byte = INREG8(VGA_CRTC_DATA) | DISABLE_BLOCK_WRITE_2D;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
* bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
* at A000:0.
*/
OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */
byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000));
OUTREG8(VGA_CRTC_DATA, byte); /* perhaps this should be 0x0c */
/* turn on screen */
OUTREG8(VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) & ~0x20;
OUTREG8(VGA_SEQ_DATA, byte);
/* program the GBD and SBD's */
OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_GLB_BD_HIGH, si->GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart);
}
static void
SavageSetGBD_3D(DisplayMode* pMode)
{
uint32 ulTmp;
uint8 byte;
int bci_enable;
TRACE(("SavageSetGBD_3D\n"));
bci_enable = BCI_ENABLE;
/* MM81C0 and 81C4 are used to control primary stream. */
OUTREG32(PRI_STREAM_FBUF_ADDR0, 0);
OUTREG32(PRI_STREAM_FBUF_ADDR1, 0);
/*
* Program Primary Stream Stride Register.
*
* Tell engine if tiling on or off, set primary stream stride, and
* if tiling, set tiling bits/pixel and primary stream tile offset.
* Note that tile offset (bits 16 - 29) must be scanline width in
* bytes/128bytespertile * 256 Qwords/tile. This is equivalent to
* lDelta * 2. Remember that if tiling, lDelta is screenwidth in
* bytes padded up to an even number of tilewidths.
*/
OUTREG32(PRI_STREAM_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFFE000) |
(pMode->bytesPerRow & 0x00001fff));
/*
* CR69, bit 7 = 1
* to use MM streams processor registers to control primary stream.
*/
OUTREG8(VGA_CRTC_INDEX, 0x69);
byte = INREG8(VGA_CRTC_DATA) | 0x80;
OUTREG8(VGA_CRTC_DATA, byte);
OUTREG32(0x8128, 0xFFFFFFFFL);
OUTREG32(0x812C, 0xFFFFFFFFL);
OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
/* CR50, bit 7,6,0 = 111, Use GBD.*/
OUTREG8(VGA_CRTC_INDEX, 0x50);
byte = INREG8(VGA_CRTC_DATA) | 0xC1;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* if MS1NB style linear tiling mode.
* bit MM850C[15] = 0 select NB linear tile mode.
* bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
*/
ulTmp = INREG32(ADVANCED_FUNC_CTRL) | 0x8000; /* use MS-s style tile mode*/
OUTREG32(ADVANCED_FUNC_CTRL, ulTmp);
/*
* Tiled Surface 0 Registers MM48C40:
* bit 0~23: tile surface 0 frame buffer offset
* bit 24~29:tile surface 0 width
* bit 30~31:tile surface 0 bits/pixel
* 00: reserved
* 01, 8 bits
* 10, 16 Bits.
* 11, 32 Bits.
*/
/*
* Global Bitmap Descriptor Register MM816C
* bit 24~25: tile format
* 00: linear
* 01: reserved
* 10: 16 bpp tiles
* 11: 32 bpp tiles
* bit 28: block write disable/enable
* 0: enable
* 1: disable
*/
/*
* Do not enable block_write even for non-tiling modes, because
* the driver cannot determine if the memory type is the certain
* type of SGRAM for which block_write can be used.
*/
si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */
si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */
/* HW uses width */
si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line
si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp);
si->GlobalBD.bd1.Offset = si->frameBufferOffset;
/*
* CR88, bit 4 - Block write enabled/disabled.
*
* Note: Block write must be disabled when writing to tiled
* memory. Even when writing to non-tiled memory, block
* write should only be enabled for certain types of SGRAM.
*/
OUTREG8(VGA_CRTC_INDEX, 0x88);
byte = INREG8(VGA_CRTC_DATA) | DISABLE_BLOCK_WRITE_2D;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
* bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
* at A000:0.
*/
OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */
byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000));
OUTREG8(VGA_CRTC_DATA, byte); /* perhaps this should be 0x0c */
/* turn on screen */
OUTREG8(VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) & ~0x20;
OUTREG8(VGA_SEQ_DATA, byte);
/* program the GBD and SBD's */
OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_GLB_BD_HIGH, si->GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart);
}
static void
SavageSetGBD_M7(DisplayMode* pMode)
{
uint8 byte;
int bci_enable;
TRACE(("SavageSetGBD_M7\n"));
bci_enable = BCI_ENABLE;
/* following is the enable case */
/* SR01:turn off screen */
OUTREG8 (VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) | 0x20;
OUTREG8(VGA_SEQ_DATA, byte);
/*
* CR67_3:
* = 1 stream processor MMIO address and stride register
* are used to control the primary stream
* = 0 standard VGA address and stride registers
* are used to control the primary streams
*/
OUTREG8(VGA_CRTC_INDEX, 0x67);
byte = INREG8(VGA_CRTC_DATA) | 0x08;
OUTREG8(VGA_CRTC_DATA, byte);
/* IGA 2 */
OUTREG16(VGA_SEQ_INDEX, SELECT_IGA2_READS_WRITES);
OUTREG8(VGA_CRTC_INDEX, 0x67);
byte = INREG8(VGA_CRTC_DATA) | 0x08;
OUTREG8(VGA_CRTC_DATA, byte);
OUTREG16(VGA_SEQ_INDEX, SELECT_IGA1);
/* Set primary stream to bank 0 */
OUTREG8(VGA_CRTC_INDEX, MEMORY_CTRL0_REG); /* CRCA */
byte = INREG8(VGA_CRTC_DATA) & ~(MEM_PS1 + MEM_PS2) ;
OUTREG8(VGA_CRTC_DATA, byte);
/* MM81C0 and 81C4 are used to control primary stream. */
OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset & 0x7fffff);
OUTREG32(PRI_STREAM_FBUF_ADDR1, si->frameBufferOffset & 0x7fffff);
OUTREG32(PRI_STREAM2_FBUF_ADDR0, si->frameBufferOffset & 0x7fffff);
OUTREG32(PRI_STREAM2_FBUF_ADDR1, si->frameBufferOffset & 0x7fffff);
/*
* Program Primary Stream Stride Register.
*
* Tell engine if tiling on or off, set primary stream stride, and
* if tiling, set tiling bits/pixel and primary stream tile offset.
* Note that tile offset (bits 16 - 29) must be scanline width in
* bytes/128bytespertile * 256 Qwords/tile. This is equivalent to
* lDelta * 2. Remember that if tiling, lDelta is screenwidth in
* bytes padded up to an even number of tilewidths.
*/
OUTREG32(PRI_STREAM_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) |
(pMode->bytesPerRow & 0x00003fff));
OUTREG32(PRI_STREAM2_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) |
(pMode->bytesPerRow & 0x00003fff));
OUTREG32(0x8128, 0xFFFFFFFFL);
OUTREG32(0x812C, 0xFFFFFFFFL);
OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
/* CR50, bit 7,6,0 = 111, Use GBD.*/
OUTREG8(VGA_CRTC_INDEX, 0x50);
byte = INREG8(VGA_CRTC_DATA) | 0xC1;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* CR78, bit 3 - Block write enabled(1)/disabled(0).
* bit 2 - Block write cycle time(0:2 cycles,1: 1 cycle)
* Note: Block write must be disabled when writing to tiled
* memory. Even when writing to non-tiled memory, block
* write should only be enabled for certain types of SGRAM.
*/
OUTREG8(VGA_CRTC_INDEX, 0x78);
byte = INREG8(VGA_CRTC_DATA) | 0xfb;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* Tiled Surface 0 Registers MM48C40:
* bit 0~23: tile surface 0 frame buffer offset
* bit 24~29:tile surface 0 width
* bit 30~31:tile surface 0 bits/pixel
* 00: reserved
* 01, 8 bits
* 10, 16 Bits.
* 11, 32 Bits.
*/
/*
* Global Bitmap Descriptor Register MM816C
* bit 24~25: tile format
* 00: linear
* 01: reserved
* 10: 16 bit
* 11: 32 bit
* bit 28: block write disble/enable
* 0: enable
* 1: disable
*/
/*
* Do not enable block_write even for non-tiling modes, because
* the driver cannot determine if the memory type is the certain
* type of SGRAM for which block_write can be used.
*/
si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */
si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */
/* HW uses width */
si->GlobalBD.bd1.HighPart.Stride = (uint16)(pMode->width); // number of pixels per line
si->GlobalBD.bd1.HighPart.Bpp = (uint8)(pMode->bpp);
si->GlobalBD.bd1.Offset = si->frameBufferOffset;
/*
* CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
* bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
* at A000:0.
*/
OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */
byte = (INREG8(VGA_CRTC_DATA) | 0x04) & 0xFE;
OUTREG8(VGA_CRTC_DATA, byte);
/* program the GBD and SBD's */
OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart );
/* 8: bci enable */
OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart
| bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart);
OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart);
/* turn on screen */
OUTREG8(VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) & ~0x20;
OUTREG8(VGA_SEQ_DATA, byte);
}
static void
SavageSetGBD_PM(DisplayMode* pMode)
{
uint8 byte;
int bci_enable;
TRACE(("SavageSetGBD_PM\n"));
bci_enable = BCI_ENABLE_TWISTER;
/* following is the enable case */
/* SR01:turn off screen */
OUTREG8 (VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) | 0x20;
OUTREG8(VGA_SEQ_DATA, byte);
/*
* CR67_3:
* = 1 stream processor MMIO address and stride register
* are used to control the primary stream
* = 0 standard VGA address and stride registers
* are used to control the primary streams
*/
OUTREG8(VGA_CRTC_INDEX, 0x67);
byte = INREG8(VGA_CRTC_DATA) | 0x08;
OUTREG8(VGA_CRTC_DATA, byte);
/* IGA 2 */
OUTREG16(VGA_SEQ_INDEX, SELECT_IGA2_READS_WRITES);
OUTREG8(VGA_CRTC_INDEX, 0x67);
byte = INREG8(VGA_CRTC_DATA) | 0x08;
OUTREG8(VGA_CRTC_DATA, byte);
OUTREG16(VGA_SEQ_INDEX, SELECT_IGA1);
/*
* load ps1 active registers as determined by MM81C0/81C4
* load ps2 active registers as determined by MM81B0/81B4
*/
OUTREG8(VGA_CRTC_INDEX, 0x65);
byte = INREG8(VGA_CRTC_DATA) | 0x03;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* Program Primary Stream Stride Register.
*
* Tell engine if tiling on or off, set primary stream stride, and
* if tiling, set tiling bits/pixel and primary stream tile offset.
* Note that tile offset (bits 16 - 29) must be scanline width in
* bytes/128bytespertile * 256 Qwords/tile. This is equivalent to
* lDelta * 2. Remember that if tiling, lDelta is screenwidth in
* bytes padded up to an even number of tilewidths.
*/
OUTREG32(PRI_STREAM_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) |
(pMode->bytesPerRow & 0x00001fff));
OUTREG32(PRI_STREAM2_STRIDE,
(((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) |
(pMode->bytesPerRow & 0x00001fff));
/* MM81C0 and 81C4 are used to control primary stream. */
OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset);
OUTREG32(PRI_STREAM_FBUF_ADDR1, 0x80000000);
OUTREG32(PRI_STREAM2_FBUF_ADDR0, (si->frameBufferOffset & 0xfffffffc) | 0x80000000);
OUTREG32(PRI_STREAM2_FBUF_ADDR1, si->frameBufferOffset & 0xfffffffc);
OUTREG32(0x8128, 0xFFFFFFFFL);
OUTREG32(0x812C, 0xFFFFFFFFL);
/* bit 28:block write disable */
OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000);
/* CR50, bit 7,6,0 = 111, Use GBD.*/
OUTREG8(VGA_CRTC_INDEX, 0x50);
byte = INREG8(VGA_CRTC_DATA) | 0xC1;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* Do not enable block_write even for non-tiling modes, because
* the driver cannot determine if the memory type is the certain
* type of SGRAM for which block_write can be used.
*/
si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */
si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */
/* HW uses width */
si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line
si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp);
si->GlobalBD.bd1.Offset = si->frameBufferOffset;
/*
* CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
* bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
* at A000:0.
*/
OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG);
byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000));
OUTREG8(VGA_CRTC_DATA, byte);
/* program the GBD and SBDs */
OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart );
OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart
| bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart);
OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart);
/* turn on screen */
OUTREG8(VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) & ~0x20;
OUTREG8(VGA_SEQ_DATA, byte);
}
static void
SavageSetGBD_2000(DisplayMode* pMode)
{
uint32 ulYRange;
uint8 byte;
int bci_enable;
TRACE(("SavageSetGBD_2000\n"));
bci_enable = BCI_ENABLE_TWISTER;
if (pMode->width > 1024)
ulYRange = 0x40000000;
else
ulYRange = 0x20000000;
/* following is the enable case */
/* SR01:turn off screen */
OUTREG8 (VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) | 0x20;
OUTREG8(VGA_SEQ_DATA, byte);
/* MM81C0 and 81B0 are used to control primary stream. */
OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset);
OUTREG32(PRI_STREAM2_FBUF_ADDR0, si->frameBufferOffset);
/*
* Program Primary Stream Stride Register.
*
* Tell engine if tiling on or off, set primary stream stride, and
* if tiling, set tiling bits/pixel and primary stream tile offset.
* Note that tile offset (bits 16 - 29) must be scanline width in
* bytes/128bytespertile * 256 Qwords/tile. This is equivalent to
* lDelta * 2. Remember that if tiling, lDelta is screenwidth in
* bytes padded up to an even number of tilewidths.
*/
OUTREG32(PRI_STREAM_STRIDE, ((pMode->bytesPerRow << 4) & 0x7ff0));
OUTREG32(PRI_STREAM2_STRIDE, ((pMode->bytesPerRow << 4) & 0x7ff0));
/*
* CR67_3:
* = 1 stream processor MMIO address and stride register
* are used to control the primary stream
* = 0 standard VGA address and stride registers
* are used to control the primary streams
*/
OUTREG8(VGA_CRTC_INDEX, 0x67);
byte = INREG8(VGA_CRTC_DATA) | 0x08;
OUTREG8(VGA_CRTC_DATA, byte);
OUTREG32(0x8128, 0xFFFFFFFFL);
OUTREG32(0x812C, 0xFFFFFFFFL);
/* bit 28:block write disable */
OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000);
/* CR50, bit 7,6,0 = 111, Use GBD.*/
OUTREG8(VGA_CRTC_INDEX, 0x50);
byte = INREG8(VGA_CRTC_DATA) | 0xC1;
OUTREG8(VGA_CRTC_DATA, byte);
/* CR73 bit 5 = 0 block write disable */
OUTREG8(VGA_CRTC_INDEX, 0x73);
byte = INREG8(VGA_CRTC_DATA) & ~0x20;
OUTREG8(VGA_CRTC_DATA, byte);
/*
* Do not enable block_write even for non-tiling modes, because
* the driver cannot determine if the memory type is the certain
* type of SGRAM for which block_write can be used.
*/
si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */
si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */
/* HW uses width */
si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line
si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp);
si->GlobalBD.bd1.Offset = si->frameBufferOffset;
/*
* CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
* bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
* at A000:0.
*/
OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG);
byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000));
OUTREG8(VGA_CRTC_DATA, byte);
/* program the GBD and SBDs */
OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart );
OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart
| bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart);
OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart);
OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart);
/* turn on screen */
OUTREG8(VGA_SEQ_INDEX, 0x01);
byte = INREG8(VGA_SEQ_DATA) & ~0x20;
OUTREG8(VGA_SEQ_DATA, byte);
}
void
SavageSetGBD(DisplayMode* pMode)
{
TRACE(("SavageSetGBD\n"));
UnProtectCRTC();
UnLockExtRegs();
VerticalRetraceWait();
switch (si->chipset) {
case S3_SAVAGE3D:
SavageSetGBD_3D(pMode);
break;
case S3_SAVAGE_MX:
SavageSetGBD_M7(pMode);
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_TWISTER:
case S3_PROSAVAGEDDR:
SavageSetGBD_Twister(pMode);
break;
case S3_SUPERSAVAGE:
SavageSetGBD_PM(pMode);
break;
case S3_SAVAGE2000:
SavageSetGBD_2000(pMode);
break;
}
}
void
SavageInitialize2DEngine(DisplayMode* pMode)
{
uint32 thresholds;
TRACE(("SavageInitialize2DEngine\n"));
OUTREG16(VGA_CRTC_INDEX, 0x0140);
OUTREG8(VGA_CRTC_INDEX, 0x31);
OUTREG8(VGA_CRTC_DATA, 0x0c);
/* Setup plane masks */
OUTREG(0x8128, ~0); /* enable all write planes */
OUTREG(0x812C, ~0); /* enable all read planes */
OUTREG16(0x8134, 0x27);
OUTREG16(0x8136, 0x07);
switch (si->chipset) {
case S3_SAVAGE3D:
case S3_SAVAGE_MX:
/* Disable BCI */
OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0);
/* Setup BCI command overflow buffer */
OUTREG(0x48C14, (si->cobOffset >> 11) | (si->cobIndex << 29)); /* tim */
/* Program shadow status update. */
thresholds = ((si->bciThresholdLo & 0xffff) << 16) |
(si->bciThresholdHi & 0xffff);
OUTREG(0x48C10, thresholds);
OUTREG(0x48C0C, 0);
/* Enable BCI and command overflow buffer */
OUTREG(0x48C18, INREG(0x48C18) | 0x0C);
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_TWISTER:
case S3_PROSAVAGEDDR:
case S3_SUPERSAVAGE:
/* Disable BCI */
OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0);
if (!si->bDisableCOB) {
/* Setup BCI command overflow buffer */
OUTREG(0x48C14, (si->cobOffset >> 11) | (si->cobIndex << 29));
}
/* Program shadow status update */ /* AGD: what should this be? */
thresholds = ((si->bciThresholdLo & 0x1fffe0) << 11)
| ((si->bciThresholdHi & 0x1fffe0) >> 5);
OUTREG(0x48C10, thresholds);
OUTREG(0x48C0C, 0);
if (si->bDisableCOB)
OUTREG(0x48C18, INREG(0x48C18) | 0x08); // enable BCI without COB
else
OUTREG(0x48C18, INREG(0x48C18) | 0x0C); // enable BCI with COB
break;
case S3_SAVAGE2000:
/* Disable BCI */
OUTREG(0x48C18, 0);
/* Setup BCI command overflow buffer */
OUTREG(0x48C18, (si->cobOffset >> 7) | (si->cobIndex));
/* Disable shadow status update */
OUTREG(0x48A30, 0);
/* Enable BCI and command overflow buffer */
OUTREG(0x48C18, INREG(0x48C18) | 0x00280000 );
break;
}
/* Use and set global bitmap descriptor. */
/* For reasons I do not fully understand yet, on the Savage4, the */
/* write to the GBD register, MM816C, does not "take" at this time. */
/* Only the low-order byte is acknowledged, resulting in an incorrect */
/* stride. Writing the register later, after the mode switch, works */
/* correctly. This needs to get resolved. */
SavageSetGBD(pMode);
}

View File

@ -1,177 +0,0 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2007
*/
#include "GlobalData.h"
#include "savage.h"
// Certain HW cursor operations seem to require a delay to prevent lockups.
static void
WaitHSync(int n)
{
while (n--) {
while ((ReadST01()) & 0x01) {};
while (!(ReadST01()) & 0x01) {};
}
}
void
SavageHideCursor(void)
{
/* Turn cursor off. */
if (S3_SAVAGE4_SERIES(si->chipset))
WaitHSync(5);
WriteCrtc(0x45, ReadCrtc(0x45) & 0xfe);
si->cursor.bIsVisible = false;
}
void
SavageShowCursor(void)
{
/* Turn cursor on. */
WriteCrtc(0x45, ReadCrtc(0x45) | 0x01);
si->cursor.bIsVisible = true;
}
void
SavageSetCursorPosition(int x, int y)
{
uint8 xoff, yoff;
if (S3_SAVAGE4_SERIES(si->chipset))
WaitHSync(5);
/* adjust for frame buffer base address granularity */
if (si->bitsPerPixel == 8)
x += ((si->frameX0) & 3);
else if (si->bitsPerPixel == 16)
x += ((si->frameX0) & 1);
else if (si->bitsPerPixel == 32)
x += ((si->frameX0 + 2) & 3) - 2;
/*
* Make these even when used. There is a bug/feature on at least
* some chipsets that causes a "shadow" of the cursor in interlaced
* mode. Making this even seems to have no visible effect, so just
* do it for the generic case.
*/
if (x < 0) {
xoff = (( -x) & 0xFE);
x = 0;
} else {
xoff = 0;
}
if (y < 0) {
yoff = (( -y) & 0xFE);
y = 0;
} else {
yoff = 0;
}
/* This is the recomended order to move the cursor */
WriteCrtc( 0x46, (x & 0xff00) >> 8 );
WriteCrtc( 0x47, (x & 0xff) );
WriteCrtc( 0x49, (y & 0xff) );
WriteCrtc( 0x4e, xoff );
WriteCrtc( 0x4f, yoff );
WriteCrtc( 0x48, (y & 0xff00) >> 8 );
}
static void
SavageSetCursorColors(int bg, int fg)
{
/* With the streams engine on HW Cursor seems to be 24bpp ALWAYS */
//@ TRACE(("SavageSetCursorColors\n"));
/* Do it straight, full 24 bit color. */
/* Reset the cursor color stack pointer */
ReadCrtc(0x45);
/* Write low, mid, high bytes - foreground */
WriteCrtc(0x4a, fg);
WriteCrtc(0x4a, fg >> 8);
WriteCrtc(0x4a, fg >> 16);
/* Reset the cursor color stack pointer */
ReadCrtc(0x45);
/* Write low, mid, high bytes - background */
WriteCrtc(0x4b, bg);
WriteCrtc(0x4b, bg >> 8);
WriteCrtc(0x4b, bg >> 16);
}
/* Assume width and height are byte-aligned. */
bool
SavageLoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
{
int i, colByte, row;
uint8* fbCursor;
uint16* fbCursor16;
// TRACE(("SavageLoadCursorImage, width: %ld height: %ld\n", width, height));
if ( ! andMask || ! xorMask)
return false;
// Initialize the hardware cursor as completely transparent.
fbCursor16 = (void *)((addr_t)si->videoMemAddr + si->cursorOffset);
for (i = 0; i < 1024 / 4; i++) {
*fbCursor16++ = ~0; // and bits
*fbCursor16++ = 0; // xor bits
}
// Now load the AND & XOR masks for the cursor image into the cursor
// buffer.
fbCursor = (void *)((addr_t)si->videoMemAddr + si->cursorOffset);
for (row = 0; row < height; row++) {
for (colByte = 0; colByte < width / 8; colByte++) {
fbCursor[row * 16 + colByte] = *andMask++;
fbCursor[row * 16 + colByte + 2] = *xorMask++;
}
}
SavageSetCursorColors(~0, 0); // set cursor colors to black & white
/* Set cursor location in video memory. */
WriteCrtc(0x4d, (0xff & si->cursorOffset / 1024));
WriteCrtc(0x4c, (0xff00 & si->cursorOffset / 1024) >> 8);
if (S3_SAVAGE4_SERIES(si->chipset)) {
/*
* Bug in Savage4 Rev B requires us to do an MMIO read after
* loading the cursor.
*/
volatile unsigned int k = ALT_STATUS_WORD0;
(void)k++; /* Not to be optimised out */
}
return true;
}

View File

@ -1,133 +0,0 @@
/*
Haiku S3 Savage driver adapted from the X.org Savage driver.
Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
Copyright (c) 2003-2006, X.Org Foundation
Copyright 2007 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac 2006-2007
*/
#include "GlobalData.h"
#include "AccelerantPrototypes.h"
#include "savage.h"
status_t
SET_DPMS_MODE(uint32 dpmsMode)
{
// Set the display into one of the Display Power Management modes,
// and return B_OK if successful, else return B_ERROR.
uint8 sr8 = 0x00, srd = 0x00;
TRACE(("SET_DPMS_MODE, mode: %d, display type: %d\n", dpmsMode, si->displayType));
if (si->displayType == MT_CRT) {
OUTREG8(VGA_SEQ_INDEX, 0x08);
sr8 = INREG8(VGA_SEQ_DATA);
sr8 |= 0x06;
OUTREG8(VGA_SEQ_DATA, sr8);
OUTREG8(VGA_SEQ_INDEX, 0x0d);
srd = INREG8(VGA_SEQ_DATA);
srd &= 0x03;
switch (dpmsMode) {
case B_DPMS_ON:
break;
case B_DPMS_STAND_BY:
srd |= 0x10;
break;
case B_DPMS_SUSPEND:
srd |= 0x40;
break;
case B_DPMS_OFF:
srd |= 0x50;
break;
default:
TRACE(("Invalid DPMS mode %d\n", dpmsMode));
return B_ERROR;
}
OUTREG8(VGA_SEQ_INDEX, 0x0d);
OUTREG8(VGA_SEQ_DATA, srd);
} else if (si->displayType == MT_LCD || si->displayType == MT_DFP) {
switch (dpmsMode) {
case B_DPMS_ON:
OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */
OUTREG8(VGA_SEQ_DATA, INREG8(VGA_SEQ_DATA) | 0x10);
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */
OUTREG8(VGA_SEQ_DATA, INREG8(VGA_SEQ_DATA) & ~0x10);
break;
default:
TRACE(("Invalid DPMS mode %d\n", dpmsMode));
return B_ERROR;
}
}
return B_OK;
}
uint32
DPMS_CAPABILITIES (void)
{
// Return DPMS modes supported by this device.
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
}
uint32
DPMS_MODE (void)
{
// Return the current DPMS mode.
// Note: I do not know whether the following code is correctly reading
// the current DPMS mode. I'm assuming that reading back the bits that
// were set by function SET_DPMS_MODE will give the current DPMS mode.
uint32 mode = B_DPMS_ON;
uint8 srd;
if (si->displayType == MT_CRT) {
OUTREG8(VGA_SEQ_INDEX, 0x0d);
srd = INREG8(VGA_SEQ_DATA);
switch (srd & 0x70) {
case 0:
mode = B_DPMS_ON;
break;
case 0x10:
mode = B_DPMS_STAND_BY;
break;
case 0x40:
mode = B_DPMS_SUSPEND;
break;
case 0x50:
mode = B_DPMS_OFF;
break;
default:
TRACE(("Unknown DPMS mode read from device %X\n", srd));
}
} else if (si->displayType == MT_LCD || si->displayType == MT_DFP) {
OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */
srd = INREG8(VGA_SEQ_DATA);
mode = ((srd & 0x10) ? B_DPMS_ON : B_DPMS_OFF);
}
TRACE(("DPMS_MODE = %d\n", mode));
return mode;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3savage ;
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 vesa ;

View File

@ -0,0 +1,16 @@
SubDir HAIKU_TOP src add-ons kernel drivers graphics s3 ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders [ FDirName graphics s3 ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
UsePrivateHeaders graphics kernel ;
KernelAddon s3 :
driver.cpp
;
Package haiku-s3-cvs :
s3 :
boot home config add-ons kernel drivers bin ;
PackageDriverSymLink haiku-s3-cvs : graphics s3 ;

View File

@ -0,0 +1,799 @@
/*
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-2008
*/
#include <KernelExport.h>
#include <PCI.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <graphic_driver.h>
#include "DriverInterface.h"
#undef TRACE
#ifdef ENABLE_DEBUG_TRACE
# define TRACE(x...) dprintf("S3: " x)
#else
# define TRACE(x...) ;
#endif
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
#define SKD_HANDLER_INSTALLED 0x80000000
#define MAX_DEVICES 8
#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X"
int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support
struct ChipInfo {
uint16 chipID; // PCI device id of the chip
uint16 chipType; // assigned chip type identifier
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.
// Note that the Trio64 and Trio64V+ chips have the same ID, but have a different
// revision number. After the revision number is examined, the Trio64V+ will
// have a different chip type code and name assigned.
static const ChipInfo S3_ChipTable[] = {
{ 0x8811, S3_TRIO64, "Trio64" }, // see comment above
{ 0x8814, S3_TRIO64_UVP, "Trio64 UV+" },
{ 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" },
{ 0x5631, S3_VIRGE, "Virge" },
{ 0x883D, S3_VIRGE_VX, "Virge VX" },
{ 0x8A01, S3_VIRGE_DXGX, "Virge DX/GX" },
{ 0x8A10, S3_VIRGE_GX2, "Virge GX2" },
{ 0x8C01, S3_VIRGE_MX, "Virge MX" },
{ 0x8C03, S3_VIRGE_MXP, "Virge MX+" },
{ 0x8904, S3_TRIO_3D, "Trio 3D" },
{ 0x8A13, S3_TRIO_3D_2X, "Trio 3D/2X" },
{ 0x8a20, S3_SAVAGE_3D, "Savage3D" },
{ 0x8a21, S3_SAVAGE_3D, "Savage3D-MV" },
{ 0x8a22, S3_SAVAGE4, "Savage4" },
{ 0x8a25, S3_PROSAVAGE, "ProSavage PM133" },
{ 0x8a26, S3_PROSAVAGE, "ProSavage KM133" },
{ 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" },
{ 0x8c11, S3_SAVAGE_MX, "Savage/MX" },
{ 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" },
{ 0x8c13, S3_SAVAGE_MX, "Savage/IX" },
{ 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" },
{ 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" },
{ 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" },
{ 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" },
{ 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" },
{ 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" },
{ 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" },
{ 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" },
{ 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" },
{ 0x8d01, S3_TWISTER, "Twister PN133" },
{ 0x8d02, S3_TWISTER, "Twister KN133" },
{ 0x8d03, S3_PROSAVAGE_DDR, "ProSavage DDR" },
{ 0x8d04, S3_PROSAVAGE_DDR, "ProSavage DDR-K" },
{ 0x9102, S3_SAVAGE2000, "Savage2000" },
{ 0, 0, NULL }
};
#define VENDOR_ID 0x5333 // S3 vendor ID
static struct {
uint16 vendorID;
const ChipInfo* devices;
} SupportedDevices[] = {
{ VENDOR_ID, S3_ChipTable },
{ 0x0000, 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* si; // pointer to the shared area
vuint8* regs; // kernel's pointer to memory mapped registers
const ChipInfo* pChipInfo; // info about the selected chip
pci_info pcii; // copy of pci info for this device
char name[B_OS_NAME_LENGTH]; // name of device
};
struct DeviceData {
uint32 count; // number of devices actually found
benaphore kernel; // for serializing opens/closes
char* deviceNames[MAX_DEVICES + 1]; // device name pointer storage
DeviceInfo di[MAX_DEVICES]; // device specific stuff
};
// Prototypes for our private functions.
static status_t open_hook (const char* name, uint32 flags, void** cookie);
static status_t close_hook (void* dev);
static status_t free_hook (void* dev);
static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len);
static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len);
static status_t control_hook (void* dev, uint32 msg, void* buf, size_t len);
static status_t map_device(DeviceInfo* di);
static void unmap_device(DeviceInfo* di);
static void probe_devices(void);
static int32 s3_interrupt(void* data);
static DeviceData* pd;
static pci_module_info* pci_bus;
static device_hooks graphics_device_hooks =
{
open_hook,
close_hook,
free_hook,
control_hook,
read_hook,
write_hook,
NULL,
NULL,
NULL,
NULL
};
// Functions for dealing with Vertical Blanking Interrupts. Currently, I do
// not know the commands to handle these operations; thus, these functions
// currently do nothing.
static bool
InterruptIsVBI()
{
// return true only if a vertical blanking interrupt has occured
return false;
}
static void
ClearVBI()
{
}
static void
EnableVBI()
{
}
static void
DisableVBI()
{
}
static const ChipInfo*
FindDeviceMatch(uint16 vendorID, uint16 deviceID)
{
// Search the table of supported devices to find a chip/device that
// matches the vendor ID and device ID passed by the caller.
// Return pointer to the struct containing the chip info if match
// is found; else return NULL.
int vendor = 0;
while (SupportedDevices[vendor].vendorID != 0) { // end of table?
if (SupportedDevices[vendor].vendorID == vendorID) {
const ChipInfo* pDevice = SupportedDevices[vendor].devices;
while (pDevice->chipID != 0) { // end of table?
if (pDevice->chipID == deviceID)
return pDevice; // matching device/chip found
pDevice++;
}
}
vendor++;
}
return NULL; // no match found
}
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.
long pci_index = 0;
pci_info pcii;
const ChipInfo* pDevice = NULL;
if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK)
return B_ERROR; // unable to access PCI bus
// Check all pci devices for a device supported by this driver.
while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id);
if (pDevice != NULL)
break;
pci_index++;
}
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**)&pci_bus) != B_OK)
return B_ERROR;
pd = (DeviceData*)calloc(1, sizeof(DeviceData));
if (NULL == pd) {
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
INIT_BEN(pd->kernel); // initialize the benaphore
probe_devices(); // find all devices supported by this driver
return B_OK;
}
const char**
publish_devices(void)
{
return (const char**)pd->deviceNames; // return list of supported devices
}
device_hooks*
find_device(const char* name)
{
int index = 0;
while (pd->deviceNames[index]) {
if (strcmp(name, pd->deviceNames[index]) == 0)
return &graphics_device_hooks;
index++;
}
return NULL;
}
void
uninit_driver(void)
{
// Free the driver data.
DELETE_BEN(pd->kernel);
free(pd);
pd = NULL;
put_module(B_PCI_MODULE_NAME); // put the pci module away
}
static status_t
map_device(DeviceInfo* di)
{
char areaName[B_OS_NAME_LENGTH];
SharedInfo* si = di->si;
pci_info* pcii = &(di->pcii);
TRACE("enter map_device()\n");
// enable memory mapped IO and VGA I/O
uint32 tmpUlong = get_pci(PCI_command, 2);
tmpUlong |= PCI_command_io | PCI_command_memory | PCI_command_master;
set_pci(PCI_command, 2, tmpUlong);
const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB
const uint32 SavageMmioRegBaseNew = 0x0000000;
const uint32 SavageMmioRegSize = 0x0080000; // 512 KB reg area size
const uint32 VirgeMmioRegBase = 0x1000000; // 16 MB
const uint32 VirgeMmioRegSize = 0x10000; // 64 KB reg area size
uint32 videoRamAddr = 0;
uint32 videoRamSize = 0;
uint32 regsBase = 0;
uint32 regAreaSize = 0;
// Since we do not know at this point the actual size of the video
// memory, set it to the largest value that the respective chipset
// family can have.
if (S3_SAVAGE_FAMILY(di->pChipInfo->chipType)) {
if (S3_SAVAGE_3D_SERIES(di->pChipInfo->chipType)) {
// Savage 3D & Savage MX chips.
regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseOld;
regAreaSize = SavageMmioRegSize;
videoRamAddr = di->pcii.u.h0.base_registers[0];
videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series
si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]);
} else {
// All other Savage chips.
regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseNew;
regAreaSize = SavageMmioRegSize;
videoRamAddr = di->pcii.u.h0.base_registers[1];
videoRamSize = di->pcii.u.h0.base_register_sizes[1];
si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]);
}
} else {
// Trio/Virge chips.
regsBase = di->pcii.u.h0.base_registers[0] + VirgeMmioRegBase;
regAreaSize = VirgeMmioRegSize;
videoRamAddr = di->pcii.u.h0.base_registers[0];
videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips
si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]);
}
// Map the MMIO register area.
sprintf(areaName, DEVICE_FORMAT " regs",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->regsArea = map_physical_memory(areaName, (void*)regsBase, regAreaSize,
B_ANY_KERNEL_ADDRESS,
0, // neither read nor write, to hide it from user space apps
(void**)(&(di->regs)));
if (si->regsArea < 0)
return si->regsArea; // return error code
// Map the video memory.
sprintf(areaName, DEVICE_FORMAT " framebuffer",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->videoMemArea = map_physical_memory(
areaName,
(void*)videoRamAddr,
videoRamSize,
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA + B_WRITE_AREA,
&(si->videoMemAddr));
if (si->videoMemArea < 0) {
// Try to map this time without write combining.
si->videoMemArea = map_physical_memory(
areaName,
(void*)videoRamAddr,
videoRamSize,
B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA + B_WRITE_AREA,
&(si->videoMemAddr));
}
TRACE("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si->videoMemArea,
(uint32)(si->videoMemAddr), videoRamSize);
// If there was an error, delete other areas.
if (si->videoMemArea < 0) {
delete_area(si->regsArea);
si->regsArea = -1;
}
TRACE("leave map_device(); result: %ld\n", si->videoMemArea);
return si->videoMemArea;
}
static void
unmap_device(DeviceInfo* di)
{
SharedInfo* si = di->si;
pci_info* pcii = &(di->pcii);
TRACE("enter unmap_device()\n");
// Disable memory mapped IO.
uint32 tmpUlong = get_pci(PCI_command, 2);
tmpUlong &= ~(PCI_command_io | PCI_command_memory);
set_pci(PCI_command, 2, tmpUlong);
if (si->regsArea >= 0)
delete_area(si->regsArea);
if (si->videoMemArea >= 0)
delete_area(si->videoMemArea);
si->regsArea = si->videoMemArea = -1;
si->videoMemAddr = NULL;
di->regs = NULL;
TRACE("exit unmap_device()\n");
}
static void
probe_devices(void)
{
uint32 pci_index = 0;
uint32 count = 0;
DeviceInfo* di = pd->di;
const ChipInfo* pDevice;
while ((count < MAX_DEVICES)
&& ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id);
if (pDevice != NULL) {
// Compose device name.
sprintf(di->name, "graphics/" DEVICE_FORMAT,
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
TRACE("probe_devices() match found; name: %s\n", di->name);
pd->deviceNames[count] = di->name;
di->openCount = 0; // mark driver as available for R/W open
di->sharedArea = -1; // indicate shared area not yet created
di->si = NULL;
di->pChipInfo = pDevice;
di++;
count++;
}
pci_index++;
}
pd->count = count;
pd->deviceNames[pd->count] = NULL; // terminate list with null pointer
TRACE("probe_devices() %ld supported devices\n", pd->count);
}
static uint32
thread_interrupt_work(DeviceInfo* di)
{
SharedInfo* si = di->si;
uint32 handled = B_HANDLED_INTERRUPT;
// Release vertical blanking semaphore.
if (si->vertBlankSem >= 0) {
int32 blocked;
if ((get_sem_count(si->vertBlankSem, &blocked) == B_OK) && (blocked < 0)) {
release_sem_etc(si->vertBlankSem, -blocked, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER;
}
}
return handled;
}
static int32
s3_interrupt(void* data)
{
int32 handled = B_UNHANDLED_INTERRUPT;
DeviceInfo* di = (DeviceInfo*)data;
int32* flags = &(di->flags);
// Is someone already handling an interrupt for this device?
if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED)
return B_UNHANDLED_INTERRUPT;
if (InterruptIsVBI()) { // was interrupt a VBI?
ClearVBI(); // clear interrupt
handled = thread_interrupt_work(di); // release semaphore
}
atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore
return handled;
}
// #pragma mark - Device Hooks
static status_t
open_hook(const char* name, uint32 flags, void** cookie)
{
int32 index = 0;
SharedInfo* si;
thread_id thid;
thread_info thinfo;
status_t result = B_OK;
char sharedName[B_OS_NAME_LENGTH];
(void)flags; // avoid compiler warning for unused arg
TRACE("open_hook() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie);
// Find the device name in the list of devices.
while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0))
index++;
DeviceInfo* di = &(pd->di[index]);
// Make sure no one else has write access to the common data.
AQUIRE_BEN(pd->kernel);
if (di->openCount > 0)
goto mark_as_open;
// Create the area for shared info with NO user-space read or write permissions,
// to prevent accidental damage.
sprintf(sharedName, DEVICE_FORMAT " shared",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
di->sharedArea = create_area(sharedName, (void**) &(di->si), B_ANY_KERNEL_ADDRESS,
((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)),
B_FULL_LOCK, 0);
if (di->sharedArea < 0) {
result = di->sharedArea; // return error
goto done;
}
si = di->si;
si->vendorID = di->pcii.vendor_id;
si->deviceID = di->pcii.device_id;
si->revision = di->pcii.revision;
si->chipType = di->pChipInfo->chipType;
strcpy(si->chipName, di->pChipInfo->chipName);
// Trio64 and Trio64V+ chips have the same ID but different revision numbers.
// Since the Trio64V+ supports MMIO, better performance can be obtained
// from it if it is distinguished from the Trio64.
if (si->chipType == S3_TRIO64 && si->revision & 0x40) {
si->chipType = S3_TRIO64_VP;
strcpy(si->chipName, "Trio64 V+");
}
result = map_device(di);
if (result < 0)
goto free_shared;
result = B_OK;
DisableVBI(); // disable & clear any pending interrupts
si->bInterruptAssigned = false; // indicate interrupt not assigned yet
// Create a semaphore for vertical blank management.
si->vertBlankSem = create_sem(0, di->name);
if (si->vertBlankSem < 0)
goto mark_as_open;
// Change the owner of the semaphores to the opener's team.
// This is required because apps can't aquire kernel semaphores.
thid = find_thread(NULL);
get_thread_info(thid, &thinfo);
set_sem_owner(si->vertBlankSem, thinfo.team);
// If there is a valid interrupt assigned, set up interrupts.
if ((di->pcii.u.h0.interrupt_pin == 0x00) ||
(di->pcii.u.h0.interrupt_line == 0xff) || // no IRQ assigned
(di->pcii.u.h0.interrupt_line <= 0x02)) { // system IRQ assigned
// Interrupt does not exist; thus delete semaphore as it won't be used.
delete_sem(si->vertBlankSem);
si->vertBlankSem = -1;
} else {
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, (void*)di, 0);
if (result != B_OK) {
// Delete semaphore as it won't be used.
delete_sem(si->vertBlankSem);
si->vertBlankSem = -1;
} else {
// Inform accelerant(s) we can use interrupt related functions.
si->bInterruptAssigned = true;
}
}
mark_as_open:
di->openCount++; // mark device open
*cookie = di; // send cookie to opener
goto done;
free_shared:
delete_area(di->sharedArea);
di->sharedArea = -1;
di->si = NULL;
done:
// End of critical section.
RELEASE_BEN(pd->kernel);
TRACE("open_hook() returning 0x%08lx\n", result);
return result;
}
static status_t
read_hook(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
write_hook(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
close_hook(void* dev)
{
(void)dev; // avoid compiler warning for unused arg
TRACE("close_hook()\n");
return B_NO_ERROR;
}
static status_t
free_hook(void* dev)
{
DeviceInfo* di = (DeviceInfo*)dev;
SharedInfo* si = di->si;
TRACE("enter free_hook()\n");
AQUIRE_BEN(pd->kernel); // lock driver
// If opened multiple times, decrement the open count and exit.
if (di->openCount > 1)
goto unlock_and_exit;
DisableVBI(); // disable & clear any pending interrupts
if (si->bInterruptAssigned) {
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, di);
}
// Delete the semaphores, ignoring any errors because the owning team may have died.
if (si->vertBlankSem >= 0)
delete_sem(si->vertBlankSem);
si->vertBlankSem = -1;
unmap_device(di); // free regs and frame buffer areas
delete_area(di->sharedArea);
di->sharedArea = -1;
di->si = NULL;
unlock_and_exit:
if (di->openCount > 0)
di->openCount--; // mark device available
RELEASE_BEN(pd->kernel); // unlock driver
TRACE("exit free_hook()\n");
return B_OK;
}
static status_t
control_hook(void* dev, uint32 msg, void* buf, size_t len)
{
DeviceInfo* di = (DeviceInfo*)dev;
(void)len; // avoid compiler warning for unused arg
switch (msg) {
case B_GET_ACCELERANT_SIGNATURE:
strcpy((char*)buf, "s3.accelerant");
return B_OK;
case S3_DEVICE_NAME:
strncpy((char*)buf, di->name, B_OS_NAME_LENGTH);
((char*)buf)[B_OS_NAME_LENGTH -1] = '\0';
return B_OK;
case S3_GET_PRIVATE_DATA:
{
S3GetPrivateData* gpd = (S3GetPrivateData*)buf;
if (gpd->magic == S3_PRIVATE_DATA_MAGIC) {
gpd->sharedInfoArea = di->sharedArea;
return B_OK;
}
break;
}
case S3_RUN_INTERRUPTS:
{
S3SetBoolState* ri = (S3SetBoolState*)buf;
if (ri->magic == S3_PRIVATE_DATA_MAGIC) {
if (ri->bEnable)
EnableVBI();
else
DisableVBI();
}
return B_OK;
}
case S3_GET_PIO:
{
S3GetSetPIO* gsp = (S3GetSetPIO*)buf;
if (gsp->magic == S3_PRIVATE_DATA_MAGIC) {
switch (gsp->size) {
case 1:
gsp->value = pci_bus->read_io_8(gsp->offset);
break;
case 2:
gsp->value = pci_bus->read_io_16(gsp->offset);
break;
case 4:
gsp->value = pci_bus->read_io_32(gsp->offset);
break;
default:
TRACE("control_hook() S3_GET_PIO invalid size: %ld\n", gsp->size);
return B_ERROR;
}
return B_OK;
}
break;
}
case S3_SET_PIO:
{
S3GetSetPIO* gsp = (S3GetSetPIO*)buf;
if (gsp->magic == S3_PRIVATE_DATA_MAGIC) {
switch (gsp->size) {
case 1:
pci_bus->write_io_8(gsp->offset, gsp->value);
break;
case 2:
pci_bus->write_io_16(gsp->offset, gsp->value);
break;
case 4:
pci_bus->write_io_32(gsp->offset, gsp->value);
break;
default:
TRACE("control_hook() S3_SET_PIO invalid size: %ld\n", gsp->size);
return B_ERROR;
}
return B_OK;
}
break;
}
}
return B_DEV_INVALID_IOCTL;
}

View File

@ -1,16 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel drivers graphics s3savage ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders [ FDirName graphics s3savage ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
UsePrivateHeaders graphics kernel ;
KernelAddon s3savage :
driver.c
;
Package haiku-s3savage-cvs :
s3savage :
boot home config add-ons kernel drivers bin ;
PackageDriverSymLink haiku-s3savage-cvs : graphics s3savage ;

View File

@ -1,803 +0,0 @@
/*
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 2006-2007
*/
#include <KernelExport.h>
#include <PCI.h>
#include <OS.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "DriverInterface.h"
/* this is for the standardized portion of the driver API */
/* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */
#include <graphic_driver.h>
#ifdef TRACE_S3SAVAGE
# define TRACE(a) TraceLog a
#else
# define TRACE(a)
#endif
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
#define SKD_HANDLER_INSTALLED 0x80000000
#define MAX_DEVICES 8
#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X"
#define SAVAGE_NEWMMIO_REGBASE_S3 0x1000000 /* 16MB */
#define SAVAGE_NEWMMIO_REGBASE_S4 0x0000000
#define SAVAGE_NEWMMIO_REGSIZE 0x0080000 /* 512kb */
/* Tell the kernel what revision of the driver API we support */
int32 api_version = B_CUR_DRIVER_API_VERSION;
/* these structures are private to the kernel driver */
typedef struct {
uint16 chipID; // PCI device id of the chipset
uint16 chipset; // assigned chipset family identifier
char* chipName; // user recognizable name for chipset (must be < 32 chars)
} ChipInfo;
/* This table maps a PCI device ID to a chipset family identifier and the chipset
name. */
static ChipInfo SavageChipTable[] = {
{ 0x8a20, S3_SAVAGE3D, "Savage3D" },
{ 0x8a21, S3_SAVAGE3D, "Savage3D-MV" },
{ 0x8a22, S3_SAVAGE4, "Savage4" },
{ 0x8a25, S3_PROSAVAGE, "ProSavage PM133" },
{ 0x8a26, S3_PROSAVAGE, "ProSavage KM133" },
{ 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" },
{ 0x8c11, S3_SAVAGE_MX, "Savage/MX" },
{ 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" },
{ 0x8c13, S3_SAVAGE_MX, "Savage/IX" },
{ 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" },
{ 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" },
{ 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" },
{ 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" },
{ 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" },
{ 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" },
{ 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" },
{ 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" },
{ 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" },
{ 0x8d01, S3_TWISTER, "Twister PN133" },
{ 0x8d02, S3_TWISTER, "Twister KN133" },
{ 0x8d03, S3_PROSAVAGEDDR, "ProSavage DDR" },
{ 0x8d04, S3_PROSAVAGEDDR, "ProSavage DDR-K" },
{ 0x9102, S3_SAVAGE2000, "Savage2000" },
{ 0, 0, NULL }
};
#define VENDOR_ID_SAVAGE 0x5333 /* S3 Savage vendor ID */
static struct {
uint16 vendorID;
ChipInfo* devices;
} SupportedDevices[] = {
{ VENDOR_ID_SAVAGE, SavageChipTable },
{ 0x0000, NULL }
};
typedef struct {
uint32 is_open; /* a count of how many times the devices has been opened */
area_id sharedArea; /* the area shared between the driver and all of the accelerants */
SharedInfo *si; /* a pointer to the shared area, for convenience */
vuint8 *regs; /* kernel's pointer to memory mapped registers */
ChipInfo *pChipInfo; /* info about the selected chipset */
pci_info pcii; /* a convenience copy of the pci info for this device */
char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */
} DeviceInfo;
typedef struct {
uint32 count; /* number of devices actually found */
benaphore kernel; /* for serializing opens/closes */
char *deviceNames[MAX_DEVICES+1]; /* device name pointer storage */
DeviceInfo di[MAX_DEVICES]; /* device specific stuff */
} DeviceData;
/* prototypes for our private functions */
static status_t open_hook (const char* name, uint32 flags, void** cookie);
static status_t close_hook (void* dev);
static status_t free_hook (void* dev);
static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len);
static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len);
static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len);
static status_t map_device(DeviceInfo *di);
static void unmap_device(DeviceInfo *di);
static void probe_devices(void);
static int32 savage_interrupt(void *data);
static DeviceData *pd;
static pci_module_info *pci_bus;
static device_hooks graphics_device_hooks =
{
open_hook,
close_hook,
free_hook,
control_hook,
read_hook,
write_hook,
NULL,
NULL,
NULL,
NULL
};
#ifdef TRACE_S3SAVAGE
static void
TraceLog(const char *fmt, ...)
{
char string[1024];
va_list args;
strcpy(string, "savage: ");
va_start(args, fmt);
vsprintf(&string[strlen(string)], fmt, args);
dprintf(string);
}
#endif
// Functions for dealing with Vertical Blanking Interrupts. Currently, I do
// not know the commands to handle these operations; thus, these functions
// currently do nothing.
static bool
InterruptIsVBI()
{
// return true only if a vertical blanking interrupt has occured
return false;
}
static void
ClearVBI()
{
}
static void
EnableVBI()
{
}
static void
DisableVBI()
{
}
static ChipInfo*
FindDeviceMatch(uint16 vendorID, uint16 deviceID)
{
// Search the table of supported devices to find a chipset/device that
// matches the vendor ID and device ID passed by the caller.
// Return pointer to the struct containing the chipset info if match
// is found; else return NULL.
int vendor = 0;
while (SupportedDevices[vendor].vendorID != 0) { // end of table?
if (SupportedDevices[vendor].vendorID == vendorID) {
ChipInfo* pDevice = SupportedDevices[vendor].devices;
while (pDevice->chipID != 0) { // end of table?
if (pDevice->chipID == deviceID)
return pDevice; // matching device/chipset found
pDevice++;
}
}
vendor++;
}
return NULL; // no match found
}
/*
init_hardware() - Returns B_OK if a device supported by this driver
is found; otherwise, returns B_ERROR so the driver will be unloaded.
*/
status_t
init_hardware(void)
{
long pci_index = 0;
pci_info pcii;
ChipInfo* pDevice = NULL;
/* choke if we can't find the PCI bus */
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
return B_ERROR;
/* while there are more pci devices */
while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
// TRACE(("init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, pcii.vendor_id, pcii.device_id));
pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id);
if (pDevice != NULL)
break;
/* next pci_info struct, please */
pci_index++;
}
TRACE(("init_hardware - %s\n", pDevice == NULL ? "no supported devices" : "device supported"));
/* put away the module manager */
put_module(B_PCI_MODULE_NAME);
return (pDevice == NULL ? B_ERROR : B_OK);
}
status_t init_driver(void)
{
// TRACE(("enter init_driver\n"));
/* get a handle for the pci bus */
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
return B_ERROR;
/* driver private data */
pd = (DeviceData *)calloc(1, sizeof(DeviceData));
if (NULL == pd) {
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
/* initialize the benaphore */
INIT_BEN(pd->kernel);
/* find all of our supported devices */
probe_devices();
// TRACE(("exit init_driver\n"));
return B_OK;
}
const char**
publish_devices(void)
{
/* return the list of supported devices */
return (const char **)pd->deviceNames;
}
device_hooks*
find_device(const char *name)
{
int index = 0;
while (pd->deviceNames[index]) {
if (strcmp(name, pd->deviceNames[index]) == 0)
return &graphics_device_hooks;
index++;
}
return NULL;
}
void
uninit_driver(void)
{
/* free the driver data */
DELETE_BEN(pd->kernel);
free(pd);
pd = NULL;
/* put the pci module away */
put_module(B_PCI_MODULE_NAME);
}
static status_t
map_device(DeviceInfo *di)
{
/* default: frame buffer in [0], control regs in [1] */
char buffer[B_OS_NAME_LENGTH];
SharedInfo *si = di->si;
uint32 tmpUlong;
pci_info *pcii = &(di->pcii);
uint32 videoRamAddr = 0;
uint32 videoRamSize = 0;
uint32 regsBase = 0;
TRACE(("enter map_device\n"));
/* enable memory mapped IO, disable VGA I/O - this is defined in the PCI standard */
tmpUlong = get_pci(PCI_command, 2);
tmpUlong |= PCI_command_memory; // enable PCI access
tmpUlong |= PCI_command_master; // enable busmastering
tmpUlong &= ~PCI_command_io; // disable ISA I/O access
set_pci(PCI_command, 2, tmpUlong);
// Since we do not know at this point the actual size of the video
// memory, set it to the largest value that the respective chipset
// family can have.
if (S3_SAVAGE3D_SERIES(di->pChipInfo->chipset)) {
regsBase = di->pcii.u.h0.base_registers[0] + SAVAGE_NEWMMIO_REGBASE_S3;
videoRamAddr = di->pcii.u.h0.base_registers[0];
videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series
si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]);
} else {
regsBase = di->pcii.u.h0.base_registers[0] + SAVAGE_NEWMMIO_REGBASE_S4;
videoRamAddr = di->pcii.u.h0.base_registers[1];
videoRamSize = di->pcii.u.h0.base_register_sizes[1];
si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]);
}
TRACE(("base_registers 0: 0x%08lX 0x%08lX 0x%08lX\n", di->pcii.u.h0.base_registers[0], di->pcii.u.h0.base_registers_pci[0], di->pcii.u.h0.base_register_sizes[0] ));
TRACE(("base_registers 1: 0x%08lX 0x%08lX 0x%08lX\n", di->pcii.u.h0.base_registers[1], di->pcii.u.h0.base_registers_pci[1], di->pcii.u.h0.base_register_sizes[1] ));
/* map the areas */
sprintf(buffer, DEVICE_FORMAT " regs",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->regsArea = map_physical_memory(
buffer,
(void *)regsBase,
SAVAGE_NEWMMIO_REGSIZE,
B_ANY_KERNEL_ADDRESS,
0, /* B_READ_AREA + B_WRITE_AREA, */ /* neither read nor write, to hide it from user space apps */
(void **)(&(di->regs)));
/* return the error if there was some problem */
if (si->regsArea < 0)
return si->regsArea;
sprintf(buffer, DEVICE_FORMAT " framebuffer",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->videoMemArea = map_physical_memory(
buffer,
(void *)videoRamAddr,
videoRamSize,
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA + B_WRITE_AREA,
&(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(
buffer,
(void *)videoRamAddr,
videoRamSize,
B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA + B_WRITE_AREA,
&(si->videoMemAddr));
}
// TRACE(("Video memory, area: %ld, addr: 0x%lX\n", si->videoMemArea, (uint32)(si->videoMemAddr)));
/* if there was an error, delete our other areas */
if (si->videoMemArea < 0) {
delete_area(si->regsArea);
si->regsArea = -1;
}
/* in any case, return the result */
TRACE(("leave map_device\n"));
return si->videoMemArea;
}
static void
unmap_device(DeviceInfo *di)
{
SharedInfo *si = di->si;
uint32 tmpUlong;
pci_info *pcii = &(di->pcii);
TRACE(("enter unmap_device(%08lx)\n", (uint32)di));
// TRACE(("regsArea: %ld\n\tvideoMemArea: %ld\n", si->regsArea, si->videoMemArea));
/* disable memory mapped IO */
tmpUlong = get_pci(PCI_command, 2);
tmpUlong &= ~(PCI_command_io | PCI_command_memory);
set_pci(PCI_command, 2, tmpUlong);
/* delete the areas */
if (si->regsArea >= 0)
delete_area(si->regsArea);
if (si->videoMemArea >= 0)
delete_area(si->videoMemArea);
si->regsArea = si->videoMemArea = -1;
si->videoMemAddr = NULL;
di->regs = NULL;
TRACE(("exit unmap_device()\n"));
}
static void
probe_devices(void)
{
uint32 pci_index = 0;
uint32 count = 0;
DeviceInfo *di = pd->di;
ChipInfo* pDevice;
// TRACE(("enter probe_devices()\n"));
/* while there are more pci devices */
while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
// TRACE(("checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, di->pcii.vendor_id, di->pcii.device_id));
/* if we match a supported vendor & device */
pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id);
if (pDevice != NULL) {
/* publish the device name */
sprintf(di->name, "graphics/" DEVICE_FORMAT,
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
TRACE(("probe_devices: match found; name: %s\n", di->name));
pd->deviceNames[count] = di->name;
di->is_open = 0; // mark driver as available for R/W open
di->sharedArea = -1; // indicate shared area not yet created
di->si = NULL;
di->pChipInfo = pDevice;
di++;
count++;
}
pci_index++;
}
pd->count = count;
pd->deviceNames[pd->count] = NULL; // terminate list with null pointer
TRACE(("probe_devices: %ld supported devices\n", pd->count));
}
static uint32
thread_interrupt_work(DeviceInfo *di)
{
SharedInfo *si = di->si;
uint32 handled = B_HANDLED_INTERRUPT;
/* release the vblank semaphore */
if (si->vblank >= 0) {
int32 blocked;
if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) {
release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER;
}
}
return handled;
}
static int32
savage_interrupt(void *data)
{
int32 handled = B_UNHANDLED_INTERRUPT;
DeviceInfo *di = (DeviceInfo *)data;
int32 *flags = &(di->si->flags);
/* is someone already handling an interrupt for this device? */
if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED)
goto exit0;
if (InterruptIsVBI()) { // was the interrupt a VBI?
ClearVBI(); // clear the interrupt
handled = thread_interrupt_work(di); // release the semaphore
}
/* note that we're not in the handler any more */
atomic_and(flags, ~SKD_HANDLER_INSTALLED);
exit0:
return handled;
}
// #pragma mark - Device Hooks
static status_t
open_hook(const char* name, uint32 flags, void** cookie)
{
int32 index = 0;
DeviceInfo *di;
SharedInfo *si;
thread_id thid;
thread_info thinfo;
status_t result = B_OK;
char sharedName[B_OS_NAME_LENGTH];
(void)flags; // avoid compiler warning for unused arg
TRACE(("open_hook(%s, 0x%08lx)\n", name, (uint32)cookie));
/* find the device name in the list of devices */
/* we're never passed a name we didn't publish */
while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0))
index++;
/* for convienience */
di = &(pd->di[index]);
/* make sure no one else has write access to the common data */
AQUIRE_BEN(pd->kernel);
/* if it's already open for writing */
if (di->is_open) {
/* mark it open another time */
goto mark_as_open;
}
/* create the shared area */
sprintf(sharedName, DEVICE_FORMAT " shared",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
/* create this area with NO user-space read or write permissions, to prevent accidental dammage */
di->sharedArea = create_area(sharedName, (void **) &(di->si), B_ANY_KERNEL_ADDRESS,
((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)),
B_FULL_LOCK, 0);
if (di->sharedArea < 0) {
/* return the error */
result = di->sharedArea;
goto done;
}
/* save a few dereferences */
si = di->si;
/* save the vendor and device IDs */
si->vendorID = di->pcii.vendor_id;
si->deviceID = di->pcii.device_id;
si->revision = di->pcii.revision;
si->chipset = di->pChipInfo->chipset;
strcpy(si->chipsetName, di->pChipInfo->chipName);
/* map the device */
result = map_device(di);
if (result < 0)
goto free_shared;
result = B_OK;
DisableVBI(); // disable & clear any pending interrupts
si->bInterruptAssigned = false; // indicate interrupt not assigned yet
/* create a semaphore for vertical blank management */
si->vblank = create_sem(0, di->name);
if (si->vblank < 0)
goto mark_as_open;
/* change the owner of the semaphores to the opener's team */
/* this is required because apps can't aquire kernel semaphores */
thid = find_thread(NULL);
get_thread_info(thid, &thinfo);
set_sem_owner(si->vblank, thinfo.team);
/* If there is a valid interrupt assigned, set up interrupts */
if ((di->pcii.u.h0.interrupt_pin == 0x00) ||
(di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */
(di->pcii.u.h0.interrupt_line <= 0x02)) { /* system IRQ assigned */
/* Interrupt does not exist; thus delete semaphore as it won't be used */
delete_sem(si->vblank);
si->vblank = -1;
} else {
/* otherwise install our interrupt handler */
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, (void *)di, 0);
if (result != B_OK) {
/* delete the semaphore as it won't be used */
delete_sem(si->vblank);
si->vblank = -1;
} else {
/* inform accelerant(s) we can use interrupt related functions */
si->bInterruptAssigned = true;
}
}
mark_as_open:
/* mark the device open */
di->is_open++;
/* send the cookie to the opener */
*cookie = di;
goto done;
free_shared:
/* clean up our shared area */
delete_area(di->sharedArea);
di->sharedArea = -1;
di->si = NULL;
done:
/* end of critical section */
RELEASE_BEN(pd->kernel);
/* all done, return the status */
TRACE(("open_hook returning 0x%08lx\n", result));
return result;
}
static status_t
read_hook(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
write_hook(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
close_hook(void* dev)
{
(void)dev; // avoid compiler warning for unused arg
TRACE(("close_hook()\n"));
/* we don't do anything on close: there might be dup'd fd */
return B_NO_ERROR;
}
static status_t
free_hook(void* dev)
{
DeviceInfo *di = (DeviceInfo*)dev;
SharedInfo *si = di->si;
TRACE(("enter free_hook()\n"));
/* lock the driver */
AQUIRE_BEN(pd->kernel);
/* if opened multiple times, decrement the open count and exit */
if (di->is_open > 1)
goto unlock_and_exit;
DisableVBI(); // disable & clear any pending interrupts
if (si->bInterruptAssigned) {
/* remove interrupt handler */
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, di);
}
/* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
if (si->vblank >= 0)
delete_sem(si->vblank);
si->vblank = -1;
/* free regs and frame buffer areas */
unmap_device(di);
/* clean up our shared area */
delete_area(di->sharedArea);
di->sharedArea = -1;
di->si = NULL;
unlock_and_exit:
/* mark the device available */
di->is_open--;
/* unlock the driver */
RELEASE_BEN(pd->kernel);
TRACE(("exit free_hook()\n"));
/* all done */
return B_OK;
}
static status_t
control_hook(void* dev, uint32 msg, void *buf, size_t len)
{
DeviceInfo *di = (DeviceInfo *)dev;
status_t result = B_DEV_INVALID_IOCTL;
(void)len; // avoid compiler warning for unused arg
// TRACE(("control_hook; ioctl: %d, buf: 0x%08x, len: %d\n", msg, buf, len));
switch (msg) {
/* the only PUBLIC ioctl */
case B_GET_ACCELERANT_SIGNATURE:
{
char *sig = (char *)buf;
strcpy(sig, "s3savage.accelerant");
result = B_OK;
break;
}
/* PRIVATE ioctl from here on */
case SAVAGE_GET_PRIVATE_DATA:
{
SavageGetPrivateData *gpd = (SavageGetPrivateData *)buf;
if (gpd->magic == SAVAGE_PRIVATE_DATA_MAGIC) {
gpd->sharedInfoArea = di->sharedArea;
result = B_OK;
}
break;
}
case SAVAGE_GET_PCI:
{
SavageGetSetPci *gsp = (SavageGetSetPci *)buf;
if (gsp->magic == SAVAGE_PRIVATE_DATA_MAGIC) {
pci_info *pcii = &(di->pcii);
gsp->value = get_pci(gsp->offset, gsp->size);
result = B_OK;
}
break;
}
case SAVAGE_SET_PCI:
{
SavageGetSetPci *gsp = (SavageGetSetPci *)buf;
if (gsp->magic == SAVAGE_PRIVATE_DATA_MAGIC) {
pci_info *pcii = &(di->pcii);
set_pci(gsp->offset, gsp->size, gsp->value);
result = B_OK;
}
break;
}
case SAVAGE_DEVICE_NAME:
{
SavageDeviceName *dn = (SavageDeviceName *)buf;
if (dn->magic == SAVAGE_PRIVATE_DATA_MAGIC) {
strcpy(dn->name, di->name);
result = B_OK;
}
break;
}
case SAVAGE_RUN_INTERRUPTS:
{
SavageSetBoolState *ri = (SavageSetBoolState *)buf;
if (ri->magic == SAVAGE_PRIVATE_DATA_MAGIC) {
if (ri->bEnable) {
EnableVBI();
} else {
DisableVBI();
}
}
result = B_OK;
break;
}
}
return result;
}