782 lines
19 KiB
C
782 lines
19 KiB
C
/*
|
|
* ______ ____ ______ _____ ______
|
|
* | ____| | _ \| ____| / / _ \| ____|
|
|
* | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
|
|
* | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
|
|
* | | | | | __/ __/ |_) | |____ / / | | | | |
|
|
* |_| |_| \___|\___|____/|______/_/ |_| |_|_|
|
|
*
|
|
*
|
|
* S3 driver (based on the Allegro S3 code).
|
|
*
|
|
* By Shawn Hargreaves and Michael Bukin.
|
|
*
|
|
* Hardware acceleration by Michal Stencl.
|
|
*
|
|
* See freebe.txt for copyright information.
|
|
*/
|
|
|
|
|
|
// #define NO_HWPTR
|
|
|
|
|
|
#include <pc.h>
|
|
|
|
#include "../vbeaf.h"
|
|
|
|
|
|
|
|
/* driver function prototypes */
|
|
void SetBank32();
|
|
void SetBank32End();
|
|
int ExtStub();
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo);
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc);
|
|
void RestoreTextMode(AF_DRIVER *af);
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock);
|
|
void SaveRestoreState(AF_DRIVER *af, int subfunc, void *saveBuf);
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT);
|
|
void SetActiveBuffer(AF_DRIVER *af, long index);
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT);
|
|
int GetDisplayStartStatus(AF_DRIVER *af);
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT);
|
|
void SetBank(AF_DRIVER *af, long bank);
|
|
void BitBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op);
|
|
void BitBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
|
|
void WaitTillIdle(AF_DRIVER *af);
|
|
|
|
|
|
|
|
#define S86c911A 0x82
|
|
|
|
|
|
/* list which ports we are going to access (only needed under Linux) */
|
|
unsigned short ports_table[] = { 0xFFFF };
|
|
|
|
|
|
|
|
/* internal driver state variables */
|
|
int af_bpp;
|
|
int af_width;
|
|
int af_height;
|
|
int af_visible_page;
|
|
int af_active_page;
|
|
int af_scroll_x;
|
|
int af_scroll_y;
|
|
int af_bank;
|
|
int af_chipid;
|
|
|
|
|
|
/* FreeBE/AF extension allowing farptr access to video memory */
|
|
FAF_HWPTR_DATA hwptr;
|
|
|
|
|
|
|
|
/* list of available video modes */
|
|
typedef struct VIDEO_MODE
|
|
{
|
|
int w, h;
|
|
int bpp;
|
|
int num;
|
|
int bpl;
|
|
int redsize;
|
|
int redpos;
|
|
int greensize;
|
|
int greenpos;
|
|
int bluesize;
|
|
int bluepos;
|
|
int rsvdsize;
|
|
int rsvdpos;
|
|
} VIDEO_MODE;
|
|
|
|
|
|
VIDEO_MODE mode_list[] =
|
|
{
|
|
{ 640, 400, 8, 0x100, 640 },
|
|
{ 640, 480, 8, 0x101, 640 },
|
|
{ 800, 600, 8, 0x103, 800 },
|
|
{ 1024, 768, 8, 0x105, 1024 },
|
|
{ 1280, 1024, 8, 0x107, 1280 },
|
|
{ 640, 480, 15, 0x110, 1280,5,10,5,5,5,0,0,0},
|
|
{ 800, 600, 15, 0x113, 1600,5,10,5,5,5,0,0,0},
|
|
{ 1024, 768, 15, 0x116, 2048,5,10,5,5,5,0,0,0},
|
|
{ 1280, 1024, 15, 0x119, 2560,5,10,5,5,5,0,0,0},
|
|
{ 640, 480, 16, 0x111, 1024,5,11,6,5,5,0,0,0},
|
|
{ 800, 600, 16, 0x114, 1600,5,11,6,5,5,0,0,0},
|
|
{ 1024, 768, 16, 0x117, 2048,5,11,6,5,5,0,0,0},
|
|
{ 1280, 1024, 16, 0x11A, 2560,5,11,6,5,5,0,0,0},
|
|
{ 640, 480, 32, 0x112, 2048,8,16,8,8,8,0,0,0},
|
|
{ 800, 600, 32, 0x115, 3200,8,16,8,8,8,0,0,0},
|
|
{ 1024, 768, 32, 0x118, 4096,8,16,8,8,8,0,0,0}
|
|
};
|
|
|
|
|
|
#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
|
|
|
|
|
|
short available_modes[NUM_MODES+1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
|
13, 14, 15, 16, -1 };
|
|
|
|
|
|
|
|
void mod_vga_register_bits ( int reg, int m, int mask, int nwv )
|
|
{
|
|
int temp = (read_vga_register(reg,m) & (!mask))+(nwv & mask);
|
|
write_vga_register(reg, m, temp);
|
|
};
|
|
|
|
void set_vga_register_bits ( int reg, int m, int b )
|
|
{
|
|
int x = read_vga_register(reg,m);
|
|
write_vga_register(reg, m, x | b);
|
|
};
|
|
|
|
void clear_vga_register_bits ( int reg, int m, int b )
|
|
{
|
|
int x = read_vga_register(reg,m);
|
|
write_vga_register(reg, m, x & (!b));
|
|
};
|
|
|
|
void accelIT ( void )
|
|
{
|
|
write_vga_register(0x3D4, 0x38, 0x48);
|
|
write_vga_register(0x3D4, 0x39, 0xA5);
|
|
clear_vga_register_bits(0x3D4, 0x58, 0x14);
|
|
mod_vga_register_bits(0x3D4, 0x40, 9, 1);
|
|
clear_vga_register_bits(0x3D4, 0x53, 0xF);
|
|
write_vga_register(0x3D4, 0x54, 0xA0);
|
|
outportw(0xBEE8, 0xE000);
|
|
outportw(0xAAE8, 0xFFFF);
|
|
outportw(0xAEE8, 0xFFFF);
|
|
if ( af_bpp >= 24 ) {
|
|
outportw(0xBEE8, 0xE010);
|
|
outportw(0xAAE8, 0xFFFF);
|
|
outportw(0xAEE8, 0xFFFF);
|
|
};
|
|
};
|
|
|
|
|
|
void unaccelIT ( void )
|
|
{
|
|
write_vga_register(0x3D4, 0x38, 0x48); /* unlock cr38 */
|
|
write_vga_register(0x3D4, 0x39, 0xA5); /* unlock cr39 */
|
|
if ( read_vga_register(0x3D4, 0x40) )
|
|
do ; while ( inportw(0x9AE8) & 0x200 ); /* if graph. procesor is busy (9bit)*/
|
|
clear_vga_register_bits(0x3D4, 0x40, 1); /* not enhanced reg access */
|
|
set_vga_register_bits(0x3D4, 0x40, 8); /* enable fast write buffer (3bit) */
|
|
};
|
|
|
|
int readchipid ( void )
|
|
{
|
|
return read_vga_register(0x3d4, 0x30);
|
|
};
|
|
|
|
/* detect:
|
|
* Detects the presence of a S3 card.
|
|
*/
|
|
int detect()
|
|
{
|
|
int old;
|
|
int result = FALSE;
|
|
|
|
old = read_vga_register(0x3D4, 0x38);
|
|
write_vga_register(0x3D4, 0x38, 0); /* disable ext. */
|
|
if (!test_vga_register(0x3D4, 0x35, 0xF)) { /* test */
|
|
write_vga_register(0x3D4, 0x38, 0x48); /* enable ext. */
|
|
if (test_vga_register(0x3D4, 0x35, 0xF)) /* test again */
|
|
result = TRUE; /* found it */
|
|
af_chipid = readchipid();
|
|
}
|
|
|
|
write_vga_register(0x3D4, 0x38, old);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/* SetupDriver:
|
|
* Fills in our driver header block.
|
|
*/
|
|
int SetupDriver(AF_DRIVER *af)
|
|
{
|
|
int vram_size;
|
|
|
|
if (!detect())
|
|
return 1;
|
|
|
|
if (get_vesa_info(&vram_size, NULL, NULL) != 0)
|
|
return -1;
|
|
|
|
af->AvailableModes = available_modes;
|
|
|
|
af->TotalMemory = vram_size/1024;
|
|
|
|
af->Attributes = (afHaveMultiBuffer |
|
|
afHaveVirtualScroll |
|
|
afHaveAccel2D |
|
|
afHaveBankedBuffer);
|
|
|
|
af->BankSize = 64;
|
|
af->BankedBasePtr = 0xA0000;
|
|
|
|
af->IOPortsTable = ports_table;
|
|
|
|
af->SetBank32 = SetBank32;
|
|
af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
|
|
af->SupplementalExt = ExtStub;
|
|
af->GetVideoModeInfo = GetVideoModeInfo;
|
|
af->SetVideoMode = SetVideoMode;
|
|
af->RestoreTextMode = RestoreTextMode;
|
|
af->GetClosestPixelClock = GetClosestPixelClock;
|
|
af->SaveRestoreState = SaveRestoreState;
|
|
af->SetDisplayStart = SetDisplayStart;
|
|
af->SetActiveBuffer = SetActiveBuffer;
|
|
af->SetVisibleBuffer = SetVisibleBuffer;
|
|
af->GetDisplayStartStatus = GetDisplayStartStatus;
|
|
af->SetPaletteData = SetPaletteData;
|
|
af->SetBank = SetBank;
|
|
|
|
// af->WaitTillIdle = WaitTillIdle;
|
|
af->Set8x8MonoPattern = NULL;
|
|
af->DrawScan = NULL;
|
|
af->DrawPattScan = NULL;
|
|
af->DrawRect = NULL;
|
|
af->DrawPattRect = NULL;
|
|
af->DrawLine = NULL;
|
|
af->DrawTrap = NULL;
|
|
af->PutMonoImage = NULL;
|
|
af->BitBlt = BitBlt;
|
|
af->BitBltSys = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* InitDriver:
|
|
* The second thing to be called during the init process, after the
|
|
* application has mapped all the memory and I/O resources we need.
|
|
*/
|
|
int InitDriver(AF_DRIVER *af)
|
|
{
|
|
hwptr_init(hwptr.IOMemMaps[0], af->IOMemMaps[0]);
|
|
hwptr_init(hwptr.IOMemMaps[1], af->IOMemMaps[1]);
|
|
hwptr_init(hwptr.IOMemMaps[2], af->IOMemMaps[2]);
|
|
hwptr_init(hwptr.IOMemMaps[3], af->IOMemMaps[3]);
|
|
hwptr_init(hwptr.BankedMem, af->BankedMem);
|
|
hwptr_init(hwptr.LinearMem, af->LinearMem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* FreeBEX:
|
|
* Returns an interface structure for the requested FreeBE/AF extension.
|
|
*/
|
|
void *FreeBEX(AF_DRIVER *af, unsigned long id)
|
|
{
|
|
switch (id) {
|
|
|
|
#ifndef NO_HWPTR
|
|
|
|
case FAFEXT_HWPTR:
|
|
/* allow farptr access to video memory */
|
|
return &hwptr;
|
|
|
|
#endif
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ExtStub:
|
|
* Vendor-specific extension hook: we don't provide any.
|
|
*/
|
|
int ExtStub()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* GetVideoModeInfo:
|
|
* Retrieves information about this video mode, returning zero on success
|
|
* or -1 if the mode is invalid.
|
|
*/
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo)
|
|
{
|
|
VIDEO_MODE *info;
|
|
int i;
|
|
|
|
if ((mode <= 0) || (mode > NUM_MODES))
|
|
return -1;
|
|
|
|
info = &mode_list[mode-1];
|
|
|
|
for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
|
|
((char *)modeInfo)[i] = 0;
|
|
|
|
modeInfo->Attributes = (afHaveMultiBuffer |
|
|
afHaveVirtualScroll |
|
|
afHaveBankedBuffer);
|
|
|
|
modeInfo->XResolution = info->w;
|
|
modeInfo->YResolution = info->h;
|
|
modeInfo->BitsPerPixel = info->bpp;
|
|
|
|
modeInfo->MaxBuffers = (af->TotalMemory*1024) /
|
|
(info->w*info->h*BYTES_PER_PIXEL(info->bpp));
|
|
|
|
if (info->w > 1024) {
|
|
modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
|
|
modeInfo->MaxScanLineWidth = 2048;
|
|
}
|
|
else {
|
|
modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
|
|
modeInfo->MaxScanLineWidth = 1024;
|
|
}
|
|
|
|
modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
|
|
modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
|
|
|
|
modeInfo->RedMaskSize = info->redsize;
|
|
modeInfo->RedFieldPosition = info->redpos;
|
|
modeInfo->GreenMaskSize = info->greensize;
|
|
modeInfo->GreenFieldPosition = info->greenpos;
|
|
modeInfo->BlueMaskSize = info->bluesize;
|
|
modeInfo->BlueFieldPosition = info->bluepos;
|
|
modeInfo->RsvdMaskSize = info->rsvdsize;
|
|
modeInfo->RsvdFieldPosition = info->rsvdpos;
|
|
|
|
/* for linear video modes, fill in these variables: */
|
|
modeInfo->LinBytesPerScanLine = modeInfo->BytesPerScanLine;
|
|
modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
|
|
modeInfo->LinRedMaskSize = info->redsize;
|
|
modeInfo->LinRedFieldPosition = info->redpos;
|
|
modeInfo->LinGreenMaskSize = info->greensize;
|
|
modeInfo->LinGreenFieldPosition = info->greenpos;
|
|
modeInfo->LinBlueMaskSize = info->bluesize;
|
|
modeInfo->LinBlueFieldPosition = info->bluepos;
|
|
modeInfo->LinRsvdMaskSize = info->rsvdsize;
|
|
modeInfo->LinRsvdFieldPosition = info->rsvdpos;
|
|
|
|
modeInfo->MaxPixelClock = 135000000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* SetVideoMode:
|
|
* Sets the specified video mode, returning zero on success.
|
|
*/
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
|
|
{
|
|
int noclear = ((mode & 0x8000) != 0);
|
|
long available_vram;
|
|
long used_vram;
|
|
int pitch;
|
|
VIDEO_MODE *info;
|
|
RM_REGS r;
|
|
|
|
/* reject anything with hardware stereo or linear framebuffer */
|
|
if (mode & 0x4400)
|
|
return -1;
|
|
|
|
mode &= 0x3FF;
|
|
|
|
if ((mode <= 0) || (mode > NUM_MODES))
|
|
return -1;
|
|
|
|
info = &mode_list[mode-1];
|
|
|
|
/* call VESA to set the mode */
|
|
r.x.ax = 0x4F02;
|
|
r.x.bx = info->num;
|
|
if (noclear)
|
|
r.x.bx |= 0x8000;
|
|
rm_int(0x10, &r);
|
|
if (r.h.ah)
|
|
return -1;
|
|
|
|
|
|
if (virtualX*BYTES_PER_PIXEL(info->bpp) > info->bpl) {
|
|
r.x.ax = 0x4F06;
|
|
r.x.bx = 0;
|
|
r.x.cx = virtualX;
|
|
rm_int(0x10, &r);
|
|
if (r.h.ah)
|
|
return -1;
|
|
*bytesPerLine = r.x.bx;
|
|
}
|
|
else
|
|
*bytesPerLine = info->bpl;
|
|
|
|
pitch = ((*bytesPerLine)*8)/info->bpp;
|
|
/* write_vga_register(0x3D4, 0x13, pitch);*/
|
|
clear_vga_register_bits(0x3D4, 0x50, 193);
|
|
clear_vga_register_bits(0x3d4, 0x50, 48);
|
|
|
|
switch ( info->bpp ) {
|
|
case 16 : set_vga_register_bits(0x3D4, 0x50, 16); break;
|
|
case 24 : set_vga_register_bits(0x3D4, 0x50, 32); break;
|
|
case 32 : set_vga_register_bits(0x3D4, 0x50, 48); break;
|
|
};
|
|
|
|
switch ( pitch ) {
|
|
case 640 : set_vga_register_bits(0x3D4, 0x50, 64); break;
|
|
case 800 : set_vga_register_bits(0x3D4, 0x50, 128); break;
|
|
case 1152 : set_vga_register_bits(0x3D4, 0x50, 1); break;
|
|
case 1280 : set_vga_register_bits(0x3D4, 0x50, 129); break;
|
|
case 1600 : set_vga_register_bits(0x3D4, 0x50, 192); break;
|
|
};
|
|
|
|
/* adjust the virtual width for widescreen modes */
|
|
|
|
/* store info about the current mode */
|
|
af_bpp = info->bpp;
|
|
af_width = *bytesPerLine;
|
|
af_height = MAX(info->h, virtualY);
|
|
af_visible_page = 0;
|
|
af_active_page = 0;
|
|
af_scroll_x = 0;
|
|
af_scroll_y = 0;
|
|
af_bank = -1;
|
|
|
|
af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
|
|
af->BufferEndY = af_height-1;
|
|
af->OriginOffset = 0;
|
|
|
|
used_vram = af_width * af_height * numBuffers;
|
|
available_vram = af->TotalMemory*1024 ;
|
|
|
|
if (used_vram > available_vram)
|
|
return -1;
|
|
|
|
if (available_vram-used_vram >= af_width) {
|
|
af->OffscreenOffset = used_vram;
|
|
af->OffscreenStartY = af_height*numBuffers;
|
|
af->OffscreenEndY = available_vram/af_width-1;
|
|
}
|
|
else {
|
|
af->OffscreenOffset = 0;
|
|
af->OffscreenStartY = 0;
|
|
af->OffscreenEndY = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* RestoreTextMode:
|
|
* Returns to text mode, shutting down the accelerator hardware.
|
|
*/
|
|
void RestoreTextMode(AF_DRIVER *af)
|
|
{
|
|
RM_REGS r;
|
|
|
|
r.x.ax = 3;
|
|
rm_int(0x10, &r);
|
|
}
|
|
|
|
|
|
|
|
/* GetClosestPixelClock:
|
|
* I don't have a clue what this should return: it is used for the
|
|
* refresh rate control.
|
|
*/
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock)
|
|
{
|
|
/* ??? */
|
|
return 135000000;
|
|
}
|
|
|
|
|
|
|
|
/* SaveRestoreState:
|
|
* Stores the current driver status: not presently implemented.
|
|
*/
|
|
void SaveRestoreState(AF_DRIVER *af, int subfunc, void *saveBuf)
|
|
{
|
|
/* not implemented (not used by Allegro) */
|
|
}
|
|
|
|
|
|
|
|
/* SetDisplayStart:
|
|
* Hardware scrolling function. The waitVRT value may be one of:
|
|
*
|
|
* -1 = don't set hardware, just store values for next page flip to use
|
|
* 0 = set values and return immediately
|
|
* 1 = set values and wait for retrace
|
|
*/
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
|
|
{
|
|
if (waitVRT >= 0) {
|
|
long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
|
|
|
|
asm volatile ("cli");
|
|
|
|
if (waitVRT) {
|
|
do {
|
|
} while (inportb(0x3DA) & 1);
|
|
}
|
|
|
|
/* write high bits to S3-specific registers */
|
|
write_vga_register(0x3D4, 0x38, 0x48);
|
|
alter_vga_register(0x3D4, 0x31, 0x30, a>>14);
|
|
alter_vga_register(0x3D4, 0x51, 0x03, a>>20);
|
|
write_vga_register(0x3D4, 0x38, 0);
|
|
|
|
/* write to normal VGA address registers */
|
|
write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
|
|
write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
|
|
|
|
asm volatile ("sti");
|
|
|
|
if (waitVRT) {
|
|
do {
|
|
} while (!(inportb(0x3DA) & 8));
|
|
}
|
|
}
|
|
|
|
af_scroll_x = x;
|
|
af_scroll_y = y;
|
|
}
|
|
|
|
|
|
|
|
/* SetActiveBuffer:
|
|
* Sets which buffer is being drawn onto, for use in multi buffering
|
|
* systems (not used by Allegro).
|
|
*/
|
|
void SetActiveBuffer(AF_DRIVER *af, long index)
|
|
{
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY += af_active_page*af_height;
|
|
af->OffscreenEndY += af_active_page*af_height;
|
|
}
|
|
|
|
af_active_page = index;
|
|
|
|
af->OriginOffset = af_width*af_height*index;
|
|
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY -= af_active_page*af_height;
|
|
af->OffscreenEndY -= af_active_page*af_height;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SetVisibleBuffer:
|
|
* Sets which buffer is displayed on the screen, for use in multi buffering
|
|
* systems (not used by Allegro).
|
|
*/
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT)
|
|
{
|
|
af_visible_page = index;
|
|
|
|
SetDisplayStart(af, af_scroll_x, af_scroll_y, waitVRT);
|
|
}
|
|
|
|
|
|
|
|
/* GetDisplayStartStatus:
|
|
* Status poll for triple buffering. Not possible on the majority of
|
|
* present cards: this function is just a placeholder.
|
|
*/
|
|
int GetDisplayStartStatus(AF_DRIVER *af)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/* SetPaletteData:
|
|
* Palette setting routine.
|
|
*/
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT)
|
|
{
|
|
int i;
|
|
|
|
if (waitVRT) {
|
|
do {
|
|
} while (inportb(0x3DA) & 8);
|
|
|
|
do {
|
|
} while (!(inportb(0x3DA) & 8));
|
|
}
|
|
|
|
for (i=0; i<num; i++) {
|
|
outportb(0x3C8, index+i);
|
|
outportb(0x3C9, pal[i].red/4);
|
|
outportb(0x3C9, pal[i].green/4);
|
|
outportb(0x3C9, pal[i].blue/4);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SetBank32:
|
|
* Relocatable bank switch function, called with a bank number in %edx.
|
|
*/
|
|
|
|
asm ("
|
|
|
|
.globl _SetBank32, _SetBank32End
|
|
|
|
.align 4
|
|
_SetBank32:
|
|
pushl %ecx
|
|
pushl %edx
|
|
movl %edx, %ecx
|
|
movl $0x3D4, %edx
|
|
|
|
movb $0x38, %al /* enable extensions */
|
|
outb %al, %dx
|
|
incl %edx
|
|
movb $0x48, %al
|
|
outb %al, %dx
|
|
decl %edx
|
|
|
|
movb $0x31, %al /* read register 0x31 */
|
|
outb %al, %dx
|
|
incl %edx
|
|
inb %dx, %al
|
|
decl %edx
|
|
|
|
movb %al, %ah /* set bank write and vid mem > 256K flags */
|
|
movb $0x31, %al
|
|
outb %al, %dx
|
|
movb %ah, %al
|
|
orb $9, %al
|
|
incl %edx
|
|
outb %al, %dx
|
|
decl %edx
|
|
|
|
movb $0x35, %al /* read register 0x35 */
|
|
outb %al, %dx
|
|
incl %edx
|
|
inb %dx, %al
|
|
decl %edx
|
|
|
|
andb $0xF0, %al /* mix bits 0-3 of bank number */
|
|
movb %cl, %ch
|
|
andb $0x0F, %ch
|
|
orb %al, %ch
|
|
|
|
movb $0x35, %al /* write the bits 0-3 of bank number */
|
|
outb %al, %dx
|
|
incl %edx
|
|
movb %ch, %al
|
|
outb %al, %dx
|
|
decl %edx
|
|
|
|
movb $0x51, %al /* read register 0x51 */
|
|
outb %al, %dx
|
|
incl %edx
|
|
inb %dx, %al
|
|
decl %edx
|
|
|
|
andb $0xF3, %al /* mix bits 4-5 of bank number */
|
|
shrb $2, %cl
|
|
andb $0x0C, %cl
|
|
orb %al, %cl
|
|
|
|
movb $0x51, %al /* write the bits 4-5 of bank number */
|
|
outb %al, %dx
|
|
incl %edx
|
|
movb %cl, %al
|
|
outb %al, %dx
|
|
decl %edx
|
|
|
|
movb $0x38, %al /* disable extensions */
|
|
outb %al, %dx
|
|
incl %edx
|
|
xorb %al, %al
|
|
outb %al, %dx
|
|
decl %edx
|
|
|
|
popl %edx
|
|
popl %ecx
|
|
ret
|
|
|
|
_SetBank32End:
|
|
|
|
");
|
|
|
|
/* SetBank:
|
|
* C-callable bank switch function. This version simply chains to the
|
|
* relocatable SetBank32() above.
|
|
*/
|
|
void SetBank(AF_DRIVER *af, long bank)
|
|
{
|
|
asm (
|
|
" call _SetBank32 "
|
|
:
|
|
: "d" (bank)
|
|
);
|
|
|
|
af_bank = bank;
|
|
}
|
|
|
|
void WaitTillIdle(AF_DRIVER *af) {
|
|
unaccelIT();
|
|
};
|
|
|
|
|
|
/* BitBlt:
|
|
* Blits from one part of video memory to another, using the specified
|
|
* mix operation. This must correctly handle the case where the two
|
|
* regions overlap.
|
|
*/
|
|
void blitvram ( int srcx, int srcy, int dstx, int dsty, int dx, int dy, int dir )
|
|
{
|
|
do ; while ( inportb(0x9AE8) & 0xFF );
|
|
outportw(0xBAE8, 0x67);
|
|
outportw(0xBEE8, 0xA000);
|
|
outportw(0x86E8, srcx);
|
|
outportw(0x82E8, srcy);
|
|
outportw(0x8EE8, dstx);
|
|
outportw(0x8AE8, dsty);
|
|
|
|
outportw(0x96E8, dx-1);
|
|
outportw(0xBEE8, dy-1);
|
|
do ; while ( inportb(0x9AE8) & 0xFF ); /* 0xc013 = 14,15,7,0,2 bits set */
|
|
if ( dir ) outportw(0x9AE8, 0xC013); else outportw(0x9AE8, 0xC0F3);
|
|
/* 0xc0f3 = 14,15,8,5,1,0 bits set */
|
|
};
|
|
|
|
void copyvram ( int srcx, int srcy, int dstx, int dsty, int dx, int dy )
|
|
{
|
|
int dir = 0;
|
|
if ( dsty < srcy || ( srcy == dsty && dstx < srcx )) dir = 0;
|
|
else {
|
|
dir = 1;
|
|
srcx += dx-1;
|
|
srcy += dy-1;
|
|
dstx += dx-1;
|
|
dsty += dy-1;
|
|
};
|
|
accelIT();
|
|
blitvram(srcx, srcy, dstx, dsty, dx, dy, dir);
|
|
if ( af_bpp > 8 && af_chipid <= S86c911A )
|
|
blitvram(srcx+1024, srcy, dstx+1024, dsty, dx, dy, dir);
|
|
unaccelIT();
|
|
};
|
|
|
|
void BitBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op)
|
|
{
|
|
copyvram(left, top, dstLeft, dstTop, width, height);
|
|
};
|
|
|
|
|
|
|