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

📄 adviosub.c

📁 pc机上经由pci连接的ata和atapi设备驱动
💻 C
字号:
//********************************************************************
// ATA LOW LEVEL I/O DRIVER -- ADVIOSUB.C
//
// by Hale Landis (hlandis@ata-atapi.com)
//
// There is no copyright and there are no restrictions on the use
// of this ATA Low Level I/O Driver code.  It is distributed to
// help other programmers understand how the ATA device interface
// works and it is distributed without any warranty.  Use this
// code at your own risk.
//
// Compile with one of the Borland C or C++ compilers.
//
// This C source contains common subroutines to support
// the PIO and DMA command execution and trace functions.
//********************************************************************

#include <dos.h>

#include "advio.h"

//*************************************************************
//
// sub_zero_return_data() -- zero the return data areas.
//
//*************************************************************

void sub_zero_return_data( void )

{

   ADP->ec = 0;
   ADP->to = 0;
   ADP->totalBytesXfer = 0;
   ADP->drqPackets = 0;
   ADP->failbits = 0;
}

//*************************************************************
//
// sub_setup_command() -- setup the command parameters
//                        in FR, SC, SN, CL, CH and DH.
//
//*************************************************************

void sub_setup_command( void )

{
   unsigned char fr48[2];
   unsigned char sc48[2];
   unsigned char lba48[8];

   // WARNING: THIS CODE IS DESIGNED FOR A STUPID PROCESSOR
   // LIKE INTEL X86 THAT IS Little-Endian, THAT IS, A
   // PROCESSOR THAT STORES DATA IN MEMORY IN THE WRONG
   // BYTE ORDER !!!

   * (unsigned int *) fr48 = ADP->fr1;
   * (unsigned int *) sc48 = ADP->sc1;
   * (unsigned long *) ( lba48 + 4 ) = ADP->lbaHigh1;
   * (unsigned long *) ( lba48 + 0 ) = ADP->lbaLow1;

   pio_outbyte( CB_DC, ADP->irqActive ? 0 : CB_DC_NIEN );

   if ( ADP->lbaSize == LBA28 )
   {
      // in ATA LBA28 mode
      pio_outbyte( CB_FR, fr48[0] );
      pio_outbyte( CB_SC, sc48[0] );
      ADP->sn1 = lba48[0];
      pio_outbyte( CB_SN, lba48[0] );
      ADP->cl1 = lba48[1];
      pio_outbyte( CB_CL, lba48[1] );
      ADP->ch1 = lba48[2];
      pio_outbyte( CB_CH, lba48[2] );
      pio_outbyte( CB_DH, ( ADP->dh1 & 0xf0 ) | ( lba48[3] & 0x0f ) );
   }
   else
   if ( ADP->lbaSize == LBA48 )
   {
      // in ATA LBA48 mode
      pio_outbyte( CB_FR, fr48[1] );
      pio_outbyte( CB_SC, sc48[1] );
      pio_outbyte( CB_SN, lba48[3] );
      pio_outbyte( CB_CL, lba48[4] );
      pio_outbyte( CB_CH, lba48[5] );
      pio_outbyte( CB_FR, fr48[0] );
      pio_outbyte( CB_SC, sc48[0] );
      ADP->sn1 = lba48[0];
      pio_outbyte( CB_SN, lba48[0] );
      ADP->cl1 = lba48[1];
      pio_outbyte( CB_CL, lba48[1] );
      ADP->ch1 = lba48[2];
      pio_outbyte( CB_CH, lba48[2] );
      pio_outbyte( CB_DH, ADP->dh1  );
   }
   else
   {
      // in ATA CHS or ATAPI LBA32 mode
      pio_outbyte( CB_FR, ADP->fr1  );
      pio_outbyte( CB_SC, ADP->sc1  );
      pio_outbyte( CB_SN, ADP->sn1  );
      pio_outbyte( CB_CL, ADP->cl1  );
      pio_outbyte( CB_CH, ADP->ch1  );
      pio_outbyte( CB_DH, ADP->dh1  );
   }
}

//*************************************************************
//
// sub_trace_command() -- trace the end of a command.
//
//*************************************************************

void sub_trace_command( void )

{
   unsigned long lba;
   unsigned char sc48[2];
   unsigned char lba48[8];

   ADP->st2 = pio_inbyte( CB_STAT );
   ADP->as2 = pio_inbyte( CB_ASTAT );
   ADP->er2 = pio_inbyte( CB_ERR );
   if ( ADP->lbaSize == LBA48 )
   {
      // read back ATA LBA48...
      sc48[0]  = pio_inbyte( CB_SC );
      lba48[0] = pio_inbyte( CB_SN );
      lba48[1] = pio_inbyte( CB_CL );
      lba48[2] = pio_inbyte( CB_CH );
      pio_outbyte( CB_DC, CB_DC_HOB );
      sc48[1]  = pio_inbyte( CB_SC );
      lba48[3] = pio_inbyte( CB_SN );
      ADP->sn2 = lba48[3];
      lba48[4] = pio_inbyte( CB_CL );
      ADP->cl2 = lba48[4];
      lba48[5] = pio_inbyte( CB_CH );
      pio_outbyte( CB_DC, 0 );
      ADP->ch2 = lba48[5];
      lba48[6] = 0;
      lba48[7] = 0;
      ADP->sc2 = * (unsigned int *) sc48;
      ADP->lbaHigh2 = * (unsigned long *) ( lba48 + 4 );
      ADP->lbaLow2  = * (unsigned long *) ( lba48 + 0 );
      ADP->dh2 = pio_inbyte( CB_DH );
   }
   else
   {
      // read back ATA CHS, ATA LBA28 or ATAPI LBA32
      ADP->sc2 = pio_inbyte( CB_SC );
      ADP->sn2 = pio_inbyte( CB_SN );
      ADP->cl2 = pio_inbyte( CB_CL );
      ADP->ch2 = pio_inbyte( CB_CH );
      ADP->dh2 = pio_inbyte( CB_DH );
      ADP->lbaHigh2 = 0;
      ADP->lbaLow2 = 0;
      if ( ADP->lbaSize == LBA28 )
      {
         lba = ADP->dh2 & 0x0f;
         lba = lba << 8;
         lba = lba | ADP->ch2;
         lba = lba << 8;
         lba = lba | ADP->cl2;
         lba = lba << 8;
         lba = lba | ADP->sn2;
         ADP->lbaLow2 = lba;
      }
   }
   trc_cht();
}

//*************************************************************
//
// sub_select() - function used to select a drive.
//
// Function to select a drive making sure that BSY=0 and DRQ=0.
//
//**************************************************************

int sub_select( void )

{
   unsigned char status;

   // We don't know which drive is currently selected but we should
   // wait BSY=0 and DRQ=0. Normally both BSY=0 and DRQ=0
   // unless something is very wrong!

   trc_llt( 0, 0, TRC_LLT_PNBSY );
   while ( 1 )
   {
      status = pio_inbyte( CB_STAT );
      if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == 0 )
         break;
      if ( tmr_chk_timeout() )
      {
         trc_llt( 0, 0, TRC_LLT_TOUT );
         ADP->to = 1;
         ADP->ec = 11;
         trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
         ADP->st2 = status;
         ADP->as2 = pio_inbyte( CB_ASTAT );
         ADP->er2 = pio_inbyte( CB_ERR );
         ADP->sc2 = pio_inbyte( CB_SC );
         ADP->sn2 = pio_inbyte( CB_SN );
         ADP->cl2 = pio_inbyte( CB_CL );
         ADP->ch2 = pio_inbyte( CB_CH );
         ADP->dh2 = pio_inbyte( CB_DH );
         return 1;
      }
   }

   // Here we select the drive we really want to work with by
   // setting the DEV bit in the Drive/Head register.

   pio_outbyte( CB_DH, ADP->devBit );
   DELAY400NS;

   // Wait for the selected device to have BSY=0 and DRQ=0.
   // Normally the drive should be in this state unless
   // something is very wrong (or initial power up is still in
   // progress).

   trc_llt( 0, 0, TRC_LLT_PNBSY );
   while ( 1 )
   {
      status = pio_inbyte( CB_STAT );
      if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == 0 )
         break;
      if ( tmr_chk_timeout() )
      {
         trc_llt( 0, 0, TRC_LLT_TOUT );
         ADP->to = 1;
         ADP->ec = 12;
         trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
         ADP->st2 = status;
         ADP->as2 = pio_inbyte( CB_ASTAT );
         ADP->er2 = pio_inbyte( CB_ERR );
         ADP->sc2 = pio_inbyte( CB_SC );
         ADP->sn2 = pio_inbyte( CB_SN );
         ADP->cl2 = pio_inbyte( CB_CL );
         ADP->ch2 = pio_inbyte( CB_CH );
         ADP->dh2 = pio_inbyte( CB_DH );
         return 1;
      }
   }

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

   if ( ADP->ec )
      return 1;
   return 0;
}

//***********************************************************
//
// read/write BMCR/BMIDE Command and Status regs
//
//***********************************************************


unsigned char sub_readBusMstrCmd( void )

{
   unsigned char x;

   if ( ADP->bmcrBase < 0x0100 )
      return 0;
   x = inportb( ADP->bmcrBase + BM_COMMAND_REG );
   trc_llt( 0, x, TRC_LLT_R_BM_CR );
   return x;
}


unsigned char sub_readBusMstrStatus( void )

{
   unsigned char x;

   if ( ADP->bmcrBase < 0x0100 )
      return 0;
   x = inportb( ADP->bmcrBase + BM_STATUS_REG );
   trc_llt( 0, x, TRC_LLT_R_BM_SR );
   return x;
}


void sub_writeBusMstrCmd( unsigned char x )

{

   if ( ADP->bmcrBase < 0x0100 )
      return;
   trc_llt( 0, x, TRC_LLT_W_BM_CR );
   outportb( ADP->bmcrBase + BM_COMMAND_REG, x );
}

void sub_writeBusMstrStatus( unsigned char x )


{

   if ( ADP->bmcrBase < 0x0100 )
      return;
   trc_llt( 0, x, TRC_LLT_W_BM_SR );
   outportb( ADP->bmcrBase + BM_STATUS_REG, x );
}

// end adviosub.c

⌨️ 快捷键说明

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