program IDE_Info;

{
 IDEINFO.PAS -- v0.1
 
 Reports IDE information from installed IDE hard drives.

 TP source code written by Scott Earnest (setech@ix.netcom.com), 1997.

 Based closely on C code written by Doug Merrett (dcm@mincom.oz.au),
 available on sites as DUG_IDE.C in DUGIDE10.ZIP.

 Disclaimer:  Standard.  It works on my system, I can't guarantee it will
 work on yours.

 Known problems:  WILL NOT WORK IN A WIN95 DOS SESSION.  This may have
 something to do with the way Win 95 intercepts low-level I/O in its DOS
 sessions.  It will, however, work under DOS 7.0 if you boot directly to
 DOS without starting Win 95.

 Note:  This code is rather sloppy and IMHO not well organized.  There are
 very few comments, so modify at your own risk.  Also intended to work with
 the first IDE channel only.
}

uses
  crt, dos;

const
  ret_val : string = '';
  outval : array[0..1] of byte = ($a0,$b0);

var
  num_drv : byte;
  dd : array[0..255] of word;
  dd_off : word;
  loop : word;
  ddc : array[0..511] of char absolute dd;
  reg : registers;
  bios_cyl, bios_head, bios_sec : array[0..1] of word;  { Cylinders, Heads,
Sectors }

function getascii (in_data : array of word; off_start, off_end : word) :
string;

var
  wk : array[0..511] of char;
  loop, loop1 : word;

begin
  loop1 := 1;
  for loop := off_start to off_end do
    begin
      ret_val[loop1] := char(hi(in_data[loop]));
      inc (loop1);
      ret_val[loop1] := char(lo(in_data[loop]));
      inc (loop1);
    end;
  ret_val[0] := char(succ(off_end-off_start)*2);
  getascii := ret_val;
end;

begin
  assign (input,'');
  reset (input);
  assign (output,'');
  rewrite (output);
  directvideo := false;
  textattr := $1f;
  num_drv := mem[Seg0040:$75];
  for loop := 0 to pred(num_drv) do
    begin
      while port[$1f7]<>$50 do ; {wait until controller not busy}
      port[$1f6] := outval[loop];
      port[$1f7] := $ec;
      while port[$1f7]<>$58 do ; {wait for data ready}
      for dd_off := 0 to 255 do
        dd[dd_off] := portw[$1f0];

      for dd_off := 0 to 255 do
        write (char(hi(dd[dd_off])),char(lo(dd[dd_off])));
     { Get BIOS drive info }

      reg.ah := $08;            { Get drive info }
      reg.dl := $80+loop;    { Drive is 80H for Disk 0, 81H for Disk 1 }
      intr ($13,reg);
      if (reg.flags and fCarry=0) then  { All OK if carry not set }
        begin
          bios_head[loop] := reg.dh+1; { Heads are from 0 }
          bios_sec[loop] := reg.cl and $3F; { sec is bits 5 - 0 }
          bios_cyl[loop] := ((reg.cl and $C0) shl 2)+reg.ch+2; { +1 because
starts from 0 and +1 for FDISK leaving one out }
        end;

      writeln ('DRIVE ', loop);
      writeln ('Model Number______________________: ', getascii (dd, 27,
46));
      writeln ('Serial Number_____________________: ', getascii (dd, 10,
19));
      writeln ('Controller Revision Number________: ', getascii (dd, 23,
26));
      writeln;
      write ('Able to do Double Word Transfer___: ');
      if dd[48]=0 then
        writeln ('No')
      else
        writeln ('Yes');
      writeln ('Controller type___________________: ', dd[20]);
      writeln ('Controller buffer size (bytes)____: ',
longint(dd[21])*512);
      writeln ('Number of ECC bytes transferred___: ', dd[22]);
      writeln ('Number of sectors per interrupt___: ', dd[47]);
      writeln;
      writeln ('Hard Disk Reports');
      writeln ('Number of Cylinders (Fixed)_______: ', dd[1]);
      writeln ('Number of Heads___________________: ', dd[3]);
      writeln ('Number of Sectors per Track_______: ', dd[6]);
      writeln;
      writeln ('BIOS Reports');
      writeln ('Number of Cylinders_______________: ', bios_cyl[loop]);
      writeln ('Number of Heads___________________: ', bios_head[loop]);
      writeln ('Number of Sectors per Track_______: ', bios_sec[loop]);
      writeln;
      if loop<>1 then
        begin
          writeln ('Press a key');
          readkey;
        end;
    end;
end.

