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

📄 adviopio.c

📁 pc机上经由pci连接的ata和atapi设备驱动
💻 C
字号:
//********************************************************************
// ADVANCED ATA LOW LEVEL I/O DRIVER -- ADVIOPIO.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 module contains inline assembler code so you'll
// also need Borland's TASM assembler.
//
// This C source contains the low level I/O port IN/OUT functions.
//********************************************************************

#include <dos.h>

#include "advio.h"

//*************************************************************
//
// Set the host adapter i/o base addresses.
//
//*************************************************************

void pio_set_iobase_addr( unsigned int base1,
                          unsigned int base2,
                          unsigned int base3 )

{

   ADP->pio_base_addr1 = base1;
   ADP->pio_base_addr2 = base2;
   ADP->bmcrBase = base3;
   ADP->pio_reg_addrs[ CB_DATA ] = ADP->pio_base_addr1 + 0;  // 0
   ADP->pio_reg_addrs[ CB_FR   ] = ADP->pio_base_addr1 + 1;  // 1
   ADP->pio_reg_addrs[ CB_SC   ] = ADP->pio_base_addr1 + 2;  // 2
   ADP->pio_reg_addrs[ CB_SN   ] = ADP->pio_base_addr1 + 3;  // 3
   ADP->pio_reg_addrs[ CB_CL   ] = ADP->pio_base_addr1 + 4;  // 4
   ADP->pio_reg_addrs[ CB_CH   ] = ADP->pio_base_addr1 + 5;  // 5
   ADP->pio_reg_addrs[ CB_DH   ] = ADP->pio_base_addr1 + 6;  // 6
   ADP->pio_reg_addrs[ CB_CMD  ] = ADP->pio_base_addr1 + 7;  // 7
   ADP->pio_reg_addrs[ CB_DC   ] = ADP->pio_base_addr2 + 6;  // 8
}

//*************************************************************
//
// These functions do basic IN/OUT of byte and word values:
//
//    pio_inbyte()
//    pio_outbyte()
//    pio_inword()
//    pio_outword()
//
//*************************************************************

unsigned char pio_inbyte( unsigned int addr )

{
   unsigned int regAddr;
   unsigned char uc;

   regAddr = ADP->pio_reg_addrs[ addr ];

   // uc = (unsigned char) inportb( regAddr );

   // READ THIS: If you get a compile error on the following
   // statement you are trying to use BASM (the assembler
   // built into Borland C). BASM can not assemble 386
   // instructions. You must use Borland TASM as is shown
   // in the EXAMPLE1.MAK or EXAMPLE2.MAK "make files".

   asm   .386

   asm   push  ax
   asm   push  dx

   asm   mov   dx,regAddr

   asm   in    al,dx
   asm   mov   uc,al

   asm   pop   dx
   asm   pop   ax

   if ( addr == CB_STAT || addr == CB_ASTAT )
      trc_llt( addr, uc & ( ~ CB_STAT_IDX ), TRC_LLT_INB );
   else
      trc_llt( addr, uc, TRC_LLT_INB );
   return uc;
}

//*************************************************************

void pio_outbyte( unsigned int addr, unsigned char data )

{
   unsigned int regAddr;

   regAddr = ADP->pio_reg_addrs[ addr ];
   // outportb( regAddr, data );

   asm   .386

   asm   push  ax
   asm   push  dx

   asm   mov   dx,regAddr
   asm   mov   al,data

   asm   out   dx,al

   asm   pop   dx
   asm   pop   ax

   trc_llt( addr, data, TRC_LLT_OUTB );
}

//*************************************************************

unsigned int pio_inword( unsigned int addr )

{
   unsigned int regAddr;
   unsigned int ui;

   regAddr = ADP->pio_reg_addrs[ addr ];

   // ui = inport( regAddr );

   asm   .386

   asm   push  ax
   asm   push  dx

   asm   mov   dx,regAddr

   asm   in    ax,dx
   asm   mov   ui,ax

   asm   pop   dx
   asm   pop   ax

   trc_llt( addr, 0, TRC_LLT_INW );
   return ui;
}

//*************************************************************

void pio_outword( unsigned int addr, unsigned int data )

{
   unsigned int regAddr;

   regAddr = ADP->pio_reg_addrs[ addr ];

   // outport( regAddr, data );

   asm   .386

   asm   push  ax
   asm   push  dx

   asm   mov   dx,regAddr
   asm   mov   ax,data

   asm   out   dx,ax

   asm   pop   dx
   asm   pop   ax

   trc_llt( addr, 0, TRC_LLT_OUTW );
}

//*************************************************************
//
// These functions are normally used to transfer DRQ blocks:
//
// pio_drq_block_in()
// pio_drq_block_out()
//
//*************************************************************

// Note: pio_drq_block_in() is the primary way perform PIO
// Data In transfers. It will handle 8-bit, 16-bit and 32-bit
// I/O based data transfers and 8-bit and 16-bit PCMCIA Memory
// mode transfers.

void pio_drq_block_in( unsigned int addrDataReg,
                       unsigned int bufSeg, unsigned int bufOff,
                       long wordCnt )

{
   int pxw;
   long wc;
   long bufAddr;

   // NOTE: wordCnt is the size of a DRQ data block/packet
   // in words. The maximum value of wordCnt is normally:
   // a) For ATA, 16384 words or 32768 bytes (64 sectors,
   //    only with READ/WRITE MULTIPLE commands),
   // b) For ATAPI, 32768 words or 65536 bytes
   //    (actually 65535 bytes plus a pad byte).

   // normalize bufSeg:bufOff

   bufAddr = bufSeg;
   bufAddr = bufAddr << 4;
   bufAddr = bufAddr + bufOff;

   // adjust pio_xfer_width - don't use DWORD if wordCnt is odd.

   pxw = ADP->pio_xfer_width;
   if ( ( pxw == 32 ) && ( wordCnt & 0x00000001L ) )
      pxw = 16;

   // Data transfer using INS instruction.
   // Break the transfer into chunks of 32768 or fewer bytes.

   while ( wordCnt > 0 )
   {
      bufSeg = (unsigned int) ( bufAddr >> 4 );
      bufOff = (unsigned int) ( bufAddr & 0x0000000fL );
      if ( wordCnt > 16384L )
         wc = 16384;
      else
         wc = wordCnt;
      if ( pxw == 8 )
      {
         // do REP INS
         pio_rep_inbyte( addrDataReg, bufSeg, bufOff, wc * 2L );
      }
      else
      if ( pxw == 32 )
      {
         // do REP INSD
         pio_rep_indword( addrDataReg, bufSeg, bufOff, wc / 2L );
      }
      else
      {
         // do REP INSW
         pio_rep_inword( addrDataReg, bufSeg, bufOff, wc );
      }
      bufAddr = bufAddr + ( wc * 2L );
      wordCnt = wordCnt - wc;
   }

   return;
}

//*************************************************************

// Note: pio_drq_block_out() is the primary way perform PIO
// Data Out transfers. It will handle 8-bit, 16-bit and 32-bit
// I/O based data transfers and 8-bit and 16-bit PCMCIA Memory
// mode transfers.

void pio_drq_block_out( unsigned int addrDataReg,
                        unsigned int bufSeg, unsigned int bufOff,
                        long wordCnt )

{
   int pxw;
   long wc;
   long bufAddr;

   // NOTE: wordCnt is the size of a DRQ data block/packet
   // in words. The maximum value of wordCnt is normally:
   // a) For ATA, 16384 words or 32768 bytes (64 sectors,
   //    only with READ/WRITE MULTIPLE commands),
   // b) For ATAPI, 32768 words or 65536 bytes
   //    (actually 65535 bytes plus a pad byte).

   // normalize bufSeg:bufOff

   bufAddr = bufSeg;
   bufAddr = bufAddr << 4;
   bufAddr = bufAddr + bufOff;

   // adjust pio_xfer_width - don't use DWORD if wordCnt is odd.

   pxw = ADP->pio_xfer_width;
   if ( ( pxw == 32 ) && ( wordCnt & 0x00000001L ) )
      pxw = 16;

   // Data transfer using OUTS instruction.
   // Break the transfer into chunks of 32768 or fewer bytes.

   while ( wordCnt > 0 )
   {
      bufOff = (unsigned int) ( bufAddr & 0x0000000fL );
      bufSeg = (unsigned int) ( bufAddr >> 4 );
      if ( wordCnt > 16384L )
         wc = 16384;
      else
         wc = wordCnt;
      if ( pxw == 8 )
      {
         // do REP OUTS
         pio_rep_outbyte( addrDataReg, bufSeg, bufOff, wc * 2L );
      }
      else
      if ( pxw == 32 )
      {
         // do REP OUTSD
         pio_rep_outdword( addrDataReg, bufSeg, bufOff, wc / 2L );
      }
      else
      {
         // do REP OUTSW
         pio_rep_outword( addrDataReg, bufSeg, bufOff, wc );
      }
      bufAddr = bufAddr + ( wc * 2L );
      wordCnt = wordCnt - wc;
   }

   return;
}

//*************************************************************
//
// These functions do REP INS/OUTS data transfers
// (PIO data transfers in I/O mode):
//
// pio_rep_inbyte()
// pio_rep_outbyte()
// pio_rep_inword()
// pio_rep_outword()
// pio_rep_indword()
// pio_rep_outdword()
//
// These functions can be called directly but usually they
// are called by the pio_drq_block_in() and pio_drq_block_out()
// functions to perform I/O mode transfers. See the
// ADP->pio_xfer_width variable!
//
//*************************************************************

void pio_rep_inbyte( unsigned int addrDataReg,
                     unsigned int bufSeg, unsigned int bufOff,
                     long byteCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int bCnt = (unsigned int) byteCnt;

   // Warning: Avoid calling this function with
   // byteCnt > 32768 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  di
   asm   push  es

   asm   mov   ax,bufSeg
   asm   mov   es,ax
   asm   mov   di,bufOff

   asm   mov   cx,bCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   insb

   asm   pop   es
   asm   pop   di
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_INSB );
}

//*************************************************************

void pio_rep_outbyte( unsigned int addrDataReg,
                      unsigned int bufSeg, unsigned int bufOff,
                      long byteCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int bCnt = (unsigned int) byteCnt;

   // Warning: Avoid calling this function with
   // byteCnt > 32768 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  si
   asm   push  ds

   asm   mov   ax,bufSeg
   asm   mov   ds,ax
   asm   mov   si,bufOff

   asm   mov   cx,bCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   outsb

   asm   pop   ds
   asm   pop   si
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_OUTSB );
}

//*************************************************************

void pio_rep_inword( unsigned int addrDataReg,
                     unsigned int bufSeg, unsigned int bufOff,
                     long wordCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int wCnt = (unsigned int) wordCnt;

   // Warning: Avoid calling this function with
   // wordCnt > 16384 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  di
   asm   push  es

   asm   mov   ax,bufSeg
   asm   mov   es,ax
   asm   mov   di,bufOff

   asm   mov   cx,wCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   insw

   asm   pop   es
   asm   pop   di
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_INSW );
}

//*************************************************************

void pio_rep_outword( unsigned int addrDataReg,
                      unsigned int bufSeg, unsigned int bufOff,
                      long wordCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int wCnt = (unsigned int) wordCnt;

   // Warning: Avoid calling this function with
   // wordCnt > 16384 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  si
   asm   push  ds

   asm   mov   ax,bufSeg
   asm   mov   ds,ax
   asm   mov   si,bufOff

   asm   mov   cx,wCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   outsw

   asm   pop   ds
   asm   pop   si
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_OUTSW );
}

//*************************************************************

void pio_rep_indword( unsigned int addrDataReg,
                      unsigned int bufSeg, unsigned int bufOff,
                      long dwordCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int dwCnt = (unsigned int) dwordCnt;

   // Warning: Avoid calling this function with
   // dwordCnt > 8192 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  di
   asm   push  es

   asm   mov   ax,bufSeg
   asm   mov   es,ax
   asm   mov   di,bufOff

   asm   mov   cx,dwCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   insd

   asm   pop   es
   asm   pop   di
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_INSD );
}

//*************************************************************

void pio_rep_outdword( unsigned int addrDataReg,
                       unsigned int bufSeg, unsigned int bufOff,
                       long dwordCnt )

{
   unsigned int dataRegAddr = ADP->pio_reg_addrs[ addrDataReg ];
   unsigned int dwCnt = (unsigned int) dwordCnt;

   // Warning: Avoid calling this function with
   // dwordCnt > 8192 (transfers 32768 bytes).
   // bufSeg and bufOff should be normalized such
   // that bufOff is a value between 0 and 15 (0xf).

   asm   .386

   asm   push  ax
   asm   push  cx
   asm   push  dx
   asm   push  si
   asm   push  ds

   asm   mov   ax,bufSeg
   asm   mov   ds,ax
   asm   mov   si,bufOff

   asm   mov   cx,dwCnt
   asm   mov   dx,dataRegAddr

   asm   cld

   asm   rep   outsd

   asm   pop   ds
   asm   pop   si
   asm   pop   dx
   asm   pop   cx
   asm   pop   ax

   trc_llt( addrDataReg, 0, TRC_LLT_OUTSD );
}

// end adviopio.c

⌨️ 快捷键说明

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