📄 read.c
字号:
Always false.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = Context;
SERIAL_LOCKED_PAGED_CODE();
extension->CountOnLastRead = extension->ReadByIsr;
extension->ReadByIsr = 0;
return FALSE;
}
VOID
SerialIntervalReadTimeout(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
/*++
Routine Description:
This routine is used timeout the request if the time between
characters exceed the interval time. A global is kept in
the device extension that records the count of characters read
the last the last time this routine was invoked (This dpc
will resubmit the timer if the count has changed). If the
count has not changed then this routine will attempt to complete
the irp. Note the special case of the last count being zero.
The timer isn't really in effect until the first character is
read.
Arguments:
Dpc - Not Used.
DeferredContext - Really points to the device extension.
SystemContext1 - Not Used.
SystemContext2 - Not Used.
Return Value:
None.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
KIRQL oldIrql;
UNREFERENCED_PARAMETER(SystemContext1);
UNREFERENCED_PARAMETER(SystemContext2);
IoAcquireCancelSpinLock(&oldIrql);
SerialDump(SERTRACECALLS, ("SERIAL: SerialIntervalReadTimeout\n"));
if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) {
//
// This value is only set by the total
// timer to indicate that it has fired.
// If so, then we should simply try to complete.
//
SerialTryToCompleteCurrent(
extension,
SerialGrabReadFromIsr,
oldIrql,
STATUS_TIMEOUT,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
SerialStartRead,
SerialGetNextIrp,
SERIAL_REF_INT_TIMER
);
} else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) {
//
// This value is only set by the regular
// completion routine.
//
// If so, then we should simply try to complete.
//
SerialTryToCompleteCurrent(
extension,
SerialGrabReadFromIsr,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
SerialStartRead,
SerialGetNextIrp,
SERIAL_REF_INT_TIMER
);
} else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) {
//
// This value is only set by the cancel
// read routine.
//
// If so, then we should simply try to complete.
//
SerialTryToCompleteCurrent(
extension,
SerialGrabReadFromIsr,
oldIrql,
STATUS_CANCELLED,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
SerialStartRead,
SerialGetNextIrp,
SERIAL_REF_INT_TIMER
);
} else if (extension->CountOnLastRead || extension->ReadByIsr) {
//
// Something has happened since we last came here. We
// check to see if the ISR has read in any more characters.
// If it did then we should update the isr's read count
// and resubmit the timer.
//
if (extension->ReadByIsr) {
KeSynchronizeExecution(
extension->Interrupt,
SerialUpdateReadByIsr,
extension
);
//
// Save off the "last" time something was read.
// As we come back to this routine we will compare
// the current time to the "last" time. If the
// difference is ever larger then the interval
// requested by the user, then time out the request.
//
KeQuerySystemTime(
&extension->LastReadTime
);
SerialSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
} else {
//
// Take the difference between the current time
// and the last time we had characters and
// see if it is greater then the interval time.
// if it is, then time out the request. Otherwise
// go away again for a while.
//
//
// No characters read in the interval time. Kill
// this read.
//
LARGE_INTEGER currentTime;
KeQuerySystemTime(
¤tTime
);
if ((currentTime.QuadPart - extension->LastReadTime.QuadPart) >=
extension->IntervalTime.QuadPart) {
SerialTryToCompleteCurrent(
extension,
SerialGrabReadFromIsr,
oldIrql,
STATUS_TIMEOUT,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
SerialStartRead,
SerialGetNextIrp,
SERIAL_REF_INT_TIMER
);
} else {
SerialSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
}
}
} else {
//
// Timer doesn't really start until the first character.
// So we should simply resubmit ourselves.
//
SerialSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
}
SerialDpcEpilogue(extension, Dpc);
}
ULONG
SerialGetCharsFromIntBuffer(
PSERIAL_DEVICE_EXTENSION Extension
)
/*++
Routine Description:
This routine is used to copy any characters out of the interrupt
buffer into the users buffer. It will be reading values that
are updated with the ISR but this is safe since this value is
only decremented by synchronization routines. This routine will
return the number of characters copied so some other routine
can call a synchronization routine to update what is seen at
interrupt level.
Arguments:
Extension - A pointer to the device extension.
Return Value:
The number of characters that were copied into the user
buffer.
--*/
{
//
// This value will be the number of characters that this
// routine returns. It will be the minimum of the number
// of characters currently in the buffer or the number of
// characters required for the read.
//
ULONG numberOfCharsToGet;
//
// This holds the number of characters between the first
// readable character and - the last character we will read or
// the real physical end of the buffer (not the last readable
// character).
//
ULONG firstTryNumberToGet;
SERIAL_LOCKED_PAGED_CODE();
//
// The minimum of the number of characters we need and
// the number of characters available
//
numberOfCharsToGet = Extension->CharsInInterruptBuffer;
if (numberOfCharsToGet > Extension->NumberNeededForRead) {
numberOfCharsToGet = Extension->NumberNeededForRead;
}
if (numberOfCharsToGet) {
//
// This will hold the number of characters between the
// first available character and the end of the buffer.
// Note that the buffer could wrap around but for the
// purposes of the first copy we don't care about that.
//
firstTryNumberToGet = (ULONG)(Extension->LastCharSlot -
Extension->FirstReadableChar) + 1;
if (firstTryNumberToGet > numberOfCharsToGet) {
//
// The characters don't wrap. Actually they may wrap but
// we don't care for the purposes of this read since the
// characters we need are available before the wrap.
//
RtlMoveMemory(
((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
+ (IoGetCurrentIrpStackLocation(
Extension->CurrentReadIrp
)->Parameters.Read.Length
- Extension->NumberNeededForRead
),
Extension->FirstReadableChar,
numberOfCharsToGet
);
Extension->NumberNeededForRead -= numberOfCharsToGet;
//
// We now will move the pointer to the first character after
// what we just copied into the users buffer.
//
// We need to check if the stream of readable characters
// is wrapping around to the beginning of the buffer.
//
// Note that we may have just taken the last characters
// at the end of the buffer.
//
if ((Extension->FirstReadableChar + (numberOfCharsToGet - 1)) ==
Extension->LastCharSlot) {
Extension->FirstReadableChar = Extension->InterruptReadBuffer;
} else {
Extension->FirstReadableChar += numberOfCharsToGet;
}
} else {
//
// The characters do wrap. Get up until the end of the buffer.
//
RtlMoveMemory(
((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
+ (IoGetCurrentIrpStackLocation(
Extension->CurrentReadIrp
)->Parameters.Read.Length
- Extension->NumberNeededForRead
),
Extension->FirstReadableChar,
firstTryNumberToGet
);
Extension->NumberNeededForRead -= firstTryNumberToGet;
//
// Now get the rest of the characters from the beginning of the
// buffer.
//
RtlMoveMemory(
((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
+ (IoGetCurrentIrpStackLocation(
Extension->CurrentReadIrp
)->Parameters.Read.Length
- Extension->NumberNeededForRead
),
Extension->InterruptReadBuffer,
numberOfCharsToGet - firstTryNumberToGet
);
Extension->FirstReadableChar = Extension->InterruptReadBuffer +
(numberOfCharsToGet -
firstTryNumberToGet);
Extension->NumberNeededForRead -= (numberOfCharsToGet -
firstTryNumberToGet);
}
}
Extension->CurrentReadIrp->IoStatus.Information += numberOfCharsToGet;
return numberOfCharsToGet;
}
BOOLEAN
SerialUpdateInterruptBuffer(
IN PVOID Context
)
/*++
Routine Description:
This routine is used to update the number of characters that
remain in the interrupt buffer. We need to use this routine
since the count could be updated during the update by execution
of the ISR.
NOTE: This is called by KeSynchronizeExecution.
Arguments:
Context - Points to a structure that contains a pointer to the
device extension and count of the number of characters
that we previously copied into the users buffer. The
structure actually has a third field that we don't
use in this routine.
Return Value:
Always FALSE.
--*/
{
PSERIAL_UPDATE_CHAR update = Context;
PSERIAL_DEVICE_EXTENSION extension = update->Extension;
SERIAL_LOCKED_PAGED_CODE();
ASSERT(extension->CharsInInterruptBuffer >= update->CharsCopied);
extension->CharsInInterruptBuffer -= update->CharsCopied;
//
// Deal with flow control if necessary.
//
SerialHandleReducedIntBuffer(extension);
return FALSE;
}
BOOLEAN
SerialUpdateAndSwitchToUser(
IN PVOID Context
)
/*++
Routine Description:
This routine gets the (hopefully) few characters that
remain in the interrupt buffer after the first time we tried
to get them out. If we still don't have enough characters
to satisfy the read it will then we set things up so that the
ISR uses the user buffer copy into.
This routine is also used to update a count that is maintained
by the ISR to keep track of the number of characters in its buffer.
NOTE: This is called by KeSynchronizeExecution.
Arguments:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -