XTCFMODE Source
Jump to navigation
Jump to search
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}