2045 lines
80 KiB
C
2045 lines
80 KiB
C
/*
|
|
* ______ ____ ______ _____ ______
|
|
* | ____| | _ \| ____| / / _ \| ____|
|
|
* | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
|
|
* | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
|
|
* | | | | | __/ __/ |_) | |____ / / | | | | |
|
|
* |_| |_| \___|\___|____/|______/_/ |_| |_|_|
|
|
*
|
|
*
|
|
* Cirrus54xx (not 546x) driver
|
|
*
|
|
* See freebe.txt for copyright information.
|
|
*/
|
|
|
|
#include <pc.h>
|
|
|
|
#include "cirdefs.h"
|
|
#include "vbeaf.h"
|
|
|
|
/******************************************************************************/
|
|
/* If you are having trouble getting this driver to work, try uncommenting */
|
|
/* the line below to disable memory-mapped IO. Also, read NOTES.TXT. */
|
|
/******************************************************************************/
|
|
//#define DISABLE_MMIO
|
|
|
|
//#define NO_CACHE //the values in registers BitBLT doesn't changed won't be
|
|
//cached
|
|
|
|
/* 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 SetMix(AF_DRIVER *af, long foreMix, long backMix);
|
|
void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern);
|
|
void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern);
|
|
void Use8x8ColorPattern(AF_DRIVER *af, int index);
|
|
|
|
/* if you need some video memory for internal use by the accelerator
|
|
* code (for example storing pattern data), you can define this value to
|
|
* reserve room for yourself at the very end of the memory space, that
|
|
* the application will not be allowed to use.
|
|
*/
|
|
#define RESERVED_VRAM 2048
|
|
|
|
// last 256 bytes can be used by MMIO on 5429, so I reserve them for sure
|
|
|
|
#define MONOPATTSTART 1024
|
|
#define SOLIDPATTSTART 768
|
|
#define COLPATTSTART 512
|
|
#define CURSORSTART 2048
|
|
#define DISPLACEMENT 0x10000
|
|
#define CIRRUS_PCI_VENDOR_ID 0x1013
|
|
|
|
CIRRUS_DETECT detect_info[] = { { CLGD5426, 0x15, 0, "CLGD-5426", 0 },
|
|
{ CLGD5428, 0x18, 0, "CLGD-5428", 0 },
|
|
{ CLGD5429, 0x19, 0, "CLGD-5429", 1 },
|
|
{ CLGD5430, 0x32, 0xa0, "CLGD-5430", 2 },
|
|
{ CLGD5434, 0x31, 0xa4, "CLGD-5434", 3 },
|
|
{ CLGD5434E, 0x33, 0xa8, "CLGD-5434 rev E", 4 },
|
|
{ CLGD5436, 0x36, 0xac, "CLGD-5436", 5 },
|
|
{ CLGD5440, 0x32, 0xa0, "CLGD-5440",
|
|
2 }, // find by reading chip id register 0xb0
|
|
{ CLGD5446, 0x39, 0xb8, "CLGD-5446", 5 },
|
|
{ CLGD5480, 0x3a, 0xbc, "CLGD-5480", 6 },
|
|
{ CLGD7541, 0x41, 0x1204, "CLGD-7541", 7 },
|
|
{ CLGD7542, 0x43, 0x1200, "CLGD-7542", -1 },
|
|
{ CLGD7543, 0x42, 0x1202, "CLGD-7543", 7 },
|
|
{ CLGD7548, 0x44, 0x38, "CLGD-7548", -1 },
|
|
{ CLGD7555, 0x46, 0, "CLGD-7555", -1 },
|
|
{ CLGD7556, 0x47, 0, "CLGD-7556", -1 } };
|
|
|
|
/* list which ports we are going to access (only needed under Linux) */
|
|
unsigned short ports_table[] = { 0x3c0, 0x3c4, 0x3ce, 0x3d4, 0x3da, 0xFFFF };
|
|
|
|
typedef struct _GFX_MODE_INFO {
|
|
int w, h;
|
|
int bpp;
|
|
int bpl;
|
|
int num;
|
|
// int tweak; //index to height modifiing table (substract 1 to get real
|
|
// index)
|
|
} _GFX_MODE_INFO;
|
|
|
|
#define MAX_MODES 25
|
|
|
|
_GFX_MODE_INFO mode_list[] = { { 640, 400, 8, 640, 0x5E },
|
|
{ 640, 480, 8, 640, 0x5F },
|
|
{ 800, 600, 8, 800, 0x5C },
|
|
{ 1024, 768, 8, 1024, 0x60 },
|
|
{ 1280, 1024, 8, 1280, 0x6D },
|
|
{ 1600, 1200, 8, 1600, 0x78 },
|
|
{ 640, 480, 15, 1280, 0x66 },
|
|
{ 800, 600, 15, 1600, 0x67 },
|
|
{ 1024, 768, 15, 2048, 0x68 },
|
|
{ 1280, 1024, 15, 2560, 0x69 },
|
|
{ 320, 200, 16, 640, 0x6F },
|
|
{ 640, 480, 16, 1280, 0x64 },
|
|
{ 800, 600, 16, 1600, 0x65 },
|
|
{ 1024, 768, 16, 2048, 0x74 },
|
|
{ 1280, 1024, 16, 2560, 0x75 },
|
|
{ 320, 200, 24, 960, 0x70 },
|
|
{ 640, 480, 24, 2048, 0x71 },
|
|
{ 1280, 1024, 24, 3840, 0x77 },
|
|
{ 640, 480, 32, 2560, 0x76 },
|
|
{ 800, 600, 32, 3200, 0x72 },
|
|
{ 1024, 768, 32, 4096, 0x73 },
|
|
{ 1152, 870, 32, 4608, 0x79 },
|
|
{ 0, 0, 0, 0, 0 } };
|
|
|
|
int cir_maxpitch = 0;
|
|
int cir_useblt24 = 0;
|
|
int cir_useblt32 = 0;
|
|
int cir_offmono = 0; // linear address in VRAM where mono pattern starts
|
|
int cir_offscreen =
|
|
0; // linear address in VRAM where full pattern starts (solid fills)
|
|
int cir_offcolor = 0; // linear address in VRAM where color pattern starts
|
|
int cir_bpp = 0;
|
|
int cir_bltmode = 0;
|
|
int cir_bltrop = 0;
|
|
int cir_pixmode = 0;
|
|
int cir_maxheight = 0;
|
|
int cir_maxwidth = 0;
|
|
int mouse_fg = 0;
|
|
int cir_cursor_visible = 0;
|
|
|
|
/* old values (used for caching) */
|
|
int cir_fg = -1;
|
|
int cir_bg = -1;
|
|
int cir_trans = -1;
|
|
int cir_oldbltmode = -1;
|
|
int cir_oldbltrop = -1;
|
|
int cir_height = -1;
|
|
int cir_card = -1;
|
|
int need_wait = 0;
|
|
unsigned long linear_addr = 0;
|
|
|
|
short available_modes[MAX_MODES + 1] = { -1 };
|
|
short num_modes = -1;
|
|
|
|
/* internal driver state variables */
|
|
int af_bpp;
|
|
int af_bank;
|
|
int af_width;
|
|
int af_height;
|
|
int af_linear;
|
|
unsigned long af_mmio = 0;
|
|
int af_visible_page;
|
|
int af_active_page;
|
|
int af_last_bank;
|
|
int af_fore_mix;
|
|
int af_back_mix;
|
|
int af_memory;
|
|
|
|
/* 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.
|
|
*/
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT) {
|
|
long b = x * cir_bpp + (y + af_visible_page * af_height) * af_width;
|
|
long a = b >> 2;
|
|
long t;
|
|
|
|
af->WaitTillIdle(af);
|
|
|
|
DISABLE( );
|
|
if (waitVRT) { _vsync_out_h( ); }
|
|
/* write high bits to Cirrus 54xx registers */
|
|
t = (a >> 16) & 1; // bit 16
|
|
t += (a >> 15) & 12; /* funny format, uses bits 0, 2, and 3 */
|
|
alter_vga_register(_crtc, 0x1B, 0xD, t);
|
|
alter_vga_register(_crtc, 0x1D, 0x80, (a >> 11) & 0x80);
|
|
/* write to normal VGA address registers */
|
|
write_vga_register(_crtc, 0x0D, (a)&0xFF);
|
|
write_vga_register(_crtc, 0x0C, (a >> 8) & 0xFF);
|
|
|
|
ENABLE( );
|
|
/* write low 2 bits to VGA horizontal pan register */
|
|
_write_hpp(b & 3);
|
|
|
|
if (waitVRT) { _vsync_in( ); }
|
|
}
|
|
|
|
/* 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, 0, 0, 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;
|
|
}
|
|
|
|
AF_PALETTE af_pal[256];
|
|
|
|
/* 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)); }
|
|
|
|
outportb(0x3c8, index);
|
|
for (i = index; i < num + index; i++) {
|
|
af_pal[index + i] = pal[i];
|
|
outportb(0x3C9, pal[i].red / 4);
|
|
outportb(0x3C9, pal[i].green / 4);
|
|
outportb(0x3C9, pal[i].blue / 4);
|
|
}
|
|
if ((index >= mouse_fg && index + num < mouse_fg) || (index >= 0)) {
|
|
alter_vga_register(
|
|
0x3c4, 0x12, 3,
|
|
2); // index 12 - enable access to extended DAC palette entries
|
|
outportb(0x3c8, 0xf); // cursor foreground
|
|
outportb(0x3c9, af_pal[mouse_fg].red);
|
|
outportb(0x3c9, af_pal[mouse_fg].green);
|
|
outportb(0x3c9, af_pal[mouse_fg].blue);
|
|
outportb(0x3c8, 0); // cursor background
|
|
outportb(0x3c9, af_pal[0].red);
|
|
outportb(0x3c9, af_pal[0].green);
|
|
outportb(0x3c9, af_pal[0].blue);
|
|
alter_vga_register(
|
|
0x3c4, 0x12, 3,
|
|
0); // index 12 - enable access to extended DAC palette entries
|
|
}
|
|
}
|
|
|
|
/* SetBank32:
|
|
* Relocatable bank switch function. This is called with a bank number in
|
|
* %edx. I'm not sure what registers it is allowed to clobber, so it is
|
|
* probably a good idea to save them all.
|
|
*
|
|
* This function may be copied anywhere within the address space of the
|
|
* calling program, so it must be 100% relocatable. That means that you
|
|
* must not refer to any internal variables of the /AF driver, because
|
|
* 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,
|
|
* 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
|
|
* applications if you don't provide it.
|
|
*
|
|
*/
|
|
asm ("
|
|
|
|
.globl _SetBank32, _SetBank32End
|
|
|
|
.align 4
|
|
_SetBank32:
|
|
pushl %edx /* I have 16K bank gran, but driver probably */
|
|
movb %dl,%ah /* don't know about that, so I must multiply by 4 */
|
|
shlb $2,%ah
|
|
movl $0x3CE, %edx
|
|
movb $9, %al
|
|
outw %ax, %dx
|
|
popl %edx
|
|
ret
|
|
_SetBank32End:
|
|
|
|
");
|
|
|
|
/* 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)
|
|
{
|
|
asm("
|
|
movb %
|
|
% al,
|
|
% % ah shlb $2, % % ah movl $0x3CE, % % edx movb $9, % % al outw % % ax,
|
|
% %
|
|
dx "
|
|
::"a"(bank)
|
|
: "%dx");
|
|
af_bank = bank;
|
|
}
|
|
|
|
#ifdef NO_CACHE
|
|
#define SET_ROP_MODE(bltrop, bltmode) \
|
|
{ \
|
|
CIR_BLTROP(bltrop); \
|
|
CIR_BLTMODE(bltmode); \
|
|
}
|
|
|
|
#define SET_ROP_MODEMMIO(bltrop, bltmode) CIR_ROP_MODEMMIO(bltrop, bltmode);
|
|
|
|
#define SET_TRANS(color) CIR_TRANS(color)
|
|
|
|
#define SET_TRANSMMIO(color) CIR_TRANSMMIO(color)
|
|
|
|
#define SET_WIDTH_HEIGHT(width, height) \
|
|
{ \
|
|
CIR_WIDTH(width); \
|
|
CIR_HEIGHT(height); \
|
|
}
|
|
|
|
#define SET_FG8(fg) CIR_FORG8(fg)
|
|
#define SET_FG16(fg) CIR_FORG16(fg)
|
|
#define SET_FG24(fg) CIR_FORG24(fg)
|
|
#define SET_FG32(fg) CIR_FORG32(fg)
|
|
|
|
#define SET_BG8(bg) CIR_BACKG8(bg)
|
|
#define SET_BG16(bg) CIR_BACKG16(bg)
|
|
#define SET_BG24(bg) CIR_BACKG24(bg)
|
|
#define SET_BG32(bg) CIR_BACKG32(bg)
|
|
|
|
#define SET_FG8MMIO(fg) CIR_FORG8MMIO(fg)
|
|
#define SET_FG16MMIO(fg) CIR_FORG16MMIO(fg)
|
|
#define SET_FG24MMIO(fg) CIR_FORG24MMIO(fg)
|
|
#define SET_FG32MMIO(fg) CIR_FORG32MMIO(fg)
|
|
|
|
#define SET_BG8MMIO(bg) CIR_BACKG8MMIO(bg)
|
|
#define SET_BG16MMIO(bg) CIR_BACKG16MMIO(bg)
|
|
#define SET_BG24MMIO(bg) CIR_BACKG24MMIO(bg)
|
|
#define SET_BG32MMIO(bg) CIR_BACKG32MMIO(bg)
|
|
|
|
#else
|
|
|
|
#define SET_ROP_MODE(bltrop, bltmode) \
|
|
if (cir_oldbltrop != bltrop) { \
|
|
cir_oldbltrop = bltrop; \
|
|
CIR_BLTROP(cir_oldbltrop); \
|
|
} \
|
|
if (cir_oldbltmode != bltmode) { \
|
|
cir_oldbltmode = bltmode; \
|
|
CIR_BLTMODE(cir_oldbltmode); \
|
|
}
|
|
|
|
#define SET_ROP_MODEMMIO(bltrop, bltmode) \
|
|
if (cir_oldbltrop != bltrop) { \
|
|
if (cir_oldbltmode != bltmode) { \
|
|
cir_oldbltmode = bltmode; \
|
|
cir_oldbltrop = bltrop; \
|
|
CIR_ROP_MODEMMIO(bltrop, bltmode); \
|
|
} else { \
|
|
cir_oldbltrop = bltrop; \
|
|
CIR_BLTROPMMIO(bltrop); \
|
|
} \
|
|
} else if (cir_oldbltmode != bltmode) { \
|
|
cir_oldbltmode = bltmode; \
|
|
CIR_BLTMODEMMIO(bltmode); \
|
|
}
|
|
|
|
#define SET_FG8(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG8(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG16(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG16(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG24(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG24(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG32(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG32(cir_fg); \
|
|
}
|
|
|
|
#define SET_BG8(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG8(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG16(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG16(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG24(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG24(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG32(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG32(cir_bg); \
|
|
}
|
|
|
|
#define SET_FG8MMIO(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG8(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG16MMIO(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG16(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG24MMIO(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG24(cir_fg); \
|
|
}
|
|
|
|
#define SET_FG32MMIO(color) \
|
|
if (cir_fg != color) { \
|
|
cir_fg = color; \
|
|
CIR_FORG32(cir_fg); \
|
|
}
|
|
|
|
#define SET_BG8MMIO(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG8(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG16MMIO(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG16(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG24MMIO(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG24(cir_bg); \
|
|
}
|
|
|
|
#define SET_BG32MMIO(color) \
|
|
if (cir_bg != color) { \
|
|
cir_bg = color; \
|
|
CIR_BACKG32(cir_bg); \
|
|
}
|
|
|
|
#define SET_TRANS(color) \
|
|
if (cir_trans != (color)) { \
|
|
cir_trans = color; \
|
|
CIR_TRANS(cir_trans); \
|
|
}
|
|
|
|
#define SET_TRANSMMIO(color) \
|
|
if (cir_trans != (color)) { \
|
|
cir_trans = color; \
|
|
CIR_TRANSMMIO(cir_trans); \
|
|
}
|
|
|
|
#define SET_WIDTH_HEIGHT(width, height) \
|
|
{ \
|
|
CIR_HEIGHT(height); \
|
|
CIR_WIDTH(width); \
|
|
}
|
|
|
|
/*
|
|
//doesn't work on 7543 but should on 5426-9
|
|
#define SET_HEIGHT(height) if (cir_height!=height){ \
|
|
cir_height=height; \
|
|
CIR_HEIGHT(height); \
|
|
}
|
|
*/
|
|
|
|
#endif
|
|
|
|
inline void waitidle()
|
|
{
|
|
if (need_wait) {
|
|
outportb(GRX, 0x31);
|
|
while (inportb(GRX + 1) & 1)
|
|
;
|
|
need_wait = 0;
|
|
}
|
|
}
|
|
|
|
inline void waitidleMMIO()
|
|
{
|
|
if (need_wait) {
|
|
while (inmb(0x40) & 1)
|
|
;
|
|
need_wait = 0;
|
|
}
|
|
}
|
|
|
|
/* WaitTillIdle:
|
|
* Delay until the hardware controller has finished drawing.
|
|
*/
|
|
|
|
#define WaitMacro(bpp) \
|
|
void WaitTillIdle##bpp##(AF_DRIVER * af) { \
|
|
if (need_wait) { \
|
|
outportb(GRX, 0x31); \
|
|
while (inportb(GRX + 1) & 1) \
|
|
; \
|
|
need_wait = 0; \
|
|
} \
|
|
SET_FG##bpp##(0); \
|
|
}
|
|
|
|
WaitMacro(8)
|
|
WaitMacro(16)
|
|
WaitMacro(24)
|
|
WaitMacro(32)
|
|
|
|
#define WaitMacroMMIO(bpp) \
|
|
void WaitTillIdle##bpp##MMIO(AF_DRIVER *af) { \
|
|
if (need_wait) { \
|
|
while (inmb(0x40) & 1) \
|
|
; \
|
|
need_wait = 0; \
|
|
} \
|
|
SET_FG##bpp##MMIO(0); \
|
|
}
|
|
|
|
WaitMacroMMIO(8)
|
|
WaitMacroMMIO(16)
|
|
WaitMacroMMIO(24)
|
|
WaitMacroMMIO(32)
|
|
|
|
|
|
int af_mix_fore(int mix)
|
|
{
|
|
switch (mix) {
|
|
case AF_REPLACE_MIX: return CIR_ROP_COPY;
|
|
case AF_AND_MIX: return CIR_ROP_AND;
|
|
case AF_XOR_MIX: return CIR_ROP_XOR;
|
|
case AF_OR_MIX: return CIR_ROP_OR;
|
|
case AF_NOP_MIX: return CIR_ROP_NOP;
|
|
default: return CIR_ROP_NOP;
|
|
}
|
|
}
|
|
|
|
/* 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 both 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 mix types. 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)
|
|
{
|
|
af_fore_mix = foreMix;
|
|
cir_bltrop = af_mix_fore(foreMix);
|
|
if (backMix == AF_FORE_MIX)
|
|
af_back_mix = foreMix;
|
|
else
|
|
af_back_mix = backMix;
|
|
if (backMix == AF_NOP_MIX) // transparent
|
|
cir_bltmode =
|
|
CIR_BLT_TRANS | CIR_BLT_PATT | CIR_BLT_COLEXP | cir_pixmode;
|
|
else
|
|
cir_bltmode = CIR_BLT_PATT | CIR_BLT_COLEXP | cir_pixmode;
|
|
}
|
|
|
|
|
|
inline unsigned char rolb(unsigned char x, unsigned char count)
|
|
{
|
|
asm volatile("rolb %%cl,%b2" : "=a"(x) : "c"(count), "r"(x));
|
|
return x;
|
|
}
|
|
|
|
unsigned char mono_pattern[16];
|
|
/* stored color pattern data */
|
|
unsigned long color_pattern[8][64];
|
|
unsigned long *current_color_pattern = color_pattern[0];
|
|
|
|
int last_mono_x,last_mono_y;
|
|
int last_color_x,last_color_y;
|
|
|
|
#define copymonomacro(mmio, bpp) \
|
|
void copymonopattern##bpp####mmio##(AF_DRIVER * af, int x, int y) { \
|
|
int i; \
|
|
unsigned char *p; \
|
|
\
|
|
SET_FG##bpp####mmio##(0); \
|
|
if ((last_mono_y != (y & 7)) || (last_mono_x != (x & 7))) { \
|
|
last_mono_y = y & 7; \
|
|
last_mono_x = x & 7; \
|
|
if (af_linear) { \
|
|
p = af->LinearMem + af_memory - MONOPATTSTART; \
|
|
for (i = 0; i < 8; i++) \
|
|
p[i] = rolb(mono_pattern[i + last_mono_y], last_mono_x); \
|
|
} else { \
|
|
p = af->BankedMem + DISPLACEMENT - MONOPATTSTART; \
|
|
SetBank(af, af_last_bank); \
|
|
for (i = 0; i < 8; i++) \
|
|
p[i] = rolb(mono_pattern[i + last_mono_y], last_mono_x); \
|
|
cir_bltmode |= CIR_BLT_COLEXP; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
copymonomacro(,8)
|
|
copymonomacro(,16)
|
|
copymonomacro(,24)
|
|
copymonomacro(,32)
|
|
|
|
copymonomacro(MMIO,8)
|
|
copymonomacro(MMIO,16)
|
|
copymonomacro(MMIO,24)
|
|
copymonomacro(MMIO,32)
|
|
|
|
#define copycolormacro(mmio, bpp) \
|
|
void copycolorpattern##bpp####mmio##(AF_DRIVER * af, int x, int y) { \
|
|
int i, j; \
|
|
\
|
|
SET_FG##bpp####mmio##(0); \
|
|
if ((last_color_y != (y & 7)) || (last_color_x != (x & 7))) { \
|
|
last_color_y = y & 7; \
|
|
last_color_x = x & 7; \
|
|
switch (bpp) { \
|
|
case 8: \
|
|
if (af_linear) { \
|
|
unsigned char *p = \
|
|
af->LinearMem + af_memory - COLPATTSTART; \
|
|
\
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} else { \
|
|
unsigned char *p = \
|
|
af->BankedMem + DISPLACEMENT - COLPATTSTART; \
|
|
\
|
|
SetBank(af, af_last_bank); \
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} \
|
|
case 15: \
|
|
case 16: \
|
|
if (af_linear) { \
|
|
unsigned short *p = \
|
|
af->LinearMem + af_memory - COLPATTSTART; \
|
|
\
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} else { \
|
|
unsigned short *p = \
|
|
af->BankedMem + DISPLACEMENT - COLPATTSTART; \
|
|
\
|
|
SetBank(af, af_last_bank); \
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} \
|
|
case 24: \
|
|
if (af_linear) { \
|
|
unsigned char *p = \
|
|
af->LinearMem + af_memory - COLPATTSTART; \
|
|
\
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
*((unsigned long *)(((unsigned char *)p) + \
|
|
(i * 8 + j) * 3)) = \
|
|
current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} else { \
|
|
unsigned char *p = \
|
|
af->BankedMem + DISPLACEMENT - COLPATTSTART; \
|
|
\
|
|
SetBank(af, af_last_bank); \
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
*((unsigned long *)(((unsigned char *)p) + \
|
|
(i * 8 + j) * 3)) = \
|
|
current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} \
|
|
case 32: \
|
|
if (af_linear) { \
|
|
unsigned long *p = \
|
|
af->LinearMem + af_memory - COLPATTSTART; \
|
|
\
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} else { \
|
|
unsigned long *p = \
|
|
af->BankedMem + DISPLACEMENT - COLPATTSTART; \
|
|
\
|
|
SetBank(af, af_last_bank); \
|
|
for (i = 0; i < 8; i++) \
|
|
for (j = 0; j < 8; j++) \
|
|
p[i * 8 + j] = current_color_pattern \
|
|
[((i + last_color_y) & 7) * 8 + \
|
|
((j + last_color_x) & 7)]; \
|
|
break; \
|
|
} \
|
|
} \
|
|
cir_bltmode &= ~CIR_BLT_COLEXP; \
|
|
} \
|
|
}
|
|
|
|
copycolormacro(,8)
|
|
copycolormacro(,16)
|
|
copycolormacro(,24)
|
|
copycolormacro(,32)
|
|
|
|
copycolormacro(MMIO,8)
|
|
copycolormacro(MMIO,16)
|
|
copycolormacro(MMIO,24)
|
|
copycolormacro(MMIO,32)
|
|
|
|
/* Set8x8MonoPattern:
|
|
* Downloads a monochrome (packed bit) pattern, for use by the
|
|
* DrawPattScan() and DrawPattRect() functions. This is always sized
|
|
* 8x8, and aligned with the top left corner of video memory: if other
|
|
* alignments are desired, the pattern will be prerotated before it
|
|
* is passed to this routine.
|
|
*/
|
|
void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern)
|
|
{
|
|
int i;
|
|
|
|
last_mono_x = last_mono_y = -1;
|
|
for (i = 0; i < 16; i++) mono_pattern[i] = pattern[i & 7];
|
|
}
|
|
|
|
/* Set8x8ColorPattern:
|
|
* Downloads a color pattern, for use by the DrawColorPattScan() and
|
|
* DrawColorPattRect() functions. This is always sized 8x8, and aligned
|
|
* with the top left corner of video memory: if other alignments are
|
|
* desired, the pattern will be prerotated before it is passed to this
|
|
* routine. The color values are presented in the native format for
|
|
* the current video mode, but padded to 32 bits (so the pattern is
|
|
* always an 8x8 array of longs).
|
|
*
|
|
* VBE/AF supports 8 different color patterns, which may be downloaded
|
|
* individually and then selected for use with the Use8x8ColorPattern()
|
|
* function. If the card is not able to cache these patterns in hardware,
|
|
* the driver is responsible for storing them internally and downloading
|
|
* the appropriate data when Use8x8ColorPattern() is called.
|
|
*
|
|
* Allegro only actually ever uses the first of these patterns, so
|
|
* you only need to bother about this if you want your code to work
|
|
* with other programs as well.
|
|
*/
|
|
void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 64; i++) color_pattern[index][i] = pattern[i];
|
|
}
|
|
|
|
|
|
|
|
/* Use8x8ColorPattern:
|
|
* Selects one of the patterns previously downloaded by Set8x8ColorPattern().
|
|
*/
|
|
void Use8x8ColorPattern(AF_DRIVER *af, int index)
|
|
{
|
|
last_color_x = last_color_y = -1;
|
|
current_color_pattern = color_pattern[index];
|
|
}
|
|
|
|
/* DrawScan:
|
|
* Fills a scanline in the current foreground mix mode. Draws up to but
|
|
* not including the second x coordinate. If the second coord is less
|
|
* than the first, they are swapped. If they are equal, nothing is drawn.
|
|
*/
|
|
#define DrawScanMacro(mmio, bpp) \
|
|
void DrawScan##bpp####mmio##(AF_DRIVER * af, long color, long y, long x1, \
|
|
long x2) { \
|
|
if (x2 < x1) { \
|
|
int tmp = x1; \
|
|
x1 = x2; \
|
|
x2 = tmp; \
|
|
} \
|
|
\
|
|
y += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE(cir_bltrop, cir_bltmode); \
|
|
SET_FG##bpp####mmio##(color); \
|
|
SET_WIDTH_HEIGHT##mmio##((x2 - x1) * (bpp / 8) - 1, 0); \
|
|
SET_DSTADDR##mmio##(y * af_width + x1 * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offscreen); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawScanMacro(,8)
|
|
DrawScanMacro(,16)
|
|
DrawScanMacro(,24)
|
|
DrawScanMacro(,32)
|
|
|
|
DrawScanMacro(MMIO,8)
|
|
DrawScanMacro(MMIO,16)
|
|
DrawScanMacro(MMIO,24)
|
|
DrawScanMacro(MMIO,32)
|
|
|
|
/* DrawPattScan:
|
|
* Fills a scanline using the current mono pattern. Set pattern bits are
|
|
* drawn using the specified foreground color and the foreground mix
|
|
* mode, and clear bits use the background color and background mix mode.
|
|
*/
|
|
#define DrawPattScanMacro(mmio, bpp) \
|
|
void DrawPattScan##bpp####mmio##(AF_DRIVER * af, long foreColor, \
|
|
long backColor, long y, long x1, \
|
|
long x2) { \
|
|
if (x2 < x1) { \
|
|
int tmp = x1; \
|
|
x1 = x2; \
|
|
x2 = tmp; \
|
|
} \
|
|
\
|
|
y += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
copymonopattern##bpp####mmio##(af, x1, y); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE(cir_bltrop, cir_bltmode); \
|
|
SET_FG##bpp####mmio##(foreColor); \
|
|
SET_BG##bpp####mmio##(backColor); \
|
|
SET_WIDTH_HEIGHT##mmio##((x2 - x1) * (bpp / 8) - 1, 0); \
|
|
SET_DSTADDR##mmio##(y * af_width + x1 * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offmono); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawPattScanMacro(,8)
|
|
DrawPattScanMacro(,16)
|
|
DrawPattScanMacro(,24)
|
|
DrawPattScanMacro(,32)
|
|
|
|
DrawPattScanMacro(MMIO,8)
|
|
DrawPattScanMacro(MMIO,16)
|
|
DrawPattScanMacro(MMIO,24)
|
|
DrawPattScanMacro(MMIO,32)
|
|
|
|
/* DrawColorPattScan:
|
|
* Fills a scanline using the current color pattern and mix mode.
|
|
*/
|
|
#define DrawColorPattScanMacro(mmio, bpp) \
|
|
void DrawColorPattScan##bpp####mmio##(AF_DRIVER * af, long y, long x1, \
|
|
long x2) { \
|
|
if (x2 < x1) { \
|
|
int tmp = x1; \
|
|
x1 = x2; \
|
|
x2 = tmp; \
|
|
} \
|
|
\
|
|
y += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
copycolorpattern##bpp####mmio##(af, x1, y); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE##mmio##(cir_bltrop, cir_bltmode); \
|
|
SET_WIDTH_HEIGHT##mmio##((x2 - x1) * (bpp / 8) - 1, 0); \
|
|
SET_DSTADDR##mmio##(y * af_width + x1 * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offcolor); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawColorPattScanMacro(,8)
|
|
DrawColorPattScanMacro(,16)
|
|
DrawColorPattScanMacro(,24)
|
|
DrawColorPattScanMacro(,32)
|
|
|
|
DrawColorPattScanMacro(MMIO,8)
|
|
DrawColorPattScanMacro(MMIO,16)
|
|
DrawColorPattScanMacro(MMIO,24)
|
|
DrawColorPattScanMacro(MMIO,32)
|
|
|
|
/* DrawRect:
|
|
* Fills a rectangle in the current foreground mix mode.
|
|
*/
|
|
#define DrawRectMacro(mmio, bpp) \
|
|
void DrawRect##bpp####mmio##(AF_DRIVER * af, unsigned long color, \
|
|
long left, long top, long width, \
|
|
long height) { \
|
|
top += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE##mmio##(cir_bltrop, cir_bltmode); \
|
|
SET_FG##bpp####mmio##((int)color); \
|
|
SET_WIDTH_HEIGHT##mmio##(width * (bpp / 8) - 1, height - 1); \
|
|
SET_DSTADDR##mmio##(top * af_width + left * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offscreen); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawRectMacro(,8)
|
|
DrawRectMacro(,16)
|
|
DrawRectMacro(,24)
|
|
DrawRectMacro(,32)
|
|
|
|
DrawRectMacro(MMIO,8)
|
|
DrawRectMacro(MMIO,16)
|
|
DrawRectMacro(MMIO,24)
|
|
DrawRectMacro(MMIO,32)
|
|
|
|
/* DrawPattRect:
|
|
* Fills a rectangle using the current mono pattern. Set pattern bits are
|
|
* drawn using the specified foreground color and the foreground mix
|
|
* mode, and clear bits use the background color and background mix mode.
|
|
*/
|
|
#define DrawPattRectMacro(mmio, bpp) \
|
|
void DrawPattRect##bpp####mmio##(AF_DRIVER * af, unsigned long foreColor, \
|
|
unsigned long backColor, long left, \
|
|
long top, long width, long height) { \
|
|
top += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
copymonopattern##bpp####mmio##(af, left, top); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE##mmio##(cir_bltrop, cir_bltmode); \
|
|
SET_FG##bpp####mmio##((int)foreColor); \
|
|
SET_BG##bpp####mmio##((int)backColor); \
|
|
SET_WIDTH_HEIGHT##mmio##(width * (bpp / 8) - 1, height - 1); \
|
|
SET_DSTADDR##mmio##(top * af_width + left * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offmono); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawPattRectMacro(,8)
|
|
DrawPattRectMacro(,16)
|
|
DrawPattRectMacro(,24)
|
|
DrawPattRectMacro(,32)
|
|
|
|
DrawPattRectMacro(MMIO,8)
|
|
DrawPattRectMacro(MMIO,16)
|
|
DrawPattRectMacro(MMIO,24)
|
|
DrawPattRectMacro(MMIO,32)
|
|
|
|
/* DrawColorPattRect:
|
|
* Fills a rectangle using the current color pattern and mix mode.
|
|
*/
|
|
#define DrawColorPattRectMacro(mmio, bpp) \
|
|
void DrawColorPattRect##bpp####mmio##(AF_DRIVER * af, long left, long top, \
|
|
long width, long height) { \
|
|
top += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
copycolorpattern##bpp####mmio##(af, left, top); \
|
|
need_wait = 1; \
|
|
SET_ROP_MODE##mmio##(cir_bltrop, cir_bltmode); \
|
|
SET_WIDTH_HEIGHT##mmio##(width * (bpp / 8) - 1, height - 1); \
|
|
SET_DSTADDR##mmio##(top * af_width + left * (bpp / 8)); \
|
|
SET_SRCADDR##mmio##(cir_offcolor); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
DrawColorPattRectMacro(,8)
|
|
DrawColorPattRectMacro(,16)
|
|
DrawColorPattRectMacro(,24)
|
|
DrawColorPattRectMacro(,32)
|
|
|
|
DrawColorPattRectMacro(MMIO,8)
|
|
DrawColorPattRectMacro(MMIO,16)
|
|
DrawColorPattRectMacro(MMIO,24)
|
|
DrawColorPattRectMacro(MMIO,32)
|
|
|
|
/* 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.
|
|
*/
|
|
#define BitBltMacro(mmio, bpp, pixmode) \
|
|
void BitBlt##bpp####mmio##(AF_DRIVER * af, long left, long top, \
|
|
long width, long height, long dstLeft, \
|
|
long dstTop, long op) { \
|
|
unsigned long pdst, psrc; \
|
|
int bltmode = pixmode, bltrop; \
|
|
\
|
|
top += af_active_page * af_height; \
|
|
dstTop += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
width *= (bpp / 8); \
|
|
width--; \
|
|
height--; \
|
|
left *= (bpp / 8); \
|
|
dstLeft *= (bpp / 8); \
|
|
need_wait = 1; \
|
|
if ((dstTop > top) || ((top == dstTop) && (dstLeft > left))) { \
|
|
psrc = (((top + height) * af_width) + left + width); \
|
|
pdst = (((dstTop + height) * af_width) + dstLeft + width); \
|
|
bltmode |= CIR_BLT_BACK; \
|
|
} else { \
|
|
psrc = ((top * af_width) + left); \
|
|
pdst = ((dstTop * af_width) + dstLeft); \
|
|
} \
|
|
SET_WIDTH_HEIGHT##mmio##(width, height); \
|
|
SET_SRCADDR##mmio##(psrc); \
|
|
SET_DSTADDR##mmio##(pdst); \
|
|
bltrop = af_mix_fore(op); \
|
|
SET_ROP_MODE##mmio##(bltrop, bltmode); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
BitBltMacro(,8,CIR_BLT_PIX8)
|
|
BitBltMacro(,16,CIR_BLT_PIX16)
|
|
BitBltMacro(,24,CIR_BLT_PIX24)
|
|
BitBltMacro(,32,CIR_BLT_PIX32)
|
|
|
|
BitBltMacro(MMIO,8,CIR_BLT_PIX8)
|
|
BitBltMacro(MMIO,16,CIR_BLT_PIX16)
|
|
BitBltMacro(MMIO,24,CIR_BLT_PIX24)
|
|
BitBltMacro(MMIO,32,CIR_BLT_PIX32)
|
|
|
|
/* SrcTransBlt:
|
|
* Blits from one part of video memory to another, using the specified
|
|
* mix operation and skipping any source pixels which match the specified
|
|
* transparent color. Results are undefined if the two regions overlap.
|
|
*/
|
|
#define SrcTransBltMacro(mmio, bpp, pixmode) \
|
|
void SrcTransBlt##bpp####mmio##( \
|
|
AF_DRIVER * af, long left, long top, long width, long height, \
|
|
long dstLeft, long dstTop, long op, unsigned long transparent) { \
|
|
unsigned long pdst, psrc; \
|
|
int bltmode = pixmode | CIR_BLT_TRANS, bltrop; \
|
|
\
|
|
top += af_active_page * af_height; \
|
|
dstTop += af_active_page * af_height; \
|
|
waitidle##mmio##( ); \
|
|
width *= (bpp / 8); \
|
|
width--; \
|
|
height--; \
|
|
left *= (bpp / 8); \
|
|
dstLeft *= (bpp / 8); \
|
|
need_wait = 1; \
|
|
if ((dstTop > top) || ((top == dstTop) && (dstLeft > left))) { \
|
|
psrc = (((top + height) * af_width) + left + width); \
|
|
pdst = (((dstTop + height) * af_width) + dstLeft + width); \
|
|
bltmode |= CIR_BLT_BACK; \
|
|
} else { \
|
|
psrc = ((top * af_width) + left); \
|
|
pdst = ((dstTop * af_width) + dstLeft); \
|
|
} \
|
|
SET_TRANS##mmio##((int)transparent); \
|
|
SET_WIDTH_HEIGHT##mmio##(width, height); \
|
|
SET_SRCADDR##mmio##(psrc); \
|
|
SET_DSTADDR##mmio##(pdst); \
|
|
bltrop = af_mix_fore(op); \
|
|
SET_ROP_MODE##mmio##(bltrop, bltmode); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
}
|
|
|
|
SrcTransBltMacro(,8,CIR_BLT_PIX8)
|
|
SrcTransBltMacro(,16,CIR_BLT_PIX16)
|
|
SrcTransBltMacro(,24,CIR_BLT_PIX24)
|
|
SrcTransBltMacro(,32,CIR_BLT_PIX32)
|
|
|
|
SrcTransBltMacro(MMIO,8,CIR_BLT_PIX8)
|
|
SrcTransBltMacro(MMIO,16,CIR_BLT_PIX16)
|
|
SrcTransBltMacro(MMIO,24,CIR_BLT_PIX24)
|
|
SrcTransBltMacro(MMIO,32,CIR_BLT_PIX32)
|
|
|
|
int hw_cur_x=0,hw_cur_y=0;
|
|
|
|
void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor)
|
|
{
|
|
int i, j;
|
|
unsigned long *p, andMask, xorMask;
|
|
|
|
af->WaitTillIdle(af);
|
|
alter_vga_register(0x3c4, 0x12, 3, 0);
|
|
write_vga_register(0x3d4, 11, 0x24);
|
|
if (af_linear)
|
|
p = af->LinearMem + af_memory - CURSORSTART;
|
|
else {
|
|
p = af->BankedMem + DISPLACEMENT - CURSORSTART;
|
|
SetBank(af, af_last_bank);
|
|
}
|
|
for (i = 0; i < 32; i++) {
|
|
andMask = xorMask = 0;
|
|
for (j = 0; j < 32; j++) {
|
|
if (cursor->andMask[i] & (1 << j)) {
|
|
if (cursor->xorMask[i] & (1 << j)) {
|
|
andMask |= (1 << j); // foreground
|
|
xorMask |= (1 << j);
|
|
} else {
|
|
xorMask |= (1 << j); // background
|
|
}
|
|
} else if (cursor->xorMask[i] & (1 << j))
|
|
andMask |= (1 << j); // inverted
|
|
}
|
|
*p = andMask;
|
|
p[32] = xorMask;
|
|
p++;
|
|
}
|
|
hw_cur_x = cursor->hotx;
|
|
hw_cur_y = cursor->hoty;
|
|
write_vga_register(0x3c4, 0x13, 0x38);
|
|
if (cir_cursor_visible) alter_vga_register(0x3c4, 0x12, 1, 1);
|
|
}
|
|
|
|
void SetCursorPos(AF_DRIVER *af, long x, long y)
|
|
{
|
|
x -= hw_cur_x;
|
|
if (x < 0) x = 0;
|
|
y -= hw_cur_y;
|
|
if (y < 0) y = 0;
|
|
__asm__("movw $0x3c4,%%dx
|
|
outw %
|
|
% ax,
|
|
% % dx movw % % bx, % % ax outw % % ax, % % dx "
|
|
:
|
|
: "a"((x << 5) + 0x10), "b"((y << 5) + 0x11)
|
|
: "%dx");
|
|
}
|
|
|
|
void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green, unsigned char blue)
|
|
{
|
|
alter_vga_register(
|
|
0x3c4, 0x12, 2,
|
|
2); // index 12 - enable access to extended DAC palette entries
|
|
if (af_bpp == 8) {
|
|
mouse_fg = red;
|
|
outportb(0x3c8, 0xf); // cursor foreground
|
|
outportb(0x3c9, af_pal[mouse_fg].red);
|
|
outportb(0x3c9, af_pal[mouse_fg].green);
|
|
outportb(0x3c9, af_pal[mouse_fg].blue);
|
|
outportb(0x3c8, 0); // cursor background
|
|
outportb(0x3c9, af_pal[0].red);
|
|
outportb(0x3c9, af_pal[0].green);
|
|
outportb(0x3c9, af_pal[0].blue);
|
|
} else {
|
|
outportb(0x3c8, 0xf); // cursor foreground
|
|
outportb(0x3c9, red);
|
|
outportb(0x3c9, green);
|
|
outportb(0x3c9, blue);
|
|
outportb(0x3c8, 0); // cursor background
|
|
outportb(0x3c9, 0);
|
|
outportb(0x3c9, 0);
|
|
outportb(0x3c9, 0);
|
|
}
|
|
alter_vga_register(
|
|
0x3c4, 0x12, 2,
|
|
0); // index 12 - disable access to extended DAC palette entries
|
|
}
|
|
|
|
void ShowCursor(AF_DRIVER *af, long visible)
|
|
{
|
|
if (visible) {
|
|
alter_vga_register(0x3c4, 0x12, 5, 1);
|
|
cir_cursor_visible = 1;
|
|
} else {
|
|
alter_vga_register(0x3c4, 0x12, 5, 0);
|
|
cir_cursor_visible = 0;
|
|
}
|
|
}
|
|
|
|
#define BitBltSysMacro(mmio, bpp, pixmode) \
|
|
void BitBltSys##bpp####mmio##(AF_DRIVER * af, void *srcAddr, \
|
|
long srcPitch, long srcLeft, long srcTop, \
|
|
long width, long height, long dstLeft, \
|
|
long dstTop, long op) { \
|
|
unsigned long pdst; \
|
|
int bltmode = pixmode, bltrop; \
|
|
\
|
|
width *= (bpp / 8); \
|
|
width--; \
|
|
height--; \
|
|
srcLeft *= (bpp / 8); \
|
|
dstLeft *= (bpp / 8); \
|
|
waitidle##mmio##( ); \
|
|
need_wait = 1; \
|
|
dstTop += af_active_page * af_height; \
|
|
pdst = dstTop * af_width + dstLeft; \
|
|
SET_WIDTH_HEIGHT##mmio##(width, height); \
|
|
SET_SRCADDR##mmio##(0); \
|
|
SET_DSTADDR##mmio##(pdst); \
|
|
bltrop = af_mix_fore(op); \
|
|
bltmode |= CIR_BLT_MEM; \
|
|
SET_ROP_MODE##mmio##(bltrop, bltmode); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
width++; \
|
|
height++; \
|
|
__asm__ __volatile__("\
|
|
cld;\
|
|
1:;\
|
|
pushl %%edi;\
|
|
pushl %%ecx;\
|
|
rep; movsl;\
|
|
movsw;\
|
|
movsw;\
|
|
popl %%ecx;\
|
|
addl %%ebx,%%esi;\
|
|
popl %%edi;\
|
|
decl %%edx;\
|
|
jnz 1b\
|
|
" ::"S"(srcAddr + srcTop * srcPitch + srcLeft), \
|
|
"D"(af_linear ? af->LinearMem : af->BankedMem), \
|
|
"b"(srcPitch - ((width - 1) & 0xfffffffc) - 4), \
|
|
"c"((width - 1) >> 2), "d"(height) \
|
|
: "eax", "ebx", "ecx", "edx", "esi", "edi", \
|
|
"cc"); \
|
|
}
|
|
|
|
BitBltSysMacro(,8,CIR_BLT_PIX8)
|
|
BitBltSysMacro(,16,CIR_BLT_PIX16)
|
|
BitBltSysMacro(,24,CIR_BLT_PIX24)
|
|
BitBltSysMacro(,32,CIR_BLT_PIX32)
|
|
|
|
BitBltSysMacro(MMIO,8,CIR_BLT_PIX8)
|
|
BitBltSysMacro(MMIO,16,CIR_BLT_PIX16)
|
|
BitBltSysMacro(MMIO,24,CIR_BLT_PIX24)
|
|
BitBltSysMacro(MMIO,32,CIR_BLT_PIX32)
|
|
|
|
#define SrcTransBltSysMacro(mmio, bpp, pixmode) \
|
|
void SrcTransBltSys##bpp####mmio##( \
|
|
AF_DRIVER * af, void *srcAddr, long srcPitch, long srcLeft, \
|
|
long srcTop, long width, long height, long dstLeft, long dstTop, \
|
|
long op, unsigned long transparent) { \
|
|
unsigned long pdst; \
|
|
int bltmode, bltrop; \
|
|
\
|
|
width *= (bpp / 8); \
|
|
width--; \
|
|
height--; \
|
|
srcLeft *= (bpp / 8); \
|
|
dstLeft *= (bpp / 8); \
|
|
waitidle##mmio##( ); \
|
|
need_wait = 1; \
|
|
dstTop += af_active_page * af_height; \
|
|
pdst = dstTop * af_width + dstLeft; \
|
|
bltrop = af_mix_fore(op); \
|
|
bltmode = CIR_BLT_MEM | CIR_BLT_TRANS | pixmode; \
|
|
SET_ROP_MODE##mmio##(bltrop, bltmode); \
|
|
SET_WIDTH_HEIGHT##mmio##(width, height); \
|
|
SET_TRANS##mmio##((int)transparent); \
|
|
SET_SRCADDR##mmio##(0); \
|
|
SET_DSTADDR##mmio##(pdst); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
width++; \
|
|
height++; \
|
|
__asm__ __volatile__(" \
|
|
cld; \
|
|
1:; \
|
|
pushl %%edi; \
|
|
pushl %%ecx; \
|
|
rep; movsl; \
|
|
movsw; \
|
|
movsw; \
|
|
popl %%ecx; \
|
|
addl %%ebx,%%esi; \
|
|
popl %%edi; \
|
|
decl %%edx; \
|
|
jnz 1b; \
|
|
" \
|
|
: \
|
|
: "S"(srcAddr + srcTop * srcPitch + srcLeft), \
|
|
"D"(af_linear ? af->LinearMem : af->BankedMem), \
|
|
"b"(srcPitch - ((width - 1) & 0xfffffffc) - 4), \
|
|
"c"((width - 1) >> 2), "d"(height) \
|
|
: "eax", "ebx", "ecx", "edx", "esi", "edi", \
|
|
"cc"); \
|
|
}
|
|
|
|
SrcTransBltSysMacro(,8,CIR_BLT_PIX8)
|
|
SrcTransBltSysMacro(,16,CIR_BLT_PIX16)
|
|
SrcTransBltSysMacro(,24,CIR_BLT_PIX24)
|
|
SrcTransBltSysMacro(,32,CIR_BLT_PIX32)
|
|
|
|
SrcTransBltSysMacro(MMIO,8,CIR_BLT_PIX8)
|
|
SrcTransBltSysMacro(MMIO,16,CIR_BLT_PIX16)
|
|
SrcTransBltSysMacro(MMIO,24,CIR_BLT_PIX24)
|
|
SrcTransBltSysMacro(MMIO,32,CIR_BLT_PIX32)
|
|
|
|
inline void shiftleft(unsigned char *line,int bytes,unsigned char bits)
|
|
{
|
|
asm("
|
|
movb $8,
|
|
% % ch addb % % cl, % % ch movb % % dl, % % al 1
|
|
: movb(% % esi), % % ah andl $0xffff, % % eax shll % % cl,
|
|
% % eax movb % % ah, (% % esi) xchgb % % ch, % % cl shrl % % cl,
|
|
% % eax decl % % esi xchgb % % ch, % % cl decl % %
|
|
ebx jnz 1b "
|
|
::"S"(line + bytes - 1),
|
|
"c"((bits & 31) | ((32 - (bits & 31)) << 8)), "d"(0), "b"(bytes));
|
|
}
|
|
|
|
unsigned char lines[1024];
|
|
|
|
#define PutMonoImageMacro(mmio, bpp, pixmode) \
|
|
void PutMonoImage##bpp####mmio##( \
|
|
AF_DRIVER * af, long foreColor, long backColor, long dstX, long dstY, \
|
|
long byteWidth, long srcX, long srcY, long width, long height, \
|
|
unsigned char *image) { \
|
|
unsigned long pdst; \
|
|
int i, j, bytelen = (width + 7) / 8; \
|
|
int bltmode = CIR_BLT_MEM | CIR_BLT_COLEXP | pixmode; \
|
|
\
|
|
if (width * 8 == byteWidth) { \
|
|
for (i = 0; i < byteWidth * height; i++) lines[i] = image[i]; \
|
|
} else { \
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < bytelen; j++) \
|
|
lines[i * bytelen + j] = \
|
|
image[(i + srcY) * byteWidth + j + (srcX / 8)]; \
|
|
if (srcX & 7) \
|
|
shiftleft(lines + i * bytelen, bytelen, srcX & 7); \
|
|
} \
|
|
} \
|
|
\
|
|
width *= (bpp / 8); \
|
|
width--; \
|
|
dstX *= (bpp / 8); \
|
|
waitidle##mmio##( ); \
|
|
need_wait = 1; \
|
|
dstY += af_active_page * af_height; \
|
|
pdst = dstY * af_width + dstX; \
|
|
if (cir_bltmode & CIR_BLT_TRANS) { \
|
|
if (backColor == foreColor) backColor = !backColor; \
|
|
bltmode |= CIR_BLT_TRANS; \
|
|
if ((bpp / 8) == 1) { \
|
|
backColor |= backColor << 8; \
|
|
SET_TRANS##mmio##(backColor); \
|
|
backColor &= 0xff; \
|
|
} else \
|
|
SET_TRANS(backColor); \
|
|
} \
|
|
SET_BG##bpp####mmio##(backColor); \
|
|
SET_ROP_MODE##mmio##(cir_bltrop, bltmode); \
|
|
SET_FG##bpp####mmio##(foreColor); \
|
|
SET_WIDTH_HEIGHT##mmio##(width, height - 1); \
|
|
SET_SRCADDR##mmio##(0); \
|
|
SET_DSTADDR##mmio##(pdst); \
|
|
CIR_CMD(CIR_CMD_RUN); \
|
|
__asm__ __volatile__(" \
|
|
cld; \
|
|
rep; movsl; \
|
|
" \
|
|
: \
|
|
: "S"(lines), \
|
|
"D"(af_linear ? af->LinearMem : af->BankedMem), \
|
|
"c"((height * bytelen + 3) / 4), "d"(height) \
|
|
: "eax", "ecx", "edx", "esi", "edi", "cc"); \
|
|
}
|
|
|
|
PutMonoImageMacro(,8,CIR_BLT_PIX8)
|
|
PutMonoImageMacro(,16,CIR_BLT_PIX16)
|
|
PutMonoImageMacro(,24,CIR_BLT_PIX24)
|
|
PutMonoImageMacro(,32,CIR_BLT_PIX32)
|
|
|
|
PutMonoImageMacro(MMIO,8,CIR_BLT_PIX8)
|
|
PutMonoImageMacro(MMIO,16,CIR_BLT_PIX16)
|
|
PutMonoImageMacro(MMIO,24,CIR_BLT_PIX24)
|
|
PutMonoImageMacro(MMIO,32,CIR_BLT_PIX32)
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
#define SetupMacro(mmio, bpp) \
|
|
void SetupFuncPtr##bpp####mmio##(AF_DRIVER * af) { \
|
|
af->DrawScan = DrawScan##bpp####mmio##; \
|
|
af->DrawPattScan = DrawPattScan##bpp####mmio##; \
|
|
af->DrawColorPattScan = DrawColorPattScan##bpp####mmio##; \
|
|
af->DrawRect = DrawRect##bpp####mmio##; \
|
|
af->DrawPattRect = DrawPattRect##bpp####mmio##; \
|
|
af->DrawColorPattRect = DrawColorPattRect##bpp####mmio##; \
|
|
af->BitBlt = BitBlt##bpp####mmio##; \
|
|
af->BitBltSys = BitBltSys##bpp####mmio##; \
|
|
af->SrcTransBlt = SrcTransBlt##bpp####mmio##; \
|
|
af->SrcTransBltSys = SrcTransBltSys##bpp####mmio##; \
|
|
af->WaitTillIdle = WaitTillIdle##bpp####mmio##; \
|
|
af->PutMonoImage = PutMonoImage##bpp####mmio##; \
|
|
}
|
|
|
|
|
|
SetupMacro(,8);
|
|
SetupMacro(,16);
|
|
SetupMacro(,24);
|
|
SetupMacro(,32);
|
|
|
|
SetupMacro(MMIO,8);
|
|
SetupMacro(MMIO,16);
|
|
SetupMacro(MMIO,24);
|
|
SetupMacro(MMIO,32);
|
|
|
|
int SetupDriver(AF_DRIVER *af)
|
|
{
|
|
RM_REGS regs;
|
|
int i, j, card, bus_type = 0;
|
|
|
|
regs.x.ax = 0x1200; // cirrus extended bios
|
|
regs.x.bx = 0x80; // get chip version
|
|
rm_int(0x10, ®s);
|
|
card = regs.h.al;
|
|
for (i = 0; i < KNOWN_CARDS; i++)
|
|
if (card == detect_info[i].biosnum) {
|
|
cir_card = i;
|
|
break;
|
|
}
|
|
if (cir_card == -1) return -1;
|
|
regs.x.ax = 0x1200; // cirrus extended bios
|
|
regs.x.bx = 0x85; // get available memory
|
|
rm_int(0x10, ®s);
|
|
af_memory = (regs.h.al << 6) * 1024;
|
|
af->TotalMemory = (af_memory - RESERVED_VRAM) / 1024;
|
|
if (!detect_info[cir_card].pcinum) goto pcinotfound;
|
|
regs.x.ax = 0xB101;
|
|
rm_int(0x1A, ®s);
|
|
if (regs.h.ah) goto pcinotfound;
|
|
regs.x.ax = 0xB102;
|
|
regs.x.cx = detect_info[cir_card].pcinum;
|
|
regs.x.dx = CIRRUS_PCI_VENDOR_ID;
|
|
regs.x.si = 0;
|
|
rm_int(0x1A, ®s);
|
|
if (regs.h.ah) goto pcinotfound;
|
|
bus_type = regs.x.bx;
|
|
af->PCIVendorID = CIRRUS_PCI_VENDOR_ID;
|
|
af->PCIDeviceID = detect_info[cir_card].pcinum;
|
|
regs.x.bx = bus_type;
|
|
regs.x.ax = 0xB10A;
|
|
regs.x.di = 16;
|
|
rm_int(0x1A, ®s);
|
|
linear_addr = regs.d.ecx & 0xff000000;
|
|
pcinotfound:
|
|
|
|
i = j = 0;
|
|
while (mode_list[i].w != 0) {
|
|
regs.h.ah = 0x12; /*cirrus bios extensions*/
|
|
regs.h.al = mode_list[i].num;
|
|
regs.d.ebx = 0xA0; /*get availability of video mode*/
|
|
rm_int(0x10, ®s);
|
|
if ((regs.h.ah & 1) && (mode_list[i].bpp < 24 ||
|
|
(mode_list[i].bpp == 24 && cir_useblt24) ||
|
|
(mode_list[i].bpp == 32 && cir_useblt32))) {
|
|
available_modes[j++] = i + 1;
|
|
}
|
|
i++;
|
|
}
|
|
num_modes = i;
|
|
available_modes[j] = -1;
|
|
|
|
/* pointer to a list of the available mode numbers, ended by -1.
|
|
* Our mode numbers just count up from 1, so the mode numbers can
|
|
* be used as indexes into the mode_list[] table (zero is an
|
|
* invalid mode number, so this indexing must be offset by 1).
|
|
*/
|
|
af->AvailableModes = available_modes;
|
|
|
|
/* driver attributes (see definitions in vbeaf.h) */
|
|
af->Attributes = (afHaveMultiBuffer | afHaveVirtualScroll |
|
|
afHaveBankedBuffer | afHaveAccel2D);
|
|
af->Attributes |= afHaveHWCursor;
|
|
|
|
if (linear_addr) af->Attributes |= afHaveLinearBuffer;
|
|
|
|
/* banked memory size and location: zero if not supported */
|
|
af->BankSize = 64;
|
|
af->BankedBasePtr = 0xA0000;
|
|
|
|
/* linear framebuffer size and location: zero if not supported */
|
|
if (linear_addr) {
|
|
af->LinearSize = af_memory / 1024;
|
|
af->LinearBasePtr = linear_addr;
|
|
} else {
|
|
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) */
|
|
for (i = 0; i < 4; i++) {
|
|
af->IOMemoryBase[i] = 0;
|
|
af->IOMemoryLen[i] = 0;
|
|
}
|
|
|
|
#ifndef DISABLE_MMIO
|
|
switch (detect_info[cir_card].family) {
|
|
case 0:
|
|
/* 5426, 5428 do not support MMIO */
|
|
break;
|
|
case 1:
|
|
/* MMIO for 5429 -- could we support this card's linear
|
|
* framebuffer?? */
|
|
af->IOMemoryBase[0] = 0xb8000;
|
|
af->IOMemoryLen[0] = 256;
|
|
break;
|
|
case 2:
|
|
case 5:
|
|
/* 5430,5436,5440,5446 */
|
|
if (linear_addr)
|
|
af->IOMemoryBase[0] = linear_addr + 4 * 1024 * 1024 - 256;
|
|
else
|
|
af->IOMemoryBase[0] = 0xb8000;
|
|
af->IOMemoryLen[0] = 256;
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
/* 5434 only allows MMIO at 0xb8000*/
|
|
af->IOMemoryBase[0] = 0xb8000;
|
|
af->IOMemoryLen[0] = 256;
|
|
break;
|
|
case 6:
|
|
/* 5480 */
|
|
/* if (linear_addr&&bus_type) {
|
|
regs.x.ax = 0xB102;
|
|
regs.x.bx=bus_type;
|
|
if (regs.h.ah)
|
|
goto pcinotfound;
|
|
regs.x.ax = 0xB102;
|
|
regs.x.cx = detect_info[cir_card].pcinum;
|
|
regs.x.dx = CIRRUS_PCI_VENDOR_ID;
|
|
regs.x.di = 32;
|
|
rm_int(0x1A, ®s);
|
|
if (regs.h.al) //should never occur
|
|
af->IOMemoryBase[0] = 0xb8000;
|
|
else
|
|
af->IOMemoryBase[0] = regs.d.ecx;
|
|
} else*/
|
|
af->IOMemoryBase[0] = 0xb8000;
|
|
af->IOMemoryLen[0] = 256;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
/* 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 (not supported: not used by Allegro) */
|
|
af->SetCursor = SetCursor;
|
|
af->SetCursorPos = SetCursorPos;
|
|
af->SetCursorColor = SetCursorColor;
|
|
af->ShowCursor = ShowCursor;
|
|
/* on some cards the CPU cannot access the framebuffer while it is in
|
|
* 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.
|
|
* The application will call EnableDirectAccess() whenever it is about
|
|
* to write to the framebuffer directly, and DisableDirectAccess()
|
|
* before it calls any hardware drawing routines. If this arbitration is
|
|
* 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 = Set8x8MonoPattern;
|
|
af->Set8x8ColorPattern = Set8x8ColorPattern;
|
|
af->Use8x8ColorPattern = Use8x8ColorPattern;
|
|
|
|
/* not supported: not used by Allegro */
|
|
af->DrawScanList = NULL;
|
|
af->DrawPattScanList = NULL;
|
|
af->DrawColorPattScanList = NULL;
|
|
|
|
/* not supported: not used by Allegro */
|
|
af->DrawLine = NULL;
|
|
af->DrawStippleLine = NULL;
|
|
af->DrawTrap = NULL;
|
|
af->DrawTri = NULL;
|
|
af->DrawQuad = NULL;
|
|
|
|
af->BitBltLin = NULL;
|
|
af->BitBltBM = NULL;
|
|
|
|
af->PutMonoImageLin = NULL;
|
|
af->PutMonoImageBM = 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;
|
|
|
|
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;
|
|
|
|
SetupFuncPtr8(af);
|
|
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.
|
|
* This is in charge of finding the card, returning 0 on success or
|
|
* -1 to abort.
|
|
*/
|
|
int InitDriver(AF_DRIVER *af)
|
|
{
|
|
if (cir_card == -1)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* FreeBEX:
|
|
* Returns an interface structure for the requested FreeBE/AF extension.
|
|
*/
|
|
void *FreeBEX(AF_DRIVER *af, unsigned long id)
|
|
{
|
|
switch (id) {
|
|
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)
|
|
{
|
|
_GFX_MODE_INFO *info;
|
|
int i;
|
|
|
|
if ((mode <= 0) || (mode > num_modes)) return -1;
|
|
|
|
for (i = 0; i < (int)sizeof(AF_MODE_INFO); i++) ((char *)modeInfo)[i] = 0;
|
|
|
|
info = &mode_list[mode - 1];
|
|
/* copy data across from our stored list of mode attributes */
|
|
modeInfo->Attributes = (afHaveMultiBuffer | afHaveVirtualScroll |
|
|
afHaveBankedBuffer | afHaveAccel2D);
|
|
modeInfo->Attributes |= afHaveHWCursor;
|
|
|
|
if (linear_addr) modeInfo->Attributes |= afHaveLinearBuffer;
|
|
|
|
modeInfo->XResolution = info->w;
|
|
modeInfo->YResolution = info->h;
|
|
modeInfo->BitsPerPixel = info->bpp;
|
|
|
|
/* available pages of video memory */
|
|
modeInfo->MaxBuffers = (af->TotalMemory * 1024) / (info->bpl * info->h);
|
|
|
|
/* 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->MaxBytesPerScanLine = 1024 * BYTES_PER_PIXEL(info->bpp);
|
|
modeInfo->MaxScanLineWidth = 1024;
|
|
|
|
/* for banked video modes, fill in these variables: */
|
|
modeInfo->BytesPerScanLine = info->bpl;
|
|
modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
|
|
switch (info->bpp) {
|
|
case 8: break;
|
|
case 15:
|
|
modeInfo->RedMaskSize = 5;
|
|
modeInfo->RedFieldPosition = 10;
|
|
modeInfo->GreenMaskSize = 5;
|
|
modeInfo->GreenFieldPosition = 5;
|
|
modeInfo->BlueMaskSize = 5;
|
|
modeInfo->RsvdMaskSize = 1;
|
|
modeInfo->RsvdFieldPosition = 15;
|
|
break;
|
|
case 16:
|
|
modeInfo->RedMaskSize = 5;
|
|
modeInfo->RedFieldPosition = 11;
|
|
modeInfo->GreenMaskSize = 6;
|
|
modeInfo->GreenFieldPosition = 5;
|
|
modeInfo->BlueMaskSize = 5;
|
|
break;
|
|
case 24:
|
|
modeInfo->RedMaskSize = 8;
|
|
modeInfo->RedFieldPosition = 16;
|
|
modeInfo->GreenMaskSize = 8;
|
|
modeInfo->GreenFieldPosition = 8;
|
|
modeInfo->BlueMaskSize = 8;
|
|
break;
|
|
case 32:
|
|
modeInfo->RedMaskSize = 8;
|
|
modeInfo->RedFieldPosition = 16;
|
|
modeInfo->GreenMaskSize = 8;
|
|
modeInfo->GreenFieldPosition = 8;
|
|
modeInfo->BlueMaskSize = 8;
|
|
modeInfo->RsvdMaskSize = 8;
|
|
modeInfo->RsvdFieldPosition = 24;
|
|
break;
|
|
}
|
|
|
|
/* for linear video modes, fill in these variables: */
|
|
modeInfo->LinBytesPerScanLine = modeInfo->BytesPerScanLine;
|
|
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;
|
|
}
|
|
|
|
int set_width(int width)
|
|
{
|
|
width >>= 3;
|
|
if (width < 512) {
|
|
write_vga_register(_crtc, 0x13, width & 0xFF);
|
|
alter_vga_register(_crtc, 0x1B, 16, (width >> 4) & 16);
|
|
return width << 3;
|
|
} else
|
|
return af_width;
|
|
}
|
|
|
|
/* 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
|
|
*/
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
|
|
{
|
|
int linear = ((mode & 0x4000) != 0);
|
|
int noclear = ((mode & 0x8000) != 0);
|
|
int i;
|
|
long available_vram;
|
|
long used_vram;
|
|
unsigned char *p;
|
|
_GFX_MODE_INFO *info;
|
|
RM_REGS r;
|
|
|
|
/* reject anything with hardware stereo */
|
|
if (mode & 0x400) return -1;
|
|
|
|
/* mask off the other flag bits */
|
|
mode &= 0x3FF;
|
|
|
|
if ((mode <= 0) || (mode > num_modes)) return -1;
|
|
|
|
info = &mode_list[mode - 1];
|
|
|
|
r.x.ax = info->num; /*set the mode through bios function 0*/
|
|
if (noclear) r.x.ax |= 0x80;
|
|
rm_int(0x10, &r);
|
|
if (info->bpp == 15) {
|
|
inportb(0x3c6); // to access hidden dac register on cirruses 4
|
|
inportb(0x3c6); // consecutive reads must be perforamed
|
|
inportb(0x3c6);
|
|
inportb(0x3c6);
|
|
mode = inportb(0x3c6);
|
|
mode &= 0xef; // mask out bit 4 which enables extended 15 bit modes
|
|
// (bit 15 of color data determines if data is regular 15bit color or
|
|
// palette index)
|
|
inportb(0x3c6); // to access hidden dac register on cirruses 4
|
|
inportb(0x3c6); // consecutive reads must be perforamed
|
|
inportb(0x3c6);
|
|
inportb(0x3c6);
|
|
outportb(0x3c6, mode);
|
|
}
|
|
/* 16k banks, single page, disable extensions */
|
|
alter_vga_register(0x3CE, 0xB, 0x21, 0x20);
|
|
/* reject the linear flag if the mode doesn't support it */
|
|
if (linear && linear_addr) {
|
|
alter_vga_register(0x3c4, 0x7, 0xf0, 0xf0);
|
|
} else
|
|
linear = 0;
|
|
|
|
/* adjust the virtual width for widescreen modes */
|
|
if (virtualX * BYTES_PER_PIXEL(info->bpp) > info->bpl) {
|
|
*bytesPerLine = set_width(virtualX * BYTES_PER_PIXEL(info->bpp));
|
|
} else
|
|
*bytesPerLine = info->bpl;
|
|
|
|
/* store info about the current mode */
|
|
af_bpp = info->bpp;
|
|
af_width = *bytesPerLine;
|
|
af_height = MAX(info->h, virtualY);
|
|
af_linear = linear;
|
|
af_visible_page = 0;
|
|
af_active_page = 0;
|
|
af_bank = -1;
|
|
|
|
/* return framebuffer dimensions to the application */
|
|
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;
|
|
}
|
|
|
|
af_fore_mix = AF_REPLACE_MIX;
|
|
af_back_mix = AF_FORE_MIX;
|
|
|
|
cir_bpp = BYTES_PER_PIXEL(af_bpp);
|
|
|
|
CIR_SRCPITCH(af_width);
|
|
CIR_DSTPITCH(af_width);
|
|
if (af->IOMemoryBase[0]) {
|
|
// setup MMIO
|
|
if (af_linear)
|
|
alter_vga_register(0x3c4, 0x17, 0x44, 0x44);
|
|
else
|
|
alter_vga_register(0x3c4, 0x17, 0x44, 0x04);
|
|
af_mmio = (unsigned long)af->IOMemMaps[0];
|
|
switch (af_bpp) {
|
|
case 8:
|
|
cir_pixmode = CIR_BLT_PIX8;
|
|
SetupFuncPtr8MMIO(af);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
cir_pixmode = CIR_BLT_PIX16;
|
|
SetupFuncPtr16MMIO(af);
|
|
break;
|
|
case 24:
|
|
cir_pixmode = CIR_BLT_PIX24;
|
|
SetupFuncPtr24MMIO(af);
|
|
break;
|
|
case 32:
|
|
cir_pixmode = CIR_BLT_PIX32;
|
|
SetupFuncPtr32MMIO(af);
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
switch (af_bpp) {
|
|
case 8:
|
|
cir_pixmode = CIR_BLT_PIX8;
|
|
SetupFuncPtr8(af);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
cir_pixmode = CIR_BLT_PIX16;
|
|
SetupFuncPtr16(af);
|
|
break;
|
|
case 24:
|
|
cir_pixmode = CIR_BLT_PIX24;
|
|
SetupFuncPtr24(af);
|
|
break;
|
|
case 32:
|
|
cir_pixmode = CIR_BLT_PIX32;
|
|
SetupFuncPtr32(af);
|
|
break;
|
|
}
|
|
}
|
|
cir_offmono = af_memory - MONOPATTSTART;
|
|
cir_offscreen = af_memory - SOLIDPATTSTART;
|
|
cir_offcolor = af_memory - COLPATTSTART;
|
|
cir_bltmode = CIR_BLT_PATT | CIR_BLT_COLEXP | cir_pixmode;
|
|
cir_bltrop = CIR_ROP_COPY;
|
|
af_last_bank = (af_memory) / 64 / 1024 - 1;
|
|
if (af_linear) {
|
|
p = af->LinearMem + af_memory - SOLIDPATTSTART;
|
|
for (i = 0; i < 8; i++) p[i] = 0xff;
|
|
} else {
|
|
p = af->BankedMem + DISPLACEMENT - SOLIDPATTSTART;
|
|
SetBank(af, af_last_bank);
|
|
for (i = 0; i < 8; i++) p[i] = 0xff;
|
|
}
|
|
return 0;
|
|
}
|