Added the S3 Savage driver from BeBits - accoring to Siarzhuk it doesn't work yet
under Haiku, though. If someone has access to this card, feel free to fix this :-) I renamed the driver to s3savage (from BeSavage), and added the license text separately (dunno if that's really needed, though). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18978 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef DRIVERINTERFACE_H
|
||||
#define DRIVERINTERFACE_H
|
||||
|
||||
#include <Accelerant.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
|
||||
|
||||
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 0x1234 /* a private driver rev, of sorts */
|
||||
|
||||
#define MAX_SAVAGE_DEVICE_NAME_LENGTH 32
|
||||
|
||||
#define SKD_MOVE_CURSOR 0x00000001
|
||||
#define SKD_PROGRAM_CLUT 0x00000002
|
||||
#define SKD_SET_START_ADDR 0x00000004
|
||||
#define SKD_SET_CURSOR 0x00000008
|
||||
#define SKD_HANDLER_INSTALLED 0x80000000
|
||||
|
||||
enum
|
||||
{
|
||||
SAVAGE_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
|
||||
SAVAGE_GET_PCI,
|
||||
SAVAGE_SET_PCI,
|
||||
SAVAGE_DEVICE_NAME,
|
||||
SAVAGE_RUN_INTERRUPTS,
|
||||
SAVAGE_DPRINTF
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 vendor_id; /* PCI vendor ID, from pci_info */
|
||||
uint16 device_id; /* PCI device ID, from pci_info */
|
||||
uint8 revision; /* PCI device revsion, from pci_info */
|
||||
area_id regs_area; /* Kernel's area_id for the memory mapped registers.
|
||||
It will be cloned into the accelerant's address
|
||||
space. */
|
||||
area_id fb_area; /* Frame buffer's area_id. The addresses are shared
|
||||
with all teams. */
|
||||
void *framebuffer; /* As viewed from virtual memory */
|
||||
void *framebuffer_pci; /* As viewed from the PCI bus (for DMA) */
|
||||
area_id rom_area; /* Mapped ROM's area_id */
|
||||
void *rom; /* As viewed from virtual memory. Shared by all teams */
|
||||
area_id mode_area; /* Contains the list of display modes the driver supports */
|
||||
uint32 mode_count; /* Number of display modes in the list */
|
||||
sem_id vblank; /* The vertical blank semaphore. Ownership will be
|
||||
transfered to the team opening the device first */
|
||||
int32 flags;
|
||||
int32 start_addr;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8* data; /* Pointer into the frame buffer to where the
|
||||
cursor data starts */
|
||||
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 is_visible; /* Is the cursor currently displayed? */
|
||||
} cursor;
|
||||
uint16 first_color;
|
||||
uint16 color_count;
|
||||
bigtime_t refresh_period; /* Duration of one frame (ie 1/refresh rate) */
|
||||
bigtime_t blank_period; /* Duration of the blanking period. These are
|
||||
usefull when faking vertical blanking
|
||||
interrupts. */
|
||||
uint8 color_data[3 * 256]; /* */
|
||||
uint8 cursor0[64*64/8]; /* AND mask for a 64x64 cursor */
|
||||
uint8 cursor1[512]; /* XOR mask for a 64x64 cursor */
|
||||
display_mode dm; /* current display mode configuration */
|
||||
frame_buffer_config
|
||||
fbc; /* bytes_per_row and start of frame buffer */
|
||||
struct
|
||||
{
|
||||
uint64 count; /* last fifo slot used */
|
||||
uint64 last_idle; /* last fifo slot we *know* the engine was idle after */
|
||||
benaphore lock; /* for serializing access to the acceleration engine */
|
||||
} engine;
|
||||
|
||||
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. */
|
||||
uint32 mem_size; /* Frame buffer memory, in bytes. */
|
||||
} shared_info;
|
||||
|
||||
/* 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 */
|
||||
} savage_get_set_pci;
|
||||
|
||||
/* Set some boolean condition (like enabling or disabling interrupts) */
|
||||
typedef struct
|
||||
{
|
||||
uint32 magic; /* magic number to make sure the caller groks us */
|
||||
bool do_it; /* state to set */
|
||||
} savage_set_bool_state;
|
||||
|
||||
/* 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 shared_info_area; /* area_id containing the shared information */
|
||||
} savage_get_private_data;
|
||||
|
||||
/* 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 */
|
||||
} savage_device_name;
|
||||
|
||||
enum
|
||||
{
|
||||
SAVAGE_WAIT_FOR_VBLANK = (0 << 0)
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/* Savage3D series */
|
||||
PCI_PID_SAVAGE3D = 0x8a20, /* Savage3D */
|
||||
PCI_PID_SAVAGE3DMV = 0x8a21, /* Savage3D/MV */
|
||||
PCI_PID_SAVAGEMXMV = 0x8c10, /* Savage/MX-MV */
|
||||
PCI_PID_SAVAGEMX = 0x8c11, /* Savage/MX */
|
||||
PCI_PID_SAVAGEIXMV = 0x8c12, /* Savage/IX-MV */
|
||||
PCI_PID_SAVAGEIX = 0x8c13, /* Savage/IX */
|
||||
|
||||
/* Savage4 series */
|
||||
PCI_PID_SAVAGE4_2 = 0x8a22, /* Savage4 */
|
||||
PCI_PID_SAVAGE4_3 = 0x8a23, /* Savage4 */
|
||||
PCI_PID_SAVAGE2000 = 0x9102, /* Savage2000 */
|
||||
PCI_PID_PM133 = 0x8a25, /* ProSavage PM133 */
|
||||
PCI_PID_KM133 = 0x8a26, /* ProSavage KM133 */
|
||||
PCI_PID_PN133 = 0x8d01, /* ProSavage PN133, 86C380 [ProSavageDDR K4M266] */
|
||||
PCI_PID_KN133 = 0x8d02, /* ProSavage KN133/TwisterK AGP4X VT8636A */
|
||||
PCI_PID_KM266 = 0x8d04, /* ProSavage8 KM266/KL266 VT8375 */
|
||||
PCI_PID_PN266 = 0x8d03, /* VT8751 [ProSavageDDR P4M266] */
|
||||
|
||||
/* SuperSavage series (unsupported) */
|
||||
PCI_PID_SUPERSAVAGE_MX128 = 0x8c22, /* SuperSavage MX/128 */
|
||||
PCI_PID_SUPERSAVAGE_MX64 = 0x8c24, /* SuperSavage MX/64 */
|
||||
PCI_PID_SUPERSAVAGE_MX64C = 0x8c26, /* SuperSavage MX/64C */
|
||||
PCI_PID_SUPERSAVAGE_IX128_SDR = 0x8c2a, /* SuperSavage IX/128 SDR */
|
||||
PCI_PID_SUPERSAVAGE_IX128_DDR = 0x8c2b, /* SuperSavage IX/128 DDR */
|
||||
PCI_PID_SUPERSAVAGE_IX64_SDR = 0x8c2c, /* SuperSavage IX/64 SDR */
|
||||
PCI_PID_SUPERSAVAGE_IX64_DDR = 0x8c2d, /* SuperSavage IX/64 DDR */
|
||||
PCI_PID_SUPERSAVAGE_IXC_SDR = 0x8c2e, /* SuperSavage IX/C SDR */
|
||||
PCI_PID_SUPERSAVAGE_IXC_DDR = 0x8c2f, /* SuperSavage IX/C DDR */
|
||||
};
|
||||
|
||||
#define isSavage4Family(p) \
|
||||
((p) == PCI_PID_SAVAGE4_2 || \
|
||||
(p) == PCI_PID_SAVAGE4_3 || \
|
||||
(p) == PCI_PID_SAVAGE2000 || \
|
||||
(p) == PCI_PID_PM133 || \
|
||||
(p) == PCI_PID_KM133 || \
|
||||
(p) == PCI_PID_PN133 || \
|
||||
(p) == PCI_PID_KN133 || \
|
||||
(p) == PCI_PID_KM266)
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -7,6 +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 tdfx ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants skeleton ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants vesa ;
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "s3accel.h"
|
||||
#include "s3mmio.h"
|
||||
|
||||
void
|
||||
SCREEN_TO_SCREEN_BLIT (
|
||||
engine_token *et, blit_params *list, uint32 count)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0067);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
int cmd = 0xc0b1;
|
||||
int src_x = list->src_left;
|
||||
int src_y = list->src_top;
|
||||
int dest_x = list->dest_left;
|
||||
int dest_y = list->dest_top;
|
||||
int width = list->width;
|
||||
int height = list->height;
|
||||
|
||||
if (src_x < dest_x)
|
||||
{
|
||||
src_x += width; dest_x += width;
|
||||
cmd ^=32;
|
||||
}
|
||||
|
||||
if (src_y < dest_y)
|
||||
{
|
||||
src_y += height; dest_y += height;
|
||||
cmd ^=128;
|
||||
}
|
||||
|
||||
UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y);
|
||||
UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y);
|
||||
UpdateGEReg (ALT_PCNT, (width<<16)|height);
|
||||
UpdateGEReg (CMD, cmd);
|
||||
|
||||
list ++;
|
||||
}
|
||||
|
||||
s3accel_wait_for_fifo (3);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
}
|
||||
|
||||
void
|
||||
FILL_RECTANGLE (
|
||||
engine_token *et, uint32 color, fill_rect_params *list, uint32 count)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg (FRGD_COLOR, color);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
int x = list->left;
|
||||
int y = list->top;
|
||||
int w = list->right - x;
|
||||
int h = list->bottom - y;
|
||||
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (ALT_CURXY, (x<<16)|y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, 0x000040b1);
|
||||
|
||||
list++;
|
||||
}
|
||||
s3accel_wait_for_fifo(3);
|
||||
}
|
||||
|
||||
void
|
||||
INVERT_RECTANGLE (
|
||||
engine_token *et, fill_rect_params *list, uint32 count)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0020);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
int x = list->left;
|
||||
int y = list->top;
|
||||
int w = list->right - x;
|
||||
int h = list->bottom - y;
|
||||
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (ALT_CURXY, (x<<16)|y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, 0x000040b1);
|
||||
|
||||
list++;
|
||||
}
|
||||
|
||||
s3accel_wait_for_fifo (3);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
}
|
||||
|
||||
void
|
||||
FILL_SPAN (
|
||||
engine_token *et, uint32 color, uint16 *list, uint32 count)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg (FRGD_COLOR, color);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
int y = *list ++;
|
||||
int x = *list ++;
|
||||
int w = *list - x; list ++;
|
||||
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (ALT_CURXY, (x<<16)|y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|1);
|
||||
UpdateGEReg (CMD, 0x000040b1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "s3drv.h"
|
||||
|
||||
void set_cursor_colors(void)
|
||||
{
|
||||
/* it's only called by the INIT_ACCELERANT() */
|
||||
s3drv_set_cursor_color (0, ~0);
|
||||
}
|
||||
|
||||
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;
|
||||
s3drv_load_cursor ((byte_t*)framebuffer, 0,
|
||||
width, height, andMask, xorMask);
|
||||
}
|
||||
|
||||
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 x_p, uint16 y_p)
|
||||
{
|
||||
int x = x_p, y = y_p;
|
||||
bool move_screen = false;
|
||||
/* the current horizontal starting pixel */
|
||||
uint16 hds = si->dm.h_display_start;
|
||||
/* the current vertical starting line */
|
||||
uint16 vds = si->dm.v_display_start;
|
||||
|
||||
/* Need to set this value for 32 bit */
|
||||
uint16 h_adjust = 3;
|
||||
|
||||
/* 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 + h_adjust) & ~h_adjust;
|
||||
move_screen = true;
|
||||
}
|
||||
else if (x < hds)
|
||||
{
|
||||
hds = x & ~h_adjust;
|
||||
move_screen = true;
|
||||
}
|
||||
if (y >= (si->dm.timing.v_display + vds))
|
||||
{
|
||||
vds = y - si->dm.timing.v_display + 1;
|
||||
move_screen = true;
|
||||
}
|
||||
else if (y < vds)
|
||||
{
|
||||
vds = y;
|
||||
move_screen = true;
|
||||
}
|
||||
|
||||
/* reposition the desktop on the display if required */
|
||||
if (move_screen) MOVE_DISPLAY(hds,vds);
|
||||
|
||||
/* put cursor in correct physical position */
|
||||
x -= hds;
|
||||
y -= vds;
|
||||
x -= si->cursor.hot_x;
|
||||
y -= si->cursor.hot_y;
|
||||
|
||||
/* position the cursor on the display */
|
||||
s3drv_move_cursor (x, y);
|
||||
}
|
||||
|
||||
void SHOW_CURSOR (bool is_visible)
|
||||
{
|
||||
if (is_visible)
|
||||
s3drv_show_cursor ();
|
||||
else
|
||||
s3drv_hide_cursor ();
|
||||
|
||||
/* record for our info */
|
||||
si->cursor.is_visible = is_visible;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "s3drv.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)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
}
|
||||
|
||||
/* release the shared benaphore */
|
||||
RELEASE_BEN(si->engine.lock)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WAIT_ENGINE_IDLE(void)
|
||||
{
|
||||
s3drv_wait_for_idle ();
|
||||
// note our current possition
|
||||
si->engine.last_idle = si->engine.count;
|
||||
}
|
||||
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st)
|
||||
{
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t SYNC_TO_TOKEN(sync_token *st)
|
||||
{
|
||||
s3drv_wait_for_idle ();
|
||||
si->engine.last_idle = st->counter;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "generic.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) {
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.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 *afb)
|
||||
{
|
||||
/* easy again, as the last mode set stored the info in a convienient form */
|
||||
*afb = 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;
|
||||
}
|
||||
|
||||
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc)
|
||||
{
|
||||
status_t retval;
|
||||
|
||||
dtc->h_res = 8;
|
||||
dtc->h_sync_min = 2*8;
|
||||
dtc->h_sync_max = 32*8 - 1;
|
||||
dtc->h_blank_min = 0;
|
||||
dtc->h_blank_max = 64*8 - 1;
|
||||
dtc->v_res = 1;
|
||||
dtc->v_sync_min = 2;
|
||||
dtc->v_sync_max = 15;
|
||||
dtc->v_blank_min = 0;
|
||||
dtc->v_blank_max = 255;
|
||||
|
||||
retval = B_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the semaphore id that will be used to signal a vertical retrace
|
||||
occured.
|
||||
*/
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
|
||||
{
|
||||
/*
|
||||
NOTE:
|
||||
The kernel driver created this for us. We don't know if the system is
|
||||
using real interrupts, or if we're faking it, and we don't care.
|
||||
If we choose not to support this at all, we'd just return B_ERROR here,
|
||||
and the user wouldn't get any kind of vertical retrace support.
|
||||
*/
|
||||
return si->vblank;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
int fd;
|
||||
shared_info *si;
|
||||
area_id shared_info_area;
|
||||
vuint32 *regs;
|
||||
area_id regs_area;
|
||||
vuint32 *framebuffer;
|
||||
area_id fb_area;
|
||||
display_mode *my_mode_list;
|
||||
area_id my_mode_list_area;
|
||||
int accelerantIsClone;
|
||||
|
||||
void dpf (const char * format, ...)
|
||||
{
|
||||
char buffer[4096] = "SAVAGE: ";
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
vsprintf (buffer + 8, format, args);
|
||||
ioctl (fd, SAVAGE_DPRINTF, buffer, 0);
|
||||
va_end (args);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#if !defined(GLOBALDATA_H)
|
||||
#define GLOBALDATA_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
extern int fd;
|
||||
extern shared_info *si;
|
||||
extern area_id shared_info_area;
|
||||
extern vuint32 *regs;
|
||||
extern area_id regs_area;
|
||||
extern vuint32 *framebuffer;
|
||||
extern area_id fb_area;
|
||||
extern display_mode *my_mode_list;
|
||||
extern area_id my_mode_list_area;
|
||||
extern int accelerantIsClone;
|
||||
|
||||
/* Print debug message through kernel driver. Should move to other location later. */
|
||||
extern void dpf (const char * format, ...);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "s3drv.h"
|
||||
#include "s3mmio.h"
|
||||
#include "s3accel.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "unistd.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "fcntl.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* defined in ProposeDisplayMode.c */
|
||||
extern status_t create_mode_list(void);
|
||||
/* defined in Cursor.c */
|
||||
extern void set_cursor_colors(void);
|
||||
|
||||
/* Get the linear address of an area. Workaround for BeOS bug that
|
||||
returns invalid pointer from clone_area. */
|
||||
static void * __get_area_address (area_id area)
|
||||
{
|
||||
area_info ai;
|
||||
get_area_info (area, &ai);
|
||||
return ai.address;
|
||||
}
|
||||
|
||||
// Determines the amount of card memory available by seeing how far up
|
||||
// the frame buffer data can be written and read back reliably. Does a
|
||||
// paranoia check to make sure that it isn't just wrapping, either.
|
||||
unsigned long Get_Card_Mem_Size()
|
||||
{
|
||||
// Allowed sizes actually go up to 16 megs, but clip at the
|
||||
// register window for now.
|
||||
const unsigned long AllowedSizes[] =
|
||||
{ 0x00080000, 0x00100000, 0x00180000, 0x00200000,
|
||||
0x00280000, 0x00300000, 0x00380000, 0x00400000,
|
||||
0x00500000, 0x00600000, 0x00700000, 0x007FF800,
|
||||
0x0 };
|
||||
|
||||
unsigned long MaxMem;
|
||||
unsigned long RWIndex;
|
||||
int iMaxIndex, iTestIndex, iX;
|
||||
unsigned long LTemp;
|
||||
int IsOk;
|
||||
uint32 *VramBase;
|
||||
|
||||
VramBase = (uint32 *)framebuffer;
|
||||
MaxMem = 0; // Default.
|
||||
IsOk = 1;
|
||||
// Step through ever-larger memory sizes, recording size if passes test and
|
||||
// ignoring otherwise.
|
||||
for (iMaxIndex = 0; (AllowedSizes[iMaxIndex] != 0) && IsOk; iMaxIndex++)
|
||||
{
|
||||
// Write test values to the linear aperature.
|
||||
// Only need to do this for the farthest location, as previous
|
||||
// locations already have been written to in previous passes.
|
||||
RWIndex = AllowedSizes[iMaxIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; iX < 4096; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it should
|
||||
// be extremely unlikely to get these values through a glitch, and
|
||||
// the pattern only repeats at prime intervals, so aliasing
|
||||
// shouldn't fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
VramBase[RWIndex] = LTemp;
|
||||
RWIndex++;
|
||||
}
|
||||
|
||||
// Verify that all test patterns are still intact. If values written
|
||||
// past the end of memory drop off the face of the frame buffer, the
|
||||
// farthest pattern(s) will not be what they should be. If values
|
||||
// written past the end of memory wrap, then previous patterns will
|
||||
// be overwritten (or partly overwritten, as the test location at
|
||||
// 8 megs is actually at 8 megs - 2k).
|
||||
// As soon as an invalid value is detected, IsOk is set to 0, which
|
||||
// should quickly terminate the test loops.
|
||||
for (iTestIndex = 0; (iTestIndex <= iMaxIndex) && IsOk; iTestIndex++)
|
||||
{
|
||||
RWIndex = AllowedSizes[iTestIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; (iX < 4096) && IsOk; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it
|
||||
// should be extremely unlikely to get these values through
|
||||
// a glitch, and the pattern only repeats at prime intervals,
|
||||
// so aliasing shouldn't fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
// Test against the value read from the frame buffer.
|
||||
if (VramBase[RWIndex] != LTemp)
|
||||
IsOk = 0;
|
||||
RWIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// If the test patterns check out, update MaxMem accordingly.
|
||||
if (IsOk)
|
||||
MaxMem = AllowedSizes[iMaxIndex];
|
||||
}
|
||||
|
||||
return MaxMem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t init_common(int the_fd);
|
||||
|
||||
/* Initialization code shared between primary and cloned accelerants */
|
||||
static status_t init_common(int the_fd)
|
||||
{
|
||||
status_t result;
|
||||
savage_get_private_data gpd;
|
||||
|
||||
/* memorize the file descriptor */
|
||||
fd = the_fd;
|
||||
dpf ("init_common begin\n");
|
||||
/* 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(fd, SAVAGE_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/* clone the shared area for our use */
|
||||
shared_info_area = clone_area (
|
||||
"SAVAGE shared info", (void **)&si, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
|
||||
if (shared_info_area < 0)
|
||||
{
|
||||
result = shared_info_area;
|
||||
goto error0;
|
||||
}
|
||||
/* clone the memory mapped registers for our use */
|
||||
regs_area = clone_area (
|
||||
"SAVAGE regs area", (void **)®s, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, si->regs_area);
|
||||
if (regs_area < 0)
|
||||
{
|
||||
result = regs_area;
|
||||
goto error1;
|
||||
}
|
||||
regs = __get_area_address (regs_area);
|
||||
|
||||
dpf ("PCI VENDOR_ID = 0x%4X, DEVICE_ID = 0x%4X\n",
|
||||
read16 ((byte_t*)regs + 0x8000),
|
||||
read16 ((byte_t*)regs + 0x8002));
|
||||
|
||||
/* clone the framebuffer buffer for our use */
|
||||
fb_area = clone_area (
|
||||
"SAVAGE fb area", (void **)&framebuffer, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, si->fb_area);
|
||||
if (fb_area < 0)
|
||||
{
|
||||
result = regs_area;
|
||||
goto error2;
|
||||
}
|
||||
framebuffer = __get_area_address (fb_area);
|
||||
|
||||
s3drv_init ((byte_t*)regs);
|
||||
dpf ("s3drv_init called\n");
|
||||
s3accel_init (s3drv_get_context ());
|
||||
dpf ("s3accel_init called\n");
|
||||
s3drv_unlock_regs ();
|
||||
|
||||
/* all done */
|
||||
goto error0;
|
||||
|
||||
error2:
|
||||
delete_area(regs_area);
|
||||
error1:
|
||||
delete_area(shared_info_area);
|
||||
error0:
|
||||
dpf ("init_common done\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Clean up code shared between primary and cloned accelrants */
|
||||
static void uninit_common(void)
|
||||
{
|
||||
/* release framebuffer area */
|
||||
delete_area (fb_area);
|
||||
/* release the memory mapped registers */
|
||||
delete_area(regs_area);
|
||||
/* a little cheap paranoia */
|
||||
regs = 0;
|
||||
/* release our copy of the shared info from the kernel driver */
|
||||
delete_area(shared_info_area);
|
||||
/* more cheap paranoia */
|
||||
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;
|
||||
/* note that we're the primary accelerant (accelerantIsClone is global) */
|
||||
accelerantIsClone = 0;
|
||||
|
||||
/* do the initialization common to both the primary and the clones */
|
||||
result = init_common(the_fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/*
|
||||
If there is a possiblity that the kernel driver will recognize a card that
|
||||
the accelerant can't support, you should check for that here. Perhaps some
|
||||
odd memory configuration or some such.
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a good place to go and initialize your card. The details are so
|
||||
device specific, we're not even going to pretend to provide you with sample
|
||||
code. If this fails, we'll have to bail out, cleaning up the resources
|
||||
we've already allocated.
|
||||
*/
|
||||
/* call the device specific init code */
|
||||
{
|
||||
SVGAMode orig, newmode;
|
||||
PixelTiming timing =
|
||||
{ 0, { 640, 656, 752, 800, 0 }, { 480, 490, 492, 525, 0 } };
|
||||
s3drv_unlock_regs ();
|
||||
s3drv_get_mode (&timing, 32, (byte_t*)&newmode, sizeof (newmode));
|
||||
s3drv_save_mode ((byte_t*)&orig, sizeof (orig));
|
||||
s3drv_restore_mode ((byte_t*)&newmode, sizeof (newmode), 1);
|
||||
s3accel_init (s3drv_get_context ());
|
||||
//si->mem_size = s3drv_detect_vram_mb_size ((byte_t*)framebuffer, 32);
|
||||
//dpf ("si->mem_size = %dMB\n", si->mem_size);
|
||||
si->mem_size = s3drv_detect_vram_mb_size (NULL, 2);
|
||||
dpf ("si->mem_size = %dMB\n", si->mem_size);
|
||||
si->mem_size *= 1024*1024;
|
||||
s3drv_restore_mode ((byte_t*)&orig, sizeof (orig), 1);
|
||||
s3drv_lock_regs ();
|
||||
}
|
||||
|
||||
si->pix_clk_max8 = 250000;
|
||||
si->pix_clk_max16 = 250000;
|
||||
si->pix_clk_max32 = 250000;
|
||||
|
||||
/* bail out if it failed */
|
||||
if (result != B_OK) 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 error2;
|
||||
|
||||
/*
|
||||
Initialize the frame buffer and cursor pointers. Most newer video cards
|
||||
have integrated the DAC into the graphics engine, and so the cursor shape
|
||||
is stored in the frame buffer RAM. Also, newer cards tend not to have as
|
||||
many restrictions about the placement of the start of the frame buffer in
|
||||
frame buffer RAM. If you're supporting an older card with frame buffer
|
||||
positioning restrictions, or one without an integrated DAC, you'll have to
|
||||
change this accordingly.
|
||||
*/
|
||||
/*
|
||||
Put the cursor at the start of the frame buffer. The typical 64x64 4 color
|
||||
(black, white, transparent, inverse) takes up 1024 bytes of RAM.
|
||||
*/
|
||||
si->cursor.data = (uint8 *)si->framebuffer;
|
||||
/* Initialize the rest of the cursor information while we're here */
|
||||
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;
|
||||
/*
|
||||
Put the frame buffer immediately following the cursor data. We store this
|
||||
info in a frame_buffer_config structure to make it convienient to return
|
||||
to the app_server later.
|
||||
*/
|
||||
si->fbc.frame_buffer = (void *)(((char *)si->framebuffer) + 1024);
|
||||
si->fbc.frame_buffer_dma = (void *)(((char *)si->framebuffer_pci) + 1024);
|
||||
si->start_addr = 1024;
|
||||
|
||||
/* init the shared semaphore */
|
||||
INIT_BEN(si->engine.lock);
|
||||
|
||||
/* initialize the engine synchronization variables */
|
||||
|
||||
/* count of issued parameters or commands */
|
||||
si->engine.last_idle = si->engine.count = 0;
|
||||
|
||||
/* bail out if something failed */
|
||||
if (result != B_OK) goto error3;
|
||||
|
||||
/* set the cursor colors. You may or may not have to do this, depending
|
||||
on the device. */
|
||||
set_cursor_colors();
|
||||
|
||||
/* ensure cursor state */
|
||||
SHOW_CURSOR(false);
|
||||
/* a winner! */
|
||||
result = B_OK;
|
||||
goto error0;
|
||||
|
||||
error3:
|
||||
/* free up the benaphore */
|
||||
DELETE_BEN(si->engine.lock);
|
||||
|
||||
error2:
|
||||
/*
|
||||
Clean up any resources allocated in your device specific initialization
|
||||
code.
|
||||
*/
|
||||
|
||||
error1:
|
||||
/*
|
||||
Initialization failed after init_common() succeeded, so we need to clean
|
||||
up before quiting.
|
||||
*/
|
||||
uninit_common();
|
||||
|
||||
error0:
|
||||
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 MAX_SAVAGE_DEVICE_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)
|
||||
{
|
||||
savage_device_name 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(fd, 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 */
|
||||
fd = open(path, B_READ_WRITE);
|
||||
if (fd < 0)
|
||||
{
|
||||
result = fd;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* note that we're a clone accelerant */
|
||||
accelerantIsClone = 1;
|
||||
|
||||
/* call the shared initialization code */
|
||||
result = init_common(fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/* get shared area for display modes */
|
||||
result = my_mode_list_area = clone_area(
|
||||
"SAVAGE cloned display_modes",
|
||||
(void **)&my_mode_list,
|
||||
B_ANY_ADDRESS,
|
||||
B_READ_AREA,
|
||||
si->mode_area
|
||||
);
|
||||
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(fd);
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
void UNINIT_ACCELERANT(void)
|
||||
{
|
||||
/* free our mode list area */
|
||||
delete_area(my_mode_list_area);
|
||||
/* paranoia */
|
||||
my_mode_list = 0;
|
||||
/* release our cloned data */
|
||||
uninit_common();
|
||||
/* close the file handle ONLY if we're the clone */
|
||||
if (accelerantIsClone) close(fd);
|
||||
}
|
||||
|
||||
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi)
|
||||
{
|
||||
status_t retval;
|
||||
static const char * names1[] =
|
||||
{ "Savage3D", "Savage3D/MV", "Savage4", "Savage4",
|
||||
"Savage4", "ProSavage PM133", "ProSavage KM133" };
|
||||
static const char * names2[] =
|
||||
{ "Savage/MX-MV", "Savage/MX", "Savage/IX-MV", "Savage/IX" };
|
||||
static const char * names3[] =
|
||||
{ "ProSavage PN133", "ProSavage KN133", "ProSavage P4M266", "ProSavage8 KM266" };
|
||||
|
||||
adi->version = 0x10000;
|
||||
if (si->device_id == PCI_PID_SAVAGE2000)
|
||||
{
|
||||
strcpy (adi->name, "Savage2000");
|
||||
strcpy (adi->chipset, "Savage2000");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ** names = NULL;
|
||||
int offset = 0;
|
||||
switch (si->device_id & 0xFFF0)
|
||||
{
|
||||
case 0x8a20:
|
||||
names = names1;
|
||||
offset = si->device_id - PCI_PID_SAVAGE3D;
|
||||
break;
|
||||
case 0x8c10:
|
||||
names = names2;
|
||||
offset = si->device_id - PCI_PID_SAVAGEMXMV;
|
||||
break;
|
||||
case 0x8d00:
|
||||
names = names3;
|
||||
offset = si->device_id - PCI_PID_PN133;
|
||||
break;
|
||||
}
|
||||
if (names != NULL)
|
||||
{
|
||||
strcpy (adi->name, names[offset]);
|
||||
strcpy (adi->chipset, names[offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (adi->name, "not supported");
|
||||
strcpy (adi->chipset, "Savage");
|
||||
}
|
||||
}
|
||||
strcpy (adi->serial_no, "0");
|
||||
adi->memory = si->mem_size;
|
||||
adi->dac_speed = 250;
|
||||
|
||||
retval = B_OK;
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants s3savage ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics s3savage ] ;
|
||||
|
||||
Addon s3savage.accelerant : accelerants :
|
||||
Acceleration.c
|
||||
Cursor.c
|
||||
EngineManagement.c
|
||||
GetAccelerantHook.c
|
||||
GetModeInfo.c
|
||||
GlobalData.c
|
||||
InitAccelerant.c
|
||||
ProposeDisplayMode.c
|
||||
SetDisplayMode.c
|
||||
|
||||
s3accel.c
|
||||
s3drv.c
|
||||
s3vga.c
|
||||
|
||||
: false
|
||||
: be
|
||||
;
|
||||
|
||||
Package haiku-s3savage-cvs :
|
||||
s3savage.accelerant :
|
||||
boot home config add-ons accelerants ;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
This is a modified version of the XFree86 license.
|
||||
|
||||
The binary and source form of this software is covered by the
|
||||
following copyright/license.
|
||||
|
||||
Copyright (C) 1999 Erdi Chen. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.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) */
|
||||
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
|
||||
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
|
||||
{ { 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) */
|
||||
{ { 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) */
|
||||
{ { 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) */
|
||||
{ { 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) */
|
||||
{ { 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) */
|
||||
};
|
||||
|
||||
|
||||
/* 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"
|
||||
|
||||
If the mode is not (or cannot) be made valid for this device, return B_ERROR.
|
||||
If a valid mode can be constructed, but it does not fall within the limits,
|
||||
return B_BAD_VALUE.
|
||||
If the mode is both valid AND falls within the limits, return B_OK.
|
||||
*/
|
||||
status_t PROPOSE_DISPLAY_MODE (
|
||||
display_mode *target, const display_mode *low, const display_mode *high)
|
||||
{
|
||||
const uint16 h_display_bits = MASKFROMWIDTH(8);
|
||||
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);
|
||||
const uint16 v_total_bits = MASKFROMWIDTH(11);
|
||||
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
|
||||
/* 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 minium 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;
|
||||
|
||||
/* 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->mem_size)
|
||||
target->virtual_height = si->mem_size / 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;
|
||||
|
||||
/*
|
||||
Bit Flag Encoding
|
||||
|
||||
The way the bit flags works is as follows:
|
||||
|
||||
low high meaning
|
||||
--- ---- -------
|
||||
0 0 Feature must NOT be enabled
|
||||
0 1 Feature MAY be enabled, prefered enabled
|
||||
1 0 Feature MAY be enabled, prefered disabled
|
||||
1 1 Feature MUST be enabled
|
||||
|
||||
*/
|
||||
/* MORE WORK REQUIRED HERE. Current drivers mostly ignore the flags */
|
||||
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->mode_count;
|
||||
}
|
||||
|
||||
/*
|
||||
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, my_mode_list, si->mode_count * 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, j,
|
||||
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 spaces[] =
|
||||
// {B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE};
|
||||
{B_CMAP8, B_RGB16_LITTLE, B_RGB32_LITTLE};
|
||||
#else
|
||||
color_space spaces[] =
|
||||
// {B_CMAP8, B_RGB15_BIG, B_RGB16_BIG, B_RGB32_BIG};
|
||||
{B_CMAP8, B_RGB16_BIG, B_RGB32_BIG};
|
||||
#endif
|
||||
|
||||
/* figure out how big the list could be, and adjust up to nearest
|
||||
multiple of B_PAGE_SIZE */
|
||||
max_size = (((MODE_COUNT * sizeof (spaces) / sizeof (color_space))
|
||||
* sizeof(display_mode))
|
||||
+ (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
|
||||
/* create an area to hold the info */
|
||||
si->mode_area = my_mode_list_area =
|
||||
create_area (
|
||||
"SAVAGE accelerant mode info", (void **)&my_mode_list,
|
||||
B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||
if (my_mode_list_area < B_OK) return my_mode_list_area;
|
||||
|
||||
/* walk through our predefined list and see which modes fit this device */
|
||||
src = mode_list;
|
||||
dst = my_mode_list;
|
||||
si->mode_count = 0;
|
||||
for (i = 0; i < MODE_COUNT; i++)
|
||||
{
|
||||
/* set ranges for acceptable values */
|
||||
low = high = *src;
|
||||
/* range is 6.25% of default clock: arbitrarily picked */
|
||||
pix_clk_range = low.timing.pixel_clock >> 5;
|
||||
low.timing.pixel_clock -= pix_clk_range;
|
||||
high.timing.pixel_clock += pix_clk_range;
|
||||
/* some cards need wider virtual widths for certain modes */
|
||||
high.virtual_width = 2048;
|
||||
/* do it once for each depth we want to support */
|
||||
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) {
|
||||
/* set target values */
|
||||
*dst = *src;
|
||||
/* poke the specific space */
|
||||
dst->space = low.space = high.space = spaces[j];
|
||||
if (spaces[j] != B_CMAP8) dst->flags &= ~B_8_BIT_DAC;
|
||||
/* ask for a compatible mode */
|
||||
if (1 || PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
|
||||
/* count it, and move on to next mode */
|
||||
dst++;
|
||||
si->mode_count++;
|
||||
}
|
||||
}
|
||||
/* advance to next mode */
|
||||
src++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "s3drv.h"
|
||||
#include "s3accel.h"
|
||||
#include "s3mmio.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/*
|
||||
Enable/Disable interrupts. Just a wrapper around the
|
||||
ioctl() to the kernel driver.
|
||||
*/
|
||||
static void interrupt_enable(bool flag)
|
||||
{
|
||||
status_t result;
|
||||
savage_set_bool_state sbs;
|
||||
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
sbs.magic = SAVAGE_PRIVATE_DATA_MAGIC;
|
||||
sbs.do_it = flag;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, 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 do_set_display_mode(display_mode *dm)
|
||||
{
|
||||
uint bpp;
|
||||
SVGAMode s3mode;
|
||||
PixelTiming timing;
|
||||
status_t result;
|
||||
|
||||
dpf ("do_set_display_mode begin\n");
|
||||
/* disable interrupts using the kernel driver */
|
||||
interrupt_enable(false);
|
||||
|
||||
bpp = calcBitsPerPixel (dm->space);
|
||||
|
||||
timing.dot_clock_khz = dm->timing.pixel_clock;
|
||||
timing.x.disp = dm->timing.h_display;
|
||||
timing.x.sync_start = dm->timing.h_sync_start;
|
||||
timing.x.sync_end = dm->timing.h_sync_end;
|
||||
timing.x.total = dm->timing.h_total;
|
||||
timing.x.polarity = (dm->timing.flags & B_POSITIVE_HSYNC) ? 1 : 0;
|
||||
timing.y.disp = dm->timing.v_display;
|
||||
timing.y.sync_start = dm->timing.v_sync_start;
|
||||
timing.y.sync_end = dm->timing.v_sync_end;
|
||||
timing.y.total = dm->timing.v_total;
|
||||
timing.y.polarity = (dm->timing.flags & B_POSITIVE_VSYNC) ? 1 : 0;
|
||||
dpf ("TIMING = { %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d }\n",
|
||||
timing.dot_clock_khz,
|
||||
timing.x.disp, timing.x.sync_start, timing.x.sync_end,
|
||||
timing.x.total, timing.x.polarity,
|
||||
timing.y.disp, timing.y.sync_start, timing.y.sync_end,
|
||||
timing.y.total, timing.y.polarity);
|
||||
|
||||
s3drv_unlock_regs ();
|
||||
memset (&s3mode, 0, sizeof (s3mode));
|
||||
result = s3drv_get_mode (&timing, bpp, (byte_t*)&s3mode, sizeof (s3mode));
|
||||
if (result > 0) dpf ("s3drv_get_mode succeeded\n");
|
||||
else dpf ("s3drv_get_mode failed\n");
|
||||
dpf ("depth = %d, width = %d, height = %d\n",
|
||||
s3mode.pixel_size, s3mode.pixel_width, s3mode.pixel_height);
|
||||
result = s3drv_restore_mode ((byte_t*)&s3mode, sizeof (s3mode), true);
|
||||
if (result > 0) dpf ("s3drv_set_mode succeeded\n");
|
||||
else dpf ("s3drv_set_mode failed\n");
|
||||
|
||||
/* enable interrupts using the kernel driver */
|
||||
interrupt_enable(true);
|
||||
|
||||
dpf ("si->start_addr = %d\n", si->start_addr);
|
||||
s3drv_set_display_start (si->start_addr);
|
||||
s3drv_set_logical_width (dm->virtual_width);
|
||||
si->fbc.bytes_per_row = (dm->virtual_width * bpp + 7) / 8;
|
||||
s3accel_init (s3drv_get_context ());
|
||||
dpf ("s3accel_init called\n");
|
||||
|
||||
//s3drv_lock_regs ();
|
||||
dpf ("do_set_display_mode done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
The exported mode setting routine. First validate the mode,
|
||||
then call our private routine to hammer the registers.
|
||||
*/
|
||||
status_t SET_DISPLAY_MODE (display_mode *mode_to_set)
|
||||
{
|
||||
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;
|
||||
do_set_display_mode(&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 */
|
||||
s3drv_adjust_viewport (h_display_start, v_display_start);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Set the indexed color palette.
|
||||
*/
|
||||
void SET_INDEXED_COLORS (
|
||||
uint count, uint8 first, uint8 *color_data, uint32 flags)
|
||||
{
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
s3drv_unlock_regs ();
|
||||
write_sr ((byte_t*)regs + 0x8000, 0x1B, 0x10);
|
||||
while (count--)
|
||||
{
|
||||
s3drv_set_palette (
|
||||
first++, color_data[0], color_data[1], color_data[2]);
|
||||
color_data += 3;
|
||||
}
|
||||
s3drv_lock_regs ();
|
||||
}
|
||||
|
||||
|
||||
/* masks for DPMS control bits */
|
||||
enum
|
||||
{
|
||||
H_SYNC_OFF = 0x01,
|
||||
V_SYNC_OFF = 0x02,
|
||||
DISPLAY_OFF = 0x04,
|
||||
BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF
|
||||
};
|
||||
|
||||
/*
|
||||
Put the display into one of the Display Power Management modes.
|
||||
*/
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags)
|
||||
{
|
||||
uint32 LTemp;
|
||||
|
||||
/*
|
||||
The register containing the horizontal and vertical sync control bits
|
||||
usually contains other control bits, so do a read-modify-write.
|
||||
*/
|
||||
/* FIXME - read the bits */
|
||||
LTemp = *regs;
|
||||
/* this mask is device dependant */
|
||||
LTemp &= ~BITSMASK; /* clear all disable bits (including display disable) */
|
||||
|
||||
/* now pick one of the DPMS configurations */
|
||||
switch(dpms_flags)
|
||||
{
|
||||
case B_DPMS_ON: /* H: on, V: on */
|
||||
/* do nothing, bits already clear */
|
||||
/* usually, but it may be different for your device */
|
||||
break;
|
||||
case B_DPMS_STAND_BY: /* H: off, V: on, display off */
|
||||
LTemp |= H_SYNC_OFF | DISPLAY_OFF;
|
||||
break;
|
||||
case B_DPMS_SUSPEND: /* H: on, V: off, display off */
|
||||
LTemp |= V_SYNC_OFF | DISPLAY_OFF;
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
LTemp |= H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF;
|
||||
break;
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
/* FIXME - write the bits */
|
||||
*regs = LTemp;
|
||||
|
||||
/*
|
||||
NOTE: if you're driving a device with a backlight (like a digital
|
||||
LCD), you may want to turn off the backlight here when in a DPMS
|
||||
power saving mode.
|
||||
|
||||
if (dpms_flags == B_DPMS_ON)
|
||||
// turn on the back light
|
||||
;
|
||||
else
|
||||
// turn off the back light
|
||||
;
|
||||
*/
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Report device DPMS capabilities. Most newer cards can do it all.
|
||||
I've only seen one older card that can do a subset (ON and OFF).
|
||||
Very early cards may not be able to do this at all.
|
||||
*/
|
||||
uint32 DPMS_CAPABILITIES (void)
|
||||
{
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the current DPMS mode.
|
||||
*/
|
||||
uint32 DPMS_MODE (void)
|
||||
{
|
||||
uint32 LTemp;
|
||||
uint32 mode = B_DPMS_ON;
|
||||
|
||||
/* read the control bits from the device */
|
||||
/* FIXME - read the bits */
|
||||
LTemp = *regs;
|
||||
|
||||
/* what mode is set? */
|
||||
switch (LTemp & (H_SYNC_OFF | V_SYNC_OFF))
|
||||
{
|
||||
case 0: /* H: on, V: on */
|
||||
mode = B_DPMS_ON;
|
||||
break;
|
||||
case H_SYNC_OFF: /* H: off, V: on */
|
||||
mode = B_DPMS_STAND_BY;
|
||||
break;
|
||||
case V_SYNC_OFF: /* H: on, V: off */
|
||||
mode = B_DPMS_SUSPEND;
|
||||
break;
|
||||
case (H_SYNC_OFF | V_SYNC_OFF): /* H: off, V: off */
|
||||
mode = B_DPMS_OFF;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
#ifndef __DATA_TYPES_H__
|
||||
#define __DATA_TYPES_H__
|
||||
|
||||
|
||||
#define TEXT_MODE_SIZE 256*1024
|
||||
#define TEXT_FONT_SIZE 32*1024
|
||||
#define DISPLAY_START 1024*0
|
||||
|
||||
#define CRTC_INDEX 0x3d4
|
||||
#define CRTC_DATA 0x3d5
|
||||
#define SEQ_INDEX 0x3c4
|
||||
#define SEQ_DATA 0x3c5
|
||||
|
||||
typedef unsigned char byte_t;
|
||||
typedef unsigned short word_t;
|
||||
typedef unsigned long dword_t;
|
||||
|
||||
extern byte_t vga_mode_numbers[];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte_t col;
|
||||
byte_t row;
|
||||
byte_t height;
|
||||
byte_t buf_size0;
|
||||
byte_t buf_size1;
|
||||
byte_t seq_regs[0x04];
|
||||
byte_t misc_output;
|
||||
byte_t crtc_regs[0x19];
|
||||
byte_t attr_regs[0x14];
|
||||
byte_t graph_regs[0x09];
|
||||
} VGAMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte_t col;
|
||||
byte_t row;
|
||||
byte_t height;
|
||||
byte_t buf_size0;
|
||||
byte_t buf_size1;
|
||||
byte_t seq_regs[0x04];
|
||||
byte_t misc_output;
|
||||
byte_t crtc_regs[0x19];
|
||||
byte_t attr_regs[0x14];
|
||||
byte_t graph_regs[0x09];
|
||||
byte_t refresh_rate;
|
||||
word_t pixel_size;
|
||||
word_t pixel_width;
|
||||
word_t pixel_height;
|
||||
byte_t sr12;
|
||||
byte_t sr13;
|
||||
byte_t sr29;
|
||||
byte_t misc_ctrl;
|
||||
byte_t cr43;
|
||||
byte_t cr50;
|
||||
byte_t cr51;
|
||||
byte_t cr5d;
|
||||
byte_t cr5e;
|
||||
byte_t cr5f;
|
||||
byte_t cr66;
|
||||
byte_t cr67;
|
||||
byte_t cr31;
|
||||
byte_t cr58;
|
||||
byte_t cr69;
|
||||
} SVGAMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte_t s3mode;
|
||||
byte_t mode_tab0;
|
||||
byte_t mode_tab1;
|
||||
byte_t mode_attr;
|
||||
byte_t cr66;
|
||||
byte_t cr67;
|
||||
byte_t seq4;
|
||||
byte_t patch0;
|
||||
byte_t patch1;
|
||||
} SVGAModeInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte_t crtc0;
|
||||
byte_t crtc1;
|
||||
byte_t rate_attr;
|
||||
byte_t rate_freq;
|
||||
byte_t sr13;
|
||||
byte_t sr12;
|
||||
byte_t sr29;
|
||||
byte_t misc_ctrl;
|
||||
byte_t cr50;
|
||||
byte_t cr5d;
|
||||
byte_t cr5e;
|
||||
} SVGAPatchTable;
|
||||
|
||||
|
||||
#endif /* __DATA_TYPES_H__ */
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#if !defined(GENERIC_H)
|
||||
#define GENERIC_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);
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
typedef enum
|
||||
{
|
||||
B_NO_COLOR_SPACE = 0x0000, /* byte in memory order, high bit first */
|
||||
|
||||
/* linear color space (little endian is the default) */
|
||||
B_RGB32 = 0x0008, /* B[7:0] G[7:0] R[7:0] -[7:0] */
|
||||
B_RGBA32 = 0x2008, /* B[7:0] G[7:0] R[7:0] A[7:0] */
|
||||
B_RGB24 = 0x0003, /* B[7:0] G[7:0] R[7:0] */
|
||||
B_RGB16 = 0x0005, /* G[2:0],B[4:0] R[4:0],G[5:3] */
|
||||
B_RGB15 = 0x0010, /* G[2:0],B[4:0] -[0],R[4:0],G[4:3] */
|
||||
B_RGBA15 = 0x2010, /* G[2:0],B[4:0] A[0],R[4:0],G[4:3] */
|
||||
B_CMAP8 = 0x0004, /* D[7:0] */
|
||||
B_GRAY8 = 0x0002, /* Y[7:0] */
|
||||
B_GRAY1 = 0x0001, /* Y0[0],Y1[0],Y2[0],Y3[0],Y4[0],Y5[0],Y6[0],Y7[0] */
|
||||
|
||||
/* big endian version, when the encoding is not endianess independant */
|
||||
B_RGB32_BIG = 0x1008, /* -[7:0] R[7:0] G[7:0] B[7:0] */
|
||||
B_RGBA32_BIG = 0x3008, /* A[7:0] R[7:0] G[7:0] B[7:0] */
|
||||
B_RGB24_BIG = 0x1003, /* R[7:0] G[7:0] B[7:0] */
|
||||
B_RGB16_BIG = 0x1005, /* R[4:0],G[5:3] G[2:0],B[4:0] */
|
||||
B_RGB15_BIG = 0x1010, /* -[0],R[4:0],G[4:3] G[2:0],B[4:0] */
|
||||
B_RGBA15_BIG = 0x3010, /* A[0],R[4:0],G[4:3] G[2:0],B[4:0] */
|
||||
|
||||
/* little-endian declarations, for completness */
|
||||
B_RGB32_LITTLE = B_RGB32,
|
||||
B_RGBA32_LITTLE = B_RGBA32,
|
||||
B_RGB24_LITTLE = B_RGB24,
|
||||
B_RGB16_LITTLE = B_RGB16,
|
||||
B_RGB15_LITTLE = B_RGB15,
|
||||
B_RGBA15_LITTLE = B_RGBA15,
|
||||
|
||||
/* non linear color space -- note that these are here for exchange purposes; */
|
||||
/* a BBitmap or BView may not necessarily support all these color spaces. */
|
||||
|
||||
/* Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128) */
|
||||
|
||||
B_YCbCr422 = 0x4000, /* Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0]... */
|
||||
/* Cb2[7:0] Y3[7:0] Cr2[7:0] */
|
||||
B_YCbCr411 = 0x4001, /* Cb0[7:0] Y0[7:0] Cr0[7:0] Y1[7:0] Cb4[7:0]...*/
|
||||
/* Y2[7:0] Cr4[7:0] Y3[7:0] Y4[7:0] Y5[7:0]... */
|
||||
/* Y6[7:0] Y7[7:0] */
|
||||
B_YCbCr444 = 0x4003, /* Y0[7:0] Cb0[7:0] Cr0[7:0] */
|
||||
B_YCbCr420 = 0x4004, /* Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ... */
|
||||
/* Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines */
|
||||
|
||||
/* Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128) */
|
||||
/* note that YUV byte order is different from YCbCr */
|
||||
/* USE YCbCr, not YUV, when that's what you mean! */
|
||||
B_YUV422 = 0x4020, /* U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] ... */
|
||||
/* U2[7:0] Y2[7:0] V2[7:0] Y3[7:0] */
|
||||
B_YUV411 = 0x4021, /* U0[7:0] Y0[7:0] Y1[7:0] V0[7:0] Y2[7:0] Y3[7:0] */
|
||||
/* U4[7:0] Y4[7:0] Y5[7:0] V4[7:0] Y6[7:0] Y7[7:0] */
|
||||
B_YUV444 = 0x4023, /* U0[7:0] Y0[7:0] V0[7:0] U1[7:0] Y1[7:0] V1[7:0] */
|
||||
B_YUV420 = 0x4024, /* Non-interlaced only, U0 Y0 Y1 U2 Y2 Y3 on even scan lines ... */
|
||||
/* V0 Y0 Y1 V2 Y2 Y3 on odd scan lines */
|
||||
B_YUV9 = 0x402C, /* planar? 410? */
|
||||
B_YUV12 = 0x402D, /* planar? 420? */
|
||||
|
||||
B_UVL24 = 0x4030, /* U0[7:0] V0[7:0] L0[7:0] ... */
|
||||
B_UVL32 = 0x4031, /* U0[7:0] V0[7:0] L0[7:0] X0[7:0]... */
|
||||
B_UVLA32 = 0x6031, /* U0[7:0] V0[7:0] L0[7:0] A0[7:0]... */
|
||||
|
||||
B_LAB24 = 0x4032, /* L0[7:0] a0[7:0] b0[7:0] ... (a is not alpha!) */
|
||||
B_LAB32 = 0x4033, /* L0[7:0] a0[7:0] b0[7:0] X0[7:0] ... (b is not alpha!) */
|
||||
B_LABA32 = 0x6033, /* L0[7:0] a0[7:0] b0[7:0] A0[7:0] ... (A is alpha) */
|
||||
|
||||
/* red is at hue = 0 */
|
||||
|
||||
B_HSI24 = 0x4040, /* H[7:0] S[7:0] I[7:0] */
|
||||
B_HSI32 = 0x4041, /* H[7:0] S[7:0] I[7:0] X[7:0] */
|
||||
B_HSIA32 = 0x6041, /* H[7:0] S[7:0] I[7:0] A[7:0] */
|
||||
|
||||
B_HSV24 = 0x4042, /* H[7:0] S[7:0] V[7:0] */
|
||||
B_HSV32 = 0x4043, /* H[7:0] S[7:0] V[7:0] X[7:0] */
|
||||
B_HSVA32 = 0x6043, /* H[7:0] S[7:0] V[7:0] A[7:0] */
|
||||
|
||||
B_HLS24 = 0x4044, /* H[7:0] L[7:0] S[7:0] */
|
||||
B_HLS32 = 0x4045, /* H[7:0] L[7:0] S[7:0] X[7:0] */
|
||||
B_HLSA32 = 0x6045, /* H[7:0] L[7:0] S[7:0] A[7:0] */
|
||||
|
||||
B_CMY24 = 0xC001, /* C[7:0] M[7:0] Y[7:0] No gray removal done */
|
||||
B_CMY32 = 0xC002, /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
|
||||
B_CMYA32 = 0xE002, /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
|
||||
B_CMYK32 = 0xC003, /* C[7:0] M[7:0] Y[7:0] K[7:0] */
|
||||
|
||||
/* compatibility declarations */
|
||||
B_MONOCHROME_1_BIT = B_GRAY1,
|
||||
B_GRAYSCALE_8_BIT = B_GRAY8,
|
||||
B_COLOR_8_BIT = B_CMAP8,
|
||||
B_RGB_32_BIT = B_RGB32,
|
||||
B_RGB_16_BIT = B_RGB15,
|
||||
B_BIG_RGB_32_BIT = B_RGB32_BIG,
|
||||
B_BIG_RGB_16_BIT = B_RGB15_BIG
|
||||
} color_space;
|
||||
#endif
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#include "datatype.h"
|
||||
#include "s3mmio.h"
|
||||
#include "s3accel.h"
|
||||
#include "s3drv.h"
|
||||
|
||||
|
||||
#define MIX_MASK 0x000f
|
||||
|
||||
#define MIX_NOT_DST 0x0000
|
||||
#define MIX_0 0x0001
|
||||
#define MIX_1 0x0002
|
||||
#define MIX_DST 0x0003
|
||||
#define MIX_NOT_SRC 0x0004
|
||||
#define MIX_XOR 0x0005
|
||||
#define MIX_XNOR 0x0006
|
||||
#define MIX_SRC 0x0007
|
||||
#define MIX_NAND 0x0008
|
||||
#define MIX_NOT_SRC_OR_DST 0x0009
|
||||
#define MIX_SRC_OR_NOT_DST 0x000a
|
||||
#define MIX_OR 0x000b
|
||||
#define MIX_AND 0x000c
|
||||
#define MIX_SRC_AND_NOT_DST 0x000d
|
||||
#define MIX_NOT_SRC_AND_DST 0x000e
|
||||
#define MIX_NOR 0x000f
|
||||
|
||||
|
||||
byte_t s3alu[16] =
|
||||
{
|
||||
MIX_0,
|
||||
MIX_AND,
|
||||
MIX_SRC_AND_NOT_DST,
|
||||
MIX_SRC,
|
||||
MIX_NOT_SRC_AND_DST,
|
||||
MIX_DST,
|
||||
MIX_XOR,
|
||||
MIX_OR,
|
||||
MIX_NOR,
|
||||
MIX_XNOR,
|
||||
MIX_NOT_DST,
|
||||
MIX_SRC_OR_NOT_DST,
|
||||
MIX_NOT_SRC,
|
||||
MIX_NOT_SRC_OR_DST,
|
||||
MIX_NAND,
|
||||
MIX_1
|
||||
};
|
||||
|
||||
|
||||
byte_t * __vga_base = 0;
|
||||
byte_t * __mmio_base = 0;
|
||||
dword_t s3accelCmd = 0;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
S3DriverContext * s3dc;
|
||||
byte_t * mmio_base;
|
||||
byte_t * vga_base;
|
||||
byte_t * bci_base;
|
||||
byte_t * fb_base;
|
||||
int fb_size;
|
||||
word_t device_id;
|
||||
dword_t global_bd;
|
||||
dword_t primary_bd;
|
||||
dword_t secondary_bd;
|
||||
int bpp;
|
||||
int logical_width;
|
||||
int logical_height;
|
||||
} S3AccelContext;
|
||||
|
||||
static S3AccelContext S3AC = { 0 };
|
||||
|
||||
|
||||
int s3accel_init (S3DriverContext * s3dc)
|
||||
{
|
||||
byte_t sr1;
|
||||
int stride;
|
||||
int display_start;
|
||||
|
||||
if (!s3dc) return 0;
|
||||
S3AC.s3dc = s3dc;
|
||||
S3AC.mmio_base = __mmio_base = S3AC.s3dc->mmio_base;
|
||||
S3AC.vga_base = __vga_base = S3AC.s3dc->vga_base;
|
||||
S3AC.fb_base = S3AC.s3dc->fb_base;
|
||||
S3AC.fb_size = S3AC.s3dc->fb_size;
|
||||
S3AC.bpp = S3AC.s3dc->bpp;
|
||||
S3AC.logical_width = S3AC.s3dc->logical_width;
|
||||
|
||||
s3drv_unlock_regs ();
|
||||
write32 (S3AC.mmio_base + 0x850C, 0x11);
|
||||
write32 (S3AC.mmio_base + 0x850C, 0x11);
|
||||
S3AC.device_id = read16 (__vga_base + 2);
|
||||
sr1 = read_sr (__vga_base, 1);
|
||||
write_sr (__vga_base, 1, sr1 | 0x20);
|
||||
|
||||
UpdateGEReg (ALT_CURXY, 0);
|
||||
UpdateGEReg (ALT_STEP, 0);
|
||||
UpdateGEReg (ERR_TERM, 0);
|
||||
UpdateGEReg (SHORT_STROKE,0);
|
||||
UpdateGEReg (BKGD_COLOR, 0x00000000);
|
||||
UpdateGEReg (FRGD_COLOR, 0xffffffff);
|
||||
UpdateGEReg (WRT_MASK, 0xffffffff);
|
||||
UpdateGEReg (RD_MASK, 0xffffffff);
|
||||
UpdateGEReg (COLOR_CMP, 0x00000000);
|
||||
UpdateGEReg (ALT_MIX, 0x00270007);
|
||||
UpdateGEReg (SCISSORS_LT, 0x20001000);
|
||||
UpdateGEReg (SCISSORS_RB, 0x4fff3fff);
|
||||
UpdateGEReg (PIX_CNTL, 0xd000a000);
|
||||
UpdateGEReg (MULT_MISC, 0xf000e200);
|
||||
UpdateGEReg (ALT_PCNT, 0);
|
||||
|
||||
display_start = S3AC.s3dc->display_start;
|
||||
s3drv_dpf ("display_start = %d\n", display_start);
|
||||
write32 (__mmio_base + 0x81c0, display_start);
|
||||
stride = (S3AC.logical_width * S3AC.bpp + 7) >> 3;
|
||||
write32 (__mmio_base + 0x81c8, stride); /* set stride */
|
||||
write32 (__mmio_base + 0x8168, display_start);
|
||||
S3AC.global_bd = (S3AC.logical_width & 0x1ff0)|(S3AC.bpp<<16)|0x10000001;
|
||||
/* Need to write GBD twice after an engine reset */
|
||||
write32 (__mmio_base + 0x816c, S3AC.global_bd);
|
||||
write32 (__mmio_base + 0x816c, S3AC.global_bd);
|
||||
S3AC.s3dc->global_bd = S3AC.global_bd;
|
||||
write_sr (__vga_base, 1, sr1);
|
||||
s3drv_lock_regs ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3accel_wait_for_idle ()
|
||||
{
|
||||
s3drv_wait_for_idle ();
|
||||
UpdateGEReg (WRT_MASK, 0xffffffff);
|
||||
UpdateGEReg (RD_MASK, 0xffffffff);
|
||||
UpdateGEReg (ALT_MIX, 0x00270007);
|
||||
UpdateGEReg (SCISSORS_LT, 0x20001000);
|
||||
UpdateGEReg (SCISSORS_RB, 0x4fff3fff);
|
||||
UpdateGEReg (PIX_CNTL, 0xd000a000);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3accel_wait_for_fifo (int count)
|
||||
{
|
||||
int i;
|
||||
s3drv_wait_for_idle ();
|
||||
i = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
__inline__ void s3accel_set_fg_color (dword_t color)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg (FRGD_COLOR, color);
|
||||
}
|
||||
|
||||
__inline__ void s3accel_set_bg_color (dword_t color)
|
||||
{
|
||||
s3accel_wait_for_fifo (1);
|
||||
UpdateGEReg (BKGD_COLOR, color);
|
||||
}
|
||||
|
||||
void s3accel_set_clip_rect (int x1, int y1, int x2, int y2)
|
||||
{
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (SCISSORS_LT, (y1 << 16) | (x1 & 0xffff));
|
||||
UpdateGEReg (SCISSORS_RB, (y2 << 16) | (x2 & 0xffff));
|
||||
}
|
||||
|
||||
#if S3ACCEL_NEED_FUNCTIONS
|
||||
|
||||
void s3accel_setup_fill_rect (int color, int rop, dword_t planemask)
|
||||
{
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (WRT_MASK, planemask);
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0020 | s3alu[rop]);
|
||||
s3drv_dpf ("FRGD_MIX is 0x%4X\n", 0x0020 | s3alu[rop]);
|
||||
UpdateGEReg (FRGD_COLOR, color);
|
||||
s3accelCmd = 0x40b1;
|
||||
}
|
||||
|
||||
void s3accel_repeat_fill_rect (int x, int y, int w, int h)
|
||||
{
|
||||
w--; h--;
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (ALT_CURXY, (x<<16)|y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, 0x000040b1);
|
||||
}
|
||||
|
||||
void s3accel_fill_rect (int x, int y, int w, int h)
|
||||
{
|
||||
w--; h--;
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
write32 (__mmio_base + ALT_CURXY, (x<<16)|y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, 0x000040b1);
|
||||
}
|
||||
|
||||
__inline__ void s3accel_setup_copy_rect (
|
||||
int xdir, int ydir, int rop, dword_t planemask,
|
||||
int transparency_color)
|
||||
{
|
||||
s3accelCmd = 0xc011;
|
||||
if (xdir == 1) s3accelCmd |= 0x20;
|
||||
if (ydir == 1) s3accelCmd |= 0x80;
|
||||
s3accel_wait_for_fifo (2);
|
||||
UpdateGEReg (WRT_MASK, planemask);
|
||||
if (transparency_color != -1)
|
||||
{
|
||||
UpdateGEReg (COLOR_CMP, transparency_color);
|
||||
UpdateGEReg16 (PIX_CNTL, 0xa100);
|
||||
}
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0060 | s3alu[rop]);
|
||||
}
|
||||
|
||||
__inline__ void s3accel_repeat_copy_rect (
|
||||
int src_x, int src_y, int dest_x, int dest_y, int w, int h)
|
||||
{
|
||||
w--; h--;
|
||||
if (!(s3accelCmd & 0x20))
|
||||
{
|
||||
src_x += w; dest_x += w;
|
||||
}
|
||||
if (!(s3accelCmd & 0x80))
|
||||
{
|
||||
src_y += h; dest_y += h;
|
||||
}
|
||||
|
||||
s3accel_wait_for_fifo (4);
|
||||
UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y);
|
||||
UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, s3accelCmd);
|
||||
}
|
||||
|
||||
void s3accel_copy_rect (int is_patterned, int src_x, int src_y,
|
||||
int dest_x, int dest_y, int w, int h)
|
||||
{
|
||||
int cmd = 0xc0b1;
|
||||
|
||||
w--; h--;
|
||||
if (is_patterned)
|
||||
cmd |= 0x4000;
|
||||
else
|
||||
{
|
||||
if ((src_x < dest_x) )//&& (src_x + w) > dest_x)
|
||||
{
|
||||
src_x += w; dest_x += w;
|
||||
cmd ^= 32;
|
||||
}
|
||||
if ((src_y < dest_y) )//&& (src_y + h) > dest_y)
|
||||
{
|
||||
src_y += h; dest_y += h;
|
||||
cmd ^= 128;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0067);
|
||||
UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y);
|
||||
UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y);
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h);
|
||||
UpdateGEReg (CMD, cmd);
|
||||
}
|
||||
|
||||
void s3accel_draw_line (int x1, int y1, int x2, int y2, int no_endpoint)
|
||||
{
|
||||
int cmd = 0x20b1;
|
||||
int min, max, err_term, *tmp=&max;
|
||||
|
||||
/*
|
||||
max = max(abs(x2-x1),abs(y2-y1));
|
||||
min = min(abs(x2-x1),abs(y2-y1));
|
||||
*/
|
||||
|
||||
max = x2 - x1;
|
||||
min = y2 - y1;
|
||||
|
||||
if (max < 0)
|
||||
{
|
||||
max = -max;
|
||||
cmd ^= 32;
|
||||
}
|
||||
|
||||
if (min < 0)
|
||||
{
|
||||
min = -min;
|
||||
cmd ^= 128;
|
||||
}
|
||||
|
||||
if (max < min)
|
||||
{
|
||||
max = min;
|
||||
min = &tmp;
|
||||
cmd |= 0x40;
|
||||
}
|
||||
|
||||
err_term = 2 * min - max;
|
||||
if (!(cmd & 0x20)) err_term --;
|
||||
if (no_endpoint) cmd |= 4;
|
||||
|
||||
s3accel_wait_for_idle ();
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0027);
|
||||
UpdateGEReg (ALT_CURXY, (x1<<16)|y1);
|
||||
/* Databook says MAJ_AXIS_PCNT = max - 1,
|
||||
but MAJ_AXIS_PCNT = max seems to produce correct result. */
|
||||
UpdateGEReg16 (MAJ_AXIS_PCNT, max);
|
||||
UpdateGEReg (ALT_STEP, ((2*(min-max))<<16)|(2*min));
|
||||
UpdateGEReg (ERR_TERM, err_term);
|
||||
UpdateGEReg (CMD, cmd);
|
||||
}
|
||||
|
||||
|
||||
void s3accel_repeat_draw_line (
|
||||
int x1, int y1, int x2, int y2, dword_t bias)
|
||||
{
|
||||
s3accel_draw_line (x1, y1, x2, y2, bias & 0x100);
|
||||
}
|
||||
|
||||
|
||||
void s3accel_write_image (int x, int y, int w, int h)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = (((w * S3AC.bpp) + 31) >> 5) * h;
|
||||
w--; h--;
|
||||
s3accel_wait_for_idle ();
|
||||
UpdateGEReg16 (FRGD_MIX, 0x0047);
|
||||
UpdateGEReg (ALT_CURXY, (x<<16)|y); /* destination */
|
||||
UpdateGEReg (ALT_PCNT, (w<<16)|h); /* width/height */
|
||||
UpdateGEReg (CMD, 0x55b1);
|
||||
|
||||
while (count --) { write32 (__mmio_base, ~0); }
|
||||
}
|
||||
#endif /* S3ACCEL_NEED_FUNCTIONS */
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __S3ACCEL_H__
|
||||
#define __S3ACCEL_H__
|
||||
|
||||
|
||||
#include "s3drv.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALT_CURXY = 0x8100,
|
||||
CUR_Y = 0x8100,
|
||||
CUR_X = 0x8102,
|
||||
ALT_STEP = 0x8108,
|
||||
DESTY_AXSTP = 0x8108,
|
||||
DESTX_DIASTP = 0x810a,
|
||||
ERR_TERM = 0x8110,
|
||||
CMD = 0x8118,
|
||||
SHORT_STROKE = 0x811c,
|
||||
BKGD_COLOR = 0x8120,
|
||||
FRGD_COLOR = 0x8124,
|
||||
WRT_MASK = 0x8128,
|
||||
RD_MASK = 0x812c,
|
||||
COLOR_CMP = 0x8130,
|
||||
ALT_MIX = 0x8134,
|
||||
BKGD_MIX = 0x8134,
|
||||
FRGD_MIX = 0x8136,
|
||||
SCISSORS_LT = 0x8138,
|
||||
SCISSORS_T = 0x8138,
|
||||
SCISSORS_L = 0x813a,
|
||||
SCISSORS_RB = 0x813c,
|
||||
SCISSORS_B = 0x813c,
|
||||
SCISSORS_R = 0x813e,
|
||||
PIX_CNTL = 0x8140,
|
||||
MULT_MISC2 = 0x8142,
|
||||
MULT_MISC = 0x8144,
|
||||
READ_SEL = 0x8144,
|
||||
ALT_PCNT = 0x8148,
|
||||
MIN_AXIS_PCNT = 0x8148,
|
||||
MAJ_AXIS_PCNT = 0x814a
|
||||
} S3GERegister;
|
||||
|
||||
extern byte_t s3alu[16];
|
||||
extern byte_t * __vga_base;
|
||||
extern byte_t * __mmio_base;
|
||||
|
||||
|
||||
#define UpdateGEReg(reg, val)\
|
||||
write32 (__mmio_base + reg, val);\
|
||||
|
||||
#define UpdateGEReg16(reg, val)\
|
||||
write16 (__mmio_base + reg, val);\
|
||||
|
||||
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
extern int s3accel_init (S3DriverContext * s3dc);
|
||||
extern int s3accel_wait_for_idle ();
|
||||
extern int s3accel_wait_for_fifo (int count);
|
||||
extern void s3accel_set_pattern ();
|
||||
extern void s3accel_set_fg_color (dword_t fg_color);
|
||||
extern void s3accel_set_bg_color (dword_t bg_color);
|
||||
extern void s3accel_set_clip_rect (int x1, int y1, int x2, int y2);
|
||||
|
||||
extern void s3accel_setup_copy_rect (
|
||||
int xdir, int ydir, int rop,
|
||||
dword_t planemask, int transparency_color);
|
||||
extern void s3accel_repeat_copy_rect (
|
||||
int x1, int y1, int x2, int y2, int w, int h);
|
||||
extern void s3accel_copy_rect (int is_patterned, int src_x, int src_y,
|
||||
int dest_x, int dest_y, int w, int h);
|
||||
|
||||
extern void s3accel_setup_fill_rect (int color, int rop, dword_t planemask);
|
||||
extern void s3accel_repeat_fill_rect (int x, int y, int w, int h);
|
||||
extern void s3accel_fill_rect (int x, int y, int w, int h);
|
||||
|
||||
extern void s3accel_fill_polygon ();
|
||||
extern void s3accel_setup_fill_polygon ();
|
||||
extern void s3accel_repeat_fill_polygon (int count, short * xw);
|
||||
|
||||
extern void s3accel_draw_line (int x1, int y1, int x2, int y2,
|
||||
int no_endpoint);
|
||||
extern void s3accel_draw_polyline (int count, short * xy);
|
||||
extern void s3accel_draw_segments (int count, short * xy);
|
||||
extern void s3accel_setup_draw_line ();
|
||||
extern void s3accel_repeat_draw_line (int x1, int y1, int x2, int y2,
|
||||
dword_t bias);
|
||||
|
||||
extern void s3accel_draw_scanline ();
|
||||
extern void s3accel_setup_draw_scanline ();
|
||||
extern void s3accel_repeat_draw_scanline (int x, int width);
|
||||
extern void s3accel_draw_multi_scanlines (int count, int starty, short * xw);
|
||||
|
||||
extern void s3accel_write_image (int x, int y, int w, int h);
|
||||
extern void s3accel_write_bitmap ();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __S3ACCEL_H__ */
|
||||
@@ -0,0 +1,683 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#include "s3mmio.h"
|
||||
#include "s3drv.h"
|
||||
#include "DriverInterface.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
extern int __s3drv_get_svga_mode (
|
||||
SVGAMode * svgamode, PixelTiming * pixel_timing);
|
||||
|
||||
static S3DriverContext S3DC =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
void s3drv_dpf (const char * format, ...)
|
||||
{
|
||||
#if DEBUG > 0
|
||||
va_list args;
|
||||
char buffer[4096];
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (buffer, format, args);
|
||||
fputs (buffer, stderr);
|
||||
va_end (args);
|
||||
#endif
|
||||
}
|
||||
|
||||
S3DriverContext * s3drv_get_context ()
|
||||
{
|
||||
return &S3DC;
|
||||
}
|
||||
|
||||
int s3drv_init (byte_t * mb)
|
||||
{
|
||||
if (!mb) return 0;
|
||||
S3DC.mmio_base = mb;
|
||||
S3DC.vga_base = mb + 0x8000;
|
||||
S3DC.device_id = read16 (S3DC.vga_base + 2);
|
||||
S3DC.viewport_x = 0;
|
||||
S3DC.viewport_y = 0;
|
||||
S3DC.display_start = DISPLAY_START;
|
||||
write32 (mb + 0x8510, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int __reg_unlock_count = 0;
|
||||
|
||||
void s3drv_lock_regs ()
|
||||
{
|
||||
__reg_unlock_count --;
|
||||
if (__reg_unlock_count < 1)
|
||||
{
|
||||
__reg_unlock_count = 0;
|
||||
s3_lock_regs (S3DC.vga_base);
|
||||
}
|
||||
}
|
||||
|
||||
void s3drv_unlock_regs ()
|
||||
{
|
||||
s3_unlock_regs (S3DC.vga_base);
|
||||
__reg_unlock_count ++;
|
||||
}
|
||||
|
||||
int s3drv_detect_vram_mb_size (byte_t * vram_start, int max_mb)
|
||||
{
|
||||
int ram_size_mb;
|
||||
byte_t * vga_base = S3DC.vga_base;
|
||||
|
||||
s3drv_unlock_regs ();
|
||||
|
||||
if (vram_start)
|
||||
{
|
||||
byte_t cr58, cr66;
|
||||
byte_t * magic_spot;
|
||||
|
||||
if (!vga_base) return 2;
|
||||
if (!vram_start) return 2;
|
||||
|
||||
magic_spot = vram_start + 1024*1024;
|
||||
cr58 = read_cr (vga_base, 0x58);
|
||||
write_cr (vga_base, 0x58, 0x13);
|
||||
cr66 = read_cr (vga_base, 0x66);
|
||||
write_cr (vga_base, 0x66, cr66 | 1);
|
||||
for (ram_size_mb = 1; ram_size_mb < max_mb; ram_size_mb ++)
|
||||
{
|
||||
read32 (vga_base);
|
||||
write32 (magic_spot, 0xC55CC55C);
|
||||
if (read32 (magic_spot) != 0xC55CC55C) break;
|
||||
write32 (vram_start, 0);
|
||||
write32 (magic_spot, 0xFFFFFFFF);
|
||||
if (read32 (vram_start) == 0xFFFFFFFF) break;
|
||||
magic_spot += 1024*1024;
|
||||
}
|
||||
write_cr (vga_base, 0x58, cr58);
|
||||
write_cr (vga_base, 0x66, cr66);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_t cr36;
|
||||
word_t device;
|
||||
|
||||
device = (read_cr (vga_base, 0x2d) << 8) | read_cr (vga_base, 0x2e);
|
||||
cr36 = read_cr (vga_base, 0x36);
|
||||
ram_size_mb = 2;
|
||||
if (isSavage4Family(device))
|
||||
{
|
||||
switch (cr36 >> 5)
|
||||
{
|
||||
case 0:
|
||||
ram_size_mb = 2;
|
||||
break;
|
||||
case 1:
|
||||
ram_size_mb = 4;
|
||||
case 2:
|
||||
ram_size_mb = 8;
|
||||
break;
|
||||
case 3:
|
||||
ram_size_mb = 12;
|
||||
break;
|
||||
case 4:
|
||||
ram_size_mb = 16;
|
||||
break;
|
||||
case 5:
|
||||
ram_size_mb = 32;
|
||||
break;
|
||||
case 6:
|
||||
ram_size_mb = 64;
|
||||
break;
|
||||
case 7:
|
||||
ram_size_mb = 128;
|
||||
break;
|
||||
case 8:
|
||||
ram_size_mb = 256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cr36 >> 6)
|
||||
{
|
||||
case 0:
|
||||
ram_size_mb = 8;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
ram_size_mb = 4;
|
||||
break;
|
||||
case 3:
|
||||
ram_size_mb = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s3drv_lock_regs ();
|
||||
|
||||
return ram_size_mb;
|
||||
}
|
||||
|
||||
int s3drv_is_text_mode ()
|
||||
{
|
||||
return !(read_gr (S3DC.vga_base, 0x06) & 1);
|
||||
}
|
||||
|
||||
int s3drv_save_font (byte_t * vram, byte_t * font_buf, int buf_size)
|
||||
{
|
||||
int i;
|
||||
byte_t * font;
|
||||
byte_t * plane2;
|
||||
if (!font_buf) return 0;
|
||||
font = font_buf;
|
||||
plane2 = vram + 2;
|
||||
*font = *plane2;
|
||||
for (i = 0; i < buf_size; i ++) *(font++) = *(plane2+=4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3drv_restore_font (byte_t * vram, byte_t * font_buf, int buf_size)
|
||||
{
|
||||
int i;
|
||||
byte_t * font;
|
||||
byte_t * plane2;
|
||||
if (!font_buf) return 0;
|
||||
plane2 = vram + 2;
|
||||
font = font_buf;
|
||||
*plane2 = *font;
|
||||
for (i = 0; i < buf_size; i ++) *(plane2+=4) = *(font++);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3drv_get_mode (PixelTiming * timing, int bpp,
|
||||
byte_t * mode_buf, int buf_size)
|
||||
{
|
||||
SVGAMode * s3mode;
|
||||
if (!timing || !mode_buf) return 0;
|
||||
if (buf_size < sizeof (SVGAMode)) return - sizeof (SVGAMode);
|
||||
|
||||
s3mode = (SVGAMode*) mode_buf;
|
||||
|
||||
__s3drv_get_svga_mode(s3mode, timing);
|
||||
s3mode->pixel_size = bpp;
|
||||
s3mode->pixel_width = timing->x.disp;
|
||||
s3mode->pixel_height = timing->y.disp;
|
||||
s3mode->seq_regs[0] = 0x01;
|
||||
s3mode->seq_regs[1] = 0x0F;
|
||||
s3mode->seq_regs[2] = 0x00;
|
||||
s3mode->seq_regs[3] = 0x0E;
|
||||
s3mode->attr_regs[0x10] = 0x01;
|
||||
s3mode->attr_regs[0x11] = 0x00;
|
||||
s3mode->attr_regs[0x12] = 0x0F;
|
||||
s3mode->attr_regs[0x13] = 0x00;
|
||||
s3mode->graph_regs[0] = 0x00;
|
||||
s3mode->graph_regs[1] = 0x00;
|
||||
s3mode->graph_regs[2] = 0x00;
|
||||
s3mode->graph_regs[3] = 0x00;
|
||||
s3mode->graph_regs[4] = 0x00;
|
||||
s3mode->graph_regs[5] = 0x00;
|
||||
s3mode->graph_regs[6] = 0x05;
|
||||
s3mode->graph_regs[7] = 0x0F;
|
||||
s3mode->graph_regs[8] = 0xFF;
|
||||
s3mode->misc_ctrl = s3mode->misc_output & 0xc0;
|
||||
s3mode->cr31 = 0x0d;
|
||||
/* Savage3D and Savage/MX need double horizontal timing for 16bpp */
|
||||
s3mode->cr43 = (!isSavage4Family(S3DC.device_id) &&
|
||||
(((bpp + 7)/8) == 2) ) ? 0x80 : 0;
|
||||
s3mode->cr50 = 0xC1 | ((((bpp+7)>>3) - 1) << 4);
|
||||
s3mode->cr51 =
|
||||
(((s3mode->pixel_width * s3mode->pixel_size + 31) >> 6) & 0x300) >> 4;
|
||||
s3mode->cr58 = 0x13;
|
||||
s3mode->cr66 = 0x89;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 8:
|
||||
s3mode->cr67 = 0x00;
|
||||
break;
|
||||
case 15:
|
||||
s3mode->cr67 = 0x20;
|
||||
break;
|
||||
case 16:
|
||||
s3mode->cr67 = 0x40;
|
||||
break;
|
||||
case 32:
|
||||
s3mode->cr67 = 0xd0;
|
||||
break;
|
||||
default:
|
||||
s3mode->cr67 = 0x00;
|
||||
}
|
||||
s3mode->cr69 = 0x80;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3drv_display_is_off ()
|
||||
{
|
||||
return read_sr (S3DC.vga_base, 0x01) & 0x20;
|
||||
}
|
||||
|
||||
void s3drv_turn_display_off ()
|
||||
{
|
||||
write_sr (S3DC.vga_base, 0x01, read_sr (S3DC.vga_base, 0x01) | 0x20);
|
||||
}
|
||||
|
||||
void s3drv_turn_display_on ()
|
||||
{
|
||||
byte_t sr1 = read_sr (S3DC.vga_base, 0x01) & ~0x20;
|
||||
s3drv_wait_for_vsync ();
|
||||
write_sr (S3DC.vga_base, 0x01, sr1);
|
||||
}
|
||||
|
||||
int s3drv_set_logical_width (int width)
|
||||
{
|
||||
if (width >= S3DC.width)
|
||||
{
|
||||
int stride;
|
||||
width += 15;
|
||||
width &= ~15;
|
||||
stride = (width * S3DC.bpp + 7) >> 3;
|
||||
S3DC.logical_width = width;
|
||||
write32 (S3DC.mmio_base + 0x81c8, stride); /* set stride */
|
||||
if (S3DC.global_bd)
|
||||
{
|
||||
S3DC.global_bd = (S3DC.global_bd & 0xffffe00f) | stride;
|
||||
write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd);
|
||||
write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd);
|
||||
}
|
||||
}
|
||||
|
||||
return S3DC.logical_width;
|
||||
}
|
||||
|
||||
int s3drv_adjust_viewport (int x, int y)
|
||||
{
|
||||
int viewport_start;
|
||||
|
||||
if (x < 0 || y < 0) return 0;
|
||||
S3DC.viewport_x = x;
|
||||
S3DC.viewport_y = y;
|
||||
viewport_start = ((y * S3DC.logical_width + x) * S3DC.bpp + 7) / 8;
|
||||
viewport_start += S3DC.display_start;
|
||||
if (S3DC.bpp == 32)
|
||||
{
|
||||
S3DC.cursor_adjustment = (viewport_start & 15) / 4;
|
||||
viewport_start &= ~15;
|
||||
}
|
||||
write32 (S3DC.mmio_base + 0x81c0, viewport_start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int s3drv_set_display_start (int offset)
|
||||
{
|
||||
if (offset > -1)
|
||||
{
|
||||
S3DC.display_start = offset + DISPLAY_START;
|
||||
write32 (S3DC.mmio_base + 0x8168, S3DC.display_start);
|
||||
s3drv_adjust_viewport (S3DC.viewport_x, S3DC.viewport_y);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void s3drv_wait_for_vsync ()
|
||||
{
|
||||
int i;
|
||||
if (!s3drv_display_is_off ())
|
||||
for (i = 0; i < 1000; i ++)
|
||||
if ( (read8 (S3DC.vga_base + 0x3da) & 9) == 9) break;
|
||||
}
|
||||
|
||||
void s3drv_wait_for_idle ()
|
||||
{
|
||||
int i;
|
||||
if (isSavage4Family(S3DC.device_id)) for (i = 0; i < 10000000; i ++)
|
||||
{
|
||||
if ( (read32 (S3DC.mmio_base + 0x48c00) & 0x5e01ffff) == 0x5e000000)
|
||||
break;
|
||||
}
|
||||
else for (i = 0; i < 10000000; i ++)
|
||||
{
|
||||
if ( (read32 (S3DC.mmio_base + 0x48c00) & 0x005fffff) == 0x005e0000)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int s3drv_set_cursor_color (dword_t fg_color, dword_t bg_color)
|
||||
{
|
||||
read_cr (S3DC.vga_base, 0x45);
|
||||
if (S3DC.bpp != 8)
|
||||
{
|
||||
write_cr (S3DC.vga_base, 0x4a, fg_color >> 16);
|
||||
write_cr (S3DC.vga_base, 0x4a, fg_color >> 8);
|
||||
}
|
||||
write_cr (S3DC.vga_base, 0x4a, fg_color);
|
||||
|
||||
read_cr (S3DC.vga_base, 0x45);
|
||||
if (S3DC.bpp != 8)
|
||||
{
|
||||
write_cr (S3DC.vga_base, 0x4b, bg_color >> 16);
|
||||
write_cr (S3DC.vga_base, 0x4b, bg_color >> 8);
|
||||
}
|
||||
write_cr (S3DC.vga_base, 0x4b, bg_color);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Assume width and height are byte-aligned. */
|
||||
|
||||
int s3drv_load_cursor (
|
||||
byte_t * lfb, int offset, int width, int height,
|
||||
byte_t * and_mask, byte_t * xor_mask)
|
||||
{
|
||||
int i, x, y, bit_shift;
|
||||
byte_t and_buf[512];
|
||||
byte_t xor_buf[512];
|
||||
byte_t * and_ptr = (byte_t*)and_mask;
|
||||
byte_t * xor_ptr = (byte_t*)xor_mask;
|
||||
|
||||
if (!lfb || !and_mask || !xor_mask) return 0;
|
||||
|
||||
bit_shift = width & 7;
|
||||
width /= 8;
|
||||
|
||||
if (width != 64 || height != 64)
|
||||
{
|
||||
and_ptr = (byte_t*)and_buf;
|
||||
xor_ptr = (byte_t*)xor_buf;
|
||||
|
||||
for (y = 0; y < height; y ++)
|
||||
{
|
||||
for (x = 0; x < width; x ++)
|
||||
{
|
||||
*and_ptr ++ = *and_mask ++;
|
||||
*xor_ptr ++ = *xor_mask ++;
|
||||
}
|
||||
|
||||
if (bit_shift)
|
||||
{
|
||||
x ++;
|
||||
*and_ptr ++ = 0xFF ^ ((*and_mask ++) & (~(0xFF >> bit_shift)));
|
||||
*xor_ptr ++ = (*xor_mask ++) & (~(0xFF >> bit_shift));
|
||||
}
|
||||
|
||||
for ( ; x < 8; x ++)
|
||||
{
|
||||
*and_ptr ++ = 0xFF;
|
||||
*xor_ptr ++ = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; y < 64; y ++)
|
||||
{
|
||||
*(dword_t*)and_ptr = ~0; and_ptr += 4;
|
||||
*(dword_t*)and_ptr = ~0; and_ptr += 4;
|
||||
*(dword_t*)xor_ptr = 0; xor_ptr += 4;
|
||||
*(dword_t*)xor_ptr = 0; xor_ptr += 4;
|
||||
}
|
||||
|
||||
and_ptr = (byte_t*)and_buf;
|
||||
xor_ptr = (byte_t*)xor_buf;
|
||||
}
|
||||
|
||||
lfb += offset * 1024;
|
||||
write_cr (S3DC.vga_base, 0x4d, offset);
|
||||
write_cr (S3DC.vga_base, 0x4c, offset >> 8);
|
||||
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
#if 0
|
||||
dword_t tmp = (*(word_t*)and_ptr << 16) | *(word_t*)xor_ptr;
|
||||
*(dword_t*)lfb = tmp; lfb += 4;
|
||||
#else
|
||||
write16 (lfb, *(word_t*)and_ptr);
|
||||
lfb += 2;
|
||||
write16 (lfb, *(word_t*)xor_ptr);
|
||||
lfb += 2;
|
||||
#endif
|
||||
and_ptr += 2; xor_ptr += 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void s3drv_move_cursor (int x, int y)
|
||||
{
|
||||
int xoff = 0, yoff = 0;
|
||||
|
||||
x += S3DC.cursor_adjustment;
|
||||
if (x < 0)
|
||||
{
|
||||
xoff = (x < -63) ? 63 : -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
yoff = (y < -63) ? 63 : -y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
write_cr (S3DC.vga_base, 0x46, (x & 0xff00) >> 8);
|
||||
write_cr (S3DC.vga_base, 0x47, (x & 0xff));
|
||||
write_cr (S3DC.vga_base, 0x49, (y & 0xff));
|
||||
write_cr (S3DC.vga_base, 0x4e, (xoff));
|
||||
write_cr (S3DC.vga_base, 0x4f, (yoff));
|
||||
write_cr (S3DC.vga_base, 0x48, (y & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
void s3drv_show_cursor ()
|
||||
{
|
||||
write_cr (S3DC.vga_base, 0x45, read_cr (S3DC.vga_base, 0x45) | 1);
|
||||
}
|
||||
|
||||
void s3drv_hide_cursor ()
|
||||
{
|
||||
write_cr (S3DC.vga_base, 0x45, read_cr (S3DC.vga_base, 0x45) & ~1);
|
||||
}
|
||||
|
||||
void s3drv_set_palette (int index, int red, int green, int blue)
|
||||
{
|
||||
byte_t * vga_base = S3DC.vga_base;
|
||||
write8 (vga_base + 0x3c8, index);
|
||||
write8 (vga_base + 0x3c9, red);
|
||||
write8 (vga_base + 0x3c9, green);
|
||||
write8 (vga_base + 0x3c9, blue);
|
||||
}
|
||||
|
||||
void s3drv_get_palette (int index, int *red, int *green, int *blue)
|
||||
{
|
||||
byte_t * vga_base = S3DC.vga_base;
|
||||
write8 (vga_base + 0x3c7, index);
|
||||
*red = read8 (vga_base + 0x3c9);
|
||||
*green = read8 (vga_base + 0x3c9);
|
||||
*blue = read8 (vga_base + 0x3c9);
|
||||
}
|
||||
|
||||
int s3drv_save_mode (byte_t * mode_buf, int buf_size)
|
||||
{
|
||||
int i;
|
||||
byte_t * vga_base = S3DC.vga_base;
|
||||
SVGAMode * mode = (SVGAMode*)(mode_buf);
|
||||
|
||||
if (!mode_buf || buf_size < sizeof (SVGAMode))
|
||||
{
|
||||
return - sizeof (SVGAMode);
|
||||
}
|
||||
|
||||
s3drv_unlock_regs ();
|
||||
for (i = 0; i < 4; i ++) mode->seq_regs[i] = read_sr (vga_base, i+1);
|
||||
mode->misc_output = read8 (vga_base + 0x3cc);
|
||||
for (i = 0; i < 0x19; i ++) mode->crtc_regs[i] = read_cr (vga_base, i);
|
||||
for (i = 0; i < 0x14; i ++) mode->attr_regs[i] = read_ar (vga_base, i);
|
||||
for (i = 0; i < 0x09; i ++) mode->graph_regs[i] = read_gr (vga_base, i);
|
||||
mode->refresh_rate = 0xff;
|
||||
mode->sr12 = read_sr (vga_base, 0x12);
|
||||
mode->sr13 = read_sr (vga_base, 0x13);
|
||||
mode->sr29 = read_sr (vga_base, 0x29);
|
||||
mode->misc_ctrl = mode->misc_output & 0xc0;
|
||||
mode->cr43 = read_cr (vga_base, 0x43);
|
||||
mode->cr50 = read_cr (vga_base, 0x50);
|
||||
mode->cr51 = read_cr (vga_base, 0x51);
|
||||
mode->cr5d = read_cr (vga_base, 0x5d);
|
||||
mode->cr5e = read_cr (vga_base, 0x5e);
|
||||
mode->cr5f = read_cr (vga_base, 0x5f);
|
||||
mode->cr66 = read_cr (vga_base, 0x66);
|
||||
mode->cr67 = read_cr (vga_base, 0x67);
|
||||
mode->cr31 = read_cr (vga_base, 0x31);
|
||||
mode->cr58 = read_cr (vga_base, 0x58);
|
||||
mode->cr69 = read_cr (vga_base, 0x69);
|
||||
mode->pixel_width =
|
||||
( ( ((mode->cr5f & 0x0c) << 7) |
|
||||
((mode->cr5d & 0x02) << 7) |
|
||||
( mode->crtc_regs[1] ) ) + 1 ) * 8;
|
||||
mode->pixel_height = 1 +
|
||||
( ((mode->cr5e & 0x02) << 9) |
|
||||
((mode->crtc_regs[0x07] & 0x40) << 3) |
|
||||
((mode->crtc_regs[0x07] & 0x02) << 7) |
|
||||
( mode->crtc_regs[0x12] ) );
|
||||
|
||||
switch ( (mode->cr67 & 0xf0) >> 4)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
mode->pixel_size = (read_cr (vga_base, 0x3a) & 0x10) ? 8 : 4;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
mode->pixel_size = 15;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
mode->pixel_size = 16;
|
||||
break;
|
||||
case 0xd:
|
||||
mode->pixel_size = 32;
|
||||
break;
|
||||
default:
|
||||
mode->pixel_size = 8;
|
||||
}
|
||||
s3drv_lock_regs ();
|
||||
|
||||
return sizeof (SVGAMode);
|
||||
}
|
||||
|
||||
static word_t crtc_reg_defaults[] =
|
||||
{
|
||||
0x4838, 0xa539, 0x0531, 0x4032, 0x0833, 0x0034, 0x0035, 0x053a,
|
||||
0x103c, 0x0040, 0x0042, 0x0043, 0x0045, 0x0050, 0x0051, 0x0053,
|
||||
0x0055, 0x0058, 0x005d, 0x005e, 0x005f, 0x005b, 0x0066, 0x0067,
|
||||
0x0069, 0x006a, 0xc071, 0x0090,
|
||||
0x0087, 0x3070, 0xc071, 0x0772, 0x1f73, 0x1f74, 0x1f75, 0x0f76,
|
||||
0x1f77, 0x0178, 0x0179, 0x1f7a, 0x1f7b, 0x171c, 0x177d, 0x177e,
|
||||
0x0060,
|
||||
0x0000
|
||||
};
|
||||
|
||||
static word_t seq_reg_defaults[] =
|
||||
{
|
||||
0x0608, 0x0014, 0x4018, 0x0029, 0x601c,
|
||||
0x0000
|
||||
};
|
||||
|
||||
int s3drv_restore_mode (byte_t * mode_buf, int buf_size, int restore_vga)
|
||||
{
|
||||
int i;
|
||||
byte_t cr3a;
|
||||
byte_t * vga_base = S3DC.vga_base;
|
||||
SVGAMode * mode = (SVGAMode*)(mode_buf);
|
||||
if (!mode || buf_size < sizeof (SVGAMode))
|
||||
{
|
||||
return - sizeof (SVGAMode);
|
||||
}
|
||||
|
||||
if (mode->pixel_size) S3DC.bpp = mode->pixel_size;
|
||||
if (mode->pixel_width) S3DC.width = mode->pixel_width;
|
||||
if (mode->pixel_height) S3DC.height = mode->pixel_height;
|
||||
if (!S3DC.logical_width) S3DC.logical_width = mode->pixel_width;
|
||||
S3DC.display_start = 0;
|
||||
|
||||
s3drv_unlock_regs ();
|
||||
write_sr (vga_base, 0x01, read_sr (vga_base, 0x01) | 0x20);
|
||||
for (i = 0; crtc_reg_defaults[i] != 0; i ++)
|
||||
write16 (vga_base + CRTC_INDEX, crtc_reg_defaults[i]);
|
||||
for (i = 0; seq_reg_defaults[i] != 0; i ++)
|
||||
write16 (vga_base + SEQ_INDEX, seq_reg_defaults[i]);
|
||||
if (restore_vga > 0)
|
||||
{
|
||||
write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) & 0x7f);
|
||||
for (i = 1; i < 4; i ++)
|
||||
write_sr (vga_base, i+1, mode->seq_regs[i]);
|
||||
for (i = 0; i < 0x0c; i ++)
|
||||
write_cr (vga_base, i, mode->crtc_regs[i]);
|
||||
for (i = 0x10; i < 0x19; i ++)
|
||||
write_cr (vga_base, i, mode->crtc_regs[i]);
|
||||
for (i = 0; i < 0x14; i ++)
|
||||
write_ar (vga_base, i, mode->attr_regs[i]);
|
||||
for (i = 0; i < 0x09; i ++)
|
||||
write_gr (vga_base, i, mode->graph_regs[i]);
|
||||
}
|
||||
|
||||
write8 (vga_base + 0x3c2, 0x23);
|
||||
write_sr (vga_base, 0x15, (mode->misc_ctrl & 0x10) | 2);
|
||||
write8 (vga_base + 0x3c2,
|
||||
((mode->misc_output & 0x3f) |
|
||||
(mode->misc_ctrl & 0xc0)));
|
||||
if ((mode->misc_output & 0x0c) == 0x0c)
|
||||
{
|
||||
write_sr (vga_base, 0x12, mode->sr12);
|
||||
write_sr (vga_base, 0x13, mode->sr13);
|
||||
write_sr (vga_base, 0x29, mode->sr29);
|
||||
}
|
||||
|
||||
if (mode->refresh_rate != 0)
|
||||
{
|
||||
write_cr (vga_base, 0x43, mode->cr43);
|
||||
write_cr (vga_base, 0x50, mode->cr50);
|
||||
write_cr (vga_base, 0x51, mode->cr51);
|
||||
write_cr (vga_base, 0x5d, mode->cr5d);
|
||||
write_cr (vga_base, 0x5e, mode->cr5e);
|
||||
write_cr (vga_base, 0x5e, mode->cr5f);
|
||||
write_cr (vga_base, 0x66, mode->cr66);
|
||||
write_cr (vga_base, 0x67, mode->cr67);
|
||||
write_cr (vga_base, 0x31, mode->cr31);
|
||||
write_cr (vga_base, 0x58, mode->cr58);
|
||||
write_cr (vga_base, 0x69, mode->cr69);
|
||||
}
|
||||
|
||||
/* Turn off hardware graphics cursor */
|
||||
|
||||
write_cr (vga_base, 0x45, read_cr (vga_base, 0x45) & ~1);
|
||||
cr3a = read_cr (vga_base, 0x3a);
|
||||
|
||||
/* Set attribute controller for enhanced mode */
|
||||
if (mode->pixel_size < 8) cr3a &= ~0x10;
|
||||
else cr3a |= 0x10;
|
||||
write_cr (vga_base, 0x3a, cr3a);
|
||||
|
||||
/* RAMDAC mask */
|
||||
write8 (vga_base + 0x3c6, 0xff);
|
||||
|
||||
write_sr (vga_base, 0x01, mode->seq_regs[0]);
|
||||
s3drv_lock_regs ();
|
||||
|
||||
if (mode->cr66 & 1)
|
||||
{
|
||||
write32 (S3DC.mmio_base + 0x81c0, S3DC.display_start);
|
||||
write32 (S3DC.mmio_base + 0x81c8, /* set stride */
|
||||
(S3DC.logical_width * S3DC.bpp + 7) >> 3);
|
||||
write32 (S3DC.mmio_base + 0x8168, S3DC.display_start);
|
||||
/* Need to write GBD twice after an engine reset */
|
||||
if (S3DC.global_bd)
|
||||
{
|
||||
write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd);
|
||||
write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __S3DRV_H__
|
||||
#define __S3DRV_H__
|
||||
|
||||
|
||||
#include "datatype.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
word_t disp;
|
||||
word_t sync_start;
|
||||
word_t sync_end;
|
||||
word_t total;
|
||||
word_t polarity;
|
||||
} CrtcTiming;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dword_t dot_clock_khz;
|
||||
CrtcTiming x;
|
||||
CrtcTiming y;
|
||||
} PixelTiming;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte_t * mmio_base;
|
||||
byte_t * vga_base;
|
||||
byte_t * rom_base;
|
||||
byte_t * fb_base;
|
||||
word_t device_id;
|
||||
int fb_size;
|
||||
int vram_size;
|
||||
dword_t bpp;
|
||||
dword_t width;
|
||||
dword_t height;
|
||||
dword_t logical_width;
|
||||
dword_t display_start;
|
||||
dword_t global_bd;
|
||||
word_t viewport_x;
|
||||
word_t viewport_y;
|
||||
int cursor_adjustment;
|
||||
} S3DriverContext;
|
||||
|
||||
|
||||
extern void s3drv_dpf (const char * format, ...);
|
||||
extern S3DriverContext * s3drv_get_context ();
|
||||
extern int s3drv_init (byte_t * mmio_base);
|
||||
extern void s3drv_lock_regs ();
|
||||
extern void s3drv_unlock_regs ();
|
||||
extern int s3drv_detect_vram_mb_size (
|
||||
byte_t * vram_start, int max_mb);
|
||||
|
||||
extern int s3drv_is_text_mode ();
|
||||
extern int s3drv_save_font (
|
||||
byte_t * vram, byte_t * font_buf, int buf_size);
|
||||
extern int s3drv_restore_font (
|
||||
byte_t * vram, byte_t * font_buf, int buf_size);
|
||||
extern int s3drv_get_mode (
|
||||
PixelTiming * timing, int bpp,
|
||||
byte_t * mode_buf, int buf_size);
|
||||
#if 0
|
||||
extern int s3drv_get_gtf_mode (
|
||||
int width, int height, int depth,
|
||||
int rrate, byte_t * mode_buf,
|
||||
int buf_size);
|
||||
#endif
|
||||
extern int s3drv_get_bios_mode (
|
||||
int vesamode, int refresh_rate,
|
||||
byte_t * mode_buf, int buf_size,
|
||||
byte_t * rom);
|
||||
extern int s3drv_save_mode (
|
||||
byte_t * mode_buf, int buf_size);
|
||||
extern int s3drv_restore_mode (
|
||||
byte_t * mode_buf, int buf_size,
|
||||
int restore_vga);
|
||||
|
||||
extern int s3drv_display_is_off ();
|
||||
extern void s3drv_turn_display_off ();
|
||||
extern void s3drv_turn_display_on ();
|
||||
|
||||
extern int s3drv_set_logical_width (int width);
|
||||
extern int s3drv_adjust_viewport (int x, int y);
|
||||
extern int s3drv_set_display_start (int offset);
|
||||
|
||||
extern void s3drv_wait_for_vsync ();
|
||||
extern void s3drv_wait_for_idle ();
|
||||
|
||||
extern int s3drv_set_cursor_color (
|
||||
dword_t foreground, dword_t background);
|
||||
extern int s3drv_load_cursor (
|
||||
byte_t * lfb, int offset, int width, int height,
|
||||
byte_t * image, byte_t * mask);
|
||||
extern void s3drv_move_cursor (int x, int y);
|
||||
extern void s3drv_show_cursor ();
|
||||
extern void s3drv_hide_cursor ();
|
||||
|
||||
extern void s3drv_set_palette (
|
||||
int index, int red,
|
||||
int green, int blue);
|
||||
extern void s3drv_get_palette (
|
||||
int index, int *red,
|
||||
int *green, int *blue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __S3DRV_H__ */
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __S3MMIO_H__
|
||||
#define __S3MMIO_H__
|
||||
|
||||
#include "datatype.h"
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
|
||||
#undef __inline__
|
||||
#define __inline__
|
||||
#define read8(addr) (*(volatile byte_t*) (addr))
|
||||
#define read16(addr) (*(volatile word_t*) (addr))
|
||||
#define read32(addr) (*(volatile dword_t*) (addr))
|
||||
#define write8(addr, val) ((*(volatile byte_t*) (addr)) = (byte_t) (val))
|
||||
#define write16(addr, val) ((*(volatile word_t*) (addr)) = (word_t) (val))
|
||||
#define write32(addr, val) ((*(volatile dword_t*) (addr)) = (dword_t) (val))
|
||||
|
||||
#else
|
||||
|
||||
static __inline__ byte_t read8 (byte_t * addr)
|
||||
{
|
||||
return *(volatile byte_t*) addr;
|
||||
}
|
||||
|
||||
static __inline__ word_t read16 (byte_t * addr)
|
||||
{
|
||||
return *(volatile word_t*) addr;
|
||||
}
|
||||
|
||||
static __inline__ dword_t read32 (byte_t *addr)
|
||||
{
|
||||
return *(volatile dword_t*) addr;
|
||||
}
|
||||
|
||||
static __inline__ void write8 (byte_t * addr, byte_t val)
|
||||
{
|
||||
*(volatile byte_t*) addr = val;
|
||||
}
|
||||
|
||||
static __inline__ void write16 (byte_t * addr, word_t val)
|
||||
{
|
||||
*(volatile word_t*) addr = val;
|
||||
}
|
||||
|
||||
static __inline__ void write32 (byte_t * addr, dword_t val)
|
||||
{
|
||||
*(volatile dword_t*) addr = val;
|
||||
}
|
||||
|
||||
#endif /* __STRICT_ANSI__ */
|
||||
|
||||
|
||||
static __inline__ byte_t read_sr (byte_t * vga_base, byte_t reg)
|
||||
{
|
||||
write8 (vga_base + SEQ_INDEX, reg);
|
||||
return read8 (vga_base + SEQ_DATA);
|
||||
}
|
||||
|
||||
static __inline__ void write_sr (byte_t * vga_base, byte_t reg, byte_t val)
|
||||
{
|
||||
write16 (vga_base + SEQ_INDEX, (val << 8) | reg);
|
||||
}
|
||||
|
||||
static __inline__ byte_t read_cr (byte_t * vga_base, byte_t reg)
|
||||
{
|
||||
write8 (vga_base + CRTC_INDEX, reg);
|
||||
return read8 (vga_base + CRTC_DATA);
|
||||
}
|
||||
|
||||
static __inline__ void write_cr (byte_t * vga_base, byte_t reg, byte_t val)
|
||||
{
|
||||
write16 (vga_base + CRTC_INDEX, (val << 8) | reg);
|
||||
}
|
||||
|
||||
static __inline__ byte_t read_gr (byte_t * vga_base, byte_t reg)
|
||||
{
|
||||
write8 (vga_base + 0x3ce, reg);
|
||||
return read8 (vga_base + 0x3cf);
|
||||
}
|
||||
|
||||
static __inline__ void write_gr (byte_t * vga_base, byte_t reg, byte_t val)
|
||||
{
|
||||
write16 (vga_base + 0x3ce, (val << 8) | reg);
|
||||
}
|
||||
|
||||
static __inline__ byte_t read_ar (byte_t * vga_base, byte_t reg)
|
||||
{
|
||||
byte_t value, index;
|
||||
read8 (vga_base + 0x3da);
|
||||
index = read8 (vga_base + 0x3c0);
|
||||
write8 (vga_base + 0x3c0, reg);
|
||||
value = read8 (vga_base + 0x3c1);
|
||||
read8 (vga_base + 0x3da);
|
||||
write8 (vga_base + 0x3c0, index);
|
||||
return value;
|
||||
}
|
||||
|
||||
static __inline__ void write_ar (byte_t * vga_base, byte_t reg, byte_t val)
|
||||
{
|
||||
byte_t index;
|
||||
read8 (vga_base + 0x3da);
|
||||
index = read8 (vga_base + 0x3c0);
|
||||
write8 (vga_base + 0x3c0, reg);
|
||||
write8 (vga_base + 0x3c0, val);
|
||||
write8 (vga_base + 0x3c0, index);
|
||||
}
|
||||
|
||||
static __inline__ void s3_lock_regs (byte_t * vga_base)
|
||||
{
|
||||
write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) | 0x80);
|
||||
write_cr (vga_base, 0x33, (0x50 | read_cr (vga_base, 0x33)) & ~2);
|
||||
write_cr (vga_base, 0x38, 0x00);
|
||||
write_cr (vga_base, 0x39, 0x00);
|
||||
write_sr (vga_base, 0x08, 0x00);
|
||||
}
|
||||
|
||||
static __inline__ void s3_unlock_regs (byte_t * vga_base)
|
||||
{
|
||||
write_sr (vga_base, 0x08, 0x06);
|
||||
write_cr (vga_base, 0x38, 0x48);
|
||||
write_cr (vga_base, 0x39, 0xa0);
|
||||
write_cr (vga_base, 0x40, 0x01);
|
||||
write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) & 0x7f);
|
||||
write_cr (vga_base, 0x33, (~0x50 & read_cr (vga_base, 0x33)) | 2);
|
||||
write_cr (vga_base, 0x35, 0x00);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __S3MMIO_H__ */
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 1999 Erdi Chen
|
||||
*/
|
||||
|
||||
|
||||
#include "datatype.h"
|
||||
#include "s3drv.h"
|
||||
|
||||
#define BASE_FREQ 14.318
|
||||
|
||||
static int pll_limits[] =
|
||||
{
|
||||
1, 511, /* min M, max M */
|
||||
1, 127, /* min N, max N */
|
||||
0, 4, /* min R, max R */
|
||||
317500, 635000 /* min VCO, max VCO */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
word_t h_display_end;
|
||||
word_t h_sync_start;
|
||||
word_t h_sync_end;
|
||||
word_t h_total;
|
||||
word_t h_polarity;
|
||||
word_t v_display_end;
|
||||
word_t v_sync_start;
|
||||
word_t v_sync_end;
|
||||
word_t v_total;
|
||||
word_t v_polarity;
|
||||
word_t h_blank_start;
|
||||
word_t h_blank_end;
|
||||
word_t v_blank_start;
|
||||
word_t v_blank_end;
|
||||
} CharTiming;
|
||||
|
||||
|
||||
static int vga_convert_timing(int pixel_per_char,
|
||||
CharTiming * char_timing,
|
||||
PixelTiming * pixel_timing)
|
||||
{
|
||||
int i, blank_offset;
|
||||
char_timing->h_total = pixel_timing->x.total / pixel_per_char;
|
||||
char_timing->h_sync_start = pixel_timing->x.sync_start / pixel_per_char;
|
||||
char_timing->h_sync_end = pixel_timing->x.sync_end / pixel_per_char;
|
||||
char_timing->h_display_end = pixel_timing->x.disp / pixel_per_char;
|
||||
#if 0
|
||||
char_timing->h_blank_start = char_timing->h_display_end;
|
||||
char_timing->h_blank_end = char_timing->h_sync_end + 1;
|
||||
#else
|
||||
blank_offset = (pixel_timing->x.disp * 3 + 100) / 200;
|
||||
if (blank_offset < 2) blank_offset = 2;
|
||||
char_timing->h_blank_start = char_timing->h_display_end + blank_offset;
|
||||
char_timing->h_blank_end = char_timing->h_total - blank_offset;
|
||||
i = char_timing->h_blank_end - char_timing->h_blank_start - 127;
|
||||
if (i > 0)
|
||||
{
|
||||
char_timing->h_blank_start += (i + 1) / 2;
|
||||
char_timing->h_blank_end -= i / 2;
|
||||
}
|
||||
char_timing->h_blank_end ++;
|
||||
#endif
|
||||
char_timing->v_total = pixel_timing->y.total;
|
||||
char_timing->v_sync_start = pixel_timing->y.sync_start;
|
||||
char_timing->v_sync_end = pixel_timing->y.sync_end;
|
||||
char_timing->v_display_end = pixel_timing->y.disp;
|
||||
char_timing->v_blank_start = char_timing->v_display_end + 7;
|
||||
char_timing->v_blank_end = (char_timing->v_total + 7) - 0x10;
|
||||
|
||||
char_timing->h_polarity = (pixel_timing->x.polarity ? 1 : 0) << 6;
|
||||
char_timing->v_polarity = (pixel_timing->y.polarity ? 1 : 0) << 7;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vga_get_mode (VGAMode * vgamode,
|
||||
CharTiming * char_timing,
|
||||
PixelTiming * pixel_timing)
|
||||
{
|
||||
word_t line_compare;
|
||||
word_t double_scan;
|
||||
word_t row_width;
|
||||
word_t mem_addr_size;
|
||||
word_t pixel_per_addr;
|
||||
|
||||
if (!vgamode || !pixel_timing) return 0;
|
||||
|
||||
double_scan = 0;
|
||||
line_compare = 0x3ff;
|
||||
mem_addr_size = 4;
|
||||
pixel_per_addr = 1;
|
||||
row_width = 2 * pixel_timing->x.disp / (pixel_per_addr * mem_addr_size);
|
||||
|
||||
char_timing->h_total -= 5;
|
||||
char_timing->h_display_end --;
|
||||
char_timing->v_total -= 2;
|
||||
char_timing->v_display_end --;
|
||||
char_timing->v_sync_start --;
|
||||
char_timing->v_sync_end --;
|
||||
|
||||
vgamode->misc_output = 3 |
|
||||
(!char_timing->h_polarity) << 6 |
|
||||
(!char_timing->v_polarity) << 7;
|
||||
|
||||
vgamode->crtc_regs[0x00] = char_timing->h_total & 0xff;
|
||||
vgamode->crtc_regs[0x01] = char_timing->h_display_end & 0xff;
|
||||
vgamode->crtc_regs[0x02] = char_timing->h_blank_start & 0xff;
|
||||
vgamode->crtc_regs[0x03] = 0x80 | (char_timing->h_blank_end & 0x1f);
|
||||
vgamode->crtc_regs[0x04] = char_timing->h_sync_start & 0xff;
|
||||
vgamode->crtc_regs[0x05] = ((char_timing->h_blank_end & 0x20) << 2) |
|
||||
(char_timing->h_sync_end & 0x1f);
|
||||
vgamode->crtc_regs[0x06] = char_timing->v_total & 0xff;
|
||||
vgamode->crtc_regs[0x07] = ((char_timing->v_total & 0x100) >> 8) |
|
||||
((char_timing->v_display_end & 0x100) >> 7) |
|
||||
((char_timing->v_sync_start & 0x100) >> 6) |
|
||||
((char_timing->v_blank_start & 0x100) >> 5) |
|
||||
((line_compare & 0x100) >> 4) |
|
||||
((char_timing->v_total & 0x200) >> 4) |
|
||||
((char_timing->v_display_end & 0x200) >> 3) |
|
||||
((char_timing->v_sync_start & 0x200) >> 2);
|
||||
vgamode->crtc_regs[0x08] = 0;
|
||||
vgamode->crtc_regs[0x09] = (double_scan & 0x80) |
|
||||
((char_timing->v_blank_start & 0x200) >> 4) |
|
||||
((line_compare & 0x200) >> 3);
|
||||
vgamode->crtc_regs[0x2a] = 0;
|
||||
vgamode->crtc_regs[0x0b] = 0;
|
||||
vgamode->crtc_regs[0x0c] = 0;
|
||||
vgamode->crtc_regs[0x0d] = 0;
|
||||
vgamode->crtc_regs[0x0e] = 0xff;
|
||||
vgamode->crtc_regs[0x0f] = 0;
|
||||
vgamode->crtc_regs[0x10] = char_timing->v_sync_start & 0xff;
|
||||
vgamode->crtc_regs[0x11] = (char_timing->v_sync_end & 0x0f) | 0x80;
|
||||
vgamode->crtc_regs[0x12] = char_timing->v_display_end & 0xff;
|
||||
vgamode->crtc_regs[0x13] = row_width & 0xff;
|
||||
vgamode->crtc_regs[0x14] = ((mem_addr_size > 3) ? 0x60 : 0);
|
||||
vgamode->crtc_regs[0x15] = char_timing->v_blank_start & 0xff;
|
||||
vgamode->crtc_regs[0x16] = char_timing->v_blank_end & 0xff;
|
||||
vgamode->crtc_regs[0x17] = ((mem_addr_size == 1) ? 0x40 : 0x08) | 0xa3;
|
||||
vgamode->crtc_regs[0x18] = line_compare & 0xff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------
|
||||
* 1, 511, min M, max M
|
||||
* 1, 127, min N, max N
|
||||
* 0, 4, min R, max R
|
||||
* 317500, 635000 min VCO, max VCO
|
||||
* --------------------------------------------------------------*/
|
||||
void __s3drv_encode_clock (long freq, int * pll_limits,
|
||||
int * mdiv, int * ndiv, int * pll_r)
|
||||
{
|
||||
double ffreq, ffreq_min, ffreq_max;
|
||||
double div, diff, best_diff;
|
||||
int m;
|
||||
int n, r;
|
||||
int best_n = 16 + 2;
|
||||
int best_r = 2;
|
||||
int best_m = 125 + 2;
|
||||
|
||||
int min_m, max_m;
|
||||
int min_n, max_n;
|
||||
int min_r, max_r;
|
||||
long freq_min, freq_max;
|
||||
|
||||
min_m = pll_limits[0]; max_m = pll_limits[1];
|
||||
min_n = pll_limits[2]; max_n = pll_limits[3];
|
||||
min_r = pll_limits[4]; max_r = pll_limits[5];
|
||||
freq_min = pll_limits[6]; freq_max = pll_limits[7];
|
||||
|
||||
ffreq = freq / 1000.0 / BASE_FREQ;
|
||||
ffreq_min = freq_min / 1000.0 / BASE_FREQ;
|
||||
ffreq_max = freq_max / 1000.0 / BASE_FREQ;
|
||||
|
||||
if (ffreq < ffreq_min / (1<<max_r))
|
||||
{
|
||||
ffreq = ffreq_min / (1<<max_r);
|
||||
}
|
||||
|
||||
if (ffreq > ffreq_max / (1<<min_r))
|
||||
{
|
||||
ffreq = ffreq_max / (1 << min_r);
|
||||
}
|
||||
|
||||
best_diff = ffreq;
|
||||
|
||||
for (r = min_r; r <= max_r; r ++)
|
||||
{
|
||||
for (n = min_n + 2; n <= max_n + 2; n ++)
|
||||
{
|
||||
m = (int)(ffreq * n * (1 << r) + 0.5);
|
||||
if (m < min_m + 2 || m > max_m + 2)
|
||||
continue;
|
||||
div = (double)(m) / (double)(n);
|
||||
|
||||
if ((div >= ffreq_min) &&
|
||||
(div <= ffreq_max))
|
||||
{
|
||||
diff = ffreq - div / (1 << r);
|
||||
if (diff < 0.0)
|
||||
diff = -diff;
|
||||
if (diff < best_diff)
|
||||
{
|
||||
best_diff = diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
best_r = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ndiv = best_n - 2;
|
||||
*pll_r = best_r;
|
||||
*mdiv = best_m - 2;
|
||||
}
|
||||
|
||||
static void __s3drv_convert_clock (SVGAMode * svgamode, dword_t dot_clock_khz)
|
||||
{
|
||||
int m, n, r;
|
||||
|
||||
__s3drv_encode_clock (dot_clock_khz, & pll_limits[0], &m, &n, &r);
|
||||
svgamode->sr12 = (n & 0x3f) | ((r & 0x3) << 6);
|
||||
svgamode->sr13 = (m & 0xff);
|
||||
svgamode->sr29 = (r & 0x04) | ((m & 0x100) >> 5) | ((n & 0x40) >> 2);
|
||||
}
|
||||
|
||||
int __s3drv_get_svga_mode(SVGAMode * svgamode,
|
||||
PixelTiming * pixel_timing)
|
||||
{
|
||||
int blank_width, sync_width;
|
||||
dword_t dot_clock;
|
||||
CharTiming char_timing;
|
||||
|
||||
if (!svgamode || !pixel_timing) return 0;
|
||||
|
||||
vga_convert_timing (8, & char_timing, pixel_timing);
|
||||
vga_get_mode ((VGAMode*) svgamode, & char_timing, pixel_timing);
|
||||
svgamode->misc_output |= 0x0c;
|
||||
dot_clock = pixel_timing->dot_clock_khz;
|
||||
if (!dot_clock)
|
||||
{
|
||||
svgamode->refresh_rate = 60;
|
||||
dot_clock = pixel_timing->x.total * pixel_timing->y.total * 60 / 1000;
|
||||
}
|
||||
else
|
||||
svgamode->refresh_rate = dot_clock * 1000 /
|
||||
(pixel_timing->x.total * pixel_timing->y.total);
|
||||
__s3drv_convert_clock (svgamode, dot_clock);
|
||||
|
||||
blank_width = char_timing.h_blank_end - char_timing.h_blank_start;
|
||||
sync_width = char_timing.h_sync_end - char_timing.h_sync_start;
|
||||
svgamode->cr5d |= (char_timing.h_total & 0x100) >> 8 |
|
||||
(char_timing.h_display_end & 0x100) >> 7 |
|
||||
(char_timing.h_blank_start & 0x100) >> 6 |
|
||||
(char_timing.h_sync_start & 0x100) >> 4;
|
||||
if (blank_width > 32) svgamode->cr5d |= 0x20;
|
||||
if (sync_width > 64) svgamode->cr5d |= 0x04;
|
||||
|
||||
svgamode->cr5e = (char_timing.v_total & 0x400) >> 10 |
|
||||
(char_timing.v_display_end & 0x400) >> 9 |
|
||||
(char_timing.v_blank_start & 0x400) >> 8 |
|
||||
(char_timing.v_sync_start & 0x400) >> 6;
|
||||
|
||||
svgamode->cr5f |= (char_timing.h_total & 0x600) >> 9 |
|
||||
(char_timing.h_display_end & 0x600) >> 7 |
|
||||
(char_timing.h_blank_start & 0x600) >> 5 |
|
||||
(char_timing.h_sync_start & 0x600) >> 3;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -7,6 +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 tdfx ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vesa ;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
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 ;
|
||||
@@ -0,0 +1,27 @@
|
||||
This is a modified version of the XFree86 license.
|
||||
|
||||
The binary and source form of this software is covered by the
|
||||
following copyright/license.
|
||||
|
||||
Copyright (C) 1999 Erdi Chen. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user