⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isorwr.c

📁 WINDDK开发代码
💻 C
📖 第 1 页 / 共 4 页
字号:

        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 + -