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

📄 isorwr.c

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

Copyright (c) 2000  Microsoft Corporation

Module Name:

    isorwr.c

Abstract:

    This file has dispatch routines for read and write.

Environment:

    Kernel mode

Notes:

    Copyright (c) 2000 Microsoft Corporation.  
    All Rights Reserved.

--*/

#include "isousb.h"
#include "isopnp.h"
#include "isopwr.h"
#include "isodev.h"
#include "isowmi.h"
#include "isousr.h"
#include "isorwr.h"
#include "isostrm.h"

NTSTATUS
IsoUsb_DispatchReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
/*++
 
Routine Description:

    This routine does some validation and 
    invokes appropriate function to perform
    Isoch transfer

Arguments:

    DeviceObject - pointer to device object
    Irp - I/O request packet

Return Value:

    NT status value

--*/
{
    ULONG                  totalLength;
    ULONG                  packetSize;
    NTSTATUS               ntStatus;
    PFILE_OBJECT           fileObject;
    PDEVICE_EXTENSION      deviceExtension;
    PIO_STACK_LOCATION     irpStack;
    PFILE_OBJECT_CONTENT   fileObjectContent;
    PUSBD_PIPE_INFORMATION pipeInformation;

    //
    // initialize vars
    //
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpStack->FileObject;
    totalLength = 0;
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

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

    IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
    IsoUsb_IoIncrement(deviceExtension);

    if(deviceExtension->DeviceState != Working) {

        IsoUsb_DbgPrint(1, ("Invalid device state\n"));

        ntStatus = STATUS_INVALID_DEVICE_STATE;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    //
    // make sure that the selective suspend request has been completed.
    //
    if(deviceExtension->SSEnable) {

        //
        // It is true that the client driver cancelled the selective suspend
        // request in the dispatch routine for create Irps.
        // But there is no guarantee that it has indeed completed.
        // so wait on the NoIdleReqPendEvent and proceed only if this event
        // is signalled.
        //
        IsoUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));

        
        KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, 
                              Executive, 
                              KernelMode, 
                              FALSE, 
                              NULL);
    }

    //
    // obtain the pipe information for read 
    // and write from the fileobject.
    //
    if(fileObject && fileObject->FsContext) {

        fileObjectContent = (PFILE_OBJECT_CONTENT) fileObject->FsContext;

        pipeInformation = (PUSBD_PIPE_INFORMATION)
                          fileObjectContent->PipeInformation;
    }
    else {

        IsoUsb_DbgPrint(1, ("Invalid device state\n"));

        ntStatus = STATUS_INVALID_DEVICE_STATE;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    if((pipeInformation == NULL) ||
       (UsbdPipeTypeIsochronous != pipeInformation->PipeType)) {

        IsoUsb_DbgPrint(1, ("Incorrect pipe\n"));

        ntStatus = STATUS_INVALID_DEVICE_STATE;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    if(Irp->MdlAddress) {

        totalLength = MmGetMdlByteCount(Irp->MdlAddress);
    }

    if(totalLength == 0) {

        IsoUsb_DbgPrint(1, ("Transfer data length = 0\n"));

        ntStatus = STATUS_SUCCESS;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    //
    // each packet can hold this much info
    //
    packetSize = pipeInformation->MaximumPacketSize;

    if(packetSize == 0) {

        IsoUsb_DbgPrint(1, ("Invalid parameter\n"));

        ntStatus = STATUS_INVALID_PARAMETER;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    //
    // atleast packet worth of data to be transferred.
    //
    if(totalLength < packetSize) {

        IsoUsb_DbgPrint(1, ("Atleast packet worth of data..\n"));

        ntStatus = STATUS_INVALID_PARAMETER;
        goto IsoUsb_DispatchReadWrite_Exit;
    }

    // perform reset. if there are some active transfers queued up
    // for this endpoint then the reset pipe will fail.
    //
    IsoUsb_ResetPipe(DeviceObject, pipeInformation);

    if(deviceExtension->IsDeviceHighSpeed) {

        ntStatus = PerformHighSpeedIsochTransfer(DeviceObject,
                                                 pipeInformation,
                                                 Irp,
                                                 totalLength);

    }
    else {

        ntStatus = PerformFullSpeedIsochTransfer(DeviceObject,
                                                 pipeInformation,
                                                 Irp,
                                                 totalLength);

    }

    return ntStatus;

IsoUsb_DispatchReadWrite_Exit:

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

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
    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 then
    1. creates a ISOUSB_RW_CONTEXT for each
       read/write to be performed.
    2. creates SUB_CONTEXT for each irp/urb pair.
       (Each irp/urb pair can transfer a max of 1024 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
    Irp - I/O request packet

Return Value:

    NT status value

--*/
{
    ULONG              i;
    ULONG              j;
    ULONG              numIrps;
    ULONG              stageSize;
    ULONG              contextSize;
    ULONG              packetSize;
    ULONG              numberOfPackets;
    ULONG              actualPackets;
    ULONG              minDataInEachPacket;
    ULONG              dataLeftToBeDistributed;
    ULONG              numberOfPacketsFilledToBrim;
    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;

    if(TotalLength < 8) {

        ntStatus = STATUS_INVALID_PARAMETER;
        goto PerformHighSpeedIsochTransfer_Exit;
    }

    //
    // each packet can hold this much info
    //
    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));

    //
    // for every read/write transfer
    // we create an ISOUSB_RW_CONTEXT
    //
    // initialize the read/write context
    //
    
    contextSize = sizeof(ISOUSB_RW_CONTEXT);

    rwContext = (PISOUSB_RW_CONTEXT) ExAllocatePool(NonPagedPool,
                                                    contextSize);

    if(rwContext == NULL) {

        IsoUsb_DbgPrint(1, ("Failed to alloc mem for rwContext\n"));

⌨️ 快捷键说明

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