📄 isorwr.c
字号:
the cancel routine will free all the resources.
we do free the urb and mdl.
it is expected of the cancellation routine to free
all the irps, free the subcontext and the context
and complete the main irp
Case 3 is executed in Block 1b.
Case 4:
when we complete the last of the subsidiary irp,
we check if the cancel routine for the main Irp
has run. If yes, we atomically decrement the
rwContext->Lock field. (the completion routine
is in race with Cancel routine). If the count is 0,
we free the irp, subcontext and the context and
complete the main irp. we also free the urb and
the mdl for this particular stage.
the reason we do not free the subsidiary irp at its
completion is because the cancellation routine can
run any time.
Case 4 is executed in Block 1a.
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Context - context for the completion routine
Return Value:
NT status value
--*/
{
PURB urb;
PMDL mdl;
PIRP mainIrp;
KIRQL oldIrql;
ULONG info;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PISOUSB_RW_CONTEXT rwContext;
PIO_STACK_LOCATION irpStack;
irpStack = IoGetCurrentIrpStackLocation(Irp);
urb = (PURB) irpStack->Parameters.Others.Argument1;
mdl = (PMDL) irpStack->Parameters.Others.Argument2;
info = 0;
ntStatus = Irp->IoStatus.Status;
rwContext = (PISOUSB_RW_CONTEXT) Context;
deviceExtension = rwContext->DeviceExtension;
IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - begins\n"));
ASSERT(rwContext);
KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
if(NT_SUCCESS(ntStatus) &&
USBD_SUCCESS(urb->UrbHeader.Status)) {
rwContext->NumXfer +=
urb->UrbIsochronousTransfer.TransferBufferLength;
IsoUsb_DbgPrint(1, ("rwContext->NumXfer = %d\n", rwContext->NumXfer));
}
else {
ULONG i;
IsoUsb_DbgPrint(1, ("read-write irp failed with status %X\n", ntStatus));
IsoUsb_DbgPrint(1, ("urb header status %X\n", urb->UrbHeader.Status));
for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
IsoUsb_DbgPrint(2, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %X\n",
i,
urb->UrbIsochronousTransfer.IsoPacket[i].Length,
i,
urb->UrbIsochronousTransfer.IsoPacket[i].Status));
}
}
if(InterlockedDecrement(&rwContext->IrpsPending) == 0) {
IsoUsb_DbgPrint(3, ("no more irps pending\n"));
if(NT_SUCCESS(ntStatus)) {
ULONG i;
IsoUsb_DbgPrint(1, ("urb start frame %X\n",
urb->UrbIsochronousTransfer.StartFrame));
for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
if(urb->UrbIsochronousTransfer.IsoPacket[i].Length == 0) {
IsoUsb_DbgPrint(2, ("IsoPacket[%d].Status = %X\n",
i,
urb->UrbIsochronousTransfer.IsoPacket[i].Status));
}
}
}
mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
ASSERT(mainIrp);
if(IoSetCancelRoutine(mainIrp, NULL) == NULL) {
//
// cancel routine has begun the race
//
// Block 1a.
//
IsoUsb_DbgPrint(3, ("cancel routine has begun the race\n"));
if(InterlockedDecrement(&rwContext->Lock) == 0) {
ULONG i;
//
// do the cleanup job ourselves
//
IsoUsb_DbgPrint(3, ("losers do the cleanup\n"));
for(i = 0; i < rwContext->NumIrps; i++) {
IoFreeIrp(rwContext->SubContext[i].SubIrp);
rwContext->SubContext[i].SubIrp = NULL;
}
info = rwContext->NumXfer;
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
ExFreePool(rwContext->SubContext);
ExFreePool(rwContext);
//
// if we transferred some data, main Irp completes with success
//
IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
IsoUsb_DbgPrint(1, ("***\n"));
mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
mainIrp->IoStatus.Information = info;
IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("-------------------------------\n"));
goto IsoUsb_SinglePairComplete_Exit;
}
else {
//
// Block 1b.
//
IsoUsb_DbgPrint(3, ("cancel routine performs the cleanup\n"));
}
}
else {
//
// Block 2.
//
ULONG i;
IsoUsb_DbgPrint(3, ("cancel routine has NOT run\n"));
for(i = 0; i < rwContext->NumIrps; i++) {
IoFreeIrp(rwContext->SubContext[i].SubIrp);
rwContext->SubContext[i].SubIrp = NULL;
}
info = rwContext->NumXfer;
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
ExFreePool(rwContext->SubContext);
ExFreePool(rwContext);
//
// if we transferred some data, main Irp completes with success
//
IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
IsoUsb_DbgPrint(1, ("***\n"));
mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
mainIrp->IoStatus.Information = info;
IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("-------------------------------\n"));
goto IsoUsb_SinglePairComplete_Exit;
}
}
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
IsoUsb_SinglePairComplete_Exit:
//
// Block 3.
//
ExFreePool(urb);
IoFreeMdl(mdl);
IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - ends\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
IsoUsb_CancelReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the cancellation routine for the main read/write Irp.
The policy is as follows:
If the cancellation routine is the last to decrement
rwContext->Lock, then free the irps, subcontext and
the context. Complete the main irp
Otherwise, call IoCancelIrp on each of the subsidiary irp.
It is valid to call IoCancelIrp on irps for which the
completion routine has executed, because, we do not free the
irps in the completion routine.
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Return Value:
None
--*/
{
PIRP mainIrp;
KIRQL oldIrql;
ULONG i;
ULONG info;
PDEVICE_EXTENSION deviceExtension;
PISOUSB_RW_CONTEXT rwContext;
//
// initialize vars
//
info = 0;
IoReleaseCancelSpinLock(Irp->CancelIrql);
IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - begins\n"));
rwContext = (PISOUSB_RW_CONTEXT) Irp->Tail.Overlay.DriverContext[0];
ASSERT(rwContext);
deviceExtension = rwContext->DeviceExtension;
KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
if(InterlockedDecrement(&rwContext->Lock)) {
IsoUsb_DbgPrint(3, ("about to cancel sub context irps..\n"));
for(i = 0; i < rwContext->NumIrps; i++) {
if(rwContext->SubContext[i].SubIrp) {
IoCancelIrp(rwContext->SubContext[i].SubIrp);
}
}
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - ends\n"));
return;
}
else {
ULONG i;
for(i = 0; i < rwContext->NumIrps; i++) {
IoFreeIrp(rwContext->SubContext[i].SubIrp);
rwContext->SubContext[i].SubIrp = NULL;
}
mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
info = rwContext->NumXfer;
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
ExFreePool(rwContext->SubContext);
ExFreePool(rwContext);
//
// if we transferred some data, main Irp completes with success
//
IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
IsoUsb_DbgPrint(1, ("***\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Status = info;
/*
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
*/
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("-------------------------------\n"));
return;
}
}
ULONG
IsoUsb_GetCurrentFrame(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine send an irp/urb pair with
function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
to fetch the current frame
Arguments:
DeviceObject - pointer to device object
PIRP - I/O request packet
Return Value:
Current frame
--*/
{
KEVENT event;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION nextStack;
struct _URB_GET_CURRENT_FRAME_NUMBER urb;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//
// initialize the urb
//
IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - begins\n"));
urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
urb.Hdr.Length = sizeof(urb);
urb.FrameNumber = (ULONG) -1;
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
KeInitializeEvent(&event,
NotificationEvent,
FALSE);
IoSetCompletionRoutine(Irp,
IsoUsb_StopCompletion,
&event,
TRUE,
TRUE,
TRUE);
IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
IsoUsb_IoIncrement(deviceExtension);
IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
KeWaitForSingleObject((PVOID) &event,
Executive,
KernelMode,
FALSE,
NULL);
IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - ends\n"));
return urb.FrameNumber;
}
NTSTATUS
IsoUsb_StopCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This is the completion routine for request to retrieve the frame number
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Context - context passed to the completion routine
Return Value:
NT status value
--*/
{
PKEVENT event;
IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - begins\n"));
event = (PKEVENT) Context;
KeSetEvent(event, IO_NO_INCREMENT, FALSE);
IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - ends\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -