⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winhpa48.cpp

📁 HPA就是host protect area
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <windows.h>
#include <stdio.h>
#include "winio.h"
//********************************************************************
//  ATA LOW LEVEL I/O HPA 	DRIVER -- testhpa.C
//
// by SUN HongZhi (shz@cumtb.edu.cn)
//
// Testhpa has a single header file(test.h) and a single C file. 
// This code is based on the ATA/ATAPI-4,-5 and -6 standards and
// on interviews with various ATA controller .
//
// Note that testhpa does not support ATA CHS addressing.
//
// Most of the code is standard C code and should compile
// using any C compiler. It has been tested using Tc C/C++ 3.0.
//
//********************************************************************

#include "testhpa.h"

//**************************************************************
//
struct REG_CMD_INFO reg_cmd_info;

int reg_config_info[2];

unsigned char * pio_bmide_base_addr;

unsigned int pio_reg_addrs[9] =
{
   PIO_BASE_ADDR1 + 0,  // [0] CB_DATA
   PIO_BASE_ADDR1 + 1,  // [1] CB_FR & CB_ER
   PIO_BASE_ADDR1 + 2,  // [2] CB_SC
   PIO_BASE_ADDR1 + 3,  // [3] CB_SN
   PIO_BASE_ADDR1 + 4,  // [4] CB_CL
   PIO_BASE_ADDR1 + 5,  // [5] CB_CH
   PIO_BASE_ADDR1 + 6,  // [6] CB_DH
   PIO_BASE_ADDR1 + 7,  // [7] CB_CMD & CB_STAT
   PIO_BASE_ADDR2 + 6   // [8] CB_DC & CB_ASTAT
} ;

unsigned char pio_xfer_width = PIO_DEFAULT_XFER_WIDTH;

//**************************************************************
//
// functions internal and private to testhpa
//
//**************************************************************

static void sub_setup_command( void );
static void sub_trace_command( void );
static int sub_select( unsigned char dev );
static unsigned char pio_inbyte( unsigned char addr );
static void pio_outbyte( int addr, unsigned char data );
static unsigned int pio_inword( unsigned char addr );
static void pio_outword( int addr, unsigned int data );
static unsigned long pio_indword( unsigned char addr );
static void pio_outdword( int addr, unsigned long data );
static void sub_wait_poll( unsigned char we, unsigned char pe );

static unsigned char pio_readBusMstrCmd( void );
static unsigned char pio_readBusMstrStatus( void );
static void pio_writeBusMstrCmd( unsigned char x );
static void pio_writeBusMstrStatus( unsigned char x );

static long tmr_cmd_start_time;     // command start time
static void tmr_set_timeout( void );
static int tmr_chk_timeout( void );

// This macro provides a small delay that is used in several
// places in the ATA command protocols:

#define DELAY400NS  { pio_inbyte( CB_ASTAT ); pio_inbyte( CB_ASTAT );  \
                      pio_inbyte( CB_ASTAT ); pio_inbyte( CB_ASTAT ); }

//*************************************************************
//
// reg_config() - Check the host adapter and determine the
//                number and type of drives attached.
//
// This process is not documented by any of the ATA standards.
//
// Infomation is returned by this function is in
// reg_config_info[] -- see testhpa.H.
//
//*************************************************************

int reg_config( void )

{
   int numDev = 0;
   unsigned char sc;
   unsigned char sn;
   unsigned char cl;
   unsigned char ch;
   unsigned char st;
   unsigned char dc;

   // setup register values

   dc = (unsigned char) ( int_use_intr_flag ? 0 : CB_DC_NIEN );

   // reset Bus Master Error bit

   pio_writeBusMstrStatus( BM_SR_MASK_ERR );

   // assume there are no devices

   reg_config_info[0] = REG_CONFIG_TYPE_NONE;
   reg_config_info[1] = REG_CONFIG_TYPE_NONE;

   // set up Device Control register

   pio_outbyte( CB_DC, dc );

   // lets see if there is a device 0

   pio_outbyte( CB_DH, CB_DH_DEV0 );
   DELAY400NS;
   pio_outbyte( CB_SC, 0x55 );
   pio_outbyte( CB_SN, 0xaa );
   pio_outbyte( CB_SC, 0xaa );
   pio_outbyte( CB_SN, 0x55 );
   pio_outbyte( CB_SC, 0x55 );
   pio_outbyte( CB_SN, 0xaa );
   sc = pio_inbyte( CB_SC );
   sn = pio_inbyte( CB_SN );
   if ( ( sc == 0x55 ) && ( sn == 0xaa ) )
      reg_config_info[0] = REG_CONFIG_TYPE_UNKN;

   // lets see if there is a device 1

   pio_outbyte( CB_DH, CB_DH_DEV1 );
   DELAY400NS;
   pio_outbyte( CB_SC, 0x55 );
   pio_outbyte( CB_SN, 0xaa );
   pio_outbyte( CB_SC, 0xaa );
   pio_outbyte( CB_SN, 0x55 );
   pio_outbyte( CB_SC, 0x55 );
   pio_outbyte( CB_SN, 0xaa );
   sc = pio_inbyte( CB_SC );
   sn = pio_inbyte( CB_SN );
   if ( ( sc == 0x55 ) && ( sn == 0xaa ) )
      reg_config_info[1] = REG_CONFIG_TYPE_UNKN;

   // now we think we know which devices, if any are there,
   // so lets try a soft reset (ignoring any errors).

   pio_outbyte( CB_DH, CB_DH_DEV0 );
   DELAY400NS;
   reg_reset( 0 );

   // lets check device 0 again, is device 0 really there?
   // is it ATA or ATAPI?

   pio_outbyte( CB_DH, CB_DH_DEV0 );
   DELAY400NS;
   sc = pio_inbyte( CB_SC );
   sn = pio_inbyte( CB_SN );
   if ( ( sc == 0x01 ) && ( sn == 0x01 ) )
   {
      reg_config_info[0] = REG_CONFIG_TYPE_UNKN;
      st = pio_inbyte( CB_STAT );
      cl = pio_inbyte( CB_CL );
      ch = pio_inbyte( CB_CH );
      if ( ( ( cl == 0x14 ) && ( ch == 0xeb ) )       // PATAPI
           ||
           ( ( cl == 0x69 ) && ( ch == 0x96 ) )       // SATAPI
         )
      {
         reg_config_info[0] = REG_CONFIG_TYPE_ATAPI;
      }
      else
      if ( ( st != 0 )
           &&
           ( ( ( cl == 0x00 ) && ( ch == 0x00 ) )     // PATA
             ||
             ( ( cl == 0x3c ) && ( ch == 0xc3 ) ) )   // SATA
         )
      {
         reg_config_info[0] = REG_CONFIG_TYPE_ATA;
      }
   }

   // lets check device 1 again, is device 1 really there?
   // is it ATA or ATAPI?

   pio_outbyte( CB_DH, CB_DH_DEV1 );
   DELAY400NS;
   sc = pio_inbyte( CB_SC );
   sn = pio_inbyte( CB_SN );
   if ( ( sc == 0x01 ) && ( sn == 0x01 ) )
   {
      reg_config_info[1] = REG_CONFIG_TYPE_UNKN;
      st = pio_inbyte( CB_STAT );
      cl = pio_inbyte( CB_CL );
      ch = pio_inbyte( CB_CH );
      if ( ( ( cl == 0x14 ) && ( ch == 0xeb ) )       // PATAPI
           ||
           ( ( cl == 0x69 ) && ( ch == 0x96 ) )       // SATAPI
         )
      {
         reg_config_info[1] = REG_CONFIG_TYPE_ATAPI;
      }
      else
      if ( ( st != 0 )
           &&
           ( ( ( cl == 0x00 ) && ( ch == 0x00 ) )     // PATA
             ||
             ( ( cl == 0x3c ) && ( ch == 0xc3 ) ) )   // SATA
         )
      {
         reg_config_info[1] = REG_CONFIG_TYPE_ATA;
      }
   }

   // If possible, select a device that exists, try device 0 first.

   if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE )
   {
      pio_outbyte( CB_DH, CB_DH_DEV1 );
      DELAY400NS;
      numDev ++ ;
   }
   if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE )
   {
      pio_outbyte( CB_DH, CB_DH_DEV0 );
      DELAY400NS;
      numDev ++ ;
   }

   // BMIDE Error=1?

   if ( pio_readBusMstrStatus() & BM_SR_MASK_ERR )
   {
      reg_cmd_info.ec = 78;                  // yes
   }

   // return the number of devices found

   return numDev;
}

//*************************************************************
//
// reg_reset() - Execute a Software Reset.
//
// See ATA-2 Section 9.2, ATA-3 Section 9.2, ATA-4 Section 8.3.
//
//*************************************************************

int reg_reset( unsigned char devRtrn )

{
   unsigned char sc;
   unsigned char sn;
   unsigned char status;
   unsigned char dc;

   // setup register values

   dc = (unsigned char) ( int_use_intr_flag ? 0 : CB_DC_NIEN );

   // reset Bus Master Error bit

   pio_writeBusMstrStatus( BM_SR_MASK_ERR );

   // initialize the command timeout counter

   tmr_set_timeout();

   // Set and then reset the soft reset bit in the Device Control
   // register.  This causes device 0 be selected.

   pio_outbyte( CB_DC, (unsigned char) ( dc | CB_DC_SRST ) );
   DELAY400NS;
   pio_outbyte( CB_DC, dc );
   DELAY400NS;

   // If there is a device 0, wait for device 0 to set BSY=0.

   if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE )
   {
      while ( 1 )
      {
         status = pio_inbyte( CB_STAT );
         if ( ( status & CB_STAT_BSY ) == 0 )
            break;
         if ( tmr_chk_timeout() )
         {
            reg_cmd_info.to = 1;
            reg_cmd_info.ec = 1;
            break;
         }
      }
   }

   // If there is a device 1, wait until device 1 allows
   // register access.

   if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE )
   {  int i=0;
      while ( 1 )
      {
	 pio_outbyte( CB_DH, CB_DH_DEV1 );
	 DELAY400NS;i++;
	 sc = pio_inbyte( CB_SC );
	 sn = pio_inbyte( CB_SN );
	 if ( ( sc == 0x01 ) && ( sn == 0x01 ) )
            break;
	 if ( tmr_chk_timeout() || i>3000 )
         {
	    reg_cmd_info.to = 1;
            reg_cmd_info.ec = 2;
            break;
         }
      }

      // Now check if drive 1 set BSY=0.

      if ( reg_cmd_info.ec == 0 )
      {
         if ( pio_inbyte( CB_STAT ) & CB_STAT_BSY )
         {
            reg_cmd_info.ec = 3;
         }
      }
   }

   // RESET_DONE:

   // We are done but now we must select the device the caller
   // requested. This will cause
   // the correct data to be returned in reg_cmd_info.

   pio_outbyte( CB_DH, (unsigned char) ( devRtrn ? CB_DH_DEV1 : CB_DH_DEV0 ) );
   DELAY400NS;

   // If possible, select a device that exists,
   // try device 0 first.

   if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE )
   {
      pio_outbyte( CB_DH, CB_DH_DEV1 );
      DELAY400NS;
   }
   if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE )
   {
      pio_outbyte( CB_DH, CB_DH_DEV0 );
      DELAY400NS;
   }

   // BMIDE Error=1?

   if ( pio_readBusMstrStatus() & BM_SR_MASK_ERR )
   {
      reg_cmd_info.ec = 78;                  // yes
   }

   // All done.  The return values of this function are described in
   // testhpa.H.

   sub_trace_command();
   if ( reg_cmd_info.ec )
      return 1;
   return 0;
}

//*************************************************************
//
// exec_non_data_cmd() - Execute a non-data command.
//
// This includes the strange ATAPI DEVICE RESET 'command'
// (command code 08H).
//
// Note special handling for Execute Device Diagnostics
// command when there is no device 0.
//
// See ATA-2 Section 9.5, ATA-3 Section 9.5,
// ATA-4 Section 8.8 Figure 12.  Also see Section 8.5.
//
//*************************************************************

static int exec_non_data_cmd( unsigned char dev );

static int exec_non_data_cmd( unsigned char dev )

{
   unsigned char secCnt;

   // reset Bus Master Error bit

   pio_writeBusMstrStatus( BM_SR_MASK_ERR );

   // Set command time out.

   tmr_set_timeout();

   // PAY ATTENTION HERE
   // If the caller is attempting a Device Reset command, then
   // don't do most of the normal stuff.  Device Reset has no
   // parameters, should not generate an interrupt and it is the
   // only command that can be written to the Command register
   // when a device has BSY=1 (a very strange command!).  Not
   // all devices support this command (even some ATAPI devices
   // don't support the command.

      // Select the drive - call the sub_select function.
      // Quit now if this fails.

      if ( sub_select( dev ) )
      {
         return 1;
      }

      // Set up all the registers except the command register.

      sub_setup_command();

for(secCnt=0;secCnt<200;secCnt++){DELAY400NS};
   // Start the command by setting the Command register.  The drive
   // should immediately set BUSY status.

   pio_outbyte( CB_CMD, reg_cmd_info.cmd );

   // Waste some time by reading the alternate status a few times.
   // This gives the drive time to set BUSY in the status register on
   // really fast systems.  If we don't do this, a slow drive on a fast
   // system may not set BUSY fast enough and we would think it had
   // completed the command when it really had not even started the
   // command yet.

   DELAY400NS;
for(secCnt=0;secCnt<200;secCnt++){DELAY400NS};

   // NON_DATA_DONE:

   // All done.  The return values of this function are described in
   // testhpa.H.

   sub_trace_command();
   if ( reg_cmd_info.ec )
      return 1;
   return 0;
}

//*************************************************************
//
// reg_non_data_lba28() - Easy way to execute a non-data command
//                        using an LBA sector address.
//
//*************************************************************

int reg_non_data_lba28( unsigned char dev, unsigned char cmd,
                        unsigned int fr, unsigned int sc,
                        unsigned long lba )

{

   // Setup current command information.

   reg_cmd_info.cmd = cmd;
   reg_cmd_info.fr = fr;
   reg_cmd_info.sc = sc;
   reg_cmd_info.dh = (unsigned char) ( CB_DH_LBA | ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) );
   reg_cmd_info.dc = (unsigned char) ( int_use_intr_flag ? 0 : CB_DC_NIEN );
   reg_cmd_info.ns  = sc;
   reg_cmd_info.lbaSize = LBA28;
   reg_cmd_info.lbaHigh = 0L;
   reg_cmd_info.lbaLow = lba;

   // Execute the command.

   return exec_non_data_cmd( dev );
}

//*************************************************************
//
// reg_non_data_lba48() - Easy way to execute a non-data command
//                        using an LBA sector address.
//
//*************************************************************

int reg_non_data_lba48( unsigned char dev, unsigned char cmd,
                        unsigned int fr, unsigned int sc,
                        unsigned long lbahi, unsigned long lbalo )

{

   // Setup current command infomation.

   reg_cmd_info.cmd = cmd;
   reg_cmd_info.fr = fr;
   reg_cmd_info.sc = sc;
   reg_cmd_info.dh = (unsigned char) ( CB_DH_LBA | ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) );
   reg_cmd_info.dc = (unsigned char) ( int_use_intr_flag ? 0 : CB_DC_NIEN );
   reg_cmd_info.ns  = sc;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -