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

📄 bthlink.cxx

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 CXX
📖 第 1 页 / 共 3 页
字号:
//
// 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.


Abstract:
	Windows CE Bluetooth stack layer sample

**/
#include <windows.h>

#if defined (SDK_BUILD)
#undef CP_UTF8
#endif

#include <svsutil.hxx>

#include <pkfuncs.h>
#include <bt_debug.h>
#include <bt_tdbg.h>
#include <bt_api.h>
#include <bt_buffer.h>
#include <bt_ddi.h>

#include "bthlink.hxx"

#define DEBUG_LAYER_TRACE			0x00000040

DECLARE_DEBUG_VARS();

#define CALL_HCI_CONNECT			0x01
#define CALL_HCI_DISCONNECT			0x02
#define CALL_HCI_EVENTFILTER		0x03

// SCO baseband packet types
#define BT_PACKET_TYPE_HV1			0x0020
#define BT_PACKET_TYPE_HV2			0x0040
#define BT_PACKET_TYPE_HV3			0x0080

#define BT_LINK_TYPE_SCO			0
#define BT_LINK_TYPE_ACL			1

#define MAX_BASEBAND_CONNECTIONS	20

struct Link {
	Link			*pNext;
	BD_ADDR			b;
	unsigned short	h;

	HANDLE			hProcOwner;
};

struct SCall {
	SCall			*pNext;

	HANDLE			hEvent;
	HANDLE			hProcOwner;

	int				iResult;

	unsigned int	fWhat			: 8;

	SCall (void) {
		memset (this, 0, sizeof(*this));
	}
};

static int bthlink_CloseDriverInstance (void);

static int bthlink_ConnectionCompleteEvent		(void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, BD_ADDR *pba, unsigned char link_type, unsigned char encryption_mode);
static int bthlink_DisconnectionCompleteEvent   (void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, unsigned char reason);
static int bthlink_hStackEvent                  (void *pUserContext, int iEvent, void *pEventContext);

static int bthlink_SetEventFilter_Out   (void *pCallContext, unsigned char status);
static int bthlink_CreateConnection_Out	(void *pCallContext, unsigned char status);
static int bthlink_Disconnect_Out       (void *pCallContext, unsigned char status);
static int bthlink_hCallAborted         (void *pCallContext, int iError);

class BTHLINK : public SVSSynch, public SVSRefObj {
public:
	SCall			*pCalls;
	Link			*pLinks;

	unsigned int	fIsRunning : 1;
	unsigned int	fConnected : 1;

	HANDLE			hHCI;
	HCI_INTERFACE	hci_if;

	BTHLINK (void) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Initializing\n"));

		pLinks = NULL;
		pCalls = NULL;

		fIsRunning = FALSE;
		fConnected = FALSE;

		hHCI = NULL;

		HCI_EVENT_INDICATION hei;
		memset (&hei, 0, sizeof (hei));

		hei.hci_ConnectionCompleteEvent    = bthlink_ConnectionCompleteEvent;
		hei.hci_DisconnectionCompleteEvent = bthlink_DisconnectionCompleteEvent;

		hei.hci_StackEvent = bthlink_hStackEvent;

		HCI_CALLBACKS hc;
		memset (&hc, 0, sizeof (hc));

		hc.hci_CreateConnection_Out = bthlink_CreateConnection_Out;
		hc.hci_Disconnect_Out       = bthlink_Disconnect_Out;
		hc.hci_SetEventFilter_Out   = bthlink_SetEventFilter_Out;

		hc.hci_CallAborted = bthlink_hCallAborted;

		int cHciHeaders = 0;
		int cHciTrailers = 0;

		if (ERROR_SUCCESS != HCI_EstablishDeviceContext (this, BTH_CONTROL_DEVICEONLY, NULL, 0, 0, &hei, &hc, &hci_if, &cHciHeaders, &cHciTrailers, &hHCI)) {
			IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Could not create device context\n"));
			return;
		}

		fIsRunning = TRUE;

		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Init successful\n"));
	}

	~BTHLINK (void) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: deinitializing\n"));
		if (hHCI)
			HCI_CloseDeviceContext (hHCI);
	}
};

static BTHLINK *gpLayerState = NULL;
//
//	Auxiliary code
//
static SCall *RemoveCallFromList (void *pC) {
	SCall *pParent = NULL;
	SCall *pCall = gpLayerState->pCalls;

	while (pCall && (pCall != pC)) {
		pParent = pCall;
		pCall = pCall->pNext;
	}

	if (! pCall)
		return NULL;

	if (pParent)
		pParent->pNext = pCall->pNext;
	else
		gpLayerState->pCalls = pCall->pNext;

	return pCall;
}

static void GetConnectionState (void) {
	__try {
		int fConnected = FALSE;
		int dwRet = 0;
		gpLayerState->hci_if.hci_ioctl (gpLayerState->hHCI, BTH_STACK_IOCTL_GET_CONNECTED, 0, NULL, sizeof(fConnected), (char *)&fConnected, &dwRet);
		if ((dwRet == sizeof(fConnected)) && fConnected)
			gpLayerState->fConnected = TRUE;
	} __except (1) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK GetConnectionState : exception in hci_ioctl BTH_STACK_IOCTL_GET_CONNECTED\n"));
	}

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK GetConnectionState : %s\n", gpLayerState->fConnected ? L"CONNECTED" : L"DISCONNECTED"));
}

static int StatusToError (unsigned char status, int iGeneric) {
	switch (status) {
	case BT_ERROR_SUCCESS:
		return ERROR_SUCCESS;

    case BT_ERROR_COMMAND_DISALLOWED:
    case BT_ERROR_UNKNOWN_HCI_COMMAND:
    case BT_ERROR_UNSUPPORTED_FEATURE_OR_PARAMETER:
    case BT_ERROR_INVALID_HCI_PARAMETER:
    case BT_ERROR_UNSUPPORTED_REMOTE_FEATURE:
		return ERROR_CALL_NOT_IMPLEMENTED;

    case BT_ERROR_NO_CONNECTION:
		return ERROR_DEVICE_NOT_CONNECTED;

    case BT_ERROR_HARDWARE_FAILURE:
    case BT_ERROR_UNSPECIFIED_ERROR:
		return ERROR_ADAP_HDW_ERR;

    case BT_ERROR_PAGE_TIMEOUT:
    case BT_ERROR_CONNECTION_TIMEOUT:
    case BT_ERROR_HOST_TIMEOUT:
		return ERROR_TIMEOUT;

    case BT_ERROR_AUTHENTICATION_FAILURE:
		return ERROR_NOT_AUTHENTICATED;

    case BT_ERROR_KEY_MISSING:
		return ERROR_NO_USER_SESSION_KEY;

    case BT_ERROR_MEMORY_FULL:
		return ERROR_OUTOFMEMORY;

    case BT_ERROR_MAX_NUMBER_OF_CONNECTIONS:
    case BT_ERROR_MAX_NUMBER_OF_SCO_CONNECTIONS:
    case BT_ERROR_MAX_NUMBER_OF_ACL_CONNECTIONS:
		return ERROR_NO_SYSTEM_RESOURCES;

    case BT_ERROR_HOST_REJECTED_LIMITED_RESOURCES:
    case BT_ERROR_HOST_REJECTED_SECURITY_REASONS:
    case BT_ERROR_HOST_REJECTED_PERSONAL_DEVICE:
    case BT_ERROR_PAIRING_NOT_ALLOWED:
		return ERROR_CONNECTION_REFUSED;

    case BT_ERROR_OETC_USER_ENDED:
    case BT_ERROR_OETC_LOW_RESOURCES:
    case BT_ERROR_OETC_POWERING_OFF:
		return ERROR_GRACEFUL_DISCONNECT;

    case BT_ERROR_CONNECTION_TERMINATED_BY_LOCAL_HOST:
		return ERROR_CONNECTION_ABORTED;

    case BT_ERROR_REPEATED_ATTEMPTS:
		return ERROR_CONNECTION_COUNT_LIMIT;
	}

	return iGeneric;
}

static BTHLINK *CreateNewState (void) {
	return new BTHLINK;
}

static DWORD WINAPI StackDisconnect (LPVOID lpVoid) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Disconnecting stack\n"));
	bthlink_CloseDriverInstance ();

	return ERROR_SUCCESS;
}

static DWORD WINAPI StackDown (LPVOID lpVoid) {
	if (! gpLayerState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpLayerState->Lock ();

	if ((! gpLayerState->fIsRunning) || (! gpLayerState->fConnected)) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Down received :: already down\n"));
		
		gpLayerState->Unlock ();

		return ERROR_SERVICE_NOT_ACTIVE;
	}

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Down :: taking down\n"));

	gpLayerState->fConnected = FALSE;

    Link *pLink = gpLayerState->pLinks;

	while (gpLayerState->pLinks) {
		Link *pNext = gpLayerState->pLinks->pNext;
		delete gpLayerState->pLinks;
		gpLayerState->pLinks = pNext;
	}

	SCall *pC = gpLayerState->pCalls;
	gpLayerState->pCalls = NULL;

	while (pC) {
		SCall *pNext = pC->pNext;
		pC->iResult = ERROR_SHUTDOWN_IN_PROGRESS;
		pC->pNext = NULL;

		SetEvent (pC->hEvent);

		pC = pNext;
	}

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Is Down\n"));

	gpLayerState->Unlock ();
	return ERROR_SUCCESS;
}

static DWORD WINAPI StackUp (LPVOID lpVoid) {
	if (! gpLayerState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpLayerState->Lock ();
	if ((! gpLayerState->fIsRunning) || gpLayerState->fConnected) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Up received :: already up\n"));
		gpLayerState->Unlock ();

		return ERROR_SERVICE_NOT_ACTIVE;
	}

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Up received :: UP\n"));

	gpLayerState->fConnected = TRUE;
	gpLayerState->Unlock ();

	return ERROR_SUCCESS;
}

static void ProcessExited (HANDLE hProc) {
	if (! gpLayerState)
		return;

	gpLayerState->Lock ();

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited : 0x%08x\n", hProc));

	if (! gpLayerState->fIsRunning) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: in shutdown\n", hProc));
		gpLayerState->Unlock ();
		return;
	}

	SCall *pCall = gpLayerState->pCalls;
	SCall *pCallParent = NULL;

	while (pCall) {
		if (pCall->hProcOwner == hProc) {
			if (pCallParent)
				pCallParent->pNext = pCall->pNext;
			else
				gpLayerState->pCalls = pCall->pNext;

			pCall->iResult = ERROR_SHUTDOWN_IN_PROGRESS;
			pCall->pNext = NULL;
			SetEvent (pCall->hEvent);

			IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: aborted call 0x%08x %s\n", pCall, pCall->fWhat == CALL_HCI_CONNECT ? L"CONNECT" : L"DISCONNECT"));

			pCall = pCallParent ? pCallParent->pNext : gpLayerState->pCalls;
			continue;
		}

		pCallParent = pCall;
		pCall = pCall->pNext;
	}


    Link *pLink = gpLayerState->pLinks;
	Link *pParentLink = NULL;

	while (pLink) {
		if (pLink->hProcOwner == hProc) {
			if (pParentLink)
				pParentLink->pNext = pLink->pNext;
			else
				gpLayerState->pLinks = pLink->pNext;

			unsigned short h = pLink->h;

			delete pLink;

			if (h) {
				IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: closing connection 0x%04x\n", h));

				HANDLE hHCI = gpLayerState->hHCI;
				HCI_Disconnect_In pCallback = gpLayerState->hci_if.hci_Disconnect_In;

				gpLayerState->AddRef ();
				gpLayerState->Unlock ();

				__try {
					pCallback (hHCI, NULL, h, 0x13);
				} __except (1) {
					IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: exception in hci_Disconnect_In\n"));
				}

				gpLayerState->Lock ();
				gpLayerState->DelRef ();

				pLink = gpLayerState->pLinks;
				pParentLink = NULL;
				continue;
			}

			pLink = pParentLink ? pParentLink->pNext : gpLayerState->pLinks;
			continue;
		} else {
			pParentLink = pLink;
			pLink = pLink->pNext;
		}
	}

	gpLayerState->Unlock ();
}
//
//	Callbacks -- HCI
//
static int bthlink_hCallAborted (void *pCallContext, int iError) {
	if (! gpLayerState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpLayerState->Lock ();

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: call 0x%08x, error %d\n", pCallContext, iError));

	if (! gpLayerState->fIsRunning) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: system shutdwon\n"));
		gpLayerState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	SCall *pCall = RemoveCallFromList (pCallContext);

	if (! pCall) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: call not found\n"));
		gpLayerState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	pCall->iResult = iError;
	pCall->pNext   = NULL;

	SetEvent (pCall->hEvent);

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Abort :: aborted call 0x%08x %s\n", pCall, pCall->fWhat == CALL_HCI_CONNECT ? L"CONNECT" : L"DISCONNECT"));

	gpLayerState->Unlock ();

	return ERROR_SUCCESS;
}

static int bthlink_Disconnect_Out (void *pCallContext, unsigned char status) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Disconnect_Out :: call 0x%08x, status 0x%02x\n", pCallContext, status));

	if (status != 0)
		return bthlink_hCallAborted (pCallContext, StatusToError (status, ERROR_INTERNAL_ERROR));

	return ERROR_SUCCESS;
}

static int bthlink_CreateConnection_Out (void *pCallContext, unsigned char status) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Connect_Out :: call 0x%08x, status 0x%02x\n", pCallContext, status));

	if (status != 0)
		return bthlink_hCallAborted (pCallContext, StatusToError (status, ERROR_INTERNAL_ERROR));

	return ERROR_SUCCESS;
}

static int bthlink_SetEventFilter_Out (void *pCallContext, unsigned char status) {
	if (! gpLayerState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpLayerState->Lock ();
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: call 0x%08x, status 0x%02x\n", pCallContext, status));

	if (! gpLayerState->fIsRunning) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: shutting down\n"));
		gpLayerState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	SCall *pCall = RemoveCallFromList (pCallContext);

	if (! pCall) {
		IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: no context\n"));
		gpLayerState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	pCall->iResult = StatusToError (status, ERROR_PROTOCOL_UNREACHABLE);
	pCall->pNext   = NULL;

	SetEvent (pCall->hEvent);

	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: Completed call 0x%08x\n", pCall));

	gpLayerState->Unlock ();

⌨️ 快捷键说明

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