mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
857 lines
19 KiB
857 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1991, 1992, 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code that perform queueing and completion
|
|
manipulation on requests.
|
|
|
|
Author:
|
|
|
|
Anthony V. Ercolano 26-Sep-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
VOID
|
|
SerialRundownIrpRefs(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PKTIMER IntervalTimer,
|
|
IN PKTIMER TotalTimer
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGESER,SerialKillAllReadsOrWrites)
|
|
#pragma alloc_text(PAGESER,SerialGetNextIrp)
|
|
#pragma alloc_text(PAGESER,SerialTryToCompleteCurrent)
|
|
#pragma alloc_text(PAGESER,SerialStartOrQueue)
|
|
#pragma alloc_text(PAGESER,SerialCancelQueued)
|
|
#pragma alloc_text(PAGESER,SerialCompleteIfError)
|
|
#pragma alloc_text(PAGESER,SerialRundownIrpRefs)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
SerialKillAllReadsOrWrites(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PLIST_ENTRY QueueToClean,
|
|
IN PIRP *CurrentOpIrp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to cancel all queued and the current irps
|
|
for reads or for writes.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - A pointer to the serial device object.
|
|
|
|
QueueToClean - A pointer to the queue which we're going to clean out.
|
|
|
|
CurrentOpIrp - Pointer to a pointer to the current irp.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL cancelIrql;
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
|
|
//
|
|
// We acquire the cancel spin lock. This will prevent the
|
|
// irps from moving around.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
//
|
|
// Clean the list from back to front.
|
|
//
|
|
|
|
while (!IsListEmpty(QueueToClean)) {
|
|
|
|
PIRP currentLastIrp = CONTAINING_RECORD(
|
|
QueueToClean->Blink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
|
|
RemoveEntryList(QueueToClean->Blink);
|
|
|
|
cancelRoutine = currentLastIrp->CancelRoutine;
|
|
currentLastIrp->CancelIrql = cancelIrql;
|
|
currentLastIrp->CancelRoutine = NULL;
|
|
currentLastIrp->Cancel = TRUE;
|
|
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
currentLastIrp
|
|
);
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
}
|
|
|
|
//
|
|
// The queue is clean. Now go after the current if
|
|
// it's there.
|
|
//
|
|
|
|
if (*CurrentOpIrp) {
|
|
|
|
|
|
cancelRoutine = (*CurrentOpIrp)->CancelRoutine;
|
|
(*CurrentOpIrp)->Cancel = TRUE;
|
|
|
|
//
|
|
// If the current irp is not in a cancelable state
|
|
// then it *will* try to enter one and the above
|
|
// assignment will kill it. If it already is in
|
|
// a cancelable state then the following will kill it.
|
|
//
|
|
|
|
if (cancelRoutine) {
|
|
|
|
(*CurrentOpIrp)->CancelRoutine = NULL;
|
|
(*CurrentOpIrp)->CancelIrql = cancelIrql;
|
|
|
|
//
|
|
// This irp is already in a cancelable state. We simply
|
|
// mark it as canceled and call the cancel routine for
|
|
// it.
|
|
//
|
|
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
*CurrentOpIrp
|
|
);
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SerialGetNextIrp(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess,
|
|
OUT PIRP *NextIrp,
|
|
IN BOOLEAN CompleteCurrent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to make the head of the particular
|
|
queue the current irp. It also completes the what
|
|
was the old current irp if desired.
|
|
|
|
Arguments:
|
|
|
|
CurrentOpIrp - Pointer to a pointer to the currently active
|
|
irp for the particular work list. Note that
|
|
this item is not actually part of the list.
|
|
|
|
QueueToProcess - The list to pull the new item off of.
|
|
|
|
NextIrp - The next Irp to process. Note that CurrentOpIrp
|
|
will be set to this value under protection of the
|
|
cancel spin lock. However, if *NextIrp is NULL when
|
|
this routine returns, it is not necessaryly true the
|
|
what is pointed to by CurrentOpIrp will also be NULL.
|
|
The reason for this is that if the queue is empty
|
|
when we hold the cancel spin lock, a new irp may come
|
|
in immediately after we release the lock.
|
|
|
|
CompleteCurrent - If TRUE then this routine will complete the
|
|
irp pointed to by the pointer argument
|
|
CurrentOpIrp.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
PIRP oldIrp;
|
|
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
oldIrp = *CurrentOpIrp;
|
|
|
|
if (oldIrp) {
|
|
|
|
if (CompleteCurrent) {
|
|
|
|
ASSERT(!oldIrp->CancelRoutine);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if there is a new irp to start up.
|
|
//
|
|
|
|
if (!IsListEmpty(QueueToProcess)) {
|
|
|
|
PLIST_ENTRY headOfList;
|
|
|
|
headOfList = RemoveHeadList(QueueToProcess);
|
|
|
|
*CurrentOpIrp = CONTAINING_RECORD(
|
|
headOfList,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
*CurrentOpIrp,
|
|
NULL
|
|
);
|
|
|
|
} else {
|
|
|
|
*CurrentOpIrp = NULL;
|
|
|
|
}
|
|
|
|
*NextIrp = *CurrentOpIrp;
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
if (CompleteCurrent) {
|
|
|
|
if (oldIrp) {
|
|
|
|
SerialDump(
|
|
SERIRPPATH,
|
|
("SERIAL: Complete Irp: %x\n",oldIrp)
|
|
);
|
|
IoCompleteRequest(
|
|
oldIrp,
|
|
IO_SERIAL_INCREMENT
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SerialTryToCompleteCurrent(
|
|
IN PSERIAL_DEVICE_EXTENSION Extension,
|
|
IN PKSYNCHRONIZE_ROUTINE SynchRoutine OPTIONAL,
|
|
IN KIRQL IrqlForRelease,
|
|
IN NTSTATUS StatusToUse,
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess OPTIONAL,
|
|
IN PKTIMER IntervalTimer OPTIONAL,
|
|
IN PKTIMER TotalTimer OPTIONAL,
|
|
IN PSERIAL_START_ROUTINE Starter OPTIONAL,
|
|
IN PSERIAL_GET_NEXT_ROUTINE GetNextIrp OPTIONAL,
|
|
IN LONG RefType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to kill all of the reasons there are
|
|
references on the current read/write. If everything can be killed
|
|
it will complete this read/write and try to start another.
|
|
|
|
NOTE: This routine assumes that it is called with the cancel
|
|
spinlock held.
|
|
|
|
Arguments:
|
|
|
|
Extension - Simply a pointer to the device extension.
|
|
|
|
SynchRoutine - A routine that will synchronize with the isr
|
|
and attempt to remove the knowledge of the
|
|
current irp from the isr. NOTE: This pointer
|
|
can be null.
|
|
|
|
IrqlForRelease - This routine is called with the cancel spinlock held.
|
|
This is the irql that was current when the cancel
|
|
spinlock was acquired.
|
|
|
|
StatusToUse - The irp's status field will be set to this value, if
|
|
this routine can complete the irp.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// We can decrement the reference to "remove" the fact
|
|
// that the caller no longer will be accessing this irp.
|
|
//
|
|
|
|
SERIAL_CLEAR_REFERENCE(
|
|
*CurrentOpIrp,
|
|
RefType
|
|
);
|
|
|
|
if (SynchRoutine) {
|
|
|
|
KeSynchronizeExecution(
|
|
Extension->Interrupt,
|
|
SynchRoutine,
|
|
Extension
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Try to run down all other references to this irp.
|
|
//
|
|
|
|
SerialRundownIrpRefs(
|
|
CurrentOpIrp,
|
|
IntervalTimer,
|
|
TotalTimer
|
|
);
|
|
|
|
//
|
|
// See if the ref count is zero after trying to kill everybody else.
|
|
//
|
|
|
|
if (!SERIAL_REFERENCE_COUNT(*CurrentOpIrp)) {
|
|
|
|
PIRP newIrp;
|
|
|
|
|
|
//
|
|
// The ref count was zero so we should complete this
|
|
// request.
|
|
//
|
|
// The following call will also cause the current irp to be
|
|
// completed.
|
|
//
|
|
|
|
(*CurrentOpIrp)->IoStatus.Status = StatusToUse;
|
|
|
|
if (StatusToUse == STATUS_CANCELLED) {
|
|
|
|
(*CurrentOpIrp)->IoStatus.Information = 0;
|
|
|
|
}
|
|
|
|
if (GetNextIrp) {
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
GetNextIrp(
|
|
CurrentOpIrp,
|
|
QueueToProcess,
|
|
&newIrp,
|
|
TRUE
|
|
);
|
|
|
|
if (newIrp) {
|
|
|
|
Starter(Extension);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PIRP oldIrp = *CurrentOpIrp;
|
|
|
|
//
|
|
// There was no get next routine. We will simply complete
|
|
// the irp. We should make sure that we null out the
|
|
// pointer to the pointer to this irp.
|
|
//
|
|
|
|
*CurrentOpIrp = NULL;
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
SerialDump(
|
|
SERIRPPATH,
|
|
("SERIAL: Complete Irp: %x\n",oldIrp)
|
|
);
|
|
IoCompleteRequest(
|
|
oldIrp,
|
|
IO_SERIAL_INCREMENT
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SerialRundownIrpRefs(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PKTIMER IntervalTimer OPTIONAL,
|
|
IN PKTIMER TotalTimer OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs through the various items that *could*
|
|
have a reference to the current read/write. It try's to kill
|
|
the reason. If it does succeed in killing the reason it
|
|
will decrement the reference count on the irp.
|
|
|
|
NOTE: This routine assumes that it is called with the cancel
|
|
spin lock held.
|
|
|
|
Arguments:
|
|
|
|
CurrentOpIrp - Pointer to a pointer to current irp for the
|
|
particular operation.
|
|
|
|
IntervalTimer - Pointer to the interval timer for the operation.
|
|
NOTE: This could be null.
|
|
|
|
TotalTimer - Pointer to the total timer for the operation.
|
|
NOTE: This could be null.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// This routine is called with the cancel spin lock held
|
|
// so we know only one thread of execution can be in here
|
|
// at one time.
|
|
//
|
|
|
|
//
|
|
// First we see if there is still a cancel routine. If
|
|
// so then we can decrement the count by one.
|
|
//
|
|
|
|
if ((*CurrentOpIrp)->CancelRoutine) {
|
|
|
|
SERIAL_CLEAR_REFERENCE(
|
|
*CurrentOpIrp,
|
|
SERIAL_REF_CANCEL
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
*CurrentOpIrp,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
if (IntervalTimer) {
|
|
|
|
//
|
|
// Try to cancel the operations interval timer. If the operation
|
|
// returns true then the timer did have a reference to the
|
|
// irp. Since we've canceled this timer that reference is
|
|
// no longer valid and we can decrement the reference count.
|
|
//
|
|
// If the cancel returns false then this means either of two things:
|
|
//
|
|
// a) The timer has already fired.
|
|
//
|
|
// b) There never was an interval timer.
|
|
//
|
|
// In the case of "b" there is no need to decrement the reference
|
|
// count since the "timer" never had a reference to it.
|
|
//
|
|
// In the case of "a", then the timer itself will be coming
|
|
// along and decrement it's reference. Note that the caller
|
|
// of this routine might actually be the this timer, but it
|
|
// has already decremented the reference.
|
|
//
|
|
|
|
if (KeCancelTimer(IntervalTimer)) {
|
|
|
|
SERIAL_CLEAR_REFERENCE(
|
|
*CurrentOpIrp,
|
|
SERIAL_REF_INT_TIMER
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (TotalTimer) {
|
|
|
|
//
|
|
// Try to cancel the operations total timer. If the operation
|
|
// returns true then the timer did have a reference to the
|
|
// irp. Since we've canceled this timer that reference is
|
|
// no longer valid and we can decrement the reference count.
|
|
//
|
|
// If the cancel returns false then this means either of two things:
|
|
//
|
|
// a) The timer has already fired.
|
|
//
|
|
// b) There never was an total timer.
|
|
//
|
|
// In the case of "b" there is no need to decrement the reference
|
|
// count since the "timer" never had a reference to it.
|
|
//
|
|
// In the case of "a", then the timer itself will be coming
|
|
// along and decrement it's reference. Note that the caller
|
|
// of this routine might actually be the this timer, but it
|
|
// has already decremented the reference.
|
|
//
|
|
|
|
if (KeCancelTimer(TotalTimer)) {
|
|
|
|
SERIAL_CLEAR_REFERENCE(
|
|
*CurrentOpIrp,
|
|
SERIAL_REF_TOTAL_TIMER
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
SerialStartOrQueue(
|
|
IN PSERIAL_DEVICE_EXTENSION Extension,
|
|
IN PIRP Irp,
|
|
IN PLIST_ENTRY QueueToExamine,
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PSERIAL_START_ROUTINE Starter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to either start or queue any requst
|
|
that can be queued in the driver.
|
|
|
|
Arguments:
|
|
|
|
Extension - Points to the serial device extension.
|
|
|
|
Irp - The irp to either queue or start. In either
|
|
case the irp will be marked pending.
|
|
|
|
QueueToExamine - The queue the irp will be place on if there
|
|
is already an operation in progress.
|
|
|
|
CurrentOpIrp - Pointer to a pointer to the irp the is current
|
|
for the queue. The pointer pointed to will be
|
|
set with to Irp if what CurrentOpIrp points to
|
|
is NULL.
|
|
|
|
Starter - The routine to call if the queue is empty.
|
|
|
|
Return Value:
|
|
|
|
This routine will return STATUS_PENDING if the queue is
|
|
not empty. Otherwise, it will return the status returned
|
|
from the starter routine (or cancel, if the cancel bit is
|
|
on in the irp).
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
//
|
|
// If this is a write irp then take the amount of characters
|
|
// to write and add it to the count of characters to write.
|
|
//
|
|
|
|
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
|
|
== IRP_MJ_WRITE) {
|
|
|
|
Extension->TotalCharsQueued +=
|
|
IoGetCurrentIrpStackLocation(Irp)
|
|
->Parameters.Write.Length;
|
|
|
|
} else if ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction
|
|
== IRP_MJ_DEVICE_CONTROL) &&
|
|
((IoGetCurrentIrpStackLocation(Irp)
|
|
->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_IMMEDIATE_CHAR) ||
|
|
(IoGetCurrentIrpStackLocation(Irp)
|
|
->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_XOFF_COUNTER))) {
|
|
|
|
Extension->TotalCharsQueued++;
|
|
|
|
}
|
|
|
|
if ((IsListEmpty(QueueToExamine)) &&
|
|
!(*CurrentOpIrp)) {
|
|
|
|
//
|
|
// There were no current operation. Mark this one as
|
|
// current and start it up.
|
|
//
|
|
|
|
*CurrentOpIrp = Irp;
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return Starter(Extension);
|
|
|
|
} else {
|
|
|
|
//
|
|
// We don't know how long the irp will be in the
|
|
// queue. So we need to handle cancel.
|
|
//
|
|
|
|
if (Irp->Cancel) {
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
|
|
SerialDump(
|
|
SERIRPPATH,
|
|
("SERIAL: Complete Irp: %x\n",Irp)
|
|
);
|
|
IoCompleteRequest(
|
|
Irp,
|
|
0
|
|
);
|
|
|
|
return STATUS_CANCELLED;
|
|
|
|
} else {
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(Irp);
|
|
|
|
InsertTailList(
|
|
QueueToExamine,
|
|
&Irp->Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
Irp,
|
|
SerialCancelQueued
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SerialCancelQueued(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to cancel Irps that currently reside on
|
|
a queue.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
|
|
Irp - Pointer to the IRP to be canceled.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
|
|
|
//
|
|
// If this is a write irp then take the amount of characters
|
|
// to write and subtract it from the count of characters to write.
|
|
//
|
|
|
|
if (irpSp->MajorFunction == IRP_MJ_WRITE) {
|
|
|
|
extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;
|
|
|
|
} else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
|
|
|
|
//
|
|
// If it's an immediate then we need to decrement the
|
|
// count of chars queued. If it's a resize then we
|
|
// need to deallocate the pool that we're passing on
|
|
// to the "resizing" routine.
|
|
//
|
|
|
|
if ((irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_IMMEDIATE_CHAR) ||
|
|
(irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_XOFF_COUNTER)) {
|
|
|
|
extension->TotalCharsQueued--;
|
|
|
|
} else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_SET_QUEUE_SIZE) {
|
|
|
|
//
|
|
// We shoved the pointer to the memory into the
|
|
// the type 3 buffer pointer which we KNOW we
|
|
// never use.
|
|
//
|
|
|
|
ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
|
|
|
|
ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
|
|
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
SerialDump(
|
|
SERIRPPATH,
|
|
("SERIAL: Complete Irp: %x\n",Irp)
|
|
);
|
|
IoCompleteRequest(
|
|
Irp,
|
|
IO_SERIAL_INCREMENT
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
SerialCompleteIfError(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
|
|
there is an error and the application requested abort on errors,
|
|
then cancel the irp.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
|
|
Irp - Pointer to the IRP to test.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or STATUS_CANCELLED.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
if ((extension->HandFlow.ControlHandShake &
|
|
SERIAL_ERROR_ABORT) && extension->ErrorWord) {
|
|
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// There is a current error in the driver. No requests should
|
|
// come through except for the GET_COMMSTATUS.
|
|
//
|
|
|
|
if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
|
|
(irpSp->Parameters.DeviceIoControl.IoControlCode !=
|
|
IOCTL_SERIAL_GET_COMMSTATUS)) {
|
|
|
|
status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
SerialDump(
|
|
SERIRPPATH,
|
|
("SERIAL: Complete Irp: %x\n",Irp)
|
|
);
|
|
IoCompleteRequest(
|
|
Irp,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|