⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ezusbisotransfer.h

📁 DriverStdio的一个USB驱动程序
💻 H
📖 第 1 页 / 共 2 页
字号:
// 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 + -