Implement Functions that Setup and Shutdown the Extension Layer (Compact 2013)

3/26/2014

After implementing the APIs for interfacing with the Bluetooth stack, you must implement functions for setting up and shutting down the extension layer. Since the extension layer must run on top of the Bluetooth stack as an installable stream device driver, these functions must setup and shut down the extension layer as a driver instance.

To implement functions for setting up and shutting down the extension layer, you must do the following:

  1. Initialize the driver in Layer_InitializeOnce.
  2. Create an instance of the driver in Layer_CreateDriverInstance.
  3. Uninitialize the driver in Layer_UnitializeOnce.
  4. Shutdown the driver in Layer_CloseDriverInstance.

Initialize the Driver

You must call Layer_InitializeOnce one time during driver load from DLLMain. Do not perform any tasks in this function except for initializing synchronization primitives and I/O. You must call this function only one time, and then the function must check whether the driver has been initialized. If the driver initialization has already occurred, uninitialize the driver by calling the Layer_UninitializeOnce function.

The return value for this function is ignored by the calling code.

The following example code from the Bt_ddi.h header file shows the declaration for the function.

l2cap_InitializeOnce.
int l2cap_InitializeOnce (void);

Create an Instance of the Driver

Use ExtensionLayer_CreateDriverInstance to initialize the stack layer. This function is called after Extension_InitializeOnce is called. Therefore, the synchronization primitives are already initialized. You can call this function out of sequence by using Extension_CloseDriverInstance. However, you must implement the function to maintain state and protect against duplicate calls.

This function must start the stack layer by first connecting to the bottom layer, then preparing for connection requests from top layers, then initializing hardware if appropriate, and so on.

If the function succeeds, you return ERROR_SUCCESS. Otherwise, return an appropriate error status from winerror.h. You must only return ERROR_SUCCESS if the stack layer is in an operational state.

The following example code from the Bt_ddi.h header file shows the declaration for the function l2cap_CreateDriverInstance.

int l2cap_CreateDriverInstance (void);

The following example code from the sample L2capdev shows an implementation of the function l2capdev_CreateDriverInstance.

int l2capdev_CreateDriverInstance (void) {
    IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"+l2capdev_CreateDriverInstance\n"));

    if (gpState) {
        IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CreateDriverInstance : ERROR_ALREADY_INITIALIZED\n"));
        return ERROR_ALREADY_INITIALIZED;
    }

    gpState = CreateNewState ();

    if ((! gpState) || (! gpState->fIsRunning)) {
        IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CreateDriverInstance : ERROR_OUTOFMEMORY\n"));
        if (gpState)
            delete gpState;
        gpState = NULL;
        return ERROR_OUTOFMEMORY;
    }

    IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CreateDriverInstance : ERROR_SUCCESS\n"));
    return ERROR_SUCCESS;
}

Uninitialize the Driver

DLLMain calls ExtensionLayer_UninitializeOnce one time during driver unload. You must implement the ExtensionLayer_UninitializeOnce function so that it contains only code that uninitializes synchronization primitives that were created in ExtensionLayer_InitializeOnce. This function is called only one time after the driver has already entered the shutdown state. The driver is unloaded immediately afterward.

The return value for this function is ignored by the calling code.

The following example code from the bt_ddi header file displays the declaration for the function l2cap_UninitializeOnce.

int l2cap_UninitializeOnce (void);

Shutdown the Driver

ExtensionLayer_CloseDriverInstance is used to uninitialize the stack layer. This function is called after Extension_UninitializeOnce is called. Therefore, synchronization primitives will already be uninitialized. This function can be called out of sequence by using Extension_CreateDeviceInstance. However, it must maintain state and protect against duplicate calls. This function must stop the stack layer by closing all connections. This frees its interface to the lower layer, notifying upper layers of its shutdown, destroying all threads, and freeing everything allocated in Extension_CreateDeviceInstance.

If the function succeeds, return ERROR_SUCCESS. Otherwise, return an appropriate error status from winerror.h.

The following example code from the Bt_ddi.h header file shows the declaration for the function l2cap_CloseDriverInstance.

int l2cap_CloseDriverInstance (void);

The following example code from the sample L2capdev shows an implementation of the function l2capdev_CloseDriverInstance.

int l2capdev_CloseDriverInstance (void) {
    IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"+l2capdev_CloseDriverInstance\n"));

    if (! gpState) {
        IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CloseDriverInstance : ERROR_SERVICE_NOT_ACTIVE\n"));
        return ERROR_SERVICE_NOT_ACTIVE;
    }

    gpState->Lock ();
    if (! gpState->fIsRunning) {
        IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CloseDriverInstance : ERROR_SERVICE_NOT_ACTIVE\n"));
        gpState->Unlock ();

        return ERROR_SERVICE_NOT_ACTIVE;
    }

    gpState->fIsRunning = FALSE;

    while (gpState->GetRefCount () > 1) {
        IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Waiting for ref count in l2capdev_CloseDriverInstance\n"));
        gpState->Unlock ();
        Sleep (200);
        gpState->Lock ();
    }

    while (gpState->pCalls) {
        SetEvent (gpState->pCalls->hEvent);
        gpState->pCalls->iResult = ERROR_CANCELLED;
        gpState->pCalls = gpState->pCalls->pNext;
    }

    while (gpState->pLinks) {
        unsigned short cid = gpState->pLinks->cid;

        gpState->Unlock ();
        gpState->l2cap_if.l2ca_Disconnect_In (gpState->hL2CAP, NULL, cid);
        gpState->Lock ();

        gpState->pLinks = gpState->pLinks->pNext;
    }

    IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"-l2capdev_CloseDriverInstance : ERROR_SUCCESS\n"));

    gpState->Unlock ();
    delete gpState;
    gpState = NULL;

    return ERROR_SUCCESS;
}

See Also

Concepts

Bluetooth Stack Extension Layer
Implement the Bluetooth Stack Data Structures
Create an Installable Stream Device Driver for the Extension Layer

Other Resources

Bluetooth Architecture