📄 bthuniv.cxx
字号:
//
// 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 + -