isorwr.c
资源名称:isousb.rar [点击查看]
上传用户:leituo004
上传日期:2014-11-03
资源大小:159k
文件大小:54k
源码类别:
驱动编程
开发平台:
Visual C++
- /*++
- 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 - beginsn"));
- IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
- IsoUsb_IoIncrement(deviceExtension);
- if(deviceExtension->DeviceState != Working) {
- IsoUsb_DbgPrint(1, ("Invalid device staten"));
- 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 IdleReqPendEventn"));
- 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 staten"));
- ntStatus = STATUS_INVALID_DEVICE_STATE;
- goto IsoUsb_DispatchReadWrite_Exit;
- }
- if((pipeInformation == NULL) ||
- (UsbdPipeTypeIsochronous != pipeInformation->PipeType)) {
- IsoUsb_DbgPrint(1, ("Incorrect pipen"));
- 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 = 0n"));
- ntStatus = STATUS_SUCCESS;
- goto IsoUsb_DispatchReadWrite_Exit;
- }
- //
- // each packet can hold this much info
- //
- packetSize = pipeInformation->MaximumPacketSize;
- if(packetSize == 0) {
- IsoUsb_DbgPrint(1, ("Invalid parametern"));
- 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 = %dn", TotalLength));
- IsoUsb_DbgPrint(1, ("PacketSize = %dn", packetSize));
- IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
- numberOfPacketsFilledToBrim,
- packetSize));
- }
- else {
- dataLeftToBeDistributed = TotalLength -
- (minDataInEachPacket * actualPackets);
- numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
- (packetSize - minDataInEachPacket);
- dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
- (packetSize - minDataInEachPacket));
- IsoUsb_DbgPrint(1, ("TotalLength = %dn", TotalLength));
- IsoUsb_DbgPrint(1, ("PacketSize = %dn", packetSize));
- IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
- numberOfPacketsFilledToBrim,
- packetSize));
- if(dataLeftToBeDistributed) {
- IsoUsb_DbgPrint(1, ("One packet has %d bytesn",
- minDataInEachPacket + dataLeftToBeDistributed));
- IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
- actualPackets - (numberOfPacketsFilledToBrim + 1),
- minDataInEachPacket));
- }
- else {
- IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytesn",
- 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 = %dn", 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 rwContextn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformHighSpeedIsochTransfer_Exit;
- }
- RtlZeroMemory(rwContext, contextSize);
- //
- // allocate memory for every stage context -
- // subcontext has state information for every irp/urb pair.
- //
- rwContext->SubContext = (PSUB_CONTEXT)
- ExAllocatePool(NonPagedPool,
- numIrps * sizeof(SUB_CONTEXT));
- if(rwContext->SubContext == NULL) {
- IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContextn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- ExFreePool(rwContext);
- goto PerformHighSpeedIsochTransfer_Exit;
- }
- RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
- rwContext->RWIrp = Irp;
- rwContext->Lock = 2;
- rwContext->NumIrps = numIrps;
- rwContext->IrpsPending = numIrps;
- rwContext->DeviceExtension = deviceExtension;
- KeInitializeSpinLock(&rwContext->SpinLock);
- //
- // save the rwContext pointer in the tail union.
- //
- Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
- stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
- virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
- for(i = 0; i < numIrps; i++) {
- PIRP subIrp;
- PURB subUrb;
- PMDL subMdl;
- ULONG nPackets;
- ULONG siz;
- ULONG offset;
- //
- // for every stage of transfer we need to do the following
- // tasks
- // 1. allocate an irp
- // 2. allocate an urb
- // 3. allocate a mdl.
- //
- // create a subsidiary irp
- //
- subIrp = IoAllocateIrp(stackSize, FALSE);
- if(subIrp == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irpn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformHighSpeedIsochTransfer_Free;
- }
- rwContext->SubContext[i].SubIrp = subIrp;
- if(actualPackets <= 1024) {
- nPackets = actualPackets;
- actualPackets = 0;
- }
- else {
- nPackets = 1024;
- actualPackets -= 1024;
- }
- IsoUsb_DbgPrint(1, ("nPackets = %d for Irp/URB pair %dn", nPackets, i));
- ASSERT(nPackets <= 1024);
- siz = GET_ISO_URB_SIZE(nPackets);
- //
- // create a subsidiary urb.
- //
- subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
- if(subUrb == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urbn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformHighSpeedIsochTransfer_Free;
- }
- rwContext->SubContext[i].SubUrb = subUrb;
- if(nPackets > numberOfPacketsFilledToBrim) {
- stageSize = packetSize * numberOfPacketsFilledToBrim;
- stageSize += (minDataInEachPacket *
- (nPackets - numberOfPacketsFilledToBrim));
- stageSize += dataLeftToBeDistributed;
- }
- else {
- stageSize = packetSize * nPackets;
- }
- //
- // allocate a mdl.
- //
- subMdl = IoAllocateMdl((PVOID) virtualAddress,
- stageSize,
- FALSE,
- FALSE,
- NULL);
- if(subMdl == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdln"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformHighSpeedIsochTransfer_Free;
- }
- IoBuildPartialMdl(Irp->MdlAddress,
- subMdl,
- (PVOID) virtualAddress,
- stageSize);
- rwContext->SubContext[i].SubMdl = subMdl;
- virtualAddress += stageSize;
- TotalLength -= stageSize;
- //
- // Initialize the subsidiary urb
- //
- RtlZeroMemory(subUrb, siz);
- subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
- subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
- subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
- if(read) {
- IsoUsb_DbgPrint(1, ("readn"));
- subUrb->UrbIsochronousTransfer.TransferFlags =
- USBD_TRANSFER_DIRECTION_IN;
- }
- else {
- IsoUsb_DbgPrint(1, ("writen"));
- subUrb->UrbIsochronousTransfer.TransferFlags =
- USBD_TRANSFER_DIRECTION_OUT;
- }
- subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
- subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
- /*
- This is a way to set the start frame and NOT specify ASAP flag.
- subUrb->UrbIsochronousTransfer.StartFrame =
- IsoUsb_GetCurrentFrame(DeviceObject, Irp) +
- SOME_LATENCY;
- */
- subUrb->UrbIsochronousTransfer.TransferFlags |=
- USBD_START_ISO_TRANSFER_ASAP;
- subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
- subUrb->UrbIsochronousTransfer.UrbLink = NULL;
- //
- // set the offsets for every packet for reads/writes
- //
- if(read) {
- offset = 0;
- for(j = 0; j < nPackets; j++) {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
- if(numberOfPacketsFilledToBrim) {
- offset += packetSize;
- numberOfPacketsFilledToBrim--;
- stageSize -= packetSize;
- }
- else if(dataLeftToBeDistributed) {
- offset += (minDataInEachPacket + dataLeftToBeDistributed);
- stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
- dataLeftToBeDistributed = 0;
- }
- else {
- offset += minDataInEachPacket;
- stageSize -= minDataInEachPacket;
- }
- }
- ASSERT(stageSize == 0);
- }
- else {
- offset = 0;
- for(j = 0; j < nPackets; j++) {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
- if(numberOfPacketsFilledToBrim) {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
- offset += packetSize;
- numberOfPacketsFilledToBrim--;
- stageSize -= packetSize;
- }
- else if(dataLeftToBeDistributed) {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Length =
- minDataInEachPacket + dataLeftToBeDistributed;
- offset += (minDataInEachPacket + dataLeftToBeDistributed);
- stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
- dataLeftToBeDistributed = 0;
- }
- else {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = minDataInEachPacket;
- offset += minDataInEachPacket;
- stageSize -= minDataInEachPacket;
- }
- }
- ASSERT(stageSize == 0);
- }
- IoSetNextIrpStackLocation(subIrp);
- nextStack = IoGetCurrentIrpStackLocation(subIrp);
- nextStack->DeviceObject = DeviceObject;
- nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
- nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
- nextStack = IoGetNextIrpStackLocation(subIrp);
- nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
- nextStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_INTERNAL_USB_SUBMIT_URB;
- IoSetCompletionRoutine(subIrp,
- (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
- (PVOID) rwContext,
- TRUE,
- TRUE,
- TRUE);
- }
- //
- // while we were busy create subsidiary irp/urb pairs..
- // the main read/write irp may have been cancelled !!
- //
- KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
- IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
- if(Irp->Cancel) {
- //
- // The Cancel flag for the Irp has been set.
- //
- IsoUsb_DbgPrint(3, ("Cancel flag setn"));
- ntStatus = STATUS_CANCELLED;
- if(IoSetCancelRoutine(Irp, NULL)) {
- //
- // But the I/O manager did not call our cancel routine.
- // we need to free the 1) irp, 2) urb and 3) mdl for every
- // stage and complete the main Irp after releasing the lock
- //
- IsoUsb_DbgPrint(3, ("cancellation routine NOT runn"));
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- goto PerformHighSpeedIsochTransfer_Free;
- }
- else {
- //
- // The cancel routine will resume the moment we release the lock.
- //
- for(j = 0; j < numIrps; j++) {
- if(rwContext->SubContext[j].SubUrb) {
- ExFreePool(rwContext->SubContext[j].SubUrb);
- rwContext->SubContext[j].SubUrb = NULL;
- }
- if(rwContext->SubContext[j].SubMdl) {
- IoFreeMdl(rwContext->SubContext[j].SubMdl);
- rwContext->SubContext[j].SubMdl = NULL;
- }
- }
- IoMarkIrpPending(Irp);
- //
- // it is the job of the cancellation routine to free
- // sub-context irps, release rwContext and complete
- // the main readwrite irp
- //
- InterlockedDecrement(&rwContext->Lock);
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- return STATUS_PENDING;
- }
- }
- else {
- //
- // normal processing
- //
- IsoUsb_DbgPrint(3, ("normal processingn"));
- IoMarkIrpPending(Irp);
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- for(j = 0; j < numIrps; j++) {
- IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
- IsoUsb_IoIncrement(deviceExtension);
- IoCallDriver(deviceExtension->TopOfStackDeviceObject,
- rwContext->SubContext[j].SubIrp);
- }
- return STATUS_PENDING;
- }
- PerformHighSpeedIsochTransfer_Free:
- for(j = 0; j < numIrps; j++) {
- if(rwContext->SubContext[j].SubIrp) {
- IoFreeIrp(rwContext->SubContext[j].SubIrp);
- rwContext->SubContext[j].SubIrp = NULL;
- }
- if(rwContext->SubContext[j].SubUrb) {
- ExFreePool(rwContext->SubContext[j].SubUrb);
- rwContext->SubContext[j].SubUrb = NULL;
- }
- if(rwContext->SubContext[j].SubMdl) {
- IoFreeMdl(rwContext->SubContext[j].SubMdl);
- rwContext->SubContext[j].SubMdl = NULL;
- }
- }
- ExFreePool(rwContext->SubContext);
- ExFreePool(rwContext);
- PerformHighSpeedIsochTransfer_Exit:
- Irp->IoStatus.Status = ntStatus;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("-------------------------------n"));
- return ntStatus;
- }
- NTSTATUS
- PerformFullSpeedIsochTransfer(
- IN PDEVICE_OBJECT DeviceObject,
- IN PUSBD_PIPE_INFORMATION PipeInformation,
- IN PIRP Irp,
- IN ULONG TotalLength
- )
- /*++
- Routine Description:
- This routine
- 1. creates a ISOUSB_RW_CONTEXT for every
- read/write to be performed.
- 2. creates SUB_CONTEXT for each irp/urb pair.
- (Each irp/urb pair can transfer only 255 packets.)
- 3. All the irp/urb pairs are initialized
- 4. The subsidiary irps (of the irp/urb pair) are passed
- down the stack at once.
- 5. The main Read/Write irp is pending
- Arguments:
- DeviceObject - pointer to device object
- PipeInformation - USBD_PIPE_INFORMATION
- Irp - I/O request packet
- TotalLength - no. of bytes to be transferred
- Return Value:
- NT status value
- --*/
- {
- ULONG i;
- ULONG j;
- ULONG packetSize;
- ULONG numIrps;
- ULONG stageSize;
- ULONG contextSize;
- CCHAR stackSize;
- KIRQL oldIrql;
- PUCHAR virtualAddress;
- BOOLEAN read;
- NTSTATUS ntStatus;
- PDEVICE_EXTENSION deviceExtension;
- PIO_STACK_LOCATION irpStack;
- PIO_STACK_LOCATION nextStack;
- PISOUSB_RW_CONTEXT rwContext;
- //
- // initialize vars
- //
- irpStack = IoGetCurrentIrpStackLocation(Irp);
- read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
- deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
- IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer - beginsn"));
- /*
- if(read) {
- pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX];
- }
- else {
- pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_OUT_PIPE_INDEX];
- }
- */
- //
- // each packet can hold this much info
- //
- packetSize = PipeInformation->MaximumPacketSize;
- IsoUsb_DbgPrint(3, ("totalLength = %dn", TotalLength));
- IsoUsb_DbgPrint(3, ("packetSize = %dn", packetSize));
- //
- // there is an inherent limit on the number of packets
- // that can be passed down the stack with each
- // irp/urb pair (255)
- // if the number of required packets is > 255,
- // we shall create "required-packets / 255 + 1" number
- // of irp/urb pairs.
- // Each irp/urb pair transfer is also called a stage transfer.
- //
- if(TotalLength > (packetSize * 255)) {
- stageSize = packetSize * 255;
- }
- else {
- stageSize = TotalLength;
- }
- IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::stageSize = %dn", stageSize));
- //
- // 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 = (TotalLength + stageSize - 1) / stageSize;
- IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::numIrps = %dn", 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 rwContextn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformFullSpeedIsochTransfer_Exit;
- }
- RtlZeroMemory(rwContext, contextSize);
- //
- // allocate memory for every stage context -
- // subcontext has state information for every irp/urb pair.
- //
- rwContext->SubContext = (PSUB_CONTEXT)
- ExAllocatePool(NonPagedPool,
- numIrps * sizeof(SUB_CONTEXT));
- if(rwContext->SubContext == NULL) {
- IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContextn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- ExFreePool(rwContext);
- goto PerformFullSpeedIsochTransfer_Exit;
- }
- RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
- rwContext->RWIrp = Irp;
- rwContext->Lock = 2;
- rwContext->NumIrps = numIrps;
- rwContext->IrpsPending = numIrps;
- rwContext->DeviceExtension = deviceExtension;
- KeInitializeSpinLock(&rwContext->SpinLock);
- //
- // save the rwContext pointer in the tail union.
- //
- Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
- stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
- virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
- for(i = 0; i < numIrps; i++) {
- PIRP subIrp;
- PURB subUrb;
- PMDL subMdl;
- ULONG nPackets;
- ULONG siz;
- ULONG offset;
- //
- // for every stage of transfer we need to do the following
- // tasks
- // 1. allocate an irp
- // 2. allocate an urb
- // 3. allocate a mdl.
- //
- // create a subsidiary irp
- //
- subIrp = IoAllocateIrp(stackSize, FALSE);
- if(subIrp == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irpn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformFullSpeedIsochTransfer_Free;
- }
- rwContext->SubContext[i].SubIrp = subIrp;
- nPackets = (stageSize + packetSize - 1) / packetSize;
- IsoUsb_DbgPrint(3, ("nPackets = %d for Irp/URB pair %dn", nPackets, i));
- ASSERT(nPackets <= 255);
- siz = GET_ISO_URB_SIZE(nPackets);
- //
- // create a subsidiary urb.
- //
- subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
- if(subUrb == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urbn"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformFullSpeedIsochTransfer_Free;
- }
- rwContext->SubContext[i].SubUrb = subUrb;
- //
- // allocate a mdl.
- //
- subMdl = IoAllocateMdl((PVOID) virtualAddress,
- stageSize,
- FALSE,
- FALSE,
- NULL);
- if(subMdl == NULL) {
- IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdln"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto PerformFullSpeedIsochTransfer_Free;
- }
- IoBuildPartialMdl(Irp->MdlAddress,
- subMdl,
- (PVOID) virtualAddress,
- stageSize);
- rwContext->SubContext[i].SubMdl = subMdl;
- virtualAddress += stageSize;
- TotalLength -= stageSize;
- //
- // Initialize the subsidiary urb
- //
- RtlZeroMemory(subUrb, siz);
- subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
- subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
- subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
- if(read) {
- IsoUsb_DbgPrint(3, ("readn"));
- subUrb->UrbIsochronousTransfer.TransferFlags =
- USBD_TRANSFER_DIRECTION_IN;
- }
- else {
- IsoUsb_DbgPrint(3, ("writen"));
- 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;
- subUrb->UrbIsochronousTransfer.UrbLink = NULL;
- //
- // set the offsets for every packet for reads/writes
- //
- if(read) {
- offset = 0;
- for(j = 0; j < nPackets; j++) {
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
- subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
- if(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));
- }
- }
- }
- IoSetNextIrpStackLocation(subIrp);
- nextStack = IoGetCurrentIrpStackLocation(subIrp);
- nextStack->DeviceObject = DeviceObject;
- nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
- nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
- nextStack = IoGetNextIrpStackLocation(subIrp);
- nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
- nextStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_INTERNAL_USB_SUBMIT_URB;
- IoSetCompletionRoutine(subIrp,
- (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
- (PVOID) rwContext,
- TRUE,
- TRUE,
- TRUE);
- 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 !!
- //
- KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
- IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
- if(Irp->Cancel) {
- //
- // The Cancel flag for the Irp has been set.
- //
- IsoUsb_DbgPrint(3, ("Cancel flag setn"));
- ntStatus = STATUS_CANCELLED;
- if(IoSetCancelRoutine(Irp, NULL)) {
- //
- // But the I/O manager did not call our cancel routine.
- // we need to free the 1) irp, 2) urb and 3) mdl for every
- // stage and complete the main Irp after releasing the lock
- //
- IsoUsb_DbgPrint(3, ("cancellation routine NOT runn"));
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- goto PerformFullSpeedIsochTransfer_Free;
- }
- else {
- //
- // The cancel routine will resume the moment we release the lock.
- //
- for(j = 0; j < numIrps; j++) {
- if(rwContext->SubContext[j].SubUrb) {
- ExFreePool(rwContext->SubContext[j].SubUrb);
- rwContext->SubContext[j].SubUrb = NULL;
- }
- if(rwContext->SubContext[j].SubMdl) {
- IoFreeMdl(rwContext->SubContext[j].SubMdl);
- rwContext->SubContext[j].SubMdl = NULL;
- }
- }
- IoMarkIrpPending(Irp);
- //
- // it is the job of the cancellation routine to free
- // sub-context irps, release rwContext and complete
- // the main readwrite irp
- //
- InterlockedDecrement(&rwContext->Lock);
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- return STATUS_PENDING;
- }
- }
- else {
- //
- // normal processing
- //
- IsoUsb_DbgPrint(3, ("normal processingn"));
- IoMarkIrpPending(Irp);
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- for(j = 0; j < numIrps; j++) {
- IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
- IsoUsb_IoIncrement(deviceExtension);
- IoCallDriver(deviceExtension->TopOfStackDeviceObject,
- rwContext->SubContext[j].SubIrp);
- }
- return STATUS_PENDING;
- }
- PerformFullSpeedIsochTransfer_Free:
- for(j = 0; j < numIrps; j++) {
- if(rwContext->SubContext[j].SubIrp) {
- IoFreeIrp(rwContext->SubContext[j].SubIrp);
- rwContext->SubContext[j].SubIrp = NULL;
- }
- if(rwContext->SubContext[j].SubUrb) {
- ExFreePool(rwContext->SubContext[j].SubUrb);
- rwContext->SubContext[j].SubUrb = NULL;
- }
- if(rwContext->SubContext[j].SubMdl) {
- IoFreeMdl(rwContext->SubContext[j].SubMdl);
- rwContext->SubContext[j].SubMdl = NULL;
- }
- }
- ExFreePool(rwContext->SubContext);
- ExFreePool(rwContext);
- PerformFullSpeedIsochTransfer_Exit:
- 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
- IsoUsb_SinglePairComplete(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
- /*++
- Routine Description:
- This is the completion routine for the subsidiary irp.
- For every irp/urb pair, we have allocated
- 1. an irp
- 2. an urb
- 3. a mdl.
- Case 1:
- we do NOT free the irp on its completion
- we do free the urb and the mdl.
- Case 1 is executed in Block 3.
- Case 2:
- when we complete the last of the subsidiary irp,
- we check if the cancel routine for the main Irp
- has run. If not, we free all the irps, release
- the subcontext and the context and complete the
- main Irp.we also free the urb and mdl for this
- stage.
- Case 2 is executed in Block 2.
- Case 3:
- when we complete the last of the subsidiary irp,
- we check if the cancel routine for the main Irp
- has run. If yes, we atomically decrement the
- rwContext->Lock field. (the completion routine
- is in race with Cancel routine). If the count is 1,
- the cancel routine will free all the resources.
- we do free the urb and mdl.
- it is expected of the cancellation routine to free
- all the irps, free the subcontext and the context
- and complete the main irp
- Case 3 is executed in Block 1b.
- Case 4:
- when we complete the last of the subsidiary irp,
- we check if the cancel routine for the main Irp
- has run. If yes, we atomically decrement the
- rwContext->Lock field. (the completion routine
- is in race with Cancel routine). If the count is 0,
- we free the irp, subcontext and the context and
- complete the main irp. we also free the urb and
- the mdl for this particular stage.
- the reason we do not free the subsidiary irp at its
- completion is because the cancellation routine can
- run any time.
- Case 4 is executed in Block 1a.
- Arguments:
- DeviceObject - pointer to device object
- Irp - I/O request packet
- Context - context for the completion routine
- Return Value:
- NT status value
- --*/
- {
- PURB urb;
- PMDL mdl;
- PIRP mainIrp;
- KIRQL oldIrql;
- ULONG info;
- NTSTATUS ntStatus;
- PDEVICE_EXTENSION deviceExtension;
- PISOUSB_RW_CONTEXT rwContext;
- PIO_STACK_LOCATION irpStack;
- irpStack = IoGetCurrentIrpStackLocation(Irp);
- urb = (PURB) irpStack->Parameters.Others.Argument1;
- mdl = (PMDL) irpStack->Parameters.Others.Argument2;
- info = 0;
- ntStatus = Irp->IoStatus.Status;
- rwContext = (PISOUSB_RW_CONTEXT) Context;
- deviceExtension = rwContext->DeviceExtension;
- IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - beginsn"));
- ASSERT(rwContext);
- KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
- if(NT_SUCCESS(ntStatus) &&
- USBD_SUCCESS(urb->UrbHeader.Status)) {
- rwContext->NumXfer +=
- urb->UrbIsochronousTransfer.TransferBufferLength;
- IsoUsb_DbgPrint(1, ("rwContext->NumXfer = %dn", rwContext->NumXfer));
- }
- else {
- ULONG i;
- IsoUsb_DbgPrint(1, ("read-write irp failed with status %Xn", ntStatus));
- IsoUsb_DbgPrint(1, ("urb header status %Xn", urb->UrbHeader.Status));
- for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
- IsoUsb_DbgPrint(2, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %Xn",
- i,
- urb->UrbIsochronousTransfer.IsoPacket[i].Length,
- i,
- urb->UrbIsochronousTransfer.IsoPacket[i].Status));
- }
- }
- if(InterlockedDecrement(&rwContext->IrpsPending) == 0) {
- IsoUsb_DbgPrint(3, ("no more irps pendingn"));
- if(NT_SUCCESS(ntStatus)) {
- ULONG i;
- IsoUsb_DbgPrint(1, ("urb start frame %Xn",
- urb->UrbIsochronousTransfer.StartFrame));
- for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
- if(urb->UrbIsochronousTransfer.IsoPacket[i].Length == 0) {
- IsoUsb_DbgPrint(2, ("IsoPacket[%d].Status = %Xn",
- i,
- urb->UrbIsochronousTransfer.IsoPacket[i].Status));
- }
- }
- }
- mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
- ASSERT(mainIrp);
- if(IoSetCancelRoutine(mainIrp, NULL) == NULL) {
- //
- // cancel routine has begun the race
- //
- // Block 1a.
- //
- IsoUsb_DbgPrint(3, ("cancel routine has begun the racen"));
- if(InterlockedDecrement(&rwContext->Lock) == 0) {
- ULONG i;
- //
- // do the cleanup job ourselves
- //
- IsoUsb_DbgPrint(3, ("losers do the cleanupn"));
- for(i = 0; i < rwContext->NumIrps; i++) {
- IoFreeIrp(rwContext->SubContext[i].SubIrp);
- rwContext->SubContext[i].SubIrp = NULL;
- }
- info = rwContext->NumXfer;
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- ExFreePool(rwContext->SubContext);
- ExFreePool(rwContext);
- //
- // if we transferred some data, main Irp completes with success
- //
- IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
- IsoUsb_DbgPrint(1, ("***n"));
- mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
- mainIrp->IoStatus.Information = info;
- IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
- IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("-------------------------------n"));
- goto IsoUsb_SinglePairComplete_Exit;
- }
- else {
- //
- // Block 1b.
- //
- IsoUsb_DbgPrint(3, ("cancel routine performs the cleanupn"));
- }
- }
- else {
- //
- // Block 2.
- //
- ULONG i;
- IsoUsb_DbgPrint(3, ("cancel routine has NOT runn"));
- for(i = 0; i < rwContext->NumIrps; i++) {
- IoFreeIrp(rwContext->SubContext[i].SubIrp);
- rwContext->SubContext[i].SubIrp = NULL;
- }
- info = rwContext->NumXfer;
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- ExFreePool(rwContext->SubContext);
- ExFreePool(rwContext);
- //
- // if we transferred some data, main Irp completes with success
- //
- IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
- IsoUsb_DbgPrint(1, ("***n"));
- mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
- mainIrp->IoStatus.Information = info;
- IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
- IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("-------------------------------n"));
- goto IsoUsb_SinglePairComplete_Exit;
- }
- }
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- IsoUsb_SinglePairComplete_Exit:
- //
- // Block 3.
- //
- ExFreePool(urb);
- IoFreeMdl(mdl);
- IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - endsn"));
- return STATUS_MORE_PROCESSING_REQUIRED;
- }
- VOID
- IsoUsb_CancelReadWrite(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
- /*++
- Routine Description:
- This is the cancellation routine for the main read/write Irp.
- The policy is as follows:
- If the cancellation routine is the last to decrement
- rwContext->Lock, then free the irps, subcontext and
- the context. Complete the main irp
- Otherwise, call IoCancelIrp on each of the subsidiary irp.
- It is valid to call IoCancelIrp on irps for which the
- completion routine has executed, because, we do not free the
- irps in the completion routine.
- Arguments:
- DeviceObject - pointer to device object
- Irp - I/O request packet
- Return Value:
- None
- --*/
- {
- PIRP mainIrp;
- KIRQL oldIrql;
- ULONG i;
- ULONG info;
- PDEVICE_EXTENSION deviceExtension;
- PISOUSB_RW_CONTEXT rwContext;
- //
- // initialize vars
- //
- info = 0;
- IoReleaseCancelSpinLock(Irp->CancelIrql);
- IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - beginsn"));
- rwContext = (PISOUSB_RW_CONTEXT) Irp->Tail.Overlay.DriverContext[0];
- ASSERT(rwContext);
- deviceExtension = rwContext->DeviceExtension;
- KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
- if(InterlockedDecrement(&rwContext->Lock)) {
- IsoUsb_DbgPrint(3, ("about to cancel sub context irps..n"));
- for(i = 0; i < rwContext->NumIrps; i++) {
- if(rwContext->SubContext[i].SubIrp) {
- IoCancelIrp(rwContext->SubContext[i].SubIrp);
- }
- }
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - endsn"));
- return;
- }
- else {
- ULONG i;
- for(i = 0; i < rwContext->NumIrps; i++) {
- IoFreeIrp(rwContext->SubContext[i].SubIrp);
- rwContext->SubContext[i].SubIrp = NULL;
- }
- mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
- info = rwContext->NumXfer;
- KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
- ExFreePool(rwContext->SubContext);
- ExFreePool(rwContext);
- //
- // if we transferred some data, main Irp completes with success
- //
- IsoUsb_DbgPrint(1, ("Total data transferred = %Xn", info));
- IsoUsb_DbgPrint(1, ("***n"));
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Status = info;
- /*
- Irp->IoStatus.Status = STATUS_CANCELLED;
- Irp->IoStatus.Information = 0;
- */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("-------------------------------n"));
- return;
- }
- }
- ULONG
- IsoUsb_GetCurrentFrame(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
- /*++
- Routine Description:
- This routine send an irp/urb pair with
- function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
- to fetch the current frame
- Arguments:
- DeviceObject - pointer to device object
- PIRP - I/O request packet
- Return Value:
- Current frame
- --*/
- {
- KEVENT event;
- PDEVICE_EXTENSION deviceExtension;
- PIO_STACK_LOCATION nextStack;
- struct _URB_GET_CURRENT_FRAME_NUMBER urb;
- deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
- //
- // initialize the urb
- //
- IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - beginsn"));
- urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
- urb.Hdr.Length = sizeof(urb);
- urb.FrameNumber = (ULONG) -1;
- nextStack = IoGetNextIrpStackLocation(Irp);
- nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
- nextStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_INTERNAL_USB_SUBMIT_URB;
- nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- KeInitializeEvent(&event,
- NotificationEvent,
- FALSE);
- IoSetCompletionRoutine(Irp,
- IsoUsb_StopCompletion,
- &event,
- TRUE,
- TRUE,
- TRUE);
- IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
- IsoUsb_IoIncrement(deviceExtension);
- IoCallDriver(deviceExtension->TopOfStackDeviceObject,
- Irp);
- KeWaitForSingleObject((PVOID) &event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
- IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
- IsoUsb_IoDecrement(deviceExtension);
- IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - endsn"));
- return urb.FrameNumber;
- }
- NTSTATUS
- IsoUsb_StopCompletion(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
- /*++
- Routine Description:
- This is the completion routine for request to retrieve the frame number
- Arguments:
- DeviceObject - pointer to device object
- Irp - I/O request packet
- Context - context passed to the completion routine
- Return Value:
- NT status value
- --*/
- {
- PKEVENT event;
- IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - beginsn"));
- event = (PKEVENT) Context;
- KeSetEvent(event, IO_NO_INCREMENT, FALSE);
- IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - endsn"));
- return STATUS_MORE_PROCESSING_REQUIRED;
- }