📄 isorwr.c
字号:
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformHighSpeedIsochTransfer_Exit;
}
RtlZeroMemory(rwContext, contextSize);
//
// allocate memory for every stage context -
// subcontext has state information for every irp/urb pair.
//
rwContext->SubContext = (PSUB_CONTEXT)
ExAllocatePool(NonPagedPool,
numIrps * sizeof(SUB_CONTEXT));
if(rwContext->SubContext == NULL) {
IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContext\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(rwContext);
goto PerformHighSpeedIsochTransfer_Exit;
}
RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
rwContext->RWIrp = Irp;
rwContext->Lock = 2;
rwContext->NumIrps = numIrps;
rwContext->IrpsPending = numIrps;
rwContext->DeviceExtension = deviceExtension;
KeInitializeSpinLock(&rwContext->SpinLock);
//
// save the rwContext pointer in the tail union.
//
Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
for(i = 0; i < numIrps; i++) {
PIRP subIrp;
PURB subUrb;
PMDL subMdl;
ULONG nPackets;
ULONG siz;
ULONG offset;
//
// for every stage of transfer we need to do the following
// tasks
// 1. allocate an irp
// 2. allocate an urb
// 3. allocate a mdl.
//
// create a subsidiary irp
//
subIrp = IoAllocateIrp(stackSize, FALSE);
if(subIrp == NULL) {
IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irp\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformHighSpeedIsochTransfer_Free;
}
rwContext->SubContext[i].SubIrp = subIrp;
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);
siz = GET_ISO_URB_SIZE(nPackets);
//
// create a subsidiary urb.
//
subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
if(subUrb == NULL) {
IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urb\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformHighSpeedIsochTransfer_Free;
}
rwContext->SubContext[i].SubUrb = subUrb;
if(nPackets > numberOfPacketsFilledToBrim) {
stageSize = packetSize * numberOfPacketsFilledToBrim;
stageSize += (minDataInEachPacket *
(nPackets - numberOfPacketsFilledToBrim));
stageSize += dataLeftToBeDistributed;
}
else {
stageSize = packetSize * nPackets;
}
//
// allocate a mdl.
//
subMdl = IoAllocateMdl((PVOID) virtualAddress,
stageSize,
FALSE,
FALSE,
NULL);
if(subMdl == NULL) {
IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdl\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto PerformHighSpeedIsochTransfer_Free;
}
IoBuildPartialMdl(Irp->MdlAddress,
subMdl,
(PVOID) virtualAddress,
stageSize);
rwContext->SubContext[i].SubMdl = subMdl;
virtualAddress += stageSize;
TotalLength -= stageSize;
//
// Initialize the subsidiary urb
//
RtlZeroMemory(subUrb, siz);
subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
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;
subUrb->UrbIsochronousTransfer.UrbLink = NULL;
//
// 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);
}
IoSetNextIrpStackLocation(subIrp);
nextStack = IoGetCurrentIrpStackLocation(subIrp);
nextStack->DeviceObject = DeviceObject;
nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
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_SinglePairComplete,
(PVOID) rwContext,
TRUE,
TRUE,
TRUE);
}
//
// while we were busy create subsidiary irp/urb pairs..
// the main read/write irp may have been cancelled !!
//
KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
if(Irp->Cancel) {
//
// The Cancel flag for the Irp has been set.
//
IsoUsb_DbgPrint(3, ("Cancel flag set\n"));
ntStatus = STATUS_CANCELLED;
if(IoSetCancelRoutine(Irp, NULL)) {
//
// But the I/O manager did not call our cancel routine.
// we need to free the 1) irp, 2) urb and 3) mdl for every
// stage and complete the main Irp after releasing the lock
//
IsoUsb_DbgPrint(3, ("cancellation routine NOT run\n"));
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
goto PerformHighSpeedIsochTransfer_Free;
}
else {
//
// The cancel routine will resume the moment we release the lock.
//
for(j = 0; j < numIrps; j++) {
if(rwContext->SubContext[j].SubUrb) {
ExFreePool(rwContext->SubContext[j].SubUrb);
rwContext->SubContext[j].SubUrb = NULL;
}
if(rwContext->SubContext[j].SubMdl) {
IoFreeMdl(rwContext->SubContext[j].SubMdl);
rwContext->SubContext[j].SubMdl = NULL;
}
}
IoMarkIrpPending(Irp);
//
// it is the job of the cancellation routine to free
// sub-context irps, release rwContext and complete
// the main readwrite irp
//
InterlockedDecrement(&rwContext->Lock);
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
return STATUS_PENDING;
}
}
else {
//
// normal processing
//
IsoUsb_DbgPrint(3, ("normal processing\n"));
IoMarkIrpPending(Irp);
KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
for(j = 0; j < numIrps; j++) {
IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
IsoUsb_IoIncrement(deviceExtension);
IoCallDriver(deviceExtension->TopOfStackDeviceObject,
rwContext->SubContext[j].SubIrp);
}
return STATUS_PENDING;
}
PerformHighSpeedIsochTransfer_Free:
for(j = 0; j < numIrps; j++) {
if(rwContext->SubContext[j].SubIrp) {
IoFreeIrp(rwContext->SubContext[j].SubIrp);
rwContext->SubContext[j].SubIrp = NULL;
}
if(rwContext->SubContext[j].SubUrb) {
ExFreePool(rwContext->SubContext[j].SubUrb);
rwContext->SubContext[j].SubUrb = NULL;
}
if(rwContext->SubContext[j].SubMdl) {
IoFreeMdl(rwContext->SubContext[j].SubMdl);
rwContext->SubContext[j].SubMdl = NULL;
}
}
ExFreePool(rwContext->SubContext);
ExFreePool(rwContext);
PerformHighSpeedIsochTransfer_Exit:
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
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
1. creates a ISOUSB_RW_CONTEXT for every
read/write to be performed.
2. creates SUB_CONTEXT for each irp/urb pair.
(Each irp/urb pair can transfer only 255 packets.)
3. All the irp/urb pairs are initialized
4. The subsidiary irps (of the irp/urb pair) are passed
down the stack at once.
5. The main Read/Write irp is pending
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
--*/
{
ULONG i;
ULONG j;
ULONG packetSize;
ULONG numIrps;
ULONG stageSize;
ULONG contextSize;
CCHAR stackSize;
KIRQL oldIrql;
PUCHAR virtualAddress;
BOOLEAN read;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
PIO_STACK_LOCATION nextStack;
PISOUSB_RW_CONTEXT rwContext;
//
// initialize vars
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer - begins\n"));
/*
if(read) {
pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX];
}
else {
pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_OUT_PIPE_INDEX];
}
*/
//
// each packet can hold this much info
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -