📄 openclos.cpp
字号:
/*++
Abstract:
This module contains the code that is very specific to
opening, closing, and cleaning up in the serial driver.
--*/
#include "precomp.h"
// Just a bogus little routine to make sure that we
// can synch with the ISR.
BOOLEAN KdSerialDevice::NullSynch()
{
return FALSE;
}
NTSTATUS KdSerialDevice::DispatchCreate(IN KdIrp &Irp)
/*++
Routine Description:
We connect up to the interrupt for the create/open and initialize
the structures needed to maintain an open for a device.
Arguments:
Irp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
NTSTATUS localStatus;
DebugDump(DBG_DIAG6, ("Dispatch entry for: %x\n",Irp) );
DebugDump(DBG_DIAG3, ("In DispatchOpen\n") );
// Before we do anything, let's make sure they aren't trying
// to create a directory. This is a silly, but what's a driver to do!?
if (Irp.GetStackLocation(STACK_NEXT)->Parameters.Create.Options & FILE_DIRECTORY_FILE)
{
Irp.Status() = STATUS_NOT_A_DIRECTORY;
Irp.Information() = 0;
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete();
return STATUS_NOT_A_DIRECTORY;
}
// Create a buffer for the RX data when no reads are outstanding.
m_InterruptReadBuffer = NULL;
m_BufferSize = 0;
switch (MmQuerySystemSize())
{
case MmLargeSystem:
m_BufferSize = 4096;
m_InterruptReadBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, m_BufferSize);
if (m_InterruptReadBuffer)
break;
case MmMediumSystem:
m_BufferSize = 1024;
m_InterruptReadBuffer = (PUCHAR)ExAllocatePool(NonPagedPool, m_BufferSize);
if (m_InterruptReadBuffer)
break;
case MmSmallSystem:
m_BufferSize = 128;
m_InterruptReadBuffer = (PUCHAR)ExAllocatePool(NonPagedPool, m_BufferSize);
}
if (!m_InterruptReadBuffer)
{
m_BufferSize = 0;
Irp.Status() = STATUS_INSUFFICIENT_RESOURCES;
Irp.Information() = 0;
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete();
return STATUS_INSUFFICIENT_RESOURCES;
}
// Ok, it looks like we really are going to open. Lock down the driver.
// On a new open we "flush" the read queue by initializing the
// count of characters.
m_CharsInInterruptBuffer = 0;
m_LastCharSlot = m_InterruptReadBuffer +
(m_BufferSize - 1);
m_ReadBufferBase = m_InterruptReadBuffer;
m_CurrentCharSlot = m_InterruptReadBuffer;
m_FirstReadableChar = m_InterruptReadBuffer;
m_TotalCharsQueued = 0;
// We set up the default xon/xoff limits.
m_HandFlow.XoffLimit = m_BufferSize >> 3;
m_HandFlow.XonLimit = m_BufferSize >> 1;
m_BufferSizePt8 = ((3*(m_BufferSize>>2))+
(m_BufferSize>>4));
m_IrpMaskLocation = NULL;
m_HistoryMask = 0;
m_IsrWaitMask = 0;
m_SendXonChar = FALSE;
m_SendXoffChar = FALSE;
// Clear out the statistics.
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) ClearStats);
// The escape char replacement must be reset upon every open.
m_EscapeChar = 0;
if (!m_PermitShare)
{
if (!m_InterruptShareable)
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) CheckOpen, &Irp.Status());
else
{
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) MarkOpen);
Irp.Status() = STATUS_SUCCESS;
}
}
else
{
// Synchronize with the ISR and let it know that the device
// has been successfully opened.
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) MarkOpen);
Irp.Status() = STATUS_SUCCESS;
}
localStatus = Irp.Status();
Irp.Information() =0L;
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete();
return localStatus;
}
NTSTATUS KdSerialDevice::DispatchClose(KdIrp &Irp)
/*++
Routine Description:
We simply disconnect the interrupt for now.
Arguments:
Irp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
// This "timer value" is used to wait 10 character times
// after the hardware is empty before we actually "run down"
// all of the flow control/break junk.
LARGE_INTEGER tenCharDelay;
// Holds a character time.
LARGE_INTEGER charTime;
DebugDump(DBG_DIAG6, ("Dispatch entry for: %x\n",Irp) );
DebugDump(DBG_DIAG3, ("In DispatchClose\n") );
charTime.QuadPart = -GetCharTime().QuadPart;
// Do this now so that if the isr gets called it won't do anything
// to cause more chars to get sent. We want to run down the hardware.
m_DeviceIsOpened = FALSE;
// Synchronize with the isr to turn off break if it
// is already on.
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) TurnOffBreak);
// Wait until all characters have been emptied out of the hardware.
while ((m_pController->ReadByte(LINE_STATUS_REGISTER) &
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
{
KeDelayExecutionThread(KernelMode, FALSE, &charTime);
}
// Synchronize with the ISR to let it know that interrupts are
// no longer important.
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) MarkClose);
// If the driver has automatically transmitted an Xoff in
// the context of automatic receive flow control then we
// should transmit an Xon.
if (m_RXHolding & SERIAL_RX_XOFF)
{
// Loop until the holding register is empty.
while (!(m_pController->ReadByte(LINE_STATUS_REGISTER) & SERIAL_LSR_THRE))
KeDelayExecutionThread(KernelMode, FALSE, &charTime);
m_pController->WriteByte(TRANSMIT_HOLDING_REGISTER, m_SpecialChars.XonChar);
// Wait until the character have been emptied out of the hardware.
while ((m_pController->ReadByte(LINE_STATUS_REGISTER) &
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
{
KeDelayExecutionThread(KernelMode, FALSE, &charTime);
}
}
// The hardware is empty. Delay 10 character times before
// shut down all the flow control.
tenCharDelay.QuadPart = charTime.QuadPart * 10;
KeDelayExecutionThread(KernelMode, TRUE, &tenCharDelay);
ClrDTR();
// We have to be very careful how we clear the RTS line.
// Transmit toggling might have been on at some point.
//
// We know that there is nothing left that could start
// out the "polling" execution path. We need to
// check the counter that indicates that the execution
// path is active. If it is then we loop delaying one
// character time. After each delay we check to see if
// the counter has gone to zero. When it has we know that
// the execution path should be just about finished. We
// make sure that we still aren't in the routine that
// synchronized execution with the ISR by synchronizing
// ourselves with the ISR.
if (m_CountOfTryingToLowerRTS)
{
do {
KeDelayExecutionThread(KernelMode, FALSE, &charTime);
} while (m_CountOfTryingToLowerRTS);
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) NullSynch);
// The execution path should no longer exist that
// is trying to push down the RTS. Well just
// make sure it's down by falling through to
// code that forces it down.
}
ClrRTS();
// Clean out the holding reasons (since we are closed).
m_RXHolding = 0;
m_TXHolding = 0;
// All is done. The port has been disabled from interrupting
// so there is no point in keeping the memory around.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -