alder_lake_bios/Intel/AlderLake/Features/BluetoothPkg/BluetoothConnectionManagerDxe/BluetoothConnectionManagerD...

4271 lines
137 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
Bluetooth LE Connection Manager.
Copyright (c) 2013 - 2021, 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 "BluetoothConnectionManagerDxe.h"
#include <Library/PerformanceLib.h>
//
// These are the VFR compiler generated data representing our VFR data.
//
extern UINT8 BluetoothConnectionManagerBin[];
extern UINT8 BluetoothConfigDxeStrings[];
BT_CONFIG_DEV *mBtConfigDevice;
EFI_GUID gHiiBluetoothConfigFormSetGuid = HII_BLUETOOTH_CONFIG_FORM_SET_GUID;
EFI_GUID gIfrRefreshRemoteDevGuid = HII_IFR_REFRESH_REMOT_DEV_GUID;
CHAR16 mLocalDeviceDataVariableName[] = L"LocalDeviceData";
HII_VENDOR_DEVICE_PATH mBtConfigDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
}
},
HII_BLUETOOTH_CONFIG_FORM_SET_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8) (END_DEVICE_PATH_LENGTH),
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
EFI_DRIVER_BINDING_PROTOCOL gBluetoothConfigDriverBinding = {
BluetoothConfigDriverBindingSupported,
BluetoothConfigDriverBindingStart,
BluetoothConfigDriverBindingStop,
0xa,
NULL,
NULL
};
typedef struct {
BLUETOOTH_UUID Uuid;
CHAR16 *Name;
} UUID_NAME;
CHAR16 mUnknownUuidName[] = L"UnknownUUID (0x0000)";
UUID_NAME mServiceUuid16Name[] = {
{BluetoothUuidServiceDiscoveryServerServiceClassID, L"ServiceDiscoveryServerServiceClassID"},
{BluetoothUuidBrowseGroupDescriptorServiceClassID, L"BrowseGroupDescriptorServiceClassID"},
{BluetoothUuidSerialPort, L"SerialPort"},
{BluetoothUuidLANAccessUsingPPP, L"LANAccessUsingPPP"},
{BluetoothUuidDialupNetworking, L"DialupNetworking"},
{BluetoothUuidIrMCSync, L"IrMCSync"},
{BluetoothUuidOBEXObjectPush, L"OBEXObjectPush"},
{BluetoothUuidOBEXFileTransfer, L"OBEXFileTransfer"},
{BluetoothUuidIrMCSyncCommand, L"IrMCSyncCommand"},
{BluetoothUuidHeadset, L"Headset"},
{BluetoothUuidCordlessTelephony, L"CordlessTelephony"},
{BluetoothUuidAudioSource, L"AudioSource"},
{BluetoothUuidAudioSink, L"AudioSink"},
{BluetoothUuidAVRemoteControlTarget, L"AVRemoteControlTarget"},
{BluetoothUuidAdvancedAudioDistribution, L"AdvancedAudioDistribution"},
{BluetoothUuidAVRemoteControl, L"AVRemoteControl"},
{BluetoothUuidAVRemoteControlController, L"AVRemoteControlController"},
{BluetoothUuidIntercom, L"Intercom"},
{BluetoothUuidFax, L"Fax"},
{BluetoothUuidHeadsetAudioGateway, L"HeadsetAudioGateway"},
{BluetoothUuidWAP, L"WAP"},
{BluetoothUuidWAPClient, L"WAPClient"},
{BluetoothUuidPANU, L"PANU"},
{BluetoothUuidNAP, L"NAP"},
{BluetoothUuidGN, L"GN"},
{BluetoothUuidDirectPrinting, L"DirectPrinting"},
{BluetoothUuidReferencePrinting, L"ReferencePrinting"},
{BluetoothUuidBasicImagingProfile, L"BasicImagingProfile"},
{BluetoothUuidImagingResponder, L"ImagingResponder"},
{BluetoothUuidImagingAutomaticArchive, L"ImagingAutomaticArchive"},
{BluetoothUuidImagingReferencedObjects, L"ImagingReferencedObjects"},
{BluetoothUuidHandsfree, L"Handsfree"},
{BluetoothUuidHandsfreeAudioGateway, L"HandsfreeAudioGateway"},
{BluetoothUuidDirectPrintingReferenceObjectsService, L"DirectPrintingReferenceObjectsService"},
{BluetoothUuidReflectedUI, L"ReflectedUI"},
{BluetoothUuidBasicPrinting, L"BasicPrinting"},
{BluetoothUuidPrintingStatus, L"PrintingStatus"},
{BluetoothUuidHumanInterfaceDeviceService, L"HumanInterfaceDeviceService"},
{BluetoothUuidHardcopyCableReplacement, L"HardcopyCableReplacement"},
{BluetoothUuidHCRPrint, L"HCRPrint"},
{BluetoothUuidHCRScan, L"HCRScan"},
{BluetoothUuidCommonISDNAccess, L"CommonISDNAccess"},
{BluetoothUuidSIMAccess, L"SIMAccess"},
{BluetoothUuidPhonebookAccessPCE, L"PhonebookAccessPCE"},
{BluetoothUuidPhonebookAccessPSE, L"PhonebookAccessPSE"},
{BluetoothUuidPhonebookAccess, L"PhonebookAccess"},
{BluetoothUuidHeadsetHS, L"HeadsetHS"},
{BluetoothUuidMessageAccessServer, L"MessageAccessServer"},
{BluetoothUuidMessageNotificationServer, L"MessageNotificationServer"},
{BluetoothUuidMessageAccessProfile, L"MessageAccessProfile"},
{BluetoothUuidGNSS, L"GNSS"},
{BluetoothUuidGNSSServer, L"GNSSServer"},
{BluetoothUuid3DDisplay, L"3DDisplay"},
{BluetoothUuid3DGlasses, L"3DGlasses"},
{BluetoothUuid3DSynchronization, L"3DSynchronization"},
{BluetoothUuidMPSProfile, L"MPSProfile"},
{BluetoothUuidMPSSC, L"MPSSC"},
{BluetoothUuidPnPInformation, L"PnPInformation"},
{BluetoothUuidGenericNetworking, L"GenericNetworking"},
{BluetoothUuidGenericFileTransfer, L"GenericFileTransfer"},
{BluetoothUuidGenericAudio, L"GenericAudio"},
{BluetoothUuidGenericTelephony, L"GenericTelephony"},
{BluetoothUuidUPNPService, L"UPNPService"},
{BluetoothUuidUPNPIPService, L"UPNPIPService"},
{BluetoothUuidESDPUPNPIPPAN, L"ESDPUPNPIPPAN"},
{BluetoothUuidESDPUPNPIPLAP, L"ESDPUPNPIPLAP"},
{BluetoothUuidESDPUPNPL2CAP, L"ESDPUPNPL2CAP"},
{BluetoothUuidVideoSource, L"VideoSource"},
{BluetoothUuidVideoSink, L"VideoSink"},
{BluetoothUuidVideoDistribution, L"VideoDistribution"},
{BluetoothUuidHDP, L"HDP"},
{BluetoothUuidHDPSource, L"HDPSource"},
{BluetoothUuidHDPSink, L"HDPSink"},
{BluetoothUuidPublicBrowseRoot, L"PublicBrowseRoot"},
{BluetoothUuidAlertNotificationService, L"AlertNotificationService"},
{BluetoothUuidAutomationIO, L"AutomationIO"},
{BluetoothUuidBatteryService, L"BatteryService"},
{BluetoothUuidBloodPressure, L"BloodPressure"},
{BluetoothUuidBodyComposition, L"BodyComposition"},
{BluetoothUuidBondManagement, L"BondManagement"},
{BluetoothUuidContinuousGlucoseMonitoring, L"ContinuousGlucoseMonitoring"},
{BluetoothUuidCurrentTimeService, L"CurrentTimeService"},
{BluetoothUuidCyclingPower, L"CyclingPower"},
{BluetoothUuidCyclingSpeedandCadence, L"CyclingSpeedandCadence"},
{BluetoothUuidDeviceInformation, L"DeviceInformation"},
{BluetoothUuidEnvironmentalSensing, L"EnvironmentalSensing"},
{BluetoothUuidGenericAccess, L"GenericAccess"},
{BluetoothUuidGenericAttribute, L"GenericAttribute"},
{BluetoothUuidGlucose, L"Glucose"},
{BluetoothUuidHealthThermometer, L"HealthThermometer"},
{BluetoothUuidHeartRate, L"HeartRate"},
{BluetoothUuidHTTPProxy, L"HTTPProxy"},
{BluetoothUuidHumanInterfaceDevice, L"HumanInterfaceDevice"},
{BluetoothUuidImmediateAlert, L"ImmediateAlert"},
{BluetoothUuidIndoorPositioning, L"IndoorPositioning"},
{BluetoothUuidInternetProtocolSupport, L"InternetProtocolSupport"},
{BluetoothUuidLinkLoss, L"LinkLoss"},
{BluetoothUuidLocationandNavigation, L"LocationandNavigation"},
{BluetoothUuidNextDSTChangeService, L"NextDSTChangeService"},
{BluetoothUuidObjectTransfer, L"ObjectTransfer"},
{BluetoothUuidPhoneAlertStatusService, L"PhoneAlertStatusService"},
{BluetoothUuidPulseOximeter, L"PulseOximeter"},
{BluetoothUuidReferenceTimeUpdateService, L"ReferenceTimeUpdateService"},
{BluetoothUuidRunningSpeedandCadence, L"RunningSpeedandCadence"},
{BluetoothUuidScanParameters, L"ScanParameters"},
{BluetoothUuidTransportDiscovery, L"TransportDiscovery"},
{BluetoothUuidTxPower, L"TxPower"},
{BluetoothUuidUserData, L"UserData"},
{BluetoothUuidWeightScale, L"WeightScale"},
};
/**
Connects all controllers with EFI Bluetooth ATTRIBUTE service binding
protocol recursively.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context The pointer to the notification function's context,
which is implementation-dependent.
**/
VOID
EFIAPI
StartDeviceDrivers (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_HANDLE *HandleBuffer;
UINTN NumberOfHandles;
UINTN Index;
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiBluetoothAttributeServiceBindingProtocolGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
for (Index = 0; Index < NumberOfHandles; Index++) {
gBS->ConnectController (
HandleBuffer[Index],
NULL,
NULL,
TRUE
);
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
}
/**
Checks whether a given Bluetooth device address is valid or not.
@param[in] Address A pointer to a Bluetooth device address to check.
@retval TRUE The given Bluetooth device address is valid.
@retval FALSE The given Bluetooth device address is not valid.
**/
BOOLEAN
IsValidBleAddress (
IN BLUETOOTH_LE_ADDRESS *Address
)
{
BLUETOOTH_LE_ADDRESS NullAddress;
ASSERT (Address != NULL);
ZeroMem (&NullAddress, sizeof(BLUETOOTH_LE_ADDRESS));
return (BOOLEAN) (CompareMem (Address, &NullAddress, sizeof (BLUETOOTH_LE_ADDRESS)) != 0);
}
/**
Finds a specific type of Generic Access Profile data from the Bluetooth LE
advertisement data.
@param[in] AdvertisementData A pointer to the BluetoothLE advertisement
data.
@param[in] AdvertisementDataSize The size of AdvertisementData in bytes.
@param[in] Type The given type of Generic Access Profile
data to find in AdvertisementData.
@retval NULL If the given type is not found in AdvertisementData.
@retval Others Points to start of the given type in AdvertisementData.
**/
UINT8 *
FindTypeFromAdvertisementData (
IN UINT8 *AdvertisementData,
IN UINTN AdvertisementDataSize,
IN UINT8 Type
)
{
UINT8 *Data;
Data = AdvertisementData;
while (Data < AdvertisementData + AdvertisementDataSize) {
if (*Data == 0) {
break;
}
if (*(Data + 1) == Type) {
return Data;
}
Data += (*Data + 1);
}
return NULL;
}
/**
Get detail info for host controller.
The caller need to free the buffer after using it.
@param BluetoothLeConfig BluetoothLE config protocol for this device.
@param DataType Type for the infor which need to get.
@param DataSize Return the size of the return buffer.
@param Data Return the data for this info.
@retval EFI_SUCCESS The image has been unloaded.
**/
EFI_STATUS
GetInfoFromHandle (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *BluetoothLeConfig,
IN EFI_BLUETOOTH_CONFIG_DATA_TYPE DataType,
IN OUT UINTN *DataSize,
IN OUT VOID **Data OPTIONAL
)
{
EFI_STATUS Status;
UINTN BufferSize;
UINT8 *Buffer;
if ((BluetoothLeConfig == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
return EFI_INVALID_PARAMETER;
}
if (DataType >= EfiBluetoothConfigDataTypeMax) {
return EFI_NOT_FOUND;
}
*DataSize = 0;
BufferSize = 0;
Buffer = NULL;
Status = BluetoothLeConfig->GetData (BluetoothLeConfig, DataType, &BufferSize, Buffer);
if (Status != EFI_BUFFER_TOO_SMALL) {
return Status;
}
Buffer = AllocatePool (BufferSize);
ASSERT (Buffer != NULL);
Status = BluetoothLeConfig->GetData (BluetoothLeConfig, DataType, &BufferSize, Buffer);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
*DataSize = BufferSize;
*Data = Buffer;
return EFI_SUCCESS;
}
/**
Locate the device from device list based on the MAC address.
@param[in] Addr Input device address.
@param[in] AddressType Address type.
@return The device
**/
BT_REMOTE_DEVICE_ATTRIBUTE *
LocateDevInList (
IN UINT8 *Addr,
IN EFI_BLUETOOTH_ADDRESS_TYPE AddressType
)
{
LIST_ENTRY *Link;
BT_REMOTE_DEVICE_ATTRIBUTE *Dev;
ASSERT (AddressType < EfiInvalidAddressType);
for ( Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList)
; !IsNull (&mBtConfigDevice->RemoteDeviceList, Link)
; Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link)) {
Dev = BT_REMOTE_DEVICE_FROM_LINK (Link);
switch (AddressType) {
case EfiIdentifyAddressType:
if (CompareMem (Addr, Dev->IDAddr.Address, sizeof (Dev->IDAddr.Address)) == 0) {
return Dev;
}
break;
case EfiAdvertisementAddressType:
if (CompareMem (Addr, Dev->AdvAddr.Address, sizeof (Dev->AdvAddr.Address)) == 0) {
return Dev;
}
break;
default:
ASSERT(AddressType == EfiAnyAddressType);
if (((CompareMem (Addr, Dev->AdvAddr.Address, sizeof (Dev->AdvAddr.Address)) == 0)) ||
((CompareMem (Addr, Dev->IDAddr.Address, sizeof (Dev->IDAddr.Address)) == 0))) {
return Dev;
}
break;
}
}
return NULL;
}
/**
Locate the device from Paired device storage based on the MAC address.
@param[in] IDAddr Input device address. It's Identify address.
@param[in, out] Index The index in the device array.
@return The device storage.
**/
BT_LE_REMOTE_DEV_STORAGE *
LocateDevInGlobalData (
IN BLUETOOTH_LE_ADDRESS *IDAddr,
IN OUT UINTN *Index
)
{
UINTN Count;
for (Count = 0; Count < EFI_BLUETOOTH_LE_MAX_BONDED_DEV; Count++) {
if (CompareMem (IDAddr->Address, &mBtConfigDevice->ControllerData.RemoteIDAddr[Count].Address, sizeof (IDAddr->Address)) == 0) {
if (Index != NULL) {
*Index = Count;
}
return &mBtConfigDevice->PairedDevData[Count];
}
}
return NULL;
}
/**
Refresh the device information.
@param[in] Dev Pointer to the new device.
@param[in] ScanInfo Data related to scan result.
**/
VOID
RefreshDeviceInformation (
IN BT_REMOTE_DEVICE_ATTRIBUTE *Dev,
IN EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION *ScanInfo
)
{
UINT8 Len;
UINT8 *Data;
Dev->RSSI = ScanInfo->RSSI;
//
// ID matches but BD might not match. So update it.
//
CopyMem (&Dev->AdvAddr, &ScanInfo->BDAddr.Address, sizeof(BLUETOOTH_LE_ADDRESS));
Data = BluetoothFindTypeFromAdvData (ScanInfo->AdvertisementData, ScanInfo->AdvertisementDataSize, BluetoothGapTypeCompleteLocalName, &Len);
if (Data != NULL) {
ZeroMem(Dev->LocalName, sizeof(Dev->LocalName));
CopyMem (Dev->LocalName, Data, MIN (Len, sizeof (Dev->LocalName) - 1));
}
Data = BluetoothFindTypeFromAdvData (ScanInfo->AdvertisementData, ScanInfo->AdvertisementDataSize, BluetoothGapTypeAppearance, &Len);
if (Data != NULL) {
Dev->Appearance = *((UINT16*)Data);
}
}
/**
Dump the data.
@param[in] ScanInfo Data related to scan result.
**/
VOID
DumpScanInfo (
IN EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION *ScanInfo
)
{
UINTN Index;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: ScanInfo from %02x:%02x:%02x:%02x:%02x:%02x(%x)",
ScanInfo->BDAddr.Address[0], ScanInfo->BDAddr.Address[1],
ScanInfo->BDAddr.Address[2], ScanInfo->BDAddr.Address[3],
ScanInfo->BDAddr.Address[4], ScanInfo->BDAddr.Address[5],
ScanInfo->BDAddr.Type
));
DEBUG ((DEBUG_INFO, "/%02x:%02x:%02x:%02x:%02x:%02x(%x), ",
ScanInfo->DirectAddress.Address[0], ScanInfo->DirectAddress.Address[1],
ScanInfo->DirectAddress.Address[2], ScanInfo->DirectAddress.Address[3],
ScanInfo->DirectAddress.Address[4], ScanInfo->DirectAddress.Address[5],
ScanInfo->DirectAddress.Type
));
DEBUG ((DEBUG_INFO, "State/dBm/DataSize = %x/%d/%x\n",
ScanInfo->RemoteDeviceState,
ScanInfo->RSSI,
ScanInfo->AdvertisementDataSize
));
for (Index = 0; Index < ScanInfo->AdvertisementDataSize; ) {
DEBUG ((DEBUG_INFO, " %02x", ((UINT8*)ScanInfo->AdvertisementData)[Index]));
Index++;
if ((Index % 0x10) == 0) {
DEBUG ((DEBUG_INFO, "\n"));
}
}
if ((Index % 0x10) != 0) {
DEBUG ((DEBUG_INFO, "\n"));
}
}
/**
Dump remote device list information.
**/
VOID
DumpRemoteDeviceList (
VOID
)
{
LIST_ENTRY *Link;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
UINTN Index;
Index = 0;
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Dump Remote Device List Begin:\n"));
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
for ( Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList)
; !IsNull (&mBtConfigDevice->RemoteDeviceList, Link)
; Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link)
) {
RemoteDev = BT_REMOTE_DEVICE_FROM_LINK(Link);
DEBUG ((DEBUG_INFO, " %02d - %02x:%02x:%02x:%02x:%02x:%02x(%x)",
Index,
RemoteDev->AdvAddr.Address[0], RemoteDev->AdvAddr.Address[1],
RemoteDev->AdvAddr.Address[2], RemoteDev->AdvAddr.Address[3],
RemoteDev->AdvAddr.Address[4], RemoteDev->AdvAddr.Address[5],
RemoteDev->AdvAddr.Type
));
DEBUG ((DEBUG_INFO, "/%02x:%02x:%02x:%02x:%02x:%02x(%x), ",
RemoteDev->IDAddr.Address[0], RemoteDev->IDAddr.Address[1],
RemoteDev->IDAddr.Address[2], RemoteDev->IDAddr.Address[3],
RemoteDev->IDAddr.Address[4], RemoteDev->IDAddr.Address[5],
RemoteDev->IDAddr.Type
));
DEBUG ((DEBUG_INFO, "State/dBm/Appearance/Name = %x/%d/%x/%a\n",
RemoteDev->RemoteDeviceState,
RemoteDev->RSSI,
RemoteDev->Appearance,
RemoteDev->LocalName
));
Index ++;
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
}
/**
Callback function used by bus driver to inform new device founded.
@param[in] This Blue tooth config protocol for this device.
@param[in] Context Context used by caller.
@param[in] ScanInfo Data related to scan result. NULL ScanInfo means scan
complete.
@retval EFI_SUCCESS The image has been unloaded.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
**/
EFI_STATUS
EFIAPI
ScanCallback (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN VOID *Context,
IN EFI_BLUETOOTH_LE_SCAN_CALLBACK_INFORMATION *ScanInfo
)
{
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDevAttr;
if (!mBtConfigDevice->InScanning) {
DEBUG ((DEBUG_ERROR, "BtCfgDxe :: Scan callback trigged not during scanning!!!\n"));
}
mBtConfigDevice->FoundNewDevice = TRUE;
gBS->SignalEvent (mBtConfigDevice->RefreshRemoteDevEvent);
if (ScanInfo == NULL) {
//
// NULL ScanInfo indicates scan is finished.
//
mBtConfigDevice->UpdateScanMenu = TRUE;
mBtConfigDevice->InScanning = FALSE;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: !!! Scan finished !!!\n"));
DumpRemoteDeviceList();
return EFI_SUCCESS;
}
DumpScanInfo (ScanInfo);
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
RemoteDevAttr = LocateDevInList (ScanInfo->BDAddr.Address, EfiAdvertisementAddressType);
if (RemoteDevAttr != NULL) {
//
// Refresh information for existing device.
//
RefreshDeviceInformation(RemoteDevAttr, ScanInfo);
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Refresh device in list in scanning: %02x:%02x:%02x:%02x:%02x:%02x(%x), Name : %a\n",
RemoteDevAttr->AdvAddr.Address[0], RemoteDevAttr->AdvAddr.Address[1],
RemoteDevAttr->AdvAddr.Address[2], RemoteDevAttr->AdvAddr.Address[3],
RemoteDevAttr->AdvAddr.Address[4], RemoteDevAttr->AdvAddr.Address[5],
RemoteDevAttr->AdvAddr.Type,
RemoteDevAttr->LocalName
));
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
return EFI_SUCCESS;
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
//
// A new device is found in scanning.
//
RemoteDevAttr = AllocateZeroPool (sizeof (BT_REMOTE_DEVICE_ATTRIBUTE));
if (RemoteDevAttr == NULL){
return EFI_OUT_OF_RESOURCES;
}
RemoteDevAttr->Signature = BT_REMOTE_DEVICE_SIGNATURE;
RefreshDeviceInformation(RemoteDevAttr, ScanInfo);
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
InsertTailList (&mBtConfigDevice->RemoteDeviceList, &RemoteDevAttr->Link);
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Add device to List in scanning: %02x:%02x:%02x:%02x:%02x:%02x(%x), Name : %a\n",
RemoteDevAttr->AdvAddr.Address[0], RemoteDevAttr->AdvAddr.Address[1],
RemoteDevAttr->AdvAddr.Address[2], RemoteDevAttr->AdvAddr.Address[3],
RemoteDevAttr->AdvAddr.Address[4], RemoteDevAttr->AdvAddr.Address[5],
RemoteDevAttr->AdvAddr.Type,
RemoteDevAttr->LocalName
));
return EFI_SUCCESS;
}
/**
Dump remote device data structure.
@param[in] RemoteDevData Remote device data structure.
**/
VOID
DumpRemoteDeviceData (
IN BT_LE_REMOTE_DEV_STORAGE *RemoteDevData
)
{
UINTN Count;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Dump RemoteDevData begin:\n"));
DEBUG ((DEBUG_INFO, " PeerName: %a\n", RemoteDevData->PeerName));
DEBUG ((DEBUG_INFO, " KeysDistributed: 0x%x\n", RemoteDevData->KeysDistributed));
DEBUG ((DEBUG_INFO, " KeySize: 0x%x\n", RemoteDevData->KeySize));
DEBUG ((DEBUG_INFO, " AuthReq: 0x%x\n", RemoteDevData->AuthReq));
DEBUG ((DEBUG_INFO, " PeerEdiv: 0x%x\n", RemoteDevData->PeerEdiv));
DEBUG ((DEBUG_INFO, " PeerSignCounter: 0x%x\n", RemoteDevData->PeerSignCounter));
DEBUG ((DEBUG_INFO, " LocalSignCounter: 0x%x\n",RemoteDevData->LocalSignCounter));
DEBUG ((DEBUG_INFO, " PeerLtk:"));
for (Count = 0; Count < sizeof (RemoteDevData->PeerLtk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->PeerLtk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " PeerIrk:"));
for (Count = 0; Count < sizeof (RemoteDevData->PeerIrk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->PeerIrk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " PeerCsrk:"));
for (Count = 0; Count < sizeof (RemoteDevData->PeerCsrk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->PeerCsrk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " PeerRand:"));
for (Count = 0; Count < sizeof (RemoteDevData->PeerRand); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->PeerRand[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " LocalLtk:"));
for (Count = 0; Count < sizeof (RemoteDevData->LocalLtk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->LocalLtk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " LocalIrk:"));
for (Count = 0; Count < sizeof (RemoteDevData->LocalIrk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->LocalIrk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " LocalCsrk:"));
for (Count = 0; Count < sizeof (RemoteDevData->LocalCsrk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", RemoteDevData->LocalCsrk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
}
/**
Dump local device data structure.
@param[in] LocalData Local device data structure.
**/
VOID
DumpLocalDeviceData (
IN BT_LE_LOCAL_DEV_STORAGE *LocalData
)
{
UINTN Count;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Dump LocalDeviceData (%a) begin:\n Irk:", LocalData->LocalName));
for (Count = 0; Count < sizeof (LocalData->KeyIrk); Count++) {
DEBUG ((DEBUG_INFO, " %02x", LocalData->KeyIrk[Count]));
}
DEBUG ((DEBUG_INFO, "\n"));
for (Count = 0; Count < EFI_BLUETOOTH_LE_MAX_BONDED_DEV; Count++) {
if (IsValidBleAddress (&LocalData->RemoteIDAddr[Count])) {
DEBUG ((DEBUG_INFO, " %02x - %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
Count,
LocalData->RemoteIDAddr[Count].Address[0],
LocalData->RemoteIDAddr[Count].Address[1],
LocalData->RemoteIDAddr[Count].Address[2],
LocalData->RemoteIDAddr[Count].Address[3],
LocalData->RemoteIDAddr[Count].Address[4],
LocalData->RemoteIDAddr[Count].Address[5],
LocalData->RemoteIDAddr[Count].Type));
}
}
}
/**
Dump advertisement data.
@param[in] AdvertisementData A pointer to the BluetoothLE advertisement data.
@param[in] AdvertisementDataSize The size of AdvertisementData in bytes.
**/
VOID
DumpAdvertisementData (
IN UINT8 *AdvertisementData,
IN UINT32 AdvertisementDataSize
)
{
UINTN Count;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Dump Advertisement Data: Length = 0x%x\n", AdvertisementDataSize));
for (Count = 0; Count < AdvertisementDataSize; ) {
DEBUG ((DEBUG_INFO, " %02x", AdvertisementData[Count]));
Count++;
if (Count % 16 == 0) {
DEBUG ((DEBUG_INFO, "\n"));
}
}
DEBUG ((DEBUG_INFO, "\n"));
}
/**
Delete the specified device from global data and storage.
@param[in] RemoteIDAddr Remote device address. Input the Identify Address.
@param[in] DeleteStorage Delete related storage or not.
**/
EFI_STATUS
DeletePairedDevice (
IN BLUETOOTH_LE_ADDRESS *RemoteIDAddr,
IN BOOLEAN DeleteStorage
)
{
EFI_STATUS Status;
UINTN LocalDataSize;
UINTN Index;
CHAR16 RemoteBdAddrStr[LE_BD_ADDR_STR_LEN];
BT_LE_REMOTE_DEV_STORAGE *RemoteData;
DumpLocalDeviceData (&mBtConfigDevice->ControllerData);
RemoteData = LocateDevInGlobalData (RemoteIDAddr, &Index);
if (RemoteData == NULL) {
DEBUG ((EFI_D_ERROR , "BtCfgDxe :: Device is not in LocalDeviceData (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
return EFI_NOT_FOUND;
}
ZeroMem (RemoteData, sizeof (BT_LE_REMOTE_DEV_STORAGE));
ZeroMem (&mBtConfigDevice->ControllerData.RemoteIDAddr[Index], sizeof (BLUETOOTH_LE_ADDRESS));
if (!DeleteStorage) {
return EFI_SUCCESS;
}
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->SetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LocalDataSize,
&mBtConfigDevice->ControllerData);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR , "BtCfgDxe :: Failed to delete device in LocalDeviceData (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
return EFI_ACCESS_DENIED;
}
ZeroMem(RemoteBdAddrStr, sizeof(RemoteBdAddrStr));
LE_BDADDR_TO_STRING(RemoteBdAddrStr, RemoteIDAddr->Address, RemoteIDAddr->Type);
Status = gRT->SetVariable(RemoteBdAddrStr,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
0,
NULL);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR , "BtCfgDxe :: Can't delete device local stoage (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
return EFI_ACCESS_DENIED;
}
mBtConfigDevice->PairedDevDataSaved[Index] = FALSE;
mBtConfigDevice->PairedDevCount--;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: SUCCESS delete device in local data and stoage (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
return EFI_SUCCESS;
}
/**
Save the specified device to storage.
@param[in] RemoteIDAddr Remote device address. Input the identify address.
**/
EFI_STATUS
SavePairedDevice (
IN BLUETOOTH_LE_ADDRESS *RemoteIDAddr
)
{
CHAR16 RemoteBdAddrStr[LE_BD_ADDR_STR_LEN];
UINTN RemoteDataSize;
UINTN LocalDataSize;
UINTN Index;
BT_LE_REMOTE_DEV_STORAGE *RemoteData;
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Begin to save Device %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
DumpLocalDeviceData (&mBtConfigDevice->ControllerData);
RemoteData = LocateDevInGlobalData (RemoteIDAddr, &Index);
if (RemoteData == NULL) {
DEBUG ((DEBUG_ERROR, "BtCfgDxe :: Device not found in the maintained storage!"));
return EFI_NOT_FOUND;
}
DumpRemoteDeviceData (RemoteData);
ZeroMem(RemoteBdAddrStr, sizeof(RemoteBdAddrStr));
LE_BDADDR_TO_STRING(RemoteBdAddrStr, RemoteIDAddr->Address, RemoteIDAddr->Type);
RemoteDataSize = sizeof(BT_LE_REMOTE_DEV_STORAGE);
Status = gRT->SetVariable(RemoteBdAddrStr,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
RemoteDataSize,
RemoteData);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Add new storage for Device = %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
RemoteIDAddr->Address[0], RemoteIDAddr->Address[1],
RemoteIDAddr->Address[2], RemoteIDAddr->Address[3],
RemoteIDAddr->Address[4], RemoteIDAddr->Address[5],
RemoteIDAddr->Type));
}
//
// Saved this device before means this devcie already saved in
// LocalDeviceData, so skip to save in LocalDeviceData.
//
if (mBtConfigDevice->PairedDevDataSaved[Index]) {
return EFI_SUCCESS;
}
mBtConfigDevice->PairedDevDataSaved[Index] = TRUE;
mBtConfigDevice->PairedDevCount++;
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->SetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LocalDataSize,
&mBtConfigDevice->ControllerData);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
/**
Connect device.
@param[in] RemoteDev Disconnect the device specified.
**/
VOID
ConnectDevice (
IN BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev
)
{
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
BLUETOOTH_LE_ADDRESS *BleAddress;
LeConfigProtocol = mBtConfigDevice->BluetoothLeConfig;
mBtConfigDevice->CurrentBondingDev = RemoteDev;
if (IsValidBleAddress(&RemoteDev->IDAddr)) {
mBtConfigDevice->CurrentBondingIDAddress = TRUE;
BleAddress = &RemoteDev->IDAddr;
} else {
mBtConfigDevice->CurrentBondingIDAddress = FALSE;
BleAddress = &RemoteDev->AdvAddr;
}
ASSERT (mBtConfigDevice->ConnectState == StateIdle);
//
// Change BluetoothPhaseType to StateConnecting to let later while code to wait for the connect return.
//
mBtConfigDevice->ConnectState = StateConnecting;
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Connect Device: %a, IDAddr: %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
RemoteDev->LocalName,
BleAddress->Address[0], BleAddress->Address[1],
BleAddress->Address[2], BleAddress->Address[3],
BleAddress->Address[4], BleAddress->Address[5],
BleAddress->Type
));
LeConfigProtocol->Connect (LeConfigProtocol, TRUE, TRUE, 0, BleAddress);
do {} while (mBtConfigDevice->ConnectState == StateConnecting);
ASSERT (mBtConfigDevice->ConnectState == StateIdle);
mBtConfigDevice->CurrentBondingDev = NULL;
}
/**
Disconnect device.
@param[in] RemoteDev Disconnect the device specified.
@param[in] Reason Bluetooth disconnect reason.
**/
VOID
DisconnectDevice (
IN BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev,
IN UINT8 Reason
)
{
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
BLUETOOTH_LE_ADDRESS *BleAddress;
ASSERT (mBtConfigDevice->ConnectState == StateIdle);
ASSERT ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED) != 0);
LeConfigProtocol = mBtConfigDevice->BluetoothLeConfig;
mBtConfigDevice->CurrentBondingDev = RemoteDev;
if (IsValidBleAddress(&RemoteDev->IDAddr)) {
mBtConfigDevice->CurrentBondingIDAddress = TRUE;
BleAddress = &RemoteDev->IDAddr;
} else {
mBtConfigDevice->CurrentBondingIDAddress = FALSE;
BleAddress = &RemoteDev->AdvAddr;
}
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Disconnect Device[%x]: %a, IDAddr: %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
RemoteDev->RemoteDeviceState,
RemoteDev->LocalName,
BleAddress->Address[0], BleAddress->Address[1],
BleAddress->Address[2], BleAddress->Address[3],
BleAddress->Address[4], BleAddress->Address[5],
BleAddress->Type
));
//
// Change BluetoothPhaseType to StateDisconnecting to let later while code to wait for the disconnect return.
//
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) != 0) {
mBtConfigDevice->ConnectState = StateDisconnecting;
}
//
// Even if device is disconnected, still call it to let iLE stack remove this device from auto reconnect list.
//
LeConfigProtocol->Disconnect (LeConfigProtocol, BleAddress, Reason);
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) != 0) {
//
// Wait until LinkConnCompCallback transfer from StateDisconnecting to StateIdle.
//
do {} while (mBtConfigDevice->ConnectState == StateDisconnecting);
}
ASSERT (mBtConfigDevice->ConnectState == StateIdle);
mBtConfigDevice->CurrentBondingDev = NULL;
}
/**
Delete the specified device from device list.
@param[in] IDAddr A pointer to a Bluetooth device address to delete.
Address is Identify address.
**/
VOID
DeleteRemoteDeviceByAddress (
IN BLUETOOTH_LE_ADDRESS *IDAddr
)
{
LIST_ENTRY *Link;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
ASSERT (IDAddr != NULL);
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList);
while (!IsNull (&mBtConfigDevice->RemoteDeviceList, Link)) {
RemoteDev = BT_REMOTE_DEVICE_FROM_LINK (Link);
Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link);
if (CompareMem (RemoteDev->IDAddr.Address, IDAddr->Address, sizeof (IDAddr->Address)) == 0) {
RemoveEntryList (&RemoteDev->Link);
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
DEBUG ((EFI_D_INFO, "BtCfgDxe :: User request Delete device: %02x:%02x:%02x:%02x:%02x:%02x(%x) (%a)\n",
RemoteDev->IDAddr.Address[0], RemoteDev->IDAddr.Address[1],
RemoteDev->IDAddr.Address[2], RemoteDev->IDAddr.Address[3],
RemoteDev->IDAddr.Address[4], RemoteDev->IDAddr.Address[5],
RemoteDev->IDAddr.Type,
RemoteDev->LocalName
));
DeletePairedDevice (&RemoteDev->IDAddr, TRUE);
FreePool (RemoteDev);
return;
}
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
DEBUG ((EFI_D_ERROR, "BtCfgDxe :: Not found device in List %02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
IDAddr->Address[0], IDAddr->Address[1],
IDAddr->Address[2], IDAddr->Address[3],
IDAddr->Address[4], IDAddr->Address[5],
IDAddr->Type));
DumpRemoteDeviceList ();
}
/**
Delete the specified device from Device state
@param[in] DeviceState Specify the device state. Idle/connect/paired.
**/
VOID
DeleteRemoteDeviceByState (
IN UINT32 DeviceState
)
{
LIST_ENTRY *Link;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList);
while (!IsNull (&mBtConfigDevice->RemoteDeviceList, Link)) {
RemoteDev = BT_REMOTE_DEVICE_FROM_LINK (Link);
Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link);
if (RemoteDev->RemoteDeviceState == DeviceState) {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: User request to Delete device: %02x:%02x:%02x:%02x:%02x:%02x(%x) (%a)\n",
RemoteDev->AdvAddr.Address[0], RemoteDev->AdvAddr.Address[1],
RemoteDev->AdvAddr.Address[2], RemoteDev->AdvAddr.Address[3],
RemoteDev->AdvAddr.Address[4], RemoteDev->AdvAddr.Address[5],
RemoteDev->AdvAddr.Type,
RemoteDev->LocalName
));
RemoveEntryList (&RemoteDev->Link);
FreePool (RemoteDev);
}
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
}
/**
Gets an string that contains the address information of the host controller.
@param[in] ConfigProtocol A pointer to EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
structure.
@param[out] DevAddress A pointer to an string which contains the
address information of the host controller.
@retval Other A value from other functions.
@retval EFI_SUCCESS The host controller address string is returned.
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
**/
EFI_STATUS
GetDeviceAddress (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *ConfigProtocol,
OUT CHAR16 **DevAddress
)
{
EFI_STATUS Status;
UINTN DataSize;
UINT8 *Buffer;
BLUETOOTH_LE_ADDRESS *LeAddr;
DataSize = 0;
Buffer = NULL;
Status = GetInfoFromHandle(ConfigProtocol, EfiBluetoothConfigDataTypeBDADDR, &DataSize, (void**)&Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
if(Buffer == NULL){
return EFI_NOT_FOUND;
}
LeAddr = (BLUETOOTH_LE_ADDRESS *) Buffer;
*DevAddress = AllocateZeroPool (DataSize * sizeof (CHAR16) * 3);
ASSERT (*DevAddress != NULL);
UnicodeSPrint (
*DevAddress,
DataSize * sizeof (CHAR16) * 3,
L"%02x-%02x-%02x-%02x-%02x-%02x",
(UINTN)LeAddr->Address[0],
(UINTN)LeAddr->Address[1],
(UINTN)LeAddr->Address[2],
(UINTN)LeAddr->Address[3],
(UINTN)LeAddr->Address[4],
(UINTN)LeAddr->Address[5]
);
FreePool (Buffer);
return EFI_SUCCESS;
}
/**
Gets an string that contains the device name of the host controller.
@param[in] ConfigProtocol A pointer to EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
structure.
@param[out] LocalName A pointer to an string which contains the
device name of the host controller.
@retval EFI_SUCCESS The host controller device name is returned.
@retval Other A value from other functions.
**/
EFI_STATUS
GetLocalName (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *ConfigProtocol,
OUT CHAR16 **LocalName
)
{
EFI_STATUS Status;
UINTN DataSize;
UINT8 *Buffer;
CHAR16 *UniDeviceName;
DataSize = 0;
Buffer = NULL;
Status = EFI_SUCCESS;
Status = GetInfoFromHandle(ConfigProtocol, EfiBluetoothConfigDataTypeDeviceName, &DataSize, (void**)&Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
if (DataSize == 0) {
//
// Device Name is NULL, get the Address.
//
Status = GetDeviceAddress (ConfigProtocol, &UniDeviceName);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Get local name from %a\n", Buffer));
UniDeviceName = AllocateZeroPool (DataSize * sizeof (CHAR16));
ASSERT (UniDeviceName != NULL);
AsciiStrToUnicodeStrS ((const CHAR8*)Buffer, UniDeviceName, DataSize);
}
*LocalName = UniDeviceName;
FreePool (Buffer);
return EFI_SUCCESS;
}
/**
Sets the device name of the host controller with a given string.
@param[in] ConfigProtocol A pointer to EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
structure.
@param[in] LocalName A pointer to an string that will be set as the
device name of the host controller.
@retval Other A value from other functions.
**/
EFI_STATUS
SetLocalName (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *ConfigProtocol,
IN CHAR16 *LocalName
)
{
CHAR8 *AsciiName;
EFI_STATUS Status;
UINTN LocalDataSize;
UINTN MaxStrLen;
MaxStrLen = StrLen (LocalName) + 1;
AsciiName = AllocateZeroPool (MaxStrLen);
ASSERT (AsciiName != NULL);
UnicodeStrToAsciiStrS(LocalName, AsciiName, MaxStrLen);
AsciiStrCpyS((CHAR8 *)mBtConfigDevice->ControllerData.LocalName, sizeof (mBtConfigDevice->ControllerData.LocalName), AsciiName);
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->SetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LocalDataSize,
&mBtConfigDevice->ControllerData);
ASSERT_EFI_ERROR (Status);
return ConfigProtocol->SetData (ConfigProtocol, EfiBluetoothConfigDataTypeDeviceName, AsciiStrnLenS (AsciiName, MaxStrLen), AsciiName);
}
/**
Update the question value input in Callback function.
@param Type The input value type.
@param Value The input value buffer.
@param RetValue The value need to return.
**/
VOID
GetInputValue (
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT UINT64 *RetValue
)
{
switch (Type) {
case EFI_IFR_TYPE_NUM_SIZE_8:
*RetValue = Value->u8;
break;
case EFI_IFR_TYPE_NUM_SIZE_16:
*RetValue = Value->u16;
break;
case EFI_IFR_TYPE_NUM_SIZE_32:
*RetValue = Value->u32;
break;
case EFI_IFR_TYPE_NUM_SIZE_64:
*RetValue = Value->u64;
break;
case EFI_IFR_TYPE_BOOLEAN:
*RetValue = Value->b;
break;
case EFI_IFR_TYPE_STRING:
*RetValue = Value->string;
break;
default:
break;
}
}
CHAR16 *mRssiStr[] = {
L"*****",
L"****-",
L"***--",
L"**---",
L"*----",
L"-----"
};
/**
Genereate signal level base on RSSI value.
The valid RSSI value from -128 ~ 0, higher is better.
@param RSSI RSSI value.
@retval String Return the string about signal level.
**/
CHAR16 *
RssiToString (
IN INT8 RSSI
)
{
ASSERT (RSSI >= -128 && RSSI <= 0);
RSSI = -RSSI;
RSSI /= 25;
return mRssiStr[RSSI];
}
/**
Genereate device name base on the local name or deivce address.
@param[in] LocalName Device Name.
@param[in] BDAddr Device Address.
@retval DeviceName A Unicode string which contains the device name.
**/
CHAR16 *
GenerateDeviceName (
IN CHAR8 *LocalName,
IN BLUETOOTH_LE_ADDRESS *BDAddr
)
{
CHAR16 *DeviceName;
UINTN StringLen;
if (LocalName[0] == '\0') {
StringLen = (sizeof (BLUETOOTH_ADDRESS) * 3) * sizeof (CHAR16);
DeviceName = AllocateZeroPool (StringLen);
ASSERT (DeviceName != NULL);
UnicodeSPrint (
DeviceName,
StringLen,
L"%02x:%02x:%02x:%02x:%02x:%02x",
(UINTN)BDAddr->Address[0],
(UINTN)BDAddr->Address[1],
(UINTN)BDAddr->Address[2],
(UINTN)BDAddr->Address[3],
(UINTN)BDAddr->Address[4],
(UINTN)BDAddr->Address[5]
);
} else {
StringLen = (sizeof (BLUETOOTH_ADDRESS) * 3 + AsciiStrnLenS (LocalName, MAX_DEVICE_NAME_LEN) + 4 ) * sizeof (CHAR16);
DeviceName = AllocateZeroPool (StringLen);
ASSERT (DeviceName != NULL);
UnicodeSPrint (
DeviceName,
StringLen,
L"%02x:%02x:%02x:%02x:%02x:%02x(%a)",
(UINTN)BDAddr->Address[0],
(UINTN)BDAddr->Address[1],
(UINTN)BDAddr->Address[2],
(UINTN)BDAddr->Address[3],
(UINTN)BDAddr->Address[4],
(UINTN)BDAddr->Address[5],
LocalName
);
}
return DeviceName;
}
/**
Genereate device name base on the local name or deivce address.
@param[in] LocalName Device Name.
@param[in] Address Device Address.
@param[in] RSSI Bluetooth RSSI.
@param[in] IsPaired Whether this device is connected.
@retval DeviceName A Unicode string which contains the device name.
**/
CHAR16 *
GenerateDeviceStatus (
IN CHAR8 *LocalName,
IN BLUETOOTH_LE_ADDRESS *Address,
IN INT8 RSSI,
IN BOOLEAN IsPaired
)
{
CHAR16 *DeviceStatus;
UINTN StringLen;
CHAR16 *DeviceName;
//
// Show name like "##:##:##:##:##:##(Name) [***--] "
// if "##:##:##:##:##:##(Name)" length > MAX_DEVICE_NAME_LENGTH, cut it.
//
DeviceName = GenerateDeviceName (LocalName, Address);
if (DeviceName == NULL){
return DeviceName;
}
if (StrLen (DeviceName) > MAX_UI_DEVICE_NAME_FIELD) {
DeviceName[MAX_UI_DEVICE_NAME_FIELD] = '\0';
}
//
// Assume the device name is small than 45.
// else we will cut the name to 45.
//
if (IsPaired) {
StringLen = (MAX_UI_DEVICE_NAME_FIELD) * sizeof (CHAR16);
} else {
StringLen = (MAX_UI_DEVICE_NAME_FIELD + StrSize (L" [*****]")) * sizeof (CHAR16);
}
DeviceStatus = AllocateZeroPool (StringLen);
ASSERT (DeviceStatus != NULL);
if (IsPaired) {
UnicodeSPrint (DeviceStatus, StringLen, L"%-*s", MAX_UI_DEVICE_NAME_FIELD, DeviceName);
} else {
UnicodeSPrint (DeviceStatus, StringLen, L"%-*s [%s]", MAX_UI_DEVICE_NAME_FIELD, DeviceName, RssiToString (RSSI));
}
FreePool (DeviceName);
return DeviceStatus;
}
/**
Updates the status of scanning remote Bluetooth devices on the scan page.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_SUCCESS Succeed to update the scan menu.
**/
EFI_STATUS
UpdateScanMenu (
VOID
)
{
VOID *ScanStartOpCodeHandle;
VOID *ScanEndOpCodeHandle;
EFI_IFR_GUID_LABEL *ScanStartLabel;
EFI_IFR_GUID_LABEL *ScanEndLabel;
//
// Allocate space for creation of UpdateData Buffer
//
ScanStartOpCodeHandle = HiiAllocateOpCodeHandle ();
if (ScanStartOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
ScanEndOpCodeHandle = HiiAllocateOpCodeHandle ();
if (ScanEndOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
//
// Create Hii Extend Label OpCode as the start opcode
//
ScanStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (ScanStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
ScanStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
ScanStartLabel->Number = LABEL_BLUETOOTH_SCAN;
//
// Create Hii Extend Label OpCode as the end opcode
//
ScanEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (ScanEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
ScanEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
ScanEndLabel->Number = LABEL_BLUETOOTH_SCAN_END;
if (mBtConfigDevice->InScanning) {
HiiCreateTextOpCode (
ScanStartOpCodeHandle,
STRING_TOKEN(STR_SCANNING_STRING),
STRING_TOKEN(STR_SCANNING_STRING_HELP),
0
);
} else {
HiiCreateActionOpCode (
ScanStartOpCodeHandle,
KEY_SCAN_DEVICE_ID,
STRING_TOKEN(STR_SCAN_STRING),
STRING_TOKEN(STR_SCAN_STRING_HELP),
EFI_IFR_FLAG_CALLBACK,
0
);
}
HiiUpdateForm (
mBtConfigDevice->HiiHandle,
&gHiiBluetoothConfigFormSetGuid,
BLUETOOTH_DEVICE_MANAGEMENT_FORM,
ScanStartOpCodeHandle,
ScanEndOpCodeHandle
);
HiiFreeOpCodeHandle (ScanStartOpCodeHandle);
HiiFreeOpCodeHandle (ScanEndOpCodeHandle);
return EFI_SUCCESS;
}
/**
Update Remote BT device info.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
**/
EFI_STATUS
UpdateDevicePage (
VOID
)
{
LIST_ENTRY *Link;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
CHAR16 *DeviceName;
VOID *PairedStartOpCodeHandle;
VOID *PairedEndOpCodeHandle;
VOID *StartOpCodeHandle;
EFI_IFR_GUID_LABEL *PairedStartLabel;
EFI_IFR_GUID_LABEL *PairedEndLabel;
VOID *AvailableStartOpCodeHandle;
VOID *AvailableEndOpCodeHandle;
EFI_IFR_GUID_LABEL *AvailableStartLabel;
EFI_IFR_GUID_LABEL *AvailableEndLabel;
EFI_STRING_ID Token;
UINTN Index;
BOOLEAN IsPaired;
Index = 0;
//
// Allocate space for creation of UpdateData Buffer
//
AvailableStartOpCodeHandle = HiiAllocateOpCodeHandle ();
if (AvailableStartOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
AvailableEndOpCodeHandle = HiiAllocateOpCodeHandle ();
if (AvailableEndOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
//
// Create Hii Extend Label OpCode as the start opcode
//
AvailableStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (AvailableStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
AvailableStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
AvailableStartLabel->Number = LABEL_BLUETOOTH_AVAILABLE_DEVICE_LIST;
//
// Create Hii Extend Label OpCode as the end opcode
//
AvailableEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (AvailableEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
AvailableEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
AvailableEndLabel->Number = LABEL_BLUETOOTH_AVAILABLE_END;
//
// Allocate space for creation of UpdateData Buffer
//
PairedStartOpCodeHandle = HiiAllocateOpCodeHandle ();
if (PairedStartOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
PairedEndOpCodeHandle = HiiAllocateOpCodeHandle ();
if (PairedEndOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
//
// Create Hii Extend Label OpCode as the start opcode
//
PairedStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (PairedStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
PairedStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
PairedStartLabel->Number = LABEL_BLUETOOTH_PAIRED_DEVICE_LIST;
//
// Create Hii Extend Label OpCode as the end opcode
//
PairedEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (PairedEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
PairedEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
PairedEndLabel->Number = LABEL_BLUETOOTH_PAIRED_END;
//
// Lock device list during updating scan result page.
// Device status maybe update by LinkConnCompCallback.
//
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList);
while (!IsNull (&mBtConfigDevice->RemoteDeviceList, Link)) {
RemoteDev = BT_REMOTE_DEVICE_FROM_LINK (Link);
Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link);
IsPaired = ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED) != 0)? TRUE: FALSE;
if (IsValidBleAddress(&RemoteDev->IDAddr)) {
DeviceName = GenerateDeviceStatus((CHAR8 *)(RemoteDev->LocalName), &RemoteDev->IDAddr, RemoteDev->RSSI, IsPaired);
} else {
DeviceName = GenerateDeviceStatus((CHAR8 *)(RemoteDev->LocalName), &RemoteDev->AdvAddr, RemoteDev->RSSI, IsPaired);
}
Token = HiiSetString (mBtConfigDevice->HiiHandle, 0, DeviceName, NULL);
if (IsPaired) {
StartOpCodeHandle = PairedStartOpCodeHandle;
HiiCreateTextOpCode (
StartOpCodeHandle,
Token,
0,
0
);
} else {
StartOpCodeHandle = AvailableStartOpCodeHandle;
HiiCreateGotoOpCode (
StartOpCodeHandle,
BLUETOOTH_REMOTE_DEVICE_FORM,
Token,
STRING_TOKEN (STR_GOTO_REMOTE_DEVICE_HELP),
EFI_IFR_FLAG_CALLBACK,
(EFI_QUESTION_ID)(REMOTE_DEVICE_OFFSET + Index)
);
}
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) != 0) {
HiiCreateActionOpCode (
StartOpCodeHandle,
(EFI_QUESTION_ID)(DISCONNECT_DEVICE_OFFSET + Index),
STRING_TOKEN (STR_DEVICE_ACTION_NOT_CONNECT),
STRING_TOKEN (STR_DEVICE_ACTION_NOT_CONNECT_HELP),
EFI_IFR_FLAG_CALLBACK,
0
);
} else {
HiiCreateActionOpCode (
StartOpCodeHandle,
(EFI_QUESTION_ID)(CONNECT_DEVICE_OFFSET + Index),
STRING_TOKEN (STR_DEVICE_ACTION_CONNECT),
STRING_TOKEN (STR_DEVICE_ACTION_CONNECT_HELP),
EFI_IFR_FLAG_CALLBACK,
0
);
}
if (IsPaired) {
HiiCreateActionOpCode (
StartOpCodeHandle,
(EFI_QUESTION_ID)(DELETE_DEVICE_OFFSET + Index),
STRING_TOKEN (STR_DEVICE_ACTION_DELETE),
STRING_TOKEN (STR_DEVICE_ACTION_DELETE_HELP),
EFI_IFR_FLAG_CALLBACK,
0
);
}
HiiCreateSubTitleOpCode (
StartOpCodeHandle,
STRING_TOKEN (STR_NULL_STRING),
0,
0,
0);
Index++;
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
HiiUpdateForm (
mBtConfigDevice->HiiHandle,
&gHiiBluetoothConfigFormSetGuid,
BLUETOOTH_DEVICE_MANAGEMENT_FORM,
PairedStartOpCodeHandle,
PairedEndOpCodeHandle
);
HiiUpdateForm (
mBtConfigDevice->HiiHandle,
&gHiiBluetoothConfigFormSetGuid,
BLUETOOTH_DEVICE_MANAGEMENT_FORM,
AvailableStartOpCodeHandle,
AvailableEndOpCodeHandle
);
HiiFreeOpCodeHandle (PairedStartOpCodeHandle);
HiiFreeOpCodeHandle (PairedEndOpCodeHandle);
HiiFreeOpCodeHandle (AvailableStartOpCodeHandle);
HiiFreeOpCodeHandle (AvailableEndOpCodeHandle);
return EFI_SUCCESS;
}
/**
Displays a popup window to indicate the result of a connect/disconnect
operation.
@param[in] RemoteDev A pointer to the BT_REMOTE_DEVICE_ATTRIBUTE
structure that specifies the target device.
@param[in] ErrorType Input the error type.
**/
VOID
ConnectResultPopup (
IN BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev,
IN EFI_BLUETOOTH_ERROR_TYPE ErrorType
)
{
EFI_INPUT_KEY Key;
CHAR16 *StringBuffer1;
CHAR16 *StringBuffer2;
CHAR16 *DeviceName;
StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer1 != NULL);
StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer2 != NULL);
if (IsValidBleAddress (&RemoteDev->IDAddr)) {
DeviceName = GenerateDeviceName ((CHAR8 *)RemoteDev->LocalName, &RemoteDev->IDAddr);
} else {
DeviceName = GenerateDeviceName ((CHAR8 *)RemoteDev->LocalName, &RemoteDev->AdvAddr);
}
switch (ErrorType) {
case ResultExceedMaxPairedDevices:
UnicodeSPrint (
StringBuffer1,
MAX_STRING_LEN,
L" Number of paired devices cannot be larger than %d! ",
EFI_BLUETOOTH_LE_MAX_BONDED_DEV
);
break;
case ResultConnectFail:
UnicodeSPrint (
StringBuffer1,
MAX_STRING_LEN,
L" Connect to %s fail! ",
DeviceName
);
break;
case ResultDisconnectFail:
UnicodeSPrint (
StringBuffer1,
MAX_STRING_LEN,
L" Disconnect to %s fail! ",
DeviceName
);
break;
default:
break;
}
StrCpyS (StringBuffer2, MAX_STRING_LEN, L" Press Enter to continue ");
//
// Popup a info to notice user
//
do {
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
FreePool (StringBuffer1);
FreePool (StringBuffer2);
FreePool (DeviceName);
}
/**
Displays a popup window to get the user's choice on a authorization request.
@param[in] IndicatorString Additional string that will be displayed on the
popup window.
@retval 0 User rejects the authorization request.
@retval 1 User approves the authorization request.
**/
UINT8
HandleAuthorizationRequestEvent (
IN CHAR16 *IndicatorString
)
{
EFI_INPUT_KEY Key;
CHAR16 *StringBuffer2;
CHAR16 *StringBuffer3;
CHAR16 *StringBuffer4;
CHAR16 ApproveResponse;
CHAR16 RejectResponse;
ApproveResponse = L'Y';
RejectResponse = L'N';
StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer2 != NULL);
StringBuffer3 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer3 != NULL);
UnicodeSPrint (
StringBuffer2,
StrSize (L"Approve it, please input <Y>"),
L"Approve it, please input <Y>"
);
UnicodeSPrint (
StringBuffer3,
StrSize (L"Reject it, please input <N>"),
L"Reject it, please input <N>"
);
StringBuffer4 = L"";
//
// Popup a menu to notice user
//
do {
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, IndicatorString, StringBuffer4, StringBuffer2, StringBuffer3, StringBuffer4, NULL);
}while (
((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (ApproveResponse | UPPER_LOWER_CASE_OFFSET)) &&
((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (RejectResponse | UPPER_LOWER_CASE_OFFSET))
);
FreePool (StringBuffer2);
FreePool (StringBuffer3);
if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (ApproveResponse | UPPER_LOWER_CASE_OFFSET)) {
return 1;
} else {
return 0;
}
}
/**
Count the storage space of a Unicode string.
This function handles the Unicode string with NARROW_CHAR
and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
does not count in the resultant output. If a WIDE_CHAR is
hit, then 2 Unicode character will consume an output storage
space with size of CHAR16 till a NARROW_CHAR is hit.
@param String The input string to be counted.
@param LimitLen Whether need to limit the string length.
@param MaxWidth The max length this function supported.
@param Offset The max index of the string can be show out.
@return Storage space for the input string.
**/
UINTN
GetStringWidth (
IN CHAR16 *String,
IN BOOLEAN LimitLen,
IN UINTN MaxWidth,
OUT UINTN *Offset
)
{
UINTN Index;
UINTN Count;
UINTN IncrementValue;
if (String == NULL) {
return 0;
}
Index = 0;
Count = 0;
IncrementValue = 1;
do {
//
// Advance to the null-terminator or to the first width directive
//
for (;(String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); Index++) {
Count = Count + IncrementValue;
if (LimitLen && Count > MaxWidth) {
break;
}
}
//
// We hit the null-terminator, we now have a count
//
if (String[Index] == 0) {
break;
}
if (LimitLen && Count > MaxWidth) {
*Offset = Index;
break;
}
//
// We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
// and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
//
if (String[Index] == NARROW_CHAR) {
//
// Skip to the next character
//
Index++;
IncrementValue = 1;
} else {
//
// Skip to the next character
//
Index++;
IncrementValue = 2;
}
} while (String[Index] != 0);
return Count * sizeof (CHAR16);
}
/**
Draws a dialog box to the console output device specified by
ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke
from the console input device specified by ConIn defined in the
EFI_SYSTEM_TABLE.
If there are no strings in the variable argument list, then ASSERT().
If all the strings in the variable argument list are empty, then ASSERT().
@param[in] Attribute Specifies the foreground and background color of the popup.
@param[in] ... The variable argument list that contains pointers to Null-
terminated Unicode strings to display in the dialog box.
The variable argument list is terminated by a NULL.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_SUCCESS Pop up pass key successfully.
**/
EFI_STATUS
EFIAPI
PopUpPasskey (
IN UINTN Attribute,
...
)
{
VA_LIST Args;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
UINTN Columns;
UINTN Rows;
UINTN Column;
UINTN Row;
UINTN NumberOfLines;
UINTN MaxLength;
CHAR16 *String;
UINTN Length;
CHAR16 *Line;
UINTN EventIndex;
CHAR16 *TmpString;
//
// Determine the length of the longest line in the popup and the the total
// number of lines in the popup
//
VA_START (Args, Attribute);
MaxLength = 0;
NumberOfLines = 0;
while ((String = VA_ARG (Args, CHAR16 *)) != NULL) {
MaxLength = MAX (MaxLength, GetStringWidth (String, FALSE, 0, NULL) / 2);
NumberOfLines++;
}
VA_END (Args);
//
// If the total number of lines in the popup is zero, then ASSERT()
//
ASSERT (NumberOfLines != 0);
//
// If the maximum length of all the strings is zero, then ASSERT()
//
ASSERT (MaxLength != 0);
//
// Cache a pointer to the Simple Text Output Protocol in the EFI System Table
//
ConOut = gST->ConOut;
//
// Save the current console cursor position and attributes
//
CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));
//
// Retrieve the number of columns and rows in the current console mode
//
ConOut->QueryMode (ConOut, SavedConsoleMode.Mode, &Columns, &Rows);
//
// Disable cursor and set the foreground and background colors specified by Attribute
//
ConOut->EnableCursor (ConOut, FALSE);
ConOut->SetAttribute (ConOut, Attribute);
//
// Limit NumberOfLines to height of the screen minus 3 rows for the box itself
//
NumberOfLines = MIN (NumberOfLines, Rows - 3);
//
// Limit MaxLength to width of the screen minus 2 columns for the box itself
//
MaxLength = MIN (MaxLength, Columns - 2);
//
// Compute the starting row and starting column for the popup
//
Row = (Rows - (NumberOfLines + 3)) / 2;
Column = (Columns - (MaxLength + 2)) / 2;
//
// Allocate a buffer for a single line of the popup with borders and a Null-terminator
//
Line = AllocateZeroPool ((MaxLength + 3) * sizeof (CHAR16));
if (Line == NULL){
return EFI_OUT_OF_RESOURCES;
}
//
// Draw top of popup box
//
SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
Line[0] = BOXDRAW_DOWN_RIGHT;
Line[MaxLength + 1] = BOXDRAW_DOWN_LEFT;
Line[MaxLength + 2] = L'\0';
ConOut->SetCursorPosition (ConOut, Column, Row++);
ConOut->OutputString (ConOut, Line);
//
// Draw middle of the popup with strings
//
VA_START (Args, Attribute);
while ((String = VA_ARG (Args, CHAR16 *)) != NULL && NumberOfLines > 0) {
SetMem16 (Line, (MaxLength + 2) * 2, L' ');
Line[0] = BOXDRAW_VERTICAL;
Line[MaxLength + 1] = BOXDRAW_VERTICAL;
Line[MaxLength + 2] = L'\0';
ConOut->SetCursorPosition (ConOut, Column, Row);
ConOut->OutputString (ConOut, Line);
Length = GetStringWidth (String, FALSE, 0, NULL) / 2;
if (Length <= MaxLength) {
//
// Length <= MaxLength
//
ConOut->SetCursorPosition (ConOut, Column + 1 + (MaxLength - Length) / 2, Row++);
ConOut->OutputString (ConOut, String);
} else {
//
// Length > MaxLength
//
GetStringWidth (String, TRUE, MaxLength, &Length);
TmpString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
ASSERT (TmpString != NULL);
StrnCpyS (TmpString, Length + 1, String, Length - 3);
StrCatS (TmpString, Length + 1, L"...");
ConOut->SetCursorPosition (ConOut, Column + 1, Row++);
ConOut->OutputString (ConOut, TmpString);
FreePool (TmpString);
}
NumberOfLines--;
}
VA_END (Args);
//
// Draw bottom of popup box
//
SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
Line[0] = BOXDRAW_UP_RIGHT;
Line[MaxLength + 1] = BOXDRAW_UP_LEFT;
Line[MaxLength + 2] = L'\0';
ConOut->SetCursorPosition (ConOut, Column, Row++);
ConOut->OutputString (ConOut, Line);
//
// Free the allocated line buffer
//
FreePool (Line);
//
// Restore the cursor visibility, position, and attributes
//
ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible);
ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute);
//
// Wait for a event.
//
gBS->WaitForEvent (1, &mBtConfigDevice->PasskeyInputEvent, &EventIndex);
return EFI_SUCCESS;
}
/**
Displays a window to inform user of the passkey information.
@param[in] IndicatorString Additional string that will be displayed on the
window.
@param[in] DataSize The size of Data in bytes.
@param[in] Data The passkey data.
**/
VOID
HandlePasskeyReadyEvent (
IN CHAR16 *IndicatorString,
IN UINTN DataSize,
IN VOID *Data
)
{
CHAR16 *StringBuffer2;
UINT32 Passkey;
UINTN StringLength;
CopyMem(&Passkey, Data, MIN(DataSize, sizeof(Passkey)));
StringLength = StrLen (L"Please enter passkey ") + 6 + StrLen (L" in the other device") + 1;
StringBuffer2 = AllocateZeroPool (StringLength * sizeof (CHAR16));
ASSERT (StringBuffer2 != NULL);
UnicodeSPrint (
StringBuffer2,
StringLength * sizeof (CHAR16),
L"Please enter passkey %06d in the other device",
Passkey
);
//
// Popup the passkey info to let user know.
//
PopUpPasskey (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, IndicatorString, StringBuffer2, NULL);
FreePool (StringBuffer2);
}
/**
Get password input from the popup windows, and unlock the device.
@param[in] IndicatorString Not used.
@param[in] DataSize Not used.
@param[in] Data Not used.
@retval 0 No passkey is input.
@retval UINT32 The passkey entered by the user.
**/
UINT32
HandlePasskeyRequestEvent (
IN CHAR16 *IndicatorString,
IN UINTN DataSize,
IN VOID *Data
)
{
EFI_INPUT_KEY InputKey;
UINTN InputLength;
CHAR16 Unicode[MAX_PASSKEY_SIZE + 1];
CHAR16 *StringBuffer1;
CHAR16 *StringBuffer2;
CHAR16 *StringBuffer3;
CHAR16 *StringBuffer4;
UINT32 Passkey;
Print(L"Please enter passkey displayed on the other device");
StringBuffer2 = L"Please enter passkey displayed on the other device";
StringBuffer4 = L"";
StringBuffer3 = L"Press <O> for OK";
StringBuffer1 = L"Press <C> for Cancel";
ZeroMem(Unicode, sizeof(Unicode));
InputLength = 0;
Unicode[InputLength] = '_';
while (TRUE) {
CreatePopUp(
EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
&InputKey,
StringBuffer2,
StringBuffer4,
Unicode,
StringBuffer4,
StringBuffer3,
StringBuffer1,
NULL
);
//
// Check key.
//
if (InputKey.ScanCode == SCAN_NULL) {
if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
if (InputLength > 0) {
Unicode[InputLength] = 0;
InputLength--;
}
} else if ((InputKey.UnicodeChar == 'O') || (InputKey.UnicodeChar == 'o')) {
//
// pass key finished
//
//
// Add the null terminator.
//
Unicode[InputLength] = 0;
InputLength++;
break;
} else if ((InputKey.UnicodeChar == 'C') || (InputKey.UnicodeChar == 'c')) {
break;
} else {
if (InputLength < MAX_PASSKEY_SIZE) {
//
// add Next key entry
//
Unicode[InputLength] = InputKey.UnicodeChar;
InputLength++;
if (InputLength == MAX_PASSKEY_SIZE) {
//
// Add the null terminator.
//
Unicode[InputLength] = 0;
} else {
Unicode[InputLength] = '_';
}
}
}
}
}
if ((InputLength == 0) || (InputKey.UnicodeChar == 'C') || (InputKey.UnicodeChar == 'c')) {
return 0;
}
Passkey = (UINT32) StrDecimalToUintn (Unicode);
ZeroMem(Unicode, sizeof(Unicode)); // Clear the stack
return Passkey;
}
/**
Displays a popup window for user to confirm whether the passkey is displayed
on the remote device.
@param[in] IndicatorString Additional string that will be displayed on the
popup window.
@param[in] DataSize The size of Data in bytes.
@param[in] Data The passkey data.
@retval 0 The shown passkey is different from the one displayed on the
remote device.
@retval 1 The shown passkey is the same as the one displayed on the remote
device.
**/
UINT8
HandleNumericComparisonEvent (
IN CHAR16 *IndicatorString,
IN UINTN DataSize,
IN VOID *Data
)
{
EFI_INPUT_KEY Key;
CHAR16 *StringBuffer1;
CHAR16 *StringBuffer2;
CHAR16 *StringBuffer3;
CHAR16 *StringBuffer4;
UINT32 Passkey;
UINTN StringLength;
CHAR16 ConfirmResponse;
CHAR16 RejectResponse;
CopyMem(&Passkey, Data, MIN(DataSize, sizeof(Passkey)));
StringLength = StrLen (L"Is ") + 6 + StrLen (L" being displayed on the other device (0/1)? ");
StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer2 != NULL);
UnicodeSPrint (
StringBuffer2,
StringLength * sizeof (CHAR16),
L"Is %06d being displayed on the other device (0/1)? ",
Passkey
);
StringBuffer4 = L"";
ConfirmResponse = L'Y';
RejectResponse = L'N';
StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer2 != NULL);
StringBuffer3 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer3 != NULL);
UnicodeSPrint (
StringBuffer1,
StrSize (L"If Yes, please input <Y>"),
L"If Yes, please input <Y>"
);
UnicodeSPrint (
StringBuffer3,
StrSize (L"If No, please input <N>"),
L"f No, please input <N>"
);
//
// Popup a menu to notice user
//
do {
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, IndicatorString, StringBuffer2, StringBuffer4, StringBuffer1, StringBuffer3, StringBuffer4, NULL);
}while (
((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (ConfirmResponse | UPPER_LOWER_CASE_OFFSET)) &&
((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (RejectResponse | UPPER_LOWER_CASE_OFFSET))
);
FreePool (StringBuffer2);
FreePool (StringBuffer3);
if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (ConfirmResponse | UPPER_LOWER_CASE_OFFSET)) {
return 1;
} else {
return 0;
}
}
/**
The callback function for SMP.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
instance.
@param[in] Context Data passed into callback function. This is
optional parameter and may be NULL.
@param[in] BDAddr Remote BluetoothLE device address.
@param[in] EventDataType Event data type in
EFI_BLUETOOTH_LE_SMP_EVENT_DATA_TYPE.
@param[in] DataSize Indicates the size, in bytes, of the data buffer
specified by Data.
@param[in] Data A pointer to the buffer of data.
@retval EFI_SUCCESS The callback function complete successfully.
@retval EFI_DEVICE_ERROR Fail to generate the device name.
@retval Other A value from other functions.
**/
EFI_STATUS
EFIAPI
SmpCallback (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN VOID *Context,
IN BLUETOOTH_LE_ADDRESS *BDAddr,
IN EFI_BLUETOOTH_LE_SMP_EVENT_DATA_TYPE EventDataType,
IN UINTN DataSize,
IN VOID *Data
)
{
UINT8 Auth;
UINT32 Passkey;
CHAR16 *StringBuffer;
UINTN StringLength;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
CHAR16 *DevName;
EFI_STATUS Status = EFI_SUCCESS;
if (mBtConfigDevice->ConnectState != StateConnecting) {
DEBUG ((DEBUG_ERROR, "BtCfgDxe :: SmpCallback trigged not during connecting!!!"));
}
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
RemoteDev = LocateDevInList (BDAddr->Address, EfiAnyAddressType);
if (RemoteDev == NULL) {
DEBUG ((EFI_D_ERROR, "BtCfgDxe :: SmpCallback : Could not found the input device in the list!\n"));
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
DumpRemoteDeviceList ();
return EFI_SUCCESS;
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
if (IsValidBleAddress(&RemoteDev->IDAddr)) {
DevName = GenerateDeviceName((CHAR8 *)RemoteDev->LocalName, &RemoteDev->IDAddr);
} else {
DevName = GenerateDeviceName((CHAR8 *)RemoteDev->LocalName, &RemoteDev->AdvAddr);
}
if (DevName == NULL){
return EFI_DEVICE_ERROR;
}
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Paired reqeust from %s, Event = %u \n", DevName, EventDataType));
StringBuffer = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
ASSERT (StringBuffer != NULL);
StringLength = StrSize (L"Pairing Request from ") + StrSize (DevName);
UnicodeSPrint (StringBuffer, StringLength, L"Pairing Request from %s\n", DevName);
FreePool (DevName);
switch(EventDataType)
{
case EfiBluetoothSmpAuthorizationRequestEvent:
Auth = HandleAuthorizationRequestEvent (StringBuffer);
Data = &Auth;
DataSize = sizeof(Auth);
break;
case EfiBluetoothSmpPasskeyReadyEvent:
HandlePasskeyReadyEvent (StringBuffer, DataSize, Data);
DataSize = 0;
Data = 0;
break;
case EfiBluetoothSmpPasskeyRequestEvent:
Passkey = HandlePasskeyRequestEvent (StringBuffer, DataSize, Data);
Data = &Passkey;
DataSize = sizeof(Passkey);
break;
case EfiBluetoothSmpNumericComparisonEvent:
Auth = HandleNumericComparisonEvent (StringBuffer, DataSize, Data);
Data = &Auth;
DataSize = sizeof(Auth);
break;
case EfiBluetoothSmpOOBDataRequestEvent:
CopyMem(&Passkey, Data, MIN(DataSize, sizeof(Passkey)));
DEBUG ((EFI_D_INFO, "EfiBlutoothSmpOOBDataRequestEvent is not supported yet!\n"));
DataSize = 0;
Data = 0;
break;
}
if (DataSize != 0) {
Status = mBtConfigDevice->BluetoothLeConfig->SendSmpAuthData(This, BDAddr, EventDataType, DataSize, Data);
}
Passkey = 0; // Clear the stack entry
return Status;
}
/**
Check whether the input device address is the current bonding one.
@param[in] Address Remote BluetoothLE device address.
**/
BOOLEAN
IsCurrentBondingDevice (
IN BLUETOOTH_LE_ADDRESS *Address
)
{
if (mBtConfigDevice->CurrentBondingDev == NULL) {
return FALSE;
}
if (mBtConfigDevice->CurrentBondingIDAddress &&
CompareMem (Address->Address, mBtConfigDevice->CurrentBondingDev->IDAddr.Address, sizeof (Address->Address)) == 0) {
return TRUE;
}
if (!mBtConfigDevice->CurrentBondingIDAddress &&
CompareMem (Address->Address, mBtConfigDevice->CurrentBondingDev->AdvAddr.Address, sizeof (Address->Address)) == 0) {
return TRUE;
}
return FALSE;
}
/**
The callback function to hook connect complete event.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
instance.
@param[in] Context Data passed into callback function. This is
optional parameter and may be NULL.
@param[in] CallbackType The value defined in
EFI_BLUETOOTH_CONNECT_COMPLETE_CALLBACK_TYPE.
@param[in] Address Remote BluetoothLE device address.
Call in with same address when user call connect
or disconnect.
@param[in] InputBuffer A pointer to the buffer of data that is input from callback caller.
@param[in] InputBufferSize Indicates the size, in bytes, of the data buffer specified by InputBuffer.
@retval EFI_SUCCESS The callback function complete successfully.
**/
EFI_STATUS
EFIAPI
LinkConnCompCallback (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN VOID *Context,
IN EFI_BLUETOOTH_CONNECT_COMPLETE_CALLBACK_TYPE CallbackType,
IN BLUETOOTH_LE_ADDRESS *Address,
IN VOID *InputBuffer,
IN UINTN InputBufferSize
)
{
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
BT_LE_REMOTE_DEV_STORAGE *PairedDevData;
UINTN Index;
DEBUG ((EFI_D_INFO, "LeConnCompCallback - %d\n", CallbackType));
DEBUG ((EFI_D_INFO, "LeConnCompCallback - BDAddr %02x:%02x:%02x:%02x:%02x:%02x Type %02x\n",
Address->Address[0], Address->Address[1],
Address->Address[2], Address->Address[3],
Address->Address[4], Address->Address[5],
Address->Type
));
EfiAcquireLock (&mBtConfigDevice->DeviceListLock);
RemoteDev = LocateDevInList (Address->Address, EfiAnyAddressType);
if (RemoteDev == NULL) {
DEBUG ((EFI_D_ERROR, "BtCfgDxe :: ConnCompCallback not found the input device in the list!\n"));
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
DumpRemoteDeviceList ();
return EFI_SUCCESS;
}
switch (CallbackType) {
case EfiBluetoothConnCallbackTypeDisconnected:
RemoteDev->RemoteDeviceState &= ~EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED;
//
// If not trigged by the device which is connecting, just skip.
//
if (mBtConfigDevice->ConnectState == StateConnecting) {
if (IsCurrentBondingDevice (Address)) {
PERF_END (NULL, "Connect", "Bluetooth", 0);
//
// IsValidBleAddress(&RemoteDev->IDAddr) == TRUE means this device has called LeSmpSetDataCallback
// to update mBtConfigDevice->PairedDevData[Index]. Check whether need to clean it.
//
if (IsValidBleAddress(&RemoteDev->IDAddr)) {
PairedDevData = LocateDevInGlobalData(&RemoteDev->IDAddr, &Index);
ASSERT (PairedDevData != NULL);
//
// mBtConfigDevice->PairedDevDataSaved[Index] == TRUE means this device is connected before, now
// is reconnecting, should not clear mBtConfigDevice->PairedDevData[Index] if connect failed now.
// Else means this device is first time connecting and return failed, need to clean the maintained
// mBtConfigDevice->PairedDevData[Index].
//
if (!mBtConfigDevice->PairedDevDataSaved[Index]) {
DeletePairedDevice (&RemoteDev->IDAddr, FALSE);
}
} else {
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Identify address is invalid, not delete Paired device data!\n"));
}
}
}
break;
case EfiBluetoothConnCallbackTypeConnected:
RemoteDev->RemoteDeviceState |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED;
RemoteDev->AdvAddr.Type = Address->Type;
break;
case EfiBluetoothConnCallbackTypeEncrypted:
RemoteDev->RemoteDeviceState |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED;
RemoteDev->RemoteDeviceState |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED;
//
// If not trigged by the device which is connecting, just return.
//
if (mBtConfigDevice->ConnectState == StateConnecting) {
if (IsCurrentBondingDevice (Address)) {
ASSERT (IsValidBleAddress(&RemoteDev->IDAddr));
//
// Update Remote device name from local database
//
PairedDevData = LocateDevInGlobalData(&RemoteDev->IDAddr, &Index);
ASSERT (PairedDevData != NULL);
ZeroMem(PairedDevData->PeerName, sizeof(PairedDevData->PeerName));
CopyMem(PairedDevData->PeerName, RemoteDev->LocalName, MIN(sizeof(PairedDevData->PeerName) - 1, sizeof(RemoteDev->LocalName)));
SavePairedDevice (&RemoteDev->IDAddr);
gBS->SignalEvent (mBtConfigDevice->PasskeyInputEvent);
}
}
gBS->SignalEvent (mBtConfigDevice->ConnectDriverEvent);
break;
default:
break;
}
EfiReleaseLock (&mBtConfigDevice->DeviceListLock);
//
// Call LinkConnCompCallback has two cases:
// 1. User requests connect action trigged 2. iLE stack auto reconnection trigged.
// Before user request connect trigges this function, iLE stack auto reconnection may trigges this function,
// in this case, we should not update mBtConfigDevice->BluetoothPhaseType. Base on
// mBtConfigDevice->CurBondingDevAddr to decide whether need to update it.
//
if (IsCurrentBondingDevice (Address)) {
mBtConfigDevice->ConnectState = StateIdle;
}
//
// Fake found new device event to let the form refresh the connect status.
//
mBtConfigDevice->FoundNewDevice = TRUE;
gBS->SignalEvent (mBtConfigDevice->RefreshRemoteDevEvent);
return EFI_SUCCESS;
}
/**
Find the remote device base on the index.
@param Offset The device index in the list.
@retval The remote device info.
**/
BT_REMOTE_DEVICE_ATTRIBUTE *
GetRemoteDevice (
IN UINTN Offset
)
{
LIST_ENTRY *Link;
UINTN Index;
Index = 0;
Link = GetFirstNode (&mBtConfigDevice->RemoteDeviceList);
while (!IsNull (&mBtConfigDevice->RemoteDeviceList, Link)) {
if (Index == Offset) {
break;
}
Link = GetNextNode (&mBtConfigDevice->RemoteDeviceList, Link);
Index ++;
}
if (IsNull (&mBtConfigDevice->RemoteDeviceList, Link)) {
return NULL;
}
return BT_REMOTE_DEVICE_FROM_LINK (Link);
}
/**
To find the service name based on the ServiceUuid.
The returned service name is allocated through AllocateZeroPoolreturn function,
caller needs to free it.
@param AdvertisementData Point to the AdvertisementData.
@retval A Unicode string which contains the service name.
**/
CHAR16*
UuidToName (
IN UINT8 *AdvertisementData
)
{
UINT16 Uuid16;
UINTN Index;
UINTN StringLen;
CHAR16 *UuidName;
CHAR16 *DisplayName;
//
// Skip the length (1 byte) and type (1 byte)
// then point to the value of UUID.
//
AdvertisementData += 2;
Uuid16 = ReadUnaligned16 ((UINT16*)AdvertisementData);
UuidName = mUnknownUuidName;
for (Index = 0; Index < sizeof (mServiceUuid16Name) / sizeof (mServiceUuid16Name[0]); Index++) {
if (Uuid16 == mServiceUuid16Name[Index].Uuid) {
UuidName = mServiceUuid16Name[Index].Name;
break;
}
}
StringLen = StrSize (UuidName) + sizeof (L" ");
DisplayName = AllocatePool (StringLen);
ASSERT (DisplayName != NULL);
UnicodeSPrint (DisplayName, StringLen, L" %s", UuidName);
return DisplayName;
}
/**
Updates the service information of a remote Bluetooth device.
@param[in] AdvertisementData A pointer to the BluetoothLE advertisement
data.
@param[in] AdvertisementDataSize The size of AdvertisementData in bytes.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_SUCCESS Update service information successfully.
**/
EFI_STATUS
UpdateServiceInfoForRemoteDev (
IN UINT8 *AdvertisementData,
IN UINT32 AdvertisementDataSize
)
{
UINT8 *AdInCompUuid16;
UINT8 *AdCompUuid16;
UINT8 *TempAdvertisementData;
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle;
EFI_IFR_GUID_LABEL *StartLabel;
EFI_IFR_GUID_LABEL *EndLabel;
EFI_STRING_ID StringId;
CHAR16 *UnicodeData;
UINT32 TempAdvertisementDataSize;
//
// Allocate space for creation of UpdateData Buffer
//
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
if (StartOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
if (EndOpCodeHandle == NULL){
return EFI_OUT_OF_RESOURCES;
}
//
// Create Hii Extend Label OpCode as the start opcode
//
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartLabel->Number = LABEL_BLUETOOTH_AVAILABLE_SERVICE_LIST;
//
// Create Hii Extend Label OpCode as the end opcode
//
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
EndLabel->Number = LABEL_BLUETOOTH_AVAILABLE_SERVICE_END;
TempAdvertisementData = AdvertisementData;
TempAdvertisementDataSize = AdvertisementDataSize;
if (TempAdvertisementData != NULL) {
AdInCompUuid16 = FindTypeFromAdvertisementData (TempAdvertisementData, TempAdvertisementDataSize,BluetoothGapTypeIncomplete16BitServiceClassUUIDs);
while ((AdInCompUuid16 != NULL) && ((AdInCompUuid16 + 4) <= (TempAdvertisementData + TempAdvertisementDataSize))) {
UnicodeData = UuidToName (AdInCompUuid16);
StringId = HiiSetString (mBtConfigDevice->HiiHandle, 0, UnicodeData, NULL);
FreePool(UnicodeData);
HiiCreateTextOpCode (
StartOpCodeHandle,
StringId,
0,
0
);
if (TempAdvertisementDataSize < (UINT32)(*AdInCompUuid16 + 1)) {
break;
}
TempAdvertisementData += (*AdInCompUuid16 + 1);
TempAdvertisementDataSize -= (*AdInCompUuid16 + 1);
AdInCompUuid16 = FindTypeFromAdvertisementData (TempAdvertisementData, TempAdvertisementDataSize,BluetoothGapTypeIncomplete16BitServiceClassUUIDs);
}
AdCompUuid16 = FindTypeFromAdvertisementData (AdvertisementData, AdvertisementDataSize, BluetoothGapTypeComplete16BitServiceClassUUIDs);
if ((AdInCompUuid16 != NULL) && ((AdInCompUuid16 + 4) <= (AdvertisementData + AdvertisementDataSize))) {
UnicodeData = UuidToName (AdCompUuid16);
StringId = HiiSetString (mBtConfigDevice->HiiHandle, 0, UnicodeData, NULL);
FreePool(UnicodeData);
HiiCreateTextOpCode (
StartOpCodeHandle,
StringId,
0,
0
);
}
}
HiiUpdateForm (
mBtConfigDevice->HiiHandle,
&gHiiBluetoothConfigFormSetGuid,
BLUETOOTH_REMOTE_DEVICE_FORM,
StartOpCodeHandle,
EndOpCodeHandle
);
HiiFreeOpCodeHandle (StartOpCodeHandle);
HiiFreeOpCodeHandle (EndOpCodeHandle);
return EFI_SUCCESS;
}
/**
Updates the information of a remote Bluetooth device for display.
@param[in] RemoteDev A pointer to the BT_REMOTE_DEVICE_ATTRIBUTE structure.
@retval EFI_SUCCESS The information of the specified remote
Bluetooth device has been updated
successfully.
@retval EFI_OUT_OF_RESOURCES The operation fails due to memory allocation
failure.
@retval Other A value from other functions.
**/
EFI_STATUS
UpdateRemoteDevPageInfo (
IN BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev
)
{
EFI_STRING_ID StringId;
CHAR16 *UniValue;
EFI_STATUS Status;
VOID *Buffer;
UINTN BufferSize;
Status = EFI_SUCCESS;
//
// Update remote dev name.
//
if (AsciiStrnLenS ((const CHAR8*)(RemoteDev->LocalName), MAX_DEVICE_NAME_LEN) != 0) {
UniValue = AllocateZeroPool (AsciiStrSize ((const CHAR8*)(RemoteDev->LocalName)) * sizeof (CHAR16));
ASSERT (UniValue != NULL);
AsciiStrToUnicodeStrS ((const CHAR8*)(RemoteDev->LocalName), UniValue, AsciiStrSize ((const CHAR8*)(RemoteDev->LocalName)));
} else {
UniValue = AllocateCopyPool (StrSize (L" "), L" ");
}
StringId = HiiSetString (
mBtConfigDevice->HiiHandle,
STRING_TOKEN (STR_NAME_STRING_VALUE),
UniValue,
NULL
);
if (StringId == 0) {
return EFI_OUT_OF_RESOURCES;
}
//
// Update remote dev address.
//
UniValue = AllocateZeroPool ((3 * 6) * sizeof (CHAR16));
ASSERT (UniValue != NULL);
UnicodeSPrint (
UniValue,
(3 * 6) * sizeof (CHAR16),
L"%02x-%02x-%02x-%02x-%02x-%02x",
(UINTN)RemoteDev->AdvAddr.Address[0],
(UINTN)RemoteDev->AdvAddr.Address[1],
(UINTN)RemoteDev->AdvAddr.Address[2],
(UINTN)RemoteDev->AdvAddr.Address[3],
(UINTN)RemoteDev->AdvAddr.Address[4],
(UINTN)RemoteDev->AdvAddr.Address[5]
);
StringId = HiiSetString (
mBtConfigDevice->HiiHandle,
STRING_TOKEN (STR_REMOTE_ADDRESS_STRING_VALUE),
UniValue,
NULL
);
if (StringId == 0) {
return EFI_OUT_OF_RESOURCES;
}
//
// Update remote dev state info.
//
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) != 0) {
UniValue = AllocateCopyPool (StrSize (L"Connected"), L"Connected");
} else {
UniValue = AllocateCopyPool (StrSize (L"Disconnected"), L"Disconnected");
}
StringId = HiiSetString (
mBtConfigDevice->HiiHandle,
STRING_TOKEN (STR_STATE_STRING_VALUE),
UniValue,
NULL
);
if (StringId == 0) {
return EFI_OUT_OF_RESOURCES;
}
//
// Get Sdp Info for this device.
//
BufferSize = 0;
Buffer = NULL;
Status = mBtConfigDevice->BluetoothLeConfig->GetRemoteData (mBtConfigDevice->BluetoothLeConfig, EfiBluetoothConfigDataTypeAdvertisementData, &RemoteDev->AdvAddr, &BufferSize, Buffer);
if (Status == EFI_BUFFER_TOO_SMALL) {
Buffer = AllocateZeroPool (BufferSize);
Status = mBtConfigDevice->BluetoothLeConfig->GetRemoteData(mBtConfigDevice->BluetoothLeConfig, EfiBluetoothConfigDataTypeAdvertisementData, &RemoteDev->AdvAddr, &BufferSize, Buffer);
if (Status == EFI_SUCCESS) {
ASSERT (Buffer != NULL);
DumpAdvertisementData (Buffer, (UINT32)BufferSize);
UpdateServiceInfoForRemoteDev (Buffer, (UINT32)BufferSize);
FreePool (Buffer);
} else {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Get AdvertisementData from remote device failed!\n"));
}
} else {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Get AdvertisementData from remote device failed!\n"));
//
// If get SDP info return error, skip it.
//
Status = EFI_SUCCESS;
}
return Status;
}
/**
This function allows a caller to extract the current configuration for one
or more named elements from the target driver.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Request A null-terminated Unicode string in <ConfigRequest> format.
@param Progress On return, points to a character in the Request string.
Points to the string's null terminator if request was successful.
Points to the most recent '&' before the first failing name/value
pair (or the beginning of the string if the failure is in the
first name/value pair) if the request was not successful.
@param Results A null-terminated Unicode string in <ConfigAltResp> format which
has all values filled in for the names in the Request string.
String to be allocated by the called function.
@retval EFI_SUCCESS The Results is filled with the requested values.
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
**/
EFI_STATUS
EFIAPI
HiiConfigAccessExtractConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
)
{
if (Progress == NULL || Results == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Request;
return EFI_NOT_FOUND;
}
/**
This function processes the results of changes in configuration.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Configuration A null-terminated Unicode string in <ConfigResp> format.
@param Progress A pointer to a string filled in with the offset of the most
recent '&' before the first failing name/value pair (or the
beginning of the string if the failure is in the first
name/value pair) or the terminating NULL if all was successful.
@retval EFI_SUCCESS The Results is processed successfully.
@retval EFI_INVALID_PARAMETER Configuration is NULL.
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
**/
EFI_STATUS
EFIAPI
HiiConfigAccessRouteConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
)
{
if (Configuration == NULL || Progress == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Configuration + StrLen (Configuration);
return EFI_SUCCESS;
}
/**
The callback function to get SMP data.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
instance.
@param[in] Context Data passed into callback function. This is
optional parameter and may be NULL.
@param[in] IDAddr Remote BluetoothLE device address. For Local
device setting, it should be NULL.
Call in with Identify address.
@param[in] DataType Data type in EFI_BLUETOOTH_LE_SMP_DATA_TYPE.
@param[in, out] DataSize On input, indicates the size, in bytes, of the
data buffer specified by Data. On output,
indicates the amount of data actually returned.
@param[out] Data A pointer to the buffer of data that will be
returned.
@retval EFI_SUCCESS The SMP get data callback function is
registered successfully.
@retval EFI_BUFFER_TOO_SMALL Data is too small to hold the return data.
@retval EFI_INVALID_PARAMETER The value of DataType is not in
EFI_BLUETOOTH_LE_SMP_DATA_TYPE.
@retval EFI_UNSUPPORTED The given DataType is currently not
supported.
@retval Other A value from other functions.
**/
EFI_STATUS
EFIAPI
LeSmpGetDataCallback (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN VOID *Context,
IN BLUETOOTH_LE_ADDRESS *IDAddr,
IN EFI_BLUETOOTH_LE_SMP_DATA_TYPE DataType,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
EFI_STATUS Status;
BT_LE_REMOTE_DEV_STORAGE *RemoteData;
UINT8 Count;
UINT8 *DataPtr;
Status = EFI_SUCCESS;
if (IDAddr == NULL) {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpGetDataCallback DataType = 0x%x, IDAddr = NULL\n", DataType));
} else {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpGetDataCallback DataType = 0x%x, IDAddr = %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
DataType,
IDAddr->Address[0], IDAddr->Address[1],
IDAddr->Address[2], IDAddr->Address[3],
IDAddr->Address[4], IDAddr->Address[5],
IDAddr->Type));
}
if (*DataSize == 0) {
*DataSize = MAX((EFI_BLUETOOTH_LE_MAX_BONDED_DEV * sizeof(BLUETOOTH_LE_ADDRESS)), MAX_DEVICE_NAME_LEN);
return EFI_BUFFER_TOO_SMALL;
}
if (Data == NULL) {
*DataSize = 0;
return EFI_BUFFER_TOO_SMALL;
}
if (IDAddr == NULL) {
switch(DataType) {
case EfiBluetoothSmpLocalIRK:
*DataSize = sizeof(mBtConfigDevice->ControllerData.KeyIrk);
CopyMem(Data, mBtConfigDevice->ControllerData.KeyIrk, sizeof(mBtConfigDevice->ControllerData.KeyIrk));
break;
case EfiBluetoothSmpPeerAddressList:
DataPtr = (UINT8*)Data;
*DataSize = 0;
for (Count = 0; Count < EFI_BLUETOOTH_LE_MAX_BONDED_DEV; Count++) {
if (IsValidBleAddress(&mBtConfigDevice->ControllerData.RemoteIDAddr[Count])) {
//
// Found remote device entry in local device storage
//
CopyMem(DataPtr, &mBtConfigDevice->ControllerData.RemoteIDAddr[Count], sizeof(BLUETOOTH_LE_ADDRESS));
DataPtr += sizeof(BLUETOOTH_LE_ADDRESS);
*DataSize += sizeof(BLUETOOTH_LE_ADDRESS);
}
}
break;
default:
*DataSize = 0;
Status = EFI_INVALID_PARAMETER;
break;
}
} else {
RemoteData = LocateDevInGlobalData (IDAddr, NULL);
if (RemoteData == NULL) {
/* Remote Entry is not Available */
*DataSize = 0;
return EFI_NOT_FOUND;
}
switch(DataType) {
case EfiBluetoothSmpLocalIR:
*DataSize = 0;
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpLocalER:
*DataSize = 0;
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpLocalDHK:
*DataSize = 0;
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpKeysDistributed:
*DataSize = sizeof(RemoteData->KeysDistributed);
CopyMem(Data, &RemoteData->KeysDistributed, sizeof(RemoteData->KeysDistributed));
break;
case EfiBluetoothSmpKeySize:
*DataSize = sizeof(RemoteData->KeySize);
CopyMem(Data, &RemoteData->KeySize, sizeof(RemoteData->KeySize));
break;
case EfiBluetoothSmpKeyType:
*DataSize = sizeof(RemoteData->AuthReq);
CopyMem(Data, &RemoteData->AuthReq, sizeof(RemoteData->AuthReq));
break;
case EfiBluetoothSmpPeerLTK:
*DataSize = sizeof(RemoteData->PeerLtk);
CopyMem(Data, RemoteData->PeerLtk, sizeof(RemoteData->PeerLtk));
break;
case EfiBluetoothSmpPeerIRK:
*DataSize = sizeof(RemoteData->PeerIrk);
CopyMem(Data, RemoteData->PeerIrk, sizeof(RemoteData->PeerIrk));
break;
case EfiBluetoothSmpPeerCSRK:
*DataSize = sizeof(RemoteData->PeerCsrk);
CopyMem(Data, RemoteData->PeerCsrk, sizeof(RemoteData->PeerCsrk));
break;
case EfiBluetoothSmpPeerRand:
*DataSize = sizeof(RemoteData->PeerRand);
CopyMem(Data, RemoteData->PeerRand, sizeof(RemoteData->PeerRand));
break;
case EfiBluetoothSmpPeerEDIV:
*DataSize = sizeof(RemoteData->PeerEdiv);
CopyMem(Data, &RemoteData->PeerEdiv, sizeof(RemoteData->PeerEdiv));
break;
case EfiBluetoothSmpPeerSignCounter:
*DataSize = sizeof(RemoteData->PeerSignCounter);
CopyMem(Data, &RemoteData->PeerSignCounter, sizeof(RemoteData->PeerSignCounter));
break;
case EfiBluetoothSmpLocalLTK:
*DataSize = sizeof(RemoteData->LocalLtk);
CopyMem(Data, RemoteData->LocalLtk, sizeof(RemoteData->LocalLtk));
break;
case EfiBluetoothSmpLocalIRK:
*DataSize = sizeof(RemoteData->LocalIrk);
CopyMem(Data, RemoteData->LocalIrk, sizeof(RemoteData->LocalIrk));
break;
case EfiBluetoothSmpLocalCSRK:
*DataSize = sizeof(RemoteData->LocalCsrk);
CopyMem(Data, RemoteData->LocalCsrk, sizeof(RemoteData->LocalCsrk));
break;
case EfiBluetoothSmpLocalSignCounter:
*DataSize = sizeof(RemoteData->LocalSignCounter);
CopyMem(Data, &RemoteData->LocalSignCounter, sizeof(RemoteData->LocalSignCounter));
break;
case EfiBluetoothSmpLocalDIV:
*DataSize = 0;
Status = EFI_UNSUPPORTED;
break;
default:
*DataSize = 0;
Status = EFI_INVALID_PARAMETER;
break;
}
}
return Status;
}
/**
The callback function to set SMP data.
@param[in] This Pointer to the EFI_BLUETOOTH_LE_CONFIG_PROTOCOL
instance.
@param[in] Context Data passed into callback function. This is optional
parameter and may be NULL.
@param[in] IDAddr Remote BluetoothLE device address.
Call in with Identify address.
@param[in] DataType Data type in EFI_BLUETOOTH_LE_SMP_DATA_TYPE.
@param[in] DataSize Indicates the size, in bytes, of the data buffer
specified by Data.
@param[in] Data A pointer to the buffer of data.
@retval EFI_SUCCESS The SMP set data callback function is
registered successfully.
@retval EFI_INVALID_PARAMETER The value of DataType is not in
EFI_BLUETOOTH_LE_SMP_DATA_TYPE.
@retval EFI_UNSUPPORTED The given DataType is currently not
supported.
@retval Other A value from other functions.
**/
EFI_STATUS
EFIAPI
LeSmpSetDataCallback (
IN EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *This,
IN VOID *Context,
IN BLUETOOTH_LE_ADDRESS *IDAddr,
IN EFI_BLUETOOTH_LE_SMP_DATA_TYPE DataType,
IN UINTN DataSize,
IN VOID *Data
)
{
EFI_STATUS Status;
BT_LE_REMOTE_DEV_STORAGE *RemoteData;
UINTN LocalDataSize;
UINTN Index;
Status = EFI_SUCCESS;
if (mBtConfigDevice->ConnectState != StateConnecting) {
DEBUG ((DEBUG_INFO, "BtCfgDxe :: LeSmpSetDataCallback call in not in CONNECTING phase!\n"));
}
if (IDAddr == NULL) {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpSetDataCallback DataType = 0x%x, IDAddr = NULL\n", DataType));
} else {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpSetDataCallback DataType = 0x%x, IDAddr = %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
DataType,
IDAddr->Address[0], IDAddr->Address[1],
IDAddr->Address[2], IDAddr->Address[3],
IDAddr->Address[4], IDAddr->Address[5],
IDAddr->Type));
if (DataType != EfiBluetoothSmpKeysDistributed) {
//
// EfiBluetoothSmpKeysDistributed is first type which called in to update the
// mBtConfigDevice->CurrentBondingDev->IDAddr.
// If current call in type is not EfiBluetoothSmpKeysDistributed and mBtConfigDevice->CurrentBondingDev->IDAddr
// still invalid, this is not a correct situation. So add ASSERT code here.
//
if (!IsValidBleAddress(&mBtConfigDevice->CurrentBondingDev->IDAddr)) {
DEBUG ((DEBUG_ERROR, "BtCfgDxe :: !!!WARNING!!! IDAddr still invalid after EfiBluetoothSmpKeysDistributed type!\n"));
ASSERT (FALSE);
}
}
}
if (IDAddr == NULL) {
switch(DataType) {
case EfiBluetoothSmpLocalIRK:
{
if (DataSize == sizeof(mBtConfigDevice->ControllerData.KeyIrk) && (Data != NULL)) {
CopyMem(mBtConfigDevice->ControllerData.KeyIrk, Data, sizeof(mBtConfigDevice->ControllerData.KeyIrk));
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->SetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LocalDataSize,
&mBtConfigDevice->ControllerData);
ASSERT_EFI_ERROR (Status);
}
}
break;
default:
Status = EFI_INVALID_PARAMETER;
break;
}
} else {
RemoteData = LocateDevInGlobalData (IDAddr, &Index);
if (RemoteData == NULL) {
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpSetDataCallback allocate new Global Data!\n"));
//
// Add new device to local device storage.
//
for (Index = 0; Index < EFI_BLUETOOTH_LE_MAX_BONDED_DEV; Index++) {
if (!IsValidBleAddress (&mBtConfigDevice->ControllerData.RemoteIDAddr[Index])) {
CopyMem(&mBtConfigDevice->ControllerData.RemoteIDAddr[Index], IDAddr, sizeof(BLUETOOTH_LE_ADDRESS));
ZeroMem (&mBtConfigDevice->PairedDevData[Index], sizeof (&mBtConfigDevice->PairedDevData[Index]));
RemoteData = &mBtConfigDevice->PairedDevData[Index];
break;
}
}
if (RemoteData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
switch(DataType) {
case EfiBluetoothSmpLocalIR:
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpLocalER:
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpLocalDHK:
Status = EFI_UNSUPPORTED;
break;
case EfiBluetoothSmpKeysDistributed:
//
// This is new pairing entry, so deleting all other information if already exist
//
SetMem(RemoteData, sizeof(BT_LE_REMOTE_DEV_STORAGE), 0);
CopyMem(&mBtConfigDevice->CurrentBondingDev->IDAddr, IDAddr, sizeof(BLUETOOTH_LE_ADDRESS));
DEBUG ((EFI_D_INFO, "BtCfgDxe :: LeSmpSetDataCallback call in, update IDAdrr success!\n"));
CopyMem(&RemoteData->KeysDistributed, Data, sizeof(RemoteData->KeysDistributed));
break;
case EfiBluetoothSmpKeySize:
CopyMem(&RemoteData->KeySize, Data, sizeof(RemoteData->KeySize));
break;
case EfiBluetoothSmpKeyType:
CopyMem(&RemoteData->AuthReq, Data, sizeof(RemoteData->AuthReq));
break;
case EfiBluetoothSmpPeerLTK:
CopyMem(RemoteData->PeerLtk, Data, sizeof(RemoteData->PeerLtk));
break;
case EfiBluetoothSmpPeerIRK:
CopyMem(RemoteData->PeerIrk, Data, sizeof(RemoteData->PeerIrk));
break;
case EfiBluetoothSmpPeerCSRK:
CopyMem(RemoteData->PeerCsrk, Data, sizeof(RemoteData->PeerCsrk));
break;
case EfiBluetoothSmpPeerRand:
CopyMem(RemoteData->PeerRand, Data, sizeof(RemoteData->PeerRand));
break;
case EfiBluetoothSmpPeerEDIV:
CopyMem(&RemoteData->PeerEdiv, Data, sizeof(RemoteData->PeerEdiv));
break;
case EfiBluetoothSmpPeerSignCounter:
CopyMem(&RemoteData->PeerSignCounter, Data, sizeof(RemoteData->PeerSignCounter));
break;
case EfiBluetoothSmpLocalLTK:
CopyMem(RemoteData->LocalLtk, Data, sizeof(RemoteData->LocalLtk));
break;
case EfiBluetoothSmpLocalIRK:
CopyMem(RemoteData->LocalIrk, Data, sizeof(RemoteData->LocalIrk));
break;
case EfiBluetoothSmpLocalCSRK:
CopyMem(RemoteData->LocalCsrk, Data, sizeof(RemoteData->LocalCsrk));
break;
case EfiBluetoothSmpLocalSignCounter:
CopyMem(&RemoteData->LocalSignCounter, Data, sizeof(RemoteData->LocalSignCounter));
break;
case EfiBluetoothSmpLocalDIV:
Status = EFI_UNSUPPORTED;
break;
default:
Status = EFI_INVALID_PARAMETER;
break;
}
//
// Only save the data if the remote device storage has saved before.
// It means this callback type is trigged after connect complete.
//
if (mBtConfigDevice->PairedDevDataSaved[Index]) {
SavePairedDevice(IDAddr);
}
}
return Status;
}
/**
Update device status.
**/
VOID
UpdateDeviceStatus (
VOID
)
{
EFI_HANDLE *Handles;
UINTN NumberOfHandles;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
BLUETOOTH_LE_DEVICE_PATH *LeDevicePath;
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiBluetoothAttributeServiceBindingProtocolGuid,
NULL,
&NumberOfHandles,
&Handles
);
for (Index = 0; Index < NumberOfHandles; Index++) {
DevicePath = DevicePathFromHandle (Handles[Index]);
if (DevicePath == NULL) {
continue;
}
while (!IsDevicePathEnd (DevicePath)) {
if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH && DevicePathSubType (DevicePath) == MSG_BLUETOOTH_LE_DP) {
LeDevicePath = (BLUETOOTH_LE_DEVICE_PATH *) DevicePath;
DEBUG ((DEBUG_VERBOSE , "BtCfgDxe :: Find BLE Device Node (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
LeDevicePath->Address.Address[0], LeDevicePath->Address.Address[1],
LeDevicePath->Address.Address[2], LeDevicePath->Address.Address[3],
LeDevicePath->Address.Address[4], LeDevicePath->Address.Address[5],
LeDevicePath->Address.Type));
RemoteDev = LocateDevInList(LeDevicePath->Address.Address, EfiAnyAddressType);
if (RemoteDev != NULL) {
RemoteDev->RemoteDeviceState |= EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED;
DEBUG ((DEBUG_INFO , "BtCfgDxe :: Add Connected status for device (%02x:%02x:%02x:%02x:%02x:%02x(%x))\n",
LeDevicePath->Address.Address[0], LeDevicePath->Address.Address[1],
LeDevicePath->Address.Address[2], LeDevicePath->Address.Address[3],
LeDevicePath->Address.Address[4], LeDevicePath->Address.Address[5],
LeDevicePath->Address.Type));
}
break;
}
DevicePath = NextDevicePathNode (DevicePath);
}
}
if (Handles != NULL) {
FreePool (Handles);
}
}
/**
Initialize the Paired device list.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_SUCCESS Initialize the Paired device list successfully.
**/
EFI_STATUS
InitializePairedDevice (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
CHAR16 RemoteBdAddrStr[LE_BD_ADDR_STR_LEN];
UINTN RemoteDataSize;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDevAttr;
InitializeListHead (&mBtConfigDevice->RemoteDeviceList);
for (Index = 0; Index < EFI_BLUETOOTH_LE_MAX_BONDED_DEV; Index++) {
if (!IsValidBleAddress(&mBtConfigDevice->ControllerData.RemoteIDAddr[Index])) {
continue;
}
//
// Found remote device entry in local device storage
//
ZeroMem(RemoteBdAddrStr, sizeof(RemoteBdAddrStr));
LE_BDADDR_TO_STRING(RemoteBdAddrStr, mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address, mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Type);
RemoteDataSize = sizeof(BT_LE_REMOTE_DEV_STORAGE);
Status = gRT->GetVariable(RemoteBdAddrStr,
&gEfiBluetoothLeConfigProtocolGuid,
NULL,
&RemoteDataSize,
&mBtConfigDevice->PairedDevData[Index]);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "BtCfgDxe :: Warning! Device in LocalDeviceData don't have local storage! %02x:%02x:%02x:%02x:%02x:%02x(%x)!\n",
mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[0], mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[1],
mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[2], mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[3],
mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[4], mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Address[5],
mBtConfigDevice->ControllerData.RemoteIDAddr[Index].Type
));
ZeroMem (&mBtConfigDevice->ControllerData.RemoteIDAddr[Index], sizeof(BLUETOOTH_LE_ADDRESS));
ZeroMem (&mBtConfigDevice->PairedDevData[Index], sizeof(BT_LE_REMOTE_DEV_STORAGE));
continue;
}
DumpRemoteDeviceData(&mBtConfigDevice->PairedDevData[Index]);
mBtConfigDevice->PairedDevDataSaved[Index] = TRUE;
mBtConfigDevice->PairedDevCount++;
RemoteDevAttr = AllocateZeroPool (sizeof (BT_REMOTE_DEVICE_ATTRIBUTE));
if (RemoteDevAttr == NULL){
return EFI_OUT_OF_RESOURCES;
}
RemoteDevAttr->Signature = BT_REMOTE_DEVICE_SIGNATURE;
CopyMem (&RemoteDevAttr->IDAddr, &mBtConfigDevice->ControllerData.RemoteIDAddr[Index], sizeof (RemoteDevAttr->IDAddr));
CopyMem (RemoteDevAttr->LocalName, mBtConfigDevice->PairedDevData[Index].PeerName, sizeof(RemoteDevAttr->LocalName));
RemoteDevAttr->RemoteDeviceState = EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED;
InsertTailList (&mBtConfigDevice->RemoteDeviceList, &RemoteDevAttr->Link);
}
UpdateDeviceStatus ();
DumpRemoteDeviceList ();
return EFI_SUCCESS;
}
/**
Initialize the host controller related data.
**/
VOID
InitializeControllerData (
VOID
)
{
EFI_STATUS Status;
UINTN LocalDataSize;
Status = EFI_SUCCESS;
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->GetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
NULL,
&LocalDataSize,
&mBtConfigDevice->ControllerData);
if ((LocalDataSize != sizeof(BT_LE_LOCAL_DEV_STORAGE)) || (mBtConfigDevice->ControllerData.LocalName[MAX_DEVICE_NAME_LEN - 1] != 0)) {
Status = RETURN_COMPROMISED_DATA; // Data is corrupted
}
if (EFI_ERROR (Status)) {
SetMem(&mBtConfigDevice->ControllerData, sizeof(BT_LE_LOCAL_DEV_STORAGE), 0);
AsciiStrCpyS((CHAR8 *)mBtConfigDevice->ControllerData.LocalName, sizeof(mBtConfigDevice->ControllerData.LocalName), BT_DEFAULT_NAME);
LocalDataSize = sizeof(BT_LE_LOCAL_DEV_STORAGE);
Status = gRT->SetVariable(mLocalDeviceDataVariableName,
&gEfiBluetoothLeConfigProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LocalDataSize,
&mBtConfigDevice->ControllerData);
ASSERT_EFI_ERROR (Status);
}
DumpLocalDeviceData (&mBtConfigDevice->ControllerData);
}
/**
Initialize the ble stack.
@retval return the status.
**/
EFI_STATUS
InitializeBleStack (
VOID
)
{
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
EFI_STATUS Status;
Status = EFI_SUCCESS;
LeConfigProtocol = mBtConfigDevice->BluetoothLeConfig;
LeConfigProtocol->RegisterSmpGetDataCallback(LeConfigProtocol, LeSmpGetDataCallback, NULL);
LeConfigProtocol->RegisterSmpSetDataCallback(LeConfigProtocol, LeSmpSetDataCallback, NULL);
LeConfigProtocol->RegisterSmpAuthCallback(LeConfigProtocol, SmpCallback, NULL);
LeConfigProtocol->RegisterLinkConnectCompleteCallback(LeConfigProtocol, LinkConnCompCallback, NULL);
Status = LeConfigProtocol->Init (LeConfigProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
Status = LeConfigProtocol->SetData (
LeConfigProtocol,
EfiBluetoothConfigDataTypeDeviceName,
AsciiStrnLenS ((CHAR8 *)mBtConfigDevice->ControllerData.LocalName, MAX_DEVICE_NAME_LEN),
mBtConfigDevice->ControllerData.LocalName
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "BtCfgDxe :: Update host controller name to %a!\n", mBtConfigDevice->ControllerData.LocalName));
return EFI_SUCCESS;
}
/**
This function processes the results of changes in configuration.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Action Specifies the type of action taken by the browser.
@param QuestionId A unique value which is sent to the original exporting driver
so that it can identify the type of data to expect.
@param Type The type of value for the question.
@param Value A pointer to the data being sent to the original exporting driver.
@param ActionRequest On return, points to the action requested by the callback function.
@retval EFI_SUCCESS The callback successfully handled the action.
@retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
@retval EFI_DEVICE_ERROR The variable could not be saved.
@retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
**/
EFI_STATUS
EFIAPI
HiiConfigAccessCallback (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
)
{
EFI_STATUS Status;
UINT64 InputValue;
CHAR16 *UnicodeData;
EFI_STRING_ID StringId;
BT_REMOTE_DEVICE_ATTRIBUTE *RemoteDev;
EFI_INPUT_KEY Key;
UINT8 Index;
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
Status = EFI_SUCCESS;
UnicodeData = NULL;
LeConfigProtocol = mBtConfigDevice->BluetoothLeConfig;
if ((LeConfigProtocol == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)) {
return EFI_UNSUPPORTED;
}
switch (Action) {
case EFI_BROWSER_ACTION_FORM_OPEN:
{
switch (QuestionId) {
case KEY_HOST_CONTROLLER_LOCAL_NAME:
if (!mBtConfigDevice->FinishHostInit) {
Status = GetDeviceAddress (LeConfigProtocol, &UnicodeData);
if (!EFI_ERROR (Status)) {
StringId = HiiSetString (
mBtConfigDevice->HiiHandle,
STRING_TOKEN (STR_ADDRESS_STRING_VALUE),
UnicodeData,
NULL
);
FreePool (UnicodeData);
}
mBtConfigDevice->FinishHostInit = TRUE;
}
break;
case KEY_GOTO_DEVICE_MANAGER:
UpdateScanMenu ();
UpdateDevicePage ();
break;
default:
break;
}
}
break;
case EFI_BROWSER_ACTION_RETRIEVE:
{
switch (QuestionId) {
case KEY_HOST_CONTROLLER_LOCAL_NAME:
Status = GetLocalName (LeConfigProtocol, &UnicodeData);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
} else {
StringId = HiiSetString (
mBtConfigDevice->HiiHandle,
Value->string,
UnicodeData,
NULL
);
if (StringId == 0) {
Status = EFI_OUT_OF_RESOURCES;
}
}
break;
case KEY_REFRESH_DEVICE_ID:
if (mBtConfigDevice->FoundNewDevice) {
mBtConfigDevice->FoundNewDevice = FALSE;
UpdateDevicePage ();
if (mBtConfigDevice->UpdateScanMenu) {
UpdateScanMenu ();
mBtConfigDevice->UpdateScanMenu = FALSE;
}
}
break;
default:
break;
}
}
break;
case EFI_BROWSER_ACTION_CHANGING:
{
if (QuestionId >= CONNECT_DEVICE_OFFSET && QuestionId < CONNECT_DEVICE_OFFSET + DEVICE_LIST_MAX) {
//
// Press connect for one device.
//
RemoteDev = GetRemoteDevice (QuestionId - CONNECT_DEVICE_OFFSET);
if (RemoteDev == NULL){
return EFI_DEVICE_ERROR;
}
if (((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED) == 0) &&
(mBtConfigDevice->PairedDevCount == EFI_BLUETOOTH_LE_MAX_BONDED_DEV)) {
//
// Forbid to connect to a new device when paired device count is equal to EFI_BLUETOOTH_LE_MAX_BONDED_DEV.
//
ConnectResultPopup (RemoteDev, ResultExceedMaxPairedDevices);
Status = EFI_UNSUPPORTED;
break;
}
PERF_START (NULL, "Connect", "Bluetooth", 0);
ConnectDevice (RemoteDev);
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) == 0) {
ConnectResultPopup(RemoteDev, ResultConnectFail);
}
} else if (QuestionId >= DISCONNECT_DEVICE_OFFSET && QuestionId < DISCONNECT_DEVICE_OFFSET + DEVICE_LIST_MAX) {
//
// Press disconnect for one device.
//
RemoteDev = GetRemoteDevice (QuestionId - DISCONNECT_DEVICE_OFFSET);
if (RemoteDev == NULL){
ASSERT (RemoteDev != NULL);
return EFI_DEVICE_ERROR;
}
DisconnectDevice(RemoteDev, BluetoothDisconnectReasonTypeRemoteUserTerminatedConnection);
if ((RemoteDev->RemoteDeviceState & EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED) != 0) {
ConnectResultPopup(RemoteDev, ResultDisconnectFail);
}
} else if (QuestionId >= REMOTE_DEVICE_OFFSET && QuestionId < REMOTE_DEVICE_OFFSET + DEVICE_LIST_MAX) {
//
// Press DeviceInfo for one device.
//
RemoteDev = GetRemoteDevice (QuestionId - REMOTE_DEVICE_OFFSET);
if (RemoteDev == NULL){
ASSERT (RemoteDev != NULL);
return EFI_DEVICE_ERROR;
}
DEBUG ((EFI_D_INFO, "BtCfgDxe :: Enter remote Device page: %a, Addr: %02x:%02x:%02x:%02x:%02x:%02x(%x)\n",
RemoteDev->LocalName,
RemoteDev->AdvAddr.Address[0],RemoteDev->AdvAddr.Address[1],
RemoteDev->AdvAddr.Address[2],RemoteDev->AdvAddr.Address[3],
RemoteDev->AdvAddr.Address[4],RemoteDev->AdvAddr.Address[5],
RemoteDev->AdvAddr.Type
));
Status = UpdateRemoteDevPageInfo (RemoteDev);
} else if (QuestionId >= DELETE_DEVICE_OFFSET && QuestionId < DELETE_DEVICE_OFFSET + DEVICE_LIST_MAX) {
//
// Press Delete for one device.
//
RemoteDev = GetRemoteDevice (QuestionId - DELETE_DEVICE_OFFSET);
if (RemoteDev == NULL){
ASSERT (RemoteDev != NULL);
return EFI_DEVICE_ERROR;
}
DisconnectDevice (RemoteDev, BluetoothDisconnectReasonTypeRemoteDeviceTerminatedConnectionDueToLowResources);
DeleteRemoteDeviceByAddress (&RemoteDev->IDAddr);
} else if (QuestionId == KEY_HOST_CONTROLLER_LOCAL_NAME) {
GetInputValue (Type, Value, &InputValue);
UnicodeData = HiiGetString (mBtConfigDevice->HiiHandle, (EFI_STRING_ID) InputValue, NULL);
if (UnicodeData == NULL){
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < StrLen (UnicodeData); Index ++) {
if (UnicodeData[Index] != L' ') {
break;
}
}
if (Index == StrLen (UnicodeData)) {
do {
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Update fail! LocalName cannot contain only spaces", L"Press ENTER to continue", NULL);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
Status = EFI_DEVICE_ERROR;
}
FreePool (UnicodeData);
}
}
break;
case EFI_BROWSER_ACTION_CHANGED:
{
if ((QuestionId >= DELETE_DEVICE_OFFSET && QuestionId < DELETE_DEVICE_OFFSET + DEVICE_LIST_MAX) ||
(QuestionId >= CONNECT_DEVICE_OFFSET && QuestionId < CONNECT_DEVICE_OFFSET + DEVICE_LIST_MAX) ||
(QuestionId >= DISCONNECT_DEVICE_OFFSET && QuestionId < DISCONNECT_DEVICE_OFFSET + DEVICE_LIST_MAX)){
//
// Update the remote device list form.
//
UpdateDevicePage ();
} else {
switch (QuestionId) {
case KEY_HOST_CONTROLLER_LOCAL_NAME:
GetInputValue (Type, Value, &InputValue);
UnicodeData = HiiGetString (mBtConfigDevice->HiiHandle, (EFI_STRING_ID) InputValue, NULL);
if (UnicodeData == NULL){
return EFI_OUT_OF_RESOURCES;
}
Status = SetLocalName (LeConfigProtocol, UnicodeData);
FreePool (UnicodeData);
break;
case KEY_SCAN_DEVICE_ID:
//
// Clean the saved device list before do the new scan.
// Clean the available device in scan page before do the new scan.
//
DeleteRemoteDeviceByState (0);
UpdateDevicePage ();
mBtConfigDevice->InScanning = TRUE;
Status = LeConfigProtocol->Scan (LeConfigProtocol, TRUE, 10, NULL, ScanCallback, NULL);
if (!EFI_ERROR (Status)) {
UpdateScanMenu ();
}
break;
default:
break;
}
}
}
break;
default:
break;
}
return Status;
}
/**
Initialization function for HII.
@param[in] ImageHandle The image handle of this driver.
@param[in] Controller The controller handle.
@param[in] DevicePath Device path of the HII form set.
@retval EFI_SUCESS The HII initialization completes successfully.
@retval Other A value from other functions.
**/
EFI_STATUS
EFIAPI
BluetoothConfigHiiInit (
IN EFI_HANDLE ImageHandle,
IN EFI_HANDLE *Controller,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_STATUS Status;
mBtConfigDevice->ConfigAccess.ExtractConfig = HiiConfigAccessExtractConfig;
mBtConfigDevice->ConfigAccess.RouteConfig = HiiConfigAccessRouteConfig;
mBtConfigDevice->ConfigAccess.Callback = HiiConfigAccessCallback;
//
// Publish sample Fromset
//
Status = gBS->InstallMultipleProtocolInterfaces (
Controller,
&gEfiDevicePathProtocolGuid,
DevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mBtConfigDevice->ConfigAccess,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
mBtConfigDevice->HiiHandle = HiiAddPackages (
&gHiiBluetoothConfigFormSetGuid,
*Controller,
BluetoothConnectionManagerBin,
BluetoothConfigDxeStrings,
NULL
);
ASSERT (mBtConfigDevice->HiiHandle != NULL);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
EfiEventEmptyFunction,
NULL,
&gIfrRefreshRemoteDevGuid,
&mBtConfigDevice->RefreshRemoteDevEvent
);
ASSERT_EFI_ERROR (Status);
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
EfiEventEmptyFunction,
NULL,
&mBtConfigDevice->PasskeyInputEvent
);
ASSERT_EFI_ERROR (Status);
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
StartDeviceDrivers,
NULL,
&mBtConfigDevice->ConnectDriverEvent
);
ASSERT_EFI_ERROR (Status);
//
// Create a lock for performing device list update.
//
EfiInitializeLock (&mBtConfigDevice->DeviceListLock, TPL_NOTIFY);
return EFI_SUCCESS;
}
/**
Unloads the application and its installed protocol.
@param[in] ImageHandle Handle that identifies the image to be unloaded.
@retval EFI_SUCCESS The image has been unloaded.
**/
EFI_STATUS
BluetoothConfigUninit (
VOID
)
{
gBS->CloseEvent (mBtConfigDevice->RefreshRemoteDevEvent);
gBS->CloseEvent (mBtConfigDevice->PasskeyInputEvent);
gBS->CloseEvent (mBtConfigDevice->ConnectDriverEvent);
if (mBtConfigDevice->ControllerHandle != NULL) {
gBS->UninstallMultipleProtocolInterfaces (
mBtConfigDevice->ControllerHandle,
&gEfiDevicePathProtocolGuid,
mBtConfigDevice->DevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mBtConfigDevice->ConfigAccess,
NULL
);
}
if (mBtConfigDevice->HiiHandle != NULL) {
HiiRemovePackages (mBtConfigDevice->HiiHandle);
}
return EFI_SUCCESS;
}
/**
Clean up global data mBtConfigDevice.
@param This The HID KB driver binding instance.
@param Controller Handle of device to bind driver to.
**/
VOID
CleanUpBtConfigDevice (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller
)
{
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
LeConfigProtocol = mBtConfigDevice->BluetoothLeConfig;
LeConfigProtocol->RegisterSmpAuthCallback(LeConfigProtocol, NULL, NULL);
LeConfigProtocol->RegisterLinkConnectCompleteCallback(LeConfigProtocol, NULL, NULL);
LeConfigProtocol->RegisterSmpGetDataCallback(LeConfigProtocol, NULL, NULL);
LeConfigProtocol->RegisterSmpSetDataCallback(LeConfigProtocol, NULL, NULL);
gBS->CloseProtocol (
Controller,
&gEfiBluetoothLeConfigProtocolGuid,
This->DriverBindingHandle,
Controller
);
BluetoothConfigUninit ();
DeleteRemoteDeviceByState (0);
DeleteRemoteDeviceByState (EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED);
DeleteRemoteDeviceByState (EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_PAIRED | EFI_BLUETOOTH_CONFIG_REMOTE_DEVICE_STATE_CONNECTED);
ASSERT (IsListEmpty (&mBtConfigDevice->RemoteDeviceList));
if (mBtConfigDevice->DevicePath != NULL) {
FreePool (mBtConfigDevice->DevicePath);
}
if (mBtConfigDevice->ControllerNameTable != NULL) {
FreePool (mBtConfigDevice->ControllerNameTable);
}
FreePool (mBtConfigDevice);
}
/**
Entrypoint of HID KB Driver.
This function is the entrypoint of HID KB Driver. It installs Driver Binding
Protocols together with Component Name Protocols.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
**/
EFI_STATUS
EFIAPI
BluetoothConfigDriverBindingEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gBluetoothConfigDriverBinding,
ImageHandle,
&gBluetoothConfigComponentName,
&gBluetoothConfigComponentName2
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
/**
Check whether HID KB driver supports this device.
@param This The HID KB driver binding protocol.
@param Controller The controller handle to check.
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The driver supports this controller.
@retval other This device isn't supported.
**/
EFI_STATUS
EFIAPI
BluetoothConfigDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *ConfigProtocol;
Status = gBS->OpenProtocol (
Controller,
&gEfiBluetoothLeConfigProtocolGuid,
(VOID **) &ConfigProtocol,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
Controller,
&gEfiBluetoothLeConfigProtocolGuid,
This->DriverBindingHandle,
Controller
);
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingSupported: %r\n", Status));
return Status;
}
/**
Starts the HID KB device with this driver.
This function consumes Hid I/O Portocol, intializes HID KB device,
installs SimpleTextIn Protocol.
@param This The HID KB driver binding instance.
@param Controller Handle of device to bind driver to.
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_UNSUPPORTED This driver does not support this device.
@retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_ALREADY_STARTED This driver has been started.
**/
EFI_STATUS
EFIAPI
BluetoothConfigDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_BLUETOOTH_LE_CONFIG_PROTOCOL *LeConfigProtocol;
EFI_DEVICE_PATH *DevicePath;
BT_CONFIG_DEV *BtConfigDevice;
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingStart: Enter Controller = %p\n", Controller));
BtConfigDevice = NULL;
//
// Open Hid I/O Protocol
//
Status = gBS->OpenProtocol (
Controller,
&gEfiBluetoothLeConfigProtocolGuid,
(VOID **) &LeConfigProtocol,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the Device Path Protocol on Controller's handle
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &DevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
Controller,
&gEfiBluetoothLeConfigProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
BtConfigDevice = AllocateZeroPool (sizeof (BT_CONFIG_DEV));
if (BtConfigDevice == NULL){
return EFI_OUT_OF_RESOURCES;
}
BtConfigDevice->Signature = BTCONFIG_DEV_SIGNATURE;
BtConfigDevice->BluetoothLeConfig = LeConfigProtocol;
BtConfigDevice->DevicePath = AppendDevicePath (DevicePath, (EFI_DEVICE_PATH *)&mBtConfigDevicePath);
mBtConfigDevice = BtConfigDevice;
Status = BluetoothConfigHiiInit (This->DriverBindingHandle, &BtConfigDevice->ControllerHandle, BtConfigDevice->DevicePath);
ASSERT_EFI_ERROR (Status);
BtConfigDevice->ControllerNameTable = NULL;
AddUnicodeString2 (
"eng",
gBluetoothConfigComponentName.SupportedLanguages,
&BtConfigDevice->ControllerNameTable,
L"Bluetooth Config Driver",
TRUE
);
AddUnicodeString2 (
"en",
gBluetoothConfigComponentName2.SupportedLanguages,
&BtConfigDevice->ControllerNameTable,
L"Bluetooth Config Driver",
FALSE
);
InitializeControllerData ();
InitializePairedDevice ();
Status = InitializeBleStack ();
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingStart: Exit Success\n"));
PERF_END (NULL, "Init", "Bluetooth", 0);
return EFI_SUCCESS;
//
// Error handler
//
ErrorExit:
if (EFI_ERROR (Status)) {
CleanUpBtConfigDevice (This, Controller);
}
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingStart: Exit - %r\n", Status));
return Status;
}
/**
Stop the HID KB device handled by this driver.
@param This The HID KB driver binding protocol.
@param Controller The controller to release.
@param NumberOfChildren The number of handles in ChildHandleBuffer.
@param ChildHandleBuffer The array of child handle.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_UNSUPPORTED SimpleTextIn Protocol is not installed on Controller.
@retval Others Fail to uninstall protocols attached on the device.
**/
EFI_STATUS
EFIAPI
BluetoothConfigDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingStop: ctrl = %x, no = %x\n", Controller, NumberOfChildren));
CleanUpBtConfigDevice (This, Controller);
DEBUG ((EFI_D_ERROR, "BluetoothConfigDriverBindingStop: Exit status = EFI_SUCCESS\n"));
return EFI_SUCCESS;
}