unit Vesa;

{ VESA support for GR,
  Copr. 1994, 1996 Matthias K"oppe

  Simply link this unit to your program, and all VESA modes will
  be available with the graphic modules using GR. Don't care about
  the things in the interface.
 
  $Id: vesa.pas 1.3 1999/02/09 10:51:26 mkoeppe Exp $

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}

interface

{ Vesa-specific map address function
}
const
  qVesaMapAddr = 40;

{ Vesa-specific init graphics function
}
const
  qInitVesaGraph = 40;

function InitVesaGraph: Boolean;

{ Vesa-driver detection
}
function DetectVesa: Boolean;

{ Enable second screen page
}
function EnablePage1: Boolean;

implementation

uses Gr, VesaInt;

function DetectVesa: Boolean;
Begin
  AllocInfoArea(256);
  DetectVesa := GetVesaInfo;
  FreeInfoArea
End;

procedure SetStdMapAddr;
Begin
  MapAddrProc := VgaMapAddr
{  If qVesaMapAddr > qMapAddrProc
  then Begin
    AllocInfoArea(256);
    If GetVesaModeInfo($102) then Begin
      qMapAddrProc := qVesaMapAddr;
      @MapAddrProc := MapFunc(PVesaModeInfo(InfoPtr)^.vmPositionProc)
    End;
    FreeInfoArea
  End}
End;

{$L vesamem.obj (vesamem.asm) }

function ld(x: Word): ShortInt; near; external;
procedure DetermineEndSeg; near; external;
function CalcPageSize: Word; near; external;

{/$L}

function DesiredVesaMode: Word;
begin
  case GrMode of
    gr640x480x256:
      DesiredVesaMode := $101;
    gr800x600x16:
      DesiredVesaMode := $102;
    gr800x600x256:
      DesiredVesaMode := $103;
    gr1024x768x16:
      DesiredVesaMode := $104;
    gr1024x768x256:
      DesiredVesaMode := $105;
    gr1280x1024x16:
      DesiredVesaMode := $106;
    gr1280x1024x256:
      DesiredVesaMode := $107;
    gr640x400x256:
      DesiredVesaMode := $100;
    else
      DesiredVesaMode := 0
  end
end;

function InitVesaGraph: Boolean;
var
  VesaMode: Word;
Begin
  VesaMode := DesiredVesaMode;
  If VesaMode = 0
  then InitVesaGraph := InitBiosGraph
  else begin
    SaveTextMode;
    InitVesaGraph := SetVesaMode(VesaMode)
  end
End;

function EnablePage1: Boolean;
var
  PageSize: Word;
Begin
  EnablePage1 := false;
  PageSize := Free1Seg - Page0Seg;
  If Free1Seg + PageSize <= EndSeg then Begin
    Page1Seg := Free1Seg;
    Free1Seg := Free1Seg + PageSize;
    EnablePage1 := true
  End
End;

var
  NextNotifyEarly,
  NextNotifyLate: TNotifyProc;
  ProtCode: pointer;

procedure vesaInitGraphics;
var
  Info: TVesaModeInfo;
  VesaMode: Word;
  m: LongInt;
  Res: Boolean;

	procedure FailInit;
	begin
	  RestoreTextMode;
	  WriteLn('VESA: Cannot access adaptor.');
	  Halt(1)
	end;

Begin
  VesaMode := DesiredVesaMode;
  If VesaMode <> 0
  then begin
    AllocInfoArea(256);
    Res := GetVesaModeInfo(VesaMode);
    Move(InfoPtr^, Info, 256);
    FreeInfoArea;
    If not Res then FailInit;
    with Info do
    begin
      If vmModeAttrib and vmaSupported = 0 then FailInit;
      If vmAWindowAttrib and (vwaExists + vwaReadable + vwaWritable) <>
	 (vwaExists + vwaReadable + vwaWritable) then FailInit;
      If GrFlags and gfMap <> 0
      then begin
	MapGranRight 	:= ld(vmGranularity) + 10;
	MapGranLeft	:= 16 - MapGranRight;
	MapGran32       := 32 - MapGranRight;
	WindowSize32 	:= LongInt(vmWindowSize) shl 10;
	OffsetMask32 	:= WindowSize32 - 1;
	MapGranMask32	:= LongInt(vmGranularity) shl 10 - 1;
	GransPerWindow 	:= vmWindowSize div vmGranularity;
	WindowAddr 	:= SelOfsZero(Ptr(vmAWindowSegment, 0));
{$ifdef DPMI}
{	ProtCode := GetProtModeCode(vpmSetBank);
	If ProtCode <> nil
	then @MapAddrProc := ProtCode
	else}
{$endif}
	     @MapAddrProc := MapFunc(vmPositionProc);
      end;
      RealBytesPerLine32  := vmBytesPerLine;
      BytesPerLine32 	  := vmBytesPerLine;
    end
  end;
  If GrFlags and gfMap <> 0
  then begin
    DetermineEndSeg;
    Free1Seg := Page0Seg + CalcPageSize
  end
End;

procedure vesaCloseGraphics;
Begin
{$ifdef DPMI}
  FreeProtModeCode(ProtCode);
  ProtCode := nil;
{$endif}
  SetStdMapAddr
End;

function NotifyVesaEarly(Notice: Word; Info: LongInt): LongInt; far;
Begin
  case Notice of
    gnpInitGraphics:
      vesaInitGraphics;
  end;
  NotifyVesaEarly := DefaultNotify(Notice, Info, NotifyVesaEarly, NextNotifyEarly, 50);
End;

function NotifyVesaLate(Notice: Word; Info: LongInt): LongInt; far;
Begin
  case Notice of
    gnpCloseGraphics:
      vesaCloseGraphics;
  end;
  NotifyVesaLate := DefaultNotify(Notice, Info, NotifyVesaLate, NextNotifyLate, 5);
End;

begin
  ProtCode := nil;
  If DetectVesa then Begin
    If qInitVesaGraph > qInitGraphProc then Begin
      qInitGraphProc := qInitVesaGraph;
       InitGraphProc :=  InitVesaGraph
    End;
    SetStdMapAddr;
    InstallNotifyProc(GrNotifyProc, NotifyVesaEarly);
    InstallNotifyProc(GrNotifyProc, NotifyVesaLate)
  End
end.
