📄 usbfx2lk_io.cpp
字号:
return STATUS_PENDING;
UsbFx2LkWrite_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;
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkWriteCompletionRoutine
//
// This routine is called by the IO Manager when a USB Write 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 UsbFx2LkWriteCompletionRoutine(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,("UsbFx2LkWriteCompletionRoutine: Entered.\n"));
//
// There's no reason why this pointer
// shouldn't be valid
//
ASSERT(pFx2Context);
//
// See if we 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,
("UsbFx2LkWriteCompletionRoutine: 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 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,IssueUsbWriteRequest,CriticalWorkQueue,pFx2Context);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkWriteCompletionRoutine: 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.TotalBulkBytesWritten += pFx2Context->Numxfer ;
pFx2Context->DevExt->WmiStatistics.TotalBulkWriteIrpCount++;
//
// Indicate number of bytes transfered.
//
Irp->IoStatus.Information = pFx2Context->Numxfer;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: Write Complete.\n"));
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: failed status = %08.8x %s\n", status,OsrNtStatusToString(status)));
}
//
// dump Fx2Context
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: pFx2Context->Urb = %p\n",
pFx2Context->Urb));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: pFx2Context->Mdl = %p\n",
pFx2Context->Mdl));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: pFx2Context->RemainingLength = %d\n",
pFx2Context->RemainingLength));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: pFx2Context->Numxfer = %d\n",
pFx2Context->Numxfer));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: pFx2Context->VirtualAddress = %p\n",
pFx2Context->VirtualAddress));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
("UsbFx2LkWriteCompletionRoutine: 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,("UsbFx2LkWriteCompletionRoutine: Exit.\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// IssueUsbWriteRequest
//
// This routine is called in response to our UsbFx2LkWriteCompletionRoutine
// queuing the Work Item to do the next stage of the write request.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Context - our pFx2Context
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// System Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID IssueUsbWriteRequest(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context)
{
PUSBFX2LK_IO_CONTEXT pFx2Context = (PUSBFX2LK_IO_CONTEXT) Context;
PIO_STACK_LOCATION nextStack;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("IssueUsbWriteRequest: Entered.\n"));
//
// Prepare the next stack location so that we can resubmit the irp
// to do the next part of the transfer. Note that this step is
// required because the I/O manager zeroes the lower stack
// locations as part of completion processing.
//
nextStack = IoGetNextIrpStackLocation(pFx2Context->Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = pFx2Context->Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
//
// Set our completion routine to be called when this stage of
// the read completes.
//
IoSetCompletionRoutine(pFx2Context->Irp,
UsbFx2LkWriteCompletionRoutine,
pFx2Context,
TRUE,
TRUE,
TRUE);
//
// Send the write request to the Bus Driver.
//
IoCallDriver(pFx2Context->DevExt->DeviceToSendIrpsTo,
pFx2Context->Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("IssueUsbWriteRequest: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrProcessQueuedRequests
//
// This interface checks the current state of the read and write
// queues, and starts requests on the device if either are not
// busy.
//
// INPUTS:
//
// DevExt - Pointer to device extension of device on which to
// start the transfers
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID OsrProcessQueuedRequests(PUSBFX2LK_EXT DevExt)
{
PIRP irp = NULL;
KIRQL oldIrql;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,("OsrProcessQueuedRequests: Entered.\n"));
//
// We should never be here and not at <= DISPATCH_LEVEL
//
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
//
// Try to start up any queued I/O on the
// device.
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("OsrProcessQueuedRequests: PnP State = %s\n",
OsrPrintState(DevExt)));
//
// Are we in a proper PnP/Power state?
//
KeAcquireSpinLock(&DevExt->IoStateLock,&oldIrql);
if (DevExt->DevicePnPState < STATE_ALL_BELOW_DRAIN) {
KeReleaseSpinLock(&DevExt->IoStateLock,oldIrql);
//
// We're good to go. Attempt to remove an
// IRP off of the queue
//
while((irp = IoCsqRemoveNextIrp(&DevExt->CancelSafeIoQueue, NULL))) {
(VOID)IoCallDriver(DevExt->DeviceToSendIrpsTo,irp);
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,("OsrProcessQueuedRequests: Exit. Irps Queued.\n"));
} else {
KeReleaseSpinLock(&DevExt->IoStateLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,("OsrProcessQueuedRequests: Exit. Not Processing Queue.\n"));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -