📄 initunlo.c
字号:
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
--*/
{
PAGED_CODE();
SerialDump(SERTRACECALLS,("SERIAL: Enter SerialReleaseResources\n"));
//
// Remove us from any lists we may be on
//
if (PDevExt->Interrupt != NULL) {
KeSynchronizeExecution(PDevExt->Interrupt, SerialCleanLists, PDevExt);
}
//
// SerialCleanLists can remove our interrupt from us...
//
if (PDevExt->Interrupt != NULL) {
//
// Stop servicing interrupts if we are the owner
//
SerialDump(SERPNPPOWER,
("SERIAL: Release - disconnecting interrupt %08X\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) {
SerialDump(SERPNPPOWER,("SERIAL: 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);
//
// If necessary, unmap the device registers.
//
if (PDevExt->UnMapRegisters) {
MmUnmapIoSpace(PDevExt->Controller, PDevExt->SpanOfController);
}
if (PDevExt->UnMapStatus) {
MmUnmapIoSpace(PDevExt->InterruptStatus,
PDevExt->SpanOfInterruptStatus);
}
SerialDump(SERTRACECALLS,("SERIAL: Leave SerialReleaseResources\n"));
}
NTSTATUS
SerialPrepareRemove(IN PDEVICE_OBJECT PDevObj)
/*++
Routine Description:
Removes a serial device object from the system.
Arguments:
PDevObj - A pointer to the Device Object we want removed.
Return Value:
Always TRUE
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt
= (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
POWER_STATE state;
ULONG pendingIRPs;
PAGED_CODE();
SerialDump(SERTRACECALLS,("SERIAL: Enter SerialPrepareRemove\n"));
//
// Mark as not accepting requests
//
SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
//
// Complete all pending requests
//
SerialKillPendingIrps(PDevObj);
//
// Wait for any pending requests we raced on.
//
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
if (pendingIRPs) {
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive, KernelMode,
FALSE, NULL);
}
state.DeviceState = PowerDeviceD3;
PoSetPowerState(PDevObj, DevicePowerState, state);
return TRUE;
}
VOID
SerialDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
BOOLEAN DisableUART)
{
PSERIAL_DEVICE_EXTENSION pDevExt
= (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
PAGED_CODE();
SerialDump(SERTRACECALLS,("SERIAL: Enter SerialDisableInterfaces\n"));
//
// Only do these many things if the device has started and still
// has resources allocated
//
if (pDevExt->Flags & SERIAL_FLAGS_STARTED) {
if (!(pDevExt->Flags & SERIAL_FLAGS_STOPPED)) {
if (DisableUART) {
//
// Mask off interrupts
//
DISABLE_ALL_INTERRUPTS(pDevExt->Controller);
}
SerialReleaseResources(pDevExt);
}
//
// Remove us from WMI consideration
//
IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
}
//
// Undo external names
//
SerialUndoExternalNaming(pDevExt);
SerialDump(SERTRACECALLS,("SERIAL: Exit SerialDisableInterfaces\n"));
}
NTSTATUS
SerialRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
/*++
Routine Description:
Removes a serial device object from the system.
Arguments:
PDevObj - A pointer to the Device Object we want removed.
Return Value:
Always TRUE
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt
= (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
PAGED_CODE();
SerialDump(SERTRACECALLS,("SERIAL: Enter SerialRemoveDevObj\n"));
if (!(pDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
//
// Disable all external interfaces and release resources
//
SerialDisableInterfacesResources(PDevObj, TRUE);
}
IoDetachDevice(pDevExt->LowerDeviceObject);
//
// Free memory allocated in the extension
//
if (pDevExt->NtNameForPort.Buffer != NULL) {
ExFreePool(pDevExt->NtNameForPort.Buffer);
}
if (pDevExt->DeviceName.Buffer != NULL) {
ExFreePool(pDevExt->DeviceName.Buffer);
}
if (pDevExt->SymbolicLinkName.Buffer != NULL) {
ExFreePool(pDevExt->SymbolicLinkName.Buffer);
}
if (pDevExt->DosName.Buffer != NULL) {
ExFreePool(pDevExt->DosName.Buffer);
}
if (pDevExt->ObjectDirectory.Buffer) {
ExFreePool(pDevExt->ObjectDirectory.Buffer);
}
//
// Delete the devobj
//
IoDeleteDevice(PDevObj);
SerialDump(SERTRACECALLS,("SERIAL: Leave SerialRemoveDevObj\n"));
return STATUS_SUCCESS;
}
VOID
SerialKillPendingIrps(PDEVICE_OBJECT PDevObj)
/*++
Routine Description:
This routine kills any irps pending for the passed device object.
Arguments:
PDevObj - Pointer to the device object whose irps must die.
Return Value:
VOID
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
KIRQL oldIrql;
SerialDump (SERTRACECALLS,("SERIAL: Enter SerialKillPendingIrps\n"));
//
// First kill all the reads and writes.
//
SerialKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
&pDevExt->CurrentWriteIrp);
SerialKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
&pDevExt->CurrentReadIrp);
//
// Next get rid of purges.
//
SerialKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
&pDevExt->CurrentPurgeIrp);
//
// Get rid of any mask operations.
//
SerialKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
&pDevExt->CurrentMaskIrp);
//
// Now get rid a pending wait mask irp.
//
IoAcquireCancelSpinLock(&oldIrql);
if (pDevExt->CurrentWaitIrp) {
PDRIVER_CANCEL cancelRoutine;
cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
pDevExt->CurrentWaitIrp->Cancel = TRUE;
if (cancelRoutine) {
pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
}
} else {
IoReleaseCancelSpinLock(oldIrql);
}
//
// Cancel any pending wait-wake irps
//
if (pDevExt->PendingWakeIrp != NULL) {
IoCancelIrp(pDevExt->PendingWakeIrp);
pDevExt->PendingWakeIrp = NULL;
}
//
// Finally, dump any stalled IRPS
//
SerialKillAllStalled(PDevObj);
SerialDump (SERTRACECALLS,("SERIAL: Leave SerialKillPendingIrps\n"));
}
BOOLEAN
SerialSingleToMulti(PVOID Context)
/*++
Routine Description:
This routine converts a root device set up to be a single port
device to a multiport device while that device is running.
Arguments:
Context - Actually a pointer to the device extension of the root
device we are turning into a multiport device.
Return Value:
Always TRUE
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
PSERIAL_MULTIPORT_DISPATCH pOurIsrContext;
PSERIAL_MULTIPORT_DISPATCH pNewIsrContext
= (PSERIAL_MULTIPORT_DISPATCH)pDevExt->NewExtension;
PVOID isrFunc;
SerialDump (SERTRACECALLS,("SERIAL: Enter SerialSingleToMulti\n"));
//
// Stomp OurIsrContext since we are going from one to many
// thus our previous context was just pDevExt and doesn't
// need to be released (i.e., no call to ExFreePool() is needed).
//
pOurIsrContext = pDevExt->OurIsrContext = pDevExt->TopLevelOurIsrContext
= pNewIsrContext;
//
// We are now multiport
//
pDevExt->PortOnAMultiportCard = TRUE;
//
// Update our personal extensions slot
//
pOurIsrContext->Extensions[pDevExt->PortIndex - 1] = pDevExt;
pOurIsrContext->InterruptStatus = pDevExt->InterruptStatus;
//
// We have to pick a new ISR and a new context.
// As soon as this is done, the ISR will change, so we have to
// be ready to handle things there.
//
if (pDevExt->Indexed == FALSE) {
pOurIsrContext->UsablePortMask = 1 << (pDevExt->PortIndex - 1);
pOurIsrContext->MaskInverted = pDevExt->MaskInverted;
isrFunc = SerialBitMappedMultiportIsr;
} else {
isrFunc = SerialIndexedMultiportIsr;
}
pDevExt->OurIsr = isrFunc;
pDevExt->TopLevelOurIsr = isrFunc;
if (pDevExt->CIsrSw->IsrFunc != SerialSharerIsr) {
pDevExt->CIsrSw->IsrFunc = isrFunc;
pDevExt->CIsrSw->Context = pOurIsrContext;
}
SerialDump (SERTRACECALLS,("SERIAL: Leave SerialSingleToMulti\n"));
return TRUE;
}
BOOLEAN
SerialAddToMulti(PVOID Context)
/*++
Routine Description:
This routine adds a new port to a multiport device while that device is
running.
Arguments:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -