alder_lake_bios/Intel/AlderLake/Features/BluetoothPkg/BluetoothBusDxe/BluetoothConfigConnect.c

491 lines
17 KiB
C

//
// This file contains a 'Sample Driver' and is licensed as such
// under the terms of your license agreement with Intel or your
// vendor. This file may be modified by the user, subject to
// the additional terms of the license agreement
//
/** @file
The file provides some help functions which are used in device connection.
Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
**/
#include "BluetoothBusDxe.h"
#include "uefi_app.h"
EFI_BLUETOOTH_ATTRIBUTE_PROTOCOL mBluetoothAttribute = {
BluetoothAttributeSendRequest,
BluetoothAttributeRegisterForServerNotification,
BluetoothAttributeGetServiceInfo,
BluetoothAttributeGetDeviceInfo
};
/**
Creates a BluetoothLE Service Binding device.
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
@param[in] BtLeDevInfo A pointer to the BT_LE_DEV_INFO structure, which
contains the BluetoothLE device information.
@retval A pointer to the BT_LE_SB_DEV structure or NULL if memory allocation
fails.
**/
BT_LE_SB_DEV*
BtCreateLeSbDev (
IN BTHC_DEV *BtHcDev,
IN BT_LE_DEV_INFO *BtLeDevInfo
)
{
BT_LE_SB_DEV *BtLeSbDev;
BLUETOOTH_LE_ADDRESS DummyAddr;
BtLeSbDev = AllocateZeroPool (sizeof(BT_LE_SB_DEV));
if (BtLeSbDev == NULL) {
return BtLeSbDev;
}
BtLeSbDev->Signature = BT_LE_SB_DEV_SIGNATURE;
ZeroMem(&DummyAddr, sizeof(BLUETOOTH_LE_ADDRESS));
if (CompareMem(&BtLeDevInfo->IDAddr, &DummyAddr, sizeof(BLUETOOTH_LE_ADDRESS))) {
BtAppendBtLeDevPath (
&BtLeSbDev->DevicePath,
BtHcDev->DevicePath,
&BtLeDevInfo->IDAddr
);
} else {
BtAppendBtLeDevPath (
&BtLeSbDev->DevicePath,
BtHcDev->DevicePath,
&BtLeDevInfo->BDAddr
);
}
CopyMem (&BtLeSbDev->ServiceBinding, &mBluetoothLeServiceBinding, sizeof (mBluetoothLeServiceBinding));
BtLeSbDev->BtLeDevInfo = BtLeDevInfo;
BtLeSbDev->BtHcDev = BtHcDev;
InitializeListHead (&BtLeSbDev->Link);
InitializeListHead (&BtLeSbDev->ChildrenList);
BtLeSbDev->Initialized = FALSE;
return BtLeSbDev;
}
/**
Initializes the given BluetoothLE Service Binding device.
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
@param[in] BtLeSbDev A pointer to the BT_LE_SB_DEV structure, which
specifies the BluetoothLE Service Binding device to
initialize.
@retval EFI_SUCCESS The initialization succeeds.
@retval Others The initialization fails.
**/
EFI_STATUS
BtInitLeSbDev (
IN BTHC_DEV *BtHcDev,
IN BT_LE_SB_DEV *BtLeSbDev
)
{
EFI_STATUS Status;
EFI_BLUETOOTH_HC_PROTOCOL *BluetoothHc;
Status = gBS->InstallMultipleProtocolInterfaces (
&BtLeSbDev->DeviceHandle,
&gEfiDevicePathProtocolGuid, BtLeSbDev->DevicePath,
&gEfiBluetoothAttributeServiceBindingProtocolGuid, &BtLeSbDev->ServiceBinding,
NULL
);
ASSERT_EFI_ERROR (Status);
Status = gBS->OpenProtocol (
BtHcDev->ControllerHandle,
&gEfiBluetoothHcProtocolGuid,
(VOID **)&BluetoothHc,
BtHcDev->DriverBindingHandle,
BtLeSbDev->DeviceHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_ERROR, "BleBus: BtInitLeSbDev %p\n", BtLeSbDev->DeviceHandle));
BtLeSbDev->Initialized = TRUE;
return Status;
}
/**
Creates a new device path by appending a Bluetooth device node to a given
base device path.
@param[in,out] DevPtr A pointer to the generated device path if
EFI_SUCCESS is returned. Or NULL if
EFI_OUT_OF_RESOURCES is returned.
@param[in] BaseDevPtr A pointer to a device path data structure.
@param[in] BDAddr A pointer to a Bluetooth device address.
@retval EFI_SUCCESS The new device path is created.
@retval EFI_OUT_OF_RESOURCES The creation of the new device path fails due
to memory allocation failure.
**/
EFI_STATUS
BtAppendBtLeDevPath (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
IN BLUETOOTH_LE_ADDRESS *BDAddr
)
{
BLUETOOTH_LE_DEVICE_PATH BtLeAddrNode;
EFI_DEVICE_PATH_PROTOCOL *EndNode;
UINT16 TotalPathLen;
UINT16 BasePathLen;
UINT8 *DevicePtr;
ZeroMem (&BtLeAddrNode, sizeof (BtLeAddrNode));
CopyMem (&BtLeAddrNode.Address, BDAddr, sizeof(BLUETOOTH_LE_ADDRESS));
BtLeAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
BtLeAddrNode.Header.SubType = MSG_BLUETOOTH_LE_DP;
SetDevicePathNodeLength (&BtLeAddrNode.Header, sizeof (BLUETOOTH_LE_DEVICE_PATH));
//
// find the size of the base dev path.
//
EndNode = BaseDevPtr;
while (!IsDevicePathEnd (EndNode)) {
EndNode = NextDevicePathNode (EndNode);
}
BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
//
// create space for full dev path
//
TotalPathLen = (UINT16) (BasePathLen + sizeof (BtLeAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
DevicePtr = AllocatePool (TotalPathLen);
if (DevicePtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// copy the base path, BT addr and end_dev_path nodes
//
*DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
CopyMem (DevicePtr, (VOID *) BaseDevPtr, BasePathLen);
DevicePtr += BasePathLen;
CopyMem (DevicePtr, (VOID *) &BtLeAddrNode, sizeof (BtLeAddrNode));
DevicePtr += sizeof (BtLeAddrNode);
CopyMem (DevicePtr, (VOID *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
return EFI_SUCCESS;
}
/**
Adds a given BluetoothLE Service Binding device to the BluetoothLE Service
Binding device list.
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
@param[in] BtLeSbDev A pointer to the BT_LE_SB_DEV structure, which
specifies the BluetoothLE Service Binding device to
add into the list.
@retval TRUE This function always return TRUE.
**/
BOOLEAN
BtAddLeSb (
IN BTHC_DEV *BtHcDev,
IN BT_LE_SB_DEV *BtLeSbDev
)
{
EFI_TPL OldTpl;
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
InsertTailList (&BtHcDev->BtLeSbList, &BtLeSbDev->Link);
gBS->RestoreTPL (OldTpl);
return TRUE;
}
/**
Removes a given BluetoothLE Service Binding device to the BluetoothLE Service
Binding device list.
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
@param[in] BtLeSbDev A pointer to the BT_LE_SB_DEV structure, which
specifies the BluetoothLE Service Binding device to
remove from the list.
@retval FALSE The specified BluetoothLE Service Binding device has not been
removed from the list.
@retval TRUE The specified BluetoothLE Service Binding device has been
removed from the list.
**/
BOOLEAN
BtDelLeSb (
IN BTHC_DEV *BtHcDev,
IN BT_LE_SB_DEV *BtLeSbDev
)
{
EFI_TPL OldTpl;
EFI_STATUS Status;
EFI_BLUETOOTH_HC_PROTOCOL *BluetoothHc;
DEBUG ((DEBUG_ERROR, "BleBusDxe: BtDelLeSb (%p, %p)\n", BtHcDev, BtLeSbDev));
if (BtHcDev == NULL || BtLeSbDev == NULL) {
return FALSE;
}
if (BtLeSbDev->Initialized) {
//
// Close the OPEN_BY_CHILD_CONTROLLER
//
Status = gBS->CloseProtocol (
BtHcDev->ControllerHandle,
&gEfiBluetoothHcProtocolGuid,
BtHcDev->DriverBindingHandle,
BtLeSbDev->DeviceHandle
);
ASSERT_EFI_ERROR (Status);
//
// Destroy the Ble device handle.
// It will call BluetoothAttributeDriverBindingStop()
//
Status = gBS->UninstallMultipleProtocolInterfaces (
BtLeSbDev->DeviceHandle,
&gEfiDevicePathProtocolGuid, BtLeSbDev->DevicePath,
&gEfiBluetoothAttributeServiceBindingProtocolGuid, &BtLeSbDev->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
Status = gBS->OpenProtocol (
BtHcDev->ControllerHandle,
&gEfiBluetoothHcProtocolGuid,
(VOID **)&BluetoothHc,
BtHcDev->DriverBindingHandle,
BtLeSbDev->DeviceHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
ASSERT_EFI_ERROR (Status);
return FALSE;
//
// TODO: iLE stack should take care of the return status. Currently not!
//
}
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
RemoveEntryList (&BtLeSbDev->Link);
gBS->RestoreTPL (OldTpl);
}
FreePool (BtLeSbDev->DevicePath);
FreePool (BtLeSbDev);
return TRUE;
}
/**
Connect a BluetoothLE device.
The Connect() function connects a Bluetooth device. When this function is returned successfully,
a new EFI_BLUETOOTH_IO_PROTOCOL is created.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL instance.
@param[in] AutoReconnect If TRUE, the BluetoothLE host controller needs to do an auto
reconnect. If FALSE, the BluetoothLE host controller does not do
an auto reconnect.
@param[in] DoBonding If TRUE, the BluetoothLE host controller needs to do a bonding.
If FALSE, the BluetoothLE host controller does not do a bonding.
@param[in] ConnectParameter If it is not NULL, the ConnectParameter is used to perform a
scan by the BluetoothLE bus driver. If it is NULL, the default
parameter is used.
@param[in] BD_ADDR The address of the BluetoothLE device to be connected.
@retval EFI_SUCCESS The BluetoothLE device is connected successfully.
@retval EFI_ALREADY_STARTED The BluetoothLE device is already connected.
@retval EFI_NOT_FOUND The BluetoothLE device is not found.
@retval EFI_DEVICE_ERROR A hardware error occurred trying to connect the BluetoothLE device.
**/
EFI_STATUS
EFIAPI
BluetoothLeConfigConnect (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN BOOLEAN AutoReconnect,
IN BOOLEAN DoBonding,
IN EFI_BLUETOOTH_LE_CONFIG_CONNECT_PARAMETER *ConnectParameter, OPTIONAL
IN BLUETOOTH_LE_ADDRESS *BD_ADDR
)
{
BTHC_DEV *BtHcDev;
BT_LE_SB_DEV *BtLeSbDev;
BT_LE_DEV_INFO *BtLeDevInfo;
BT_LE_PAIRED_DEV_INFO *BtLePairedDevInfo;
EFI_STATUS Status;
BtHcDev = BTHC_DEV_FROM_BLUETOOTH_LE_CONFIG_PROTOCOL (This);
DEBUG ((EFI_D_INFO, "BluetoothLeConfigConnect\n"));
BtLeDevInfo = BtLeFindDeviceInfo (BtHcDev, BD_ADDR);
if (BtLeDevInfo == NULL) {
BtLePairedDevInfo = BtFindLePairedDevByBDAddr(BtHcDev, BD_ADDR);
if (BtLePairedDevInfo != NULL) {
/* Add device to local list */
if (!BtLeUpdateDevice(BtHcDev, &BtLePairedDevInfo->BDAddr, &BtLePairedDevInfo->IDAddr,
NULL, 0, 0, 0, 0, NULL, NULL, 0, TRUE)) {
return EFI_PROTOCOL_ERROR;
}
} else {
DEBUG ((EFI_D_INFO, "BluetoothLeConfigConnect - DevInfo NOT FOUND\n"));
return EFI_NOT_FOUND;
}
}
BtLeSbDev = BtFindLeSbDevByBDaddr (BtHcDev, BD_ADDR);
if (BtLeSbDev != NULL) {
DEBUG ((EFI_D_INFO, "BluetoothLeConfigConnect - BtSbDev already exist\n"));
return EFI_ALREADY_STARTED;
}
Status = stack_connect (BD_ADDR, ConnectParameter, AutoReconnect, DoBonding);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_INFO, "BluetoothLeConfigConnect - Enter BtDelIoDev\n"));
BtLeSbDev = BtFindLeSbDevByBDaddr (BtHcDev, BD_ADDR);
if (BtLeSbDev != NULL) {
BtDelLeSb (BtHcDev, BtLeSbDev);
}
DEBUG ((EFI_D_INFO, "BluetoothLeConfigConnect - %r\n", Status));
return Status;
}
return EFI_SUCCESS;
}
/**
Adds a BluetoothLE device into the paired device list.
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
@param[in] BDAddr A pointer to a Bluetooth device address.
@param[in] IDAddr A pointer to a device identity address.
@param[in] BluetoothHc A pointer to a EFI_BLUETOOTH_HC_PROTOCOL instance.
@retval EFI_SUCCESS This function always returns EFI_SUCCESS.
**/
EFI_STATUS
BtAddLePairedDev (
IN BTHC_DEV *BtHcDev,
IN BLUETOOTH_LE_ADDRESS *BDAddr,
IN BLUETOOTH_LE_ADDRESS *IDAddr,
IN EFI_BLUETOOTH_HC_PROTOCOL *BluetoothHc
)
{
BT_LE_PAIRED_DEV_INFO *LePairedDevInfo;
ASSERT (BDAddr != NULL);
ASSERT (IDAddr != NULL);
LePairedDevInfo = BtFindLePairedDevByBDAddr (BtHcDev, BDAddr);
if(LePairedDevInfo == NULL){
LePairedDevInfo = AllocateZeroPool (sizeof (BT_LE_PAIRED_DEV_INFO));
if (LePairedDevInfo == NULL) {
DEBUG ((EFI_D_ERROR, "AllocateZeroPool failed for %d bytes", sizeof(BT_LE_PAIRED_DEV_INFO)));
return EFI_OUT_OF_RESOURCES;
}
LePairedDevInfo->Signature = BT_LE_PAIRED_DEV_INFO_SIGNATURE;
CopyMem (&LePairedDevInfo->BDAddr, BDAddr, sizeof (BLUETOOTH_LE_ADDRESS));
CopyMem (&LePairedDevInfo->IDAddr, IDAddr, sizeof (BLUETOOTH_LE_ADDRESS));
InsertTailList (&BtHcDev->BtLePairedList, &LePairedDevInfo->Link);
}
return EFI_SUCCESS;
}
/**
Disconnect a BluetoothLE device.
The Disconnect() function disconnects a BluetoothLE device. When this function is returned
successfully, the EFI_BLUETOOTH_ATTRIBUTE_PROTOCOL associated with this device is
destroyed and all services associated are stopped.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL instance.
@param[in] BD_ADDR The address of BluetoothLE device to be connected.
@param[in] Reason Bluetooth disconnect reason. See Bluetooth specification for detail.
@retval EFI_SUCCESS The BluetoothLE device is disconnected successfully.
@retval EFI_NOT_STARTED The BluetoothLE device is not connected.
@retval EFI_NOT_FOUND The BluetoothLE device is not found.
@retval EFI_DEVICE_ERROR A hardware error occurred trying to disconnect the BluetoothLE device.
**/
EFI_STATUS
EFIAPI
BluetoothLeConfigDisconnect (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN BLUETOOTH_LE_ADDRESS *BD_ADDR,
IN UINT8 Reason
)
{
BTHC_DEV *BtHcDev;
EFI_STATUS Status;
BT_LE_SB_DEV *BtLeSbDev;
Status = EFI_NOT_FOUND;
BtHcDev = BTHC_DEV_FROM_BLUETOOTH_LE_CONFIG_PROTOCOL(This);
BtLeSbDev = BtFindLeSbDevByBDaddr(BtHcDev, BD_ADDR);
if (Reason == BluetoothDisconnectReasonTypeRemoteDeviceTerminatedConnectionDueToLowResources) {
/* User has Deleted device bonding information */
stack_remove_device(BD_ADDR);
}
if (BtLeSbDev != NULL) {
Status = stack_disconnect(BD_ADDR, BtLeSbDev->ConnectionId, Reason);
}
DEBUG ((EFI_D_INFO, "BluetoothLeConfigDisconnect\n"));
return Status;
}
/**
Send user authentication/authorization to remote device.
The SendSmpAuthData() function sends user authentication/authorization to remote device. It
should be used to send these information after the caller gets the request data from the callback
function by RegisterSmpAuthCallback().
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL instance.
@param[in] BDAddr Remote BluetoothLE device address.
@param[in] EventDataType Event data type in EFI_BLUETOOTH_LE_SMP_EVENT_DATA_TYPE.
@param[in] DataSize The size of Data in bytes, of the data buffer specified by Data.
@param[in] Data A pointer to the buffer of data that will be sent. The data format
depends on the type of SMP event data being responded to.
@retval EFI_SUCCESS The SMP authorization data is sent successfully.
@retval EFI_NOT_READY SMP is not in the correct state to receive the auth data.
**/
EFI_STATUS
EFIAPI
BluetoothLeConfigSendSmpAuthData (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN BLUETOOTH_LE_ADDRESS *BDAddr,
IN EFI_BLUETOOTH_LE_SMP_EVENT_DATA_TYPE EventDataType,
IN UINTN DataSize,
IN VOID *Data
)
{
return stack_smp_auth(BDAddr, EventDataType, DataSize, Data);
}