_A VIDEO-COMPATIBILITY INTERFACE FOR TURBO DEBUGGER_ by Danny Thorpe {------------------------------------------------------------ Windows video interface DLL for Borland's Turbo Debugger for Windows 3.0 Orchid Fahrenheit 1280 graphics accellerator card driver version 1.0 ------------------------------------------------------------} { Copyright (C) 1992 by Danny Thorpe } {$D TDW 3.0 Video DLL 1.0 for Orchid Fahrenheit 1280 } {$A+,B-,D-,F-,G+,L-,N-,R-,S+,V+,W-,X+} library fahr1280; { This driver is for the Orchid Fahrenheit 1280 video card. The modes supported are 640x480x256 and 800x600x256. Borland does not provide technical support on this file or the TDW video DLL interface, and reserves the right to change the DLL requirements in future versions of TDW. The Fahrenheit's graphics coprocessor is an 86C911 by S3 Inc. The S3 Technical Reference was the source for all enhanced mode video information used by this driver. VESA bios calls are used to identify the Orchid card. -Danny Thorpe } uses Wintypes, Winprocs, strings; Type PWordArray = ^WordArray; WordArray = array [0..($FFF0 div sizeof(Word))] of Word; VesaInfoBlock = record Signature : array [1..4] of char; { not a PChar, = 'VESA'} VersionMinor : byte; VersionMajor : byte; OEMString : PChar; { points into BIOS } Capabilities : longint; VideoModes : PWordArray; { points to string of supported modes, $FFFF terminated} OrchidCardName: array [0..255-18] of char; { a copy of OEMString } { a copy of VideoModes array follows the OEMString null terminator} end; RealRegs = record { for DPMI simulated real mode interrupts } rDI, rSI, rBP, Reserved, rBX, rDX, rCX, rAX: Longint; rFLAGS, rES, rDS, rFS, rGS, rIP, rCS, rSP, rSS: Word; end; const { the Fahrenheit 1280 graphics modes } m640x480x256 = $201; { Works fine } m800x600x16 = $202; { not supported in this driver version} m800x600x256 = $203; { Works fine } m1024x768x16 = $204; { not supported in this driver version} m1024x768x256 = $205; { not supported in this driver version} m1280x960x16 = $206; { not supported in this driver version} m1280x1024x16 = $208; { not supported in this driver version} HighestVGAMode = $13; RegisterLock1 = $48; RegisterLock2 = $A0; VesaDontErase = $8000; var { global variables } GraphicsMode: Word; VGAPalette: array [0..255,0..2] of byte; LockStates: array [0..2] of byte; ColorScreen: Boolean; VGA50LineMode: Boolean; { Utility functions } procedure SavePalette; near; var i,j: byte; begin Port[$3C7] := 0; for j := 0 to 255 do for i := 0 to 2 do VGAPalette[j,i] := Port[$3C9]; end; procedure RestorePalette; near; var i,j: byte; begin Port[$3C8] := 0; for j := 0 to 255 do for i := 0 to 2 do Port[$3C9] := VGAPalette[j,i]; end; procedure LockEnhancedRegisters; near; { Disable coprocessor commands and register access } begin Port[$3d4] := $40; Port[$3d5] := Port[$3d5] and not 1; Port[$3d4] := $40; Port[$3d4] := $38; Port[$3d5] := $0; { lock 1 } Port[$3d4] := $39; Port[$3d5] := $0; { lock 2 } end; procedure UnlockEnhancedRegisters; near; { Give ourselves access to the graphics coprocessor commands & registers } begin Port[$3d4] := $38; Port[$3d5] := $48; { Enhanced mode unlock 1 } Port[$3d4] := $39; Port[$3d5] := $a0; { Enhanced mode unlock 2 } Port[$3d4] := $40; Port[$3d5] := Port[$3d5] or 1; { Enable Enhanced commands & registers } end; procedure SaveLockStates; near; begin Port[$3d4] := $38; LockStates[0] := Port[$3D5]; { Enhanced mode lock 1 = $48 if unlocked} Port[$3d4] := $39; LockStates[1] := Port[$3d5]; { Enhanced mode lock 2 = $A0 if unlocked } Port[$3d4] := $40; LockStates[2] := Port[$3d5] and 1; { Enable Enhanced commands & registers } end; procedure RestoreLockStates; near; begin UnlockEnhancedRegisters; Port[$3d4] := $40; Port[$3d5] := Port[$3d5] or LockStates[2]; Port[$3d4] := $38; Port[$3d5] := LockStates[0]; Port[$3d4] := $39; Port[$3d5] := LockStates[1]; end; function VESAGetVideoMode: Word; near; assembler; asm mov ax, $4F03 int $10 mov ax,bx { move video mode from bx to ax - our function result has to be in ax } end; function VESAGetInfo(var InfoBlock: VesaInfoBlock): Boolean; near; var Regs: RealRegs; Twins: Longint; { Use VESA bios calls to verify that this is an Orchid Fahrenheit 1280 card } { Since we have to pass a pointer to a buffer to this VESA call in the es:di registers, and BIOS requires real mode addresses, and real mode address can't be loaded into es:di in protected mode, we have to use a DPMI Simulate Real Mode Interrupt function. } begin Twins := GlobalDosAlloc(sizeof(InfoBlock)); asm mov di, ss mov es, di lea di, Regs push di mov cx, 21 { size of Regs } xor ax,ax cld rep stosw { zero out Regs data } pop di mov ax, $300 { DPMI Simulate Real Mode Interrupt function } mov word ptr Regs.rAX, $4F00 { vesa get info } mov bx, word ptr Twins[2] mov word ptr Regs.rES, bx { info block (for bios) is at es:0000, real mode } mov cx, 0 mov bx, $10 int $31 jc @@1 { jump if there was a DPMI error } mov ax, word ptr Regs.rAX push ds mov ds, word ptr Twins[0] xor si, si { info block (for us) is at ds:si, protected mode } les di, InfoBlock mov cx, 128 rep movsw { copy the data from the local block to the parameter } pop ds cmp al, $4F { Was vesa call accepted? } jne @@1 { If not, jump to error section } or ah,ah { Did the function execute successfully? } jnz @@1 { If not, jump to error section } mov @Result, 1 { vesa info successfully retreived } jmp @@2 @@1: mov @Result, 0 { fail the initiallization - incorrect video card } @@2: end; GlobalDosFree(LoWord(Twins)); end; {****************************************************************} function VideoInit: Word; export; { Called when TDW first loads up. All dynamic allocation and chip and video mode detection should be preformed here. Any failure will cause TDW to unload TDVIDEO.DLL. Return codes are: } const Success = 0; { success } BadCard = 1; { Incorrect video card was detected } BadMode = 2; { Unsupported video mode of correct card was detected } NoMemory= 3; { Could not allocate the memory needed from Windows } NoNeed = 4; { Regular video mode detected (TDVIDEO.DLL not required) } Error = 5; { Misc. error } var CardInfo: VESAInfoBlock; begin { Verify that we're running an Orchid Fahrenheit 1280 card. } if (not VESAGetInfo(CardInfo)) or (stricomp(CardInfo.OrchidCardName, 'Orchid Technology Fahrenheit 1280') <> 0) then begin VideoInit := BadCard; Exit; end; GraphicsMode := VESAGetVideoMode; case GraphicsMode of m640x480x256, m800x600x256 : ; { do nothing } else begin if GraphicsMode < HighestVGAMode then VideoInit := NoNeed else VideoInit := BadMode; Exit; end; end; VGA50LineMode := False; { 80x25 standard text mode} SaveLockStates; UnlockEnhancedRegisters; { Put the Fahrenheit card into dual-page (graphics and text) mode } asm mov ax, 4fffh mov bx, 2 int 10h end; ColorScreen := True; VideoInit := Success; end; {****************************************************************} function VideoDone: Word; export; { Called when TDW exits back to Windows. All memory allocated must be freed by the end of this function (Don't rely on ExitProc). 1 means success, 0 means it failed. } { All memory for this DLL is statically stored in the data segment. } begin RestoreLockStates; { Put the enhanced mode locks back the way we found them. } VideoDone := 1; end; { Magic functions to get the selectors of these areas of physical memory } procedure __B000; far; external 'KERNEL' index 181; procedure __B800; far; external 'KERNEL' index 182; {****************************************************************} function VideoGetTextSelector(Display: Integer): Word; export; { Called when TDW needs the selector (protected mode segment) value of the text mode screen requested. If display is 0, return the selector for 0xB800 (color). If display is 1, return the selector for 0xB000 (mono). This can be done with the Windows pre-defined selectors: _B800H and _B000H. } begin ColorScreen := Display = 0; if ColorScreen then VideoGetTextSelector := Ofs(__B800) else VideoGetTextSelector := Ofs(__B000); end; {****************************************************************} procedure VideoSetCursor(X, Y: Word); export; { Called when TDW needs to set the cursor position on the text mode screen. Most VGA cards can use the code here (since it's a non SuperVga register that controls the cursor position). TDW will call this function when it needs to make the cursor disappear (by placing it at an off-screen position). } var P: word; begin if ColorScreen then P := $3D4 else P := $3B4; X := X + Y * 80; Port[P] := $E; { cursor location high byte reg. } PortW[P+1]:= Hi(X); Port[P] := $F; { cursor location low byte reg. } PortW[P+1]:= Lo(X); end; {****************************************************************} procedure VideoSetSize(BigFlag: Word); export; assembler; { Called when TDW wants to switch the resolution of the text mode screen. Bigflag will be 1 if high res, 0 if low res. } asm lea bx, BigFlag mov ax, ss:[bx] or ax, ax jz @@1 { BigFlag = 1, so do 50 line text mode } mov byte ptr VGA50LineMode, 1 mov ax, $1112 { load 8x8 font } xor bx, bx int $10 jmp @@2 @@1: { else BigFlag = 0, so do 25 line mode } mov byte ptr VGA50LineMode, 0 mov ax, $1111 { load 8x14 font } xor bx, bx int $10 mov ax, $83 int $10 @@2: end; {****************************************************************} procedure VideoDebuggerScreen; export; { Called when TDW wants to switch to the text mode screen. This function must save the appropriate memory locations, save the VGA palette, and switch to text mode. } begin if ColorScreen then { We're assuming that a mono screen will be dual monitor } begin SavePalette; asm mov ax, $83 { select text mode $03, don't clear the screen ($80) } int $10 end; VideoSetSize(word(VGA50LineMode)); end; end; {****************************************************************} procedure VideoWindowsScreen; export; { Called when TDW wants to switch back to the Windows screen. This function must switch back to the original graphics mode, restore the palette, and restore the SuperVGA graphics memory planes that were blown away by text mode. } begin if ColorScreen then begin asm mov ax, $4f02 mov bx, word ptr GraphicsMode or bx, VesaDontErase { don't erase the graphics or text screens } int 10h end; RestorePalette; end; end; {****************************************************************} function VideoBigSize: Word; export; assembler; { Called when TDW needs to determine if there is a higher resolution text mode availible (usually 43 or 50 lines). The maximum number of lines that this you are able to support should be returned here. } asm mov ax,50 end; {****************************************************************} function VideoIsColor: Word; export; assembler; { Returns 1 for color, and 0 for monochrome; } asm xor ax, ax mov al, byte ptr ColorScreen end; exports VideoDone, VideoInit, VideoGetTextSelector, VideoDebuggerScreen, VideoWindowsScreen, VideoSetCursor, VideoSetSize, VideoBigSize, VideoIsColor; begin end.