mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 09:39:32 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			126 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{ This program demonstrates the usage of DOS real mode memory by
 | 
						|
executing a software interrupt which needs a buffer to store data
 | 
						|
into. Because these interrupts are real mode funcs, the buffer must
 | 
						|
be located in real mode memory space (first MB of memory). Such
 | 
						|
memory can only be allocated by the global_dos_alloc() and
 | 
						|
global_dos_free() functions of the GO32 unit.
 | 
						|
 | 
						|
In more detail this program tries to detect a VESA 2.0 BIOS
 | 
						|
extension of your graphics card and outputs its version.
 | 
						|
 | 
						|
Here's the necessary interrupt call description:
 | 
						|
 | 
						|
  Int 10h 4f00h : VESA BIOS extension installation check
 | 
						|
  Input : AX = 4F00h
 | 
						|
          ES:DI = pointer to 512 byte information buffer
 | 
						|
  Output : AX = 004Fh if successful
 | 
						|
           ES:DI = pointer to filled buffer
 | 
						|
 | 
						|
  Buffer structure : (relevant to this example)
 | 
						|
 | 
						|
           must be 'VESA' in the first 4 chars of the buffer to be
 | 
						|
           valid VBE version in the next word
 | 
						|
 | 
						|
  Note : to request VBE 2.0 information, the first 4 bytes of the
 | 
						|
  	buffer must contain 'VBE2' prior to the interrupt call.
 | 
						|
 | 
						|
	(this makes the problem a bit tougher; we first have to copy the
 | 
						|
	buffer with the 'VBE2' id to dos memory...)
 | 
						|
}
 | 
						|
 | 
						|
uses
 | 
						|
	go32;
 | 
						|
 | 
						|
{The following 2 functions are wrappers to the GO32
 | 
						|
global_dos_alloc() and global_dos_free() functions to simplify their
 | 
						|
usage }
 | 
						|
 | 
						|
{ Function : dosalloc }
 | 
						|
{ Input    : size of a real mode location }
 | 
						|
{ Output   : selector and segment of a real mode location }
 | 
						|
procedure dosalloc(var selector : word;
 | 
						|
	var segment : word; size : longint);
 | 
						|
var
 | 
						|
	res : longint;
 | 
						|
begin
 | 
						|
	{ try to allocate real mode memory  }
 | 
						|
	res := global_dos_alloc(size);
 | 
						|
	{ the lower 16 bits of the result contain the selector to the
 | 
						|
	allocated memory block }
 | 
						|
	selector := word(res);
 | 
						|
	{ the upper 16 bits contain the real mode segment address of
 | 
						|
	this block; the offset is always 0, so we don't need to return
 | 
						|
	this }
 | 
						|
	segment := word(res shr 16);
 | 
						|
end;
 | 
						|
 | 
						|
{ Function    : dosfree }
 | 
						|
{ Input       : selector of a real mode block }
 | 
						|
{ Output      : none }
 | 
						|
{ Description : de-allocates a previously allocated real mode
 | 
						|
memory}
 | 
						|
procedure dosfree(selector : word);
 | 
						|
begin
 | 
						|
	{ call the GO32 function with the selector }
 | 
						|
	global_dos_free(selector);
 | 
						|
end;
 | 
						|
 | 
						|
type
 | 
						|
	VBEInfoBuf = packed record
 | 
						|
		{ contains 'VESA' if successful }
 | 
						|
		Signature : array[0..3] of char;
 | 
						|
		Version : Word;
 | 
						|
		{ pad to 512 bytes length }
 | 
						|
		reserved : array[0..505] of byte;
 | 
						|
	end;
 | 
						|
 | 
						|
var
 | 
						|
	{ selector to our real mode buffer }
 | 
						|
	selector,
 | 
						|
	{ real mode segment address of buffer }
 | 
						|
	segment : Word;
 | 
						|
 | 
						|
	{ register structure to issue a software interrupt }
 | 
						|
	r : trealregs;
 | 
						|
	infobuf : VBEInfoBuf;
 | 
						|
 | 
						|
begin
 | 
						|
	{ first we reset the registers and infobuf variable }
 | 
						|
	fillchar(r, sizeof(r), 0);
 | 
						|
	fillchar(infobuf, sizeof(VBEInfoBuf), 0);
 | 
						|
	{ allocate real mode memory }
 | 
						|
	dosalloc(selector, segment, sizeof(VBEInfoBuf));
 | 
						|
	{ check if an error occured during allocation }
 | 
						|
	if (int31error<>0) then begin
 | 
						|
		Writeln('Error while allocating real mode memory, halting');
 | 
						|
		halt;
 | 
						|
	end;
 | 
						|
	{ request VBE 2.0 information, fill out information buffer }
 | 
						|
	infobuf.Signature := 'VBE2';
 | 
						|
	{ copy buffer to the allocated real mode memory }
 | 
						|
	dosmemput(segment, 0, infobuf, sizeof(infobuf));
 | 
						|
	{ issue the interrupt; remember : DI = 0 }
 | 
						|
	r.ax := $4f00; r.es := segment;
 | 
						|
	realintr($10, r);
 | 
						|
	{ copy buffer to our infobuf variable again }
 | 
						|
	dosmemget(segment, 0, infobuf, sizeof(infobuf));
 | 
						|
	{ free allocated real mode memory, because we don't need it
 | 
						|
	anymore }
 | 
						|
	dosfree(selector);
 | 
						|
	{ check if interrupt call was successful }
 | 
						|
	if (r.ax <> $4f) then begin
 | 
						|
		{ write message and exit, because the infobuf doesn't contain
 | 
						|
		any useful data we could tell the user }
 | 
						|
		Writeln('VBE BIOS extension not available, function call ',
 | 
						|
			'failed');
 | 
						|
		halt;
 | 
						|
	end;
 | 
						|
	{ check if buffer is valid }
 | 
						|
	if (infobuf.signature[0] = 'V') and
 | 
						|
		(infobuf.signature[1] = 'E') and
 | 
						|
		(infobuf.signature[2] = 'S') and
 | 
						|
		(infobuf.signature[3] = 'A') then begin
 | 
						|
		Writeln('VBE version ', hi(infobuf.version), '.',
 | 
						|
			lo(infobuf.version), ' detected');
 | 
						|
	end;
 | 
						|
end. |