mirror of https://github.com/tongzx/nt5src
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.
1700 lines
65 KiB
1700 lines
65 KiB
/***************************************************************************
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
iso.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
PURPOSE.
|
|
|
|
Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
|
|
|
|
|
|
Revision History:
|
|
|
|
****************************************************************************/
|
|
|
|
#define DRIVER
|
|
|
|
#pragma warning(disable:4214) // bitfield nonstd
|
|
#include "wdm.h"
|
|
#pragma warning(default:4214)
|
|
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
#pragma warning(disable:4200) //non std struct used
|
|
#include "usbdi.h"
|
|
#pragma warning(default:4200)
|
|
|
|
#include "usbdlib.h"
|
|
#include "usb.h"
|
|
|
|
#include "ioctl.h"
|
|
#include "isoperf.h"
|
|
#include "iso.h"
|
|
|
|
#define MAX_URBS_PER_PIPE 16
|
|
|
|
UCHAR ucIsoInterface = 0;
|
|
|
|
// Memory Leak detection global counters
|
|
ULONG gulBytesAllocated = 0;
|
|
ULONG gulBytesFreed = 0;
|
|
|
|
NTSTATUS
|
|
ISOPERF_RefreshIsoUrb(
|
|
PURB urb,
|
|
USHORT packetSize,
|
|
USBD_PIPE_HANDLE pipeHandle,
|
|
PVOID pvDataBuffer,
|
|
ULONG ulDataBufferLen
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Refreshes an Iso Usb Request Block in prep for resubmission to USB stack.
|
|
|
|
Arguments:
|
|
urb - pointer to urb to refresh
|
|
packetsize - max packet size for the endpoint for which this urb is intended
|
|
pipeHandle - Usbd pipe handle for the Urb
|
|
pvDataBuff - pointer to a data buffer that will contain data or will receive data
|
|
ulDataBufLen- length of data buffer
|
|
|
|
Return Value:
|
|
NT status code:
|
|
STATUS_SUCCESS indicates Urb successfully refreshed
|
|
Other status codes indicate error (most likely is a bad parameter passed in, which
|
|
would result in STATUS_INVALID_PARAMETER to be returned)
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
ULONG siz = 0;
|
|
ULONG i = 0;
|
|
ULONG numPackets = 0;
|
|
|
|
// Calculate the number of packets in this buffer
|
|
numPackets = ulDataBufferLen/packetSize;
|
|
|
|
// Adjust num packets by one if data buffer can accommodate it
|
|
if (numPackets*packetSize < ulDataBufferLen) {
|
|
numPackets++;
|
|
}
|
|
|
|
//
|
|
// Use macro from provided by stack to figure out Urb length for given size of packets. This is
|
|
// necessary since Urb for iso transfers depends on the number of packets in the data buffer
|
|
// since per-packet information is passed on the usbd interface
|
|
//
|
|
siz = GET_ISO_URB_SIZE(numPackets);
|
|
|
|
// Clear out any garbage that may have gotten put in the urb by the last transfer
|
|
RtlZeroMemory(urb, siz);
|
|
|
|
// Now fill in the Urb
|
|
urb->UrbIsochronousTransfer.Length = (USHORT) siz;
|
|
urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
|
|
urb->UrbIsochronousTransfer.PipeHandle = pipeHandle;
|
|
urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
|
|
urb->UrbIsochronousTransfer.TransferBufferMDL = NULL;
|
|
urb->UrbIsochronousTransfer.TransferBuffer = pvDataBuffer;
|
|
urb->UrbIsochronousTransfer.TransferBufferLength = numPackets * packetSize;
|
|
|
|
ASSERT (ulDataBufferLen >= numPackets*packetSize);
|
|
|
|
// This flag tells the stack to start sending/receiving right away
|
|
urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
|
|
urb->UrbIsochronousTransfer.StartFrame = 0;
|
|
|
|
urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
|
|
urb->UrbIsochronousTransfer.ReservedMBZ = 0;
|
|
|
|
for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Offset
|
|
= i * packetSize;
|
|
}//for
|
|
|
|
return ntStatus;
|
|
|
|
}//ISOPERF_RefreshIsoUrb
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_IsoInCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the completion routine that is called at the end of an iso Irp/Urb. It is
|
|
called when the Usb stack completes the Irp.
|
|
|
|
NOTE: IoCompletion routine always runs at IRQL DISPATCH_LEVEL.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device object that represents this USB iso test device
|
|
DeviceObject is obtained from context due to old, old bug
|
|
in initial WDM implemenations
|
|
Irp - pointer to the Irp that was completed by the usb stack
|
|
Context - caller-supplied context that is passed in for use by this completion routine
|
|
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
PIsoTxterContext pIsoContext = Context;
|
|
PDEVICE_OBJECT myDeviceObject = pIsoContext->DeviceObject;
|
|
PDEVICE_EXTENSION deviceExtension = myDeviceObject->DeviceExtension;
|
|
pConfig_Stat_Info pStatInfo = deviceExtension->pConfig_Stat_Information;
|
|
PIO_STACK_LOCATION nextStack = NULL;
|
|
PURB urb = pIsoContext->urb;
|
|
PISOPERF_WORKITEM isoperfWorkItem = NULL;
|
|
PDEVICE_EXTENSION MateDeviceExtension = NULL;
|
|
ULONG unew,lnew,uold,lold;
|
|
char * pcWork = NULL; //a worker pointer
|
|
ULONG i = 0;
|
|
char tempStr[32];
|
|
|
|
ISO_ASSERT (pIsoContext != NULL);
|
|
ISO_ASSERT (pStatInfo != NULL);
|
|
ISO_ASSERT (deviceExtension != NULL);
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("In IsoInCompletionRoutine %x %x %x\n",
|
|
DeviceObject, Irp, Context));
|
|
|
|
|
|
// Check the USBD status code and only proceed in resubmission if the Urb was successful
|
|
// or if the device extension flag that indicates the device is gone is FALSE
|
|
if ( (USBD_SUCCESS(urb->UrbHeader.Status)) && ((deviceExtension->StopTransfers) == FALSE) ) {
|
|
|
|
ISOPERF_GetUrbTimeStamp (urb, &lold, &uold); //Get the Urb's timestamp
|
|
|
|
GET_PENTIUM_CLOCK_COUNT(unew,lnew); //Get the time now
|
|
|
|
pStatInfo->ulUrbDeltaClockCount = lnew-lold; //Compute & store the delta
|
|
|
|
// Check that data is incrementing from last data pattern received on this pipe
|
|
if ((ISOPERF_IsDataGood(pIsoContext))== TRUE) {
|
|
|
|
// Data was good
|
|
pStatInfo->ulSuccessfulIrps++;
|
|
pStatInfo->ulBytesTransferredIn += pIsoContext->ulBufferLen;
|
|
|
|
} else {
|
|
|
|
// An error occured, so stop the test by setting the flag to stop the test
|
|
deviceExtension->bStopIsoTest = TRUE;
|
|
deviceExtension->ulCountDownToStop = 0;
|
|
|
|
// Put this information in the status area for the device so the app can see it when it asks
|
|
pStatInfo->erError = DataCompareFailed;
|
|
pStatInfo->bStopped = 1;
|
|
|
|
}//else data was bad
|
|
|
|
if ( (deviceExtension->bStopIsoTest == TRUE) && (deviceExtension->ulCountDownToStop > 0) ) {
|
|
|
|
// User has requested a stop to the Iso Test so, decrement the countdown value
|
|
(deviceExtension->ulCountDownToStop)--;
|
|
|
|
}//if user requested a stop
|
|
|
|
// If device extension says to keep going on this test then continue on
|
|
if ((deviceExtension->ulCountDownToStop) > 0) {
|
|
|
|
// Refresh this Urb before we resubmit it to the stack
|
|
ISOPERF_RefreshIsoUrb (pIsoContext->urb,
|
|
pIsoContext->PipeInfo->MaximumPacketSize,
|
|
pIsoContext->PipeInfo->PipeHandle,
|
|
pIsoContext->pvBuffer,
|
|
pIsoContext->ulBufferLen
|
|
);
|
|
|
|
// If this iso in device has a mate, then start a thread to have it use this data buffer
|
|
if (deviceExtension->MateDeviceObject) {
|
|
|
|
MateDeviceExtension = deviceExtension->MateDeviceObject->DeviceExtension;
|
|
|
|
// Check if the mate device is up and running
|
|
if ( (MateDeviceExtension->Stopped == FALSE) && (MateDeviceExtension->StopTransfers == FALSE) ) {
|
|
|
|
//start a Work Item to use this buffer which will only do so when the buffer has arrived
|
|
isoperfWorkItem = ISOPERF_ExAllocatePool(NonPagedPool, sizeof(ISOPERF_WORKITEM),&gulBytesAllocated);
|
|
|
|
isoperfWorkItem->DeviceObject = deviceExtension->MateDeviceObject;
|
|
isoperfWorkItem->pvBuffer = pIsoContext->pvBuffer;
|
|
isoperfWorkItem->ulBufferLen = pIsoContext->ulBufferLen;
|
|
isoperfWorkItem->bFirstUrb = pIsoContext->bFirstUrb;
|
|
isoperfWorkItem->InMaxPacket = pIsoContext->PipeInfo->MaximumPacketSize;
|
|
isoperfWorkItem->ulNumberOfFrames = urb->UrbIsochronousTransfer.NumberOfPackets;
|
|
|
|
// Call the OUT pipe transfer routine
|
|
ISOPERF_StartIsoOutTest (isoperfWorkItem);
|
|
|
|
// Since the firstUrb flag is used to tell the outpipe whether it's a virgin or not,
|
|
// and since this Urb can be recycled through here again, we have to de-virginize the
|
|
// flag so this Urb doesn't always cause the outpipe to think it's dealing with a virgin Urb.
|
|
if (pIsoContext->bFirstUrb == TRUE) {
|
|
pIsoContext->bFirstUrb = FALSE;
|
|
}//if this was the first Urb
|
|
|
|
}//if mate device is ok
|
|
|
|
}//if there is a mate device in the system (that this driver runs)
|
|
|
|
// Get the next lower driver's stack
|
|
nextStack = IoGetNextIrpStackLocation(Irp);
|
|
ASSERT(nextStack != NULL);
|
|
|
|
//
|
|
// Set up the next lower driver's stack parameters which is where that
|
|
// driver will go to get its parameters for this internal IOCTL Irp
|
|
//
|
|
nextStack->Parameters.Others.Argument1 = urb;
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
ISOPERF_IsoInCompletion,
|
|
pIsoContext,
|
|
TRUE,
|
|
TRUE,
|
|
FALSE); //INVOKE ON CANCEL
|
|
|
|
// Time stamp the Urb before we send it down the stack
|
|
ISOPERF_TimeStampUrb (urb, &unew, &lnew);
|
|
|
|
// Call the driver
|
|
IoCallDriver (deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
|
|
// Tell the IO Manager that we want to handle this Irp from here on...
|
|
return (STATUS_MORE_PROCESSING_REQUIRED);
|
|
|
|
} else {
|
|
|
|
ISOPERF_KdPrint (("Stopped Iso test (did not resubmit Irp/Urb due to device extension flag)\n"));
|
|
|
|
}/* else the tests should be stopped */
|
|
|
|
}//if Urb status was successful
|
|
|
|
// Otherwise, the Urb was unsuccessful
|
|
else {
|
|
pStatInfo->erError = UsbdErrorInCompletion;
|
|
pStatInfo->ulUnSuccessfulIrps++;
|
|
|
|
FIRE_OFF_CATC;
|
|
|
|
if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
|
|
ISOPERF_KdPrint (("Urb unsuccessful (status: %#x)\n",urb->UrbHeader.Status));
|
|
|
|
// Dump out the status for the packets
|
|
for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
|
|
i,
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Status));
|
|
|
|
// Put the last known bad packet status code into this space in the stat area
|
|
if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
|
|
pStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
|
|
}//if hit a fail code
|
|
sprintf (tempStr, "Data: %x", *((PULONG)(urb->UrbIsochronousTransfer.TransferBuffer)));
|
|
ISOPERF_KdPrint (("First data in buffer: %s\n",tempStr));
|
|
|
|
}//for all the packets
|
|
|
|
}else {
|
|
ISOPERF_KdPrint (("Urb successful, but StopTransfers flag is set (%d)\n",deviceExtension->StopTransfers));
|
|
}
|
|
|
|
|
|
}//Urb was unsuccessful, so don't repost it and fall thru to cleanup code
|
|
|
|
// Clean up section. This only executes if:
|
|
// --Urb (bus transfer) was unsuccessful (stop the test)
|
|
// --Buffer didn't look right (a hiccup was detected, etc.)
|
|
// --User requested tests to stop
|
|
ISOPERF_KdPrint (("Stopping Iso In Stream and Cleaning Up...U:%x|C:%x|B:%x\n",
|
|
urb,
|
|
pIsoContext,
|
|
pIsoContext->pvBuffer));
|
|
|
|
// Free up the memory created for this transfer that we are retiring
|
|
if (urb) {
|
|
// We can't free the Urb itself, since it has some junk before it, so we have to roll back the
|
|
// pointer to get to the beginning of the block that we originally allocated, and then try to free it.
|
|
pcWork = (char*)urb; //get the urb
|
|
urb = (PURB) (pcWork - (2*sizeof(ULONG))); //the original pointer is 2 DWORDs behind the Urb
|
|
ISOPERF_KdPrint (("Freeing urb %x\n",urb));
|
|
ISOPERF_ExFreePool (urb, &gulBytesFreed); //Free that buffer
|
|
}//if
|
|
|
|
if (pIsoContext) {
|
|
|
|
// Free the data buffer
|
|
if (pIsoContext->pvBuffer) {
|
|
ISOPERF_KdPrint (("Freeing databuff %x\n",pIsoContext->pvBuffer));
|
|
ISOPERF_ExFreePool (pIsoContext->pvBuffer, &gulBytesFreed);
|
|
}
|
|
|
|
// Free the Iso Context
|
|
ISOPERF_KdPrint (("Freeing pIsoContext %x\n",pIsoContext));
|
|
ISOPERF_ExFreePool (pIsoContext, &gulBytesFreed);
|
|
|
|
}//if valid Iso Context
|
|
|
|
//Decrement the number of outstanding Irps since this one is being retired
|
|
(deviceExtension->ulNumberOfOutstandingIrps)--;
|
|
|
|
// If this is the last Irp we are retiring, then the device should be marked as not busy
|
|
if (deviceExtension->ulNumberOfOutstandingIrps == 0) {
|
|
deviceExtension->DeviceIsBusy = FALSE;
|
|
pStatInfo->bDeviceRunning = FALSE;
|
|
}//if not irps left outstanding on this device
|
|
|
|
//Free the IoStatus block that we allocated for this Irp
|
|
if (Irp->UserIosb) {
|
|
ISOPERF_KdPrint (("Freeing My IoStatusBlock %x\n",Irp->UserIosb));
|
|
ISOPERF_ExFreePool(Irp->UserIosb, &gulBytesFreed);
|
|
} else {
|
|
//Bad thing...no IoStatus block pointer??
|
|
ISOPERF_KdPrint (("ERROR: Irp's IoStatus block is apparently NULL!\n"));
|
|
TRAP();
|
|
}//else bad iostatus pointer
|
|
|
|
//Free the Irp here and return STATUS_MORE_PROCESSING_REQUIRED instead of SUCCESS
|
|
ISOPERF_KdPrint (("Freeing Irp %x\n",Irp));
|
|
IoFreeIrp(Irp);
|
|
|
|
// Tell the IO Manager that we want to handle this Irp from here on...
|
|
ISOPERF_KdPrint (("Returning STATUS_MORE_PROCESSING_REQUIRED from IsoInCompletion\n"));
|
|
return (STATUS_MORE_PROCESSING_REQUIRED);
|
|
|
|
}//ISOPERF_IsoInCompletion
|
|
|
|
|
|
PURB
|
|
ISOPERF_BuildIsoRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSBD_PIPE_INFORMATION pPipeInfo,
|
|
IN BOOLEAN Read,
|
|
IN ULONG length,
|
|
IN ULONG ulFrameNumber,
|
|
IN PVOID pvTransferBuffer,
|
|
IN PMDL pMDL
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Allocates and initializes most of a URB. The caller must initialize the FLAGS field
|
|
with any further flags they desire after this function is called.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
pPipeInfo - ptr to pipe descr for which to build the iso request (urb)
|
|
Read - if TRUE, it's a read, FALSE it's a write
|
|
length - length of the data buffer or MDL, used for packetizing the buffer for iso txfer
|
|
ulframeNumber- if non-zero, use this frame number to build in the urb and don't set flags
|
|
pvTransferBuffer - Non-NULL: this is the TB ; NULL: an MDL is specified
|
|
ulTransferBufferLength - len of buffer specified in pvTransferBuffer
|
|
pMDL - if an MDL is being used, this is a ptr to it
|
|
|
|
Return Value:
|
|
Almost initialized iso urb. Caller must fill in the flags after this fn is called.
|
|
|
|
--*/
|
|
{
|
|
ULONG siz;
|
|
ULONG packetSize,numPackets, i;
|
|
PURB urb = NULL;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
char * pcWork = NULL;
|
|
ISO_ASSERT(pPipeInfo!=NULL)
|
|
|
|
packetSize = pPipeInfo->MaximumPacketSize;
|
|
|
|
numPackets = length/packetSize;
|
|
if (numPackets*packetSize < length) {
|
|
numPackets++;
|
|
}
|
|
|
|
siz = GET_ISO_URB_SIZE(numPackets);
|
|
|
|
//Add room for a URB time stamp at the beginning of the Urb by allocating more than
|
|
//siz by 4 DWORDs. The pentium clock count macro can then be used by the caller of
|
|
//this routine to fill in the clock count stamp. We allocate an extra 2 DWORDs more than
|
|
//we need to allow some room for stuff to put at the end of the URB in the future.
|
|
pcWork = ISOPERF_ExAllocatePool(NonPagedPool, (siz+(4*sizeof(ULONG))), &gulBytesAllocated);
|
|
|
|
urb = (PURB) (pcWork + (2*sizeof(ULONG))); //Push pass the clock count area to the urb area
|
|
|
|
if (urb) {
|
|
RtlZeroMemory(urb, siz);
|
|
|
|
urb->UrbIsochronousTransfer.Length = (USHORT) siz;
|
|
urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
|
|
urb->UrbIsochronousTransfer.PipeHandle = pPipeInfo->PipeHandle;
|
|
urb->UrbIsochronousTransfer.TransferFlags = Read ? USBD_TRANSFER_DIRECTION_IN : 0;
|
|
|
|
urb->UrbIsochronousTransfer.TransferBufferMDL = pMDL;
|
|
urb->UrbIsochronousTransfer.TransferBuffer = pvTransferBuffer;
|
|
urb->UrbIsochronousTransfer.TransferBufferLength = length;
|
|
urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
|
|
|
|
if (ulFrameNumber==0) {
|
|
//No frame number specified, just start asap
|
|
urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
|
|
}else{
|
|
//use specific starting framenumber & don't set (unset) the asap flag
|
|
urb->UrbIsochronousTransfer.StartFrame = ulFrameNumber;
|
|
urb->UrbIsochronousTransfer.TransferFlags &= ~USBD_START_ISO_TRANSFER_ASAP;
|
|
}//if framenumber was specified
|
|
|
|
urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
|
|
urb->UrbIsochronousTransfer.ReservedMBZ = 0;
|
|
|
|
// Fill in the packet size array
|
|
for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Offset
|
|
= i * packetSize;
|
|
} //for
|
|
|
|
}//if urb
|
|
|
|
return urb;
|
|
}
|
|
|
|
|
|
PVOID
|
|
ISOPERF_GetBuff (
|
|
PDEVICE_OBJECT DeviceObject,
|
|
ULONG ulPipeNumber,
|
|
ULONG ulInterfaceNumber,
|
|
ULONG ulNumberOfFrames,
|
|
PULONG pulBufferSize
|
|
)
|
|
/*++
|
|
ISOPERF_GetBuff
|
|
|
|
Routine Description:
|
|
Creates a buffer as specified by input params. If the input params specify a buffer
|
|
that is too big to be submitted to this pipe, then this request will fail.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
|
|
Return Value:
|
|
Returns a pointer to the allocated data buffer
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = NULL;
|
|
ULONG ulMaxPacketSize = 0;
|
|
ULONG ulBufferSize = 0;
|
|
ULONG ulMaxTxferSize = 0;
|
|
PVOID pvBuffer = NULL;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
ulMaxPacketSize = deviceExtension->Interface[ulInterfaceNumber]->Pipes[ulPipeNumber].MaximumPacketSize;
|
|
ulMaxTxferSize = deviceExtension->Interface[ulInterfaceNumber]->Pipes[ulPipeNumber].MaximumTransferSize;
|
|
|
|
ulBufferSize = *pulBufferSize = ulMaxPacketSize * ulNumberOfFrames;
|
|
|
|
// Check if this buffer is too big to submit on this pipe (per its initial setup)
|
|
if (ulBufferSize > ulMaxTxferSize) {
|
|
*pulBufferSize = 0;
|
|
return (NULL);
|
|
} else {
|
|
return ( ISOPERF_ExAllocatePool (NonPagedPool, ulBufferSize, &gulBytesAllocated) );
|
|
}
|
|
|
|
}//ISOPERF_GetBuff
|
|
|
|
ULONG
|
|
ISOPERF_StartIsoInTest (
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP pIrp
|
|
)
|
|
/*++
|
|
ISOPERF_StartIsoInTest
|
|
|
|
Routine Description:
|
|
Starts the Iso In Test
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
pIrp - pointer to the Irp from the Ioctl
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
|
|
PDEVICE_EXTENSION deviceExtension = NULL;
|
|
PURB urb = NULL;
|
|
ULONG ulFrameNumber = 0;
|
|
ULONG UrbNumber = 0;
|
|
ULONG NumberOfFrames = 0;
|
|
PUSBD_INTERFACE_INFORMATION pInterfaceInfo = NULL;
|
|
PUSBD_PIPE_INFORMATION pUsbdPipeInfo = NULL;
|
|
PUSBD_INTERFACE_INFORMATION pMateInterfaceInfo = NULL;
|
|
PUSBD_PIPE_INFORMATION pMateUsbdPipeInfo = NULL;
|
|
ULONG ulBufferSize = 0;
|
|
IsoTxferContext * pIsoContext = NULL;
|
|
PVOID pvBuff = NULL;
|
|
BOOLEAN bFirstUrb = FALSE;
|
|
BOOLEAN bHaveMate = FALSE;
|
|
ULONG Upper, Lower;
|
|
pConfig_Stat_Info configStatInfo = NULL;
|
|
ULONG Max_Urbs_Per_Pipe = 0;
|
|
PDEVICE_OBJECT mateDeviceObject = NULL;
|
|
PDEVICE_EXTENSION mateDeviceExtension = NULL;
|
|
pConfig_Stat_Info mateConfigStatInfo = NULL;
|
|
char * pcWork = NULL;
|
|
|
|
ISOPERF_KdPrint (("Enter ISOPERF_StartIsoInTest (%x) (%x)\n",DeviceObject, pIrp));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
pInterfaceInfo = deviceExtension->Interface[ucIsoInterface];
|
|
ISO_ASSERT (pInterfaceInfo!=NULL)
|
|
|
|
//make sure this is an IN Iso device
|
|
if (deviceExtension->dtTestDeviceType != Iso_In_With_Pattern) {
|
|
ISOPERF_KdPrint (("Error: not an Iso IN device! (%d)\n",deviceExtension->dtTestDeviceType));
|
|
TRAP();
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}//if it's NOT an ISO IN then bounce it back
|
|
|
|
// Get the config info for the In Iso Device
|
|
configStatInfo = deviceExtension->pConfig_Stat_Information;
|
|
ASSERT (configStatInfo != NULL);
|
|
|
|
// Check out the offset provided to make sure it's not too big
|
|
if (configStatInfo->ulFrameOffset >= USBD_ISO_START_FRAME_RANGE) {
|
|
ISOPERF_KdPrint (("Error: Detected a FrameOffset Larger than allowed! (%d)\n",configStatInfo->ulFrameOffset));
|
|
TRAP();
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}//if bad frame offset
|
|
|
|
if (configStatInfo) {
|
|
Max_Urbs_Per_Pipe = configStatInfo->ulMax_Urbs_Per_Pipe;
|
|
NumberOfFrames = configStatInfo->ulNumberOfFrames;
|
|
}//if configstatinfo is not null
|
|
|
|
// Only set up the output device if the config info indicates a desire to do the In->Out test
|
|
if (configStatInfo->ulDoInOutTest) {
|
|
//If there is an OUT Iso device, and we are trying to do a IN->OUT test, then set that device object up
|
|
ntStatus = ISOPERF_FindMateDevice (DeviceObject);
|
|
|
|
if (ntStatus == STATUS_SUCCESS) {
|
|
bHaveMate = TRUE;
|
|
mateDeviceObject = deviceExtension->MateDeviceObject;
|
|
mateDeviceExtension = mateDeviceObject->DeviceExtension;
|
|
pMateInterfaceInfo = mateDeviceExtension->Interface[ucIsoInterface];
|
|
mateConfigStatInfo = mateDeviceExtension->pConfig_Stat_Information;
|
|
mateConfigStatInfo->ulFrameOffset = configStatInfo->ulFrameOffsetMate;
|
|
|
|
}//if status success
|
|
|
|
// Reset the pipe on the mate device if it's also here
|
|
// NOTE: we only reset the first pipe on the mate device here
|
|
if (bHaveMate == TRUE) {
|
|
ASSERT (pMateInterfaceInfo!=NULL);
|
|
pMateUsbdPipeInfo = &(pMateInterfaceInfo->Pipes[0]);
|
|
ASSERT (pMateUsbdPipeInfo != NULL);
|
|
ISOPERF_ResetPipe(deviceExtension->MateDeviceObject,pMateUsbdPipeInfo);
|
|
}// if mate
|
|
} else {
|
|
// Set the mate dev obj to NULL so completion routine knows not to use it
|
|
deviceExtension->MateDeviceObject = NULL;
|
|
}//if In->Out test is not being requested
|
|
|
|
// Reset the first pipe on the IN device
|
|
pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
|
|
ISOPERF_ResetPipe(DeviceObject, pUsbdPipeInfo);
|
|
|
|
// Untrigger the CATC so if we trigger it later it will go off
|
|
RESTART_CATC;
|
|
|
|
// Get the current frame number
|
|
ulFrameNumber = ISOPERF_GetCurrentFrame(DeviceObject);
|
|
|
|
//Save away the current frame number so the app can peek at it
|
|
configStatInfo->ulFrameNumberAtStart = ulFrameNumber;
|
|
|
|
// See what the user wants to do wrt starting frame number by looking at the config info
|
|
if (configStatInfo->ulFrameOffset == 0) {
|
|
// This means start ASAP
|
|
ulFrameNumber = 0;
|
|
}else {
|
|
//Add the offset that the User wants to add to this frame number (it better be less than 1024!)
|
|
ulFrameNumber += configStatInfo->ulFrameOffset;
|
|
} //else
|
|
|
|
//Save away the starting frame number so the app can peek at it
|
|
configStatInfo->ulStartingFrameNumber = ulFrameNumber;
|
|
|
|
// Set flag to indicate first Urb
|
|
bFirstUrb = TRUE;
|
|
|
|
// Get the pipe info for the first pipe
|
|
pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
|
|
|
|
// Build all the urbs for each pipe (note we send multiple Urbs down the stack)
|
|
for (UrbNumber=0;UrbNumber<Max_Urbs_Per_Pipe;UrbNumber++) {
|
|
|
|
//
|
|
// Calculate the buffer size required and get a pointer to the buffer
|
|
// Note: this buffer needs to be freed when the StopIsoInTest ioctl is
|
|
// received. The completion routine will free the buffer when it
|
|
// sees that it is time to stop the iso in test (the pointer is grabbed
|
|
// from the irp).
|
|
//
|
|
pvBuff = ISOPERF_GetBuff (DeviceObject,
|
|
0, // pipe number
|
|
0, // interface number
|
|
NumberOfFrames, // Nbr of mS worth of data to post
|
|
&ulBufferSize);
|
|
|
|
|
|
ISO_ASSERT (pvBuff!=NULL);
|
|
|
|
//
|
|
// Create the context for this transfer out of the nonpaged pool since it survives
|
|
// this routine and is used in the completion routine
|
|
//
|
|
pIsoContext = ISOPERF_ExAllocatePool (NonPagedPool, sizeof (IsoTxferContext), &gulBytesAllocated);
|
|
|
|
//build the urb
|
|
urb = ISOPERF_BuildIsoRequest(DeviceObject,
|
|
pUsbdPipeInfo, //Pipe info struct
|
|
TRUE, //READ
|
|
ulBufferSize, //Data buffer size
|
|
bFirstUrb ? ulFrameNumber : 0, //Frame Nbr
|
|
pvBuff, //Data buffer
|
|
NULL //no MDL used
|
|
);
|
|
if (urb) {
|
|
|
|
// Fill in the iso context
|
|
pIsoContext->urb = urb;
|
|
pIsoContext->DeviceObject = DeviceObject;
|
|
pIsoContext->PipeInfo = pUsbdPipeInfo;
|
|
pIsoContext->irp = pIrp;
|
|
pIsoContext->pvBuffer = pvBuff;
|
|
pIsoContext->ulBufferLen = ulBufferSize;
|
|
pIsoContext->PipeNumber = UrbNumber;
|
|
pIsoContext->NumPackets = urb->UrbIsochronousTransfer.NumberOfPackets;
|
|
pIsoContext->bFirstUrb = bFirstUrb;
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("Urb %d pvBuff %x ulBuffSz %d NumPackts %d pIsoCont %x Urb: %x\n",
|
|
UrbNumber,pvBuff,ulBufferSize,pIsoContext->NumPackets,pIsoContext,urb));
|
|
|
|
// Time stamp the Urb before we send it down the stack
|
|
ISOPERF_TimeStampUrb(urb, &Lower, &Upper);
|
|
|
|
//Create our own Irp for the device and call the usb stack w/ our urb/irp
|
|
ntStatus = ISOPERF_CallUSBDEx ( DeviceObject,
|
|
urb,
|
|
FALSE, //Don't block
|
|
ISOPERF_IsoInCompletion, //Completion routine
|
|
pIsoContext, //pvContext
|
|
FALSE); //don't want timeout
|
|
|
|
|
|
// Set the busy flag if the Urb/Irp succeed
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
deviceExtension->DeviceIsBusy = TRUE;
|
|
//Set to some huge value; ioctl to stop the test will set this to a smaller value
|
|
deviceExtension->ulCountDownToStop = 0xFFFF;
|
|
deviceExtension->bStopIsoTest = FALSE;
|
|
deviceExtension->StopTransfers = FALSE;
|
|
|
|
configStatInfo->erError = NoError;
|
|
configStatInfo->bDeviceRunning = TRUE;
|
|
|
|
} else {
|
|
|
|
deviceExtension->DeviceIsBusy = FALSE;
|
|
deviceExtension->bStopIsoTest = TRUE;
|
|
deviceExtension->StopTransfers = TRUE;
|
|
|
|
configStatInfo->erError = ErrorInPostingUrb;
|
|
configStatInfo->UrbStatusCode = urb->UrbHeader.Status;
|
|
|
|
if (bFirstUrb) {
|
|
//since this is the first Urb, we know for sure the device isn't running
|
|
configStatInfo->bDeviceRunning = FALSE;
|
|
configStatInfo->bStopped = TRUE;
|
|
}//if first Urb
|
|
|
|
} //else FAILED calling USB stack
|
|
|
|
}//if urb[UrbNumber] exists
|
|
|
|
// Reset the flag that indicates it's the first Urb
|
|
bFirstUrb = FALSE;
|
|
|
|
}//for all the urbs per pipe (UrbNumber)
|
|
|
|
|
|
ISOPERF_KdPrint (("Exit ISOPERF_StartIsoInTest (%x)\n",ntStatus));
|
|
|
|
return ntStatus;
|
|
|
|
}//StartIsoInTest
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_ResetPipe(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN USBD_PIPE_INFORMATION * pPipeInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Resets the given Pipe by calling a USBD function
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to dev obj for this instance of usb device
|
|
pPipeInfo - pointer to usbd pipe info struct
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PURB urb;
|
|
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
ISO_ASSERT (pPipeInfo!=NULL)
|
|
|
|
urb = ISOPERF_ExAllocatePool(NonPagedPool,((sizeof(struct _URB_PIPE_REQUEST))+64), &gulBytesAllocated);
|
|
|
|
if (urb) {
|
|
|
|
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
|
|
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
|
|
urb->UrbPipeRequest.PipeHandle = pPipeInfo->PipeHandle;
|
|
|
|
ntStatus = ISOPERF_CallUSBD ( DeviceObject,
|
|
urb);
|
|
|
|
} else {
|
|
ntStatus = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
ISOPERF_KdPrint (("Freeing urb in RESET_PIPE: %x\n",urb));
|
|
|
|
// Free the urb we created since we blocked on this function
|
|
if (urb) {
|
|
ISOPERF_ExFreePool (urb, &gulBytesFreed);
|
|
}//if urb
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ISOPERF_GetCurrentFrame(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
ISOPERF_GetCurrentFrame
|
|
|
|
Arguments:
|
|
DeviceExtension - pointer to the device extension for this instance
|
|
|
|
Return Value:
|
|
Current Frame Number
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PURB urb;
|
|
ULONG currentUSBFrame = 0;
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("In ISOPERF_GetCurrentFrame: (%x)\n",DeviceObject));
|
|
|
|
urb = ISOPERF_ExAllocatePool(NonPagedPool,sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER), &gulBytesAllocated);
|
|
|
|
if (urb) {
|
|
|
|
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_GET_CURRENT_FRAME_NUMBER);
|
|
urb->UrbHeader.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
|
|
|
|
ntStatus = ISOPERF_CallUSBD ( DeviceObject,
|
|
urb
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(URB_STATUS(urb))) {
|
|
currentUSBFrame = urb->UrbGetCurrentFrameNumber.FrameNumber;
|
|
|
|
// Since a ZERO for the USBFrameNumber indicates an error, and if it really is zero by chance, then just bump it by one
|
|
if (currentUSBFrame==0) {
|
|
currentUSBFrame++;
|
|
}
|
|
}
|
|
|
|
ISOPERF_ExFreePool(urb, &gulBytesFreed);
|
|
|
|
} else {
|
|
ntStatus = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("Exit ISOPERF_GetCurrentFrame: (%x)\n",currentUSBFrame));
|
|
|
|
return currentUSBFrame;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_StopIsoInTest (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Stops the Iso IN test by setting fields in the device extension so that the completion
|
|
routine no longer does checks and resubmits Irps to keep the iso stream running.
|
|
|
|
This call causes no USB stack calls nor USB bus traffic.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
Irp - pointer to the Irp created in the Ioctl
|
|
|
|
Return Value:
|
|
Always returns NT status of STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
ULONG Upper, Lower;
|
|
|
|
GET_PENTIUM_CLOCK_COUNT(Upper,Lower);
|
|
|
|
ISOPERF_KdPrint (("Enter StopIsoInTest\n"));
|
|
ISOPERF_KdPrint (("Upper:Lower -- %ld : %ld\n",Upper,Lower));
|
|
|
|
ISO_ASSERT (deviceExtension != NULL);
|
|
|
|
deviceExtension->bStopIsoTest = TRUE;
|
|
deviceExtension->ulCountDownToStop = 100;
|
|
|
|
ISOPERF_KdPrint (("Stopped: %d\n", deviceExtension->Stopped));
|
|
ISOPERF_KdPrint (("StopTransfers: %d\n", deviceExtension->StopTransfers));
|
|
ISOPERF_KdPrint (("DeviceIsBusy: %d\n", deviceExtension->DeviceIsBusy));
|
|
ISOPERF_KdPrint (("NeedCleanup: %d\n", deviceExtension->NeedCleanup));
|
|
ISOPERF_KdPrint (("bStopIsoTest: %d\n", deviceExtension->bStopIsoTest));
|
|
ISOPERF_KdPrint (("ulNumberOfOutstandingIrps: %d\n", deviceExtension->ulNumberOfOutstandingIrps));
|
|
ISOPERF_KdPrint (("ulCountDownToStop: %d\n", deviceExtension->ulCountDownToStop));
|
|
|
|
|
|
ISOPERF_KdPrint (("Exit StopIsoInTest\n"));
|
|
|
|
return (STATUS_SUCCESS);
|
|
}//ISOPERF_StopIsoInTest
|
|
|
|
|
|
BOOLEAN
|
|
ISOPERF_IsDataGood(PIsoTxterContext pIsoContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks the data in the buffer for an incrementing pattern in every "maxpacketsize" granule
|
|
of bytes.
|
|
|
|
Arguments:
|
|
pIsoContext - pointer to the Iso context that contains what this routine needs to process the buffer
|
|
|
|
Return Value:
|
|
TRUE - indicates buffer looks good
|
|
FALSE - buffer has an error
|
|
|
|
--*/
|
|
{
|
|
PUCHAR pchWork, pchEnd;
|
|
UCHAR cCurrentValue, cNextValue;
|
|
ULONG ulMaxPacketSize;
|
|
|
|
pchWork = pIsoContext->pvBuffer;
|
|
ulMaxPacketSize = pIsoContext->PipeInfo->MaximumPacketSize;
|
|
|
|
if (pchWork==NULL) {
|
|
ISOPERF_KdPrint (("Bad pchWork in IsDataGood (%x)\n",pchWork));
|
|
return (FALSE);
|
|
}
|
|
|
|
if (ulMaxPacketSize >= 1024) {
|
|
ISOPERF_KdPrint (("Bad MaxPacketSize in IsDataGood (%x)\n",ulMaxPacketSize));
|
|
return (FALSE);
|
|
}
|
|
|
|
pchEnd = pchWork + ((pIsoContext->ulBufferLen) - ulMaxPacketSize);
|
|
|
|
if (pchEnd > (pchWork + ((pIsoContext->NumPackets)*(ulMaxPacketSize)))) {
|
|
ISOPERF_KdPrint (("Buffer Problem in IsDataGood: Base: %x | End: %x | NumPackts: %d | MaxPacktSz: %d\n",
|
|
pchWork, pchEnd, pIsoContext->NumPackets, ulMaxPacketSize));
|
|
}
|
|
|
|
ASSERT (pchEnd <= (pchWork + ((pIsoContext->NumPackets)*ulMaxPacketSize)));
|
|
|
|
cCurrentValue = *pchWork;
|
|
|
|
while (pchWork < pchEnd) {
|
|
|
|
// Get the next frame's byte value
|
|
cNextValue = *(pchWork + ulMaxPacketSize);
|
|
|
|
if (cNextValue == (cCurrentValue + 1)) {
|
|
//Success, go on to next packet
|
|
pchWork+=ulMaxPacketSize;
|
|
cCurrentValue = *pchWork;
|
|
}else{
|
|
|
|
// Maybe this is the rollover case, so check for it and don't fail it if it is
|
|
if (cNextValue==0) {
|
|
if (cCurrentValue==0xFF) {
|
|
//Success, go on to next packet
|
|
pchWork+=ulMaxPacketSize;
|
|
cCurrentValue = *pchWork;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ISOPERF_KdPrint (("Fail data compare: pchWork: %x | cNextValue: %x | *pchWork: %x | Base: %x\n",
|
|
pchWork, cNextValue, *pchWork, pIsoContext->pvBuffer));
|
|
FIRE_OFF_CATC;
|
|
RESTART_CATC;
|
|
return (FALSE);
|
|
}
|
|
|
|
} //while
|
|
|
|
return (TRUE);
|
|
|
|
}//ISOPERF_IsDataGood
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_GetStats (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN OUT pConfig_Stat_Info pStatInfoOut,
|
|
IN ULONG ulBufferLen
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Copies the existing Iso traffic counter values into buffer supplied by caller. The
|
|
values of the counter variables are defined in IOCTL.H in the pIsoStats structure.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
Irp - pointer to the Irp created in the Ioctl
|
|
pIsoStats - pointer to buffer where stats will go
|
|
ulBufferLen - len of above output buffer
|
|
|
|
Return Value:
|
|
NT status of STATUS_SUCCESS means copy was successful
|
|
NT status of STATUS_INVALID_PARAMETER means a param (usually a pointer) was bad
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG Upper, Lower;
|
|
pConfig_Stat_Info pStatInfo = NULL;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("In GetStats (%x) (%x) (%x) (%d)\n",
|
|
DeviceObject,Irp,pStatInfoOut,ulBufferLen));
|
|
|
|
ASSERT (deviceExtension != NULL);
|
|
|
|
if (deviceExtension) {
|
|
pStatInfo = deviceExtension->pConfig_Stat_Information;
|
|
}
|
|
|
|
ASSERT (pStatInfo!= NULL);
|
|
|
|
GET_PENTIUM_CLOCK_COUNT(Upper,Lower);
|
|
|
|
if ( (pStatInfoOut) && (ulBufferLen >= sizeof(Config_Stat_Info)) ) {
|
|
|
|
// Only copy the stat info from the dev ext area if it exists
|
|
if (pStatInfo) {
|
|
memcpy (pStatInfoOut, pStatInfo, sizeof (Config_Stat_Info));
|
|
}/* if dev ext's stat/config info exists */
|
|
|
|
// Get the global mem alloc/free info
|
|
pStatInfoOut->ulBytesAllocated = gulBytesAllocated;
|
|
pStatInfoOut->ulBytesFreed = gulBytesFreed;
|
|
|
|
// Get the current countdown value
|
|
pStatInfoOut->ulCountDownToStop= deviceExtension->ulCountDownToStop;
|
|
|
|
// Get the Pentium counter values
|
|
pStatInfoOut->ulUpperClockCount=Upper;
|
|
pStatInfoOut->ulLowerClockCount=Lower;
|
|
|
|
// Get the device type
|
|
pStatInfoOut->DeviceType = deviceExtension->dtTestDeviceType;
|
|
|
|
Irp->IoStatus.Information = sizeof (Config_Stat_Info);
|
|
|
|
} else {
|
|
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
}/* else */
|
|
|
|
return (ntStatus);
|
|
|
|
}//ISOPERF_GetStats
|
|
|
|
NTSTATUS
|
|
ISOPERF_SetDriverConfig (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN OUT pConfig_Stat_Info pConfInfoIn,
|
|
IN ULONG ulBufferLen
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Sets the driver's test parameters. These are only checked by this driver when the
|
|
Iso tests are started. So, if a user mode app tries to set these after a test has started
|
|
they will take effect on the next "start" of the test.
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device extension for this instance of the device
|
|
Irp - pointer to the Irp created in the Ioctl
|
|
pIsoStats - pointer to buffer where config info is located
|
|
ulBufferLen - len of above input buffer
|
|
|
|
Return Value:
|
|
NT status of STATUS_SUCCESS means setting of params was successful
|
|
NT status of STATUS_INVALID_PARAMETER means a param (usually a pointer) was bad
|
|
|
|
--*/
|
|
{
|
|
pConfig_Stat_Info pDriverConfigInfo = NULL;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
ASSERT (deviceExtension != NULL);
|
|
|
|
if (deviceExtension) {
|
|
pDriverConfigInfo = deviceExtension->pConfig_Stat_Information;
|
|
}else{
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
}//else bad dev ext
|
|
|
|
ASSERT (pDriverConfigInfo!= NULL);
|
|
|
|
if ( (pConfInfoIn) && (ulBufferLen >= sizeof(Config_Stat_Info)) ) {
|
|
|
|
// Only copy the stat info from the dev ext area if it exists
|
|
if (pDriverConfigInfo) {
|
|
|
|
//Set the config info in the driver's config/stat area
|
|
pDriverConfigInfo->ulNumberOfFrames = pConfInfoIn->ulNumberOfFrames;
|
|
pDriverConfigInfo->ulMax_Urbs_Per_Pipe = pConfInfoIn->ulMax_Urbs_Per_Pipe;
|
|
pDriverConfigInfo->ulDoInOutTest = pConfInfoIn->ulDoInOutTest;
|
|
pDriverConfigInfo->ulFrameOffset = pConfInfoIn->ulFrameOffset;
|
|
pDriverConfigInfo->ulFrameOffsetMate = pConfInfoIn->ulFrameOffsetMate;
|
|
|
|
ISOPERF_KdPrint (("Setting Driver Config-Number of Frames: %d | MaxUrbsPerPipe: %d | DoInOut: %d | FrameOffset %d | MateOffset %d\n",
|
|
pDriverConfigInfo->ulNumberOfFrames,
|
|
pDriverConfigInfo->ulMax_Urbs_Per_Pipe,
|
|
pDriverConfigInfo->ulDoInOutTest,
|
|
pDriverConfigInfo->ulFrameOffset,
|
|
pDriverConfigInfo->ulFrameOffsetMate));
|
|
|
|
}/* if dev ext's stat/config info exists */
|
|
else {
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
}//else bad dev extension
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
} else {
|
|
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
}/* else bad buffer passed in (pointer was bad, or length was not correct) */
|
|
|
|
return (ntStatus);
|
|
|
|
}//ISOPERF_SetDriverConfig
|
|
|
|
NTSTATUS
|
|
ISOPERF_FindMateDevice (
|
|
PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
Searches the linked list of device objects looking for the long lost mate device for the
|
|
given device object. By practicing safe device mating rituals (ie., checking that the device
|
|
object is a known type, etc.) it then puts the mate's device object pointer into the device extension
|
|
of the given device object.
|
|
|
|
If no mate is found, sadly, then this routine puts a NULL in the mate deviceobject field in the dev extension,
|
|
and returns a STATUS_NOT_FOUND result code
|
|
|
|
++*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PDRIVER_OBJECT driverObject = DeviceObject->DriverObject;
|
|
PDEVICE_OBJECT NextDeviceObject = DeviceObject->NextDevice;
|
|
PDEVICE_EXTENSION NextDeviceExtension = NULL;
|
|
dtDeviceType dtMateTestDeviceTypeA = Unknown_Device_Type;
|
|
dtDeviceType dtMateTestDeviceTypeB = Unknown_Device_Type;
|
|
|
|
ASSERT (DeviceObject != NULL);
|
|
ASSERT (deviceExtension!=NULL);
|
|
|
|
if (NextDeviceObject == NULL) {
|
|
ISOPERF_KdPrint(("FindMateDevice: No Next Device\n"));
|
|
|
|
// NOTE: (old code)
|
|
// WDM appears to be loading an entirely separate driver image for the same venid/prodid.
|
|
// This makes the approach where we look at the device chain to find the next device in the
|
|
// chain not feasible, so as a shortterm fix we'll put the Device Object for a Output Iso device
|
|
// in a global variable (which does seem to persist across dd loads) and we'll see if that is a
|
|
// mate. kjaff 12/24/96
|
|
if (gMyOutputDevice!=NULL) {
|
|
ISOPERF_KdPrint(("There is a global device us to check...(%x)\n",gMyOutputDevice));
|
|
NextDeviceObject = gMyOutputDevice;
|
|
NextDeviceExtension = NextDeviceObject->DeviceExtension;
|
|
} else {
|
|
ISOPERF_KdPrint (("No global device found either...exiting...\n"));
|
|
return STATUS_NOT_FOUND;
|
|
}//else no global either
|
|
|
|
}else{
|
|
NextDeviceExtension = NextDeviceObject->DeviceExtension;
|
|
ISOPERF_KdPrint(("Found a NextDevice: %x\n",NextDeviceObject));
|
|
}//else there is a next device
|
|
|
|
// The Mate for the device is dependent on the device type
|
|
switch (deviceExtension->dtTestDeviceType) {
|
|
case Iso_In_With_Pattern:
|
|
//This dev can have 2 mate types
|
|
ISOPERF_KdPrint (("Looking for a mate for Iso_In_With_Pattern %d\n",deviceExtension->dtTestDeviceType));
|
|
dtMateTestDeviceTypeA = Iso_Out_With_Interrupt_Feedback;
|
|
dtMateTestDeviceTypeB = Iso_Out_Without_Feedback;
|
|
break;
|
|
|
|
case Iso_Out_With_Interrupt_Feedback:
|
|
break;
|
|
|
|
case Iso_Out_Without_Feedback:
|
|
break;
|
|
|
|
case Unknown_Device_Type:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}//switch on device type
|
|
|
|
ntStatus = STATUS_NOT_FOUND; //assume we haven't found the mate
|
|
|
|
while (NextDeviceObject != NULL) {
|
|
|
|
NextDeviceExtension = NextDeviceObject->DeviceExtension;
|
|
|
|
// Is this the mate?
|
|
if ( (NextDeviceExtension->dtTestDeviceType == dtMateTestDeviceTypeA) ||
|
|
(NextDeviceExtension->dtTestDeviceType == dtMateTestDeviceTypeB) ) {
|
|
|
|
ISOPERF_KdPrint (("Found a mate for Dev %X : %X\n",DeviceObject, NextDeviceObject));
|
|
|
|
//Found a mate, so fill in this dev object into the given dev obj's ext
|
|
deviceExtension->MateDeviceObject = NextDeviceObject;
|
|
ntStatus = STATUS_SUCCESS;
|
|
break; //drop out of the while
|
|
|
|
} else {
|
|
|
|
ISOPERF_KdPrint (("%x is not a mate for Dev %X (type:%d\n",
|
|
NextDeviceObject,
|
|
DeviceObject,
|
|
NextDeviceExtension->dtTestDeviceType));
|
|
|
|
// Get the next device object
|
|
NextDeviceObject = NextDeviceObject->NextDevice;
|
|
|
|
}//else go on to next device object
|
|
|
|
}//while next dev obj
|
|
|
|
ISOPERF_KdPrint (("FindMateDevice exiting...\n"));
|
|
|
|
return ntStatus;
|
|
|
|
}//ISOPERF_FindMateDevice
|
|
|
|
|
|
VOID
|
|
ISOPERF_StartIsoOutTest (
|
|
IN PISOPERF_WORKITEM IsoperfWorkItem
|
|
)
|
|
/*++
|
|
|
|
Queues an Irp to the USB stack on the given device object.
|
|
|
|
Inputs:
|
|
IsoperfWorkItem - This routine is designed to be fired offf either directly or via a Work Item. The
|
|
work item structure only allows for one parameter to be passed to the work item
|
|
routine, hence this single workitem parameter.
|
|
|
|
Return Value:
|
|
None
|
|
|
|
++*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
PDEVICE_EXTENSION deviceExtension = NULL;
|
|
PUSBD_INTERFACE_INFORMATION pInterfaceInfo = NULL;
|
|
PUSBD_PIPE_INFORMATION pUsbdPipeInfo = NULL;
|
|
pConfig_Stat_Info configStatInfo = NULL;
|
|
PVOID pvBuff = NULL;
|
|
PURB urb = NULL;
|
|
ULONG ulBufferSize = 0;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
IsoTxferContext * pIsoContext = NULL;
|
|
ULONG ulFrameNumber = 0;
|
|
ULONG NumberOfFrames = 0;
|
|
ULONG i = 0;
|
|
|
|
deviceObject = IsoperfWorkItem->DeviceObject;
|
|
pvBuff = IsoperfWorkItem->pvBuffer;
|
|
ulBufferSize = IsoperfWorkItem->ulBufferLen;
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
pInterfaceInfo = deviceExtension->Interface[ucIsoInterface];
|
|
configStatInfo = deviceExtension->pConfig_Stat_Information;
|
|
|
|
ASSERT (pInterfaceInfo!=NULL);
|
|
ASSERT (configStatInfo != NULL);
|
|
ASSERT (deviceObject != NULL);
|
|
|
|
if ( (configStatInfo==NULL) || (pInterfaceInfo==NULL) || (deviceObject==NULL) ) {
|
|
ISOPERF_KdPrint (("Bad Parameter Received: configInf: %x | InterfInfo: %x | DevObj: %x\n",
|
|
configStatInfo, pInterfaceInfo, deviceObject));
|
|
TRAP();
|
|
return;
|
|
}//if any params are bad
|
|
|
|
// Check out the offset provided to make sure it's not too big
|
|
if (configStatInfo->ulFrameOffset >= USBD_ISO_START_FRAME_RANGE) {
|
|
ISOPERF_KdPrint (("ISOOUT: Error-Detected a FrameOffset Larger than allowed! (%d)\n",configStatInfo->ulFrameOffset));
|
|
TRAP();
|
|
return;
|
|
}//if bad frame offset
|
|
|
|
if (IsoperfWorkItem->bFirstUrb) {
|
|
|
|
// We have to match the endpoint maxpacket sizes for this to work (we can't assume that this is the
|
|
// case since the Out device sometimes seems to have a larger maxpacket than the In device
|
|
// DESIGNDESIGN This may be OK if we later on want to do some rate-matching emulation here.
|
|
if ( (deviceExtension->Interface[0]->Pipes[0].MaximumPacketSize) >= IsoperfWorkItem->InMaxPacket ) {
|
|
deviceExtension->Interface[0]->Pipes[0].MaximumPacketSize = IsoperfWorkItem->InMaxPacket;
|
|
} else {
|
|
//if the OUT device's maxpacket is smaller than the IN device's this seems incorrect so do nothing
|
|
return;
|
|
}//else the endpoint sizes seem out of whack
|
|
|
|
//#if 0
|
|
// Since this is the first Urb, we need the frame number, so get it
|
|
ulFrameNumber = ISOPERF_GetCurrentFrame(deviceObject);
|
|
|
|
ISOPERF_KdPrint (("StartISOOut got Frame Number: %x | Offset: %d\n",ulFrameNumber,configStatInfo->ulFrameOffset));
|
|
|
|
if (ulFrameNumber==0) {
|
|
ISOPERF_KdPrint (("Got Bad Frame Number (%x) ...exiting...\n",ulFrameNumber));
|
|
deviceExtension->StopTransfers = TRUE; //set flag so further transfers stop
|
|
return;
|
|
}//if bad frame #
|
|
|
|
//Save away the current frame number so the app can peek at it
|
|
configStatInfo->ulFrameNumberAtStart = ulFrameNumber;
|
|
|
|
// See what the user wants to do wrt starting frame number by looking at the config info
|
|
if (configStatInfo->ulFrameOffset == 0) {
|
|
// This means start ASAP
|
|
ulFrameNumber = 0;
|
|
}else {
|
|
//Add the offset that the User wants to add to this frame number (it better be less than 1024!)
|
|
ulFrameNumber += configStatInfo->ulFrameOffset;
|
|
} //else
|
|
|
|
//Save away the starting frame number so the app can peek at it
|
|
configStatInfo->ulStartingFrameNumber = ulFrameNumber;
|
|
|
|
ISOPERF_KdPrint (("StartISOOut using Frame Number: %x\n",ulFrameNumber));
|
|
|
|
//#endif
|
|
|
|
}//if this is the first Urb
|
|
else
|
|
{
|
|
ISOPERF_KdPrint (("StartISOOut _NOT_ the First URB!\n"));
|
|
}//else not first Urb
|
|
|
|
|
|
// Get the pipe info for the first pipe
|
|
pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
|
|
ASSERT(pUsbdPipeInfo != NULL);
|
|
|
|
if (deviceExtension->StopTransfers != TRUE) {
|
|
|
|
//We get the Urbs to submit and the Nbr of frames from the workitem because we want to
|
|
//make sure this is the same as the setting for the In device (this is filled in by InComplRoutine)
|
|
NumberOfFrames = IsoperfWorkItem->ulNumberOfFrames;
|
|
|
|
ASSERT (NumberOfFrames > 0);
|
|
|
|
//We get our own buffer for now...in the future this will be passed in if we decide to reuse the
|
|
//input device's buffer
|
|
pvBuff = ISOPERF_GetBuff (deviceObject,
|
|
0,//pipe number
|
|
0,//interfacenumber
|
|
NumberOfFrames,
|
|
&ulBufferSize
|
|
);
|
|
|
|
if (pvBuff==NULL){
|
|
return;
|
|
}else{
|
|
//Copy the input buffer into our output buffer (they should be the same size)
|
|
ASSERT (IsoperfWorkItem->ulBufferLen == ulBufferSize);
|
|
RtlCopyMemory (pvBuff, IsoperfWorkItem->pvBuffer, ulBufferSize);
|
|
}//if pvbuff
|
|
//...to here
|
|
|
|
//build the urb
|
|
urb = ISOPERF_BuildIsoRequest(deviceObject,
|
|
pUsbdPipeInfo, //Pipe info struct
|
|
FALSE, //WRITE
|
|
ulBufferSize, //Data buffer size
|
|
IsoperfWorkItem->bFirstUrb ? ulFrameNumber : 0,
|
|
pvBuff, //Data buffer
|
|
NULL //no MDL used
|
|
);
|
|
ISOPERF_KdPrint_MAXDEBUG (("OUT Urb: %x\n",urb));
|
|
|
|
pIsoContext = ISOPERF_ExAllocatePool (NonPagedPool, sizeof (IsoTxferContext), &gulBytesAllocated);
|
|
|
|
// Fill in the iso context
|
|
pIsoContext->urb = urb;
|
|
pIsoContext->DeviceObject = deviceObject;
|
|
pIsoContext->PipeInfo = pUsbdPipeInfo;
|
|
pIsoContext->pvBuffer = pvBuff; //NOTE: set this to NULL if you're using the IN device's buffer
|
|
pIsoContext->ulBufferLen = ulBufferSize;
|
|
pIsoContext->PipeNumber = 0;
|
|
pIsoContext->NumPackets = urb->UrbIsochronousTransfer.NumberOfPackets;
|
|
pIsoContext->bFirstUrb = IsoperfWorkItem->bFirstUrb;
|
|
|
|
//Create our own Irp for the device and call the usb stack w/ our urb/irp
|
|
ntStatus = ISOPERF_CallUSBDEx ( deviceObject,
|
|
urb,
|
|
FALSE, //Don't block
|
|
ISOPERF_IsoOutCompletion,//Completion routine
|
|
pIsoContext, //pvContext
|
|
FALSE); //don't want timeout
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
deviceExtension->DeviceIsBusy = TRUE;
|
|
deviceExtension->bStopIsoTest = FALSE;
|
|
deviceExtension->StopTransfers = FALSE;
|
|
configStatInfo->erError = NoError;
|
|
configStatInfo->bDeviceRunning = 1;
|
|
|
|
} else {
|
|
|
|
// An error occurred, so stop things and report it thru config/stat info
|
|
deviceExtension->DeviceIsBusy = FALSE;
|
|
deviceExtension->bStopIsoTest = TRUE;
|
|
deviceExtension->StopTransfers = TRUE;
|
|
configStatInfo->erError = ErrorInPostingUrb;
|
|
configStatInfo->bDeviceRunning = 0;
|
|
|
|
// If the URB status code got filled in then extract the info returned
|
|
if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
|
|
ISOPERF_KdPrint (("StartIsoOut -- Urb unsuccessful (status: %#x)\n",urb->UrbHeader.Status));
|
|
|
|
configStatInfo->UrbStatusCode = urb->UrbHeader.Status;
|
|
|
|
// Dump out the status for the packets
|
|
for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
|
|
i,
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Status));
|
|
|
|
// Put the last known bad packet status code into this space in the stat area
|
|
if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
|
|
configStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
|
|
}//if hit a fail code
|
|
|
|
}//for all the packets
|
|
}// if bad Urb status code
|
|
|
|
}//else there was an error
|
|
|
|
}else{
|
|
ISOPERF_KdPrint_MAXDEBUG (("IsoOut not submitting Urbs because StopTransfers is asserted!\n"));
|
|
}//else we are being asked to stoptransfers
|
|
|
|
//Free the work item junk
|
|
ISOPERF_ExFreePool (IsoperfWorkItem, &gulBytesFreed);
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("Exit StartIsoOut\n"));
|
|
|
|
return;
|
|
|
|
}//ISOPERF_StartIsoOutTest
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_IsoOutCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
This is the completion routine for the Iso OUT transfer
|
|
|
|
Inputs:
|
|
Device Object - the device object
|
|
Irp - The Irp we posted that is being completed
|
|
Context - pointer to our defined context which has our DeviceObject since it comes back as NULL here
|
|
DeviceObject is obtained from context due to old, old bug
|
|
in initial WDM implemenations
|
|
|
|
Return Value:
|
|
ntStatus
|
|
|
|
++*/
|
|
{
|
|
PIsoTxterContext pIsoContext;
|
|
PDEVICE_OBJECT myDeviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PURB urb;
|
|
pConfig_Stat_Info pStatInfo;
|
|
char * pcWork = NULL; //a worker pointer
|
|
ULONG i = 0;
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("In IsoOUTCompletion\n"));
|
|
|
|
TRAP();
|
|
|
|
pIsoContext = Context;
|
|
myDeviceObject = pIsoContext->DeviceObject;
|
|
deviceExtension = myDeviceObject->DeviceExtension;
|
|
urb = pIsoContext->urb;
|
|
pStatInfo = deviceExtension->pConfig_Stat_Information;
|
|
|
|
// Check the USBD status code and only proceed in resubmission if the Urb was successful
|
|
// or if the device extension flag that indicates the device is gone is FALSE
|
|
if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
|
|
ISOPERF_KdPrint (("IsoOUT Urb %x unsuccessful (status: %x)\n",urb,(urb->UrbHeader.Status)));
|
|
|
|
// Don't let it go on w/ the tests
|
|
deviceExtension->StopTransfers = TRUE;
|
|
|
|
// Fill in stat info
|
|
if (pStatInfo) {
|
|
pStatInfo->erError = UsbdErrorInCompletion;
|
|
pStatInfo->bStopped = 1;
|
|
pStatInfo->UrbStatusCode = urb->UrbHeader.Status;
|
|
|
|
}//if pStatInfo
|
|
|
|
// Dump out the status for the packets
|
|
for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
|
|
ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
|
|
i,
|
|
urb->UrbIsochronousTransfer.IsoPacket[i].Status));
|
|
|
|
// Put the last known bad packet status code into this space in the stat area
|
|
if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
|
|
|
|
pStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
|
|
|
|
}//if hit a fail code
|
|
|
|
}//for all the packets
|
|
|
|
}//if failure detected
|
|
|
|
// Free up the URB memory created for this transfer that we are retiring
|
|
if (urb) {
|
|
|
|
|
|
// We can't free the Urb itself, since it has some junk before it, so we have to roll back the
|
|
// pointer to get to the beginning of the block that we originally allocated, and then try to free it.
|
|
pcWork = (char*)urb; //get the urb
|
|
urb = (PURB) (pcWork - (2*sizeof(ULONG))); //the original pointer is 2 DWORDs behind the Urb
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("Freeing Urb: %x\n",urb));
|
|
ISOPERF_ExFreePool (urb, &gulBytesFreed);
|
|
|
|
}//if
|
|
|
|
if (pIsoContext) {
|
|
|
|
// Free the data buffer
|
|
// NOTE: This only can be done if we own this data buffer. If the same data buffer that
|
|
// the IN device is using is being used here, then we don't want to free this buffer.
|
|
// The presence of a pointer to the data buffer will tell us that
|
|
if (pIsoContext->pvBuffer) {
|
|
ISOPERF_KdPrint_MAXDEBUG (("Freeing pvBuffer: %x\n",pIsoContext->pvBuffer));
|
|
ISOPERF_ExFreePool(pIsoContext->pvBuffer, &gulBytesFreed);
|
|
}//if pvbuffer
|
|
|
|
// Free the Iso Context
|
|
ISOPERF_KdPrint_MAXDEBUG (("Freeing pIsoContext: %x\n",pIsoContext));
|
|
ISOPERF_ExFreePool (pIsoContext, &gulBytesFreed);
|
|
|
|
}//if valid Iso Context
|
|
|
|
//Free the IoStatus block
|
|
if (Irp->UserIosb) {
|
|
ISOPERF_KdPrint_MAXDEBUG (("Freeing My IoStatus Block: %x\n",Irp->UserIosb));
|
|
ISOPERF_ExFreePool(Irp->UserIosb, &gulBytesFreed);
|
|
} else {
|
|
//Bad thing...no IoStatus block pointer??
|
|
ISOPERF_KdPrint (("ERROR: Irp's IoStatus block is apparently NULL!\n"));
|
|
TRAP();
|
|
}//else bad iostatus pointer
|
|
|
|
// Free the Irp we created
|
|
ISOPERF_KdPrint (("Freeing Irp %x\n",Irp));
|
|
IoFreeIrp(Irp);
|
|
|
|
ISOPERF_KdPrint_MAXDEBUG (("Exit IsoOUTCompletion\n"));
|
|
|
|
return (STATUS_MORE_PROCESSING_REQUIRED); //Leave the Irp alone, IOS, since we're the top level driver
|
|
|
|
}//ISOPERF_IsoOutCompletion
|
|
|
|
|
|
NTSTATUS
|
|
ISOPERF_TimeStampUrb ( PVOID urb,
|
|
PULONG pulLower,
|
|
PULONG pulUpper
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Puts a Pentium Clock count time stamp 2 DWORDS before the given pointer (usually a urb,
|
|
hence the name of the function).
|
|
|
|
This function can also be used to simply get the Pentium clock count, although there
|
|
is already a Macro to do that.
|
|
|
|
Inputs:
|
|
PVOID urb - pointer to a chunk of memory that ususally contains a Urb
|
|
PULONG puLower - pointer to a ULONG that gets the current upper CPU clock count (eax)
|
|
PULONG puUpper - same as lower, but the upper ULONG value (edx)
|
|
|
|
Return Value:
|
|
ntStatus indiciating success/fail
|
|
|
|
--*/
|
|
{
|
|
char * pcWork;
|
|
ULONG u,l;
|
|
|
|
GET_PENTIUM_CLOCK_COUNT (u,l);
|
|
|
|
// Time stamp the Urb before we send it down the stack
|
|
pcWork = (char*) (urb);
|
|
|
|
//Backup 2 DWORDS
|
|
pcWork -= (2*sizeof(ULONG));
|
|
|
|
//First DWORD is the Upper value (edx)
|
|
*((PULONG)pcWork) = u;
|
|
|
|
//Goto next DWORD
|
|
pcWork += sizeof(ULONG);
|
|
|
|
//Second DWORD is the Lower value (eax)
|
|
*((PULONG)pcWork) = l;
|
|
|
|
// Copy the values to the caller's supplied area
|
|
*pulUpper = u;
|
|
*pulLower = l;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ISOPERF_GetUrbTimeStamp ( PVOID urb,
|
|
PULONG pulLower,
|
|
PULONG pulUpper
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
Gets the Pentium Clock count time stamp 2 DWORDS before the given pointer (usually a urb,
|
|
hence the name of the function).
|
|
|
|
Inputs:
|
|
PVOID urb - pointer to a chunk of memory that ususally contains a Urb
|
|
PULONG puLower - pointer to a ULONG that gets the upper CPU clock count from the timestamp area(eax)
|
|
PULONG puUpper - same as lower, but the upper ULONG value (edx)
|
|
|
|
Return Value:
|
|
ntStatus indiciating success/fail
|
|
--*/
|
|
{
|
|
|
|
char * pcWork;
|
|
|
|
//Get the Urb's pointer
|
|
pcWork = (char *) urb;
|
|
|
|
//The first DW before the Urb is the lower DW of the clk cnt...
|
|
pcWork -= (sizeof(ULONG));
|
|
|
|
//...when the Urb was posted to the Usb stack
|
|
*pulLower = *((ULONG*)pcWork);
|
|
|
|
//NOTE: we don't care about the upper value right now...
|
|
*pulUpper = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}//ISOPERF_GetUrbTimeStamp
|
|
|