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

📄 usbdev.h

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 H
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
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.

Module Name:  

    usbdev.h

Abstract:  

    Bluetooth HCI USB interface

    
Functions:


Notes:

--*/
#ifndef _USBDEV_H_
#define _USBDEB_H_

//
//	There are two build flags that define how desynchronization
//	of event and data channel is handled.
//
//	Problem description:
//	There is not synchronization between event and data channels,
//	which means that data on connection can preceed connection completion
//	event and therefore thrown out. This is solved in USB driver (if
//  CONNECTION_TRACKING is defined) by keeping list of existing connections
//	and stalling data pipe if data packet came on nonexistent connection.
//	The following events are processed to track connection states:
//			HCI_Connection_Complete_Event			= 0x03,
//			HCI_Disconnection_Complete_Event		= 0x05,
//			HCI_Command_Complete_Event				= 0x0e for HCI_Reset command
//	Note, that this policy makes reversal of data packet and
//	disconnection events even worse, but this is less likely since
//	normally there is a lag between last packet and when the connection is
//	actually closed. Slight bias in processing events (they are processed
//	before data) is given to rectify this situation even further.
//
//	If CONNECTION_TRACKING is not defined, NATIVE_SEQUENCING flag can be
//	used to forwrd packets up in exactly the sequence in which they arrived
//	from the driver. If this flag is not defined, slight bias is given to
//	event packets.
//
#define CONNECTION_TRACKING		1

#if defined (CONNECTION_TRACKING) && defined (NATIVE_SEQUENCING)
#error Connection tracking and native sequencing not supported
#endif

#define SCO_DEFAULT_SAMPLE_SIZE             8
#define SCO_DEFAULT_WRITE_LOW_NUM_PACKETS   4
#define SCO_DEFAULT_WRITE_HIGH_NUM_PACKETS  8
#define SCO_DEFAULT_PACKET_SIZE             27

#define SCO_WRITE_FRAMES_PER_PACKET   3
#define SCO_READ_FRAMES_PER_PACKET    3

#define SCO_READ_PACKETS_PER_TRANSFER       9
#define MAX_SCO_READ_PACKETS_PER_TRANSFER   15
#define MAX_SCO_READ_FRAMES_PER_TRANSFER    (MAX_SCO_READ_PACKETS_PER_TRANSFER * SCO_READ_FRAMES_PER_PACKET)

//
// These constants control the characteristics of the SCO writing system.
//

#define DEFPACKETSIZE		256		
#define DEFBLOCKSIZE		5

#define NUM_SCO_ENDPOINTS	6	
#define NUM_IN_PIPES		3
#define NUM_OUT_PIPES		2

#define PACKET_SCO			0
#define PACKET_ACL			1
#define PACKET_COMMAND		2

#define SCO_HEADER_SIZE		3
#define ACL_HEADER_SIZE		4
#define EVENT_HEADER_SIZE	2

#define EVENT_ISOCH			0
#define EVENT_BULK			1
#define EVENT_INTERRUPT		2
#define EVENT_CLOSE			3
#define EVENT_WRITTEN		4

#define PACKET_SIZE_R		(64 * 1024 + 128)
#define PACKET_SIZE_W		(255 + 3)

#if defined (CONNECTION_TRACKING)
#define CONNECTION_TRACKING_TIMEOUT	1000
#endif

class PACKET;
class CUsbPipe;
class CUsbDevice;
class CSynch;
class CRingBuffer;

extern CSynch				*gpsynchUsbDevice;
extern CUsbDevice			*gpUsbDevice;
extern CRingBuffer			*gpRingBuffer;
extern HANDLE				gheventRead[NUM_IN_PIPES];
extern HANDLE				gheventClose;
extern HANDLE				gheventWritten;
extern HANDLE				gheventPackets;

extern HCI_TransportCallback gCallback;
extern HINSTANCE ghInst;

class CSynch : public SVSSynch
{
};

class CLocalCriticalSection 
{
protected:
	CSynch *m_pSynch;

public:
	CLocalCriticalSection (CSynch *pSynch) 
	{
		m_pSynch = pSynch;
		pSynch->Lock();
	}

	~CLocalCriticalSection (void) 
	{
		m_pSynch->Unlock();
	}
	
	inline int IsLocked()	
	{
		return m_pSynch->IsLocked();
	}
};


class CUsbPipe
{
public:
	USB_PIPE		_hPipe;
	USB_TRANSFER	_hTransfer;
	PACKET			*_pCurPacket;

	PACKET			*_pPackets;
	PACKET			*_pLastPacket;

	int				iTotalQueue;

public:
	CUsbPipe()
	{
		memset (this, 0, sizeof(*this));
	}
};

#if defined (NATIVE_SEQUENCING)
struct CompletedPacket {
	CompletedPacket *pNext;
	int				eType;
	int				cLength;

	unsigned char	ucData[1];
};
#endif

class CUsbDevice
{
public:
	CUsbDevice();
	~CUsbDevice();

	BOOL DeviceAttach(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs);
	BOOL CloseDevice();
	BOOL StartHardware();
	BOOL StopHardware();
	
	DWORD OpenConnection(void);
	void  CloseConnection(void);

	int WritePacket (unsigned char *pBuffer, int nLen, HCI_TYPE eType);
	int ReadPacket (unsigned char *pBuffer, int *pnLen, int *pnType);

	DWORD ScoWriteInit();
	DWORD ScoWriteDeinit();

	BOOL IsScoActive();

protected:
	
	static DWORD WINAPI ReadNotify(LPVOID lpvNotifyParameter);
	static DWORD WINAPI WriteNotify(LPVOID lpvNotifyParameter);
	static DWORD WINAPI ScoWriteNotify(LPVOID lpvNotifyParameter);

	static DWORD WINAPI ReadThreadProcStub(LPVOID lpvNotifyParameter);
	DWORD ReadThreadProc(void);

	BOOL ParseConfig(LPCUSB_CONFIGURATION lpConfig);
	BOOL Initialize(void);
	BOOL CheckDevice();
	BOOL SubmitReadRequest(int nEvent);

	int GetBuffer (int nType, int cOffset, int cNeeded, unsigned char *d, int fCleanPackets);
	int PacketSize (int nType);
	int CompletePacket (int nType);

	int RetrievePacket (unsigned char *pBuffer, int *pnLen, int *pnType, DWORD *pdwTimeout);
	
	BOOL CloseConnectionHelper();

public:
    LPCUSB_FUNCS				_lpUsbFuncs;	
	FixedMemDescr				*_pfmdPackets;

protected:
    USB_HANDLE					_hDevice;

	USB_ENDPOINT_DESCRIPTOR		_endpEvents;
	USB_ENDPOINT_DESCRIPTOR		_endpACLIn;
	USB_ENDPOINT_DESCRIPTOR		_endpACLOut;

	USB_ENDPOINT_DESCRIPTOR 	_endpSCOIn[NUM_SCO_ENDPOINTS];
	UCHAR						_endpSCOAltSetting[NUM_SCO_ENDPOINTS];
	USB_ENDPOINT_DESCRIPTOR 	_endpSCOOut[NUM_SCO_ENDPOINTS];
	int 						_nSCOInCount, _nSCOOutCount;
	int 						_nScoPipeIdx;
	DWORD						_dwInTransferLens[MAX_SCO_READ_FRAMES_PER_TRANSFER];
	DWORD						_dwOutTransferLens[SCO_WRITE_FRAMES_PER_PACKET];
	DWORD						_dwSuggestedScoAltSetting;

	LPCUSB_INTERFACE			_pIntfEvent;

	CUsbPipe					_usbPipes[NUM_IN_PIPES];

	USB_PIPE					_hOutPipes[NUM_OUT_PIPES];

	BOOL						_bClosing;
	BOOL						_bInitialized;
	BOOL						_bCloseScoIO;

	unsigned int				_uiPacketSize;
	unsigned int				_uiBlockSize;
	unsigned int				_uiMinPacketSize;
	unsigned int				_uiSCOReadFrames;

#if defined (NATIVE_SEQUENCING)
	CompletedPacket				*_pPacketList;
	CompletedPacket				*_pLastPacket;
#endif

#if defined (CONNECTION_TRACKING)
	SVSTree						*_pHandleTree;
#endif
};

typedef struct _USBWritePacket {
	USB_TRANSFER hTransfer;
	HCI_TYPE eType;
	UCHAR* pBuffer;
	DWORD dwLens[SCO_WRITE_FRAMES_PER_PACKET];
} USBWritePacket;

typedef struct _USBDescriptor {
	USBWritePacket packet;
	DWORD dwIdxStart;
	BOOL fReturned;
	DWORD dwTotalLen;
} USBDescriptor;

#define RING_BUFFER_SIZE		10240
#define MAX_ASYNC_PACKET_SIZE	2048
#define RING_BUFFER_END			(RING_BUFFER_SIZE - MAX_ASYNC_PACKET_SIZE)
#define MAX_ASYNC_PACKETS		32

class CRingBuffer : public SVSSynch {
public:
	CRingBuffer() {
		m_dwFreeSpace = RING_BUFFER_END;
		m_pBuffer = NULL;
		m_dwIdxCurrent = 0;
		m_cPackets = 0;
		m_dwNextDesc = 0;
		m_dwLastReturnedDesc = 0;
		m_dwIdxComplete = 0;
#ifdef DEBUG
		for(UINT i=0; i<MAX_ASYNC_PACKETS; i++) {
			m_desc[i].fReturned = TRUE;
			m_desc[i].dwIdxStart = 0xFFFFFFFF;
		}
#endif
	}

	DWORD Init(void) {
		m_pBuffer = new UCHAR[RING_BUFFER_SIZE];
		if (! m_pBuffer) {
			return ERROR_OUTOFMEMORY;	
		}	
		
		return ERROR_SUCCESS;
	}

	void Deinit(void) {
		delete[] m_pBuffer;
		m_pBuffer = NULL;
	}

	USBWritePacket* GetWritePacket(DWORD dwLen, DWORD* pdwIdxStart) {
		USBWritePacket* pPacket = NULL;

		Lock();

		if (m_dwFreeSpace < dwLen) {
			// No space left in ring buffer
			goto exit;
		}

		if (m_cPackets >= MAX_ASYNC_PACKETS) {
			// Out of packet descriptors
			goto exit;
		}

		if (dwLen > MAX_ASYNC_PACKET_SIZE) {
			// Packet is too large
			goto exit;
		}

		// Fill in descriptor
		ASSERT(m_desc[m_dwNextDesc].fReturned);
		m_desc[m_dwNextDesc].fReturned = FALSE;		
		m_desc[m_dwNextDesc].dwIdxStart = m_dwIdxCurrent;
		m_desc[m_dwNextDesc].dwTotalLen = dwLen;
		m_desc[m_dwNextDesc].packet.hTransfer = NULL;
		
		*pdwIdxStart = m_dwIdxCurrent;		

		// Get packet
		pPacket = &m_desc[m_dwNextDesc].packet;
		pPacket->pBuffer = &m_pBuffer[m_dwIdxCurrent];\

		// Calculate free space and current index
		m_dwFreeSpace -= dwLen;
		m_dwIdxCurrent += dwLen;
		if (m_dwIdxCurrent > RING_BUFFER_END) {
			m_dwFreeSpace += m_dwIdxCurrent - RING_BUFFER_END; // recalculate free space
			m_dwIdxCurrent = 0; // wrap around
		}
		
		// Increment packet count and descriptor index
		m_cPackets++;
		m_dwNextDesc = (m_dwNextDesc + 1) % MAX_ASYNC_PACKETS;

	exit:		
		Unlock();
		return pPacket;
	}

	void SignalComplete(DWORD dwIdxStart) {
		Lock ();
		
		m_dwComplete[m_dwIdxComplete] = dwIdxStart;
		m_dwIdxComplete++;

		SetEvent(gheventWritten);

		Unlock ();
	}

	DWORD CompletePackets(void) {
		Lock ();

		USB_TRANSFER hTransfer;

		for (DWORD i = 0; i < m_dwIdxComplete; i++) {
			hTransfer = NULL;
			if (ERROR_SUCCESS == CompletePacket(m_dwComplete[i], &hTransfer)) {
				if (hTransfer) {
					(*gpUsbDevice->_lpUsbFuncs->lpCloseTransfer)(hTransfer);
				}
			}
		}

		m_dwIdxComplete = 0;		

		Unlock ();

		return ERROR_SUCCESS;
	}

	DWORD CompletePacket(DWORD dwIdxStart, USB_TRANSFER* phTransfer) {
		DWORD dwRet = ERROR_SUCCESS;
		Lock();

		// Loop through the list of packets looking for dwIdxStart

		int i = m_dwLastReturnedDesc;
		DWORD dwCount = 0;
		while ((dwCount < m_cPackets) && (m_desc[i].dwIdxStart != dwIdxStart)) {
			dwCount++;
			i++;
			
			if (i == MAX_ASYNC_PACKETS) {
				i = 0;
			}
		}

		if (dwCount == m_cPackets) {
			dwRet = ERROR_NOT_FOUND; // not found
			ASSERT(FALSE);
			goto exit;
		}

		// Found packet, mark it as "returned"
		m_desc[i].fReturned = TRUE;

		if (phTransfer)
			*phTransfer = m_desc[i].packet.hTransfer;		

		// Loop through the descriptors and increment last returned descriptor
		// until we run into a descriptor that has not been returned yet or
		// get to the end of the list.

		ASSERT(m_dwLastReturnedDesc < MAX_ASYNC_PACKETS);
		dwCount = 0;
		DWORD dwTotal = m_cPackets;
		while ((dwCount < dwTotal) && m_desc[m_dwLastReturnedDesc].fReturned) {
			ASSERT(m_cPackets);			
			m_cPackets--;

			// Calculate free space
			DWORD dwIdxEnd = m_desc[m_dwLastReturnedDesc].dwIdxStart + m_desc[m_dwLastReturnedDesc].dwTotalLen;
			if (dwIdxEnd > RING_BUFFER_END) {
				ASSERT(m_desc[m_dwLastReturnedDesc].dwIdxStart <= RING_BUFFER_END);
				m_dwFreeSpace += (RING_BUFFER_END - m_desc[m_dwLastReturnedDesc].dwIdxStart);
			} else {				
				m_dwFreeSpace += m_desc[m_dwLastReturnedDesc].dwTotalLen;
			}

			m_dwLastReturnedDesc = (m_dwLastReturnedDesc + 1) % MAX_ASYNC_PACKETS;

			dwCount++;
		}		

	exit:
		Unlock();	
		return dwRet;
	}

private:
	DWORD m_dwIdxCurrent;
	DWORD m_dwFreeSpace;
	UCHAR* m_pBuffer;
	DWORD m_cPackets;
	DWORD m_dwLastReturnedDesc;
	DWORD m_dwNextDesc;
	USBDescriptor m_desc[MAX_ASYNC_PACKETS];
	DWORD m_dwIdxComplete;
	DWORD m_dwComplete[MAX_ASYNC_PACKETS];
};


class  PACKET
{
public:
	int 			nSize;
	int				nOffset;
	PACKET			*pNext;

#if defined (CONNECTION_TRACKING)
	DWORD			dwWhenReceived;
#endif

	unsigned char	data[1];

public:
	PACKET (void)
	{
		memset (this, 0, sizeof(*this));
	}

	void *operator new(size_t nSize)
	{
		ASSERT(gpUsbDevice->_pfmdPackets);
		ASSERT(nSize == sizeof(PACKET));

		void *pPacket = svsutil_GetFixed(gpUsbDevice->_pfmdPackets);
		ASSERT(pPacket);
		return pPacket;
	}

	void operator delete(void *ptr)
	{
		ASSERT(ptr);
		svsutil_FreeFixed(ptr, gpUsbDevice->_pfmdPackets);
	}
};

#if defined (CONNECTION_TRACKING)
#define HCI_Connection_Complete_Event			0x03
#define HCI_Disconnection_Complete_Event		0x05
#define HCI_Command_Complete_Event				0x0e
#define HCI_Reset								0x0c03
#endif

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -