XTCFMODE Source
Revision as of 21:08, 5 June 2013 by Lo-tech>James (Initial content)
Source code for the XTCFMODE utility, which can be compiled using Turbo Pascal 6. Compiled code can be downloaded here.
Code
Program XTCFMode;
{For XT-CF family of adapters, lists current mode and changes the mode.
Dependent on XTIDE Universal BIOS, version 2 or newer.}
uses dos, crt;
type
tSectorBuffer = Array[0..511] of BYTE;
pSectorBuffer = ^tSectorBuffer;
const
Version = '0.32';
Author = 'James Pearce';
BuildDate = '05-May-13';
HelpNameOnly = 1;
HelpQuick = 2;
HelpFull = 4;
XTCF_8BIT_PIO_MODE = $00;
XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD = $01;
XTCF_DMA_MODE = $02;
INVALID_MODE = $04;
DEVICE_ERROR = $08;
var
VERBOSE : BOOLEAN;
Procedure PrintHelp(mode : byte);
begin
WriteLn('XTCFMODE - transfer mode utility for XT-CF family of adapters.');
WriteLn('See http://www.lo-tech.co.uk/XT-CF');
WriteLn;
If mode = HelpFull then
begin
WriteLn;
WriteLn('To display current mode: xtcfmode [BIOS_drive_number]');
WriteLn('To change mode: xtcfmode [BIOS_drive_number] set [mode]');
WriteLn(' where [mode] is one of:');
Write(' ',XTCF_8BIT_PIO_MODE);
WriteLn(' - for PIO 8-bit (slowest & safest)');
Write(' ',XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD);
WriteLn(' - for PIO 16-bit (faster on most systems, but depends on proper BIU');
WriteLn(' implementation on system board - won''t work with AT&T PC6300)');
Write(' ',XTCF_DMA_MODE);
WriteLn(' - for DMA mode (via channel 3, supported by XT-CFv3 adapter only);');
WriteLn(' fastest on 8088 hardware');
WriteLn;
WriteLn('Specify [BIOS_drive_number] in hex, i.e. 80h, 81h etc');
end;{if mode =}
end;{procedure PrintHelp}
Function GetMode( Device : Byte ) : byte;
var
Regs : Registers;
begin
with regs do begin
ah := $1E; {XT-CF functions}
al := 2; {get XT-CF transfer mode}
dl := Device;
end;
Intr($13,regs);
if regs.flags and FCarry = FCarry then GetMode := DEVICE_ERROR
else GetMode := regs.DH; {return mode}
WriteLn('Read mode: ', regs.DH);
WriteLn('Block mode sectors: ', regs.DL);
end;{function GetMode}
Function SetMode( Device, Mode : Byte ) : Byte;
var
regs : registers;
begin
with regs do begin
ah := $1E;
al := 1; {set mode}
dl := Device;
dh := Mode;
end;{with}
Intr($13,regs);
if regs.flags and FCarry = FCarry then SetMode := DEVICE_ERROR
else SetMode := Mode; {return mode set}
end;{function}
FUNCTION ReadSectors(drive, head, track, sector, numtoread : Byte; buff: Pointer): Byte; assembler;
{function courtesy of Trixter - http://trixter.oldskool.org/}
{ drive = 0 for drive A:, 1 = B:, }
{ 80h = first hard drive. }
ASM
mov ah,02h
mov al,numtoread
les bx,buff { es:bx -> buffer }
mov ch,track
mov cl,sector
mov dh,head
mov dl,drive
int 13h
{numsectors read in al, status in ah, cf=0 if successful}
END;
function BuffersMatch(Buff1, Buff2 : pSectorBuffer) : Boolean;
var
i,j,a,b,k : word;
Error : Boolean;
begin
If VERBOSE then WriteLn('Comparing buffers...');
Error := false;
for i := 0 to Pred(SizeOf(tSectorBuffer)) do
if Buff1^[i] <> Buff2^[i] then
begin
Error := true;
k := i;
i := Pred(SizeOf(tSectorBuffer));
end;{if}
BuffersMatch := Not Error;
If VERBOSE then begin
Write('Buffers ');
if Error then begin
WriteLn('did not match. Trace:');
WriteLn('Ofs Buff1 Buff2');
if k > 10 then a := k - 10 else a := 0;
if k < 500 then b := k + 10 else b := 511;
for j := a to b do
WriteLn(j,' ',Buff1^[j],' ',Buff2^[j]);
end else Write('matched.');
end;
end;{function}
Function ParamSpecified(s : string) : boolean;
{returns true is s was specified in a command line parameter,
either directly or via - or /, e.g. these are equivalent: h, -h, /h}
var
i,x : byte;
found : boolean;
comp : string;
begin
found := false;
for x := 1 to length(s) do s[x] := UpCase(s[x]);
for i := 1 to ParamCount do
begin
comp := ParamStr(i);
for x := 1 to length(s) do comp[x] := UpCase(comp[x]);
if (comp[1] = '/') or (comp[1] = '-') then
if length(comp) > 1 then comp := copy( comp,2,pred(length(comp)) )
else comp := '';
if comp = s then found := true;
if found then i := ParamCount;
end;{for}
ParamSpecified := found;
end;{function ParamSpecified}
var
res, Device, mode : byte;
valres : integer;
error : Boolean;
Buffer1, Buffer2 : pSectorBuffer;
Ch : Char;
begin
If (ParamCount = 0) or (ParamSpecified('?')) or (ParamSpecified('h')) then
PrintHelp(HelpFull)
else begin
Device := 0;
{first check for verbose mode}
if ParamSpecified('vv') then VERBOSE := TRUE else VERBOSE := FALSE;
{user gave some parameters, so see what we're doing}
if VERBOSE then WriteLn('Checking parameters...');
if (ParamStr(1) = '80') or (ParamStr(1) = '80h') then Device := $80;
if (ParamStr(1) = '81') or (ParamStr(1) = '81h') then Device := $81;
if (ParamStr(1) = '82') or (ParamStr(1) = '82h') then Device := $82;
if (ParamStr(1) = '83') or (ParamStr(1) = '83h') then Device := $83;
if Device = 0 then
begin
if VERBOSE then WriteLn('Device still 0 - exiting');
PrintHelp(HelpFull)
end else begin
if (ParamSpecified('set')) and (ParamCount >= 3) then
begin
Val(ParamStr(3),mode,valres);
if valres <> 0 then PrintHelp(HelpFull)
else begin
{all looks OK}
{if BIU_OFFLOAD was specified, also perform a disk read test to confirm if it's supported}
If VERBOSE then WriteLn('Allocating buffers');
New(Buffer1); New(Buffer2);
error := false;
if Mode = XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD then
begin
{first perform a read against sector 1, which hopefully should always have something on it}
If VERBOSE then WriteLn('Attempting to read 1st sector of selected device');
if ReadSectors(Device,0,0,1,1,Buffer1) AND $00FF <> 1 then Error := true;
end;
if not error then
begin
case SetMode(Device,Mode) of
XTCF_8BIT_PIO_MODE : WriteLn('8-bit PIO mode selected.');
XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD : WriteLn('8-bit PIO with BIU offload mode selected.');
XTCF_DMA_MODE : WriteLn('DMA mode selected.');
INVALID_MODE : begin
WriteLn('Invalid mode specified.');
Error := true;
end;
DEVICE_ERROR : begin
WriteLn('Selected device not XT-CF.');
Error := true;
end;
end;{case}
If VERBOSE then
begin
if error then WriteLn('Error flag set - SetMode() failed. Continuing anyhow.')
else WriteLn('SetMode() succeeded.');
end;{if VERBOSE}
if (Mode = XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD) and (not error) then
begin
{read sector 1 again, and check it matched the first read}
If VERBOSE then WriteLn('Attempting to read 1st sector of selected device again');
if ReadSectors(Device,0,0,1,1,Buffer2) AND $00FF <> 1 then Error := true;
if not error then
begin
If VERBOSE then WriteLn('Read second buffer OK');
if not BuffersMatch(Buffer1,Buffer2) then
begin
WriteLn('It appears that BIU offload mode is not supported on this machine.');
Write('Reset to 8-bit PIO <Y/N>? ');
Repeat Ch := UpCase(ReadKey) until Ch in ['Y','N'];
WriteLn(Ch);
if Ch = 'Y' then
begin
if SetMode(Device,XTCF_8BIT_PIO_MODE) <> XTCF_8BIT_PIO_MODE then
begin
WriteLn('WARNING: Unable to return device to 8-bit PIO mode. Restart system to');
Write(' avoid system corruption.');
repeat Ch := ReadKey; until Ch = 'C'; {soft hang}
end else WriteLn('8-bit PIO mode selected.');
end;{if Ch='Y'}
end;{if not BuffersMatch}
end;{if not error}
end;
If VERBOSE then WriteLn('About to dispose of buffers');
Dispose(Buffer1); Dispose(Buffer2);
If VERBOSE then WriteLn('Buffer RAM freed');
end {if not error}
else WriteLn('Error encountered reading from specified device.');
end;{if/else}
end {if ParamSpecified('set')}
else if ParamCount = 1 then
begin
PrintHelp(HelpNameOnly);
Write('Device ',ParamStr(1),': ');
case GetMode(Device) of
XTCF_8BIT_PIO_MODE : WriteLn('8-bit PIO');
XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD : WriteLn('8-bit PIO with BIU offload');
XTCF_DMA_MODE : WriteLn('DMA');
DEVICE_ERROR : WriteLn('Device is not XT-CF.');
end;{case}
end {if ParamCount}
else PrintHelp(HelpFull);
end;{if Device = 0/Else}
end;{if ParamCount = 0}
If VERBOSE then WriteLn('Program terminating - returning control to OS.');
END.{Program}