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

📄 isorwr.c

📁 传说中的 usb 端口 驱动 源码 啊啊啊啊啊啊啊
💻 C
📖 第 1 页 / 共 4 页
字号:
        subMdl = IoAllocateMdl((PVOID) virtualAddress,
                               stageSize,
                               FALSE,
                               FALSE,
                               NULL);

        if (subMdl == NULL)
        {
            IsoUsb_DbgPrint(1, ("failed to allocate subMdl\n"));

            ntStatus = STATUS_INSUFFICIENT_RESOURCES;

            goto PerformFullSpeedIsochTransfer_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(3, ("read\n"));

            subUrb->UrbIsochronousTransfer.TransferFlags =
                USBD_TRANSFER_DIRECTION_IN;
        }
        else
        {
            IsoUsb_DbgPrint(3, ("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;
*/
        //
        // when the client driver sets the ASAP flag, it basically
        // guarantees that it will make data available to the HC
        // and that the HC should transfer it in the next transfer frame
        // for the endpoint.(The HC maintains a next transfer frame
        // state variable for each endpoint). By resetting the pipe,
        // we make the pipe as virgin. If the data does not get to the HC
        // fast enough, the USBD_ISO_PACKET_DESCRIPTOR - Status is
        // USBD_STATUS_BAD_START_FRAME on uhci. On ohci it is 0xC000000E.
        //

        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 (stageSize > packetSize)
                {
                    offset    += packetSize;
                    stageSize -= packetSize;
                }
                else
                {
                    offset    += stageSize;
                    stageSize  = 0;
                }
            }
        }
        else
        {
            offset = 0;

            for (j = 0; j < nPackets; j++)
            {
                subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;

                if (stageSize > packetSize)
                {
                    subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
                    offset    += packetSize;
                    stageSize -= packetSize;
                }
                else
                {
                    subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = stageSize;
                    offset    += stageSize;
                    stageSize  = 0;

                    ASSERT(offset == (subUrb->UrbIsochronousTransfer.IsoPacket[j].Length +
                                      subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset));
                }
            }
        }

        // 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);

        // Update loop variables for next iteration.
        //
        if (TotalLength > (packetSize * 255))
        {
            stageSize = packetSize * 255;
        }
        else
        {
            stageSize = TotalLength;
        }
    }

    //
    // 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, ("PerformFullSpeedIsochTransfer::"));

            // 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;
    }

    //
    // Resource allocation failure, or the main request Irp was
    // cancelled before the cancel routine was set.  Free any resource
    // allocations and complete the main request Irp.
    //
    // No sub requests were ever called down the driver stack in this
    // case.
    //

PerformFullSpeedIsochTransfer_Free:

    if (subRequestContextArray != NULL)
    {
        for (i = 0; i < numIrps; i++)
        {
            subRequestContext = subRequestContextArray[i];

            if (subRequestContext != NULL)
            {
                if (subRequestContext->SubIrp != NULL)
                {
                    IoFreeIrp(subRequestContext->SubIrp);
                }

                if (subRequestContext->SubUrb != NULL)
                {
                    ExFreePool(subRequestContext->SubUrb);
                }

                if (subRequestContext->SubMdl != NULL)
                {
                    IoFreeMdl(subRequestContext->SubMdl);
                }

                ExFreePool(subRequestContext);
            }
        }

        ExFreePool(subRequestContextArray);
    }

    Irp->IoStatus.Status = ntStatus;
    Irp->IoStatus.Information = 0;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
    IsoUsb_IoDecrement(deviceExtension);

    IsoUsb_DbgPrint(3, ("-------------------------------\n"));

    return ntStatus;
}


NTSTATUS
PerformHighSpeedIsochTransfer(
    IN PDEVICE_OBJECT         DeviceObject,
    IN PUSBD_PIPE_INFORMATION PipeInformation,
    IN PIRP                   Irp,
    IN ULONG                  TotalLength
    )
/*++

Routine Description:

    High Speed Isoch Transfer requires packets in multiples of 8.
    (Argument: 8 micro-frames per ms frame)
    Another restriction is that each Irp/Urb pair can be associated
    with a max of 1024 packets.

    Here is one of the ways of creating Irp/Urb pairs.
    Depending on the characteristics of real-world device,
    the algorithm may be different

    This algorithm will distribute data evenly among all the packets.

    Input:
    TotalLength - no. of bytes to be transferred.

    Other parameters:
    packetSize - max size of each packet for this pipe.

    Implementation Details:

    Step 1:
    ASSERT(TotalLength >= 8)

    Step 2:
    Find the exact number of packets required to transfer all of this data

    numberOfPackets = (TotalLength + packetSize - 1) / packetSize

    Step 3:
    Number of packets in multiples of 8.

    if(0 == (numberOfPackets % 8)) {

        actualPackets = numberOfPackets;
    }
    else {

        actualPackets = numberOfPackets +
                        (8 - (numberOfPackets % 8));
    }

    Step 4:
    Determine the min. data in each packet.

    minDataInEachPacket = TotalLength / actualPackets;

    Step 5:
    After placing min data in each packet,
    determine how much data is left to be distributed.

    dataLeftToBeDistributed = TotalLength -
                              (minDataInEachPacket * actualPackets);

    Step 6:
    Start placing the left over data in the packets
    (above the min data already placed)

    numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
                                  (packetSize - minDataInEachPacket);

    Step 7:
    determine if there is any more data left.

    dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
                                (packetSize - minDataInEachPacket));

    Step 8:
    The "dataLeftToBeDistributed" is placed in the packet at index
    "numberOfPacketsFilledToBrim"

    Algorithm at play:

    TotalLength  = 8193
    packetSize   = 8
    Step 1

    Step 2
    numberOfPackets = (8193 + 8 - 1) / 8 = 1025

    Step 3
    actualPackets = 1025 + 7 = 1032

    Step 4
    minDataInEachPacket = 8193 / 1032 = 7 bytes

    Step 5
    dataLeftToBeDistributed = 8193 - (7 * 1032) = 969.

    Step 6
    numberOfPacketsFilledToBrim = 969 / (8 - 7) = 969.

    Step 7
    dataLeftToBeDistributed = 969 - (969 * 1) = 0.

    Step 8
    Done :)

    Another algorithm
    Completely fill up (as far as possible) the early packets.
    Place 1 byte each in the rest of them.
    Ensure that the total number of packets is multiple of 8.

    This routine the does the following:

    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
    Irp - I/O request packet

Return Value:

    NT status value

--*/
{
    PDEVICE_EXTENSION       deviceExtension;
    PIO_STACK_LOCATION      irpStack;
    BOOLEAN                 read;
    ULONG                   packetSize;
    ULONG                   numberOfPackets;
    ULONG                   actualPackets;
    ULONG                   minDataInEachPacket;
    ULONG                   numberOfPacketsFilledToBrim;
    ULONG                   dataLeftToBeDistributed;
    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;

    if (TotalLength < 8)
    {
        ntStatus = STATUS_INVALID_PARAMETER;

        goto PerformHighSpeedIsochTransfer_Exit;
    }

    //
    // each packet can hold this much info
    //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -