📄 initunlo.c
字号:
/*++
Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
Module Name:
initunlo.c
Abstract:
This module contains the code that is very specific to initialization
and unload operations in the serial driver
Author:
Anthony V. Ercolano 26-Sep-1991
Environment:
Kernel mode
--*/
#include "precomp.h"
//
// All our global variables except DebugLevel stashed in one
// little package
//
SERIAL_GLOBALS SerialGlobals;
static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
//
// We use this to query into the registry as to whether we
// should break at driver entry.
//
SERIAL_FIRMWARE_DATA driverDefaults;
//
// This is exported from the kernel. It is used to point
// to the address that the kernel debugger is using.
//
extern PUCHAR *KdComPortInUse;
//
// INIT - only needed during init and then can be disposed
// PAGESRP0 - always paged / never locked
// PAGESER - must be locked when a device is open, else paged
//
//
// INIT is used for DriverEntry() specific code
//
// PAGESRP0 is used for code that is not often called and has nothing
// to do with I/O performance. An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
// support functions
//
// PAGESER is used for code that needs to be locked after an open for both
// performance and IRQL reasons.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGESRP0, SerialInitMultiPort)
#pragma alloc_text(PAGESRP0, SerialInitOneController)
#pragma alloc_text(PAGESRP0, SerialInitController)
#pragma alloc_text(PAGESRP0, SerialGetMappedAddress)
#pragma alloc_text(PAGESRP0, SerialRemoveDevObj)
#pragma alloc_text(PAGESRP0, SerialUnload)
#pragma alloc_text(PAGESRP0, SerialMemCompare)
//
// PAGESER handled is keyed off of SerialReset, so SerialReset
// must remain in PAGESER for things to work properly
//
#pragma alloc_text(PAGESER, SerialGetDivisorFromBaud)
#pragma alloc_text(PAGESER, SerialReset)
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
The entry point that the system point calls to initialize
any driver.
This routine will gather the configuration information,
report resource usage, attempt to initialize all serial
devices, connect to interrupts for ports. If the above
goes reasonably well it will fill in the dispatch points,
reset the serial devices and then return to the system.
Arguments:
DriverObject - Just what it says, really of little use
to the driver itself, it is something that the IO system
cares more about.
PathToRegistry - points to the entry for this driver
in the current control set of the registry.
Return Value:
Always STATUS_SUCCESS
--*/
{
//
// Lock the paged code in their frames
//
PVOID lockPtr = MmLockPagableCodeSection(SerialReset);
PAGED_CODE();
ASSERT(SerialGlobals.PAGESER_Handle == NULL);
#if DBG
SerialGlobals.PAGESER_Count = 0;
SerialLogInit();
#endif
SerialGlobals.PAGESER_Handle = lockPtr;
SerialGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
SerialGlobals.RegistryPath.Length = RegistryPath->Length;
SerialGlobals.RegistryPath.Buffer
= ExAllocatePool(PagedPool, SerialGlobals.RegistryPath.MaximumLength);
if (SerialGlobals.RegistryPath.Buffer == NULL) {
MmUnlockPagableImageSection(lockPtr);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(SerialGlobals.RegistryPath.Buffer,
SerialGlobals.RegistryPath.MaximumLength);
RtlMoveMemory(SerialGlobals.RegistryPath.Buffer,
RegistryPath->Buffer, RegistryPath->Length);
KeInitializeSpinLock(&SerialGlobals.GlobalsSpinLock);
//
// Initialize all our globals
//
InitializeListHead(&SerialGlobals.AllDevObjs);
//
// Call to find out default values to use for all the devices that the
// driver controls, including whether or not to break on entry.
//
SerialGetConfigDefaults(&driverDefaults, RegistryPath);
//
// Break on entry if requested via registry
//
if (driverDefaults.ShouldBreakOnEntry) {
DbgBreakPoint();
}
//
// Just dump out how big the extension is.
//
SerialDbgPrintEx(DPFLTR_INFO_LEVEL, "The number of bytes in the extension "
"is: %d\n", sizeof(SERIAL_DEVICE_EXTENSION));
//
// Initialize the Driver Object with driver's entry points
//
DriverObject->DriverUnload = SerialUnload;
DriverObject->DriverExtension->AddDevice = SerialAddDevice;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = SerialFlush;
DriverObject->MajorFunction[IRP_MJ_WRITE] = SerialWrite;
DriverObject->MajorFunction[IRP_MJ_READ] = SerialRead;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SerialIoControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
= SerialInternalIoControl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreateOpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
DriverObject->MajorFunction[IRP_MJ_PNP] = SerialPnpDispatch;
DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPowerDispatch;
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
= SerialQueryInformationFile;
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
= SerialSetInformationFile;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
= SerialSystemControlDispatch;
#if !defined(NO_LEGACY_DRIVERS)
#define SerialDoLegacyConversion() (~0)
//
// Enumerate and Initialize legacy devices if necessary. This should go away
// and be done by setup.
//
if (SerialDoLegacyConversion()) {
#if DBG
InterlockedIncrement(&SerialGlobals.PAGESER_Count);
#endif
(void)SerialEnumerateLegacy(DriverObject, RegistryPath, &driverDefaults);
#if DBG
InterlockedDecrement(&SerialGlobals.PAGESER_Count);
#endif
}
#endif // NO_LEGACY_DRIVERS
//
// Unlock pageable text
//
MmUnlockPagableImageSection(lockPtr);
return STATUS_SUCCESS;
}
BOOLEAN
SerialCleanLists(IN PVOID Context)
/*++
Routine Description:
Removes a device object from any of the serial linked lists it may
appear on.
Arguments:
Context - Actually a PSERIAL_DEVICE_EXTENSION (for the devobj being
removed).
Return Value:
Always TRUE
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
KIRQL oldIrql;
//
// If we are a multiport device, remove our entry
//
if (pDevExt->PortOnAMultiportCard) {
PSERIAL_MULTIPORT_DISPATCH pDispatch
= (PSERIAL_MULTIPORT_DISPATCH)pDevExt->OurIsrContext;
SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: removing multiport isr "
"ext\n");
pDispatch->Extensions[pDevExt->PortIndex - 1] = NULL;
if (pDevExt->Indexed == FALSE) {
pDispatch->UsablePortMask &= ~(1 << (pDevExt->PortIndex - 1));
pDispatch->MaskInverted &= ~(pDevExt->NewMaskInverted);
}
}
if (!IsListEmpty(&pDevExt->TopLevelSharers)) {
SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: removing multiport isr ext"
"\n");
SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: Device is a sharer\n");
//
// If we have siblings, the first becomes the sharer
//
if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
PSERIAL_DEVICE_EXTENSION pNewRoot;
SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Transferring to siblings\n");
pNewRoot = CONTAINING_RECORD(pDevExt->MultiportSiblings.Flink,
SERIAL_DEVICE_EXTENSION,
MultiportSiblings);
//
// He should not be on there already
//
ASSERT(IsListEmpty(&pNewRoot->TopLevelSharers));
InsertTailList(&pDevExt->TopLevelSharers, &pNewRoot->TopLevelSharers);
}
//
// Remove ourselves
//
RemoveEntryList(&pDevExt->TopLevelSharers);
InitializeListHead(&pDevExt->TopLevelSharers);
//
// Now check the master list to see if anyone is left...
//
if (!IsListEmpty(&pDevExt->CIsrSw->SharerList)) {
//
// Others are chained on this interrupt, so we don't want to
// disconnect it.
//
pDevExt->Interrupt = NULL;
}
}
//
// If this is part of a multiport board and we still have
// siblings, remove us from that list
//
if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Has multiport siblings\n");
RemoveEntryList(&pDevExt->MultiportSiblings);
InitializeListHead(&pDevExt->MultiportSiblings);
}
if (!IsListEmpty(&pDevExt->CommonInterruptObject)) {
SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Common intobj member\n");
RemoveEntryList(&pDevExt->CommonInterruptObject);
InitializeListHead(&pDevExt->CommonInterruptObject);
//
// Others are sharing this interrupt object so we detach ourselves
// from it this way instead of disconnecting.
//
pDevExt->Interrupt = NULL;
}
return TRUE;
}
VOID
SerialReleaseResources(IN PSERIAL_DEVICE_EXTENSION PDevExt)
/*++
Routine Description:
Releases resources (not pool) stored in the device extension.
Arguments:
PDevExt - Pointer to the device extension to release resources from.
Return Value:
VOID
--*/
{
KIRQL oldIrql;
SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, ">SerialReleaseResources(%X)\n",
PDevExt);
//
// Remove us from any lists we may be on
//
if (PDevExt->Interrupt != NULL) {
KeSynchronizeExecution(PDevExt->Interrupt, SerialCleanLists, PDevExt);
//
// AllDevObjs should never be empty since we have a sentinal
//
KeAcquireSpinLock(&SerialGlobals.GlobalsSpinLock, &oldIrql);
ASSERT(!IsListEmpty(&PDevExt->AllDevObjs));
RemoveEntryList(&PDevExt->AllDevObjs);
KeReleaseSpinLock(&SerialGlobals.GlobalsSpinLock, oldIrql);
InitializeListHead(&PDevExt->AllDevObjs);
}
//
// SerialCleanLists can remove our interrupt from us...
//
if (PDevExt->Interrupt != NULL) {
//
// Stop servicing interrupts if we are the owner
//
SerialDbgPrintEx(SERPNPPOWER, "Release - disconnecting interrupt %X\n",
PDevExt->Interrupt);
IoDisconnectInterrupt(PDevExt->Interrupt);
PDevExt->Interrupt = NULL;
if (PDevExt->CIsrSw != NULL) {
ExFreePool(PDevExt->CIsrSw);
PDevExt->CIsrSw = NULL;
}
}
if (PDevExt->PortOnAMultiportCard) {
ULONG i;
//
// If we are the last device, free this memory
//
for (i = 0; i < SERIAL_MAX_PORTS_INDEXED; i++) {
if (((PSERIAL_MULTIPORT_DISPATCH)PDevExt->OurIsrContext)
->Extensions[i] != NULL) {
break;
}
}
if (i == SERIAL_MAX_PORTS_INDEXED) {
SerialDbgPrintEx(SERPNPPOWER, "Release - freeing multi context\n");
ExFreePool(PDevExt->OurIsrContext);
}
}
//
// Stop handling timers
//
SerialCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
SerialCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
SerialCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
SerialCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
SerialCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
SerialCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);
//
// Stop servicing DPC's
//
SerialRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
SerialRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -