Files
Pete Batard 03f36b8fcf Platforms/RPi3: Restructure platform in preparation for Pi 4
In preparation for adding Raspberry Pi 4 support, the Pi 3 platform
is restructured by factorizing all the drivers and libraries that are
going to be commonly used by the two platforms.

Because much of the Pi 4 SoC is an extension of the Pi 3 one this
means that almost everything, except the ACPI tables, is moved up
into a new common RaspberryPi/ subdirectory that will serve both
platforms. The .dec is also moved to this directory, under a new
RaspberryPi.dec name, and existing references to it are updated.

This commit requires the edk2-non-osi in use to contain commit 243e55f622ea
in order to build.

Signed-off-by: Pete Batard <pete@akeo.ie>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
2019-10-21 15:32:32 +01:00

370 lines
10 KiB
C

/** @file
*
* Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
* Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
/*
* Loosely based on CrScreenShotDxe (https://github.com/LongSoft/CrScreenshotDxe).
*
* Copyright (c) 2016, Nikolaj Schlej, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "DisplayDxe.h"
#include <Protocol/SimpleFileSystem.h>
#include <Library/PrintLib.h>
#include <Library/BmpSupportLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
/*
* ShowStatus defs.
*/
#define STATUS_SQUARE_SIDE 5
#define STATUS_YELLOW 0xff, 0xff, 0x00
#define STATUS_GREEN 0x00, 0xff, 0x00
#define STATUS_BLUE 0x00, 0x00, 0xff
#define STATUS_RED 0xff, 0x00, 0x00
EFI_STATUS
ShowStatus (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN UINT8 Red,
IN UINT8 Green,
IN UINT8 Blue
)
{
UINTN Index;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Square[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE];
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Backup[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE];
for (Index = 0; Index < STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE; Index++) {
Square[Index].Blue = Blue;
Square[Index].Green = Green;
Square[Index].Red = Red;
Square[Index].Reserved = 0x00;
}
// Backup current image.
GraphicsOutput->Blt (GraphicsOutput, Backup,
EfiBltVideoToBltBuffer, 0, 0, 0, 0,
STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
// Draw the status square.
GraphicsOutput->Blt (GraphicsOutput, Square,
EfiBltBufferToVideo, 0, 0, 0, 0,
STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
// Wait 500ms.
gBS->Stall (500 * 1000);
// Restore the backup.
GraphicsOutput->Blt (GraphicsOutput, Backup,
EfiBltBufferToVideo, 0, 0, 0, 0,
STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
FindWritableFs (
OUT EFI_FILE_PROTOCOL **WritableFs
)
{
EFI_FILE_PROTOCOL *Fs = NULL;
EFI_HANDLE *HandleBuffer = NULL;
UINTN HandleCount;
UINTN Index;
EFI_STATUS Status = gBS->LocateHandleBuffer (ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs = NULL;
EFI_FILE_PROTOCOL *File = NULL;
Status = gBS->HandleProtocol (HandleBuffer[Index],
&gEfiSimpleFileSystemProtocolGuid,
(VOID**)&SimpleFs);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
/*
* Not supposed to happen.
*/
continue;
}
Status = SimpleFs->OpenVolume (SimpleFs, &Fs);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a OpenVolume[%u] returned %r\n", __FUNCTION__, Index, Status));
continue;
}
Status = Fs->Open (Fs, &File, L"--------.---",
EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE, 0);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a Open[%u] returned %r\n", __FUNCTION__, Index, Status));
continue;
}
/*
* Okay, we have a writable filesystem!
*/
Fs->Delete (File);
*WritableFs = Fs;
Status = EFI_SUCCESS;
break;
}
if (HandleBuffer) {
FreePool (HandleBuffer);
}
return Status;
}
STATIC
VOID
TakeScreenshot (
VOID
)
{
VOID *BmpImage = NULL;
EFI_FILE_PROTOCOL *Fs = NULL;
EFI_FILE_PROTOCOL *File = NULL;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = &gDisplayProto;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Image = NULL;
EFI_STATUS Status;
CHAR16 FileName[8 + 1 + 3 + 1];
UINT32 ScreenWidth;
UINT32 ScreenHeight;
UINTN ImageSize;
UINTN BmpSize;
UINTN Index;
EFI_TIME Time;
Status = FindWritableFs (&Fs);
if (EFI_ERROR (Status)) {
ShowStatus (GraphicsOutput, STATUS_YELLOW);
}
ScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
ScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
ImageSize = ScreenWidth * ScreenHeight;
Status = gRT->GetTime (&Time, NULL);
if (!EFI_ERROR (Status)) {
UnicodeSPrint (FileName, sizeof (FileName), L"%02d%02d%02d%02d.bmp",
Time.Day, Time.Hour, Time.Minute, Time.Second);
} else {
UnicodeSPrint (FileName, sizeof (FileName), L"scrnshot.bmp");
}
Image = AllocatePool (ImageSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
if (Image == NULL) {
Status = EFI_OUT_OF_RESOURCES;
ShowStatus (GraphicsOutput, STATUS_RED);
goto Done;
}
Status = GraphicsOutput->Blt (GraphicsOutput, Image,
EfiBltVideoToBltBuffer, 0, 0, 0, 0,
ScreenWidth, ScreenHeight, 0);
if (EFI_ERROR (Status)) {
ShowStatus (GraphicsOutput, STATUS_RED);
goto Done;
}
for (Index = 0; Index < ImageSize; Index++) {
if (Image[Index].Red != 0x00 ||
Image[Index].Green != 0x00 ||
Image[Index].Blue != 0x00) {
break;
}
}
if (Index == ImageSize) {
ShowStatus (GraphicsOutput, STATUS_BLUE);
goto Done;
}
Status = TranslateGopBltToBmp (Image, ScreenHeight, ScreenWidth,
&BmpImage, (UINT32*)&BmpSize);
if (EFI_ERROR (Status)) {
ShowStatus (GraphicsOutput, STATUS_RED);
goto Done;
}
Status = Fs->Open (Fs, &File, FileName, EFI_FILE_MODE_CREATE |
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
if (EFI_ERROR (Status)) {
ShowStatus (GraphicsOutput, STATUS_RED);
goto Done;
}
Status = File->Write (File, &BmpSize, BmpImage);
File->Close (File);
if (EFI_ERROR (Status)) {
ShowStatus (GraphicsOutput, STATUS_RED);
goto Done;
}
ShowStatus (GraphicsOutput, STATUS_GREEN);
Done:
if (BmpImage != NULL) {
FreePool (BmpImage);
}
if (Image != NULL) {
FreePool (Image);
}
}
STATIC
EFI_STATUS
EFIAPI
ScreenshotKeyHandler (
IN EFI_KEY_DATA *KeyData
)
{
TakeScreenshot ();
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
ProcessScreenshotHandler (
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_KEY_DATA ScreenshotKey;
/*
* LCtrl+LAlt+F12
*/
ScreenshotKey.Key.ScanCode = SCAN_F12;
ScreenshotKey.Key.UnicodeChar = 0;
ScreenshotKey.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID |
EFI_LEFT_CONTROL_PRESSED | EFI_LEFT_ALT_PRESSED;
ScreenshotKey.KeyState.KeyToggleState = 0;
Status = SimpleTextInEx->RegisterKeyNotify (
SimpleTextInEx,
&ScreenshotKey,
ScreenshotKeyHandler,
&Handle
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: couldn't register key notification: %r\n", __FUNCTION__, Status));
return Status;
}
return EFI_SUCCESS;
}
STATIC
VOID
ProcessScreenshotHandlers (
VOID
)
{
UINTN Index;
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInputExProtocolGuid,
NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index],
&gEfiSimpleTextInputExProtocolGuid,
(VOID**)&SimpleTextInEx);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
/*
* Not supposed to happen.
*/
continue;
}
Status = ProcessScreenshotHandler (SimpleTextInEx);
if (EFI_ERROR (Status)) {
continue;
}
}
}
STATIC
VOID
EFIAPI
OnTextInExInstall (
IN EFI_EVENT Event,
IN VOID *Context
)
{
ProcessScreenshotHandlers ();
}
VOID
RegisterScreenshotHandlers (
VOID
)
{
EFI_STATUS Status;
EFI_EVENT TextInExInstallEvent;
VOID *TextInExInstallRegistration;
ProcessScreenshotHandlers ();
Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
OnTextInExInstall, NULL,
&TextInExInstallEvent);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: couldn't create protocol install event: %r\n", __FUNCTION__, Status));
return;
}
Status = gBS->RegisterProtocolNotify (&gEfiSimpleTextInputExProtocolGuid,
TextInExInstallEvent,
&TextInExInstallRegistration);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: couldn't register protocol install notify: %r\n", __FUNCTION__, Status));
return;
}
}