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

📄 modmflow.c

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

Copyright (c) 1991, 1992, 1993 Microsoft Corporation

Module Name:

    modmflow.c

Abstract:

    This module contains *MOST* of the code used to manipulate
    the modem control and status registers.  The vast majority
    of the remainder of flow control is concentrated in the
    Interrupt service routine.  A very small amount resides
    in the read code that pull characters out of the interrupt
    buffer.

Author:

    Anthony V. Ercolano 26-Sep-1991

Environment:

    Kernel mode

Revision History :

--*/

#include "precomp.h"

BOOLEAN
SerialDecrementRTSCounter(
    IN PVOID Context
    );

#ifdef ALLOC_PRAGMA
#if 0
#pragma alloc_text(PAGESER,SerialHandleReducedIntBuffer)
#pragma alloc_text(PAGESER,SerialProdXonXoff)
#pragma alloc_text(PAGESER,SerialHandleModemUpdate)
#pragma alloc_text(PAGESER,SerialPerhapsLowerRTS)
#pragma alloc_text(PAGESER,SerialStartTimerLowerRTS)
#pragma alloc_text(PAGESER,SerialInvokePerhapsLowerRTS)
#pragma alloc_text(PAGESER,SerialSetDTR)
//#pragma alloc_text(PAGESER,SerialClrDTR)
#pragma alloc_text(PAGESER,SerialSetRTS)
//#pragma alloc_text(PAGESER,SerialClrRTS)
//#pragma alloc_text(PAGESER,SerialSetupNewHandFlow)
#pragma alloc_text(PAGESER,SerialSetHandFlow)
#pragma alloc_text(PAGESER,SerialTurnOnBreak)
#pragma alloc_text(PAGESER,SerialTurnOffBreak)
#pragma alloc_text(PAGESER,SerialPretendXoff)
#pragma alloc_text(PAGESER,SerialPretendXon)
#pragma alloc_text(PAGESER,SerialDecrementRTSCounter)
#endif
#endif

BOOLEAN
SerialSetDTR(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to set the DTR in the modem control register.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;
    UCHAR ModemControl;

    ModemControl = READ_MODEM_CONTROL(Extension->Controller);

    ModemControl |= SERIAL_MCR_DTR;

    SerialDbgPrintEx(SERFLOW, "Setting DTR for %x\n", Extension->Controller);

    WRITE_MODEM_CONTROL(Extension->Controller, ModemControl);

    return FALSE;

}

BOOLEAN
SerialClrDTR(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to clear the DTR in the modem control register.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;
    UCHAR ModemControl;

    ModemControl = READ_MODEM_CONTROL(Extension->Controller);

    ModemControl &= ~SERIAL_MCR_DTR;

    SerialDbgPrintEx(SERFLOW, "Clearing DTR for %x\n", Extension->Controller);

    WRITE_MODEM_CONTROL(Extension->Controller, ModemControl);

    return FALSE;

}

BOOLEAN
SerialSetRTS(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to set the RTS in the modem control register.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;
    UCHAR ModemControl;

    ModemControl = READ_MODEM_CONTROL(Extension->Controller);

    ModemControl |= SERIAL_MCR_RTS;

    SerialDbgPrintEx(SERFLOW, "Setting Rts for %x\n", Extension->Controller);

    WRITE_MODEM_CONTROL(Extension->Controller, ModemControl);

    return FALSE;

}

BOOLEAN
SerialClrRTS(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to clear the RTS in the modem control register.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;
    UCHAR ModemControl;

    ModemControl = READ_MODEM_CONTROL(Extension->Controller);

    ModemControl &= ~SERIAL_MCR_RTS;

    SerialDbgPrintEx(SERFLOW, "Clearing Rts for %x\n", Extension->Controller);

    WRITE_MODEM_CONTROL(Extension->Controller, ModemControl);

    return FALSE;

}

BOOLEAN
SerialSetupNewHandFlow(
    IN PSERIAL_DEVICE_EXTENSION Extension,
    IN PSERIAL_HANDFLOW NewHandFlow
    )

/*++

Routine Description:

    This routine adjusts the flow control based on new
    control flow.

Arguments:

    Extension - A pointer to the serial device extension.

    NewHandFlow - A pointer to a serial handflow structure
                  that is to become the new setup for flow
                  control.

Return Value:

    This routine always returns FALSE.

--*/

{

    SERIAL_HANDFLOW New = *NewHandFlow;

    //
    // If the Extension->DeviceIsOpened is FALSE that means
    // we are entering this routine in response to an open request.
    // If that is so, then we always proceed with the work regardless
    // of whether things have changed.
    //

    //
    // First we take care of the DTR flow control.  We only
    // do work if something has changed.
    //

    if ((!Extension->DeviceIsOpened) ||
        ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=
         (New.ControlHandShake & SERIAL_DTR_MASK))) {

        SerialDbgPrintEx(SERFLOW, "Processing DTR flow for %x\n",
                         Extension->Controller);

        if (New.ControlHandShake & SERIAL_DTR_MASK) {

            //
            // Well we might want to set DTR.
            //
            // Before we do, we need to check whether we are doing
            // dtr flow control.  If we are then we need to check
            // if then number of characters in the interrupt buffer
            // exceeds the XoffLimit.  If it does then we don't
            // enable DTR AND we set the RXHolding to record that
            // we are holding because of the dtr.
            //

            if ((New.ControlHandShake & SERIAL_DTR_MASK)
                == SERIAL_DTR_HANDSHAKE) {

                if ((Extension->BufferSize - New.XoffLimit) >
                    Extension->CharsInInterruptBuffer) {

                    //
                    // However if we are already holding we don't want
                    // to turn it back on unless we exceed the Xon
                    // limit.
                    //

                    if (Extension->RXHolding & SERIAL_RX_DTR) {

                        //
                        // We can assume that its DTR line is already low.
                        //

                        if (Extension->CharsInInterruptBuffer >
                            (ULONG)New.XonLimit) {

                            SerialDbgPrintEx(SERFLOW, "Removing DTR block on "
                                             "reception for %x\n",
                                             Extension->Controller);

                            Extension->RXHolding &= ~SERIAL_RX_DTR;
                            SerialSetDTR(Extension);

                        }

                    } else {

                        SerialSetDTR(Extension);

                    }

                } else {

                    SerialDbgPrintEx(SERFLOW, "Setting DTR block on reception "
                                     "for %x\n", Extension->Controller);
                    Extension->RXHolding |= SERIAL_RX_DTR;
                    SerialClrDTR(Extension);

                }

            } else {

                //
                // Note that if we aren't currently doing dtr flow control then
                // we MIGHT have been.  So even if we aren't currently doing
                // DTR flow control, we should still check if RX is holding
                // because of DTR.  If it is, then we should clear the holding
                // of this bit.
                //

                if (Extension->RXHolding & SERIAL_RX_DTR) {
                    SerialDbgPrintEx(SERFLOW, "Removing dtr block of reception "
                                     "for %x\n", Extension->Controller);
                    Extension->RXHolding &= ~SERIAL_RX_DTR;
                }

                SerialSetDTR(Extension);

            }

        } else {

            //
            // The end result here will be that DTR is cleared.
            //
            // We first need to check whether reception is being held
            // up because of previous DTR flow control.  If it is then
            // we should clear that reason in the RXHolding mask.
            //

            if (Extension->RXHolding & SERIAL_RX_DTR) {

                SerialDbgPrintEx(SERFLOW, "removing dtr block of reception for"
                                 " %x\n", Extension->Controller);
                Extension->RXHolding &= ~SERIAL_RX_DTR;

            }

            SerialClrDTR(Extension);

        }

    }

    //
    // Time to take care of the RTS Flow control.
    //
    // First we only do work if something has changed.
    //

    if ((!Extension->DeviceIsOpened) ||
        ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) !=
         (New.FlowReplace & SERIAL_RTS_MASK))) {

        SerialDbgPrintEx(SERFLOW, "Processing RTS flow\n",
                         Extension->Controller);

        if ((New.FlowReplace & SERIAL_RTS_MASK) ==
            SERIAL_RTS_HANDSHAKE) {

            //
            // Well we might want to set RTS.
            //
            // Before we do, we need to check whether we are doing
            // rts flow control.  If we are then we need to check
            // if then number of characters in the interrupt buffer
            // exceeds the XoffLimit.  If it does then we don't
            // enable RTS AND we set the RXHolding to record that
            // we are holding because of the rts.
            //

            if ((Extension->BufferSize - New.XoffLimit) >
                Extension->CharsInInterruptBuffer) {

                //
                // However if we are already holding we don't want
                // to turn it back on unless we exceed the Xon
                // limit.
                //

                if (Extension->RXHolding & SERIAL_RX_RTS) {

                    //
                    // We can assume that its RTS line is already low.
                    //

                    if (Extension->CharsInInterruptBuffer >
                        (ULONG)New.XonLimit) {

                       SerialDbgPrintEx(SERFLOW, "Removing rts block of "
                                        "reception for %x\n",
                                        Extension->Controller);
                        Extension->RXHolding &= ~SERIAL_RX_RTS;
                        SerialSetRTS(Extension);

                    }

                } else {

                    SerialSetRTS(Extension);

                }

            } else {

                SerialDbgPrintEx(SERFLOW, "Setting rts block of reception for "
                                 "%x\n", Extension->Controller);
                Extension->RXHolding |= SERIAL_RX_RTS;
                SerialClrRTS(Extension);

            }

        } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==
                   SERIAL_RTS_CONTROL) {

            //
            // Note that if we aren't currently doing rts flow control then
            // we MIGHT have been.  So even if we aren't currently doing
            // RTS flow control, we should still check if RX is holding
            // because of RTS.  If it is, then we should clear the holding
            // of this bit.
            //

            if (Extension->RXHolding & SERIAL_RX_RTS) {

                SerialDbgPrintEx(SERFLOW, "Clearing rts block of reception for "
                                 "%x\n", Extension->Controller);
                Extension->RXHolding &= ~SERIAL_RX_RTS;

            }

            SerialSetRTS(Extension);

        } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==
                   SERIAL_TRANSMIT_TOGGLE) {

            //
            // We first need to check whether reception is being held
            // up because of previous RTS flow control.  If it is then
            // we should clear that reason in the RXHolding mask.
            //

            if (Extension->RXHolding & SERIAL_RX_RTS) {

                SerialDbgPrintEx(SERFLOW, "TOGGLE Clearing rts block of "
                                 "reception for %x\n", Extension->Controller);
                Extension->RXHolding &= ~SERIAL_RX_RTS;

            }

            //
            // We have to place the rts value into the Extension
            // now so that the code that tests whether the
            // rts line should be lowered will find that we
            // are "still" doing transmit toggling.  The code
            // for lowering can be invoked later by a timer so
            // it has to test whether it still needs to do its
            // work.
            //

            Extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
            Extension->HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;

            //
            // The order of the tests is very important below.
            //
            // If there is a break then we should turn on the RTS.
            //
            // If there isn't a break but there are characters in
            // the hardware, then turn on the RTS.
            //
            // If there are writes pending that aren't being held
            // up, then turn on the RTS.
            //

            if ((Extension->TXHolding & SERIAL_TX_BREAK) ||
                ((SerialProcessLSR(Extension) & (SERIAL_LSR_THRE |
                                                 SERIAL_LSR_TEMT)) !=
                                                (SERIAL_LSR_THRE |
                                                 SERIAL_LSR_TEMT)) ||
                (Extension->CurrentWriteIrp || Extension->TransmitImmediate ||
                 (!IsListEmpty(&Extension->WriteQueue)) &&
                 (!Extension->TXHolding))) {

                SerialSetRTS(Extension);

            } else {

                //
                // This routine will check to see if it is time
                // to lower the RTS because of transmit toggle
                // being on.  If it is ok to lower it, it will,
                // if it isn't ok, it will schedule things so
                // that it will get lowered later.
                //

                Extension->CountOfTryingToLowerRTS++;
                SerialPerhapsLowerRTS(Extension);

            }

        } else {

            //
            // The end result here will be that RTS is cleared.
            //
            // We first need to check whether reception is being held
            // up because of previous RTS flow control.  If it is then
            // we should clear that reason in the RXHolding mask.
            //

            if (Extension->RXHolding & SERIAL_RX_RTS) {

                SerialDbgPrintEx(SERFLOW, "Clearing rts block of reception for"
                                 " %x\n", Extension->Controller);
                Extension->RXHolding &= ~SERIAL_RX_RTS;

            }

            SerialClrRTS(Extension);

        }

    }

    //
    // We now take care of automatic receive flow control.
    // We only do work if things have changed.
    //

    if ((!Extension->DeviceIsOpened) ||
        ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=
         (New.FlowReplace & SERIAL_AUTO_RECEIVE))) {

        if (New.FlowReplace & SERIAL_AUTO_RECEIVE) {

            //
            // We wouldn't be here if it had been on before.
            //
            // We should check to see whether we exceed the turn
            // off limits.
            //
            // Note that since we are following the OS/2 flow
            // control rules we will never send an xon if
            // when enabling xon/xoff flow control we discover that
            // we could receive characters but we are held up do
            // to a previous Xoff.
            //

            if ((Extension->BufferSize - New.XoffLimit) <=
                Extension->CharsInInterruptBuffer) {

                //
                // Cause the Xoff to be sent.
                //

                Extension->RXHolding |= SERIAL_RX_XOFF;

                SerialProdXonXoff(
                    Extension,
                    FALSE
                    );

⌨️ 快捷键说明

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