📄 advioint.c
字号:
//********************************************************************
// 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 + -