📄 openclos.c
字号:
/*++
Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
Module Name:
openclos.c
Abstract:
This module contains the code that is very specific to
opening, closing, and cleaning up in the serial driver.
Author:
Anthony V. Ercolano 26-Sep-1991
Environment:
Kernel mode
--*/
#include "precomp.h"
BOOLEAN
SerialMarkOpen(
IN PVOID Context
);
BOOLEAN
SerialCheckOpen(
IN PVOID Context
);
BOOLEAN
SerialNullSynch(
IN PVOID Context
);
NTSTATUS
SerialCreateOpen(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
#ifdef ALLOC_PRAGMA
//
// Paged for open and PnP transactions
//
#pragma alloc_text(PAGESER,SerialGetCharTime)
#pragma alloc_text(PAGESER,SerialCleanup)
#pragma alloc_text(PAGESER,SerialClose)
#pragma alloc_text(PAGESER, SerialCheckOpen)
#pragma alloc_text(PAGESER, SerialMarkOpen)
//
// Always paged
//
#pragma alloc_text(PAGESRP0,SerialCreateOpen)
#pragma alloc_text(PAGESRP0, SerialDrainUART)
#endif // ALLOC_PRAGMA
typedef struct _SERIAL_CHECK_OPEN {
PSERIAL_DEVICE_EXTENSION Extension;
NTSTATUS *StatusOfOpen;
} SERIAL_CHECK_OPEN,*PSERIAL_CHECK_OPEN;
//
// Just a bogus little routine to make sure that we
// can synch with the ISR.
//
BOOLEAN
SerialNullSynch(
IN PVOID Context
) {
UNREFERENCED_PARAMETER(Context);
return FALSE;
}
NTSTATUS
SerialCreateOpen(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP 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:
DeviceObject - Pointer to the device object for this device
Irp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
SERIAL_CHECK_OPEN checkOpen;
NTSTATUS localStatus;
KIRQL oldIrql;
PAGED_CODE();
if (extension->PNPState != SERIAL_PNP_STARTED) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Lock out changes to PnP state until we have our open state decided
//
ExAcquireFastMutex(&extension->OpenMutex);
if ((localStatus = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
ExReleaseFastMutex(&extension->OpenMutex);
if(localStatus != STATUS_PENDING) {
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
}
return localStatus;
}
if (InterlockedIncrement(&extension->OpenCount) != 1) {
ExReleaseFastMutex(&extension->OpenMutex);
InterlockedDecrement(&extension->OpenCount);
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_ACCESS_DENIED;
}
SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", Irp);
SerialDbgPrintEx(SERDIAG3, "In SerialCreateOpen\n");
//
// Before we do anything, let's make sure they aren't trying
// to create a directory. what's a driver to do!?
//
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
FILE_DIRECTORY_FILE) {
ExReleaseFastMutex(&extension->OpenMutex);
Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
Irp->IoStatus.Information = 0;
InterlockedDecrement(&extension->OpenCount);
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_NOT_A_DIRECTORY;
}
//
// Create a buffer for the RX data when no reads are outstanding.
//
extension->InterruptReadBuffer = NULL;
extension->BufferSize = 0;
switch (MmQuerySystemSize()) {
case MmLargeSystem: {
extension->BufferSize = 4096;
extension->InterruptReadBuffer = ExAllocatePool(
NonPagedPool,
extension->BufferSize
);
if (extension->InterruptReadBuffer) {
break;
}
}
case MmMediumSystem: {
extension->BufferSize = 1024;
extension->InterruptReadBuffer = ExAllocatePool(
NonPagedPool,
extension->BufferSize
);
if (extension->InterruptReadBuffer) {
break;
}
}
case MmSmallSystem: {
extension->BufferSize = 128;
extension->InterruptReadBuffer = ExAllocatePool(
NonPagedPool,
extension->BufferSize
);
}
}
if (!extension->InterruptReadBuffer) {
ExReleaseFastMutex(&extension->OpenMutex);
extension->BufferSize = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
InterlockedDecrement(&extension->OpenCount);
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Ok, it looks like we really are going to open. Lock down the
// driver.
//
SerialLockPagableSectionByHandle(SerialGlobals.PAGESER_Handle);
//
// Power up the stack
//
(void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD0);
//
// Not currently waiting for wake up
//
extension->SendWaitWake = FALSE;
//
// On a new open we "flush" the read queue by initializing the
// count of characters.
//
extension->CharsInInterruptBuffer = 0;
extension->LastCharSlot = extension->InterruptReadBuffer +
(extension->BufferSize - 1);
extension->ReadBufferBase = extension->InterruptReadBuffer;
extension->CurrentCharSlot = extension->InterruptReadBuffer;
extension->FirstReadableChar = extension->InterruptReadBuffer;
extension->TotalCharsQueued = 0;
//
// We set up the default xon/xoff limits.
//
extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
extension->HandFlow.XonLimit = extension->BufferSize >> 1;
extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;
extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
(extension->BufferSize>>4));
//
// Mark the device as busy for WMI
//
extension->WmiCommData.IsBusy = TRUE;
extension->IrpMaskLocation = NULL;
extension->HistoryMask = 0;
extension->IsrWaitMask = 0;
extension->SendXonChar = FALSE;
extension->SendXoffChar = FALSE;
#if !DBG
//
// Clear out the statistics.
//
KeSynchronizeExecution(
extension->Interrupt,
SerialClearStats,
extension
);
#endif
//
// The escape char replacement must be reset upon every open.
//
extension->EscapeChar = 0;
if (!extension->PermitShare) {
if (!extension->InterruptShareable) {
checkOpen.Extension = extension;
checkOpen.StatusOfOpen = &Irp->IoStatus.Status;
KeSynchronizeExecution(
extension->Interrupt,
SerialCheckOpen,
&checkOpen
);
} else {
KeSynchronizeExecution(
extension->Interrupt,
SerialMarkOpen,
extension
);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
} else {
//
// Synchronize with the ISR and let it know that the device
// has been successfully opened.
//
KeSynchronizeExecution(
extension->Interrupt,
SerialMarkOpen,
extension
);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
//
// We have been marked open, so now the PnP state can change
//
ExReleaseFastMutex(&extension->OpenMutex);
localStatus = Irp->IoStatus.Status;
Irp->IoStatus.Information=0L;
if (!NT_SUCCESS(localStatus)) {
if (extension->InterruptReadBuffer != NULL) {
ExFreePool(extension->InterruptReadBuffer);
extension->InterruptReadBuffer = NULL;
}
InterlockedDecrement(&extension->OpenCount);
}
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return localStatus;
}
VOID
SerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt,
IN PLARGE_INTEGER PDrainTime)
{
PAGED_CODE();
//
// Wait until all characters have been emptied out of the hardware.
//
while ((READ_LINE_STATUS(PDevExt->Controller) &
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
!= (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
KeDelayExecutionThread(KernelMode, FALSE, PDrainTime);
}
}
NTSTATUS
SerialClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
We simply disconnect the interrupt for now.
Arguments:
DeviceObject - Pointer to the device object for this device
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;
//
// Just what it says. This is the serial specific device
// extension of the device object create for the serial driver.
//
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
NTSTATUS status;
//
// Number of opens still active
//
LONG openCount;
//
// Number of DPC's still pending
//
ULONG pendingDPCs;
ULONG flushCount;
KIRQL oldIrql;
//
// Grab a mutex
//
ExAcquireFastMutex(&extension->CloseMutex);
//
// We succeed a close on a removing device
//
if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
SerialDbgPrintEx(DPFLTR_INFO_LEVEL, "Close prologue failed for: %x\n",
Irp);
if (status == STATUS_DELETE_PENDING) {
extension->BufferSize = 0;
ExFreePool(extension->InterruptReadBuffer);
extension->InterruptReadBuffer = NULL;
status = Irp->IoStatus.Status = STATUS_SUCCESS;
}
if (status != STATUS_PENDING) {
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
openCount = InterlockedDecrement(&extension->OpenCount);
ASSERT(openCount == 0);
}
ExReleaseFastMutex(&extension->CloseMutex);
return status;
}
ASSERT(extension->OpenCount >= 1);
if (extension->OpenCount < 1) {
SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Close open count bad for: 0x%x\n",
Irp);
SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Count: %x Addr: 0x%x\n",
extension->OpenCount, &extension->OpenCount);
ExReleaseFastMutex(&extension->CloseMutex);
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", Irp);
SerialDbgPrintEx(SERDIAG3, "In SerialClose\n");
charTime.QuadPart = -SerialGetCharTime(extension).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.
//
SetDeviceIsOpened(extension, FALSE, FALSE);
//
// Synchronize with the isr to turn off break if it
// is already on.
//
KeSynchronizeExecution(
extension->Interrupt,
SerialTurnOffBreak,
extension
);
//
// Wait a reasonable amount of time (20 * fifodepth) until all characters
// have been emptied out of the hardware.
//
for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
if ((READ_LINE_STATUS(extension->Controller) &
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
KeDelayExecutionThread(KernelMode, FALSE, &charTime);
} else {
break;
}
}
if (flushCount == 0) {
SerialMarkHardwareBroken(extension);
}
//
// Synchronize with the ISR to let it know that interrupts are
// no longer important.
//
KeSynchronizeExecution(
extension->Interrupt,
SerialMarkClose,
extension
);
//
// If the driver has automatically transmitted an Xoff in
// the context of automatic receive flow control then we
// should transmit an Xon.
//
if (extension->RXHolding & SERIAL_RX_XOFF) {
//
// Loop until the holding register is empty.
//
while (!(READ_LINE_STATUS(extension->Controller) &
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -