From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:4864:20::d43; helo=mail-io1-xd43.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-io1-xd43.google.com (mail-io1-xd43.google.com [IPv6:2607:f8b0:4864:20::d43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 512C3211A2D93 for ; Fri, 14 Dec 2018 07:07:11 -0800 (PST) Received: by mail-io1-xd43.google.com with SMTP id k7so4654968iob.6 for ; Fri, 14 Dec 2018 07:07:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=lO+NW4S2C0KgpN90fZuixPqy2JKK7Oat7/jJBQoUBe8=; b=i0KIT6FQukN1ISyXl//WB4KRuP4kzsRPJy3TsdHFm+p0oX+5P8SIAe270LF7JQILK3 EDHF74nkqFbspjFucroq3QKJ+m4En1U47BRgzvIXq0TwsSVL5XOph4yUH9fHM48oDebA 4QW1+QSzuWZAa+4jCC7ezhXfgoLS/bUfYcHDQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=lO+NW4S2C0KgpN90fZuixPqy2JKK7Oat7/jJBQoUBe8=; b=PONuFZFQmy488ZSGHFSSWdM2lTw/pi+IaC+w+dxNZW62D9sVyuyAqMLyR3WgzuDnGq mc/4Mj3SV/wi1NHM7fMQn8noNmM7SLbC1oynbmX8r7BPuOVQ7BdKzig3qM8HnhSVMXvK 3Ecxr2yjrUQWXQtamCCBDvYSLgCqiN0eIw2OKOWGnAb1G1VUlAf1MHtEhol6mIYpEGxk HbCA+rK//cMPVTlJj1dCMw2h8c41A15beLgwZP9MamRaYUGwvxAZy4J/jZwhcBonDL9B +CgxrOflZVsvuqtF7F3NA9NcF1jYauiX/rhdIhvSqPsf7Qw8BIxgn8uZlSNe2UOdcIol oF8g== X-Gm-Message-State: AA+aEWayypmx4kX5FozQW4wBXFaczVQNX/Bou9x4I4ePuij4mI6wBaNc XrfJIYQQlyeUEwXihVte2GFj54yj0XT47+/x1E7aYTAkTDg= X-Google-Smtp-Source: AFSGD/XcWAaAbJSxe/N2LPw7goIsLBq2EFXYs1xJc2TKDsdtGtloUlzdSkPgMC118xYLURyPczYNVvRpKEX48bYYqJA= X-Received: by 2002:a5e:cb0b:: with SMTP id p11mr2964118iom.60.1544800030097; Fri, 14 Dec 2018 07:07:10 -0800 (PST) MIME-Version: 1.0 References: <20181210123853.4864-1-pete@akeo.ie> <20181210123853.4864-9-pete@akeo.ie> In-Reply-To: <20181210123853.4864-9-pete@akeo.ie> From: Ard Biesheuvel Date: Fri, 14 Dec 2018 16:06:59 +0100 Message-ID: To: Pete Batard Cc: "edk2-devel@lists.01.org" Subject: Re: [PATCH v2 edk2-platforms 08/20] Platform/Broadcom/RPi3: Add Display driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Dec 2018 15:07:11 -0000 Content-Type: text/plain; charset="UTF-8" On Mon, 10 Dec 2018 at 13:39, Pete Batard wrote: > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Pete Batard Please fix the usual things like INF_VERSION and space before ( in function or macro invocations. Otherwise, this looks fine ' > --- > Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c | 222 +++++++ > Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c | 606 ++++++++++++++++++++ > Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h | 43 ++ > Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf | 71 +++ > Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c | 379 ++++++++++++ > 5 files changed, 1321 insertions(+) > > diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c > new file mode 100644 > index 000000000000..e639826c60b1 > --- /dev/null > +++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c > @@ -0,0 +1,222 @@ > +/** @file > + * > + * Copyright (c) 2018, Andrei Warkentin > + * Copyright (c) 2006-2016, Intel Corporation. All rights reserved. > + * > + * This program and the accompanying materials > + * are licensed and made available under the terms and conditions of the BSD License > + * which accompanies this distribution. The full text of the license may be found at > + * http://opensource.org/licenses/bsd-license.php > + * > + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + * > + **/ > + > +#include "DisplayDxe.h" > + > +STATIC > +EFI_STATUS > +EFIAPI > +ComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > +); > + > +STATIC > +EFI_STATUS > +EFIAPI > +ComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle, > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ); > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gComponentName = { > + ComponentNameGetDriverName, > + ComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ComponentNameGetControllerName, > + "en" > +}; > + > + > +STATIC EFI_UNICODE_STRING_TABLE mDriverName[] = { > + { > + "eng;en", > + (CHAR16 *)L"Raspberry Pi Display Driver" > + }, > + { > + NULL, > + NULL > + } > +}; > + > +STATIC EFI_UNICODE_STRING_TABLE mDeviceName[] = { > + { > + "eng;en", > + (CHAR16 *)L"Raspberry Pi Framebuffer" > + }, > + { > + NULL, > + NULL > + } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the driver. > + > + This function retrieves the user readable name of a driver in the form of a > + Unicode string. If the driver specified by This has a user readable name in > + the language specified by Language, then a pointer to the driver name is > + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified > + by This does not support the language specified by Language, > + then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. The > + number of languages supported by a driver is up > + to the driver writer. Language is specified > + in RFC 4646 or ISO 639-2 language code format. > + > + @param DriverName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + driver specified by This in the language > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver specified by > + This and the language specified by Language was > + returned in DriverName. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ) > +{ > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + mDriverName, > + DriverName, > + (BOOLEAN)(This == &gComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the controller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller specified by > + ControllerHandle and ChildHandle in the form of a Unicode string. If the > + driver specified by This has a user readable name in the language specified by > + Language, then a pointer to the controller name is returned in ControllerName, > + and EFI_SUCCESS is returned. If the driver specified by This is not currently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This does not > + support the language specified by Language, then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param ControllerHandle[in] The handle of a controller that the driver > + specified by This is managing. This handle > + specifies the controller whose name is to be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to retrieve > + the name of. This is an optional parameter that > + may be NULL. It will be NULL for device > + drivers. It will also be NULL for a bus drivers > + that wish to retrieve the name of the bus > + controller. It will not be NULL for a bus > + driver that wishes to retrieve the name of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. The > + number of languages supported by a driver is up > + to the driver writer. Language is specified in > + RFC 4646 or ISO 639-2 language code format. > + > + @param ControllerName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + controller specified by ControllerHandle and > + ChildHandle in the language specified by > + Language from the point of view of the driver > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable name in > + the language specified by Language for the > + driver specified by This was returned in > + DriverName. > + > + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. > + > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid > + EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This is not currently > + managing the controller specified by > + ControllerHandle and ChildHandle. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle, > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ) > +{ > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + mDeviceName, > + ControllerName, > + (BOOLEAN)(This == &gComponentName) > + ); > +} > diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c > new file mode 100644 > index 000000000000..e8b7f67c8870 > --- /dev/null > +++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c > @@ -0,0 +1,606 @@ > +/** @file > + * > + * Copyright (c) 2017-2018, Andrei Warkentin > + * Copyright (c) Microsoft Corporation. All rights reserved. > + * > + * This program and the accompanying materials > + * are licensed and made available under the terms and conditions of the BSD License > + * which accompanies this distribution. The full text of the license may be found at > + * http://opensource.org/licenses/bsd-license.php > + * > + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + * > + **/ > + > +#include "DisplayDxe.h" > + > +#define POS_TO_FB(posX, posY) ((UINT8 *) \ > + ((UINTN)This->Mode->FrameBufferBase + \ > + (posY) * This->Mode->Info->PixelsPerScanLine * \ > + PI3_BYTES_PER_PIXEL + \ > + (posX) * PI3_BYTES_PER_PIXEL)) > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ); > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplayQueryMode( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN UINT32 ModeNumber, > + OUT UINTN *SizeOfInfo, > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info > + ); > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplaySetMode( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN UINT32 ModeNumber > + ); > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplayBlt( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > + IN UINTN SourceX, > + IN UINTN SourceY, > + IN UINTN DestinationX, > + IN UINTN DestinationY, > + IN UINTN Width, > + IN UINTN Height, > + IN UINTN Delta OPTIONAL > + ); > + > +STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = { > + DriverSupported, > + DriverStart, > + DriverStop, > + 0xa, > + NULL, > + NULL > +}; > + > +typedef struct { > + VENDOR_DEVICE_PATH DisplayDevicePath; > + EFI_DEVICE_PATH EndDevicePath; > +} DISPLAY_DEVICE_PATH; > + > +typedef struct { > + UINT32 Width; > + UINT32 Height; > +} GOP_MODE_DATA; > + > +STATIC UINT32 mBootWidth; > +STATIC UINT32 mBootHeight; > +STATIC EFI_HANDLE mDevice; > +STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol; > +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; > + > +STATIC UINTN mLastMode; > +STATIC GOP_MODE_DATA mGopModeData[] = { > + { 800, 600 }, /* Legacy */ > + { 640, 480 }, /* Legacy */ > + { 1024, 768 }, /* Legacy */ > + { 1280, 720 }, /* 720p */ > + { 1920, 1080 }, /* 1080p */ > + { 0, 0 }, /* Physical */ > +}; > + > +STATIC DISPLAY_DEVICE_PATH mDisplayProtoDevicePath = > + { > + { > + { > + HARDWARE_DEVICE_PATH, > + HW_VENDOR_DP, > + { > + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), > + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), > + } > + }, > + EFI_CALLER_ID_GUID, > + }, > + { > + END_DEVICE_PATH_TYPE, > + END_ENTIRE_DEVICE_PATH_SUBTYPE, > + { > + sizeof(EFI_DEVICE_PATH_PROTOCOL), > + 0 > + } > + } > + }; > + > +#define PI3_BITS_PER_PIXEL (32) > +#define PI3_BYTES_PER_PIXEL (PI3_BITS_PER_PIXEL / 8) > + > +EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplayProto = { > + DisplayQueryMode, > + DisplaySetMode, > + DisplayBlt, > + NULL > +}; > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplayQueryMode( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN UINT32 ModeNumber, > + OUT UINTN *SizeOfInfo, > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info > + ) > +{ > + EFI_STATUS Status; > + GOP_MODE_DATA *Mode; > + > + if (ModeNumber > mLastMode) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status = gBS->AllocatePool( > + EfiBootServicesData, > + sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), > + (VOID **)Info > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Mode = &mGopModeData[ModeNumber]; > + > + *SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); > + (*Info)->Version = This->Mode->Info->Version; > + (*Info)->HorizontalResolution = Mode->Width; > + (*Info)->VerticalResolution = Mode->Height; > + (*Info)->PixelFormat = This->Mode->Info->PixelFormat; > + (*Info)->PixelsPerScanLine = Mode->Width; > + > + return EFI_SUCCESS; > +} > + > +STATIC > +VOID > +ClearScreen( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This > + ) > +{ > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill; > + > + Fill.Red = 0x00; > + Fill.Green = 0x00; > + Fill.Blue = 0x00; > + This->Blt (This, &Fill, EfiBltVideoFill, > + 0, 0, 0, 0, This->Mode->Info->HorizontalResolution, > + This->Mode->Info->VerticalResolution, > + This->Mode->Info->HorizontalResolution * > + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplaySetMode( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN UINT32 ModeNumber > + ) > +{ > + UINTN FbSize; > + UINTN FbPitch; > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS FbBase; > + GOP_MODE_DATA *Mode = &mGopModeData[ModeNumber]; > + > + if (ModeNumber > mLastMode) { > + return EFI_UNSUPPORTED; > + } > + > + DEBUG((DEBUG_INFO, "Setting mode %u from %u: %u x %u\n", > + ModeNumber, This->Mode->Mode, Mode->Width, Mode->Height)); > + Status = mFwProtocol->GetFB(Mode->Width, Mode->Height, > + PI3_BITS_PER_PIXEL, &FbBase, > + &FbSize, &FbPitch); > + if (EFI_ERROR(Status)) { > + DEBUG((DEBUG_ERROR, "Could not set mode %u\n", ModeNumber)); > + return EFI_DEVICE_ERROR; > + } > + > + DEBUG((DEBUG_INFO, "Mode %u: %u x %u framebuffer is %u bytes at %p\n", > + ModeNumber, Mode->Width, Mode->Height, FbSize, FbBase)); > + > + if (FbPitch / PI3_BYTES_PER_PIXEL != Mode->Width) { > + DEBUG((DEBUG_ERROR, "Error: Expected width %u, got width %u\n", > + Mode->Width, FbPitch / PI3_BYTES_PER_PIXEL)); > + return EFI_DEVICE_ERROR; > + } > + > + /* > + * WT, because certain OS loaders access the frame buffer directly > + * and we don't want to see corruption due to missing WB cache > + * maintenance. Performance with WT is good. > + */ > + Status = mCpu->SetMemoryAttributes(mCpu, FbBase, > + ALIGN_VALUE(FbSize, EFI_PAGE_SIZE), > + EFI_MEMORY_WT); > + if (Status != EFI_SUCCESS) { > + DEBUG((DEBUG_ERROR, "Couldn't set framebuffer attributes: %r\n", Status)); > + return Status; > + } > + > + This->Mode->Mode = ModeNumber; > + This->Mode->Info->Version = 0; > + This->Mode->Info->HorizontalResolution = Mode->Width; > + This->Mode->Info->VerticalResolution = Mode->Height; > + /* > + * NOTE: Windows REQUIRES BGR in 32 or 24 bit format. > + */ > + This->Mode->Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; > + This->Mode->Info->PixelsPerScanLine = Mode->Width; > + This->Mode->SizeOfInfo = sizeof(*This->Mode->Info); > + This->Mode->FrameBufferBase = FbBase; > + This->Mode->FrameBufferSize = FbSize; > + > + ClearScreen(This); > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +DisplayBlt( > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > + IN UINTN SourceX, > + IN UINTN SourceY, > + IN UINTN DestinationX, > + IN UINTN DestinationY, > + IN UINTN Width, > + IN UINTN Height, > + IN UINTN Delta OPTIONAL > + ) > +{ > + UINT8 *VidBuf, *BltBuf, *VidBuf1; > + UINTN i; > + > + switch(BltOperation) { > + case EfiBltVideoFill: > + BltBuf = (UINT8 *)BltBuffer; > + > + for (i = 0; i < Height; i++) { > + VidBuf = POS_TO_FB(DestinationX, DestinationY + i); > + > + SetMem32(VidBuf, Width * PI3_BYTES_PER_PIXEL, *(UINT32 *) BltBuf); > + } > + break; > + > + case EfiBltVideoToBltBuffer: > + if (Delta == 0) { > + Delta = Width * PI3_BYTES_PER_PIXEL; > + } > + > + for (i = 0; i < Height; i++) { > + VidBuf = POS_TO_FB(SourceX, SourceY + i); > + > + BltBuf = (UINT8 *)((UINTN)BltBuffer + (DestinationY + i) * Delta + > + DestinationX * PI3_BYTES_PER_PIXEL); > + > + gBS->CopyMem((VOID *)BltBuf, (VOID *)VidBuf, PI3_BYTES_PER_PIXEL * Width); > + } > + break; > + > + case EfiBltBufferToVideo: > + if (Delta == 0) { > + Delta = Width * PI3_BYTES_PER_PIXEL; > + } > + > + for (i = 0; i < Height; i++) { > + VidBuf = POS_TO_FB(DestinationX, DestinationY + i); > + BltBuf = (UINT8 *)((UINTN) BltBuffer + (SourceY + i) * Delta + > + SourceX * PI3_BYTES_PER_PIXEL); > + > + gBS->CopyMem((VOID *)VidBuf, (VOID *)BltBuf, Width * PI3_BYTES_PER_PIXEL); > + } > + break; > + > + case EfiBltVideoToVideo: > + for (i = 0; i < Height; i++) { > + VidBuf = POS_TO_FB(SourceX, SourceY + i); > + VidBuf1 = POS_TO_FB(DestinationX, DestinationY + i); > + > + gBS->CopyMem((VOID *)VidBuf1, (VOID *)VidBuf, Width * PI3_BYTES_PER_PIXEL); > + } > + break; > + > + default: > + ASSERT_EFI_ERROR(EFI_SUCCESS); > + break; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Initialize the state information for the Display Dxe > + > + @param ImageHandle of the loaded driver > + @param SystemTable Pointer to the System Table > + > + @retval EFI_SUCCESS Protocol registered > + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure > + @retval EFI_DEVICE_ERROR Hardware problems > + > +**/ > +EFI_STATUS > +EFIAPI > +DisplayDxeInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + > + Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL, > + (VOID **)&mFwProtocol); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, > + (VOID **) &mCpu); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Query the current display resolution from mailbox > + Status = mFwProtocol->GetFBSize(&mBootWidth, &mBootHeight); > + if(EFI_ERROR(Status)) { > + return Status; > + } > + > + DEBUG((DEBUG_INFO, "Display boot mode is %u x %u\n", > + mBootWidth, mBootHeight)); > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &mDevice, &gEfiDevicePathProtocolGuid, > + &mDisplayProtoDevicePath, &gEfiCallerIdGuid, > + NULL, NULL); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = EfiLibInstallDriverBindingComponentName2 ( > + ImageHandle, > + SystemTable, > + &mDriverBinding, > + ImageHandle, > + &gComponentName, > + &gComponentName2 > + ); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return Status; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > +{ > + VOID *Temp; > + > + if (Controller != mDevice) { > + return EFI_UNSUPPORTED; > + } > + > + if (gBS->HandleProtocol(Controller, &gEfiGraphicsOutputProtocolGuid, > + (VOID **) &Temp) == EFI_SUCCESS) { > + return EFI_ALREADY_STARTED; > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > +{ > + UINTN Index; > + EFI_STATUS Status; > + VOID *Dummy; > + > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiCallerIdGuid, > + (VOID **) &Dummy, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + gDisplayProto.Mode = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); > + if (gDisplayProto.Mode == NULL) { > + Status = EFI_OUT_OF_RESOURCES; > + goto done; > + } > + > + gDisplayProto.Mode->Info = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); > + if (gDisplayProto.Mode->Info == NULL) { > + Status = EFI_OUT_OF_RESOURCES; > + goto done; > + } > + > + > + if (PcdGet32(PcdDisplayEnableVModes)) { > + mLastMode = ELES(mGopModeData) - 1; > + } else { > + mLastMode = 0; > + /* > + * mBootWidth x mBootHeight may not be sensible, > + * so clean it up, since we won't be adding > + * any other extra vmodes. > + */ > + if (mBootWidth < 640 || > + mBootHeight < 480) { > + mBootWidth = 640; > + mBootHeight = 480; > + } > + } > + > + mGopModeData[mLastMode].Width = mBootWidth; > + mGopModeData[mLastMode].Height = mBootHeight; > + > + for (Index = 0; Index <= mLastMode; Index++) { > + UINTN FbSize; > + UINTN FbPitch; > + EFI_PHYSICAL_ADDRESS FbBase; > + > + GOP_MODE_DATA *Mode = &mGopModeData[Index]; > + > + Status = mFwProtocol->GetFB(Mode->Width, Mode->Height, > + PI3_BITS_PER_PIXEL, &FbBase, > + &FbSize, &FbPitch); > + if (EFI_ERROR(Status)) { > + goto done; > + } > + > + // > + // There is no way to communicate pitch back to OS. OS and even UEFI > + // expect a fully linear frame buffer. So the width should > + // be based on the frame buffer's pitch value. In some cases VC > + // firmware would allocate ao frame buffer with some padding > + // presumably to be 8 byte align. > + // > + Mode->Width = FbPitch / PI3_BYTES_PER_PIXEL; > + > + DEBUG((DEBUG_INFO, "Mode %u: %u x %u framebuffer is %u bytes at %p\n", > + Index, Mode->Width, Mode->Height, FbSize, FbBase)); > + > + ASSERT (FbPitch != 0); > + ASSERT (FbBase != 0); > + ASSERT (FbSize != 0); > + } > + > + // Both set the mode and initialize current mode information. > + gDisplayProto.Mode->MaxMode = mLastMode + 1; > + DisplaySetMode(&gDisplayProto, 0); > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Controller, &gEfiGraphicsOutputProtocolGuid, > + &gDisplayProto, NULL); > + if (EFI_ERROR (Status)) { > + goto done; > + } > + > + if (PcdGet32(PcdDisplayEnableSShot)) { > + RegisterScreenshotHandlers(); > + } else { > + DEBUG((DEBUG_INFO, "Screenshot capture disabled\n")); > + } > + > +done: > + if (EFI_ERROR (Status)) { > + DEBUG((DEBUG_ERROR, "Could not start DisplayDxe: %r\n", Status)); > + if (gDisplayProto.Mode->Info != NULL) { > + FreePool(gDisplayProto.Mode->Info); > + gDisplayProto.Mode->Info = NULL; > + } > + > + if (gDisplayProto.Mode != NULL) { > + FreePool(gDisplayProto.Mode); > + gDisplayProto.Mode = NULL; > + } > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiCallerIdGuid, > + This->DriverBindingHandle, > + Controller > + ); > + } > + return Status; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +DriverStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ) > +{ > + EFI_STATUS Status; > + > + ClearScreen(&gDisplayProto); > + > + Status = gBS->UninstallMultipleProtocolInterfaces ( > + Controller, &gEfiGraphicsOutputProtocolGuid, > + &gDisplayProto, NULL); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + FreePool(gDisplayProto.Mode->Info); > + gDisplayProto.Mode->Info = NULL; > + FreePool(gDisplayProto.Mode); > + gDisplayProto.Mode = NULL; > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiCallerIdGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + return Status; > +} > diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h > new file mode 100644 > index 000000000000..9fa3d4f6af83 > --- /dev/null > +++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h > @@ -0,0 +1,43 @@ > +/** @file > + * > + * Copyright (c) 2017-2018, Andrei Warkentin > + * Copyright (c) Microsoft Corporation. All rights reserved. > + * > + * This program and the accompanying materials > + * are licensed and made available under the terms and conditions of the BSD License > + * which accompanies this distribution. The full text of the license may be found at > + * http://opensource.org/licenses/bsd-license.php > + * > + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + * > + **/ > + > +#ifndef _DISPLAY_H_ > +#define _DISPLAY_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +extern EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplayProto; > +extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; > +extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; > + > +VOID > +RegisterScreenshotHandlers( > + VOID > + ); > + > +#endif /* _DISPLAY_H_ */ > diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf > new file mode 100644 > index 000000000000..1603edd4909d > --- /dev/null > +++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf > @@ -0,0 +1,71 @@ > +#/** @file > +# > +# Component description file for Graphics Output module > +# > +# Copyright (c) 2017, Andrei Warkentin > +# Copyright (c) Microsoft Corporation. All rights reserved. > +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > +#**/ > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = DisplayDxe > + FILE_GUID = c5deae31-fad2-4030-841b-cfc9644d2c5b > + MODULE_TYPE = UEFI_DRIVER > + VERSION_STRING = 1.0 > + ENTRY_POINT = DisplayDxeInitialize > + > +# > +# The following information is for reference only and not required by the build tools. > +# > +# DRIVER_BINDING = gGraphicsConsoleDriverBinding > +# COMPONENT_NAME = gGraphicsConsoleComponentName > +# COMPONENT_NAME2 = gGraphicsConsoleComponentName2 > +# > + > +[Sources] > + DisplayDxe.c > + Screenshot.c > + ComponentName.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + ArmPkg/ArmPkg.dec > + Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec > + > +[LibraryClasses] > + BaseLib > + UefiLib > + MemoryAllocationLib > + UefiDriverEntryPoint > + IoLib > + TimerLib > + BmpSupportLib > + UefiRuntimeServicesTableLib > + > +[Protocols] > + gEfiLoadedImageProtocolGuid > + gEfiDevicePathProtocolGuid > + gEfiGraphicsOutputProtocolGuid > + gRaspberryPiFirmwareProtocolGuid > + gEfiCpuArchProtocolGuid > + gEfiSimpleFileSystemProtocolGuid > + gEfiSimpleTextInputExProtocolGuid > + > +[Pcd] > + gRaspberryPiTokenSpaceGuid.PcdDisplayEnableVModes > + gRaspberryPiTokenSpaceGuid.PcdDisplayEnableSShot > + > +[Guids] > + > +[Depex] > + gEfiCpuArchProtocolGuid AND gRaspberryPiFirmwareProtocolGuid > diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c > new file mode 100644 > index 000000000000..a2feeba6084f > --- /dev/null > +++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c > @@ -0,0 +1,379 @@ > +/** @file > + * > + * Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. > + * Copyright (c) 2018, Andrei Warkentin > + * > + * This program and the accompanying materials > + * are licensed and made available under the terms and conditions of the BSD License > + * which accompanies this distribution. The full text of the license may be found at > + * http://opensource.org/licenses/bsd-license.php > + * > + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + * > + **/ > + > +/* > + * 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 > +#include > +#include > +#include > + > +/* > + * 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; > + } > +} > -- > 2.17.0.windows.1 >