📄 openclos.c
字号:
SERIAL_LSR_THRE)) {
KeDelayExecutionThread(
KernelMode,
FALSE,
&charTime
);
}
WRITE_TRANSMIT_HOLDING(
extension->Controller,
extension->SpecialChars.XonChar
);
//
// Wait a reasonable amount of time for the characters
// to be 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);
}
}
//
// The hardware is empty. Delay 10 character times before
// shut down all the flow control.
//
tenCharDelay.QuadPart = charTime.QuadPart * 10;
KeDelayExecutionThread(
KernelMode,
TRUE,
&tenCharDelay
);
SerialClrDTR(extension);
//
// 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
// ourselve with the ISR.
//
if (extension->CountOfTryingToLowerRTS) {
do {
KeDelayExecutionThread(
KernelMode,
FALSE,
&charTime
);
} while (extension->CountOfTryingToLowerRTS);
KeSynchronizeExecution(
extension->Interrupt,
SerialNullSynch,
NULL
);
//
// 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.
//
}
SerialClrRTS(extension);
//
// Clean out the holding reasons (since we are closed).
//
extension->RXHolding = 0;
extension->TXHolding = 0;
//
// Mark device as not busy for WMI
//
extension->WmiCommData.IsBusy = FALSE;
//
// All is done. The port has been disabled from interrupting
// so there is no point in keeping the memory around.
//
extension->BufferSize = 0;
if (extension->InterruptReadBuffer != NULL) {
ExFreePool(extension->InterruptReadBuffer);
}
extension->InterruptReadBuffer = NULL;
//
// Stop waiting for wakeup
//
extension->SendWaitWake = FALSE;
if (extension->PendingWakeIrp != NULL) {
IoCancelIrp(extension->PendingWakeIrp);
}
//
// Power down our device stack
//
if (!extension->RetainPowerOnClose) {
(void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD3);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0L;
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
//
// Unlock the pages. If this is the last reference to the section
// then the driver code will be flushed out.
//
//
// First, we have to let the DPC's drain. No more should be queued
// since we aren't taking interrupts now....
//
pendingDPCs = InterlockedDecrement(&extension->DpcCount);
LOGENTRY(LOG_CNT, 'DpD7', 0, extension->DpcCount, 0);
if (pendingDPCs) {
SerialDbgPrintEx(SERDIAG1,"Draining DPC's: %x\n", Irp);
KeWaitForSingleObject(&extension->PendingDpcEvent, Executive,
KernelMode, FALSE, NULL);
}
SerialDbgPrintEx(SERDIAG1, "DPC's drained: %x\n", Irp);
//
// Pages must be locked to release the mutex, so don't unlock
// them until after we release the mutex
//
ExReleaseFastMutex(&extension->CloseMutex);
//
// Reset for next open
//
InterlockedIncrement(&extension->DpcCount);
LOGENTRY(LOG_CNT, 'DpI6', 0, extension->DpcCount, 0);
openCount = InterlockedDecrement(&extension->OpenCount);
//
// Open count may be non-zero if someone was trying to open
// at the same time we decremented
//
// ASSERT(openCount == 0);
SerialUnlockPagableImageSection(SerialGlobals.PAGESER_Handle);
return STATUS_SUCCESS;
}
BOOLEAN
SerialCheckOpen(
IN PVOID Context
)
/*++
Routine Description:
This routine will traverse the circular doubly linked list
of devices that are using the same interrupt object. It will look
for other devices that are open. If it doesn't find any
it will indicate that it is ok to open this device.
If it finds another device open we have two cases:
1) The device we are trying to open is on a multiport card.
If the already open device is part of a multiport device
this code will indicate it is ok to open. We do this on the
theory that the multiport devices are daisy chained
and the cards can correctly arbitrate the interrupt
line. Note this assumption could be wrong. Somebody
could put two non-daisychained multiports on the
same interrupt. However, only a total clod would do
such a thing, and in my opinion deserves everthing they
get.
2) The device we are trying to open is not on a multiport card.
We indicate that it is not ok to open.
Arguments:
Context - This is a structure that contains a pointer to the
extension of the device we are trying to open, and
a pointer to an NTSTATUS that will indicate whether
the device was opened or not.
Return Value:
This routine always returns FALSE.
--*/
{
PSERIAL_DEVICE_EXTENSION extensionToOpen =
((PSERIAL_CHECK_OPEN)Context)->Extension;
NTSTATUS *status = ((PSERIAL_CHECK_OPEN)Context)->StatusOfOpen;
PLIST_ENTRY firstEntry = &extensionToOpen->CommonInterruptObject;
PLIST_ENTRY currentEntry = firstEntry;
PSERIAL_DEVICE_EXTENSION currentExtension;
do {
currentExtension = CONTAINING_RECORD(
currentEntry,
SERIAL_DEVICE_EXTENSION,
CommonInterruptObject
);
if (currentExtension->DeviceIsOpened) {
break;
}
currentEntry = currentExtension->CommonInterruptObject.Flink;
} while (currentEntry != firstEntry);
if (currentEntry == firstEntry) {
//
// We searched the whole list and found no other opens
// mark the status as successful and call the regular
// opening routine.
//
*status = STATUS_SUCCESS;
SerialMarkOpen(extensionToOpen);
} else {
if (!extensionToOpen->PortOnAMultiportCard) {
*status = STATUS_SHARED_IRQ_BUSY;
} else {
if (!currentExtension->PortOnAMultiportCard) {
*status = STATUS_SHARED_IRQ_BUSY;
} else {
*status = STATUS_SUCCESS;
SerialMarkOpen(extensionToOpen);
}
}
}
return FALSE;
}
BOOLEAN
SerialMarkOpen(
IN PVOID Context
)
/*++
Routine Description:
This routine merely sets a boolean to true to mark the fact that
somebody opened the device and its worthwhile to pay attention
to interrupts.
Arguments:
Context - Really a pointer to the device extension.
Return Value:
This routine always returns FALSE.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = Context;
SerialReset(extension);
//
// Prepare for the opening by re-enabling interrupts.
//
// We do this my modifying the OUT2 line in the modem control.
// In PC's this bit is "anded" with the interrupt line.
//
WRITE_MODEM_CONTROL(
extension->Controller,
(UCHAR)(READ_MODEM_CONTROL(extension->Controller) | SERIAL_MCR_OUT2)
);
extension->DeviceIsOpened = TRUE;
extension->ErrorWord = 0;
return FALSE;
}
VOID
SerialDisableUART(IN PVOID Context)
/*++
Routine Description:
This routine disables the UART and puts it in a "safe" state when
not in use (like a close or powerdown).
Arguments:
Context - Really a pointer to the device extension.
Return Value:
This routine always returns FALSE.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = Context;
//
// Prepare for the closing by stopping interrupts.
//
// We do this by adjusting the OUT2 line in the modem control.
// In PC's this bit is "anded" with the interrupt line.
//
WRITE_MODEM_CONTROL(extension->Controller,
(UCHAR)(READ_MODEM_CONTROL(extension->Controller)
& ~SERIAL_MCR_OUT2));
if (extension->FifoPresent) {
WRITE_FIFO_CONTROL(extension->Controller, (UCHAR)0);
}
}
BOOLEAN
SerialMarkClose(
IN PVOID Context
)
/*++
Routine Description:
This routine merely sets a boolean to false to mark the fact that
somebody closed the device and it's no longer worthwhile to pay attention
to interrupts. It also disables the UART.
Arguments:
Context - Really a pointer to the device extension.
Return Value:
This routine always returns FALSE.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = Context;
SerialDisableUART(Context);
extension->DeviceIsOpened = FALSE;
extension->DeviceState.Reopen = FALSE;
return FALSE;
}
NTSTATUS
SerialCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This function is used to kill all longstanding IO operations.
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;
NTSTATUS status;
PAGED_CODE();
//
// We succeed a cleanup on a removing device
//
if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
if (status == STATUS_DELETE_PENDING) {
status = Irp->IoStatus.Status = STATUS_SUCCESS;
}
if (status != STATUS_PENDING) {
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
}
return status;
}
SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", Irp);
SerialKillPendingIrps(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0L;
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
LARGE_INTEGER
SerialGetCharTime(
IN PSERIAL_DEVICE_EXTENSION Extension
)
/*++
Routine Description:
This function will return the number of 100 nanosecond intervals
there are in one character time (based on the present form
of flow control.
Arguments:
Extension - Just what it says.
Return Value:
100 nanosecond intervals in a character time.
--*/
{
ULONG dataSize;
ULONG paritySize;
ULONG stopSize;
ULONG charTime;
ULONG bitTime;
LARGE_INTEGER tmp;
if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {
dataSize = 5;
} else if ((Extension->LineControl & SERIAL_DATA_MASK)
== SERIAL_6_DATA) {
dataSize = 6;
} else if ((Extension->LineControl & SERIAL_DATA_MASK)
== SERIAL_7_DATA) {
dataSize = 7;
} else if ((Extension->LineControl & SERIAL_DATA_MASK)
== SERIAL_8_DATA) {
dataSize = 8;
}
paritySize = 1;
if ((Extension->LineControl & SERIAL_PARITY_MASK)
== SERIAL_NONE_PARITY) {
paritySize = 0;
}
if (Extension->LineControl & SERIAL_2_STOP) {
//
// Even if it is 1.5, for sanities sake were going
// to say 2.
//
stopSize = 2;
} else {
stopSize = 1;
}
//
// First we calculate the number of 100 nanosecond intervals
// are in a single bit time (Approximately).
//
bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
tmp.QuadPart = charTime;
return tmp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -