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

📄 ataioint.c

📁 ~{S2EL~}wdm~{G}6/~}
💻 C
字号:
//********************************************************************
// ATA LOW LEVEL I/O DRIVER -- ATAIOINT.C
//
// by Hale Landis (hlandis@ibm.net)
//
// 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.
//
// This code is based on the ATA-2, ATA-3 and ATA-4 standards and
// on interviews with various ATA controller and drive designers.
//
// This code has been run on many ATA (IDE) drives and
// MFM/RLL controllers.  This code may be a little
// more picky about the status it sees at various times.  A real
// BIOS probably would not check the status as carefully.
//
// Compile with one of the Borland C or C++ compilers.
//
// This C source contains the low level interrupt set up and
// interrupt handler functions.
//********************************************************************

#include <dos.h>

#include "ataio.h"

#include "ataiopd.h"

//*************************************************************
//
// Global interrupt mode data
//
//*************************************************************

int int_use_intr_flag = 0;    // use INT mode if != 0

int int_irq_number = 0;       // IRQ number in use -- only
                              // IRQ's 8-15 are supported.

int int_int_vector = 0;       // INT vector in use -- only
                              // INT vectors 70H to 77H
                              // are supported.

volatile int int_intr_flag;   // interrupt flag -- incremented
                              // each time there is an INT

//*************************************************************
//
// Local data
//
//*************************************************************

static void interrupt ( far * sys_int7x_vect ) (); // save area for the
                                                   // system's INT 7x vector

static int full_time_mode = 0;   // full time mode flag

static int got_it_now = 0;       // have INT 7x now flag

#define  PIC0_ADDR 0x21          // PIC0 address
#define  PIC1_ADDR 0xA1          // PIC1 address

#define  PIC0_ENABLE_PIC1 0xFB   // mask to enable PIC1

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

//*************************************************************
//
// INT 7x (IRQ 8-15) Interrupt Handler.
//
// Increment the interrupt flag and send End of Interrupt
// to the PIC's.
//
//*************************************************************

static void far interrupt int_7x( void );

static void far interrupt int_7x( void )

{
   #define IH1_CONTROL 0x20      // int controller 1 address
   #define IH2_CONTROL 0xa0      // int controller 2 address
   #define IH_EOI      0x20      // end of interrupt

   // Increment the interrupt flag;

   int_intr_flag ++ ;

   // Send End-of-Interrupt to the system interrupt controllers.

   outportb( IH1_CONTROL, IH_EOI );
   outportb( IH2_CONTROL, IH_EOI );
}

//*************************************************************
//
// Enable interrupt mode -- get the IRQ number we are using.
//
// The function MUST be called before interrupt mode can
// be used!
//
// If this function is called then the int_disable_irq()
// function MUST be called before exiting to DOS.
//
//*************************************************************

int int_enable_irq( int irqNum )

{

   // must use IRQ 8 to IRQ 15

   if ( ( irqNum < 8 ) || ( irqNum > 15 ) )
      return 1;

   // save IRQ number and INT number

   int_irq_number = irqNum;
   int_int_vector = 0x70 + ( irqNum - 8 );

   // interrupts are enabled now

   int_use_intr_flag = 1;

   // disable interrupts

   disable();

   // If the system has no interrupt handler, then install
   // our interrupt handler in full time mode.
   // Does the interrupt vector point to an "IRET" instruction?

   sys_int7x_vect = getvect( int_int_vector );
   if ( * (unsigned char far *) sys_int7x_vect == 0xCF )
   {
      // set full time mode is active

      full_time_mode = 1;

      // Save and take over the 7xH interrupt vector.

      sys_int7x_vect = getvect( int_int_vector );
      setvect( int_int_vector, int_7x );

      // In PIC0 change the PIC1 enable bit to 0 (enable IRQ 2)
      // In PIC1 change the IRQ enable bit to 0

      outportb( PIC0_ADDR, ( inportb( PIC0_ADDR ) & PIC0_ENABLE_PIC1 ) );
      outportb( PIC1_ADDR, ( inportb( PIC1_ADDR )
                         & pic1_enable_irq[ int_irq_number - 8 ] ) );
   }

   // Reset the interrupt flag.
   // Enable interrupts.
   // Done.

   int_intr_flag = 0;
   enable();
   return 0;
}

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

void int_disable_irq( void )

{

   // if we have INT 7x now, restore INT 7x now.

   if ( full_time_mode || got_it_now )
   {

      // Disable interrupts.
      // Restore the system's 7xH interrupt vector.
      // Enable interrupts.

      disable();
      setvect( int_int_vector, sys_int7x_vect );
      enable();
   }

   // Reset all the interrupt data.

   int_use_intr_flag = 0;
   int_irq_number = 0;
   int_int_vector = 0;
   int_intr_flag = 0;
   full_time_mode = 0;
   got_it_now = 0;
}

//*************************************************************
//
// Take over the INT 7x vector.
//
// Interrupt mode MUST be setup by calling int_enable_irq()
// before calling this function.
//
//*************************************************************

void int_save_int_vect( void )

{

   // Reset the interrupt flag.

   int_intr_flag = 0;

   // Do nothing if interrupts disabled.
   // Do nothing if in full time mode.
   // Do nothing if we have INT 7x now.

   if ( ! int_use_intr_flag )
      return;
   if ( full_time_mode )
      return;
   if ( got_it_now )
      return;

   // Disable interrupts.
   // Save and take over the 7xH interrupt vector.

   disable();
   sys_int7x_vect = getvect( int_int_vector );
   setvect( int_int_vector, int_7x );

   // In PIC0 change the PIC1 enable bit to 0 (enable IRQ 2)
   // In PIC1 change the IRQ enable bit to 0

   outportb( PIC0_ADDR, ( inportb( PIC0_ADDR ) & PIC0_ENABLE_PIC1 ) );
   outportb( PIC1_ADDR, ( inportb( PIC1_ADDR )
                      & pic1_enable_irq[ int_irq_number - 8 ] ) );

   // We have INT 7x now.
   // Enable interrupts.

   got_it_now = 1;
   enable();
}

//*************************************************************
//
// Restore the INT 7x vector.
//
// Interrupt mode MUST be setup by calling int_enable_irq()
// before calling this function.
//
//*************************************************************

void int_restore_int_vect( void )

{

   // Do nothing if interrupts disabled.
   // Do nothing if in full time mode.
   // Do nothing if INT 7x is not taken over now.

   if ( ! int_use_intr_flag )
      return;
   if ( full_time_mode )
      return;
   if ( ! got_it_now )
      return;

   // Disable interrupts.
   // Restore the 7xH interrupt vector.
   // We don't have the INT 7x now.
   // Enable interrupts.

   disable();
   setvect( int_int_vector, sys_int7x_vect );
   got_it_now = 0;
   enable();
}

// end ataioint.c

⌨️ 快捷键说明

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