📄 bthsco.cxx
字号:
}
Link *pLink = gpLayerState->pLinks;
while (gpLayerState->pLinks) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_CloseDriverInstance :: Deleting link 0x%04x\n", gpLayerState->pLinks->hScoConnection));
Link *pNext = gpLayerState->pLinks->pNext;
delete gpLayerState->pLinks;
gpLayerState->pLinks = pNext;
}
Call *pC = gpLayerState->pCalls;
gpLayerState->pCalls = NULL;
while (pC) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_CloseDriverInstance :: signalling call 0x%08x\n", pC));
Call *pNext = pC->pNext;
pC->pNext = NULL;
pC->pPrev = NULL;
CallSignal (pC, ERROR_SHUTDOWN_IN_PROGRESS);
pC = pNext;
}
if (gpLayerState->hHCI) {
SVSUTIL_ASSERT(gpfHCI_CloseDeviceContext);
gpfHCI_CloseDeviceContext (gpLayerState->hHCI);
}
gpLayerState->Zero();
gpLayerState->Unlock();
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_CloseDriverInstance :: ERROR_SUCCESS\n"));
return ERROR_SUCCESS;
}
int sco_Bind(void *pUserData, SCO_CALLBACKS *pCallbacks, SCO_INTERFACE *pInterface)
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Bind\n"));
if (!pCallbacks || !pInterface) {
return ERROR_INVALID_PARAMETER;
}
gpLayerState->Lock ();
if (!gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Bind :: ERROR_SHUTDOWN_IN_PROGRESS\n"));
gpLayerState->Unlock();
return ERROR_SHUTDOWN_IN_PROGRESS;
}
if (gpLayerState->fIsBinded) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: sco_Bind :: ERROR_ALREADY_INITIALIZED\n"));
return ERROR_ALREADY_INITIALIZED;
}
pInterface->Call = sco_Call_In;
pInterface->AbortCall = sco_AbortUserCall_In;
pInterface->DataPacketDown = sco_DataPacketDown_In;
memcpy(&gpLayerState->sco_callbacks, pCallbacks, sizeof(SCO_CALLBACKS));
gpLayerState->pUserData = pUserData;
gpLayerState->fIsBinded = TRUE;
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Bind :: return ERROR_SUCCESS\n"));
gpLayerState->Unlock ();
return ERROR_SUCCESS;
}
int sco_Unbind()
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Unbind\n"));
gpLayerState->Lock ();
if (!gpLayerState->fIsBinded) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: sco_Unbind :: ERROR_SERVICE_NOT_ACTIVE\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
//
// abort all current Calls
//
Call *pCall = gpLayerState->pCalls;
gpLayerState->pCalls = NULL;
while (pCall)
{
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: sco_Unbind :: aborting call %#x\n", pCall));
Call *pNext = pCall->pNext;
pCall->pNext = NULL;
pCall->pPrev = NULL;
if (pCall->fInvokedHCI) {
//
// inform HCI that the call is being aborted
// the gpLayerState->pCalls already been NULLed so the sco_CallAborted_Out
// callback won't do anything useful
//
BT_LAYER_ABORT_CALL pFunction = gpLayerState->hci_if.hci_AbortCall;
HANDLE hHCI = gpLayerState->hHCI;
int iRes = ERROR_INTERNAL_ERROR;
gpLayerState->AddRef ();
gpLayerState->Unlock ();
__try {
iRes = pFunction (hHCI, pCall);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: sco_AbortCall :: exception in hci_AbortCall\n"));
}
gpLayerState->Lock ();
gpLayerState->DelRef ();
}
CallSignal(pCall, ERROR_OPERATION_ABORTED);
pCall = pNext;
}
//
// abort all Links
//
Link *pLink = gpLayerState->pLinks;
gpLayerState->pLinks = NULL;
while (pLink)
{
Link *pNextLink = pLink->pNext;
USHORT hSco = pLink->hScoConnection;
USHORT hAcl = pLink->hAclConnection;
int iRes = ERROR_INTERNAL_ERROR;
if (gpLayerState->fIsRunning && gpLayerState->fConnected) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Unbind :: disconnecting Link=%#x, hSco=%#x, hAcl=%#x\n", pLink, hSco, hAcl));
HCI_Disconnect_In pFunction = gpLayerState->hci_if.hci_Disconnect_In;
HANDLE hHCI = gpLayerState->hHCI;
gpLayerState->AddRef ();
gpLayerState->Unlock ();
__try {
iRes = pFunction (hHCI, NULL, hSco, BT_ERROR_OETC_USER_ENDED);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: sco_Unbind %#x :: exception in hci_Disconnect_In\n", pLink));
}
gpLayerState->Lock ();
gpLayerState->DelRef ();
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Unbind :: deleting Link=%#x, hSco=%#x, hAcl=%#x\n", pLink, hSco, hAcl));
delete pLink;
pLink = pNextLink;
}
memset(&gpLayerState->sco_callbacks, 0, sizeof(SCO_CALLBACKS));
gpLayerState->pUserData = NULL;
gpLayerState->fIsBinded = FALSE;
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: sco_Unbind :: return ERROR_SUCCESS\n"));
gpLayerState->Unlock ();
return ERROR_SUCCESS;
}
////////////////////////////////////////////
// stack notification routines
// note: they are executed asynchronously (a thread is created for them)
// (they do not execute on same thread as HCI callback)
//
// StackInitDevice
// StackNotifyUser
// The following 3 routines are ThreadProcs [see function sco_Stack_Event]
// StackDisconnect
// StackDown
// StackUp
////////////////////////////////////////////
// helper function
static int SetSCOFlowControl(BOOL bEnable)
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: SetSCOFlowControl(%s)\n", bEnable ? L"TRUE" : L"FALSE"));
SVSUTIL_ASSERT(gpLayerState);
SVSUTIL_ASSERT(gpLayerState->IsLocked());
if (!gpLayerState->fIsRunning) {
return ERROR_SERVICE_NOT_ACTIVE;
}
Call *pCall = CallCreateNew (CALL_TYPE_WRITE_SCO_FLOW_CONTROL, TRUE, NULL);
if (!pCall) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: SetSCOFlowControl :: ERROR_OUTOFMEMORY\n"));
return ERROR_OUTOFMEMORY;
}
CallInsert(pCall);
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: SetSCOFlowControl :: created call 0x%08x\n", pCall));
HCI_WriteSCOFlowControlEnable_In pFunction = gpLayerState->hci_if.hci_WriteSCOFlowControlEnable_In;
HANDLE hHCI = gpLayerState->hHCI;
int iRes = ERROR_INTERNAL_ERROR;
pCall->fInvokedHCI = TRUE;
gpLayerState->AddRef ();
gpLayerState->Unlock ();
__try {
iRes = pFunction (hHCI, pCall, bEnable ? TRUE : FALSE);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: SetSCOFlowControl :: exception in hci_WriteSCOFlowControlEnable_In\n"));
}
if (iRes) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: SetSCOFlowControl :: hci_WriteSCOFlowControlEnable_In failed with %d\n", iRes));
gpLayerState->Lock ();
gpLayerState->DelRef ();
if (CallVerify(pCall, CALL_TYPE_WRITE_SCO_FLOW_CONTROL)) {
CallRemove(pCall);
CallSignal(pCall, iRes);
}
return iRes;
}
// wait for completion
int iResult;
DWORD dwWait = WaitForSingleObject(pCall->hEvent, 5000);
gpLayerState->Lock ();
gpLayerState->DelRef ();
if (WAIT_OBJECT_0 == dwWait) {
iResult = pCall->iResult;
CallDelete(pCall);
}
else {
iResult = ERROR_TIMEOUT;
CallRemove(pCall);
CallDelete(pCall);
}
if (!gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: SetSCOFlowControl :: ERROR_SHUTDOWN_IN_PROGRESS\n"));
return ERROR_SHUTDOWN_IN_PROGRESS;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: SetSCOFlowControl returning %#x\n", iResult));
return iResult;
}
static int StackInitDevice ()
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: StackInitDevice\n"));
gpLayerState->Lock ();
if (!gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: StackInitDevice :: ERROR_SERVICE_NOT_ACTIVE\n"));
gpLayerState->Unlock();
return ERROR_SERVICE_NOT_ACTIVE;
}
if (ERROR_SUCCESS != SetSCOFlowControl(TRUE)) {
// It is ok if this fails. We have flow control in HCI.
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: Failed to set SCO flow control.\n"));
}
gpLayerState->Unlock();
return ERROR_SUCCESS;
}
static int StackNotifyUser(int iEvent)
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
gpLayerState->Lock();
SCO_CALLBACK_StackEvent pCallBack = gpLayerState->sco_callbacks.StackEvent;
if (pCallBack) {
int iRes = ERROR_INTERNAL_ERROR;
void *pUserData = gpLayerState->pUserData;
gpLayerState->AddRef ();
gpLayerState->Unlock ();
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: StackNotifyUser :: going into callback\n"));
__try {
iRes = pCallBack (pUserData, iEvent);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"SCO :: StackNotifyUser :: exception in callback\n"));
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: StackNotifyUser :: came from callback\n"));
gpLayerState->Lock ();
gpLayerState->DelRef ();
}
gpLayerState->Unlock();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackDisconnect (LPVOID lpVoid)
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: Disconnecting stack\n"));
StackNotifyUser(BTH_STACK_DISCONNECT);
sco_CloseDriverInstance();
sco_UninitializeOnce();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackDown (LPVOID lpVoid)
{
if (! gpLayerState) {
return ERROR_SERVICE_NOT_ACTIVE;
}
StackNotifyUser(BTH_STACK_DOWN);
// gpLayerState may be disconnecting, in which case StackDown does not need
// to do anything.
if(WaitForSingleObject(gpLayerState->hClosingEvent, 0) != WAIT_TIMEOUT) {
return 0;
}
gpLayerState->Lock ();
if ((! gpLayerState->fIsRunning) || (! gpLayerState->fConnected)) {
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: Stack Down received :: already down\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_SCO_TRACE, L"SCO :: 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;
}
Call *pC = gpLayerState->pCalls;
while (pC) {
CallRemove (pC);
CallSignal (pC, ERROR_SHUTDOWN_IN_PROGRESS);
pC = gpLayerState->pCalls;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -