* 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:
parent
a8af2b6dda
commit
35db13ea5a
@ -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
|
||||
|
238
headers/private/graphics/s3/DriverInterface.h
Normal file
238
headers/private/graphics/s3/DriverInterface.h
Normal 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
|
@ -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 */
|
@ -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 ;
|
||||
|
43
src/add-ons/accelerants/s3/Jamfile
Normal file
43
src/add-ons/accelerants/s3/Jamfile
Normal 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 ;
|
||||
|
217
src/add-ons/accelerants/s3/accel.cpp
Normal file
217
src/add-ons/accelerants/s3/accel.cpp
Normal 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;
|
||||
}
|
202
src/add-ons/accelerants/s3/accel.h
Normal file
202
src/add-ons/accelerants/s3/accel.h
Normal 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
|
81
src/add-ons/accelerants/s3/cursor.cpp
Normal file
81
src/add-ons/accelerants/s3/cursor.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Gerald Zajac 2007-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);
|
||||
}
|
||||
|
79
src/add-ons/accelerants/s3/engine.cpp
Normal file
79
src/add-ons/accelerants/s3/engine.cpp
Normal 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;
|
||||
}
|
||||
|
69
src/add-ons/accelerants/s3/hooks.cpp
Normal file
69
src/add-ons/accelerants/s3/hooks.cpp
Normal 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
|
||||
}
|
470
src/add-ons/accelerants/s3/mode.cpp
Normal file
470
src/add-ons/accelerants/s3/mode.cpp
Normal 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__
|
245
src/add-ons/accelerants/s3/register_io.cpp
Normal file
245
src/add-ons/accelerants/s3/register_io.cpp
Normal 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);
|
||||
}
|
||||
}
|
59
src/add-ons/accelerants/s3/register_io.h
Normal file
59
src/add-ons/accelerants/s3/register_io.h
Normal 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__
|
116
src/add-ons/accelerants/s3/savage.h
Normal file
116
src/add-ons/accelerants/s3/savage.h
Normal 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__
|
144
src/add-ons/accelerants/s3/savage_cursor.cpp
Normal file
144
src/add-ons/accelerants/s3/savage_cursor.cpp
Normal 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;
|
||||
}
|
118
src/add-ons/accelerants/s3/savage_dpms.cpp
Normal file
118
src/add-ons/accelerants/s3/savage_dpms.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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));
|
99
src/add-ons/accelerants/s3/savage_edid.cpp
Normal file
99
src/add-ons/accelerants/s3/savage_edid.cpp
Normal 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;
|
||||
}
|
400
src/add-ons/accelerants/s3/savage_init.cpp
Normal file
400
src/add-ons/accelerants/s3/savage_init.cpp
Normal 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;
|
||||
}
|
||||
|
1088
src/add-ons/accelerants/s3/savage_mode.cpp
Normal file
1088
src/add-ons/accelerants/s3/savage_mode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
62
src/add-ons/accelerants/s3/trio64.h
Normal file
62
src/add-ons/accelerants/s3/trio64.h
Normal 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__
|
112
src/add-ons/accelerants/s3/trio64_cursor.cpp
Normal file
112
src/add-ons/accelerants/s3/trio64_cursor.cpp
Normal 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;
|
||||
}
|
93
src/add-ons/accelerants/s3/trio64_dpms.cpp
Normal file
93
src/add-ons/accelerants/s3/trio64_dpms.cpp
Normal 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;
|
||||
}
|
155
src/add-ons/accelerants/s3/trio64_draw.cpp
Normal file
155
src/add-ons/accelerants/s3/trio64_draw.cpp
Normal 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 ++;
|
||||
}
|
||||
}
|
176
src/add-ons/accelerants/s3/trio64_init.cpp
Normal file
176
src/add-ons/accelerants/s3/trio64_init.cpp
Normal 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;
|
||||
}
|
333
src/add-ons/accelerants/s3/trio64_mode.cpp
Normal file
333
src/add-ons/accelerants/s3/trio64_mode.cpp
Normal 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;
|
||||
}
|
||||
}
|
78
src/add-ons/accelerants/s3/virge.h
Normal file
78
src/add-ons/accelerants/s3/virge.h
Normal 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__
|
112
src/add-ons/accelerants/s3/virge_cursor.cpp
Normal file
112
src/add-ons/accelerants/s3/virge_cursor.cpp
Normal 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;
|
||||
}
|
93
src/add-ons/accelerants/s3/virge_dpms.cpp
Normal file
93
src/add-ons/accelerants/s3/virge_dpms.cpp
Normal 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;
|
||||
}
|
161
src/add-ons/accelerants/s3/virge_draw.cpp
Normal file
161
src/add-ons/accelerants/s3/virge_draw.cpp
Normal 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 ++;
|
||||
}
|
||||
}
|
130
src/add-ons/accelerants/s3/virge_edid.cpp
Normal file
130
src/add-ons/accelerants/s3/virge_edid.cpp
Normal 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;
|
||||
}
|
271
src/add-ons/accelerants/s3/virge_init.cpp
Normal file
271
src/add-ons/accelerants/s3/virge_init.cpp
Normal 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;
|
||||
}
|
767
src/add-ons/accelerants/s3/virge_mode.cpp
Normal file
767
src/add-ons/accelerants/s3/virge_mode.cpp
Normal 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,
|
||||
®Rec.SR13, ®Rec.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,
|
||||
®Rec.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,
|
||||
®Rec.SR13, ®Rec.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,
|
||||
®Rec.SR13, ®Rec.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;
|
||||
}
|
||||
}
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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**)®s, 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);
|
||||
}
|
||||
|
@ -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 ;
|
||||
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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__
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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 ;
|
||||
|
16
src/add-ons/kernel/drivers/graphics/s3/Jamfile
Normal file
16
src/add-ons/kernel/drivers/graphics/s3/Jamfile
Normal 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 ;
|
799
src/add-ons/kernel/drivers/graphics/s3/driver.cpp
Normal file
799
src/add-ons/kernel/drivers/graphics/s3/driver.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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 ;
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user