📄 usbfx2lk_io.cpp
字号:
urbFlags,
NULL);
//
// Set up our USBFX2 I/O context so that when the URB completes we can
// resume from where we left off.
//
pFx2Context->Urb = urb;
pFx2Context->Irp = Irp;
pFx2Context->Mdl = pMdl;
//
// Indicate how much more data there is to process
//
pFx2Context->RemainingLength = totalLength - stageLength;
pFx2Context->Numxfer = 0;
//
// Update the VirtualAddress pointer. We pass this pointer to
// IoBuildPartialMdl each time we want to map a portion of the
// MDL to indicate the portion of the MDL that we want to map.
// It must be adjusted after each transfer stage.
//
pFx2Context->VirtualAddress = virtualAddress + stageLength;
pFx2Context->DevExt = devExt;
pFx2Context->TotalLength = totalLength;
//
// We will need a workitem in order to resubmit this IRP in
// the case of a multistage transfer.
//
pFx2Context->PWorkItem = IoAllocateWorkItem(devExt->FunctionalDeviceObject);
if(!pFx2Context->PWorkItem) {
status = STATUS_INSUFFICIENT_RESOURCES;
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkRead: Failed IoAllocateWorkItem\n"));
ExFreePool(pFx2Context);
IoFreeMdl(pMdl);
ExFreePool(urb);
goto UsbFx2LkRead_Exit;
}
//
// use the Users Irp as an internal device control irp, which
// is what is used to submit URBs to the host controller
//
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
//
// The USB drivers expect the URB to be in
// Parameters.Others.Argument1
//
nextStack->Parameters.Others.Argument1 = (PVOID) urb;
//
// Setup the I/O control code
//
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
//
// We need a completion routine for this transfer.
//
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)UsbFx2LkReadCompletionRoutine,
pFx2Context,
TRUE,
TRUE,
TRUE);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkRead: Queuing Read Irp\n"));
//
// While we have the Irp in our queue, store the address of the IO Context in our
// DriverContext field of the Irp. We do this so that if the Irp is canceled while
// in our queue, we have enough information to do the correct cleanup.
//
Irp->Tail.Overlay.DriverContext[0] = pFx2Context;
//
// Mark the IRP as being in-progress before queueing it,
// because we're going to be returning STATUS_PENDING
// from this entry point
//
IoMarkIrpPending(Irp);
//
// Queue the using the appropriate cancel safe queue routin
//
#ifdef W2K3
//
// IoCsqInsertIrpEx returns whatever we return from OsrCsqInsertIoIrpEx,
// which for us is STATUS_SUCCESS.
//
status = IoCsqInsertIrpEx(&devExt->CancelSafeIoQueue,Irp,NULL,devExt);
ASSERT(status == STATUS_SUCCESS);
#else // W2K3
IoCsqInsertIrp(&devExt->CancelSafeIoQueue,Irp,NULL);
#endif // W2K3
//
// We have queued this IRP onto our internal queue.
// Now call our helper routine ProcessNextIrpInQueue
// to pass this request (or possibly another request
// that was running parallel and beat us to the queue)
// to the host controller.
//
// ProcessNextIrpInQueue will pass the request on to the
// host if we are in an applicable PnP state otherwise the
// request will just stay in the queue.
//
ProcessNextIrpInQueue(devExt);
return STATUS_PENDING;
UsbFx2LkRead_Exit:
//
// If we're here then we are failing the request.
// Decrement our outstanding I/O count
//
ASSERT(!NT_SUCCESS(status));
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkReadCompletionRoutine
//
// This routine is called by the IO Manager when a USB Read Completes
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Irp - The Irp to process.
// Context -
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// User Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkReadCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
NTSTATUS status = Irp->IoStatus.Status;
PUSBFX2LK_IO_CONTEXT pFx2Context = (PUSBFX2LK_IO_CONTEXT) Context;
ULONG stageLength = 0;
UNREFERENCED_PARAMETER(DeviceObject);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine: Entered.\n"));
//
// There's no reason why this pointer
// shouldn't be valid
//
ASSERT(pFx2Context);
//
// successfully performed a stageLength of transfer.
// check if we need to recirculate the irp.
//
if(NT_SUCCESS(status)) {
//
// The transfer completed successfully, see if we need to continue transfering.
//
//
// Calculate how much data has been recently received.
//
pFx2Context->Numxfer += pFx2Context->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
//
// Determine if there is more to transfer.
//
if(pFx2Context->RemainingLength) {
//
// Set up the next stage of the transfer.
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: Another stage transfer %d of %d\n",
pFx2Context->Numxfer,pFx2Context->TotalLength));
//
// Compare the remaining length to our maximum stage size.
// If it is larger, then this transfer will require at
// least two more sub-transfers
//
if(pFx2Context->RemainingLength > pFx2Context->MaxmimumStageSize) {
stageLength = pFx2Context->MaxmimumStageSize;
} else {
stageLength = pFx2Context->RemainingLength;
}
//
// Prepare the partial MDL to be reused for the next part of the transfer.
// This function unmaps any pages that may have been previously mapped
// by this MDL before reusing it.
//
MmPrepareMdlForReuse(pFx2Context->Mdl);
//
// Setup the partial MDL again, but this time we
// use the updated VirtualAddress pointer from the
// original MDL. This is the cookie that the memory
// manager uses to figure out which portion of the
// MDL needs to be mapped into the partial MDL.
//
IoBuildPartialMdl(Irp->MdlAddress,
pFx2Context->Mdl,
(PVOID)pFx2Context->VirtualAddress,
stageLength);
//
// reinitialize the urb
//
pFx2Context->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;
//
// And update the VirtualAddress and remaining transfer length in the
// FX2 I/O context.
//
pFx2Context->VirtualAddress += stageLength;
pFx2Context->RemainingLength -= stageLength;
//
// We cannot simply resubmit the IRP here with IoCallDriver for two
// reasons:
//
// 1) We may be running at IRQL == DISPATCH_LEVEL and the USB stack
// is not explicitly documented to be called at its dispatch
// entry points at IRQL DISPATCH_LEVEL
//
// 2) If the request is completed in the lower driver's dispatch entry
// point, we will be called back here at our completion routine
// recursively. If we then submit the IRP back down inline, we
// can continue doing this recursion until we finally run out
// stack space
//
// For those two reasons, we will queue a work item (guaranteeing an
// IRQL of PASSIVE_LEVEL and a fresh stack) and resubmit the IRP
// from the work item.
//
IoQueueWorkItem(pFx2Context->PWorkItem,IssueUsbReadRequest,CriticalWorkQueue,pFx2Context);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine: Next Stage.\n"));
//
// We are going to be resubmitting this IRP to the host in our
// work item, so we need to indicate to the I/O manager
// that we are still processing the IRP by returning the
// special STATUS_MORE_PROCESSING_REQUIRED status
//
return STATUS_MORE_PROCESSING_REQUIRED;
} else {
//
// this is the last transfer
//
//
// Update Statistics
//
pFx2Context->DevExt->WmiStatistics.TotalBulkBytesRead += pFx2Context->Numxfer;
pFx2Context->DevExt->WmiStatistics.TotalBulkReadIrpCount++;
//
// Indicate the number of bytes transfered.
//
Irp->IoStatus.Information = pFx2Context->Numxfer;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: Receive Complete.\n"));
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: failed status = %08.8x %s\n", status,OsrNtStatusToString(status)));
}
//
// dump Fx2Context
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->Urb = %p\n",
pFx2Context->Urb));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->Mdl = %p\n",
pFx2Context->Mdl));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->RemainingLength = %d\n",
pFx2Context->RemainingLength));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->Numxfer = %d\n",
pFx2Context->Numxfer));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->VirtualAddress = %p\n",
pFx2Context->VirtualAddress));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkReadCompletionRoutine: pFx2Context->DevExt = %p\n",
pFx2Context->DevExt));
//
// Decrement the outstanding IO count
//
OsrDecrementOutstandingIoCount(pFx2Context->DevExt,__FILE__,__LINE__);
//
// Clean up all of the resources used for this transfer
//
IoFreeWorkItem(pFx2Context->PWorkItem);
ExFreePool(pFx2Context->Urb);
IoFreeMdl(pFx2Context->Mdl);
ExFreePool(pFx2Context);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine: Exit.\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// IssueUsbReadRequest
//
// This routine is called in response to our UsbFx2LkReadCompletionRoutine
// queuing the Work Item to do the next stage of the Read request.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Context - our pFx2Context
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// System Context
//
// NOTES:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -