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

📄 isorwr.c

📁 传说中的 usb 端口 驱动 源码 啊啊啊啊啊啊啊
💻 C
📖 第 1 页 / 共 4 页
字号:
    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 + -