Justin Frodsham wrote:
As a matter of fact, there is an issue with Hidclass not cleaning up
ping pong Irp’s in surprise removal under win2k. The MS engineer inspected
the source code and verified. Correct me if I am wrong, but I think that
is an error. Does the WDM architecture not require this? It doesn’t
usually matter, because when you pull the plug on a USB device any Irp’s
forwarded there get completed with an error code. That is not my
situation. My hid mini is virtual and the end user chooses whether or not
to expose the Hid interface to our device. The work around would seem to
be creating my own irp relaying the hid irp. I can then manually cancel it
from my surprise removal which is what the Hidclass failed to do. I have
also already mentioned that none of this is needed on XP as the code was
updated to fix this. Hidclass cleans up in surprise remove and all is
good. Unfortunately, I am having to add additional complexity to my driver
to compensate for the oversight and allow 2k compatibility. I am not
holding my breath that MS is going to supply us a hotfix or otherwise.
Okay, then. You *can* cancel an IRP that someone else created, which I
think was the fundamental stumbling block. Here’s an excerpt from that
soon-to-be-a-best-seller, “Programming the Microsoft Windows Driver
Model, Second Edition”:
Canceling Someone Else’s IRP on Which You’re Not Waiting
Suppose you’ve forwarded somebody else’s IRP to another driver, but you
weren’t planning to wait for it to complete. For whatever reason, you
decide later on that you’d like to cancel that IRP.
typedef struct _DEVICE_EXTENSION {
PIRP TheIrp;
ULONG CancelFlag;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS DispatchSomething(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnComplete,
(PVOID) pdx,
TRUE, TRUE, TRUE);
pdx->CancelFlag = 0;
pdx->TheIrp = Irp;
IoMarkIrpPending(Irp);
IoCallDriver(pdx->LowerDeviceObject, Irp);
return STATUS_PENDING;
}
VOID CancelTheIrp(PDEVICE_EXTENSION pdx)
{
PIRP Irp = (PIRP) InterlockedExchangePointer(
(PVOID*) &pdx->TheIrp, NULL);
if (Irp)
{
IoCancelIrp(Irp);
if (InterlockedExchange(&pdx->CancelFlag, 1))
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
NTSTATUS OnComplete(PDEVICE_OBJECT fdo, PIRP Irp,
PDEVICE_EXTENSION pdx)
{
if (InterlockedExchangePointer((PVOID*) &pdx->TheIrp, NULL)
|| InterlockedExchange(&pdx->CancelFlag, 1))
return STATUS_SUCCESS;
return STATUS_MORE_PROCESSING_REQUIRED;
}
This code is similar to the code I showed earlier for cancelling your
own asynchronous IRP. Here, however, allowing IoCompleteRequest to
finish completing the IRP takes the place of the call to IoFreeIrp we
made when we were dealing with our own IRP. If the completion routine is
last on the scene, it returns STATUS_SUCCESS to allow IoCompleteRequest
to finish completing the IRP. If CancelTheIrp is last on the scene, it
calls IoCompleteRequest to resume the completion processing that the
completion routine short-circuited by returning
STATUS_MORE_PROCESSING_REQUIRED.
One extremely subtle point about this example is the call to
IoMarkIrpPending in the dispatch routine. Ordinarily, it would be safe
to just do this step conditionally in the completion routine, but not
this time. If we should happen to call CancelTheIrp in the context of
some thread other than the one in which the dispatch routine runs, the
pending flag is needed so that IoCompleteRequest will schedule an APC to
cleanup the IRP in the proper thread. The easiest way to make that true
is to simply always mark the IRP pending.
–
Walter Oney, Consulting and Training
Basic and Advanced Driver Programming Seminars
Now teaming with John Hyde for USB Device Engineering Seminars
Check out our schedule at http://www.oneysoft.com