Contributor: ARNE DE.BRUIJN

{
 RP> Has anyone any ideas how to interrogate an IDE drive to get
 RP> its setup parameters
}

{ Read IDE drive info, Arne de Bruijn, 1994, PD }
{ Information from 'Alles over PC Hardware' by Hans-Peter Messmer }

{$G+}
uses Crt,Dos;

var
 Buffer:pointer;
{ Buffer filled with following information (word offsets):
  0 configuration:
    bit 0 reserved
        1 1=hard-sector drive
        2 1=soft-sector drive
        3 1=RLL/ARLL format
        4 1=headswitchdelay is 15 ms
        5 1=less currency mode implented
        6 1=hard disk
        7 1=exchangable medium (mostly CD-ROM drive)
        8 1=internal datatransfer <5 Mbit/s
        9 1=internal datatransfer between 5 and 10 Mbit/s
       10 1=internal datatransfer >10 Mbit/s
       11 1=rotation speed toleration >0,5% (notebook)
       12-15 reserved
  1 no of physical cylinders
  2 reserved
  3 no of heads
  4 no of not-formatted bytes per physical sector
  5 no of not-formatted bytes per sector
  6 no of physical sectors
  7-9 reserved for manufacturer
 10-19 ASCII serial number
 20 buffertype (01h one-directional, 02h bi-directional, 03h=cache buffer)
 21 buffersize/512
 22 no of ECC bytes transferred at read/writelong cmds
 23-26 ASCII controller-firmware ID
 27-46 ASCII modelnumber
 47 bit 0..7 no of sectors between two interrupts, bit 8..15 reserved
 48 bit 0: 1=32 bit-I/O, 0 no 32 bit-I/O, bit 1..7 reserved
 49 bit 0..7 reserved, bit 8: 1=DMA, 0=no DMA, bit 9: 1=LBA, 0=no LBA
 50 reserved
 51 bit 0..7 reserved, bit 8..15 PIO cyclus time
    (0=600ns, 1=380ns, 2=240ns, 3=180ns)
 52 bit 0..7 reserved, bit 8..15 DMA cyclus time
    (0=960ns, 1=380ns, 2=240ns, 3=150ns)
 53 reserved
 54 no of logical cylinders
 55 no of logical heads
 56 no of logical sectors per track
 57-58 Bytes per logical sector
 59 bit 0..7 no of sectors
 60-61 addressable sectors in LBA mode
 62 single DMA: bit 0..7=supported modes, bit 8..15=active modes
 63 multiple DMA: bit 0..7=supported modes, bit 8..15=active modes
 64-127 reserved
 128-159 manufacturer specific
 160-255 reserved
}
 GotData:boolean;

function SwitchChars(var X; Len:byte):string; assembler;
{ Returns Len bytes from X, each word swapped }
asm
 push ds
 les di,@Result
 xor ah,ah
 mov al,Len
 mov cx,ax
 shl al,1
 stosb
 jcxz @NoCopy
 lds si,X
@Copy:
 lodsw
 xchg al,ah
 stosw
 loop @Copy
@NoCopy:
 pop ds
end;

procedure HDInt; interrupt;
{ Interrupt called when data is ready }
begin
 if Port[$1f7] and 8<>0 then
  begin
   asm
    mov dx,1f0h
    les di,Buffer
    mov cx,256
    rep insw            { Get 256 words (512 bytes) }
   end;
   GotData:=true;
  end;
 Port[$a0]:=$20;        { Send EOI to PIC 2 }
 Port[$20]:=$20;        { Send EOI to PIC 1 }
end;

type
 AWord=array[0..32766] of word;
var
 Timer:longint absolute $40:$6c;
 Slave:boolean;
 LastTimer,T:byte;
 OldInt:pointer;
 OldPic1M,OldPic2M:byte;
begin
 Clrscr;
 Slave:=false; { True is check for slave, false check for master }
 GetMem(Buffer,512);
 T:=2;         { Wait 2 clock ticks }
 while (Port[$1f7] and $c0<>$40) and (T>0) do
  if byte(Timer)<>LastTimer then begin Dec(T); LastTimer:=byte(Timer); end;
 if Port[$1f7] and $c0<>$40 then
  begin
   WriteLn('Timeout 1!');
   Halt(1);
  end;
 GetIntVec($76,OldInt);   { Set interrupt (IRQ 14 = int $76) }
 SetIntVec($76,@HDInt);
 OldPic1M:=Port[$21]; OldPic2M:=Port[$a1]; { Save PIC masks }
 Port[$21]:=OldPic1M and (not 4);   { Enable IRQ 14 }
 Port[$a1]:=OldPic2M and (not 64);
 GotData:=false;
 Port[$1f6]:=$a0+byte(Slave)*16;    { Send drive no }
 Port[$1f7]:=$EC;                   { Send command code }
 T:=3;
 while (not GotData) and (T>0) do
  if byte(Timer)<>LastTimer then begin Dec(T); LastTimer:=byte(Timer); end;
 Port[$21]:=OldPic1M; Port[$a1]:=OldPic2M; { Restore PIC masks }
 SetIntVec($76,OldInt);   { Restore interrupt }
 if not GotData then
  begin
   WriteLn('Timeout 2!');
   Halt(1);
  end;
 WriteLn('Heads:',AWord(Buffer^)[3],' Cylinders:',AWord(Buffer^)[1],
  ' Sectors:',AWord(Buffer^)[6]);
 WriteLn('Serial number:',SwitchChars(AWord(Buffer^)[10],10));
 WriteLn('Controller firmware ID:',SwitchChars(AWord(Buffer^)[23],4));
 WriteLn('Modelnumber:',SwitchChars(AWord(Buffer^)[27],20));
 Port[$1F6]:=$a0+byte(Slave)*16;
 FreeMem(Buffer,512);
end.