alder_lake_bios/Insyde/InsydeModulePkg/Universal/Console/SnapScreenDxe/SnapLib.c

934 lines
19 KiB
C

/** @file
SnapScree driver for capature screen image to BMP file.
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Library/PrintLib.h>
#include <Library/VariableLib.h>
#include <IndustryStandard/Atapi.h>
#include "SnapLib.h"
#include "SnapConOut.h"
#include <Protocol/DiskInfo.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Guid/FileSystemInfo.h>
#include <Guid/GlobalVariable.h>
#define TYPE_IDENTIFY 0
#define TYPE_INQUIRY 1
#define MAX_LABEL_LENGHT 11
typedef struct _DISK_TYPE_INFO {
DISK_TYPE Type;
EFI_GUID *Guid;
} DISK_TYPE_INFO;
DISK_TYPE_INFO gDiskType[] = {
{DT_IDE, &gEfiDiskInfoIdeInterfaceGuid},
{DT_SCSI, &gEfiDiskInfoScsiInterfaceGuid},
{DT_USB, &gEfiDiskInfoUsbInterfaceGuid},
{DT_AHCI, &gEfiDiskInfoAhciInterfaceGuid},
{DT_UNKNOW, NULL}
};
static EFI_GRAPHICS_OUTPUT_PROTOCOL *mActiveVgaGop = NULL;
/**
Removes (trims) specified leading and trailing characters from a string.
@param[in, out] Str Pointer to the null-terminated string to be trimmed. On return,
Str will hold the trimmed string.
@param[in] CharC Character will be trimmed from str.
**/
VOID
StrTrim (
IN OUT CHAR16 *Str,
IN CHAR16 CharC
)
{
CHAR16 *Pointer1;
CHAR16 *Pointer2;
if (*Str == 0) {
return;
}
//
// Trim off the leading and trailing characters c
//
for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
;
}
Pointer2 = Str;
if (Pointer2 == Pointer1) {
while (*Pointer1 != 0) {
Pointer2++;
Pointer1++;
}
} else {
while (*Pointer1 != 0) {
*Pointer2 = *Pointer1;
Pointer1++;
Pointer2++;
}
*Pointer2 = 0;
}
for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
;
}
if (Pointer1 != Str + StrLen(Str) - 1) {
*(Pointer1 + 1) = 0;
}
}
/**
Duplicates a string.
@param Src Source string.
@return The duplicated string.
**/
CHAR16 *
StrDuplicate (
IN CONST CHAR16 *Src
)
{
return AllocateCopyPool (StrSize (Src), Src);
}
CHAR16 *
EfiStrDuplicate (
IN CHAR16 *Src
)
{
CHAR16 *Dest;
UINTN Size;
Size = StrSize (Src);
Dest = AllocateZeroPool (Size);
ASSERT (Dest != NULL);
if (Dest) {
CopyMem (Dest, Src, Size);
}
return Dest;
}
/**
Calculate the size of device path
@param DevicePath Pointer of EFI_DEVICE_PATH_PROTOCOL
@retval Size of device path
**/
STATIC
UINTN
DevicePathSize (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *Start;
if (DevicePath == NULL) {
return 0;
}
//
// Search for the end of the device path structure
//
Start = DevicePath;
while (!IsDevicePathEnd (DevicePath)) {
DevicePath = NextDevicePathNode (DevicePath);
}
//
// Compute the size and add back in the size of the end device path structure
//
return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
}
VOID
TruncateLastNode (
IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *LastNode = NULL;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
DevPath = DevicePath;
while (!IsDevicePathEnd(DevPath)) {
LastNode = DevPath;
DevPath = NextDevicePathNode (DevPath);
}
if (LastNode != NULL) {
CopyMem( LastNode, DevPath, sizeof(EFI_DEVICE_PATH_PROTOCOL));
}
return;
}
EFI_STATUS
GetParentHandle (
EFI_HANDLE ChildHandle,
EFI_HANDLE *ParentHandle
)
{
EFI_STATUS Status = EFI_NOT_FOUND;
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_PROTOCOL *TmpDevPath;
EFI_DEVICE_PATH_PROTOCOL *OrgDevPath;
Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
if (EFI_ERROR(Status)) {
return Status;
}
OrgDevPath = DuplicateDevicePath (DevicePath);
TmpDevPath = OrgDevPath;
if (TmpDevPath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
TruncateLastNode (TmpDevPath);
gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TmpDevPath, &Handle);
if (IsDevicePathEnd(TmpDevPath)) {
*ParentHandle = Handle;
Status = EFI_SUCCESS;
}
FreePool (OrgDevPath);
return Status;
}
VOID
ValueToString (
UINTN Value,
UINTN Digitals,
CHAR16 *Buffer,
UINTN Flags
)
{
CHAR8 Str[30];
UINTN mod;
CHAR8 *p1;
CHAR16 *p2;
CHAR16 StuffChar = 0;
UINTN count = 0;
UINTN Padding;
p1 = Str;
p2 = Buffer;
if (Flags == VTS_RIGHT_ALIGN)
StuffChar = L' ';
if (Flags == VTS_LEAD_0)
StuffChar = L'0';
if (Value == 0) {
// Stuff specify char to buffer
if (StuffChar != 0) {
Padding = Digitals - 1;
while (Padding > 0) {
*p2 = StuffChar;
p2++;
Padding--;
}
}
*p2++ = '0';
*p2 = 0;
return ;
}
while (Value) {
mod = Value % 10;
*p1 = (CHAR8)(mod + '0');
Value = Value / 10;
p1++;
count++;
}
if ((count < Digitals) && (StuffChar != 0)) {
Padding = Digitals - count;
while (Padding) {
*p2 = StuffChar;
p2++;
Padding--;
}
}
while (count > 0) {
p1--;
*p2 = *p1;
p2++;
count--;
}
*p2 = 0;
}
EFI_STATUS
GetDiskIdentifyData (
EFI_DISK_INFO_PROTOCOL *DiskInfo,
UINT8 **Buffer,
UINTN *BufferSize
)
{
EFI_STATUS Status;
UINT8 *IdentifyData = NULL;
UINT32 DataSize;
DataSize = 0;
Status = DiskInfo->Identify (DiskInfo, IdentifyData, &DataSize);
// process buffer too small
if (Status == EFI_BUFFER_TOO_SMALL) {
IdentifyData = AllocatePool ( DataSize);
if (IdentifyData == NULL)
return EFI_OUT_OF_RESOURCES;
Status = DiskInfo->Identify (DiskInfo, IdentifyData, &DataSize);
}
if (EFI_ERROR(Status)) {
if (IdentifyData != NULL)
FreePool (IdentifyData);
return Status;
}
*Buffer = IdentifyData;
*BufferSize = DataSize;
return Status;
}
EFI_STATUS
GetDiskInquiryData (
EFI_DISK_INFO_PROTOCOL *DiskInfo,
UINT8 **Buffer,
UINTN *BufferSize
)
{
EFI_STATUS Status;
UINT8 *InquiryData = NULL;
UINT32 DataSize;
DataSize = 0;
Status = DiskInfo->Inquiry (DiskInfo, InquiryData, &DataSize);
// process buffer too small
if (Status == EFI_BUFFER_TOO_SMALL) {
InquiryData = AllocatePool ( DataSize);
Status = DiskInfo->Inquiry (DiskInfo, InquiryData, &DataSize);
}
//
if (EFI_ERROR(Status)) {
if (InquiryData != NULL)
FreePool (InquiryData);
return Status;
}
*Buffer = InquiryData;
*BufferSize = DataSize;
return Status;
}
VOID
UsbVendorIdToUnicodeStr (
CHAR16 *Buffer,
CHAR8 *VendorId
)
{
UINTN Index;
for (Index = 0; Index < 8; Index++)
*Buffer++ = *VendorId++;
*Buffer = 0;
// Trim space char
StrTrim(Buffer, L' ');
return;
}
CHAR16 *
GetNameFromInquiry (
DISK_TYPE Type,
UINT8 *Data
)
{
CHAR16 Buffer[9];
CHAR16 *Str;
ATAPI_INQUIRY_DATA *InquiryData;
USB_BOOT_INQUIRY_DATA *UsbInquiry;
Buffer [8] = 0;
switch (Type) {
case DT_IDE :
case DT_AHCI :
case DT_SCSI :
InquiryData = (ATAPI_INQUIRY_DATA *) Data;
UsbVendorIdToUnicodeStr( Buffer, InquiryData->vendor_info);
Str = StrDuplicate( Buffer);
break;
case DT_USB :
UsbInquiry = (USB_BOOT_INQUIRY_DATA *) Data;
UsbVendorIdToUnicodeStr (Buffer, UsbInquiry->VendorID);
Str = StrDuplicate(Buffer);
break;
default :
Str = NULL;
}
return Str;
}
VOID
IdentifyModelNameToUnicode (
CHAR16 *Buffer,
CHAR8 *ModelName
)
{
UINTN Index;
CHAR8 SwModelName[41];
CHAR8 *Ptr;
// swap ATA hi-lo byte
for (Index=0; Index < 40; Index+=2) {
SwModelName[Index] = ModelName[Index+1];
SwModelName[Index+1] = ModelName[Index];
}
SwModelName[40] = 0;
Ptr = SwModelName;
while (*Ptr && *Ptr == ' ') Ptr++;
for (Index = 0; Index <= 12; Index++) {
if (*Ptr == 0)
break;
*Buffer++ = *Ptr++;
}
*Buffer = 0;
}
CHAR16 *
GetNameFromIdentify (
DISK_TYPE Type,
UINT8 *Data
)
{
ATA5_IDENTIFY_DATA *AtaIdentifyData;
CHAR16 *ModelName;
CHAR16 Buffer[13];
switch (Type) {
case DT_IDE :
case DT_AHCI :
case DT_SCSI :
AtaIdentifyData = (ATA5_IDENTIFY_DATA *) Data;
IdentifyModelNameToUnicode (Buffer, AtaIdentifyData->ModelName);
StrTrim (Buffer, L' ');
ModelName = StrDuplicate(Buffer);
break;
case DT_USB :
default :
ModelName = NULL;
}
return ModelName;
}
DISK_TYPE
GetDiskInfoType (
EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_DISK_INFO_PROTOCOL *DiskInfo;
UINTN Index;
Status = gBS->HandleProtocol (Handle, &gEfiDiskInfoProtocolGuid, (VOID **)&DiskInfo);
if (EFI_ERROR(Status))
return DT_UNKNOW;
for (Index=0; gDiskType[Index].Type != DT_UNKNOW; Index++) {
if (CompareGuid(&DiskInfo->Interface, gDiskType[Index].Guid) == TRUE)
break;
}
return gDiskType[Index].Type;
}
CHAR16 *
GetDiskInfoName (
EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_DISK_INFO_PROTOCOL *DiskInfo;
UINTN BufferSize = 512;
UINT8 *Buffer = NULL;
DISK_TYPE DiskType;
UINT8 DataType;
CHAR16 *ProductName = NULL;
DiskType = GetDiskInfoType (Handle);
if (DiskType == DT_UNKNOW) {
return NULL;
}
Status = gBS->HandleProtocol (Handle, &gEfiDiskInfoProtocolGuid, (VOID **)&DiskInfo);
if (EFI_ERROR(Status))
return NULL;
DataType = TYPE_IDENTIFY;
Status = GetDiskIdentifyData ( DiskInfo, &Buffer, &BufferSize);
if (EFI_ERROR(Status)) {
DataType = TYPE_INQUIRY;
Status = GetDiskInquiryData (DiskInfo, &Buffer, &BufferSize);
if (EFI_ERROR(Status)) {
return NULL;
}
}
switch (DataType) {
case TYPE_IDENTIFY :
ProductName = GetNameFromIdentify (DiskType, Buffer);
break;
case TYPE_INQUIRY :
ProductName = GetNameFromInquiry (DiskType, Buffer);
break;
}
if (Buffer != NULL)
FreePool (Buffer);
return ProductName;
}
CHAR16 *
GetVolumnName (
EFI_HANDLE FsHandle
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
EFI_FILE *RootFs;
UINTN Size;
EFI_FILE_SYSTEM_INFO *VolumeInfo;
CHAR16 LabelStr[MAX_LABEL_LENGHT+1] = {0};
CHAR16 *VolumeName = NULL;
Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileSystem);
if (EFI_ERROR(Status))
return NULL;
Status = FileSystem->OpenVolume (FileSystem, &RootFs);
if (EFI_ERROR(Status))
return NULL;
Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocatePool (Size);
if (VolumeInfo == NULL) {
return NULL;
}
Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
if (Status == EFI_SUCCESS) {
if (VolumeInfo->VolumeLabel[0] != 0) {
StrnCpyS (LabelStr, sizeof (LabelStr) / sizeof (CHAR16), VolumeInfo->VolumeLabel, MAX_LABEL_LENGHT);
VolumeName = StrDuplicate(LabelStr);
}
}
FreePool (VolumeInfo);
return VolumeName;
}
VOID
ConvDititalByUnit (
CHAR16 *Str,
UINTN StrBufSize
)
{
UINTN Len;
UINTN Quotient;
CHAR16 *Ptr;
CHAR16 LastD;
INT16 Pos;
Len = StrLen(Str);
Quotient = (Len-1) / 3;
Ptr = Str;
while (*Ptr != 0) Ptr++;
if (Quotient != 0) {
Pos = -((INT16)Quotient * 3);
LastD = Ptr[Pos];
if (LastD != L'0') {
Ptr[Pos++] = L'.';
Ptr[Pos++] = LastD;
Ptr[Pos] = 0;
}
else {
Ptr[Pos] = 0;
}
}
switch (Quotient) {
//Bytes
case 0:
StrCatS (Str, StrBufSize / sizeof(CHAR16), L"Byte");
break;
// KB
case 1:
StrCatS (Str, StrBufSize / sizeof(CHAR16), L" KB");
break;
// MB
case 2:
StrCatS (Str, StrBufSize / sizeof(CHAR16), L" MB");
break;
// GB
case 3 :
StrCatS (Str, StrBufSize / sizeof(CHAR16), L" GB");
break;
default :
StrCatS (Str, StrBufSize / sizeof(CHAR16), L" TB");
break;
}
}
CHAR16 *
GetVolumnSizeAsString (
EFI_HANDLE FsHandle
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
EFI_FILE *RootFs;
UINTN Size;
EFI_FILE_SYSTEM_INFO *VolumeInfo;
CHAR16 *VolumeSizeStr = NULL;
CHAR16 Buffer[32];
Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileSystem);
if (EFI_ERROR(Status))
return NULL;
Status = FileSystem->OpenVolume (FileSystem, &RootFs);
if (EFI_ERROR(Status))
return NULL;
Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocatePool (Size);
if (VolumeInfo == NULL) {
return NULL;
}
Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
if (Status == EFI_SUCCESS) {
ValueToString ((UINTN)VolumeInfo->VolumeSize, 32, Buffer, VTS_LEFT_ALIGN);
ConvDititalByUnit (Buffer, sizeof(Buffer));
VolumeSizeStr = StrDuplicate( Buffer);
}
FreePool (VolumeInfo);
return VolumeSizeStr;
}
BOOLEAN
IsRecordableDevice (
EFI_HANDLE Handle
)
{
EFI_BLOCK_IO_PROTOCOL *BlkIo;
EFI_STATUS Status;
Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
if (EFI_ERROR(Status))
return FALSE;
if (BlkIo->Media->ReadOnly)
return FALSE;
//if (!BlkIo->Media->RemovableMedia)
// return FALSE;
return TRUE;
}
/**
Function compares a device path data structure to that of all the nodes of a
second device path instance.
@param [in] Multi A pointer to a multi-instance device path data structure.
@param [in] Single A pointer to a single-instance device path data structure.
@retval TRUE If the Single is contained within Multi
@retval FALSE The Single is not match within Multi
**/
BOOLEAN
MatchDevicePaths (
IN EFI_DEVICE_PATH_PROTOCOL *Multi,
IN EFI_DEVICE_PATH_PROTOCOL *Single
)
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
UINTN Size;
if (!Multi || !Single) {
return FALSE;
}
DevicePath = Multi;
DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
//
// Search for the match of 'Single' in 'Multi'
//
while (DevicePathInst != NULL) {
//
// If the single device path is found in multiple device paths,
// return success
//
if (CompareMem (Single, DevicePathInst, Size) == 0) {
FreePool (DevicePathInst);
return TRUE;
}
FreePool (DevicePathInst);
DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
}
return FALSE;
}
EFI_STATUS
GetActiveVgaHandle (
EFI_HANDLE *VgaHandle
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *ConOutDevPath;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
static EFI_HANDLE mActiveVgaHandle = NULL;
// verify parameter
if (VgaHandle == NULL)
return EFI_INVALID_PARAMETER;
//3 If we have the VGA handle just return it.
if (mActiveVgaHandle != NULL) {
*VgaHandle = mActiveVgaHandle;
return EFI_SUCCESS;
}
// Get ConOut device path from variable
ConOutDevPath = CommonGetVariableData (L"ConOut", &gEfiGlobalVariableGuid);
if (ConOutDevPath == NULL)
return EFI_NOT_READY;
// Get all GOP protocol handles
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiGraphicsOutputProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR(Status))
return EFI_NOT_READY;
// compare Active VGA device path
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevPath);
if (EFI_ERROR(Status))
continue;
if (MatchDevicePaths (ConOutDevPath, DevPath)) {
mActiveVgaHandle = HandleBuffer[Index];
break;
}
}
if (mActiveVgaHandle == NULL)
return EFI_UNSUPPORTED;
// Set return value
*VgaHandle = mActiveVgaHandle;
FreePool (ConOutDevPath);
FreePool (HandleBuffer);
return EFI_SUCCESS;
}
EFI_STATUS
GetActiveVgaGop (
EFI_GRAPHICS_OUTPUT_PROTOCOL **Gop
)
{
EFI_STATUS Status;
EFI_HANDLE VgaHandle;
if (mActiveVgaGop == NULL) {
Status = GetActiveVgaHandle(&VgaHandle);
if (EFI_ERROR(Status))
return EFI_NOT_READY;
gBS->HandleProtocol (VgaHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&mActiveVgaGop);
}
*Gop = mActiveVgaGop;
return EFI_SUCCESS;
}
VOID
GetKey (
OUT EFI_INPUT_KEY *Key
)
{
Key->ScanCode = 0;
Key->UnicodeChar = 0;
do {
gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
} while ((Key->ScanCode == 0) && (Key->UnicodeChar == 0));
}
EFI_STATUS
LocateDriverIndex (
EFI_GUID *ProtocolGuid
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN HIndex;
UINTN PIndex;
UINTN ProtocolCount;
EFI_GUID **ProtocolBuffer;
VOID *Interface;
Status = gBS->LocateProtocol (ProtocolGuid, NULL, (VOID **)&Interface);
if (EFI_ERROR(Status))
return Status;
Status = gBS->LocateHandleBuffer (
AllHandles,
NULL,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
//Print(L"LibScanHandleDatabase ERROR!!!\n");
//UnicodeSPrint(NULL,NULL,L"LibScanHandleDatabase ERROR!!!\n");
return Status;
}
for (HIndex = HandleCount; HIndex > 0; HIndex--) {
Status = gBS->ProtocolsPerHandle (HandleBuffer[HIndex-1], &ProtocolBuffer, &ProtocolCount);
for (PIndex = 0; PIndex < ProtocolCount; PIndex++) {
if(CompareGuid(ProtocolBuffer[PIndex], ProtocolGuid) == TRUE) {
//Print (L"SnapScreen Image Handle Index : 0x%X\n", HIndex);
//UnicodeSPrint (NULL,NULL,L"SnapScreen Image Handle Index : 0x%X\n", HIndex);
return EFI_SUCCESS;
}
}
FreePool (ProtocolBuffer);
}
FreePool (HandleBuffer);
return EFI_NOT_FOUND;
}