FreeBE/cirrus54/driver.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, &regs);
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, &regs);
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, &regs);
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, &regs);
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, &regs);
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, &regs);
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, &regs);
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;
}