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

📄 pcirq.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
字号:
//
//  PCIRQ.CPP
//
//  Source code from:
//
//  Serial Communications: A C++ Developer's Guide, 2nd Edition
//  by Mark Nelson, IDG Books, 1999
//
//  Please see the book for information on usage.
//
//  This module contains the interrupt management code.
//  ConnectToIRQ() is called to establish an interrupt handler
//  function, DisconnectFromIRQ() is called to break the
//  connection.

#include <dos.h>
#include "pcirq.h"

typedef void ( __far __interrupt *HANDLER )( void );

// Prototypes for all the handlers defined here

void __far __interrupt isr2( void );
void __far __interrupt isr3( void );
void __far __interrupt isr4( void );
void __far __interrupt isr5( void );
void __far __interrupt isr7( void );
void __far __interrupt isr10( void );
void __far __interrupt isr11( void );
void __far __interrupt isr15( void );
void __far __interrupt int1b( void );
void __far __interrupt int23( void );

// When any IRQs are hooked by one of our routines, the IRQ code
// disables control-break termination by taking over the two
// control-break vectors.  The saved control-break state is
// stored in the following three variables.

static HANDLER old_int1b;
static HANDLER old_int23;
static unsigned char old_dos_break_state;

// A count of the number of handlers currently in use.

static int count = 0;

// This structure keeps track of the state of each of the eight
// possible IRQ lines our program can take over.  This includes
// the address of the new handler, the old handler, and most
// importantly, the data pointer passed to the new handler when
// it is invoked.

struct {
    enum irq_name irq;
    void *isr_data;
    void ( *isr_routine)( void *isr_data );
    HANDLER handler;
    HANDLER old_isr;
    int old_pic_enable_bit;
} irq_data[] = { { IRQ2,  0, 0, isr2,  0, 0 },
                 { IRQ3,  0, 0, isr3,  0, 0 },
                 { IRQ4,  0, 0, isr4,  0, 0 },
                 { IRQ5,  0, 0, isr5,  0, 0 },
                 { IRQ7,  0, 0, isr7,  0, 0 },
                 { IRQ10, 0, 0, isr10, 0, 0 },
                 { IRQ11, 0, 0, isr11, 0, 0 },
                 { IRQ15, 0, 0, isr15, 0, 0 }
               };

// All of the new ISR handlers are called when the interrupt
// occurs.  All they do is call the hooked routine, passing it
// a pointer to the data block it asked for in the
// ConnectToIRQ() routine.  When this is done, they take care
// of issuing the EOI instruction and then exiting.  The
// "return 1" is necessary for Zortech's interrupt handlers.
// If a "return 0" is used, the handler will then chain to the
// old interrupt, which we don't want.

void __far __interrupt isr2( void )
{
    irq_data[ 0 ].isr_routine( irq_data[ 0 ].isr_data );
    _disable();
    outp( 0x20, 0x20 );
}

void __far __interrupt isr3( void )
{
    irq_data[ 1 ].isr_routine( irq_data[ 1 ].isr_data );
    _disable();
    outp( 0x20, 0x20 );
}

void __far __interrupt isr4( void )
{
    irq_data[ 2 ].isr_routine( irq_data[ 2 ].isr_data );
    _disable();
    outp( 0x20, 0x20 );
}

void __far __interrupt isr5( void )
{
    irq_data[ 3 ].isr_routine( irq_data[ 3 ].isr_data );
    _disable();
    outp( 0x20, 0x20 );
}

void __far __interrupt isr7( void )
{
    irq_data[ 4 ].isr_routine( irq_data[ 4 ].isr_data );
    _disable();
    outp( 0x20, 0x20 );
}


// These routines have to send an EOI to the second 8250 PIC
// as well as the first.

void __far __interrupt isr10( void )
{
    irq_data[ 5 ].isr_routine( irq_data[ 5 ].isr_data );
    _disable();
    outp( 0xa0, 0x20 );
    outp( 0x20, 0x20 );
}

void __far __interrupt isr11( void )
{
    irq_data[ 6 ].isr_routine( irq_data[ 6 ].isr_data );
    _disable();
    outp( 0xa0, 0x20 );
    outp( 0x20, 0x20 );
}

void __far __interrupt isr15( void )
{
    irq_data[ 7 ].isr_routine( irq_data[ 7 ].isr_data );
    _disable();
    outp( 0xa0, 0x20 );
    outp( 0x20, 0x20 );
}

// The two control-break vectors do nothing, so that Control-C
// and Contrl-Break both have no effect on our program.

void __far __interrupt int1b( void )
{
}

void __far __interrupt int23( void )
{
}

// This utility routine is only used internally to these
// routines.  It sets control of the given interrupt number to
// the handler specifified as a parameter.  It returns the
// address of the old handler to the caller, so it can be
// stored for later restoration.  Note that Zortech stores the
// old handler internally, so we just return a 0.

HANDLER HookVector( int interrupt_number, HANDLER new_handler )
{
    union REGS r;
    struct SREGS s = { 0, 0, 0, 0 };
    HANDLER old_handler = 0;

    r.h.al = (unsigned char) interrupt_number;
    r.h.ah = 0x35;
    int86x( 0x21, &r, &r, &s );
    *( (unsigned __far *) old_handler + 1 ) = s.es;
    *( (unsigned __far *) old_handler ) = r.x.bx;
    s.ds = FP_SEG( new_handler );
    r.x.dx = FP_OFF( new_handler );
    r.h.al = (unsigned char) interrupt_number;
    r.h.ah = 0x25;
    int86x( 0x21, &r, &r, &s );
    return old_handler;
}

// When we are done with an IRQ, we restore the old handler
// here.  Note once again that Zortech does this internally, so
// we don't have to.

void UnHookVector( int interrupt_number, HANDLER old_handler )
{
    union REGS r;
    struct SREGS s = { 0, 0, 0, 0 };

    s.ds = FP_SEG( old_handler );
    r.x.dx = FP_OFF( old_handler );
    r.h.al = (unsigned char) interrupt_number;
    r.h.ah = 0x25;
    int86x( 0x21, &r, &r, &s );
}

// When we have taken over an interrupt, we don't want keyboard
// breaks to cause us to exit without properly restoring
// vectors.  This routine takes over the DOS and BIOS
// control-break routines, and sets the DOS BREAK flag to 0.
// The old state of all these variables is saved off so it can
// be restored when the last interrupt routine is restored.

void TrapKeyboardBreak( void )
{
    union REGS r;

    old_int1b = HookVector( 0x1b, int1b );
    old_int23 = HookVector( 0x23, int23 );
    r.h.ah = 0x33;
    r.h.al = 0;
    int86( 0x21, &r, &r );
    old_dos_break_state = r.h.dl;
    r.h.ah = 0x33;
    r.h.al = 1;
    r.h.dl = 0;
    int86( 0x21, &r, &r );
}

// When the last interrupt is restored, we can set the
// control-break vectors back where they belong, and restore
// the old setting of the DOS break flag.

void RestoreKeyboardBreak( void )
{
    union REGS r;

    UnHookVector( 0x1b, old_int1b );
    UnHookVector( 0x23, old_int23 );
    r.h.ah = 0x33;
    r.h.al = 1;
    r.h.dl = old_dos_break_state;
    int86( 0x21, &r, &r );
}

// When connecting to an IRQ, I pass it an irq number, plus a
// pointer to a function that will handle the interrupt.  The
// function gets passed a pointer to a data block of its choice,
// which will vary depending on what type of interrupt is being
// handled.

RS232Error
ConnectToIrq( enum irq_name irq,
              void *isr_data,
              void ( *isr_routine )( void *isr_data ) )
{
    int i;
    int pic_mask;
    int pic_address;
    int interrupt_number;
    int temp;

    for ( i = 0 ; ; i++ ) {
        if ( irq_data[ i ].irq == irq )
            break;
        if ( irq_data[ i ].irq == IRQ15 )
            return RS232_ILLEGAL_IRQ;
    }
    if ( irq_data[ i ].isr_routine != 0 )
        return RS232_IRQ_IN_USE;
    if ( count++ == 0 )
        TrapKeyboardBreak();
    irq_data[ i ].isr_data = isr_data;
    irq_data[ i ].isr_routine = isr_routine;

    pic_mask = 1 << ( irq % 8 );
    if ( irq < IRQ8 ) {
        pic_address = 0x20;
        interrupt_number = irq + 8;
    } else {
        interrupt_number = irq + 104;
        pic_address = 0xa0;
    }
    irq_data[ i ].old_isr = HookVector( interrupt_number,
                                        irq_data[ i ].handler );

    temp = inp( pic_address + 1 );
    irq_data[ i ].old_pic_enable_bit = temp & pic_mask;
    outp( pic_address + 1, temp & ~pic_mask );
    return RS232_SUCCESS;
}

// This routine restores an old interrupt vector.

int DisconnectFromIRQ( enum irq_name irq )
{
    int i;
    int pic_mask;
    int pic_address;
    int interrupt_number;
    int temp;

    for ( i = 0 ; ; i++ ) {
        if ( irq_data[ i ].irq == irq )
            break;
        if ( irq_data[ i ].irq == IRQ15 )
            return 0;
    }
    if ( irq_data[ i ].isr_routine == 0 )
        return 0;

    irq_data[ i ].isr_data = 0;
    irq_data[ i ].isr_routine = 0;

    pic_mask = 1 << ( irq % 8 );
    if ( irq < IRQ8 ) {
        pic_address = 0x20;
        interrupt_number = irq + 8;
    } else {
        interrupt_number = irq + 104;
        pic_address = 0xa0;
    }

    temp = inp( pic_address + 1 );
    temp &= ~pic_mask;
    temp |= irq_data[ i ].old_pic_enable_bit;
    outp( pic_address + 1, temp );

    UnHookVector( interrupt_number, irq_data[ i ].old_isr );

    if ( --count == 0 )
        RestoreKeyboardBreak();
    return 1;
}
// ******************** END OF PCIRQ.CPP ********************

⌨️ 快捷键说明

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