📄 isorwr.c
字号:
packetSize = PipeInformation->MaximumPacketSize;
numberOfPackets = (TotalLength + packetSize - 1) / packetSize;
if (0 == (numberOfPackets % 8))
{
actualPackets = numberOfPackets;
}
else
{
//
// we need multiple of 8 packets only.
//
actualPackets = numberOfPackets +
(8 - (numberOfPackets % 8));
}
minDataInEachPacket = TotalLength / actualPackets;
if (minDataInEachPacket == packetSize)
{
numberOfPacketsFilledToBrim = actualPackets;
dataLeftToBeDistributed = 0;
IsoUsb_DbgPrint(1, ("TotalLength = %d\n", TotalLength));
IsoUsb_DbgPrint(1, ("PacketSize = %d\n", packetSize));
IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
numberOfPacketsFilledToBrim,
packetSize));
}
else
{
dataLeftToBeDistributed = TotalLength -
(minDataInEachPacket * actualPackets);
numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
(packetSize - minDataInEachPacket);
dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
(packetSize - minDataInEachPacket));
IsoUsb_DbgPrint(1, ("TotalLength = %d\n", TotalLength));
IsoUsb_DbgPrint(1, ("PacketSize = %d\n", packetSize));
IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
numberOfPacketsFilledToBrim,
packetSize));
if (dataLeftToBeDistributed)
{
IsoUsb_DbgPrint(1, ("One packet has %d bytes\n",
minDataInEachPacket + dataLeftToBeDistributed));
IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
actualPackets - (numberOfPacketsFilledToBrim + 1),
minDataInEachPacket));
}
else
{
IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
actualPackets - numberOfPacketsFilledToBrim,
minDataInEachPacket));
}
}
//
// determine how many stages of transfer needs to be done.
// in other words, how many irp/urb pairs required.
// this irp/urb pair is also called the subsidiary irp/urb pair
//
numIrps = (actualPackets + 1023) / 1024;
IsoUsb_DbgPrint(1, ("PeformHighSpeedIsochTransfer::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 PerformHighSpeedIsochTransfer_Free;
}
RtlZeroMemory(subRequestContextArray, numIrps * sizeof(PSUB_REQUEST_CONTEXT));
for (i = 0; i < numIrps; i++)
{
PIRP subIrp;
PURB subUrb;
PMDL subMdl;
ULONG nPackets;
ULONG urbSize;
ULONG stageSize;
ULONG offset;
// The following outer scope variables are updated during each
// iteration of the loop: virtualAddress, TotalLength,
// actualPackets, numberOfPacketsFilledToBrim,
// dataLeftToBeDistributed
//
// 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 PerformHighSpeedIsochTransfer_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 PerformHighSpeedIsochTransfer_Free;
}
subRequestContext->SubIrp = subIrp;
//
// 3. Allocate a sub request urb.
//
if (actualPackets <= 1024)
{
nPackets = actualPackets;
actualPackets = 0;
}
else
{
nPackets = 1024;
actualPackets -= 1024;
}
IsoUsb_DbgPrint(1, ("nPackets = %d for Irp/URB pair %d\n", nPackets, i));
ASSERT(nPackets <= 1024);
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 PerformHighSpeedIsochTransfer_Free;
}
subRequestContext->SubUrb = subUrb;
//
// 4. Compute stageSize and allocate a sub request mdl.
//
if (nPackets > numberOfPacketsFilledToBrim)
{
stageSize = packetSize * numberOfPacketsFilledToBrim;
stageSize += (minDataInEachPacket *
(nPackets - numberOfPacketsFilledToBrim));
stageSize += dataLeftToBeDistributed;
}
else
{
stageSize = packetSize * nPackets;
}
subMdl = IoAllocateMdl((PVOID) virtualAddress,
stageSize,
FALSE,
FALSE,
NULL);
if (subMdl == NULL)
{
IsoUsb_DbgPrint(1, ("failed to allocate subMdl\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformHighSpeedIsochTransfer_Free;
}
subRequestContext->SubMdl = subMdl;
IoBuildPartialMdl(Irp->MdlAddress,
subMdl,
(PVOID) virtualAddress,
stageSize);
// Update loop variables for next iteration.
//
virtualAddress += stageSize;
TotalLength -= stageSize;
//
// Initialize the sub request urb.
//
RtlZeroMemory(subUrb, urbSize);
subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT)urbSize;
subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
if (read)
{
IsoUsb_DbgPrint(1, ("read\n"));
subUrb->UrbIsochronousTransfer.TransferFlags =
USBD_TRANSFER_DIRECTION_IN;
}
else
{
IsoUsb_DbgPrint(1, ("write\n"));
subUrb->UrbIsochronousTransfer.TransferFlags =
USBD_TRANSFER_DIRECTION_OUT;
}
subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
/*
This is a way to set the start frame and NOT specify ASAP flag.
subUrb->UrbIsochronousTransfer.StartFrame =
IsoUsb_GetCurrentFrame(DeviceObject, Irp) +
SOME_LATENCY;
*/
subUrb->UrbIsochronousTransfer.TransferFlags |=
USBD_START_ISO_TRANSFER_ASAP;
subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
//
// set the offsets for every packet for reads/writes
//
if (read)
{
offset = 0;
for (j = 0; j < nPackets; j++)
{
subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
if (numberOfPacketsFilledToBrim)
{
offset += packetSize;
numberOfPacketsFilledToBrim--;
stageSize -= packetSize;
}
else if (dataLeftToBeDistributed)
{
offset += (minDataInEachPacket + dataLeftToBeDistributed);
stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
dataLeftToBeDistributed = 0;
}
else
{
offset += minDataInEachPacket;
stageSize -= minDataInEachPacket;
}
}
ASSERT(stageSize == 0);
}
else
{
offset = 0;
for (j = 0; j < nPackets; j++)
{
subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
if (numberOfPacketsFilledToBrim)
{
subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
offset += packetSize;
numberOfPacketsFilledToBrim--;
stageSize -= packetSize;
}
else if (dataLeftToBeDistributed)
{
subUrb->UrbIsochronousTransfer.IsoPacket[j].Length =
minDataInEachPacket + dataLeftToBeDistributed;
offset += (minDataInEachPacket + dataLeftToBeDistributed);
stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
dataLeftToBeDistributed = 0;
}
else
{
subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = minDataInEachPacket;
offset += minDataInEachPacket;
stageSize -= minDataInEachPacket;
}
}
ASSERT(stageSize == 0);
}
// Initialize the sub irp stack location
//
nextStack = IoGetNextIrpStackLocation(subIrp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(subIrp,
(PIO_COMPLETION_ROUTINE)IsoUsb_SubRequestComplete,
(PVOID)subRequestContext,
TRUE,
TRUE,
TRUE);
}
//
// While we were busy create subsidiary irp/urb pairs..
// the main read/write irp may have been cancelled !!
//
if (!Irp->Cancel)
{
//
// normal processing
//
IsoUsb_DbgPrint(3, ("normal processing\n"));
IoMarkIrpPending(Irp);
// The cancel routine might run simultaneously as soon as it is
// set. Do not access the main request Irp in any way after
// setting the cancel routine.
//
// Note that it is still safe to access the sub requests up to
// the point where each sub request is called down the driver
// stack due to the sub request reference count which must be
// decremented by the completion routine. Do not access a sub
// request in any way after it is called down the driver stack.
//
// After setting the main request Irp cancel routine we are
// committed to calling each of the sub requests down the
// driver stack.
//
IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
for (i = 0; i < numIrps; i++)
{
subRequestContext = subRequestContextArray[i];
IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
// Increment the device object reference before this sub
// request is called down the driver stack. The reference
// will be decremented in either the sub request completion
// routine or in the main request cancel routine, at the
// time when the sub request is freed.
//
IsoUsb_IoIncrement(deviceExtension);
IoCallDriver(deviceExtension->TopOfStackDeviceObject,
subRequestContext->SubIrp);
}
// The sub requests are freed in either the sub request
// completion routine or in the main request Irp cancel routine.
//
// Main request Irp is completed only in sub request completion
// routine.
ExFreePool(subRequestContextArray);
return STATUS_PENDING;
}
else
{
//
// The Cancel flag for the Irp has been set.
//
IsoUsb_DbgPrint(3, ("Cancel flag set\n"));
ntStatus = STATUS_CANCELLED;
}
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -