isorwr.c
上传用户:leituo004
上传日期:2014-11-03
资源大小:159k
文件大小:54k
源码类别:

驱动编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 2000  Microsoft Corporation
  3. Module Name:
  4.     isorwr.c
  5. Abstract:
  6.     This file has dispatch routines for read and write.
  7. Environment:
  8.     Kernel mode
  9. Notes:
  10.     Copyright (c) 2000 Microsoft Corporation.  
  11.     All Rights Reserved.
  12. --*/
  13. #include "isousb.h"
  14. #include "isopnp.h"
  15. #include "isopwr.h"
  16. #include "isodev.h"
  17. #include "isowmi.h"
  18. #include "isousr.h"
  19. #include "isorwr.h"
  20. #include "isostrm.h"
  21. NTSTATUS
  22. IsoUsb_DispatchReadWrite(
  23.     IN PDEVICE_OBJECT DeviceObject,
  24.     IN PIRP           Irp
  25.     )
  26. /*++
  27.  
  28. Routine Description:
  29.     This routine does some validation and 
  30.     invokes appropriate function to perform
  31.     Isoch transfer
  32. Arguments:
  33.     DeviceObject - pointer to device object
  34.     Irp - I/O request packet
  35. Return Value:
  36.     NT status value
  37. --*/
  38. {
  39.     ULONG                  totalLength;
  40.     ULONG                  packetSize;
  41.     NTSTATUS               ntStatus;
  42.     PFILE_OBJECT           fileObject;
  43.     PDEVICE_EXTENSION      deviceExtension;
  44.     PIO_STACK_LOCATION     irpStack;
  45.     PFILE_OBJECT_CONTENT   fileObjectContent;
  46.     PUSBD_PIPE_INFORMATION pipeInformation;
  47.     //
  48.     // initialize vars
  49.     //
  50.     irpStack = IoGetCurrentIrpStackLocation(Irp);
  51.     fileObject = irpStack->FileObject;
  52.     totalLength = 0;
  53.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  54.     IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite - beginsn"));
  55.     IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
  56.     IsoUsb_IoIncrement(deviceExtension);
  57.     if(deviceExtension->DeviceState != Working) {
  58.         IsoUsb_DbgPrint(1, ("Invalid device staten"));
  59.         ntStatus = STATUS_INVALID_DEVICE_STATE;
  60.         goto IsoUsb_DispatchReadWrite_Exit;
  61.     }
  62.     //
  63.     // make sure that the selective suspend request has been completed.
  64.     //
  65.     if(deviceExtension->SSEnable) {
  66.         //
  67.         // It is true that the client driver cancelled the selective suspend
  68.         // request in the dispatch routine for create Irps.
  69.         // But there is no guarantee that it has indeed completed.
  70.         // so wait on the NoIdleReqPendEvent and proceed only if this event
  71.         // is signalled.
  72.         //
  73.         IsoUsb_DbgPrint(3, ("Waiting on the IdleReqPendEventn"));
  74.         
  75.         KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, 
  76.                               Executive, 
  77.                               KernelMode, 
  78.                               FALSE, 
  79.                               NULL);
  80.     }
  81.     //
  82.     // obtain the pipe information for read 
  83.     // and write from the fileobject.
  84.     //
  85.     if(fileObject && fileObject->FsContext) {
  86.         fileObjectContent = (PFILE_OBJECT_CONTENT) fileObject->FsContext;
  87.         pipeInformation = (PUSBD_PIPE_INFORMATION)
  88.                           fileObjectContent->PipeInformation;
  89.     }
  90.     else {
  91.         IsoUsb_DbgPrint(1, ("Invalid device staten"));
  92.         ntStatus = STATUS_INVALID_DEVICE_STATE;
  93.         goto IsoUsb_DispatchReadWrite_Exit;
  94.     }
  95.     if((pipeInformation == NULL) ||
  96.        (UsbdPipeTypeIsochronous != pipeInformation->PipeType)) {
  97.         IsoUsb_DbgPrint(1, ("Incorrect pipen"));
  98.         ntStatus = STATUS_INVALID_DEVICE_STATE;
  99.         goto IsoUsb_DispatchReadWrite_Exit;
  100.     }
  101.     if(Irp->MdlAddress) {
  102.         totalLength = MmGetMdlByteCount(Irp->MdlAddress);
  103.     }
  104.     if(totalLength == 0) {
  105.         IsoUsb_DbgPrint(1, ("Transfer data length = 0n"));
  106.         ntStatus = STATUS_SUCCESS;
  107.         goto IsoUsb_DispatchReadWrite_Exit;
  108.     }
  109.     //
  110.     // each packet can hold this much info
  111.     //
  112.     packetSize = pipeInformation->MaximumPacketSize;
  113.     if(packetSize == 0) {
  114.         IsoUsb_DbgPrint(1, ("Invalid parametern"));
  115.         ntStatus = STATUS_INVALID_PARAMETER;
  116.         goto IsoUsb_DispatchReadWrite_Exit;
  117.     }
  118.     //
  119.     // atleast packet worth of data to be transferred.
  120.     //
  121.     if(totalLength < packetSize) {
  122.         IsoUsb_DbgPrint(1, ("Atleast packet worth of data..n"));
  123.         ntStatus = STATUS_INVALID_PARAMETER;
  124.         goto IsoUsb_DispatchReadWrite_Exit;
  125.     }
  126.     // perform reset. if there are some active transfers queued up
  127.     // for this endpoint then the reset pipe will fail.
  128.     //
  129.     IsoUsb_ResetPipe(DeviceObject, pipeInformation);
  130.     if(deviceExtension->IsDeviceHighSpeed) {
  131.         ntStatus = PerformHighSpeedIsochTransfer(DeviceObject,
  132.                                                  pipeInformation,
  133.                                                  Irp,
  134.                                                  totalLength);
  135.     }
  136.     else {
  137.         ntStatus = PerformFullSpeedIsochTransfer(DeviceObject,
  138.                                                  pipeInformation,
  139.                                                  Irp,
  140.                                                  totalLength);
  141.     }
  142.     return ntStatus;
  143. IsoUsb_DispatchReadWrite_Exit:
  144.     Irp->IoStatus.Status = ntStatus;
  145.     Irp->IoStatus.Information = 0;
  146.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
  147.     IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
  148.     IsoUsb_IoDecrement(deviceExtension);
  149.     IsoUsb_DbgPrint(3, ("-------------------------------n"));
  150.     return ntStatus;
  151. }
  152. NTSTATUS
  153. PerformHighSpeedIsochTransfer(
  154.     IN PDEVICE_OBJECT         DeviceObject,
  155.     IN PUSBD_PIPE_INFORMATION PipeInformation,
  156.     IN PIRP                   Irp,
  157.     IN ULONG                  TotalLength
  158.     )
  159. /*++
  160.  
  161. Routine Description:
  162.     High Speed Isoch Transfer requires packets in multiples of 8.
  163.     (Argument: 8 micro-frames per ms frame)
  164.     Another restriction is that each Irp/Urb pair can be associated
  165.     with a max of 1024 packets.
  166.     Here is one of the ways of creating Irp/Urb pairs.
  167.     Depending on the characteristics of real-world device,
  168.     the algorithm may be different
  169.     This algorithm will distribute data evenly among all the packets.
  170.     Input:
  171.     TotalLength - no. of bytes to be transferred.
  172.     Other parameters:
  173.     packetSize - max size of each packet for this pipe.
  174.     Implementation Details:
  175.     
  176.     Step 1:
  177.     ASSERT(TotalLength >= 8)
  178.     Step 2: 
  179.     Find the exact number of packets required to transfer all of this data
  180.     numberOfPackets = (TotalLength + packetSize - 1) / packetSize
  181.     Step 3: 
  182.     Number of packets in multiples of 8.
  183.     if(0 == (numberOfPackets % 8)) {
  184.         
  185.         actualPackets = numberOfPackets;
  186.     }
  187.     else {
  188.         actualPackets = numberOfPackets + 
  189.                         (8 - (numberOfPackets % 8));
  190.     }
  191.     
  192.     Step 4:
  193.     Determine the min. data in each packet.
  194.     minDataInEachPacket = TotalLength / actualPackets;
  195.     Step 5:
  196.     After placing min data in each packet, 
  197.     determine how much data is left to be distributed. 
  198.     
  199.     dataLeftToBeDistributed = TotalLength - 
  200.                               (minDataInEachPacket * actualPackets);
  201.     Step 6:
  202.     Start placing the left over data in the packets 
  203.     (above the min data already placed)
  204.     numberOfPacketsFilledToBrim = dataLeftToBeDistributed / 
  205.                                   (packetSize - minDataInEachPacket);
  206.     Step 7:
  207.     determine if there is any more data left.
  208.     dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim * 
  209.                                 (packetSize - minDataInEachPacket));
  210.     Step 8:
  211.     The "dataLeftToBeDistributed" is placed in the packet at index
  212.     "numberOfPacketsFilledToBrim"
  213.     Algorithm at play:
  214.     TotalLength  = 8193
  215.     packetSize   = 8
  216.     Step 1
  217.     Step 2
  218.     numberOfPackets = (8193 + 8 - 1) / 8 = 1025
  219.     
  220.     Step 3
  221.     actualPackets = 1025 + 7 = 1032
  222.     Step 4
  223.     minDataInEachPacket = 8193 / 1032 = 7 bytes
  224.     Step 5
  225.     dataLeftToBeDistributed = 8193 - (7 * 1032) = 969.
  226.     Step 6
  227.     numberOfPacketsFilledToBrim = 969 / (8 - 7) = 969.
  228.   
  229.     Step 7
  230.     dataLeftToBeDistributed = 969 - (969 * 1) = 0.
  231.     
  232.     Step 8
  233.     Done :)
  234.     Another algorithm
  235.     Completely fill up (as far as possible) the early packets.
  236.     Place 1 byte each in the rest of them.
  237.     Ensure that the total number of packets is multiple of 8.
  238.     This routine then
  239.     1. creates a ISOUSB_RW_CONTEXT for each
  240.        read/write to be performed.
  241.     2. creates SUB_CONTEXT for each irp/urb pair.
  242.        (Each irp/urb pair can transfer a max of 1024 packets.)
  243.     3. All the irp/urb pairs are initialized
  244.     4. The subsidiary irps (of the irp/urb pair) are passed 
  245.        down the stack at once.
  246.     5. The main Read/Write irp is pending
  247. Arguments:
  248.     DeviceObject - pointer to device object
  249.     Irp - I/O request packet
  250. Return Value:
  251.     NT status value
  252. --*/
  253. {
  254.     ULONG              i;
  255.     ULONG              j;
  256.     ULONG              numIrps;
  257.     ULONG              stageSize;
  258.     ULONG              contextSize;
  259.     ULONG              packetSize;
  260.     ULONG              numberOfPackets;
  261.     ULONG              actualPackets;
  262.     ULONG              minDataInEachPacket;
  263.     ULONG              dataLeftToBeDistributed;
  264.     ULONG              numberOfPacketsFilledToBrim;
  265.     CCHAR              stackSize;
  266.     KIRQL              oldIrql;
  267.     PUCHAR             virtualAddress;
  268.     BOOLEAN            read;
  269.     NTSTATUS           ntStatus;
  270.     PDEVICE_EXTENSION  deviceExtension;
  271.     PIO_STACK_LOCATION irpStack;
  272.     PIO_STACK_LOCATION nextStack;
  273.     PISOUSB_RW_CONTEXT rwContext;
  274.     //
  275.     // initialize vars
  276.     //
  277.     irpStack = IoGetCurrentIrpStackLocation(Irp);
  278.     read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
  279.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  280.     if(TotalLength < 8) {
  281.         ntStatus = STATUS_INVALID_PARAMETER;
  282.         goto PerformHighSpeedIsochTransfer_Exit;
  283.     }
  284.     //
  285.     // each packet can hold this much info
  286.     //
  287.     packetSize = PipeInformation->MaximumPacketSize;
  288.     numberOfPackets = (TotalLength + packetSize - 1) / packetSize;
  289.     if(0 == (numberOfPackets % 8)) {
  290.         actualPackets = numberOfPackets;
  291.     }
  292.     else {
  293.         //
  294.         // we need multiple of 8 packets only.
  295.         //
  296.         actualPackets = numberOfPackets +
  297.                         (8 - (numberOfPackets % 8));
  298.     }
  299.     minDataInEachPacket = TotalLength / actualPackets;
  300.     if(minDataInEachPacket == packetSize) {
  301.         numberOfPacketsFilledToBrim = actualPackets;
  302.         dataLeftToBeDistributed     = 0;
  303.         IsoUsb_DbgPrint(1, ("TotalLength = %dn", TotalLength));
  304.         IsoUsb_DbgPrint(1, ("PacketSize  = %dn", packetSize));
  305.         IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn", 
  306.                             numberOfPacketsFilledToBrim,
  307.                             packetSize));
  308.     }
  309.     else {
  310.         dataLeftToBeDistributed = TotalLength - 
  311.                               (minDataInEachPacket * actualPackets);
  312.         numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
  313.                                   (packetSize - minDataInEachPacket);
  314.         dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
  315.                                 (packetSize - minDataInEachPacket));
  316.     
  317.         IsoUsb_DbgPrint(1, ("TotalLength = %dn", TotalLength));
  318.         IsoUsb_DbgPrint(1, ("PacketSize  = %dn", packetSize));
  319.         IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn", 
  320.                             numberOfPacketsFilledToBrim,
  321.                             packetSize));
  322.         if(dataLeftToBeDistributed) {
  323.             IsoUsb_DbgPrint(1, ("One packet has %d bytesn",
  324.                                 minDataInEachPacket + dataLeftToBeDistributed));
  325.             IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
  326.                                 actualPackets - (numberOfPacketsFilledToBrim + 1),
  327.                                 minDataInEachPacket));
  328.         }
  329.         else {
  330.             IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
  331.                                 actualPackets - numberOfPacketsFilledToBrim,
  332.                                 minDataInEachPacket));
  333.         }
  334.     }
  335.     //
  336.     // determine how many stages of transfer needs to be done.
  337.     // in other words, how many irp/urb pairs required. 
  338.     // this irp/urb pair is also called the subsidiary irp/urb pair
  339.     //
  340.     numIrps = (actualPackets + 1023) / 1024;
  341.     IsoUsb_DbgPrint(1, ("PeformHighSpeedIsochTransfer::numIrps = %dn", numIrps));
  342.     //
  343.     // for every read/write transfer
  344.     // we create an ISOUSB_RW_CONTEXT
  345.     //
  346.     // initialize the read/write context
  347.     //
  348.     
  349.     contextSize = sizeof(ISOUSB_RW_CONTEXT);
  350.     rwContext = (PISOUSB_RW_CONTEXT) ExAllocatePool(NonPagedPool,
  351.                                                     contextSize);
  352.     if(rwContext == NULL) {
  353.         IsoUsb_DbgPrint(1, ("Failed to alloc mem for rwContextn"));
  354.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  355.         goto PerformHighSpeedIsochTransfer_Exit;
  356.     }
  357.     RtlZeroMemory(rwContext, contextSize);
  358.     //
  359.     // allocate memory for every stage context - 
  360.     // subcontext has state information for every irp/urb pair.
  361.     //
  362.     rwContext->SubContext = (PSUB_CONTEXT) 
  363.                             ExAllocatePool(NonPagedPool, 
  364.                                            numIrps * sizeof(SUB_CONTEXT));
  365.     if(rwContext->SubContext == NULL) {
  366.         IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContextn"));
  367.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  368.         ExFreePool(rwContext);
  369.         goto PerformHighSpeedIsochTransfer_Exit;
  370.     }
  371.     RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
  372.     rwContext->RWIrp = Irp;
  373.     rwContext->Lock = 2;
  374.     rwContext->NumIrps = numIrps;
  375.     rwContext->IrpsPending = numIrps;
  376.     rwContext->DeviceExtension = deviceExtension;
  377.     KeInitializeSpinLock(&rwContext->SpinLock);
  378.     //
  379.     // save the rwContext pointer in the tail union.
  380.     //
  381.     Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
  382.     stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
  383.     virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  384.     for(i = 0; i < numIrps; i++) {
  385.     
  386.         PIRP  subIrp;
  387.         PURB  subUrb;
  388.         PMDL  subMdl;
  389.         ULONG nPackets;
  390.         ULONG siz;
  391.         ULONG offset;
  392.         //
  393.         // for every stage of transfer we need to do the following
  394.         // tasks
  395.         // 1. allocate an irp
  396.         // 2. allocate an urb
  397.         // 3. allocate a mdl.
  398.         //
  399.         // create a subsidiary irp
  400.         //
  401.         subIrp = IoAllocateIrp(stackSize, FALSE);
  402.         if(subIrp == NULL) {
  403.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irpn"));
  404.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  405.             goto PerformHighSpeedIsochTransfer_Free;
  406.         }
  407.         rwContext->SubContext[i].SubIrp = subIrp;
  408.         if(actualPackets <= 1024) {
  409.             
  410.             nPackets = actualPackets;
  411.             actualPackets = 0;
  412.         }
  413.         else {
  414.             nPackets = 1024;
  415.             actualPackets -= 1024;
  416.         }
  417.         IsoUsb_DbgPrint(1, ("nPackets = %d for Irp/URB pair %dn", nPackets, i));
  418.         ASSERT(nPackets <= 1024);
  419.         siz = GET_ISO_URB_SIZE(nPackets);
  420.         //
  421.         // create a subsidiary urb.
  422.         //
  423.         subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
  424.         if(subUrb == NULL) {
  425.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urbn"));
  426.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  427.             goto PerformHighSpeedIsochTransfer_Free;
  428.         }
  429.         rwContext->SubContext[i].SubUrb = subUrb;
  430.         if(nPackets > numberOfPacketsFilledToBrim) {
  431.             
  432.             stageSize =  packetSize * numberOfPacketsFilledToBrim;
  433.             stageSize += (minDataInEachPacket * 
  434.                           (nPackets - numberOfPacketsFilledToBrim));
  435.             stageSize += dataLeftToBeDistributed;
  436.         }
  437.         else {
  438.             stageSize = packetSize * nPackets;
  439.         }
  440.         //
  441.         // allocate a mdl.
  442.         //
  443.         subMdl = IoAllocateMdl((PVOID) virtualAddress, 
  444.                                stageSize,
  445.                                FALSE,
  446.                                FALSE,
  447.                                NULL);
  448.         if(subMdl == NULL) {
  449.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdln"));
  450.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  451.             goto PerformHighSpeedIsochTransfer_Free;
  452.         }
  453.         IoBuildPartialMdl(Irp->MdlAddress,
  454.                           subMdl,
  455.                           (PVOID) virtualAddress,
  456.                           stageSize);
  457.         rwContext->SubContext[i].SubMdl = subMdl;
  458.         virtualAddress += stageSize;
  459.         TotalLength -= stageSize;
  460.         //
  461.         // Initialize the subsidiary urb
  462.         //
  463.         RtlZeroMemory(subUrb, siz);
  464.         subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
  465.         subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
  466.         subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
  467.         if(read) {
  468.             IsoUsb_DbgPrint(1, ("readn"));
  469.             subUrb->UrbIsochronousTransfer.TransferFlags = 
  470.                                                      USBD_TRANSFER_DIRECTION_IN;
  471.         }
  472.         else {
  473.             IsoUsb_DbgPrint(1, ("writen"));
  474.             subUrb->UrbIsochronousTransfer.TransferFlags =
  475.                                                      USBD_TRANSFER_DIRECTION_OUT;
  476.         }
  477.         subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
  478.         subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
  479. /*
  480.         This is a way to set the start frame and NOT specify ASAP flag.
  481.         subUrb->UrbIsochronousTransfer.StartFrame = 
  482.                         IsoUsb_GetCurrentFrame(DeviceObject, Irp) + 
  483.                         SOME_LATENCY;
  484. */
  485.         subUrb->UrbIsochronousTransfer.TransferFlags |=
  486.                                         USBD_START_ISO_TRANSFER_ASAP;
  487.         subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
  488.         subUrb->UrbIsochronousTransfer.UrbLink = NULL;
  489.         //
  490.         // set the offsets for every packet for reads/writes
  491.         //
  492.         if(read) {
  493.             
  494.             offset = 0;
  495.             for(j = 0; j < nPackets; j++) {
  496.             
  497.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  498.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
  499.                 if(numberOfPacketsFilledToBrim) {
  500.                     offset += packetSize;
  501.                     numberOfPacketsFilledToBrim--;
  502.                     stageSize -= packetSize;
  503.                 }
  504.                 else if(dataLeftToBeDistributed) {
  505.                     offset += (minDataInEachPacket + dataLeftToBeDistributed);
  506.                     stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
  507.                     dataLeftToBeDistributed = 0;                    
  508.                 }
  509.                 else {
  510.                     offset += minDataInEachPacket;
  511.                     stageSize -= minDataInEachPacket;
  512.                 }
  513.             }
  514.             ASSERT(stageSize == 0);
  515.         }
  516.         else {
  517.             offset = 0;
  518.             for(j = 0; j < nPackets; j++) {
  519.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  520.                 if(numberOfPacketsFilledToBrim) {
  521.                     subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
  522.                     offset += packetSize;
  523.                     numberOfPacketsFilledToBrim--;
  524.                     stageSize -= packetSize;
  525.                 }
  526.                 else if(dataLeftToBeDistributed) {
  527.                     
  528.                     subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 
  529.                                         minDataInEachPacket + dataLeftToBeDistributed;
  530.                     offset += (minDataInEachPacket + dataLeftToBeDistributed);
  531.                     stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
  532.                     dataLeftToBeDistributed = 0;
  533.                     
  534.                 }
  535.                 else {
  536.                     subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = minDataInEachPacket;
  537.                     offset += minDataInEachPacket;
  538.                     stageSize -= minDataInEachPacket;
  539.                 }
  540.             }
  541.             ASSERT(stageSize == 0);
  542.         }
  543.         IoSetNextIrpStackLocation(subIrp);
  544.         nextStack = IoGetCurrentIrpStackLocation(subIrp);
  545.         nextStack->DeviceObject = DeviceObject;
  546.         nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  547.         nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
  548.         nextStack = IoGetNextIrpStackLocation(subIrp);
  549.         nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  550.         nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  551.         nextStack->Parameters.DeviceIoControl.IoControlCode = 
  552.                                              IOCTL_INTERNAL_USB_SUBMIT_URB;
  553.         IoSetCompletionRoutine(subIrp,
  554.                                (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
  555.                                (PVOID) rwContext,
  556.                                TRUE,
  557.                                TRUE,
  558.                                TRUE);       
  559.     }
  560.     //
  561.     // while we were busy create subsidiary irp/urb pairs..
  562.     // the main read/write irp may have been cancelled !!
  563.     //
  564.     KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  565.     IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
  566.     if(Irp->Cancel) {
  567.         //
  568.         // The Cancel flag for the Irp has been set. 
  569.         //
  570.         IsoUsb_DbgPrint(3, ("Cancel flag setn"));
  571.         ntStatus = STATUS_CANCELLED;
  572.         if(IoSetCancelRoutine(Irp, NULL)) {
  573.             //
  574.             // But the I/O manager did not call our cancel routine.
  575.             // we need to free the 1) irp, 2) urb and 3) mdl for every 
  576.             // stage and complete the main Irp after releasing the lock
  577.             //
  578.             IsoUsb_DbgPrint(3, ("cancellation routine NOT runn"));
  579.             KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  580.             goto PerformHighSpeedIsochTransfer_Free;
  581.         }
  582.         else {
  583.             
  584.             //
  585.             // The cancel routine will resume the moment we release the lock.
  586.             //
  587.             for(j = 0; j < numIrps; j++) {
  588.                 if(rwContext->SubContext[j].SubUrb) {
  589.                     ExFreePool(rwContext->SubContext[j].SubUrb);
  590.                     rwContext->SubContext[j].SubUrb = NULL;
  591.                 }
  592.                 if(rwContext->SubContext[j].SubMdl) {
  593.                     IoFreeMdl(rwContext->SubContext[j].SubMdl);
  594.                     rwContext->SubContext[j].SubMdl = NULL;
  595.                 }
  596.             }
  597.             IoMarkIrpPending(Irp);
  598.             //
  599.             // it is the job of the cancellation routine to free
  600.             // sub-context irps, release rwContext and complete 
  601.             // the main readwrite irp
  602.             //
  603.             InterlockedDecrement(&rwContext->Lock);
  604.             KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  605.             return STATUS_PENDING;
  606.         }
  607.     }
  608.     else {
  609.         //
  610.         // normal processing
  611.         //
  612.         IsoUsb_DbgPrint(3, ("normal processingn"));
  613.         IoMarkIrpPending(Irp);
  614.         KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  615.         for(j = 0; j < numIrps; j++) {
  616.             IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
  617.             IsoUsb_IoIncrement(deviceExtension);
  618.             
  619.             IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  620.                          rwContext->SubContext[j].SubIrp);
  621.         }
  622.         return STATUS_PENDING;
  623.     }
  624. PerformHighSpeedIsochTransfer_Free:
  625.     for(j = 0; j < numIrps; j++) {
  626.         if(rwContext->SubContext[j].SubIrp) {
  627.             IoFreeIrp(rwContext->SubContext[j].SubIrp);
  628.             rwContext->SubContext[j].SubIrp = NULL;
  629.         }
  630.         if(rwContext->SubContext[j].SubUrb) {
  631.             ExFreePool(rwContext->SubContext[j].SubUrb);
  632.             rwContext->SubContext[j].SubUrb = NULL;
  633.         }
  634.         if(rwContext->SubContext[j].SubMdl) {
  635.             IoFreeMdl(rwContext->SubContext[j].SubMdl);
  636.             rwContext->SubContext[j].SubMdl = NULL;
  637.         }
  638.     }
  639.     ExFreePool(rwContext->SubContext);
  640.     ExFreePool(rwContext);
  641. PerformHighSpeedIsochTransfer_Exit:
  642.     Irp->IoStatus.Status = ntStatus;
  643.     Irp->IoStatus.Information = 0;
  644.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
  645.     IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
  646.     IsoUsb_IoDecrement(deviceExtension);
  647.     IsoUsb_DbgPrint(3, ("-------------------------------n"));
  648.     return ntStatus;
  649. }
  650. NTSTATUS
  651. PerformFullSpeedIsochTransfer(
  652.     IN PDEVICE_OBJECT         DeviceObject,
  653.     IN PUSBD_PIPE_INFORMATION PipeInformation,
  654.     IN PIRP                   Irp,
  655.     IN ULONG                  TotalLength
  656.     )
  657. /*++
  658.  
  659. Routine Description:
  660.     This routine 
  661.     1. creates a ISOUSB_RW_CONTEXT for every
  662.        read/write to be performed.
  663.     2. creates SUB_CONTEXT for each irp/urb pair.
  664.        (Each irp/urb pair can transfer only 255 packets.)
  665.     3. All the irp/urb pairs are initialized
  666.     4. The subsidiary irps (of the irp/urb pair) are passed 
  667.        down the stack at once.
  668.     5. The main Read/Write irp is pending
  669. Arguments:
  670.     DeviceObject - pointer to device object
  671.     PipeInformation - USBD_PIPE_INFORMATION
  672.     Irp - I/O request packet
  673.     TotalLength - no. of bytes to be transferred
  674. Return Value:
  675.     NT status value
  676. --*/
  677. {
  678.     ULONG              i;
  679.     ULONG              j;
  680.     ULONG              packetSize;
  681.     ULONG              numIrps;
  682.     ULONG              stageSize;
  683.     ULONG              contextSize;
  684.     CCHAR              stackSize;
  685.     KIRQL              oldIrql;
  686.     PUCHAR             virtualAddress;
  687.     BOOLEAN            read;
  688.     NTSTATUS           ntStatus;
  689.     PDEVICE_EXTENSION  deviceExtension;
  690.     PIO_STACK_LOCATION irpStack;
  691.     PIO_STACK_LOCATION nextStack;
  692.     PISOUSB_RW_CONTEXT rwContext;
  693.     //
  694.     // initialize vars
  695.     //
  696.     irpStack = IoGetCurrentIrpStackLocation(Irp);
  697.     read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
  698.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  699.     IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer - beginsn"));
  700. /*
  701.     if(read) {
  702.         pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX];
  703.     }
  704.     else {
  705.         pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_OUT_PIPE_INDEX];
  706.     }
  707. */
  708.     //
  709.     // each packet can hold this much info
  710.     //
  711.     packetSize = PipeInformation->MaximumPacketSize;
  712.     IsoUsb_DbgPrint(3, ("totalLength = %dn", TotalLength));
  713.     IsoUsb_DbgPrint(3, ("packetSize = %dn", packetSize));
  714.     //
  715.     // there is an inherent limit on the number of packets
  716.     // that can be passed down the stack with each 
  717.     // irp/urb pair (255)
  718.     // if the number of required packets is > 255,
  719.     // we shall create "required-packets / 255 + 1" number 
  720.     // of irp/urb pairs. 
  721.     // Each irp/urb pair transfer is also called a stage transfer.
  722.     //
  723.     if(TotalLength > (packetSize * 255)) {
  724.         stageSize = packetSize * 255;
  725.     }
  726.     else {
  727.         stageSize = TotalLength;
  728.     }
  729.     IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::stageSize = %dn", stageSize));
  730.     //
  731.     // determine how many stages of transfer needs to be done.
  732.     // in other words, how many irp/urb pairs required. 
  733.     // this irp/urb pair is also called the subsidiary irp/urb pair
  734.     //
  735.     numIrps = (TotalLength + stageSize - 1) / stageSize;
  736.     IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::numIrps = %dn", numIrps));
  737.     //
  738.     // for every read/write transfer
  739.     // we create an ISOUSB_RW_CONTEXT
  740.     //
  741.     // initialize the read/write context
  742.     //
  743.     
  744.     contextSize = sizeof(ISOUSB_RW_CONTEXT);
  745.     rwContext = (PISOUSB_RW_CONTEXT) ExAllocatePool(NonPagedPool,
  746.                                                     contextSize);
  747.     if(rwContext == NULL) {
  748.         IsoUsb_DbgPrint(1, ("Failed to alloc mem for rwContextn"));
  749.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  750.         goto PerformFullSpeedIsochTransfer_Exit;
  751.     }
  752.     RtlZeroMemory(rwContext, contextSize);
  753.     //
  754.     // allocate memory for every stage context - 
  755.     // subcontext has state information for every irp/urb pair.
  756.     //
  757.     rwContext->SubContext = (PSUB_CONTEXT) 
  758.                             ExAllocatePool(NonPagedPool, 
  759.                                            numIrps * sizeof(SUB_CONTEXT));
  760.     if(rwContext->SubContext == NULL) {
  761.         IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContextn"));
  762.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  763.         ExFreePool(rwContext);
  764.         goto PerformFullSpeedIsochTransfer_Exit;
  765.     }
  766.     RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
  767.     rwContext->RWIrp = Irp;
  768.     rwContext->Lock = 2;
  769.     rwContext->NumIrps = numIrps;
  770.     rwContext->IrpsPending = numIrps;
  771.     rwContext->DeviceExtension = deviceExtension;
  772.     KeInitializeSpinLock(&rwContext->SpinLock);
  773.     //
  774.     // save the rwContext pointer in the tail union.
  775.     //
  776.     Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
  777.     stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
  778.     virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  779.     for(i = 0; i < numIrps; i++) {
  780.     
  781.         PIRP  subIrp;
  782.         PURB  subUrb;
  783.         PMDL  subMdl;
  784.         ULONG nPackets;
  785.         ULONG siz;
  786.         ULONG offset;
  787.         //
  788.         // for every stage of transfer we need to do the following
  789.         // tasks
  790.         // 1. allocate an irp
  791.         // 2. allocate an urb
  792.         // 3. allocate a mdl.
  793.         //
  794.         // create a subsidiary irp
  795.         //
  796.         subIrp = IoAllocateIrp(stackSize, FALSE);
  797.         if(subIrp == NULL) {
  798.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irpn"));
  799.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  800.             goto PerformFullSpeedIsochTransfer_Free;
  801.         }
  802.         rwContext->SubContext[i].SubIrp = subIrp;
  803.         nPackets = (stageSize + packetSize - 1) / packetSize;
  804.         IsoUsb_DbgPrint(3, ("nPackets = %d for Irp/URB pair %dn", nPackets, i));
  805.         ASSERT(nPackets <= 255);
  806.         siz = GET_ISO_URB_SIZE(nPackets);
  807.         //
  808.         // create a subsidiary urb.
  809.         //
  810.         subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
  811.         if(subUrb == NULL) {
  812.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urbn"));
  813.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  814.             goto PerformFullSpeedIsochTransfer_Free;
  815.         }
  816.         rwContext->SubContext[i].SubUrb = subUrb;
  817.         //
  818.         // allocate a mdl.
  819.         //
  820.         subMdl = IoAllocateMdl((PVOID) virtualAddress, 
  821.                             stageSize,
  822.                             FALSE,
  823.                             FALSE,
  824.                             NULL);
  825.         if(subMdl == NULL) {
  826.             IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdln"));
  827.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  828.             goto PerformFullSpeedIsochTransfer_Free;
  829.         }
  830.         IoBuildPartialMdl(Irp->MdlAddress,
  831.                           subMdl,
  832.                           (PVOID) virtualAddress,
  833.                           stageSize);
  834.         rwContext->SubContext[i].SubMdl = subMdl;
  835.         virtualAddress += stageSize;
  836.         TotalLength -= stageSize;
  837.         //
  838.         // Initialize the subsidiary urb
  839.         //
  840.         RtlZeroMemory(subUrb, siz);
  841.         subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
  842.         subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
  843.         subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
  844.         if(read) {
  845.             IsoUsb_DbgPrint(3, ("readn"));
  846.             subUrb->UrbIsochronousTransfer.TransferFlags = 
  847.                                                      USBD_TRANSFER_DIRECTION_IN;
  848.         }
  849.         else {
  850.             IsoUsb_DbgPrint(3, ("writen"));
  851.             subUrb->UrbIsochronousTransfer.TransferFlags =
  852.                                                      USBD_TRANSFER_DIRECTION_OUT;
  853.         }
  854.         subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
  855.         subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
  856. /*
  857.         This is a way to set the start frame and NOT specify ASAP flag.
  858.         subUrb->UrbIsochronousTransfer.StartFrame = 
  859.                         IsoUsb_GetCurrentFrame(DeviceObject, Irp) + 
  860.                         SOME_LATENCY;
  861. */
  862.         // 
  863.         // when the client driver sets the ASAP flag, it basically
  864.         // guarantees that it will make data available to the HC
  865.         // and that the HC should transfer it in the next transfer frame 
  866.         // for the endpoint.(The HC maintains a next transfer frame
  867.         // state variable for each endpoint). By resetting the pipe,
  868.         // we make the pipe as virgin. If the data does not get to the HC
  869.         // fast enough, the USBD_ISO_PACKET_DESCRIPTOR - Status is 
  870.         // USBD_STATUS_BAD_START_FRAME on uhci. On ohci it is 0xC000000E.
  871.         //
  872.         subUrb->UrbIsochronousTransfer.TransferFlags |=
  873.                                     USBD_START_ISO_TRANSFER_ASAP;
  874.         subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
  875.         subUrb->UrbIsochronousTransfer.UrbLink = NULL;
  876.         //
  877.         // set the offsets for every packet for reads/writes
  878.         //
  879.         if(read) {
  880.             
  881.             offset = 0;
  882.             for(j = 0; j < nPackets; j++) {
  883.             
  884.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  885.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
  886.                 if(stageSize > packetSize) {
  887.                     offset += packetSize;
  888.                     stageSize -= packetSize;
  889.                 }
  890.                 else {
  891.                     offset += stageSize;
  892.                     stageSize = 0;
  893.                 }
  894.             }
  895.         }
  896.         else {
  897.             offset = 0;
  898.             for(j = 0; j < nPackets; j++) {
  899.                 subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  900.                 if(stageSize > packetSize) {
  901.                     subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
  902.                     offset += packetSize;
  903.                     stageSize -= packetSize;
  904.                 }
  905.                 else {
  906.                     subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = stageSize;
  907.                     offset += stageSize;
  908.                     stageSize = 0;
  909.                     ASSERT(offset == (subUrb->UrbIsochronousTransfer.IsoPacket[j].Length + 
  910.                                       subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset));
  911.                 }
  912.             }
  913.         }
  914.         IoSetNextIrpStackLocation(subIrp);
  915.         nextStack = IoGetCurrentIrpStackLocation(subIrp);
  916.         nextStack->DeviceObject = DeviceObject;
  917.         nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  918.         nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
  919.         nextStack = IoGetNextIrpStackLocation(subIrp);
  920.         nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  921.         nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  922.         nextStack->Parameters.DeviceIoControl.IoControlCode = 
  923.                                              IOCTL_INTERNAL_USB_SUBMIT_URB;
  924.         IoSetCompletionRoutine(subIrp,
  925.                                (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
  926.                                (PVOID) rwContext,
  927.                                TRUE,
  928.                                TRUE,
  929.                                TRUE);
  930.         if(TotalLength > (packetSize * 255)) {
  931.             stageSize = packetSize * 255;
  932.         }
  933.         else {
  934.             stageSize = TotalLength;
  935.         }
  936.     }
  937.     //
  938.     // while we were busy create subsidiary irp/urb pairs..
  939.     // the main read/write irp may have been cancelled !!
  940.     //
  941.     KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  942.     IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
  943.     if(Irp->Cancel) {
  944.         //
  945.         // The Cancel flag for the Irp has been set. 
  946.         //
  947.         IsoUsb_DbgPrint(3, ("Cancel flag setn"));
  948.         ntStatus = STATUS_CANCELLED;
  949.         if(IoSetCancelRoutine(Irp, NULL)) {
  950.             //
  951.             // But the I/O manager did not call our cancel routine.
  952.             // we need to free the 1) irp, 2) urb and 3) mdl for every 
  953.             // stage and complete the main Irp after releasing the lock
  954.             //
  955.             IsoUsb_DbgPrint(3, ("cancellation routine NOT runn"));
  956.             KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  957.             goto PerformFullSpeedIsochTransfer_Free;
  958.         }
  959.         else {
  960.             
  961.             //
  962.             // The cancel routine will resume the moment we release the lock.
  963.             //
  964.             for(j = 0; j < numIrps; j++) {
  965.                 if(rwContext->SubContext[j].SubUrb) {
  966.                     ExFreePool(rwContext->SubContext[j].SubUrb);
  967.                     rwContext->SubContext[j].SubUrb = NULL;
  968.                 }
  969.                 if(rwContext->SubContext[j].SubMdl) {
  970.                     IoFreeMdl(rwContext->SubContext[j].SubMdl);
  971.                     rwContext->SubContext[j].SubMdl = NULL;
  972.                 }
  973.             }
  974.             IoMarkIrpPending(Irp);
  975.             //
  976.             // it is the job of the cancellation routine to free
  977.             // sub-context irps, release rwContext and complete 
  978.             // the main readwrite irp
  979.             //
  980.             InterlockedDecrement(&rwContext->Lock);
  981.             KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  982.             return STATUS_PENDING;
  983.         }
  984.     }
  985.     else {
  986.         //
  987.         // normal processing
  988.         //
  989.         IsoUsb_DbgPrint(3, ("normal processingn"));
  990.         IoMarkIrpPending(Irp);
  991.         KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  992.         for(j = 0; j < numIrps; j++) {
  993.             IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
  994.             IsoUsb_IoIncrement(deviceExtension);
  995.             
  996.             IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  997.                          rwContext->SubContext[j].SubIrp);
  998.         }
  999.         return STATUS_PENDING;
  1000.     }
  1001. PerformFullSpeedIsochTransfer_Free:
  1002.     for(j = 0; j < numIrps; j++) {
  1003.         if(rwContext->SubContext[j].SubIrp) {
  1004.             IoFreeIrp(rwContext->SubContext[j].SubIrp);
  1005.             rwContext->SubContext[j].SubIrp = NULL;
  1006.         }
  1007.         if(rwContext->SubContext[j].SubUrb) {
  1008.             ExFreePool(rwContext->SubContext[j].SubUrb);
  1009.             rwContext->SubContext[j].SubUrb = NULL;
  1010.         }
  1011.         if(rwContext->SubContext[j].SubMdl) {
  1012.             IoFreeMdl(rwContext->SubContext[j].SubMdl);
  1013.             rwContext->SubContext[j].SubMdl = NULL;
  1014.         }
  1015.     }
  1016.     ExFreePool(rwContext->SubContext);
  1017.     ExFreePool(rwContext);
  1018. PerformFullSpeedIsochTransfer_Exit:
  1019.     Irp->IoStatus.Status = ntStatus;
  1020.     Irp->IoStatus.Information = 0;
  1021.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1022.     IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
  1023.     IsoUsb_IoDecrement(deviceExtension);
  1024.     IsoUsb_DbgPrint(3, ("-------------------------------n"));
  1025.     return ntStatus;
  1026. }
  1027. NTSTATUS
  1028. IsoUsb_SinglePairComplete(
  1029.     IN PDEVICE_OBJECT DeviceObject,
  1030.     IN PIRP           Irp,
  1031.     IN PVOID          Context
  1032.     )
  1033. /*++
  1034.  
  1035. Routine Description:
  1036.     This is the completion routine for the subsidiary irp.
  1037.     For every irp/urb pair, we have allocated
  1038.     1. an irp
  1039.     2. an urb
  1040.     3. a mdl.
  1041.     Case 1:
  1042.     we do NOT free the irp on its completion
  1043.     we do free the urb and the mdl.
  1044.     Case 1 is executed in Block 3.
  1045.     Case 2:
  1046.     when we complete the last of the subsidiary irp,
  1047.     we check if the cancel routine for the main Irp
  1048.     has run. If not, we free all the irps, release
  1049.     the subcontext and the context and complete the
  1050.     main Irp.we also free the urb and mdl for this
  1051.     stage.
  1052.     Case 2 is executed in Block 2.
  1053.     Case 3:
  1054.     when we complete the last of the subsidiary irp,
  1055.     we check if the cancel routine for the main Irp
  1056.     has run. If yes, we atomically decrement the
  1057.     rwContext->Lock field. (the completion routine
  1058.     is in race with Cancel routine). If the count is 1, 
  1059.     the cancel routine will free all the resources.
  1060.     we do free the urb and mdl.
  1061.     it is expected of the cancellation routine to free 
  1062.     all the irps, free the subcontext and the context 
  1063.     and complete the main irp
  1064.     Case 3 is executed in Block 1b.
  1065.     Case 4:
  1066.     when we complete the last of the subsidiary irp,
  1067.     we check if the cancel routine for the main Irp
  1068.     has run. If yes, we atomically decrement the 
  1069.     rwContext->Lock field. (the completion routine
  1070.     is in race with Cancel routine). If the count is 0,
  1071.     we free the irp, subcontext and the context and
  1072.     complete the main irp. we also free the urb and
  1073.     the mdl for this particular stage.
  1074.     the reason we do not free the subsidiary irp at its
  1075.     completion is because the cancellation routine can
  1076.     run any time.
  1077.     Case 4 is executed in Block 1a.
  1078.     
  1079. Arguments:
  1080.     DeviceObject - pointer to device object
  1081.     Irp - I/O request packet
  1082.     Context - context for the completion routine
  1083. Return Value:
  1084.     NT status value
  1085. --*/
  1086. {
  1087.     PURB               urb;
  1088.     PMDL               mdl;
  1089.     PIRP               mainIrp;
  1090.     KIRQL              oldIrql;
  1091.     ULONG              info;
  1092.     NTSTATUS           ntStatus;
  1093.     PDEVICE_EXTENSION  deviceExtension;
  1094.     PISOUSB_RW_CONTEXT rwContext;
  1095.     PIO_STACK_LOCATION irpStack;
  1096.     irpStack = IoGetCurrentIrpStackLocation(Irp);
  1097.     urb = (PURB) irpStack->Parameters.Others.Argument1;
  1098.     mdl = (PMDL) irpStack->Parameters.Others.Argument2;
  1099.     info = 0;
  1100.     ntStatus = Irp->IoStatus.Status;
  1101.     rwContext = (PISOUSB_RW_CONTEXT) Context;
  1102.     deviceExtension = rwContext->DeviceExtension;
  1103.     IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - beginsn"));
  1104.     ASSERT(rwContext);
  1105.     
  1106.     KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  1107.     if(NT_SUCCESS(ntStatus) &&
  1108.        USBD_SUCCESS(urb->UrbHeader.Status)) {
  1109.         rwContext->NumXfer += 
  1110.                 urb->UrbIsochronousTransfer.TransferBufferLength;
  1111.         IsoUsb_DbgPrint(1, ("rwContext->NumXfer = %dn", rwContext->NumXfer));
  1112.     }
  1113.     else {
  1114.         
  1115.         ULONG i;
  1116.         IsoUsb_DbgPrint(1, ("read-write irp failed with status %Xn", ntStatus));
  1117.         IsoUsb_DbgPrint(1, ("urb header status %Xn", urb->UrbHeader.Status));
  1118.         for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  1119.             IsoUsb_DbgPrint(2, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %Xn",
  1120.                                 i,
  1121.                                 urb->UrbIsochronousTransfer.IsoPacket[i].Length,
  1122.                                 i,
  1123.                                 urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  1124.         }
  1125.     }
  1126.     if(InterlockedDecrement(&rwContext->IrpsPending) == 0) {
  1127.         IsoUsb_DbgPrint(3, ("no more irps pendingn"));
  1128.         if(NT_SUCCESS(ntStatus)) {
  1129.             
  1130.             ULONG i;
  1131.         
  1132.             IsoUsb_DbgPrint(1, ("urb start frame %Xn", 
  1133.                                 urb->UrbIsochronousTransfer.StartFrame));
  1134.             for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  1135.                 if(urb->UrbIsochronousTransfer.IsoPacket[i].Length == 0) {
  1136.                     IsoUsb_DbgPrint(2, ("IsoPacket[%d].Status = %Xn",
  1137.                                         i,
  1138.                                         urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  1139.                 }
  1140.             }
  1141.         }
  1142.         mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
  1143.         ASSERT(mainIrp);
  1144.         if(IoSetCancelRoutine(mainIrp, NULL) == NULL) {
  1145.             
  1146.             //
  1147.             // cancel routine has begun the race
  1148.             //
  1149.             // Block 1a.
  1150.             //
  1151.             IsoUsb_DbgPrint(3, ("cancel routine has begun the racen"));
  1152.             if(InterlockedDecrement(&rwContext->Lock) == 0) {
  1153.                 ULONG i;
  1154.                 //
  1155.                 // do the cleanup job ourselves
  1156.                 //
  1157.                 IsoUsb_DbgPrint(3, ("losers do the cleanupn"));
  1158.                 for(i = 0; i < rwContext->NumIrps; i++) {
  1159.                     IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1160.                     rwContext->SubContext[i].SubIrp = NULL;
  1161.                 }
  1162.                 info = rwContext->NumXfer;
  1163.                 KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1164.                 ExFreePool(rwContext->SubContext);
  1165.                 ExFreePool(rwContext);
  1166.                 //
  1167.                 // if we transferred some data, main Irp completes with success
  1168.                 //
  1169.                 IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
  1170.                 IsoUsb_DbgPrint(1, ("***n"));
  1171.                 
  1172.                 mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
  1173.                 mainIrp->IoStatus.Information = info;
  1174.         
  1175.                 IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
  1176.                 IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1177.                 IsoUsb_IoDecrement(deviceExtension);
  1178.                 IsoUsb_DbgPrint(3, ("-------------------------------n"));
  1179.                 goto IsoUsb_SinglePairComplete_Exit;
  1180.             }
  1181.             else {
  1182.                 //
  1183.                 // Block 1b.
  1184.                 //
  1185.                 IsoUsb_DbgPrint(3, ("cancel routine performs the cleanupn"));
  1186.             }
  1187.         }
  1188.         else {
  1189.             //
  1190.             // Block 2.
  1191.             //
  1192.             ULONG i;
  1193.             IsoUsb_DbgPrint(3, ("cancel routine has NOT runn"));
  1194.             for(i = 0; i < rwContext->NumIrps; i++) {
  1195.                 IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1196.                 rwContext->SubContext[i].SubIrp = NULL;
  1197.             }
  1198.             info = rwContext->NumXfer;
  1199.             KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1200.             ExFreePool(rwContext->SubContext);
  1201.             ExFreePool(rwContext);
  1202.             //
  1203.             // if we transferred some data, main Irp completes with success
  1204.             //
  1205.             IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
  1206.             IsoUsb_DbgPrint(1, ("***n"));
  1207.             
  1208.             mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
  1209.             mainIrp->IoStatus.Information = info;
  1210.         
  1211.             IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
  1212.             IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1213.             IsoUsb_IoDecrement(deviceExtension);
  1214.             IsoUsb_DbgPrint(3, ("-------------------------------n"));
  1215.             goto IsoUsb_SinglePairComplete_Exit;
  1216.         }
  1217.     }
  1218.     KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1219. IsoUsb_SinglePairComplete_Exit:
  1220.     //
  1221.     // Block 3.
  1222.     //
  1223.     ExFreePool(urb);
  1224.     IoFreeMdl(mdl);
  1225.     IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1226.     IsoUsb_IoDecrement(deviceExtension);
  1227.     IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - endsn"));
  1228.     return STATUS_MORE_PROCESSING_REQUIRED;
  1229. }
  1230. VOID
  1231. IsoUsb_CancelReadWrite(
  1232.     IN PDEVICE_OBJECT DeviceObject,
  1233.     IN PIRP           Irp
  1234.     )
  1235. /*++
  1236.  
  1237. Routine Description:
  1238.     This is the cancellation routine for the main read/write Irp.
  1239.     The policy is as follows:
  1240.     If the cancellation routine is the last to decrement
  1241.     rwContext->Lock, then free the irps, subcontext and
  1242.     the context. Complete the main irp
  1243.     
  1244.     Otherwise, call IoCancelIrp on each of the subsidiary irp.
  1245.     It is valid to call IoCancelIrp on irps for which the 
  1246.     completion routine has executed, because, we do not free the
  1247.     irps in the completion routine.
  1248. Arguments:
  1249.     DeviceObject - pointer to device object
  1250.     Irp - I/O request packet
  1251. Return Value:
  1252.     None
  1253. --*/
  1254. {
  1255.     PIRP               mainIrp;
  1256.     KIRQL              oldIrql;
  1257.     ULONG              i;
  1258.     ULONG              info;
  1259.     PDEVICE_EXTENSION  deviceExtension;
  1260.     PISOUSB_RW_CONTEXT rwContext;
  1261.     //
  1262.     // initialize vars
  1263.     //
  1264.     info = 0;
  1265.     IoReleaseCancelSpinLock(Irp->CancelIrql);
  1266.     IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - beginsn"));
  1267.     rwContext = (PISOUSB_RW_CONTEXT) Irp->Tail.Overlay.DriverContext[0];
  1268.     ASSERT(rwContext);
  1269.     deviceExtension = rwContext->DeviceExtension;
  1270.     KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  1271.     if(InterlockedDecrement(&rwContext->Lock)) {
  1272.         IsoUsb_DbgPrint(3, ("about to cancel sub context irps..n"));
  1273.         for(i = 0; i < rwContext->NumIrps; i++) {
  1274.             if(rwContext->SubContext[i].SubIrp) {
  1275.                 IoCancelIrp(rwContext->SubContext[i].SubIrp);
  1276.             }
  1277.         }
  1278.         KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1279.         IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - endsn"));
  1280.         return;
  1281.     }
  1282.     else {
  1283.         ULONG i;
  1284.         for(i = 0; i < rwContext->NumIrps; i++) {
  1285.             IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1286.             rwContext->SubContext[i].SubIrp = NULL;
  1287.         }
  1288.         mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
  1289.         info = rwContext->NumXfer;
  1290.         KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1291.         ExFreePool(rwContext->SubContext);
  1292.         ExFreePool(rwContext);
  1293.         //
  1294.         // if we transferred some data, main Irp completes with success
  1295.         //
  1296.         IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
  1297.         IsoUsb_DbgPrint(1, ("***n"));
  1298.         Irp->IoStatus.Status = STATUS_SUCCESS;
  1299.         Irp->IoStatus.Status = info;
  1300. /*        
  1301.         Irp->IoStatus.Status = STATUS_CANCELLED;
  1302.         Irp->IoStatus.Information = 0;
  1303. */
  1304.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1305.         IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite::"));
  1306.         IsoUsb_IoDecrement(deviceExtension);
  1307.         IsoUsb_DbgPrint(3, ("-------------------------------n"));
  1308.         return;
  1309.     }
  1310. }
  1311. ULONG
  1312. IsoUsb_GetCurrentFrame(
  1313.     IN PDEVICE_OBJECT DeviceObject,
  1314.     IN PIRP           Irp
  1315.     )
  1316. /*++
  1317.  
  1318. Routine Description:
  1319.     This routine send an irp/urb pair with
  1320.     function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
  1321.     to fetch the current frame
  1322. Arguments:
  1323.     DeviceObject - pointer to device object
  1324.     PIRP - I/O request packet
  1325. Return Value:
  1326.     Current frame
  1327. --*/
  1328. {
  1329.     KEVENT                               event;
  1330.     PDEVICE_EXTENSION                    deviceExtension;
  1331.     PIO_STACK_LOCATION                   nextStack;
  1332.     struct _URB_GET_CURRENT_FRAME_NUMBER urb;
  1333.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1334.     //
  1335.     // initialize the urb
  1336.     //
  1337.     IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - beginsn"));
  1338.     urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
  1339.     urb.Hdr.Length = sizeof(urb);
  1340.     urb.FrameNumber = (ULONG) -1;
  1341.     nextStack = IoGetNextIrpStackLocation(Irp);
  1342.     nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
  1343.     nextStack->Parameters.DeviceIoControl.IoControlCode = 
  1344.                                 IOCTL_INTERNAL_USB_SUBMIT_URB;
  1345.     nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1346.     KeInitializeEvent(&event,
  1347.                       NotificationEvent,
  1348.                       FALSE);
  1349.     IoSetCompletionRoutine(Irp,
  1350.                            IsoUsb_StopCompletion,
  1351.                            &event,
  1352.                            TRUE,
  1353.                            TRUE,
  1354.                            TRUE);
  1355.     IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
  1356.     IsoUsb_IoIncrement(deviceExtension);
  1357.     IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  1358.                  Irp);
  1359.     KeWaitForSingleObject((PVOID) &event,
  1360.                           Executive,
  1361.                           KernelMode,
  1362.                           FALSE,
  1363.                           NULL);
  1364.     IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
  1365.     IsoUsb_IoDecrement(deviceExtension);
  1366.     IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - endsn"));
  1367.     return urb.FrameNumber;
  1368. }
  1369. NTSTATUS
  1370. IsoUsb_StopCompletion(
  1371.     IN PDEVICE_OBJECT DeviceObject,
  1372.     IN PIRP           Irp,
  1373.     IN PVOID          Context
  1374.     )
  1375. /*++
  1376.  
  1377. Routine Description:
  1378.     This is the completion routine for request to retrieve the frame number
  1379. Arguments:
  1380.     DeviceObject - pointer to device object
  1381.     Irp - I/O request packet
  1382.     Context - context passed to the completion routine
  1383. Return Value:
  1384.     NT status value
  1385. --*/
  1386. {
  1387.     PKEVENT event;
  1388.     IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - beginsn"));
  1389.     event = (PKEVENT) Context;
  1390.     KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  1391.     IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - endsn"));
  1392.     return STATUS_MORE_PROCESSING_REQUIRED;
  1393. }