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

📄 bthuniv.cxx

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//
// 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.
//
//------------------------------------------------------------------------------
// 
//      Bluetooth HCI interface
// 
// 
// Module Name:
// 
//      bthuniv.cxx
// 
// Abstract:
// 
//      This file implements a universal transport manager for bluetooth.
//		It forwards calls to the real driver. It first looks for PnP devices, and if 
//		doesn't find any it will try the builtin devices in order of preference 
//		listed in the registry.
//		
// 
//------------------------------------------------------------------------------
#include <windows.h>
#include <windev.h>
#include <dbt.h>
#include <usbdi.h>
#include <pnp.h>
#include <Msgqueue.h>

#include <bt_buffer.h>
#include <bt_hcip.h>
#include <bt_os.h>
#include <bt_debug.h>
#include <svsutil.hxx>
#include <bt_tdbg.h>

typedef int (* HCI_READHCIPARAMETERS)(HCI_PARAMETERS *);
typedef int (* HCI_STARTHARDWARE )(void);
typedef int (* HCI_STOPHARDWARE )(void);
typedef int (* HCI_OPENCONNECTION)(void);
typedef int (* HCI_READPACKET )(HCI_TYPE *, BD_BUFFER *);
typedef int (* HCI_WRITEPACKET )(HCI_TYPE , BD_BUFFER *);
typedef void (* HCI_CLOSECONNECTION )(void);
typedef int (* HCI_SETCALLBACK )(HCI_TransportCallback );

static HCI_READHCIPARAMETERS	pfnReadHciParameters = NULL;
static HCI_STARTHARDWARE		pfnStartHardware = NULL;
static HCI_STOPHARDWARE			pfnStopHardware = NULL;
static HCI_SETCALLBACK			pfnSetCallback = NULL;
static HCI_OPENCONNECTION		pfnOpenConnection = NULL;
static HCI_READPACKET			pfnReadPacket = NULL;
static HCI_WRITEPACKET			pfnWritePacket = NULL;
static HCI_CLOSECONNECTION		pfnCloseConnection = NULL;

static HCI_TransportCallback	pfnCallback = NULL;


static BOOL InitPointers();
static BOOL DeInitPointers();


DECLARE_DEBUG_VARS();

static HINSTANCE	ghInstance = NULL;
static HANDLE		ghStopNotifyThread;
static HANDLE		ghNotifyThread;

static BOOL			gfInitialized = FALSE;
static BOOL			gfStopHardware = FALSE;

static GUID			gIClassGuid;
static WCHAR		gwszDevName[MAX_DEVCLASS_NAMELEN];

HINSTANCE			ghCurDriver;

class CSynch : public SVSSynch, public SVSRefObj
{
};

CSynch	*gpSynch = NULL;

enum InCall
{
	eOther,
	eOpen,
	eClose
};
InCall	geInCall = eOther;

BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
    switch (dwReason) 
    {
    case DLL_PROCESS_ATTACH:
		svsutil_Initialize ();
		SVSUTIL_ASSERT(!gpSynch);

		gpSynch = new CSynch();
		if (!gpSynch)
			return FALSE;

		ghInstance = (HINSTANCE) hinstDLL;
		DisableThreadLibraryCalls((HMODULE) hinstDLL);
        break;
	
	case DLL_PROCESS_DETACH:
		SVSUTIL_ASSERT(gpSynch);
		SVSUTIL_ASSERT(!gpSynch->IsLocked());
		delete gpSynch;
		gpSynch = NULL;
		svsutil_DeInitialize ();
		break;

    default:
        break;
    }
    return TRUE ;
}


int GetGUID(WCHAR *psz, GUID *pGUID) {
	int data1, data2, data3;
	int data4[8];

	if (11 ==  swscanf(psz, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
					&data1, &data2, &data3,
					&data4[0], &data4[1], &data4[2], &data4[3], 
					&data4[4], &data4[5], &data4[6], &data4[7])) {
		pGUID->Data1 = data1;
		pGUID->Data2 = data2 & 0xffff;
		pGUID->Data3 = data3 & 0xffff;

		for (int i = 0 ; i < 8 ; ++i)
			pGUID->Data4[i] = data4[i] & 0xff;

		return TRUE;
	}

	return FALSE;
}

static VOID CopyValue(HKEY hkDest, HKEY hkSrc, LPWSTR pszValueName)
{
	WCHAR szValue[256];
	DWORD dwType = 0;
	DWORD dwSize = sizeof(szValue);
	
	if (!hkDest || !hkSrc || !pszValueName || !(*pszValueName))
		return;

	if (ERROR_SUCCESS == RegQueryValueEx(hkSrc, pszValueName, NULL, &dwType, (LPBYTE )szValue, &dwSize))
	{
		LONG lRet = RegSetValueEx(hkDest, pszValueName, 0, dwType, (LPBYTE )szValue, dwSize);
		SVSUTIL_ASSERT(lRet == ERROR_SUCCESS);
	}
}

static VOID DeleteValues(HKEY hk)
{
	DWORD dwIndex = 0;
	WCHAR szValueName[256];
	DWORD cbValueName = sizeof(szValueName) / sizeof(WCHAR);
	DWORD dwType = 0;

	if (!hk)
		return;

	while(ERROR_SUCCESS==RegEnumValue(hk, 0, szValueName, &cbValueName, NULL, &dwType, NULL, NULL))
	{
		LONG lRet = RegDeleteValue(hk, szValueName);
		SVSUTIL_ASSERT(lRet == ERROR_SUCCESS);
		cbValueName = sizeof(szValueName) / sizeof(WCHAR);
	}
}

static VOID CopyValues(HKEY hkDest, HKEY hkSrc)
{
	DWORD dwIndex = 0;
	WCHAR szValueName[256];
	DWORD cbValueName = sizeof(szValueName) / sizeof(WCHAR);
	DWORD dwType = 0;

	while(ERROR_SUCCESS==RegEnumValue(hkSrc, dwIndex++, szValueName, &cbValueName, NULL, &dwType, NULL, NULL))
	{
		CopyValue (hkDest, hkSrc, szValueName);
		cbValueName = sizeof(szValueName) / sizeof(WCHAR);
	}
}

static VOID CopyRegistryEntry(LPWSTR szTo, LPWSTR szFrom, HKEY hkFrom, int fCleanKey)
{
	HKEY hKey1=NULL, hKey2=NULL;
	DWORD dwDisp = 0;

	LONG lRet = RegCreateKeyEx(HKEY_BASE, szTo, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey1, &dwDisp);
	SVSUTIL_ASSERT(lRet == ERROR_SUCCESS);

	lRet = RegOpenKeyEx(hkFrom, szFrom, 0, 0, &hKey2);
	SVSUTIL_ASSERT(lRet == ERROR_SUCCESS);

	if (hKey1 && hKey2)
	{
		if (fCleanKey)
			DeleteValues(hKey1);
		CopyValues (hKey1, hKey2);
	}
	if (hKey1)
		RegCloseKey(hKey1);
	if (hKey2)
		RegCloseKey(hKey2);
}


/*

This function is called by the current transport driver to indicate
"DEVICE_UP" or "DEVICE_DOWN".  This function will call back into HCI
to notify device insertion.

*/
static int TransportCallback(HCI_EVENT iEvent, void *lpEvent) 
{
	int nRet = S_FALSE;
	
	gpSynch->Lock();
	BOOL fInit = gfInitialized;
	HCI_TransportCallback	pfn = pfnCallback;
	BOOL fStopHardware = gfStopHardware;
	HINSTANCE hLib = ghCurDriver;
	gpSynch->AddRef();
	gpSynch->Unlock();

	if ((fInit) && (pfn) && (!fStopHardware) && (!hLib))
		nRet = pfn(iEvent, lpEvent);

	gpSynch->Lock();
	gpSynch->DelRef();
	gpSynch->Unlock();

	return nRet;
}


/*

Thread which listens for device insertions/removals.

*/
static DWORD WINAPI HciUnivNotifyThread(PVOID pv)
{
	HKEY hkTrans = NULL;
	HANDLE ph[MAXIMUM_WAIT_OBJECTS];
	HANDLE phMsgQueue[MAXIMUM_WAIT_OBJECTS-1];
	HANDLE phDevNotif[MAXIMUM_WAIT_OBJECTS-1];	
	DWORD dwIClassSize = MAX_PATH;
	WCHAR szIClass[MAX_PATH];
	DWORD cdwIClass = 0;
	BYTE pPNPBuf[sizeof(DEVDETAIL) + MAX_DEVCLASS_NAMELEN * sizeof(TCHAR)] = {0};
	DEVDETAIL *pd = (DEVDETAIL*)pPNPBuf;

	//
	// Get IClass list from registry and request notifications
	//	

	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_BASE, L"Software\\Microsoft\\Bluetooth\\Transports\\PnP", 0, 0, &hkTrans)) {
		IFDBG(DebugOut(DEBUG_HCI_INIT, L"[HCIUNIV] HciUnivNotifyThread - Could not open PnP transport registry key\n"));
		goto exit;
	}

	//
	// Need to clear the present device from the registry before registering for device
	// notifications.  This could happen if the hardware is pulled out while the device
	// was turned off.
	//
	RegDeleteValue(hkTrans, L"Present");
	
	ph[0] = ghStopNotifyThread;
	while(ERROR_SUCCESS == RegEnumKeyEx(hkTrans, cdwIClass, szIClass, &dwIClassSize, NULL, NULL, NULL, NULL))
	{
		MSGQUEUEOPTIONS msgopts;
		GUID guid = {0};

		if (cdwIClass+1 >= MAXIMUM_WAIT_OBJECTS) {
			// Maximum number of IClasses is MAXIMUM_WAIT_OBJECTS - 1
			IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] The number of Bluetooth IClass GUIDs has exceeded the universal transport manager's limit.\n"));
			ASSERT(0);
			goto exit;
		}
		
		if (FALSE == GetGUID(szIClass, &guid)) {
			IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] HciUnivNotifyThread - Failed reading IClass.\n"));
			goto exit;
		}			

		memset(&msgopts, 0, sizeof(msgopts));
		msgopts.dwFlags = 0;
		msgopts.dwSize = sizeof(msgopts);
		msgopts.dwMaxMessages = 0; 
		msgopts.cbMaxMessage = sizeof(pPNPBuf);
		msgopts.bReadAccess = TRUE;

		phMsgQueue[cdwIClass] = CreateMsgQueue(NULL, &msgopts);
		if (phMsgQueue[cdwIClass] == 0) {
			IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] HciUnivNotifyThread - failed to create message queue.\n"));
			goto exit;
		}

		phDevNotif[cdwIClass] = RequestDeviceNotifications(&guid, phMsgQueue[cdwIClass], TRUE);

		ph[cdwIClass+1] = phMsgQueue[cdwIClass];

		dwIClassSize = MAX_PATH;
		cdwIClass++;
	}

	RegCloseKey(hkTrans);
	hkTrans = NULL;

	//
	// Wait for device notifications to fire
	//

	while (1) {
		DWORD dwSize;
		DWORD dwFlags;
		DWORD dwWait;
		DWORD dwQueue;
		
		dwWait = WaitForMultipleObjects(cdwIClass+1, ph, FALSE, INFINITE);
		if ((dwWait < WAIT_OBJECT_0) || (dwWait >= (WAIT_OBJECT_0 + cdwIClass + 1))) {
			IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] HciUnivNotifyThread - WaitForMultipleObjects returned failure.\n"));
			break;
		}

		if (dwWait == WAIT_OBJECT_0) {
			// We have been signalled to shut down this thread
			break;
		}

		dwQueue = (dwWait - WAIT_OBJECT_0) - 1;
		
		if (! ReadMsgQueue(phMsgQueue[dwQueue], pd, sizeof(pPNPBuf), &dwSize, 1, &dwFlags)) {
			IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] HciUnivNotifyThread - failed to read message queue.\n"));
			break;
		}

		if (pd->fAttached) {
			// Device has been inserted
			
			memcpy(&gIClassGuid, &pd->guidDevClass, sizeof(GUID));
			wcsncpy(gwszDevName, pd->szName, MAX_DEVCLASS_NAMELEN);
			gwszDevName[MAX_DEVCLASS_NAMELEN-1] = 0;

			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Bluetooth\\Transports\\PnP", 0, 0, &hkTrans)) {
				RegSetValueEx(hkTrans, L"Present", NULL, REG_BINARY, (PBYTE)&gIClassGuid, sizeof(gIClassGuid));
				RegCloseKey(hkTrans);
				hkTrans = NULL;
			}
				
			TransportCallback(DEVICE_UP, NULL);
		}
		else {
			// Device has been ejected
			
			memset(&gIClassGuid, 0, sizeof(GUID));
			gwszDevName[0] = 0;

			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Bluetooth\\Transports\\PnP", 0, 0, &hkTrans)) {
				RegDeleteValue(hkTrans, L"Present");
				RegCloseKey(hkTrans);
				hkTrans = NULL;
			}
		}
	}

exit:
	
	//
	// Clean up
	//

	for (DWORD i = 0; i < cdwIClass; i++) {
		StopDeviceNotifications(phDevNotif[i]);
		CloseMsgQueue(phMsgQueue[i]);
	}

	if (hkTrans) {
		RegCloseKey(hkTrans);
		hkTrans = NULL;
	}
	
	return 0;
}


/*

This function is called to initialize the functions in the active transport driver.

*/
static BOOL InitPointers()
{
	SVSUTIL_ASSERT(gpSynch->IsLocked());

	SVSUTIL_ASSERT(gfInitialized);

	if (pfnReadHciParameters && pfnStartHardware && pfnStopHardware && pfnOpenConnection && pfnReadPacket &&
			pfnWritePacket && pfnCloseConnection)
		return TRUE;

	SVSUTIL_ASSERT(ghCurDriver);

	pfnReadHciParameters = (HCI_READHCIPARAMETERS )GetProcAddress(ghCurDriver, L"HCI_ReadHciParameters");
	pfnStartHardware = (HCI_STARTHARDWARE )GetProcAddress(ghCurDriver, L"HCI_StartHardware");
	pfnStopHardware = (HCI_STOPHARDWARE	)GetProcAddress(ghCurDriver, L"HCI_StopHardware");
	pfnOpenConnection = (HCI_OPENCONNECTION	)GetProcAddress(ghCurDriver, L"HCI_OpenConnection");
	pfnReadPacket = (HCI_READPACKET	)GetProcAddress(ghCurDriver, L"HCI_ReadPacket");
	pfnWritePacket = (HCI_WRITEPACKET )GetProcAddress(ghCurDriver, L"HCI_WritePacket");
	pfnCloseConnection = (HCI_CLOSECONNECTION )GetProcAddress(ghCurDriver, L"HCI_CloseConnection");
	pfnSetCallback = (HCI_SETCALLBACK )GetProcAddress(ghCurDriver, L"HCI_SetCallback");

	BOOL bRet = pfnReadHciParameters && pfnStartHardware && pfnStopHardware && pfnOpenConnection && pfnReadPacket &&
			pfnWritePacket && pfnCloseConnection;

	if (!bRet)
	{
		IFDBG(DebugOut(DEBUG_ERROR, L"[HCIUNIV] GetProcAddress failed!\n"));
		DeInitPointers();
	}

	return bRet;
}


/*

This function is called when unloading the current transport driver.

*/
static BOOL DeInitPointers()
{
	SVSUTIL_ASSERT(gpSynch->IsLocked());

	SVSUTIL_ASSERT(ghCurDriver);

	pfnReadHciParameters = NULL;
	pfnStartHardware = NULL;
	pfnStopHardware = NULL;
	pfnOpenConnection = NULL;
	pfnReadPacket = NULL;
	pfnWritePacket = NULL;
	pfnCloseConnection = NULL;

	HINSTANCE hLib = ghCurDriver;
	ghCurDriver = NULL;

	while(gpSynch->GetRefCount() > 1)
	{
		IFDBG(DebugOut (DEBUG_HCI_INIT, L"[HCIUNIV] Waiting to free library 0x%08x\n", hLib));
		gpSynch->Unlock();
		Sleep(500);
		gpSynch->Lock();
	}
	
	SVSUTIL_ASSERT(hLib);
	
	FreeLibrary(hLib);
	
	IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[HCIUNIV] No active device.\n"));

	return TRUE;
}


/*

This function is called when the universal transport manager is initialized.

*/
static BOOL Initialize()
{
	SVSUTIL_ASSERT(gpSynch->IsLocked());

	if (gfInitialized)
		return TRUE;

	IFDBG(DebugOut(DEBUG_HCI_INIT, L"[HCIUNIV] +Initialize...\n"));

	ghCurDriver = NULL;

	ghStopNotifyThread = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (NULL == ghStopNotifyThread)

⌨️ 快捷键说明

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