home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / DSUTIL11 / IDE-ATA / IDE-ATA.PAS < prev   
Pascal/Delphi Source File  |  1993-11-28  |  67KB  |  1,694 lines

  1. {-----------------------------------------------------------------------}
  2. { PROJECT        NON-PROFIT HIGH QUALITY PROFESSIONAL SOFTWARE,  }
  3. {            AVAILABLE FOR ALL WORLD                }
  4. { LIBRARY        SYSTEM UTILITIES                                }
  5. { MODULE        IDE_ATA_DRIVE_INFO                              }
  6. { FILE NAME        IDE-ATA.PAS                    }
  7. { PURPOSE        Read IDE/ATA-drive internal information         }
  8. { VERSION        1.31                        }
  9. { DATE            25-Nov-93                    }
  10. { DESIGN        Dmitry Stefankov                }
  11. {                       (Original idea of Thomas J. Newman, 1991)       }
  12. { IMPLEMENTATION    Dmitry Stefankov                 }
  13. { COMPANY        Freelance Software Engineer            }
  14. { ADDRESS        Isakowskogo str, 4-2-30                }
  15. {            Moscow, 123181                    }
  16. {            USSR                        }
  17. {            Tel. 007 (095) 944-6304                }
  18. { COPYRIGHT NOTICE    Copyright (C) 1987-1993, Dmitry Stefankov    }
  19. { RESTRICTED RIGHTS    AVAILABLE ONLY FOR FREE DISTRIBUTION,           }
  20. {            NOT FOR COMMERCIAL PURPOSE            }
  21. { COMPUTER        IBM PC or compatible                }
  22. { OPERATING SYSTEM    MS/PC-DOS Version 3.30 or higher        }
  23. { COMPILER        Turbo Pascal Version 6.0            }
  24. {                       (Borland International Inc.)  or compatible     }
  25. { ASSEMBLY LANGUAGE    Microsoft MASM 5.10 or compatible               }
  26. { LINKER        Turbo Pascal internal                           }
  27. { ARGUMENTS        <screenlines>  ---  # lines for each screen page}
  28. {            <filewrite>    ---  any string to ask filename  }
  29. {                       <cmos|all|max> ---  find all match CMOS parms   }
  30. {                        (any string except <CMOS>)    }
  31. {                        and/or display HDD ROM table}
  32. { RETURN        None                        }
  33. { REQUIRES        None                                            }
  34. { NATURAL LANGUAGE      English Language                                 }
  35. { SPECIAL        Please note this program can have the problem    }
  36. {            with some 80286 (usually older) mainboards     }
  37. {            because their manufacturers don't wish to cor-    }
  38. {            rectly implement the ATA/IDE standard interface.}
  39. { DESCRIPTION        1. Test drive 0 hardware for primary controller }
  40. {                       2. If hardware test successful                  }
  41. {                             then issue IDENTIFY command for IDE-drive }
  42. {                       3. If command not failed                        }
  43. {                            then display lot of info about drive,      }
  44. {                            and ask about write buffer to file,        }
  45. {                            and display possible logical configuration }
  46. {                            for drive through linear translation       }
  47. {                       4.  Repeat steps  1 - 3  for (like above step)  }
  48. {                            drive 1 on primary controller              }
  49. {                            drive 0 on secondary controller            }
  50. {                            drive 1 on secondary controller            }
  51. {                       5. Display ROM BIOS HDD types table             }
  52. {                       6. Get # of hard disks from System BIOS         }
  53. {                       7. Display # of found IDE/ATA-drives            }
  54. { REVISION HISTORY    Dima Stefankov (DS)                }
  55. {               1.00   26-Aug-92  DS  initial release        }
  56. {                       1.01   27-Aug-92  DS  some corrections          }
  57. {                       1.02   29-Aug-92  DS  correct some bugs         }
  58. {                       1.10   08-Oct-92  DS  added buffer write to file}
  59. {                       1.11   27-Oct-92  DS  some corrections          }
  60. {                       1.12   02-Nov-92  DS  some style changes        }
  61. {            1.20   24-Feb-93  DS  fixed a bug with hexflags,}
  62. {                          added PLO bytes parameter    }
  63. {            1.21   04-Jul-93  DS  updated documentation    }
  64. {                       1.22   30-Aug-93  DS  added paged screen output }
  65. {            1.23   09-Sep-93  DS  changed parameters order    }
  66. {            1.24   24-Sep-93  DS  added CMOS suggested parms}
  67. {                                             calculations screen, also }
  68. {                                             added display of ROM BIOS }
  69. {                                             HDD types table for CMOS  }
  70. {                                             disk parameters setup, and}
  71. {                          fixed a bug with task file}
  72. {                          loading                }
  73. {                       1.30   19-Oct-93  DS  added more ATA parameters }
  74. {                                             according ATA draft stand-}
  75. {                                             dard r4a of April 1993    }
  76. {            1.31   25-Nov-93  DS  fixed a timing problem for}
  77. {                          a buffer reading (DRQ bit }
  78. {                          checking)            }
  79. {-----------------------------------------------------------------------}
  80.  
  81.  
  82. {*======================= PROGRAM HEADER PART ==========================*}
  83.  
  84. PROGRAM   READ_IDE_ATA_DRIVE_INFO;
  85.  
  86.  
  87.  
  88. {*** other modules ***}
  89. {*USES;*}
  90.  
  91. {** switches for compilation **}
  92. {$S-}        {*  stack checking   *}
  93. {$R-}           {*  range checking   *}
  94.  
  95.  
  96. {** miscellaneous version **}
  97. {***$DEFINE  DebugVersion}        {* generate a debugging version *}
  98.  
  99.  
  100.  
  101. {*========================== CONSTANTS PART ============================*}
  102.  
  103. CONST
  104.      asPurpose                  =       'IDE/ATA DRIVE INFO';
  105.      asVersion                  =       '1.31';
  106.      asAuthor                   =       'Dima Stefankov';
  107.      asCopyright                =       'Copyright (c) 1987, 1993';
  108.      asProgram                  =       'IDE/ATA-Info';
  109.      asProgramPrompt            =       asProgram+': ';
  110.  
  111.      { exit codes }
  112.        errTerminateOK           =     0;
  113.        errUserAbort             =     1;
  114.        errBadNumeric            =     2;
  115.        errBadCPU                =     3;
  116.        errBadSecsNum            =     4;
  117.  
  118.     { miscellaneous }
  119.       achSpace                  =     ' ';
  120.       asBlank                   =     '';
  121.       achHexPrefix              =     '$';
  122.       achDosDelim               =     '.';
  123.       asDefExt                  =     'bin';
  124.       asPrimary                 =     'primary';
  125.       asSecondary               =     'secondary';
  126.       aPercent100               =     100;
  127.  
  128.      { screen output }
  129.        aDisableScreenPage       =     0;
  130.        aMinOutLineOnScreen      =     1;
  131.        aDefMaxOutLineForScreen  =     23;
  132.        aBigOutLinesForScreenNum =     2048;
  133.  
  134.      { Dos equates }
  135.        aBytesPerKByte           =     1024;
  136.        aKBytesPerMbyte          =     1024;
  137.        aBytesPerDosSector       =     512;
  138.        aWordsPerDosSector       =     aBytesPerDosSector DIV 2;
  139.        aPhysDriveNum_0          =     0;
  140.        aPhysDriveNum_1          =     1;
  141.  
  142.      { Bios equates }
  143.        aMinBiosCylNum           =     0;
  144.        aMaxBiosCylNum           =     1023;
  145.        aMinBiosHeadNum          =     0;
  146.        aMaxBiosHeadNum          =     255;
  147.        aMinBiosSecNum           =     1;
  148.        aMaxBiosSecNum           =     63;
  149.        aDefStdDosBiosSecNum     =     17;
  150.        aStartHeadNum            =     aMinBiosHeadNum + 1;
  151.        aMinHDD_CMOSType         =     1;
  152.        aMaxHDD_CMOSType         =     47;
  153.        aRomBiosSeg              =     $F000;
  154.  
  155.      { magic words }
  156.        asNoFileToAsk        =    'NOFILE';
  157.        asHddTableDisplayOnly    =    'CMOS';
  158.        asMaxCapacityOnly    =    'MAX';
  159.  
  160.      { Bit-mapped flags }
  161.        btIdeDrive_00            =     $01;
  162.        btIdeDrive_01            =     $02;
  163.        btIdeDrive_02            =     $04;
  164.        btIdeDrive_03            =     $08;
  165.  
  166.      { PC hardware ports }
  167.        aDriveCtrlrBaseReg_0     =     $1F0;       { primary controller }
  168.        aDriveCtrlrBaseReg_1     =     $1F0;
  169.        aDriveCtrlrBaseReg_2     =     $170;       { secondary controller }
  170.        aDriveCtrlrBaseReg_3     =     $170;
  171.        aAltDriveStatusReg_0     =     $3F6;
  172.        aAltDriveStatusReg_1     =     $376;
  173.  
  174.      { controller status register bits }
  175.        btCtlrBusy               =     $80;
  176.        btDriveReady             =     $40;
  177.        btWriteFault             =     $20;
  178.        btSeekComplete           =     $10;
  179.        btDataRequest            =     $08;
  180.        btCmdErr                 =     $01;
  181.  
  182.      { sector/drive/head info }
  183.        btCRCmode                =     $80;
  184.        btSecSize512             =     $20;
  185.  
  186.      { sector equates }
  187.         aSectorCountRegVal    =     $01;
  188.         aSectorNumberRegVal    =     $01;
  189.  
  190.      { controller commands opcodes }
  191.        cmdIDENTIFY              =     $EC;
  192.        cmdDisableInts           =     $04;
  193.        cmdEnableInts            =     $00;
  194.  
  195.      { IDE info record hard-coded values }
  196.         dbSerialNumberLen                   =      20;
  197.         dbCntlrFirmwareRevisionLen          =      8;
  198.         dbModelNumberLen                    =      40;
  199.         dwReservedPartSize1                 =      $100-$80;
  200.         dbVendorUniqueInfoTextLen           =      $140-$100;
  201.         dwReservedPartSize2                 =      aBytesPerDosSector-$140;
  202.  
  203.     { bit values }
  204.        btBit_0_ON               =       $0001;
  205.        btBit_1_ON               =       $0002;
  206.        btBit_2_ON               =       $0004;
  207.        btBit_3_ON               =       $0008;
  208.        btBit_4_ON               =       $0010;
  209.        btBit_5_ON               =       $0020;
  210.        btBit_6_ON               =       $0040;
  211.        btBit_7_ON               =       $0080;
  212.        btBit_8_ON               =       $0100;
  213.        btBit_9_ON               =       $0200;
  214.        btBit_A_ON               =       $0400;
  215.        btBit_B_ON               =       $0800;
  216.        btBit_C_ON               =       $1000;
  217.        btBit_D_ON               =       $2000;
  218.        btBit_E_ON               =       $4000;
  219.        btBit_F_ON               =       $8000;
  220.  
  221.     { bit values }
  222.        aTestPattern_00          =       $00;
  223.        aTestPattern_55          =       $55;
  224.        aTestPattern_AA          =       $AA;
  225.        aTestPattern_FF          =       $FF;
  226.  
  227.  
  228. {*==================== TYPE DECLARATIONS PART ==========================*}
  229.  
  230. TYPE
  231.   {* strings *}
  232.        STR2                     =     STRING[2];
  233.        STR4                     =     STRING[4];
  234.        STR8                     =     STRING[8];
  235.  
  236.   {* hard drive controller registers read map *}
  237.     recHDISK_READ_REGS          =       RECORD
  238.                  dwDataReg_RD              :     System.Word;
  239.                  dwErrorReg_RD             :     System.Word;
  240.                  dwSectorCountReg_RD       :     System.Word;
  241.                  dwSectorNumberReg_RD      :     System.Word;
  242.                  dwCylinderLowReg_RD       :     System.Word;
  243.                  dwCylinderHighReg_RD      :     System.Word;
  244.                  dwSDH_Reg_RD              :     System.Word;
  245.                  dwStatusReg_RD            :     System.Word;
  246.                                         END;
  247.     {* recHDISK_READ_REGS *}
  248.  
  249.  
  250.   {* hard drive controller registers write map *}
  251.     recHDISK_WRITE_REGS          =       RECORD
  252.                  dwDataReg_WR              :     System.Word;
  253.                  dwWRC_Reg_WR              :     System.Word;
  254.                  dwSectorCountReg_WR       :     System.Word;
  255.                  dwSectorNumberReg_WR      :     System.Word;
  256.                  dwCylinderLowReg_WR       :     System.Word;
  257.                  dwCylinderHighReg_WR      :     System.Word;
  258.                  dwSDH_Reg_WR              :     System.Word;
  259.                  dwCommand_Reg_WR          :     System.Word;
  260.                                         END;
  261.     {* recHDISK_WRITE_REGS *}
  262.  
  263.  
  264.     {* hard disk drive controller control block *}
  265.       recHDISK_WRITE_CMD_BLOCK    =       RECORD
  266.                  dbData_WR                 :     System.Byte;
  267.                  dbWRC_WR                  :     System.Byte;
  268.                  dbSectorCount_WR          :     System.Byte;
  269.                  dbSectorNumber_WR         :     System.Byte;
  270.                  dbCylinderLow_WR          :     System.Byte;
  271.                  dbCylinderHigh_WR         :     System.Byte;
  272.                  dbSDH_WR                  :     System.Byte;
  273.                  dbCommand_WR              :     System.Byte;
  274.                                           END;
  275.     {* recHDISK_WRITE_CMD_BLOCK *}
  276.  
  277.  
  278.     {* Configuration Parameters of IDE disk drive *}
  279.     recIDE_Info_Sector  =  RECORD
  280.                  dwGeneralConfigFlags           :       System.Word;                                              {00}
  281.                  dwFixedCylsNum                 :       System.Word;                                              {02}
  282.                  dwRemovableCylsNum             :       System.Word;                                              {04}
  283.                  dwHeadsNum                     :       System.Word;                                              {06}
  284.                  dwUnfmtdBytesPerPhysTrk        :       System.Word;                                              {08}
  285.                  dwUnfmtdBytesPerSec            :       System.Word;                                              {0A}
  286.                  dwPhysSecsPerTrk               :       System.Word;                                              {0C}
  287.                  dwInterSecGapBytesNumVU        :       System.Word;                                              {0E}
  288.                  dwSyncFieldsBytesNumVU         :       System.Word;                                              {10}
  289.                  dwPLObyteNumVU                 :       System.Word;                                              {12}
  290.                  dbSerialNumber                 :       ARRAY[1..dbSerialNumberLen]  OF System.Char;              {14}
  291.                  dwControllerType               :       System.Word;                                              {28}
  292.                  dwControllerBufSize            :       System.Word;                                              {2A}
  293.                  dwECCbytes                     :       System.Word;                                              {2C}
  294.                  dbCntlrFirmwareRevision        :       ARRAY[1..dbCntlrFirmwareRevisionLen]   OF System.Byte;    {2E}
  295.                  dbModelNumber                  :       ARRAY[1..dbModelNumberLen]   OF System.Char;              {36}
  296.                  dwSecsPerIntr                  :       System.Word;                                              {5E}
  297.                  dwDoubleWordTransferFlag       :       System.Word;                                              {60}
  298.                  dwAssignAlternate              :       System.Word;                                              {62}
  299.                  dwReserved_64                  :       System.Word;                                       {64}
  300.          dwPIODataXFRCycleTimingMode    :    System.Word;                          {66}
  301.          dwDMADataXFRCycleTimingMode    :    System.Word;                          {68}
  302.                  dwCurrentSettingsValidFlag     :       System.Word;                                              {6A}
  303.                  dwCurrentCylsNum               :       System.Word;                                              {6C}
  304.                  dwCurrentHeadsNum              :       System.Word;                                              {6E}
  305.                  dwCurrentSecsPerTrack          :       System.Word;                                              {70}
  306.                  ddCurrentDriveCapacityInSecs   :       System.Longint;                                           {72}
  307.                  dwMultipleSecsModeXfrSettings  :       System.Word;                                              {76}
  308.                  ddTotalUserSecsInLBA_Mode      :       System.Longint;                                           {78}
  309.                  dwSingleWordDMA_XfrMode        :       System.Word;                                              {7C}
  310.                  dwMultiWordDMA_XfrMode         :       System.Word;                                              {7E}
  311.                  dbReserved_80                  :       ARRAY[1..dwReservedPartSize1] OF System.Byte;             {80}
  312.                  dbVendorUniqueInfoText         :       ARRAY[1..dbVendorUniqueInfoTextLen]  OF  System.Char;     {100}
  313.                  dbReserved_140                 :       ARRAY[1..dwReservedPartSize2] OF System.Byte;             {140}
  314.                            END;
  315.     {* recIDE_Info_Sector *}
  316.  
  317.  
  318.     {* Hard Disk Parameters Table *}
  319.     recHARD_DISK_PARMS    = RECORD
  320.         dwMAX_CYLS_NUM             :    System.Word;     {00}
  321.         dbMAX_HEADS_NUM             :    System.Byte;     {02}
  322.         dwSTART_WRC_XT             :    System.Word;     {03}
  323.         dwSTART_WRC                  :    System.Word;     {05}
  324.         dbMAX_ECC_DATA_BURST_LEN     :    System.Byte;     {07}
  325.         dbCONTROL_BYTE               :    System.Byte;     {08}
  326.         dbSTD_TIME_OUT_XT            :    System.Byte;     {09}
  327.         dbFMT_TIME_OUT_XT            :    System.Byte;     {0A}
  328.         dbCHECK_TIME_OUT_XT          :    System.Byte;     {0B}
  329.         dwLANDING_ZONE               :    System.Word;     {0C}
  330.         dbSECTORS_PER_TRACK          :    System.Byte;     {0E}
  331.         dbPARM_RESERVED              :    System.Byte;     {0F}
  332.                       END;
  333.     {* Hard Disk Parameters Table *}
  334.  
  335.  
  336. {*====================== TYPED CONSTANTS PART ==========================*}
  337.  
  338. CONST
  339.     setAscii7_NoCtrl  :    SET OF System.Char  =  [#32..#127];
  340.     setHexChars       :    SET OF System.Char  =  ['0'..'9','A'..'F','a'..'f'];
  341.  
  342.     gbFileWriteOk     :    System.Boolean      =  System.False;
  343.     gbFindAllOk       :    System.Boolean      =  System.False;
  344.     gbFindCMOSOk      :    System.Boolean      =  System.False;
  345.     gbFindMaxOk          :    System.Boolean      =  System.False;
  346.  
  347.     gdwTextLineNum    :    System.Word         =  aMinOutLineOnScreen;
  348.     gdwMaxScreenLines :    System.Word         =  aDefMaxOutLineForScreen;
  349.  
  350.  
  351.  
  352. {*=========================== VARIABLES PART ===========================*}
  353.  
  354. VAR
  355.    grecDriveInfoBuf      :   recIDE_Info_Sector;
  356.    grecRD_HDISK_Regs     :   recHDISK_READ_REGS;
  357.    grecWRT_HDISK_Regs    :   recHDISK_WRITE_REGS;
  358.    grecWR_CMD_BLOCK      :   recHDISK_WRITE_CMD_BLOCK;
  359.    gliTotalDiskSectors   :   System.Longint;
  360.    giErrorCode           :   System.Integer;
  361.    gdwIndex              :   System.Word;
  362.    gdwAlternateStatus    :   System.Word;
  363.    gdbIDE_Disks_Count    :   System.Byte;
  364.    gdbSDH_TestVal        :   System.Byte;
  365.    gbDiskStatusOK        :   System.Boolean;
  366.    gsTemp                :   STRING;
  367.  
  368.  { absolute references to memory locations}
  369.    gdbBIOS_Drives_Num    :   System.Byte   ABSOLUTE  $40:$75;
  370.    gdbROM_BIOS_HDD_TYPES_TABLE : ARRAY[aMinHDD_CMOSType..aMaxHDD_CMOSType]
  371.                                  OF  recHARD_DISK_PARMS  ABSOLUTE $F000:$E401;
  372.  
  373.  
  374.  
  375.  
  376.  
  377. {*=========================== PROCEDURAL PART ==========================*}
  378.  
  379. PROCEDURE _IO_DELAY_2;
  380. {* Some i/o bus delay. *}
  381. INLINE($EB/$00/     { jmp short $ + 2 }
  382.        $EB/$00);    { jmp short $ + 2 }
  383. { _IO_DELAY_2 }
  384.  
  385.  
  386. PROCEDURE _IO_DELAY_4;
  387. {* Some i/o bus delay. *}
  388. INLINE($EB/$00/     { jmp short $ + 2 }
  389.        $EB/$00/     { jmp short $ + 2 }
  390.        $EB/$00/     { jmp short $ + 2 }
  391.        $EB/$00);    { jmp short $ + 2 }
  392. { _IO_DELAY_4 }
  393.  
  394.  
  395. PROCEDURE _IO_DELAY_6;
  396. {* Some i/o bus delay. *}
  397. INLINE($EB/$00/     { jmp short $ + 2 }
  398.        $EB/$00/     { jmp short $ + 2 }
  399.        $EB/$00/     { jmp short $ + 2 }
  400.        $EB/$00/     { jmp short $ + 2 }
  401.        $EB/$00/     { jmp short $ + 2 }
  402.        $EB/$00);    { jmp short $ + 2 }
  403. { _IO_DELAY_6 }
  404.  
  405.  
  406. PROCEDURE _IO_DELAY_8;
  407. {* Some i/o bus delay. *}
  408. INLINE($EB/$00/     { jmp short $ + 2 }
  409.        $EB/$00/     { jmp short $ + 2 }
  410.        $EB/$00/     { jmp short $ + 2 }
  411.        $EB/$00/     { jmp short $ + 2 }
  412.        $EB/$00/     { jmp short $ + 2 }
  413.        $EB/$00/     { jmp short $ + 2 }
  414.        $EB/$00/     { jmp short $ + 2 }
  415.        $EB/$00);    { jmp short $ + 2 }
  416. { _IO_DELAY_8 }
  417.  
  418.  
  419. PROCEDURE _ReadDataSector512(VAR dbBuf; dwBaseDataReg, dwTransferCount : System.Word);
  420. {* Transfer 512-bytes sector into memory buffer. *}
  421. INLINE($59/           {  pop     cx           ; CX = # words to xfr }
  422.        $5A/           {  pop     dx           ; DX = base data reg  }
  423.        $5F/           {  pop     di           ; DI = Ofs(dbBuf)     }
  424.        $07/           {  pop     es           ; ES = Seg(dbBuf)     }
  425.        $FA/           {  cli                  ; intrs off           }
  426.        $FC/           {  cld                  ; go forward          }
  427.        $F3/$6D/       {  rep     insw         ; i/o (286+)          }
  428.        $FB);          {  sti                  ; intrs on            }
  429. { _ReadDataSector512 }
  430.  
  431.  
  432.  
  433. {*=========================== FUNCTIONAL PART ==========================*}
  434.  
  435. FUNCTION  _fndbReadControllerStatus(dwStatusReg : System.Word) : System.Byte;
  436. {* Read fixed disk drive controller status. *}
  437. VAR
  438.   dbStatus : System.Byte;
  439.  
  440. BEGIN
  441.   {* assume that status ok *}
  442.    gbDiskStatusOK := System.True;
  443.  
  444.   {* just read some couple bits *}
  445.    dbStatus  := System.Port[dwStatusReg];
  446.    IF (((dbStatus AND (btDriveReady+btWriteFault+btSeekComplete+btCmdErr))
  447.           XOR (btDriveReady+btSeekComplete)) <> 0)
  448.      THEN  gbDiskStatusOK := System.False;
  449.    {if-then}
  450.  
  451.   {* return result *}
  452.   _fndbReadControllerStatus := dbStatus;
  453. END; { _fndbReadControllerStatus }
  454.  
  455.  
  456. FUNCTION  _fnbControllerIsReady(dwStatusReg : System.Word) : System.Boolean;
  457. {* Test disk controller ready status. *}
  458. VAR
  459.   dwTimeOutCount  :   System.Word;
  460.   dwOuterCount      :   System.Word;
  461.   dbStatus        :   System.Byte;
  462.   bResVal         :   System.Boolean;
  463.  
  464. BEGIN
  465.   {* assume that controller ready now *}
  466.     dwTimeOutCount := $FFFF;
  467.     dwOuterCount := $4000;
  468.     gbDiskStatusOK := System.False;
  469.     bResVal        := System.False;
  470.  
  471.   {* test controller status *}
  472.   WHILE (dwOuterCount <> 0)  DO
  473.   BEGIN
  474.     WHILE (dwTimeOutCount <> 0) DO
  475.     BEGIN
  476.         {* read status port *}
  477.         _IO_DELAY_2;
  478.         dbStatus  := System.Port[dwStatusReg];
  479.  
  480.         {* controller busy? *}
  481.         IF ((dbStatus AND btCtlrBusy) = 0)
  482.           THEN  BEGIN
  483.               {* here we found status ok *}
  484.                dwTimeOutCount := 0;
  485.                dwOuterCount := 1;
  486.                gbDiskStatusOK := System.True;
  487.                bResVal        := System.True;
  488.             END
  489.           ELSE
  490.         System.Dec(dwTimeOutCount);
  491.         {if-then-else}
  492.     END;
  493.     {while-do}
  494.   System.Dec(dwOuterCount);
  495.   END;
  496.   {while-do}
  497.  
  498.   {* return result *}
  499.     _fnbControllerIsReady := bResVal;
  500.   {$IFDEF  DebugVersion}
  501.     System.WriteLn('Ready state: ',dbStatus);
  502.   {$ENDIF  DebugVersion}
  503. END; { _fnbControllerIsReady }
  504.  
  505.  
  506.  
  507. FUNCTION  _fnbDriveIsReady(dwStatusReg : System.Word) : System.Boolean;
  508. {* Test disk drive ready status. *}
  509. VAR
  510.   dwTimeOutCount  :   System.Word;
  511.   dbStatus        :   System.Byte;
  512.   bResVal         :   System.Boolean;
  513.  
  514. BEGIN
  515.   {* assume that controller ready now *}
  516.     dwTimeOutCount := $FFFF;
  517.     gbDiskStatusOK := System.False;
  518.     bResVal        := System.False;
  519.  
  520.   {* test controller status *}
  521.     WHILE (dwTimeOutCount <> 0) DO
  522.     BEGIN
  523.         {* read status port *}
  524.     _IO_DELAY_2;
  525.         dbStatus  := System.Port[dwStatusReg];
  526.  
  527.         {* drive busy? *}
  528.         IF ((dbStatus AND btDriveReady) <> 0)
  529.           THEN  BEGIN
  530.                   {* drive ready to accept command *}
  531.                    dwTimeOutCount := 0;
  532.                    gbDiskStatusOK := System.True;
  533.                    bResVal        := System.True;
  534.                 END
  535.           ELSE
  536.             System.Dec(dwTimeOutCount);
  537.         {if-then-else}
  538.     END;
  539.     {while-do}
  540.  
  541.   {* return result *}
  542.     _fnbDriveIsReady := bResVal;
  543. END; { _fnbDriveIsReady }
  544.  
  545.  
  546. FUNCTION  _fnbWaitDRQ(dwStatusReg : System.Word) : System.Boolean;
  547. {* Wait while sector buffer not full. *}
  548. VAR
  549.   dwTimeOutCount  :   System.Word;
  550.   dwOuterCount      :   System.Word;
  551.   dbStatus        :   System.Byte;
  552.   bResVal         :   System.Boolean;
  553.  
  554. PROCEDURE  _SimulateLongDelay(dwWaitCount : System.Word);
  555. {* Fix a time-out problem before a controller will have ready. *}
  556. BEGIN
  557.   WHILE  (dwWaitCount <> 0) DO
  558.   BEGIN
  559.      _IO_DELAY_8;
  560.      System.Dec(dwWaitCount);
  561.   END;
  562.   {while-do}
  563. END;
  564. { _SimulateLongDelay }
  565.  
  566. BEGIN
  567.   {* assume that controller ready now *}
  568.     dwTimeOutCount := $FFFF;                {* Hard-coded value!! *}
  569.     dwOuterCount := $FFFF;
  570.     gbDiskStatusOK := System.False;
  571.     bResVal        := System.False;
  572.  
  573.   {* test controller status *}
  574.     WHILE  (dwOuterCount <> 0)  DO
  575.     BEGIN
  576.     WHILE (dwTimeOutCount <> 0) DO
  577.     BEGIN
  578.         {* read status port *}
  579.         _SimulateLongDelay(20);
  580.         dbStatus  := System.Port[dwStatusReg];
  581.  
  582.         {* buffer full? *}
  583.         IF (((dbStatus AND btCtlrBusy) = 0) AND 
  584.                 (((dbStatus AND (btDataRequest+btDriveReady+btSeekComplete)) <> 0)))
  585.           THEN  BEGIN
  586.               {* controller reports that buffer ready to read *}
  587.                dwTimeOutCount := 0;
  588.                dwOuterCount := 1;
  589.                gbDiskStatusOK := System.True;
  590.                bResVal        := System.True;
  591.             END
  592.           ELSE
  593.         System.Dec(dwTimeOutCount);
  594.         {if-then-else}
  595.     END;
  596.     {while-do}
  597.     System.Dec(dwOuterCount);
  598.     END;
  599.     {while-do}
  600.  
  601.   {* return result *}
  602.     _fnbWaitDRQ := bResVal;
  603.   {$IFDEF  DebugVersion}
  604.     System.WriteLn('DRQ state: ',dbStatus);
  605.   {$ENDIF  DebugVersion}
  606. END; { _fnbWaitDRQ }
  607.  
  608.  
  609. FUNCTION   _fnsByteToHexFmt(dbInput : System.Byte) : STR2;
  610. {* Converts a byte to the hex format number representation. *}
  611. CONST
  612.     dbHexCharTable : ARRAY[0..15] OF System.Char = '0123456789ABCDEF';
  613.  
  614. BEGIN
  615.   _fnsByteToHexFmt := dbHexCharTable[dbInput SHR 4] + dbHexCharTable[dbInput AND $0F];
  616. END;  { _fnsByteToHexFmt }
  617.  
  618.  
  619. FUNCTION   _fnsWordToHexFmt(dwInput : System.Word) : STR4;
  620. {* Converts a word to the hex format number representation. *}
  621. BEGIN
  622.   _fnsWordToHexFmt := _fnsByteToHexFmt(System.Hi(dwInput)) +
  623.                       _fnsByteToHexFmt(System.Lo(dwInput));
  624. END;  { _fnsWordToHexFmt }
  625.  
  626.  
  627. FUNCTION  _fnsAsciiInfo(pMem : System.Pointer; dwMemLen : System.Word;
  628.                         bSwapBytes : System.Boolean) : STRING;
  629. {* Return string only with match ASCII chars. *}
  630. VAR
  631.   sTemp        :    STRING;
  632.   dwMemOfs     :    System.Word;
  633.   dwChar2      :    System.Word;
  634.  
  635.  
  636. PROCEDURE  _AddNewChar(chNew : System.Char);
  637. {* Add match char to string. *}
  638. BEGIN
  639.    IF  (chNew IN setAscii7_NoCtrl)
  640.       THEN  sTemp := sTemp + chNew;
  641.    {if-then}
  642. END; { _AddNewChar }
  643.  
  644. BEGIN
  645.   {* initialize *}
  646.    sTemp     := asBlank;
  647.    dwMemOfs  := 0;
  648.    dwMemLen  := dwMemLen SHR 1;    { words count }
  649.  
  650.   {* read all bytes in format HIGH-LOW (Motorola format) *}
  651.    WHILE (dwMemLen <> 0) DO
  652.    BEGIN
  653.       dwChar2   := System.MemW[System.Seg(pMem^):(System.Ofs(pMem^)+dwMemOfs)];
  654.  
  655.      IF (bSwapBytes)
  656.        THEN  BEGIN
  657.          _AddNewChar(System.Char(System.Hi(dwChar2)));
  658.          _AddNewChar(System.Char(System.Lo(dwChar2)));
  659.              END
  660.        ELSE  BEGIN
  661.          _AddNewChar(System.Char(System.Lo(dwChar2)));
  662.          _AddNewChar(System.Char(System.Hi(dwChar2)));
  663.              END;
  664.      {if-then-else}
  665.  
  666.       System.Dec(dwMemLen);
  667.       System.Inc(dwMemOfs,2);
  668.    END;
  669.    {while-do}
  670.  
  671.   {* return string as result *}
  672.    _fnsAsciiInfo := sTemp;
  673. END; { _fnsAsciiInfo }
  674.  
  675.  
  676. FUNCTION  _fnsForceFileExtension(sFileName, sDefExt : STRING) : STRING;
  677. {* Add extension for filename if not present. *}
  678. BEGIN
  679.    IF (System.Pos(achDosDelim,sFileName) = 0)
  680.      THEN  sFileName := sFileName + achDosDelim + sDefExt;
  681.    {if-then}
  682.   _fnsForceFileExtension := sFileName;
  683. END;
  684. { _fnsForceFileExtension }
  685.  
  686.  
  687. FUNCTION  _fnsNumToStr(liNum : System.Longint; dwWidth : System.Word) : STRING;
  688. {* Convert a numeric value to its string representation. *}
  689. VAR
  690.   sTemp : STRING;
  691.  
  692. BEGIN
  693.   IF (dwWidth <> 0)
  694.     THEN  System.Str(liNum:dwWidth,sTemp)
  695.     ELSE  System.Str(liNum,sTemp);
  696.   {if-then-else}
  697.  
  698.   WHILE (System.Length(sTemp) <> 0) AND (sTemp[1] = achSpace)
  699.   DO  System.Delete(sTemp,1,1);
  700.   {while-do}
  701.  
  702.   _fnsNumToStr := sTemp;
  703. END;
  704. { _fnsNumToStr }
  705.  
  706.  
  707. FUNCTION  _fnsNumToStrNoAdj(liNum : System.Longint; dwWidth : System.Word) : STRING;
  708. {* Convert a numeric value to its string representation. *}
  709. VAR
  710.   sTemp : STRING;
  711.  
  712. BEGIN
  713.   IF (dwWidth <> 0)
  714.     THEN  System.Str(liNum:dwWidth,sTemp)
  715.     ELSE  System.Str(liNum,sTemp);
  716.   {if-then-else}
  717.  
  718.   _fnsNumToStrNoAdj := sTemp;
  719. END;
  720. { _fnsNumToStrNoAdj }
  721.  
  722.  
  723. FUNCTION  _fnsNumToRealStr(rNum : System.Real;dwWidth,dwDecimals : System.Word) : STRING;
  724. {* Convert a real numeric value to its string representation. *}
  725. VAR
  726.   sTemp : STRING;
  727.  
  728. BEGIN
  729.   System.Str(rNum:dwWidth:dwDecimals,sTemp);
  730.  
  731.   WHILE (System.Length(sTemp) <> 0) AND (sTemp[1] = achSpace)
  732.   DO  System.Delete(sTemp,1,1);
  733.   {while-do}
  734.  
  735.   _fnsNumToRealStr := sTemp;
  736. END;
  737. { _fnsNumToRealStr }
  738.  
  739.  
  740. FUNCTION  _fnsNumToRealStrNoAdj(rNum : System.Real;dwWidth,dwDecimals : System.Word) : STRING;
  741. {* Convert a real numeric value to its string representation. *}
  742. VAR
  743.   sTemp : STRING;
  744.  
  745. BEGIN
  746.   System.Str(rNum:dwWidth:dwDecimals,sTemp);
  747.  
  748.   _fnsNumToRealStrNoAdj := sTemp;
  749. END;
  750. { _fnsNumToRealStrNoAdj }
  751.  
  752.  
  753. FUNCTION   _fnsUpCase(sInput : STRING) : STRING;
  754. {* Translate characters to upper case. *}
  755. VAR
  756.    dbIndex  :  System.Byte;
  757.    dbCount  :  System.Byte  ABSOLUTE  sInput;
  758.  
  759. BEGIN
  760.   IF (dbCount <> 0)
  761.     THEN   FOR  dbIndex := 1 TO dbCount DO
  762.                sInput[dbIndex] := System.UpCase(sInput[dbIndex]);
  763.            {for-to-do}
  764.   {if-then}
  765.  
  766.    _fnsUpCase := sInput;
  767. END;
  768. {  _fnsUpCase }
  769.  
  770.  
  771. FUNCTION  _fnsDmaTransferModeInfo(dwBitsInfoMode : System.Word) : STRING;
  772. {* Returns string describing a DMA transfer modes supported by drive. *}
  773. VAR
  774.   dbTempValue  :  System.Byte;
  775.   sTemp        :  STRING;
  776.  
  777. BEGIN
  778.       IF (dwBitsInfoMode <> 0)
  779.         THEN  BEGIN
  780.              dbTempValue := System.Lo(dwBitsInfoMode);
  781.              sTemp := asBlank;
  782.              IF ((dbTempValue AND btBit_0_ON) <> 0)
  783.                THEN  sTemp := sTemp + '0';
  784.              {if-then}
  785.              IF ((dbTempValue AND btBit_1_ON) <> 0)
  786.                THEN  sTemp := sTemp + ',1';
  787.              {if-then}
  788.              IF ((dbTempValue AND btBit_2_ON) <> 0)
  789.                THEN  sTemp := sTemp + ',2';
  790.              {if-then}
  791.              sTemp := sTemp + '(active is ';
  792.              dbTempValue := System.Hi(dwBitsInfoMode);
  793.              IF ((dbTempValue AND btBit_0_ON) <> 0)
  794.                THEN  sTemp := sTemp + '0';
  795.              {if-then}
  796.              IF ((dbTempValue AND btBit_1_ON) <> 0)
  797.                THEN  sTemp := sTemp + ',1';
  798.              {if-then}
  799.              IF ((dbTempValue AND btBit_2_ON) <> 0)
  800.                THEN  sTemp := sTemp + ',2';
  801.              {if-then}
  802.              sTemp := sTemp + ')';
  803.               END
  804.         ELSE
  805.             sTemp := 'none';
  806.       {if-then}
  807.       _fnsDmaTransferModeInfo := sTemp;
  808. END;
  809. { _fnsDmaTransferModeInfo }
  810.  
  811. {*=========================== PROCEDURAL PART ==========================*}
  812.  
  813. PROCEDURE    _OutputMessageNoLF(sMessage : STRING);
  814. {* Writes a message without the linefeed. *}
  815. BEGIN
  816.   System.Write(sMessage);
  817. END;
  818. { _OutputMessageNoLF }
  819.  
  820.  
  821. PROCEDURE    _OutputMessage(sMessage : STRING);
  822. {* Writes a message through the paged stream output. *}
  823. VAR
  824.   sTemp   :   STRING;
  825.  
  826. BEGIN
  827.    System.WriteLn(sMessage);
  828.    IF (gdwTextLineNum <> aDisableScreenPage)
  829.      THEN  BEGIN
  830.       System.Inc(gdwTextLineNum);
  831.       IF (gdwTextLineNum > gdwMaxScreenLines)
  832.         THEN  BEGIN
  833.        gdwTextLineNum := aMinOutLineOnScreen;
  834.            System.Write(asProgramPrompt+' Press <ENTER> to continue or type any string to abort:');
  835.            System.ReadLn(sTemp);
  836.            IF (sTemp <> asBlank)
  837.              THEN  BEGIN
  838.                 System.WriteLn(asProgramPrompt+' Aborted by user.');
  839.                 System.Halt(errUserAbort);
  840.                    END;
  841.            {if-then}
  842.               END;
  843.       {if-then}
  844.             END;
  845.    {if-then}
  846. END;
  847. { _OutputMessage }
  848.  
  849.  
  850. PROCEDURE    _CopyrightDisplay;
  851. {* Outputs the copyright notice. *}
  852. BEGIN
  853.      _OutputMessage(asPurpose+'  Version '+asVersion+',  '+asCopyright+'  '+asAuthor);
  854. END;  { _CopyrightDisplay }
  855.  
  856.  
  857. PROCEDURE  _WriteSDH_Val(dwSDH_Reg : System.Word; dbDiskNum : System.Byte);
  858. {* Write a value to sector/drive/head register. *}
  859. VAR
  860.   dbWriteVal  :  System.Byte;
  861.  
  862. BEGIN
  863.   {* select default modes *}
  864.     dbWriteVal := ((dbDiskNum SHL 4) OR (btCRCmode+btSecSize512)) OR (gdbSDH_TestVal AND $0F);
  865.     gdbSDH_TestVal := dbWriteVal;
  866.  
  867.   {* output a value *}
  868.     System.Port[dwSDH_Reg] := dbWriteVal;
  869. END; { _WriteSDH_Val }
  870.  
  871.  
  872. PROCEDURE  _TestDiskControllerHardware(recRD_HDISK_Regs  : recHDISK_READ_REGS;
  873.                                        recWRT_HDISK_Regs : recHDISK_WRITE_REGS;
  874.                                        dbDiskNum : System.Byte);
  875. {* Test for disk drive controller present. *}
  876. BEGIN
  877.     {* we assume that unsuccess will occurred *}
  878.      gbDiskStatusOK := System.False;
  879.  
  880.     {* test 1: write value (non-FF) to SDH and read it back*}
  881.     _WriteSDH_Val(recWRT_HDISK_Regs.dwSDH_Reg_WR,dbDiskNum);
  882.      IF (System.Port[recRD_HDISK_Regs.dwStatusReg_RD] = aTestPattern_FF)
  883.         THEN  System.Exit;
  884.      {if-then}
  885.  
  886.     {* test 2: controller busy? *}
  887.      IF NOT(_fnbControllerIsReady(recRD_HDISK_Regs.dwStatusReg_RD))
  888.         THEN  System.Exit;
  889.      {if-then}
  890.  
  891.     {* test 3: write wanted value to SDH and read it back *}
  892.       gbDiskStatusOK := System.False;
  893.       System.Port[recWRT_HDISK_Regs.dwSDH_Reg_WR] := gdbSDH_TestVal;
  894.       _IO_DELAY_2;
  895.       IF (System.Port[recRD_HDISK_Regs.dwSDH_Reg_RD] <> gdbSDH_TestVal)
  896.         THEN  System.Exit;
  897.       {if-then}
  898.  
  899.     {* test 4: write test pattern to SDH and read it back *}
  900.       System.Port[recWRT_HDISK_Regs.dwCylinderLowReg_WR] := aTestPattern_AA;
  901.       _IO_DELAY_2;
  902.       IF (System.Port[recRD_HDISK_Regs.dwCylinderLowReg_RD] <> aTestPattern_AA)
  903.         THEN  System.Exit;
  904.       {if-then}
  905.  
  906.     {* test 5: write test pattern to SDH and read it back *}
  907.       System.Port[recWRT_HDISK_Regs.dwCylinderLowReg_WR] := aTestPattern_55;
  908.       _IO_DELAY_2;
  909.       IF (System.Port[recRD_HDISK_Regs.dwCylinderLowReg_RD] <> aTestPattern_55)
  910.         THEN  System.Exit;
  911.       {if-then}
  912.  
  913.     {* test 6: drive ready? *}
  914.        _IO_DELAY_4;
  915.        IF ((System.Port[recRD_HDISK_Regs.dwStatusReg_RD] AND btDriveReady) <> 0)
  916.           THEN  gbDiskStatusOK := System.True;
  917.        {if-then}
  918.  
  919. END; { _TestDiskControllerHardware }
  920.  
  921.  
  922. PROCEDURE  _OutputCommandBlock(VAR recWR_CMD_BLOCK :  recHDISK_WRITE_CMD_BLOCK;
  923.                                dwBaseReg : System.Word);
  924. {* Write all control bytes to registers. *}
  925. BEGIN
  926.   WITH  recWR_CMD_BLOCK  DO
  927.   BEGIN
  928.      System.Port[dwBaseReg+$01] := dbWRC_WR;
  929.      _IO_DELAY_2;
  930.      System.Port[dwBaseReg+$02] := dbSectorCount_WR;
  931.      _IO_DELAY_2;
  932.      System.Port[dwBaseReg+$03] := dbSectorNumber_WR;
  933.      _IO_DELAY_2;
  934.      System.Port[dwBaseReg+$04] := dbCylinderLow_WR;
  935.      _IO_DELAY_2;
  936.      System.Port[dwBaseReg+$05] := dbCylinderHigh_WR;
  937.      _IO_DELAY_2;
  938.      System.Port[dwBaseReg+$06] := dbSDH_WR;
  939.   END;
  940.   {with-do}
  941. END; { _OutputCommandBlock }
  942.  
  943.  
  944. PROCEDURE  _HardResetController(dwStatusPort : System.Word);
  945. {* Do a hard reset of controller. *}
  946.  
  947. PROCEDURE  _WaitOperation(dwWaitCount :  System.Word);
  948. BEGIN
  949.     WHILE (dwWaitCount <> 0) DO
  950.     BEGIN
  951.        _IO_DELAY_8;
  952.         System.Dec(dwWaitCount);
  953.     END;
  954.     {while-do}
  955. END;
  956. { _WaitOperation }
  957.  
  958. BEGIN
  959.     System.Port[dwStatusPort] := cmdDisableInts;
  960.     _WaitOperation($4000);
  961.     System.Port[dwStatusPort] := cmdEnableInts;
  962.     _WaitOperation($4000);
  963. END;
  964. { _HardResetController }
  965.  
  966. PROCEDURE  _WriteControllerCommand(recRD_HDISK_Regs    :  recHDISK_READ_REGS;
  967.                                    recWRT_HDISK_Regs   :  recHDISK_WRITE_REGS;
  968.                                    recWR_CMD_BLOCK     :  recHDISK_WRITE_CMD_BLOCK);
  969. {* Write a controller command bytes. *}
  970. BEGIN
  971.   {* controller not buzy? *}
  972.      IF NOT(_fnbControllerIsReady(recRD_HDISK_Regs.dwStatusReg_RD))
  973.         THEN  System.Exit;
  974.      {if-then}
  975.  
  976.   {* enable/disable the controller operations *}
  977.     _HardResetController(gdwAlternateStatus);
  978.  
  979.   {* write first 6 command bytes to controller *}
  980.     _OutputCommandBlock(recWR_CMD_BLOCK,recWRT_HDISK_Regs.dwDataReg_WR);
  981.  
  982.   {* is drive ready? *}
  983.      IF NOT(_fnbDriveIsReady(recRD_HDISK_Regs.dwStatusReg_RD))
  984.         THEN  System.Exit;
  985.      {if-then}
  986.  
  987.   {* write last command byte into controller stack space *}
  988.     _IO_DELAY_2;
  989.     System.Port[recWRT_HDISK_Regs.dwCommand_Reg_WR] :=  recWR_CMD_BLOCK.dbCommand_WR;
  990.  
  991. END; { _WriteControllerCommand }
  992.  
  993.  
  994. PROCEDURE  _InitCommandBlock(VAR recWR_CMD_BLOCK :  recHDISK_WRITE_CMD_BLOCK);
  995. {* Build command block for controller. *}
  996. BEGIN
  997.   WITH  recWR_CMD_BLOCK  DO
  998.   BEGIN
  999.       dbWRC_WR          := $00;             { see tech. ref. of any IDE/ATA drive }
  1000.       dbSectorCount_WR  := $00;
  1001.       dbSectorNumber_WR := $00;
  1002.       dbCylinderLow_WR  := $00;
  1003.       dbCylinderHigh_WR := $00;
  1004.       dbSDH_WR          := gdbSDH_TestVal;  { std value }
  1005.       dbCommand_WR      := cmdIDENTIFY;
  1006.   END;
  1007.   {with-do}
  1008. END; { _InitCommandBlock }
  1009.  
  1010.  
  1011. PROCEDURE  _ReadDriveParameters(VAR  recDriveInfoBuf  :  recIDE_Info_Sector;
  1012.                                 recRD_HDISK_Regs      :  recHDISK_READ_REGS;
  1013.                                 recWRT_HDISK_Regs     :  recHDISK_WRITE_REGS;
  1014.                                 recWR_CMD_BLOCK       :  recHDISK_WRITE_CMD_BLOCK;
  1015.                                 dbDiskNum : System.Byte);
  1016. {* Try to issue an IDENTIFY command for IDE/ATA drive. *}
  1017. VAR
  1018.   dbTestVal  :  System.Byte;
  1019.  
  1020. BEGIN
  1021.  
  1022.   {* test message *}
  1023.     _OutputMessage(asProgramPrompt+' Issue IDENTIFY command.');
  1024.  
  1025.   {* make command block for controller *}
  1026.    _InitCommandBlock(recWR_CMD_BLOCK);
  1027.  
  1028.   {* try to load this command *}
  1029.    _WriteControllerCommand(recRD_HDISK_Regs,recWRT_HDISK_Regs,recWR_CMD_BLOCK);
  1030.    IF  NOT(gbDiskStatusOK)
  1031.       THEN  System.Exit;
  1032.    {if-then}
  1033.  
  1034.   {* wait data transfer from disk drive *}
  1035.    IF NOT(_fnbWaitDRQ(recRD_HDISK_Regs.dwStatusReg_RD))
  1036.         THEN  System.Exit;
  1037.    {if-then}
  1038.  
  1039.   {* get drive info buffer *}
  1040.    _ReadDataSector512(recDriveInfoBuf,recWRT_HDISK_Regs.dwDataReg_WR,aWordsPerDosSector);
  1041.  
  1042.   {* Reading of status register must be clear IRQ14 latch!!! *}
  1043.    dbTestVal := _fndbReadControllerStatus(recRD_HDISK_Regs.dwStatusReg_RD);
  1044.  
  1045. END; { _ReadDriveParameters }
  1046.  
  1047.  
  1048.  
  1049.  
  1050. PROCEDURE  _InitDiskDriveRegsReadMap(VAR recRD_HDISK_Regs : recHDISK_READ_REGS;
  1051.                                      dwDskCtlrBaseReg : System.Word);
  1052. {* Initialize disk drive controller registers read map. *}
  1053. BEGIN
  1054.   WITH  recRD_HDISK_Regs  DO
  1055.    BEGIN
  1056.        dwDataReg_RD              := dwDskCtlrBaseReg + $00;
  1057.        dwErrorReg_RD             := dwDskCtlrBaseReg + $01;
  1058.        dwSectorCountReg_RD       := dwDskCtlrBaseReg + $02;
  1059.        dwSectorNumberReg_RD      := dwDskCtlrBaseReg + $03;
  1060.        dwCylinderLowReg_RD       := dwDskCtlrBaseReg + $04;
  1061.        dwCylinderHighReg_RD      := dwDskCtlrBaseReg + $05;
  1062.        dwSDH_Reg_RD              := dwDskCtlrBaseReg + $06;
  1063.        dwStatusReg_RD            := dwDskCtlrBaseReg + $07;
  1064.    END;
  1065.   {with-do}
  1066. END; { _InitDiskDriveRegsReadMap }
  1067.  
  1068.  
  1069. PROCEDURE  _InitDiskDriveRegsWriteMap(VAR recWRT_HDISK_Regs : recHDISK_WRITE_REGS;
  1070.                                      dwDskCtlrBaseReg : System.Word);
  1071. {* Initialize disk drive controller registers write map. *}
  1072. BEGIN
  1073.   WITH  recWRT_HDISK_Regs  DO
  1074.    BEGIN
  1075.       dwDataReg_WR              := dwDskCtlrBaseReg + $00;
  1076.       dwWRC_Reg_WR              := dwDskCtlrBaseReg + $01;
  1077.       dwSectorCountReg_WR       := dwDskCtlrBaseReg + $02;
  1078.       dwSectorNumberReg_WR      := dwDskCtlrBaseReg + $03;
  1079.       dwCylinderLowReg_WR       := dwDskCtlrBaseReg + $04;
  1080.       dwCylinderHighReg_WR      := dwDskCtlrBaseReg + $05;
  1081.       dwSDH_Reg_WR              := dwDskCtlrBaseReg + $06;
  1082.       dwCommand_Reg_WR          := dwDskCtlrBaseReg + $07;
  1083.    END;
  1084.   {with-do}
  1085. END; { _InitDiskDriveRegsWriteMap }
  1086.  
  1087.  
  1088. PROCEDURE  _DisplayDriveParameters(VAR  recDriveInfoBuf  :  recIDE_Info_Sector; dbDiskNum : System.Byte);
  1089. {* Detail info about IDE-drive parameters. *}
  1090. VAR
  1091.   sTemp                 :       STRING;
  1092.   liCalcTotalSectors    :       System.Longint;
  1093.   dwCapacityRatio,
  1094.   dwCalcParmsCount,
  1095.   dwMaxCalcHeadNum,
  1096.   dwCalcHeads,
  1097.   dwCalcCylinders,
  1098.   dwCalcSectors         :       System.Word;
  1099.   dbTempValue           :       System.Byte;
  1100.   bUserNoAskExit,
  1101.   bDisplayEnable        :       System.Boolean;
  1102.  
  1103. BEGIN
  1104.  
  1105.   {* header message *}
  1106.    _OutputMessage(asBlank);
  1107.    _OutputMessage(asProgramPrompt+'Screen 1 of 4 -> Disk Drive '+_fnsNumToStr(dbDiskNum,1)+' Internal Information');
  1108.  
  1109.   {* general parameters of drive *}
  1110.    WITH  recDriveInfoBuf  DO
  1111.    BEGIN
  1112.       _OutputMessage('-----> Default Translation Mode Parameters <-----');
  1113.       _OutputMessage('Fixed Cylinders ...................... '+_fnsNumToStr(dwFixedCylsNum,4));
  1114.       IF (dwRemovableCylsNum <> 0)
  1115.         THEN  _OutputMessage('Removable Cylinders .................. '+_fnsNumToStr(dwRemovableCylsNum,4));
  1116.       {if-then}
  1117.       _OutputMessage('R(ead)/W(rite) Heads ................. '+_fnsNumToStr(dwHeadsNum,3));
  1118.       _OutputMessage('Unformatted Bytes Per Physical Track.. '+_fnsNumToStr(dwUnfmtdBytesPerPhysTrk,5));
  1119.       _OutputMessage('Unformatted Bytes Per Sector.......... '+_fnsNumToStr(dwUnfmtdBytesPerSec,5));
  1120.       _OutputMessage('Physical Sectors Per Track............ '+_fnsNumToStr(dwPhysSecsPerTrk,5));
  1121.  
  1122.       gliTotalDiskSectors := System.Longint(dwPhysSecsPerTrk) * dwHeadsNum * dwFixedCylsNum;
  1123.  
  1124.       _OutputMessage('-----> Controller/Drive/Firmware Information <-----');
  1125.       _OutputMessage('Controller/Buffer Type................ '+'Type '+_fnsNumToStr(dwControllerType,5));
  1126.       CASE  dwControllerType OF
  1127.               $0000   :   _OutputMessage('    (not specified)');
  1128.               $0001   :   _OutputMessage('    (single ported single sector buffer)');
  1129.               $0002   :   _OutputMessage('    (dual ported multiple sectors buffer)');
  1130.               $0003   :   _OutputMessage('    (dual ported multiple sectors buffer with look-ahead read)');
  1131.        ELSE
  1132.                           _OutputMessage('    (Reserved)');
  1133.       END;
  1134.       {case-of}
  1135.       _OutputMessage('Controller Buffer Size................ '+_fnsNumToStr((dwControllerBufSize DIV 2),5)+
  1136.                                                               '.'+
  1137.                                                               +_fnsNumToStr((dwControllerBufSize MOD 2)*5,5)+
  1138.                                                               ' KB ('+_fnsNumToStr((dwControllerBufSize),3)+' sectors)');
  1139.       _OutputMessage('Controller Firmware Revision ......... '+
  1140.                      _fnsAsciiInfo(System.Ptr(Seg(dbCntlrFirmwareRevision),
  1141.                                    System.Ofs(dbCntlrFirmwareRevision)),
  1142.                                    dbCntlrFirmwareRevisionLen,System.True));
  1143.       _OutputMessage('Serial Number ........................ '+
  1144.                      _fnsAsciiInfo(System.Ptr(Seg(dbSerialNumber),System.Ofs(dbSerialNumber)),dbSerialNumberLen,System.True));
  1145.       _OutputMessage('Model Number ......................... '+
  1146.                      _fnsAsciiInfo(System.Ptr(Seg(dbModelNumber),System.Ofs(dbModelNumber)),dbModelNumberLen,System.True));
  1147.  
  1148.       _OutputMessage('-----> Miscellaneous Drive Transfer Information <-----');
  1149.       _OutputMessage('ECC bytes............................. '+_fnsNumToStr(dwECCbytes,5));
  1150.       _OutputMessageNOLF('Max. Secs/Interrupt for R/W MultiMode. ');
  1151.       IF (System.Hi(dwSecsPerIntr) <> 0)
  1152.         THEN
  1153.           _OutputMessage(_fnsNumToStr((System.Lo(dwSecsPerIntr)),3)+' sectors')
  1154.         ELSE
  1155.           _OutputMessage('not supported');
  1156.       {if-then-else}
  1157.       _OutputMessageNOLF('Current Secs/Int for R/W MultiMode.... ');
  1158.       IF ((dwMultipleSecsModeXfrSettings AND btBit_8_ON) = 0)
  1159.         THEN  _OutputMessage('not valid')
  1160.         ELSE  _OutputMessage('valid ('+_fnsNumToStr((System.Lo(dwMultipleSecsModeXfrSettings)),3)+' sectors/int)');
  1161.       {if-then-else}
  1162.       _OutputMessageNoLF('Double Word Transfer Flag............. ');
  1163.       CASE dwDoubleWordTransferFlag OF
  1164.                0    :    _OutputMessage('not supported');
  1165.                1    :    _OutputMessage('supported');
  1166.       ELSE
  1167.          _OutputMessage(achHexPrefix+_fnsWordToHexFmt(dwDoubleWordTransferFlag)+' = unknown');
  1168.       END;
  1169.       {case-of}
  1170.       _OutputMessageNoLF('Assign Alternate...................... ');
  1171.       CASE System.Lo(dwAssignAlternate) OF
  1172.                0    :    _OutputMessage('not supported');
  1173.                1    :    _OutputMessage('supported');
  1174.       ELSE
  1175.          _OutputMessage(achHexPrefix+_fnsWordToHexFmt(dwAssignAlternate)+' (unknown, VU)');
  1176.       END;
  1177.       {case-of}
  1178.       _OutputMessageNoLF('D(irect) M(emory) A(ccess) support.... ');
  1179.       IF ((System.Hi(dwAssignAlternate) AND btBit_8_ON) = 0)
  1180.         THEN  _OutputMessage('no')
  1181.         ELSE  _OutputMessage('yes');
  1182.       {if-then-else}
  1183.       _OutputMessageNoLF('L(ogical) B(lock) A(ddressing) found.. ');
  1184.       IF ((System.Hi(dwAssignAlternate) AND btBit_9_ON) = 0)
  1185.         THEN  _OutputMessage('no')
  1186.         ELSE  _OutputMessage('yes');
  1187.       {if-then-else}
  1188.       IF (dwPIODataXFRCycleTimingMode <> 0)
  1189.         THEN  BEGIN
  1190.           _OutputMessageNOLF('PIO Data Transfer Cycle Timing Mode... ');
  1191.           dbTempValue := System.Hi(dwPIODataXFRCycleTimingMode);
  1192.           sTemp := 'mode 0';
  1193.           IF ((240 <= dbTempValue) AND (dbTempValue < 383))
  1194.             THEN  sTemp := 'mode 2';
  1195.           {if-then}
  1196.           IF ((383 <= dbTempValue) AND (dbTempValue < 600))
  1197.             THEN  sTemp := 'mode 1';
  1198.           {if-then}
  1199.           _OutputMessage(sTemp+' ('+_fnsNumToStr(dbTempValue,5)+' ns)');
  1200.               END;
  1201.       {if-then}
  1202.       IF (dwDMADataXFRCycleTimingMode<> 0)
  1203.         THEN  BEGIN
  1204.           _OutputMessageNOLF('DMA Data Transfer Cycle Timing Mode... ');
  1205.           dbTempValue := System.Hi(dwPIODataXFRCycleTimingMode);
  1206.           sTemp := 'mode 0';
  1207.           IF ((240 <= dbTempValue) AND (dbTempValue < 383))
  1208.             THEN  sTemp := 'mode 2';
  1209.           {if-then}
  1210.           IF ((383 <= dbTempValue) AND (dbTempValue < 600))
  1211.             THEN  sTemp := 'mode 1';
  1212.           {if-then}
  1213.           _OutputMessage(sTemp+' ('+_fnsNumToStr(dbTempValue,5)+' ns)');
  1214.               END;
  1215.       {if-then}
  1216.       _OutputMessage('Total sectors per drive (LBA mode).... '+_fnsNumToStr(ddTotalUserSecsInLBA_Mode,8));
  1217.       _OutputMessage('Single Word DMA Data Transfer Modes... '+_fnsDmaTransferModeInfo(dwSingleWordDMA_XfrMode));
  1218.       _OutputMessage('Multi-Word DMA Data Transfer Modes.... '+_fnsDmaTransferModeInfo(dwMultiWordDMA_XfrMode));
  1219.  
  1220.       _OutputMessage('-----> V(endor) U(nique) Fields for Drive <-----');
  1221.       IF (dwInterSecGapBytesNumVU <> 0)
  1222.         THEN  _OutputMessage('Inter-Sector Gap Bytes................ '+_fnsNumToStr(dwInterSecGapBytesNumVU,5));
  1223.       {if-then}
  1224.       IF (dwSyncFieldsBytesNumVU <> 0)
  1225.         THEN  _OutputMessage('Bytes in Synch Fields................. '+_fnsNumToStr(dwSyncFieldsBytesNumVU,5));
  1226.       {if-then}
  1227.       IF (dwPLObyteNumVU <> 0)
  1228.         THEN  _OutputMessage('Min. PLO Bytes........................ '+_fnsNumToStr(dwPLObyteNumVU,5));
  1229.       {if-then}
  1230.       _OutputMessage('Vendor Unique Text Field..............');
  1231.       _OutputMessage('  '+
  1232.           _fnsAsciiInfo(System.Ptr(Seg(dbVendorUniqueInfoText),System.Ofs(dbVendorUniqueInfoText)),
  1233.                         dbVendorUniqueInfoTextLen,System.False));
  1234.  
  1235.       _OutputMessage('-----> Current Translation Mode Parameters <-----');
  1236.       _OutputMessageNoLF('Settings for this mode................ ');
  1237.       IF ((dwCurrentSettingsValidFlag AND btBit_0_ON) = 0)
  1238.         THEN  _OutputMessage('may be valid')
  1239.         ELSE  _OutputMessage('valid');
  1240.       {if-then}
  1241.       _OutputMessage('Current Cylinders Number.............. '+_fnsNumToStr(dwCurrentCylsNum,4));
  1242.       _OutputMessage('Current Heads Number.................. '+_fnsNumToStr(dwCurrentHeadsNum,3));
  1243.       _OutputMessage('Current Sectors Per Track Number...... '+_fnsNumToStr(dwCurrentSecsPerTrack,5));
  1244.       _OutputMessage('Current total sectors per drive ...... '+_fnsNumToStr(ddCurrentDriveCapacityInSecs,8));
  1245.  
  1246.       _OutputMessage('-----> Calculated Parameters for This Drive <-----');
  1247.       _OutputMessage('Total sectors per phys. drive (calc).. '+_fnsNumToStr(gliTotalDiskSectors,8));
  1248.       _OutputMessage('Unformatted Drive Capacity (calc)..... '+
  1249.                      +_fnsNumToRealStr((System.Longint(dwUnfmtdBytesPerPhysTrk)*dwHeadsNum*dwFixedCylsNum) /
  1250.                        (aBytesPerKByte*aKBytesPerMByte),5,2)+
  1251.                      ' MBytes');
  1252.       _OutputMessage('Expected DOS Drive Capacity (calc).... '+
  1253.                      +_fnsNumToRealStr((System.Longint(dwPhysSecsPerTrk)*dwHeadsNum*dwFixedCylsNum*aBytesPerDosSector) /
  1254.                        (aBytesPerKByte*aKBytesPerMByte),5,2)+
  1255.                      ' MBytes');
  1256.      _OutputMessage(asBlank);
  1257.  
  1258.    {* configuration info for drive *}
  1259.      _OutputMessage(asProgramPrompt+'Screen 2 of 4 -> Internal Configuration Flags Map for Drive '+_fnsNumToStr(dbDiskNum,1));
  1260.      _OutputMessage('Configuration Flags................... '+achHexPrefix+_fnsWordToHexFmt(dwGeneralConfigFlags));
  1261.      IF ((dwGeneralConfigFlags AND btBit_1_ON) = 0)
  1262.        THEN  _OutputMessage('... Non-hard sectored')
  1263.        ELSE  _OutputMessage('... Hard sectored');
  1264.      {if-then-else}
  1265.      IF ((dwGeneralConfigFlags AND btBit_2_ON) = 0)
  1266.        THEN  _OutputMessage('... Non-soft sectored')
  1267.        ELSE  _OutputMessage('... Soft sectored');
  1268.      {if-then-else}
  1269.      IF ((dwGeneralConfigFlags AND btBit_3_ON) = 0)
  1270.        THEN  _OutputMessage('... MFM encoded')
  1271.        ELSE  _OutputMessage('... Non-MFM encoded');
  1272.      {if-then-else}
  1273.      IF ((dwGeneralConfigFlags AND btBit_4_ON) = 0)
  1274.        THEN  _OutputMessage('... Head switch time <= 15 us')
  1275.        ELSE  _OutputMessage('... Head switch time > 15 us');
  1276.      {if-then-else}
  1277.      IF ((dwGeneralConfigFlags AND btBit_5_ON) = 0)
  1278.        THEN  _OutputMessage('... Spindle motor control option not implemented')
  1279.        ELSE  _OutputMessage('... Spindle motor control option implemented');
  1280.      {if-then-else}
  1281.      IF ((dwGeneralConfigFlags AND btBit_6_ON) = 0)
  1282.        THEN  _OutputMessage('... Non-fixed disk drive')
  1283.        ELSE  _OutputMessage('... Fixed disk drive');
  1284.      {if-then-else}
  1285.      IF ((dwGeneralConfigFlags AND btBit_7_ON) = 0)
  1286.        THEN  _OutputMessage('... Non-removable cartridge drive')
  1287.        ELSE  _OutputMessage('... Removable cartridge drive');
  1288.      {if-then-else}
  1289.      IF ((dwGeneralConfigFlags AND btBit_8_ON) = 0)
  1290.        THEN  _OutputMessage('... Transfer rate > 5 Mb/sec')
  1291.        ELSE  _OutputMessage('... Transfer rate <= 5 Mb/sec');
  1292.      {if-then-else}
  1293.      IF ((dwGeneralConfigFlags AND btBit_9_ON) = 0)
  1294.        THEN  _OutputMessage('... NOT (5 Mb/sec < Transfer rate <= 10 Mb/sec)')
  1295.        ELSE  _OutputMessage('... 5 Mb/sec < Transfer rate <= 10 Mb/sec');
  1296.      {if-then-else}
  1297.      IF ((dwGeneralConfigFlags AND btBit_A_ON) = 0)
  1298.        THEN  _OutputMessage('... Transfer rate < 10 Mb/sec')
  1299.        ELSE  _OutputMessage('... Transfer rate >= 10 Mb/sec');
  1300.      {if-then-else}
  1301.      IF ((dwGeneralConfigFlags AND btBit_B_ON) = 0)
  1302.        THEN  _OutputMessage('... Rotational speed tolerance <= 0.5%')
  1303.        ELSE  _OutputMessage('... Rotational speed tolerance > 0.5%');
  1304.      {if-then-else}
  1305.      IF ((dwGeneralConfigFlags AND btBit_C_ON) = 0)
  1306.        THEN  _OutputMessage('... Data strobe offset option not implemented')
  1307.        ELSE  _OutputMessage('... Data strobe offset option implemented');
  1308.      {if-then-else}
  1309.      IF ((dwGeneralConfigFlags AND btBit_D_ON) = 0)
  1310.        THEN  _OutputMessage('... Track offset option not implemented')
  1311.        ELSE  _OutputMessage('... Track offset option implemented');
  1312.      {if-then-else}
  1313.      IF ((dwGeneralConfigFlags AND btBit_E_ON) = 0)
  1314.        THEN  _OutputMessage('... Format speed tolerance gap not required')
  1315.        ELSE  _OutputMessage('... Format speed tolerance gap required');
  1316.      {if-then-else}
  1317.      IF ((dwGeneralConfigFlags AND btBit_F_ON) = 0)
  1318.        THEN  _OutputMessage('... Magnetic disk drive')
  1319.        ELSE  _OutputMessage('... Non-magnetic disk drive');
  1320.      {if-then-else}
  1321.      _OutputMessage(asBlank);
  1322.  
  1323.    {* suggested CMOS parameters for drive *}
  1324.      _OutputMessage(asProgramPrompt+'Screen 3 of 4 -> Suggested CMOS parameters for Drive '+_fnsNumToStr(dbDiskNum,1));
  1325.      bUserNoAskExit := System.True;
  1326.      IF (gbFindAllOk)
  1327.        THEN  dwCalcSectors := aMinBiosSecNum
  1328.        ELSE  dwCalcSectors := aDefStdDosBiosSecNum;
  1329.      {if-then-else}
  1330.  
  1331.      WHILE  (bUserNoAskExit) DO
  1332.      BEGIN
  1333.          dwMaxCalcHeadNum := dwHeadsNum * (dwPhysSecsPerTrk DIV dwCalcSectors);
  1334.          dwCalcHeads := aStartHeadNum;
  1335.          dwCalcParmsCount := 0;
  1336.          _OutputMessage(asProgramPrompt+
  1337.                         'Find match drive parameters if number of sectors = '+
  1338.                        _fnsNumToStr(dwCalcSectors,5));
  1339.          _OutputMessage(' --- Cyls --- Hds --- Secs --- Calc/Actual/Percentage (total secs) ---');
  1340.  
  1341.          REPEAT
  1342.            {* calculate # of cyls at fixed # of secs/heads *}
  1343.             dwCalcCylinders :=  gliTotalDiskSectors DIV (dwCalcSectors*dwCalcHeads);
  1344.             liCalcTotalSectors := System.Longint(dwCalcSectors * dwCalcHeads) * dwCalcCylinders;
  1345.  
  1346.            {* check if match parameters present before output *}
  1347.             IF ((dwCalcCylinders <> 0) AND
  1348.                (dwCalcCylinders <= aMaxBiosCylNum) AND
  1349.                (dwCalcHeads <= aMaxBiosHeadNum)  AND
  1350.                (dwCalcSectors <= aMaxBiosSecNum))
  1351.               THEN  BEGIN
  1352.         dwCapacityRatio := (liCalcTotalSectors*aPercent100) DIV gliTotalDiskSectors;
  1353.         bDisplayEnable := System.True;
  1354.         IF ((gbFindMaxOk) AND (dwCapacityRatio <> aPercent100))
  1355.            THEN  BEGIN
  1356.              bDisplayEnable := System.False;
  1357.              END;
  1358.         {if-then}
  1359.  
  1360.         IF (bDisplayEnable)
  1361.            THEN  BEGIN
  1362.                System.Inc(dwCalcParmsCount);
  1363.                _OutputMessage('     '+_fnsNumToStrNoAdj(dwCalcCylinders,4)+
  1364.                               '     '+_fnsNumToStrNoAdj(dwCalcHeads,3)+
  1365.                               '      '+_fnsNumToStrNoAdj(dwCalcSectors,2)+
  1366.                               '       '+_fnsNumToStrNoAdj(liCalcTotalSectors,8)+
  1367.                               ' / '+_fnsNumToStr(gliTotalDiskSectors,8)+
  1368.                               ' / '+_fnsNumToRealStr(((liCalcTotalSectors*aPercent100) / gliTotalDiskSectors),2,2)+
  1369.                               '    ('+
  1370.                               +_fnsNumToRealStr((System.Longint(dwCalcSectors)*dwCalcHeads*
  1371.                                                 dwCalcCylinders*aBytesPerDosSector) /
  1372.                                                 (aBytesPerKByte*aKBytesPerMByte),5,2)+
  1373.                                                 ' MB)');
  1374.              END;
  1375.         {if-then}
  1376.                     END;
  1377.             {if-then}
  1378.             System.Inc(dwCalcHeads);
  1379.          UNTIL (dwCalcHeads > dwMaxCalcHeadNum);
  1380.          {repeat-until}
  1381.  
  1382.          {* display this message if none parameters are matching *}
  1383.          IF (dwCalcParmsCount = 0)
  1384.            THEN  _OutputMessage(' No match parameters found');
  1385.          {if-then}
  1386.          _OutputMessage(asBlank);
  1387.  
  1388.        {* ask user about other possible disk types based on sector/track *}
  1389.          IF (gdwMaxScreenLines <> aDisableScreenPage)
  1390.            THEN  BEGIN
  1391.              _OutputMessageNoLF(asProgramPrompt+'Enter number of sectors (CR=exit): ');
  1392.              System.ReadLn(sTemp);
  1393.                  END
  1394.            ELSE
  1395.              sTemp := asBlank;
  1396.          {if-then-else}
  1397.  
  1398.          IF (sTemp <> asBlank)
  1399.             THEN  BEGIN
  1400.               System.Val(sTemp,dwCalcSectors,giErrorCode);
  1401.               IF (giErrorCode <> 0) OR (dwCalcSectors = 0)
  1402.                 THEN  BEGIN
  1403.                    System.WriteLn(asProgramPrompt+' Bad value for sectors number.');
  1404.                    System.Halt(errBadSecsNum);
  1405.                      END;
  1406.               {if-then}
  1407.                  END
  1408.             ELSE
  1409.                bUserNoAskExit := System.False;
  1410.          {if-then-else}
  1411.  
  1412.          IF (gbFindAllOk)
  1413.            THEN BEGIN
  1414.               System.Inc(dwCalcSectors);
  1415.               IF (dwCalcSectors <= aMaxBiosSecNum)
  1416.                 THEN  bUserNoAskExit := System.True;
  1417.               {if-then}
  1418.                 END;
  1419.          {if-then}
  1420.  
  1421.      END;
  1422.      {while-do}
  1423.  
  1424.    END;
  1425.    {with-do}
  1426.  
  1427. END; { _DisplayDriveParameters }
  1428.  
  1429.  
  1430. PROCEDURE  _WriteBufToFile(VAR  recDriveInfoBuf  :  recIDE_Info_Sector);
  1431. {* Detail info about IDE-drive parameters. *}
  1432. VAR
  1433.    recDriveInfOutputStream      :   FILE  OF  recIDE_Info_Sector;
  1434.    sFileName                    :   STRING;
  1435.  
  1436. BEGIN
  1437.    _OutputMessageNoLF(asProgramPrompt+' Enter filename (def.ext.='+asDefExt+'): ');
  1438.    System.ReadLn(sFileName);
  1439.    IF (sFileName <> asBlank)
  1440.    THEN BEGIN
  1441.      sFileName := _fnsForceFileExtension(sFileName,asDefExt);
  1442.      System.Assign(recDriveInfOutputStream,sFileName);
  1443.      System.Rewrite(recDriveInfOutputStream);
  1444.      System.Write(recDriveInfOutputStream,recDriveInfoBuf);
  1445.      System.Close(recDriveInfOutputStream);
  1446.         END;
  1447.    {if-then}
  1448. END;
  1449. { _WriteBufToFile }
  1450.  
  1451.  
  1452. PROCEDURE  _ScanDrive(VAR  recDriveInfoBuf  :  recIDE_Info_Sector;
  1453.                       recRD_HDISK_Regs      :  recHDISK_READ_REGS;
  1454.                       recWRT_HDISK_Regs     :  recHDISK_WRITE_REGS;
  1455.                       recWR_CMD_BLOCK       :  recHDISK_WRITE_CMD_BLOCK;
  1456.                       dwDriveCtrlrBaseReg   :  System.Word;
  1457.                       dbDiskIncVal          :  System.Byte;
  1458.                       dbDiskNum             :  System.Byte;
  1459.                       sCtlr                 :  STRING);
  1460. {* Test the disk drive. *}
  1461. BEGIN
  1462.  
  1463.   {* try drive/controller *}
  1464.      gdbSDH_TestVal := (btCRCmode+btSecSize512);
  1465.     _InitDiskDriveRegsReadMap(grecRD_HDISK_Regs,dwDriveCtrlrBaseReg);
  1466.     _InitDiskDriveRegsWriteMap(grecWRT_HDISK_Regs,dwDriveCtrlrBaseReg);
  1467.     _TestDiskControllerHardware(grecRD_HDISK_Regs,grecWRT_HDISK_Regs,dbDiskNum);
  1468.  
  1469.      IF (gbDiskStatusOK)
  1470.        THEN  BEGIN
  1471.            _OutputMessage(asProgramPrompt+' IDE/ATA drive '+_fnsNumToStr(dbDiskNum,1)+' found  (primary controller)');
  1472.           _ReadDriveParameters(grecDriveInfoBuf, grecRD_HDISK_Regs,
  1473.                                grecWRT_HDISK_Regs, grecWR_CMD_BLOCK,
  1474.                                dbDiskNum);
  1475.           IF  (gbDiskStatusOK)
  1476.              THEN  BEGIN
  1477.                System.Inc(gdbIDE_Disks_Count,dbDiskIncVal);
  1478.                _DisplayDriveParameters(grecDriveInfoBuf,dbDiskNum);
  1479.                IF (gbFileWriteOk)
  1480.                  THEN  _WriteBufToFile(grecDriveInfoBuf);
  1481.                {if-then}
  1482.                    END
  1483.              ELSE
  1484.                 _OutputMessage(asProgramPrompt+' IDENTIFY command failed.');
  1485.           {if-then-else}
  1486.              END
  1487.        ELSE
  1488.            _OutputMessage(asProgramPrompt+' No hardware for drive '+_fnsNumToStr(dbDiskNum,1)+
  1489.                           ' ('+sCtlr+' controller)');
  1490.      {if-then-else}
  1491.  
  1492. END; { _ScanDrive }
  1493.  
  1494.  
  1495. PROCEDURE  _Disp_IDE_disks_Count(dbIDE_Disks_Count : System.Byte);
  1496. {* Output # of IDE-disks in the system. *}
  1497. CONST
  1498.   dbDiskCount  :  System.Byte   =   0;
  1499.  
  1500. BEGIN
  1501.   {* counts the disks *}
  1502.     IF (dbIDE_Disks_Count AND btIdeDrive_00) <> 0
  1503.       THEN  System.Inc(dbDiskCount);
  1504.     {if-then}
  1505.     IF (dbIDE_Disks_Count AND btIdeDrive_01) <> 0
  1506.       THEN  System.Inc(dbDiskCount);
  1507.     {if-then}
  1508.     IF (dbIDE_Disks_Count AND btIdeDrive_02) <> 0
  1509.       THEN  System.Inc(dbDiskCount);
  1510.     {if-then}
  1511.     IF (dbIDE_Disks_Count AND btIdeDrive_03) <> 0
  1512.       THEN  System.Inc(dbDiskCount);
  1513.     {if-then}
  1514.  
  1515.   {* display total *}
  1516.     _OutputMessage(asProgramPrompt+' '+_fnsNumToStr(dbDiskCount,1)+' IDE/ATA-drive(s) found for this computer system.');
  1517.  
  1518. END; { _Disp_IDE_disks_Count }
  1519.  
  1520.  
  1521.  
  1522. {*============================== MAIN PART =============================*}
  1523.  
  1524. BEGIN
  1525.  
  1526.   {* simple test for CPU type *}
  1527.     giErrorCode := 0;
  1528.     asm
  1529.           push    sp
  1530.           pop     ax
  1531.  
  1532.           cmp     ax, sp
  1533.           je      @CPU186
  1534.  
  1535.           mov     giErrorCode, -1
  1536.        @CPU186:
  1537.     end;
  1538.     {asm-end}
  1539.     IF (giErrorCode <> 0)
  1540.           THEN  BEGIN
  1541.              System.WriteLn(asProgramPrompt+' Requires Intel 80186 processor or higher.');
  1542.              System.Halt(errBadCPU);
  1543.           END;
  1544.     {if-then}
  1545.  
  1546.   {* init some variables *}
  1547.     IF  (System.ParamCount > 1)
  1548.       THEN  BEGIN
  1549.        IF (_fnsUpCase(System.ParamStr(2)) <> asNoFileToAsk)
  1550.          THEN  gbFileWriteOk := System.True;
  1551.        {if-then}
  1552.             END;
  1553.     {if-then}
  1554.  
  1555.     IF  (System.ParamCount > 2)
  1556.       THEN  BEGIN
  1557.       gsTemp := _fnsUpCase(System.ParamStr(3));
  1558.           gbFindCMOSOk := System.True;
  1559.           IF  (gsTemp <> asHddTableDisplayOnly)
  1560.             THEN  gbFindAllOk  := System.True;
  1561.       {if-then}
  1562.           IF  (gsTemp = asMaxCapacityOnly)
  1563.             THEN  gbFindMaxOk  := System.True;
  1564.           {if-then}
  1565.             END;
  1566.     {if-then}
  1567.  
  1568.     IF  (System.ParamCount <> 0)
  1569.       THEN  BEGIN
  1570.         System.Val(System.ParamStr(1),gdwMaxScreenLines,giErrorCode);
  1571.         IF (giErrorCode <> 0)
  1572.           THEN  BEGIN
  1573.              System.WriteLn(asProgramPrompt+' Bad value for screen lines.');
  1574.              System.Halt(errBadNumeric);
  1575.                 END
  1576.         ELSE  IF (gdwMaxScreenLines = aDisableScreenPage)
  1577.                 THEN  gdwTextLineNum := aDisableScreenPage;
  1578.               {if-then}
  1579.         {if-then-else}
  1580.             END;
  1581.     {if-then}
  1582.  
  1583.     gdbIDE_Disks_Count := 0;
  1584.     gdwAlternateStatus    := aAltDriveStatusReg_0;
  1585.  
  1586.  
  1587.    {* copyright message *}
  1588.     _CopyrightDisplay;
  1589.  
  1590.  
  1591.   {* try drive 0 hardware/primary controller *}
  1592.     _ScanDrive(grecDriveInfoBuf,
  1593.                grecRD_HDISK_Regs,
  1594.                grecWRT_HDISK_Regs, grecWR_CMD_BLOCK,
  1595.                aDriveCtrlrBaseReg_0,
  1596.                btIdeDrive_00,
  1597.                aPhysDriveNum_0,
  1598.                asPrimary);
  1599.  
  1600.  
  1601.   {* try drive 1 hardware/primary controller *}
  1602.     _ScanDrive(grecDriveInfoBuf,
  1603.                grecRD_HDISK_Regs,
  1604.                grecWRT_HDISK_Regs, grecWR_CMD_BLOCK,
  1605.                aDriveCtrlrBaseReg_1,
  1606.                btIdeDrive_01,
  1607.                aPhysDriveNum_1,
  1608.                asPrimary);
  1609.  
  1610.  
  1611.   {* init some vars *}
  1612.     gdwAlternateStatus    := aAltDriveStatusReg_1;
  1613.  
  1614.  
  1615.   {* try drive 0 hardware/secondary controller *}
  1616.       _ScanDrive(grecDriveInfoBuf,
  1617.                grecRD_HDISK_Regs,
  1618.                grecWRT_HDISK_Regs, grecWR_CMD_BLOCK,
  1619.                aDriveCtrlrBaseReg_2,
  1620.                btIdeDrive_02,
  1621.                aPhysDriveNum_0,
  1622.                asSecondary);
  1623.  
  1624.  
  1625.   {* try drive 1 hardware/secondary controller *}
  1626.       _ScanDrive(grecDriveInfoBuf,
  1627.                grecRD_HDISK_Regs,
  1628.                grecWRT_HDISK_Regs, grecWR_CMD_BLOCK,
  1629.                aDriveCtrlrBaseReg_3,
  1630.                btIdeDrive_03,
  1631.                aPhysDriveNum_1,
  1632.                asSecondary);
  1633.  
  1634.   {* display ROM CMOS HDD types table *}
  1635.      IF  (NOT(gbFindCMOSOk) AND
  1636.           NOT(gbFindAllOk)  AND
  1637.           (gdwMaxScreenLines <> aDisableScreenPage))
  1638.        THEN BEGIN
  1639.          _OutputMessage(asBlank);
  1640.          _OutputMessageNoLF(asProgramPrompt+'Display ROM BIOS HDD types table? (N/Y): ');
  1641.          System.ReadLn(gsTemp);
  1642.          gsTemp := _fnsUpCase(gsTemp);
  1643.          IF ((gsTemp <> asBlank) AND (gsTemp[1] = 'Y'))
  1644.             THEN gbFindCMOSOk := System.True;
  1645.          {if-then}
  1646.             END;
  1647.      {if-then}
  1648.  
  1649.      IF (gbFindCMOSOk)
  1650.        THEN BEGIN
  1651.          _OutputMessage(asBlank);
  1652.          _OutputMessage(asProgramPrompt+'Screen 4 of 4 -> ROM BIOS HDD types table for CMOS drive types');
  1653.          _OutputMessage(' -- Type -- Cyls -- Hds -- WRC -- Secs -- Cntrl -- LZone -- TotalSecs -- MB --');
  1654.          FOR  gdwIndex := aMinHDD_CMOSType  TO  aMaxHDD_CMOSType  DO
  1655.           WITH  recHARD_DISK_PARMS(gdbROM_BIOS_HDD_TYPES_TABLE[gdwIndex])  DO
  1656.            BEGIN
  1657.                gliTotalDiskSectors := System.Longint(dbSECTORS_PER_TRACK) * dbMAX_HEADS_NUM * dwMAX_CYLS_NUM;
  1658.                _OutputMessage('     '+_fnsNumToStrNoAdj(gdwIndex,2)+
  1659.                               '    '+_fnsNumToStrNoAdj(dwMAX_CYLS_NUM,4)+
  1660.                               '    '+_fnsNumToStrNoAdj(dbMAX_HEADS_NUM,3)+
  1661.                               '    '+_fnsNumToStrNoAdj(dwSTART_WRC,5)+
  1662.                               '    '+_fnsNumToStrNoAdj(dbSECTORS_PER_TRACK,2)+
  1663.                               '     '+_fnsNumToStrNoAdj(dbCONTROL_BYTE,3)+
  1664.                               '      '+_fnsNumToStrNoAdj(dwLANDING_ZONE,4)+
  1665.                               '    '+_fnsNumToStrNoAdj(gliTotalDiskSectors,8)+
  1666.                               '    '+_fnsNumToRealStr(((gliTotalDiskSectors*aBytesPerDosSector) /
  1667.                                                        (aBytesPerKByte*aKBytesPerMByte)),5,2));
  1668.             END;
  1669.            {with-do}
  1670.           {for-to-do}
  1671.          _OutputMessage(asBlank);
  1672.             END;
  1673.      {if-then}
  1674.  
  1675.   {* find the number of hard disk drives reported by SYSTEM BIOS *}
  1676.     _OutputMessage(asProgramPrompt+' '+_fnsNumToStr(gdbBIOS_Drives_Num,1)+
  1677.                    ' hard disk drive(s) found by the System BIOS.');
  1678.  
  1679.   {** last report  **}
  1680.     _Disp_IDE_disks_Count(gdbIDE_Disks_Count);
  1681.     _OutputMessage(asProgramPrompt+'Done.');
  1682.  
  1683.   {* write a true value for Sector/Drive/Head: this must be reset a micro-code logic to defaults *}
  1684.    IF  ((gdbIDE_Disks_Count AND (btIdeDrive_02 OR btIdeDrive_03)) <> 0)
  1685.       THEN  System.Port[aDriveCtrlrBaseReg_2+$06] := (btCRCmode+btSecSize512);
  1686.    {if-then}
  1687.    IF  ((gdbIDE_Disks_Count AND (btIdeDrive_00 OR btIdeDrive_01)) <> 0)
  1688.       THEN  System.Port[aDriveCtrlrBaseReg_0+$06] := (btCRCmode+btSecSize512);
  1689.    {if-then}
  1690.  
  1691.   {* System.Halt(errTerminateOk); *}
  1692.  
  1693. END.
  1694.