📄 bthsco.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.
//
/**
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 SCO layer
**/
#include <windows.h>
#if defined (SDK_BUILD)
#undef CP_UTF8
#endif
#include <pkfuncs.h>
#include <bt_hcip.h>
#include "bthsco.h"
DECLARE_DEBUG_VARS();
#define DEBUG_SCO_TRACE DEBUG_HCI_TRACE //0x4
#define DEBUG_DATA_PACKET_UP DEBUG_HCI_TRACE
#define DEBUG_DATA_PACKET_DOWN DEBUG_HCI_TRACE
//
// Need typedefs for HCI_EstablishDeviceContext and HCI_CloseDeviceContext because
// we do LoadLibrary on btd.dll to invoke those functions.
//
typedef int (*HCI_EstablishDeviceContext_t)
(
void *pUserContext, /* IN */
unsigned int uiControl, /* IN */
BD_ADDR *pba, /* IN */
unsigned int class_of_device, /* IN */
unsigned char link_type, /* IN */
HCI_EVENT_INDICATION *pInd, /* IN */
HCI_CALLBACKS *pCall, /* IN */
HCI_INTERFACE *pInt, /* OUT */
int *pcDataHeaders, /* OUT */
int *pcDataTrailers, /* OUT */
HANDLE *phDeviceContext /* OUT */
);
typedef int (*HCI_CloseDeviceContext_t)
(
HANDLE hDeviceContext /* IN */
);
#define BT_ROLE_SWITCH 0
#define BT_NO_ROLE_SWITCH 1
// SCO baseband packet types
#define BT_PACKET_TYPE_HV1 0x0020
#define BT_PACKET_TYPE_HV2 0x0040
#define BT_PACKET_TYPE_HV3 0x0080
#define SCO_PACKET_HEADER_LEN 3
//
// Call definitions
//
// values for fCallType
#define CALL_TYPE_CONNECT 1
#define CALL_TYPE_DISCONNECT 2
#define CALL_TYPE_READ_VOICE_SETTING 3
#define CALL_TYPE_WRITE_VOICE_SETTING 4
#define CALL_TYPE_WAIT_FOR_INCOMING_CONNECTION 5
#define CALL_TYPE_ACCEPT_INCOMING_CONNECTION 6
#define CALL_TYPE_WRITE_PACKET 7
#define CALL_TYPE_DATA_PACKET_DOWN 8
#define CALL_TYPE_WRITE_SCO_FLOW_CONTROL 9
#define CALL_TYPE_READ_SCO_FLOW_CONTROL 10
struct Call {
Call *pNext;
Call *pPrev;
HANDLE hEvent;
int iResult;
//
// each fCallType has a struct (although it can be empty)
// place stuff there that needs to be passed around from anywhere
// from initial HCI function call to callback to event handler to
// user return data
//
unsigned char fCallType;
union {
// CALL_TYPE_CONNECT
struct {
USHORT hAclConnection;
USHORT hScoConnection;
} Connect;
// CALL_TYPE_DISCONNECT
struct {
} Disconnect;
// CALL_TYPE_READ_VOICE_SETTING
struct {
VOICE_SETTING Setting;
} ReadVoiceSetting;
// CALL_TYPE_WRITE_VOICE_SETTING
struct {
} WriteVoiceSetting;
// CALL_TYPE_WAIT_FOR_INCOMING_CONNECTION
struct {
BOOL bAllAddresses;
BD_ADDR Address;
} WaitIncomingConnection;
// CALL_TYPE_ACCEPT_INCOMING_CONNECTION
struct {
BD_ADDR Address;
USHORT hScoConnection;
} AcceptIncomingConnection;
// CALL_TYPE_WRITE_PACKET
struct {
} WritePacket;
// CALL_TYPE_DATA_PACKET_DOWN
struct {
USHORT hConnection;
void *pPacketUserContext;
} DataPacketDown;
// CALL_TYPE_WRITE_SCO_FLOW_CONTROL
struct {
} WriteScoFlowControl;
// CALL_TYPE_READ_SCO_FLOW_CONTROL
struct {
BOOL bEnabled;
} ReadScoFlowControl;
} uParameters;
SCO_USER_CALL *pUserCall;
// a call that is on the queue, is either waiting to be sent to HCI
// or currently being processed by HCI.
unsigned char fInvokedHCI : 1;
Call (void) {
memset (this, 0, sizeof(*this));
}
};
//
// Link definitions
//
struct Link {
Link *pNext;
BD_ADDR b;
unsigned short hScoConnection;
unsigned short hAclConnection;
};
class SCO : public SVSSynch, public SVSRefObj {
public:
Call *pCalls;
Link *pLinks;
unsigned int fIsRunning : 1; // whether SCO is successfully connected to HCI (via HCI_EstablishedDeviceContext)
unsigned int fConnected : 1; // whether entire stack is up or down (BTH_STACK_DOWN,BTH_STACK_UP,BTH_STACK_DISCONNECT)
unsigned int fIsBinded : 1; // whether SoundDriver has invoked sco_Bind
HANDLE hHCI;
HANDLE hClosingEvent;
HCI_INTERFACE hci_if;
void *pUserData;
SCO_CALLBACKS sco_callbacks;
int cHciHeaders;
int cHciTrailers;
void Zero ()
{
pLinks = NULL;
pCalls = NULL;
hHCI = NULL;
hClosingEvent = NULL;
fIsRunning = FALSE;
fConnected = FALSE;
fIsBinded = FALSE;
memset (&hci_if, 0, sizeof (hci_if));
pUserData = NULL;
memset (&sco_callbacks, 0, sizeof (sco_callbacks));
cHciHeaders = 0;
cHciTrailers = 0;
}
SCO (void)
{
Zero();
}
~SCO (void)
{
if (hClosingEvent) {
CloseHandle(hClosingEvent);
hClosingEvent = NULL;
}
}
};
//
// init/deinit functions
//
int sco_InitializeOnce (void);
int sco_UninitializeOnce (void);
int sco_CreateDriverInstance(void);
int sco_CloseDriverInstance (void);
//
// stack notification/init routines
//
static int StackInitDevice ();
static int StackNotifyUser (int iEvent);
static DWORD WINAPI StackDisconnect (LPVOID lpVoid);
static DWORD WINAPI StackDown (LPVOID lpVoid);
static DWORD WINAPI StackUp (LPVOID lpVoid);
//
// event handlers
//
static int sco_ConnectionComplete_Event (void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, BD_ADDR *pba, unsigned char link_type, unsigned char encryption_mode);
static int sco_ConnectionRequest_Event (void *pUserContext, void *pCallContext, BD_ADDR *pba, unsigned int class_of_device, unsigned char link_type);
static int sco_DisconnectionComplete_Event (void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, unsigned char reason);
static int sco_Stack_Event (void *pUserContext, int iEvent, void *pEventContext);
static int sco_NumberOfCompletedPackets_Event (void *pUserContext, void *pCallContext, unsigned short connection_handle, unsigned short num_of_completed_packets);
static int sco_DataPacketUp_Event (void *pUserContext, unsigned short connection_handle, BD_BUFFER *pBuffer);
//
// callbacks
//
static int sco_CallAborted_Out (void *pCallContext, int iError);
static int sco_DataPacketDown_Out (void *pCallContext, int iError);
static int sco_AddSCOConnection_Out (void *pCallContext, unsigned char status);
static int sco_Disconnect_Out (void *pCallContext, unsigned char status);
static int sco_AcceptConnectionRequest_Out (void *pCallContext, unsigned char status);
static int sco_WriteVoiceSetting_Out (void *pCallContext, unsigned char status);
static int sco_ReadVoiceSetting_Out (void *pCallContext, unsigned char status, unsigned short voice_channel_setting);
static int sco_WriteSCOFlowControlEnable_Out(void *pCallContext, unsigned char status);
static int sco_ReadSCOFlowControlEnable_Out (void *pCallContext, unsigned char status, unsigned char SCO_flow_control_enable);
//
// interface
//
static int sco_Call_In (SCO_USER_CALL* pUserCall);
static int sco_AbortUserCall_In (SCO_USER_CALL* pUserCall);
static int sco_DataPacketDown_In (void* pPacketUserContext, USHORT hConnection, PUCHAR pBuffer, DWORD dwBufferLen);
static int sco_Connect (SCO_USER_CALL* pUserCall);
static int sco_Disconnect (SCO_USER_CALL* pUserCall);
static int sco_WriteVoiceSetting (SCO_USER_CALL* pUserCall);
static int sco_ReadVoiceSetting (SCO_USER_CALL* pUserCall);
static int sco_RecvConnection (SCO_USER_CALL* pUserCall);
static int sco_WritePacket (SCO_USER_CALL* pUserCall);
static int sco_ioctl (SCO_USER_CALL* pUserCall);
static int sco_AbortCall (Call *pCall, BOOL bHciAbort);
// Call functions
static Call* CallCreateNew (unsigned char fCallType, BOOL bCreateCallEvent, SCO_USER_CALL *pUserCall);
static void CallDelete (Call* pCall);
static Call* CallVerify (Call* pCall, unsigned char fCallType);
static void CallInsert (Call* pCall);
static void CallRemove (Call* pCall);
static void CallSetUserData (SCO_USER_CALL *pUserCall, Call *pCall);
static void CallSignal (Call *pCall, int iResult);
static Call* CallFindByUserCall (SCO_USER_CALL *pUserCall);
//
// global variables
//
static SCO* gpLayerState = NULL;
static HMODULE ghModBtd = NULL;
static HCI_EstablishDeviceContext_t gpfHCI_EstablishDeviceContext = NULL;
static HCI_CloseDeviceContext_t gpfHCI_CloseDeviceContext = NULL;
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;
}
///////////////////////////////////////////////////
// Call functions
///////////////////////////////////////////////////
static Call* CallCreateNew(unsigned char fCallType, BOOL bCreateCallEvent, SCO_USER_CALL *pUserCall)
{
Call *pCall = new Call;
if (!pCall) {
return NULL;
}
if (bCreateCallEvent) {
pCall->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!pCall->hEvent) {
delete pCall;
return NULL;
}
}
pCall->fCallType = fCallType;
pCall->pUserCall = pUserCall;
return pCall;
}
static void CallDelete(Call* pCall)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -