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

📄 advioint.c

📁 pc机上经由pci连接的ata和atapi设备驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
//********************************************************************
// ADVANCED ATA LOW LEVEL I/O DRIVER -- ADVIOINT.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 interrupt set up and
// interrupt handler functions.
//********************************************************************

#include <dos.h>

#include "advio.h"

#define DEBUG_INT 0x00  // not zero for debug
                        // 0x02 debug int_info data

#if DEBUG_INT & 0x02
   #include <stdio.h>
   extern unsigned char far LFB[128];
   extern void prt( void );
   extern void pstr( unsigned char * s );
   extern void Vid_Goto_Rc( int r, int c );
   extern void Vid_Out_Str( unsigned char * s );
#endif

//*************************************************************
//
// Static interrupt mode data
//
//*************************************************************

// IRQ table -
// Note: IRQ 0 to 15 are defined in the table but
// IRQ 0 and 2 are never used.

static struct IRQ_INFO
{
   int configFlag;                        // != 0 if any useFlag != 0
   int useFlag[4];                        // use flag for P0, P1, S0 and S1,
                                          //   !=0 if configured
   int irqShared;                         // != 0 if IRQ is shared
   int intNum;                            // INT number for this IRQ
   unsigned int priBmcrAddr;              // primary side BMCR/BMIDE i/o addr
   unsigned int secBmcrAddr;              // secondary side BMCR/BMIDE i/o addr
   struct ADVIO_DEVICE * devPtr[4];       // pointer to device data,
                                          //    P0, P1, S0 and S1
   void interrupt ( far * intVect ) ();   // original INT vector
} irq_info[16];

// declaration of the interrupt handers (see below).

// static void far interrupt int_handler0( void );
static void far interrupt int_handler1( void );
// static void far interrupt int_handler2( void );
static void far interrupt int_handler3( void );
static void far interrupt int_handler4( void );
static void far interrupt int_handler5( void );
static void far interrupt int_handler6( void );
static void far interrupt int_handler7( void );
static void far interrupt int_handler8( void );
static void far interrupt int_handler9( void );
static void far interrupt int_handler10( void );
static void far interrupt int_handler11( void );
static void far interrupt int_handler12( void );
static void far interrupt int_handler13( void );
static void far interrupt int_handler14( void );
static void far interrupt int_handler15( void );

// table of interrupt handler entry points

static struct
{
   void interrupt ( far * newVect ) ();
} intVects[16] =
   {
      { (void far *) 0 },
      { int_handler1 },
      { (void far *) 0 },
      { int_handler3 },
      { int_handler4 },
      { int_handler5 },
      { int_handler6 },
      { int_handler7 },
      { int_handler8 },
      { int_handler9 },
      { int_handler10 },
      { int_handler11 },
      { int_handler12 },
      { int_handler13 },
      { int_handler14 },
      { int_handler15 },
   } ;

// common interrupt handler function

static void far int_monitor( void );

// temp variables used by int_monitor()

static int monIrqNum;
static unsigned char monBmStatus;
static int monNdx;
static struct ADVIO_DEVICE * monADP;

// temp holding place for old int vector

void interrupt ( far * oldVect ) ();

// system interrupt controller data...

#define PIC0_CTRL 0x20           // PIC0 i/o address
#define PIC0_MASK 0x21           // PIC0 i/o address
#define PIC1_CTRL 0xA0           // PIC1 i/o address
#define PIC1_MASK 0xA1           // PIC1 i/o address

#define PIC0_ENABLE_PIC1 0xFB    // mask to enable PIC1 in PIC0

static pic_enable_irq[8] =       // mask to enable
   { 0xFE, 0xFD, 0xFB, 0xF7,     //   IRQ 0-7 in PIC 0 or
     0xEF, 0xDF, 0xBF, 0x7F  };  //   IRQ 8-15 in PIC 1

#define PIC_EOI      0x20        // end of interrupt

//*************************************************************
//
// Enable interrupt mode
//
// If this function is called then the int_disable()
// function MUST be called before exiting to DOS.
//
//*************************************************************

int int_config( int shared, int irqNum, int chanNum, int devNum )

{
   int ndx;

   // error if...
   // ...invalid IRQ
   // ...bmcr i/o address invalid
   // ...shared and no bmcr i/o address
   // ...ata cmd block i/o address invalid
   if ( ( irqNum < 1 ) || ( irqNum > 15 ) )
      return 1;
   if ( irqNum == 2 )
      return 1;
   if ( ADP->bmcrBase < 0x0100 )
      return 2;
   if ( ADP->pio_base_addr1 < 0x0100 )
      return 3;

   // compute index (0 to 3) from chan and device numbers
   ndx = ( ( chanNum ? 1 : 0 ) * 2 )
         + ( devNum ? 1 : 0 );

   // check for duplicate
   if ( irq_info[irqNum].useFlag[ndx] )
      return 4;

   // setup IRQ info data
   if ( ndx <= 1 )
   {
      if ( irq_info[irqNum].useFlag[ndx]
           && ( irq_info[irqNum].priBmcrAddr != ADP->bmcrBase ) )
         return 5;
      irq_info[irqNum].priBmcrAddr = ADP->bmcrBase;
      irq_info[irqNum].secBmcrAddr = ADP->bmcrBase + 8;
   }
   else
   {
      if ( irq_info[irqNum].useFlag[ndx]
           && ( irq_info[irqNum].secBmcrAddr != ADP->bmcrBase ) )
         return 5;
      irq_info[irqNum].priBmcrAddr = ADP->bmcrBase - 8;;
      irq_info[irqNum].secBmcrAddr = ADP->bmcrBase;
   }
   irq_info[irqNum].irqShared = shared;
   irq_info[irqNum].intNum =
      ( irqNum < 8 ) ? ( irqNum + 8 ) : ( 0x70 + ( irqNum - 8 ) );
   irq_info[irqNum].devPtr[ndx] = ADP;
   irq_info[irqNum].intVect = (void *) 0;
   irq_info[irqNum].useFlag[ndx] = 1;
   irq_info[irqNum].configFlag = 1;

   // set up device IRQ info data
   ADP->irqActive = 0;
   ADP->irqNum = irqNum;
   ADP->intNum =
      ( irqNum < 8 ) ? ( irqNum + 8 ) : ( 0x70 + ( irqNum - 8 ) );
   ADP->intOnOff = 0;
   ADP->intFlag = 0;

   // Done
   return 0;
}

//*************************************************************
//
// Enable interrupt mode - install our interurpt handlers.
//
// If this function is called then the int_disable()
// function MUST be called before exiting to DOS.
//
//*************************************************************

void int_enable( void )

{
   int irqNum;
   int ndx;
   struct ADVIO_DEVICE * tmpADP;

   // enable all IRQs
   for ( irqNum = 0; irqNum < 16; irqNum ++ )
   {

      // skip IRQ 0 and 2
      if ( ( irqNum == 0 ) || ( irqNum == 2 ) )
         continue;

      #if DEBUG_INT & 0x02
         sprintf( LFB, "=>[int] 1 irqnum %d configFlag %d useFlag %d %d %d %d"
                                  " irqShared %d intNum %02X",
                                  irqNum,
                                  irq_info[irqNum].configFlag,
                                  irq_info[irqNum].useFlag[0],
                                  irq_info[irqNum].useFlag[1],
                                  irq_info[irqNum].useFlag[2],
                                  irq_info[irqNum].useFlag[3],
                                  irq_info[irqNum].irqShared,
                                  irq_info[irqNum].intNum );
         prt();
         sprintf( LFB, "=>[int] 2 irqnum %d priBmcrAddr %04X secBmcrAddr %04X",
                                  irqNum,
                                  irq_info[irqNum].priBmcrAddr,
                                  irq_info[irqNum].secBmcrAddr );
         prt();
      #endif

      // skip if not used
      if ( ! irq_info[irqNum].configFlag )
         continue;

      // save current INT vector and point the INT to us
      disable();
      irq_info[irqNum].intVect = getvect( irq_info[irqNum].intNum );
      setvect( irq_info[irqNum].intNum, intVects[irqNum].newVect );
      enable();

      // turn on the device's IRQ active flag and zero the INT flag
      for ( ndx = 0; ndx < 4; ndx ++ )
      {
         tmpADP = irq_info[irqNum].devPtr[ndx];
         if ( tmpADP )
         {
            tmpADP->irqActive = 1;
            tmpADP->intOnOff = 0;
            tmpADP->intFlag = 0;

            #if DEBUG_INT & 0x02

                  sprintf( LFB, "=>[int] 3 irqNum %d ndx %d irqActive %d irqNum %d"
                                           " intNum %02X intOnOff %d",
                                           irqNum, ndx,
                                           tmpADP->irqActive, tmpADP->irqNum,
                                           tmpADP->intNum, tmpADP->intOnOff );
                  prt();
                  sprintf( LFB, "=>[int] 4 irqNum %d ndx %d bmcrBase %04X"
                                           " pio_base_addr1 %04X",
                                           irqNum, ndx,
                                           tmpADP->bmcrBase,
                                           tmpADP->pio_base_addr1 );
                  prt();

            #endif
         }
      }

      // enable the IRQ/INT in PIC0/PCI1
      if ( irqNum < 8 )
      {
         // In PIC0 change the IRQ 0-7 enable bit to 0
         outportb( PIC0_MASK, ( inportb( PIC0_MASK )
                            & pic_enable_irq[ irqNum ] ) );
      }
      else
      {
         // In PIC0 change the PIC1 enable bit to 0 (enable IRQ 2)
         // In PIC1 change the IRQ enable bit to 0
         outportb( PIC0_MASK, ( inportb( PIC0_MASK ) & PIC0_ENABLE_PIC1 ) );
         outportb( PIC1_MASK, ( inportb( PIC1_MASK )
                            & pic_enable_irq[ irqNum - 8 ] ) );
      }
   }
}

//*************************************************************
//
// Disable interrupt mode.
//
// If the int_enable() function has been called,
// this function MUST be called before exiting to DOS.
//
//*************************************************************

void int_disable( void )

{
   int irqNum;
   int ndx;
   struct ADVIO_DEVICE * tmpADP;

   // disable all IRQs
   for ( irqNum = 0; irqNum < 16; irqNum ++ )
   {

      // skip IRQ 0 and 2
      if ( ( irqNum == 0 ) || ( irqNum == 2 ) )
         continue;

      // skip if IRQ not in use
      if ( ! irq_info[irqNum].configFlag )
         continue;

      // turn off the device's IRQ active flag
      for ( ndx = 0; ndx < 4; ndx ++ )
      {
         tmpADP = irq_info[irqNum].devPtr[ndx];
         if ( tmpADP )
         {
            tmpADP->irqActive = 0;
            tmpADP->intOnOff = 0;
         }
      }

      // restore the original INT vector
      if ( irq_info[irqNum].intVect )
         setvect( irq_info[irqNum].intNum, irq_info[irqNum].intVect );

      // zero in use flags
      irq_info[irqNum].configFlag = 0;

⌨️ 快捷键说明

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