📄 isorwr.c
字号:
/*++
Copyright (c) 2004 Microsoft Corporation
Module Name:
isorwr.c
Abstract:
This file has dispatch routines for read and write.
Environment:
Kernel mode
Notes:
Copyright (c) 2004 Microsoft Corporation.
All Rights Reserved.
--*/
#include "isousb.h"
#include "isopnp.h"
#include "isopwr.h"
#include "isodev.h"
#include "isowmi.h"
#include "isousr.h"
#include "isorwr.h"
#include "isostrm.h"
NTSTATUS
IsoUsb_DispatchReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine does some validation and
invokes appropriate function to perform
Isoch transfer
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Return Value:
NT status value
--*/
{
ULONG totalLength;
ULONG packetSize;
NTSTATUS ntStatus;
PFILE_OBJECT fileObject;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
PFILE_OBJECT_CONTENT fileObjectContent;
PUSBD_PIPE_INFORMATION pipeInformation;
//
// initialize vars
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
totalLength = 0;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite - begins\n"));
IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
IsoUsb_IoIncrement(deviceExtension);
if(deviceExtension->DeviceState != Working) {
IsoUsb_DbgPrint(1, ("Invalid device state\n"));
ntStatus = STATUS_INVALID_DEVICE_STATE;
goto IsoUsb_DispatchReadWrite_Exit;
}
//
// make sure that the selective suspend request has been completed.
//
if(deviceExtension->SSEnable) {
//
// It is true that the client driver cancelled the selective suspend
// request in the dispatch routine for create Irps.
// But there is no guarantee that it has indeed completed.
// so wait on the NoIdleReqPendEvent and proceed only if this event
// is signalled.
//
IsoUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
//
// obtain the pipe information for read
// and write from the fileobject.
//
if(fileObject && fileObject->FsContext) {
fileObjectContent = (PFILE_OBJECT_CONTENT) fileObject->FsContext;
pipeInformation = (PUSBD_PIPE_INFORMATION)
fileObjectContent->PipeInformation;
}
else {
IsoUsb_DbgPrint(1, ("Invalid device state\n"));
ntStatus = STATUS_INVALID_DEVICE_STATE;
goto IsoUsb_DispatchReadWrite_Exit;
}
if((pipeInformation == NULL) ||
(UsbdPipeTypeIsochronous != pipeInformation->PipeType)) {
IsoUsb_DbgPrint(1, ("Incorrect pipe\n"));
ntStatus = STATUS_INVALID_DEVICE_STATE;
goto IsoUsb_DispatchReadWrite_Exit;
}
if(Irp->MdlAddress) {
totalLength = MmGetMdlByteCount(Irp->MdlAddress);
}
if(totalLength == 0) {
IsoUsb_DbgPrint(1, ("Transfer data length = 0\n"));
ntStatus = STATUS_SUCCESS;
goto IsoUsb_DispatchReadWrite_Exit;
}
//
// each packet can hold this much info
//
packetSize = pipeInformation->MaximumPacketSize;
if(packetSize == 0) {
IsoUsb_DbgPrint(1, ("Invalid parameter\n"));
ntStatus = STATUS_INVALID_PARAMETER;
goto IsoUsb_DispatchReadWrite_Exit;
}
//
// atleast packet worth of data to be transferred.
//
if(totalLength < packetSize) {
IsoUsb_DbgPrint(1, ("Atleast packet worth of data..\n"));
ntStatus = STATUS_INVALID_PARAMETER;
goto IsoUsb_DispatchReadWrite_Exit;
}
// perform reset. if there are some active transfers queued up
// for this endpoint then the reset pipe will fail.
//
IsoUsb_AbortResetPipe(DeviceObject,
pipeInformation->PipeHandle,
TRUE);
if(deviceExtension->IsDeviceHighSpeed) {
ntStatus = PerformHighSpeedIsochTransfer(DeviceObject,
pipeInformation,
Irp,
totalLength);
}
else {
ntStatus = PerformFullSpeedIsochTransfer(DeviceObject,
pipeInformation,
Irp,
totalLength);
}
return ntStatus;
IsoUsb_DispatchReadWrite_Exit:
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
IsoUsb_IoDecrement(deviceExtension);
IsoUsb_DbgPrint(3, ("-------------------------------\n"));
return ntStatus;
}
NTSTATUS
PerformFullSpeedIsochTransfer(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION PipeInformation,
IN PIRP Irp,
IN ULONG TotalLength
)
/*++
Routine Description:
This routine splits up a main isoch transfer request into one or
more sub requests as necessary. Each isoch irp/urb pair can span at
most 255 packets.
1. It creates a SUB_REQUEST_CONTEXT for each irp/urb pair and
attaches it to the main request irp.
2. It intializes all of the sub request irp/urb pairs, and sub mdls
too.
3. It passes down the driver stack all of the sub request irps.
4. It leaves the completion of the main request irp as the
responsibility of the sub request irp completion routine, except
in the exception case where the main request irp is canceled
prior to passing any of the the sub request irps down the driver
stack.
Arguments:
DeviceObject - pointer to device object
PipeInformation - USBD_PIPE_INFORMATION
Irp - I/O request packet
TotalLength - no. of bytes to be transferred
Return Value:
NT status value
--*/
{
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
BOOLEAN read;
ULONG packetSize;
ULONG stageSize;
ULONG numIrps;
PMAIN_REQUEST_CONTEXT mainRequestContext;
PSUB_REQUEST_CONTEXT * subRequestContextArray;
PSUB_REQUEST_CONTEXT subRequestContext;
PLIST_ENTRY subRequestEntry;
CCHAR stackSize;
PUCHAR virtualAddress;
ULONG i;
ULONG j;
KIRQL oldIrql;
NTSTATUS ntStatus;
PIO_STACK_LOCATION nextStack;
//
// initialize vars
//
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer - begins\n"));
//
// each packet (frame) can hold this much info
//
packetSize = PipeInformation->MaximumPacketSize;
IsoUsb_DbgPrint(3, ("totalLength = %d\n", TotalLength));
IsoUsb_DbgPrint(3, ("packetSize = %d\n", packetSize));
//
// There is an inherent limit on the number of packets that can be
// passed down the stack with each irp/urb pair (255)
//
// If the number of required packets is > 255, we shall create
// "(required-packets / 255) [+ 1]" number of irp/urb pairs.
//
// Each irp/urb pair transfer is also called a stage transfer.
//
if (TotalLength > (packetSize * 255))
{
stageSize = packetSize * 255;
numIrps = (TotalLength + stageSize - 1) / stageSize;
}
else
{
stageSize = TotalLength;
numIrps = 1;
}
IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::stageSize = %d\n",
stageSize));
IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::numIrps = %d\n",
numIrps));
// Initialize the main request Irp read/write context, which is
// overlaid on top of Irp->Tail.Overlay.DriverContext.
//
mainRequestContext = (PMAIN_REQUEST_CONTEXT)
Irp->Tail.Overlay.DriverContext;
InitializeListHead(&mainRequestContext->SubRequestList);
stackSize = deviceExtension->TopOfStackDeviceObject->StackSize;
virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
// Allocate an array to keep track of the sub requests that will be
// allocated below. This array exists only during the execution of
// this routine and is used only to keep track of the sub requests
// before calling them down the driver stack.
//
subRequestContextArray = (PSUB_REQUEST_CONTEXT *)
ExAllocatePool(NonPagedPool,
numIrps * sizeof(PSUB_REQUEST_CONTEXT));
if (subRequestContextArray == NULL)
{
IsoUsb_DbgPrint(1, ("failed to allocate subRequestContextArray\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformFullSpeedIsochTransfer_Free;
}
RtlZeroMemory(subRequestContextArray, numIrps * sizeof(PSUB_REQUEST_CONTEXT));
//
// Allocate the sub requests
//
for (i = 0; i < numIrps; i++)
{
PIRP subIrp;
PURB subUrb;
PMDL subMdl;
ULONG nPackets;
ULONG urbSize;
ULONG offset;
// The following outer scope variables are updated during each
// iteration of the loop: virtualAddress, TotalLength, stageSize
//
// For every stage of transfer we need to do the following
// tasks:
//
// 1. Allocate a sub request context (SUB_REQUEST_CONTEXT).
// 2. Allocate a sub request irp.
// 3. Allocate a sub request urb.
// 4. Allocate a sub request mdl.
// 5. Initialize the above allocations.
//
//
// 1. Allocate a Sub Request Context (SUB_REQUEST_CONTEXT)
//
subRequestContext = (PSUB_REQUEST_CONTEXT)
ExAllocatePool(NonPagedPool,
sizeof(SUB_REQUEST_CONTEXT));
if (subRequestContext == NULL)
{
IsoUsb_DbgPrint(1, ("failed to allocate subRequestContext\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformFullSpeedIsochTransfer_Free;
}
RtlZeroMemory(subRequestContext, sizeof(SUB_REQUEST_CONTEXT));
// Attach it to the main request irp.
//
InsertTailList(&mainRequestContext->SubRequestList,
&subRequestContext->ListEntry);
// Remember it independently so we can refer to it later without
// walking the sub request list.
//
subRequestContextArray[i] = subRequestContext;
subRequestContext->MainIrp = Irp;
// The reference count on the sub request prevents it from being
// freed until the completion routine for the sub request
// executes.
//
subRequestContext->ReferenceCount = 1;
//
// 2. Allocate a sub request irp
//
subIrp = IoAllocateIrp(stackSize, FALSE);
if (subIrp == NULL)
{
IsoUsb_DbgPrint(1, ("failed to allocate subIrp\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformFullSpeedIsochTransfer_Free;
}
subRequestContext->SubIrp = subIrp;
//
// 3. Allocate a sub request urb.
//
nPackets = (stageSize + packetSize - 1) / packetSize;
IsoUsb_DbgPrint(3, ("nPackets = %d for Irp/URB pair %d\n", nPackets, i));
ASSERT(nPackets <= 255);
urbSize = GET_ISO_URB_SIZE(nPackets);
subUrb = (PURB)ExAllocatePool(NonPagedPool, urbSize);
if (subUrb == NULL)
{
IsoUsb_DbgPrint(1, ("failed to allocate subUrb\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformFullSpeedIsochTransfer_Free;
}
subRequestContext->SubUrb = subUrb;
//
// 4. Allocate a sub request mdl.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -