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

📄 ataiopci.c

📁 ATADRVR是DOS下的磁盘驱动程序,采用PIO传输 ,PCI DMA传输,ATA包,等非常全面代码示例... 内部有C与Asm描述. 编译环境:Borland C/C++ 4.52 与 Bo
💻 C
📖 第 1 页 / 共 3 页
字号:
   bufStart = bufStart << 4;
   bufStart = bufStart + (unsigned long) off;
   bufStart = bufStart & 0xfffffffeL;
   // move up to dword boundary
   bufStart = ( bufStart + 15L ) & 0xfffffff0;
   // compute end
   bufEnd = bufStart + bufSize;
   // compute start/end of 64K area (pma)
   // that will be the I/O buffer
   pmaStart = ( bufStart + 0x00010000L ) & 0xffff0000;
   pmaEnd = pmaStart + 0x00010000L;

   // if pma is in buffer then...
   if ( ( pmaStart < bufEnd ) && ( pmaEnd <= bufEnd ) )
   {
      // ...find location for PRD list
      if ( ( pmaStart - bufStart ) >= 4096L )
      {
         // PRD buffer first (I/O buffer second)
         dma_pci_largePrdBufPtr = MK_FP( (unsigned int) ( bufStart >> 4 ), 0 );
      }
      else
      if ( ( bufEnd - pmaEnd ) >= 4096L )
      {
         // PRD buffer second (I/O buffer first)
         dma_pci_largePrdBufPtr = MK_FP( (unsigned int) ( pmaEnd >> 4 ), 0 );
      }
      if ( dma_pci_largePrdBufPtr )
      {
         dma_pci_largeIoBufPtr = MK_FP( (unsigned int) ( pmaStart >> 4 ), 0 );
         dma_pci_largeMaxB = 65536L * 512L;
         dma_pci_largeMaxS = 65536L;
      }
   }

   #if DEBUG_PCI & 0x02
      pstr( "=>[dma] dma_pci_set_max_xfer()..." );
      sprintf( LFB, "=>[dma] seg %04x off %04x bufSize %lx", seg, off, bufSize );
      prt();
      sprintf( LFB, "=>[dma] bufStart %lx bufEnd %lx", bufStart, bufEnd );
      prt();
      sprintf( LFB, "=>[dma] pmaStart %lx pmaEnd %lx", pmaStart, pmaEnd );
      prt();
      sprintf( LFB, "=>[dma] largePrdBufPtr %Fp largeIoBufPtr %Fp",
                             dma_pci_largePrdBufPtr, dma_pci_largeIoBufPtr );
      prt();
      sprintf( LFB, "=>[dma] dma_pci_largeMaxB %ld dma_pci_largeMaxS %ld",
                             dma_pci_largeMaxB, dma_pci_largeMaxS );
      prt();
   #endif

}

//***********************************************************
//
// exec_pci_ata_cmd() - PCI Bus Master for ATA R/W DMA commands
//
//***********************************************************

static int exec_pci_ata_cmd( int dev,
                             unsigned int seg, unsigned int off,
                             long numSect );

static int exec_pci_ata_cmd( int dev,
                             unsigned int seg, unsigned int off,
                             long numSect )

{
   unsigned int cntr;
   unsigned char status;
   long lw;

   // mark start of a R/W DMA command in low level trace

   trc_llt( 0, 0, TRC_LLT_S_RWD );

   // Quit now if the command is incorrect.

   if (    ( reg_cmd_info.cmd != CMD_READ_DMA )
        && ( reg_cmd_info.cmd != CMD_READ_DMA_EXT )
        && ( reg_cmd_info.cmd != CMD_WRITE_DMA )
        && ( reg_cmd_info.cmd != CMD_WRITE_DMA_EXT ) )
   {
      reg_cmd_info.ec = 77;
      trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      sub_trace_command();
      trc_llt( 0, 0, TRC_LLT_E_RWD );
      return 1;
   }

   // Quit now if no dma channel set up
   // or interrupts are not enabled.

   if ( ( ! pio_bmcr_base_addr ) || ( ! int_use_intr_flag ) )
   {
      reg_cmd_info.ec = 70;
      trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      sub_trace_command();
      trc_llt( 0, 0, TRC_LLT_E_RWD );
      return 1;
   }

   // Quit now if 1) I/O buffer overrun possible.
   // or 2) DMA can't handle the transfer size.

   lw = numSect * 512L;
   if ( (    ( dma_pci_prd_type != PRD_TYPE_LARGE )
          && ( ( lw > MAX_TRANSFER_SIZE ) || ( lw > reg_buffer_size ) ) )
        ||
        (    ( dma_pci_prd_type == PRD_TYPE_LARGE )
          && ( lw > dma_pci_largeMaxB ) )
      )
   {
      reg_cmd_info.ec = 61;
      trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      sub_trace_command();
      trc_llt( 0, 0, TRC_LLT_E_PID );
      return 1;
   }

   // Set up the dma transfer

   if ( set_up_xfer( ( reg_cmd_info.cmd == CMD_WRITE_DMA )
                     ||
                     ( reg_cmd_info.cmd == CMD_WRITE_DMA_EXT ),
                     numSect * 512L, seg, off ) )
   {
      reg_cmd_info.ec = 61;
      trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      sub_trace_command();
      trc_llt( 0, 0, TRC_LLT_E_PID );
      return 1;
   }

   // Set command time out.

   tmr_set_timeout();

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

   if ( sub_select( dev ) )
   {
      sub_trace_command();
      trc_llt( 0, 0, TRC_LLT_E_RWD );
      return 1;
   }

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

   sub_setup_command();

   // For interrupt mode, install interrupt handler.

   int_save_int_vect();

   // Start the command by setting the Command register.  The drive
   // should immediately set BUSY status.

   pio_outbyte( CB_CMD, reg_cmd_info.cmd );

   // The drive should start executing the command including any
   // data transfer.

   // Data transfer...
   // read the BMIDE regs
   // enable/start the dma channel.
   // read the BMIDE regs again

   sub_readBusMstrCmd();
   sub_readBusMstrStatus();
   sub_writeBusMstrCmd( rwControl | BM_CR_MASK_START );
   sub_readBusMstrCmd();
   sub_readBusMstrStatus();

   // Data transfer...
   // the device and dma channel transfer the data here while we start
   // checking for command completion...
   // wait for the PCI BM Interrupt=1 (see ATAIOINT.C)...

   trc_llt( 0, 0, TRC_LLT_WINT );
   cntr = 0;
   while ( 1 )
   {
      cntr ++ ;
      if ( ! ( cntr & 0x1fff ) )
      {
         sub_readBusMstrStatus();         // read BM status (for trace)
         if ( ! ( reg_incompat_flags & REG_INCOMPAT_DMA_POLL ) )
            pio_inbyte( CB_ASTAT );       // poll Alt Status
      }
      if ( int_intr_flag )                // interrupt ?
      {
         trc_llt( 0, 0, TRC_LLT_INTRQ );  // yes
         trc_llt( 0, int_bm_status, TRC_LLT_R_BM_SR );
         trc_llt( CB_STAT, int_ata_status, TRC_LLT_INB );
         trc_llt( 0, 0x04, TRC_LLT_W_BM_SR );
         break;
      }
      if ( tmr_chk_timeout() )            // time out ?
      {
         trc_llt( 0, 0, TRC_LLT_TOUT );   // yes
         reg_cmd_info.to = 1;
         reg_cmd_info.ec = 73;
         trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
         break;
      }
   }

   if ( reg_incompat_flags & REG_INCOMPAT_DMA_DELAY )
      delay( 1 );    // delay for buggy controllers

   // End of command...
   // disable/stop the dma channel

   status = int_bm_status;                // read BM status
   status &= ~ BM_SR_MASK_ACT;            // ignore Active bit
   sub_writeBusMstrCmd( BM_CR_MASK_STOP );    // shutdown DMA
   sub_readBusMstrCmd();                      // read BM cmd (just for trace)
   status |= sub_readBusMstrStatus();         // read BM status again

   if ( reg_incompat_flags & REG_INCOMPAT_DMA_DELAY )
      delay( 1 );    // delay for buggy controlers

   if ( reg_cmd_info.ec == 0 )
   {
      if ( status & BM_SR_MASK_ERR )            // bus master error?
      {
         reg_cmd_info.ec = 78;                  // yes
         trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      }
   }
   if ( reg_cmd_info.ec == 0 )
   {
      if ( status & BM_SR_MASK_ACT )            // end of PRD list?
      {
         reg_cmd_info.ec = 71;                  // no
         trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      }
   }

   #if DEBUG_PCI & 0x01
      trc_llt( 0, int_intr_cntr, TRC_LLT_DEBUG );  // for debugging
   #endif

   // End of command...
   // If no error use the Status register value that was read
   // by the interrupt handler. If there was an error
   // read the Status register because it may not have been
   // read by the interrupt handler.

   if ( reg_cmd_info.ec )
      status = pio_inbyte( CB_STAT );
   else
      status = int_ata_status;

   // Final status check...
   // if no error, check final status...
   // Error if BUSY, DEVICE FAULT, DRQ or ERROR status now.

   if ( reg_cmd_info.ec == 0 )
   {
      if ( status & ( CB_STAT_BSY | CB_STAT_DF | CB_STAT_DRQ | CB_STAT_ERR ) )
      {
         reg_cmd_info.ec = 74;
         trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
      }
   }

   // Final status check...
   // if any error, update total bytes transferred.

   if ( reg_cmd_info.ec == 0 )
      reg_cmd_info.totalBytesXfer = numSect * 512L;
   else
      reg_cmd_info.totalBytesXfer = 0L;

   // Done...
   // Read the output registers and trace the command.

   sub_trace_command();

   // Done...
   // For interrupt mode, remove interrupt handler.

   int_restore_int_vect();

   // Done...
   // mark end of a R/W DMA command in low level trace

   trc_llt( 0, 0, TRC_LLT_E_RWD );

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

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

//***********************************************************
//
// dma_pci_chs() - PCI Bus Master for ATA R/W DMA commands
//
//***********************************************************

int dma_pci_chs( int dev, int cmd,
                 unsigned int fr, unsigned int sc,
                 unsigned int cyl, unsigned int head, unsigned int sect,
                 unsigned int seg, unsigned int off,
                 long numSect )

{

   // Setup current command information.

   sub_zero_return_data();
   reg_cmd_info.flg = TRC_FLAG_ATA;
   reg_cmd_info.ct  = TRC_TYPE_ADMAI;
   if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
      reg_cmd_info.ct  = TRC_TYPE_ADMAO;
   reg_cmd_info.cmd = cmd;
   reg_cmd_info.fr1 = fr;
   reg_cmd_info.sc1 = sc;
   reg_cmd_info.sn1 = sect;
   reg_cmd_info.cl1 = cyl & 0x00ff;
   reg_cmd_info.ch1 = ( cyl & 0xff00 ) >> 8;
   reg_cmd_info.dh1 = ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) | ( head & 0x0f );
   reg_cmd_info.dc1 = 0x00;      // nIEN=0 required on PCI !
   reg_cmd_info.ns  = numSect;
   reg_cmd_info.lbaSize = LBACHS;

   // Execute the command.

   return exec_pci_ata_cmd( dev, seg, off, numSect );
}

//***********************************************************
//
// dma_pci_lba28() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************

int dma_pci_lba28( int dev, int cmd,
                   unsigned int fr, unsigned int sc,
                   unsigned long lba,
                   unsigned int seg, unsigned int off,
                   long numSect )

{

   // Setup current command information.

   sub_zero_return_data();
   reg_cmd_info.flg = TRC_FLAG_ATA;
   reg_cmd_info.ct  = TRC_TYPE_ADMAI;
   if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
      reg_cmd_info.ct  = TRC_TYPE_ADMAO;
   reg_cmd_info.cmd = cmd;
   reg_cmd_info.fr1 = fr;
   reg_cmd_info.sc1 = sc;
   reg_cmd_info.dh1 = CB_DH_LBA | (dev ? CB_DH_DEV1 : CB_DH_DEV0 );
   reg_cmd_info.dc1 = 0x00;      // nIEN=0 required on PCI !
   reg_cmd_info.ns  = numSect;
   reg_cmd_info.lbaSize = LBA28;
   reg_cmd_info.lbaHigh1 = 0L;
   reg_cmd_info.lbaLow1 = lba;

   // Execute the command.

   return exec_pci_ata_cmd( dev, seg, off, numSect );
}

//***********************************************************
//
// dma_pci_lba48() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************

int dma_pci_lba48( int dev, int cmd,
                   unsigned int fr, unsigned int sc,
                   unsigned long lbahi, unsigned long lbalo,
                   unsigned int seg, unsigned int off,
                   long numSect )

{

   // Setup current command information.

   sub_zero_return_data();
   reg_cmd_info.flg = TRC_FLAG_ATA;
   reg_cmd_info.ct  = TRC_TYPE_ADMAI;
   if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
      reg_cmd_info.ct  = TRC_TYPE_ADMAO;
   reg_cmd_info.cmd = cmd;
   reg_cmd_info.fr1 = fr;
   reg_cmd_info.sc1 = sc;
   reg_cmd_info.dh1 = CB_DH_LBA | (dev ? CB_DH_DEV1 : CB_DH_DEV0 );
   reg_cmd_info.dc1 = 0x00;      // nIEN=0 required on PCI !
   reg_cmd_info.ns  = numSect;
   reg_cmd_info.lbaSize = LBA48;
   reg_cmd_info.lbaHigh1 = lbahi;
   reg_cmd_info.lbaLow1 = lbalo;

   // Execute the command.

⌨️ 快捷键说明

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