📄 ezusbisotransfer.h
字号:
// EzUsbIsoTransfer.h
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060 USA
//
// Copyright (c) 1999 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================
#ifndef __EzUsbIsoTransfer__h__
#define __EzUsbIsoTransfer__h__
#define USB_MAX_NUM_ISO_PACKETS_IN_AN_URB 255
//MACROs for iso packets
#define ISO_PKT_STATUS(pUrb, i) pUrb->UrbIsochronousTransfer.IsoPacket[i].Status
#define ISO_PKT_LENGTH(pUrb, i) pUrb->UrbIsochronousTransfer.IsoPacket[i].Length
//This is the typedef for client callback function
typedef
VOID (*PISO_TRANSFER_COMPLETE_CALLBACK)(
PVOID pContext
);
//This is context for completion routine
typedef struct _ISOCH_COMPLETION_INFO
{
PVOID m_pClass;
PURB m_pUrb;
PVOID m_pClientContext;
PISO_TRANSFER_COMPLETE_CALLBACK m_pfnClientCallback;
} ISOCH_COMPLETION_INFO, *PISOCH_COMPLETION_INFO;
//This is the return value status codes
//for client's callback function
enum USB_STREAM_STATUS
{
USB_STREAM_STATUS_CONTINUE = 0,
USB_STREAM_STATUS_STOP
};
//=============================================================================
// template< class D >
// class KUsbIsochStream
//
// This class abstracts a continuous stream of IRP's from a driver to USBD.
//
template< class D >
class KUsbIsochStream
{
//Constructors/Destructors
public:
KUsbIsochStream<D>(void)
{
Data = NULL;
m_bStopTheStream = FALSE;
m_bStarted = FALSE;
m_NumIrps = 0;
m_ConstructorStatus = STATUS_SUCCESS;
m_pIsoXferDoneEvent = NULL;
m_ppIrp = NULL;
m_pDev = NULL;
m_pContext = NULL;
}
NTSTATUS Initialize(
D* d,
KUsbLowerDevice* dev
);
SAFE_DESTRUCTORS;
~KUsbIsochStream<D>(void);
void Invalidate(void);
BOOLEAN IsValid(void) { return NULL != Data;}
//Methods
public:
//Initiate continuous isoch xfers (asynchronous form)
NTSTATUS StartStream(
PISO_TRANSFER_COMPLETE_CALLBACK pfnCallback,
PVOID pClientContext=NULL
);
//Initiate continuous isoch xfers (synchronous form)
NTSTATUS StartStream(ULONG mSecTimeOut=0);
//stop isoch xfers (eventually)
NTSTATUS StopStream(
BOOLEAN bWait = TRUE,
ULONG mSecTimeOut = 100
);
BOOLEAN IsStarted(void){ return m_bStarted; }
BOOLEAN StopRequested(void){ return m_bStopTheStream; }
protected:
//used by synch form of Start to wait for completion routine to signal event
NTSTATUS WaitForTransferToFinish(ULONG mSecTimeOut);
//completion routine(s)
NTSTATUS IsoTransferCompletionRoutine(KIrp I, PISOCH_COMPLETION_INFO pContext);
static NTSTATUS __stdcall IsoTransferComplete(
PDEVICE_OBJECT pDevObj,
PIRP pIrp,
PVOID context
)
{
KIrp I(pIrp);
return reinterpret_cast<KUsbIsochStream<D>*>(((PISOCH_COMPLETION_INFO)context)->m_pClass)
->IsoTransferCompletionRoutine(I, (PISOCH_COMPLETION_INFO)context);
UNREFERENCED_PARAMETER(pDevObj);
}
//Data members
protected:
D* Data;
KUsbLowerDevice* m_pDev;
//Count of IRPs in use.
KInterlockedCounter m_PendingIrpCount;
//event set in completion routine
KEvent* m_pIsoXferDoneEvent;
//Pointer to IRPs
PIRP* m_ppIrp;
//Pointer to completion routine context
PISOCH_COMPLETION_INFO m_pContext;
//flag to stop the stream
BOOLEAN m_bStopTheStream;
//flag indicating that the stream has been started
BOOLEAN m_bStarted;
NTSTATUS m_ConstructorStatus;
//Total number of IRPs sent
ULONG m_dwTotalTransfers;
//this is how many IRPs are used
UCHAR m_NumIrps;
};
template <class D>
NTSTATUS KUsbIsochStream<D>::Initialize(
D* pD,
KUsbLowerDevice* pDev
)
{
ASSERT( pDev );
ASSERT( pD );
//Initialize data members
m_pDev = pDev;
Data = pD;
m_dwTotalTransfers = 0;
m_bStopTheStream = FALSE;
m_NumIrps = pD->NumberOfUrbs();
ASSERT(m_NumIrps);
m_pIsoXferDoneEvent = new (NonPagedPool) KEvent(SynchronizationEvent, FALSE);
if( NULL == m_pIsoXferDoneEvent )
{
return m_ConstructorStatus = STATUS_INSUFFICIENT_RESOURCES;
}
m_ppIrp = new (NonPagedPool) PIRP[m_NumIrps];
if( NULL == m_ppIrp )
{
delete m_pIsoXferDoneEvent;
m_pIsoXferDoneEvent = NULL;
return m_ConstructorStatus = STATUS_INSUFFICIENT_RESOURCES;
}
CCHAR stacks = static_cast<UCHAR>(pDev->StackRequirement());
ASSERT( stacks );
for( UCHAR i = 0; i < m_NumIrps; i++)
{
m_ppIrp[i] = IoAllocateIrp(stacks, FALSE);
if( NULL == m_ppIrp[i] )
{
m_ConstructorStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
//check for successful completion of the above loop
if( STATUS_INSUFFICIENT_RESOURCES == m_ConstructorStatus )
{
for( UCHAR j = 0; j < i; j++ )
{
IoFreeIrp( m_ppIrp[j] );
}
delete m_pIsoXferDoneEvent;
m_pIsoXferDoneEvent = NULL;
delete m_ppIrp;
m_ppIrp = NULL;
}
return m_ConstructorStatus;
}
template <class D>
KUsbIsochStream<D>::~KUsbIsochStream<D>(void)
{
if( IsValid() )
Invalidate();
}
template <class D>
void KUsbIsochStream<D>::Invalidate(void)
{
for( UCHAR k = 0; k < m_NumIrps; k++)
{
if( m_ppIrp[k] )
IoFreeIrp( m_ppIrp[k] );
}
delete m_ppIrp;
m_ppIrp = NULL;
delete m_pIsoXferDoneEvent;
m_pIsoXferDoneEvent = NULL;
Data = NULL;
m_bStopTheStream = FALSE;
m_bStarted = FALSE;
m_NumIrps = 0;
m_ConstructorStatus = STATUS_SUCCESS;
}
template <class D>
NTSTATUS KUsbIsochStream<D>::StartStream(ULONG mSecTimeOut)
{
ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
NTSTATUS status = StartStream(PISO_TRANSFER_COMPLETE_CALLBACK(NULL));
if( STATUS_SUCCESS == status )
{
status = WaitForTransferToFinish(mSecTimeOut);
}
return status;
}
template <class D>
NTSTATUS KUsbIsochStream<D>::StartStream(
PISO_TRANSFER_COMPLETE_CALLBACK pfnCallback,
PVOID pClientContext
)
{
NTSTATUS status = STATUS_SUCCESS;
m_pContext = new (NonPagedPool) ISOCH_COMPLETION_INFO[m_NumIrps];
if( NULL == m_pContext )
{
return STATUS_INSUFFICIENT_RESOURCES;
}
for( UCHAR i = 0; i < m_NumIrps; i++ )
{
PURB pUrb = Data->GetUrb(i);
if( pUrb )
{
m_pContext[i].m_pClass = this;
m_pContext[i].m_pUrb = pUrb;
m_pContext[i].m_pClientContext = pClientContext;
m_pContext[i].m_pfnClientCallback = pfnCallback;
++m_PendingIrpCount;
status = m_pDev->SubmitUrb(m_ppIrp[i], pUrb, IsoTransferComplete, &m_pContext[i]);
}
}
m_bStarted = TRUE;
return STATUS_SUCCESS;
}
template <class D>
NTSTATUS KUsbIsochStream<D>::StopStream(BOOLEAN bWait, ULONG mSecTimeOut)
{
NTSTATUS status = STATUS_SUCCESS;
m_bStopTheStream = TRUE;
if(bWait)
{
ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
status = WaitForTransferToFinish(mSecTimeOut);
}
m_bStarted = FALSE;
return status;
}
template <class D>
NTSTATUS KUsbIsochStream<D>::IsoTransferCompletionRoutine(
KIrp I,
PISOCH_COMPLETION_INFO pContext
)
{
ASSERT( pContext );
PURB pUrb = pContext->m_pUrb;
ASSERT( pUrb );
m_dwTotalTransfers++;
BOUNDS_CHECKER(COMPLETED_URB, (m_pDev, pUrb, I, I.Status()) );
USB_STREAM_STATUS StreamStatus = Data->OnCompletedUrb(pUrb, I.Status());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -