📄 usbfx2lk_io.cpp
字号:
//
///////////////////////////////////////////////////////////////////////////////
VOID IssueUsbReadRequest(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,("IssueUsbReadRequest: 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,
UsbFx2LkReadCompletionRoutine,
pFx2Context,
TRUE,
TRUE,
TRUE);
//
// Send the request to the USB Driver.
//
IoCallDriver(pFx2Context->DevExt->DeviceToSendIrpsTo,
pFx2Context->Irp);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("IssueUsbReadRequest: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkWrite
//
// This routine is called by the IO Manager to process a IRP_MJ_WRITE
// Irp.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Irp - The Irp to process.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// STATUS_PENDING, or an ERROR.
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User Context
//
// NOTES:
//
// WRITE requests are always serviced by the bulk out pipe
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkWrite(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
KIRQL oldIrql;
PUSBFX2LK_IO_CONTEXT pFx2Context = NULL;
NTSTATUS status;
PMDL pMdl = NULL;
ULONG totalLength = 0;
ULONG urbFlags = 0;
PUCHAR virtualAddress = 0;
ULONG stageLength = 0;
PURB urb = NULL;
PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
//
// We should never be here and not at PASSIVE_LEVEL
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Major issue is we haven't setup our bulk output pipe yet
//
ASSERT(devExt->BulkOutPipe);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE, ("UsbFx2LkWrite Entered...\n"));
//
// Increment the number of outstanding IOs queued to the device.
//
OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// See what sort of state we're in.
//
KeAcquireSpinLock(&devExt->IoStateLock,&oldIrql);
if (devExt->DevicePnPState < STATE_ALL_BELOW_FAIL) {
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkWrite: Failing request due to Pnp State! Current PnP state - %s\n",
OsrPrintState(devExt)));
status = STATUS_INVALID_DEVICE_STATE;
goto UsbFx2LkWrite_Exit;
}
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
//
//
// We do not support zero length operations in this driver
//
if(!ioStack->Parameters.Write.Length || !Irp->MdlAddress) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkWrite: Invalid Parameters to Write \n"));
status = STATUS_INVALID_PARAMETER;
goto UsbFx2LkWrite_Exit;
}
//
// Get the total length of the transfer we are asked to perform.
//
totalLength = ioStack->Parameters.Write.Length;
//
// See if the transfer length is greater than the maximum packet
// size of the pipe * the amount of buffering that the firmware
// provides. If the transfer is too large, we will reject it here
// without further processing
//
if(totalLength >
(ULONG)(devExt->BulkOutPipe->PipeInformation.MaximumPacketSize * \
USBFX2LK_BULK_TRANSFER_FW_BUFFERING)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkWrite: Length exceeds %d\n",
devExt->BulkOutPipe->PipeInformation.MaximumPacketSize * USBFX2LK_BULK_TRANSFER_FW_BUFFERING));
status = STATUS_INVALID_PARAMETER;
goto UsbFx2LkWrite_Exit;
}
//
// Allocate a USBFX2 I/O context. This is a driver specific
// structure that we'll use to contain all the necessary
// information about this particular request while we
// own that request
//
pFx2Context = (PUSBFX2LK_IO_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,sizeof(USBFX2LK_IO_CONTEXT),'ciuO');
if(pFx2Context == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to allocate IO Context\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto UsbFx2LkWrite_Exit;
}
//
// Get the user's base virtual address from the MDL. This
// will be used as a cookie to indicate what area of the
// user's data buffer we are currently copying data into
//
virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
//
// the transfer request is for totalLength. We can perform a maximum of
// the BulkOut pipe's PipeInformation.MaximumPacketSize in each stage.
//
pFx2Context->MaxmimumStageSize = devExt->BulkInPipe->PipeInformation.MaximumPacketSize;
if(totalLength > pFx2Context->MaxmimumStageSize) {
//
// Total length is bigger that we can send, so we will break up
// the transfer into smaller pieces.
//
stageLength = pFx2Context->MaxmimumStageSize;
} else {
//
// We can send this packet in one transfer.
//
stageLength = totalLength;
}
//
// We asked the I/O manager to supply reads and writes from user
// mode components in the form of MDLs by setting the DO_DIRECT_IO
// bit in our device object during AddDevice. This will result in
// the I/O manager sending our driver MDLs that describe the entire
// length of the user's buffer for the entire operation.
//
// However, we may need to split this single user transfer up
// into multiple "stages" so that we don't send our device
// I/O operations that exceed the maximum supported single
// transfer size. To do this, we will build what are called
// "partial MDLs" that describe only the portion of the user's
// data buffer that we will be transferring at each individual
// stage.
//
// The first step in building partial MDLs will be allocating
// a new MDL that is large enough to describe the passed in MDL.
//
pMdl = IoAllocateMdl((PVOID)virtualAddress,
totalLength,
FALSE,
FALSE,
NULL);
if(pMdl == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to Allocate Mdl\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(pFx2Context);
goto UsbFx2LkWrite_Exit;
}
//
// Now, build a partial MDL out of the newly allocated
// MDL. This will map the first stageLength bytes of
// the MDL in the IRP into the newly allocated MDL
//
IoBuildPartialMdl(Irp->MdlAddress,
pMdl,
(PVOID)virtualAddress,
stageLength);
//
// Allocate an URB to be used for the transfer.
//
urb = (PURB) ExAllocatePoolWithTag(NonPagedPool,sizeof(URB),'bruO');
if(urb == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to allocate URB\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(pFx2Context);
IoFreeMdl(pMdl);
goto UsbFx2LkWrite_Exit;
}
//
// Build the Transfer URB.
//
//
// Indicate that this is a write function and that we will allow short
// transfers of data.
//
urbFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT;
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
devExt->BulkOutPipe->PipeInformation.PipeHandle,
NULL,
pMdl,
stageLength,
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,("UsbFx2LkWrite: Failed IoAllocateWorkItem\n"));
ExFreePool(pFx2Context);
IoFreeMdl(pMdl);
ExFreePool(urb);
goto UsbFx2LkWrite_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)UsbFx2LkWriteCompletionRoutine,
pFx2Context,
TRUE,
TRUE,
TRUE);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkWrite: Queuing Write 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -