443 lines
17 KiB
C
443 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 implements interfaces defined in EFI_BLUETOOTH_CONFIG_PROTOCOL.
|
|
|
|
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 <IndustryStandard/BluetoothAssignedNumbers.h>
|
|
#include "uefi_app.h"
|
|
|
|
/**
|
|
Sets the validity of BluetoothLE devices.
|
|
|
|
If a BluetoothLE device has already been discovered, the validity attribute
|
|
will be set to TRUE. Otherwise, FALSE will be set.
|
|
|
|
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
|
|
|
|
**/
|
|
VOID
|
|
BtLeSetDeviceInfoInvalid (
|
|
IN BTHC_DEV *BtHcDev
|
|
)
|
|
{
|
|
LIST_ENTRY *BtLeDevInfoList;
|
|
LIST_ENTRY *Link;
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
BT_LE_SB_DEV *BtLeSbDev;
|
|
EFI_TPL OldTpl;
|
|
|
|
BtLeDevInfoList = &BtHcDev->BtLeDevInfoList;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Link = GetFirstNode(BtLeDevInfoList);
|
|
while (!IsNull(BtLeDevInfoList, Link))
|
|
{
|
|
BtLeDevInfo = CR (
|
|
Link,
|
|
BT_LE_DEV_INFO,
|
|
Link,
|
|
BT_LE_DEV_INFO_SIGNATURE
|
|
);
|
|
|
|
BtLeSbDev = BtFindLeSbDevByBDaddr(BtHcDev, &BtLeDevInfo->BDAddr);
|
|
if (BtLeSbDev == NULL) {
|
|
Link = RemoveEntryList(Link);
|
|
if (BtLeDevInfo->AdvertisementData != NULL) {
|
|
FreePool(BtLeDevInfo->AdvertisementData);
|
|
}
|
|
FreePool(BtLeDevInfo);
|
|
} else {
|
|
Link = GetNextNode(BtLeDevInfoList, Link);
|
|
}
|
|
}
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
Gets the device information of a BluetoothLE device specified by the
|
|
Bluetooth device address.
|
|
|
|
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
|
|
@param[in] BDAddr A pointer to a Bluetooth device address.
|
|
|
|
@retval A pointer to the BT_LE_DEV_INFO structure which contains the device
|
|
information for the specified BluetoothLE device.
|
|
@retval NULL If a BluetoothLE device with address specified by 'BDAddr'
|
|
cannot be found.
|
|
|
|
**/
|
|
BT_LE_DEV_INFO *
|
|
BtLeFindDeviceInfo (
|
|
IN BTHC_DEV *BtHcDev,
|
|
IN BLUETOOTH_LE_ADDRESS *BDAddr
|
|
)
|
|
{
|
|
LIST_ENTRY *BtLeDevInfoList;
|
|
LIST_ENTRY *Link;
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
BtLeDevInfoList = &BtHcDev->BtLeDevInfoList;
|
|
|
|
for (Link = BtLeDevInfoList->ForwardLink; Link != BtLeDevInfoList; Link = Link->ForwardLink) {
|
|
BtLeDevInfo = CR (Link, BT_LE_DEV_INFO, Link, BT_LE_DEV_INFO_SIGNATURE);
|
|
|
|
/* Currently checking only with BD Address as Stack in not returning the correct BD Address Type in case of Privacy 1.2.
|
|
* TODO: Check with BD Address Type as well. */
|
|
if ((CompareMem (&BtLeDevInfo->BDAddr.Address, &BDAddr->Address, sizeof(BDAddr->Address)) == 0) ||
|
|
((CompareMem (&BtLeDevInfo->IDAddr.Address, &BDAddr->Address, sizeof(BDAddr->Address)) == 0))) {
|
|
return BtLeDevInfo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Gets the data needed for the scan callback function call of a BluetoothLE
|
|
device.
|
|
|
|
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
|
|
@param[in] BDAddr A pointer to a Bluetooth device address.
|
|
@param[out] LeScanCallbackInfo A pointer to store the scan callback
|
|
function data of the a BluetoothLE device.
|
|
|
|
@retval FALSE Fail to get the scan callback function data.
|
|
@retval TRUE Successfully get the scan callback function data.
|
|
|
|
**/
|
|
BOOLEAN
|
|
BtLeGetScanCallBackInformation(
|
|
IN BTHC_DEV *BtHcDev,
|
|
IN BLUETOOTH_LE_ADDRESS *BDAddr,
|
|
OUT EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION *LeScanCallbackInfo
|
|
)
|
|
{
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
BT_LE_SB_DEV *BtLeSbDev;
|
|
BT_LE_PAIRED_DEV_INFO *BtLePairedDev;
|
|
BtLeDevInfo = BtLeFindDeviceInfo(BtHcDev, BDAddr);
|
|
if (BtLeDevInfo == NULL){
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMem (LeScanCallbackInfo, sizeof (EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION));
|
|
CopyMem (&LeScanCallbackInfo->BDAddr, &BtLeDevInfo->BDAddr, sizeof(BLUETOOTH_LE_ADDRESS));
|
|
CopyMem (&LeScanCallbackInfo->DirectAddress, &BtLeDevInfo->Direct_BD_ADDR, sizeof(BLUETOOTH_LE_ADDRESS));
|
|
LeScanCallbackInfo->RSSI = BtLeDevInfo->RSSI;
|
|
LeScanCallbackInfo->AdvertisementDataSize = BtLeDevInfo->AdvertisementDataSize;
|
|
LeScanCallbackInfo->AdvertisementData = AllocateZeroPool (BtLeDevInfo->AdvertisementDataSize);
|
|
ASSERT (LeScanCallbackInfo->AdvertisementData != NULL);
|
|
CopyMem (LeScanCallbackInfo->AdvertisementData, BtLeDevInfo->AdvertisementData, BtLeDevInfo->AdvertisementDataSize);
|
|
|
|
LeScanCallbackInfo->RemoteDeviceState = 0x00;
|
|
BtLeSbDev = BtFindLeSbDevByBDaddr(BtHcDev, BDAddr);
|
|
if (BtLeSbDev != NULL) {
|
|
(LeScanCallbackInfo->RemoteDeviceState) |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED;
|
|
}
|
|
BtLePairedDev = BtFindLePairedDevByBDAddr(BtHcDev, BDAddr);
|
|
if (BtLePairedDev != NULL) {
|
|
(LeScanCallbackInfo->RemoteDeviceState) |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
Add the device information of a BluetoothLE device to the device information
|
|
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] Direct_BD_ADDR A pointer to a direct Bluetooth device
|
|
address.
|
|
@param[in] RSSI The Bluetooth RSSI.
|
|
@param[in] TxPower The transmitted power level of the packet
|
|
containing the data type.
|
|
@param[in] Appearance The external appearance of the device.
|
|
@param[in] RoleSupported The LE role capabilities of the device.
|
|
@param[in] LocalReadableName The local name assigned to the device.
|
|
@param[in] AdvertisementData A pointer to the BluetoothLEadvertisement
|
|
data.
|
|
@param[in] AdvertisementDataSize The size of AdvertisementData in bytes.
|
|
|
|
@retval TRUE Device information of the specific BluetoothLE device has
|
|
been added successfully.
|
|
@retval FALSE Device information of the specific BluetoothLE device has not
|
|
been added.
|
|
|
|
**/
|
|
BOOLEAN
|
|
BtLeAddDevice (
|
|
IN BTHC_DEV *BtHcDev,
|
|
IN BLUETOOTH_LE_ADDRESS *BDAddr,
|
|
IN BLUETOOTH_LE_ADDRESS *IDAddr,
|
|
IN BLUETOOTH_LE_ADDRESS *Direct_BD_ADDR,
|
|
IN INT8 RSSI,
|
|
IN UINT8 TxPower,
|
|
IN UINT16 Appearance,
|
|
IN UINT8 RoleSupported,
|
|
IN UINT8 *LocalReadableName,
|
|
IN UINT8 *AdvertisementData,
|
|
IN UINT8 AdvertisementDataSize
|
|
)
|
|
{
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
EFI_TPL OldTpl;
|
|
EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION LeScanCallbackInfo;
|
|
|
|
ASSERT (BDAddr != NULL);
|
|
BtLeDevInfo = AllocateZeroPool (sizeof(*BtLeDevInfo));
|
|
if (BtLeDevInfo == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "AllocateZeroPool failed for %d bytes", sizeof(*BtLeDevInfo)));
|
|
return FALSE;
|
|
}
|
|
BtLeDevInfo->Signature = BT_LE_DEV_INFO_SIGNATURE;
|
|
CopyMem (&BtLeDevInfo->BDAddr, BDAddr, sizeof(BtLeDevInfo->BDAddr));
|
|
if (IDAddr != NULL) {
|
|
CopyMem (&BtLeDevInfo->IDAddr, IDAddr, sizeof(BtLeDevInfo->IDAddr));
|
|
}
|
|
CopyMem (&BtLeDevInfo->Direct_BD_ADDR, Direct_BD_ADDR, sizeof(BtLeDevInfo->Direct_BD_ADDR));
|
|
BtLeDevInfo->RSSI = RSSI;
|
|
|
|
BtLeDevInfo->AdvertisementDataSize = AdvertisementDataSize;
|
|
BtLeDevInfo->AdvertisementData = AllocateZeroPool (AdvertisementDataSize);
|
|
ASSERT (BtLeDevInfo->AdvertisementData != NULL);
|
|
CopyMem (BtLeDevInfo->AdvertisementData, AdvertisementData, AdvertisementDataSize);
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
InsertTailList (&BtHcDev->BtLeDevInfoList, &BtLeDevInfo->Link);
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
if (BtHcDev->LeScanCallBackFunc != NULL) {
|
|
BtLeGetScanCallBackInformation (BtHcDev, BDAddr, &LeScanCallbackInfo);
|
|
BtHcDev->LeScanCallBackFunc (&BtHcDev->BluetoothLeConfig, BtHcDev->LeScanCallBackFuncContext, &LeScanCallbackInfo);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Updates the device information of a BluetoothLE device.
|
|
|
|
@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] Direct_BD_ADDR A pointer to a direct Bluetooth device
|
|
address.
|
|
@param[in] RSSI The Bluetooth RSSI.
|
|
@param[in] TxPower The transmitted power level of the packet
|
|
containing the data type.
|
|
@param[in] Appearance The external appearance of the device.
|
|
@param[in] RoleSupported The LE role capabilities of the device.
|
|
@param[in] LocalReadableName The local name assigned to the device.
|
|
@param[in] AdvertisementData A pointer to the BluetoothLE advertisement
|
|
data.
|
|
@param[in] AdvertisementDataSize The size of AdvertisementData in bytes.
|
|
@param[in] NeedAdd Add the BluetoothLE device to the device
|
|
information list or not.
|
|
|
|
@retval TRUE Device information of the specific BluetoothLE device has
|
|
been updated successfully.
|
|
@retval FALSE Device information of the specific BluetoothLE device has not
|
|
been updated.
|
|
|
|
**/
|
|
BOOLEAN
|
|
BtLeUpdateDevice (
|
|
IN BTHC_DEV *BtHcDev,
|
|
IN BLUETOOTH_LE_ADDRESS *BDAddr,
|
|
IN BLUETOOTH_LE_ADDRESS *IDAddr,
|
|
IN BLUETOOTH_LE_ADDRESS *Direct_BD_ADDR,
|
|
IN INT8 RSSI,
|
|
IN UINT8 TxPower,
|
|
IN UINT16 Appearance,
|
|
IN UINT8 RoleSupported,
|
|
IN UINT8 *LocalReadableName,
|
|
IN UINT8 *AdvertisementData,
|
|
IN UINT8 AdvertisementDataSize,
|
|
IN BOOLEAN NeedAdd
|
|
)
|
|
{
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION LeScanCallbackInfo;
|
|
UINT8 *TempAdvData;
|
|
UINTN TempAdvDataSize;
|
|
|
|
BtLeDevInfo = BtLeFindDeviceInfo (BtHcDev, BDAddr);
|
|
if (BtLeDevInfo == NULL) {
|
|
//
|
|
// Not found
|
|
//
|
|
if (!NeedAdd) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Add
|
|
//
|
|
return BtLeAddDevice (
|
|
BtHcDev,
|
|
BDAddr,
|
|
IDAddr,
|
|
Direct_BD_ADDR,
|
|
RSSI,
|
|
TxPower,
|
|
Appearance,
|
|
RoleSupported,
|
|
LocalReadableName,
|
|
AdvertisementData,
|
|
AdvertisementDataSize
|
|
);
|
|
}
|
|
|
|
//
|
|
// Update
|
|
// Note: Do not update the Identity Address here
|
|
//
|
|
CopyMem (&BtLeDevInfo->BDAddr, BDAddr, sizeof(BtLeDevInfo->BDAddr));
|
|
CopyMem (&BtLeDevInfo->Direct_BD_ADDR, Direct_BD_ADDR, sizeof(BtLeDevInfo->Direct_BD_ADDR));
|
|
BtLeDevInfo->RSSI = RSSI;
|
|
|
|
if (BtLeDevInfo->AdvertisementData != NULL) {
|
|
// This is scan reponse packet, append the advertisement data
|
|
TempAdvDataSize = BtLeDevInfo->AdvertisementDataSize + AdvertisementDataSize;
|
|
TempAdvData = AllocateZeroPool (TempAdvDataSize);
|
|
ASSERT (TempAdvData != NULL);
|
|
if (BtLeDevInfo->AdvertisementData != NULL) {
|
|
CopyMem (&TempAdvData[0], BtLeDevInfo->AdvertisementData, BtLeDevInfo->AdvertisementDataSize);
|
|
}
|
|
CopyMem (&TempAdvData[BtLeDevInfo->AdvertisementDataSize], AdvertisementData, AdvertisementDataSize);
|
|
} else {
|
|
// First time receiving the advertisement report during current scanning
|
|
TempAdvDataSize = AdvertisementDataSize;
|
|
TempAdvData = AllocateZeroPool (TempAdvDataSize);
|
|
ASSERT (TempAdvData != NULL);
|
|
CopyMem (TempAdvData, AdvertisementData, AdvertisementDataSize);
|
|
}
|
|
|
|
// Free previous advertisement data
|
|
if (BtLeDevInfo->AdvertisementData != NULL) {
|
|
FreePool(BtLeDevInfo->AdvertisementData);
|
|
}
|
|
|
|
BtLeDevInfo->AdvertisementDataSize = TempAdvDataSize;
|
|
BtLeDevInfo->AdvertisementData = TempAdvData;
|
|
|
|
if (BtHcDev->LeScanCallBackFunc != NULL) {
|
|
BtLeGetScanCallBackInformation (BtHcDev, BDAddr, &LeScanCallbackInfo);
|
|
BtHcDev->LeScanCallBackFunc (&BtHcDev->BluetoothLeConfig, BtHcDev->LeScanCallBackFuncContext, &LeScanCallbackInfo);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Scans BluetoothLE devices.
|
|
|
|
@param[in] BtHcDev A pointer to the BTHC_DEV structure.
|
|
@param[in] BluetoothHc A pointer to the EFI_BLUETOOTH_HC_PROTOCOL
|
|
instance.
|
|
@param[in] Timeout The timeout, in millisecond units, to use for the
|
|
execution of the scan. A Timeout value of 0 means
|
|
that this function will wait indefinitely for the
|
|
scan to complete.
|
|
@param[in] ScanParameter If ScanParameter is not NULL, it is used to
|
|
perform a scan by the BluetoothLE bus driver.
|
|
Otherwise, the default parameter is used.
|
|
|
|
**/
|
|
VOID
|
|
BtLeScan (
|
|
IN BTHC_DEV *BtHcDev,
|
|
IN EFI_BLUETOOTH_HC_PROTOCOL *BluetoothHc,
|
|
IN UINTN Timeout,
|
|
IN EFI_BLUETOOTH_LE_CONFIG_SCAN_PARAMETER *ScanParameter OPTIONAL
|
|
)
|
|
{
|
|
|
|
BtLeSetDeviceInfoInvalid (BtHcDev);
|
|
stack_scan ((UINT32)Timeout, ScanParameter);
|
|
}
|
|
|
|
/**
|
|
Scan BluetoothLE device.
|
|
|
|
The Scan() function scans BluetoothLE device. When this function is returned, it just means scan
|
|
request is submitted. It does not mean scan process is started or finished. Whenever there is a
|
|
BluetoothLE device is found, the Callback function will be called. Callback function might be
|
|
called before this function returns or after this function returns
|
|
|
|
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL instance.
|
|
@param[in] ReScan If TRUE, a new scan request is submitted no matter there is scan result before.
|
|
If FALSE and there is scan result, the previous scan result is returned and no scan request
|
|
is submitted.
|
|
@param[in] Timeout Duration in milliseconds for which to scan.
|
|
@param[in] ScanParameter If it is not NULL, the ScanParameter is used to perform a scan by the BluetoothLE bus driver.
|
|
If it is NULL, the default parameter is used.
|
|
@param[in] Callback The callback function. This function is called if a BluetoothLE device is found during
|
|
scan process.
|
|
@param[in] Context Data passed into Callback function. This is optional parameter and may be NULL.
|
|
|
|
@retval EFI_SUCCESS The Bluetooth scan request is submitted.
|
|
@retval EFI_DEVICE_ERROR A hardware error occurred trying to scan the BluetoothLE device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BluetoothLeConfigScan (
|
|
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
|
|
IN BOOLEAN ReScan,
|
|
IN UINT32 Timeout,
|
|
IN EFI_BLUETOOTH_LE_CONFIG_SCAN_PARAMETER *ScanParameter, OPTIONAL
|
|
IN EFI_BLUETOOTH_LE_CONFIG_SCAN_CALLBACK_FUNCTION Callback,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
BTHC_DEV *BtHcDev;
|
|
LIST_ENTRY *Link;
|
|
BT_LE_DEV_INFO *BtLeDevInfo;
|
|
EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION LeScanCallbackInfo;
|
|
|
|
BtHcDev = BTHC_DEV_FROM_BLUETOOTH_LE_CONFIG_PROTOCOL(This);
|
|
BtHcDev->LeScanCallBackFunc = Callback;
|
|
BtHcDev->LeScanCallBackFuncContext = Context;
|
|
|
|
DEBUG ((EFI_D_INFO, "BluetoothLeConfigScan\n"));
|
|
if ((!ReScan) && (BtHcDev->LeScanned)) {
|
|
for ( Link = BtHcDev->BtLeDevInfoList.ForwardLink;
|
|
Link != &BtHcDev->BtLeDevInfoList;
|
|
Link = Link->ForwardLink
|
|
) {
|
|
BtLeDevInfo = CR (Link, BT_LE_DEV_INFO, Link, BT_LE_DEV_INFO_SIGNATURE);
|
|
BtLeGetScanCallBackInformation(BtHcDev, &BtLeDevInfo->BDAddr, &LeScanCallbackInfo);
|
|
BtHcDev->LeScanCallBackFunc (&BtHcDev->BluetoothLeConfig, BtHcDev->LeScanCallBackFuncContext, &LeScanCallbackInfo);
|
|
}
|
|
BtHcDev->LeScanCallBackFunc (&BtHcDev->BluetoothLeConfig, BtHcDev->LeScanCallBackFuncContext, NULL);
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
BtLeScan (BtHcDev, BtHcDev->BluetoothHc, Timeout, ScanParameter);
|
|
BtHcDev->LeScanned = TRUE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|