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

📄 isr.c

📁 串口Windows驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++

Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation

Module Name:

    isr.c

Abstract:

    This module contains the interrupt service routine for the
    serial driver.

Author:

    Anthony V. Ercolano 26-Sep-1991

Environment:

    Kernel mode

--*/

#include "precomp.h"


#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESER,SerialPutChar)
#pragma alloc_text(PAGESER,SerialProcessLSR)
#endif


BOOLEAN
SerialCIsrSw(IN PKINTERRUPT InterruptObject, IN PVOID Context)
/*++

Routine Description:

    All Serial interrupts get vectored through here and switched.
    This is necessary so that previously single port serial boards
    can be switched to multiport without having to disconnect
    the interrupt object etc.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We merely pass this parameter along.

    Context - Actually a PSERIAL_CISR_SW; a switch structure for
    serial ISR's that contains the real function and context to use.

Return Value:

    This function will return TRUE if a serial port using this
    interrupt was the source of this interrupt, FALSE otherwise.

--*/
{
   PSERIAL_CISR_SW csw = (PSERIAL_CISR_SW)Context;

   return (*(csw->IsrFunc))(InterruptObject, csw->Context);
}



BOOLEAN
SerialSharerIsr(
    IN PKINTERRUPT InterruptObject,
    IN PVOID Context
    )

/*++

Routine Description:

    This is the isr that the system will call if there are any
    serial devices sharing the same interrupt and they aren't
    all confined to one multiport card.  This routine traverses
    a linked list structure that contains a pointer to a more
    refined isr and context that will indicate whether one of
    the ports on this interrupt actually was interrupting.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.

    Context - Pointer to a linked list of contextes and isrs.
    device.

Return Value:

    This function will return TRUE if a serial port using this
    interrupt was the source of this interrupt, FALSE otherwise.

--*/

{

    BOOLEAN servicedAnInterrupt = FALSE;
    BOOLEAN thisPassServiced;
    PLIST_ENTRY interruptEntry = ((PLIST_ENTRY)Context)->Flink;
    PLIST_ENTRY firstInterruptEntry = Context;

    if (IsListEmpty(firstInterruptEntry)) {
       return FALSE;
    }

    do {

        thisPassServiced = FALSE;
        do {

            PSERIAL_DEVICE_EXTENSION extension = CONTAINING_RECORD(
                                                     interruptEntry,
                                                     SERIAL_DEVICE_EXTENSION,
                                                     TopLevelSharers
                                                     );

            thisPassServiced |= extension->TopLevelOurIsr(
                                    InterruptObject,
                                    extension->TopLevelOurIsrContext
                                    );

            servicedAnInterrupt |= thisPassServiced;
            interruptEntry = interruptEntry->Flink;

        } while (interruptEntry != firstInterruptEntry);

    } while (thisPassServiced);

    return servicedAnInterrupt;

}

BOOLEAN
SerialIndexedMultiportIsr(
    IN PKINTERRUPT InterruptObject,
    IN PVOID Context
    )

/*++

Routine Description:

    This routine is used to figure out if a port on a multiport
    card is the source of an interrupt.  If so, this routine
    uses a dispatch structure to actually call the normal isr
    to process the interrupt.

    NOTE: This routine is peculiar to Digiboard interrupt status registers.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.

    Context - Points to a dispatch structure that contains the
    device extension of each port on this multiport card.

Return Value:


    This function will return TRUE if a serial port using this
    interrupt was the source of this interrupt, FALSE otherwise.

--*/

{

    BOOLEAN servicedAnInterrupt = FALSE;
    BOOLEAN thisStatusReadServiced;
    PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
    ULONG whichPort;
    UCHAR statusRegister;

    do {

        thisStatusReadServiced = FALSE;
        statusRegister = READ_PORT_UCHAR(
                             dispatch->InterruptStatus
                             );

        whichPort = statusRegister & 0x07;

        //
        // We test against 0xff, which signals that no port
        // is interruping. The reason 0xff (rather than 0)
        // is that that would indicate the 0th (first) port
        // or the 0th daisy chained card.
        //

        if (statusRegister != 0xff) {

            if (dispatch->Extensions[whichPort]) {

                thisStatusReadServiced = SerialISR(
                                             InterruptObject,
                                              dispatch->Extensions[whichPort]
                                              );

                servicedAnInterrupt |= thisStatusReadServiced;

            }

        }

    } while (thisStatusReadServiced);

    return servicedAnInterrupt;

}

BOOLEAN
SerialBitMappedMultiportIsr(
    IN PKINTERRUPT InterruptObject,
    IN PVOID Context
    )

/*++

Routine Description:

    This routine is used to figure out if a port on a multiport
    card is the source of an interrupt.  If so, this routine
    uses a dispatch structure to actually call the normal isr
    to process the interrupt.

    NOTE: This routine is peculiar to status registers that use
    a bitmask to denote the interrupting port.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.

    Context - Points to a dispatch structure that contains the
    device extension of each port on this multiport card.

Return Value:


    This function will return TRUE if a serial port using this
    interrupt was the source of this interrupt, FALSE otherwise.

--*/

{

    BOOLEAN servicedAnInterrupt = FALSE;
    PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
    ULONG whichPort;
    UCHAR statusRegister;

    do {

        statusRegister = READ_PORT_UCHAR(
                             dispatch->InterruptStatus
                             );
        if (dispatch->MaskInverted) {
            statusRegister = ~statusRegister;
        }
        statusRegister &= dispatch->UsablePortMask;

        if (statusRegister) {

            if (statusRegister & 0x0f) {

                if (statusRegister & 0x03) {

                    if (statusRegister & 1) {

                        whichPort = 0;

                    } else {

                        whichPort = 1;

                    }

                } else {

                    if (statusRegister & 0x04) {

                        whichPort = 2;

                    } else {

                        whichPort = 3;

                    }

                }

            } else {

                if (statusRegister & 0x30) {

                    if (statusRegister & 0x10) {

                        whichPort = 4;

                    } else {

                        whichPort = 5;

                    }

                } else {

                    if (statusRegister & 0x40) {

                        whichPort = 6;

                    } else {

                        whichPort = 7;

                    }

                }

            }

            if (dispatch->Extensions[whichPort]) {

                if (SerialISR(
                        InterruptObject,
                        dispatch->Extensions[whichPort]
                        )) {

                    servicedAnInterrupt = TRUE;

                }

            }

        }

    } while (statusRegister);

    return servicedAnInterrupt;

}

BOOLEAN
SerialISR(
    IN PKINTERRUPT InterruptObject,
    IN PVOID Context
    )

/*++

Routine Description:

    This is the interrupt service routine for the serial port driver.
    It will determine whether the serial port is the source of this
    interrupt.  If it is, then this routine will do the minimum of
    processing to quiet the interrupt.  It will store any information
    necessary for later processing.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.

    Context - This is really a pointer to the device extension for this
    device.

Return Value:

    This function will return TRUE if the serial port is the source
    of this interrupt, FALSE otherwise.

--*/

{

    //
    // Holds the information specific to handling this device.
    //
    PSERIAL_DEVICE_EXTENSION Extension = Context;

    //
    // Holds the contents of the interrupt identification record.
    // A low bit of zero in this register indicates that there is
    // an interrupt pending on this device.
    //
    UCHAR InterruptIdReg;

    //
    // Will hold whether we've serviced any interrupt causes in this
    // routine.
    //
    BOOLEAN ServicedAnInterrupt;

    UCHAR tempLSR;

    UNREFERENCED_PARAMETER(InterruptObject);

    //
    // Make sure we have an interrupt pending.  If we do then
    // we need to make sure that the device is open.  If the
    // device isn't open or powered down then quiet the device.  Note that
    // if the device isn't opened when we enter this routine
    // it can't open while we're in it.
    //

    InterruptIdReg = READ_INTERRUPT_ID_REG(Extension->Controller);

    //
    // Apply lock so if close happens concurrently we don't miss the DPC
    // queueing
    //

    InterlockedIncrement(&Extension->DpcCount);
    LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0);

    if ((InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING)) {

        ServicedAnInterrupt = FALSE;

    } else if (!Extension->DeviceIsOpened
               || (Extension->PowerState != PowerDeviceD0)) {


        //
        // We got an interrupt with the device being closed or when the
        // device is supposed to be powered down.  This
        // is not unlikely with a serial device.  We just quietly
        // keep servicing the causes until it calms down.
        //

        ServicedAnInterrupt = TRUE;
        do {

            InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
            switch (InterruptIdReg) {

                case SERIAL_IIR_RLS: {

                    READ_LINE_STATUS(Extension->Controller);
                    break;

                }

                case SERIAL_IIR_RDA:
                case SERIAL_IIR_CTI: {


                    READ_RECEIVE_BUFFER(Extension->Controller);
                    break;

                }

                case SERIAL_IIR_THR: {

                    //
                    // Alread clear from reading the iir.
                    //
                    // We want to keep close track of whether
                    // the holding register is empty.
                    //

                    Extension->HoldingEmpty = TRUE;
                    break;

⌨️ 快捷键说明

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