2024-05-29 19:55:33 +03:00
|
|
|
/*
|
2024-05-29 20:11:25 +03:00
|
|
|
* ______ ____ ______ _____ ______
|
2024-05-29 19:55:33 +03:00
|
|
|
* | ____| | _ \| ____| / / _ \| ____|
|
2024-05-29 20:11:25 +03:00
|
|
|
* | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
|
2024-05-29 19:55:33 +03:00
|
|
|
* | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
|
|
|
|
* | | | | | __/ __/ |_) | |____ / / | | | | |
|
|
|
|
* |_| |_| \___|\___|____/|______/_/ |_| |_|_|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Trident driver (based on the Allegro Trident code).
|
|
|
|
*
|
|
|
|
* By Shawn Hargreaves and Mark Habersack.
|
|
|
|
*
|
|
|
|
* See freebe.txt for copyright information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// #define NO_HWPTR
|
|
|
|
|
|
|
|
#include <pc.h>
|
|
|
|
|
|
|
|
#include "vbeaf.h"
|
|
|
|
|
|
|
|
/* chipset information */
|
|
|
|
int chip_id = 0;
|
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
char *descriptions[] = { "TVGA 8900CL/D", "TVGA 9000i", "TVGA 9200CXr",
|
|
|
|
"TVGA LCD9100B", "TVGA GUI9420", "TVGA LX8200",
|
|
|
|
"TVGA 9400CXi", "TVGA LCD9320", "Unknown",
|
|
|
|
"TVGA GUI9420", "TVGA GUI9660", "TVGA GUI9440",
|
|
|
|
"TVGA GUI9430", "TVGA 9000C" };
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
#define TV_LAST 13
|
2024-05-29 19:55:33 +03:00
|
|
|
|
|
|
|
/* driver function prototypes */
|
2024-05-29 20:11:25 +03:00
|
|
|
void DualSetBank32( );
|
|
|
|
void DualSetBank32End( );
|
2024-05-29 19:55:33 +03:00
|
|
|
void DualSetBank(AF_DRIVER *af, long bank);
|
2024-05-29 20:11:25 +03:00
|
|
|
void SingleSetBank32( );
|
|
|
|
void SingleSetBank32End( );
|
2024-05-29 19:55:33 +03:00
|
|
|
void SingleSetBank(AF_DRIVER *af, long bank);
|
2024-05-29 20:11:25 +03:00
|
|
|
int ExtStub( );
|
2024-05-29 19:55:33 +03:00
|
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo);
|
2024-05-29 20:11:25 +03:00
|
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
|
|
|
|
long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc);
|
2024-05-29 19:55:33 +03:00
|
|
|
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);
|
2024-05-29 20:11:25 +03:00
|
|
|
int GetDisplayStartStatus(AF_DRIVER *af);
|
|
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index,
|
|
|
|
long waitVRT);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/* FreeBE/AF extension allowing farptr access to video memory */
|
|
|
|
FAF_HWPTR_DATA hwptr;
|
|
|
|
|
|
|
|
/* list of available video modes */
|
2024-05-29 20:11:25 +03:00
|
|
|
typedef struct VIDEO_MODE {
|
|
|
|
int w, h;
|
|
|
|
int bpp;
|
|
|
|
int num;
|
2024-05-29 19:55:33 +03:00
|
|
|
} VIDEO_MODE;
|
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
VIDEO_MODE mode_list[] = { { 640, 400, 8, 0x5C },
|
|
|
|
{ 640, 480, 8, 0x5D },
|
|
|
|
{ 800, 600, 8, 0x5E },
|
|
|
|
{ 1024, 768, 8, 0x62 } };
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
#define NUM_MODES (int)(sizeof(mode_list) / sizeof(VIDEO_MODE))
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
short available_modes[NUM_MODES + 1] = { 1, 2, 3, 4, -1 };
|
2024-05-29 19:55:33 +03:00
|
|
|
|
|
|
|
/* detect:
|
|
|
|
* Detects the presence of a Trident card.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
char *detect(unsigned long *vidmem) {
|
|
|
|
int old1, old2, val;
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
old1 = read_vga_register(0x3C4, 0x0B);
|
|
|
|
write_vga_register(0x3C4, 0x0B, 0); /* force old mode registers */
|
|
|
|
chip_id = inportb(0x3C5); /* now we have the ID */
|
|
|
|
|
|
|
|
old2 = read_vga_register(0x3C4, 0x0E);
|
|
|
|
outportb(0x3C4 + 1, old2 ^ 0x55);
|
|
|
|
val = inportb(0x3C5);
|
|
|
|
outportb(0x3C5, old2);
|
|
|
|
|
|
|
|
if (((val ^ old2) & 0x0F) == 7) { /* if bit 2 is inverted... */
|
|
|
|
outportb(0x3C5, old2 ^ 2); /* we're dealing with Trident */
|
|
|
|
|
|
|
|
if (chip_id <= 2) /* don't like 8800 chips */
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
val = read_vga_register(0x3D4, 0x1F); /* determine the memory size */
|
|
|
|
switch (val & 3) {
|
|
|
|
case 0: *vidmem = 256; break;
|
|
|
|
case 1: *vidmem = 512; break;
|
|
|
|
case 2: *vidmem = 768; break;
|
|
|
|
case 3:
|
|
|
|
if ((chip_id >= 0x33) && (val & 4))
|
|
|
|
*vidmem = 2048;
|
|
|
|
else
|
|
|
|
*vidmem = 1024;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* provide user with a description of the chip s/he has */
|
|
|
|
if ((chip_id == 0x33) && (read_vga_register(0x3D4, 0x28) & 0x80))
|
|
|
|
/* is it TVGA 9000C */
|
|
|
|
name = descriptions[TV_LAST];
|
|
|
|
else if (chip_id >= 0x33)
|
|
|
|
name = descriptions[((chip_id & 0xF0) >> 4) - 3];
|
|
|
|
else {
|
|
|
|
switch (chip_id) {
|
|
|
|
case 3: name = "TR 8900B"; break;
|
|
|
|
case 4: name = "TVGA 8900C"; break;
|
|
|
|
case 0x13: name = "TVGA 8900C"; break;
|
|
|
|
case 0x23: name = "TR 9000"; break;
|
|
|
|
default: name = "Unknown"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_vga_register(0x3C4, 0x0B, old1);
|
|
|
|
return NULL;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SetupDriver:
|
|
|
|
* Fills in our driver header block.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
int SetupDriver(AF_DRIVER *af) {
|
|
|
|
char *name;
|
|
|
|
int i;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
name = detect(&af->TotalMemory);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
if (!name) return 1;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
i = 0;
|
|
|
|
while (af->OemVendorName[i]) i++;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->OemVendorName[i++] = ',';
|
|
|
|
af->OemVendorName[i++] = ' ';
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
while (*name) af->OemVendorName[i++] = *(name++);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->OemVendorName[i] = 0;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->AvailableModes = available_modes;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->Attributes =
|
|
|
|
(afHaveMultiBuffer | afHaveVirtualScroll | afHaveBankedBuffer);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->BankSize = 64;
|
|
|
|
af->BankedBasePtr = 0xA0000;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->IOPortsTable = ports_table;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
if (chip_id >= 0x33) {
|
|
|
|
af->SetBank = DualSetBank;
|
|
|
|
af->SetBank32 = DualSetBank32;
|
|
|
|
af->SetBank32Len = (long)DualSetBank32End - (long)DualSetBank32;
|
|
|
|
} else {
|
|
|
|
af->SetBank = SingleSetBank;
|
|
|
|
af->SetBank32 = SingleSetBank32;
|
|
|
|
af->SetBank32Len = (long)SingleSetBank32End - (long)SingleSetBank32;
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
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;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
return 0;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* InitDriver:
|
2024-05-29 20:11:25 +03:00
|
|
|
* The second thing to be called during the init process, after the
|
2024-05-29 19:55:33 +03:00
|
|
|
* application has mapped all the memory and I/O resources we need.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
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;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* FreeBEX:
|
|
|
|
* Returns an interface structure for the requested FreeBE/AF extension.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
void *FreeBEX(AF_DRIVER *af, unsigned long id) {
|
|
|
|
switch (id) {
|
|
|
|
#ifndef NO_HWPTR
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
case FAFEXT_HWPTR:
|
|
|
|
/* allow farptr access to video memory */
|
|
|
|
return &hwptr;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
#endif
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
default: return NULL;
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ExtStub:
|
|
|
|
* Vendor-specific extension hook: we don't provide any.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
int ExtStub( ) {
|
|
|
|
return 0;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* GetVideoModeInfo:
|
|
|
|
* Retrieves information about this video mode, returning zero on success
|
|
|
|
* or -1 if the mode is invalid.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo) {
|
|
|
|
VIDEO_MODE *info;
|
|
|
|
int i;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
if ((mode <= 0) || (mode > NUM_MODES)) return -1;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
info = &mode_list[mode - 1];
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
for (i = 0; i < (int)sizeof(AF_MODE_INFO); i++) ((char *)modeInfo)[i] = 0;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
modeInfo->Attributes =
|
|
|
|
(afHaveMultiBuffer | afHaveVirtualScroll | afHaveBankedBuffer);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
modeInfo->XResolution = info->w;
|
|
|
|
modeInfo->YResolution = info->h;
|
|
|
|
modeInfo->BitsPerPixel = info->bpp;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
modeInfo->MaxBuffers = (af->TotalMemory * 1024) /
|
|
|
|
(info->w * info->h * BYTES_PER_PIXEL(info->bpp));
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
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;
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
modeInfo->BytesPerScanLine = info->w * BYTES_PER_PIXEL(info->bpp);
|
|
|
|
modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
modeInfo->MaxPixelClock = 135000000;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
return 0;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SetVideoMode:
|
|
|
|
* Sets the specified video mode, returning zero on success.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
|
|
|
|
long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc) {
|
|
|
|
long available_vram;
|
|
|
|
long used_vram;
|
|
|
|
int width;
|
|
|
|
VIDEO_MODE *info;
|
|
|
|
RM_REGS r;
|
|
|
|
|
|
|
|
/* reject anything with hardware stereo, linear framebuffer, or noclear */
|
|
|
|
if (mode & 0xC400) return -1;
|
|
|
|
|
|
|
|
mode &= 0x3FF;
|
|
|
|
|
|
|
|
if ((mode <= 0) || (mode > NUM_MODES)) return -1;
|
|
|
|
|
|
|
|
info = &mode_list[mode - 1];
|
|
|
|
|
|
|
|
/* call BIOS to set the mode */
|
|
|
|
r.x.ax = info->num;
|
|
|
|
rm_int(0x10, &r);
|
|
|
|
|
|
|
|
/* adjust the virtual width for widescreen modes */
|
|
|
|
if (virtualX > info->w) {
|
|
|
|
if (virtualX > 1024) return -1;
|
|
|
|
|
|
|
|
*bytesPerLine = ((virtualX * BYTES_PER_PIXEL(info->bpp)) + 15) & 0xFFF0;
|
|
|
|
|
|
|
|
width = read_vga_register(0x3D4, 0x13);
|
|
|
|
write_vga_register(0x3D4, 0x13,
|
|
|
|
(width * (*bytesPerLine)) /
|
|
|
|
(info->w * BYTES_PER_PIXEL(info->bpp)));
|
|
|
|
} else
|
|
|
|
*bytesPerLine = info->w * BYTES_PER_PIXEL(info->bpp);
|
|
|
|
|
|
|
|
/* set up some hardware registers */
|
|
|
|
if (chip_id >= 0x33)
|
|
|
|
write_vga_register(0x3CE, 0x0F, 5); /* read/write banks */
|
|
|
|
else
|
|
|
|
read_vga_register(0x3C4, 0x0B); /* switch to new mode */
|
|
|
|
|
|
|
|
/* 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;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* RestoreTextMode:
|
|
|
|
* Returns to text mode, shutting down the accelerator hardware.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
void RestoreTextMode(AF_DRIVER *af) {
|
|
|
|
RM_REGS r;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
r.x.ax = 3;
|
|
|
|
rm_int(0x10, &r);
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* GetClosestPixelClock:
|
|
|
|
* I don't have a clue what this should return: it is used for the
|
|
|
|
* refresh rate control.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock) {
|
|
|
|
/* ??? */
|
|
|
|
return 135000000;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SaveRestoreState:
|
|
|
|
* Stores the current driver status: not presently implemented.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
void SaveRestoreState(AF_DRIVER *af, int subfunc, void *saveBuf) {
|
|
|
|
/* not implemented (not used by Allegro) */
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
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)) >>
|
|
|
|
2;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
asm volatile("cli");
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
if (waitVRT) {
|
|
|
|
do { } while (inportb(0x3DA) & 1); }
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
/* first set the standard CRT Start registers */
|
|
|
|
outportw(0x3D4, (a & 0xFF00) | 0x0C);
|
|
|
|
outportw(0x3D4, ((a & 0x00FF) << 8) | 0x0D);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
/* set bit 16 of the screen start address */
|
|
|
|
outportb(0x3D4, 0x1E);
|
|
|
|
outportb(0x3D5, (inportb(0x3D5) & 0xDF) | ((a & 0x10000) >> 11));
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
/* bits 17-19 of the start address: uses the 8900CL/D+ register */
|
|
|
|
outportb(0x3D4, 0x27);
|
|
|
|
outportb(0x3D5, (inportb(0x3D5) & 0xF8) | ((a & 0xE0000) >> 17));
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
/* set pel register */
|
|
|
|
if (waitVRT) {
|
|
|
|
do { } while (!(inportb(0x3DA) & 8)); }
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
write_vga_register(0x3C0, 0x33, x & 3);
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
asm volatile("sti");
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af_scroll_x = x;
|
|
|
|
af_scroll_y = y;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SetActiveBuffer:
|
|
|
|
* Sets which buffer is being drawn onto, for use in multi buffering
|
|
|
|
* systems (not used by Allegro).
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
void SetActiveBuffer(AF_DRIVER *af, long index) {
|
|
|
|
if (af->OffscreenOffset) {
|
|
|
|
af->OffscreenStartY += af_active_page * af_height;
|
|
|
|
af->OffscreenEndY += af_active_page * af_height;
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af_active_page = index;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af->OriginOffset = af_width * af_height * index;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
if (af->OffscreenOffset) {
|
|
|
|
af->OffscreenStartY -= af_active_page * af_height;
|
|
|
|
af->OffscreenEndY -= af_active_page * af_height;
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SetVisibleBuffer:
|
|
|
|
* Sets which buffer is displayed on the screen, for use in multi buffering
|
|
|
|
* systems (not used by Allegro).
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT) {
|
|
|
|
af_visible_page = index;
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
SetDisplayStart(af, af_scroll_x, af_scroll_y, waitVRT);
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* GetDisplayStartStatus:
|
|
|
|
* Status poll for triple buffering. Not possible on the majority of
|
|
|
|
* present cards: this function is just a placeholder.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
int GetDisplayStartStatus(AF_DRIVER *af) {
|
|
|
|
return 1;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SetPaletteData:
|
|
|
|
* Palette setting routine.
|
|
|
|
*/
|
2024-05-29 20:11:25 +03:00
|
|
|
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);
|
|
|
|
}
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* DualSetBank32:
|
|
|
|
* Relocatable bank switch function, called with a bank number in %edx.
|
|
|
|
*/
|
|
|
|
|
|
|
|
asm ("
|
|
|
|
|
|
|
|
.globl _DualSetBank32, _DualSetBank32End
|
|
|
|
|
|
|
|
.align 4
|
|
|
|
_DualSetBank32:
|
|
|
|
pushl %edx
|
|
|
|
pushl %eax
|
|
|
|
movl %edx, %eax
|
|
|
|
|
|
|
|
movl $0x3D8, %edx
|
|
|
|
outb %al, %dx
|
|
|
|
|
|
|
|
incl %edx
|
|
|
|
outb %al, %dx
|
|
|
|
|
|
|
|
popl %eax
|
|
|
|
popl %edx
|
|
|
|
ret
|
|
|
|
|
|
|
|
_DualSetBank32End:
|
|
|
|
|
|
|
|
");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* DualSetBank:
|
|
|
|
* C-callable bank switch function. This version simply chains to the
|
|
|
|
* relocatable DualSetBank32() above.
|
|
|
|
*/
|
|
|
|
void DualSetBank(AF_DRIVER *af, long bank)
|
|
|
|
{
|
2024-05-29 20:11:25 +03:00
|
|
|
asm(" call _DualSetBank32 " : : "d"(bank));
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af_bank = bank;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* SingleSetBank32:
|
|
|
|
* Relocatable bank switch function, called with a bank number in %edx.
|
|
|
|
*/
|
|
|
|
|
|
|
|
asm ("
|
|
|
|
|
|
|
|
.globl _SingleSetBank32, _SingleSetBank32End
|
|
|
|
|
|
|
|
.align 4
|
|
|
|
_SingleSetBank32:
|
|
|
|
pushl %edx
|
|
|
|
pushl %eax
|
|
|
|
movb %dl, %ah /* save bank into ah */
|
|
|
|
|
|
|
|
movl $0x3C4, %edx /* read port 3C4 register 0xE */
|
|
|
|
movb $0xE, %al
|
|
|
|
outb %al, %dx
|
|
|
|
incl %edx
|
|
|
|
inb %dx, %al
|
|
|
|
decl %edx
|
|
|
|
|
|
|
|
andb $0xF0, %al /* mask low four bits */
|
|
|
|
xorb $2, %ah /* xor bank number with 2 */
|
|
|
|
orb %al, %ah
|
|
|
|
|
|
|
|
movb $0xE, %al /* write to port 3C4 register 0xE */
|
|
|
|
outb %al, %dx
|
|
|
|
incl %edx
|
|
|
|
movb %ah, %al
|
|
|
|
outb %al, %dx
|
|
|
|
|
|
|
|
popl %eax
|
|
|
|
popl %edx
|
|
|
|
ret
|
|
|
|
|
|
|
|
_SingleSetBank32End:
|
|
|
|
|
|
|
|
");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* SingleSetBank:
|
|
|
|
* C-callable bank switch function. This version simply chains to the
|
|
|
|
* relocatable SingleSetBank32() above.
|
|
|
|
*/
|
|
|
|
void SingleSetBank(AF_DRIVER *af, long bank)
|
|
|
|
{
|
2024-05-29 20:11:25 +03:00
|
|
|
asm(" call _SingleSetBank32 " : : "d"(bank));
|
2024-05-29 19:55:33 +03:00
|
|
|
|
2024-05-29 20:11:25 +03:00
|
|
|
af_bank = bank;
|
2024-05-29 19:55:33 +03:00
|
|
|
}
|