You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
731 lines
20 KiB
731 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
isostrm.c
|
|
|
|
Abstract:
|
|
|
|
This file has routines for stream transfers.
|
|
Stream transfers are initiated and stopped using
|
|
the IOCTLs exposed by this driver.
|
|
The stream transfer information is contained in
|
|
ISOUSB_STREAM_OBJECT structure which is securely
|
|
placed in the FileObject. The ISOUSB_STREAM_OBJECT
|
|
structure has links to ISOUSB_TRANSFER_OBJECT
|
|
(each TRANSFER_OBJECT corresponds to the number of
|
|
irp/urb pair circulating).
|
|
So if the user-mode app simply crashes or aborts or
|
|
does not terminate, we can cleanly abort the stream
|
|
transfers.
|
|
|
|
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 "isousr.h"
|
|
#include "isowmi.h"
|
|
#include "isorwr.h"
|
|
#include "isostrm.h"
|
|
|
|
NTSTATUS
|
|
IsoUsb_StartIsoStream(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine create a single stream object and
|
|
invokes StartTransfer for ISOUSB_MAX_IRP number of
|
|
times.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
Irp - I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
ULONG info;
|
|
ULONG inputBufferLength;
|
|
ULONG outputBufferLength;
|
|
NTSTATUS ntStatus;
|
|
PFILE_OBJECT fileObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PISOUSB_STREAM_OBJECT streamObject;
|
|
PUSBD_PIPE_INFORMATION pipeInformation;
|
|
|
|
info = 0;
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
fileObject = irpStack->FileObject;
|
|
streamObject = NULL;
|
|
pipeInformation = NULL;
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream - begins\n"));
|
|
|
|
streamObject = ExAllocatePool(NonPagedPool,
|
|
sizeof(struct _ISOUSB_STREAM_OBJECT));
|
|
|
|
if(streamObject == NULL) {
|
|
|
|
IsoUsb_DbgPrint(1, ("failed to alloc mem for streamObject\n"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto IsoUsb_StartIsoStream_Exit;
|
|
}
|
|
|
|
RtlZeroMemory(streamObject, sizeof(ISOUSB_STREAM_OBJECT));
|
|
|
|
//
|
|
// The Isoch IN pipe for the board is the 5th pipe
|
|
//
|
|
pipeInformation = &(deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX]);
|
|
|
|
// reset the pipe
|
|
//
|
|
IsoUsb_ResetPipe(DeviceObject, pipeInformation);
|
|
|
|
streamObject->DeviceObject = DeviceObject;
|
|
streamObject->PipeInformation = pipeInformation;
|
|
|
|
KeInitializeEvent(&streamObject->NoPendingIrpEvent,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
for(i = 0; i < ISOUSB_MAX_IRP; i++) {
|
|
|
|
ntStatus = IsoUsb_StartTransfer(DeviceObject,
|
|
streamObject,
|
|
i);
|
|
|
|
if(!NT_SUCCESS(ntStatus)) {
|
|
|
|
//
|
|
// we continue sending transfer object irps..
|
|
//
|
|
|
|
IsoUsb_DbgPrint(1, ("IsoUsb_StartTransfer [%d] - failed\n", i));
|
|
|
|
if(ntStatus == STATUS_INSUFFICIENT_RESOURCES) {
|
|
|
|
ASSERT(streamObject->TransferObjectList[i] == NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(fileObject && fileObject->FsContext) {
|
|
|
|
if(streamObject->PendingIrps) {
|
|
|
|
((PFILE_OBJECT_CONTENT)fileObject->FsContext)->StreamInformation
|
|
= streamObject;
|
|
}
|
|
else {
|
|
|
|
IsoUsb_DbgPrint(1, ("no transfer object irp sent..abort..\n"));
|
|
ExFreePool(streamObject);
|
|
((PFILE_OBJECT_CONTENT)fileObject->FsContext)->StreamInformation = NULL;
|
|
}
|
|
}
|
|
|
|
IsoUsb_StartIsoStream_Exit:
|
|
|
|
Irp->IoStatus.Information = info;
|
|
Irp->IoStatus.Status = ntStatus;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream::"));
|
|
IsoUsb_IoDecrement(deviceExtension);
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
IsoUsb_StartTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PISOUSB_STREAM_OBJECT StreamObject,
|
|
IN ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a transfer object for each irp/urb pair.
|
|
After initializing the pair, it sends the irp down the stack.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object.
|
|
StreamObject - pointer to stream object
|
|
Index - index into the transfer object table in stream object
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
CCHAR stackSize;
|
|
ULONG packetSize;
|
|
ULONG maxXferSize;
|
|
ULONG numPackets;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION nextStack;
|
|
PISOUSB_TRANSFER_OBJECT transferObject;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
maxXferSize = StreamObject->PipeInformation->MaximumTransferSize;
|
|
packetSize = StreamObject->PipeInformation->MaximumPacketSize;
|
|
numPackets = maxXferSize / packetSize;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer - begins\n"));
|
|
|
|
transferObject = ExAllocatePool(NonPagedPool,
|
|
sizeof(struct _ISOUSB_TRANSFER_OBJECT));
|
|
|
|
if(transferObject == NULL) {
|
|
|
|
IsoUsb_DbgPrint(1, ("failed to alloc mem for transferObject\n"));
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(transferObject,
|
|
sizeof(struct _ISOUSB_TRANSFER_OBJECT));
|
|
|
|
|
|
transferObject->StreamObject = StreamObject;
|
|
|
|
stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
|
|
|
|
irp = IoAllocateIrp(stackSize, FALSE);
|
|
|
|
if(irp == NULL) {
|
|
|
|
IsoUsb_DbgPrint(1, ("failed to alloc mem for irp\n"));
|
|
|
|
ExFreePool(transferObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
transferObject->Irp = irp;
|
|
|
|
transferObject->DataBuffer = ExAllocatePool(NonPagedPool,
|
|
maxXferSize);
|
|
|
|
if(transferObject->DataBuffer == NULL) {
|
|
|
|
IsoUsb_DbgPrint(1, ("failed to alloc mem for DataBuffer\n"));
|
|
|
|
ExFreePool(transferObject);
|
|
IoFreeIrp(irp);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
transferObject->Urb = ExAllocatePool(NonPagedPool,
|
|
GET_ISO_URB_SIZE(numPackets));
|
|
|
|
if(transferObject->Urb == NULL) {
|
|
|
|
IsoUsb_DbgPrint(1, ("failed to alloc mem for Urb\n"));
|
|
|
|
ExFreePool(transferObject->DataBuffer);
|
|
IoFreeIrp(irp);
|
|
ExFreePool(transferObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IsoUsb_InitializeStreamUrb(DeviceObject, transferObject);
|
|
|
|
StreamObject->TransferObjectList[Index] = transferObject;
|
|
InterlockedIncrement(&StreamObject->PendingIrps);
|
|
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
nextStack->Parameters.Others.Argument1 = transferObject->Urb;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
IsoUsb_IsoIrp_Complete,
|
|
transferObject,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer::"));
|
|
IsoUsb_IoIncrement(deviceExtension);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
|
|
irp);
|
|
|
|
if(NT_SUCCESS(ntStatus)) {
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IsoUsb_InitializeStreamUrb(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PISOUSB_TRANSFER_OBJECT TransferObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the irp/urb pair in the transfer object.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
TransferObject - pointer to transfer object
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
PURB urb;
|
|
ULONG i;
|
|
ULONG siz;
|
|
ULONG packetSize;
|
|
ULONG numPackets;
|
|
ULONG maxXferSize;
|
|
PISOUSB_STREAM_OBJECT streamObject;
|
|
|
|
urb = TransferObject->Urb;
|
|
streamObject = TransferObject->StreamObject;
|
|
maxXferSize = streamObject->PipeInformation->MaximumTransferSize;
|
|
packetSize = streamObject->PipeInformation->MaximumPacketSize;
|
|
numPackets = maxXferSize / packetSize;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_InitializeStreamUrb - begins\n"));
|
|
|
|
if(numPackets > 255) {
|
|
|
|
numPackets = 255;
|
|
maxXferSize = packetSize * numPackets;
|
|
}
|
|
|
|
siz = GET_ISO_URB_SIZE(numPackets);
|
|
|
|
RtlZeroMemory(urb, siz);
|
|
|
|
urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
|
|
urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
|
|
urb->UrbIsochronousTransfer.PipeHandle =
|
|
streamObject->PipeInformation->PipeHandle;
|
|
|
|
urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
|
|
|
|
urb->UrbIsochronousTransfer.TransferBufferMDL = NULL;
|
|
urb->UrbIsochronousTransfer.TransferBuffer = TransferObject->DataBuffer;
|
|
urb->UrbIsochronousTransfer.TransferBufferLength = numPackets * packetSize;
|
|
|
|
urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
|
|
|
|
urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
|
|
urb->UrbIsochronousTransfer.UrbLink = NULL;
|
|
|
|
for(i=0; i<urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i * packetSize;
|
|
|
|
//
|
|
// For input operation, length is set to whatever the device supplies.
|
|
//
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Length = 0;
|
|
}
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_InitializeStreamUrb - ends\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
IsoUsb_IsoIrp_Complete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine of the irp in the irp/urb pair
|
|
passed down the stack for stream transfers.
|
|
|
|
If the transfer was cancelled or the device yanked out, then we
|
|
release resources, dump the statistics and return
|
|
STATUS_MORE_PROCESSING_REQUIRED, so that the cleanup module can
|
|
free the irp.
|
|
|
|
otherwise, we reinitialize the transfers and continue recirculaiton
|
|
of the irps.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object below us.
|
|
Irp - I/O completion routine.
|
|
Context - context passed to the completion routine
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION nextStack;
|
|
PISOUSB_STREAM_OBJECT streamObject;
|
|
PISOUSB_TRANSFER_OBJECT transferObject;
|
|
|
|
transferObject = (PISOUSB_TRANSFER_OBJECT) Context;
|
|
streamObject = transferObject->StreamObject;
|
|
deviceObject = streamObject->DeviceObject;
|
|
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete - begins\n"));
|
|
|
|
ntStatus = IsoUsb_ProcessTransfer(transferObject);
|
|
|
|
if((ntStatus == STATUS_CANCELLED) ||
|
|
(ntStatus == STATUS_DEVICE_NOT_CONNECTED)) {
|
|
|
|
IsoUsb_DbgPrint(3, ("Isoch irp cancelled/device removed\n"));
|
|
|
|
//
|
|
// this is the last irp to complete with this erroneous value
|
|
// signal an event and return STATUS_MORE_PROCESSING_REQUIRED
|
|
//
|
|
if(InterlockedDecrement(&streamObject->PendingIrps) == 0) {
|
|
|
|
KeSetEvent(&streamObject->NoPendingIrpEvent,
|
|
1,
|
|
FALSE);
|
|
|
|
IsoUsb_DbgPrint(3, ("-----------------------------\n"));
|
|
}
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete::"));
|
|
IsoUsb_IoDecrement(deviceExtension);
|
|
|
|
transferObject->Irp = NULL;
|
|
IoFreeIrp(Irp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//
|
|
// otherwise circulate the irps.
|
|
//
|
|
|
|
IsoUsb_InitializeStreamUrb(deviceObject, transferObject);
|
|
|
|
nextStack = IoGetNextIrpStackLocation(Irp);
|
|
nextStack->Parameters.Others.Argument1 = transferObject->Urb;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
IsoUsb_IsoIrp_Complete,
|
|
transferObject,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
transferObject->TimesRecycled++;
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
|
|
Irp);
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete - ends\n"));
|
|
IsoUsb_DbgPrint(3, ("-----------------------------\n"));
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IsoUsb_ProcessTransfer(
|
|
IN PISOUSB_TRANSFER_OBJECT TransferObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked from the completion routine to check the status
|
|
of the irp, urb and the isochronous packets.
|
|
|
|
updates statistics
|
|
|
|
Arguments:
|
|
|
|
TranferObject - pointer to transfer object for the irp/urb pair which completed.
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PURB urb;
|
|
ULONG i;
|
|
NTSTATUS ntStatus;
|
|
USBD_STATUS usbdStatus;
|
|
|
|
irp = TransferObject->Irp;
|
|
urb = TransferObject->Urb;
|
|
ntStatus = irp->IoStatus.Status;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_ProcessTransfer - begins\n"));
|
|
|
|
if(!NT_SUCCESS(ntStatus)) {
|
|
|
|
IsoUsb_DbgPrint(3, ("Isoch irp failed with status = %X\n", ntStatus));
|
|
}
|
|
|
|
usbdStatus = urb->UrbHeader.Status;
|
|
|
|
if(!USBD_SUCCESS(usbdStatus)) {
|
|
|
|
IsoUsb_DbgPrint(3, ("urb failed with status = %X\n", usbdStatus));
|
|
}
|
|
|
|
//
|
|
// check each of the urb packets
|
|
//
|
|
for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
|
|
TransferObject->TotalPacketsProcessed++;
|
|
|
|
usbdStatus = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
|
|
|
|
if(!USBD_SUCCESS(usbdStatus)) {
|
|
|
|
// IsoUsb_DbgPrint(3, ("Iso packet %d failed with status = %X\n", i, usbdStatus));
|
|
|
|
TransferObject->ErrorPacketCount++;
|
|
}
|
|
else {
|
|
|
|
TransferObject->TotalBytesProcessed += urb->UrbIsochronousTransfer.IsoPacket[i].Length;
|
|
}
|
|
}
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_ProcessTransfer - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
IsoUsb_StopIsoStream(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PISOUSB_STREAM_OBJECT StreamObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked from the IOCTL to stop the stream transfers.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
StreamObject - pointer to stream object
|
|
Irp - pointer to Irp
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
KIRQL oldIrql;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
//
|
|
// initialize vars
|
|
//
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StopIsoStream - begins\n"));
|
|
|
|
if((StreamObject == NULL) ||
|
|
(StreamObject->DeviceObject != DeviceObject)) {
|
|
|
|
IsoUsb_DbgPrint(1, ("invalid streamObject\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
IsoUsb_StreamObjectCleanup(StreamObject, deviceExtension);
|
|
|
|
IsoUsb_DbgPrint(3, ("IsoUsb_StopIsoStream - ends\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
IsoUsb_StreamObjectCleanup(
|
|
IN PISOUSB_STREAM_OBJECT StreamObject,
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked either when the user-mode app passes an IOCTL to
|
|
abort stream transfers or when the the cleanup dispatch routine is run.
|
|
It is guaranteed to run only once for every stream transfer.
|
|
|
|
Arguments:
|
|
|
|
StreamObject - StreamObject corresponding to stream transfer which
|
|
needs to be aborted.
|
|
|
|
DeviceExtension - pointer to device extension
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
ULONG timesRecycled;
|
|
ULONG totalPacketsProcessed;
|
|
ULONG totalBytesProcessed;
|
|
ULONG errorPacketCount;
|
|
PISOUSB_TRANSFER_OBJECT xferObject;
|
|
|
|
//
|
|
// initialize the variables
|
|
//
|
|
timesRecycled = 0;
|
|
totalPacketsProcessed = 0;
|
|
totalBytesProcessed = 0;
|
|
errorPacketCount = 0;
|
|
|
|
//
|
|
// cancel transferobject irps/urb pair
|
|
// safe to touch these irps because the
|
|
// completion routine always returns
|
|
// STATUS_MORE_PRCESSING_REQUIRED
|
|
//
|
|
//
|
|
for(i = 0; i < ISOUSB_MAX_IRP; i++) {
|
|
|
|
if(StreamObject->TransferObjectList[i] &&
|
|
StreamObject->TransferObjectList[i]->Irp) {
|
|
|
|
IoCancelIrp(StreamObject->TransferObjectList[i]->Irp);
|
|
}
|
|
}
|
|
|
|
//
|
|
// wait for the transfer objects irps to complete.
|
|
//
|
|
KeWaitForSingleObject(&StreamObject->NoPendingIrpEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// dump the statistics
|
|
//
|
|
for(i = 0; i < ISOUSB_MAX_IRP; i++) {
|
|
|
|
xferObject = StreamObject->TransferObjectList[i];
|
|
|
|
if(xferObject) {
|
|
|
|
timesRecycled += xferObject->TimesRecycled;
|
|
totalPacketsProcessed += xferObject->TotalPacketsProcessed;
|
|
totalBytesProcessed += xferObject->TotalBytesProcessed;
|
|
errorPacketCount += xferObject->ErrorPacketCount;
|
|
}
|
|
}
|
|
|
|
IsoUsb_DbgPrint(3, ("TimesRecycled = %d\n", timesRecycled));
|
|
IsoUsb_DbgPrint(3, ("TotalPacketsProcessed = %d\n", totalPacketsProcessed));
|
|
IsoUsb_DbgPrint(3, ("TotalBytesProcessed = %d\n", totalBytesProcessed));
|
|
IsoUsb_DbgPrint(3, ("ErrorPacketCount = %d\n", errorPacketCount));
|
|
|
|
|
|
//
|
|
// free all the buffers, urbs and transfer objects
|
|
// associated with stream object
|
|
//
|
|
for(i = 0; i < ISOUSB_MAX_IRP; i++) {
|
|
|
|
xferObject = StreamObject->TransferObjectList[i];
|
|
|
|
if(xferObject) {
|
|
|
|
if(xferObject->Urb) {
|
|
|
|
ExFreePool(xferObject->Urb);
|
|
xferObject->Urb = NULL;
|
|
}
|
|
|
|
if(xferObject->DataBuffer) {
|
|
|
|
ExFreePool(xferObject->DataBuffer);
|
|
xferObject->DataBuffer = NULL;
|
|
}
|
|
|
|
ExFreePool(xferObject);
|
|
StreamObject->TransferObjectList[i] = NULL;
|
|
}
|
|
}
|
|
|
|
ExFreePool(StreamObject);
|
|
|
|
// IsoUsb_ResetParentPort(DeviceObject);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|