FreeBE/avance/driver.c

878 lines
25 KiB
C
Raw Normal View History

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
* | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
* | | | | | __/ __/ |_) | |____ / / | | | | |
* |_| |_| \___|\___|____/|______/_/ |_| |_|_|
*
*
* Avance Logic driver file.
*
* See freebe.txt for copyright information.
*/
#include <pc.h>
#include "vbeaf.h"
/* driver function prototypes */
2024-05-29 20:11:25 +03:00
void SetBank32( );
void SetBank32End( );
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
void SetBank(AF_DRIVER *af, long bank);
void WaitTillIdle(AF_DRIVER *af);
void SetMix(AF_DRIVER *af, long foreMix, long backMix);
/* if you need some video memory for internal use by the accelerator
2024-05-29 20:11:25 +03:00
* code (for example storing pattern data), you can define this value to
2024-05-29 19:55:33 +03:00
* reserve room for yourself at the very end of the memory space, that
* the application will not be allowed to use.
*/
2024-05-29 20:11:25 +03:00
#define RESERVED_VRAM 0
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_linear;
int af_visible_page;
int af_active_page;
int af_scroll_x;
int af_scroll_y;
int af_bank;
int af_fore_mix;
int af_back_mix;
int af_lines_per_bank;
/* note about VBE/AF multiple page modes: the API supports any number of
* video memory pages, one of which is "active" (being drawn onto), while
* the other is visible on your monitor. Allegro doesn't actually use
* this functionality, so you may safely leave it out and just reject
* any mode set requests with a numBuffers value greater than one, but
2024-05-29 20:11:25 +03:00
* that might upset other VBE/AF applications if they depend on this
2024-05-29 19:55:33 +03:00
* functionality. To support multiple pages, you must offset all the
* hardware drawing operations so their coordinate system is relative
* to the active page. You must also maintain an offset from the start
* of vram to the start of the active page in the OriginOffset of the
2024-05-29 20:11:25 +03:00
* driver structure, and adjust the OffscreenStartY and OffscreenEndY
* values so they will refer to the same offscreen memory region regardless
* of the current accelerator coordinate system. This is all handled by the
* SetActiveBuffer() function below, so in practice you can simply add
2024-05-29 19:55:33 +03:00
* af_active_page*af_height onto the input Y coordinate of any accelerator
* drawing funcs, and multiple page modes should work correctly.
*/
2024-05-29 20:11:25 +03:00
#define ALG_NONE 0
#define ALG_2101 1
#define ALG_2201 2
#define ALG_2228 3
#define ALG_2301 4
2024-05-29 19:55:33 +03:00
#define ALG_UNKNOWN 5
int port_crtc = 0x3d4;
int port_attr = 0x3c0;
2024-05-29 20:11:25 +03:00
int port_seq = 0x3c4;
int port_grc = 0x3ce;
2024-05-29 19:55:33 +03:00
int alg_version = ALG_NONE, alg_vidmem = 0;
2024-05-29 20:11:25 +03:00
char *alg_name[6] = { "none", "ALG-2101", "ALG-2201",
"ALG-2228", "ALG-2301", "unknown" };
2024-05-29 19:55:33 +03:00
2024-05-29 20:11:25 +03:00
int alg_caps[6] = { 0,
afHaveMultiBuffer | afHaveBankedBuffer |
afHaveVirtualScroll /*| afHaveDualBuffers */,
afHaveMultiBuffer | afHaveBankedBuffer |
afHaveVirtualScroll /*| afHaveDualBuffers */,
afHaveMultiBuffer | afHaveBankedBuffer |
afHaveVirtualScroll /*| afHaveDualBuffers */,
afHaveMultiBuffer | afHaveBankedBuffer |
afHaveVirtualScroll /*| afHaveDualBuffers */,
0 };
2024-05-29 19:55:33 +03:00
struct mode_t {
int mode;
2024-05-29 20:11:25 +03:00
int w, h;
2024-05-29 19:55:33 +03:00
int bpp;
};
#define MAX_MODES 20
struct mode_t mode_list[] = {
/* mode width height bpp */
2024-05-29 20:11:25 +03:00
{ 0x28, 512, 512, 8 }, { 0x29, 640, 400, 8 }, { 0x2a, 640, 480, 8 },
{ 0x2c, 800, 600, 8 }, { 0x2e, 768, 1024, 8 }, { 0x31, 1024, 768, 8 },
{ 0x33, 1024, 1024, 8 }, { 0x37, 1280, 1024, 8 },
{ 0x40, 320, 200, 16 }, { 0x41, 512, 512, 16 }, { 0x42, 640, 400, 16 },
{ 0x43, 640, 480, 16 }, { 0x44, 800, 600, 16 }, { 0x45, 1024, 768, 16 },
{ 0x48, 640, 480, 24 }, { 0x49, 800, 600, 24 },
{ 0, 0, 0, 0 }
2024-05-29 19:55:33 +03:00
};
short available_modes[MAX_MODES] = { -1 };
2024-05-29 20:11:25 +03:00
static inline void clrinx(int pt, int inx, int val) {
write_vga_register(pt, inx, read_vga_register(pt, inx) & ~val);
2024-05-29 19:55:33 +03:00
}
2024-05-29 20:11:25 +03:00
static inline void setinx(int pt, int inx, int val) {
write_vga_register(pt, inx, read_vga_register(pt, inx) | val);
2024-05-29 19:55:33 +03:00
}
2024-05-29 20:11:25 +03:00
static inline void modinx(int pt, int inx, int mask, int nwv) {
write_vga_register(pt, inx,
(read_vga_register(pt, inx) & ~mask) | (nwv & mask));
2024-05-29 19:55:33 +03:00
}
/* detect_alg:
* Sees whether or not an Avance Logic graphics card is present,
* and if one is it attempts to identify it.
*/
2024-05-29 20:11:25 +03:00
int detect_alg( ) {
2024-05-29 19:55:33 +03:00
int old;
alg_version = ALG_NONE;
alg_vidmem = 0;
2024-05-29 20:11:25 +03:00
old = read_vga_register(port_crtc, 0x1a);
clrinx(port_crtc, 0x1a, 0x10);
if (!test_vga_register(port_crtc, 0x19, 0xcf)) {
setinx(port_crtc, 0x1a, 0x10);
if (test_vga_register(port_crtc, 0x19, 0xcf) &&
test_vga_register(port_crtc, 0x1a, 0x3f)) {
int tmp = read_vga_register(port_crtc, 0x1a) >> 6;
2024-05-29 19:55:33 +03:00
switch (tmp) {
2024-05-29 20:11:25 +03:00
case 3: alg_version = ALG_2101; break;
2024-05-29 19:55:33 +03:00
case 2:
2024-05-29 20:11:25 +03:00
if (read_vga_register(port_crtc, 0x1b) & 4)
2024-05-29 19:55:33 +03:00
alg_version = ALG_2228;
else
alg_version = ALG_2301;
break;
2024-05-29 20:11:25 +03:00
case 1: alg_version = ALG_2201;
default: alg_version = ALG_UNKNOWN;
2024-05-29 19:55:33 +03:00
}
2024-05-29 20:11:25 +03:00
alg_vidmem = 256 << (read_vga_register(port_crtc, 0x1e) & 3);
2024-05-29 19:55:33 +03:00
}
}
2024-05-29 20:11:25 +03:00
write_vga_register(port_crtc, 0x1a, old);
2024-05-29 19:55:33 +03:00
return alg_version;
}
/* create_available_mode_list:
* Scans the mode list checking memory requirements. Modes
* which pass the test go into the available_modes list.
*/
2024-05-29 20:11:25 +03:00
void create_available_mode_list( ) {
2024-05-29 19:55:33 +03:00
struct mode_t *mode;
short *current_mode_in_list = available_modes;
for (mode = mode_list; mode->mode; mode++)
2024-05-29 20:11:25 +03:00
if (mode->w * mode->h * BYTES_PER_PIXEL(mode->bpp) < alg_vidmem * 1024)
2024-05-29 19:55:33 +03:00
*current_mode_in_list++ = mode->mode;
*current_mode_in_list = -1;
}
/* SetupDriver:
* The first thing ever to be called after our code has been relocated.
* This is in charge of filling in the driver header with all the required
* information and function pointers. We do not yet have access to the
* video memory, so we can't talk directly to the card.
*/
2024-05-29 20:11:25 +03:00
int SetupDriver(AF_DRIVER *af) {
2024-05-29 19:55:33 +03:00
int i;
2024-05-29 20:11:25 +03:00
if (!detect_alg( )) return -1;
2024-05-29 19:55:33 +03:00
2024-05-29 20:11:25 +03:00
create_available_mode_list( );
2024-05-29 19:55:33 +03:00
/* pointer to a list of the available mode numbers, ended by -1 */
af->AvailableModes = available_modes;
/* amount of video memory in K */
af->TotalMemory = alg_vidmem;
/* driver attributes (see definitions in vbeaf.h) */
af->Attributes = alg_caps[alg_version];
2024-05-29 20:11:25 +03:00
#if 0
2024-05-29 19:55:33 +03:00
if (linear_addr)
af->Attributes |= afHaveLinearBuffer;
2024-05-29 20:11:25 +03:00
#endif
2024-05-29 19:55:33 +03:00
/* banked memory size and location: zero if not supported */
af->BankSize = 64;
af->BankedBasePtr = 0xA0000;
/* linear framebuffer size and location: zero if not supported */
af->LinearSize = 0;
af->LinearBasePtr = 0;
/* list which ports we are going to access (only needed under Linux) */
af->IOPortsTable = ports_table;
/* list physical memory regions that we need to access (zero for none) */
2024-05-29 20:11:25 +03:00
for (i = 0; i < 4; i++) {
2024-05-29 19:55:33 +03:00
af->IOMemoryBase[i] = 0;
af->IOMemoryLen[i] = 0;
}
/* driver state variables (initialised later during the mode set) */
af->BufferEndX = 0;
af->BufferEndY = 0;
af->OriginOffset = 0;
af->OffscreenOffset = 0;
af->OffscreenStartY = 0;
af->OffscreenEndY = 0;
/* relocatable bank switcher (not required by Allgero) */
af->SetBank32 = SetBank32;
af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
/* extension functions */
af->SupplementalExt = ExtStub;
/* device driver functions */
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->EnableStereoMode = NULL;
af->SetPaletteData = SetPaletteData;
af->SetGammaCorrectData = NULL;
af->SetBank = SetBank;
/* hardware cursor functions */
af->SetCursor = NULL;
af->SetCursorPos = NULL;
af->SetCursorColor = NULL;
af->ShowCursor = NULL;
/* wait until the accelerator hardware has finished drawing */
af->WaitTillIdle = WaitTillIdle;
/* on some cards the CPU cannot access the framebuffer while it is in
2024-05-29 20:11:25 +03:00
* hardware drawing mode. If this is the case, you should fill in these
* functions with routines to switch in and out of the accelerator mode.
2024-05-29 19:55:33 +03:00
* The application will call EnableDirectAccess() whenever it is about
2024-05-29 20:11:25 +03:00
* to write to the framebuffer directly, and DisableDirectAccess()
* before it calls any hardware drawing routines. If this arbitration is
2024-05-29 19:55:33 +03:00
* not required, leave these routines as NULL.
*/
af->EnableDirectAccess = NULL;
af->DisableDirectAccess = NULL;
/* sets the hardware drawing mode (solid, XOR, etc). Required. */
af->SetMix = SetMix;
/* pattern download functions. May be NULL if patterns not supported */
af->Set8x8MonoPattern = NULL;
af->Set8x8ColorPattern = NULL;
af->Use8x8ColorPattern = NULL;
/* not supported: not used by Allegro */
af->SetLineStipple = NULL;
af->SetLineStippleCount = NULL;
/* not supported. There really isn't much point in this function because
* a lot of hardware can't do clipping at all, and even when it can there
* are usually problems with very large or negative coordinates. This
* means that a software clip is still required, so you may as well
* ignore this routine.
*/
af->SetClipRect = NULL;
/* DrawScan() is required: patterned versions may be NULL */
af->DrawScan = NULL;
af->DrawPattScan = NULL;
af->DrawColorPattScan = NULL;
/* not supported: not used by Allegro */
af->DrawScanList = NULL;
af->DrawPattScanList = NULL;
af->DrawColorPattScanList = NULL;
/* rectangle filling: may be NULL */
af->DrawRect = NULL;
af->DrawPattRect = NULL;
af->DrawColorPattRect = NULL;
/* line drawing: may be NULL */
af->DrawLine = NULL;
/* not supported: not used by Allegro */
af->DrawStippleLine = NULL;
/* trapezoid filling: may be NULL */
af->DrawTrap = NULL;
/* not supported: not used by Allegro */
af->DrawTri = NULL;
af->DrawQuad = NULL;
/* monochrome character expansion: may be NULL */
af->PutMonoImage = NULL;
/* not supported: not used by Allegro */
af->PutMonoImageLin = NULL;
af->PutMonoImageBM = NULL;
/* opaque blitting: may be NULL */
af->BitBlt = NULL;
af->BitBltSys = NULL;
/* not supported: not used by Allegro */
af->BitBltLin = NULL;
af->BitBltBM = NULL;
/* masked blitting: may be NULL */
af->SrcTransBlt = NULL;
af->SrcTransBltSys = NULL;
/* not supported: not used by Allegro */
af->SrcTransBltLin = NULL;
af->SrcTransBltBM = NULL;
af->DstTransBlt = NULL;
af->DstTransBltSys = NULL;
af->DstTransBltLin = NULL;
af->DstTransBltBM = NULL;
af->StretchBlt = NULL;
af->StretchBltSys = NULL;
af->StretchBltLin = NULL;
af->StretchBltBM = NULL;
af->SrcTransStretchBlt = NULL;
af->SrcTransStretchBltSys = NULL;
af->SrcTransStretchBltLin = NULL;
af->SrcTransStretchBltBM = NULL;
af->DstTransStretchBlt = NULL;
af->DstTransStretchBltSys = NULL;
af->DstTransStretchBltLin = NULL;
af->DstTransStretchBltBM = NULL;
af->SetVideoInput = NULL;
af->SetVideoOutput = NULL;
af->StartVideoFrame = NULL;
af->EndVideoFrame = NULL;
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.
* This is in charge of finding the card, returning 0 on success or
* -1 to abort.
*/
2024-05-29 20:11:25 +03:00
int InitDriver(AF_DRIVER *af) {
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) {
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
}
/* findmode:
* Finds the given mode's entry in the mode list.
*/
2024-05-29 20:11:25 +03:00
struct mode_t *findmode(int mode) {
2024-05-29 19:55:33 +03:00
struct mode_t *ret;
for (ret = mode_list; ret->mode; ret++)
if (ret->mode == mode) return ret;
return NULL;
}
/* get_field_data:
* Fills in the mask size and position of each part of a pixel
* for the given colour depth.
*/
2024-05-29 20:11:25 +03:00
void get_field_data(int bpp, char *rm, char *rp, char *gm, char *gp, char *bm,
char *bp, char *xm, char *xp) {
2024-05-29 19:55:33 +03:00
int pos = 0;
2024-05-29 20:11:25 +03:00
#define FIELD(xxx, size) \
*xxx##p = pos; \
pos += (*xxx##m = size)
2024-05-29 19:55:33 +03:00
switch (bpp) {
case 15:
2024-05-29 20:11:25 +03:00
FIELD(b, 5);
FIELD(g, 5);
FIELD(r, 5);
FIELD(x, 1);
2024-05-29 19:55:33 +03:00
break;
case 16:
2024-05-29 20:11:25 +03:00
FIELD(b, 5);
FIELD(g, 6);
FIELD(r, 5);
FIELD(x, 0);
2024-05-29 19:55:33 +03:00
break;
case 24:
2024-05-29 20:11:25 +03:00
FIELD(b, 8);
FIELD(g, 8);
FIELD(r, 8);
FIELD(x, 0);
2024-05-29 19:55:33 +03:00
break;
case 32:
2024-05-29 20:11:25 +03:00
FIELD(b, 8);
FIELD(g, 8);
FIELD(r, 8);
FIELD(x, 8);
2024-05-29 19:55:33 +03:00
break;
default:
2024-05-29 20:11:25 +03:00
FIELD(b, 0);
FIELD(g, 0);
FIELD(r, 0);
FIELD(x, 0);
2024-05-29 19:55:33 +03:00
}
2024-05-29 20:11:25 +03:00
#undef FIELD
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) {
2024-05-29 19:55:33 +03:00
int i;
int bytes_per_scanline;
2024-05-29 20:11:25 +03:00
struct mode_t *info = findmode(mode);
2024-05-29 19:55:33 +03:00
if (!info) return -1;
/* clear the structure to zero */
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
/* copy data across from our stored list of mode attributes */
modeInfo->Attributes = alg_caps[alg_version];
modeInfo->XResolution = info->w;
modeInfo->YResolution = info->h;
modeInfo->BitsPerPixel = info->bpp;
bytes_per_scanline = info->w * BYTES_PER_PIXEL(info->bpp);
/* available pages of video memory */
2024-05-29 20:11:25 +03:00
modeInfo->MaxBuffers =
(alg_vidmem * 1024 - RESERVED_VRAM) / (bytes_per_scanline * info->h);
2024-05-29 19:55:33 +03:00
/* maximum virtual scanline length in both bytes and pixels. How wide
* this can go will very much depend on the card: 1024 is pretty safe
* on anything, but you will want to allow larger limits if the card
* is capable of them.
*/
modeInfo->MaxScanLineWidth = 1024;
2024-05-29 20:11:25 +03:00
modeInfo->MaxBytesPerScanLine =
modeInfo->MaxScanLineWidth * BYTES_PER_PIXEL(info->bpp);
2024-05-29 19:55:33 +03:00
/* for banked video modes, fill in these variables: */
modeInfo->BytesPerScanLine = bytes_per_scanline;
modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
2024-05-29 20:11:25 +03:00
get_field_data(info->bpp, &modeInfo->RedMaskSize,
&modeInfo->RedFieldPosition, &modeInfo->GreenMaskSize,
&modeInfo->GreenFieldPosition, &modeInfo->BlueMaskSize,
&modeInfo->BlueFieldPosition, &modeInfo->RsvdMaskSize,
&modeInfo->RsvdFieldPosition);
2024-05-29 19:55:33 +03:00
/* for linear video modes, fill in these variables: */
modeInfo->LinBytesPerScanLine = bytes_per_scanline;
modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
modeInfo->LinRedMaskSize = modeInfo->RedMaskSize;
modeInfo->LinRedFieldPosition = modeInfo->RedFieldPosition;
modeInfo->LinGreenMaskSize = modeInfo->GreenMaskSize;
modeInfo->LinGreenFieldPosition = modeInfo->GreenFieldPosition;
modeInfo->LinBlueMaskSize = modeInfo->BlueMaskSize;
modeInfo->LinBlueFieldPosition = modeInfo->BlueFieldPosition;
modeInfo->LinRsvdMaskSize = modeInfo->RsvdMaskSize;
modeInfo->LinRsvdFieldPosition = modeInfo->RsvdFieldPosition;
/* I'm not sure exactly what these should be: Allegro doesn't use them */
modeInfo->MaxPixelClock = 135000000;
modeInfo->VideoCapabilities = 0;
modeInfo->VideoMinXScale = 0;
modeInfo->VideoMinYScale = 0;
modeInfo->VideoMaxXScale = 0;
modeInfo->VideoMaxYScale = 0;
return 0;
}
/* setvstart:
* Sets the display start address.
*/
2024-05-29 20:11:25 +03:00
void setvstart(int x, int y) {
int addr = af_width * y + x * BYTES_PER_PIXEL(af_bpp);
2024-05-29 19:55:33 +03:00
int display, pixels;
2024-05-29 20:11:25 +03:00
if (read_vga_register(port_grc, 0x0c) & 0x10) {
2024-05-29 19:55:33 +03:00
display = addr >> 3;
pixels = addr & 7;
} else {
display = addr >> 2;
pixels = addr & 3;
}
2024-05-29 20:11:25 +03:00
write_vga_register(port_crtc, 0x20, (display >> 16) & 0x07);
write_vga_register(port_crtc, 0x0c, (display >> 8) & 0xff);
write_vga_register(port_crtc, 0x0d, display & 0xff);
2024-05-29 19:55:33 +03:00
}
/* SetVideoMode:
* Sets the specified video mode, returning zero on success.
*
* Possible flag bits that may be or'ed with the mode number:
*
* 0x8000 = don't clear video memory
* 0x4000 = enable linear framebuffer
* 0x2000 = enable multi buffering
* 0x1000 = enable virtual scrolling
* 0x0800 = use refresh rate control
* 0x0400 = use hardware stereo
*/
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
int linear = ((mode & 0x4000) != 0);
long available_vram;
long used_vram;
struct mode_t *info;
RM_REGS r;
int interlaced, word_mode, double_word_mode, _8maps, shift;
/* reject anything with hardware stereo */
2024-05-29 20:11:25 +03:00
if (mode & 0x400) return -1;
2024-05-29 19:55:33 +03:00
/* mask off the other flag bits */
mode &= 0x3FF;
2024-05-29 20:11:25 +03:00
info = findmode(mode);
2024-05-29 19:55:33 +03:00
if (!info) return -1;
/* reject the linear flag if the mode doesn't support it */
if (linear) return -1;
/* set the mode */
r.x.ax = info->mode;
2024-05-29 20:11:25 +03:00
rm_int(0x10, &r);
2024-05-29 19:55:33 +03:00
if (r.h.ah) return -1;
2024-05-29 20:11:25 +03:00
setinx(port_crtc, 0x1A, 0x10); /* enable extensions */
setinx(port_crtc, 0x19, 0x02); /* enable >256k */
setinx(port_grc, 0x0F, 0x04); /* enable separate R/W banks */
2024-05-29 19:55:33 +03:00
af_bpp = info->bpp;
/* get some information about the mode */
2024-05-29 20:11:25 +03:00
interlaced = read_vga_register(port_crtc, 0x19) & 1;
double_word_mode = !!(read_vga_register(port_crtc, 0x14) & 0x40);
word_mode = !(read_vga_register(port_crtc, 0x17) & 0x40);
_8maps = !!(read_vga_register(0x3ce, 0x0c) & 0x10);
2024-05-29 19:55:33 +03:00
/* calculate the shift factor for the scanline byte width */
shift = 0;
if (_8maps) shift++;
if (double_word_mode)
shift += 3;
else if (word_mode)
shift += 2;
else
shift++;
if (interlaced) shift--;
/* sort out the virtaul screen size */
2024-05-29 20:11:25 +03:00
af_width = MAX(info->w, virtualX) * BYTES_PER_PIXEL(af_bpp);
2024-05-29 19:55:33 +03:00
af_width = (((af_width - 1) >> shift) + 1) << shift;
/* test: force it to be power of two */
{
int i = 1;
while (i < af_width) i <<= 1;
af_width = i;
}
/* Set scanline width */
2024-05-29 20:11:25 +03:00
write_vga_register(port_crtc, 0x13, af_width >> shift);
2024-05-29 19:55:33 +03:00
/* could also write bit 8 to port_crtc:0x28 bit 8 */
2024-05-29 20:11:25 +03:00
af_height = MAX(info->h, virtualY);
2024-05-29 19:55:33 +03:00
af_linear = linear;
af_lines_per_bank = af->BankSize * 1024 / af_width;
af_visible_page = 0;
af_active_page = 0;
af_scroll_x = 0;
af_scroll_y = 0;
2024-05-29 20:11:25 +03:00
setvstart(af_scroll_x, af_scroll_y);
2024-05-29 19:55:33 +03:00
af_bank = 0;
/* return framebuffer dimensions to the application */
2024-05-29 20:11:25 +03:00
af->BufferEndX = af_width / BYTES_PER_PIXEL(af_bpp) - 1;
af->BufferEndY = af_height - 1;
2024-05-29 19:55:33 +03:00
af->OriginOffset = 0;
used_vram = af_width * af_height * numBuffers;
available_vram = af->TotalMemory * 1024 - RESERVED_VRAM;
if (used_vram > available_vram) return -1;
2024-05-29 20:11:25 +03:00
if (available_vram - used_vram >= af_width) {
2024-05-29 19:55:33 +03:00
af->OffscreenOffset = used_vram;
2024-05-29 20:11:25 +03:00
af->OffscreenStartY = af_height * numBuffers;
af->OffscreenEndY = available_vram / af_width - 1;
2024-05-29 19:55:33 +03:00
} else {
af->OffscreenOffset = 0;
af->OffscreenStartY = 0;
af->OffscreenEndY = 0;
}
af_fore_mix = AF_REPLACE_MIX;
af_back_mix = AF_FORE_MIX;
return 0;
}
/* 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) {
2024-05-29 19:55:33 +03:00
af_scroll_x = x;
af_scroll_y = y;
2024-05-29 20:11:25 +03:00
if (waitVRT >= 0) setvstart(x, y);
2024-05-29 19:55:33 +03:00
if (waitVRT == 1) {
2024-05-29 20:11:25 +03:00
while (inportb(0x3da) & 8)
;
while (!(inportb(0x3da) & 8))
;
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);
2024-05-29 19:55:33 +03:00
2024-05-29 20:11:25 +03:00
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
/* SetBank32:
* Relocatable bank switch function. This is called with a bank number in
2024-05-29 20:11:25 +03:00
* %edx. I'm not sure what registers it is allowed to clobber, so it is
2024-05-29 19:55:33 +03:00
* probably a good idea to save them all.
*
* This function may be copied anywhere within the address space of the
2024-05-29 20:11:25 +03:00
* calling program, so it must be 100% relocatable. That means that you
* must not refer to any internal variables of the /AF driver, because
2024-05-29 19:55:33 +03:00
* you know nothing about where in memory it will be located. Your only
* input is the bank number in %edx, and your only output should be
* changing the relevant hardware registers.
*
* If you are unable to provide a relocatable bank switcher of this type,
2024-05-29 20:11:25 +03:00
* remove this function (clear the SetBank32 pointer to NULL during the
* header init), and fill in the SetBank() routine below instead. Allegro
* only ever uses SetBank(), so there will be no problem with leaving this
* function out, but you may have problems running other VBE/AF
2024-05-29 19:55:33 +03:00
* applications if you don't provide it.
*/
asm ("
2024-05-29 20:11:25 +03:00
#
2024-05-29 19:55:33 +03:00
.globl _SetBank32, _SetBank32End
.align 4
_SetBank32:
pushal
andl $0x1F, %edx # Bank numbers are 5-bit
movl %edx, %eax
movl $0x3d6, %edx # 0x3d6 = read bank select port
outb %al, %dx
movl $0x3d7, %edx # 0x3d7 = r/w bank select port
outb %al, %dx
popal
ret
_SetBank32End:
2024-05-29 20:11:25 +03:00
#
2024-05-29 19:55:33 +03:00
");
/* SetBank:
* C-callable bank switch function. This version simply chains to the
* relocatable SetBank32() above. If you can't provide a relocatable
* function (because you need access to global variables or some part
* of the /AF driver structure), you should put the bank switch code
* here instead.
*/
void SetBank(AF_DRIVER *af, long bank)
{
2024-05-29 20:11:25 +03:00
asm(" call _SetBank32 " : : "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
}
/* WaitTillIdle:
* Delay until the hardware controller has finished drawing.
*/
void WaitTillIdle(AF_DRIVER *af)
{
2024-05-29 20:11:25 +03:00
#ifndef USE_ALTERNATIVE_IDLE_CHECK
while (inportb(0x82aa) & 0x0f)
;
#else
while (inportb(0x82ba) & 0x80)
;
#endif
2024-05-29 19:55:33 +03:00
}
/* SetMix:
* Specifies the pixel mix mode to be used for hardware drawing functions
* (not the blit routines: they take an explicit mix parameter). Both
* parameters should be one of the AF_mixModes enum defined in vbeaf.h.
*
* VBE/AF requires all drivers to support the REPLACE, AND, OR, XOR,
* and NOP foreground mix types, and a background mix of zero (same as
* the foreground) or NOP. This file implements all the required types,
* but Allegro only actually uses the REPLACE and XOR modes for scanline
* and rectangle fills, REPLACE mode for blitting and color pattern
* drawing, and either REPLACE or foreground REPLACE and background NOP
* for mono pattern drawing.
*
* If you want, you can set the afHaveROP2 bit in the mode attributes
* field and then implement all the AF_R2_* modes as well, but that isn't
* required by the spec, and Allegro never uses them.
*/
void SetMix(AF_DRIVER *af, long foreMix, long backMix)
{
2024-05-29 20:11:25 +03:00
af_fore_mix = foreMix;
2024-05-29 19:55:33 +03:00
2024-05-29 20:11:25 +03:00
if (backMix == AF_FORE_MIX)
af_back_mix = foreMix;
else
af_back_mix = backMix;
2024-05-29 19:55:33 +03:00
}